diff --git a/android/app/build.gradle b/android/app/build.gradle index 65cff7c..39f6b1b 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -33,7 +33,7 @@ if (keystorePropertiesFile.exists()) { } android { - compileSdkVersion 28 + compileSdkVersion 30 sourceSets { main.java.srcDirs += 'src/main/kotlin' @@ -44,12 +44,12 @@ android { } defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "com.aitrainer.aitrainer_app" minSdkVersion 16 - targetSdkVersion 28 + targetSdkVersion 30 versionCode flutterVersionCode.toInteger() versionName flutterVersionName + multiDexEnabled true } signingConfigs { @@ -63,7 +63,6 @@ android { buildTypes { release { - // TODO: Add your own signing config for the release build. // Signing with the debug keys for now, so `flutter run --release` works. signingConfig signingConfigs.release } @@ -76,6 +75,7 @@ flutter { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation 'com.google.firebase:firebase-analytics:17.2.2' - implementation 'com.facebook.android:facebook-login:[5,6)' + implementation 'com.google.firebase:firebase-analytics:17.6.0' + implementation 'com.facebook.android:facebook-login:5.5.1' + implementation 'com.android.support:multidex:1.0.3' } diff --git a/android/build.gradle b/android/build.gradle index 2297a56..4dcce1a 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,14 +1,14 @@ buildscript { - ext.kotlin_version = '1.3.72' + ext.kotlin_version = '1.4.10' repositories { google() jcenter() } dependencies { - classpath "com.android.tools.build:gradle:3.5.0" + classpath "com.android.tools.build:gradle:4.0.2" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath "com.google.gms:google-services:4.3.3" + classpath "com.google.gms:google-services:4.3.4" } } diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index bc24dcf..493072b 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip diff --git a/asset/image/development_muscles.jpg b/asset/image/development_muscles.jpg deleted file mode 100644 index c2a86b2..0000000 Binary files a/asset/image/development_muscles.jpg and /dev/null differ diff --git a/asset/image/edzesnaplom400400.jpg b/asset/image/edzesnaplom400400.jpg new file mode 100644 index 0000000..a6e4c07 Binary files /dev/null and b/asset/image/edzesnaplom400400.jpg differ diff --git a/asset/image/exercise_log.jpg b/asset/image/exercise_log.jpg deleted file mode 100644 index b2833db..0000000 Binary files a/asset/image/exercise_log.jpg and /dev/null differ diff --git a/asset/image/exercise_plan_custom.jpg b/asset/image/exercise_plan_custom.jpg new file mode 100644 index 0000000..f1a2d5a Binary files /dev/null and b/asset/image/exercise_plan_custom.jpg differ diff --git a/asset/image/exercise_plan_execute.jpg b/asset/image/exercise_plan_execute.jpg new file mode 100644 index 0000000..ba50b66 Binary files /dev/null and b/asset/image/exercise_plan_execute.jpg differ diff --git a/asset/image/exercise_plan_special.jpg b/asset/image/exercise_plan_special.jpg new file mode 100644 index 0000000..9da7b11 Binary files /dev/null and b/asset/image/exercise_plan_special.jpg differ diff --git a/asset/image/exercise_plan_stars.jpg b/asset/image/exercise_plan_stars.jpg new file mode 100644 index 0000000..170d858 Binary files /dev/null and b/asset/image/exercise_plan_stars.jpg differ diff --git a/asset/image/exercise_plan_suggested.jpg b/asset/image/exercise_plan_suggested.jpg new file mode 100644 index 0000000..7a3137b Binary files /dev/null and b/asset/image/exercise_plan_suggested.jpg differ diff --git a/asset/image/izomcsop400400.jpg b/asset/image/izomcsop400400.jpg new file mode 100644 index 0000000..5e1dee1 Binary files /dev/null and b/asset/image/izomcsop400400.jpg differ diff --git a/asset/image/testemfejl400x400.jpg b/asset/image/testemfejl400x400.jpg new file mode 100644 index 0000000..b7eced7 Binary files /dev/null and b/asset/image/testemfejl400x400.jpg differ diff --git a/asset/menu/cable triceps.png b/asset/menu/cable_triceps.png similarity index 100% rename from asset/menu/cable triceps.png rename to asset/menu/cable_triceps.png diff --git a/asset/menu/shoulder press.png b/asset/menu/shoulder_press.png similarity index 100% rename from asset/menu/shoulder press.png rename to asset/menu/shoulder_press.png diff --git a/i18n/en.json b/i18n/en.json index 009cf5a..afdff05 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -1,4 +1,5 @@ { + "OK": "OK", "Network Error, please try again later": "Network Error, please try again later", "Home": "Home", "Customers": "Customers", @@ -117,9 +118,12 @@ "Your 1RM:":"Your 1RM:", "Your Real 1RM:":"Your Real 1RM:", "Check":"Check", - "1st Control Exercise:": "1st Control Exercise:", - "2nd Control Exercise:": "2nd Control Exercise:", - "3rd Control Exercise:": "3rd Control Exercise:", + "Control Exercise:": "Control Exercise:", + "Summary of your test":"Summary of your test", + "Test":"Test", + "1st Control": "1st Control", + "2nd Control": "2nd Control", + "3rd Control": "3rd Control", "My Development":"My Development", "My Training Plan":"My Training Plan", @@ -144,7 +148,7 @@ "Edit My Custom Plan": "Edit My Custom Plan", "Suggested Training Plan": "Suggested Training Plan", "My Special Plan": "My Special Plan", - "My Arnold's Plan":"My Arnold's Plan", + "My Arnold's Plan":"Stars Execercise Plan", "My Trainee's Plan": "My Trainee's Plan", "Execute My Trainee's Training Plan": "Execute My Trainee's Training Plan", @@ -164,6 +168,8 @@ "Monthly": "Monthly", "Yearly": "Yearly", "times!": "times!", + "Please repeat with ": "Please repeat with ", + "max times!": "max times!", "Execute your active Exercise Plan!": "Execute your active Exercise Plan!", "Select the muscle type and tap on the exercise. One the next page enter the weight and repeat.": "Select the muscle type and tap on the exercise. One the next page enter the weight and repeat.", @@ -194,5 +200,9 @@ "Bring me there": "Bring me there", "My Body Development": "My Body Development", - "You see here your whole body development by muscle groups.": "You see here your whole body development by muscle groups." + "You see here your whole body development by muscle groups.": "You see here your whole body development by muscle groups.", + + "Are you sure to logout?": "Are you sure to logout?", + "hu_with": " ", + "Are you sure to delete this exercise?": "Are you sure to delete this exercise?" } \ No newline at end of file diff --git a/i18n/hu.json b/i18n/hu.json index db9f2ee..e6ba203 100644 --- a/i18n/hu.json +++ b/i18n/hu.json @@ -1,4 +1,5 @@ { + "OK": "OK", "Network Error, please try again later": "Hálózati hiba, kérlek próbáld meg később", "Home": "Főoldal", "Customers": "Ügyfelek", @@ -144,7 +145,7 @@ "Edit My Custom Plan": "Egyéni edzésterv", "Suggested Training Plan": "Javasolt edzésterv", "My Special Plan": "Speciális edzésterv", - "My Arnold's Plan": "Arnold edzésterve rám szabva", + "My Arnold's Plan": "Sztárok edzésterve rám szabva", "My Trainee's Plan" : "Kliensem edzésterve", "Execute My Trainee's Training Plan": "Kliensem edzéstervének végrehajtása", @@ -164,6 +165,8 @@ "Monthly": "Havi", "Yearly": "Éves", "times!": "ismétléssel!", + "Please repeat with ": "Kérlek ismételd meg ", + "max times!": " max. számú ismétléssel!", "Execute your active Exercise Plan!": "Hajtsd végre az aktív edzéstervedet", "Select the muscle type and tap on the exercise. One the next page enter the weight and repeat.": "Válaszd ki az izomcsoporton belül a gyakorlatot, és a következő oldalon add meg a súlyt és az ismétlés számot.", @@ -193,5 +196,16 @@ "Bring me there": "Vigyél oda", "My Body Development": "Testem fejlődése", - "You see here your whole body development by muscle groups.": "Itt láthatod a tested fejlődését izomcsoportonként" + "You see here your whole body development by muscle groups.": "Itt láthatod a tested fejlődését izomcsoportonként", + + "Are you sure to logout?": "Biztos, hogy kijelentkezel?", + "hu_with": "-mal", + "Control Exercise:": "Gyakorlat végrehajtása:", + "Test":"Teszt", + "1st Control": "1. kontrollgyakorlat", + "2nd Control": "2. kontrollgyakorlat", + "3rd Control": "3. kontrollgyakorlat", + "Summary of your test":"A teszt összefoglalása:", + + "Are you sure to delete this exercise?": "Biztos, hogy törlöd a gyakorlatot?" } \ No newline at end of file diff --git a/lib/bloc/account/account_bloc.dart b/lib/bloc/account/account_bloc.dart index 0e33c7b..f44057e 100644 --- a/lib/bloc/account/account_bloc.dart +++ b/lib/bloc/account/account_bloc.dart @@ -34,6 +34,7 @@ class AccountBloc extends Bloc { //route to Login Page } else if (event is AccountLogInFinished) { customerRepository.customer = event.customer; + this.loggedIn = true; yield AccountLoggedIn(); } else if (event is AccountLogout) { await Cache().logout(); diff --git a/lib/bloc/development_by_muscle/development_by_muscle_bloc.dart b/lib/bloc/development_by_muscle/development_by_muscle_bloc.dart index 9a69727..7dd1a73 100644 --- a/lib/bloc/development_by_muscle/development_by_muscle_bloc.dart +++ b/lib/bloc/development_by_muscle/development_by_muscle_bloc.dart @@ -188,7 +188,7 @@ class GroupChart extends GroupData with Calculate { BarChartGroupData data = BarChartGroupData( x: exercise.dateAdd.millisecondsSinceEpoch, barRods: [ - BarChartRodData(y: diagramValue, width: 12, color: Colors.lightBlue) + BarChartRodData(y: diagramValue, width: 12, colors: [Colors.lightBlue, Colors.lightBlueAccent]) ] ); _chartData.add(data); diff --git a/lib/bloc/exercise_by_plan/exercise_by_plan_event.dart b/lib/bloc/exercise_by_plan/exercise_by_plan_event.dart deleted file mode 100644 index 97c1c14..0000000 --- a/lib/bloc/exercise_by_plan/exercise_by_plan_event.dart +++ /dev/null @@ -1,21 +0,0 @@ -part of 'exercise_by_plan_bloc.dart'; - -@immutable -abstract class ExerciseByPlanEvent extends Equatable { - const ExerciseByPlanEvent(); - - @override - List get props => []; -} - -class AddExerciseByPlanEvent extends ExerciseByPlanEvent { - final ExerciseType exerciseType; - const AddExerciseByPlanEvent({this.exerciseType}); - - @override - List get props => [exerciseType]; -} - -class ExerciseByPlanLoad extends ExerciseByPlanEvent { - const ExerciseByPlanLoad(); -} diff --git a/lib/bloc/exercise_by_plan/exercise_by_plan_state.dart b/lib/bloc/exercise_by_plan/exercise_by_plan_state.dart deleted file mode 100644 index f9c89c7..0000000 --- a/lib/bloc/exercise_by_plan/exercise_by_plan_state.dart +++ /dev/null @@ -1,31 +0,0 @@ -part of 'exercise_by_plan_bloc.dart'; - -@immutable -abstract class ExerciseByPlanState extends Equatable { - const ExerciseByPlanState(); - - @override - List get props => []; -} - -class ExerciseByPlanStateInitial extends ExerciseByPlanState { - const ExerciseByPlanStateInitial(); -} - -class ExerciseByPlanLoading extends ExerciseByPlanState { - const ExerciseByPlanLoading(); -} - -// updated screen -class ExerciseByPlanReady extends ExerciseByPlanState { - const ExerciseByPlanReady(); -} - -// error splash screen -class ExerciseByPlanError extends ExerciseByPlanState { - final String message; - const ExerciseByPlanError({this.message}); - - @override - List get props => [message]; -} \ No newline at end of file diff --git a/lib/bloc/exercise_control/exercise_control_bloc.dart b/lib/bloc/exercise_control/exercise_control_bloc.dart new file mode 100644 index 0000000..60adb37 --- /dev/null +++ b/lib/bloc/exercise_control/exercise_control_bloc.dart @@ -0,0 +1,91 @@ +import 'dart:async'; +import 'package:aitrainer_app/repository/exercise_repository.dart'; +import 'package:bloc/bloc.dart'; +import 'package:equatable/equatable.dart'; +import 'package:meta/meta.dart'; + +part 'exercise_control_event.dart'; + +part 'exercise_control_state.dart'; + +class ExerciseControlBloc extends Bloc { + final ExerciseRepository exerciseRepository; + final bool readonly; + final double percentToCalculate; + int step = 1; + final List repeats = List(); + + double initialRM; + double unitQuantity; + double quantity; + double origQuantity; + + double firstQuantity; // quantity of the first test + double firstUnitQuantity; // unit quantity of the first test + + @override + ExerciseControlBloc({this.exerciseRepository, this.readonly, this.percentToCalculate}) : super(ExerciseControlInitial()) { + firstUnitQuantity = exerciseRepository.exercise.unitQuantity; + firstQuantity = exerciseRepository.exercise.quantity; + repeats.add(firstUnitQuantity); + repeats.add(firstQuantity); + + initialRM = this.calculate1RM(percent75: false); + unitQuantity = this.calculate1RM(percent75: true).roundToDouble(); + quantity = percentToCalculate == 0.75 ? 12 : 30; + origQuantity = quantity; + + exerciseRepository.setUnitQuantity(unitQuantity); + + } + + @override + Stream mapEventToState(ExerciseControlEvent event) async* { + try { + if (event is ExerciseControlLoad) { + yield ExerciseControlLoading(); + step = 1; + yield ExerciseControlReady(); + } else if (event is ExerciseControlQuantityChange ) { + yield ExerciseControlLoading(); + if ( event.step == step) { + exerciseRepository.setQuantity(event.quantity); + quantity = event.quantity; + } + yield ExerciseControlReady(); + } else if (event is ExerciseControlSubmit ) { + yield ExerciseControlLoading(); + if ( event.step == step) { + step++; + //print("step " + step.toString() + " quantity " + quantity.toString() + " origQ: " + origQuantity.toString()); + repeats.add(quantity); + quantity = origQuantity; + await exerciseRepository.addExercise(); + + + exerciseRepository.setQuantity(quantity); + } + yield ExerciseControlReady(); + } + } on Exception catch (e) { + yield ExerciseControlError(message: e.toString()); + } + } + + double calculate1RM({bool percent75}) { + if (exerciseRepository.exercise == null) { + exerciseRepository.getLastExercise(); + } + double weight = exerciseRepository.exercise.unitQuantity; + double repeat = exerciseRepository.exercise.quantity; + if ( weight == 0 || repeat == 0) { + return 0; + } + + double rmWendler = weight * repeat * 0.0333 + weight; + double rmOconner = weight * (1 + repeat / 40); + double average = (rmWendler + rmOconner) / 2; + + return percent75 ? average * this.percentToCalculate : average; + } +} diff --git a/lib/bloc/exercise_control/exercise_control_event.dart b/lib/bloc/exercise_control/exercise_control_event.dart new file mode 100644 index 0000000..3902f69 --- /dev/null +++ b/lib/bloc/exercise_control/exercise_control_event.dart @@ -0,0 +1,24 @@ +part of 'exercise_control_bloc.dart'; + +@immutable +abstract class ExerciseControlEvent extends Equatable { + const ExerciseControlEvent(); + + @override + List get props => []; +} + +class ExerciseControlLoad extends ExerciseControlEvent { + const ExerciseControlLoad(); +} + +class ExerciseControlQuantityChange extends ExerciseControlEvent { + final double quantity; + final int step; + const ExerciseControlQuantityChange({this.quantity, this.step}); +} + +class ExerciseControlSubmit extends ExerciseControlEvent { + final int step; + const ExerciseControlSubmit({this.step}); +} diff --git a/lib/bloc/exercise_control/exercise_control_state.dart b/lib/bloc/exercise_control/exercise_control_state.dart new file mode 100644 index 0000000..a8b98fe --- /dev/null +++ b/lib/bloc/exercise_control/exercise_control_state.dart @@ -0,0 +1,30 @@ +part of 'exercise_control_bloc.dart'; + +@immutable +abstract class ExerciseControlState extends Equatable { + const ExerciseControlState(); + + @override + List get props => []; +} + +class ExerciseControlInitial extends ExerciseControlState { + const ExerciseControlInitial(); +} + +class ExerciseControlLoading extends ExerciseControlState { + const ExerciseControlLoading(); +} + +class ExerciseControlReady extends ExerciseControlState { + const ExerciseControlReady(); +} + +class ExerciseControlError extends ExerciseControlState { + final String message; + const ExerciseControlError({this.message}); + + + @override + List get props => [message]; +} \ No newline at end of file diff --git a/lib/bloc/exercise_control_form_bloc.dart b/lib/bloc/exercise_control_form_bloc.dart deleted file mode 100644 index dbdd0ce..0000000 --- a/lib/bloc/exercise_control_form_bloc.dart +++ /dev/null @@ -1,132 +0,0 @@ -import 'package:aitrainer_app/repository/exercise_repository.dart'; -import 'package:flutter_form_bloc/flutter_form_bloc.dart'; - -class ExerciseControlFormBloc extends FormBloc { - final ExerciseRepository exerciseRepository; - int step = 1; - final double percentToCalculate; - final bool readonly; - String times; - - final initialRMField = TextFieldBloc( - ); - - final quantity1Field = TextFieldBloc( - ); - - final unitQuantity1Field = TextFieldBloc( - ); - - final quantity2Field = TextFieldBloc( - ); - - final unitQuantity2Field = TextFieldBloc( - ); - - final quantity3Field = TextFieldBloc( - ); - - final unitQuantity3Field = TextFieldBloc( - ); - - - - ExerciseControlFormBloc({this.exerciseRepository, this.percentToCalculate, this.readonly}) { - addFieldBlocs(fieldBlocs: [ - initialRMField, - quantity1Field, - unitQuantity1Field, - quantity2Field, - unitQuantity2Field, - quantity3Field, - unitQuantity3Field, - - ]); - - initialRMField.updateInitialValue(calculate1RM(percent75: false).toStringAsFixed(0)); - unitQuantity1Field.updateInitialValue(calculate1RM(percent75: true).toStringAsFixed(0)); - unitQuantity2Field.updateInitialValue(calculate1RM(percent75: true).toStringAsFixed(0)); - unitQuantity3Field.updateInitialValue(calculate1RM(percent75: true).toStringAsFixed(0)); - - quantity1Field.onValueChanges(onData: (previous, current) async* { - exerciseRepository.setQuantity(current.valueToDouble); - exerciseRepository.setUnitQuantity(unitQuantity1Field.valueToDouble); - }); - - quantity2Field.onValueChanges(onData: (previous, current) async* { - exerciseRepository.setQuantity(current.valueToDouble); - exerciseRepository.setUnitQuantity(unitQuantity2Field.valueToDouble); - }); - - quantity3Field.onValueChanges(onData: (previous, current) async* { - exerciseRepository.setQuantity(current.valueToDouble); - exerciseRepository.setUnitQuantity(unitQuantity3Field.valueToDouble); - }); - - times = percentToCalculate == 0.5 ? "30-35" : "12"; - - } - - @override - void onLoading() { - step = 1; - super.onLoading(); - } - - @override - void onSubmitting() async { - print("on Submitting Custom form"); - try { - emitLoading(progress: 30); - if ( step == 1) { - - //unitQuantity2Field.updateInitialValue(calculate1RM(percent75: true).toStringAsFixed(0)); - //unitQuantity3Field.updateInitialValue(calculate1RM(percent75: true).toStringAsFixed(0)); - step = 2; - } else if ( step == 2) { - //unitQuantity3Field.updateInitialValue(calculate1RM(percent75: true).toStringAsFixed(0)); - step = 3; - } else if ( step == 3 ) { - //updatedRMField.updateInitialValue(calculate1RM(percent75: false).toStringAsFixed(0)); - } - - if ( ! readonly ) { - await exerciseRepository.addExercise(); - } - - emitSuccess(canSubmitAgain: true); - } on Exception catch (ex) { - emitFailure(failureResponse: ex.toString()); - } - } - - double calculate1RM({bool percent75}) { - if (exerciseRepository.exercise == null) { - exerciseRepository.getLastExercise(); - } - double weight = exerciseRepository.exercise.unitQuantity; - double repeat = exerciseRepository.exercise.quantity; - if ( weight == 0 || repeat == 0) { - return 0; - } - - double rmWendler = weight * repeat * 0.0333 + weight; - double rmOconner = weight * (1 + repeat / 40); - double average = (rmWendler + rmOconner) / 2; - - return percent75 ? average * this.percentToCalculate : average; - } - - //@override - Future close() { - initialRMField.close(); - quantity1Field.close(); - unitQuantity1Field.close(); - quantity2Field.close(); - unitQuantity2Field.close(); - quantity3Field.close(); - unitQuantity3Field.close(); - - return super.close(); - } -} diff --git a/lib/bloc/exercise_by_plan/exercise_by_plan_bloc.dart b/lib/bloc/exercise_execute_plan/exercise_execute_plan_bloc.dart similarity index 82% rename from lib/bloc/exercise_by_plan/exercise_by_plan_bloc.dart rename to lib/bloc/exercise_execute_plan/exercise_execute_plan_bloc.dart index 42fb016..835de6c 100644 --- a/lib/bloc/exercise_by_plan/exercise_by_plan_bloc.dart +++ b/lib/bloc/exercise_execute_plan/exercise_execute_plan_bloc.dart @@ -7,16 +7,16 @@ import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; import 'package:meta/meta.dart'; -part 'exercise_by_plan_event.dart'; +part 'exercise_execute_plan_event.dart'; -part 'exercise_by_plan_state.dart'; +part 'exercise_execute_plan_state.dart'; -class ExerciseByPlanBloc extends Bloc { +class ExerciseExecutePlanBloc extends Bloc { final WorkoutTreeRepository menuTreeRepository; final ExercisePlanRepository exercisePlanRepository = ExercisePlanRepository(); int customerId; @override - ExerciseByPlanBloc({this.menuTreeRepository}) : super(ExerciseByPlanStateInitial()); + ExerciseExecutePlanBloc({this.menuTreeRepository}) : super(ExerciseByPlanStateInitial()); Future getData() async { exercisePlanRepository.setCustomerId(customerId); @@ -39,7 +39,7 @@ class ExerciseByPlanBloc extends Bloc } @override - Stream mapEventToState(ExerciseByPlanEvent event) async* { + Stream mapEventToState(ExerciseExecutePlanEvent event) async* { try { if (event is ExerciseByPlanLoad) { yield ExerciseByPlanLoading(); diff --git a/lib/bloc/exercise_execute_plan/exercise_execute_plan_event.dart b/lib/bloc/exercise_execute_plan/exercise_execute_plan_event.dart new file mode 100644 index 0000000..b50a2c9 --- /dev/null +++ b/lib/bloc/exercise_execute_plan/exercise_execute_plan_event.dart @@ -0,0 +1,21 @@ +part of 'exercise_execute_plan_bloc.dart'; + +@immutable +abstract class ExerciseExecutePlanEvent extends Equatable { + const ExerciseExecutePlanEvent(); + + @override + List get props => []; +} + +class AddExerciseByPlanEvent extends ExerciseExecutePlanEvent { + final ExerciseType exerciseType; + const AddExerciseByPlanEvent({this.exerciseType}); + + @override + List get props => [exerciseType]; +} + +class ExerciseByPlanLoad extends ExerciseExecutePlanEvent { + const ExerciseByPlanLoad(); +} diff --git a/lib/bloc/exercise_execute_plan/exercise_execute_plan_state.dart b/lib/bloc/exercise_execute_plan/exercise_execute_plan_state.dart new file mode 100644 index 0000000..cf8e919 --- /dev/null +++ b/lib/bloc/exercise_execute_plan/exercise_execute_plan_state.dart @@ -0,0 +1,31 @@ +part of 'exercise_execute_plan_bloc.dart'; + +@immutable +abstract class ExerciseExecutePlanState extends Equatable { + const ExerciseExecutePlanState(); + + @override + List get props => []; +} + +class ExerciseByPlanStateInitial extends ExerciseExecutePlanState { + const ExerciseByPlanStateInitial(); +} + +class ExerciseByPlanLoading extends ExerciseExecutePlanState { + const ExerciseByPlanLoading(); +} + +// updated screen +class ExerciseByPlanReady extends ExerciseExecutePlanState { + const ExerciseByPlanReady(); +} + +// error splash screen +class ExerciseByPlanError extends ExerciseExecutePlanState { + final String message; + const ExerciseByPlanError({this.message}); + + @override + List get props => [message]; +} \ No newline at end of file diff --git a/lib/bloc/exercise_execute_plan_add/exercise_execute_plan_add_bloc.dart b/lib/bloc/exercise_execute_plan_add/exercise_execute_plan_add_bloc.dart new file mode 100644 index 0000000..7992aa9 --- /dev/null +++ b/lib/bloc/exercise_execute_plan_add/exercise_execute_plan_add_bloc.dart @@ -0,0 +1,89 @@ +import 'dart:async'; +import 'package:aitrainer_app/bloc/exercise_execute_plan/exercise_execute_plan_bloc.dart'; +import 'package:aitrainer_app/model/cache.dart'; +import 'package:aitrainer_app/model/customer.dart'; +import 'package:aitrainer_app/model/workout_menu_tree.dart'; +import 'package:aitrainer_app/repository/exercise_plan_repository.dart'; +import 'package:aitrainer_app/repository/exercise_repository.dart'; +import 'package:bloc/bloc.dart'; +import 'package:equatable/equatable.dart'; +import 'package:meta/meta.dart'; + +part 'exercise_execute_plan_add_event.dart'; + +part 'exercise_execute_plan_add_state.dart'; + +class ExerciseExecutePlanAddBloc extends Bloc { + final ExerciseRepository exerciseRepository; + final ExercisePlanRepository exercisePlanRepository; + final WorkoutMenuTree workoutTree; + final ExerciseExecutePlanBloc planBloc; + final int customerId; + + Customer customer; + int step = 1; + int countSteps = 1; + + double quantity; + double unitQuantity; + + double scrollOffset = 0; + + @override + ExerciseExecutePlanAddBloc({ + this.exerciseRepository, + this.exercisePlanRepository, + this.customerId, + this.workoutTree, + this.planBloc}): super(ExerciseExecutePlanAddInitial()) { + exerciseRepository.exerciseType = workoutTree.exerciseType; + if ( Cache().userLoggedIn.customerId == customerId) { + customer = Cache().userLoggedIn; + } else if ( Cache().getTrainee().customerId == customerId) { + customer = Cache().getTrainee(); + } + exercisePlanRepository.setActualPlanDetailByExerciseType(workoutTree.exerciseType); + exerciseRepository.customer = customer; + countSteps = exercisePlanRepository.getActualPlanDetail().serie; + + unitQuantity = double.parse(exercisePlanRepository.getActualPlanDetail().weightEquation); + quantity = exercisePlanRepository.getActualPlanDetail().repeats.toDouble(); + + exerciseRepository.setQuantity(quantity); + exerciseRepository.setUnitQuantity(unitQuantity); + } + + @override + Stream mapEventToState(ExerciseExecutePlanAddEvent event) async* { + try { + if (event is ExerciseExecutePlanAddLoad) { + yield ExerciseExecutePlanAddLoading(); + yield ExerciseExecutePlanAddReady(); + } else if (event is ExerciseExecutePlanAddChangeQuantity) { + yield ExerciseExecutePlanAddLoading(); + quantity = event.quantity; + exerciseRepository.setQuantity(quantity); + yield ExerciseExecutePlanAddReady(); + } else if (event is ExerciseExecutePlanAddChangeUnitQuantity) { + yield ExerciseExecutePlanAddLoading(); + unitQuantity = event.quantity; + exerciseRepository.setUnitQuantity(unitQuantity); + yield ExerciseExecutePlanAddReady(); + } else if (event is ExerciseExecutePlanAddSubmit) { + yield ExerciseExecutePlanAddLoading(); + exerciseRepository.exercise.exercisePlanDetailId = + exercisePlanRepository.getActualPlanDetail().exercisePlanDetailId; + exerciseRepository.exercise.unit = workoutTree.exerciseType.unit; + workoutTree.executed = true; + print("On Submitting Exercise Execute Plan Add " + exerciseRepository.exercise.toJson().toString()); + await exerciseRepository.addExercise(); + step++; + scrollOffset = step * 200.0; + planBloc.add(ExerciseByPlanLoad()); + yield ExerciseExecutePlanAddReady(); + } + } on Exception catch (e) { + yield ExerciseExecutePlanAddError(message: e.toString()); + } + } +} diff --git a/lib/bloc/exercise_execute_plan_add/exercise_execute_plan_add_event.dart b/lib/bloc/exercise_execute_plan_add/exercise_execute_plan_add_event.dart new file mode 100644 index 0000000..85929f1 --- /dev/null +++ b/lib/bloc/exercise_execute_plan_add/exercise_execute_plan_add_event.dart @@ -0,0 +1,33 @@ +part of 'exercise_execute_plan_add_bloc.dart'; + +@immutable +abstract class ExerciseExecutePlanAddEvent extends Equatable { + const ExerciseExecutePlanAddEvent(); + + @override + List get props => []; +} + +class ExerciseExecutePlanAddLoad extends ExerciseExecutePlanAddEvent { + const ExerciseExecutePlanAddLoad(); +} + +class ExerciseExecutePlanAddChangeQuantity extends ExerciseExecutePlanAddEvent { + final double quantity; + const ExerciseExecutePlanAddChangeQuantity({this.quantity}); + + @override + List get props => [quantity]; +} + +class ExerciseExecutePlanAddChangeUnitQuantity extends ExerciseExecutePlanAddEvent { + final double quantity; + const ExerciseExecutePlanAddChangeUnitQuantity({this.quantity}); + + @override + List get props => [quantity]; +} + +class ExerciseExecutePlanAddSubmit extends ExerciseExecutePlanAddEvent { + const ExerciseExecutePlanAddSubmit(); +} diff --git a/lib/bloc/exercise_execute_plan_add/exercise_execute_plan_add_state.dart b/lib/bloc/exercise_execute_plan_add/exercise_execute_plan_add_state.dart new file mode 100644 index 0000000..576b47c --- /dev/null +++ b/lib/bloc/exercise_execute_plan_add/exercise_execute_plan_add_state.dart @@ -0,0 +1,31 @@ +part of 'exercise_execute_plan_add_bloc.dart'; + +@immutable +abstract class ExerciseExecutePlanAddState extends Equatable { + const ExerciseExecutePlanAddState(); + + @override + List get props => []; +} + +class ExerciseExecutePlanAddInitial extends ExerciseExecutePlanAddState { + const ExerciseExecutePlanAddInitial(); +} + +class ExerciseExecutePlanAddLoading extends ExerciseExecutePlanAddState { + const ExerciseExecutePlanAddLoading(); +} + +// updated screen +class ExerciseExecutePlanAddReady extends ExerciseExecutePlanAddState { + const ExerciseExecutePlanAddReady(); +} + +// error splash screen +class ExerciseExecutePlanAddError extends ExerciseExecutePlanAddState { + final String message; + const ExerciseExecutePlanAddError({this.message}); + + @override + List get props => [message]; +} \ No newline at end of file diff --git a/lib/bloc/exercise_form_bloc.dart b/lib/bloc/exercise_form_bloc.dart deleted file mode 100644 index 9253355..0000000 --- a/lib/bloc/exercise_form_bloc.dart +++ /dev/null @@ -1,68 +0,0 @@ -import 'package:aitrainer_app/repository/exercise_repository.dart'; -import 'package:flutter_form_bloc/flutter_form_bloc.dart'; - -import 'menu/menu_bloc.dart'; - -class ExerciseFormBloc extends FormBloc { - final ExerciseRepository exerciseRepository; - final MenuBloc menuBloc; - - final quantityField = TextFieldBloc( - validators: [ - FieldBlocValidators.required, - ], - ); - - final unitField = TextFieldBloc( - validators: [ - FieldBlocValidators.required, - ], - ); - - final unitQuantityField = TextFieldBloc(); - final unitQuantityUnitField = TextFieldBloc(); - - ExerciseFormBloc({this.exerciseRepository, this.menuBloc}) { - addFieldBlocs(fieldBlocs: [ - quantityField, - unitField, - unitQuantityField, - unitQuantityUnitField - ]); - - quantityField.onValueChanges(onData: (previous, current) async* { - exerciseRepository.setQuantity(current.valueToDouble); - }); - - unitField.onValueChanges(onData: (previous, current) async* { - exerciseRepository.setUnit(current.value); - }); - - unitQuantityField.onValueChanges(onData: (previous, current) async* { - exerciseRepository.setUnitQuantity(current.valueToDouble); - }); - } - - @override - void onSubmitting() async { - try { - emitLoading(progress: 30); - // Emit either Loaded or Error - await exerciseRepository.addExercise(); - menuBloc.add(MenuTreeDown(parent: 0)); - emitSuccess(canSubmitAgain: false); - - } on Exception catch (ex) { - emitFailure(failureResponse: ex.toString()); - - } - } - - @override - Future close() { - unitQuantityField.close(); - unitQuantityUnitField.close(); - return super.close(); - } - -} \ No newline at end of file diff --git a/lib/bloc/exercise_log/exercise_log_bloc.dart b/lib/bloc/exercise_log/exercise_log_bloc.dart new file mode 100644 index 0000000..1190b51 --- /dev/null +++ b/lib/bloc/exercise_log/exercise_log_bloc.dart @@ -0,0 +1,34 @@ +import 'dart:async'; +import 'package:aitrainer_app/model/exercise.dart'; +import 'package:aitrainer_app/repository/exercise_repository.dart'; +import 'package:bloc/bloc.dart'; +import 'package:equatable/equatable.dart'; +import 'package:meta/meta.dart'; + +part 'exercise_log_event.dart'; + +part 'exercise_log_state.dart'; + +class ExerciseLogBloc extends Bloc { + final ExerciseRepository exerciseRepository; + @override + ExerciseLogBloc({this.exerciseRepository}) : super(ExerciseLogInitial()); + + + @override + Stream mapEventToState(ExerciseLogEvent event) async* { + try { + if (event is ExerciseLogLoad) { + yield ExerciseLogLoading(); + yield ExerciseLogReady(); + } else if ( event is ExerciseLogDelete ) { + yield ExerciseLogLoading(); + exerciseRepository.exerciseList.remove(event.exercise); + await exerciseRepository.deleteExercise(event.exercise); + yield ExerciseLogReady(); + } + } on Exception catch (e) { + yield ExerciseLogError(message: e.toString()); + } + } +} diff --git a/lib/bloc/exercise_log/exercise_log_event.dart b/lib/bloc/exercise_log/exercise_log_event.dart new file mode 100644 index 0000000..cf8fded --- /dev/null +++ b/lib/bloc/exercise_log/exercise_log_event.dart @@ -0,0 +1,22 @@ +part of 'exercise_log_bloc.dart'; + +@immutable +abstract class ExerciseLogEvent extends Equatable { + const ExerciseLogEvent(); + + @override + List get props => []; +} + +class ExerciseLogLoad extends ExerciseLogEvent { + const ExerciseLogLoad(); +} + +class ExerciseLogDelete extends ExerciseLogEvent { + final Exercise exercise; + const ExerciseLogDelete({this.exercise}); + + @override + List get props => [exercise]; + +} diff --git a/lib/bloc/exercise_log/exercise_log_state.dart b/lib/bloc/exercise_log/exercise_log_state.dart new file mode 100644 index 0000000..1ab2133 --- /dev/null +++ b/lib/bloc/exercise_log/exercise_log_state.dart @@ -0,0 +1,30 @@ +part of 'exercise_log_bloc.dart'; + +@immutable +abstract class ExerciseLogState extends Equatable { + const ExerciseLogState(); + + @override + List get props => []; +} + +class ExerciseLogInitial extends ExerciseLogState { + const ExerciseLogInitial(); +} + +class ExerciseLogLoading extends ExerciseLogState { + const ExerciseLogLoading(); +} + +class ExerciseLogReady extends ExerciseLogState { + const ExerciseLogReady(); +} + +class ExerciseLogError extends ExerciseLogState { + final String message; + const ExerciseLogError({this.message}); + + + @override + List get props => [message]; +} \ No newline at end of file diff --git a/lib/bloc/exercise_new/exercise_new_bloc.dart b/lib/bloc/exercise_new/exercise_new_bloc.dart new file mode 100644 index 0000000..27ade8a --- /dev/null +++ b/lib/bloc/exercise_new/exercise_new_bloc.dart @@ -0,0 +1,53 @@ +import 'dart:async'; +import 'package:aitrainer_app/bloc/menu/menu_bloc.dart'; +import 'package:aitrainer_app/model/exercise_type.dart'; +import 'package:aitrainer_app/repository/exercise_repository.dart'; +import 'package:bloc/bloc.dart'; +import 'package:equatable/equatable.dart'; +import 'package:flutter_form_bloc/flutter_form_bloc.dart'; +import 'package:meta/meta.dart'; + +part 'exercise_new_event.dart'; + +part 'exercise_new_state.dart'; + +class ExerciseNewBloc extends Bloc { + final ExerciseRepository exerciseRepository; + final MenuBloc menuBloc; + double quantity = 12; + double unitQuantity = 30; + + @override + ExerciseNewBloc({this.exerciseRepository, this.menuBloc, ExerciseType exerciseType}) : super(ExerciseNewInitial()) { + exerciseRepository.setUnit(exerciseType.unit); + } + + @override + Stream mapEventToState(ExerciseNewEvent event) async* { + try { + if (event is ExerciseNewLoad) { + yield ExerciseNewLoading(); + yield ExerciseNewReady(); + } else if ( event is ExerciseNewQuantityChange ) { + yield ExerciseNewLoading(); + exerciseRepository.setQuantity(event.quantity); + quantity = event.quantity; + yield ExerciseNewReady(); + } else if ( event is ExerciseNewQuantityUnitChange ) { + yield ExerciseNewLoading(); + exerciseRepository.setUnitQuantity(event.quantity); + unitQuantity = event.quantity; + yield ExerciseNewReady(); + } else if ( event is ExerciseNewSubmit ) { + yield ExerciseNewLoading(); + await exerciseRepository.addExercise(); + menuBloc.add(MenuTreeDown(parent: 0)); + yield ExerciseNewReady(); + } + } on Exception catch (e) { + yield ExerciseNewError(message: e.toString()); + } + } +} + + diff --git a/lib/bloc/exercise_new/exercise_new_event.dart b/lib/bloc/exercise_new/exercise_new_event.dart new file mode 100644 index 0000000..9d60cb4 --- /dev/null +++ b/lib/bloc/exercise_new/exercise_new_event.dart @@ -0,0 +1,34 @@ +part of 'exercise_new_bloc.dart'; + +@immutable +abstract class ExerciseNewEvent extends Equatable { + const ExerciseNewEvent(); + + @override + List get props => []; +} + +class ExerciseNewLoad extends ExerciseNewEvent { + const ExerciseNewLoad(); +} + +class ExerciseNewQuantityChange extends ExerciseNewEvent { + final double quantity; + const ExerciseNewQuantityChange({this.quantity}); + + @override + List get props => [quantity]; +} + +class ExerciseNewQuantityUnitChange extends ExerciseNewEvent { + final double quantity; + const ExerciseNewQuantityUnitChange({this.quantity}); + + @override + List get props => [quantity]; +} + +class ExerciseNewSubmit extends ExerciseNewEvent { + const ExerciseNewSubmit(); +} + diff --git a/lib/bloc/exercise_new/exercise_new_state.dart b/lib/bloc/exercise_new/exercise_new_state.dart new file mode 100644 index 0000000..cdfc059 --- /dev/null +++ b/lib/bloc/exercise_new/exercise_new_state.dart @@ -0,0 +1,29 @@ +part of 'exercise_new_bloc.dart'; + +@immutable +abstract class ExerciseNewState extends Equatable { + const ExerciseNewState(); + + @override + List get props => []; +} + +class ExerciseNewInitial extends ExerciseNewState { + const ExerciseNewInitial(); +} + +class ExerciseNewLoading extends ExerciseNewState { + const ExerciseNewLoading(); +} + +class ExerciseNewReady extends ExerciseNewState { + const ExerciseNewReady(); +} + +class ExerciseNewError extends ExerciseNewState { + final String message; + const ExerciseNewError({this.message}); + + @override + List get props => [message]; +} \ No newline at end of file diff --git a/lib/bloc/exercise_plan/exercise_plan_bloc.dart b/lib/bloc/exercise_plan/exercise_plan_bloc.dart index dae1f06..e5de460 100644 --- a/lib/bloc/exercise_plan/exercise_plan_bloc.dart +++ b/lib/bloc/exercise_plan/exercise_plan_bloc.dart @@ -30,7 +30,8 @@ class ExercisePlanBloc extends Bloc { listWorkoutTree.forEach((workoutTree) { workoutTree.selected = false; if (exercisePlanRepository.getExercisePlanDetailSize() > 0) { - if (exercisePlanRepository.getExercisePlanDetailByExerciseId(workoutTree.exerciseTypeId) != null) { + ExercisePlanDetail planDetail = exercisePlanRepository.getExercisePlanDetailByExerciseId(workoutTree.exerciseTypeId); + if (planDetail != null && planDetail.change != ExercisePlanDetailChange.deleted) { workoutTree.selected = true; } } @@ -66,23 +67,22 @@ class ExercisePlanBloc extends Bloc { ExercisePlanDetail planDetail = event.exercisePlanDetail; exercisePlanRepository.actualPlanDetail = planDetail; - /*if ( exercisePlanRepository.exercisePlanDetails[planDetail.exerciseTypeId] == null ) { - print("Add plan detail " + planDetail.toJson().toString()); - exercisePlanRepository.actualPlanDetail.change = ExercisePlanDetailChange.add; - } else { - print("Update plan detail " + planDetail.toJson().toString()); - exercisePlanRepository.actualPlanDetail.change = ExercisePlanDetailChange.update; - } - exercisePlanRepository.addDetailToPlan();*/ - if (exercisePlanRepository.getExercisePlanDetailSize() != 0) { await exercisePlanRepository.saveExercisePlan(); } + this.menuTreeRepository.sortedTree.forEach((key, value) { + List listTreeItem = value; + listTreeItem.forEach((element) { + if ( element.exerciseType.exerciseTypeId == planDetail.exerciseTypeId) { + element.selected = true; + } + }); + }); + yield ExercisePlanReady(); } - else if (event is ExercisePlanRemoveExercise) { yield ExercisePlanLoading(); ExercisePlanDetail planDetail = event.exercisePlanDetail; @@ -101,6 +101,7 @@ class ExercisePlanBloc extends Bloc { exercisePlanRepository.saveExercisePlan(); } + yield ExercisePlanReady(); } diff --git a/lib/bloc/exercise_plan_custom_add/exercise_plan_custom_add_bloc.dart b/lib/bloc/exercise_plan_custom_add/exercise_plan_custom_add_bloc.dart new file mode 100644 index 0000000..06e25a2 --- /dev/null +++ b/lib/bloc/exercise_plan_custom_add/exercise_plan_custom_add_bloc.dart @@ -0,0 +1,87 @@ +import 'dart:async'; +import 'package:aitrainer_app/bloc/exercise_plan/exercise_plan_bloc.dart'; +import 'package:aitrainer_app/model/workout_menu_tree.dart'; +import 'package:aitrainer_app/repository/exercise_plan_repository.dart'; +import 'package:bloc/bloc.dart'; +import 'package:equatable/equatable.dart'; +import 'package:meta/meta.dart'; + +part 'exercise_plan_custom_add_event.dart'; + +part 'exercise_plan_custom_add_state.dart'; + +class ExercisePlanDetailChange { + static const String add = "add"; + static const String delete = "delete"; + static const String update = "update"; + static const String deleted = "deleted"; +} + +class ExercisePlanCustomAddBloc extends Bloc { + final ExercisePlanRepository exercisePlanRepository; + final ExercisePlanBloc planBloc; + final WorkoutMenuTree workoutMenuTree; + + double quantity; + double serie; + double quantityUnit; + + @override + ExercisePlanCustomAddBloc({this.exercisePlanRepository, this.planBloc, this.workoutMenuTree}) : super(ExercisePlanCustomAddInitial()) { + exercisePlanRepository.setActualPlanDetailByExerciseType(workoutMenuTree.exerciseType); + quantity = exercisePlanRepository.getActualPlanDetail().repeats != null ? + exercisePlanRepository.getActualPlanDetail().repeats.toDouble() : 12; + serie = exercisePlanRepository.getActualPlanDetail().serie != null ? + exercisePlanRepository.getActualPlanDetail().serie.toDouble() : 3; + quantityUnit = exercisePlanRepository.getActualPlanDetail().weightEquation != null ? + double.parse(exercisePlanRepository.getActualPlanDetail().weightEquation) : 30; + + exercisePlanRepository.getActualPlanDetail().weightEquation = quantityUnit.toString(); + exercisePlanRepository.getActualPlanDetail().serie = serie.toInt(); + exercisePlanRepository.getActualPlanDetail().repeats = quantity.toInt(); + } + + @override + Stream mapEventToState(ExercisePlanCustomAddEvent event) async* { + try { + if (event is ExercisePlanCustomAddLoad) { + yield ExercisePlanCustomAddLoading(); + yield ExercisePlanCustomAddReady(); + } else if ( event is ExercisePlanCustomAddChangeSerie ) { + yield ExercisePlanCustomAddLoading(); + serie = event.quantity; + exercisePlanRepository.getActualPlanDetail().serie = event.quantity.toInt(); + yield ExercisePlanCustomAddReady(); + } else if ( event is ExercisePlanCustomAddChangeQuantity ) { + yield ExercisePlanCustomAddLoading(); + quantity = event.quantity; + exercisePlanRepository.getActualPlanDetail().repeats = event.quantity.toInt(); + yield ExercisePlanCustomAddReady(); + } else if ( event is ExercisePlanCustomAddChangeQuantityUnit ) { + yield ExercisePlanCustomAddLoading(); + quantityUnit = event.quantity; + exercisePlanRepository.getActualPlanDetail().weightEquation = event.quantity.toStringAsFixed(0); + yield ExercisePlanCustomAddReady(); + } else if ( event is ExercisePlanCustomAddSubmit) { + yield ExercisePlanCustomAddLoading(); + if ( exercisePlanRepository.exercisePlanDetails[exercisePlanRepository.getActualPlanDetail()] == null ) { + exercisePlanRepository.getActualPlanDetail().change = ExercisePlanDetailChange.add; + } else { + exercisePlanRepository.getActualPlanDetail().change = ExercisePlanDetailChange.update; + } + exercisePlanRepository.addDetailToPlan(); + planBloc.add(ExercisePlanAddExercise(exercisePlanDetail: exercisePlanRepository.getActualPlanDetail())); + yield ExercisePlanCustomAddReady(); + } else if ( event is ExercisePlanCustomAddRemove ) { + yield ExercisePlanCustomAddLoading(); + print("Remove " + exercisePlanRepository.getActualPlanDetail().exerciseType.name); + exercisePlanRepository.getActualPlanDetail().change = ExercisePlanDetailChange.delete; + planBloc.add(ExercisePlanRemoveExercise(exercisePlanDetail: exercisePlanRepository.getActualPlanDetail())); + + yield ExercisePlanCustomAddReady(); + } + } on Exception catch (e) { + yield ExercisePlanCustomAddError(message: e.toString()); + } + } +} diff --git a/lib/bloc/exercise_plan_custom_add/exercise_plan_custom_add_event.dart b/lib/bloc/exercise_plan_custom_add/exercise_plan_custom_add_event.dart new file mode 100644 index 0000000..257b42c --- /dev/null +++ b/lib/bloc/exercise_plan_custom_add/exercise_plan_custom_add_event.dart @@ -0,0 +1,45 @@ +part of 'exercise_plan_custom_add_bloc.dart'; + +@immutable +abstract class ExercisePlanCustomAddEvent extends Equatable { + const ExercisePlanCustomAddEvent(); + + @override + List get props => []; +} + +class ExercisePlanCustomAddLoad extends ExercisePlanCustomAddEvent { + const ExercisePlanCustomAddLoad(); +} + +class ExercisePlanCustomAddChangeSerie extends ExercisePlanCustomAddEvent { + final double quantity; + const ExercisePlanCustomAddChangeSerie({this.quantity}); + + @override + List get props => [quantity]; +} + +class ExercisePlanCustomAddChangeQuantity extends ExercisePlanCustomAddEvent { + final double quantity; + const ExercisePlanCustomAddChangeQuantity({this.quantity}); + + @override + List get props => [quantity]; +} + +class ExercisePlanCustomAddChangeQuantityUnit extends ExercisePlanCustomAddEvent { + final double quantity; + const ExercisePlanCustomAddChangeQuantityUnit({this.quantity}); + + @override + List get props => [quantity]; +} + +class ExercisePlanCustomAddSubmit extends ExercisePlanCustomAddEvent { + const ExercisePlanCustomAddSubmit(); +} + +class ExercisePlanCustomAddRemove extends ExercisePlanCustomAddEvent { + const ExercisePlanCustomAddRemove(); +} \ No newline at end of file diff --git a/lib/bloc/exercise_plan_custom_add/exercise_plan_custom_add_state.dart b/lib/bloc/exercise_plan_custom_add/exercise_plan_custom_add_state.dart new file mode 100644 index 0000000..0924a0e --- /dev/null +++ b/lib/bloc/exercise_plan_custom_add/exercise_plan_custom_add_state.dart @@ -0,0 +1,30 @@ +part of 'exercise_plan_custom_add_bloc.dart'; + +@immutable +abstract class ExercisePlanCustomAddState extends Equatable { + const ExercisePlanCustomAddState(); + + @override + List get props => []; +} + +class ExercisePlanCustomAddInitial extends ExercisePlanCustomAddState { + const ExercisePlanCustomAddInitial(); +} + +class ExercisePlanCustomAddLoading extends ExercisePlanCustomAddState { + const ExercisePlanCustomAddLoading(); +} + +class ExercisePlanCustomAddReady extends ExercisePlanCustomAddState { + const ExercisePlanCustomAddReady(); +} + +class ExercisePlanCustomAddError extends ExercisePlanCustomAddState { + final String message; + const ExercisePlanCustomAddError({this.message}); + + + @override + List get props => [message]; +} \ No newline at end of file diff --git a/lib/bloc/exercise_plan_custom_form.dart b/lib/bloc/exercise_plan_custom_form.dart deleted file mode 100644 index 8038ef8..0000000 --- a/lib/bloc/exercise_plan_custom_form.dart +++ /dev/null @@ -1,99 +0,0 @@ -import 'package:aitrainer_app/bloc/exercise_plan/exercise_plan_bloc.dart'; -import 'package:aitrainer_app/model/exercise_plan_detail.dart'; -import 'package:aitrainer_app/repository/exercise_plan_repository.dart'; -import 'package:flutter_form_bloc/flutter_form_bloc.dart'; - -class ExercisePlanCustomerFormBloc extends FormBloc { - final ExercisePlanRepository exercisePlanRepository; - final ExercisePlanBloc planBloc; - final serieField = TextFieldBloc( - validators: [ - FieldBlocValidators.required, - ], - ); - - final quantityField = TextFieldBloc( - validators: [ - FieldBlocValidators.required, - ], - ); - - final weightField = TextFieldBloc( - validators: [ - FieldBlocValidators.required, - ], - ); - - final exerciseTypeField = TextFieldBloc( - validators: [ - FieldBlocValidators.required, - ], - ); - - ExercisePlanCustomerFormBloc({this.exercisePlanRepository, this.planBloc}) { - addFieldBlocs(fieldBlocs: [ - quantityField, - serieField, - weightField - ]); - - String repeatsInitial = exercisePlanRepository.getActualPlanDetail() != null && - exercisePlanRepository.getActualPlanDetail().repeats != null ? - exercisePlanRepository.getActualPlanDetail().repeats.toString() : "12"; - quantityField.updateInitialValue(repeatsInitial); - - String serieInitial = exercisePlanRepository.getActualPlanDetail() != null && - exercisePlanRepository.getActualPlanDetail().serie != null ? - exercisePlanRepository.getActualPlanDetail().serie.toString() : "3"; - serieField.updateInitialValue(serieInitial); - - String weightInitial = exercisePlanRepository.getActualPlanDetail() != null && - exercisePlanRepository.getActualPlanDetail().weightEquation != null ? - exercisePlanRepository.getActualPlanDetail().weightEquation : "30"; - weightField.updateInitialValue(weightInitial); - - quantityField.onValueChanges(onData: (previous, current) async* { - exercisePlanRepository.getActualPlanDetail().repeats = current.valueToInt; - }); - serieField.onValueChanges(onData: (previous, current) async* { - exercisePlanRepository.getActualPlanDetail().serie = current.valueToInt; - }); - weightField.onValueChanges(onData: (previous, current) async* { - exercisePlanRepository.getActualPlanDetail().weightEquation = current.value; - }); - } - - @override - void onSubmitting() async { - print("On Submitting Custom Plan form"); - try { - emitLoading(progress: 30); - // Emit either Loaded or Error - - exercisePlanRepository.getActualPlanDetail().repeats = quantityField.valueToInt; - exercisePlanRepository.getActualPlanDetail().serie = serieField.valueToInt; - exercisePlanRepository.getActualPlanDetail().weightEquation = weightField.value; - if ( exercisePlanRepository.exercisePlanDetails[exercisePlanRepository.getActualPlanDetail()] == null ) { - exercisePlanRepository.getActualPlanDetail().change = ExercisePlanDetailChange.add; - } else { - exercisePlanRepository.getActualPlanDetail().change = ExercisePlanDetailChange.update; - } - exercisePlanRepository.addDetailToPlan(); - planBloc.add(ExercisePlanAddExercise(exercisePlanDetail: exercisePlanRepository.getActualPlanDetail())); - - emitSuccess(canSubmitAgain: false); - } on Exception catch (ex) { - emitFailure(failureResponse: ex.toString()); - } - } - - - //@override - Future close() { - quantityField.close(); - serieField.close(); - weightField.close(); - exerciseTypeField.close(); - return super.close(); - } -} diff --git a/lib/library/numberpicker.dart b/lib/library/numberpicker.dart new file mode 100644 index 0000000..3dae677 --- /dev/null +++ b/lib/library/numberpicker.dart @@ -0,0 +1,772 @@ +import 'dart:math' as math; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:infinite_listview/infinite_listview.dart'; + +/// Created by Marcin Szałek + +///Define a text mapper to transform the text displayed by the picker +typedef String TextMapper(String numberText); + +///NumberPicker is a widget designed to pick a number between #minValue and #maxValue +class NumberPicker extends StatelessWidget { + ///height of every list element for normal number picker + ///width of every list element for horizontal number picker + static const double kDefaultItemExtent = 60.0; + + ///width of list view for normal number picker + ///height of list view for horizontal number picker + static const double kDefaultListViewCrossAxisSize = 120.0; + + ///constructor for horizontal number picker + NumberPicker.horizontal({ + Key key, + @required int initialValue, + @required this.minValue, + @required this.maxValue, + @required this.onChanged, + this.textMapper, + this.itemExtent = kDefaultItemExtent, + this.listViewHeight = kDefaultListViewCrossAxisSize, + this.step = 1, + this.zeroPad = false, + this.highlightSelectedValue = true, + this.decoration, + this.haptics = false, + this.textStyle, + this.textStyleHighlighted + }) : assert(initialValue != null), + assert(minValue != null), + assert(maxValue != null), + assert(maxValue > minValue), + assert(initialValue >= minValue && initialValue <= maxValue), + assert(step > 0), + selectedIntValue = initialValue, + selectedDecimalValue = -1, + decimalPlaces = 0, + intScrollController = ScrollController( + initialScrollOffset: (initialValue - minValue) ~/ step * itemExtent, + ), + scrollDirection = Axis.horizontal, + decimalScrollController = null, + listViewWidth = 3 * itemExtent, + infiniteLoop = false, + integerItemCount = (maxValue - minValue) ~/ step + 1, + super(key: key); + + ///constructor for integer number picker + NumberPicker.integer({ + Key key, + @required int initialValue, + @required this.minValue, + @required this.maxValue, + @required this.onChanged, + this.textMapper, + this.itemExtent = kDefaultItemExtent, + this.listViewWidth = kDefaultListViewCrossAxisSize, + this.step = 1, + this.scrollDirection = Axis.vertical, + this.infiniteLoop = false, + this.zeroPad = false, + this.highlightSelectedValue = true, + this.decoration, + this.haptics = false, + this.textStyle, + this.textStyleHighlighted + }) : assert(initialValue != null), + assert(minValue != null), + assert(maxValue != null), + assert(maxValue > minValue), + assert(initialValue >= minValue && initialValue <= maxValue), + assert(step > 0), + assert(scrollDirection != null), + selectedIntValue = initialValue, + selectedDecimalValue = -1, + decimalPlaces = 0, + intScrollController = infiniteLoop + ? InfiniteScrollController( + initialScrollOffset: + (initialValue - minValue) ~/ step * itemExtent, + ) + : ScrollController( + initialScrollOffset: + (initialValue - minValue) ~/ step * itemExtent, + ), + decimalScrollController = null, + listViewHeight = 3 * itemExtent, + integerItemCount = (maxValue - minValue) ~/ step + 1, + super(key: key); + + ///constructor for decimal number picker + NumberPicker.decimal({ + Key key, + @required double initialValue, + @required this.minValue, + @required this.maxValue, + @required this.onChanged, + this.textMapper, + this.decimalPlaces = 1, + this.itemExtent = kDefaultItemExtent, + this.listViewWidth = kDefaultListViewCrossAxisSize, + this.highlightSelectedValue = true, + this.decoration, + this.haptics = false, + this.textStyle, + this.textStyleHighlighted + }) : assert(initialValue != null), + assert(minValue != null), + assert(maxValue != null), + assert(decimalPlaces != null && decimalPlaces > 0), + assert(maxValue > minValue), + assert(initialValue >= minValue && initialValue <= maxValue), + selectedIntValue = initialValue.floor(), + selectedDecimalValue = ((initialValue - initialValue.floorToDouble()) * + math.pow(10, decimalPlaces)) + .round(), + intScrollController = ScrollController( + initialScrollOffset: (initialValue.floor() - minValue) * itemExtent, + ), + decimalScrollController = ScrollController( + initialScrollOffset: ((initialValue - initialValue.floorToDouble()) * + math.pow(10, decimalPlaces)) + .roundToDouble() * + itemExtent, + ), + listViewHeight = 3 * itemExtent, + step = 1, + scrollDirection = Axis.vertical, + integerItemCount = maxValue.floor() - minValue.floor() + 1, + infiniteLoop = false, + zeroPad = false, + super(key: key); + + ///called when selected value changes + final ValueChanged onChanged; + + ///min value user can pick + final int minValue; + + ///max value user can pick + final int maxValue; + + ///build the text of each item on the picker + final TextMapper textMapper; + + ///inidcates how many decimal places to show + /// e.g. 0=>[1,2,3...], 1=>[1.0, 1.1, 1.2...] 2=>[1.00, 1.01, 1.02...] + final int decimalPlaces; + + ///height of every list element in pixels + final double itemExtent; + + ///height of list view in pixels + final double listViewHeight; + + ///width of list view in pixels + final double listViewWidth; + + ///ScrollController used for integer list + final ScrollController intScrollController; + + ///ScrollController used for decimal list + final ScrollController decimalScrollController; + + ///Currently selected integer value + final int selectedIntValue; + + ///Currently selected decimal value + final int selectedDecimalValue; + + ///If currently selected value should be highlighted + final bool highlightSelectedValue; + + ///Decoration to apply to central box where the selected value is placed + final Decoration decoration; + + ///Step between elements. Only for integer datePicker + ///Examples: + /// if step is 100 the following elements may be 100, 200, 300... + /// if min=0, max=6, step=3, then items will be 0, 3 and 6 + /// if min=0, max=5, step=3, then items will be 0 and 3. + final int step; + + /// Direction of scrolling + final Axis scrollDirection; + + ///Repeat values infinitely + final bool infiniteLoop; + + ///Pads displayed integer values up to the length of maxValue + final bool zeroPad; + + ///Amount of items + final int integerItemCount; + + ///Whether to trigger haptic pulses or not + final bool haptics; + + ///TextStyle of the non-highlighted numbers + final TextStyle textStyle; + +///TextStyle of the highlighted numbers + final TextStyle textStyleHighlighted; + + // + //----------------------------- PUBLIC ------------------------------ + // + + /// Used to animate integer number picker to new selected value + void animateInt(int valueToSelect) { + int diff = valueToSelect - minValue; + int index = diff ~/ step; + animateIntToIndex(index); + } + + /// Used to animate integer number picker to new selected index + void animateIntToIndex(int index) { + _animate(intScrollController, index * itemExtent); + } + + /// Used to animate decimal part of double value to new selected value + void animateDecimal(int decimalValue) { + _animate(decimalScrollController, decimalValue * itemExtent); + } + + /// Used to animate decimal number picker to selected value + void animateDecimalAndInteger(double valueToSelect) { + animateInt(valueToSelect.floor()); + animateDecimal(((valueToSelect - valueToSelect.floorToDouble()) * + math.pow(10, decimalPlaces)) + .round()); + } + + // + //----------------------------- VIEWS ----------------------------- + // + + ///main widget + @override + Widget build(BuildContext context) { + final ThemeData themeData = Theme.of(context); + + if (infiniteLoop) { + return _integerInfiniteListView(themeData); + } + if (decimalPlaces == 0) { + return _integerListView(themeData); + } else { + return Row( + children: [ + _integerListView(themeData), + _decimalListView(themeData), + ], + mainAxisAlignment: MainAxisAlignment.center, + ); + } + } + + Widget _integerListView(ThemeData themeData) { + TextStyle defaultStyle = textStyle == null ? + themeData.textTheme.body1 : textStyle; + TextStyle selectedStyle = textStyleHighlighted == null ? + themeData.textTheme.headline.copyWith(color: themeData.accentColor) + : textStyleHighlighted; + + var listItemCount = integerItemCount + 2; + + return Listener( + onPointerUp: (ev) { + ///used to detect that user stopped scrolling + if (intScrollController.position.activity is HoldScrollActivity) { + animateInt(selectedIntValue); + } + }, + child: NotificationListener( + child: Container( + height: listViewHeight, + width: listViewWidth, + child: Stack( + children: [ + ListView.builder( + scrollDirection: scrollDirection, + controller: intScrollController, + itemExtent: itemExtent, + itemCount: listItemCount, + cacheExtent: _calculateCacheExtent(listItemCount), + itemBuilder: (BuildContext context, int index) { + final int value = _intValueFromIndex(index); + + //define special style for selected (middle) element + final TextStyle itemStyle = + value == selectedIntValue && highlightSelectedValue + ? selectedStyle + : defaultStyle; + + bool isExtra = index == 0 || index == listItemCount - 1; + + return isExtra + ? Container() //empty first and last element + : Center( + child: Text( + getDisplayedValue(value), + style: itemStyle, + ), + ); + }, + ), + _NumberPickerSelectedItemDecoration( + axis: scrollDirection, + itemExtent: itemExtent, + decoration: decoration, + ), + ], + ), + ), + onNotification: _onIntegerNotification, + ), + ); + } + + Widget _decimalListView(ThemeData themeData) { + TextStyle defaultStyle = textStyle == null ? + themeData.textTheme.body1 : textStyle; + TextStyle selectedStyle = textStyleHighlighted == null ? + themeData.textTheme.headline.copyWith(color: themeData.accentColor) + : textStyleHighlighted; + + + int decimalItemCount = + selectedIntValue == maxValue ? 3 : math.pow(10, decimalPlaces) + 2; + + return Listener( + onPointerUp: (ev) { + ///used to detect that user stopped scrolling + if (decimalScrollController.position.activity is HoldScrollActivity) { + animateDecimal(selectedDecimalValue); + } + }, + child: NotificationListener( + child: Container( + height: listViewHeight, + width: listViewWidth, + child: Stack( + children: [ + ListView.builder( + controller: decimalScrollController, + itemExtent: itemExtent, + itemCount: decimalItemCount, + itemBuilder: (BuildContext context, int index) { + final int value = index - 1; + + //define special style for selected (middle) element + final TextStyle itemStyle = + value == selectedDecimalValue && highlightSelectedValue + ? selectedStyle + : defaultStyle; + + bool isExtra = index == 0 || index == decimalItemCount - 1; + + return isExtra + ? Container() //empty first and last element + : Center( + child: Text( + value.toString().padLeft(decimalPlaces, '0'), + style: itemStyle, + ), + ); + }, + ), + _NumberPickerSelectedItemDecoration( + axis: scrollDirection, + itemExtent: itemExtent, + decoration: decoration, + ), + ], + ), + ), + onNotification: _onDecimalNotification, + ), + ); + } + + Widget _integerInfiniteListView(ThemeData themeData) { + TextStyle defaultStyle = textStyle == null ? + themeData.textTheme.body1 : textStyle; + TextStyle selectedStyle = textStyleHighlighted == null ? + themeData.textTheme.headline.copyWith(color: themeData.accentColor) + : textStyleHighlighted; + + + return Listener( + onPointerUp: (ev) { + ///used to detect that user stopped scrolling + if (intScrollController.position.activity is HoldScrollActivity) { + _animateIntWhenUserStoppedScrolling(selectedIntValue); + } + }, + child: NotificationListener( + child: Container( + height: listViewHeight, + width: listViewWidth, + child: Stack( + children: [ + InfiniteListView.builder( + controller: intScrollController, + itemExtent: itemExtent, + itemBuilder: (BuildContext context, int index) { + final int value = _intValueFromIndex(index); + + //define special style for selected (middle) element + final TextStyle itemStyle = + value == selectedIntValue && highlightSelectedValue + ? selectedStyle + : defaultStyle; + + return Center( + child: Text( + getDisplayedValue(value), + style: itemStyle, + ), + ); + }, + ), + _NumberPickerSelectedItemDecoration( + axis: scrollDirection, + itemExtent: itemExtent, + decoration: decoration, + ), + ], + ), + ), + onNotification: _onIntegerNotification, + ), + ); + } + + String getDisplayedValue(int value) { + final text = zeroPad + ? value.toString().padLeft(maxValue.toString().length, '0') + : value.toString(); + return textMapper != null ? textMapper(text) : text; + } + + // + // ----------------------------- LOGIC ----------------------------- + // + + int _intValueFromIndex(int index) { + index--; + index %= integerItemCount; + return minValue + index * step; + } + + bool _onIntegerNotification(Notification notification) { + if (notification is ScrollNotification) { + //calculate + int intIndexOfMiddleElement = + (notification.metrics.pixels / itemExtent).round(); + if (!infiniteLoop) { + intIndexOfMiddleElement = + intIndexOfMiddleElement.clamp(0, integerItemCount - 1); + } + int intValueInTheMiddle = _intValueFromIndex(intIndexOfMiddleElement + 1); + intValueInTheMiddle = _normalizeIntegerMiddleValue(intValueInTheMiddle); + + if (_userStoppedScrolling(notification, intScrollController)) { + //center selected value + animateIntToIndex(intIndexOfMiddleElement); + } + + //update selection + if (intValueInTheMiddle != selectedIntValue) { + num newValue; + if (decimalPlaces == 0) { + //return integer value + newValue = (intValueInTheMiddle); + } else { + if (intValueInTheMiddle == maxValue) { + //if new value is maxValue, then return that value and ignore decimal + newValue = (intValueInTheMiddle.toDouble()); + animateDecimal(0); + } else { + //return integer+decimal + double decimalPart = _toDecimal(selectedDecimalValue); + newValue = ((intValueInTheMiddle + decimalPart).toDouble()); + } + } + if (haptics) { + HapticFeedback.selectionClick(); + } + onChanged(newValue); + } + } + return true; + } + + bool _onDecimalNotification(Notification notification) { + if (notification is ScrollNotification) { + //calculate middle value + int indexOfMiddleElement = + (notification.metrics.pixels + listViewHeight / 2) ~/ itemExtent; + int decimalValueInTheMiddle = indexOfMiddleElement - 1; + decimalValueInTheMiddle = + _normalizeDecimalMiddleValue(decimalValueInTheMiddle); + + if (_userStoppedScrolling(notification, decimalScrollController)) { + //center selected value + animateDecimal(decimalValueInTheMiddle); + } + + //update selection + if (selectedIntValue != maxValue && + decimalValueInTheMiddle != selectedDecimalValue) { + double decimalPart = _toDecimal(decimalValueInTheMiddle); + double newValue = ((selectedIntValue + decimalPart).toDouble()); + if (haptics) { + HapticFeedback.selectionClick(); + } + onChanged(newValue); + } + } + return true; + } + + ///There was a bug, when if there was small integer range, e.g. from 1 to 5, + ///When user scrolled to the top, whole listview got displayed. + ///To prevent this we are calculating cacheExtent by our own so it gets smaller if number of items is smaller + double _calculateCacheExtent(int itemCount) { + double cacheExtent = 250.0; //default cache extent + if ((itemCount - 2) * kDefaultItemExtent <= cacheExtent) { + cacheExtent = ((itemCount - 3) * kDefaultItemExtent); + } + return cacheExtent; + } + + ///When overscroll occurs on iOS, + ///we can end up with value not in the range between [minValue] and [maxValue] + ///To avoid going out of range, we change values out of range to border values. + int _normalizeMiddleValue(int valueInTheMiddle, int min, int max) { + return math.max(math.min(valueInTheMiddle, max), min); + } + + int _normalizeIntegerMiddleValue(int integerValueInTheMiddle) { + //make sure that max is a multiple of step + int max = (maxValue ~/ step) * step; + return _normalizeMiddleValue(integerValueInTheMiddle, minValue, max); + } + + int _normalizeDecimalMiddleValue(int decimalValueInTheMiddle) { + return _normalizeMiddleValue( + decimalValueInTheMiddle, 0, math.pow(10, decimalPlaces) - 1); + } + + ///indicates if user has stopped scrolling so we can center value in the middle + bool _userStoppedScrolling( + Notification notification, + ScrollController scrollController, + ) { + return notification is UserScrollNotification && + notification.direction == ScrollDirection.idle && + scrollController.position.activity is! HoldScrollActivity; + } + + /// Allows to find currently selected element index and animate this element + /// Use it only when user manually stops scrolling in infinite loop + void _animateIntWhenUserStoppedScrolling(int valueToSelect) { + // estimated index of currently selected element based on offset and item extent + int currentlySelectedElementIndex = + intScrollController.offset ~/ itemExtent; + + // when more(less) than half of the top(bottom) element is hidden + // then we should increment(decrement) index in case of positive(negative) offset + if (intScrollController.offset > 0 && + intScrollController.offset % itemExtent > itemExtent / 2) { + currentlySelectedElementIndex++; + } else if (intScrollController.offset < 0 && + intScrollController.offset % itemExtent < itemExtent / 2) { + currentlySelectedElementIndex--; + } + + animateIntToIndex(currentlySelectedElementIndex); + } + + ///converts integer indicator of decimal value to double + ///e.g. decimalPlaces = 1, value = 4 >>> result = 0.4 + /// decimalPlaces = 2, value = 12 >>> result = 0.12 + double _toDecimal(int decimalValueAsInteger) { + return double.parse((decimalValueAsInteger * math.pow(10, -decimalPlaces)) + .toStringAsFixed(decimalPlaces)); + } + + ///scroll to selected value + _animate(ScrollController scrollController, double value) { + scrollController.animateTo( + value, + duration: Duration(seconds: 1), + curve: ElasticOutCurve(), + ); + } +} + +class _NumberPickerSelectedItemDecoration extends StatelessWidget { + final Axis axis; + final double itemExtent; + final Decoration decoration; + + const _NumberPickerSelectedItemDecoration( + {Key key, + @required this.axis, + @required this.itemExtent, + @required this.decoration}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return Center( + child: IgnorePointer( + child: Container( + width: isVertical ? double.infinity : itemExtent, + height: isVertical ? itemExtent : double.infinity, + decoration: decoration, + ), + ), + ); + } + + bool get isVertical => axis == Axis.vertical; +} + +///Returns AlertDialog as a Widget so it is designed to be used in showDialog method +class NumberPickerDialog extends StatefulWidget { + final int minValue; + final int maxValue; + final int initialIntegerValue; + final double initialDoubleValue; + final int decimalPlaces; + final Widget title; + final EdgeInsets titlePadding; + final Widget confirmWidget; + final Widget cancelWidget; + final int step; + final bool infiniteLoop; + final bool zeroPad; + final bool highlightSelectedValue; + final Decoration decoration; + final TextMapper textMapper; + final bool haptics; + + ///constructor for integer values + NumberPickerDialog.integer({ + @required this.minValue, + @required this.maxValue, + @required this.initialIntegerValue, + this.title, + this.titlePadding, + this.step = 1, + this.infiniteLoop = false, + this.zeroPad = false, + this.highlightSelectedValue = true, + this.decoration, + this.textMapper, + this.haptics = false, + Widget confirmWidget, + Widget cancelWidget, + }) : confirmWidget = confirmWidget ?? Text("OK"), + cancelWidget = cancelWidget ?? Text("CANCEL"), + decimalPlaces = 0, + initialDoubleValue = -1.0; + + ///constructor for decimal values + NumberPickerDialog.decimal({ + @required this.minValue, + @required this.maxValue, + @required this.initialDoubleValue, + this.decimalPlaces = 1, + this.title, + this.titlePadding, + this.highlightSelectedValue = true, + this.decoration, + this.textMapper, + this.haptics = false, + Widget confirmWidget, + Widget cancelWidget, + }) : confirmWidget = confirmWidget ?? Text("OK"), + cancelWidget = cancelWidget ?? Text("CANCEL"), + initialIntegerValue = -1, + step = 1, + infiniteLoop = false, + zeroPad = false; + + @override + State createState() => _NumberPickerDialogControllerState( + initialIntegerValue, initialDoubleValue); +} + +class _NumberPickerDialogControllerState extends State { + int selectedIntValue; + double selectedDoubleValue; + + _NumberPickerDialogControllerState( + this.selectedIntValue, this.selectedDoubleValue); + + void _handleValueChanged(num value) { + if (value is int) { + setState(() => selectedIntValue = value); + } else { + setState(() => selectedDoubleValue = value); + } + } + + NumberPicker _buildNumberPicker() { + if (widget.decimalPlaces > 0) { + return NumberPicker.decimal( + initialValue: selectedDoubleValue, + minValue: widget.minValue, + maxValue: widget.maxValue, + decimalPlaces: widget.decimalPlaces, + highlightSelectedValue: widget.highlightSelectedValue, + decoration: widget.decoration, + onChanged: _handleValueChanged, + textMapper: widget.textMapper, + haptics: widget.haptics, + ); + } else { + return NumberPicker.integer( + initialValue: selectedIntValue, + minValue: widget.minValue, + maxValue: widget.maxValue, + step: widget.step, + infiniteLoop: widget.infiniteLoop, + zeroPad: widget.zeroPad, + highlightSelectedValue: widget.highlightSelectedValue, + decoration: widget.decoration, + onChanged: _handleValueChanged, + textMapper: widget.textMapper, + haptics: widget.haptics, + ); + } + } + + @override + Widget build(BuildContext context) { + return AlertDialog( + title: widget.title, + titlePadding: widget.titlePadding, + content: _buildNumberPicker(), + actions: [ + FlatButton( + onPressed: () => Navigator.of(context).pop(), + child: widget.cancelWidget, + ), + FlatButton( + onPressed: () => Navigator.of(context).pop(widget.decimalPlaces > 0 + ? selectedDoubleValue + : selectedIntValue), + child: widget.confirmWidget), + ], + ); + } +} diff --git a/lib/library/tree_view.dart b/lib/library/tree_view.dart index 4775138..7cde1a1 100644 --- a/lib/library/tree_view.dart +++ b/lib/library/tree_view.dart @@ -1,8 +1,11 @@ /// Tree view widget library library tree_view; +import 'package:aitrainer_app/util/common.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; +import 'dart:math' as math; class TreeView extends InheritedWidget { final List children; @@ -39,7 +42,7 @@ class TreeView extends InheritedWidget { class _TreeViewData extends StatelessWidget { final List children; - const _TreeViewData({ + _TreeViewData({ this.children, }); @@ -90,13 +93,30 @@ class TreeViewChild extends StatefulWidget { } } -class TreeViewChildState extends State { +class TreeViewChildState extends State with Common, SingleTickerProviderStateMixin { bool isExpanded; + final GlobalKey listKey = GlobalKey(); + Color _color; + double _opacity = 0; + +/* List listWidgets; */ + AnimationController _controller; + Animation sizeAnimation; @override void initState() { super.initState(); isExpanded = widget.startExpanded; + _color = Colors.transparent; + _opacity = 0; + /* listWidgets = List.from(widget.children); */ + + /* _controller = AnimationController( + duration: const Duration(seconds: 1), + vsync: this, + ); + + sizeAnimation = Tween(begin: 0.0, end: 1.0).animate(_controller);*/ } @override @@ -114,22 +134,107 @@ class TreeViewChildState extends State { child: widget.parent, onTap: widget.onTap ?? () => toggleExpanded(), ), - AnimatedContainer( - duration: Duration(milliseconds: 400), - child: isExpanded + Flexible( + child: Container( + /*animation: _controller, + builder: (BuildContext context, Widget child) { + return Transform.scale( + scale: _controller.value, + child: child, + ); + },*/ + /* color: _color, + duration: Duration(seconds: 2), + curve: Curves.easeInOut,*/ + //height: double.infinity, + /*child: isExpanded //animateChildren() ? Column( mainAxisSize: MainAxisSize.min, children: widget.children, ) - : Offstage(), - ), + : Offstage(),*/ + child: + /*AnimatedCrossFade( + firstChild: Column( + mainAxisSize: MainAxisSize.min, + children: widget.children, + ), + secondChild: Offstage(), + duration: Duration(milliseconds:800), + crossFadeState: isExpanded ? CrossFadeState.showFirst : CrossFadeState.showSecond, + )*/ + AnimatedSwitcher( + duration: Duration(milliseconds:900), + reverseDuration: Duration(milliseconds:500), + switchInCurve: Curves.easeIn, + child: isExpanded ? Column( + mainAxisSize: MainAxisSize.min, + children: widget.children, + ) : Offstage(), + ), + ), + ) ], ); } + /*AnimatedList animateChildren() { + + return AnimatedList( + shrinkWrap: true, + key: listKey, + initialItemCount: listWidgets.length, + itemBuilder: (context, index, animation) { + return slideIt(animation, listWidgets[index]); + }, + ); + } + + Widget slideIt(Animation animation, Widget element) { + + return SizeTransition( + sizeFactor: animation, + axis: Axis.vertical, + child: element, + ); + }*/ + void toggleExpanded() { setState(() { this.isExpanded = !this.isExpanded; + _color = isExpanded ? Colors.black12 : Colors.transparent; + _opacity = isExpanded ? 1 : 0; + + /* if ( isExpanded == false ) { + _removeAllItems(); + } else { + //_addAllItems(); + listWidgets = List.from(widget.children); + }*/ }); } + + /* void _removeAllItems() { + final int itemCount = widget.children.length; + + for (var i = 0; i < itemCount; i++) { + Widget itemToRemove = listWidgets[0]; + listKey.currentState.removeItem(0, + (BuildContext context, Animation animation) => slideIt(animation, itemToRemove), + duration: const Duration(milliseconds: 250), + ); + + listWidgets.removeAt(0); + } + } + + void _addAllItems() { + final int itemCount = widget.children.length; + + for (var i = 0; i < itemCount; i++) { + listKey.currentState.insertItem(0); + listWidgets.insert(0, widget.children[i]); + } + }*/ + } diff --git a/lib/main.dart b/lib/main.dart index 62424bd..7782e57 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -9,9 +9,9 @@ import 'package:aitrainer_app/view/customer_fitness_page.dart'; import 'package:aitrainer_app/view/customer_goal_page.dart'; import 'package:aitrainer_app/view/customer_modify_page.dart'; import 'package:aitrainer_app/view/customer_welcome_page.dart'; -import 'package:aitrainer_app/view/exercise_add_by_plan_page.dart'; import 'package:aitrainer_app/view/exercise_control_page.dart'; -import 'package:aitrainer_app/view/exercise_execute_by_plan_page.dart'; +import 'package:aitrainer_app/view/exercise_execute_page.dart'; +import 'package:aitrainer_app/view/exercise_execute_plan_add_page.dart'; import 'package:aitrainer_app/view/exercise_log_page.dart'; import 'package:aitrainer_app/view/exercise_plan_custom_page.dart'; import 'package:aitrainer_app/view/exercise_plan_custom_detail_add_page.dart'; @@ -27,6 +27,8 @@ import 'package:aitrainer_app/view/myexcercise_plan_page.dart'; import 'package:aitrainer_app/view/registration.dart'; import 'package:aitrainer_app/view/settings.dart'; import 'package:aitrainer_app/widgets/home.dart'; +import 'package:firebase_analytics/firebase_analytics.dart'; +import 'package:firebase_analytics/observer.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; @@ -37,7 +39,7 @@ import 'package:sentry/sentry.dart'; import 'bloc/account/account_bloc.dart'; import 'bloc/body_development/body_development_bloc.dart'; import 'bloc/development_by_muscle/development_by_muscle_bloc.dart'; -import 'bloc/exercise_by_plan/exercise_by_plan_bloc.dart'; +import 'bloc/exercise_execute_plan/exercise_execute_plan_bloc.dart'; import 'bloc/exercise_plan/exercise_plan_bloc.dart'; import 'bloc/menu/menu_bloc.dart'; import 'bloc/session/session_bloc.dart'; @@ -127,8 +129,8 @@ Future main() async { BlocProvider( create: (BuildContext context) => ExercisePlanBloc(menuTreeRepository: menuTreeRepository), ), - BlocProvider( - create: (BuildContext context) => ExerciseByPlanBloc( + BlocProvider( + create: (BuildContext context) => ExerciseExecutePlanBloc( menuTreeRepository: menuTreeRepository), ), BlocProvider( @@ -155,6 +157,7 @@ class AitrainerApp extends StatelessWidget { @override Widget build(BuildContext context) { SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); + final FirebaseAnalytics analytics = FirebaseAnalytics(); return MaterialApp( localizationsDelegates: [ // ... app-specific localization delegate[s] here @@ -205,8 +208,8 @@ class AitrainerApp extends StatelessWidget { 'exerciseLogPage': (context) => ExerciseLogPage(), 'exercisePlanCustomPage': (context) => ExercisePlanCustomPage(), 'exercisePlanDetailAdd': (context) => ExercisePlanDetailAddPage(), - 'exerciseByPlanPage': (context) => ExerciseByPlanPage(), - 'exerciseAddByPlanPage': (context) => ExerciseAddByPlanPage(), + 'exerciseExecutePlanPage': (context) => ExerciseExecutePage(), + 'exerciseExecuteAddPage': (context) => ExerciseExecutePlanAddPage(), 'mydevelopmentMusclePage': (context) => MyDevelopmentMusclePage(), 'mydevelopmentBodyPage': (context) => MyDevelopmentBodyPage(), }, @@ -220,6 +223,9 @@ class AitrainerApp extends StatelessWidget { bodyText1: TextStyle(fontSize: 14.0), ) ), + navigatorObservers: [ + FirebaseAnalyticsObserver(analytics: analytics), + ], home: AitrainerHome(), ); diff --git a/lib/model/exercise.dart b/lib/model/exercise.dart index da04d75..9275cbf 100644 --- a/lib/model/exercise.dart +++ b/lib/model/exercise.dart @@ -18,6 +18,7 @@ class Exercise { Exercise({this.exerciseTypeId, this.customerId, this.quantity, this.dateAdd}); Exercise.fromJson(Map json) { + this.exerciseId = json['exerciseId']; this.exerciseTypeId = json['exerciseTypeId']; this.customerId = json['customerId']; this.quantity = json['quantity']; diff --git a/lib/model/exercise_plan_detail.dart b/lib/model/exercise_plan_detail.dart index 11096cc..89f79da 100644 --- a/lib/model/exercise_plan_detail.dart +++ b/lib/model/exercise_plan_detail.dart @@ -5,6 +5,7 @@ class ExercisePlanDetailChange { static const String delete = "delete"; static const String update = "update"; static const String deleted = "deleted"; + static const String saved = "saved"; } class ExercisePlanDetail { diff --git a/lib/repository/exercise_plan_repository.dart b/lib/repository/exercise_plan_repository.dart index 885b980..f34ea8f 100644 --- a/lib/repository/exercise_plan_repository.dart +++ b/lib/repository/exercise_plan_repository.dart @@ -134,15 +134,16 @@ class ExercisePlanRepository { .deleteExercisePlanDetail(exercisePlanDetail.exercisePlanDetailId); exercisePlanDetail.change = ExercisePlanDetailChange.deleted; Cache().deletedMyExercisePlanDetail(exercisePlanDetail); - } else if ( exercisePlanDetail.change == ExercisePlanDetailChange.update ) { await ExercisePlanApi() .updateExercisePlanDetail(exercisePlanDetail, exercisePlanDetail.exercisePlanDetailId); Cache().updateMyExercisePlanDetail(exercisePlanDetail); + exercisePlanDetail.change = ExercisePlanDetailChange.saved; } else if ( exercisePlanDetail.change == ExercisePlanDetailChange.add ) { await ExercisePlanApi() .saveExercisePlanDetail(exercisePlanDetail); Cache().addToMyExercisePlanDetails(exercisePlanDetail); + exercisePlanDetail.change = ExercisePlanDetailChange.saved; } }); diff --git a/lib/repository/exercise_repository.dart b/lib/repository/exercise_repository.dart index 9f4a524..52dd49f 100644 --- a/lib/repository/exercise_repository.dart +++ b/lib/repository/exercise_repository.dart @@ -74,6 +74,10 @@ class ExerciseRepository { } } + Future deleteExercise(Exercise exercise) async { + await ExerciseApi().deleteExercise(exercise); + } + setCustomer(Customer customer) => this.customer = customer; diff --git a/lib/service/exercise_service.dart b/lib/service/exercise_service.dart index 16c810d..843fcc4 100644 --- a/lib/service/exercise_service.dart +++ b/lib/service/exercise_service.dart @@ -44,4 +44,11 @@ class ExerciseApi { return savedExercise; } + Future deleteExercise(Exercise exercise) async { + int exerciseId = exercise.exerciseId; + print(" ===== delete exercise: " + exerciseId.toString() ); + final String response = await _client.post("exercises/" + exerciseId.toString(), ""); + return; + } + } \ No newline at end of file diff --git a/lib/util/session.dart b/lib/util/session.dart index 78a9118..60df05d 100644 --- a/lib/util/session.dart +++ b/lib/util/session.dart @@ -9,6 +9,7 @@ import 'package:devicelocale/devicelocale.dart'; import 'package:flutter/services.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:aitrainer_app/model/cache.dart'; +import 'package:firebase_core/firebase_core.dart'; //import '../push_notifications.dart'; @@ -30,13 +31,28 @@ class Session { await AppLocalizations.delegate.load(AppLanguage().appLocal); print (" -- Session: fetch token.."); await _fetchToken(_sharedPreferences); + await _initializeFlutterFire(); //initDeviceLocale(); + // Create the initialization Future outside of `build`: + + // PushNotificationsManager().init(); } } + // Define an async function to initialize FlutterFire + void _initializeFlutterFire() async { + try { + // Wait for Firebase to initialize and set `_initialized` state to true + await Firebase.initializeApp(); + } catch (e) { + // Set `_error` state to true if Firebase initialization fails + print("Error initializing Firebase"); + } + } + Future initDeviceLocale() async { List languages; String currentLocale; diff --git a/lib/view/account.dart b/lib/view/account.dart index 4c2c4ca..049cc07 100644 --- a/lib/view/account.dart +++ b/lib/view/account.dart @@ -129,11 +129,12 @@ class AccountPage extends StatelessWidget with Trans { color: Colors.white, onPressed: () => { if ( accountBloc.loggedIn ) { - accountBloc.add(AccountLogout()) + confirmationDialog( accountBloc ), } else { accountBloc.add(AccountLogin()), Navigator.of(context).pushNamed('login'), } + }, ), ); @@ -209,4 +210,33 @@ class AccountPage extends StatelessWidget with Trans { ); } + void confirmationDialog(AccountBloc accountBloc) { + showCupertinoDialog( + useRootNavigator: true, + context: context, + //barrierDismissible: false, + builder:(_) => CupertinoAlertDialog( + title: Text(t("Are you sure to logout?")), + content: Column( + + children: [ + Divider(), + ]), + actions: [ + FlatButton( + child: Text(t("No")), + onPressed: () => Navigator.pop(context), + ), + FlatButton( + child: Text(t("Yes")), + onPressed: () => { + accountBloc.add(AccountLogout()), + Navigator.pop(context), + }, + ) + ], + ) + ); + } + } diff --git a/lib/view/customer_modify_page.dart b/lib/view/customer_modify_page.dart index 1691778..a1e7d13 100644 --- a/lib/view/customer_modify_page.dart +++ b/lib/view/customer_modify_page.dart @@ -18,16 +18,7 @@ class CustomerModifyPage extends StatelessWidget with Trans { setContext(context); // ignore: close_sinks final accountBloc = BlocProvider.of(context); - // we cannot initialize the translations in the initState -/* genders.forEach((GenderItem element) { - if (element.dbValue == "m") { - element.name = AppLocalizations.of(context).translate("Man"); - } - if (element.dbValue == "w") { - element.name = AppLocalizations.of(context).translate("Woman"); - } - }); -*/ + return BlocProvider( create: (context) => CustomerChangeFormBloc(customerRepository: accountBloc.customerRepository), child: Builder(builder: (context) { @@ -82,20 +73,6 @@ class CustomerModifyPage extends StatelessWidget with Trans { labelText: t('Email'), ), ), - - /* TextFormField( - style: TextStyle(fontSize: 12), - decoration: InputDecoration( - fillColor: Colors.white24, - filled: true, - labelText: AppLocalizations.of(context) - .translate('Email'), - ), */ - // initialValue: customerChangingViewModel.customer - // .customer.email, - // onFieldSubmitted: (input) => - // customerChangingViewModel.customer.setEmail( - // input) ) ], ), @@ -113,19 +90,6 @@ class CustomerModifyPage extends StatelessWidget with Trans { labelText: t('Password (Leave empty if no change)'), ), ), - /*TextFormField( - style: TextStyle(fontSize: 12), - obscureText: true, - decoration: InputDecoration( - fillColor: Colors.white24, - filled: true, - labelText: AppLocalizations.of(context) - .translate( - 'Password (Leave empty if you don\'t want to change)'), - ), - //initialValue: customerChangingViewModel.customer.customer.password, - // onFieldSubmitted: (input) => customerChangingViewModel.customer.setPassword(input) - )*/ ) ], ), diff --git a/lib/view/exercise_control_page.dart b/lib/view/exercise_control_page.dart index 57c3c07..5dffd4b 100644 --- a/lib/view/exercise_control_page.dart +++ b/lib/view/exercise_control_page.dart @@ -1,47 +1,63 @@ import 'dart:collection'; -import 'package:aitrainer_app/bloc/exercise_control_form_bloc.dart'; +import 'package:aitrainer_app/bloc/exercise_control/exercise_control_bloc.dart'; import 'package:aitrainer_app/localization/app_language.dart'; -import 'package:aitrainer_app/localization/app_localization.dart'; import 'package:aitrainer_app/repository/exercise_repository.dart'; +import 'package:aitrainer_app/util/trans.dart'; import 'package:aitrainer_app/widgets/app_bar.dart'; import 'package:aitrainer_app/widgets/bottom_nav.dart'; import 'package:aitrainer_app/widgets/splash.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_form_bloc/flutter_form_bloc.dart'; +import 'package:aitrainer_app/library/numberpicker.dart'; class ExerciseControlPage extends StatefulWidget { _ExerciseControlPage createState() => _ExerciseControlPage(); } -class _ExerciseControlPage extends State { +class _ExerciseControlPage extends State with Trans { @override Widget build(BuildContext context) { LinkedHashMap arguments = ModalRoute.of(context).settings.arguments; final ExerciseRepository exerciseRepository = arguments['exerciseRepository']; final double percent = arguments['percent']; final bool readonly = arguments['readonly']; + setContext(context); return BlocProvider( - create: (context) => ExerciseControlFormBloc( - exerciseRepository: exerciseRepository, percentToCalculate: percent, readonly: readonly), - child: BlocBuilder(builder: (context, state) { - // ignore: close_sinks - final exerciseBloc = BlocProvider.of(context); - if (state is FormBlocLoading) { + create: (context) => ExerciseControlBloc( + exerciseRepository: exerciseRepository, percentToCalculate: percent, readonly: readonly).. + add(ExerciseControlLoad()), + child: + BlocConsumer( + listener: (context, state) { + + if (state is ExerciseControlError) { + Scaffold.of(context).showSnackBar(SnackBar( + backgroundColor: Colors.orange, + content: + Text(state.message, style: TextStyle(color: Colors.white)))); + } else if (state is ExerciseControlLoading) { return LoadingDialog(); - } else if (state is FormBlocSuccess) { + } + }, + builder: (context, state) { + + final exerciseBloc = BlocProvider.of(context); + if (state is ExerciseControlReady) { return getControlForm(exerciseBloc); } else { return getControlForm(exerciseBloc); } - })); + }) + + ); } - Form getControlForm(ExerciseControlFormBloc exerciseBloc) { + Form getControlForm(ExerciseControlBloc exerciseBloc) { + String exerciseName = AppLanguage().appLocal == Locale("en") ? exerciseBloc.exerciseRepository.exerciseType.name : exerciseBloc.exerciseRepository.exerciseType.nameTranslation; @@ -65,209 +81,162 @@ class _ExerciseControlPage extends State { padding: const EdgeInsets.only(top: 25, left: 25, right: 25), child: SingleChildScrollView( scrollDirection: Axis.vertical, - child: Column(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ - Text( - exerciseName, - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.deepOrange), - overflow: TextOverflow.fade, - maxLines: 1, - softWrap: true, - ), - FlatButton( - child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Icon(Icons.question_answer), - Text(AppLocalizations.of(context).translate("Why do you need Exercise Control?"), - style: TextStyle(color: Colors.blueAccent, fontWeight: FontWeight.normal, fontSize: 14)), - Icon(Icons.arrow_forward_ios), - ]), - textColor: Colors.blueAccent, - color: Colors.transparent, - onPressed: () => { - //Navigator.of(context).pushNamed('exerciseTypeDescription', arguments: exerciseBloc.exerciseRepository), - }, - ), - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ Text( - AppLocalizations.of(context).translate("Your 1RM:"), + exerciseName, + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.deepOrange), + overflow: TextOverflow.fade, + maxLines: 1, + softWrap: true, ), - Text( - " " + - exerciseBloc.initialRMField.value + + FlatButton( + child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ + Icon(Icons.info), + Flexible( + child: Text(t("Why do you need Exercise Control?"), + style: + TextStyle(color: Colors.blueAccent, fontWeight: FontWeight.normal, fontSize: 14)), + ), + Icon(Icons.arrow_forward_ios), + ]), + textColor: Colors.blueAccent, + color: Colors.transparent, + onPressed: () => { + //Navigator.of(context).pushNamed('exerciseTypeDescription', arguments: exerciseBloc.exerciseRepository), + }, + ), + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + t("Your 1RM:"), + ), + Text( " " + - exerciseBloc.exerciseRepository.exerciseType.unitQuantityUnit, - style: TextStyle(fontWeight: FontWeight.bold), + exerciseBloc.initialRM.toStringAsFixed(0) + + " " + + exerciseBloc.exerciseRepository.exerciseType.unitQuantityUnit, + style: TextStyle(fontWeight: FontWeight.bold), + ), + ], ), - ], - ), - Divider(), - Column( - mainAxisAlignment: MainAxisAlignment.spaceAround, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - AppLocalizations.of(context).translate("1st Control Exercise:"), - style: TextStyle(), - ), - TextFieldBlocBuilder( - readOnly: exerciseBloc.step != 1, - textFieldBloc: exerciseBloc.quantity1Field, - textAlign: TextAlign.center, - style: TextStyle(fontSize: 14, color: Colors.deepOrange, fontWeight: FontWeight.bold), - inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r"[\d.]"))], - decoration: InputDecoration( - fillColor: Colors.white, - filled: false, - hintStyle: TextStyle(fontSize: 12, color: Colors.black54, fontWeight: FontWeight.w100), - hintText: AppLocalizations.of(context).translate("The number of the exercise"), - labelStyle: - TextStyle(fontSize: 12, color: Colors.deepOrange, fontWeight: FontWeight.normal), - labelText: "Please repeat with " + - exerciseBloc.unitQuantity1Field.value + - " " + - exerciseBloc.exerciseRepository.exerciseType.unitQuantityUnit + - " " + - exerciseBloc.times + - " times!", - ), - ), - RaisedButton( - padding: EdgeInsets.all(0), - textColor: Colors.white, - color: exerciseBloc.step == 1 ? Colors.blue : Colors.black26, - focusColor: Colors.blueAccent, - onPressed: () => {exerciseBloc.submit()}, - child: Text( - AppLocalizations.of(context).translate("Check"), - style: TextStyle(fontSize: 12), - )), - ], - ), - Divider(), - Column( - mainAxisAlignment: MainAxisAlignment.spaceAround, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - AppLocalizations.of(context).translate("2nd Control Exercise:"), - style: TextStyle(), - ), - TextFieldBlocBuilder( - readOnly: exerciseBloc.step != 2, - textFieldBloc: exerciseBloc.quantity2Field, - textAlign: TextAlign.center, - style: TextStyle(fontSize: 14, color: Colors.deepOrange, fontWeight: FontWeight.bold), - inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r"[\d.]"))], - onChanged: (input) => { - print("Quantity 2 value $input"), - //exerciseBloc.exerciseRepository.setQuantity(double.parse(input)), - //exerciseBloc.exerciseRepository - // .setUnit(exerciseBloc.exerciseRepository.exerciseType.unit) - }, - decoration: InputDecoration( - fillColor: Colors.white, - filled: false, - hintStyle: TextStyle(fontSize: 12, color: Colors.black54, fontWeight: FontWeight.w100), - hintText: AppLocalizations.of(context).translate("The number of the exercise"), - labelStyle: - TextStyle(fontSize: 12, color: Colors.deepOrange, fontWeight: FontWeight.normal), - labelText: "Please repeat with " + - exerciseBloc.unitQuantity2Field.value + - " " + - exerciseBloc.exerciseRepository.exerciseType.unitQuantityUnit + - " 12 times!", - ), - ), - RaisedButton( - padding: EdgeInsets.all(0), - textColor: Colors.white, - color: exerciseBloc.step == 2 ? Colors.blue : Colors.black26, - focusColor: Colors.blueAccent, - onPressed: () => {exerciseBloc.submit()}, - child: Text( - AppLocalizations.of(context).translate("Check"), - style: TextStyle(fontSize: 12), - )), - ], - ), - Divider(), - Column( - mainAxisAlignment: MainAxisAlignment.spaceAround, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - AppLocalizations.of(context).translate("3rd Control Exercise:"), - style: TextStyle(), - ), - TextFieldBlocBuilder( - readOnly: exerciseBloc.step != 3, - textFieldBloc: exerciseBloc.quantity3Field, - textAlign: TextAlign.center, - style: TextStyle(fontSize: 14, color: Colors.deepOrange, fontWeight: FontWeight.bold), - inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r"[\d.]"))], - onChanged: (input) => { - print("Quantity 3 value $input"), - //exerciseBloc.exerciseRepository.setQuantity(double.parse(input)), - //exerciseBloc.exerciseRepository - // .setUnit(exerciseBloc.exerciseRepository.exerciseType.unit) - }, - decoration: InputDecoration( - fillColor: Colors.white, - filled: false, - hintStyle: TextStyle(fontSize: 12, color: Colors.black54, fontWeight: FontWeight.w100), - hintText: AppLocalizations.of(context).translate("The number of the exercise"), - labelStyle: - TextStyle(fontSize: 12, color: Colors.deepOrange, fontWeight: FontWeight.normal), - labelText: "Please repeat with " + - exerciseBloc.unitQuantity3Field.value + - " " + - exerciseBloc.exerciseRepository.exerciseType.unitQuantityUnit + - " 12 times!", - ), - ), - RaisedButton( - padding: EdgeInsets.all(0), - textColor: Colors.white, - color: exerciseBloc.step == 3 ? Colors.blue : Colors.black26, - focusColor: Colors.blueAccent, - onPressed: () => {exerciseBloc.submit()}, - child: Text( - AppLocalizations.of(context).translate("Check"), - style: TextStyle(fontSize: 12), - )), - ], - ), - ]), + Divider(), + numberPickForm(exerciseBloc, 1), + Divider(), + numberPickForm(exerciseBloc, 2), + Divider(), + numberPickForm(exerciseBloc, 3), + ]), ))), bottomNavigationBar: BottomNavigator(bottomNavIndex: 1), ), + ); + } + + Widget numberPickForm(ExerciseControlBloc exerciseBloc, int step) { + + String strTimes = step == 2 ? exerciseBloc.origQuantity.toString() : "max."; + String textInstruction = ""; + textInstruction = t("Please repeat with ") + + exerciseBloc.unitQuantity.toStringAsFixed(0) + + " " + + exerciseBloc.exerciseRepository.exerciseType.unitQuantityUnit + + t("hu_with") + " " + + strTimes + " " + t("times!"); + + String title = step.toString() + ". " + t("Control Exercise:"); + + + List listWidgets = [ + Text( + title, + style: TextStyle(fontWeight: FontWeight.bold), + ), + Text( + textInstruction, + style: TextStyle(fontSize: 12), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + NumberPicker.horizontal( + highlightSelectedValue: step == exerciseBloc.step, + initialValue: exerciseBloc.quantity.toInt(), + minValue: 0, + maxValue: 200, + step: 1, + onChanged: (value) => { + exerciseBloc.add(ExerciseControlQuantityChange(quantity: value.toDouble(), step: step)) + }, + listViewHeight: 80, + //decoration: _decoration, + ), + RaisedButton( + padding: EdgeInsets.all(0), + textColor: Colors.white, + color: step == exerciseBloc.step ? Colors.blue : Colors.black26, + focusColor: Colors.blueAccent, + onPressed: () => { + exerciseBloc.add(ExerciseControlSubmit(step: step)), + if ( step == 3 ) { + confirmationDialog(exerciseBloc) + } + }, + child: Text( + t("Save"), + style: TextStyle(fontSize: 12), + )), + ], + ), + + ]; + + return + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: listWidgets, ); } - String validateNumberInput(input) { - String error = AppLocalizations.of(context).translate("Please type the right quantity 0-10000"); - dynamic rc = (input != null && input.length > 0); - if (!rc) { - return null; - } + void confirmationDialog( ExerciseControlBloc bloc ) { - Pattern pattern = r'^\d+(?:\.\d+)?$'; - RegExp regex = new RegExp(pattern); - if (!regex.hasMatch(input)) { - return error; - } - rc = double.tryParse(input); - if (rc == null) { - return error; - } + String unit = t(bloc.exerciseRepository.exerciseType.unit); - if (!(double.parse(input) < 10000 && double.parse(input) > 0)) { - return error; - } + showCupertinoDialog( + useRootNavigator: true, + context: context, + //barrierDismissible: false, + builder:(_) => CupertinoAlertDialog( + title: Text(t("Summary of your test")), + content: Column( - return null; + children: [ + + Text(t("Test") + ": " + bloc.repeats[1].toStringAsFixed(0) + "x" + bloc.repeats[0].toStringAsFixed(0) + " " + unit , + style: (TextStyle(color: Colors.blue)),), + Divider(), + Text(t("1st Control") + ": " + bloc.repeats[2].toStringAsFixed(0) + "x" + bloc.unitQuantity.toStringAsFixed(0) + " " + unit , + style: (TextStyle(color: Colors.blue)),), + Text(t("2nd Control") + ": " + bloc.repeats[3].toStringAsFixed(0) + "x" + bloc.unitQuantity.toStringAsFixed(0) + " " + unit , + style: (TextStyle(color: Colors.blue)),), + Text(t("3rd Control") + ": " + bloc.repeats [4].toStringAsFixed(0) + "x" + bloc.unitQuantity.toStringAsFixed(0) + " " + unit , + style: (TextStyle(color: Colors.blue)),), + ]), + actions: [ + FlatButton( + child: Text(t("OK")), + onPressed: () => { + Navigator.of(context).pop(), + Navigator.of(context).pop() + }, + ) + ], + ) + ); } } diff --git a/lib/view/exercise_execute_by_plan_page.dart b/lib/view/exercise_execute_page.dart similarity index 86% rename from lib/view/exercise_execute_by_plan_page.dart rename to lib/view/exercise_execute_page.dart index a9a0725..ca67016 100644 --- a/lib/view/exercise_execute_by_plan_page.dart +++ b/lib/view/exercise_execute_page.dart @@ -1,5 +1,5 @@ import 'dart:collection'; -import 'package:aitrainer_app/bloc/exercise_by_plan/exercise_by_plan_bloc.dart'; +import 'package:aitrainer_app/bloc/exercise_execute_plan/exercise_execute_plan_bloc.dart'; import 'package:aitrainer_app/model/cache.dart'; import 'package:aitrainer_app/model/workout_menu_tree.dart'; import 'package:aitrainer_app/library/tree_view.dart'; @@ -13,15 +13,15 @@ import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -class ExerciseByPlanPage extends StatefulWidget { +class ExerciseExecutePage extends StatefulWidget { @override - _ExerciseByPlanPage createState() => _ExerciseByPlanPage(); + _ExerciseExecutePage createState() => _ExerciseExecutePage(); } -class _ExerciseByPlanPage extends State with Trans { +class _ExerciseExecutePage extends State with Trans { final GlobalKey _scaffoldKey = new GlobalKey(); // ignore: close_sinks - ExerciseByPlanBloc bloc; + ExerciseExecutePlanBloc bloc; @override void initState() { @@ -29,7 +29,7 @@ class _ExerciseByPlanPage extends State with Trans { /// We require the initializers to run after the loading screen is rendered SchedulerBinding.instance.addPostFrameCallback((_) { - BlocProvider.of(context).add(ExerciseByPlanLoad()); + BlocProvider.of(context).add(ExerciseByPlanLoad()); }); } @@ -37,7 +37,7 @@ class _ExerciseByPlanPage extends State with Trans { Widget build(BuildContext context) { LinkedHashMap arguments = ModalRoute.of(context).settings.arguments; final int customerId = arguments['customerId']; - bloc = BlocProvider.of(context); + bloc = BlocProvider.of(context); bloc.customerId = customerId; setContext(context); @@ -49,13 +49,13 @@ class _ExerciseByPlanPage extends State with Trans { decoration: BoxDecoration( image: DecorationImage( image: customerId == Cache().userLoggedIn.customerId - ? AssetImage('asset/image/WT_light_background.png') + ? AssetImage('asset/image/WT_menu_dark.png') : AssetImage('asset/image/WT_menu_dark.png'), fit: BoxFit.cover, alignment: Alignment.center, ), ), - child: BlocConsumer( + child: BlocConsumer( listener: (context, state) { if (state is ExerciseByPlanError) { Scaffold.of(context).showSnackBar(SnackBar( @@ -82,14 +82,14 @@ class _ExerciseByPlanPage extends State with Trans { ); } - Widget exerciseWidget(ExerciseByPlanBloc bloc) { + Widget exerciseWidget(ExerciseExecutePlanBloc bloc) { return TreeView( startExpanded: false, children: nodeExercisePlan(bloc), ); } - List nodeExercisePlan(ExerciseByPlanBloc bloc) { + List nodeExercisePlan(ExerciseExecutePlanBloc bloc) { List exerciseTypes = List(); Card explanation = Card( color: Colors.white38, @@ -141,7 +141,7 @@ class _ExerciseByPlanPage extends State with Trans { return exerciseTypes; } - List _getChildList(List listWorkoutTree, ExerciseByPlanBloc bloc) { + List _getChildList(List listWorkoutTree, ExerciseExecutePlanBloc bloc) { List list = List(); listWorkoutTree.forEach((element) { @@ -184,7 +184,7 @@ class _ExerciseByPlanPage extends State with Trans { IconButton( padding: EdgeInsets.all(0), - icon: Icon(Icons.description, color: Colors.black12,), + icon: Icon(Icons.info, color: Colors.black12,), onPressed: () { }, @@ -202,11 +202,11 @@ class _ExerciseByPlanPage extends State with Trans { return list; } - void addExerciseByPlanEvent(ExerciseByPlanBloc bloc, WorkoutMenuTree workoutTree) { + void addExerciseByPlanEvent(ExerciseExecutePlanBloc bloc, WorkoutMenuTree workoutTree) { LinkedHashMap args = LinkedHashMap(); args['blocExerciseByPlan'] = bloc; args['customerId'] = bloc.customerId; args['workoutTree'] = workoutTree; - Navigator.of(context).pushNamed("exerciseAddByPlanPage", arguments: args); + Navigator.of(context).pushNamed("exerciseExecuteAddPage", arguments: args); } } diff --git a/lib/view/exercise_add_by_plan_page.dart b/lib/view/exercise_execute_plan_add_page.dart similarity index 63% rename from lib/view/exercise_add_by_plan_page.dart rename to lib/view/exercise_execute_plan_add_page.dart index 0fdba59..37684f3 100644 --- a/lib/view/exercise_add_by_plan_page.dart +++ b/lib/view/exercise_execute_plan_add_page.dart @@ -1,29 +1,29 @@ import 'dart:collection'; -import 'package:aitrainer_app/bloc/exercise_add_by_plan_bloc.dart'; -import 'package:aitrainer_app/bloc/exercise_by_plan/exercise_by_plan_bloc.dart'; +import 'package:aitrainer_app/bloc/exercise_execute_plan/exercise_execute_plan_bloc.dart'; +import 'package:aitrainer_app/bloc/exercise_execute_plan_add/exercise_execute_plan_add_bloc.dart'; import 'package:aitrainer_app/localization/app_language.dart'; import 'package:aitrainer_app/model/workout_menu_tree.dart'; import 'package:aitrainer_app/repository/exercise_repository.dart'; import 'package:aitrainer_app/util/trans.dart'; import 'package:aitrainer_app/widgets/splash.dart'; -import 'package:flutter/services.dart'; +import 'package:aitrainer_app/library/numberpicker.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_form_bloc/flutter_form_bloc.dart'; -class ExerciseAddByPlanPage extends StatefulWidget{ - _ExerciseAddByPlanPage createState() => _ExerciseAddByPlanPage(); +class ExerciseExecutePlanAddPage extends StatefulWidget{ + _ExerciseExecuteAddPage createState() => _ExerciseExecuteAddPage(); } -class _ExerciseAddByPlanPage extends State with Trans { +class _ExerciseExecuteAddPage extends State with Trans { @override Widget build(BuildContext context) { LinkedHashMap arguments = ModalRoute.of(context).settings.arguments; // ignore: close_sinks - final ExerciseByPlanBloc bloc = arguments['blocExerciseByPlan']; + final ExerciseExecutePlanBloc planBloc = arguments['blocExerciseByPlan']; final int customerId = arguments['customerId']; final WorkoutMenuTree workoutTree = arguments['workoutTree']; final ExerciseRepository exerciseRepository = ExerciseRepository(); @@ -31,18 +31,29 @@ class _ExerciseAddByPlanPage extends State with Trans { return BlocProvider( create: (context) => - ExerciseAddByPlanFormBloc( + ExerciseExecutePlanAddBloc( exerciseRepository: exerciseRepository, - exercisePlanRepository: bloc.exercisePlanRepository, + exercisePlanRepository: planBloc.exercisePlanRepository, customerId: customerId, - workoutTree: workoutTree), - child: BlocBuilder( + workoutTree: workoutTree, + planBloc: planBloc), + child: BlocConsumer( + listener: (context, state) { + if (state is ExerciseExecutePlanAddError) { + Scaffold.of(context).showSnackBar(SnackBar( + backgroundColor: Colors.orange, + content: + Text(state.message, style: TextStyle(color: Colors.white)))); + } else if (state is ExerciseExecutePlanAddLoading) { + return LoadingDialog(); + } + }, builder: (context, state) { // ignore: close_sinks - final exerciseBloc = BlocProvider.of(context); - if ( state is FormBlocLoading ) { + final exerciseBloc = BlocProvider.of(context); + if ( state is ExerciseExecutePlanAddLoading ) { return LoadingDialog(); - } else if ( state is FormBlocSuccess) { + } else if ( state is ExerciseExecutePlanAddReady) { return getControlForm(exerciseBloc); } else { return getControlForm(exerciseBloc); @@ -51,7 +62,7 @@ class _ExerciseAddByPlanPage extends State with Trans { )); } - Form getControlForm( ExerciseAddByPlanFormBloc exerciseBloc) { + Form getControlForm( ExerciseExecutePlanAddBloc exerciseBloc) { String exerciseName = AppLanguage().appLocal == Locale("en") ? exerciseBloc.exerciseRepository.exerciseType.name : exerciseBloc.exerciseRepository.exerciseType.nameTranslation; @@ -65,7 +76,7 @@ class _ExerciseAddByPlanPage extends State with Trans { title: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text("Add Exercise"), + Text(t("Save Exercise"), style: TextStyle(fontSize: 18),), Image.asset( 'asset/image/WT_long_logo.png', fit: BoxFit.cover, @@ -98,6 +109,9 @@ class _ExerciseAddByPlanPage extends State with Trans { padding: const EdgeInsets.only (top: 25, left: 25, right: 25), child: SingleChildScrollView( scrollDirection: Axis.vertical, + controller: ScrollController( + initialScrollOffset: exerciseBloc.scrollOffset, + ), child: Column( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ @@ -128,7 +142,7 @@ class _ExerciseAddByPlanPage extends State with Trans { ); } - List repeatExercises(ExerciseAddByPlanFormBloc exerciseBloc) { + List repeatExercises(ExerciseExecutePlanAddBloc exerciseBloc) { List listColumns = List(); for ( int i = 0; i < exerciseBloc.countSteps; i++) { Column col = Column( @@ -138,8 +152,54 @@ class _ExerciseAddByPlanPage extends State with Trans { Divider(color: Colors.transparent,), Text(t("Execute the") + " " + (i+1).toString() + t(". set!"), style: TextStyle(),), + Divider(color: Colors.transparent,), + Text(t("Please repeat with") + " "+ exerciseBloc.unitQuantity.toStringAsFixed(0) + " " + + exerciseBloc.exerciseRepository.exerciseType.unitQuantityUnit + " " + + exerciseBloc.exercisePlanRepository.getActualPlanDetail().repeats.toString() + " " + t("times!")), + Row( + children: [ + NumberPicker.horizontal( + highlightSelectedValue: (i + 1) == exerciseBloc.step, + initialValue: exerciseBloc.unitQuantity.toInt(), + minValue: 0, + maxValue: 200, + step: 1, + textStyle: TextStyle(fontWeight: FontWeight.bold), + textStyleHighlighted: TextStyle(fontSize: 24, color: Colors.indigo, fontWeight: FontWeight.bold), + onChanged: (value) => { + exerciseBloc.add(ExerciseExecutePlanAddChangeUnitQuantity(quantity: value.toDouble())) + }, + listViewHeight: 80, + //decoration: _decoration, + ), + Text(exerciseBloc.exerciseRepository.exerciseType.unitQuantityUnit), + ] + ), - TextFieldBlocBuilder( + Row( + children: [ + NumberPicker.horizontal( + highlightSelectedValue: (i+1) == exerciseBloc.step, + initialValue: exerciseBloc.quantity.toInt(), + minValue: 0, + maxValue: 200, + step: 1, + textStyle: TextStyle(fontWeight: FontWeight.bold), + textStyleHighlighted: TextStyle(fontSize: 24, color: Colors.deepOrange, fontWeight: FontWeight.bold), + onChanged: (value) => { + exerciseBloc.add(ExerciseExecutePlanAddChangeQuantity(quantity: value.toDouble())) + }, + listViewHeight: 80, + //decoration: _decoration, + ), + Text(t("repeat")), + ] + ), + + + + + /*TextFieldBlocBuilder( readOnly: exerciseBloc.step != i+1, textFieldBloc: exerciseBloc.unitQuantity1Field, textAlign: TextAlign.center, @@ -159,8 +219,8 @@ class _ExerciseAddByPlanPage extends State with Trans { labelStyle: TextStyle(fontSize: 14, color: Colors.deepOrange, fontWeight: FontWeight.normal), labelText: exerciseBloc.exerciseRepository.exerciseType.unitQuantityUnit, ), - ), - TextFieldBlocBuilder( + ),*/ + /*TextFieldBlocBuilder( readOnly: exerciseBloc.step != i+1, textFieldBloc: exerciseBloc.quantity1Field, textAlign: TextAlign.center, @@ -183,7 +243,7 @@ class _ExerciseAddByPlanPage extends State with Trans { exerciseBloc.exerciseRepository.exerciseType.unitQuantityUnit + " " + exerciseBloc.exercisePlanRepository.getActualPlanDetail().repeats.toString() + " " + t("times!"), ), - ), + ),*/ RaisedButton( padding: EdgeInsets.all(0), @@ -194,47 +254,21 @@ class _ExerciseAddByPlanPage extends State with Trans { { print ("Submit step " + exerciseBloc.step.toString() + " (i) " + i.toString()), if ( exerciseBloc.step == i+1 ) { - exerciseBloc.submit() + exerciseBloc.add(ExerciseExecutePlanAddSubmit()) }, if ( i+1 == exerciseBloc.countSteps) { Navigator.of(context).pop() } }, child: Text( - t("Check"), + t("Save"), style: TextStyle(fontSize: 12),) ), - Divider(color: Colors.transparent,), + Divider(), ], ); listColumns.add(col); } return listColumns; } - - String validateNumberInput(input) { - String error = t("Please type the right quantity 0-10000"); - dynamic rc = (input != null && input.length > 0); - if (!rc) { - return null; - } - - Pattern pattern = r'^\d+(?:\.\d+)?$'; - RegExp regex = new RegExp(pattern); - if (!regex.hasMatch(input)) { - return error; - } - - rc = double.tryParse(input); - if (rc == null) { - return error; - } - - - if (!(double.parse(input) < 10000 && double.parse(input) > 0)) { - return error; - } - - return null; - } } diff --git a/lib/view/exercise_log_page.dart b/lib/view/exercise_log_page.dart index 836d50a..f54ea03 100644 --- a/lib/view/exercise_log_page.dart +++ b/lib/view/exercise_log_page.dart @@ -1,6 +1,10 @@ import 'dart:collection'; +import 'package:aitrainer_app/bloc/exercise_log/exercise_log_bloc.dart'; import 'package:aitrainer_app/widgets/app_bar.dart'; import 'package:aitrainer_app/widgets/bottom_nav.dart'; +import 'package:aitrainer_app/widgets/splash.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:intl/intl.dart'; import 'package:aitrainer_app/localization/app_language.dart'; import 'package:aitrainer_app/model/cache.dart'; @@ -22,36 +26,68 @@ class _ExerciseLogPage extends State with Trans, Common { @override Widget build(BuildContext context) { LinkedHashMap arguments = ModalRoute.of(context).settings.arguments; - final ExerciseRepository exerciseRepository = arguments['exerciseRepository']; + //final ExerciseRepository exerciseRepository = arguments['exerciseRepository']; final int customerId = arguments['customerId']; setContext(context); + return BlocProvider( + create: (context) => ExerciseLogBloc(exerciseRepository: ExerciseRepository()).. + add(ExerciseLogLoad()), + child: BlocConsumer( + listener: (context, state) { + if ( state is ExerciseLogLoading ) { + return LoadingDialog(); + } else if ( state is ExerciseLogError ) { + Scaffold.of(context).showSnackBar(SnackBar( + backgroundColor: Colors.orange, + content: + Text(state.message, style: TextStyle(color: Colors.white)))); + } + }, + builder: (context, state) { + final exerciseBloc = BlocProvider.of(context); + if ( state is ExerciseLogReady ) { + return getExerciseLog(customerId, exerciseBloc); + } else { + return getExerciseLog(customerId, exerciseBloc); + } + } + + ) + ); + + + } + + Widget getExerciseLog(int customerId, ExerciseLogBloc exerciseLogBloc) { return Scaffold( - appBar: AppBarNav(depth: 1), - body: Container( - padding: EdgeInsets.all(20), - decoration: BoxDecoration( - image: DecorationImage( - image: customerId == Cache().userLoggedIn.customerId ? AssetImage('asset/image/WT_light_background.png'): - AssetImage('asset/image/WT_menu_dark.png'), - fit: BoxFit.cover, - alignment: Alignment.center, - ), + appBar: AppBarNav(depth: 1), + body: Container( + padding: EdgeInsets.all(20), + decoration: BoxDecoration( + image: DecorationImage( + image: customerId == Cache().userLoggedIn.customerId ? AssetImage('asset/image/WT_light_background.png'): + AssetImage('asset/image/WT_menu_dark.png'), + fit: BoxFit.cover, + alignment: Alignment.center, ), - child: exerciseWidget(exerciseRepository, customerId), ), - bottomNavigationBar: BottomNavigator(bottomNavIndex: 1), + child: exerciseWidget(exerciseLogBloc, customerId), + ), + bottomNavigationBar: BottomNavigator(bottomNavIndex: 1), ); } - Widget exerciseWidget(ExerciseRepository exerciseRepository, int customerId) { + Widget exerciseWidget(ExerciseLogBloc exerciseLogBloc, int customerId) { return TreeView( startExpanded: false, - children: _getTreeChildren(exerciseRepository, customerId), + children: _getTreeChildren(exerciseLogBloc, customerId), ); } - List _getTreeChildren(ExerciseRepository exerciseRepository, int customerId) { + List _getTreeChildren(ExerciseLogBloc exerciseLogBloc, int customerId) { + final ExerciseRepository exerciseRepository = exerciseLogBloc.exerciseRepository; + if ( customerId == Cache().userLoggedIn.customerId ) { exerciseRepository.exerciseList = exerciseRepository.getExerciseList(); } else if ( Cache().getTrainee() != null && customerId == Cache().getTrainee().customerId ) { @@ -109,9 +145,9 @@ class _ExerciseLogPage extends State with Trans, Common { Container( margin: const EdgeInsets.only(left: 4.0), child: TreeViewChild( - startExpanded: true, + startExpanded: false, parent: TreeviewParentWidget(text: origDate), - children: _getChildList(listExercises, exerciseRepository), + children: _getChildList(listExercises, exerciseRepository, exerciseLogBloc), ) ) ); @@ -134,7 +170,7 @@ class _ExerciseLogPage extends State with Trans, Common { child: TreeViewChild( startExpanded: true, parent: TreeviewParentWidget(text: origDate), - children: _getChildList(listExercises, exerciseRepository), + children: _getChildList(listExercises, exerciseRepository, exerciseLogBloc), ) ) ); @@ -143,7 +179,7 @@ class _ExerciseLogPage extends State with Trans, Common { return listWidget; } - List _getChildList(List listExercises, ExerciseRepository exerciseRepository) { + List _getChildList(List listExercises, ExerciseRepository exerciseRepository, ExerciseLogBloc exerciseLogBloc) { List list = List(); bool isEnglish = AppLanguage().appLocal == Locale('en'); @@ -173,18 +209,28 @@ class _ExerciseLogPage extends State with Trans, Common { child: Row( mainAxisAlignment: MainAxisAlignment.start, children: [ + Icon(Icons.accessibility, color: Colors.black12), - SizedBox(width: 20), + SizedBox(width: 10,), Flexible( - child: - Text( - exerciseName, - textAlign: TextAlign.start, - style: TextStyle(fontSize: 12, color: Colors.black), - ), + fit: FlexFit.tight, + flex: 8, + child: Text( + exerciseName, + + style: TextStyle(fontSize: 12, color: Colors.black), + ), ), - SizedBox(width: 20), + Flexible(fit: FlexFit.tight, child: SizedBox(width: 10,)), Text(labelExercise , style: TextStyle(fontSize: 9, color: Colors.blueAccent.shade700),) , + Flexible(fit: FlexFit.tight, child: SizedBox(width: 10,)), + IconButton( + icon: Icon(Icons.delete, color: Colors.black12), + onPressed: () { + confirmationDialog(exerciseLogBloc, exercise); + }, + ), + ]), ) ), @@ -195,4 +241,55 @@ class _ExerciseLogPage extends State with Trans, Common { return list; } + void confirmationDialog( ExerciseLogBloc bloc, Exercise exercise ) { + + ExerciseType exerciseType = bloc.exerciseRepository.getExerciseTypeById(exercise.exerciseTypeId); + String exerciseName = AppLanguage().appLocal == Locale("en") + ? exerciseType.name + : exerciseType.nameTranslation; + + String strDate = AppLanguage().appLocal == Locale("en") + ? "on the " + DateFormat(DateFormat.YEAR_MONTH_DAY, AppLanguage().appLocal.toString()).format(exercise.dateAdd.toUtc()) + : DateFormat(DateFormat.YEAR_MONTH_DAY, AppLanguage().appLocal.toString()).format(exercise.dateAdd.toUtc()) + "-n"; + + showCupertinoDialog( + useRootNavigator: true, + context: context, + //barrierDismissible: false, + builder:(_) => CupertinoAlertDialog( + title: Text(t("Are you sure to delete this exercise?")), + content: Column( + + children: [ + Divider(), + Text(t("Exercise") + ": " + exerciseName, + style: (TextStyle(color: Colors.blue)),), + Text( + exercise.quantity.toStringAsFixed(0) + "x" + exercise.unitQuantity.toStringAsFixed(0) + " " + exerciseType.unitQuantityUnit, + style: (TextStyle(color: Colors.deepOrange)), + ), + Text( + strDate, + style: (TextStyle(color: Colors.deepOrange)), + ), + + ]), + actions: [ + FlatButton( + child: Text(t("No")), + onPressed: () => Navigator.pop(context), + ), + FlatButton( + child: Text(t("Yes")), + onPressed: () => { + print("delete exercise: " + exercise.toJson().toString()), + bloc.add(ExerciseLogDelete(exercise: exercise)), + Navigator.pop(context) + }, + ) + ], + ) + ); + } + } diff --git a/lib/view/exercise_new_page.dart b/lib/view/exercise_new_page.dart index 547e541..295110c 100644 --- a/lib/view/exercise_new_page.dart +++ b/lib/view/exercise_new_page.dart @@ -1,232 +1,214 @@ import 'dart:collection'; -import 'package:aitrainer_app/bloc/exercise_form_bloc.dart'; +import 'package:aitrainer_app/bloc/exercise_new/exercise_new_bloc.dart'; import 'package:aitrainer_app/bloc/menu/menu_bloc.dart'; import 'package:aitrainer_app/localization/app_language.dart'; -import 'package:aitrainer_app/localization/app_localization.dart'; import 'package:aitrainer_app/model/cache.dart'; import 'package:aitrainer_app/model/exercise_type.dart'; import 'package:aitrainer_app/repository/exercise_repository.dart'; +import 'package:aitrainer_app/util/trans.dart'; import 'package:aitrainer_app/widgets/app_bar.dart'; -import 'package:flutter/services.dart'; +import 'package:aitrainer_app/widgets/splash.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_form_bloc/flutter_form_bloc.dart'; +import 'package:aitrainer_app/library/numberpicker.dart'; class ExerciseNewPage extends StatefulWidget{ _ExerciseNewPageState createState() => _ExerciseNewPageState(); } -class _ExerciseNewPageState extends State { +class _ExerciseNewPageState extends State with Trans{ @override Widget build(BuildContext context) { final ExerciseType exerciseType = ModalRoute.of(context).settings.arguments; // ignore: close_sinks final menuBloc = BlocProvider.of(context); + setContext(context); return BlocProvider( - create: (context) => ExerciseFormBloc(exerciseRepository: ExerciseRepository(), menuBloc: menuBloc), - child: Builder(builder: (context) { - // ignore: close_sinks - final exerciseBloc = BlocProvider.of(context); - - - exerciseBloc.exerciseRepository.setExerciseType(exerciseType); - String exerciseName = AppLanguage().appLocal == Locale("en") ? - exerciseBloc.exerciseRepository.exerciseType.name : - exerciseBloc.exerciseRepository.exerciseType.nameTranslation; - - return Form( - autovalidate: true, - child: Scaffold( - resizeToAvoidBottomInset: true, - appBar: AppBarNav(depth: 1), - body: Container( - width: MediaQuery.of(context).size.width, - height: MediaQuery.of(context).size.height, - decoration: BoxDecoration( - image: DecorationImage( - image: AssetImage('asset/image/WT_light_background.png'), - fit: BoxFit.fill, - alignment: Alignment.center, - ), - ), - child: Container( - padding: const EdgeInsets.only (top: 25, left:25, right: 25), - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - Divider(color: Colors.transparent,), - Divider(color: Colors.transparent,), - Text(AppLocalizations.of(context).translate('Save Exercise'), - style: TextStyle(fontSize: 14, color: Colors.blueAccent)), - Text(exerciseName, - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.deepOrange), - overflow: TextOverflow.fade, - maxLines: 1, - softWrap: true, - ), - - - Divider(color: Colors.transparent,), - FlatButton( - child: Row( - - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Icon(Icons.description), - Text(AppLocalizations.of(context).translate("Description"), - style: TextStyle( - color: Colors.blueAccent, fontWeight: FontWeight.normal, fontSize: 14 )), - Icon(Icons.arrow_forward_ios), - ]), - textColor: Colors.blueAccent, - color: Colors.transparent, - onPressed: () => { - Navigator.of(context).pushNamed('exerciseTypeDescription', arguments: exerciseBloc.exerciseRepository), - }, - ), - Divider(color: Colors.transparent,), - columnQuantityUnit(exerciseBloc), - Divider(color: Colors.transparent,), - Divider(color: Colors.transparent,), - Divider(color: Colors.transparent,), - - columnQuantity(exerciseBloc), - Divider(), - - RaisedButton( - textColor: Colors.white, - color: Colors.deepOrange, - focusColor: Colors.white, - onPressed: () => - { - confirmationDialog( exerciseBloc ), - }, - child: Text(AppLocalizations.of(context).translate("Save"), style: TextStyle(fontSize: 16),) - ), - Divider(color: Colors.transparent,), - Divider(color: Colors.transparent,), - Divider(color: Colors.transparent,), - - ]), - ) - ) - ), - ), - ); - }) + create: (context) => ExerciseNewBloc(exerciseRepository: ExerciseRepository(), menuBloc: menuBloc, exerciseType: exerciseType).. + add(ExerciseNewLoad()), + child: BlocConsumer( + listener: (context, state) { + if ( state is ExerciseNewLoading ) { + return LoadingDialog(); + } else if ( state is ExerciseNewError ) { + Scaffold.of(context).showSnackBar(SnackBar( + backgroundColor: Colors.orange, + content: + Text(state.message, style: TextStyle(color: Colors.white)))); + } + }, + builder: (context, state) { + final exerciseBloc = BlocProvider.of(context); + if ( state is ExerciseNewReady ) { + return getExerciseWidget(exerciseBloc, exerciseType); + } else { + return getExerciseWidget(exerciseBloc, exerciseType); + } + }, + ) ); } - Column columnQuantityUnit( ExerciseFormBloc bloc ) { - Column column = Column(); - if ( bloc.exerciseRepository.exerciseType != null && - bloc.exerciseRepository.exerciseType.unitQuantity == "1") { - column = Column( - children: [ - TextFieldBlocBuilder( - textFieldBloc: bloc.unitQuantityField, - textAlign: TextAlign.center, - style: TextStyle(fontSize: 30, - color: Colors.lightBlue, - fontWeight: FontWeight.bold), - inputFormatters: [ - FilteringTextInputFormatter.allow(RegExp(r"[\d.]")) - ], - onChanged: (input) => - { - print("UnitQuantity value $input"), - bloc.exerciseRepository.setUnitQuantity( - double.parse(input)) - }, - decoration: InputDecoration( - fillColor: Colors.white, - filled: false, - hintStyle: TextStyle(fontSize: 16, color: Colors.black54, fontWeight: FontWeight.w100), - hintText: AppLocalizations.of(context).translate("The number of the exercise done with"), - labelStyle: TextStyle(fontSize: 16, color: Colors.lightBlue), - labelText: AppLocalizations.of(context).translate( - bloc.exerciseRepository.exerciseType.unitQuantityUnit), + Widget getExerciseWidget(ExerciseNewBloc exerciseBloc, ExerciseType exerciseType) { + + exerciseBloc.exerciseRepository.setExerciseType(exerciseType); + String exerciseName = AppLanguage().appLocal == Locale("en") ? + exerciseBloc.exerciseRepository.exerciseType.name : + exerciseBloc.exerciseRepository.exerciseType.nameTranslation; + + return Form( + autovalidate: true, + child: Scaffold( + resizeToAvoidBottomInset: true, + appBar: AppBarNav(depth: 1), + body: Container( + width: MediaQuery + .of(context) + .size + .width, + height: MediaQuery + .of(context) + .size + .height, + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage('asset/image/WT_light_background.png'), + fit: BoxFit.fill, + alignment: Alignment.center, ), ), + child: Container( + padding: const EdgeInsets.only (top: 25, left: 25, right: 25), + child: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + /*Divider(color: Colors.transparent,), + Divider(color: Colors.transparent,),*/ + Text(t('Save Exercise'), + style: TextStyle(fontSize: 14, color: Colors.blueAccent)), + Text(exerciseName, + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.deepOrange), + overflow: TextOverflow.fade, + maxLines: 1, + softWrap: true, + ), + + + //Divider(color: Colors.transparent,), + FlatButton( + child: Row( + + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Icon(Icons.description), + Text(t("Description"), + style: TextStyle( + color: Colors.blueAccent, fontWeight: FontWeight.normal, fontSize: 14)), + Icon(Icons.arrow_forward_ios), + ]), + textColor: Colors.blueAccent, + color: Colors.transparent, + onPressed: () => + { + Navigator.of(context).pushNamed( + 'exerciseTypeDescription', arguments: exerciseBloc.exerciseRepository), + }, + ), + //Divider(color: Colors.transparent,), + columnQuantityUnit(exerciseBloc), + Divider(color: Colors.transparent,), + + + columnQuantity(exerciseBloc), + Divider(), + Divider(color: Colors.transparent,), + Divider(color: Colors.transparent,), + Divider(color: Colors.transparent,), + RaisedButton( + textColor: Colors.white, + color: Colors.deepOrange, + focusColor: Colors.white, + onPressed: () => + { + confirmationDialog(exerciseBloc), + }, + child: Text(t("Save"), style: TextStyle(fontSize: 16),) + ), + ]), + ) + ) + ), + ), + ); + } + + Row columnQuantityUnit( ExerciseNewBloc bloc ) { + Row row = Row(); + if ( bloc.exerciseRepository.exerciseType != null && + bloc.exerciseRepository.exerciseType.unitQuantity == "1") { + row = Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + NumberPicker.horizontal( + highlightSelectedValue: true, + initialValue: bloc.unitQuantity.toInt(), + minValue: 0, + maxValue: 200, + step: 1, + onChanged: (value) => { + bloc.add(ExerciseNewQuantityUnitChange(quantity: value.toDouble())) + }, + listViewHeight: 80, + textStyle: TextStyle(fontSize: 24), + textStyleHighlighted: TextStyle(fontSize: 40, color: Colors.orange, fontWeight: FontWeight.bold), + //decoration: _decoration, + ), + new InkWell( - child: new Text(AppLocalizations.of(context).translate( - bloc.exerciseRepository.exerciseType.unitQuantityUnit), + child: new Text(t(bloc.exerciseRepository.exerciseType.unitQuantityUnit), style: TextStyle(fontSize: 16)), ), ]); } - return column; + return row; } - Column columnQuantity( ExerciseFormBloc bloc ) { - Column column = Column( + Row columnQuantity( ExerciseNewBloc bloc ) { + Row row = Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ - TextFieldBlocBuilder( - textFieldBloc: bloc.quantityField, - textAlign: TextAlign.center, - style: TextStyle(fontSize: 50, - color: Colors.deepOrange, - fontWeight: FontWeight.bold), - inputFormatters: [ - FilteringTextInputFormatter.allow (RegExp(r"[\d.]")) - ], - onChanged: (input) => - { - print ("Quantity value $input"), - bloc.exerciseRepository.setQuantity(double.parse(input)), - bloc.exerciseRepository.setUnit(bloc.exerciseRepository.exerciseType.unit) + NumberPicker.horizontal( + highlightSelectedValue: true, + initialValue: bloc.quantity.toInt(), + minValue: 0, + maxValue: 200, + step: 1, + onChanged: (value) => { + bloc.add(ExerciseNewQuantityChange(quantity: value.toDouble())) }, - decoration: InputDecoration( - fillColor: Colors.white, - filled: false, - hintStyle: TextStyle(fontSize: 16, color: Colors.black54, fontWeight: FontWeight.w100), - hintText: AppLocalizations.of(context).translate("The number of the exercise"), - labelStyle: TextStyle(fontSize: 16, color: Colors.deepOrange), - labelText: AppLocalizations.of(context).translate( - bloc.exerciseRepository.exerciseType.unit), - ), + listViewHeight: 80, + textStyle: TextStyle(fontSize: 24), + textStyleHighlighted: TextStyle(fontSize: 40, color: Colors.orange, fontWeight: FontWeight.bold), + //decoration: _decoration, ), + Text(t(bloc.exerciseRepository.exerciseType.unit), + style: TextStyle(fontSize: 16)), ]); - return column; + return row; } - String validateNumberInput( input ) { - String error = AppLocalizations.of(context).translate("Please type the right quantity 0-10000"); - dynamic rc = ( input != null && input.length > 0); - if ( ! rc ) { - return null; - } - - Pattern pattern = r'^\d+(?:\.\d+)?$'; - RegExp regex = new RegExp(pattern); - if (!regex.hasMatch(input)) { - return error; - } - - rc = double.tryParse(input); - if ( rc == null ) { - return error; - } - - - - if ( ! ( double.parse(input) < 10000 && double.parse(input) > 0) ) { - return error; - } - - return null; - } - - void confirmationDialog( ExerciseFormBloc bloc ) { + void confirmationDialog( ExerciseNewBloc bloc ) { LinkedHashMap args = LinkedHashMap(); print("exercise validated " + bloc.exerciseRepository.exercise.quantity.toString()); if ( bloc.exerciseRepository.exercise.quantity == null) { @@ -250,21 +232,21 @@ class _ExerciseNewPageState extends State { context: context, //barrierDismissible: false, builder:(_) => CupertinoAlertDialog( - title: Text(AppLocalizations.of(context).translate("Do you save this exercise with these parameters?")), + title: Text(t("Do you save this exercise with these parameters?")), content: Column( children: [ Divider(), - Text(AppLocalizations.of(context).translate("Exercise") + ": " + + Text(t("Exercise") + ": " + bloc.exerciseRepository.exerciseType.name, style: (TextStyle(color: Colors.blue)),), Text(quantity + " " + - AppLocalizations.of(context).translate(bloc.exerciseRepository.exerciseType.unit), + t(bloc.exerciseRepository.exerciseType.unit), style: (TextStyle(color: Colors.deepOrange)),), Text(bloc.exerciseRepository.exerciseType.unitQuantity == "1" ? - AppLocalizations.of(context).translate("with") + " " + t("with") + " " + unitQuantity + " " - + AppLocalizations.of(context).translate(bloc.exerciseRepository.exerciseType.unitQuantityUnit) : + + t(bloc.exerciseRepository.exerciseType.unitQuantityUnit) : "", style: (TextStyle(color: Colors.deepOrange)), ), @@ -272,11 +254,11 @@ class _ExerciseNewPageState extends State { ]), actions: [ FlatButton( - child: Text(AppLocalizations.of(context).translate("No")), + child: Text(t("No")), onPressed: () => Navigator.pop(context), ), FlatButton( - child: Text(AppLocalizations.of(context).translate("Yes")), + child: Text(t("Yes")), onPressed: () => { bloc.exerciseRepository.setCustomer(Cache().userLoggedIn), bloc.exerciseRepository.addExercise(), diff --git a/lib/view/exercise_plan_custom_detail_add_page.dart b/lib/view/exercise_plan_custom_detail_add_page.dart index f3e808e..012e2bd 100644 --- a/lib/view/exercise_plan_custom_detail_add_page.dart +++ b/lib/view/exercise_plan_custom_detail_add_page.dart @@ -1,12 +1,14 @@ +import 'dart:collection'; + import 'package:aitrainer_app/bloc/exercise_plan/exercise_plan_bloc.dart'; -import 'package:aitrainer_app/bloc/exercise_plan_custom_form.dart'; +import 'package:aitrainer_app/bloc/exercise_plan_custom_add/exercise_plan_custom_add_bloc.dart'; +import 'package:aitrainer_app/library/numberpicker.dart'; import 'package:aitrainer_app/localization/app_language.dart'; -import 'package:aitrainer_app/localization/app_localization.dart'; -import 'package:aitrainer_app/model/exercise_plan_detail.dart'; +import 'package:aitrainer_app/model/workout_menu_tree.dart'; import 'package:aitrainer_app/repository/exercise_plan_repository.dart'; import 'package:aitrainer_app/util/trans.dart'; import 'package:aitrainer_app/widgets/app_bar.dart'; -import 'package:flutter/services.dart'; +import 'package:aitrainer_app/widgets/splash.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -20,130 +22,229 @@ class ExercisePlanDetailAddPage extends StatefulWidget { class _ExercisePlanDetailAddPage extends State with Trans { @override Widget build(BuildContext context) { + LinkedHashMap args = ModalRoute.of(context).settings.arguments; // ignore: close_sinks - final ExercisePlanBloc planBloc = ModalRoute.of(context).settings.arguments; + final ExercisePlanBloc planBloc = args['bloc']; + final WorkoutMenuTree workoutMenuTree = args['workoutTreeItem']; final ExercisePlanRepository exercisePlanRepository = planBloc.exercisePlanRepository; setContext(context); return BlocProvider( create: (context) => - ExercisePlanCustomerFormBloc(exercisePlanRepository: exercisePlanRepository, planBloc: planBloc), - child: Builder(builder: (context) { - // ignore: close_sinks - final bloc = BlocProvider.of(context); + ExercisePlanCustomAddBloc(exercisePlanRepository: exercisePlanRepository, planBloc: planBloc, workoutMenuTree: workoutMenuTree) + ..add(ExercisePlanCustomAddLoad()), + child: BlocConsumer( + listener: (context, state) { + if (state is ExercisePlanCustomAddLoading) { + return LoadingDialog(); + } else if (state is ExercisePlanCustomAddError) { + Scaffold.of(context).showSnackBar(SnackBar( + backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white)))); + } + }, + builder: (context, state) { + // ignore: close_sinks + final bloc = BlocProvider.of(context); + return getForm(bloc, workoutMenuTree); + }, + )); + } - String exerciseName = ""; - if (bloc != null) { - exerciseName = AppLanguage().appLocal == Locale("en") - ? bloc.exercisePlanRepository.getActualPlanDetail().exerciseType.name - : bloc.exercisePlanRepository.getActualPlanDetail().exerciseType.nameTranslation; - } - - return Form( - autovalidate: true, - child: Scaffold( - resizeToAvoidBottomInset: true, - appBar: AppBarNav(depth: 1), - body: Container( - width: MediaQuery.of(context).size.width, - height: MediaQuery.of(context).size.height, - decoration: BoxDecoration( - image: DecorationImage( - image: AssetImage('asset/image/WT_light_background.png'), - fit: BoxFit.fill, - alignment: Alignment.center, - ), - ), - child: Container( - padding: const EdgeInsets.only(top: 25, left: 25, right: 25), - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: Column(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ - Text(AppLocalizations.of(context).translate('Save The Exercise To The Exercise Plan'), - style: TextStyle(fontSize: 14, color: Colors.blueAccent)), - Text( - exerciseName, - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.deepOrange), - overflow: TextOverflow.fade, - maxLines: 1, - softWrap: true, - ), - TextFieldBlocBuilder( - textFieldBloc: bloc.serieField, - textAlign: TextAlign.center, - style: TextStyle(fontSize: 30, color: Colors.lightBlue, fontWeight: FontWeight.bold), - inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r"[\d.]"))], - decoration: InputDecoration( - fillColor: Colors.white, - filled: false, - hintStyle: TextStyle(fontSize: 16, color: Colors.black54, fontWeight: FontWeight.w100), - hintText: AppLocalizations.of(context).translate("The number of the serie done with"), - labelStyle: TextStyle(fontSize: 16, color: Colors.lightBlue), - labelText: AppLocalizations.of(context).translate("Serie"), - ), - ), - TextFieldBlocBuilder( - textFieldBloc: bloc.quantityField, - textAlign: TextAlign.center, - style: TextStyle(fontSize: 30, color: Colors.lightBlue, fontWeight: FontWeight.bold), - inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r"[\d.]"))], - decoration: InputDecoration( - fillColor: Colors.white, - filled: false, - hintStyle: TextStyle(fontSize: 16, color: Colors.black54, fontWeight: FontWeight.w100), - hintText: - AppLocalizations.of(context).translate("The number of the repeats of one serie"), - labelStyle: TextStyle(fontSize: 16, color: Colors.lightBlue), - labelText: AppLocalizations.of(context).translate("Repeats"), - ), - ), - TextFieldBlocBuilder( - textFieldBloc: bloc.weightField, - textAlign: TextAlign.center, - style: TextStyle(fontSize: 30, color: Colors.lightBlue, fontWeight: FontWeight.bold), - inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r"[\d.]"))], - decoration: InputDecoration( - fillColor: Colors.white, - filled: false, - hintStyle: TextStyle(fontSize: 16, color: Colors.black54, fontWeight: FontWeight.w100), - hintText: AppLocalizations.of(context).translate("The weight"), - labelStyle: TextStyle(fontSize: 16, color: Colors.lightBlue), - labelText: AppLocalizations.of(context).translate("Weight"), - ), - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - RaisedButton( - textColor: Colors.white, - color: Colors.red.shade300, - focusColor: Colors.white, - onPressed: () => { - print("Remove " + bloc.exercisePlanRepository.getActualPlanDetail().exerciseType.name), - bloc.exercisePlanRepository.getActualPlanDetail().change = ExercisePlanDetailChange.delete, - planBloc.add(ExercisePlanRemoveExercise( - exercisePlanDetail: bloc.exercisePlanRepository.getActualPlanDetail() )), - Navigator.of(context).pop(), - }, - child: Text(t( - "Delete")), //Text(AppLocalizations.of(context).translate("Delete"), style: TextStyle(fontSize: 16),) - ), - RaisedButton( - textColor: Colors.white, - color: Colors.blueAccent, - focusColor: Colors.white, - onPressed: () => { - bloc.submit(), - Navigator.of(context).pop(), - }, - child: Text(t("Save"), style: TextStyle(fontSize: 16), - )), - ], - ), - ]), - ))), + Widget getForm(ExercisePlanCustomAddBloc bloc, WorkoutMenuTree workoutMenuTree) { + String exerciseName = ""; + if (bloc != null) { + exerciseName = AppLanguage().appLocal == Locale("en") + ? bloc.exercisePlanRepository.getActualPlanDetail().exerciseType.name + : bloc.exercisePlanRepository.getActualPlanDetail().exerciseType.nameTranslation; + } + return Form( + autovalidate: true, + child: Scaffold( + resizeToAvoidBottomInset: true, + appBar: AppBarNav(depth: 1), + body: Container( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height, + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage('asset/image/WT_light_background.png'), + fit: BoxFit.fill, + alignment: Alignment.center, + ), ), - ); - })); + child: Container( + padding: const EdgeInsets.only(top: 25, left: 25, right: 25), + child: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: Column(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ + Text(t('Save The Exercise To The Exercise Plan'), + style: TextStyle(fontSize: 14, color: Colors.blueAccent)), + Text( + exerciseName, + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.deepOrange), + overflow: TextOverflow.fade, + maxLines: 1, + softWrap: true, + ), + Divider(color: Colors.transparent,height: 30,), + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Flexible( + fit: FlexFit.tight, + flex: 8, + child: + Text(t("Serie")), + ), + NumberPicker.horizontal( + highlightSelectedValue: true, + initialValue: bloc.serie.toInt(), + minValue: 0, + maxValue: 200, + step: 1, + onChanged: (value) => { + bloc.add(ExercisePlanCustomAddChangeSerie(quantity: value.toDouble())) + }, + listViewHeight: 80, + textStyle: TextStyle(fontSize: 24), + textStyleHighlighted: TextStyle(fontSize: 40, color: Colors.orange, fontWeight: FontWeight.bold), + //decoration: _decoration, + ), + + ] + ), + Divider(), + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Flexible( + fit: FlexFit.tight, + flex: 8, + child: + Text(t("Weight") + " (" + bloc.exercisePlanRepository.getActualPlanDetail().exerciseType.unitQuantityUnit + ")"), + ), + NumberPicker.horizontal( + highlightSelectedValue: true, + initialValue: bloc.quantityUnit.toInt(), + minValue: 0, + maxValue: 200, + step: 1, + onChanged: (value) => { + bloc.add(ExercisePlanCustomAddChangeQuantityUnit(quantity: value.toDouble())) + }, + listViewHeight: 80, + textStyle: TextStyle(fontSize: 24), + textStyleHighlighted: TextStyle(fontSize: 40, color: Colors.orange, fontWeight: FontWeight.bold), + //decoration: _decoration, + ), + ]), + Divider(), + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Flexible( + fit: FlexFit.tight, + flex: 8, + child: + Text(t("Repeats")), + ), + NumberPicker.horizontal( + highlightSelectedValue: true, + initialValue: bloc.quantity.toInt(), + minValue: 0, + maxValue: 200, + step: 1, + onChanged: (value) => { + bloc.add(ExercisePlanCustomAddChangeQuantity(quantity: value.toDouble())) + }, + listViewHeight: 80, + textStyle: TextStyle(fontSize: 24), + textStyleHighlighted: TextStyle(fontSize: 40, color: Colors.orange, fontWeight: FontWeight.bold), + //decoration: _decoration, + ), + ]), + Divider(), + /*TextFieldBlocBuilder( + textFieldBloc: bloc.serieField, + textAlign: TextAlign.center, + style: TextStyle(fontSize: 30, color: Colors.lightBlue, fontWeight: FontWeight.bold), + inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r"[\d.]"))], + decoration: InputDecoration( + fillColor: Colors.white, + filled: false, + hintStyle: TextStyle(fontSize: 16, color: Colors.black54, fontWeight: FontWeight.w100), + hintText: AppLocalizations.of(context).translate("The number of the serie done with"), + labelStyle: TextStyle(fontSize: 16, color: Colors.lightBlue), + labelText: AppLocalizations.of(context).translate("Serie"), + ), + ),*/ + /*TextFieldBlocBuilder( + textFieldBloc: bloc.quantityField, + textAlign: TextAlign.center, + style: TextStyle(fontSize: 30, color: Colors.lightBlue, fontWeight: FontWeight.bold), + inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r"[\d.]"))], + decoration: InputDecoration( + fillColor: Colors.white, + filled: false, + hintStyle: TextStyle(fontSize: 16, color: Colors.black54, fontWeight: FontWeight.w100), + hintText: + AppLocalizations.of(context).translate("The number of the repeats of one serie"), + labelStyle: TextStyle(fontSize: 16, color: Colors.lightBlue), + labelText: AppLocalizations.of(context).translate("Repeats"), + ), + ),*/ + /*TextFieldBlocBuilder( + textFieldBloc: bloc.weightField, + textAlign: TextAlign.center, + style: TextStyle(fontSize: 30, color: Colors.lightBlue, fontWeight: FontWeight.bold), + inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r"[\d.]"))], + decoration: InputDecoration( + fillColor: Colors.white, + filled: false, + hintStyle: TextStyle(fontSize: 16, color: Colors.black54, fontWeight: FontWeight.w100), + hintText: AppLocalizations.of(context).translate("The weight"), + labelStyle: TextStyle(fontSize: 16, color: Colors.lightBlue), + labelText: AppLocalizations.of(context).translate("Weight"), + ), + ),*/ + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + RaisedButton( + textColor: Colors.white, + color: Colors.red.shade300, + focusColor: Colors.white, + onPressed: () => { + bloc.add(ExercisePlanCustomAddRemove()), + Navigator.of(context).pop(), + /*print("Remove " + bloc.exercisePlanRepository.getActualPlanDetail().exerciseType.name), + bloc.exercisePlanRepository.getActualPlanDetail().change = ExercisePlanDetailChange.delete, + planBloc.add(ExercisePlanRemoveExercise( + exercisePlanDetail: bloc.exercisePlanRepository.getActualPlanDetail() )), + Navigator.of(context).pop(),*/ + }, + child: Text(t( + "Delete")), //Text(AppLocalizations.of(context).translate("Delete"), style: TextStyle(fontSize: 16),) + ), + RaisedButton( + textColor: Colors.white, + color: Colors.blueAccent, + focusColor: Colors.white, + onPressed: () => { + bloc.add(ExercisePlanCustomAddSubmit()), + Navigator.of(context).pop(), + /* bloc.submit(), + Navigator.of(context).pop(),*/ + }, + child: Text( + t("Save"), + style: TextStyle(fontSize: 16), + )), + ], + ), + ]), + ))), + ), + ); } } diff --git a/lib/view/exercise_plan_custom_page.dart b/lib/view/exercise_plan_custom_page.dart index 2a3d050..2af863b 100644 --- a/lib/view/exercise_plan_custom_page.dart +++ b/lib/view/exercise_plan_custom_page.dart @@ -50,7 +50,7 @@ class _ExercisePlanCustomPage extends State with Trans { padding: EdgeInsets.all(20), decoration: BoxDecoration( image: DecorationImage( - image: customerId == Cache().userLoggedIn.customerId ? AssetImage('asset/image/WT_light_background.png'): + image: customerId == Cache().userLoggedIn.customerId ? AssetImage('asset/image/WT_menu_dark.png'): AssetImage('asset/image/WT_menu_dark.png'), fit: BoxFit.cover, alignment: Alignment.center, @@ -157,14 +157,14 @@ class _ExercisePlanCustomPage extends State with Trans { mainAxisAlignment: MainAxisAlignment.start, children: [ IconButton( - icon: element.selected ? Icon(Icons.check, color: Colors.greenAccent.shade700,) : Icon(Icons.add, color: Colors.blue.shade400,), - onPressed: () => { - bloc.add(ExercisePlanUpdateUI(workoutTree: element)), - Navigator.of(context).pushNamed("exercisePlanDetailAdd", arguments: bloc), - }, + icon: element.selected ? Icon(Icons.check, color: Colors.greenAccent.shade700,) + : Icon(Icons.add, color: Colors.blue.shade400,), + onPressed: () => clickAddDetail(bloc, element), ), - SizedBox(width: 20), + SizedBox(width: 10), Flexible( + fit: FlexFit.tight, + flex: 8, child: InkWell( child: @@ -173,10 +173,7 @@ class _ExercisePlanCustomPage extends State with Trans { textAlign: TextAlign.start, style: TextStyle(fontSize: 12, color: Colors.black), ), - onTap: () => { - bloc.add(ExercisePlanUpdateUI(workoutTree: element)), - Navigator.of(context).pushNamed("exercisePlanDetailAdd", arguments: bloc), - }, + onTap: () => clickAddDetail(bloc, element), ), ), InkWell( @@ -186,15 +183,12 @@ class _ExercisePlanCustomPage extends State with Trans { Text(bloc.exercisePlanRepository.exercisePlanDetails[element.exerciseTypeId].repeats.toString() + " x " + bloc.exercisePlanRepository.exercisePlanDetails[element.exerciseTypeId].weightEquation + " " + element.exerciseType.unitQuantityUnit, style: TextStyle(fontSize: 9, color: Colors.green),), - onTap: () => { - bloc.add(ExercisePlanUpdateUI(workoutTree: element)), - Navigator.of(context).pushNamed("exercisePlanDetailAdd", arguments: bloc), - }, + onTap: () => clickAddDetail(bloc, element), ), IconButton( padding: EdgeInsets.all(0), - icon: Icon(Icons.description, color: Colors.black12,), + icon: Icon(Icons.info, color: Colors.black12,), onPressed: () { }, @@ -211,4 +205,11 @@ class _ExercisePlanCustomPage extends State with Trans { }); return list; } + + void clickAddDetail(ExercisePlanBloc bloc, WorkoutMenuTree workoutMenuTree) { + final LinkedHashMap args = LinkedHashMap(); + args['bloc'] = bloc; + args['workoutTreeItem'] = workoutMenuTree; + Navigator.of(context).pushNamed("exercisePlanDetailAdd", arguments: args); + } } diff --git a/lib/view/menu_page.dart b/lib/view/menu_page.dart index 9ab4927..116b7ea 100644 --- a/lib/view/menu_page.dart +++ b/lib/view/menu_page.dart @@ -27,6 +27,7 @@ class _MenuPage extends State { @override Widget build(BuildContext context) { menuBloc = BlocProvider.of(context); + menuBloc.parent = widget.parent; return Scaffold( appBar: AppBarNav(isMenu: true,), body: Container( diff --git a/lib/view/mydevelopment_muscle_page.dart b/lib/view/mydevelopment_muscle_page.dart index aa9c4ac..8c40728 100644 --- a/lib/view/mydevelopment_muscle_page.dart +++ b/lib/view/mydevelopment_muscle_page.dart @@ -268,7 +268,7 @@ class _MyDevelopmentMuscleState extends State with Comm show: true, bottomTitles: SideTitles( showTitles: true, - textStyle: TextStyle(fontSize: 8, color: Colors.blueGrey), + getTextStyles: (_) => TextStyle(fontSize: 8, color: Colors.blueGrey), getTitles: (double value) { var date = new DateTime.fromMillisecondsSinceEpoch(value.toInt()); //String strDate = DateFormat('MM.dd.', AppLanguage().appLocal.toString()).format(date); @@ -278,7 +278,7 @@ class _MyDevelopmentMuscleState extends State with Comm ), leftTitles: SideTitles( showTitles: true, - textStyle: TextStyle(fontSize: 8, color: Colors.blueGrey), + getTextStyles: (_) => TextStyle(fontSize: 8, color: Colors.blueGrey), interval: bloc.listChartData[element.exerciseTypeId] == null ? 100 : bloc.listChartData[element.exerciseTypeId].interval, diff --git a/lib/view/mydevelopment_page.dart b/lib/view/mydevelopment_page.dart index b801b10..68c776d 100644 --- a/lib/view/mydevelopment_page.dart +++ b/lib/view/mydevelopment_page.dart @@ -26,10 +26,10 @@ class _MyDevelopmentPage extends State with Trans { return Scaffold( appBar: AppBarNav(depth: 0), body: Container( - padding: EdgeInsets.all(20), + padding: EdgeInsets.all(10), decoration: BoxDecoration( image: DecorationImage( - image: AssetImage('asset/image/WT_light_background.png'), + image: AssetImage('asset/image/WT_menu_dark.png'), fit: BoxFit.cover, alignment: Alignment.center, ), @@ -44,61 +44,22 @@ class _MyDevelopmentPage extends State with Trans { ImageButton( textAlignment: Alignment.topCenter, text: t("My Exercise Logs"), - style: TextStyle(fontSize: 20, color: Colors.orange, fontWeight: FontWeight.bold, backgroundColor: Colors.black54.withOpacity(0.4)), - image: "asset/image/exercise_log.jpg", - top: 40, + style: TextStyle(fontSize: 16, color: Colors.orange, fontWeight: FontWeight.bold, backgroundColor: Colors.black54.withOpacity(0.4)), + image: "asset/image/edzesnaplom400400.jpg", + top: 150, + left: 15, onTap:() => this.callBackExerciseLog(exerciseRepository, customerRepository), isLocked: false, ), - /*FlatButton( - padding: EdgeInsets.all(0), - textColor: Colors.white, - color: Colors.black12, - focusColor: Colors.blueAccent, - onPressed: () => - { - args['exerciseRepository'] = exerciseRepository, - args['customerRepository'] = customerRepository, - args['customerId'] = Cache().userLoggedIn.customerId, - Navigator.of(context).pushNamed('exerciseLogPage', - arguments: args) - }, - child: Text(t("My Exercise Logs"), - style: TextStyle(fontSize: 18),) - ),*/ - /*Stack( - fit: StackFit.passthrough, - overflow: Overflow.clip, - alignment: Alignment.topLeft, - children: [ - Image.asset('asset/image/lock.png', - height: 40, - width: 40, - ), - FlatButton( - padding: EdgeInsets.all(20), - textColor: Colors.white, - color: Colors.black12, - focusColor: Colors.blueAccent, - onPressed: () => - { - args['customerId'] = Cache().userLoggedIn.customerId, - Navigator.of(context).pushNamed('mydevelopmentBodyPage', - arguments: args) - }, - child: Text(t("My Whole Body Development"), - style: TextStyle(fontSize: 18),) - ), - ], - ),*/ ImageButton( textAlignment: Alignment.topLeft, text: t("My Whole Body Development"), - style: TextStyle(fontSize: 20, color: Colors.orange, fontWeight: FontWeight.bold, + style: TextStyle(fontSize: 16, color: Colors.orange, fontWeight: FontWeight.bold, backgroundColor: Colors.black54.withOpacity(0.4)), - image: "asset/menu/3.1.BMI.png", - top: 50, + image: "asset/image/testemfejl400x400.jpg", + top: 150, + left: 15, onTap:() => { args['customerId'] = Cache().userLoggedIn.customerId, Navigator.of(context).pushNamed('mydevelopmentBodyPage', @@ -109,82 +70,39 @@ class _MyDevelopmentPage extends State with Trans { ImageButton( textAlignment: Alignment.topLeft, text: t("Development Of Muscles"), - style: TextStyle(fontSize: 20, color: Colors.orange, fontWeight: FontWeight.bold, + style: TextStyle(fontSize: 16, color: Colors.orange, fontWeight: FontWeight.bold, backgroundColor: Colors.black54.withOpacity(0.4)), - image: "asset/image/development_muscles.jpg", - top: 50, + image: "asset/image/izomcsop400400.jpg", + top: 120, + left: 10, onTap:() => { Navigator.of(context).pushNamed('mydevelopmentMusclePage', arguments: args) }, isLocked: true, ), - /*Stack( - fit: StackFit.passthrough, - overflow: Overflow.clip, - children: [ - *//*Image.asset('asset/image/lock.png', - height: 40, - width: 40, - ),*//* - FlatButton( - padding: EdgeInsets.all(20), - textColor: Colors.white, - color: Colors.black12, - focusColor: Colors.blueAccent, - onPressed: () => - { - Navigator.of(context).pushNamed('mydevelopmentMusclePage', - arguments: args) - }, - child: Text(t("Development Of Muscles"), - style: TextStyle(fontSize: 18),) - ), - ] - ),*/ ImageButton( textAlignment: Alignment.topLeft, text: t("Predictions"), - style: TextStyle(fontSize: 20, color: Colors.orange, fontWeight: FontWeight.bold, + style: TextStyle(fontSize: 16, color: Colors.orange, fontWeight: FontWeight.bold, backgroundColor: Colors.black54.withOpacity(0.4)), image: "asset/menu/2.2.1.1RM.png", - top: 50, + top: 150, onTap:() => { }, isLocked: true, ), - /*Stack( - fit: StackFit.passthrough, - overflow: Overflow.clip, - children: [ - Image.asset('asset/image/lock.png', - height: 40, - width: 40, - ), - FlatButton( - padding: EdgeInsets.all(20), - textColor: Colors.white, - color: Colors.black12, - focusColor: Colors.blueAccent, - onPressed: () => - { - }, - child: Text(t("Predictions"), - style: TextStyle(fontSize: 18),) - ), - ] - ),*/ hiddenWidget(customerRepository, exerciseRepository), ] ), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, - mainAxisSpacing: 20.0, - crossAxisSpacing: 20.0, - childAspectRatio: 1.2, + mainAxisSpacing: 15.0, + crossAxisSpacing: 15.0, + childAspectRatio: 1.0, ), ) ] diff --git a/lib/view/myexcercise_plan_page.dart b/lib/view/myexcercise_plan_page.dart index e527193..3d51620 100644 --- a/lib/view/myexcercise_plan_page.dart +++ b/lib/view/myexcercise_plan_page.dart @@ -4,6 +4,7 @@ import 'package:aitrainer_app/repository/exercise_repository.dart'; import 'package:aitrainer_app/util/trans.dart'; import 'package:aitrainer_app/widgets/app_bar.dart'; import 'package:aitrainer_app/widgets/bottom_nav.dart'; +import 'package:aitrainer_app/widgets/image_button.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -25,7 +26,7 @@ class _MyExercisePlanPage extends State with Trans { padding: EdgeInsets.all(20), decoration: BoxDecoration( image: DecorationImage( - image: AssetImage('asset/image/WT_light_background.png'), + image: AssetImage('asset/image/WT_menu_dark.png'), fit: BoxFit.cover, alignment: Alignment.center, ), @@ -37,97 +38,82 @@ class _MyExercisePlanPage extends State with Trans { SliverGrid( delegate: SliverChildListDelegate( [ - FlatButton( - padding: EdgeInsets.all(10), - textColor: Colors.white, - color: Colors.black12, - focusColor: Colors.blueAccent, - onPressed: () => - { + ImageButton( + textAlignment: Alignment.topLeft, + text: t("Execute My Selected Training Plan"), + style: TextStyle(fontSize: 14, color: Colors.orange, fontWeight: FontWeight.bold, + backgroundColor: Colors.black54.withOpacity(0.4)), + image: "asset/image/exercise_plan_execute.jpg", + top: 150, + left: 15, + onTap:() => { args['customerId'] = Cache().userLoggedIn.customerId, - Navigator.of(context).pushNamed('exerciseByPlanPage', + Navigator.of(context).pushNamed('exerciseExecutePlanPage', arguments: args) }, - child: Text(t("Execute My Selected Training Plan"), - style: TextStyle(fontSize: 18),) + isLocked: false, ), - FlatButton( - padding: EdgeInsets.all(0), - textColor: Colors.white, - color: Colors.black12, - focusColor: Colors.blueAccent, - onPressed: () => - { + ImageButton( + textAlignment: Alignment.topLeft, + text: t("Edit My Custom Plan"), + style: TextStyle(fontSize: 14, color: Colors.orange, fontWeight: FontWeight.bold, + backgroundColor: Colors.black54.withOpacity(0.4)), + image: "asset/image/exercise_plan_custom.jpg", + top: 150, + left: 15, + onTap:() => { args['exerciseRepository'] = exerciseRepository, args['customerId'] = Cache().userLoggedIn.customerId, Navigator.of(context).pushNamed('exercisePlanCustomPage', arguments: args) }, - child: Text(t("Edit My Custom Plan"), - style: TextStyle(fontSize: 18),) + isLocked: false, ), - FlatButton( - padding: EdgeInsets.all(20), - textColor: Colors.white, - color: Colors.black12, - focusColor: Colors.blueAccent, - onPressed: () => - { + + ImageButton( + textAlignment: Alignment.topLeft, + text: t("Suggested Training Plan"), + style: TextStyle(fontSize: 14, color: Colors.orange, fontWeight: FontWeight.bold, + backgroundColor: Colors.black54.withOpacity(0.4)), + image: "asset/image/exercise_plan_suggested.jpg", + top: 150, + left: 10, + onTap:() => { }, - child: Text(t("Suggested Training Plan"), - style: TextStyle(fontSize: 18),) - ), - Stack( - fit: StackFit.passthrough, - overflow: Overflow.clip, - alignment: Alignment.topLeft, - children: [ - Image.asset('asset/image/lock.png', - height: 40, - width: 40, - ), - FlatButton( - padding: EdgeInsets.all(20), - textColor: Colors.white, - color: Colors.black12, - focusColor: Colors.blueAccent, - onPressed: () => - { - - }, - child: Text(t("My Special Plan"), - style: TextStyle(fontSize: 18),) - ), - - ], + isLocked: true, ), - Stack( - fit: StackFit.passthrough, - overflow: Overflow.clip, - children: [ - Image.asset('asset/image/lock.png', - height: 40, - width: 40, - ), - FlatButton( - padding: EdgeInsets.all(20), - textColor: Colors.white, - color: Colors.black12, - focusColor: Colors.blueAccent, - onPressed: () => - { + ImageButton( + textAlignment: Alignment.topLeft, + text: t("My Special Plan"), + style: TextStyle(fontSize: 16, color: Colors.orange, fontWeight: FontWeight.bold, + backgroundColor: Colors.black54.withOpacity(0.4)), + image: "asset/image/exercise_plan_special.jpg", + top: 150, + left: 10, + onTap:() => { - }, - child: Text(t("My Arnold's Plan"), - style: TextStyle(fontSize: 18),) - ), - - ] + }, + isLocked: true, ), + ImageButton( + textAlignment: Alignment.topLeft, + text: t("My Arnold's Plan"), + style: TextStyle(fontSize: 14, color: Colors.orange, fontWeight: FontWeight.bold, + backgroundColor: Colors.black54.withOpacity(0.4)), + image: "asset/image/exercise_plan_stars.jpg", + top: 120, + left: 10, + onTap:() => { + + }, + isLocked: true, + ), + + hiddenPlanWidget(exerciseRepository), hiddenTrainingWidget(), @@ -136,9 +122,9 @@ class _MyExercisePlanPage extends State with Trans { ), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, - mainAxisSpacing: 20.0, - crossAxisSpacing: 20.0, - childAspectRatio: 1.2, + mainAxisSpacing: 15.0, + crossAxisSpacing: 15.0, + childAspectRatio: 1.0, ), ) ] @@ -182,7 +168,7 @@ class _MyExercisePlanPage extends State with Trans { onPressed: () => { args['customerId'] = Cache().getTrainee().customerId, - Navigator.of(context).pushNamed('exerciseByPlanPage', + Navigator.of(context).pushNamed('exerciseExecutePlanPage', arguments: args) }, child: Text(t("Execute My Trainee's Training Plan"), diff --git a/lib/view/settings.dart b/lib/view/settings.dart index 61d5170..57cdc97 100644 --- a/lib/view/settings.dart +++ b/lib/view/settings.dart @@ -108,13 +108,6 @@ class SettingsPage extends StatelessWidget{ ) ), - ListTile( - leading: Icon(Icons.get_app), - title: RaisedButton( - child: Text("Check lang", style: TextStyle(fontSize: 12),), - onPressed: () => settingsBloc.add(SettingsGetLanguage()), - ) - ) ] ); } diff --git a/lib/widgets/image_button.dart b/lib/widgets/image_button.dart index 219e691..f4bc930 100644 --- a/lib/widgets/image_button.dart +++ b/lib/widgets/image_button.dart @@ -8,6 +8,7 @@ class ImageButton extends StatelessWidget { final TextStyle style; final String image; final double top; + final double left; final double height; final double width; final bool isShape; @@ -21,6 +22,7 @@ class ImageButton extends StatelessWidget { this.style, this.image, this.top, + this.left, this.height, this.width, this.bloc, @@ -48,20 +50,24 @@ class ImageButton extends StatelessWidget { Stack( alignment: Alignment.topLeft, children: [ - this.isLocked? + Positioned( + top: 50, + left: 50, + child: this.isLocked? Image.asset( 'asset/image/lock.png', - height: 40, - width: 40, + height: 60, + width: 60, ) : Container(), - ]), + )] + ), Positioned( top: top, - left: 10, + left: left, child: Container( height: 100, - width: 150, + width: 180, child: InkWell( onTap: onTap ?? onTap, child: Text( diff --git a/pubspec.lock b/pubspec.lock deleted file mode 100644 index 1530ecf..0000000 --- a/pubspec.lock +++ /dev/null @@ -1,930 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - _fe_analyzer_shared: - dependency: transitive - description: - name: _fe_analyzer_shared - url: "https://pub.dartlang.org" - source: hosted - version: "7.0.0" - analyzer: - dependency: transitive - description: - name: analyzer - url: "https://pub.dartlang.org" - source: hosted - version: "0.39.17" - archive: - dependency: transitive - description: - name: archive - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.13" - args: - dependency: transitive - description: - name: args - url: "https://pub.dartlang.org" - source: hosted - version: "1.6.0" - async: - dependency: transitive - description: - name: async - url: "https://pub.dartlang.org" - source: hosted - version: "2.5.0-nullsafety" - bloc: - dependency: transitive - description: - name: bloc - url: "https://pub.dartlang.org" - source: hosted - version: "6.0.3" - bloc_test: - dependency: "direct dev" - description: - name: bloc_test - url: "https://pub.dartlang.org" - source: hosted - version: "7.0.4" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0-nullsafety" - build: - dependency: transitive - description: - name: build - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0" - build_config: - dependency: transitive - description: - name: build_config - url: "https://pub.dartlang.org" - source: hosted - version: "0.4.2" - build_daemon: - dependency: transitive - description: - name: build_daemon - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.4" - build_resolvers: - dependency: transitive - description: - name: build_resolvers - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.11" - build_runner: - dependency: "direct dev" - description: - name: build_runner - url: "https://pub.dartlang.org" - source: hosted - version: "1.10.0" - build_runner_core: - dependency: transitive - description: - name: build_runner_core - url: "https://pub.dartlang.org" - source: hosted - version: "5.2.0" - built_collection: - dependency: transitive - description: - name: built_collection - url: "https://pub.dartlang.org" - source: hosted - version: "4.3.2" - built_value: - dependency: transitive - description: - name: built_value - url: "https://pub.dartlang.org" - source: hosted - version: "7.1.0" - characters: - dependency: transitive - description: - name: characters - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0-nullsafety.2" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0-nullsafety" - checked_yaml: - dependency: transitive - description: - name: checked_yaml - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.2" - cli_util: - dependency: transitive - description: - name: cli_util - url: "https://pub.dartlang.org" - source: hosted - version: "0.2.0" - clock: - dependency: transitive - description: - name: clock - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0-nullsafety" - code_builder: - dependency: transitive - description: - name: code_builder - url: "https://pub.dartlang.org" - source: hosted - version: "3.4.1" - collection: - dependency: transitive - description: - name: collection - url: "https://pub.dartlang.org" - source: hosted - version: "1.15.0-nullsafety.2" - convert: - dependency: transitive - description: - name: convert - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.1" - coverage: - dependency: transitive - description: - name: coverage - url: "https://pub.dartlang.org" - source: hosted - version: "0.14.1" - crypto: - dependency: transitive - description: - name: crypto - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.5" - csslib: - dependency: transitive - description: - name: csslib - url: "https://pub.dartlang.org" - source: hosted - version: "0.16.2" - cupertino_icons: - dependency: "direct main" - description: - name: cupertino_icons - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - dart_style: - dependency: transitive - description: - name: dart_style - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.6" - devicelocale: - dependency: "direct main" - description: - name: devicelocale - url: "https://pub.dartlang.org" - source: hosted - version: "0.3.2" - equatable: - dependency: "direct main" - description: - name: equatable - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.5" - fake_async: - dependency: transitive - description: - name: fake_async - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0-nullsafety" - ffi: - dependency: transitive - description: - name: ffi - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.3" - file: - dependency: transitive - description: - name: file - url: "https://pub.dartlang.org" - source: hosted - version: "6.0.0-nullsafety.1" - fixnum: - dependency: transitive - description: - name: fixnum - url: "https://pub.dartlang.org" - source: hosted - version: "0.10.11" - fl_chart: - dependency: "direct main" - description: - name: fl_chart - url: "https://pub.dartlang.org" - source: hosted - version: "0.11.1" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_bloc: - dependency: "direct main" - description: - name: flutter_bloc - url: "https://pub.dartlang.org" - source: hosted - version: "6.0.6" - flutter_driver: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - flutter_facebook_login: - dependency: "direct main" - description: - name: flutter_facebook_login - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.0" - flutter_form_bloc: - dependency: "direct main" - description: - name: flutter_form_bloc - url: "https://pub.dartlang.org" - source: hosted - version: "0.19.0" - flutter_keyboard_visibility: - dependency: transitive - description: - name: flutter_keyboard_visibility - url: "https://pub.dartlang.org" - source: hosted - version: "3.2.2" - flutter_launcher_icons: - dependency: "direct dev" - description: - name: flutter_launcher_icons - url: "https://pub.dartlang.org" - source: hosted - version: "0.8.1" - flutter_localizations: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_test: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - flutter_web_plugins: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - form_bloc: - dependency: transitive - description: - name: form_bloc - url: "https://pub.dartlang.org" - source: hosted - version: "0.19.1" - freezed: - dependency: "direct main" - description: - name: freezed - url: "https://pub.dartlang.org" - source: hosted - version: "0.12.1" - freezed_annotation: - dependency: transitive - description: - name: freezed_annotation - url: "https://pub.dartlang.org" - source: hosted - version: "0.12.0" - fuchsia_remote_debug_protocol: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - glob: - dependency: transitive - description: - name: glob - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - gradient_bottom_navigation_bar: - dependency: "direct main" - description: - name: gradient_bottom_navigation_bar - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0+4" - graphs: - dependency: transitive - description: - name: graphs - url: "https://pub.dartlang.org" - source: hosted - version: "0.2.0" - html: - dependency: transitive - description: - name: html - url: "https://pub.dartlang.org" - source: hosted - version: "0.14.0+4" - http: - dependency: "direct dev" - description: - name: http - url: "https://pub.dartlang.org" - source: hosted - version: "0.12.1" - http_multi_server: - dependency: transitive - description: - name: http_multi_server - url: "https://pub.dartlang.org" - source: hosted - version: "2.2.0" - http_parser: - dependency: transitive - description: - name: http_parser - url: "https://pub.dartlang.org" - source: hosted - version: "3.1.4" - image: - dependency: transitive - description: - name: image - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.18" - intl: - dependency: "direct dev" - description: - name: intl - url: "https://pub.dartlang.org" - source: hosted - version: "0.16.1" - io: - dependency: transitive - description: - name: io - url: "https://pub.dartlang.org" - source: hosted - version: "0.3.4" - js: - dependency: transitive - description: - name: js - url: "https://pub.dartlang.org" - source: hosted - version: "0.6.3-nullsafety.1" - json_annotation: - dependency: transitive - description: - name: json_annotation - url: "https://pub.dartlang.org" - source: hosted - version: "3.1.0" - json_rpc_2: - dependency: transitive - description: - name: json_rpc_2 - url: "https://pub.dartlang.org" - source: hosted - version: "2.2.1" - logging: - dependency: transitive - description: - name: logging - url: "https://pub.dartlang.org" - source: hosted - version: "0.11.4" - matcher: - dependency: transitive - description: - name: matcher - url: "https://pub.dartlang.org" - source: hosted - version: "0.12.10-nullsafety" - meta: - dependency: transitive - description: - name: meta - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0-nullsafety.2" - mime: - dependency: transitive - description: - name: mime - url: "https://pub.dartlang.org" - source: hosted - version: "0.9.7" - mockito: - dependency: "direct main" - description: - name: mockito - url: "https://pub.dartlang.org" - source: hosted - version: "4.1.1" - nested: - dependency: transitive - description: - name: nested - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.4" - node_interop: - dependency: transitive - description: - name: node_interop - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.1" - node_io: - dependency: transitive - description: - name: node_io - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.1" - node_preamble: - dependency: transitive - description: - name: node_preamble - url: "https://pub.dartlang.org" - source: hosted - version: "1.4.12" - package_config: - dependency: transitive - description: - name: package_config - url: "https://pub.dartlang.org" - source: hosted - version: "1.9.3" - path: - dependency: transitive - description: - name: path - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.0-nullsafety" - path_drawing: - dependency: transitive - description: - name: path_drawing - url: "https://pub.dartlang.org" - source: hosted - version: "0.4.1+1" - path_parsing: - dependency: transitive - description: - name: path_parsing - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.4" - path_provider_linux: - dependency: transitive - description: - name: path_provider_linux - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.1+2" - path_provider_platform_interface: - dependency: transitive - description: - name: path_provider_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.3" - path_provider_windows: - dependency: transitive - description: - name: path_provider_windows - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.4+1" - pedantic: - dependency: transitive - description: - name: pedantic - url: "https://pub.dartlang.org" - source: hosted - version: "1.10.0-nullsafety.1" - percent_indicator: - dependency: "direct main" - description: - name: percent_indicator - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.7+4" - petitparser: - dependency: transitive - description: - name: petitparser - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.4" - platform: - dependency: transitive - description: - name: platform - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.0-nullsafety.1" - plugin_platform_interface: - dependency: transitive - description: - name: plugin_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.3" - pool: - dependency: transitive - description: - name: pool - url: "https://pub.dartlang.org" - source: hosted - version: "1.5.0-nullsafety.1" - process: - dependency: transitive - description: - name: process - url: "https://pub.dartlang.org" - source: hosted - version: "4.0.0-nullsafety.1" - provider: - dependency: transitive - description: - name: provider - url: "https://pub.dartlang.org" - source: hosted - version: "4.3.2+2" - pub_semver: - dependency: transitive - description: - name: pub_semver - url: "https://pub.dartlang.org" - source: hosted - version: "1.4.4" - pubspec_parse: - dependency: transitive - description: - name: pubspec_parse - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.5" - quiver: - dependency: transitive - description: - name: quiver - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.3" - rainbow_color: - dependency: "direct main" - description: - name: rainbow_color - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.1" - rainbow_vis: - dependency: transitive - description: - name: rainbow_vis - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.3" - rxdart: - dependency: transitive - description: - name: rxdart - url: "https://pub.dartlang.org" - source: hosted - version: "0.24.1" - sentry: - dependency: "direct main" - description: - name: sentry - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" - shared_preferences: - dependency: "direct dev" - description: - name: shared_preferences - url: "https://pub.dartlang.org" - source: hosted - version: "0.5.12" - shared_preferences_linux: - dependency: transitive - description: - name: shared_preferences_linux - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.2+2" - shared_preferences_macos: - dependency: transitive - description: - name: shared_preferences_macos - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.1+10" - shared_preferences_platform_interface: - dependency: transitive - description: - name: shared_preferences_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.4" - shared_preferences_web: - dependency: transitive - description: - name: shared_preferences_web - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.2+7" - shared_preferences_windows: - dependency: transitive - description: - name: shared_preferences_windows - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.1+1" - shelf: - dependency: transitive - description: - name: shelf - url: "https://pub.dartlang.org" - source: hosted - version: "0.7.9" - shelf_packages_handler: - dependency: transitive - description: - name: shelf_packages_handler - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - shelf_static: - dependency: transitive - description: - name: shelf_static - url: "https://pub.dartlang.org" - source: hosted - version: "0.2.8" - shelf_web_socket: - dependency: transitive - description: - name: shelf_web_socket - url: "https://pub.dartlang.org" - source: hosted - version: "0.2.3" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_gen: - dependency: transitive - description: - name: source_gen - url: "https://pub.dartlang.org" - source: hosted - version: "0.9.7+1" - source_map_stack_trace: - dependency: transitive - description: - name: source_map_stack_trace - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0-nullsafety.2" - source_maps: - dependency: transitive - description: - name: source_maps - url: "https://pub.dartlang.org" - source: hosted - version: "0.10.10-nullsafety.1" - source_span: - dependency: transitive - description: - name: source_span - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.0-nullsafety" - spider_chart: - dependency: "direct main" - description: - name: spider_chart - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.5" - stack_trace: - dependency: transitive - description: - name: stack_trace - url: "https://pub.dartlang.org" - source: hosted - version: "1.10.0-nullsafety" - stream_channel: - dependency: transitive - description: - name: stream_channel - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0-nullsafety" - stream_transform: - dependency: transitive - description: - name: stream_transform - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - string_scanner: - dependency: transitive - description: - name: string_scanner - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0-nullsafety" - sync_http: - dependency: transitive - description: - name: sync_http - url: "https://pub.dartlang.org" - source: hosted - version: "0.2.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0-nullsafety" - test: - dependency: "direct dev" - description: - name: test - url: "https://pub.dartlang.org" - source: hosted - version: "1.16.0-nullsafety.4" - test_api: - dependency: transitive - description: - name: test_api - url: "https://pub.dartlang.org" - source: hosted - version: "0.2.19-nullsafety" - test_core: - dependency: transitive - description: - name: test_core - url: "https://pub.dartlang.org" - source: hosted - version: "0.3.12-nullsafety.4" - timing: - dependency: transitive - description: - name: timing - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.1+2" - typed_data: - dependency: transitive - description: - name: typed_data - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0-nullsafety.2" - usage: - dependency: transitive - description: - name: usage - url: "https://pub.dartlang.org" - source: hosted - version: "3.4.2" - uuid: - dependency: transitive - description: - name: uuid - url: "https://pub.dartlang.org" - source: hosted - version: "2.2.2" - vector_math: - dependency: transitive - description: - name: vector_math - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0-nullsafety.2" - vm_service: - dependency: transitive - description: - name: vm_service - url: "https://pub.dartlang.org" - source: hosted - version: "4.2.0" - vm_service_client: - dependency: transitive - description: - name: vm_service_client - url: "https://pub.dartlang.org" - source: hosted - version: "0.2.6+2" - watcher: - dependency: transitive - description: - name: watcher - url: "https://pub.dartlang.org" - source: hosted - version: "0.9.7+15" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - webdriver: - dependency: transitive - description: - name: webdriver - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.2" - webkit_inspection_protocol: - dependency: transitive - description: - name: webkit_inspection_protocol - url: "https://pub.dartlang.org" - source: hosted - version: "0.7.3" - win32: - dependency: transitive - description: - name: win32 - url: "https://pub.dartlang.org" - source: hosted - version: "1.7.3" - xdg_directories: - dependency: transitive - description: - name: xdg_directories - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.2" - xml: - dependency: transitive - description: - name: xml - url: "https://pub.dartlang.org" - source: hosted - version: "4.5.1" - yaml: - dependency: transitive - description: - name: yaml - url: "https://pub.dartlang.org" - source: hosted - version: "2.2.1" -sdks: - dart: ">=2.10.0-4.0.dev <2.10.0" - flutter: ">=1.16.0 <2.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 7981f2a..68e10e2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -25,12 +25,9 @@ dependencies: sdk: flutter cupertino_icons: ^1.0.0 - devicelocale: ^0.3.2 + devicelocale: ^0.3.3 sentry: ^3.0.1 - # firebase_messaging: ^6.0.16 - #flutter_local_notifications: ^1.5.0-beta.9 - flutter_facebook_login: ^3.0.0 - flutter_bloc: ^6.0.5 + flutter_bloc: ^6.0.6 equatable: ^1.2.5 freezed: ^0.12.1 flutter_form_bloc: ^0.19.0 @@ -38,7 +35,13 @@ dependencies: rainbow_color: ^0.1.1 percent_indicator: ^2.1.7+4 gradient_bottom_navigation_bar: ^1.0.0+4 - fl_chart: ^0.11.1 + fl_chart: ^0.12.0 + infinite_listview: ^1.0.1+1 + + firebase_core: 0.5.0+1 + firebase_analytics: ^6.0.2 + firebase_auth: ^0.18.1+2 + flutter_facebook_login: ^3.0.0 mockito: ^4.1.1 @@ -56,9 +59,9 @@ dev_dependencies: http: 0.12.1 intl: 0.16.1 - shared_preferences: ^0.5.12 + shared_preferences: ^0.5.12+2 - flutter_launcher_icons: ^0.8.0 + flutter_launcher_icons: ^0.8.1 flutter_icons: android: "launcher_icon" @@ -93,8 +96,14 @@ flutter: - asset/image/login_fb.png - asset/image/lock.png - asset/image/Congrats_N1.jpg - - asset/image/development_muscles.jpg - - asset/image/exercise_log.jpg + - asset/image/testemfejl400x400.jpg + - asset/image/izomcsop400400.jpg + - asset/image/edzesnaplom400400.jpg + - asset/image/exercise_plan_stars.jpg + - asset/image/exercise_plan_special.jpg + - asset/image/exercise_plan_execute.jpg + - asset/image/exercise_plan_custom.jpg + - asset/image/exercise_plan_suggested.jpg - asset/menu/1.cardio.png - asset/menu/1.1.aerob.png - asset/menu/1.2.anaerob.png @@ -119,12 +128,12 @@ flutter: - asset/menu/3.1.BMI.png - asset/menu/3.2.BMR.png - asset/menu/3.3.sizes.png - - asset/menu/cable triceps.png + - asset/menu/cable_triceps.png - asset/menu/Back_pullup.png - asset/menu/biceps.jpg - asset/menu/calf.png - asset/menu/legpress.jpg - - asset/menu/shoulder press.png + - asset/menu/shoulder_press.png - asset/menu/squat.jpg - asset/menu/tricdip.jpg - i18n/en.json