1.1.22+3 corrections

This commit is contained in:
bossanyit 2021-09-05 07:47:15 +02:00
parent cebd83648b
commit e34add8185
57 changed files with 1577 additions and 1490 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

View File

@ -280,7 +280,10 @@
"Unleash your potential with WorkoutTest Premium!": "Unleash your potential with WorkoutTest Premium!", "Unleash your potential with WorkoutTest Premium!": "Unleash your potential with WorkoutTest Premium!",
"feature is reachable after you finished": "feature is reachable after you finished", "feature is reachable after you finished": "feature is reachable after you finished",
"100% test circles": "100% test rounds", "100% test circles": "100% test rounds",
"Keep testing": "Keep Testing", "week": "week",
"100% completed training": "100% completed training",
"after": "after",
"Keep testing": "Keep Training",
"Enjoy also this premium fetaure to show all old evaluation data of your successful exercises.": "Enjoy also this premium fetaure to show all old evaluation data of your successful exercises.", "Enjoy also this premium fetaure to show all old evaluation data of your successful exercises.": "Enjoy also this premium fetaure to show all old evaluation data of your successful exercises.",
"Please define your Exercise Plan": "Please define your Exercise Plan", "Please define your Exercise Plan": "Please define your Exercise Plan",
"Go to: 'Training Plan' - 'Edit My Custom Plan'": "Go to: 'Training Plan' - 'Edit My Custom Plan'", "Go to: 'Training Plan' - 'Edit My Custom Plan'": "Go to: 'Training Plan' - 'Edit My Custom Plan'",
@ -463,8 +466,6 @@
"because only that way can we show you your exercises, results and evaluations.": "because only that way can we show you your exercises, results and evaluations.", "because only that way can we show you your exercises, results and evaluations.": "because only that way can we show you your exercises, results and evaluations.",
"because only that way can we show you the personalized development diagrams and analysises": "because only that way can we show you the personalized development diagrams and analysises", "because only that way can we show you the personalized development diagrams and analysises": "because only that way can we show you the personalized development diagrams and analysises",
"because only in that way can you begin to execute a training plan": "because only in that way can you begin to execute a training plan", "because only in that way can you begin to execute a training plan": "because only in that way can you begin to execute a training plan",
"Please try to execute this exercise with exact weight and repeats what is suggested": "Please try to execute this exercise with exact weight and repeats what is suggested",
"Please try to execute this exercise with exact repeats what is suggested": "Please try to execute this exercise with exact repeats what is suggested",
"Please take a relative bigger weight and at least 12 times and do your best! MAXIMIZE it!": "Please take a relative bigger weight and at least 12 times and do your best! MAXIMIZE it!", "Please take a relative bigger weight and at least 12 times and do your best! MAXIMIZE it!": "Please take a relative bigger weight and at least 12 times and do your best! MAXIMIZE it!",
"During the exercise you should try your best:": "During the exercise you should try your best:", "During the exercise you should try your best:": "During the exercise you should try your best:",
"do it with the possible maximum repeats.": "do it with the possible maximum repeats.", "do it with the possible maximum repeats.": "do it with the possible maximum repeats.",
@ -509,5 +510,35 @@
"optimized training plans, customized to your fitness state and strength:": "optimized training plans, customized to your fitness state and strength:", "optimized training plans, customized to your fitness state and strength:": "optimized training plans, customized to your fitness state and strength:",
"Soon! Check back later for the plan details": "Soon! Check back later for the plan details", "Soon! Check back later for the plan details": "Soon! Check back later for the plan details",
"mins": "mins", "mins": "mins",
"set": "set" "set": "set",
"Set / Reps / Weight": "Set / Reps / Weight",
"Weight_": "Weight",
"Got It": "Got It",
"Done!": "Done!",
"Show this tip no more": "Show this tip no more",
"Don't forget, the app can give you only the right values, if you execute the task regurarly and after the exact instructions.": "Don't forget, the app can give you only the right values, if you execute the task regurarly and after the exact instructions.",
"Please take a middle weight which you are able to do 8-20 times with.": "Please take a middle weight which you are able to do 8-20 times with.",
"Execute your MAXIMUM repeats with it!": "Execute your MAXIMUM repeats with it!",
"Type here your selected weight,": "Type here your selected weight,",
"then here, how many times could you repeat it!": "then here, how many times could you repeat it!",
"After you done, click to the OK button!": "After you done, click to the OK button!",
"If you executed less repeats than given, modify it, and click to OK!": "If you executed less repeats than given, modify it, and click to OK!",
"Please type in a real number!": "Please type in a real number!",
"Exception: Please type in a real number!": "Please type in a real number!",
"If you could do less, then modify and click to OK": "If you could do less, then modify and click to OK",
"Here is your tailored weight,": "Here is your tailored weight,",
"and executed with this number of repeats!": "and execute it with this number of repeats!",
"You can change the weight, if you could not set it in the training room": "You can change the weight, if you could not set it in the training room",
"Exception: Please type your repeats!": "Please type your maximum repeats!",
"For your optimal development we calculated a suitable weight and repeats": "For your optimal development we calculated a suitable weight and repeats",
"It is time to exhaust your muscles": "It is time to really exhaust your muscles",
"Next Exercise": "Next Exercise",
"and execute it with maximum repeats!": "and execute it with maximum repeats!",
"10 days Premium for free": "10 days Premium for free",
"Would you like to try all premium functions for 10 days, without any subscription or bank card data?": "Would you like to try all premium functions for 10 days, without any subscription or bank card data?",
"If you click to 'Yes', all premium functions will be available right now.": "If you click to 'Yes', all premium functions will be available right now.",
"If you click to 'No', you can use all basic functions, and you will loose the oppurtunity to try the premium functions for free.": "If you click to 'No', you can use all basic functions, and you will loose the oppurtunity to try the premium functions for free.",
"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"
} }

View File

@ -278,6 +278,9 @@
"Unleash your potential with WorkoutTest Premium!": "Bontakoztasd ki az erősségeidet WorkoutTest Prémiummal!", "Unleash your potential with WorkoutTest Premium!": "Bontakoztasd ki az erősségeidet WorkoutTest Prémiummal!",
"feature is reachable after you finished": "funkció elérhető számodra, miután teljesítetted", "feature is reachable after you finished": "funkció elérhető számodra, miután teljesítetted",
"100% test circles": "100%-os teszt-köröd", "100% test circles": "100%-os teszt-köröd",
"week": "hét",
"100% completed training": "alatt 100%-osan végrehajtott edzést",
"after": "",
"Keep testing": "Folytasd a tesztelést", "Keep testing": "Folytasd a tesztelést",
"Enjoy also this premium feature to show all old evaluation data of your successful exercises.": "Élvezd ezt a prémium funkciót is, amely megjeleníti a korábbi gyakorlatok teljes kiértékelését", "Enjoy also this premium feature to show all old evaluation data of your successful exercises.": "Élvezd ezt a prémium funkciót is, amely megjeleníti a korábbi gyakorlatok teljes kiértékelését",
"Please define your Exercise Plan": "Kérlek készíts edzéstervet!", "Please define your Exercise Plan": "Kérlek készíts edzéstervet!",
@ -507,5 +510,35 @@
"optimized training plans, customized to your fitness state and strength:": "optiomalizált edzés terveket, amelyeket a te erő- és fitnesz állapododra szabunk:", "optimized training plans, customized to your fitness state and strength:": "optiomalizált edzés terveket, amelyeket a te erő- és fitnesz állapododra szabunk:",
"Soon! Check back later for the plan details": "Nemsokára! Nézz vissza később, amikor már aktiváltuk az edzésterv részleteit", "Soon! Check back later for the plan details": "Nemsokára! Nézz vissza később, amikor már aktiváltuk az edzésterv részleteit",
"mins": "perc", "mins": "perc",
"set": "sorozat" "set": "sorozat",
"Set / Reps / Weight": "Sorozat / Ismétlés / Súly",
"Weight_": "Súly",
"Got It": "Értettem!",
"Done!": "Kész!",
"Show this tip no more": "Ne mutasd többet ezt a tippet",
"Don't forget, the app can give you only the right values, if you execute the task regurarly and after the exact instructions.": "Ne felejtsd el, hogy a program csak akkor tud számodra megfelelő értéket adni, ha helyesen, és az utasítás szerint végzed el a feladatokat",
"Please take a middle weight which you are able to do 8-20 times with.": "Vegyél egy közepes súlyt, amivel 8-20 ismétlésre vagy képes.",
"Execute your MAXIMUM repeats with it!": "Végezz vele MAXIMUM ismétlést",
"Type here your selected weight,": "Írd be ide a kiválasztott súlyt,",
"then here, how many times could you repeat it!": "majd ide, hogy mennyi ismétlés sikerült belőle!",
"After you done, click to the OK button!": "Ha elvégezted a gyakorlatot, kattints az OK gombra!",
"If you executed less repeats than given, modify it, and click to OK!": "Ha kevesebb sikerült, akkor írd be és utána nyomj OK-t!",
"Please type in a real number!": "Kérlek írj be egy számot eredményként",
"Exception: Please type in a real number!": "Kérlek írj be egy számot eredményként",
"If you could do less, then modify and click to OK": "Ha kevesebb sikerült, írd be és kattints az OK-ra",
"Here is your tailored weight,": "Itt van a rádszabott súly,",
"and executed with this number of repeats!": "ennyi ismétlést végezz!",
"You can change the weight, if you could not set it in the training room": "Változtasd meg a súlyt, ha éppen nincs ennyi az edzőteremben",
"Exception: Please type your repeats!": "Kérlek írd be a maximum ismétlésed számát!",
"For your optimal development we calculated a suitable weight and repeats": "A fejlődésed érdekében meghatároztuk Neked a megfelelő súlyt és ismétlésszámot",
"It is time to exhaust your muscles": "Itt az idő, hogy igazán lemerítsd az izmaidat.",
"Next Exercise": "Következő",
"and execute it with maximum repeats!": "és hajtsd végre maximális ismétléssel!",
"10 days Premium for free": "10 nap Prémium előfizetés díjmentesen",
"Would you like to try all premium functions for 10 days, without any subscription or bank card data?": "Szeretnéd kipróbálni 10 napig az összes prémium funkciót, előfizetés és bankkártya-adatok megadása nélkül?",
"If you click to 'Yes', all premium functions will be available right now.": "Ha az 'Igen'-re kattintasz, azonnal eléred az összes prémium funkciót, edzést.",
"If you click to 'No', you can use all basic functions, and you will loose the oppurtunity to try the premium functions for free.": "Ha a 'Nem'-re kattintasz, használhatod az összes alapfunkciót, de elveszted a lehetőséget, hogy a prémium funkciókat ingyen kipróbáld.",
"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"
} }

View File

@ -388,7 +388,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 3;
DEVELOPMENT_TEAM = SFJJBDCU6Z; DEVELOPMENT_TEAM = SFJJBDCU6Z;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
@ -531,7 +531,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 3;
DEVELOPMENT_TEAM = SFJJBDCU6Z; DEVELOPMENT_TEAM = SFJJBDCU6Z;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
@ -566,7 +566,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 3;
DEVELOPMENT_TEAM = SFJJBDCU6Z; DEVELOPMENT_TEAM = SFJJBDCU6Z;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (

View File

@ -1,97 +1,97 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string> <string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string> <string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key> <key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string> <string>6.0</string>
<key>CFBundleName</key> <key>CFBundleName</key>
<string>WorkoutTest</string> <string>WorkoutTest</string>
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string> <string>$(MARKETING_VERSION)</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleURLTypes</key> <key>CFBundleURLTypes</key>
<array> <array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>aitrainer.page.link</string>
<key>CFBundleURLSchemes</key>
<array>
<string>wt001</string>
<string>fb584181112271127</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>FacebookAdvertiserIDCollectionEnabled</key>
<string>TRUE</string>
<key>FacebookAppID</key>
<string>584181112271127</string>
<key>FacebookAutoLogAppEventsEnabled</key>
<string>TRUE</string>
<key>FacebookDisplayName</key>
<string>Workout Test</string>
<key>FirebaseAppDelegateProxyEnabled</key>
<string>NO</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>https</string>
<string>http</string>
<string>fbapi</string>
<string>fbapi20130214</string>
<string>fbapi20130410</string>
<string>fbapi20130702</string>
<string>fbapi20131010</string>
<string>fbapi20131219</string>
<string>fbapi20140410</string>
<string>fbapi20140116</string>
<string>fbapi20150313</string>
<string>fbapi20150629</string>
<string>fbapi20160328</string>
<string>fb-messenger-share-api</string>
<string>fbauth2</string>
<string>fbshareextension</string>
</array>
<key>LSMinimumSystemVersion</key>
<string>11.0.0</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict> <dict>
<key>NSAllowsArbitraryLoads</key> <key>CFBundleTypeRole</key>
<true/> <string>Editor</string>
<key>CFBundleURLName</key>
<string>aitrainer.page.link</string>
<key>CFBundleURLSchemes</key>
<array>
<string>wt001</string>
<string>fb584181112271127</string>
</array>
</dict> </dict>
<key>UIBackgroundModes</key> </array>
<array> <key>CFBundleVersion</key>
<string>remote-notification</string> <string>$(CURRENT_PROJECT_VERSION)</string>
</array> <key>FacebookAdvertiserIDCollectionEnabled</key>
<key>UILaunchStoryboardName</key> <string>TRUE</string>
<string>Launch Screen</string> <key>FacebookAppID</key>
<key>UIMainStoryboardFile</key> <string>584181112271127</string>
<string>Main</string> <key>FacebookAutoLogAppEventsEnabled</key>
<key>UISupportedInterfaceOrientations</key> <string>TRUE</string>
<array> <key>FacebookDisplayName</key>
<string>UIInterfaceOrientationPortrait</string> <string>Workout Test</string>
</array> <key>FirebaseAppDelegateProxyEnabled</key>
<key>UISupportedInterfaceOrientations~ipad</key> <string>NO</string>
<array> <key>LSApplicationQueriesSchemes</key>
<string>UIInterfaceOrientationPortrait</string> <array>
<string>UIInterfaceOrientationPortraitUpsideDown</string> <string>https</string>
<string>UIInterfaceOrientationLandscapeLeft</string> <string>http</string>
<string>UIInterfaceOrientationLandscapeRight</string> <string>fbapi</string>
</array> <string>fbapi20130214</string>
<key>UIViewControllerBasedStatusBarAppearance</key> <string>fbapi20130410</string>
<false/> <string>fbapi20130702</string>
<string>fbapi20131010</string>
<string>fbapi20131219</string>
<string>fbapi20140410</string>
<string>fbapi20140116</string>
<string>fbapi20150313</string>
<string>fbapi20150629</string>
<string>fbapi20160328</string>
<string>fb-messenger-share-api</string>
<string>fbauth2</string>
<string>fbshareextension</string>
</array>
<key>LSMinimumSystemVersion</key>
<string>11.0.0</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict> </dict>
<key>UIBackgroundModes</key>
<array>
<string>remote-notification</string>
</array>
<key>UILaunchStoryboardName</key>
<string>Launch Screen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist> </plist>

View File

@ -3,6 +3,7 @@ import 'dart:async';
import 'package:aitrainer_app/model/cache.dart'; import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/sport.dart'; import 'package:aitrainer_app/model/sport.dart';
import 'package:aitrainer_app/repository/customer_repository.dart'; import 'package:aitrainer_app/repository/customer_repository.dart';
import 'package:aitrainer_app/repository/mautic_repository.dart';
import 'package:aitrainer_app/util/common.dart'; import 'package:aitrainer_app/util/common.dart';
import 'package:bloc/bloc.dart'; import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
@ -29,8 +30,8 @@ class CustomerChangeBloc extends Bloc<CustomerChangeEvent, CustomerChangeState>
weight = this.customerRepository.getWeight() == 0 ? 60 : this.customerRepository.getWeight(); weight = this.customerRepository.getWeight() == 0 ? 60 : this.customerRepository.getWeight();
height = this.customerRepository.getHeight() == 0 ? 170 : this.customerRepository.getHeight(); height = this.customerRepository.getHeight() == 0 ? 170 : this.customerRepository.getHeight();
// selectedSport = customerRepository.getSport(); selectedFitnessItem = customerRepository.fitnessLevel;
//print("selected: $selectedFitnessItem sport: $selectedSport " + customerRepository.customer!.fitnessLevel.toString()); selectedSport = customerRepository.getSport();
} }
Sport? selectedSport; Sport? selectedSport;
@ -95,6 +96,7 @@ class CustomerChangeBloc extends Bloc<CustomerChangeEvent, CustomerChangeState>
} else if (event is CustomerSportChange) { } else if (event is CustomerSportChange) {
yield CustomerChangeLoading(); yield CustomerChangeLoading();
selectedSport = event.sport; selectedSport = event.sport;
print("Selected Sport $selectedSport");
yield CustomerDataChanged(); yield CustomerDataChanged();
} else if (event is CustomerSaveFitness) { } else if (event is CustomerSaveFitness) {
yield CustomerChangeLoading(); yield CustomerChangeLoading();
@ -137,6 +139,8 @@ class CustomerChangeBloc extends Bloc<CustomerChangeEvent, CustomerChangeState>
} }
await customerRepository.saveCustomer(); await customerRepository.saveCustomer();
MauticRepository mauticRepository = MauticRepository(customerRepository: customerRepository);
await mauticRepository.sendMauticDataChange();
Cache().initBadges(); Cache().initBadges();
yield CustomerSaveSuccess(); yield CustomerSaveSuccess();
} else { } else {
@ -151,10 +155,6 @@ class CustomerChangeBloc extends Bloc<CustomerChangeEvent, CustomerChangeState>
bool validation() { bool validation() {
if (customerRepository.customer == null) throw Exception("Customer object not defined"); if (customerRepository.customer == null) throw Exception("Customer object not defined");
return true; return true;
/* return (emailValidation(customerRepository.customer!.email) == null) &&
(passwordValidation(customerRepository.customer!.password) == null) &&
(nameValidation(customerRepository.customer!.firstname) == null) &&
(nameValidation(customerRepository.customer!.name) == null); */
} }
String? emailValidation(String? email) { String? emailValidation(String? email) {

View File

@ -1,5 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'package:aitrainer_app/bloc/timer/timer_bloc.dart'; import 'package:aitrainer_app/bloc/timer/timer_bloc.dart';
import 'package:aitrainer_app/model/exercise.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart'; import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:bloc/bloc.dart'; import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
@ -26,7 +27,6 @@ class ExerciseControlBloc extends Bloc<ExerciseControlEvent, ExerciseControlStat
late double initialRM; late double initialRM;
late double unitQuantity; late double unitQuantity;
late double quantity; late double quantity;
late double origQuantity;
late double oneRepQuantity; late double oneRepQuantity;
late double oneRepUnitQuantity; late double oneRepUnitQuantity;
@ -36,6 +36,8 @@ class ExerciseControlBloc extends Bloc<ExerciseControlEvent, ExerciseControlStat
double scrollOffset = 0; double scrollOffset = 0;
late ExerciseTypeLocal exerciseTypeLocal; late ExerciseTypeLocal exerciseTypeLocal;
List<Exercise> controlList = [];
@override @override
ExerciseControlBloc({required this.exerciseRepository, required this.readonly, required this.timerBloc}) ExerciseControlBloc({required this.exerciseRepository, required this.readonly, required this.timerBloc})
: super(ExerciseControlInitial()) { : super(ExerciseControlInitial()) {
@ -53,29 +55,29 @@ class ExerciseControlBloc extends Bloc<ExerciseControlEvent, ExerciseControlStat
if (oneRepQuantity > 25) { if (oneRepQuantity > 25) {
quantity = 35; quantity = 35;
} }
origQuantity = quantity;
exerciseRepository.setUnitQuantity(unitQuantity); exerciseRepository.setUnitQuantity(unitQuantity);
exerciseRepository.setQuantity(quantity); exerciseRepository.setQuantity(quantity);
for (int i = 0; i < 3; i++) {
Exercise exercise = Exercise();
exercise.quantity = quantity;
exercise.unitQuantity = unitQuantity;
controlList.add(exercise);
}
timerBloc.add(TimerStart(duration: 300)); timerBloc.add(TimerStart(duration: 300));
} }
@override @override
Stream<ExerciseControlState> mapEventToState(ExerciseControlEvent event) async* { Stream<ExerciseControlState> mapEventToState(ExerciseControlEvent event) async* {
try { try {
/* if (event is ExerciseControlLoad) {
yield ExerciseControlLoading();
step = 1;
yield ExerciseControlReady();
} else */
if (event is ExerciseControlQuantityChange) { if (event is ExerciseControlQuantityChange) {
//yield ExerciseControlLoading();
if (event.step == step) { if (event.step == step) {
exerciseRepository.setQuantity(event.quantity); exerciseRepository.setQuantity(event.quantity);
quantity = event.quantity; quantity = event.quantity;
controlList[step - 1].quantity = quantity;
} }
//yield ExerciseControlReady();
} else if (event is ExerciseControlUnitQuantityChange) { } else if (event is ExerciseControlUnitQuantityChange) {
yield ExerciseControlLoading(); yield ExerciseControlLoading();
print("event step ${event.step} quantity ${event.quantity}"); print("event step ${event.step} quantity ${event.quantity}");
@ -85,7 +87,8 @@ class ExerciseControlBloc extends Bloc<ExerciseControlEvent, ExerciseControlStat
unitQuantity = event.quantity; unitQuantity = event.quantity;
quantity = calculateQuantityByUnitQuantity().toDouble(); quantity = calculateQuantityByUnitQuantity().toDouble();
exerciseRepository.setQuantity(quantity); exerciseRepository.setQuantity(quantity);
origQuantity = quantity; controlList[step - 1].unitQuantity = event.quantity;
controlList[step - 1].quantity = quantity;
} }
yield ExerciseControlReady(); yield ExerciseControlReady();
} else if (event is ExerciseControlSubmit) { } else if (event is ExerciseControlSubmit) {
@ -94,13 +97,11 @@ class ExerciseControlBloc extends Bloc<ExerciseControlEvent, ExerciseControlStat
step++; step++;
scrollOffset = step * 400.0; scrollOffset = step * 400.0;
quantity = origQuantity;
if (exerciseRepository.exercise!.quantity == null) { if (exerciseRepository.exercise!.quantity == null) {
exerciseRepository.setQuantity(quantity); exerciseRepository.setQuantity(quantity);
} }
exerciseRepository.end = DateTime.now(); exerciseRepository.end = DateTime.now();
await exerciseRepository.addExercise(); await exerciseRepository.addExercise();
//exerciseRepository.initExercise();
step <= 3 ? timerBloc.add(TimerStart(duration: 300)) : timerBloc.add(TimerEnd(duration: 300)); step <= 3 ? timerBloc.add(TimerStart(duration: 300)) : timerBloc.add(TimerEnd(duration: 300));
} }

View File

@ -25,8 +25,8 @@ class ExerciseNewBloc extends Bloc<ExerciseNewEvent, ExerciseNewState> with Logg
final CustomerRepository customerRepository; final CustomerRepository customerRepository;
final MenuBloc menuBloc; final MenuBloc menuBloc;
late AnimationController bmiAnimationController; late AnimationController bmiAnimationController;
double quantity = 12; double quantity = -1;
double unitQuantity = 30; double unitQuantity = -1;
double bmi = 0; double bmi = 0;
double bmr = 0; double bmr = 0;
double goalBMI = 0; double goalBMI = 0;
@ -148,6 +148,10 @@ class ExerciseNewBloc extends Bloc<ExerciseNewEvent, ExerciseNewState> with Logg
yield ExerciseNewReady(); yield ExerciseNewReady();
} else if (event is ExerciseNewSubmit) { } else if (event is ExerciseNewSubmit) {
yield ExerciseNewLoading(); yield ExerciseNewLoading();
if (quantity == -1 || unitQuantity == -1) {
yield ExerciseNewReady();
throw Exception("Please type in a real number");
}
exerciseRepository.end = DateTime.now(); exerciseRepository.end = DateTime.now();
await exerciseRepository.addExercise(); await exerciseRepository.addExercise();
// exerciseRepository.initExercise(); // exerciseRepository.initExercise();

View File

@ -2,8 +2,11 @@ import 'dart:async';
import 'package:aitrainer_app/bloc/account/account_bloc.dart'; import 'package:aitrainer_app/bloc/account/account_bloc.dart';
import 'package:aitrainer_app/model/cache.dart'; import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/customer.dart';
import 'package:aitrainer_app/repository/customer_repository.dart'; import 'package:aitrainer_app/repository/customer_repository.dart';
import 'package:aitrainer_app/repository/mautic_repository.dart';
import 'package:aitrainer_app/repository/split_test_respository.dart'; import 'package:aitrainer_app/repository/split_test_respository.dart';
import 'package:aitrainer_app/repository/training_plan_repository.dart';
import 'package:aitrainer_app/repository/user_repository.dart'; import 'package:aitrainer_app/repository/user_repository.dart';
import 'package:aitrainer_app/util/common.dart'; import 'package:aitrainer_app/util/common.dart';
import 'package:aitrainer_app/util/enums.dart'; import 'package:aitrainer_app/util/enums.dart';
@ -19,7 +22,7 @@ part 'login_state.dart';
class LoginBloc extends Bloc<LoginEvent, LoginState> with Trans { class LoginBloc extends Bloc<LoginEvent, LoginState> with Trans {
final AccountBloc accountBloc; final AccountBloc accountBloc;
final UserRepository userRepository; final UserRepository userRepository;
final CustomerRepository customerRepository = CustomerRepository(); late CustomerRepository? customerRepository;
final SplitTestRepository splitTestRepository = SplitTestRepository(); final SplitTestRepository splitTestRepository = SplitTestRepository();
final BuildContext context; final BuildContext context;
final bool isRegistration; final bool isRegistration;
@ -30,7 +33,12 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> with Trans {
Color testColor = Colors.green[800]!; Color testColor = Colors.green[800]!;
bool emailCheckbox = true; bool emailCheckbox = true;
LoginBloc({required this.accountBloc, required this.userRepository, required this.context, required this.isRegistration}) LoginBloc(
{required this.accountBloc,
required this.userRepository,
required this.context,
required this.isRegistration,
this.customerRepository})
: super(LoginInitial()) { : super(LoginInitial()) {
String colorString = splitTestRepository.getSplitTestValue("registration_skip"); String colorString = splitTestRepository.getSplitTestValue("registration_skip");
if (colorString == "red") { if (colorString == "red") {
@ -40,6 +48,9 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> with Trans {
if (emailCheckboxString == "0") { if (emailCheckboxString == "0") {
emailCheckbox = false; emailCheckbox = false;
} }
if (customerRepository == null) {
customerRepository = CustomerRepository();
}
} }
@override @override
@ -87,56 +98,44 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> with Trans {
yield LoginSuccess(); yield LoginSuccess();
} else if (event is RegistrationSubmit) { } else if (event is RegistrationSubmit) {
yield LoginLoading(); yield LoginLoading();
/* if (!this.dataPolicyAllowed) {
throw Exception("Please accept our data policy");
} */
final String? validationError = validate(); final String? validationError = validate();
if (validationError != null) { if (validationError != null) {
yield LoginError(message: validationError); yield LoginError(message: validationError);
} else { } else {
await userRepository.addUser(); await userRepository.addUser();
accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!)); accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!));
customerRepository.customer!.emailSubscription = emailSubscription == true ? 1 : 0; customerRepository!.customer!.emailSubscription = emailSubscription == true ? 1 : 0;
await saveCustomer(); await afterRegistration("email");
Track().track(TrackingEvent.registration, eventValue: "email");
Cache().setLoginType(LoginType.email); Cache().setLoginType(LoginType.email);
yield LoginSuccess(); yield LoginSuccess();
} }
} else if (event is RegistrationFB) { } else if (event is RegistrationFB) {
yield LoginLoading(); yield LoginLoading();
/* if (!this.dataPolicyAllowed) {
throw Exception("Please accept our data policy");
} */
Cache().setLoginType(LoginType.fb); Cache().setLoginType(LoginType.fb);
await userRepository.addUserFB(); await userRepository.addUserFB();
accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!)); accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!));
customerRepository.customer!.emailSubscription = emailSubscription == true ? 1 : 0; customerRepository!.customer!.emailSubscription = emailSubscription == true ? 1 : 0;
await saveCustomer(); await afterRegistration("FB");
Track().track(TrackingEvent.registration, eventValue: "FB");
yield LoginSuccess(); yield LoginSuccess();
} else if (event is RegistrationGoogle) { } else if (event is RegistrationGoogle) {
yield LoginLoading(); yield LoginLoading();
/* if (!this.dataPolicyAllowed) {
throw Exception("Please accept our data policy");
} */
Cache().setLoginType(LoginType.google); Cache().setLoginType(LoginType.google);
await userRepository.addUserGoogle(); await userRepository.addUserGoogle();
accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!)); accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!));
customerRepository.customer!.emailSubscription = emailSubscription == true ? 1 : 0; customerRepository!.customer!.emailSubscription = emailSubscription == true ? 1 : 0;
await saveCustomer(); await afterRegistration("Google");
Track().track(TrackingEvent.registration, eventValue: "Google");
yield LoginSuccess(); yield LoginSuccess();
} else if (event is RegistrationApple) { } else if (event is RegistrationApple) {
yield LoginLoading(); yield LoginLoading();
/* if (!this.dataPolicyAllowed) {
throw Exception("Please accept our data policy");
} */
Cache().setLoginType(LoginType.apple); Cache().setLoginType(LoginType.apple);
await userRepository.addUserApple(); await userRepository.addUserApple();
accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!)); accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!));
customerRepository.customer!.emailSubscription = emailSubscription == true ? 1 : 0; customerRepository!.customer!.emailSubscription = emailSubscription == true ? 1 : 0;
await saveCustomer(); await afterRegistration("Apple");
Track().track(TrackingEvent.registration, eventValue: "Apple");
yield LoginSuccess(); yield LoginSuccess();
} else if (event is DataProtectionClicked) { } else if (event is DataProtectionClicked) {
@ -162,10 +161,23 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> with Trans {
} }
} }
Future<void> saveCustomer() async { Future<void> afterRegistration(String event) async {
customerRepository.customer = Cache().userLoggedIn!; Customer tempCustomer = customerRepository!.customer!;
customerRepository.customer!.dataPolicyAllowed = 1; customerRepository!.customer = Cache().userLoggedIn!;
await customerRepository.saveCustomer(); customerRepository!.customer!.fitnessLevel = tempCustomer.fitnessLevel;
customerRepository!.customer!.goal = tempCustomer.goal;
customerRepository!.customer!.sex = tempCustomer.sex;
customerRepository!.customer!.dataPolicyAllowed = 1;
customerRepository!.customer!.emailSubscription = 1;
customerRepository!.customer!.syncedDate = DateTime.now();
customerRepository!.setCustomerProperty("Weight", tempCustomer.getProperty("Weight"));
customerRepository!.setCustomerProperty("Height", tempCustomer.getProperty("Height"));
await customerRepository!.saveCustomer();
MauticRepository mauticRepository = MauticRepository(customerRepository: customerRepository!);
await mauticRepository.sendMauticSubscription();
TrainingPlanRepository trainingPlanRepository = TrainingPlanRepository();
trainingPlanRepository.generateTrainingPlan();
Track().track(TrackingEvent.registration, eventValue: event);
} }
String? emailValidation(String? email) { String? emailValidation(String? email) {

View File

@ -7,6 +7,8 @@ import 'package:aitrainer_app/model/customer_training_plan_details.dart';
import 'package:aitrainer_app/model/exercise.dart'; import 'package:aitrainer_app/model/exercise.dart';
import 'package:aitrainer_app/model/exercise_plan_detail.dart'; import 'package:aitrainer_app/model/exercise_plan_detail.dart';
import 'package:aitrainer_app/model/exercise_type.dart'; import 'package:aitrainer_app/model/exercise_type.dart';
import 'package:aitrainer_app/model/training_plan.dart';
import 'package:aitrainer_app/model/training_plan_detail.dart';
import 'package:aitrainer_app/model/workout_menu_tree.dart'; import 'package:aitrainer_app/model/workout_menu_tree.dart';
import 'package:aitrainer_app/repository/training_plan_repository.dart'; import 'package:aitrainer_app/repository/training_plan_repository.dart';
import 'package:aitrainer_app/service/exercise_service.dart'; import 'package:aitrainer_app/service/exercise_service.dart';
@ -29,6 +31,9 @@ class TrainingPlanBloc extends Bloc<TrainingPlanEvent, TrainingPlanState> {
CustomerTrainingPlan? _myPlan; CustomerTrainingPlan? _myPlan;
CustomerTrainingPlanDetails? _myDetail; CustomerTrainingPlanDetails? _myDetail;
TrainingPlan? _myTrainingPlan;
final List<String> trainingPlanDayNames = [];
bool started = false; bool started = false;
final List<String> dayNames = []; final List<String> dayNames = [];
bool restarting = false; bool restarting = false;
@ -38,6 +43,9 @@ class TrainingPlanBloc extends Bloc<TrainingPlanEvent, TrainingPlanState> {
CustomerTrainingPlan? getMyPlan() => this._myPlan; CustomerTrainingPlan? getMyPlan() => this._myPlan;
setMyPlan(CustomerTrainingPlan? myPlan) => this._myPlan = myPlan; setMyPlan(CustomerTrainingPlan? myPlan) => this._myPlan = myPlan;
TrainingPlan? getMyTrainingPlan() => this._myTrainingPlan;
setMyTrainingPlan(TrainingPlan? myTrainingPlan) => this._myTrainingPlan = myTrainingPlan;
CustomerTrainingPlanDetails? getMyDetail() => this._myDetail; CustomerTrainingPlanDetails? getMyDetail() => this._myDetail;
setMyDetail(CustomerTrainingPlanDetails? value) => this._myDetail = value; setMyDetail(CustomerTrainingPlanDetails? value) => this._myDetail = value;
@ -88,6 +96,10 @@ class TrainingPlanBloc extends Bloc<TrainingPlanEvent, TrainingPlanState> {
yield TrainingPlanReady(); yield TrainingPlanReady();
} else if (event is TrainingPlanSaveExercise) { } else if (event is TrainingPlanSaveExercise) {
yield TrainingPlanLoading(); yield TrainingPlanLoading();
if (event.detail.repeats == -1) {
yield TrainingPlanReady();
throw Exception("Please type your repeats!");
}
if (event.detail.weight == -3) { if (event.detail.weight == -3) {
print("DropSet"); print("DropSet");
event.detail.state = ExercisePlanDetailState.finished; event.detail.state = ExercisePlanDetailState.finished;
@ -293,6 +305,83 @@ class TrainingPlanBloc extends Bloc<TrainingPlanEvent, TrainingPlanState> {
getActiveDayIndex(); getActiveDayIndex();
} }
void activateTrainingPlanDays() {
if (_myTrainingPlan == null || _myTrainingPlan!.details == null) {
return;
}
trainingPlanDayNames.clear();
String dayName = ".";
_myTrainingPlan!.details!.forEach((element) {
if (element.day != null && element.day != dayName) {
trainingPlanDayNames.add(element.day!);
dayName = element.day!;
}
});
if (trainingPlanDayNames.length == 0) {
dayName = "";
trainingPlanDayNames.add(dayName);
}
}
List<TrainingPlanDetail> trainingPlanDetailSummary(TrainingPlan plan, String dayName) {
List<TrainingPlanDetail> details = [];
TrainingPlanDetail? prev;
plan.details!.forEach((element) {
if (prev == null || element.exerciseTypeId != prev!.exerciseTypeId) {
if (element.day! == dayName) {
element.summary = getSummary(element);
details.add(element);
}
prev = element;
}
});
return details;
}
List<TrainingPlanDetail> getAllTrainingPlanDetailsSameExercise(TrainingPlanDetail detail) {
List<TrainingPlanDetail> list = [];
getMyTrainingPlan()!.details!.forEach((element) {
if (detail.exerciseTypeId == element.exerciseTypeId) {
list.add(element);
}
});
return list;
}
String getSummary(TrainingPlanDetail detail) {
String summary = "";
String set = "1";
set = detail.set.toString() + "/ ";
List<TrainingPlanDetail> details = getAllTrainingPlanDetailsSameExercise(detail);
int index = 0;
String quantities = "";
details.forEach((element) {
String delimiter = ", ";
if (index == 0) {
delimiter = "";
}
if (element.repeats == -1) {
quantities += delimiter + " MAX ";
} else {
quantities += delimiter + "${element.repeats}";
}
index++;
});
//quantities += " / ? kg";
summary = quantities;
return summary;
}
void addExtraExerciseType(String name, String dayName) { void addExtraExerciseType(String name, String dayName) {
if (Cache().getExerciseTypes() == null) { if (Cache().getExerciseTypes() == null) {
return; return;

View File

@ -307,6 +307,60 @@ class SuperTooltip {
isOpen = true; isOpen = true;
} }
void showBox(BuildContext targetContext) {
final renderBox = targetContext.findRenderObject() as RenderBox;
var size = renderBox.size;
print("Size $size");
if (containsBackgroundOverlay) {
_backGroundOverlay = OverlayEntry(
builder: (context) => _AnimationWrapper(
builder: (context, opacity) => AnimatedOpacity(
opacity: opacity,
duration: const Duration(milliseconds: 600),
child: GestureDetector(
onTap: () {
if (dismissOnTapOutside) {
close();
}
},
child: Container(
decoration: ShapeDecoration(
shape: _ShapeOverlay(
touchThrougArea, touchThroughAreaShape, touchThroughAreaCornerRadius, outsideBackgroundColor))),
),
),
));
}
_ballonOverlay = OverlayEntry(
builder: (context) => _AnimationWrapper(
builder: (context, opacity) => Positioned(
left: left, //offset.dx,
top: top,
width: size.width > maxWidth! ? maxWidth : size.width,
child: AnimatedOpacity(
duration: Duration(
milliseconds: 300,
),
opacity: opacity,
child: Stack(
fit: StackFit.passthrough,
children: [_buildPopUp(), _buildCloseButton()],
),
)),
));
var overlays = <OverlayEntry>[];
if (containsBackgroundOverlay) {
overlays.add(_backGroundOverlay!);
}
overlays.add(_ballonOverlay!);
Overlay.of(targetContext)!.insertAll(overlays);
isOpen = true;
}
Widget _buildPopUp() { Widget _buildPopUp() {
return Positioned( return Positioned(
child: Container( child: Container(
@ -675,6 +729,122 @@ class _PopupBallonLayoutDelegate extends SingleChildLayoutDelegate {
} }
} }
class _PopupBallonLayoutDelegateBox extends SingleChildLayoutDelegate {
final double? _minWidth;
final double? _maxWidth;
final double? _minHeight;
final double? _maxHeight;
final double? _top;
final double? _bottom;
final double? _left;
final double? _right;
final double? _outSidePadding;
_PopupBallonLayoutDelegateBox({
double? minWidth,
double? maxWidth,
double? minHeight,
double? maxHeight,
double? outSidePadding,
double? top,
double? bottom,
double? left,
double? right,
}) : _minWidth = minWidth,
_maxWidth = maxWidth,
_minHeight = minHeight,
_maxHeight = maxHeight,
_top = top,
_bottom = bottom,
_left = left,
_right = right,
_outSidePadding = outSidePadding;
@override
Offset getPositionForChild(Size size, Size childSize) {
double? calcLeftMostXtoTarget() {
double? leftMostXtoTarget;
if (_left != null) {
leftMostXtoTarget = _left;
} else if (_right != null) {
leftMostXtoTarget = max(
size.topLeft(Offset.zero).dx + _outSidePadding!, size.topRight(Offset.zero).dx - _outSidePadding! - childSize.width - _right!);
}
return leftMostXtoTarget;
}
double? calcTopMostYtoTarget() {
double? topmostYtoTarget;
if (_top != null) {
topmostYtoTarget = _top!;
} else if (_bottom != null) {
topmostYtoTarget = max(size.topLeft(Offset.zero).dy + _outSidePadding!,
size.bottomRight(Offset.zero).dy - _outSidePadding! - childSize.height - _bottom!);
}
return topmostYtoTarget;
}
return new Offset(calcLeftMostXtoTarget()!, _top!);
}
@override
BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
// print("ParentConstraints: $constraints");
var calcMinWidth = _minWidth ?? 0.0;
var calcMaxWidth = _maxWidth ?? double.infinity;
var calcMinHeight = _minHeight ?? 0.0;
var calcMaxHeight = _maxHeight ?? double.infinity;
void calcMinMaxWidth() {
if (_left != null && _right != null) {
calcMaxWidth = constraints.maxWidth - (_left! + _right!);
} else if ((_left != null && _right == null) || (_left == null && _right != null)) {
// make sure that the sum of left, right + maxwidth isn't bigger than the screen width.
var sideDelta = (_left ?? 0.0) + (_right ?? 0.0) + _outSidePadding!;
if (calcMaxWidth > constraints.maxWidth - sideDelta) {
calcMaxWidth = constraints.maxWidth - sideDelta;
}
} else {
if (calcMaxWidth > constraints.maxWidth - 2 * _outSidePadding!) {
calcMaxWidth = constraints.maxWidth - 2 * _outSidePadding!;
}
}
}
void calcMinMaxHeight() {
if (_top != null && _bottom != null) {
calcMaxHeight = constraints.maxHeight - (_top! + _bottom!);
} else if ((_top != null && _bottom == null) || (_top == null && _bottom != null)) {
// make sure that the sum of top, bottom + maxHeight isn't bigger than the screen Height.
var sideDelta = (_top ?? 0.0) + (_bottom ?? 0.0) + _outSidePadding!;
if (calcMaxHeight > constraints.maxHeight - sideDelta) {
calcMaxHeight = constraints.maxHeight - sideDelta;
}
} else {
if (calcMaxHeight > constraints.maxHeight - 2 * _outSidePadding!) {
calcMaxHeight = constraints.maxHeight - 2 * _outSidePadding!;
}
}
}
var childConstraints = new BoxConstraints(
minWidth: calcMinWidth > calcMaxWidth ? calcMaxWidth : calcMinWidth,
maxWidth: calcMaxWidth,
minHeight: calcMinHeight > calcMaxHeight ? calcMaxHeight : calcMinHeight,
maxHeight: calcMaxHeight);
// print("Child constraints: $childConstraints");
return childConstraints;
}
@override
bool shouldRelayout(SingleChildLayoutDelegate oldDelegate) {
return false;
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
class _BubbleShape extends ShapeBorder { class _BubbleShape extends ShapeBorder {

View File

@ -41,7 +41,6 @@ import 'package:aitrainer_app/view/test_set_edit.dart';
import 'package:aitrainer_app/view/test_set_execute.dart'; import 'package:aitrainer_app/view/test_set_execute.dart';
import 'package:aitrainer_app/view/test_set_new.dart'; import 'package:aitrainer_app/view/test_set_new.dart';
import 'package:aitrainer_app/view/training_plan_activate_page.dart'; import 'package:aitrainer_app/view/training_plan_activate_page.dart';
import 'package:aitrainer_app/view/training_plan_execute_page.dart';
import 'package:aitrainer_app/view/training_plan_exercise.dart'; import 'package:aitrainer_app/view/training_plan_exercise.dart';
import 'package:aitrainer_app/widgets/home.dart'; import 'package:aitrainer_app/widgets/home.dart';
import 'package:aitrainer_app/library/facebook_app_events/facebook_app_events.dart'; import 'package:aitrainer_app/library/facebook_app_events/facebook_app_events.dart';
@ -180,8 +179,8 @@ Future<Null> main() async {
BlocProvider<TestSetExecuteBloc>( BlocProvider<TestSetExecuteBloc>(
create: (BuildContext context) => TestSetExecuteBloc(), create: (BuildContext context) => TestSetExecuteBloc(),
), ),
/* BlocProvider<TutorialBloc>( BlocProvider<TutorialBloc>(
create: (BuildContext context) => TutorialBloc(tutorialName: ActivityDone.tutorialExecuteFirstTest.toStr())), */ create: (BuildContext context) => TutorialBloc(tutorialName: ActivityDone.tutorialExecuteFirstTest.toStr())),
BlocProvider<TrainingPlanBloc>(create: (context) { BlocProvider<TrainingPlanBloc>(create: (context) {
final MenuBloc menuBloc = BlocProvider.of<MenuBloc>(context); final MenuBloc menuBloc = BlocProvider.of<MenuBloc>(context);
return TrainingPlanBloc(menuBloc: menuBloc, trainingPlanRepository: TrainingPlanRepository()); return TrainingPlanBloc(menuBloc: menuBloc, trainingPlanRepository: TrainingPlanRepository());
@ -283,7 +282,6 @@ class WorkoutTestApp extends StatelessWidget {
'myTrainingPlanCustom': (context) => TrainingPlanCustomPage(), 'myTrainingPlanCustom': (context) => TrainingPlanCustomPage(),
'myTrainingPlanCustomAdd': (context) => TrainingPlanCustomAddPage(), 'myTrainingPlanCustomAdd': (context) => TrainingPlanCustomAddPage(),
'myTrainingPlanActivate': (context) => TrainingPlanActivatePage(), 'myTrainingPlanActivate': (context) => TrainingPlanActivatePage(),
'myTrainingPlanExecute2': (context) => TrainingPlanExecutePage(),
'myTrainingPlanExecute': (context) => TrainingPlanExecute(), 'myTrainingPlanExecute': (context) => TrainingPlanExecute(),
'myTrainingPlanExercise': (context) => TrainingPlanExercise(), 'myTrainingPlanExercise': (context) => TrainingPlanExercise(),
'myTrainingEvaluation': (context) => TrainingEvaluationPage(), 'myTrainingEvaluation': (context) => TrainingEvaluationPage(),

View File

@ -71,7 +71,11 @@ enum ActivityDone {
tutorialBasicLegPress, tutorialBasicLegPress,
tutorialDevelopment, tutorialDevelopment,
isExerciseLogSeen, isExerciseLogSeen,
isMuscleDevelopmentSeen isMuscleDevelopmentSeen,
isBodyTypeSeen,
exerciseSaveTestTip,
exerciseSaveTrainingTip,
exerciseSaveTestsetTip
} }
extension ActivityDoneExt on ActivityDone { extension ActivityDoneExt on ActivityDone {
@ -641,8 +645,8 @@ class Cache with Logging {
} }
if (this._exercises == null || this._exercises!.isEmpty) { if (this._exercises == null || this._exercises!.isEmpty) {
setBadge("home", true); setBadge("home", true);
setBadge("Muscle Build / Shape Toning", true); setBadge("Custom Tests", true);
setBadge("Cardio", true); setBadge("Start Training", true);
} }
if (customerRepository.getHeight() == 0) { if (customerRepository.getHeight() == 0) {
setBadge("BMI", true); setBadge("BMI", true);
@ -726,6 +730,8 @@ class Cache with Logging {
sharedPreferences.setBool(activity.toStr(), true); sharedPreferences.setBool(activity.toStr(), true);
} }
bool isActivityDone(ActivityDone activity) => activitiesDone[activity.toStr()] == true;
List<Evaluation>? get evaluations => this._evaluations; List<Evaluation>? get evaluations => this._evaluations;
set evaluations(List<Evaluation>? value) => this._evaluations = value; set evaluations(List<Evaluation>? value) => this._evaluations = value;

View File

@ -24,6 +24,7 @@ class Customer {
DateTime? dateChange; DateTime? dateChange;
int? emailSubscription; int? emailSubscription;
int? sportId; int? sportId;
DateTime? syncedDate;
DateTime? trialDate; DateTime? trialDate;
LinkedHashMap<String, CustomerProperty> properties = LinkedHashMap(); LinkedHashMap<String, CustomerProperty> properties = LinkedHashMap();
@ -71,6 +72,7 @@ class Customer {
this.dataPolicyAllowed = json['dataPolicyAllowed']; this.dataPolicyAllowed = json['dataPolicyAllowed'];
this.emailSubscription = json['emailSubscription']; this.emailSubscription = json['emailSubscription'];
this.sportId = json['sportId']; this.sportId = json['sportId'];
this.syncedDate = json['syncedDate'] == null ? null : DateTime.parse(json['syncedDate']);
this.trialDate = json['trialDate'] == null ? null : DateTime.parse(json['trialDate']); this.trialDate = json['trialDate'] == null ? null : DateTime.parse(json['trialDate']);
this.dateAdd = json['dateAdd'] == null ? DateTime.parse("0000-00-00") : DateTime.parse(json['dateAdd']); this.dateAdd = json['dateAdd'] == null ? DateTime.parse("0000-00-00") : DateTime.parse(json['dateAdd']);
@ -96,9 +98,13 @@ class Customer {
"dateChange": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateChange!), "dateChange": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateChange!),
"emailSubscription": this.emailSubscription, "emailSubscription": this.emailSubscription,
"sportId": this.sportId, "sportId": this.sportId,
"trialDate": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.trialDate!), "syncedDate": this.syncedDate == null ? null : DateFormat('yyyy-MM-dd HH:mm:ss').format(this.syncedDate!),
"trialDate": this.trialDate == null ? null : DateFormat('yyyy-MM-dd HH:mm:ss').format(this.trialDate!),
}; };
@override
String toString() => this.toJson().toString();
double getProperty(String propertyName) { double getProperty(String propertyName) {
if (this.properties[propertyName] == null) { if (this.properties[propertyName] == null) {
return 0; return 0;

View File

@ -59,7 +59,7 @@ class CustomerTrainingPlanDetails {
this.exerciseTypeId = json['exerciseTypeId']; this.exerciseTypeId = json['exerciseTypeId'];
this.set = json['set']; this.set = json['set'];
this.repeats = json['repeats'] == "null" ? -1 : json['repeats']; this.repeats = json['repeats'] == "null" ? -1 : json['repeats'];
this.weight = json['weight']; this.weight = json['weight'] == "null" ? 0 : json['weight'];
this.restingTime = json['restingTime']; this.restingTime = json['restingTime'];
this.parallel = json['parallel'] == "false" this.parallel = json['parallel'] == "false"
? false ? false

View File

@ -1,7 +1,5 @@
import 'dart:collection'; import 'dart:collection';
import 'package:aitrainer_app/util/app_language.dart';
class Faq { class Faq {
late int faqId; late int faqId;
late String name; late String name;

40
lib/model/mautic.dart Normal file
View File

@ -0,0 +1,40 @@
class Mautic {
late int formId;
String? firstname;
String? lastname;
String? email;
String? fitnessLevel;
String? goal;
int? databaseId;
String? subscriptionDate;
String? language;
Map<String, dynamic> toJson() => {
"formId": this.formId,
"firstname": this.firstname,
"lastname": this.lastname,
"email": this.email,
"fitnessLevel": this.fitnessLevel,
"goal": this.goal,
"databaseId": this.databaseId,
"subscriptionDate": this.subscriptionDate,
"language": this.language
};
String toForm() {
String form = "mauticform[formId]=${this.formId}";
form += this.email == null ? "" : "&mauticform[email]=${this.email}";
form += this.lastname == null ? "" : "&mauticform[f_name]=${this.lastname}";
form += this.firstname == null ? "" : "&mauticform[firstname]=${this.firstname}";
form += this.fitnessLevel == null ? "" : "&mauticform[fitness_level]=${this.fitnessLevel}";
form += this.goal == null ? "" : "&mauticform[goal]=${this.goal}";
form += this.subscriptionDate == null ? "" : "&mauticform[subscribed]=${this.subscriptionDate}";
form += this.databaseId == null ? "" : "&mauticform[database_id]=${this.databaseId}";
form += this.language == null ? "" : "&mauticform[language]=${this.language}";
return form;
}
@override
String toString() => this.toJson().toString();
}

View File

@ -1,13 +1,21 @@
import 'dart:collection';
class Sport { class Sport {
late int sportId; late int sportId;
late String name; late String name;
late String sportNameTranslation;
HashMap<String, String> nameTranslations = HashMap();
Sport.fromJson(Map json) { Sport.fromJson(Map json) {
this.sportId = json['sportId']; this.sportId = json['sportId'];
this.name = json['name']; this.name = json['name'];
this.sportNameTranslation =
json['translations'] != null && (json['translations']).length > 0 ? json['translations'][0]['sportName'] : this.name; nameTranslations['en'] = name;
if (json['translations'] != null && json['translations'].length > 0) {
json['translations'].forEach((translation) {
nameTranslations[translation['languageCode']] = translation['sportName'];
});
}
} }
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {

View File

@ -10,6 +10,7 @@ class TrainingPlanDetail {
bool? parallel; bool? parallel;
int? dayId; int? dayId;
String? day; String? day;
String? summary;
TrainingPlanDetail.fromJson(Map<String, dynamic> json) { TrainingPlanDetail.fromJson(Map<String, dynamic> json) {
this.trainingPlanDetailId = json['trainingPlanDetailId']; this.trainingPlanDetailId = json['trainingPlanDetailId'];
@ -35,6 +36,7 @@ class TrainingPlanDetail {
"parallel": this.parallel, "parallel": this.parallel,
"dayId": this.dayId, "dayId": this.dayId,
"day": this.day, "day": this.day,
"summary": this.summary
}; };
@override @override

View File

@ -0,0 +1,49 @@
import 'package:intl/intl.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/mautic.dart';
import 'package:aitrainer_app/repository/customer_repository.dart';
import 'package:aitrainer_app/service/mautic.dart';
import 'package:aitrainer_app/util/app_language.dart';
class MauticRepository {
final CustomerRepository customerRepository;
const MauticRepository({required this.customerRepository});
Future<void> sendMauticSubscription() async {
Mautic mautic = Mautic();
mautic.formId = 2;
mautic.databaseId = Cache().userLoggedIn!.customerId!;
mautic.firstname = customerRepository.customer!.firstname == null ? "" : customerRepository.customer!.firstname!;
mautic.lastname = customerRepository.customer!.name == null ? "" : customerRepository.customer!.name!;
mautic.email = customerRepository.customer!.email == null ? "" : customerRepository.customer!.email!;
if (mautic.email == null || mautic.email!.contains("privaterelay.appleid.com")) {
return;
}
mautic.fitnessLevel = customerRepository.customer!.fitnessLevel == null ? "" : customerRepository.customer!.fitnessLevel!;
mautic.goal = customerRepository.customer!.goal == null ? "" : customerRepository.customer!.goal!;
mautic.subscriptionDate = DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.now());
mautic.language = AppLanguage().appLocal.languageCode;
await MauticApi().sendMauticForm(mautic);
customerRepository.customer!.syncedDate = DateTime.now();
await customerRepository.saveCustomer();
}
Future<void> sendMauticDataChange() async {
Mautic mautic = Mautic();
mautic.formId = 3;
mautic.databaseId = Cache().userLoggedIn!.customerId!;
mautic.firstname = customerRepository.customer!.firstname == null ? "" : customerRepository.customer!.firstname!;
mautic.lastname = customerRepository.customer!.name == null ? "" : customerRepository.customer!.name!;
mautic.email = customerRepository.customer!.email == null ? "" : customerRepository.customer!.email!;
if (mautic.email == null || mautic.email!.contains("privaterelay.appleid.com")) {
return;
}
mautic.fitnessLevel = customerRepository.customer!.fitnessLevel == null ? "" : customerRepository.customer!.fitnessLevel!;
mautic.goal = customerRepository.customer!.goal == null ? "" : customerRepository.customer!.goal!;
await MauticApi().sendMauticForm(mautic);
}
}

View File

@ -63,6 +63,7 @@ class TrainingPlanRepository {
TrainingPlan? trainingPlan = this.getTrainingPlanById(trainingPlanId); TrainingPlan? trainingPlan = this.getTrainingPlanById(trainingPlanId);
if (trainingPlan == null || trainingPlan.details == null) { if (trainingPlan == null || trainingPlan.details == null) {
print("trainingPlan null");
return null; return null;
} }
@ -274,14 +275,26 @@ class TrainingPlanRepository {
bool isWoman = Cache().userLoggedIn!.sex == "w"; bool isWoman = Cache().userLoggedIn!.sex == "w";
if (Cache().userLoggedIn!.fitnessLevel == FitnessState.beginner) { if (Cache().userLoggedIn!.goal == "shape_forming") {
trainingPlanId = isWoman ? getTrainingPlanByInternalName("woman_beginner") : getTrainingPlanByInternalName("beginner_man"); if (Cache().userLoggedIn!.fitnessLevel == FitnessState.beginner) {
} else if (Cache().userLoggedIn!.fitnessLevel == FitnessState.intermediate) { trainingPlanId = isWoman ? getTrainingPlanByInternalName("woman_beginner") : getTrainingPlanByInternalName("man_routine1");
trainingPlanId = isWoman ? getTrainingPlanByInternalName("woman_beginner_split") : getTrainingPlanByInternalName("beginner_split"); } else if (Cache().userLoggedIn!.fitnessLevel == FitnessState.intermediate) {
} else if (Cache().userLoggedIn!.fitnessLevel == FitnessState.advanced) { trainingPlanId = isWoman ? getTrainingPlanByInternalName("woman_beginner_split") : getTrainingPlanByInternalName("man_routine3");
trainingPlanId = isWoman ? getTrainingPlanByInternalName("woman_advanced") : getTrainingPlanByInternalName("man_routine4"); } else if (Cache().userLoggedIn!.fitnessLevel == FitnessState.advanced) {
trainingPlanId = isWoman ? getTrainingPlanByInternalName("woman_advanced") : getTrainingPlanByInternalName("man_routine4");
} else {
trainingPlanId = isWoman ? getTrainingPlanByInternalName("man_routine2") : getTrainingPlanByInternalName("man_routine2");
}
} else { } else {
trainingPlanId = isWoman ? getTrainingPlanByInternalName("5day") : getTrainingPlanByInternalName("5day"); if (Cache().userLoggedIn!.fitnessLevel == FitnessState.beginner) {
trainingPlanId = isWoman ? getTrainingPlanByInternalName("woman_beginner") : getTrainingPlanByInternalName("beginner_man");
} else if (Cache().userLoggedIn!.fitnessLevel == FitnessState.intermediate) {
trainingPlanId = isWoman ? getTrainingPlanByInternalName("woman_beginner_split") : getTrainingPlanByInternalName("man_foundation");
} else if (Cache().userLoggedIn!.fitnessLevel == FitnessState.advanced) {
trainingPlanId = isWoman ? getTrainingPlanByInternalName("woman_advanced") : getTrainingPlanByInternalName("basic_mass_building");
} else {
trainingPlanId = isWoman ? getTrainingPlanByInternalName("man_routine2") : getTrainingPlanByInternalName("mass_building");
}
} }
print("Generated plan $trainingPlanId fitness ${Cache().userLoggedIn!.fitnessLevel} - ${FitnessState.beginner}"); print("Generated plan $trainingPlanId fitness ${Cache().userLoggedIn!.fitnessLevel} - ${FitnessState.beginner}");
@ -290,6 +303,7 @@ class TrainingPlanRepository {
CustomerTrainingPlan? customerTrainingPlan = activateTrainingPlan(trainingPlanId); CustomerTrainingPlan? customerTrainingPlan = activateTrainingPlan(trainingPlanId);
if (customerTrainingPlan != null) { if (customerTrainingPlan != null) {
Cache().myTrainingPlan = customerTrainingPlan; Cache().myTrainingPlan = customerTrainingPlan;
Cache().saveMyTrainingPlan();
} }
} }
} }

29
lib/service/mautic.dart Normal file
View File

@ -0,0 +1,29 @@
import 'dart:io';
import 'package:aitrainer_app/model/mautic.dart';
import 'package:aitrainer_app/service/logging.dart';
class MauticApi with Logging {
final String mauticUrl = "https://mautic.aitrainer.app/form/submit?formId=";
Future<void> sendMauticForm(Mautic model) async {
final String body = model.toForm();
log(" ===== mautic subscription:" + body);
HttpClient client = new HttpClient();
String url = mauticUrl + model.formId.toString();
var uri = Uri.parse(url);
final HttpClientRequest request = await client.postUrl(uri);
request.headers.set('Content-Type', 'application/x-www-form-urlencoded');
request.headers.set('cache-control', 'no-cache');
request.write(body);
HttpClientResponse result = await request.close();
client.close();
if (!(result.statusCode == 200 || result.statusCode == 302)) {
trace("mautic response: ${result.statusCode}");
throw Exception("Network error, try again later!");
}
}
}

View File

@ -57,7 +57,8 @@ enum TrackingEvent {
training_plan_execute, training_plan_execute,
training_plan_finished, training_plan_finished,
training_plan_custom, training_plan_custom,
trial trial,
feedback_email
} }
T enumFromString<T>(Iterable<T> values, String value) { T enumFromString<T>(Iterable<T> values, String value) {
@ -103,3 +104,11 @@ extension ExerciseTypeTrainingPlanStateExt on ExerciseTypeTrainingPlanState {
bool equalsTo(ExerciseTypeTrainingPlanState state) => this.toString() == state.toString(); bool equalsTo(ExerciseTypeTrainingPlanState state) => this.toString() == state.toString();
bool equalsStringTo(String state) => this.toStr() == state; bool equalsStringTo(String state) => this.toStr() == state;
} }
enum ExerciseSaveType { test, training, test_set }
extension ExerciseSaveTypeExt on ExerciseSaveType {
String toStr() => this.toString().split(".").last;
bool equalsTo(ExerciseSaveType type) => this.toString() == type.toString();
bool equalsStringTo(String type) => this.toStr() == type;
}

View File

@ -5,6 +5,7 @@ import 'package:aitrainer_app/service/tracking_service.dart';
import 'package:aitrainer_app/util/enums.dart'; import 'package:aitrainer_app/util/enums.dart';
import 'package:aitrainer_app/model/tracking.dart' as model; import 'package:aitrainer_app/model/tracking.dart' as model;
import 'package:firebase_analytics/firebase_analytics.dart'; import 'package:firebase_analytics/firebase_analytics.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flurry_data/flurry_data.dart'; import 'package:flurry_data/flurry_data.dart';
import 'package:flutter_uxcam/flutter_uxcam.dart'; import 'package:flutter_uxcam/flutter_uxcam.dart';
@ -21,7 +22,7 @@ class Track with Logging {
void track(TrackingEvent event, {String eventValue = ""}) { void track(TrackingEvent event, {String eventValue = ""}) {
analytics.logEvent(name: event.enumToString(), parameters: {"value": eventValue}); analytics.logEvent(name: event.enumToString(), parameters: {"value": eventValue});
if (!isInDebugMode) { if (!isInDebugMode) {
FlurryData.logEvent(event.toString()); FlurryData.logEvent(event.enumToString());
// Smartlook.setGlobalEventProperty(event.toString(), eventValue, false); // Smartlook.setGlobalEventProperty(event.toString(), eventValue, false);
FlutterUxcam.logEventWithProperties(event.enumToString(), {"value": eventValue}); FlutterUxcam.logEventWithProperties(event.enumToString(), {"value": eventValue});
model.Tracking tracking = model.Tracking(); model.Tracking tracking = model.Tracking();
@ -32,6 +33,7 @@ class Track with Logging {
tracking.eventValue = eventValue; tracking.eventValue = eventValue;
} }
tracking.dateAdd = DateTime.now(); tracking.dateAdd = DateTime.now();
FirebaseMessaging.instance.subscribeToTopic(event.enumToString());
TrackingApi().saveTracking(tracking); TrackingApi().saveTracking(tracking);
} }
} }

View File

@ -65,7 +65,7 @@ class AccountPage extends StatelessWidget with Trans {
return ListView(padding: EdgeInsets.only(top: 35), children: <Widget>[ return ListView(padding: EdgeInsets.only(top: 35), children: <Widget>[
ListTile( ListTile(
leading: Common.badgedIcon(Colors.grey, Icons.perm_identity, "personalData"), //Icon(Icons.perm_identity), leading: Common.badgedIcon(Colors.grey, Icons.perm_identity, "personalData"), //Icon(Icons.perm_identity),
subtitle: Text(t("Profile")), subtitle: Text(t("Profile") + " " + t("and") + " " + t("Sport")),
title: TextButton( title: TextButton(
child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Text(customerName, style: TextStyle(color: Colors.blue)), Text(customerName, style: TextStyle(color: Colors.blue)),
@ -108,7 +108,7 @@ class AccountPage extends StatelessWidget with Trans {
), ),
ListTile( ListTile(
leading: Common.badgedIcon(Colors.grey, Icons.perm_contact_cal, "FitnessLevel"), //Icon(Icons.perm_contact_cal), leading: Common.badgedIcon(Colors.grey, Icons.perm_contact_cal, "FitnessLevel"), //Icon(Icons.perm_contact_cal),
subtitle: Text(t("Activity") + " " + t("and") + " " + t("Sport")), subtitle: Text(t("Activity")),
title: TextButton( title: TextButton(
child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Text(fitnessLevel, style: TextStyle(color: Colors.blue)), Text(fitnessLevel, style: TextStyle(color: Colors.blue)),

View File

@ -7,6 +7,7 @@ import 'package:aitrainer_app/repository/customer_repository.dart';
import 'package:aitrainer_app/util/enums.dart'; import 'package:aitrainer_app/util/enums.dart';
import 'package:aitrainer_app/util/trans.dart'; import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar.dart'; import 'package:aitrainer_app/widgets/app_bar.dart';
import 'package:aitrainer_app/widgets/app_bar_min.dart';
import 'package:aitrainer_app/widgets/dialog_html.dart'; import 'package:aitrainer_app/widgets/dialog_html.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
@ -34,9 +35,13 @@ class _CustomerBodyTypeAnimationPageState extends State<CustomerBodyTypeAnimatio
customerRepository = ModalRoute.of(context)!.settings.arguments as CustomerRepository; customerRepository = ModalRoute.of(context)!.settings.arguments as CustomerRepository;
} }
PreferredSizeWidget _bar = AppBarMin(
back: true,
);
setContext(context); setContext(context);
return Scaffold( return Scaffold(
appBar: AppBarNav(depth: 0), appBar: _bar,
body: Container( body: Container(
height: double.infinity, height: double.infinity,
width: double.infinity, width: double.infinity,

View File

@ -2,8 +2,6 @@ import 'dart:collection';
import 'package:aitrainer_app/bloc/customer_change/customer_change_bloc.dart'; import 'package:aitrainer_app/bloc/customer_change/customer_change_bloc.dart';
import 'package:aitrainer_app/library/custom_icon_icons.dart'; import 'package:aitrainer_app/library/custom_icon_icons.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/sport.dart';
import 'package:aitrainer_app/util/app_localization.dart'; import 'package:aitrainer_app/util/app_localization.dart';
import 'package:aitrainer_app/repository/customer_repository.dart'; import 'package:aitrainer_app/repository/customer_repository.dart';
import 'package:aitrainer_app/model/fitness_state.dart'; import 'package:aitrainer_app/model/fitness_state.dart';
@ -18,7 +16,6 @@ import 'package:google_fonts/google_fonts.dart';
import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart'; import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart';
import '../bloc/customer_change/customer_change_bloc.dart'; import '../bloc/customer_change/customer_change_bloc.dart';
import '../library/dropdown_search/dropdown_search.dart';
// ignore: must_be_immutable // ignore: must_be_immutable
class CustomerFitnessPage extends StatefulWidget { class CustomerFitnessPage extends StatefulWidget {
@ -76,8 +73,11 @@ class _CustomerFitnessPageState extends State<CustomerFitnessPage> with Trans {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white)))); SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
} else if (state is CustomerSaveSuccess) { } else if (state is CustomerSaveSuccess) {
Navigator.of(context).pop(); if (fulldata) {
Navigator.of(context).pushNamed("customerSexPage", arguments: changeBloc.customerRepository); Navigator.of(context).pop();
} else {
Navigator.of(context).popAndPushNamed("customerSexPage", arguments: changeBloc.customerRepository);
}
} }
}, },
builder: (context, state) { builder: (context, state) {
@ -103,15 +103,15 @@ class _CustomerFitnessPageState extends State<CustomerFitnessPage> with Trans {
changeBloc.add(CustomerSave()), changeBloc.add(CustomerSave()),
} }
}, },
backgroundColor: Color(0xffb4f500), backgroundColor: Colors.orange[600],
icon: Icon( icon: Icon(
CustomIcon.save, CustomIcon.save,
color: Colors.black, color: Colors.white,
size: 26, size: 26,
), ),
label: Text( label: Text(
fulldata ? t("Save") : t("Next"), fulldata ? t("Save") : t("Next"),
style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.black), style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.white),
), ),
), ),
); );
@ -141,46 +141,19 @@ class _CustomerFitnessPageState extends State<CustomerFitnessPage> with Trans {
SizedBox( SizedBox(
height: h, height: h,
), ),
getButton("Beginner", "I am beginner", FitnessState.beginner), getButton("Beginner", "I am beginner", FitnessState.beginner),
SizedBox( SizedBox(
height: h, height: h,
), ),
getButton("Intermediate", "I am intermediate", FitnessState.intermediate), getButton("Intermediate", "I am intermediate", FitnessState.intermediate),
SizedBox( SizedBox(
height: h, height: h,
), ),
getButton("Advanced", "I am advanced", FitnessState.advanced), getButton("Advanced", "I am advanced", FitnessState.advanced),
SizedBox( SizedBox(
height: h, height: h,
), ),
getButton("Professional", "I am professional", FitnessState.professional), getButton("Professional", "I am professional", FitnessState.professional),
/* Divider(),
Text(
t("Your Primary Sport") + ":",
textAlign: TextAlign.center,
style: GoogleFonts.archivoBlack(
color: Colors.orange,
fontSize: 20,
),
), */
//getSport(changeBloc),
/* Divider(),
ElevatedButton(
style: ElevatedButton.styleFrom(
onPrimary: Colors.white,
primary: Colors.orange,
),
child: Text(fulldata ? t("Save") : t("Next")),
onPressed: () => {
changeBloc.add(CustomerSave()),
Navigator.of(context).pop(),
if (!fulldata) {Navigator.of(context).pushNamed("customerBodyTypePage", arguments: customerRepository)}
},
) */
], ],
), ),
); );
@ -233,98 +206,6 @@ class _CustomerFitnessPageState extends State<CustomerFitnessPage> with Trans {
side: BorderSide(width: 4, color: Colors.white24), side: BorderSide(width: 4, color: Colors.white24),
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
); );
//return
return returnCode; return returnCode;
} }
Widget getSport(CustomerChangeBloc bloc) {
Sport? selected = bloc.selectedSport;
return Container(
padding: EdgeInsets.only(left: 65, right: 65),
child: DropdownSearch<Sport>(
dropdownSearchDecoration: InputDecoration(
contentPadding: EdgeInsets.only(left: 15, top: 5, bottom: 5),
labelText: t("Sport"),
labelStyle: GoogleFonts.inter(fontSize: 16, color: Colors.indigo),
//fillColor: Colors.black38,
filled: false,
border: OutlineInputBorder(
gapPadding: 2.0,
borderRadius: BorderRadius.circular(12.0),
borderSide: BorderSide(color: Colors.blue, width: 0.4),
),
),
mode: Mode.MENU,
compareFn: (Sport? i, Sport? s) {
if (i == null || s == null) {
return false;
} else {
return i.sportId == s.sportId;
}
},
showSelectedItem: true,
selectedItem: selected,
itemAsString: (data) => t(data!.sportNameTranslation),
onChanged: (data) {
bloc.add(CustomerSportChange(sport: data!));
},
dropdownBuilder: _customDropDownItem,
popupItemBuilder: _customMenuBuilder,
popupBarrierColor: Colors.white10,
//popupBackgroundColor: Colors.yellow,
items: Cache().getSports(),
dropDownButton: Icon(
Icons.arrow_drop_down,
color: Colors.indigo,
),
));
//items: FitnessItem().toList()));
}
Widget _customMenuBuilder(BuildContext context, Sport? sport, bool isSelected) {
return Container(
decoration: !isSelected
? BoxDecoration(color: Colors.grey[300])
: BoxDecoration(
border: Border.all(color: Colors.blue),
borderRadius: BorderRadius.circular(12),
color: Colors.grey[100],
),
child: ListTile(
selected: isSelected,
title: Text(
t(sport!.sportNameTranslation),
style: GoogleFonts.archivoBlack(fontSize: 20, color: Colors.blue[600]),
),
subtitle: Text(
t(sport.name),
style: GoogleFonts.inter(fontSize: 12, color: Colors.blue[600]),
),
),
);
}
Widget _customDropDownItem(BuildContext context, Sport? item, String itemDesignation) {
return Container(
child: (item == null)
? ListTile(
contentPadding: EdgeInsets.all(0),
title: Text(
t("No item selected"),
style: GoogleFonts.inter(fontSize: 14, color: Colors.blue[600]),
),
)
: ListTile(
contentPadding: EdgeInsets.all(0),
title: Text(
t(item.sportNameTranslation),
style: GoogleFonts.archivoBlack(fontSize: 20, color: Colors.blue[600]),
),
subtitle: Text(
t(item.name),
style: GoogleFonts.inter(fontSize: 12, color: Colors.blue[600]),
),
),
);
}
} }

View File

@ -81,7 +81,7 @@ class _CustomerGoalPage extends State<CustomerGoalPage> with Trans {
customerRepository = CustomerRepository(); customerRepository = CustomerRepository();
} }
PreferredSizeWidget _bar = AppBarMin( PreferredSizeWidget _bar = AppBarMin(
back: false, back: true,
); );
if (!fulldata) { if (!fulldata) {
_bar = AppBarProgress(max: 14, min: 0); _bar = AppBarProgress(max: 14, min: 0);
@ -107,7 +107,11 @@ class _CustomerGoalPage extends State<CustomerGoalPage> with Trans {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white)))); SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
} else if (state is CustomerSaveSuccess) { } else if (state is CustomerSaveSuccess) {
Navigator.of(context).pushNamed("customerFitnessPage", arguments: changeBloc.customerRepository); if (fulldata) {
Navigator.of(context).pop();
} else {
Navigator.of(context).popAndPushNamed("customerFitnessPage", arguments: changeBloc.customerRepository);
}
} }
}, },
builder: (context, state) { builder: (context, state) {
@ -136,15 +140,15 @@ class _CustomerGoalPage extends State<CustomerGoalPage> with Trans {
changeBloc.add(CustomerSave()), changeBloc.add(CustomerSave()),
} }
}, },
backgroundColor: Color(0xffb4f500), backgroundColor: Colors.orange[600],
icon: Icon( icon: Icon(
CustomIcon.save, CustomIcon.save,
color: Colors.black, color: Colors.white,
size: 26, size: 26,
), ),
label: Text( label: Text(
fulldata ? t("Save") : t("Next"), fulldata ? t("Save") : t("Next"),
style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.black), style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.white),
), ),
), ),
); );

View File

@ -64,8 +64,11 @@ class _CustomerHeightPageState extends State<CustomerHeightPage> with Trans {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white)))); SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
} else if (state is CustomerSaveSuccess) { } else if (state is CustomerSaveSuccess) {
Navigator.of(context).pop(); if (fulldata) {
Navigator.of(context).pushNamed("registration", arguments: changeBloc.customerRepository); Navigator.of(context).pop();
} else {
Navigator.of(context).popAndPushNamed("registration", arguments: changeBloc.customerRepository);
}
} }
}, },
builder: (context, state) { builder: (context, state) {
@ -76,15 +79,15 @@ class _CustomerHeightPageState extends State<CustomerHeightPage> with Trans {
)), )),
floatingActionButton: FloatingActionButton.extended( floatingActionButton: FloatingActionButton.extended(
onPressed: () => changeBloc.add(CustomerSaveHeight()), onPressed: () => changeBloc.add(CustomerSaveHeight()),
backgroundColor: Color(0xffb4f500), backgroundColor: Colors.orange[600],
icon: Icon( icon: Icon(
CustomIcon.save, CustomIcon.save,
color: Colors.black, color: Colors.white,
size: 26, size: 26,
), ),
label: Text( label: Text(
fulldata ? t("Save") : t("Finish"), fulldata ? t("Save") : t("Finish"),
style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.black), style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.white),
), ),
), ),
); );

View File

@ -3,7 +3,10 @@ import 'dart:collection';
import 'package:aitrainer_app/bloc/account/account_bloc.dart'; import 'package:aitrainer_app/bloc/account/account_bloc.dart';
import 'package:aitrainer_app/bloc/customer_change/customer_change_bloc.dart'; import 'package:aitrainer_app/bloc/customer_change/customer_change_bloc.dart';
import 'package:aitrainer_app/library/custom_icon_icons.dart'; import 'package:aitrainer_app/library/custom_icon_icons.dart';
import 'package:aitrainer_app/library/dropdown_search/dropdown_search.dart';
import 'package:aitrainer_app/model/cache.dart'; import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/sport.dart';
import 'package:aitrainer_app/util/app_language.dart';
import 'package:aitrainer_app/util/enums.dart'; import 'package:aitrainer_app/util/enums.dart';
import 'package:aitrainer_app/util/trans.dart'; import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar_min.dart'; import 'package:aitrainer_app/widgets/app_bar_min.dart';
@ -385,10 +388,119 @@ class CustomerModifyPage extends StatelessWidget with Trans {
}, },
), ),
Divider(), Divider(),
Divider(),
Text(
t("Your Primary Sport") + ":",
textAlign: TextAlign.center,
style: GoogleFonts.archivoBlack(
color: Colors.orange,
fontSize: 20,
),
),
getSport(customerBloc),
Divider(),
], ],
), ),
), ),
), ),
); );
} }
Widget getSport(CustomerChangeBloc bloc) {
Sport? selected = bloc.selectedSport;
return Container(
padding: EdgeInsets.only(left: 65, right: 65),
child: DropdownSearch<Sport>(
dropdownSearchDecoration: InputDecoration(
contentPadding: EdgeInsets.only(left: 15, top: 5, bottom: 5),
labelText: t("Sport"),
labelStyle: GoogleFonts.inter(fontSize: 16, color: Colors.indigo),
//fillColor: Colors.black38,
filled: false,
border: OutlineInputBorder(
gapPadding: 2.0,
borderRadius: BorderRadius.circular(12.0),
borderSide: BorderSide(color: Colors.blue, width: 0.4),
),
),
mode: Mode.MENU,
compareFn: (Sport? i, Sport? s) {
if (i == null || s == null) {
return false;
} else {
return i.sportId == s.sportId;
}
},
showSelectedItem: true,
selectedItem: selected,
itemAsString: (data) => data!.nameTranslations[AppLanguage().appLocal.toString()] != null
? data.nameTranslations[AppLanguage().appLocal.toString()]!
: data.name,
onChanged: (data) {
bloc.add(CustomerSportChange(sport: data!));
},
dropdownBuilder: _customDropDownItem,
popupItemBuilder: _customMenuBuilder,
popupBarrierColor: Colors.white10,
//popupBackgroundColor: Colors.yellow,
items: Cache().getSports(),
dropDownButton: Icon(
Icons.arrow_drop_down,
color: Colors.indigo,
),
));
//items: FitnessItem().toList()));
}
Widget _customMenuBuilder(BuildContext context, Sport? sport, bool isSelected) {
return Container(
decoration: !isSelected
? BoxDecoration(color: Colors.grey[300])
: BoxDecoration(
border: Border.all(color: Colors.blue),
borderRadius: BorderRadius.circular(12),
color: Colors.grey[100],
),
child: ListTile(
selected: isSelected,
title: Text(
sport!.nameTranslations[AppLanguage().appLocal.toString()] != null
? sport.nameTranslations[AppLanguage().appLocal.toString()]!
: sport.name,
style: GoogleFonts.archivoBlack(fontSize: 20, color: Colors.blue[600]),
),
subtitle: Text(
sport.name,
style: GoogleFonts.inter(fontSize: 12, color: Colors.blue[600]),
),
),
);
}
Widget _customDropDownItem(BuildContext context, Sport? item, String itemDesignation) {
return Container(
child: (item == null)
? ListTile(
contentPadding: EdgeInsets.all(0),
title: Text(
t("No item selected"),
style: GoogleFonts.inter(fontSize: 14, color: Colors.blue[600]),
),
)
: ListTile(
contentPadding: EdgeInsets.all(0),
title: Text(
item.nameTranslations[AppLanguage().appLocal.toString()] != null
? item.nameTranslations[AppLanguage().appLocal.toString()]!
: item.name,
style: GoogleFonts.archivoBlack(fontSize: 20, color: Colors.blue[600]),
),
subtitle: Text(
item.name,
style: GoogleFonts.inter(fontSize: 12, color: Colors.blue[600]),
),
),
);
}
} }

View File

@ -64,8 +64,11 @@ class _CustomerSexPageState extends State<CustomerSexPage> with Trans {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white)))); SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
} else if (state is CustomerSaveSuccess) { } else if (state is CustomerSaveSuccess) {
Navigator.of(context).pop(); if (fulldata) {
Navigator.of(context).pushNamed("customerWeightPage", arguments: changeBloc.customerRepository); Navigator.of(context).pop();
} else {
Navigator.of(context).popAndPushNamed("customerWeightPage", arguments: changeBloc.customerRepository);
}
} }
}, },
builder: (context, state) { builder: (context, state) {
@ -84,15 +87,15 @@ class _CustomerSexPageState extends State<CustomerSexPage> with Trans {
onPressed: () => { onPressed: () => {
changeBloc.add(CustomerSaveSex()), changeBloc.add(CustomerSaveSex()),
}, },
backgroundColor: Color(0xffb4f500), backgroundColor: Colors.orange[600],
icon: Icon( icon: Icon(
CustomIcon.save, CustomIcon.save,
color: Colors.black, color: Colors.white,
size: 26, size: 26,
), ),
label: Text( label: Text(
fulldata ? t("Save") : t("Next"), fulldata ? t("Save") : t("Next"),
style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.black), style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.white),
), ),
), ),
); );

View File

@ -1,7 +1,6 @@
import 'package:aitrainer_app/bloc/customer_change/customer_change_bloc.dart'; import 'package:aitrainer_app/bloc/customer_change/customer_change_bloc.dart';
import 'package:aitrainer_app/library/custom_icon_icons.dart'; import 'package:aitrainer_app/library/custom_icon_icons.dart';
import 'package:aitrainer_app/util/app_localization.dart';
import 'package:aitrainer_app/repository/customer_repository.dart'; import 'package:aitrainer_app/repository/customer_repository.dart';
import 'package:aitrainer_app/util/trans.dart'; import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar_min.dart'; import 'package:aitrainer_app/widgets/app_bar_min.dart';
@ -65,8 +64,11 @@ class _CustomerWeightPageState extends State<CustomerWeightPage> with Trans {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white)))); SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
} else if (state is CustomerSaveSuccess) { } else if (state is CustomerSaveSuccess) {
Navigator.of(context).pop(); if (fulldata) {
Navigator.of(context).pushNamed("customerHeightPage", arguments: changeBloc.customerRepository); Navigator.of(context).pop();
} else {
Navigator.of(context).popAndPushNamed("customerHeightPage", arguments: changeBloc.customerRepository);
}
} }
}, },
builder: (context, state) { builder: (context, state) {
@ -85,15 +87,15 @@ class _CustomerWeightPageState extends State<CustomerWeightPage> with Trans {
onPressed: () => { onPressed: () => {
changeBloc.add(CustomerSaveWeight()), changeBloc.add(CustomerSaveWeight()),
}, },
backgroundColor: Color(0xffb4f500), backgroundColor: Colors.orange[600],
icon: Icon( icon: Icon(
CustomIcon.save, CustomIcon.save,
color: Colors.black, color: Colors.white,
size: 26, size: 26,
), ),
label: Text( label: Text(
fulldata ? t("Save") : t("Next"), fulldata ? t("Save") : t("Next"),
style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.black), style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.white),
), ),
), ),
); );

View File

@ -1,4 +1,3 @@
import 'package:aitrainer_app/library/button_animations.dart';
import 'package:aitrainer_app/util/trans.dart'; import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar_min.dart'; import 'package:aitrainer_app/widgets/app_bar_min.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';

View File

@ -231,7 +231,7 @@ class _ExerciseControlPage extends State<ExerciseControlPage> with Trans {
Divider(), Divider(),
numberPickForm(exerciseBloc, 3), numberPickForm(exerciseBloc, 3),
SizedBox( SizedBox(
height: 80, height: 120,
) )
]), ]),
)), )),
@ -263,12 +263,10 @@ class _ExerciseControlPage extends State<ExerciseControlPage> with Trans {
} }
Widget numberPickForm(ExerciseControlBloc exerciseBloc, int step) { Widget numberPickForm(ExerciseControlBloc exerciseBloc, int step) {
final String strTimes = step == 2 ? exerciseBloc.origQuantity.toStringAsFixed(0) : "max."; final String strTimes = step == 2 ? exerciseBloc.controlList[step - 1].quantity!.toStringAsFixed(0) : "max.";
//print("step $step, quantity ${exerciseBloc.origQuantity}");
String title = (step + 1).toString() + "/4 " + t("Control Exercise:"); String title = (step + 1).toString() + "/4 " + t("Control Exercise:");
LinkedHashMap args = LinkedHashMap(); LinkedHashMap args = LinkedHashMap();
final TutorialBloc tutorialBloc = BlocProvider.of<TutorialBloc>(context);
List<Widget> listWidgets = [ List<Widget> listWidgets = [
Text( Text(
@ -294,7 +292,7 @@ class _ExerciseControlPage extends State<ExerciseControlPage> with Trans {
children: [ children: [
TextSpan(text: t("Please repeat with ")), TextSpan(text: t("Please repeat with ")),
TextSpan( TextSpan(
text: exerciseBloc.unitQuantity.toStringAsFixed(0) + text: exerciseBloc.controlList[step - 1].unitQuantity!.toStringAsFixed(0) +
" " + " " +
exerciseBloc.exerciseRepository.exerciseType!.unitQuantityUnit!, exerciseBloc.exerciseRepository.exerciseType!.unitQuantityUnit!,
style: GoogleFonts.inter( style: GoogleFonts.inter(
@ -324,7 +322,7 @@ class _ExerciseControlPage extends State<ExerciseControlPage> with Trans {
NumberPickerWidget( NumberPickerWidget(
minValue: 0, minValue: 0,
maxValue: 200, maxValue: 200,
initalValue: exerciseBloc.origQuantity.round(), initalValue: exerciseBloc.controlList[step - 1].quantity!.round(),
unit: t("reps"), unit: t("reps"),
color: Colors.yellow[50]!, color: Colors.yellow[50]!,
onChange: (value) => {exerciseBloc.add(ExerciseControlQuantityChange(quantity: value.toDouble(), step: step))}), onChange: (value) => {exerciseBloc.add(ExerciseControlQuantityChange(quantity: value.toDouble(), step: step))}),
@ -335,12 +333,6 @@ class _ExerciseControlPage extends State<ExerciseControlPage> with Trans {
onSurface: Colors.blueAccent, onSurface: Colors.blueAccent,
), ),
onPressed: () { onPressed: () {
if (tutorialBloc.isActive) {
if (!tutorialBloc.checkAction("Save")) {
return;
}
}
exerciseBloc.add(ExerciseControlSubmit(step: step)); exerciseBloc.add(ExerciseControlSubmit(step: step));
if (step == 3) { if (step == 3) {
Navigator.of(context).pop(); Navigator.of(context).pop();
@ -354,7 +346,7 @@ class _ExerciseControlPage extends State<ExerciseControlPage> with Trans {
children: [ children: [
Image.asset('asset/icon/gomb_orange_c.png', width: 140, height: 60), Image.asset('asset/icon/gomb_orange_c.png', width: 140, height: 60),
Text( Text(
t("Save"), t("Done!"),
style: TextStyle(fontSize: 16, color: Colors.white), style: TextStyle(fontSize: 16, color: Colors.white),
), ),
], ],
@ -436,9 +428,9 @@ class _UnitQuantityControlState extends State<UnitQuantityControl> with Trans {
height: 20, height: 20,
), ),
NumberPickerWidget( NumberPickerWidget(
minValue: (widget.exerciseBloc.unitQuantity - 30).round(), minValue: (widget.exerciseBloc.controlList[widget.step - 1].unitQuantity! - 30).round(),
maxValue: (widget.exerciseBloc.unitQuantity + 30).round(), maxValue: (widget.exerciseBloc.controlList[widget.step - 1].unitQuantity! + 30).round(),
initalValue: widget.exerciseBloc.unitQuantity.round(), initalValue: widget.exerciseBloc.controlList[widget.step - 1].unitQuantity!.round(),
unit: t("kg"), unit: t("kg"),
color: Colors.yellow[50]!, color: Colors.yellow[50]!,
onChange: (value) => { onChange: (value) => {
@ -452,9 +444,9 @@ class _UnitQuantityControlState extends State<UnitQuantityControl> with Trans {
onTap: () => { onTap: () => {
if (changedValue == null) if (changedValue == null)
{ {
changedValue = widget.exerciseBloc.unitQuantity, changedValue = widget.exerciseBloc.controlList[widget.step - 1].unitQuantity,
}, },
//print("Changed new value $changedValue"), print("Changed new value $changedValue, step ${widget.step}"),
widget.exerciseBloc.add(ExerciseControlUnitQuantityChange(quantity: changedValue!.toDouble(), step: widget.step)), widget.exerciseBloc.add(ExerciseControlUnitQuantityChange(quantity: changedValue!.toDouble(), step: widget.step)),
Navigator.of(context).pop(), Navigator.of(context).pop(),
}, },

View File

@ -8,6 +8,7 @@ import 'package:aitrainer_app/library/custom_icon_icons.dart';
import 'package:aitrainer_app/model/cache.dart'; import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/exercise_ability.dart'; import 'package:aitrainer_app/model/exercise_ability.dart';
import 'package:aitrainer_app/model/exercise_type.dart'; import 'package:aitrainer_app/model/exercise_type.dart';
import 'package:aitrainer_app/model/workout_menu_tree.dart';
import 'package:aitrainer_app/repository/customer_repository.dart'; import 'package:aitrainer_app/repository/customer_repository.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart'; import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/service/logging.dart'; import 'package:aitrainer_app/service/logging.dart';
@ -17,6 +18,7 @@ import 'package:aitrainer_app/widgets/bmi_widget.dart';
import 'package:aitrainer_app/widgets/bmr_widget.dart'; import 'package:aitrainer_app/widgets/bmr_widget.dart';
import 'package:aitrainer_app/widgets/dialog_common.dart'; import 'package:aitrainer_app/widgets/dialog_common.dart';
import 'package:aitrainer_app/widgets/exercise_save.dart'; import 'package:aitrainer_app/widgets/exercise_save.dart';
import 'package:aitrainer_app/widgets/menu_image.dart';
import 'package:aitrainer_app/widgets/size_widget.dart'; import 'package:aitrainer_app/widgets/size_widget.dart';
import 'package:aitrainer_app/widgets/tutorial_widget.dart'; import 'package:aitrainer_app/widgets/tutorial_widget.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
@ -55,7 +57,9 @@ class _ExerciseNewPageState extends State<ExerciseNewPage> with Trans, Logging {
title: t("Warning"), title: t("Warning"),
descriptions: t(state.message), descriptions: t(state.message),
text: "OK", text: "OK",
onTap: () => Navigator.of(context).pushNamed("login"), onTap: () => {
Navigator.of(context).pop(),
},
onCancel: () => { onCancel: () => {
Navigator.of(context).pop(), Navigator.of(context).pop(),
}, },
@ -114,10 +118,12 @@ class _ExerciseNewPageState extends State<ExerciseNewPage> with Trans, Logging {
return SizeWidget(exerciseBloc: exerciseBloc); return SizeWidget(exerciseBloc: exerciseBloc);
} }
WorkoutMenuTree? workoutTree = menuBloc.menuTreeRepository.getMenuItemByExerciseTypeId(exerciseType.exerciseTypeId);
return Scaffold( return Scaffold(
appBar: AppBarNav(depth: 1), appBar: AppBarNav(depth: 1),
body: Container( body: Container(
padding: EdgeInsets.only(top: 10, left: 20, right: 20), padding: EdgeInsets.only(),
decoration: BoxDecoration( decoration: BoxDecoration(
image: DecorationImage( image: DecorationImage(
image: AssetImage('asset/image/WT_black_background.jpg'), image: AssetImage('asset/image/WT_black_background.jpg'),
@ -126,37 +132,38 @@ class _ExerciseNewPageState extends State<ExerciseNewPage> with Trans, Logging {
), ),
), ),
child: ExerciseSave( child: ExerciseSave(
exerciseName: exerciseBloc.exerciseRepository.exerciseType!.nameTranslation, exerciseName: exerciseBloc.exerciseRepository.exerciseType!.nameTranslation,
exerciseDescription: exerciseBloc.exerciseRepository.exerciseType!.descriptionTranslation, exerciseDescription: exerciseBloc.exerciseRepository.exerciseType!.descriptionTranslation,
exerciseTask: exerciseBloc.exerciseRepository.exerciseType!.unitQuantityUnit != null exerciseTask: exerciseBloc.exerciseRepository.exerciseType!.unitQuantityUnit != null
? t("Please take a relative bigger weight and repeat 12-20 times and do your best! MAXIMIZE it!") ? t("Please take a relative bigger weight and repeat 12-20 times and do your best! MAXIMIZE it!")
: t("Please repeat as much times as you can! MAXIMIZE it!"), : t("Please repeat as much times as you can! MAXIMIZE it!"),
unit: exerciseBloc.exerciseRepository.exerciseType!.unit, unit: exerciseBloc.exerciseRepository.exerciseType!.unit,
unitQuantityUnit: exerciseBloc.exerciseRepository.exerciseType!.unitQuantityUnit, unitQuantityUnit: exerciseBloc.exerciseRepository.exerciseType!.unitQuantityUnit,
hasUnitQuantity: exerciseBloc.exerciseRepository.exerciseType!.unitQuantityUnit != null, hasUnitQuantity: exerciseBloc.exerciseRepository.exerciseType!.unitQuantityUnit != null,
onQuantityChanged: (value) { onQuantityChanged: (value) {
exerciseBloc.add(ExerciseNewQuantityChange(quantity: value)); exerciseBloc.add(ExerciseNewQuantityChange(quantity: value));
}, },
onUnitQuantityChanged: (value) => exerciseBloc.add(ExerciseNewQuantityUnitChange(quantity: value)), onUnitQuantityChanged: (value) => exerciseBloc.add(ExerciseNewQuantityUnitChange(quantity: value)),
//onSubmit: () => confirmationDialog(exerciseBloc, menuBloc), //onSubmit: () => confirmationDialog(exerciseBloc, menuBloc),
exerciseTypeId: exerciseType.exerciseTypeId, exerciseTypeId: exerciseType.exerciseTypeId,
)), tip: ActivityDone.exerciseSaveTestTip,
menuImage: MenuImage(
imageName: workoutTree!.imageName,
workoutTreeId: workoutTree.id,
radius: 0,
))),
floatingActionButton: FloatingActionButton.extended( floatingActionButton: FloatingActionButton.extended(
onPressed: () => save(exerciseBloc, menuBloc), onPressed: () => save(exerciseBloc, menuBloc),
backgroundColor: Colors.orange[800], backgroundColor: Colors.orange[600],
icon: Icon( icon: Icon(
CustomIcon.save, CustomIcon.ok_circled,
size: 20, size: 20,
), ),
label: Text( label: Text(
t("Save"), t("Done!"),
style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 12), style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 16),
), ),
), ),
/* bottomNavigationBar: BottomBarMultipleExercises(
isSet: false,
exerciseTypeId: exerciseType.exerciseTypeId,
), */
); );
} }
@ -195,6 +202,11 @@ class _ExerciseNewPageState extends State<ExerciseNewPage> with Trans, Logging {
return; return;
} }
if (bloc.quantity == -1 || bloc.unitQuantity == -1) {
bloc.add(ExerciseNewAddError(message: "Please type in a real number!"));
return;
}
String quantity = bloc.exerciseRepository.exercise!.quantity! % 1 == 0 String quantity = bloc.exerciseRepository.exercise!.quantity! % 1 == 0
? bloc.exerciseRepository.exercise!.quantity!.round().toString() ? bloc.exerciseRepository.exercise!.quantity!.round().toString()
: bloc.exerciseRepository.exercise!.quantity!.toString(); : bloc.exerciseRepository.exercise!.quantity!.toString();
@ -209,9 +221,9 @@ class _ExerciseNewPageState extends State<ExerciseNewPage> with Trans, Logging {
// ignore: close_sinks // ignore: close_sinks
final TestSetExecuteBloc executeBloc = BlocProvider.of<TestSetExecuteBloc>(context); final TestSetExecuteBloc executeBloc = BlocProvider.of<TestSetExecuteBloc>(context);
final question = bloc.exerciseRepository.exercise!.quantity! == 12.0 /* final question = bloc.exerciseRepository.exercise!.quantity! == 12.0
? "Did you try the MAXIMUM what you can do? Are you sure we save the exercise with ONLY 12 repeats?" ? "Did you try the MAXIMUM what you can do? Are you sure we save the exercise with ONLY 12 repeats?" */
: "Do you save this exercise with these parameters?"; final question = "Do you save this exercise with these parameters?";
showCupertinoDialog( showCupertinoDialog(
useRootNavigator: true, useRootNavigator: true,

View File

@ -37,7 +37,7 @@ class _MyDevelopmentBodyPage extends State<MyDevelopmentBodyPage> with Trans, Co
setContext(context); setContext(context);
return DialogPremium( return DialogPremium(
unlocked: Cache().hasPurchased, unlocked: Cache().hasPurchased,
unlockRound: 2, unlockRound: 4,
function: "My Whole Body Development", function: "My Whole Body Development",
unlockedText: null, unlockedText: null,
onTap: () => {Navigator.of(context).pop(), Navigator.of(context).pop()}, onTap: () => {Navigator.of(context).pop(), Navigator.of(context).pop()},

View File

@ -163,7 +163,7 @@ class _MyDevelopmentPage extends State<MyDevelopmentPage> with Trans {
builder: (BuildContext context) { builder: (BuildContext context) {
return DialogPremium( return DialogPremium(
unlocked: Cache().hasPurchased, unlocked: Cache().hasPurchased,
unlockRound: 3, unlockRound: 12,
function: "Predictions", function: "Predictions",
unlockedText: null, unlockedText: null,
onTap: () => {Navigator.of(context).pop()}, onTap: () => {Navigator.of(context).pop()},

View File

@ -2,6 +2,7 @@ import 'dart:io';
import 'package:aitrainer_app/bloc/account/account_bloc.dart'; import 'package:aitrainer_app/bloc/account/account_bloc.dart';
import 'package:aitrainer_app/bloc/login/login_bloc.dart'; import 'package:aitrainer_app/bloc/login/login_bloc.dart';
import 'package:aitrainer_app/repository/customer_repository.dart';
import 'package:aitrainer_app/repository/training_plan_repository.dart'; import 'package:aitrainer_app/repository/training_plan_repository.dart';
import 'package:aitrainer_app/repository/user_repository.dart'; import 'package:aitrainer_app/repository/user_repository.dart';
import 'package:aitrainer_app/util/trans.dart'; import 'package:aitrainer_app/util/trans.dart';
@ -23,12 +24,23 @@ class RegistrationPage extends StatelessWidget with Trans {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final accountBloc = BlocProvider.of<AccountBloc>(context); final accountBloc = BlocProvider.of<AccountBloc>(context);
CustomerRepository? customerRepository;
if (ModalRoute.of(context) != null && ModalRoute.of(context)!.settings.arguments != null) {
customerRepository = ModalRoute.of(context)!.settings.arguments as CustomerRepository;
print("CustomerFitness reg ${customerRepository.customer!.toJson()}");
}
setContext(context); setContext(context);
return Scaffold( return Scaffold(
appBar: AppBarMin(), appBar: AppBarMin(),
body: BlocProvider( body: BlocProvider(
create: (context) => create: (context) => LoginBloc(
LoginBloc(userRepository: UserRepository(), accountBloc: accountBloc, context: context, isRegistration: true), userRepository: UserRepository(),
accountBloc: accountBloc,
context: context,
isRegistration: true,
customerRepository: customerRepository),
child: BlocConsumer<LoginBloc, LoginState>(listener: (context, state) { child: BlocConsumer<LoginBloc, LoginState>(listener: (context, state) {
if (state is LoginError) { if (state is LoginError) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
@ -67,7 +79,9 @@ class RegistrationPage extends StatelessWidget with Trans {
} }
}, builder: (context, state) { }, builder: (context, state) {
final loginBloc = BlocProvider.of<LoginBloc>(context); final loginBloc = BlocProvider.of<LoginBloc>(context);
if (customerRepository != null) {
print("Customer data ${customerRepository.customer!.toJson()}");
}
return ModalProgressHUD( return ModalProgressHUD(
child: loadForm(loginBloc, accountBloc), child: loadForm(loginBloc, accountBloc),
inAsyncCall: state is LoginLoading, inAsyncCall: state is LoginLoading,

View File

@ -1,5 +1,3 @@
import 'dart:io';
import 'package:aitrainer_app/bloc/menu/menu_bloc.dart'; import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
import 'package:aitrainer_app/bloc/settings/settings_bloc.dart'; import 'package:aitrainer_app/bloc/settings/settings_bloc.dart';
import 'package:aitrainer_app/bloc/tutorial/tutorial_bloc.dart'; import 'package:aitrainer_app/bloc/tutorial/tutorial_bloc.dart';
@ -19,8 +17,8 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart'; import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart';
import 'package:toggle_switch/toggle_switch.dart'; import 'package:toggle_switch/toggle_switch.dart';
import 'package:flutter/services.dart'; import 'package:mailto/mailto.dart';
import 'dart:async'; import 'package:url_launcher/url_launcher.dart';
// ignore: must_be_immutable // ignore: must_be_immutable
class SettingsPage extends StatelessWidget with Trans { class SettingsPage extends StatelessWidget with Trans {
@ -87,7 +85,7 @@ class SettingsPage extends StatelessWidget with Trans {
//getTuturialBasic(settingsBloc), //getTuturialBasic(settingsBloc),
getTermsOfUse(), getTermsOfUse(),
getPrivacy(), getPrivacy(),
getFaq(), mailTo(),
getVersion(), getVersion(),
//getDevice(settingsBloc), //getDevice(settingsBloc),
]); ]);
@ -264,25 +262,40 @@ class SettingsPage extends StatelessWidget with Trans {
); );
} }
Future<void> _printAndCopy(String cmd) async { ListTile mailTo() {
print(cmd); return ListTile(
leading: Icon(CustomIcon.mail_1),
await Clipboard.setData(ClipboardData(text: cmd)); title: TextButton(
ScaffoldMessenger.of(context).showSnackBar( child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
const SnackBar(content: Text('Copied to Clipboard')), Text("Feedback email", style: TextStyle(color: Colors.indigo)),
Icon(
Icons.arrow_forward_ios,
color: Colors.indigo,
),
]),
style: TextButton.styleFrom(
backgroundColor: Colors.white70,
onSurface: Colors.grey,
),
onPressed: () => {
launchMailto(),
Track().track(TrackingEvent.feedback_email),
},
),
); );
} }
void link1() { launchMailto() async {
String? cmd; String from = Cache().userLoggedIn == null ? "" : Cache().userLoggedIn!.customerId!.toStringAsFixed(0);
String cmdSuffix; final mailtoLink = Mailto(
if (Platform.isIOS) { to: ['service@workouttest.com'],
cmd = '/usr/bin/xcrun simctl openurl booted'; subject: 'Feedback from app: $from',
} else if (Platform.isAndroid) { body: '',
cmd = '\$ANDROID_HOME/platform-tools/adb shell \'am start' );
' -a android.intent.action.VIEW' // Convert the Mailto instance into a string.
' -c android.intent.category.BROWSABLE -d'; // Use either Dart's string interpolation
cmdSuffix = "'"; // or the toString() method.
} print("Mailto: $mailtoLink");
await launch('$mailtoLink');
} }
} }

View File

@ -3,13 +3,16 @@ import 'dart:collection';
import 'package:aitrainer_app/bloc/test_set_execute/test_set_execute_bloc.dart'; import 'package:aitrainer_app/bloc/test_set_execute/test_set_execute_bloc.dart';
import 'package:aitrainer_app/bloc/test_set_new/test_set_new_bloc.dart'; import 'package:aitrainer_app/bloc/test_set_new/test_set_new_bloc.dart';
import 'package:aitrainer_app/library/custom_icon_icons.dart'; import 'package:aitrainer_app/library/custom_icon_icons.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/exercise_plan_detail.dart'; import 'package:aitrainer_app/model/exercise_plan_detail.dart';
import 'package:aitrainer_app/model/exercise_type.dart'; import 'package:aitrainer_app/model/exercise_type.dart';
import 'package:aitrainer_app/model/workout_menu_tree.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart'; import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/util/trans.dart'; import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar.dart'; import 'package:aitrainer_app/widgets/app_bar.dart';
import 'package:aitrainer_app/widgets/bottom_bar_multiple_exercises.dart'; import 'package:aitrainer_app/widgets/bottom_bar_multiple_exercises.dart';
import 'package:aitrainer_app/widgets/exercise_save.dart'; import 'package:aitrainer_app/widgets/exercise_save.dart';
import 'package:aitrainer_app/widgets/menu_image.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
@ -29,7 +32,6 @@ class TestSetNew extends StatelessWidget with Trans {
return Scaffold( return Scaffold(
appBar: AppBarNav(depth: 1), appBar: AppBarNav(depth: 1),
body: Container( body: Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration( decoration: BoxDecoration(
image: DecorationImage( image: DecorationImage(
image: AssetImage('asset/image/WT_black_background.jpg'), image: AssetImage('asset/image/WT_black_background.jpg'),
@ -77,7 +79,7 @@ class TestSetNew extends StatelessWidget with Trans {
backgroundColor: Colors.orange[800], backgroundColor: Colors.orange[800],
icon: Icon(CustomIcon.save), icon: Icon(CustomIcon.save),
label: Text( label: Text(
t("Save"), t("Done"),
style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 16), style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 16),
), ),
), ),
@ -89,6 +91,8 @@ class TestSetNew extends StatelessWidget with Trans {
} }
Widget getExercises(TestSetNewBloc bloc) { Widget getExercises(TestSetNewBloc bloc) {
WorkoutMenuTree? workoutTree =
bloc.executeBloc.menuBloc.menuTreeRepository.getMenuItemByExerciseTypeId(bloc.exerciseType.exerciseTypeId);
return ExerciseSave( return ExerciseSave(
exerciseName: bloc.exerciseType.nameTranslation, exerciseName: bloc.exerciseType.nameTranslation,
exerciseDescription: bloc.exerciseType.descriptionTranslation, exerciseDescription: bloc.exerciseType.descriptionTranslation,
@ -103,6 +107,12 @@ class TestSetNew extends StatelessWidget with Trans {
}, },
onUnitQuantityChanged: (value) => bloc.add(TestSetNewChangeQuantityUnit(quantity: value)), onUnitQuantityChanged: (value) => bloc.add(TestSetNewChangeQuantityUnit(quantity: value)),
exerciseTypeId: bloc.exerciseType.exerciseTypeId, exerciseTypeId: bloc.exerciseType.exerciseTypeId,
tip: ActivityDone.exerciseSaveTestsetTip,
menuImage: MenuImage(
imageName: workoutTree!.imageName,
workoutTreeId: workoutTree.id,
radius: 0,
),
/* onSubmit: () { /* onSubmit: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
bloc.add(TestSetNewSubmit()); bloc.add(TestSetNewSubmit());

View File

@ -6,6 +6,7 @@ import 'package:aitrainer_app/library/custom_icon_icons.dart';
import 'package:aitrainer_app/library/tree_view.dart'; import 'package:aitrainer_app/library/tree_view.dart';
import 'package:aitrainer_app/model/cache.dart'; import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/training_plan.dart'; import 'package:aitrainer_app/model/training_plan.dart';
import 'package:aitrainer_app/model/training_plan_detail.dart';
import 'package:aitrainer_app/model/workout_menu_tree.dart'; import 'package:aitrainer_app/model/workout_menu_tree.dart';
import 'package:aitrainer_app/util/app_language.dart'; import 'package:aitrainer_app/util/app_language.dart';
import 'package:aitrainer_app/util/trans.dart'; import 'package:aitrainer_app/util/trans.dart';
@ -58,7 +59,7 @@ class TrainingPlanActivatePage extends StatelessWidget with Trans {
title: t("Warning"), title: t("Warning"),
descriptions: t(state.message), descriptions: t(state.message),
text: "OK", text: "OK",
onTap: () => Navigator.of(context).pushNamed("login"), onTap: () => Navigator.of(context).pop(),
onCancel: () => { onCancel: () => {
Navigator.of(context).pop(), Navigator.of(context).pop(),
}, },
@ -197,21 +198,45 @@ class TrainingPlanActivatePage extends StatelessWidget with Trans {
icon: Icon(Icons.list_sharp), icon: Icon(Icons.list_sharp),
color: Colors.blue[800], color: Colors.blue[800],
), ),
children: _getChildList(element, bloc), children: _getDays(element, bloc),
))); )));
}); });
return listWidget; return listWidget;
} }
List<Widget> _getChildList(TrainingPlan plan, TrainingPlanBloc bloc) { List<Widget> _getDays(TrainingPlan plan, TrainingPlanBloc bloc) {
List<Widget> listWidget = [];
bloc.setMyTrainingPlan(plan);
bloc.activateTrainingPlanDays();
bloc.trainingPlanDayNames.forEach((value) {
listWidget.add(Container(
margin: const EdgeInsets.only(left: 4.0),
child: TreeViewChild(
startExpanded: true,
parent: TreeviewParentWidget(
text: " * " + t("Training Day") + ": " + value,
fontSize: 16,
color: Colors.white,
icon: Icon(Icons.view_day),
backgroundColor: Colors.white24,
),
children: _getChildList(plan, bloc, value),
)));
});
return listWidget;
}
List<Widget> _getChildList(TrainingPlan plan, TrainingPlanBloc bloc, String dayName) {
List<Widget> list = []; List<Widget> list = [];
bool restricted = (!plan.free && !Cache().hasPurchased); bool restricted = (!plan.free && !Cache().hasPurchased);
list.add(Card( list.add(Card(
margin: EdgeInsets.only(left: 10, top: 5), margin: EdgeInsets.only(left: 10, top: 5),
color: Colors.white60, color: Colors.white24,
child: Container( child: Container(
padding: EdgeInsets.only(left: 10, right: 10), padding: EdgeInsets.only(left: 10, right: 10),
child: Column(children: [ child: Column(children: [
@ -262,7 +287,7 @@ class TrainingPlanActivatePage extends StatelessWidget with Trans {
), ),
)) ))
: Offstage(), : Offstage(),
getPlanDetails(plan, bloc), getPlanDetails(plan, bloc, dayName),
ElevatedButton( ElevatedButton(
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
onPrimary: Colors.white, onPrimary: Colors.white,
@ -371,13 +396,17 @@ class TrainingPlanActivatePage extends StatelessWidget with Trans {
} }
} }
Widget getPlanDetails(TrainingPlan plan, TrainingPlanBloc bloc) { Widget getPlanDetails(TrainingPlan plan, TrainingPlanBloc bloc, String dayName) {
return SfDataGrid( return SfDataGrid(
headerRowHeight: 30, headerRowHeight: 30,
rowHeight: 60, rowHeight: 70,
columnWidthMode: ColumnWidthMode.lastColumnFill,
defaultColumnWidth: 50,
source: TrainingPlanDetailSource( source: TrainingPlanDetailSource(
plan: plan, plan: plan,
menuBloc: bloc.menuBloc, menuBloc: bloc.menuBloc,
bloc: bloc,
dayName: dayName,
onWeightTap: () => { onWeightTap: () => {
showDialog( showDialog(
context: context, context: context,
@ -438,18 +467,23 @@ class TrainingPlanActivatePage extends StatelessWidget with Trans {
columns: [ columns: [
GridTextColumn( GridTextColumn(
columnWidthMode: ColumnWidthMode.lastColumnFill, columnWidthMode: ColumnWidthMode.lastColumnFill,
maximumWidth: 160, maximumWidth: 130,
columnName: 'exerciseImage', columnName: 'exerciseImage',
label: Container( label: Container(
color: Colors.green[50], color: Colors.black38,
padding: EdgeInsets.only(left: 8.0), padding: EdgeInsets.only(left: 8.0),
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Text( child: Text(
t('Exercise'), t('Exercise'),
style: GoogleFonts.inter(
color: Colors.white,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.start, textAlign: TextAlign.start,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
))), ))),
GridTextColumn( GridTextColumn(
maximumWidth: 0,
visible: false, visible: false,
columnName: 'exerciseName', columnName: 'exerciseName',
label: Container( label: Container(
@ -462,47 +496,40 @@ class TrainingPlanActivatePage extends StatelessWidget with Trans {
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
))), ))),
GridTextColumn( GridTextColumn(
maximumWidth: 40, maximumWidth: 60,
columnName: 'set', columnName: 'Set',
label: Container( label: Container(
color: Colors.green[50], color: Colors.black38,
padding: EdgeInsets.symmetric(horizontal: 2.0), padding: EdgeInsets.symmetric(horizontal: 2.0),
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Text( child: Text(
t('Set'), t('Set'),
style: GoogleFonts.inter(color: Colors.white, fontWeight: FontWeight.bold),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
))), ))),
GridTextColumn( GridTextColumn(
maximumWidth: 50, maximumWidth: 100,
columnName: 'repeats', columnWidthMode: ColumnWidthMode.fill,
columnName: 'Repeats',
label: Container( label: Container(
color: Colors.green[50], color: Colors.black38,
padding: EdgeInsets.symmetric(horizontal: 2.0), padding: EdgeInsets.symmetric(horizontal: 2.0),
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Text( child: Text(
t('Reps'), t('Repeats'),
style: GoogleFonts.inter(color: Colors.white, fontWeight: FontWeight.bold),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
))), ))),
GridTextColumn( GridTextColumn(
maximumWidth: 60, maximumWidth: 60,
columnName: 'weight', columnName: 'Weight',
label: Container( label: Container(
color: Colors.green[50], color: Colors.black38,
padding: EdgeInsets.symmetric(horizontal: 2.0), padding: EdgeInsets.symmetric(horizontal: 2.0),
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Text( child: Text(
t('Weight'), t('Weight_'),
overflow: TextOverflow.ellipsis, style: GoogleFonts.inter(color: Colors.white, fontWeight: FontWeight.bold),
))),
GridTextColumn(
maximumWidth: 50,
columnName: 'day',
label: Container(
color: Colors.green[50],
padding: EdgeInsets.symmetric(horizontal: 8.0),
alignment: Alignment.centerLeft,
child: Text(
t('Day'),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
))), ))),
], ],
@ -512,19 +539,25 @@ class TrainingPlanActivatePage extends StatelessWidget with Trans {
class TrainingPlanDetailSource extends DataGridSource { class TrainingPlanDetailSource extends DataGridSource {
final TrainingPlan plan; final TrainingPlan plan;
final TrainingPlanBloc bloc;
final MenuBloc menuBloc; final MenuBloc menuBloc;
final dayName;
final VoidCallback onDropsetTap; final VoidCallback onDropsetTap;
final VoidCallback onWeightTap; final VoidCallback onWeightTap;
final VoidCallback onRepeatTap; final VoidCallback onRepeatTap;
TrainingPlanDetailSource({ TrainingPlanDetailSource({
required this.plan, required this.plan,
required this.menuBloc, required this.menuBloc,
required this.bloc,
required this.dayName,
required this.onDropsetTap, required this.onDropsetTap,
required this.onWeightTap, required this.onWeightTap,
required this.onRepeatTap, required this.onRepeatTap,
}) { }) {
if (plan.details != null) { if (plan.details != null) {
dataGridRows = plan.details!.map((dataGridRow) { List<TrainingPlanDetail> details = bloc.trainingPlanDetailSummary(plan, dayName);
dataGridRows = details.map((dataGridRow) {
WorkoutMenuTree? menuTree = menuBloc.menuTreeRepository.getMenuItemByExerciseTypeId(dataGridRow.exerciseTypeId); WorkoutMenuTree? menuTree = menuBloc.menuTreeRepository.getMenuItemByExerciseTypeId(dataGridRow.exerciseTypeId);
if (menuTree == null) { if (menuTree == null) {
return DataGridRow(cells: []); return DataGridRow(cells: []);
@ -539,9 +572,8 @@ class TrainingPlanDetailSource extends DataGridSource {
)), )),
DataGridCell<String>(columnName: 'exerciseName', value: menuTree.name), DataGridCell<String>(columnName: 'exerciseName', value: menuTree.name),
DataGridCell<int>(columnName: 'set', value: dataGridRow.set), DataGridCell<int>(columnName: 'set', value: dataGridRow.set),
DataGridCell<int>(columnName: 'reps', value: dataGridRow.repeats), DataGridCell<String>(columnName: 'reps', value: dataGridRow.summary!),
DataGridCell<double>(columnName: 'weight', value: dataGridRow.weight), DataGridCell<double>(columnName: 'weight', value: dataGridRow.weight),
DataGridCell<String>(columnName: 'day', value: dataGridRow.day),
]); ]);
}).toList(); }).toList();
} }
@ -557,9 +589,9 @@ class TrainingPlanDetailSource extends DataGridSource {
if (row.getCells().isEmpty) { if (row.getCells().isEmpty) {
return null; return null;
} }
String name = row.getCells()[1].value; String name = row.getCells()[1].value.toString();
return DataGridRowAdapter( return DataGridRowAdapter(
color: Colors.white60, color: Colors.white12,
cells: row.getCells().map<Widget>((dataGridCell) { cells: row.getCells().map<Widget>((dataGridCell) {
return Container( return Container(
alignment: dataGridCell.columnName == "exerciseImage" ? Alignment.centerLeft : Alignment.centerLeft, alignment: dataGridCell.columnName == "exerciseImage" ? Alignment.centerLeft : Alignment.centerLeft,
@ -573,8 +605,7 @@ class TrainingPlanDetailSource extends DataGridSource {
name, name,
maxLines: 3, maxLines: 3,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: style: GoogleFonts.inter(fontSize: 12, color: Colors.white, fontWeight: FontWeight.bold, shadows: <Shadow>[
GoogleFonts.inter(fontSize: 10, color: Colors.yellow[600], fontWeight: FontWeight.bold, shadows: <Shadow>[
Shadow( Shadow(
offset: Offset(2.0, 2.0), offset: Offset(2.0, 2.0),
blurRadius: 6.0, blurRadius: 6.0,
@ -590,7 +621,7 @@ class TrainingPlanDetailSource extends DataGridSource {
}, },
child: Icon( child: Icon(
CustomIcon.question_circle, CustomIcon.question_circle,
color: Colors.indigo[300], color: Colors.white,
)) ))
: dataGridCell.columnName == "weight" && dataGridCell.value == -3 : dataGridCell.columnName == "weight" && dataGridCell.value == -3
? GestureDetector( ? GestureDetector(
@ -608,12 +639,12 @@ class TrainingPlanDetailSource extends DataGridSource {
}, },
child: Icon( child: Icon(
CustomIcon.question_circle, CustomIcon.question_circle,
color: Colors.indigo[600], color: Colors.white,
)) ))
: Text(dataGridCell.value.toString(), : Text(dataGridCell.value.toString(),
style: GoogleFonts.inter( style: GoogleFonts.inter(
fontSize: 14, fontSize: 14,
color: Colors.indigo, color: Colors.white,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
))); )));
}).toList()); }).toList());

View File

@ -45,8 +45,20 @@ class _TrainingPlanExecuteState extends State<TrainingPlanExecute> with Trans {
), ),
child: BlocConsumer<TrainingPlanBloc, TrainingPlanState>(listener: (context, state) { child: BlocConsumer<TrainingPlanBloc, TrainingPlanState>(listener: (context, state) {
if (state is TrainingPlanError) { if (state is TrainingPlanError) {
ScaffoldMessenger.of(context).showSnackBar( showDialog(
SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white)))); context: context,
builder: (BuildContext context) {
return DialogCommon(
warning: true,
title: t("Warning"),
descriptions: t(state.message),
text: "OK",
onTap: () => Navigator.of(context).pop(),
onCancel: () => {
Navigator.of(context).pop(),
},
);
});
} else if (state is TrainingPlanDayFinished) { } else if (state is TrainingPlanDayFinished) {
bloc.celebrating = false; bloc.celebrating = false;
final HashMap args = HashMap(); final HashMap args = HashMap();
@ -368,7 +380,7 @@ class _ExerciseListState extends State<ExerciseList> with Trans {
bloc.getMyPlan()!.days[widget.dayName] != null && bloc.getMyPlan()!.days[widget.dayName] != null &&
bloc.getMyPlan()!.days[widget.dayName]!.isNotEmpty) { bloc.getMyPlan()!.days[widget.dayName]!.isNotEmpty) {
bloc.getMyPlan()!.days[widget.dayName]!.forEach((element) { bloc.getMyPlan()!.days[widget.dayName]!.forEach((element) {
if (prev != null && prev!.exerciseTypeId != element.exerciseTypeId) { if (prev == null || (prev != null && prev!.exerciseTypeId != element.exerciseTypeId)) {
tiles.add(GestureDetector( tiles.add(GestureDetector(
onTap: () => onTap: () =>
bloc.getNext() != null ? executeExercise(bloc, bloc.getNext()!, context) : Navigator.of(context).pushNamed('home'), bloc.getNext() != null ? executeExercise(bloc, bloc.getNext()!, context) : Navigator.of(context).pushNamed('home'),

View File

@ -1,914 +0,0 @@
import 'dart:collection';
import 'package:aitrainer_app/bloc/training_plan/training_plan_bloc.dart';
import 'package:aitrainer_app/library/custom_icon_icons.dart';
import 'package:aitrainer_app/model/customer_training_plan_details.dart';
import 'package:aitrainer_app/model/exercise_plan_detail.dart';
import 'package:aitrainer_app/util/app_localization.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar.dart';
import 'package:aitrainer_app/widgets/dialog_common.dart';
import 'package:aitrainer_app/widgets/dialog_html.dart';
import 'package:aitrainer_app/widgets/menu_image.dart';
import 'package:aitrainer_app/widgets/weight_control.dart';
import 'package:badges/badges.dart';
import 'package:extended_tabs/extended_tabs.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart';
import 'package:timeline_tile/timeline_tile.dart';
// ignore: must_be_immutable
class TrainingPlanExecutePage extends StatefulWidget {
@override
_TrainingPlanExecutePageState createState() => _TrainingPlanExecutePageState();
}
class _TrainingPlanExecutePageState extends State<TrainingPlanExecutePage> with Trans {
final scrollController = ScrollController();
TrainingPlanBloc? bloc;
@override
Widget build(BuildContext context) {
final HashMap args = HashMap();
bloc = BlocProvider.of<TrainingPlanBloc>(context);
bloc!.activateDays();
setContext(context);
return Scaffold(
appBar: AppBarNav(depth: 0),
body: Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_black_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
child: BlocConsumer<TrainingPlanBloc, TrainingPlanState>(listener: (context, state) {
if (state is TrainingPlanError) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
} else if (state is TrainingPlanDayFinished) {
bloc!.celebrating = false;
args["bloc"] = bloc;
args["day"] = bloc!.dayNames[bloc!.activeDayIndex];
Navigator.of(context).pushNamed('myTrainingEvaluation', arguments: args);
} else if (state is TrainingPlanDayReadyToRestart) {
if (!bloc!.celebrating) {
showCupertinoDialog(
useRootNavigator: true,
context: context,
builder: (_) => CupertinoAlertDialog(
title: Text(t("The training is finished")),
content: Column(children: [Divider(), Text(t("Do you want to restart, or select a new Training Plan?"))]),
actions: [
TextButton(
child: Text(t("New Training Plan"), textAlign: TextAlign.center),
onPressed: () => {
Navigator.pop(context),
Navigator.of(context).popAndPushNamed('myTrainingPlans'),
bloc!.restarting = false,
}),
TextButton(
child: Text(t("Restart")),
onPressed: () {
bloc!.restart();
Navigator.pop(context);
Navigator.of(context).popAndPushNamed('home');
},
)
],
));
}
}
}, builder: (context, state) {
return ModalProgressHUD(
child: ExerciseTabs(bloc: bloc!),
inAsyncCall: state is TrainingPlanLoading,
opacity: 0.5,
color: Colors.black54,
progressIndicator: CircularProgressIndicator(),
);
}),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () => {
args["bloc"] = bloc,
args["day"] = bloc!.dayNames[bloc!.activeDayIndex],
bloc!.getNext() != null
? _ExerciseListState.executeExercise(bloc!, bloc!.getNext()!, context)
: Navigator.of(context).pushNamed('myTrainingEvaluation', arguments: args),
},
backgroundColor: Colors.orange[800],
icon: Icon(CustomIcon.weight_hanging),
label: Text(
t("Training") + "!",
style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 16),
),
),
);
}
}
class ExerciseTabs extends StatefulWidget {
final TrainingPlanBloc bloc;
ExerciseTabs({required this.bloc});
@override
_ExerciseTabs createState() => _ExerciseTabs();
}
class _ExerciseTabs extends State<ExerciseTabs> with TickerProviderStateMixin {
late TabController tabController;
@override
void initState() {
super.initState();
print("init TAB ${widget.bloc.dayNames.length} index ${widget.bloc.activeDayIndex}");
tabController = TabController(length: widget.bloc.dayNames.length, vsync: this);
tabController.animateTo(widget.bloc.activeDayIndex, duration: Duration(milliseconds: 300));
}
@override
void dispose() {
tabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return getTabs(widget.bloc);
}
Widget getTabs(TrainingPlanBloc bloc) {
return Column(children: [
ExtendedTabBar(
indicator: BoxDecoration(
color: Colors.black87,
border: Border(
bottom: BorderSide(width: 4.0, color: Colors.blue),
top: BorderSide(width: 4.0, color: Colors.blue),
)),
labelPadding: EdgeInsets.only(left: 5, right: 5),
tabs: getTabNames(),
controller: tabController,
onTap: (index) => bloc.activeDayIndex = index,
),
Expanded(
child: ExtendedTabBarView(
children: getExerciseLists(),
controller: tabController,
/// if link is true and current tabbarview over scroll,
/// it will check and scroll ancestor or child tabbarView.
link: true,
/// cache page count
/// default is 0.
/// if cacheExtent is 1, it has two pages in cache
/// null is infinity, it will cache all pages
cacheExtent: 0,
)),
]);
}
List<Tab> getTabNames() {
List<Tab> tabs = [];
widget.bloc.dayNames.forEach((element) {
final Widget widget = Container(
//height: 50,
padding: EdgeInsets.only(top: 2, left: 5, right: 5, bottom: 2),
color: Colors.white24,
child: RichText(
textScaleFactor: 0.8,
text: TextSpan(
style: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.white,
),
children: [
TextSpan(
text: AppLocalizations.of(context)!.translate("Training Day") + ": \n",
style: GoogleFonts.inter(
fontSize: 14,
color: Colors.white,
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
)),
TextSpan(
text: element,
style: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.yellow[400],
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
)),
])));
tabs.add(Tab(child: widget));
});
return tabs;
}
List<Widget> getExerciseLists() {
List<Widget> list = [];
widget.bloc.dayNames.forEach((element) {
list.add(ExerciseList(bloc: widget.bloc, dayName: element));
});
return list;
}
}
class ExerciseList extends StatefulWidget {
final TrainingPlanBloc bloc;
final String dayName;
ExerciseList({required this.bloc, required this.dayName});
@override
_ExerciseListState createState() => _ExerciseListState();
}
class _ExerciseListState extends State<ExerciseList> with Trans {
final scrollController = ScrollController();
double offset = 5;
@override
void initState() {
WidgetsBinding.instance!.addPostFrameCallback((_) {
animate();
});
super.initState();
}
@override
void didUpdateWidget(ExerciseList page) {
super.didUpdateWidget(page);
WidgetsBinding.instance!.addPostFrameCallback((_) {
animate();
});
}
void animate() {
offset = widget.bloc.getOffset();
if (scrollController.hasClients) {
scrollController.animateTo(offset, duration: Duration(milliseconds: 300), curve: Curves.easeIn);
}
}
@override
void dispose() {
scrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
setContext(context);
return CustomScrollView(controller: scrollController, slivers: [
SliverList(delegate: SliverChildListDelegate(getTiles(widget.bloc))),
]);
}
List<Widget> getTiles(TrainingPlanBloc bloc) {
List<Widget> tiles = [];
tiles.add(getStartTile(bloc));
tiles.addAll(getExerciseTiles(bloc, context));
if (bloc.getMyPlan() != null) tiles.add(getEndTile());
return tiles;
}
Widget getStartTile(TrainingPlanBloc bloc) {
String startText = "";
String explainingText = "";
if (null == bloc.getMyPlan()) {
startText = t("No Active Training Plan");
explainingText = t("Please select one in the Training menu, or create your custom plan");
} else {
startText = bloc.isStarted() ? t("Continue your training") : t("Start your training");
explainingText = bloc.getMyPlan()!.name != null ? bloc.getMyPlan()!.name! : "";
}
return TimelineTile(
alignment: TimelineAlign.manual,
lineXY: 0.1,
isFirst: true,
afterLineStyle: const LineStyle(
color: Colors.orange,
thickness: 6,
),
indicatorStyle: IndicatorStyle(
width: 40,
color: Colors.orange,
padding: const EdgeInsets.all(8),
iconStyle: IconStyle(
color: Colors.white,
iconData: Icons.emoji_flags_rounded,
),
),
endChild: Container(
padding: EdgeInsets.only(top: 30),
constraints: const BoxConstraints(
minHeight: 120,
),
color: Colors.transparent,
child: RichText(
text: TextSpan(
style: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.white,
),
children: [
TextSpan(
text: startText,
style: GoogleFonts.inter(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.yellow[400],
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
)),
TextSpan(
text: "\n",
style: GoogleFonts.inter(
fontSize: 16,
color: Colors.white,
)),
TextSpan(
text: explainingText,
style: GoogleFonts.inter(
fontSize: 16,
color: Colors.white,
)),
])),
),
);
}
Widget getEndTile() {
return Container(
color: Colors.transparent,
child: TimelineTile(
alignment: TimelineAlign.manual,
lineXY: 0.1,
isLast: true,
beforeLineStyle: const LineStyle(
color: Colors.orange,
thickness: 6,
),
indicatorStyle: IndicatorStyle(
width: 40,
color: Colors.orange,
padding: const EdgeInsets.all(8),
iconStyle: IconStyle(
color: Colors.white,
iconData: Icons.thumb_up,
),
),
endChild: Container(
padding: EdgeInsets.only(top: 50),
constraints: const BoxConstraints(
minHeight: 120,
),
color: Colors.transparent,
child: RichText(
text: TextSpan(
style: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.white,
),
children: [
TextSpan(
text: "Finish!",
style: GoogleFonts.inter(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.yellow[400],
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
)),
])),
),
),
);
}
List<Widget> getExerciseTiles(TrainingPlanBloc bloc, BuildContext context) {
List<Widget> tiles = [];
if (bloc.getMyPlan() != null &&
bloc.getMyPlan()!.details.isNotEmpty &&
bloc.getMyPlan()!.days[widget.dayName] != null &&
bloc.getMyPlan()!.days[widget.dayName]!.isNotEmpty) {
bloc.getMyPlan()!.days[widget.dayName]!.forEach((element) {
tiles.add(
/* GestureDetector(
onTap: () => bloc.getNext() != null ? executeExercise(bloc, bloc.getNext()!, context) : Navigator.of(context).pushNamed('home'),
child: */
ExerciseTile(
bloc: bloc,
detail: element,
));
});
}
return tiles;
}
static void executeExercise(TrainingPlanBloc bloc, CustomerTrainingPlanDetails detail, BuildContext context) {
CustomerTrainingPlanDetails? next = bloc.getNext();
if (next != null) {
String title = "";
String description = "";
String description2 = "";
if (next.exerciseTypeId != detail.exerciseTypeId) {
title = AppLocalizations.of(context)!.translate("Stop!");
description = AppLocalizations.of(context)!.translate("Please continue with the next exercise in the queue:") +
next.exerciseType!.nameTranslation;
} else {
final HashMap args = HashMap();
args['exerciseType'] = next.exerciseType;
args['customerTrainingPlanDetails'] = detail;
Navigator.of(context).pushNamed('myTrainingPlanExercise', arguments: args);
return;
}
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return DialogCommon(
title: title,
descriptions: description,
description2: description2,
text: "OK",
onTap: () => {Navigator.of(context).pop()},
onCancel: () => {Navigator.of(context).pop()},
);
});
} else {
Navigator.of(context).pushNamed('home');
}
}
}
class ExerciseTile extends StatefulWidget {
final TrainingPlanBloc bloc;
final CustomerTrainingPlanDetails detail;
ExerciseTile({required this.bloc, required this.detail});
@override
_ExerciseTileState createState() => _ExerciseTileState();
}
class _ExerciseTileState extends State<ExerciseTile> with Trans {
GestureRecognizer? _tapRecognizer;
@override
void initState() {
_tapRecognizer = TapGestureRecognizer()..onTap = _onPlusMinusWeight;
super.initState();
}
@override
void dispose() {
if (_tapRecognizer != null) {
_tapRecognizer!.dispose();
}
super.dispose();
}
void _onPlusMinusWeight() {
showDialog(
context: context,
builder: (BuildContext context) {
return WeightControl(
initialValue: widget.detail.weight != null ? widget.detail.weight! : 30,
onTap: (value) => widget.bloc.add(TrainingPlanWeightChangeRecalculate(detail: widget.detail, weight: value)),
);
});
}
Widget getIndicator(ExercisePlanDetailState state) {
CustomerTrainingPlanDetails? next = widget.bloc.getNext();
bool actual = false;
if (next != null) {
if (next.exerciseTypeId == widget.detail.exerciseTypeId) {
actual = true;
}
}
if (state.equalsTo(ExercisePlanDetailState.inProgress)) {
return ClipRRect(
borderRadius: BorderRadius.circular(24.0),
child: Container(
color: actual ? Colors.green : Colors.orange,
child: Icon(
CustomIcon.calendar_2,
size: 28,
color: Colors.white,
)));
} else if (state.equalsTo(ExercisePlanDetailState.finished)) {
return ClipRRect(
borderRadius: BorderRadius.circular(24.0),
child: Container(
color: Colors.white,
child: Icon(
CustomIcon.ok_circled,
size: 40,
color: Colors.green,
)));
} else if (state.equalsTo(ExercisePlanDetailState.skipped)) {
return ClipRRect(
borderRadius: BorderRadius.circular(24.0),
child: Container(
color: Colors.white,
child: Icon(
CustomIcon.stop_1,
size: 40,
color: Colors.grey,
)));
} else if (state.equalsTo(ExercisePlanDetailState.extra)) {
return ClipRRect(
borderRadius: BorderRadius.circular(24.0),
child: Container(
color: Colors.white,
child: Icon(
CustomIcon.stopwatch_20,
size: 40,
color: Colors.blue[800],
)));
} else {
return Image.asset(
"asset/image/pict_reps_volumen_db.png",
);
}
}
@override
Widget build(BuildContext context) {
setContext(context);
final ExercisePlanDetailState state = widget.detail.state;
final bool done = state.equalsTo(ExercisePlanDetailState.finished) || state.equalsTo(ExercisePlanDetailState.skipped);
final String countSerie = widget.detail.set.toString();
final String step = (widget.detail.exercises.length).toString();
String weight = widget.detail.weight != null ? widget.detail.weight!.toStringAsFixed(1) : "-";
bool isDrop = false;
if (widget.detail.weight == -3) {
weight = "DROP";
isDrop = true;
}
String restingTime = widget.detail.restingTime == null ? "" : widget.detail.restingTime!.toStringAsFixed(0);
bool isTest = false;
if (widget.detail.weight != null && widget.detail.weight! == -1) {
weight = "TEST";
isTest = true;
}
String repeats = widget.detail.repeats!.toString();
if (widget.detail.repeats! == -1) {
repeats = t("MAX");
}
final bool extraExercise = widget.detail.exerciseType!.name == "Warming Up" || widget.detail.exerciseType!.name == "Stretching";
bool buddyWarning = widget.detail.exerciseType == null ? false : widget.detail.exerciseType!.buddyWarning;
setContext(context);
return Container(
color: Colors.transparent,
child: TimelineTile(
alignment: TimelineAlign.manual,
lineXY: 0.1,
beforeLineStyle: const LineStyle(
color: Color(0xffb4f500),
thickness: 6,
),
afterLineStyle: const LineStyle(
color: Color(0xffb4f500),
thickness: 6,
),
indicatorStyle: IndicatorStyle(
width: 40,
height: 40,
indicator: getIndicator(state),
),
startChild: Container(
child: Column(children: [
SizedBox(
height: 1,
),
SizedBox(
height: 55,
),
done
? Offstage()
: IconButton(
padding: EdgeInsets.zero,
alignment: Alignment.centerLeft,
icon: Icon(
Icons.skip_next_sharp,
size: 30,
color: Colors.orange[300],
),
onPressed: () => skip()),
]),
),
endChild: Container(
padding: EdgeInsets.only(left: 10),
child: Row(children: [
Container(
width: 120,
height: 80,
child: Badge(
elevation: 0,
padding: EdgeInsets.all(0),
position: BadgePosition.bottomStart(start: -5),
animationDuration: Duration(milliseconds: 500),
animationType: BadgeAnimationType.slide,
badgeColor: Colors.transparent,
showBadge: true,
badgeContent: IconButton(
onPressed: () => showDialog(
context: context,
builder: (BuildContext context) {
return DialogHTML(
title: widget.detail.exerciseType!.nameTranslation,
htmlData: '<p>' + widget.detail.exerciseType!.descriptionTranslation + '</p>');
}),
icon: Icon(
Icons.info_outline,
color: Colors.yellow[200],
)),
child: Badge(
elevation: 0,
padding: EdgeInsets.all(0),
position: BadgePosition.topEnd(end: -8),
animationDuration: Duration(milliseconds: 500),
animationType: BadgeAnimationType.slide,
badgeColor: Colors.transparent,
showBadge: buddyWarning,
badgeContent: IconButton(
onPressed: () => showDialog(
context: context,
builder: (BuildContext context) {
return DialogCommon(
warning: true,
text: "Warning",
descriptions: t("Attention!"),
description2: t("The safe and exact execution of this exercise you need a training buddy or a trainer"),
description3: t("Execution at your own risk!"),
onTap: () => Navigator.of(context).pop(),
onCancel: () => Navigator.of(context).pop(),
title: t('Training Buddy'),
);
}),
icon: Icon(
CustomIcon.exclamation_circle,
color: Colors.red[800],
)),
child: MenuImage(
imageName: widget.bloc.getActualImageName(widget.detail.exerciseType!.exerciseTypeId),
workoutTreeId: widget.bloc.getActualWorkoutTreeId(widget.detail.exerciseType!.exerciseTypeId)!,
radius: 12,
))),
),
SizedBox(
width: 10,
),
Expanded(
child: RichText(
text: TextSpan(
style: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.bold,
color: done ? Colors.grey[400] : Colors.white,
),
children: [
TextSpan(
text: widget.detail.exerciseType!.nameTranslation,
style: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.bold,
color: done ? Colors.grey[400] : Colors.orange[500],
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
)),
widget.detail.exerciseType!.unitQuantityUnit != null && !extraExercise
? TextSpan(
text: "\n",
)
: TextSpan(),
widget.detail.exerciseType!.unitQuantityUnit != null && !extraExercise
? TextSpan(
text: t(widget.detail.exerciseType!.unitQuantityUnit!) + ": ",
style: GoogleFonts.inter(
fontSize: 12, color: done ? Colors.grey[100] : Colors.yellow[400], fontWeight: FontWeight.bold))
: TextSpan(),
widget.detail.exerciseType!.unitQuantityUnit != null && !extraExercise
? TextSpan(
text: t(weight),
style: GoogleFonts.inter(
fontSize: 12,
))
: TextSpan(),
widget.detail.exerciseType!.unitQuantityUnit != null && !extraExercise && weight != "TEST" && weight != "DROP"
? TextSpan(
text: " - +",
style: GoogleFonts.archivoBlack(
color: Colors.blue,
fontSize: 16,
),
recognizer: _tapRecognizer,
mouseCursor: SystemMouseCursors.precise,
)
: TextSpan(),
TextSpan(
text: "\n",
),
!extraExercise
? TextSpan(
text: t(widget.detail.exerciseType!.unit) + ": ",
style: GoogleFonts.inter(
fontSize: 12, color: done ? Colors.grey[100] : Colors.yellow[400], fontWeight: FontWeight.bold))
: TextSpan(),
!extraExercise
? TextSpan(
text: repeats,
style: GoogleFonts.inter(
fontSize: 12,
))
: TextSpan(),
TextSpan(
text: "\n",
),
!extraExercise
? TextSpan(
text: t("Set") + ": ",
style: GoogleFonts.inter(
fontSize: 12, color: done ? Colors.grey[100] : Colors.yellow[400], fontWeight: FontWeight.bold))
: TextSpan(),
!extraExercise
? TextSpan(
text: step + "/" + countSerie,
style: GoogleFonts.inter(
fontSize: 12,
))
: TextSpan(),
TextSpan(
text: "\n",
),
!extraExercise
? TextSpan(
text: t("Resting time") + ": ",
style: GoogleFonts.inter(
fontSize: 12, color: done ? Colors.grey[100] : Colors.yellow[400], fontWeight: FontWeight.bold))
: TextSpan(),
!extraExercise
? TextSpan(
text: restingTime + " " + t("min(s)"),
style:
GoogleFonts.inter(fontSize: 12, color: done ? Colors.grey[100] : Colors.white, fontWeight: FontWeight.bold))
: TextSpan(),
]),
)),
isTest
? Container(
child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
GestureDetector(
onTap: () => showDialog(
context: context,
builder: (BuildContext context) {
return DialogCommon(
warning: false,
title: t("Why Test?"),
descriptions: t("This is your first exercise after at least 3 weeks."),
description2:
t("The first exercise will be a test. The following sets will be recalculated base on your test."),
description3: t("This is the most optimal way for your development"),
text: "OK",
onTap: () => Navigator.of(context).pop(),
onCancel: () => {
Navigator.of(context).pop(),
},
);
}),
child: Icon(
CustomIcon.question_circle,
color: Colors.yellowAccent[700],
size: 16,
)),
]))
: isDrop
? Container(
child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
GestureDetector(
onTap: () => showDialog(
context: context,
builder: (BuildContext context) {
return DialogCommon(
warning: false,
title: t("Drop Set"),
descriptions: t(
"Execute at least 3 sets with maximum repeats, without resting time, with decreasing the weight."),
description2:
t("The goal is to completly exhaust your muscle without lifting a ridiculous weight end the end."),
text: "OK",
onTap: () => Navigator.of(context).pop(),
onCancel: () => {
Navigator.of(context).pop(),
},
);
}),
child: Icon(
CustomIcon.question_circle,
color: Colors.orange[200],
size: 16,
)),
]))
: Offstage()
]),
),
),
);
}
void skip() {
showCupertinoDialog(
useRootNavigator: true,
context: context,
builder: (_) => CupertinoAlertDialog(
title: Text(t("You want to skip really this exercise?")),
content: Column(children: [
Divider(),
]),
actions: [
TextButton(
child: Text(t("No")),
onPressed: () => {
Navigator.pop(context),
}),
TextButton(
child: Text(t("Yes")),
onPressed: () {
Navigator.pop(context);
widget.bloc.add(TrainingPlanSkipExercise(detail: widget.detail));
},
)
],
));
}
}

View File

@ -2,10 +2,12 @@ import 'dart:collection';
import 'package:aitrainer_app/bloc/training_plan/training_plan_bloc.dart'; import 'package:aitrainer_app/bloc/training_plan/training_plan_bloc.dart';
import 'package:aitrainer_app/library/custom_icon_icons.dart'; import 'package:aitrainer_app/library/custom_icon_icons.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/customer_training_plan_details.dart'; import 'package:aitrainer_app/model/customer_training_plan_details.dart';
import 'package:aitrainer_app/util/trans.dart'; import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar.dart'; import 'package:aitrainer_app/widgets/app_bar.dart';
import 'package:aitrainer_app/widgets/exercise_save.dart'; import 'package:aitrainer_app/widgets/exercise_save.dart';
import 'package:aitrainer_app/widgets/menu_image.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
@ -26,7 +28,7 @@ class TrainingPlanExercise extends StatelessWidget with Trans {
body: Container( body: Container(
height: double.infinity, height: double.infinity,
width: double.infinity, width: double.infinity,
padding: EdgeInsets.all(20), //padding: EdgeInsets.all(20),
decoration: BoxDecoration( decoration: BoxDecoration(
image: DecorationImage( image: DecorationImage(
image: AssetImage("asset/image/WT_black_background.jpg"), image: AssetImage("asset/image/WT_black_background.jpg"),
@ -75,7 +77,7 @@ class TrainingPlanExercise extends StatelessWidget with Trans {
backgroundColor: Colors.orange[800], backgroundColor: Colors.orange[800],
icon: Icon(CustomIcon.save), icon: Icon(CustomIcon.save),
label: Text( label: Text(
isDropSet ? t("Done") : t("Save"), t("Done"),
style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 16), style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 16),
), ),
), ),
@ -92,7 +94,7 @@ class TrainingPlanExercise extends StatelessWidget with Trans {
unit: detail.exerciseType!.unit, unit: detail.exerciseType!.unit,
unitQuantityUnit: detail.exerciseType!.unitQuantityUnit, unitQuantityUnit: detail.exerciseType!.unitQuantityUnit,
hasUnitQuantity: detail.exerciseType!.unitQuantityUnit != null, hasUnitQuantity: detail.exerciseType!.unitQuantityUnit != null,
weight: detail.weight == -1 ? 0 : detail.weight, weight: detail.weight,
repeats: detail.repeats == -1 ? 99 : detail.repeats, repeats: detail.repeats == -1 ? 99 : detail.repeats,
set: detail.set, set: detail.set,
exerciseNr: detail.exercises.length + 1, exerciseNr: detail.exercises.length + 1,
@ -100,6 +102,13 @@ class TrainingPlanExercise extends StatelessWidget with Trans {
onQuantityChanged: (value) => bloc.add(TrainingPlanRepeatsChange(repeats: value.toInt(), detail: detail)), onQuantityChanged: (value) => bloc.add(TrainingPlanRepeatsChange(repeats: value.toInt(), detail: detail)),
exerciseTypeId: detail.exerciseType!.exerciseTypeId, exerciseTypeId: detail.exerciseType!.exerciseTypeId,
originalQuantity: originalQuantity, originalQuantity: originalQuantity,
tip: ActivityDone.exerciseSaveTrainingTip,
menuImage: MenuImage(
imageName: bloc.getActualImageName(detail.exerciseType!.exerciseTypeId),
workoutTreeId: bloc.getActualWorkoutTreeId(detail.exerciseType!.exerciseTypeId)!,
radius: 0,
filter: false,
),
); );
} else { } else {
return getDropSet(bloc, detail); return getDropSet(bloc, detail);

View File

@ -44,7 +44,7 @@ class MyTrainingPlans extends StatelessWidget with Trans, Logging {
title: t("Warning"), title: t("Warning"),
descriptions: t(state.message), descriptions: t(state.message),
text: "OK", text: "OK",
onTap: () => Navigator.of(context).pushNamed("login"), onTap: () => Navigator.of(context).pop(),
onCancel: () => { onCancel: () => {
Navigator.of(context).pop(), Navigator.of(context).pop(),
}, },

View File

@ -286,7 +286,7 @@ class _BMRState extends State<BMR> with Trans {
), ),
), ),
mode: Mode.MENU, mode: Mode.MENU,
compareFn: (FitnessState i, FitnessState s) => i.isEqual(s), compareFn: (FitnessState? i, FitnessState? s) => i!.isEqual(s),
showSelectedItem: true, showSelectedItem: true,
selectedItem: FitnessItem().getItem(fitnessLevel), selectedItem: FitnessItem().getItem(fitnessLevel),
itemAsString: (data) => t(data!.stateText), itemAsString: (data) => t(data!.stateText),
@ -301,7 +301,6 @@ class _BMRState extends State<BMR> with Trans {
color: Colors.yellow[200], color: Colors.yellow[200],
), ),
)); ));
//items: FitnessItem().toList()));
} }
Widget _customMenuBuilder(BuildContext context, FitnessState? item, bool isSelected) { Widget _customMenuBuilder(BuildContext context, FitnessState? item, bool isSelected) {

View File

@ -88,7 +88,7 @@ class _DialogPremiumState extends State<DialogPremium> with Trans {
alignment: AlignmentDirectional.topEnd, alignment: AlignmentDirectional.topEnd,
children: [ children: [
Text( Text(
widget.unlocked ? t("Keep testing") : t("Go Premium") + " ", widget.unlocked ? t("Keep training") : t("Go Premium") + " ",
style: GoogleFonts.archivoBlack( style: GoogleFonts.archivoBlack(
fontSize: widget.unlocked ? 20 : 24, fontSize: widget.unlocked ? 20 : 24,
color: Colors.yellow[400], color: Colors.yellow[400],
@ -257,11 +257,7 @@ class _DialogPremiumState extends State<DialogPremium> with Trans {
list.add(TextSpan(text: t(" "))); list.add(TextSpan(text: t(" ")));
list.add( list.add(
TextSpan( TextSpan(
text: widget.unlockRound == 1 text: widget.unlockRound.toString() + " " + t("week"),
? t("the first")
: widget.unlockRound == 2
? t("the second")
: t("the third"),
style: GoogleFonts.inter( style: GoogleFonts.inter(
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@ -282,7 +278,7 @@ class _DialogPremiumState extends State<DialogPremium> with Trans {
), ),
); );
list.add(TextSpan(text: t(" "))); list.add(TextSpan(text: t(" ")));
list.add(TextSpan(text: t("100% test circles"))); list.add(TextSpan(text: t("100% completed training")));
return list; return list;
} }

View File

@ -120,7 +120,7 @@ class _DialogTrialWidgetState extends State<DialogTrialWidget> with Trans {
children: [ children: [
Image.asset('asset/icon/gomb_lila_b.png', width: 100, height: 45), Image.asset('asset/icon/gomb_lila_b.png', width: 100, height: 45),
Text( Text(
t("Nem"), t("No"),
style: TextStyle(fontSize: 16, color: Colors.white), style: TextStyle(fontSize: 16, color: Colors.white),
), ),
], ],
@ -132,7 +132,7 @@ class _DialogTrialWidgetState extends State<DialogTrialWidget> with Trans {
children: [ children: [
Image.asset('asset/icon/gomb_orange_c.png', width: 100, height: 45), Image.asset('asset/icon/gomb_orange_c.png', width: 100, height: 45),
Text( Text(
t("Igen"), t("Yes"),
style: TextStyle(fontSize: 16, color: Colors.white), style: TextStyle(fontSize: 16, color: Colors.white),
), ),
], ],

View File

@ -1,21 +1,113 @@
import 'dart:async'; import 'dart:async';
import 'package:aitrainer_app/bloc/tutorial/tutorial_bloc.dart';
import 'package:aitrainer_app/library/custom_icon_icons.dart'; import 'package:aitrainer_app/library/custom_icon_icons.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/util/trans.dart'; import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/menu_image.dart';
import 'package:aitrainer_app/widgets/time_picker.dart'; import 'package:aitrainer_app/widgets/time_picker.dart';
import 'package:aitrainer_app/widgets/tutorial_widget.dart';
import 'package:badges/badges.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:keyboard_actions/keyboard_actions.dart'; import 'package:keyboard_actions/keyboard_actions.dart';
import 'package:keyboard_actions/keyboard_actions_config.dart'; import 'package:keyboard_actions/keyboard_actions_config.dart';
import 'package:stop_watch_timer/stop_watch_timer.dart'; import 'package:stop_watch_timer/stop_watch_timer.dart';
import 'package:wakelock/wakelock.dart'; import 'package:wakelock/wakelock.dart';
import 'dialog_common.dart';
import 'dialog_html.dart'; import 'dialog_html.dart';
enum Explanations { intro, introBold, explanationWeight, explanationRepeats, explanationButton, explanationButtonExt }
extension ExplanationsExt on Explanations {
String toStr() => this.toString().split(".").last;
bool equalsTo(Explanations type) => this.toString() == type.toString();
bool equalsStringTo(String type) => this.toStr() == type;
}
class ExplanationExt {
final ActivityDone tip;
final String? unitQuantityUnit;
final double? weight;
final int? repeats;
ExplanationExt({
required this.tip,
this.unitQuantityUnit,
required this.weight,
required this.repeats,
});
String getExplanation(Explanations explanation) {
String expl = "";
if (this.tip.equalsTo(ActivityDone.exerciseSaveTestTip)) {
if (explanation.equalsTo(Explanations.intro)) {
expl = "Please take a middle weight which you are able to do 8-20 times with.";
} else if (explanation.equalsTo(Explanations.introBold)) {
expl = "Execute your MAXIMUM repeats with it!";
} else if (explanation.equalsTo(Explanations.explanationWeight)) {
expl = "Type here your selected weight,";
} else if (explanation.equalsTo(Explanations.explanationRepeats)) {
expl = "then here, how many times could you repeat it!";
} else if (explanation.equalsTo(Explanations.explanationButton)) {
expl = "After you done, click to the OK button!";
} else if (explanation.equalsTo(Explanations.explanationButtonExt)) {
expl = "";
}
} else if (this.tip.equalsTo(ActivityDone.exerciseSaveTrainingTip)) {
if (unitQuantityUnit != null) {
if (weight == -1) {
if (explanation.equalsTo(Explanations.intro)) {
expl = "Please take a middle weight which you are able to do 8-20 times with.";
} else if (explanation.equalsTo(Explanations.introBold)) {
expl = "Execute your MAXIMUM repeats with it!";
}
} else if (repeats == 99) {
if (explanation.equalsTo(Explanations.intro)) {
expl = "It is time to exhaust your muscles";
}
} else {
if (explanation.equalsTo(Explanations.intro)) {
expl = "For your optimal development we calculated a suitable weight and repeats";
} else if (explanation.equalsTo(Explanations.introBold)) {
expl = "You can change the weight, if you could not set it in the training room";
}
}
if (explanation.equalsTo(Explanations.explanationButtonExt)) {
if (repeats != 99) {
expl = "If you could do less, then modify and click to OK";
}
} else if (explanation.equalsTo(Explanations.explanationWeight)) {
if (weight == -1 || weight == -2) {
expl = "Type here your selected weight,";
} else {
expl = "Here is your tailored weight,";
}
} else if (explanation.equalsTo(Explanations.explanationRepeats)) {
if (repeats == 99) {
expl = "and execute it with maximum repeats!";
} else {
expl = "and executed with this number of repeats!";
}
}
} else {
if (repeats == 99) {
if (explanation.equalsTo(Explanations.intro)) {
expl = "Please repeat as much times as you can! MAXIMIZE it!";
}
} else {
if (explanation.equalsTo(Explanations.intro)) {
expl = "Please try to execute this exercise with exact repeats what is suggested";
}
}
}
if (explanation.equalsTo(Explanations.explanationButton)) {
expl = "After you done, click to the OK button!";
}
} else if (this.tip.equalsTo(ActivityDone.exerciseSaveTestsetTip)) {}
return expl;
}
}
// ignore: must_be_immutable // ignore: must_be_immutable
class ExerciseSave extends StatefulWidget { class ExerciseSave extends StatefulWidget {
final ValueChanged<double> onQuantityChanged; final ValueChanged<double> onQuantityChanged;
@ -33,6 +125,8 @@ class ExerciseSave extends StatefulWidget {
final int? set; final int? set;
final int? exerciseNr; final int? exerciseNr;
final int? originalQuantity; final int? originalQuantity;
final MenuImage menuImage;
final ActivityDone? tip;
ExerciseSave( ExerciseSave(
{required this.onQuantityChanged, {required this.onQuantityChanged,
@ -49,7 +143,9 @@ class ExerciseSave extends StatefulWidget {
this.repeats, this.repeats,
this.set, this.set,
this.exerciseNr, this.exerciseNr,
this.originalQuantity}); this.originalQuantity,
required this.menuImage,
this.tip});
@override @override
_ExerciseSaveState createState() => _ExerciseSaveState(); _ExerciseSaveState createState() => _ExerciseSaveState();
} }
@ -72,12 +168,6 @@ class _ExerciseSaveState extends State<ExerciseSave> with Trans {
@override @override
initState() { initState() {
super.initState(); super.initState();
_controller1.text = widget.weight == null
? "0"
: widget.weight! % widget.weight!.round() == 0
? widget.weight!.toStringAsFixed(0)
: widget.weight!.toStringAsFixed(1);
_controller2.text = widget.repeats == null ? "12" : widget.repeats!.toStringAsFixed(0);
_nodeText1.addListener(() { _nodeText1.addListener(() {
if (_nodeText1.hasFocus) { if (_nodeText1.hasFocus) {
_controller1.selection = TextSelection(baseOffset: 0, extentOffset: _controller1.text.length); _controller1.selection = TextSelection(baseOffset: 0, extentOffset: _controller1.text.length);
@ -98,25 +188,31 @@ class _ExerciseSaveState extends State<ExerciseSave> with Trans {
} }
SchedulerBinding.instance!.addPostFrameCallback((_) { SchedulerBinding.instance!.addPostFrameCallback((_) {
/* //final TutorialBloc bloc = BlocProvider.of<TutorialBloc>(context); _controller1.text = widget.weight == null || widget.weight == -1
if (bloc.actualCheck == "directTest") { ? "--"
: widget.weight! % widget.weight!.round() == 0
? widget.weight!.toStringAsFixed(0)
: widget.weight!.toStringAsFixed(1);
_controller2.text = widget.repeats == null
? "--"
: widget.repeats! == 99
? "MAX"
: widget.repeats!.toStringAsFixed(0);
if (widget.unitQuantityUnit != null && widget.tip != null && Cache().isActivityDone(widget.tip!) == false) {
Timer( Timer(
Duration(milliseconds: 2000), Duration(milliseconds: 2000),
() => { () => {
showDialog( TutorialWidget().explanation(
context: context, context,
barrierDismissible: false, ExplanationWidget(
builder: (BuildContext context) { unitQuantityUnit: widget.unitQuantityUnit,
return DialogCommon( unit: widget.unit,
title: t("Attention"), tip: widget.tip,
descriptions: t(widget.exerciseTask), weight: widget.weight,
text: "OK", repeats: widget.repeats,
onTap: () => Navigator.of(context).pop(), )),
onCancel: () => Navigator.of(context).pop(),
);
})
}); });
} */ }
}); });
} }
@ -189,82 +285,139 @@ class _ExerciseSaveState extends State<ExerciseSave> with Trans {
} }
Widget getExerciseWidget() { Widget getExerciseWidget() {
ExplanationExt expl = ExplanationExt(
tip: widget.tip!,
weight: widget.weight,
repeats: widget.repeats,
unitQuantityUnit: widget.unitQuantityUnit,
);
return KeyboardActions( return KeyboardActions(
config: _buildConfig(context), config: _buildConfig(context),
child: Container( child: Container(
child: SingleChildScrollView( child: SingleChildScrollView(
scrollDirection: Axis.vertical, scrollDirection: Axis.vertical,
child: Column(mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ child: Column(mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[
Text( Stack(alignment: Alignment.bottomLeft, children: [
widget.exerciseName, Badge(
style: GoogleFonts.archivoBlack( elevation: 0,
fontWeight: FontWeight.bold, padding: EdgeInsets.all(0),
fontSize: 24, position: BadgePosition.topEnd(top: 5, end: 5),
color: Colors.white, animationDuration: Duration(milliseconds: 1500),
shadows: <Shadow>[ animationType: BadgeAnimationType.fade,
Shadow( badgeColor: Colors.transparent,
offset: Offset(5.0, 5.0), showBadge: true,
blurRadius: 12.0, badgeContent: IconButton(
color: Colors.black54, iconSize: 30,
), onPressed: () => showDialog(
Shadow( context: context,
offset: Offset(-3.0, 3.0), builder: (BuildContext context) {
blurRadius: 12.0, return DialogHTML(title: widget.exerciseName, htmlData: '<p>' + widget.exerciseDescription + '</p>');
color: Colors.black54, }),
), icon: Icon(
], CustomIcon.info_circle,
color: Colors.white,
)),
child: widget.menuImage,
), ),
overflow: TextOverflow.fade, Container(
maxLines: 4, padding: EdgeInsets.only(left: 10, bottom: 10, right: 10),
softWrap: true, child: Text(
textAlign: TextAlign.center, widget.exerciseName,
), style: GoogleFonts.archivoBlack(
SizedBox( fontWeight: FontWeight.bold,
height: 15, fontSize: 24,
), color: Colors.white,
InkWell( shadows: <Shadow>[
child: Text( Shadow(
t("Exercise descripton") + " »", offset: Offset(5.0, 5.0),
style: GoogleFonts.inter(fontSize: 12, color: Colors.blue[200]), blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
),
overflow: TextOverflow.fade,
maxLines: 4,
softWrap: true,
))
]),
ListTile(
leading: IconButton(
iconSize: 30,
onPressed: () => {
if (widget.unitQuantityUnit != null)
{
TutorialWidget().explanation(
context,
ExplanationWidget(
unitQuantityUnit: widget.unitQuantityUnit,
unit: widget.unit,
tip: widget.tip,
weight: widget.weight,
repeats: widget.repeats,
))
}
},
icon: Icon(
CustomIcon.info_circle,
color: Colors.orange[100],
)),
subtitle: Text(
t(expl.getExplanation(Explanations.intro)),
style: GoogleFonts.inter(
fontSize: 14,
color: Colors.white,
fontWeight: FontWeight.bold,
shadows: <Shadow>[
Shadow(
offset: Offset(2.0, 2.0),
blurRadius: 6.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
),
maxLines: 3,
textAlign: TextAlign.left,
overflow: TextOverflow.fade,
softWrap: true,
), ),
onTap: () => {
showDialog(
context: context,
builder: (BuildContext context) {
return DialogHTML(title: widget.exerciseName, htmlData: '<p>' + widget.exerciseDescription + '</p>');
})
},
),
Divider(
color: Colors.transparent,
),
Text(
t(widget.exerciseTask),
style: GoogleFonts.inter(
fontSize: 14,
color: Colors.orange,
fontWeight: FontWeight.bold,
shadows: <Shadow>[
Shadow(
offset: Offset(2.0, 2.0),
blurRadius: 6.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
),
maxLines: 3,
textAlign: TextAlign.center,
overflow: TextOverflow.fade,
softWrap: true,
),
Divider(
color: Colors.transparent,
), ),
expl.getExplanation(Explanations.introBold).length > 0
? Text(
t(expl.getExplanation(Explanations.introBold)),
style: GoogleFonts.inter(
fontSize: 14,
color: Colors.orange,
fontWeight: FontWeight.bold,
shadows: <Shadow>[
Shadow(
offset: Offset(2.0, 2.0),
blurRadius: 6.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
),
maxLines: 3,
textAlign: TextAlign.center,
overflow: TextOverflow.fade,
softWrap: true,
)
: Offstage(),
widget.unit == "second" widget.unit == "second"
? Text( ? Text(
getTimeGoal(widget.originalQuantity), getTimeGoal(widget.originalQuantity),
@ -289,29 +442,60 @@ class _ExerciseSaveState extends State<ExerciseSave> with Trans {
) )
: Offstage(), : Offstage(),
columnQuantityUnit(), columnQuantityUnit(),
Divider(
color: Colors.transparent,
),
columnQuantity(), columnQuantity(),
Divider( Divider(
color: Colors.transparent, color: Colors.transparent,
), ),
widget.hasUnitQuantity Text(
? Text( t(expl.getExplanation(Explanations.explanationButton)),
widget.set == null || widget.exerciseNr == null style: GoogleFonts.inter(
? t("Step") + ": " + "1/4" fontSize: 14,
: t("Step") + ": " + "${widget.exerciseNr}/${widget.set}", color: Colors.white,
style: GoogleFonts.inter( fontWeight: FontWeight.bold,
fontSize: 22, shadows: <Shadow>[
color: Colors.white, Shadow(
fontWeight: FontWeight.bold, offset: Offset(2.0, 2.0),
), blurRadius: 6.0,
maxLines: 3, color: Colors.black54,
textAlign: TextAlign.center, ),
overflow: TextOverflow.fade, Shadow(
softWrap: true, offset: Offset(-3.0, 3.0),
) blurRadius: 12.0,
: Offstage(), color: Colors.black54,
),
],
),
maxLines: 3,
textAlign: TextAlign.center,
overflow: TextOverflow.fade,
softWrap: true,
),
Padding(
padding: const EdgeInsets.only(left: 35, right: 35),
child: Text(
t(expl.getExplanation(Explanations.explanationButtonExt)),
style: GoogleFonts.inter(
fontSize: 14,
color: Colors.orange,
fontWeight: FontWeight.bold,
shadows: <Shadow>[
Shadow(
offset: Offset(2.0, 2.0),
blurRadius: 6.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
),
maxLines: 3,
textAlign: TextAlign.center,
overflow: TextOverflow.fade,
softWrap: true,
)),
Divider( Divider(
color: Colors.transparent, color: Colors.transparent,
), ),
@ -476,3 +660,168 @@ class _ExerciseSaveState extends State<ExerciseSave> with Trans {
return row; return row;
} }
} }
class ExplanationWidget extends StatefulWidget {
final String? unitQuantityUnit;
final String unit;
final ActivityDone? tip;
final double? weight;
final int? repeats;
const ExplanationWidget({
Key? key,
this.unitQuantityUnit,
required this.unit,
this.tip,
this.weight,
this.repeats,
}) : super(key: key);
@override
_ExplanationWidgetState createState() => _ExplanationWidgetState();
}
class _ExplanationWidgetState extends State<ExplanationWidget> with Trans {
bool _selected = false;
@override
Widget build(BuildContext context) {
ExplanationExt expl = ExplanationExt(
tip: widget.tip!,
weight: widget.weight,
repeats: widget.repeats,
unitQuantityUnit: widget.unitQuantityUnit,
);
setContext(context);
return Material(
color: Colors.transparent,
child: Column(
children: [
Padding(
padding: const EdgeInsets.only(top: 10, left: 10, right: 10),
child: Text(t(expl.getExplanation(Explanations.intro)),
maxLines: 5,
textAlign: TextAlign.center,
style: GoogleFonts.inter(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 16,
))),
Padding(
padding: const EdgeInsets.only(top: 10, left: 10, right: 10),
child: Text(t(expl.getExplanation(Explanations.introBold)),
maxLines: 5,
textAlign: TextAlign.center,
style: GoogleFonts.inter(
color: Colors.orange,
fontWeight: FontWeight.bold,
fontSize: 16,
))),
Stack(children: [
Padding(
padding: const EdgeInsets.only(top: 13, left: 18, right: 18),
child: Column(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [
TextFormField(
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),
),
),
initialValue: ".",
keyboardType: TextInputType.numberWithOptions(decimal: true),
textInputAction: TextInputAction.done,
style: GoogleFonts.archivoBlack(fontSize: 80, color: Colors.transparent),
onChanged: (value) {}),
])),
Container(
padding: EdgeInsets.only(top: 35, left: 35, right: 35),
child: Text(
t(expl.getExplanation(Explanations.explanationWeight)),
style: GoogleFonts.archivoBlack(fontSize: 23, color: Colors.yellow[300]),
)),
]),
Stack(children: [
Padding(
padding: const EdgeInsets.only(top: 10, left: 15, right: 15),
child: Column(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [
TextFormField(
decoration: InputDecoration(
contentPadding: EdgeInsets.only(left: 25, top: 5, bottom: 5),
labelText: t(widget.unit),
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),
),
),
initialValue: ".",
keyboardType: TextInputType.numberWithOptions(decimal: true),
textInputAction: TextInputAction.done,
style: GoogleFonts.archivoBlack(fontSize: 80, color: Colors.transparent),
onChanged: (value) {}),
])),
Container(
padding: EdgeInsets.only(top: 25, left: 35, right: 35),
child: Text(
t(expl.getExplanation(Explanations.explanationRepeats)),
style: GoogleFonts.archivoBlack(fontSize: 23, color: Colors.yellow[300]),
)),
]),
Padding(
padding: const EdgeInsets.only(top: 10, left: 5, right: 5),
child: Text(
t("Don't forget, the app can give you only the right values, if you execute the task regurarly and after the exact instructions."),
maxLines: 5,
textAlign: TextAlign.center,
style: GoogleFonts.inter(
color: Colors.white,
fontSize: 14,
))),
Divider(),
GestureDetector(
onTap: () => {
TutorialWidget().close(),
if (_selected && widget.tip != null)
{
Cache().setActivityDonePrefs(widget.tip!),
}
},
child: Stack(
alignment: Alignment.center,
children: [
Image.asset('asset/icon/gomb_orange_c.png', width: 100, height: 45),
Text(
t("Got It"),
style: TextStyle(fontSize: 20, color: Colors.white),
),
],
)),
Theme(
data: ThemeData(unselectedWidgetColor: Colors.white38),
child: CheckboxListTile(
value: _selected,
onChanged: (bool? checked) {
setState(() {
_selected = checked!;
});
},
checkColor: Colors.white,
activeColor: Colors.orange[600],
controlAffinity: ListTileControlAffinity.leading,
title: Text(
t("Show this tip no more"),
style: GoogleFonts.inter(color: Colors.grey),
)))
],
));
}
}

View File

@ -83,16 +83,16 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
context: context, context: context,
builder: (BuildContext context) { builder: (BuildContext context) {
return DialogTrialWidget( return DialogTrialWidget(
title: "10 days Premium for free", title: t("10 days Premium for free"),
description: "Would you like to try all premium functions for 10 days, without any subscription or bank card data?", description: t("Would you like to try all premium functions for 10 days, without any subscription or bank card data?"),
widget: Column(children: [ widget: Column(children: [
Text( Text(
"If you click to 'Yes', all premium functions will be available right now.", t("If you click to 'Yes', all premium functions will be available right now."),
style: GoogleFonts.inter(color: Colors.white), style: GoogleFonts.inter(color: Colors.white),
), ),
Divider(), Divider(),
Text( Text(
"If you click to 'No', you can use all basic functions, and you will loose the oppurtunity to try the premium functions for free.", t("If you click to 'No', you can use all basic functions, and you will loose the oppurtunity to try the premium functions for free."),
style: GoogleFonts.inter(color: Colors.white), style: GoogleFonts.inter(color: Colors.white),
), ),
]), ]),

View File

@ -25,6 +25,46 @@ class TutorialWidget with Trans, Logging {
} }
} }
Widget explanationFrame(Widget widget) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(24),
boxShadow: [BoxShadow(color: Colors.black, offset: Offset(0, 10), blurRadius: 10)],
image: DecorationImage(
image: AssetImage('asset/image/WT_plainblack_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
child: widget,
);
}
void explanation(BuildContext context, Widget widget) {
tooltip = SuperTooltip(
top: 120,
left: 20,
right: 20,
backgroundColor: Colors.black87,
popupDirection: TooltipDirection.up,
maxWidth: 330,
borderColor: Colors.transparent,
borderWidth: 1.0,
minimumOutSidePadding: 20,
//snapsFarAwayVertically: false,
showCloseButton: ShowCloseButton.outside,
closeButtonColor: Colors.grey,
dismissOnTapOutside: true,
outsideBackgroundColor: Colors.black.withOpacity(0.6),
hasShadow: true,
touchThrougArea: null,
//onClose: () => bloc.add(TutorialFinished()),
custom: true,
content: explanationFrame(widget));
tooltip!.showBox(context);
}
void tip(BuildContext context) { void tip(BuildContext context) {
final TutorialBloc bloc = BlocProvider.of<TutorialBloc>(context); final TutorialBloc bloc = BlocProvider.of<TutorialBloc>(context);
if (bloc.action == null) { if (bloc.action == null) {

View File

@ -707,6 +707,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.1" version: "1.0.1"
mailto:
dependency: "direct main"
description:
name: mailto
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
matcher: matcher:
dependency: transitive dependency: transitive
description: description:
@ -1294,12 +1301,12 @@ packages:
source: hosted source: hosted
version: "3.5.1" version: "3.5.1"
url_launcher: url_launcher:
dependency: transitive dependency: "direct main"
description: description:
name: url_launcher name: url_launcher
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "6.0.3" version: "6.0.9"
url_launcher_linux: url_launcher_linux:
dependency: transitive dependency: transitive
description: description:
@ -1320,7 +1327,7 @@ packages:
name: url_launcher_platform_interface name: url_launcher_platform_interface
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.2" version: "2.0.4"
url_launcher_web: url_launcher_web:
dependency: transitive dependency: transitive
description: description:

View File

@ -58,7 +58,9 @@ dependencies:
upgrader: ^3.5.1 upgrader: ^3.5.1
web_browser: ^0.5.0 web_browser: ^0.5.0
flutter_fadein: ^2.0.0 flutter_fadein: ^2.0.0
mailto: ^2.0.0
url_launcher: ^6.0.9
firebase_core: ^1.5.0 firebase_core: ^1.5.0
firebase_analytics: ^8.1.0 firebase_analytics: ^8.1.0
firebase_messaging: ^10.0.0 firebase_messaging: ^10.0.0
@ -280,6 +282,7 @@ flutter:
- asset/menu/close_grip_front_lat_pulldown.jpg - asset/menu/close_grip_front_lat_pulldown.jpg
- asset/menu/close_grip_pull_ups.jpg - asset/menu/close_grip_pull_ups.jpg
- asset/menu/close_reverse_grip_lat_pulldown.jpg - asset/menu/close_reverse_grip_lat_pulldown.jpg
- asset/menu/close_reverse_grip_pull_ups.jpg
- asset/menu/concentration.jpg - asset/menu/concentration.jpg
- asset/menu/cooper.jpg - asset/menu/cooper.jpg
- asset/menu/crisscross.jpg - asset/menu/crisscross.jpg
@ -294,6 +297,7 @@ flutter:
- asset/menu/donkey_calf_raises.jpg - asset/menu/donkey_calf_raises.jpg
- asset/menu/dumbbell_alternate_bicep_curl.jpg - asset/menu/dumbbell_alternate_bicep_curl.jpg
- asset/menu/dumbell_bench_presses.jpg - asset/menu/dumbell_bench_presses.jpg
- asset/menu/dumbbell_presses.jpg
- asset/menu/ez_bar_burl.jpg - asset/menu/ez_bar_burl.jpg
- asset/menu/flyes.jpg - asset/menu/flyes.jpg
- asset/menu/forward_raise.jpg - asset/menu/forward_raise.jpg
@ -358,6 +362,7 @@ flutter:
- asset/menu/seated_dumbbell_curl.jpg - asset/menu/seated_dumbbell_curl.jpg
- asset/menu/seated_dumbbell_shoulder_press.jpg - asset/menu/seated_dumbbell_shoulder_press.jpg
- asset/menu/seated_lateral_raises.jpg - asset/menu/seated_lateral_raises.jpg
- asset/menu/seated_leg_curls.jpg
- asset/menu/seated_triceps_extension.jpg - asset/menu/seated_triceps_extension.jpg
- asset/menu/shrugs.jpg - asset/menu/shrugs.jpg
- asset/menu/side_plank.jpg - asset/menu/side_plank.jpg
@ -372,6 +377,7 @@ flutter:
- asset/menu/sizes.jpg - asset/menu/sizes.jpg
- asset/menu/smith_machine_chest_press.jpg - asset/menu/smith_machine_chest_press.jpg
- asset/menu/smith_machine_squats.jpg - asset/menu/smith_machine_squats.jpg
- asset/menu/smith_machine_front_press.jpg
- asset/menu/squats_with_kettlebell.jpg - asset/menu/squats_with_kettlebell.jpg
- asset/menu/squat_jump_weight.jpg - asset/menu/squat_jump_weight.jpg
- asset/menu/squat_jump.jpg - asset/menu/squat_jump.jpg
@ -388,6 +394,7 @@ flutter:
- asset/menu/standing_single_arm_lateral_raises.jpg - asset/menu/standing_single_arm_lateral_raises.jpg
- asset/menu/standing_triceps_extension.jpg - asset/menu/standing_triceps_extension.jpg
- asset/menu/stiff_legged_deadlift.jpg - asset/menu/stiff_legged_deadlift.jpg
- asset/menu/straight_arm_pulldown.jpg
- asset/menu/straight-arm_rope_pull-down.jpg - asset/menu/straight-arm_rope_pull-down.jpg
- asset/menu/stretching.jpg - asset/menu/stretching.jpg
- asset/menu/t_bar_rows.jpg - asset/menu/t_bar_rows.jpg