From 9c72df1d67d8c26f02a621b78f6767ef2a532c52 Mon Sep 17 00:00:00 2001 From: bossanyit Date: Thu, 16 Sep 2021 18:40:59 +0200 Subject: [PATCH] WT1.1.23 fix changes --- i18n/en.json | 5 +- i18n/hu.json | 5 +- ios/Runner.xcodeproj/project.pbxproj | 6 +- ios/Runner/Info.plist | 2 +- .../training_plan/training_plan_bloc.dart | 55 +++- .../training_plan/training_plan_event.dart | 16 + lib/repository/training_plan_repository.dart | 13 +- lib/util/common.dart | 6 +- lib/view/exercise_control_page.dart | 1 - lib/view/exercise_log_page.dart | 76 ++++- lib/view/mydevelopment_page.dart | 282 +++++++++++++----- lib/view/training_plan_activate_page.dart | 53 +++- lib/view/training_plan_exercise.dart | 5 +- lib/widgets/exercise_save.dart | 118 ++++++-- pubspec.lock | 32 +- pubspec.yaml | 6 +- 16 files changed, 524 insertions(+), 157 deletions(-) diff --git a/i18n/en.json b/i18n/en.json index 29d0203..501cbfd 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -541,5 +541,8 @@ "Based on your initial data, we will generate the personalized training plan for you.": "Based on your initial data, we will generate the personalized training plan for you.", "No selected Training Plan": "No selected Training Plan", "Min. 10 minutes": "Min. 10 minutes", - "You want to skip really the entire exercise?": "You want to skip really the entire exercise?" + "You want to skip really the entire exercise?": "You want to skip really the entire exercise?", + "Premium function": "Premium function", + "This is a premium function, you can reach it outside of the trial period only with a valid subscription": "This is a premium function, you can reach it outside of the trial period only with a valid subscription", + "This is a premium function, you can reach it only with a valid subscription": "This is a premium function, you can reach it only with a valid subscription" } \ No newline at end of file diff --git a/i18n/hu.json b/i18n/hu.json index c2c6777..09d2b32 100644 --- a/i18n/hu.json +++ b/i18n/hu.json @@ -541,5 +541,8 @@ "Based on your initial data, we will generate the personalized training plan for you.": "A megadott adataid alapján most személyre szabott edzéstervet generálunk neked.", "No selected Training Plan": "Nincs kiválasztott edzésterved", "Min. 10 minutes": "Minimum 10 perc", - "You want to skip really the entire exercise?": "Átugrod az egész gyakorlatot?" + "You want to skip really the entire exercise?": "Átugrod az egész gyakorlatot?", + "Premium function": "Prémium tartalom", + "This is a premium function, you can reach it outside of the trial period only with a valid subscription": "Ezt a tartalmat az ingyenes időszakon kívül csak aktív előfizetéssel éred el", + "This is a premium function, you can reach it only with a valid subscription": "Ezt a tartalmat csak aktív előfizetéssel éred el" } \ No newline at end of file diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index ac8d8ef..6e4f3a9 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -388,7 +388,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 5; DEVELOPMENT_TEAM = SFJJBDCU6Z; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -531,7 +531,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 5; DEVELOPMENT_TEAM = SFJJBDCU6Z; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -566,7 +566,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 5; DEVELOPMENT_TEAM = SFJJBDCU6Z; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 4f1e1fd..2d4236f 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -11,7 +11,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleName - WorkoutTest + Workout Test CFBundlePackageType APPL CFBundleShortVersionString diff --git a/lib/bloc/training_plan/training_plan_bloc.dart b/lib/bloc/training_plan/training_plan_bloc.dart index 3b98ef1..5c734d4 100644 --- a/lib/bloc/training_plan/training_plan_bloc.dart +++ b/lib/bloc/training_plan/training_plan_bloc.dart @@ -18,6 +18,7 @@ import 'package:aitrainer_app/util/app_language.dart'; import 'package:aitrainer_app/util/common.dart'; import 'package:aitrainer_app/util/enums.dart'; import 'package:aitrainer_app/util/track.dart'; +import 'package:aitrainer_app/widgets/exercise_save.dart'; import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; @@ -74,15 +75,54 @@ class TrainingPlanBloc extends Bloc { yield TrainingPlanExerciseLoading(); event.detail.weight = event.weight; + yield TrainingPlanExerciseReady(); + yield TrainingPlanReady(); + } else if (event is TrainingPlanWeightChangeUp) { + yield TrainingPlanExerciseLoading(); + if (event.detail.weight != null) { + event.detail.repeats = + Common.reCalculateRepeatsByChangedWeight(event.detail.weight!, event.detail.repeats!.toDouble(), event.detail.weight! + 1); + event.detail.weight = event.detail.weight! + 1; + ExerciseSaveStream().weight = event.detail.weight!; + ExerciseSaveStream().repeats = event.detail.repeats!; + ExerciseSaveStream().getStreamController().add(true); + } + + yield TrainingPlanExerciseReady(); + yield TrainingPlanReady(); + } else if (event is TrainingPlanWeightChangeDown) { + yield TrainingPlanExerciseLoading(); + if (event.detail.weight != null) { + event.detail.repeats = + Common.reCalculateRepeatsByChangedWeight(event.detail.weight!, event.detail.repeats!.toDouble(), event.detail.weight! - 1); + event.detail.weight = event.detail.weight! - 1; + ExerciseSaveStream().weight = event.detail.weight!; + ExerciseSaveStream().repeats = event.detail.repeats!; + ExerciseSaveStream().getStreamController().add(true); + } + yield TrainingPlanExerciseReady(); yield TrainingPlanReady(); } else if (event is TrainingPlanWeightChangeRecalculate) { yield TrainingPlanExerciseLoading(); - event.detail.repeats = - Common.reCalculateRepeatsByChangedWeight(event.detail.weight!, event.detail.repeats!.toDouble(), event.weight); - event.detail.weight = event.weight; + /* double weightFromPlan = trainingPlanRepository.getOriginalWeight(this.getMyPlan()!.trainingPlanId!, event.detail); + print("Plan Wieght: $weightFromPlan"); + if (weightFromPlan != -1 || (weightFromPlan == -1 && event.detail.set! > 1)) { + bool isTest = weightFromPlan != -1 || weightFromPlan != -2; + if (!isTest || (isTest && event.detail.set! > 1)) { + //&& event.detail.exercises.length > 0 + event.detail.repeats = + Common.reCalculateRepeatsByChangedWeight(event.detail.weight!, event.detail.repeats!.toDouble(), event.weight); + if (event.detail.repeats! < 3) { + event.detail.repeats = 4; + } + ExerciseSaveStream().repeats = event.detail.repeats!; + ExerciseSaveStream().getStreamController().add(true); + } */ + event.detail.weight = event.weight; + yield TrainingPlanExerciseReady(); yield TrainingPlanReady(); } else if (event is TrainingPlanRepeatsChange) { yield TrainingPlanExerciseLoading(); @@ -102,6 +142,7 @@ class TrainingPlanBloc extends Bloc { yield TrainingPlanReady(); throw Exception("Please type your repeats!"); } + print("ExerciseTypeUID: ${event.detail.exerciseTypeId}"); if (event.detail.weight == -3) { print("DropSet"); event.detail.state = ExercisePlanDetailState.finished; @@ -123,8 +164,8 @@ class TrainingPlanBloc extends Bloc { // recalculate the weight to the original planned repeats for the next details if (exercise.unitQuantity != null && exercise.unitQuantity! > 0) { for (var nextDetail in _myPlan!.details) { - print("NextDetail detail: $nextDetail"); double weightFromPlan = trainingPlanRepository.getOriginalWeight(this.getMyPlan()!.trainingPlanId!, nextDetail); + print("NextDetail detail: $nextDetail *** PlanWeight: $weightFromPlan"); if (nextDetail.exerciseTypeId == event.detail.exerciseTypeId && nextDetail.weight == -2 && nextDetail.customerTrainingPlanDetailsId != event.detail.customerTrainingPlanDetailsId) { @@ -136,6 +177,12 @@ class TrainingPlanBloc extends Bloc { } else if (nextDetail.exerciseTypeId == event.detail.exerciseTypeId && nextDetail.weight == -1 && nextDetail.set! == 1) { print("recalculating -1, set 1 ${event.detail.customerTrainingPlanDetailsId}"); nextDetail = trainingPlanRepository.recalculateDetailFixRepeatsSet1(_myPlan!.trainingPlanId!, nextDetail, event.detail); + } else if (nextDetail.exerciseTypeId == event.detail.exerciseTypeId && + weightFromPlan == -2 && + nextDetail.set! == 1 && + nextDetail.exercises.length == 0) { + print("recalculating -1/ no exercise, set 1 ${event.detail.customerTrainingPlanDetailsId}"); + nextDetail = trainingPlanRepository.recalculateDetailFixRepeatsSet1(_myPlan!.trainingPlanId!, nextDetail, event.detail); } } } diff --git a/lib/bloc/training_plan/training_plan_event.dart b/lib/bloc/training_plan/training_plan_event.dart index 6d17338..f91b357 100644 --- a/lib/bloc/training_plan/training_plan_event.dart +++ b/lib/bloc/training_plan/training_plan_event.dart @@ -28,6 +28,22 @@ class TrainingPlanWeightChange extends TrainingPlanEvent { List get props => [weight, detail]; } +class TrainingPlanWeightChangeUp extends TrainingPlanEvent { + final CustomerTrainingPlanDetails detail; + const TrainingPlanWeightChangeUp({required this.detail}); + + @override + List get props => [detail]; +} + +class TrainingPlanWeightChangeDown extends TrainingPlanEvent { + final CustomerTrainingPlanDetails detail; + const TrainingPlanWeightChangeDown({required this.detail}); + + @override + List get props => [detail]; +} + class TrainingPlanWeightChangeRecalculate extends TrainingPlanEvent { final CustomerTrainingPlanDetails detail; final double weight; diff --git a/lib/repository/training_plan_repository.dart b/lib/repository/training_plan_repository.dart index 33212e5..77767f8 100644 --- a/lib/repository/training_plan_repository.dart +++ b/lib/repository/training_plan_repository.dart @@ -166,8 +166,9 @@ class TrainingPlanRepository { } Exercise? lastExercise1RM; + DateTime dt = DateTime.now().subtract(Duration(days: 30)); Cache().getExercises()!.forEach((exercise) { - if (exercise.exercisePlanDetailId == 0 && exercise.exerciseTypeId == exerciseTypeId) { + if (exercise.exerciseTypeId == exerciseTypeId && exercise.dateAdd!.compareTo(dt) >= 0) { detail.weight = weight; lastExercise1RM = exercise; } @@ -179,13 +180,13 @@ class TrainingPlanRepository { return detail; } - //double oneRepMax = Common.calculate1RM(lastExercise1RM!.unitQuantity!, lastExercise1RM!.quantity!); - //print("Exercise $exerciseTypeId - 1RM : $oneRepMax"); - //weight = oneRepMax * Common.get1RMPercent(detail.repeats!); - //print("Exercise $exerciseTypeId - weight : $weight"); + double oneRepMax = Common.calculate1RM(lastExercise1RM!.unitQuantity!, lastExercise1RM!.quantity!); + print("Exercise $exerciseTypeId - 1RM : $oneRepMax"); + weight = oneRepMax * Common.get1RMPercent(detail.repeats!); + print("Exercise $exerciseTypeId - weight : $weight"); //weight = Common.roundWeight(weight); //detail.weight = Common.calculateWeigthByChangedQuantity(detail.weight!, detail.repeats!.toDouble(), lastExercise1RM!.quantity!); - weight = lastExercise1RM!.unitQuantity! * detail.repeats! / lastExercise1RM!.quantity!; + //weight = lastExercise1RM!.unitQuantity! * detail.repeats! / lastExercise1RM!.quantity!; weight = Common.roundWeight(weight); print("Recaluclated weight ${detail.weight} - repeat: ${detail.repeats}"); diff --git a/lib/util/common.dart b/lib/util/common.dart index 62ed7bf..03b5d6d 100644 --- a/lib/util/common.dart +++ b/lib/util/common.dart @@ -179,11 +179,11 @@ mixin Common { if (weight > 35) { final double remainder = weight % 5; - if (remainder < 1.25) { + if (remainder < 1) { rounded = ((weight / 5).floor() * 5).toDouble(); - } else if (remainder > 1.25 && remainder <= 2.5) { + } else if (remainder > 1 && remainder <= 2.5) { rounded = (weight / 5).floor() * 5 + 2.5; - } else if (remainder > 2.5 && remainder < 3.75) { + } else if (remainder > 2.5 && remainder < 3.25) { rounded = (weight / 5).floor() * 5 + 2.5; } else { rounded = (((weight / 5).ceil() * 5) + 5).toDouble(); diff --git a/lib/view/exercise_control_page.dart b/lib/view/exercise_control_page.dart index 5c42e3f..c6d763f 100644 --- a/lib/view/exercise_control_page.dart +++ b/lib/view/exercise_control_page.dart @@ -2,7 +2,6 @@ import 'dart:collection'; import 'package:aitrainer_app/bloc/exercise_control/exercise_control_bloc.dart'; import 'package:aitrainer_app/bloc/timer/timer_bloc.dart'; -import 'package:aitrainer_app/bloc/tutorial/tutorial_bloc.dart'; import 'package:aitrainer_app/library/custom_icon_icons.dart'; import 'package:aitrainer_app/util/app_language.dart'; import 'package:aitrainer_app/model/cache.dart'; diff --git a/lib/view/exercise_log_page.dart b/lib/view/exercise_log_page.dart index 3a11d82..9d8cb77 100644 --- a/lib/view/exercise_log_page.dart +++ b/lib/view/exercise_log_page.dart @@ -2,7 +2,9 @@ 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/dialog_common.dart'; import 'package:aitrainer_app/widgets/dialog_premium.dart'; +import 'package:badges/badges.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:intl/intl.dart'; @@ -193,16 +195,72 @@ class ExerciseLogPage extends StatelessWidget with Trans, Common { )), GestureDetector( onTap: () => evaluation(exerciseRepository, exercise), - child: Image.asset( - "asset/image/kupa.png", - width: 35, + child: Badge( + elevation: 0, + padding: EdgeInsets.all(0), + position: BadgePosition.topStart(top: -25, start: -25), + animationDuration: Duration(milliseconds: 1500), + animationType: BadgeAnimationType.fade, + badgeColor: Colors.transparent, + showBadge: true, + badgeContent: IconButton( + iconSize: 36, + onPressed: () => showDialog( + context: context, + builder: (BuildContext context) { + return DialogCommon( + title: t("Premium function"), + descriptions: Cache().canTrial() + ? t("This is a premium function, you can reach it outside of the trial period only with a valid subscription") + : t("This is a premium function, you can reach it only with a valid subscription"), + onCancel: () => Navigator.of(context).pop(), + onTap: () => Navigator.of(context).pop(), + text: '', + ); + }), + icon: Icon( + Icons.star, + size: 14, + color: Colors.orange[400], + )), + child: Image.asset( + "asset/image/kupa.png", + width: 35, + ))), + Badge( + elevation: 0, + padding: EdgeInsets.all(0), + position: BadgePosition.topStart(top: -18, start: -17), + animationDuration: Duration(milliseconds: 1500), + animationType: BadgeAnimationType.fade, + badgeColor: Colors.transparent, + showBadge: true, + badgeContent: IconButton( + iconSize: 36, + onPressed: () => showDialog( + context: context, + builder: (BuildContext context) { + return DialogCommon( + title: t("Premium function"), + descriptions: Cache().canTrial() + ? t("This is a premium function, you can reach it outside of the trial period only with a valid subscription") + : t("This is a premium function, you can reach it only with a valid subscription"), + onCancel: () => Navigator.of(context).pop(), + onTap: () => Navigator.of(context).pop(), + text: '', + ); + }), + icon: Icon( + Icons.star, + size: 14, + color: Colors.orange[400], + )), + child: IconButton( + icon: Icon(Icons.delete, color: Colors.black12), + onPressed: () { + confirmationDialog(exerciseLogBloc, exercise); + }, )), - IconButton( - icon: Icon(Icons.delete, color: Colors.black12), - onPressed: () { - confirmationDialog(exerciseLogBloc, exercise); - }, - ), ]), )), ); diff --git a/lib/view/mydevelopment_page.dart b/lib/view/mydevelopment_page.dart index 8553ccf..895269b 100644 --- a/lib/view/mydevelopment_page.dart +++ b/lib/view/mydevelopment_page.dart @@ -6,8 +6,10 @@ import 'package:aitrainer_app/repository/exercise_repository.dart'; import 'package:aitrainer_app/util/enums.dart'; import 'package:aitrainer_app/util/track.dart'; import 'package:aitrainer_app/widgets/dialog_common.dart'; +import 'package:aitrainer_app/widgets/dialog_html.dart'; import 'package:aitrainer_app/widgets/dialog_premium.dart'; import 'package:badges/badges.dart'; +import 'package:flutter/services.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:aitrainer_app/util/trans.dart'; import 'package:aitrainer_app/widgets/app_bar.dart'; @@ -77,102 +79,187 @@ class _MyDevelopmentPage extends State with Trans { onTap: () => this.callBackExerciseLog(exerciseRepository, customerRepository), isLocked: false, )), - ImageButton( - width: imageWidth, - textAlignment: Alignment.topLeft, - text: t("My Whole Body Development"), - style: GoogleFonts.robotoMono( - textStyle: TextStyle( - fontSize: 14, color: Colors.white, fontWeight: FontWeight.bold, backgroundColor: Colors.black54.withOpacity(0.4)), - ), - image: "asset/image/testemfejl400x400.jpg", - left: 5, - onTap: () => { - if (Cache().userLoggedIn != null) - { - args['customerId'] = Cache().userLoggedIn!.customerId, - Navigator.of(context).pushNamed('mydevelopmentBodyPage', arguments: args) - } - else - { - showDialog( + Badge( + elevation: 0, + padding: EdgeInsets.all(0), + position: BadgePosition.topStart(top: -12, start: -12), + animationDuration: Duration(milliseconds: 1500), + animationType: BadgeAnimationType.fade, + badgeColor: Colors.transparent, + showBadge: Cache().hasPurchased, + badgeContent: IconButton( + iconSize: 36, + onPressed: () => showDialog( context: context, builder: (BuildContext context) { return DialogCommon( - warning: true, - title: t("Warning"), - descriptions: t("Please log in"), - description2: - t("because only that way can we show you the personalized development diagrams and analysises"), - text: "OK", - onTap: () => Navigator.of(context).popAndPushNamed("login"), - onCancel: () => { - Navigator.of(context).pop(), - }, + title: t("Premium function"), + descriptions: Cache().canTrial() + ? t("This is a premium function, you can reach it outside of the trial period only with a valid subscription") + : t("This is a premium function, you can reach it only with a valid subscription"), + onCancel: () => Navigator.of(context).pop(), + onTap: () => Navigator.of(context).pop(), + text: '', ); - }) - } - }, - isLocked: true, - ), - Badge( - padding: EdgeInsets.all(8), - position: BadgePosition.topEnd(top: -5, end: -3), - animationDuration: Duration(milliseconds: 500), - animationType: BadgeAnimationType.slide, - badgeColor: Colors.red, - showBadge: showMuscleDevelopmentBadge, - badgeContent: Text(counterMuscleDevelopmentBadge.toString(), - style: TextStyle( - color: Colors.white, - fontSize: 16, + }), + icon: Icon( + Icons.star, + color: Colors.orange[600], )), child: ImageButton( width: imageWidth, textAlignment: Alignment.topLeft, - text: t("Development Of Muscles"), + text: t("My Whole Body Development"), + style: GoogleFonts.robotoMono( + textStyle: TextStyle( + fontSize: 14, + color: Colors.white, + fontWeight: FontWeight.bold, + backgroundColor: Colors.black54.withOpacity(0.4)), + ), + image: "asset/image/testemfejl400x400.jpg", + left: 5, + onTap: () => { + if (Cache().userLoggedIn != null) + { + args['customerId'] = Cache().userLoggedIn!.customerId, + Navigator.of(context).pushNamed('mydevelopmentBodyPage', arguments: args) + } + else + { + showDialog( + context: context, + builder: (BuildContext context) { + return DialogCommon( + warning: true, + title: t("Warning"), + descriptions: t("Please log in"), + description2: + t("because only that way can we show you the personalized development diagrams and analysises"), + text: "OK", + onTap: () => Navigator.of(context).popAndPushNamed("login"), + onCancel: () => { + Navigator.of(context).pop(), + }, + ); + }) + } + }, + isLocked: true, + )), + Badge( + elevation: 0, + padding: EdgeInsets.all(0), + position: BadgePosition.topStart(top: -12, start: -12), + animationDuration: Duration(milliseconds: 1500), + animationType: BadgeAnimationType.fade, + badgeColor: Colors.transparent, + showBadge: Cache().hasPurchased, + badgeContent: IconButton( + iconSize: 36, + onPressed: () => showDialog( + context: context, + builder: (BuildContext context) { + return DialogCommon( + title: t("Premium function"), + descriptions: Cache().canTrial() + ? t("This is a premium function, you can reach it outside of the trial period only with a valid subscription") + : t("This is a premium function, you can reach it only with a valid subscription"), + onCancel: () => Navigator.of(context).pop(), + onTap: () => Navigator.of(context).pop(), + text: '', + ); + }), + icon: Icon( + Icons.star, + color: Colors.orange[600], + )), + child: Badge( + padding: EdgeInsets.all(8), + position: BadgePosition.topEnd(top: -5, end: -3), + animationDuration: Duration(milliseconds: 500), + animationType: BadgeAnimationType.slide, + badgeColor: Colors.red, + showBadge: showMuscleDevelopmentBadge, + badgeContent: Text(counterMuscleDevelopmentBadge.toString(), + style: TextStyle( + color: Colors.white, + fontSize: 16, + )), + child: ImageButton( + width: imageWidth, + textAlignment: Alignment.topLeft, + text: t("Development Of Muscles"), + style: GoogleFonts.robotoMono( + textStyle: TextStyle( + fontSize: 14, + color: Colors.white, + fontWeight: FontWeight.bold, + backgroundColor: Colors.black54.withOpacity(0.4))), + image: "asset/image/izomcsop400400.jpg", + left: 5, + onTap: () => {Navigator.of(context).pushNamed('mydevelopmentMusclePage', arguments: args)}, + isLocked: true, + ))), + Badge( + elevation: 0, + padding: EdgeInsets.all(0), + position: BadgePosition.topStart(top: -12, start: -12), + animationDuration: Duration(milliseconds: 1500), + animationType: BadgeAnimationType.fade, + badgeColor: Colors.transparent, + showBadge: Cache().hasPurchased, + badgeContent: IconButton( + iconSize: 36, + onPressed: () => showDialog( + context: context, + builder: (BuildContext context) { + return DialogCommon( + title: t("Premium function"), + descriptions: Cache().canTrial() + ? t("This is a premium function, you can reach it outside of the trial period only with a valid subscription") + : t("This is a premium function, you can reach it only with a valid subscription"), + onCancel: () => Navigator.of(context).pop(), + onTap: () => Navigator.of(context).pop(), + text: '', + ); + }), + icon: Icon( + Icons.star, + color: Colors.orange[600], + )), + child: ImageButton( + width: imageWidth, + left: 5, + textAlignment: Alignment.topLeft, + text: t("Predictions"), style: GoogleFonts.robotoMono( textStyle: TextStyle( fontSize: 14, color: Colors.white, fontWeight: FontWeight.bold, backgroundColor: Colors.black54.withOpacity(0.4))), - image: "asset/image/izomcsop400400.jpg", - left: 5, - onTap: () => {Navigator.of(context).pushNamed('mydevelopmentMusclePage', arguments: args)}, + image: "asset/image/predictions.jpg", + onTap: () => { + if (Cache().userLoggedIn != null) + { + Track().track(TrackingEvent.prediction), + showDialog( + context: context, + builder: (BuildContext context) { + return DialogPremium( + unlocked: Cache().hasPurchased, + unlockRound: 12, + function: "Predictions", + unlockedText: null, + onTap: () => {Navigator.of(context).pop()}, + ); + }) + } + }, isLocked: true, )), - ImageButton( - width: imageWidth, - left: 5, - textAlignment: Alignment.topLeft, - text: t("Predictions"), - style: GoogleFonts.robotoMono( - textStyle: TextStyle( - fontSize: 14, - color: Colors.white, - fontWeight: FontWeight.bold, - backgroundColor: Colors.black54.withOpacity(0.4))), - image: "asset/image/predictions.jpg", - onTap: () => { - if (Cache().userLoggedIn != null) - { - Track().track(TrackingEvent.prediction), - showDialog( - context: context, - builder: (BuildContext context) { - return DialogPremium( - unlocked: Cache().hasPurchased, - unlockRound: 12, - function: "Predictions", - unlockedText: null, - onTap: () => {Navigator.of(context).pop()}, - ); - }) - } - }, - isLocked: true, - ), + //developmentWidget(imageWidth, "Development Size", "asset/image/predictions.jpg", TrackingEvent.my_size_development, args), hiddenWidget(customerRepository, exerciseRepository), ]), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( @@ -186,6 +273,41 @@ class _MyDevelopmentPage extends State with Trans { bottomNavigationBar: BottomNavigator(bottomNavIndex: 1)); } + Widget developmentWidget(double imageWidth, String title, String imageUrl, TrackingEvent trackingEvent, LinkedHashMap args) { + return ImageButton( + width: imageWidth, + left: 5, + textAlignment: Alignment.topLeft, + text: t(title), + style: GoogleFonts.robotoMono( + textStyle: + TextStyle(fontSize: 14, color: Colors.white, fontWeight: FontWeight.bold, backgroundColor: Colors.black54.withOpacity(0.4))), + image: imageUrl, + onTap: () => { + if (Cache().userLoggedIn != null) + { + Track().track(trackingEvent), + SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeLeft]), + Future.delayed(Duration(seconds: 400)), + Navigator.of(context).pushNamed('mydevelopmentSizesPage', arguments: args), + + /* showDialog( + context: context, + builder: (BuildContext context) { + return DialogPremium( + unlocked: Cache().hasPurchased, + unlockRound: 12, + function: "Predictions", + unlockedText: null, + onTap: () => {Navigator.of(context).pop()}, + ); + }) */ + } + }, + isLocked: true, + ); + } + Widget hiddenWidget(CustomerRepository customerRepository, ExerciseRepository exerciseRepository) { final LinkedHashMap args = LinkedHashMap(); if (Cache().getTrainee() != null) { diff --git a/lib/view/training_plan_activate_page.dart b/lib/view/training_plan_activate_page.dart index cca0a8a..8d6896a 100644 --- a/lib/view/training_plan_activate_page.dart +++ b/lib/view/training_plan_activate_page.dart @@ -15,6 +15,7 @@ import 'package:aitrainer_app/widgets/dialog_common.dart'; import 'package:aitrainer_app/widgets/dialog_premium.dart'; import 'package:aitrainer_app/widgets/menu_image.dart'; import 'package:aitrainer_app/widgets/treeview_parent_widget.dart'; +import 'package:badges/badges.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -186,20 +187,48 @@ class TrainingPlanActivatePage extends StatelessWidget with Trans { listWidget.add(explanation); plans.forEach((element) { + bool restricted = (!element.free); listWidget.add(Container( margin: const EdgeInsets.only(left: 4.0), - child: TreeViewChild( - startExpanded: false, - parent: TreeviewParentWidget( - text: element.nameTranslations[AppLanguage().appLocal.toString()] != null - ? element.nameTranslations[AppLanguage().appLocal.toString()]! - : element.name, - fontSize: 18, - icon: Icon(Icons.list_sharp), - color: Colors.blue[800], - ), - children: _getDays(element, bloc), - ))); + child: Badge( + elevation: 0, + padding: EdgeInsets.all(0), + position: BadgePosition.topStart(top: -15, start: -18), + animationDuration: Duration(milliseconds: 1500), + animationType: BadgeAnimationType.fade, + badgeColor: Colors.transparent, + showBadge: restricted, + badgeContent: IconButton( + iconSize: 36, + onPressed: () => showDialog( + context: context, + builder: (BuildContext context) { + return DialogCommon( + title: t("Premium function"), + descriptions: Cache().canTrial() + ? t("This is a premium function, you can reach it outside of the trial period only with a valid subscription") + : t("This is a premium function, you can reach it only with a valid subscription"), + onCancel: () => Navigator.of(context).pop(), + onTap: () => Navigator.of(context).pop(), + text: '', + ); + }), + icon: Icon( + Icons.star, + color: Colors.orange[400], + )), + child: TreeViewChild( + startExpanded: false, + parent: TreeviewParentWidget( + text: element.nameTranslations[AppLanguage().appLocal.toString()] != null + ? element.nameTranslations[AppLanguage().appLocal.toString()]! + : element.name, + fontSize: 18, + icon: Icon(Icons.list_sharp), + color: Colors.blue[800], + ), + children: _getDays(element, bloc), + )))); }); return listWidget; diff --git a/lib/view/training_plan_exercise.dart b/lib/view/training_plan_exercise.dart index de8a641..0f45507 100644 --- a/lib/view/training_plan_exercise.dart +++ b/lib/view/training_plan_exercise.dart @@ -21,7 +21,6 @@ class TrainingPlanExercise extends StatelessWidget with Trans { final CustomerTrainingPlanDetails detail = args['customerTrainingPlanDetails']; // ignore: close_sinks final TrainingPlanBloc bloc = BlocProvider.of(context); - final bool isDropSet = detail.weight == -3; setContext(context); return Scaffold( appBar: AppBarNav(depth: 1), @@ -98,7 +97,9 @@ class TrainingPlanExercise extends StatelessWidget with Trans { repeats: detail.repeats == -1 ? 99 : detail.repeats, set: detail.set, exerciseNr: detail.exercises.length + 1, - onUnitQuantityChanged: (value) => bloc.add(TrainingPlanWeightChange(weight: value, detail: detail)), + onUnitQuantityChanged: (value) => bloc.add(TrainingPlanWeightChangeRecalculate(weight: value, detail: detail)), + onUnitQuantityChangeUp: () => bloc.add(TrainingPlanWeightChangeUp(detail: detail)), + onUnitQuantityChangeDown: () => bloc.add(TrainingPlanWeightChangeDown(detail: detail)), onQuantityChanged: (value) => bloc.add(TrainingPlanRepeatsChange(repeats: value.toInt(), detail: detail)), exerciseTypeId: detail.exerciseType!.exerciseTypeId, originalQuantity: originalQuantity, diff --git a/lib/widgets/exercise_save.dart b/lib/widgets/exercise_save.dart index d45310d..f6e4d31 100644 --- a/lib/widgets/exercise_save.dart +++ b/lib/widgets/exercise_save.dart @@ -16,6 +16,24 @@ import 'package:stop_watch_timer/stop_watch_timer.dart'; import 'package:wakelock/wakelock.dart'; import 'dialog_html.dart'; +class ExerciseSaveStream { + static final ExerciseSaveStream _singleton = ExerciseSaveStream._internal(); + final StreamController streamController = StreamController.broadcast(); + int repeats = 0; + double weight = 0; + + Stream get stream => streamController.stream; + StreamController getStreamController() => streamController; + + factory ExerciseSaveStream() => _singleton; + + ExerciseSaveStream._internal(); + + void dispose() { + streamController.close(); + } +} + enum Explanations { intro, introBold, explanationWeight, explanationRepeats, explanationButton, explanationButtonExt } extension ExplanationsExt on Explanations { @@ -112,6 +130,8 @@ class ExplanationExt { class ExerciseSave extends StatefulWidget { final ValueChanged onQuantityChanged; final ValueChanged? onUnitQuantityChanged; + final VoidCallback? onUnitQuantityChangeUp; + final VoidCallback? onUnitQuantityChangeDown; final VoidCallback? onSubmit; final bool hasUnitQuantity; final String? unitQuantityUnit; @@ -131,6 +151,8 @@ class ExerciseSave extends StatefulWidget { ExerciseSave( {required this.onQuantityChanged, this.onUnitQuantityChanged, + this.onUnitQuantityChangeUp, + this.onUnitQuantityChangeDown, this.onSubmit, required this.hasUnitQuantity, this.unitQuantityUnit, @@ -158,6 +180,9 @@ class _ExerciseSaveState extends State with Trans { final StopWatchTimer stopWatchTimer = StopWatchTimer( isLapHours: false, ); + final Stream stream = ExerciseSaveStream().stream; + late StreamSubscription subscription; + bool changable = false; @override Widget build(BuildContext context) { @@ -188,16 +213,24 @@ class _ExerciseSaveState extends State with Trans { } SchedulerBinding.instance!.addPostFrameCallback((_) { + subscription = stream.listen((event) { + _controller1.text = ExerciseSaveStream().weight.toStringAsFixed(0); + _controller2.text = ExerciseSaveStream().repeats.toStringAsFixed(0); + }); + print("ExerciseSave weight ${widget.weight}"); _controller1.text = widget.weight == null || widget.weight == -1 - ? "--" + ? "TEST" : widget.weight! % widget.weight!.round() == 0 ? widget.weight!.toStringAsFixed(0) : widget.weight!.toStringAsFixed(1); _controller2.text = widget.repeats == null - ? "--" + ? "TEST" : widget.repeats! == 99 ? "MAX" - : widget.repeats!.toStringAsFixed(0); + : widget.weight == -1 || widget.weight == -2 + ? "TEST" + : widget.repeats!.toStringAsFixed(0); + changable = (_controller2.text != "TEST" && _controller1.text != "TEST"); if (widget.unitQuantityUnit != null && widget.tip != null && Cache().isActivityDone(widget.tip!) == false) { Timer( Duration(milliseconds: 2000), @@ -220,9 +253,16 @@ class _ExerciseSaveState extends State with Trans { dispose() { _controller1.dispose(); stopWatchTimer.dispose(); + + subscription.cancel(); + super.dispose(); } + void isChangable() { + changable = !(widget.weight == -1 || widget.weight == -2 || widget.weight == null); + } + KeyboardActionsConfig _buildConfig(BuildContext context) { return KeyboardActionsConfig( keyboardActionsPlatform: KeyboardActionsPlatform.ALL, @@ -507,36 +547,54 @@ class _ExerciseSaveState extends State with Trans { } Widget columnQuantityUnit() { + //changable = (_controller2.text != "TEST" && _controller1.text != "TEST"); + isChangable(); + changable = false; + //print("PlusMinus: $changable - con2: ${_controller2.text} con1: ${_controller1.text}"); Widget row = Padding(padding: const EdgeInsets.only(top: 10, left: 55, right: 55), child: Column()); if (widget.hasUnitQuantity) { row = Padding( padding: const EdgeInsets.only(top: 10, left: 55, right: 55), - child: Column(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ - TextFormField( - focusNode: _nodeText1, - controller: _controller1, - decoration: InputDecoration( - contentPadding: EdgeInsets.only(left: 25, top: 5, bottom: 5), - labelText: t(widget.unitQuantityUnit!), - labelStyle: GoogleFonts.inter(fontSize: 20, color: Colors.yellow[50]), - fillColor: Colors.black38, - filled: true, - border: OutlineInputBorder( - gapPadding: 8.0, - borderRadius: BorderRadius.circular(12.0), - borderSide: BorderSide(color: Colors.white12, width: 0.4), - ), - ), - keyboardType: TextInputType.numberWithOptions(decimal: true), - textInputAction: TextInputAction.done, - style: GoogleFonts.archivoBlack(fontSize: 80, color: Colors.yellow[300]), - onChanged: (value) { - if (value.isNotEmpty) { - value = value.replaceFirst(",", "."); - value = value.replaceAll(RegExp(r'[^0-9.]'), ""); - widget.onUnitQuantityChanged!(double.parse(value)); - } - }), + child: Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ + Flexible( + child: TextFormField( + focusNode: _nodeText1, + controller: _controller1, + maxLength: 5, + decoration: InputDecoration( + contentPadding: EdgeInsets.only(left: 25, top: 5, bottom: 5), + labelText: t(widget.unitQuantityUnit!), + labelStyle: GoogleFonts.inter(fontSize: 20, color: Colors.yellow[50]), + fillColor: Colors.black38, + filled: true, + border: OutlineInputBorder( + gapPadding: 8.0, + borderRadius: BorderRadius.circular(12.0), + borderSide: BorderSide(color: Colors.white12, width: 0.4), + ), + ), + keyboardType: TextInputType.numberWithOptions(decimal: true), + textInputAction: TextInputAction.done, + style: GoogleFonts.archivoBlack(fontSize: 75, color: Colors.yellow[300]), + onChanged: (value) { + if (value.isNotEmpty) { + value = value.replaceFirst(",", "."); + value = value.replaceAll(RegExp(r'[^0-9.]'), ""); + widget.onUnitQuantityChanged!(double.parse(value)); + } + })), + changable + ? Column(children: [ + IconButton( + onPressed: () => widget.onUnitQuantityChangeUp!(), + icon: Icon(CustomIcon.plus_circle, color: Colors.orange, size: 20), + ), + IconButton( + onPressed: () => widget.onUnitQuantityChangeDown!(), + icon: Icon(CustomIcon.minus_circle, color: Colors.orange, size: 20), + ), + ]) + : Offstage() ])); } return row; @@ -646,7 +704,7 @@ class _ExerciseSaveState extends State with Trans { ), keyboardType: TextInputType.number, textInputAction: TextInputAction.next, - style: GoogleFonts.archivoBlack(fontSize: 80, color: Colors.orange[200]), + style: GoogleFonts.archivoBlack(fontSize: 75, color: Colors.orange[200]), onChanged: (value) { if (value.isNotEmpty) { value = value.replaceFirst(",", "."); diff --git a/pubspec.lock b/pubspec.lock index 4cde0b3..12c7d21 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1188,13 +1188,27 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.0" + syncfusion_flutter_calendar: + dependency: "direct main" + description: + name: syncfusion_flutter_calendar + url: "https://pub.dartlang.org" + source: hosted + version: "19.2.60" + syncfusion_flutter_charts: + dependency: "direct main" + description: + name: syncfusion_flutter_charts + url: "https://pub.dartlang.org" + source: hosted + version: "19.2.60" syncfusion_flutter_core: dependency: transitive description: name: syncfusion_flutter_core url: "https://pub.dartlang.org" source: hosted - version: "19.1.64" + version: "19.2.60" syncfusion_flutter_datagrid: dependency: "direct main" description: @@ -1202,13 +1216,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "19.1.64-beta" + syncfusion_flutter_datepicker: + dependency: transitive + description: + name: syncfusion_flutter_datepicker + url: "https://pub.dartlang.org" + source: hosted + version: "19.2.60" syncfusion_flutter_gauges: dependency: "direct main" description: name: syncfusion_flutter_gauges url: "https://pub.dartlang.org" source: hosted - version: "19.1.63" + version: "19.2.60" synchronized: dependency: transitive description: @@ -1251,6 +1272,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.0" + timezone: + dependency: transitive + description: + name: timezone + url: "https://pub.dartlang.org" + source: hosted + version: "0.7.0" timing: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index fe9749e..c89089f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.1.23+95 +version: 1.1.23+98 environment: sdk: ">=2.12.0 <3.0.0" @@ -69,8 +69,10 @@ dependencies: firebase_dynamic_links: ^2.0.8 firebase_in_app_messaging: ^0.5.0+8 - syncfusion_flutter_gauges: ^19.1.63 + syncfusion_flutter_gauges: ^19.2.60 syncfusion_flutter_datagrid: ^19.1.63 + syncfusion_flutter_charts: ^19.2.60 + syncfusion_flutter_calendar: ^19.2.60 flutter_facebook_auth: ^3.5.1 google_sign_in: ^5.0.3