Merge ssh://git.aitrainer.app:6622/bossanyit/aitrainer_app

This commit is contained in:
Tibor Bossanyi 2020-09-16 16:14:44 +02:00
commit 4ee16c9fa6
55 changed files with 2837 additions and 1220 deletions

BIN
asset/image/lock.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

View File

@ -52,6 +52,7 @@
"Sizes": "Sizes",
"Save Exercise": "Save Exercise of:",
"Save": "Save",
"Delete": "Delete",
"Name": "Name",
"Exercise": "Exercise",
@ -117,5 +118,21 @@
"3rd Control Exercise:": "3rd Control Exercise:",
"My Development":"My Development",
"My Training Plan":"My Training Plan"
"My Training Plan":"My Training Plan",
"Please add an exercise plan": "Please add an exercise plan",
"Serie": "Serie",
"Repeats": "Repeats",
"Save The Exercise To The Exercise Plan": "Save The Exercise To The Exercise Plan",
"The number of the serie done with":"The number of the serie done with",
"The number of the repeats of one serie":"The number of the repeats of one serie",
"1. Chest": "1. Chest",
"2. Biceps": "2. Biceps",
"3. Triceps": "3. Triceps",
"4. Back": "4. Back",
"5. Shoulders": "5. Shoulders",
"6. Core": "6. Core",
"7. Thigh": "7. Thigh",
"8. Calf": "8. Calf"
}

View File

@ -52,6 +52,7 @@
"Sizes": "Méretek",
"Save Exercise": "Gyakorlat mentése:",
"Save": "Mentés",
"Delete": "Törlés",
"The number of the exercise": "Írd be a gyakorlat számát",
"The number of the exercise done with": "Írd be, mennyivel csináltad a gyakorlatot",
@ -116,5 +117,22 @@
"3rd Control Exercise:": "3. kontrollgyakorlat:",
"My Development":"Fejlődésem",
"My Training Plan":"Edzéstervem"
"My Training Plan":"Edzéstervem",
"Please add an exercise plan": "Kérlek add meg az edzéstervet a gyakorlathoz",
"Serie": "Széria",
"Repeats": "Ismétlés",
"Save The Exercise To The Exercise Plan": "Gyakorlat mentése az edzéstervhez",
"The number of the serie done with":"Mennyi szériát csinálsz",
"The number of the repeats of one serie":"Hány ismétlést csinálsz egy gyakorlaton belül",
"1. Chest": "1. Mell",
"2. Biceps": "2. Bicepsz",
"3. Triceps": "3. Tricepsz",
"4. Back": "4. Hát",
"5. Shoulders": "5. Váll",
"6. Core": "6. Has",
"7. Thigh": "7. Comb",
"8. Calf": "8. Vádli"
}

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097.2" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
@ -16,10 +16,10 @@
<viewControllerLayoutGuide type="bottom" id="wCe-IQ-FAo"/>
</layoutGuides>
<view key="view" autoresizesSubviews="NO" contentMode="scaleAspectFit" translatesAutoresizingMaskIntoConstraints="NO" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="414" height="878"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="825"/>
<subviews>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleAspectFit" ambiguous="YES" image="LaunchImage" adjustsImageSizeForAccessibilityContentSizeCategory="YES" id="YRO-k0-Ey4">
<rect key="frame" x="-1" y="0.0" width="414" height="878"/>
<rect key="frame" x="-26" y="-92" width="505" height="1009"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
<preferredSymbolConfiguration key="preferredSymbolConfiguration" scale="default"/>
</imageView>

View File

@ -3,6 +3,7 @@ import 'dart:async';
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/exercise_repository.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:meta/meta.dart';
@ -13,6 +14,7 @@ part 'account_state.dart';
class AccountBloc extends Bloc<AccountEvent, AccountState> {
final CustomerRepository customerRepository;
bool loggedIn = false;
int traineeId = 0;
AccountBloc({this.customerRepository}) : super(AccountInitial()) {
if ( Cache().userLoggedIn != null ) {
customerRepository.customer = Cache().userLoggedIn;
@ -36,8 +38,21 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
} else if (event is AccountLogout) {
await Cache().logout();
customerRepository.customer = null;
customerRepository.emptyTrainees();
loggedIn = false;
yield AccountLoggedOut();
} else if ( event is AccountGetTrainees) {
yield AccountLoading();
await customerRepository.getTrainees();
yield AccountReady();
} else if ( event is AccountSelectTrainee ) {
yield AccountLoading();
customerRepository.setTrainee(event.traineeId);
Cache().setTrainee(customerRepository.getTraineeById(event.traineeId));
ExerciseRepository exerciseRepository = ExerciseRepository();
await exerciseRepository.getExercisesByCustomer(event.traineeId);
this.traineeId = event.traineeId;
yield AccountReady();
}
} on Exception catch(e) {
yield AccountError(message: e.toString());

View File

@ -44,3 +44,15 @@ class AccountLogInFinished extends AccountEvent {
@override
List<Object> get props => [customer];
}
class AccountGetTrainees extends AccountEvent {
const AccountGetTrainees();
}
class AccountSelectTrainee extends AccountEvent {
final int traineeId;
const AccountSelectTrainee({this.traineeId});
@override
List<Object> get props => [traineeId];
}

View File

@ -0,0 +1,81 @@
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/customer.dart';
import 'package:aitrainer_app/model/workout_tree.dart';
import 'package:aitrainer_app/repository/exercise_plan_repository.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:flutter_form_bloc/flutter_form_bloc.dart';
class ExerciseAddByPlanFormBloc extends FormBloc<String, String> {
final ExerciseRepository exerciseRepository;
final ExercisePlanRepository exercisePlanRepository;
final WorkoutTree workoutTree;
final customerId;
Customer customer;
int step = 1;
int countSteps = 1;
final quantity1Field = TextFieldBloc(
);
final unitQuantity1Field = TextFieldBloc(
);
ExerciseAddByPlanFormBloc({this.exerciseRepository, this.exercisePlanRepository, this.customerId, this.workoutTree}) {
addFieldBlocs(fieldBlocs: [
quantity1Field,
unitQuantity1Field,
]);
quantity1Field.onValueChanges(onData: (previous, current) async* {
exerciseRepository.setQuantity(current.valueToDouble);
});
unitQuantity1Field.onValueChanges(onData: (previous, current) async* {
exerciseRepository.setUnitQuantity(unitQuantity1Field.valueToDouble);
});
exerciseRepository.exerciseType = workoutTree.exerciseType;
if ( Cache().userLoggedIn.customerId == customerId) {
customer = Cache().userLoggedIn;
} else if ( Cache().getTrainee().customerId == customerId) {
customer = Cache().getTrainee();
}
exercisePlanRepository.setActualPlanDetail(workoutTree.exerciseType);
exerciseRepository.customer = customer;
countSteps = exercisePlanRepository.actualPlanDetail.serie;
unitQuantity1Field.updateInitialValue(exercisePlanRepository.actualPlanDetail.weightEquation);
quantity1Field.updateInitialValue(exercisePlanRepository.actualPlanDetail.repeats.toString());
}
@override
void onSubmitting() async {
try {
emitLoading(progress: 30);
step++;
exerciseRepository.setUnitQuantity(unitQuantity1Field.valueToDouble);
exerciseRepository.setQuantity(quantity1Field.valueToDouble);
exerciseRepository.exercise.exercisePlanDetailId =
exercisePlanRepository.actualPlanDetail.exercisePlanDetailId;
exerciseRepository.exercise.unit = workoutTree.exerciseType.unit;
workoutTree.executed = true;
print("On Submitting Add Exercise By Plan " + exerciseRepository.exercise.toJson().toString());
await exerciseRepository.addExercise();
emitSuccess(canSubmitAgain: true);
} on Exception catch (ex) {
emitFailure(failureResponse: ex.toString());
}
}
//@override
Future<void> close() {
quantity1Field.close();
unitQuantity1Field.close();
return super.close();
}
}

View File

@ -0,0 +1,58 @@
import 'dart:async';
import 'package:aitrainer_app/model/exercise_type.dart';
import 'package:aitrainer_app/model/workout_tree.dart';
import 'package:aitrainer_app/repository/exercise_plan_repository.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/repository/menu_tree_repository.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:meta/meta.dart';
part 'exercise_by_plan_event.dart';
part 'exercise_by_plan_state.dart';
class ExerciseByPlanBloc extends Bloc<ExerciseByPlanEvent, ExerciseByPlanState> {
final ExerciseRepository exerciseRepository;
final MenuTreeRepository menuTreeRepository;
final ExercisePlanRepository exercisePlanRepository = ExercisePlanRepository();
int customerId;
@override
ExerciseByPlanBloc({this.exerciseRepository, this.menuTreeRepository}) : super(ExerciseByPlanStateInitial());
Future<void> getData() async {
exercisePlanRepository.setCustomerId(customerId);
await exercisePlanRepository.getLastExercisePlan();
await exercisePlanRepository.getExercisePlanDetails();
menuTreeRepository.sortedTree = null;
menuTreeRepository.sortByMuscleType();
menuTreeRepository.sortedTree.forEach((key, value) {
List<WorkoutTree> listWorkoutTree = value;
listWorkoutTree.forEach((workoutTree) {
workoutTree.selected = false;
if (exercisePlanRepository.exercisePlanDetails.length > 0) {
if (exercisePlanRepository.exercisePlanDetails[workoutTree.exerciseTypeId] != null) {
workoutTree.selected = true;
}
}
});
});
}
@override
Stream<ExerciseByPlanState> mapEventToState(ExerciseByPlanEvent event) async* {
try {
if (event is ExerciseByPlanLoad) {
yield ExerciseByPlanLoading();
await this.getData();
yield ExerciseByPlanReady();
} else if (event is AddExerciseByPlanEvent) {
yield ExerciseByPlanLoading();
yield ExerciseByPlanReady();
}
} on Exception catch (e) {
yield ExerciseByPlanError(message: e.toString());
}
}
}

View File

@ -0,0 +1,21 @@
part of 'exercise_by_plan_bloc.dart';
@immutable
abstract class ExerciseByPlanEvent extends Equatable {
const ExerciseByPlanEvent();
@override
List<Object> get props => [];
}
class AddExerciseByPlanEvent extends ExerciseByPlanEvent {
final ExerciseType exerciseType;
const AddExerciseByPlanEvent({this.exerciseType});
@override
List<Object> get props => [exerciseType];
}
class ExerciseByPlanLoad extends ExerciseByPlanEvent {
const ExerciseByPlanLoad();
}

View File

@ -0,0 +1,31 @@
part of 'exercise_by_plan_bloc.dart';
@immutable
abstract class ExerciseByPlanState extends Equatable {
const ExerciseByPlanState();
@override
List<Object> get props => [];
}
class ExerciseByPlanStateInitial extends ExerciseByPlanState {
const ExerciseByPlanStateInitial();
}
class ExerciseByPlanLoading extends ExerciseByPlanState {
const ExerciseByPlanLoading();
}
// updated screen
class ExerciseByPlanReady extends ExerciseByPlanState {
const ExerciseByPlanReady();
}
// error splash screen
class ExerciseByPlanError extends ExerciseByPlanState {
final String message;
const ExerciseByPlanError({this.message});
@override
List<Object> get props => [message];
}

View File

@ -0,0 +1,89 @@
import 'dart:async';
import 'package:aitrainer_app/model/exercise_plan_detail.dart';
import 'package:aitrainer_app/model/exercise_type.dart';
import 'package:aitrainer_app/model/workout_tree.dart';
import 'package:aitrainer_app/repository/exercise_plan_repository.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/repository/menu_tree_repository.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:meta/meta.dart';
part 'exercise_plan_event.dart';
part 'exercise_plan_state.dart';
class ExercisePlanBloc extends Bloc<ExercisePlanEvent, ExercisePlanState> {
final MenuTreeRepository menuTreeRepository;
final ExerciseRepository exerciseRepository;
final ExercisePlanRepository exercisePlanRepository = ExercisePlanRepository();
int customerId;
ExercisePlanBloc({this.exerciseRepository, this.menuTreeRepository}) : super(ExercisePlanInitial());
Future<void> getData() async {
exercisePlanRepository.setCustomerId(customerId);
await exercisePlanRepository.getLastExercisePlan();
await exercisePlanRepository.getExercisePlanDetails();
menuTreeRepository.sortedTree = null;
menuTreeRepository.sortByMuscleType();
menuTreeRepository.sortedTree.forEach((key, value) {
List<WorkoutTree> listWorkoutTree = value;
listWorkoutTree.forEach((workoutTree) {
workoutTree.selected = false;
if (exercisePlanRepository.exercisePlanDetails.length > 0) {
if (exercisePlanRepository.exercisePlanDetails[workoutTree.exerciseTypeId] != null) {
//print("bingo");
workoutTree.selected = true;
}
}
});
});
}
@override
Stream<ExercisePlanState> mapEventToState(ExercisePlanEvent event) async* {
try {
if (event is ExercisePlanLoad) {
yield ExercisePlanLoading();
await this.getData();
yield ExercisePlanReady();
}
if (event is ExercisePlanUpdate) {
yield ExercisePlanLoading();
WorkoutTree workoutTree = event.workoutTree;
if (workoutTree != null) {
exercisePlanRepository.addExerciseTypeToPlan(workoutTree.exerciseType);
workoutTree.selected = true;
}
yield ExercisePlanReady();
} else if (event is ExercisePlanRemoveExercise) {
yield ExercisePlanLoading();
ExercisePlanDetail planDetail = event.exercisePlanDetail;
exercisePlanRepository.removeExerciseTypeFromPlan(planDetail.exerciseType);
this.menuTreeRepository.sortedTree.forEach((key, value) {
List<WorkoutTree> listTreeItem = value;
listTreeItem.forEach((element) {
if ( element.exerciseType.exerciseTypeId == planDetail.exerciseTypeId) {
element.selected = false;
}
});
});
yield ExercisePlanReady();
} else if (event is ExercisePlanUpdateExercise) {
yield ExercisePlanReady();
} else if (event is ExercisePlanSave) {
if (exercisePlanRepository.getExercisePlanDetailSize() == 0) {
throw Exception("Please select an exercise");
} else {
yield ExercisePlanLoading();
exercisePlanRepository.saveExercisePlan();
yield ExercisePlanReady();
}
}
} on Exception catch (e) {
yield ExercisePlanError(message: e.toString());
}
}
}

View File

@ -0,0 +1,49 @@
part of 'exercise_plan_bloc.dart';
@immutable
abstract class ExercisePlanEvent extends Equatable {
const ExercisePlanEvent();
@override
List<Object> get props => [];
}
class ExercisePlanLoad extends ExercisePlanEvent {
const ExercisePlanLoad();
}
class ExercisePlanUpdate extends ExercisePlanEvent {
final WorkoutTree workoutTree;
const ExercisePlanUpdate({this.workoutTree});
@override
List<Object> get props => [workoutTree];
}
class ExercisePlanAddExercise extends ExercisePlanEvent {
final ExerciseType exerciseType;
const ExercisePlanAddExercise({this.exerciseType});
@override
List<Object> get props => [exerciseType];
}
class ExercisePlanRemoveExercise extends ExercisePlanEvent {
final ExercisePlanDetail exercisePlanDetail;
const ExercisePlanRemoveExercise({this.exercisePlanDetail});
@override
List<Object> get props => [exercisePlanDetail];
}
class ExercisePlanUpdateExercise extends ExercisePlanEvent {
final ExercisePlanDetail exercisePlanDetail;
const ExercisePlanUpdateExercise({this.exercisePlanDetail});
@override
List<Object> get props => [exercisePlanDetail];
}
class ExercisePlanSave extends ExercisePlanEvent {
const ExercisePlanSave();
}

View File

@ -0,0 +1,37 @@
part of 'exercise_plan_bloc.dart';
@immutable
abstract class ExercisePlanState extends Equatable{
const ExercisePlanState();
@override
List<Object> get props => [];
}
// Display the last saved exercise plan
class ExercisePlanInitial extends ExercisePlanState {
const ExercisePlanInitial();
}
// Loading screen
class ExercisePlanLoading extends ExercisePlanState {
const ExercisePlanLoading();
}
// updated screen
class ExercisePlanReady extends ExercisePlanState {
const ExercisePlanReady();
}
// error splash screen
class ExercisePlanError extends ExercisePlanState {
final String message;
const ExercisePlanError({this.message});
@override
List<Object> get props => [message];
}

View File

@ -0,0 +1,94 @@
import 'package:aitrainer_app/bloc/exercise_plan/exercise_plan_bloc.dart';
import 'package:aitrainer_app/repository/exercise_plan_repository.dart';
import 'package:flutter_form_bloc/flutter_form_bloc.dart';
class ExercisePlanCustomerFormBloc extends FormBloc<String, String> {
final ExercisePlanRepository exercisePlanRepository;
final ExercisePlanBloc planBloc;
final serieField = TextFieldBloc(
validators: [
FieldBlocValidators.required,
],
);
final quantityField = TextFieldBloc(
validators: [
FieldBlocValidators.required,
],
);
final weightField = TextFieldBloc(
validators: [
FieldBlocValidators.required,
],
);
final exerciseTypeField = TextFieldBloc(
validators: [
FieldBlocValidators.required,
],
);
ExercisePlanCustomerFormBloc({this.exercisePlanRepository, this.planBloc}) {
addFieldBlocs(fieldBlocs: [
quantityField,
serieField,
weightField
]);
String repeatsInitial = exercisePlanRepository.actualPlanDetail != null &&
exercisePlanRepository.actualPlanDetail.repeats != null ?
exercisePlanRepository.actualPlanDetail.repeats.toString() : "12";
quantityField.updateInitialValue(repeatsInitial);
String serieInitial = exercisePlanRepository.actualPlanDetail != null &&
exercisePlanRepository.actualPlanDetail.serie != null ?
exercisePlanRepository.actualPlanDetail.serie.toString() : "3";
serieField.updateInitialValue(serieInitial);
String weightInitial = exercisePlanRepository.actualPlanDetail != null &&
exercisePlanRepository.actualPlanDetail.weightEquation != null ?
exercisePlanRepository.actualPlanDetail.weightEquation : "30";
weightField.updateInitialValue(weightInitial);
quantityField.onValueChanges(onData: (previous, current) async* {
exercisePlanRepository.actualPlanDetail.repeats = current.valueToInt;
});
serieField.onValueChanges(onData: (previous, current) async* {
exercisePlanRepository.actualPlanDetail.serie = current.valueToInt;
});
weightField.onValueChanges(onData: (previous, current) async* {
exercisePlanRepository.actualPlanDetail.weightEquation = current.value;
});
}
@override
void onSubmitting() async {
print("On Submitting Custom Plan form");
try {
emitLoading(progress: 30);
// Emit either Loaded or Error
exercisePlanRepository.actualPlanDetail.repeats = quantityField.valueToInt;
exercisePlanRepository.actualPlanDetail.serie = serieField.valueToInt;
exercisePlanRepository.actualPlanDetail.weightEquation = weightField.value;
exercisePlanRepository.addToPlan();
planBloc.add(ExercisePlanUpdate());
emitSuccess(canSubmitAgain: false);
} on Exception catch (ex) {
emitFailure(failureResponse: ex.toString());
}
}
//@override
Future<void> close() {
quantityField.close();
serieField.close();
weightField.close();
exerciseTypeField.close();
return super.close();
}
}

View File

@ -34,6 +34,10 @@ class SettingsBloc extends Bloc<SettingsEvent, SettingsState> {
yield SettingsLoading();
await _changeLang( event.language);
yield SettingsReady(_locale);
} else if ( event is SettingsGetLanguage) {
await AppLanguage().fetchLocale();
_locale = AppLanguage().appLocal;
yield SettingsReady(_locale);
}
}
@ -50,12 +54,13 @@ class SettingsBloc extends Bloc<SettingsEvent, SettingsState> {
break;
}
this.language = lang;
final AppLanguage appLanguage = AppLanguage();
appLanguage.changeLanguage(_locale);
await loadLang();
}
Future<void> loadLang() async{
final AppLanguage appLanguage = AppLanguage();
appLanguage.changeLanguage(_locale);
print (" -- Loading lang $_locale");
if ( context != null ) {
AppLocalizations.of(context).setLocale(_locale);
await AppLocalizations.of(context).load();

View File

@ -11,3 +11,7 @@ class SettingsChangeLanguage extends SettingsEvent {
final String language;
const SettingsChangeLanguage({this.language});
}
class SettingsGetLanguage extends SettingsEvent {
const SettingsGetLanguage();
}

View File

@ -20,19 +20,24 @@ class AppLanguage{
Future<void> fetchLocale() async {
var prefs = await SharedPreferences.getInstance();
if (prefs.getString('language_code') == null) {
String langCode = prefs.getString('language_code');
print(" ---- lang code $langCode");
if ( langCode == null) {
_appLocale = Locale('en');
} else {
_appLocale = Locale(prefs.getString('language_code'));
_appLocale = Locale(langCode);
}
print(" ---- Fetched lang: " + _appLocale.toString());
}
getLocale(SharedPreferences prefs) {
if (prefs.getString('language_code') == null) {
String langCode = prefs.getString('language_code');
if ( langCode == null) {
_appLocale = Locale('en');
}
_appLocale = Locale(prefs.getString('language_code'));
_appLocale = Locale(langCode);
print(" ---- Get lang: " + _appLocale.toString() + " lang code $langCode");
}

View File

@ -28,6 +28,7 @@ class AppLocalizations {
Future<bool> load() async {
// Load the language JSON file from the "lang" folder
print(" -- load language pieces " + locale.languageCode);
String jsonString =
await rootBundle.loadString('i18n/${locale.languageCode}.json');
Map<String, dynamic> jsonMap = json.decode(jsonString);

View File

@ -1,5 +1,6 @@
import 'dart:async';
import 'package:aitrainer_app/repository/customer_repository.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/repository/menu_tree_repository.dart';
import 'package:aitrainer_app/util/session.dart';
import 'package:aitrainer_app/view/account.dart';
@ -9,13 +10,19 @@ import 'package:aitrainer_app/view/customer_fitness_page.dart';
import 'package:aitrainer_app/view/customer_goal_page.dart';
import 'package:aitrainer_app/view/customer_modify_page.dart';
import 'package:aitrainer_app/view/customer_welcome_page.dart';
import 'package:aitrainer_app/view/exercise_add_by_plan_page.dart';
import 'package:aitrainer_app/view/exercise_control_page.dart';
import 'package:aitrainer_app/view/exercise_execute_by_plan_page.dart';
import 'package:aitrainer_app/view/exercise_log_page.dart';
import 'package:aitrainer_app/view/exercise_plan_custom_page.dart';
import 'package:aitrainer_app/view/exercise_plan_detail_add_page.dart';
import 'package:aitrainer_app/view/exercise_type_description.dart';
import 'package:aitrainer_app/view/gdpr.dart';
import 'package:aitrainer_app/view/login.dart';
import 'package:aitrainer_app/view/exercise_new_page.dart';
import 'package:aitrainer_app/view/menu_page.dart';
import 'package:aitrainer_app/view/mydevelopment_page.dart';
import 'package:aitrainer_app/view/myexcercise_plan_page.dart';
import 'package:aitrainer_app/view/registration.dart';
import 'package:aitrainer_app/view/settings.dart';
import 'package:aitrainer_app/widgets/home.dart';
@ -27,6 +34,8 @@ import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:sentry/sentry.dart';
import 'bloc/account/account_bloc.dart';
import 'bloc/exercise_by_plan/exercise_by_plan_bloc.dart';
import 'bloc/exercise_plan/exercise_plan_bloc.dart';
import 'bloc/menu/menu_bloc.dart';
import 'bloc/session/session_bloc.dart';
import 'bloc/settings/settings_bloc.dart';
@ -96,14 +105,15 @@ Future<Null> main() async {
// - https://api.dartlang.org/stable/1.24.2/dart-async/Zone-class.html
// - https://www.dartlang.org/articles/libraries/zones
runZonedGuarded<Future<Null>>(() async {
final MenuTreeRepository menuTreeRepository = MenuTreeRepository();
runApp(
MultiBlocProvider(
providers: [
providers: [
BlocProvider<SessionBloc>(
create: (BuildContext context) => SessionBloc(session: Session()),
),
BlocProvider<MenuBloc>(
create: (BuildContext context) => MenuBloc( menuTreeRepository: MenuTreeRepository()),
create: (BuildContext context) => MenuBloc( menuTreeRepository: menuTreeRepository),
),
BlocProvider<SettingsBloc>(
create: (BuildContext context) => SettingsBloc(),
@ -111,6 +121,12 @@ Future<Null> main() async {
BlocProvider<AccountBloc>(
create: (BuildContext context) => AccountBloc(customerRepository: CustomerRepository()),
),
BlocProvider<ExercisePlanBloc>(
create: (BuildContext context) => ExercisePlanBloc(menuTreeRepository: menuTreeRepository),
),
BlocProvider<ExerciseByPlanBloc>(
create: (BuildContext context) => ExerciseByPlanBloc(menuTreeRepository: menuTreeRepository, exerciseRepository: ExerciseRepository()),
),
],
child: AitrainerApp(),
@ -172,10 +188,16 @@ class AitrainerApp extends StatelessWidget {
'account': (context) => AccountPage(),
'settings': (context) => SettingsPage(),
'exerciseTypeDescription': (context) => ExerciseTypeDescription(),
'mydevelopment': (context) => MyDevelopmentPage(),
'myDevelopment': (context) => MyDevelopmentPage(),
'myExercisePlan': (context) => MyExercisePlanPage(),
'exerciseLogPage': (context) => ExerciseLogPage(),
'exercisePlanCustomPage': (context) => ExercisePlanCustomPage(),
'exercisePlanDetailAdd': (context) => ExercisePlanDetailAddPage(),
'exerciseByPlanPage': (context) => ExerciseByPlanPage(),
'exerciseAddByPlanPage': (context) => ExerciseAddByPlanPage(),
},
initialRoute: 'home',
title: 'Aitrainer',
title: 'WorkoutTest',
theme: ThemeData(
brightness: Brightness.light,
//primarySwatch: Colors.transparent,

View File

@ -1,6 +1,7 @@
import 'dart:collection';
import 'package:aitrainer_app/model/customer.dart';
import 'package:aitrainer_app/model/exercise_plan.dart';
import 'package:aitrainer_app/model/exercise_plan_detail.dart';
import 'package:aitrainer_app/model/exercise_tree.dart';
import 'package:aitrainer_app/model/exercise.dart';
import 'package:aitrainer_app/model/workout_tree.dart';
@ -55,10 +56,19 @@ class Cache {
List<ExerciseType> _exerciseTypes;
List<ExerciseTree> _exerciseTree;
List<Exercise> _exercises;
ExercisePlan _myExercisePlan;
List<ExercisePlanDetail> _myExercisesPlanDetail;
LinkedHashMap _tree = LinkedHashMap<String, WorkoutTree>();
double _percentExercises = -1;
Customer _trainee;
List<Exercise> _exercisesTrainee;
ExercisePlan _traineeExercisePlan;
List<ExercisePlanDetail> _traineeExercisesPlanDetail;
List deviceLanguages;
String startPage;
@ -73,6 +83,10 @@ class Cache {
}
}
void setTestBaseUrl() {
baseUrl = 'http://aitrainer.app:8899/api/';
}
String getAuthToken() {
return this.authToken;
}
@ -106,6 +120,12 @@ class Cache {
logout() async {
userLoggedIn = null;
authToken = "";
_trainee = null;
_percentExercises = -1;
_exercisesTrainee = null;
_traineeExercisePlan = null;
_exercises = List();
print("Trainees is null? " + (_trainee == null).toString() );
//firstLoad = true;
Future<SharedPreferences> prefs = SharedPreferences.getInstance();
await setPreferences(prefs, SharePrefsChange.logout, 0);
@ -154,6 +174,10 @@ class Cache {
this._exercises = exercises;
}
void setExercisesTrainee( List<Exercise> exercises ) {
this._exercisesTrainee = exercises;
}
void setWorkoutTree( LinkedHashMap<String, WorkoutTree> tree) {
this._tree = tree;
}
@ -170,6 +194,10 @@ class Cache {
return this._exercises;
}
List<Exercise> getExercisesTrainee() {
return this._exercisesTrainee;
}
LinkedHashMap<String, WorkoutTree> getWorkoutTree() {
return this._tree;
}
@ -186,4 +214,20 @@ class Cache {
_exercises.add(exercise);
}
void addExerciseTrainee(Exercise exercise) {
_exercisesTrainee.add(exercise);
}
Customer getTrainee() {
return this._trainee;
}
void setTrainee(Customer trainee) {
this._trainee = trainee;
}
void setTraineeExercisePlan(ExercisePlan exercisePlan) {
this._traineeExercisePlan = exercisePlan;
}
}

View File

@ -13,6 +13,7 @@ class Customer {
String fitnessLevel;
String bodyType;
int admin;
int trainer;
int dataPolicyAllowed;
@ -30,6 +31,7 @@ class Customer {
this.goal,
this.weight,
this.admin,
this.trainer,
this.dataPolicyAllowed
});
@ -47,6 +49,7 @@ class Customer {
this.goal = json['goal'];
this.weight = json['weight'];
this.admin = json['admin'];
this.trainer = json['trainer'];
}
Map<String, dynamic> toJson() =>
@ -64,6 +67,7 @@ class Customer {
"goal": goal,
"weight": weight,
"admin": admin,
"trainer": trainer,
"dataPolicyAllowed": dataPolicyAllowed,
};
}

View File

@ -8,6 +8,7 @@ class Exercise {
String unit;
double unitQuantity;
DateTime dateAdd;
int exercisePlanDetailId;
@ -30,5 +31,6 @@ class Exercise {
"unit": unit,
"unitQuantity": unitQuantity,
"dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateAdd),
"exercisePlanDetailId": exercisePlanDetailId,
};
}

View File

@ -0,0 +1,58 @@
import 'package:intl/intl.dart';
class ExercisePlan {
int exercisePlanId;
int customerId;
String name;
String description;
bool private;
DateTime dateAdd;
DateTime dateUpd;
ExercisePlan(String name, int customerId) {
this.customerId = customerId;
this.name = name;
this.dateUpd = DateTime.now();
}
ExercisePlan.fromJson(Map json) {
this.exercisePlanId = json['exercisePlanId'];
this.customerId = json['customerId'];
this.name = json['name'];
this.private = json['private'];
this.description = json['description'];
this.dateAdd = json['dateAdd'] == null ? null : DateTime.parse( json['dateAdd'] );
this.dateUpd = json['dateUpd'] == null ? null : DateTime.parse( json['dateUpd'] );
}
Map<String, dynamic> toJson() {
String formattedDateAdd;
if ( dateAdd != null) {
formattedDateAdd = DateFormat('yyyy-MM-dd HH:mm').format(dateAdd);
}
String formattedDateUpd = DateFormat('yyyy-MM-dd HH:mm').format(dateUpd);
print("DateAdd $formattedDateAdd");
if ( exercisePlanId == null ) {
return {
"customerId": customerId,
"name": name,
"description": description,
"private": private,
"dateAdd": formattedDateAdd,
"dateUpd": formattedDateUpd,
};
} else {
return {
"exercisePlanId": exercisePlanId,
"customerId": customerId,
"name": name,
"description": description,
"private": private,
"dateAdd": formattedDateAdd,
"dateUpd": formattedDateUpd,
};
}
}
}

View File

@ -0,0 +1,36 @@
import 'package:aitrainer_app/model/exercise_plan.dart';
import 'exercise_type.dart';
class ExercisePlanDetail {
int exercisePlanDetailId;
int exercisePlanId;
int exerciseTypeId;
int serie;
int repeats;
String weightEquation;
ExerciseType exerciseType;
ExercisePlanDetail(int exerciseTypeId) {
this.exerciseTypeId = exerciseTypeId;
}
ExercisePlanDetail.fromJson(Map json) {
this.exercisePlanDetailId = json['exercisePlanDetailId'];
this.exercisePlanId = json['exercisePlanId'];
this.exerciseTypeId = json['exerciseTypeId'];
this.serie = json['serie'];
this.repeats = json['repeats'];
this.weightEquation = json['weightEquation'];
}
Map<String, dynamic> toJson() =>
{
"exercisePlanId": exercisePlanId,
"exerciseTypeId": exerciseTypeId,
"serie": serie,
"repeats": repeats,
"weightEquation": weightEquation
};
}

View File

@ -5,7 +5,7 @@ import 'exercise_type.dart';
class WorkoutTree {
int id;
int parent;
String name; // is also the key
String name;
String imageName;
Color color;
double fontSize;
@ -15,7 +15,26 @@ class WorkoutTree {
bool base;
bool is1RM;
bool selected = false;
bool executed = false;
String exerciseDetail;
String nameEnglish;
WorkoutTree(this.id, this.parent, this.name, this.imageName, this.color, this.fontSize, this.child, this.exerciseTypeId, this.exerciseType, this.base, this.is1RM);
WorkoutTree(this.id, this.parent, this.name, this.imageName, this.color, this.fontSize, this.child,
this.exerciseTypeId, this.exerciseType, this.base, this.is1RM, this.nameEnglish);
Map<String, dynamic> toJson() {
return {
"id": id,
"parent": parent,
"name": name,
"imageName": imageName,
"color": color.toString(),
"fontSize": fontSize.toString(),
"child": child.toString(),
"exerciseTypeId": exerciseTypeId.toString(),
"base": base.toString(),
"is1RM": is1RM.toString(),
};
}
}

View File

@ -1,3 +1,4 @@
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/customer.dart';
import 'package:aitrainer_app/service/customer_service.dart';
@ -9,6 +10,9 @@ class GenderItem {
class CustomerRepository {
Customer customer;
Customer _trainee;
List<Customer> _trainees;
//List<CustomerRepository> customerList = List<CustomerRepository>();
bool visibleDetails = false;
List<GenderItem> genders;
@ -131,13 +135,53 @@ class CustomerRepository {
await CustomerApi().saveCustomer(modelCustomer);
}
/* Future<List<CustomerRepository>> getCustomers() async {
final results = await CustomerApi().getRealCustomers("");
this.customerList = results.map((item) => CustomerRepository(customer: item)).toList();
return this.customerList;
Future<Customer> getTraineeAsCustomer() async {
this._trainee = await CustomerApi().getTrainee(
Cache().userLoggedIn.customerId
);
return _trainee;
}
addNewCustomerToList(CustomerRepository customerViewModel) {
customerList.add(customerViewModel);
}*/
Future<List<Customer>> getTrainees() async {
int trainerId = Cache().userLoggedIn.customerId;
final results = await CustomerApi().getTrainees(trainerId);
this._trainees = results;
return results;
}
List<Customer> getTraineesList() {
return _trainees;
}
void setTrainee(int traineeId ) {
if ( _trainees == null ) {
return;
}
_trainees.forEach((element) {
if ( traineeId == element.customerId) {
this._trainee = element;
}
});
}
void emptyTrainees() {
_trainees = null;
_trainee = null;
}
Customer getTrainee() {
return this._trainee;
}
Customer getTraineeById(int customerId) {
if (_trainees == null) {
return null;
}
_trainees.forEach((element) {
if ( customerId == element.customerId) {
this._trainee = element;
}
});
return _trainee;
}
}

View File

@ -0,0 +1,167 @@
import 'dart:collection';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/exercise_plan.dart';
import 'package:aitrainer_app/model/exercise_plan_detail.dart';
import 'package:aitrainer_app/model/exercise_type.dart';
import 'package:aitrainer_app/service/exercise_plan_service.dart';
class ExercisePlanRepository {
bool newPlan = true;
ExercisePlan _exercisePlan;
LinkedHashMap<int, ExercisePlanDetail> exercisePlanDetails =
LinkedHashMap<int, ExercisePlanDetail>();
LinkedHashMap<int, ExercisePlanDetail> _origExercisePlanDetails =
LinkedHashMap<int, ExercisePlanDetail>();
int _customerId = 0;
ExercisePlanDetail actualPlanDetail;
void setCustomerId( int customerId ) {
this._customerId = customerId;
}
int getCustomerId() {
return this._customerId;
}
void addExerciseTypeToPlan(ExerciseType exerciseType) {
setActualPlanDetail(exerciseType);
}
void addToPlan() {
exercisePlanDetails[actualPlanDetail.exerciseTypeId] = actualPlanDetail;
}
void setActualPlanDetail(ExerciseType exerciseType) {
ExercisePlanDetail detail = exercisePlanDetails[exerciseType.exerciseTypeId];
if ( detail != null ) {
actualPlanDetail = detail;
} else {
actualPlanDetail = ExercisePlanDetail(exerciseType.exerciseTypeId);
}
actualPlanDetail.exerciseType = exerciseType;
}
int getPlanDetailId(int exerciseTypeId) {
ExercisePlanDetail detail = exercisePlanDetails[exerciseTypeId];
return detail.exercisePlanDetailId;
}
String getPlanDetail(int exerciseTypeId) {
ExercisePlanDetail detail = exercisePlanDetails[exerciseTypeId];
String detailString = "";
if ( detail != null) {
detailString =
detail.serie.toString() + "x" + detail.repeats.toString() + " " +
detail.weightEquation + "kg";
}
return detailString;
}
int getExercisePlanDetailSize() {
return exercisePlanDetails.length;
}
void updateExercisePlanDetail(ExerciseType exerciseType, int serie, int repeat, String weight) {
if ( exercisePlanDetails[exerciseType.exerciseTypeId] == null) {
return;
}
ExercisePlanDetail exercisePlanDetail = exercisePlanDetails[exerciseType.exerciseTypeId];
exercisePlanDetail.serie = serie;
exercisePlanDetail.repeats = repeat;
exercisePlanDetail.weightEquation = weight;
exercisePlanDetails[exerciseType.exerciseTypeId] = exercisePlanDetail;
}
void removeExerciseTypeFromPlan(ExerciseType exerciseType) {
exercisePlanDetails.remove(exerciseType.exerciseTypeId);
}
Future<void> saveExercisePlan() async {
if ( _exercisePlan == null ) {
if ( Cache().userLoggedIn == null ) {
throw Exception("please log in");
}
String exercisePlanName;
if ( this._customerId == Cache().userLoggedIn.customerId) {
exercisePlanName = Cache().userLoggedIn.name + " private";
} else {
exercisePlanName = Cache().getTrainee().name + " " + Cache().getTrainee().firstname + " private";
}
_exercisePlan = ExercisePlan(exercisePlanName, this._customerId);
}
if ( newPlan ) {
_exercisePlan.dateAdd = DateTime.now();
_exercisePlan.private = true;
ExercisePlan savedExercisePlan =
await ExercisePlanApi().saveExercisePlan(_exercisePlan);
exercisePlanDetails.forEach((exerciseTypeId, exercisePlanDetail) async {
exercisePlanDetail.exercisePlanId = savedExercisePlan.exercisePlanId;
await ExercisePlanApi().saveExercisePlanDetail(exercisePlanDetail);
});
} else {
await ExercisePlanApi().updateExercisePlan(_exercisePlan, _exercisePlan.exercisePlanId);
_origExercisePlanDetails.forEach((exerciseTypeId, exercisePlanDetail) async {
if (exercisePlanDetails[exercisePlanDetail.exercisePlanDetailId] == null) {
await ExercisePlanApi()
.deleteExercisePlanDetail(exercisePlanDetail.exercisePlanDetailId);
} else {
await ExercisePlanApi()
.updateExercisePlanDetail(exercisePlanDetail, exercisePlanDetail.exercisePlanDetailId);
}
});
exercisePlanDetails.forEach((exerciseTypeId, exercisePlanDetail) async{
exercisePlanDetail.exercisePlanId = _exercisePlan.exercisePlanId;
if ( _origExercisePlanDetails[exercisePlanDetail.exercisePlanDetailId] == null) {
await ExercisePlanApi()
.saveExercisePlanDetail(exercisePlanDetail);
}
});
}
}
Future<ExercisePlan> getLastExercisePlan() async {
if ( _customerId == 0) {
return null;
}
_exercisePlan = await ExercisePlanApi().getLastExercisePlan(_customerId);
newPlan = (_exercisePlan == null);
print("New plan: " + newPlan.toString());
return _exercisePlan;
}
Future<void> getExercisePlanDetails() async {
if (_exercisePlan == null) {
ExercisePlan exercisePlan = await this.getLastExercisePlan();
if ( exercisePlan == null ) {
exercisePlanDetails = LinkedHashMap<int, ExercisePlanDetail>();
_origExercisePlanDetails = LinkedHashMap<int, ExercisePlanDetail>();
return;
}
}
exercisePlanDetails = LinkedHashMap<int, ExercisePlanDetail>();
_origExercisePlanDetails = LinkedHashMap<int, ExercisePlanDetail>();
List<ExercisePlanDetail> list =
await ExercisePlanApi().getExercisePlanDetail(_exercisePlan.exercisePlanId);
list.forEach((element) {
newPlan = false;
ExercisePlanDetail detail = element;
_origExercisePlanDetails[detail.exerciseTypeId] = detail;
exercisePlanDetails[detail.exerciseTypeId] = detail;
});
return;
}
}

View File

@ -72,8 +72,12 @@ class ExerciseRepository {
final Exercise modelExercise = this.exercise;
modelExercise.customerId = this.customer.customerId;
modelExercise.exerciseTypeId = this.exerciseType.exerciseTypeId;
await ExerciseApi().addExercise(modelExercise);
Cache().addExercise(exercise);
Exercise savedExercise = await ExerciseApi().addExercise(modelExercise);
if ( customer.customerId == Cache().userLoggedIn.customerId) {
Cache().addExercise(savedExercise);
} else if ( Cache().getTrainee() != null && customer.customerId == Cache().getTrainee().customerId ) {
Cache().addExerciseTrainee(savedExercise);
}
}
@ -89,15 +93,26 @@ class ExerciseRepository {
Future<List<Exercise>> getExercisesByCustomer( int customerId ) async {
final results = await ExerciseApi().getExercisesByCustomer(customerId);
this.exerciseList = results;
Cache().setExercises(exerciseList);
if ( customerId == Cache().userLoggedIn.customerId) {
Cache().setExercises(exerciseList);
} else if ( Cache().getTrainee() != null && customerId == Cache().getTrainee().customerId ) {
Cache().setExercisesTrainee(exerciseList);
}
return this.exerciseList;
}
List<Exercise> getExerciseList() {
if ( this.exerciseList == null || this.exerciseList.length == 0 ) {
this.exerciseList = Cache().getExercises();
}
return this.exerciseList;
//if ( this.exerciseList == null || this.exerciseList.length == 0 ) {
return this.exerciseList = Cache().getExercises();
//}
//return this.exerciseList;
}
List<Exercise> getExerciseListTrainee() {
//if ( this.exerciseList == null || this.exerciseList.length == 0 ) {
return this.exerciseList = Cache().getExercisesTrainee();
//}
//return this.exerciseList;
}
void getBaseExerciseFinishedPercent() {

View File

@ -9,12 +9,44 @@ import 'package:aitrainer_app/service/exercise_tree_service.dart';
import 'package:aitrainer_app/service/exercisetype_service.dart';
import 'package:flutter/material.dart';
class Antagonist {
static String chest = "Chest";
static int chestNr = 1;
static String biceps = "Biceps";
static int bicepsNr = 2;
static String triceps = "Triceps";
static int tricepsNr =3;
static String back = "Back";
static int backNr = 4;
static String shoulder = "Shoulders";
static int shoulderNr = 5;
static String core = "Core";
static int coreNr = 6;
static String thigh = "Thigh";
static int thighNr = 7;
static String calf = "Calf";
static int calfNr = 8;
}
class MenuTreeRepository {
final LinkedHashMap tree = LinkedHashMap<String, WorkoutTree>();
SplayTreeMap sortedTree = SplayTreeMap<String, List<WorkoutTree>>();
bool isEnglish;
final Map<String, int> _antagonist = {
Antagonist.chest: Antagonist.chestNr,
Antagonist.biceps: Antagonist.bicepsNr,
Antagonist.triceps: Antagonist.tricepsNr,
Antagonist.back: Antagonist.backNr,
Antagonist.shoulder: Antagonist.shoulderNr,
Antagonist.core: Antagonist.coreNr,
Antagonist.thigh: Antagonist.thighNr,
Antagonist.calf: Antagonist.calfNr
};
Future<void> createTree() async {
final AppLanguage appLanguage = AppLanguage();
bool isEnglish = appLanguage.appLocal == Locale('en');
isEnglish = appLanguage.appLocal == Locale('en');
print("** Start creating tree on lang: " + appLanguage.appLocal.toString());
List<ExerciseTree> exerciseTree = Cache().getExerciseTree();
@ -25,7 +57,7 @@ class MenuTreeRepository {
exerciseTree.forEach( (treeItem) async {
String treeName = isEnglish ? treeItem.name : treeItem.nameTranslation;
String assetImage = 'asset/menu/' + treeItem.imageUrl.substring(7);
bool is1RM = treeItem.name == '1RM' ? true : false;
bool is1RM = treeItem.name == 'One Rep Max' ? true : false;
if ( is1RM == false && treeItem.parentId != 0) {
is1RM = isParent1RM(treeItem.parentId);
}
@ -34,12 +66,13 @@ class MenuTreeRepository {
treeItem.parentId,
treeName,
assetImage, Colors.white,
32,
24,
false,
0,
null,
false,
is1RM
is1RM,
treeItem.name,
);
});
@ -65,7 +98,8 @@ class MenuTreeRepository {
exerciseType.exerciseTypeId,
exerciseType,
exerciseType.base,
is1RM
is1RM,
exerciseType.name
);
});
@ -81,7 +115,7 @@ class MenuTreeRepository {
WorkoutTree treeItem = value as WorkoutTree;
if ( treeItem.id == treeId ) {
isTreeItem1RM = treeItem.is1RM;
//print (treeItem.name + " 1RM " + treeItem.is1RM.toString() );
print (treeItem.name + " 1RM " + treeItem.is1RM.toString() );
}
});
@ -99,4 +133,34 @@ class MenuTreeRepository {
});
return branch;
}
List<WorkoutTree> getBranchList(int parent) {
List branch = List<WorkoutTree>();
tree.forEach((key, value) {
WorkoutTree workoutTree = value as WorkoutTree;
if ( parent == workoutTree.parent) {
branch.add(workoutTree);
}
});
return branch;
}
void sortByMuscleType() {
sortedTree = SplayTreeMap<String, List<WorkoutTree>>();
tree.forEach((key, value) {
WorkoutTree workoutTree = value as WorkoutTree;
//print("treeitem: " + workoutTree.toJson().toString());
/*if ( workoutTree.exerciseType != null) {
print("treeItem exerciseTye " + workoutTree.exerciseType.toJson().toString());
} else {
print("treeItem exerciseType null " + workoutTree.toJson().toString());
}*/
if ( workoutTree.nameEnglish != 'One Rep Max' && workoutTree.is1RM && workoutTree.exerciseTypeId == 0) {
String treeName = _antagonist[workoutTree.nameEnglish].toString() + ". " + workoutTree.name;
sortedTree[treeName] = this.getBranchList(workoutTree.id);
}
});
return;
}
}

View File

@ -1,5 +1,6 @@
import 'dart:convert';
import 'package:aitrainer_app/util/common.dart';
import 'package:aitrainer_app/util/not_found_exception.dart';
import 'package:http/http.dart' as http;
import 'package:aitrainer_app/model/cache.dart';
@ -22,6 +23,8 @@ class APIClient with Common {
);
if(response.statusCode == 200) {
return utf8.decode(response.bodyBytes);
} else if(response.statusCode == 404 ) {
throw NotFoundException(message: "Not Found");
} else {
throw Exception("Unable to perform HTTP request!");
}

View File

@ -5,64 +5,65 @@ import 'package:aitrainer_app/service/api.dart';
import 'package:aitrainer_app/model/cache.dart';
class CustomerApi {
final APIClient _client=new APIClient();
final APIClient _client = new APIClient();
Future<List<Customer>> getRealCustomers(String param) async {
final body = await _client.get("customers/", param);
final Iterable json = jsonDecode(body);
final List<Customer> customers = json.map( (customer) => Customer.fromJson(customer) ).toList();
final List<Customer> customers = json.map((customer) =>
Customer.fromJson(customer)).toList();
return customers;
}
Future<void> saveCustomer(Customer customer) async {
String body = JsonEncoder().convert(customer.toJson());
print(" ===== saving customer id: " + customer.customerId.toString() + ":" + body );
print(" ===== saving customer id: " + customer.customerId.toString() + ":" +
body);
await _client.post(
"customers/"+customer.customerId.toString(),
body);
"customers/" + customer.customerId.toString(),
body);
}
Future<void> addCustomer(Customer customer) async {
String body = JsonEncoder().convert(customer.toJson());
print(" ===== add new customer: " + body );
print(" ===== add new customer: " + body);
await _client.post(
"customers",
body);
"customers",
body);
}
Future<void> addUser(User user) async {
String body = JsonEncoder().convert(user.toJson());
print(" ===== register new user: " + body );
print(" ===== register new user: " + body);
final String responseBody = await _client.post(
"registration",
body);
"registration",
body);
Customer customer;
try {
int status = jsonDecode(responseBody)['status'];
if ( status != null ) {
if (status != null) {
throw new Exception(jsonDecode(responseBody)['error']);
} else {
customer = Customer.fromJson(jsonDecode(responseBody));
Cache().afterRegistration(customer);
}
} on FormatException catch(exception) {
} on FormatException catch (exception) {
throw new Exception(responseBody);
}
}
Future<void> getUser(User user) async {
String body = JsonEncoder().convert(user.toJson());
print(" ===== login the user: " + body );
print(" ===== login the user: " + body);
final String responseBody = await _client.post(
"login",
body);
"login",
body);
Customer customer;
try {
customer = Customer.fromJson(jsonDecode(responseBody));
await Cache().afterLogin(customer);
} on FormatException catch(exception) {
} on FormatException catch (exception) {
throw new Exception(responseBody);
}
}
@ -70,18 +71,54 @@ class CustomerApi {
Future<void> getCustomer(int customerId) async {
String body = "";
print(" ===== get the customer by id: " + customerId.toString() );
print(" ===== get the customer by id: " + customerId.toString());
try {
final String responseBody = await _client.get(
"customers/"+customerId.toString(),
body);
"customers/" + customerId.toString(),
body);
Customer customer = Customer.fromJson(jsonDecode(responseBody));
print(" --- Customer: " + customer.toJson().toString());
Cache().afterRegistration(customer);
} catch (exception) {
print ("Exception: " + exception.toString());
print (" === go to registration ");
print("Exception: " + exception.toString());
print(" === go to registration ");
Cache().logout();
Cache().startPage = "registration";
}
}
Future<Customer> getTrainee(int customerId) async {
String body = "";
Customer customer;
print(" ===== get Trainee customer by id: " + customerId.toString());
try {
final String responseBody = await _client.get(
"customers/" + customerId.toString(),
body);
customer = Customer.fromJson(jsonDecode(responseBody));
print(" --- Trainee: " + customer.toJson().toString());
} catch (exception) {
print("Exception: " + exception.toString());
throw Exception(exception);
}
return customer;
}
Future<List<Customer>> getTrainees(int trainerId) async {
List<Customer> trainees = List<Customer>();
print("Get trainees list");
try {
String body = "";
final String responseBody = await _client.get(
"customers/trainees/" + trainerId.toString(),
body
);
final Iterable json = jsonDecode(responseBody);
trainees = json.map((customer) => Customer.fromJson(customer)).toList();
} catch (exception) {
print("Exception: " + exception.toString());
throw Exception(exception);
}
return trainees;
}
}

View File

@ -0,0 +1,145 @@
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/exercise_plan.dart';
import 'package:aitrainer_app/model/exercise_plan_detail.dart';
import 'package:aitrainer_app/util/not_found_exception.dart';
import 'dart:convert';
import 'api.dart';
class ExercisePlanApi {
final APIClient _client = new APIClient();
Future<ExercisePlan> saveExercisePlan(ExercisePlan exercisePlan) async {
String body = JsonEncoder().convert(exercisePlan.toJson());
print(" ===== saving exercisePlan $exercisePlan");
ExercisePlan savedExercisePlan;
try {
final String responseBody = await _client.post(
"exercise_plan",
body);
savedExercisePlan = ExercisePlan.fromJson(jsonDecode(responseBody));
Cache().setTraineeExercisePlan(savedExercisePlan);
} on Exception catch(e) {
throw new Exception(e.toString());
}
return savedExercisePlan;
}
Future<ExercisePlan> updateExercisePlan(
ExercisePlan exercisePlan,
int exercisePlanId) async {
String body = JsonEncoder().convert(exercisePlan.toJson());
print(" ===== saving exercisePlan $exercisePlan");
ExercisePlan updatedExercisePlan;
try {
final String responseBody = await _client.post(
"exercise_plan/" + exercisePlanId.toString(),
body);
updatedExercisePlan = ExercisePlan.fromJson(jsonDecode(responseBody));
Cache().setTraineeExercisePlan(updatedExercisePlan);
} on Exception catch(e) {
throw new Exception(e.toString());
}
return updatedExercisePlan;
}
Future<ExercisePlanDetail> saveExercisePlanDetail(ExercisePlanDetail exercisePlanDetail) async {
String body = JsonEncoder().convert(exercisePlanDetail.toJson());
print(" ===== update exercisePlanDetail $exercisePlanDetail");
ExercisePlanDetail savedExercisePlanDetail;
try {
final String responseBody = await _client.post(
"exercise_plan_detail",
body);
savedExercisePlanDetail = ExercisePlanDetail.fromJson(jsonDecode(responseBody));
} on Exception catch(e) {
throw new Exception(e.toString());
}
return savedExercisePlanDetail;
}
Future<ExercisePlanDetail> updateExercisePlanDetail(ExercisePlanDetail exercisePlanDetail,
int exercisePlanDetailId) async {
String body = JsonEncoder().convert(exercisePlanDetail.toJson());
print(" ===== update exercisePlanDetail $exercisePlanDetail");
ExercisePlanDetail savedExercisePlanDetail;
try {
final String responseBody = await _client.post(
"exercise_plan_detail/" + exercisePlanDetailId.toString(),
body);
savedExercisePlanDetail = ExercisePlanDetail.fromJson(jsonDecode(responseBody));
} on Exception catch(e) {
throw new Exception(e.toString());
}
return savedExercisePlanDetail;
}
Future<void> deleteExercisePlanDetail(int exercisePlanDetailId) async {
print(" ===== delete exercisePlanDetail $exercisePlanDetailId");
String body = "";
try {
await _client.post(
"exercise_plan_detail/delete/" + exercisePlanDetailId.toString(),
body);
} on Exception catch(e) {
throw new Exception(e.toString());
}
return;
}
Future<void> deleteExercisePlan(int exercisePlanId) async {
String body = "";
print(" ===== delete exercisePlan $exercisePlanId");
try {
await _client.post(
"exercise_plan/delete/" + exercisePlanId.toString(),
body);
} on Exception catch(e) {
throw new Exception(e.toString());
}
return;
}
Future<ExercisePlan> getLastExercisePlan(int customerId) async {
String body = "";
print(" ===== get last exercisePlan $customerId");
ExercisePlan exercisePlan;
try {
final String responseBody = await _client.get(
"exercise_plan/last/" + customerId.toString(),
body);
exercisePlan = ExercisePlan.fromJson(jsonDecode(responseBody));
} on Exception catch(e) {
if ( e is NotFoundException) {
print("ExercisePlan not found for " + customerId.toString());
return exercisePlan;
} else {
throw new Exception(e.toString());
}
}
return exercisePlan;
}
Future<List<ExercisePlanDetail>> getExercisePlanDetail(int exercisePlanId) async {
String body = "";
print(" ===== get exercisePlanDetail $exercisePlanId");
List<ExercisePlanDetail> listExercisePlanDetail;
try {
final String responseBody = await _client.get(
"exercise_plan_detail/" + exercisePlanId.toString(),
body);
print("response body:" + responseBody);
final Iterable json = jsonDecode(responseBody);
listExercisePlanDetail = json.map( (planDetail) => ExercisePlanDetail.fromJson(planDetail) ) .toList();
} on Exception catch(e) {
throw new Exception(e.toString());
}
return listExercisePlanDetail;
}
}

View File

@ -22,12 +22,14 @@ class ExerciseApi {
body);
}
Future<void> addExercise(Exercise exercise) async {
Future<Exercise> addExercise(Exercise exercise) async {
String body = JsonEncoder().convert(exercise.toJson());
print(" ===== add new exercise: " + body );
await _client.post(
final String response = await _client.post(
"exercises",
body);
final Exercise savedExercise = Exercise.fromJson(jsonDecode(response));
return savedExercise;
}
Future<List<Exercise>> getExercisesByCustomer(int customerId ) async {

View File

@ -0,0 +1,4 @@
class NotFoundException implements Exception {
final String message;
const NotFoundException({this.message});
}

View File

@ -27,7 +27,7 @@ class Session {
if ( Cache().firstLoad ) {
print (" -- Session: fetch locale..");
await appLanguage.fetchLocale();
await appLanguage.getLocale(_sharedPreferences);
await AppLocalizations.delegate.load(appLanguage.appLocal);
print (" -- Session: fetch token..");
await _fetchToken(_sharedPreferences);
@ -95,7 +95,6 @@ class Session {
//Navigator.of(context).pushNamed('login');
Cache().startPage = "login";
} else {
print("************** Store SharedPreferences");
// get API customer
customerId = prefs.getInt(Cache.customerIdKey);
await CustomerApi().getCustomer(customerId);

View File

@ -1,5 +1,7 @@
import 'package:aitrainer_app/bloc/account/account_bloc.dart';
import 'package:aitrainer_app/localization/app_language.dart';
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/model/customer.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:aitrainer_app/widgets/bottom_nav.dart';
import 'package:flutter/material.dart';
@ -7,6 +9,7 @@ import 'package:flutter/cupertino.dart';
// ignore: must_be_immutable
class AccountPage extends StatelessWidget {
// ignore: close_sinks
AccountBloc accountBloc;
@override
@ -93,7 +96,7 @@ class AccountPage extends StatelessWidget {
),
),
loginOut( context, accountBloc ),
//exercises(exerciseChangingViewModel),
getMyTrainees(context, accountBloc),
]);
}
@ -137,93 +140,72 @@ class AccountPage extends StatelessWidget {
return element;
}
/* ListTile exercises( ExerciseChangingViewModel model ) {
ListTile element = ListTile();
if ( Auth().userLoggedIn == null ) {
return element;
Widget getMyTrainees( BuildContext context, AccountBloc accountBloc ) {
if ( accountBloc.customerRepository.customer == null ) {
return Container();
}
element = ListTile(
title: Text(AppLocalizations.of(context).translate("Exercises")),
subtitle: Column(
children: [
FutureBuilder<List<ExerciseViewModel>>(
future: _exercises,
builder: (context, snapshot) {
if (snapshot.hasData) {
return getExercises( model );//CustomerListWidget(customers: _exerciseViewModel.exerciseList);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
// By default, show a loading spinner.
return CircularProgressIndicator();
}
),]
));
return element;
}
*/
/*
Widget getExercises( ExerciseChangingViewModel model ) {
List<ExerciseViewModel> exercises = model.exerciseList;
Column element = Column();
if (exercises.length > 0) {
List<Column> rows = List();
exercises.forEach((exercise) {
String exerciseName = AppLocalizations.of(context).translate(
Common.getExerciseType(exercise.getExercise().exerciseTypeId).name);
String quantity = exercise.getExercise().quantity.toString() + " " +
AppLocalizations.of(context).translate(exercise.getExercise().unit);
String unitQuantity = "";
String unitQuantityUnit = "";
String date = Common.getDateLocale(exercise.getExercise().dateAdd, false);
if (exercise.getExercise().unitQuantity != null) {
unitQuantity = exercise.getExercise().unitQuantity.toString();
unitQuantityUnit = AppLocalizations.of(context).translate(
Common.getExerciseType(exercise.getExercise().exerciseTypeId).unitQuantityUnit);
}
TableRow row = TableRow(
children: [
Text(date),
Text(exerciseName),
Text(quantity),
Text(unitQuantity + " " + unitQuantityUnit),
]
);
Table table = Table(
defaultColumnWidth: FractionColumnWidth(0.28),
children: [row],
);
Column col = Column(
children: [
table,
Row(
children: [
Text(" "),
]
)
],
);
rows.add(col);
});
element = Column(
children: rows,
if ( accountBloc.customerRepository.customer.trainer == 0 ) {
return ListTile(
title: Container(),
);
}
return element;
if (accountBloc.customerRepository.getTraineesList() == null ) {
return ListTile(
leading: Icon(Icons.people),
title: RaisedButton(
color: Colors.white70,
onPressed: () => accountBloc.add(AccountGetTrainees()),
child: Text("See my trainees"),
),
);
}
List<Widget> elements = List<Widget>();
accountBloc.customerRepository.getTraineesList().forEach((element) {
Customer trainee = element;
String name = trainee.name;
String firstName = trainee.firstname;
String nodeName = AppLanguage().appLocal == Locale("en") ?
firstName + " " + name : name + " " + firstName;
bool selected = accountBloc.traineeId == trainee.customerId;
Widget widget = FlatButton(
padding: EdgeInsets.all(10),
shape:RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(8)),
side: BorderSide(width: 2, color: selected ? Colors.blue : Colors.black26 ),
),
onPressed: () {
accountBloc.add(AccountSelectTrainee(traineeId: trainee.customerId));
//Navigator.of(context).pushNamed('login');
},
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(nodeName, style:
TextStyle(
color: selected ? Colors.blue : Colors.black54,
fontWeight: selected ? FontWeight.bold : FontWeight.normal
),
),
Icon(Icons.arrow_forward_ios),
]),
);
elements.add(widget);
});
return ListTile(
leading: Icon(Icons.people),
subtitle: Text("My Trainees"),
title: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: elements,
)
);
}
} */
}

View File

@ -0,0 +1,241 @@
import 'dart:collection';
import 'package:aitrainer_app/bloc/exercise_add_by_plan_bloc.dart';
import 'package:aitrainer_app/bloc/exercise_by_plan/exercise_by_plan_bloc.dart';
import 'package:aitrainer_app/localization/app_language.dart';
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/model/workout_tree.dart';
import 'package:aitrainer_app/repository/exercise_plan_repository.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/widgets/splash.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_form_bloc/flutter_form_bloc.dart';
class ExerciseAddByPlanPage extends StatefulWidget{
_ExerciseAddByPlanPage createState() => _ExerciseAddByPlanPage();
}
class _ExerciseAddByPlanPage extends State<ExerciseAddByPlanPage> {
@override
Widget build(BuildContext context) {
LinkedHashMap arguments = ModalRoute.of(context).settings.arguments;
// ignore: close_sinks
final ExerciseByPlanBloc bloc = arguments['blocExerciseByPlan'];
final int customerId = arguments['customerId'];
final WorkoutTree workoutTree = arguments['workoutTree'];
final ExerciseRepository exerciseRepository = ExerciseRepository();
return BlocProvider(
create: (context) =>
ExerciseAddByPlanFormBloc(
exerciseRepository: exerciseRepository,
exercisePlanRepository: bloc.exercisePlanRepository,
customerId: customerId,
workoutTree: workoutTree),
child: BlocBuilder<ExerciseAddByPlanFormBloc, FormBlocState>(
builder: (context, state) {
// ignore: close_sinks
final exerciseBloc = BlocProvider.of<ExerciseAddByPlanFormBloc>(context);
if ( state is FormBlocLoading ) {
return LoadingDialog();
} else if ( state is FormBlocSuccess) {
return getControlForm(exerciseBloc);
} else {
return getControlForm(exerciseBloc);
}
}
));
}
Form getControlForm( ExerciseAddByPlanFormBloc exerciseBloc) {
String exerciseName = AppLanguage().appLocal == Locale("en") ?
exerciseBloc.exerciseRepository.exerciseType.name :
exerciseBloc.exerciseRepository.exerciseType.nameTranslation;
return Form(
autovalidate: true,
child: Scaffold(
resizeToAvoidBottomInset: true,
appBar: AppBar(
backgroundColor: Colors.black,
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text("Add Exercise"),
Image.asset(
'asset/image/WT_long_logo.png',
fit: BoxFit.cover,
height: 65.0,
),
],
),
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colors.white),
onPressed: () => Navigator.of(context).pop(),
),
),
body: Container(
width: MediaQuery
.of(context)
.size
.width,
height: MediaQuery
.of(context)
.size
.height,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_light_background.png'),
fit: BoxFit.fill,
alignment: Alignment.center,
),
),
child: Container(
padding: const EdgeInsets.only (top: 25, left: 25, right: 25),
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Text(exerciseName,
style: TextStyle(fontWeight: FontWeight.bold,
fontSize: 18,
color: Colors.deepOrange),
overflow: TextOverflow.fade,
maxLines: 1,
softWrap: true,
),
Divider(color: Colors.transparent,),
Divider(),
Column(
children: repeatExercises(exerciseBloc),
),
Divider(),
]),
)
)
),
),
);
}
List<Column> repeatExercises(ExerciseAddByPlanFormBloc exerciseBloc) {
List<Column> listColumns = List<Column>();
for ( int i = 0; i < exerciseBloc.countSteps; i++) {
Column col = Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Divider(color: Colors.transparent,),
Text("Execute the " + (i+1).toString() + ". set!",
style: TextStyle(),),
TextFieldBlocBuilder(
readOnly: exerciseBloc.step != i+1,
textFieldBloc: exerciseBloc.quantity1Field,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14,
color: Colors.deepOrange,
fontWeight: FontWeight.bold),
inputFormatters: [
WhitelistingTextInputFormatter(RegExp(r"[\d.]"))
],
decoration: InputDecoration(
fillColor: Colors.white,
filled: false,
hintStyle: TextStyle(
fontSize: 12, color: Colors.black54, fontWeight: FontWeight.w100),
hintText: AppLocalizations.of(context)
.translate("The number of the exercise"),
labelStyle: TextStyle(fontSize: 12, color: Colors.deepOrange, fontWeight: FontWeight.normal),
labelText: "Please repeat with " + exerciseBloc.unitQuantity1Field.value + " " +
exerciseBloc.exerciseRepository.exerciseType.unitQuantityUnit + " " +
exerciseBloc.exercisePlanRepository.actualPlanDetail.repeats.toString() + " times!",
),
),
TextFieldBlocBuilder(
readOnly: exerciseBloc.step != i+1,
textFieldBloc: exerciseBloc.unitQuantity1Field,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
color: Colors.black54,
fontWeight: FontWeight.bold),
inputFormatters: [
WhitelistingTextInputFormatter(RegExp(r"[\d.]"))
],
decoration: InputDecoration(
fillColor: Colors.white,
filled: false,
hintStyle: TextStyle(
fontSize: 12, color: Colors.black54, fontWeight: FontWeight.w100),
labelStyle: TextStyle(fontSize: 12, color: Colors.deepOrange, fontWeight: FontWeight.normal),
labelText: exerciseBloc.exerciseRepository.exerciseType.unitQuantityUnit,
),
),
RaisedButton(
padding: EdgeInsets.all(0),
textColor: Colors.white,
color: exerciseBloc.step == i+1 ? Colors.blue : Colors.black26,
focusColor: Colors.blueAccent,
onPressed: () =>
{
print ("Submit step " + exerciseBloc.step.toString() + " (i) " + i.toString()),
if ( exerciseBloc.step == i+1 ) {
exerciseBloc.submit()
},
if ( i+1 == exerciseBloc.countSteps) {
Navigator.of(context).pop()
}
},
child: Text(
AppLocalizations.of(context).translate("Check"),
style: TextStyle(fontSize: 12),)
),
Divider(color: Colors.transparent,),
],
);
listColumns.add(col);
}
return listColumns;
}
String validateNumberInput(input) {
String error = AppLocalizations.of(context).translate(
"Please type the right quantity 0-10000");
dynamic rc = (input != null && input.length > 0);
if (!rc) {
return null;
}
Pattern pattern = r'^\d+(?:\.\d+)?$';
RegExp regex = new RegExp(pattern);
if (!regex.hasMatch(input)) {
return error;
}
rc = double.tryParse(input);
if (rc == null) {
return error;
}
if (!(double.parse(input) < 10000 && double.parse(input) > 0)) {
return error;
}
return null;
}
}

View File

@ -0,0 +1,187 @@
import 'dart:collection';
import 'package:aitrainer_app/bloc/exercise_by_plan/exercise_by_plan_bloc.dart';
import 'package:aitrainer_app/localization/app_language.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/workout_tree.dart';
import 'package:aitrainer_app/widgets/app_bar_common.dart';
import 'package:aitrainer_app/widgets/splash.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_treeview/tree_view.dart';
class ExerciseByPlanPage extends StatefulWidget {
@override
_ExerciseByPlanPage createState() => _ExerciseByPlanPage();
}
class _ExerciseByPlanPage extends State<ExerciseByPlanPage> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
// ignore: close_sinks
ExerciseByPlanBloc bloc;
@override
void initState() {
super.initState();
/// We require the initializers to run after the loading screen is rendered
SchedulerBinding.instance.addPostFrameCallback((_) {
BlocProvider.of<ExerciseByPlanBloc>(context).add(ExerciseByPlanLoad());
});
}
@override
Widget build(BuildContext context) {
LinkedHashMap arguments = ModalRoute.of(context).settings.arguments;
final int customerId = arguments['customerId'];
bloc = BlocProvider.of<ExerciseByPlanBloc>(context);
bloc.customerId = customerId;
return Scaffold(
key: _scaffoldKey,
appBar: AppBarCommonNav(),
body: Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
image: DecorationImage(
image: customerId == Cache().userLoggedIn.customerId ? AssetImage('asset/image/WT_light_background.png'):
AssetImage('asset/image/WT_menu_dark.png'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
child: BlocConsumer<ExerciseByPlanBloc, ExerciseByPlanState>(listener: (context, state) {
if (state is ExerciseByPlanError) {
Scaffold.of(context).showSnackBar(SnackBar(
content: Text(
state.message,
),
backgroundColor: Colors.orange,
));
} else if (state is ExerciseByPlanLoading) {
LoadingDialog();
}
},
// ignore: missing_return
builder: (context, state) {
if (state is ExerciseByPlanStateInitial || state is ExerciseByPlanLoading) {
return Container();
} else if (state is ExerciseByPlanReady) {
return exerciseWidget(bloc);
} else if (state is ExerciseByPlanError) {
return exerciseWidget(bloc);
}
})));
}
Widget exerciseWidget(ExerciseByPlanBloc bloc) {
final LinkedHashMap args = LinkedHashMap();
TreeViewController _treeViewController = TreeViewController(children: nodeExercisePlan(bloc));
TreeViewTheme _treeViewTheme = TreeViewTheme(
expanderTheme: ExpanderThemeData(
type: ExpanderType.plusMinus,
modifier: ExpanderModifier.circleOutlined,
position: ExpanderPosition.start,
color: Colors.black26,
size: 10,
),
labelStyle: TextStyle(fontSize: 14, letterSpacing: 0, color: Colors.blue.shade800),
parentLabelStyle: TextStyle(
fontSize: 14,
letterSpacing: 0.3,
fontWeight: FontWeight.w800,
color: Colors.orange.shade600,
),
iconTheme: IconThemeData(
size: 20,
color: Colors.blue.shade800,
),
colorScheme: bloc.customerId == Cache().userLoggedIn.customerId ? ColorScheme.light(background: Colors.transparent) : ColorScheme.dark(background: Colors.transparent),
);
return Scaffold(
backgroundColor: Colors.transparent,
body: TreeView(
controller: _treeViewController,
allowParentSelect: false,
supportParentDoubleTap: false,
//onExpansionChanged: _expandNodeHandler,
onNodeTap: (key) {
/* Node<dynamic> node = _treeViewController.getNode(key);
WorkoutTree workoutTree = node.data as WorkoutTree;
bloc.exercisePlanRepository.setActualPlanDetail(workoutTree.exerciseType);
print("change node " + node.label + " key " + key);
bloc.add(ExercisePlanUpdate(workoutTree: workoutTree));
Navigator.of(context).pushNamed("exercisePlanDetailAdd", arguments: bloc); */
Node<dynamic> node = _treeViewController.getNode(key);
WorkoutTree workoutTree = node.data as WorkoutTree;
args['blocExerciseByPlan'] = bloc;
args['customerId'] = bloc.customerId;
args['workoutTree'] = workoutTree;
Navigator.of(context).pushNamed("exerciseAddByPlanPage", arguments: args);
},
theme: _treeViewTheme,
),
//bottomNavigationBar: BottomNavigator(bottomNavIndex: 2),
floatingActionButtonLocation: FloatingActionButtonLocation.endDocked,
);
}
List<Node> nodeExercisePlan(ExerciseByPlanBloc bloc) {
List<Node> nodes = List<Node>();
Node actualNode;
bool isEnglish = AppLanguage().appLocal == Locale("en");
bloc.menuTreeRepository.sortedTree.forEach((name, list) {
List<WorkoutTree> listWorkoutItem = list;
List<Node> listExerciseTypePerMuscle = List<Node>();
NodeIcon icon;
listWorkoutItem.forEach((element) {
WorkoutTree treeItem = element;
if ( treeItem.selected ) {
icon =
treeItem.executed == false ? NodeIcon(codePoint: Icons.bubble_chart.codePoint, color: "blueAccent") :
NodeIcon(codePoint: Icons.check_box.codePoint, color: "green");
String exerciseLabel = isEnglish
? treeItem.name
: treeItem.exerciseType == null ? treeItem.name : treeItem.exerciseType.nameTranslation;
List<Node<dynamic>> planDetailList = List<Node<dynamic>>();
String planDetail = bloc.exercisePlanRepository.getPlanDetail(treeItem.exerciseTypeId);
if (planDetail.length > 0) {
exerciseLabel += " (" + planDetail + ")";
}
actualNode = Node(
label: exerciseLabel,
key: treeItem.id.toString(),
data: treeItem,
expanded: planDetailList.length > 0 ? true : false,
children: [],
icon: icon);
listExerciseTypePerMuscle.add(actualNode);
}
});
if (name != null) {
actualNode = Node(
label: name,
key: name,
expanded: true,
children: listExerciseTypePerMuscle,
icon: NodeIcon(codePoint: Icons.perm_identity.codePoint, color: "orange"));
nodes.add(actualNode);
}
});
return nodes;
}
}

View File

@ -0,0 +1,148 @@
import 'dart:collection';
import 'package:aitrainer_app/localization/app_language.dart';
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/exercise.dart';
import 'package:aitrainer_app/model/exercise_type.dart';
import 'package:aitrainer_app/repository/customer_repository.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/widgets/app_bar_common.dart';
import 'package:flutter/material.dart';
import 'package:flutter_treeview/tree_view.dart';
class ExerciseLogPage extends StatefulWidget {
@override
_ExerciseLogPage createState() => _ExerciseLogPage();
}
class _ExerciseLogPage extends State<ExerciseLogPage> {
@override
Widget build(BuildContext context) {
LinkedHashMap arguments = ModalRoute.of(context).settings.arguments;
final ExerciseRepository exerciseRepository = arguments['exerciseRepository'];
final CustomerRepository customerRepository = arguments['customerRepository'];
final int customerId = arguments['customerId'];
return Scaffold(
appBar: AppBarCommonNav(),
body: Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
image: DecorationImage(
image: customerId == Cache().userLoggedIn.customerId ? AssetImage('asset/image/WT_light_background.png'):
AssetImage('asset/image/WT_menu_dark.png'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
child: exerciseWidget(exerciseRepository, customerId),
)
);
}
Widget exerciseWidget(ExerciseRepository exerciseRepository, int customerId) {
TreeViewController _treeViewController =
TreeViewController(children: nodeExercises(exerciseRepository, customerId));
TreeViewTheme _treeViewTheme = TreeViewTheme(
expanderTheme: ExpanderThemeData(
type: ExpanderType.caret,
modifier: ExpanderModifier.none,
position: ExpanderPosition.start,
color: Colors.red.shade800,
size: 20,
),
labelStyle: TextStyle(
fontSize: 12,
letterSpacing: 0.1,
),
parentLabelStyle: TextStyle(
fontSize: 16,
letterSpacing: 0.1,
fontWeight: FontWeight.w800,
color: Colors.orange.shade600,
),
iconTheme: IconThemeData(
size: 18,
color: Colors.grey.shade800,
),
colorScheme: ColorScheme.light(background: Colors.transparent),
);
return TreeView(
controller: _treeViewController,
allowParentSelect: false,
supportParentDoubleTap: false,
//onExpansionChanged: _expandNodeHandler,
onNodeTap: (key) {
setState(() {
_treeViewController = _treeViewController.copyWith(selectedKey: key);
});
},
theme: _treeViewTheme,
);
}
List<Node> nodeExercises(ExerciseRepository exerciseRepository, int customerId) {
List<Node> nodes = List<Node>();
List<Exercise> exercises;
if ( customerId == Cache().userLoggedIn.customerId ) {
exercises = exerciseRepository.getExerciseList();
} else if ( Cache().getTrainee() != null && customerId == Cache().getTrainee().customerId ) {
exercises = exerciseRepository.getExerciseListTrainee();
}
String prevDay = "";
Node actualNode;
List<Node> listExercisesPerDay;
exercises.forEach((element) {
Exercise exercise = element;
ExerciseType exerciseType =
exerciseRepository.getExerciseTypeById(exercise.exerciseTypeId);
String actualDay = exercise.dateAdd.year.toString() +
"-" +
exercise.dateAdd.month.toString() +
"-" +
exercise.dateAdd.day.toString();
if (prevDay.compareTo(actualDay) != 0) {
listExercisesPerDay = List<Node>();
actualNode = Node(
label: actualDay,
key: exercise.dateAdd.toString(),
expanded: true,
children: listExercisesPerDay,
icon:
NodeIcon(codePoint: Icons.date_range.codePoint, color: "blue"));
nodes.add(actualNode);
prevDay = actualDay;
}
String exerciseName = AppLanguage().appLocal == Locale("en")
? exerciseType.name
: exerciseType.nameTranslation;
String unitQuantity = exerciseType.unitQuantity == "1"
? exercise.unitQuantity.toStringAsFixed(0) +
" " +
AppLocalizations.of(context)
.translate(exerciseType.unitQuantityUnit) +
" "
: "";
String labelExercise = exerciseName +
" " +
unitQuantity +
exercise.quantity.toStringAsFixed(0) +
" " +
AppLocalizations.of(context).translate(exercise.unit);
listExercisesPerDay.add(Node(
label: labelExercise,
key: exercise.exerciseId.toString(),
expanded: false,
icon: NodeIcon(codePoint: Icons.repeat.codePoint, color: "blue")));
});
return nodes;
}
}

View File

@ -0,0 +1,190 @@
import 'dart:collection';
import 'package:aitrainer_app/bloc/exercise_plan/exercise_plan_bloc.dart';
import 'package:aitrainer_app/localization/app_language.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/workout_tree.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/widgets/app_bar_common.dart';
import 'package:aitrainer_app/widgets/splash.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_treeview/tree_view.dart';
class ExercisePlanCustomPage extends StatefulWidget {
@override
_ExercisePlanCustomPage createState() => _ExercisePlanCustomPage();
}
class _ExercisePlanCustomPage extends State<ExercisePlanCustomPage> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
// ignore: close_sinks
ExercisePlanBloc bloc;
@override
void initState() {
super.initState();
/// We require the initializers to run after the loading screen is rendered
SchedulerBinding.instance.addPostFrameCallback((_) {
BlocProvider.of<ExercisePlanBloc>(context).add(ExercisePlanLoad());
});
}
@override
Widget build(BuildContext context) {
LinkedHashMap arguments = ModalRoute.of(context).settings.arguments;
final ExerciseRepository exerciseRepository = arguments['exerciseRepository'];
final int customerId = arguments['customerId'];
bloc = BlocProvider.of<ExercisePlanBloc>(context);
bloc.customerId = customerId;
return Scaffold(
key: _scaffoldKey,
appBar: AppBarCommonNav(),
body: Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
image: DecorationImage(
image: customerId == Cache().userLoggedIn.customerId ? AssetImage('asset/image/WT_light_background.png'):
AssetImage('asset/image/WT_menu_dark.png'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
child: BlocConsumer<ExercisePlanBloc, ExercisePlanState>(listener: (context, state) {
if (state is ExercisePlanError) {
//showInSnackBar(state.message);
//return exerciseWidget(bloc);
Scaffold.of(context).showSnackBar(SnackBar(
content: Text(
state.message,
),
backgroundColor: Colors.orange,
));
} else if (state is ExercisePlanLoading) {
LoadingDialog();
}
},
// ignore: missing_return
builder: (context, state) {
if (state is ExercisePlanInitial) {
return Container();
} else if (state is ExercisePlanReady) {
return exerciseWidget(bloc);
} else if (state is ExercisePlanError) {
return exerciseWidget(bloc);
} else if (state is ExercisePlanLoading) {
return Container();
}
})));
}
Widget exerciseWidget(ExercisePlanBloc bloc) {
TreeViewController _treeViewController = TreeViewController(children: nodeExercisePlan(bloc));
TreeViewTheme _treeViewTheme = TreeViewTheme(
expanderTheme: ExpanderThemeData(
type: ExpanderType.plusMinus,
modifier: ExpanderModifier.circleOutlined,
position: ExpanderPosition.start,
color: Colors.black26,
size: 10,
),
labelStyle: TextStyle(fontSize: 14, letterSpacing: 0, color: Colors.blue.shade800),
parentLabelStyle: TextStyle(
fontSize: 14,
letterSpacing: 0.3,
fontWeight: FontWeight.w800,
color: Colors.orange.shade600,
),
iconTheme: IconThemeData(
size: 20,
color: Colors.blue.shade800,
),
colorScheme: bloc.customerId == Cache().userLoggedIn.customerId ? ColorScheme.light(background: Colors.transparent) : ColorScheme.dark(background: Colors.transparent),
);
return Scaffold(
backgroundColor: Colors.transparent,
body: TreeView(
controller: _treeViewController,
allowParentSelect: true,
supportParentDoubleTap: false,
//onExpansionChanged: _expandNodeHandler,
onNodeTap: (key) {
Node<dynamic> node = _treeViewController.getNode(key);
WorkoutTree workoutTree = node.data as WorkoutTree;
bloc.exercisePlanRepository.setActualPlanDetail(workoutTree.exerciseType);
print("change node " + node.label + " key " + key);
bloc.add(ExercisePlanUpdate(workoutTree: workoutTree));
Navigator.of(context).pushNamed("exercisePlanDetailAdd", arguments: bloc);
},
theme: _treeViewTheme,
),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.blueAccent,
child: Icon(Icons.save_alt),
onPressed: () => {
bloc.add(ExercisePlanSave()),
if (bloc.exercisePlanRepository.getExercisePlanDetailSize() > 0) {
Navigator.of(context).pop()
}
}
),
//bottomNavigationBar: BottomNavigator(bottomNavIndex: 2),
floatingActionButtonLocation: FloatingActionButtonLocation.endDocked,
);
}
List<Node> nodeExercisePlan(ExercisePlanBloc bloc) {
List<Node> nodes = List<Node>();
Node actualNode;
bool isEnglish = AppLanguage().appLocal == Locale("en");
bloc.menuTreeRepository.sortedTree.forEach((name, list) {
List<WorkoutTree> listWorkoutItem = list;
List<Node> listExerciseTypePerMuscle = List<Node>();
NodeIcon icon;
listWorkoutItem.forEach((element) {
WorkoutTree treeItem = element;
icon =
treeItem.selected == true ? NodeIcon(codePoint: Icons.bubble_chart.codePoint, color: "blueAccent") : null;
String exerciseLabel = isEnglish
? treeItem.name
: treeItem.exerciseType == null ? treeItem.name : treeItem.exerciseType.nameTranslation;
List<Node<dynamic>> planDetailList = List<Node<dynamic>>();
String planDetail = bloc.exercisePlanRepository.getPlanDetail(treeItem.exerciseTypeId);
if (planDetail.length > 0) {
exerciseLabel += " (" + planDetail +")";
}
actualNode = Node(
label: exerciseLabel,
key: treeItem.id.toString(),
data: treeItem,
expanded: planDetailList.length > 0 ? true : false,
children: [],
icon: icon);
listExerciseTypePerMuscle.add(actualNode);
});
//print ("Node name " + name);
if (name != null) {
actualNode = Node(
label: name, // AppLocalizations.of(context).translate(name),
key: name,
expanded: true,
children: listExerciseTypePerMuscle,
icon: NodeIcon(codePoint: Icons.perm_identity.codePoint, color: "orange"));
nodes.add(actualNode);
}
});
return nodes;
}
}

View File

@ -0,0 +1,144 @@
import 'package:aitrainer_app/bloc/exercise_plan/exercise_plan_bloc.dart';
import 'package:aitrainer_app/bloc/exercise_plan_custom_form.dart';
import 'package:aitrainer_app/localization/app_language.dart';
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/repository/exercise_plan_repository.dart';
import 'package:aitrainer_app/widgets/app_bar_common.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_form_bloc/flutter_form_bloc.dart';
class ExercisePlanDetailAddPage extends StatefulWidget {
@override
_ExercisePlanDetailAddPage createState() => _ExercisePlanDetailAddPage();
}
class _ExercisePlanDetailAddPage extends State<ExercisePlanDetailAddPage> {
@override
Widget build(BuildContext context) {
// ignore: close_sinks
final ExercisePlanBloc planBloc = ModalRoute.of(context).settings.arguments;
final ExercisePlanRepository exercisePlanRepository = planBloc.exercisePlanRepository;
return BlocProvider(
create: (context) => ExercisePlanCustomerFormBloc(exercisePlanRepository: exercisePlanRepository, planBloc: planBloc),
child: Builder(builder: (context) {
// ignore: close_sinks
final bloc = BlocProvider.of<ExercisePlanCustomerFormBloc>(context);
String exerciseName = "";
if (bloc != null) {
exerciseName = AppLanguage().appLocal == Locale("en")
? bloc.exercisePlanRepository.actualPlanDetail.exerciseType.name
: bloc.exercisePlanRepository.actualPlanDetail.exerciseType.nameTranslation;
}
return Form(
autovalidate: true,
child: Scaffold(
resizeToAvoidBottomInset: true,
appBar: AppBarCommonNav(),
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_light_background.png'),
fit: BoxFit.fill,
alignment: Alignment.center,
),
),
child: Container(
padding: const EdgeInsets.only(top: 25, left: 25, right: 25),
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(mainAxisAlignment: MainAxisAlignment.spaceAround, children: <Widget>[
Text(AppLocalizations.of(context).translate('Save The Exercise To The Exercise Plan'),
style: TextStyle(fontSize: 14, color: Colors.blueAccent)),
Text(
exerciseName,
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.deepOrange),
overflow: TextOverflow.fade,
maxLines: 1,
softWrap: true,
),
TextFieldBlocBuilder(
textFieldBloc: bloc.serieField,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 30, color: Colors.lightBlue, fontWeight: FontWeight.bold),
inputFormatters: [WhitelistingTextInputFormatter(RegExp(r"[\d.]"))],
decoration: InputDecoration(
fillColor: Colors.white,
filled: false,
hintStyle: TextStyle(fontSize: 16, color: Colors.black54, fontWeight: FontWeight.w100),
hintText: AppLocalizations.of(context).translate("The number of the serie done with"),
labelStyle: TextStyle(fontSize: 16, color: Colors.lightBlue),
labelText: AppLocalizations.of(context).translate("Serie"),
),
),
TextFieldBlocBuilder(
textFieldBloc: bloc.quantityField,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 30, color: Colors.lightBlue, fontWeight: FontWeight.bold),
inputFormatters: [WhitelistingTextInputFormatter(RegExp(r"[\d.]"))],
decoration: InputDecoration(
fillColor: Colors.white,
filled: false,
hintStyle: TextStyle(fontSize: 16, color: Colors.black54, fontWeight: FontWeight.w100),
hintText: AppLocalizations.of(context).translate("The number of the repeats of one serie"),
labelStyle: TextStyle(fontSize: 16, color: Colors.lightBlue),
labelText: AppLocalizations.of(context).translate("Repeats"),
),
),
TextFieldBlocBuilder(
textFieldBloc: bloc.weightField,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 30, color: Colors.lightBlue, fontWeight: FontWeight.bold),
inputFormatters: [WhitelistingTextInputFormatter(RegExp(r"[\d.]"))],
decoration: InputDecoration(
fillColor: Colors.white,
filled: false,
hintStyle: TextStyle(fontSize: 16, color: Colors.black54, fontWeight: FontWeight.w100),
hintText: AppLocalizations.of(context).translate("The weight"),
labelStyle: TextStyle(fontSize: 16, color: Colors.lightBlue),
labelText: AppLocalizations.of(context).translate("Weight"),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
RaisedButton(
textColor: Colors.white,
color: Colors.red.shade300,
focusColor: Colors.white,
onPressed: () => {
print("Remove " + bloc.exercisePlanRepository.actualPlanDetail.exerciseType.name),
planBloc.add(ExercisePlanRemoveExercise(exercisePlanDetail: bloc.exercisePlanRepository.actualPlanDetail)),
Navigator.of(context).pop(),
},
child: Text("Delete"), //Text(AppLocalizations.of(context).translate("Delete"), style: TextStyle(fontSize: 16),)
),
RaisedButton(
textColor: Colors.white,
color: Colors.blueAccent,
focusColor: Colors.white,
onPressed: () => {
bloc.submit(),
Navigator.of(context).pop(),
},
child: Text(
AppLocalizations.of(context).translate("Save"),
style: TextStyle(fontSize: 16),
)),
],
),
]),
))),
),
);
}));
}
}

View File

@ -1,147 +0,0 @@
import 'package:aitrainer_app/localization/app_language.dart';
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/model/exercise.dart';
import 'package:aitrainer_app/model/exercise_type.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/widgets/app_bar.dart';
import 'package:aitrainer_app/widgets/bottom_nav.dart';
import 'package:flutter/material.dart';
import 'package:flutter_treeview/tree_view.dart';
class MyDevelopmentPage extends StatefulWidget {
@override
_MyDevelopmentPage createState() => _MyDevelopmentPage();
}
class _MyDevelopmentPage extends State<MyDevelopmentPage> {
@override
Widget build(BuildContext context) {
final ExerciseRepository exerciseRepository = ExerciseRepository();
return Scaffold(
appBar: AppBarNav(),
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_light_background.png'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
child: Container(
padding: EdgeInsets.all(10),
child:
exerciseWidget(exerciseRepository),
)
),
bottomNavigationBar: BottomNavigator(bottomNavIndex: 1));
}
Widget exerciseWidget(ExerciseRepository exerciseRepository) {
TreeViewController _treeViewController = TreeViewController(children: nodeExercises(exerciseRepository) );
TreeViewTheme _treeViewTheme = TreeViewTheme(
expanderTheme: ExpanderThemeData(
type: ExpanderType.caret,
modifier: ExpanderModifier.none,
position: ExpanderPosition.start,
color: Colors.red.shade800,
size: 20,
),
labelStyle: TextStyle(
fontSize: 12,
letterSpacing: 0.1,
),
parentLabelStyle: TextStyle(
fontSize: 16,
letterSpacing: 0.1,
fontWeight: FontWeight.w800,
color: Colors.orange.shade600,
),
iconTheme: IconThemeData(
size: 18,
color: Colors.grey.shade800,
),
colorScheme: ColorScheme.light(
background: Colors.transparent
),
);
return TreeView(
controller: _treeViewController,
allowParentSelect: false,
supportParentDoubleTap: false,
//onExpansionChanged: _expandNodeHandler,
onNodeTap: (key) {
setState(() {
_treeViewController = _treeViewController.copyWith(selectedKey: key);
});
},
theme: _treeViewTheme,
);
}
List<Node> nodeExercises(ExerciseRepository exerciseRepository) {
List<Node> nodes = List<Node>();
List<Exercise> exercises = exerciseRepository.getExerciseList();
String prevDay = "";
Node actualNode;
List<Node> listExercisesPerDay;
exercises.forEach((element) {
Exercise exercise = element;
ExerciseType exerciseType =
exerciseRepository.getExerciseTypeById(exercise.exerciseTypeId);
String actualDay = exercise.dateAdd.year.toString()+"-"+
exercise.dateAdd.month.toString()+"-"+
exercise.dateAdd.day.toString();
if ( prevDay.compareTo(actualDay) != 0) {
listExercisesPerDay = List<Node>();
actualNode =
Node(
label: actualDay,
key: exercise.dateAdd.toString(),
expanded: true,
children: listExercisesPerDay,
icon: NodeIcon(
codePoint: Icons.date_range.codePoint,
color: "blue"
)
);
nodes.add(actualNode);
prevDay = actualDay;
}
String exerciseName = AppLanguage().appLocal == Locale("en") ?
exerciseType.name :
exerciseType.nameTranslation;
String unitQuantity = exerciseType.unitQuantity == "1" ?
exercise.unitQuantity.toStringAsFixed(0)
+ " " + AppLocalizations.of(context).translate(exerciseType.unitQuantityUnit) + " "
: "";
String labelExercise =
exerciseName + " " + unitQuantity
+ exercise.quantity.toStringAsFixed(0) + " "
+ AppLocalizations.of(context).translate(exercise.unit);
listExercisesPerDay.add(
Node(
label: labelExercise,
key: exercise.exerciseId.toString(),
expanded: false,
icon: NodeIcon(
codePoint: Icons.repeat.codePoint,
color: "blue"
)
)
);
});
return nodes;
}
}

View File

@ -0,0 +1,196 @@
import 'dart:collection';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/widgets/app_bar_common.dart';
import 'package:aitrainer_app/widgets/bottom_nav.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class MyExercisePlanPage extends StatefulWidget {
@override
_MyExercisePlanPage createState() => _MyExercisePlanPage();
}
class _MyExercisePlanPage extends State<MyExercisePlanPage> {
@override
Widget build(BuildContext context) {
final ExerciseRepository exerciseRepository = ExerciseRepository();
final LinkedHashMap args = LinkedHashMap();
return Scaffold(
appBar: AppBarCommonNav(),
body: Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_light_background.png'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
child: CustomScrollView(
scrollDirection: Axis.vertical,
slivers:
[
SliverGrid(
delegate: SliverChildListDelegate(
[
FlatButton(
padding: EdgeInsets.all(10),
textColor: Colors.white,
color: Colors.black12,
focusColor: Colors.blueAccent,
onPressed: () =>
{
args['customerId'] = Cache().userLoggedIn.customerId,
Navigator.of(context).pushNamed('exerciseByPlanPage',
arguments: args)
},
child: Text("Execute My Selected Training Plan",
style: TextStyle(fontSize: 18),)
),
FlatButton(
padding: EdgeInsets.all(0),
textColor: Colors.white,
color: Colors.black12,
focusColor: Colors.blueAccent,
onPressed: () =>
{
args['exerciseRepository'] = exerciseRepository,
args['customerId'] = Cache().userLoggedIn.customerId,
Navigator.of(context).pushNamed('exercisePlanCustomPage',
arguments: args)
},
child: Text("Edit My Custom Plan",
style: TextStyle(fontSize: 18),)
),
FlatButton(
padding: EdgeInsets.all(20),
textColor: Colors.white,
color: Colors.black12,
focusColor: Colors.blueAccent,
onPressed: () =>
{
},
child: Text("Suggested Plan",
style: TextStyle(fontSize: 18),)
),
Stack(
fit: StackFit.passthrough,
overflow: Overflow.clip,
alignment: Alignment.topLeft,
children: [
Image.asset('asset/image/lock.png',
height: 40,
width: 40,
),
FlatButton(
padding: EdgeInsets.all(20),
textColor: Colors.white,
color: Colors.black12,
focusColor: Colors.blueAccent,
onPressed: () =>
{
},
child: Text("My Special Plan",
style: TextStyle(fontSize: 18),)
),
],
),
Stack(
fit: StackFit.passthrough,
overflow: Overflow.clip,
children: [
Image.asset('asset/image/lock.png',
height: 40,
width: 40,
),
FlatButton(
padding: EdgeInsets.all(20),
textColor: Colors.white,
color: Colors.black12,
focusColor: Colors.blueAccent,
onPressed: () =>
{
},
child: Text("My Arnold's Plan",
style: TextStyle(fontSize: 18),)
),
]
),
hiddenPlanWidget(exerciseRepository),
hiddenTrainingWidget(),
]
),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 20.0,
crossAxisSpacing: 20.0,
childAspectRatio: 1.2,
),
)
]
)
),
bottomNavigationBar: BottomNavigator(bottomNavIndex: 2));
}
Widget hiddenPlanWidget(ExerciseRepository exerciseRepository) {
final LinkedHashMap args = LinkedHashMap();
if ( Cache().getTrainee() != null ) {
return FlatButton(
padding: EdgeInsets.all(20),
textColor: Colors.white,
color: Colors.black12,
focusColor: Colors.blueAccent,
onPressed: () =>
{
args['exerciseRepository'] = exerciseRepository,
args['customerId'] = Cache().getTrainee().customerId,
Navigator.of(context).pushNamed('exercisePlanCustomPage',
arguments: args)
},
child: Text("My Trainee's Plan",
style: TextStyle(fontSize: 18),)
);
} else {
return Container();
}
}
Widget hiddenTrainingWidget() {
final LinkedHashMap args = LinkedHashMap();
if ( Cache().getTrainee() != null ) {
print ("!!Trainee: " + Cache().getTrainee().firstname + " " + Cache().getTrainee().name);
return FlatButton(
padding: EdgeInsets.all(20),
textColor: Colors.white,
color: Colors.black12,
focusColor: Colors.blueAccent,
onPressed: () =>
{
args['customerId'] = Cache().getTrainee().customerId,
Navigator.of(context).pushNamed('exerciseByPlanPage',
arguments: args)
},
child: Text("Execute My Trainee's Training Plan",
style: TextStyle(fontSize: 18),)
);
} else {
return Container();
}
}
}

View File

@ -109,6 +109,13 @@ class SettingsPage extends StatelessWidget{
)
),
ListTile(
leading: Icon(Icons.get_app),
title: RaisedButton(
child: Text("Check lang", style: TextStyle(fontSize: 12),),
onPressed: () => settingsBloc.add(SettingsGetLanguage()),
)
)
]
);
}

View File

@ -56,14 +56,15 @@ class _AppBarNav extends State<AppBarNav> with SingleTickerProviderStateMixin {
}
}); */
colorAnim = RainbowColorTween([Colors.white70,
Colors.greenAccent,
Colors.lightGreen,
Colors.lightGreenAccent,
Colors.yellow,
Colors.blueGrey,
Colors.blueAccent,
Colors.lightBlue,
Colors.lightBlueAccent,
Colors.yellowAccent,
Colors.orange,
Colors.orangeAccent,
Colors.white70])
Colors.yellowAccent,
Color(0xffcce6ff)])
.animate(colorController)
..addListener(() { setState(() {}); })
..addStatusListener((status) {
@ -103,7 +104,9 @@ class _AppBarNav extends State<AppBarNav> with SingleTickerProviderStateMixin {
icon: Icon(Icons.arrow_back, color: Colors.white),
onPressed: () =>
{
menuBloc.add(MenuTreeUp(parent: 0))
if ( menuBloc != null ) {
menuBloc.add(MenuTreeUp(parent: 0)),
}
},
)
);
@ -151,7 +154,7 @@ class _AppBarNav extends State<AppBarNav> with SingleTickerProviderStateMixin {
trailing: Icon(percent > 0.6 ? Icons.mood : Icons.mood_bad, color: colorAnim.value,),
linearStrokeCap: LinearStrokeCap.roundAll,
backgroundColor: colorAnim.value,
progressColor: Colors.blue,
progressColor: Color(0xff73e600),
animation: true,
),
],

View File

@ -0,0 +1,133 @@
import 'dart:async';
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:percent_indicator/linear_percent_indicator.dart';
import 'package:rainbow_color/rainbow_color.dart';
class AppBarCommonNav extends StatefulWidget implements PreferredSizeWidget {
@override
_AppBarCommonNav createState() => _AppBarCommonNav();
@override
Size get preferredSize => const Size.fromHeight(60);
}
class _AppBarCommonNav extends State<AppBarCommonNav> with SingleTickerProviderStateMixin {
Animation<Color> colorAnim;
AnimationController colorController;
@override
void initState() {
colorController =
AnimationController(duration: Duration(seconds: 4), vsync: this);
colorAnim = RainbowColorTween([Colors.white70,
Colors.blueGrey,
Colors.blueAccent,
Colors.lightBlue,
Colors.lightBlueAccent,
Colors.yellowAccent,
Colors.orange,
Colors.orangeAccent,
Colors.yellowAccent,
Color(0xffcce6ff)])
.animate(colorController)
..addListener(() { setState(() {}); })
..addStatusListener((status) {
if (status == AnimationStatus.completed) {
Timer(Duration(seconds: 10), () {
//colorController.reset();
if ( mounted ) {
colorController.forward();
}
});
} else if (status == AnimationStatus.dismissed) {
colorController.forward();
}
});
colorController.forward();
super.initState();
}
@override
Widget build(BuildContext context) {
return AppBar(
backgroundColor: Colors.black,
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
getAnimatedWidget(),
Image.asset(
'asset/image/WT_long_logo.png',
fit: BoxFit.cover,
height: 65.0,
),
],
),
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colors.white),
onPressed: () =>
{
Navigator.of(context).pop()
},
)
);
}
@override
void dispose() {
//sizeController.dispose();
colorController.dispose();
super.dispose();
}
Widget getAnimatedWidget() {
double percent = Cache().getPercentExercises();
if ( percent == -1) {
ExerciseRepository exerciseRepository = ExerciseRepository();
exerciseRepository.getBaseExerciseFinishedPercent();
percent = Cache().getPercentExercises();
}
int sizeExerciseList = Cache().getExercises() == null? 0 : Cache().getExercises().length;
if ( sizeExerciseList == 0 ) {
return Stack(
alignment: Alignment.topLeft,
children: [
Text(AppLocalizations.of(context).translate("Make your first test"),
style: TextStyle(fontSize: 16, color: colorAnim.value, shadows: [Shadow(color: Colors.purple , blurRadius: 15)]),
),
//TestProgress(animation: sizeAnim),
]
);
} else {
return Stack(
alignment: Alignment.topLeft,
children: [
LinearPercentIndicator(
width: 120.0,
lineHeight: 14.0,
percent: percent,
center: Text(
(percent * 100).toStringAsFixed(0) + "% finished",
style: new TextStyle(fontSize: 12.0),
),
trailing: Icon(percent > 0.6 ? Icons.mood : Icons.mood_bad, color: colorAnim.value,),
linearStrokeCap: LinearStrokeCap.roundAll,
backgroundColor: colorAnim.value,
progressColor: Color(0xff73e600),
animation: true,
),
],
);
}
}
}

View File

@ -91,12 +91,13 @@ class _NawDrawerWidget extends State<BottomNavigator> {
break;
case 1:
Navigator.of(context).pop();
Navigator.of(context).pushNamed('mydevelopment');
//Navigator.of(context).pop();
Navigator.of(context).pushNamed('myDevelopment');
break;
case 2:
//throw new StateError('This is a Dart exception on event.');
//Navigator.of(context).pop();
Navigator.of(context).pushNamed('myExercisePlan');
break;
case 3:

View File

@ -24,7 +24,6 @@ class AitrainerHome extends StatefulWidget {
class _HomePageState extends State<AitrainerHome> {
GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
final AppLanguage appLanguage = AppLanguage();
@override
void initState() {
@ -45,7 +44,9 @@ class _HomePageState extends State<AitrainerHome> {
sessionBloc.add(SessionStart());
// ignore: close_sinks
SettingsBloc settingsBloc = BlocProvider.of<SettingsBloc>(context);
settingsBloc.loadLang();
String lang = AppLanguage().appLocal.languageCode;
print (" -- Loading delayed lang $lang");
settingsBloc.add(SettingsChangeLanguage(language: lang));
}
}
});

View File

@ -6,8 +6,8 @@ class LoadingScreenMain extends StatelessWidget {
Widget build(BuildContext context) {
Image _backgroundImage = Image.asset('asset/image/WT01_loading_layers.png',
fit: BoxFit.cover,
//height: double.infinity,
//width: double.infinity,
height: double.infinity,
width: double.infinity,
alignment: Alignment.center,
);
return Scaffold(

View File

@ -37,7 +37,7 @@ class MenuPageWidget extends StatelessWidget {
child: Center(
child: Stack(
alignment: Alignment.bottomLeft,
fit: StackFit.loose,
clipBehavior: Clip.antiAliasWithSaveLayer,
children: [
FlatButton(
child: _getButtonImage(workoutTree),
@ -45,21 +45,35 @@ class MenuPageWidget extends StatelessWidget {
shape: getShape(workoutTree),
onPressed: () => menuClick(workoutTree, menuBloc, context),
),
InkWell(
onTap:() => menuClick(workoutTree, menuBloc, context),
child: Text(
" " + workoutTree.name,
maxLines: 2,
style: TextStyle(
color: workoutTree.color,
fontSize: workoutTree.fontSize,
fontFamily: 'Arial',
fontWeight: FontWeight.w900),
Positioned(
top: workoutTree.name.length > 30 ? 140 : 150,
left: 5,
child: Container(
height: 300,
width: 280,
child: InkWell(
onTap:() => menuClick(workoutTree, menuBloc, context),
child: Text(
" " + workoutTree.name,
maxLines: 2,
style: TextStyle(
color: workoutTree.color,
fontSize: workoutTree.fontSize,
fontFamily: 'Arial',
fontWeight: FontWeight.w900),
),
highlightColor: workoutTree.color,
),
color: Colors.transparent,
),
highlightColor: workoutTree.color,
),
]))));
]
)
)
)
);
});
SliverList sliverList =

View File

@ -1,888 +0,0 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
_fe_analyzer_shared:
dependency: transitive
description:
name: _fe_analyzer_shared
url: "https://pub.dartlang.org"
source: hosted
version: "7.0.0"
analyzer:
dependency: transitive
description:
name: analyzer
url: "https://pub.dartlang.org"
source: hosted
version: "0.39.17"
archive:
dependency: transitive
description:
name: archive
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.13"
args:
dependency: transitive
description:
name: args
url: "https://pub.dartlang.org"
source: hosted
version: "1.6.0"
async:
dependency: transitive
description:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.4.1"
bloc:
dependency: transitive
description:
name: bloc
url: "https://pub.dartlang.org"
source: hosted
version: "6.0.3"
bloc_test:
dependency: "direct dev"
description:
name: bloc_test
url: "https://pub.dartlang.org"
source: hosted
version: "7.0.3"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
build:
dependency: transitive
description:
name: build
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
build_config:
dependency: transitive
description:
name: build_config
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.2"
build_daemon:
dependency: transitive
description:
name: build_daemon
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.4"
build_resolvers:
dependency: transitive
description:
name: build_resolvers
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.11"
build_runner:
dependency: "direct dev"
description:
name: build_runner
url: "https://pub.dartlang.org"
source: hosted
version: "1.10.0"
build_runner_core:
dependency: transitive
description:
name: build_runner_core
url: "https://pub.dartlang.org"
source: hosted
version: "5.2.0"
built_collection:
dependency: transitive
description:
name: built_collection
url: "https://pub.dartlang.org"
source: hosted
version: "4.3.2"
built_value:
dependency: transitive
description:
name: built_value
url: "https://pub.dartlang.org"
source: hosted
version: "7.1.0"
charcode:
dependency: transitive
description:
name: charcode
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.3"
checked_yaml:
dependency: transitive
description:
name: checked_yaml
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
cli_util:
dependency: transitive
description:
name: cli_util
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0"
code_builder:
dependency: transitive
description:
name: code_builder
url: "https://pub.dartlang.org"
source: hosted
version: "3.4.1"
collection:
dependency: transitive
description:
name: collection
url: "https://pub.dartlang.org"
source: hosted
version: "1.14.12"
convert:
dependency: transitive
description:
name: convert
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
coverage:
dependency: transitive
description:
name: coverage
url: "https://pub.dartlang.org"
source: hosted
version: "0.13.11"
crypto:
dependency: transitive
description:
name: crypto
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.4"
csslib:
dependency: transitive
description:
name: csslib
url: "https://pub.dartlang.org"
source: hosted
version: "0.16.2"
cupertino_icons:
dependency: "direct main"
description:
name: cupertino_icons
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.3"
dart_style:
dependency: transitive
description:
name: dart_style
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.6"
devicelocale:
dependency: "direct main"
description:
name: devicelocale
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.1"
equatable:
dependency: "direct main"
description:
name: equatable
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.4"
file:
dependency: transitive
description:
name: file
url: "https://pub.dartlang.org"
source: hosted
version: "5.1.0"
fixnum:
dependency: transitive
description:
name: fixnum
url: "https://pub.dartlang.org"
source: hosted
version: "0.10.11"
flutter:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_bloc:
dependency: "direct main"
description:
name: flutter_bloc
url: "https://pub.dartlang.org"
source: hosted
version: "6.0.4"
flutter_driver:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
flutter_facebook_login:
dependency: "direct main"
description:
name: flutter_facebook_login
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0"
flutter_form_bloc:
dependency: "direct main"
description:
name: flutter_form_bloc
url: "https://pub.dartlang.org"
source: hosted
version: "0.19.0"
flutter_keyboard_visibility:
dependency: transitive
description:
name: flutter_keyboard_visibility
url: "https://pub.dartlang.org"
source: hosted
version: "3.2.2"
flutter_launcher_icons:
dependency: "direct dev"
description:
name: flutter_launcher_icons
url: "https://pub.dartlang.org"
source: hosted
version: "0.7.5"
flutter_local_notifications:
dependency: "direct main"
description:
name: flutter_local_notifications
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.1"
flutter_local_notifications_platform_interface:
dependency: transitive
description:
name: flutter_local_notifications_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
flutter_localizations:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_test:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
flutter_treeview:
dependency: "direct main"
description:
name: flutter_treeview
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.0+1"
flutter_web_plugins:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
form_bloc:
dependency: transitive
description:
name: form_bloc
url: "https://pub.dartlang.org"
source: hosted
version: "0.19.1"
freezed:
dependency: "direct main"
description:
name: freezed
url: "https://pub.dartlang.org"
source: hosted
version: "0.11.6"
freezed_annotation:
dependency: transitive
description:
name: freezed_annotation
url: "https://pub.dartlang.org"
source: hosted
version: "0.11.0+1"
fuchsia_remote_debug_protocol:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
glob:
dependency: transitive
description:
name: glob
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
gradient_bottom_navigation_bar:
dependency: "direct main"
description:
name: gradient_bottom_navigation_bar
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0+4"
graphs:
dependency: transitive
description:
name: graphs
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0"
html:
dependency: transitive
description:
name: html
url: "https://pub.dartlang.org"
source: hosted
version: "0.14.0+3"
http:
dependency: "direct dev"
description:
name: http
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.1"
http_multi_server:
dependency: transitive
description:
name: http_multi_server
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.0"
http_parser:
dependency: transitive
description:
name: http_parser
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.4"
image:
dependency: transitive
description:
name: image
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.12"
intl:
dependency: "direct dev"
description:
name: intl
url: "https://pub.dartlang.org"
source: hosted
version: "0.16.1"
io:
dependency: transitive
description:
name: io
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.4"
js:
dependency: transitive
description:
name: js
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.2"
json_annotation:
dependency: transitive
description:
name: json_annotation
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
json_rpc_2:
dependency: transitive
description:
name: json_rpc_2
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
logging:
dependency: transitive
description:
name: logging
url: "https://pub.dartlang.org"
source: hosted
version: "0.11.4"
matcher:
dependency: transitive
description:
name: matcher
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.6"
meta:
dependency: transitive
description:
name: meta
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.8"
mime:
dependency: transitive
description:
name: mime
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.7"
mockito:
dependency: "direct main"
description:
name: mockito
url: "https://pub.dartlang.org"
source: hosted
version: "4.1.1"
multi_server_socket:
dependency: transitive
description:
name: multi_server_socket
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
nested:
dependency: transitive
description:
name: nested
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.4"
node_interop:
dependency: transitive
description:
name: node_interop
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.1"
node_io:
dependency: transitive
description:
name: node_io
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.1"
node_preamble:
dependency: transitive
description:
name: node_preamble
url: "https://pub.dartlang.org"
source: hosted
version: "1.4.12"
package_config:
dependency: transitive
description:
name: package_config
url: "https://pub.dartlang.org"
source: hosted
version: "1.9.3"
path:
dependency: transitive
description:
name: path
url: "https://pub.dartlang.org"
source: hosted
version: "1.6.4"
path_provider_linux:
dependency: transitive
description:
name: path_provider_linux
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.1+2"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
pedantic:
dependency: transitive
description:
name: pedantic
url: "https://pub.dartlang.org"
source: hosted
version: "1.9.0"
percent_indicator:
dependency: "direct main"
description:
name: percent_indicator
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.5"
petitparser:
dependency: transitive
description:
name: petitparser
url: "https://pub.dartlang.org"
source: hosted
version: "2.4.0"
platform:
dependency: transitive
description:
name: platform
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.1"
plugin_platform_interface:
dependency: transitive
description:
name: plugin_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
pool:
dependency: transitive
description:
name: pool
url: "https://pub.dartlang.org"
source: hosted
version: "1.4.0"
process:
dependency: transitive
description:
name: process
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.12"
provider:
dependency: "direct dev"
description:
name: provider
url: "https://pub.dartlang.org"
source: hosted
version: "4.3.2+1"
pub_semver:
dependency: transitive
description:
name: pub_semver
url: "https://pub.dartlang.org"
source: hosted
version: "1.4.4"
pubspec_parse:
dependency: transitive
description:
name: pubspec_parse
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.5"
quiver:
dependency: transitive
description:
name: quiver
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.3"
rainbow_color:
dependency: "direct main"
description:
name: rainbow_color
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.1"
rainbow_vis:
dependency: transitive
description:
name: rainbow_vis
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
rxdart:
dependency: transitive
description:
name: rxdart
url: "https://pub.dartlang.org"
source: hosted
version: "0.24.1"
sentry:
dependency: "direct main"
description:
name: sentry
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
shared_preferences:
dependency: "direct dev"
description:
name: shared_preferences
url: "https://pub.dartlang.org"
source: hosted
version: "0.5.10"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.2+2"
shared_preferences_macos:
dependency: transitive
description:
name: shared_preferences_macos
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.1+10"
shared_preferences_platform_interface:
dependency: transitive
description:
name: shared_preferences_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.4"
shared_preferences_web:
dependency: transitive
description:
name: shared_preferences_web
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.2+7"
shelf:
dependency: transitive
description:
name: shelf
url: "https://pub.dartlang.org"
source: hosted
version: "0.7.9"
shelf_packages_handler:
dependency: transitive
description:
name: shelf_packages_handler
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
shelf_static:
dependency: transitive
description:
name: shelf_static
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.8"
shelf_web_socket:
dependency: transitive
description:
name: shelf_web_socket
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.3"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.99"
source_gen:
dependency: transitive
description:
name: source_gen
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.6"
source_map_stack_trace:
dependency: transitive
description:
name: source_map_stack_trace
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
source_maps:
dependency: transitive
description:
name: source_maps
url: "https://pub.dartlang.org"
source: hosted
version: "0.10.9"
source_span:
dependency: transitive
description:
name: source_span
url: "https://pub.dartlang.org"
source: hosted
version: "1.7.0"
spider_chart:
dependency: "direct main"
description:
name: spider_chart
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.5"
stack_trace:
dependency: transitive
description:
name: stack_trace
url: "https://pub.dartlang.org"
source: hosted
version: "1.9.3"
stream_channel:
dependency: transitive
description:
name: stream_channel
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
stream_transform:
dependency: transitive
description:
name: stream_transform
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
string_scanner:
dependency: transitive
description:
name: string_scanner
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.5"
sync_http:
dependency: transitive
description:
name: sync_http
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0"
term_glyph:
dependency: transitive
description:
name: term_glyph
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
test:
dependency: "direct dev"
description:
name: test
url: "https://pub.dartlang.org"
source: hosted
version: "1.14.4"
test_api:
dependency: transitive
description:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.15"
test_core:
dependency: transitive
description:
name: test_core
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.4"
timing:
dependency: transitive
description:
name: timing
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.1+2"
typed_data:
dependency: transitive
description:
name: typed_data
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.6"
usage:
dependency: transitive
description:
name: usage
url: "https://pub.dartlang.org"
source: hosted
version: "3.4.2"
uuid:
dependency: transitive
description:
name: uuid
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.2"
vector_math:
dependency: transitive
description:
name: vector_math
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.8"
vm_service:
dependency: transitive
description:
name: vm_service
url: "https://pub.dartlang.org"
source: hosted
version: "4.2.0"
vm_service_client:
dependency: transitive
description:
name: vm_service_client
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.6+2"
watcher:
dependency: transitive
description:
name: watcher
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.7+15"
web_socket_channel:
dependency: transitive
description:
name: web_socket_channel
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
webdriver:
dependency: transitive
description:
name: webdriver
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.2"
webkit_inspection_protocol:
dependency: transitive
description:
name: webkit_inspection_protocol
url: "https://pub.dartlang.org"
source: hosted
version: "0.7.3"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.0"
xml:
dependency: transitive
description:
name: xml
url: "https://pub.dartlang.org"
source: hosted
version: "3.6.1"
yaml:
dependency: transitive
description:
name: yaml
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.1"
sdks:
dart: ">=2.7.0 <3.0.0"
flutter: ">=1.16.0 <2.0.0"

View File

@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.1.0+12
version: 1.1.0+20
environment:
sdk: ">=2.7.0 <3.0.0"
@ -26,19 +26,19 @@ dependencies:
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.3
devicelocale: ^0.3.1
cupertino_icons: ^1.0.0
devicelocale: ^0.3.2
sentry: ^3.0.1
# firebase_messaging: ^6.0.16
flutter_local_notifications: 1.1.1
flutter_facebook_login: ^3.0.0
flutter_bloc: ^6.0.4
flutter_bloc: ^6.0.5
equatable: ^1.2.4
freezed: ^0.11.6
flutter_form_bloc: ^0.19.0
spider_chart: ^0.1.5
rainbow_color: ^0.1.1
percent_indicator: ^2.1.5
percent_indicator: ^2.1.6
gradient_bottom_navigation_bar: ^1.0.0+4
flutter_treeview: ^0.6.0+1
@ -51,17 +51,16 @@ dev_dependencies:
flutter_driver:
sdk: flutter
test: any
bloc_test: ^7.0.1
bloc_test: ^7.0.3
build_runner:
http: 0.12.1
provider: ^4.3.2+1
intl: 0.16.1
shared_preferences: ^0.5.10
flutter_launcher_icons: ^0.7.5
flutter_launcher_icons: ^0.8.0
flutter_icons:
android: "launcher_icon"
@ -94,6 +93,7 @@ flutter:
- asset/image/WT_weight_loss.png
- asset/image/WT_welcome.png
- asset/image/login_fb.png
- asset/image/lock.png
- asset/menu/1.cardio.png
- asset/menu/1.1.aerob.png
- asset/menu/1.2.anaerob.png

View File

@ -0,0 +1,79 @@
import 'package:aitrainer_app/bloc/account/account_bloc.dart';
import 'package:aitrainer_app/repository/customer_repository.dart';
import 'package:mockito/mockito.dart';
import 'package:test/test.dart' as test;
import 'package:flutter_test/flutter_test.dart';
class MockCustomerRepository extends Mock implements CustomerRepository {
}
void main() {
MockCustomerRepository customerRepository;
AccountBloc accountBloc;
TestWidgetsFlutterBinding.ensureInitialized();
test.setUp(() {
customerRepository = MockCustomerRepository();
accountBloc = AccountBloc(customerRepository: customerRepository);
});
test.tearDown(() {
accountBloc?.close();
});
test.test('initial state is correct', () {
expect(accountBloc.state, AccountInitial());
});
group('Account', () {
test.test(
'emits [loading, logged in] when the customer clicked login',
() {
final expectedResponse = [
AccountLoading(),
AccountLoggedIn(),
];
//verify(accountBloc.customerRepository.customer == null);
expectLater(
accountBloc, emitsInOrder(expectedResponse),
);
accountBloc.add(AccountLogin());
});
});
test.test(
'emits [loading, logged out] when the customer clicked logout',
() {
final expectedResponse = [
AccountLoading(),
AccountLoggedOut(),
];
expectLater(
accountBloc, emitsInOrder(expectedResponse),
);
accountBloc.add(AccountLogout());
});
test.test(
'emits [loading, logged out] when the customer data changed',
() {
final expectedResponse = [
AccountLoading(),
AccountReady(),
];
expectLater(
accountBloc, emitsInOrder(expectedResponse),
);
accountBloc.add(AccountChangeCustomer());
});
}

View File

@ -0,0 +1,52 @@
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/customer.dart';
import 'package:aitrainer_app/service/customer_service.dart';
import 'package:aitrainer_app/util/env.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
//import 'package:mockito/mockito.dart';
// Create a MockClient using the Mock class provided by the Mockito package.
// Create new instances of this class in each test.
/* class MockClient extends Mock implements CustomerApi {
Future<List<Customer>> getTrainees(int trainerId) async {
if (trainerId == 62) {
List<Customer> list = List<Customer>();
Customer customer1 = Customer(firstname: "Zalán", name: "Boss");
Customer customer2 = Customer(firstname: "Zétény", name: "Boss");
list.add(customer1);
list.add(customer2);
return list;
} else {
throw Exception("No trainees found");
}
}
} */
main() {
setUp(() {
Cache().setTestBaseUrl();
});
group('fetchPost', () {
test('returns a List<Customer> if the http call completes successfully', () async {
final client = CustomerApi();
// Use Mockito to return a successful response when it calls the
// provided http.Client.
List<Customer> trainees = List<Customer>();
trainees = await client.getTrainees(62);
expect(trainees.length, 2);
expect(trainees[0].firstname, "Zalán");
});
test('throws an exception if the http call completes with an error', () async {
final client = CustomerApi();
expect(client.getTrainees(22), throwsException);
});
});
}

View File

@ -0,0 +1,72 @@
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/exercise_plan.dart';
import 'package:aitrainer_app/model/exercise_plan_detail.dart';
import 'package:aitrainer_app/service/exercise_plan_service.dart';
import 'package:test/test.dart';
main() {
setUp(() {
Cache().setTestBaseUrl();
});
group('new Plan', () {
test('add new plan and plan details', () async {
final client = ExercisePlanApi();
ExercisePlan exercisePlan = ExercisePlan(
"Test plan " + DateTime.now().toIso8601String(),
62
);
exercisePlan.dateAdd = DateTime.now();
ExercisePlan savedPlan = await client.saveExercisePlan(exercisePlan);
expect(savedPlan.name.substring(0, 9), "Test plan");
expect(savedPlan.customerId, 62);
int newPlanId = savedPlan.exercisePlanId;
//savedPlan.exercisePlanId = newPlanId;
ExercisePlanDetail detail = ExercisePlanDetail(
39 //exerciseTypeId
);
detail.serie = 3;
detail.repeats = 12;
detail.weightEquation = "90";
detail.exercisePlanId = newPlanId;
ExercisePlanDetail savedDetail = await client.saveExercisePlanDetail(detail);
expect(savedDetail.weightEquation, "90");
expect(savedDetail.repeats, 12);
expect(savedDetail.exercisePlanId, newPlanId);
await client.deleteExercisePlanDetail(savedDetail.exercisePlanDetailId);
await client.deleteExercisePlan(savedPlan.exercisePlanId);
});
});
test('get the last plan and change plan details', () async {
final client = ExercisePlanApi();
ExercisePlan exercisePlan = await client.getLastExercisePlan(61);
List<ExercisePlanDetail> list = await client.getExercisePlanDetail(exercisePlan.exercisePlanId);
expect(list.length, 2);
ExercisePlanDetail detail = ExercisePlanDetail(3);
detail.serie = 4;
detail.repeats = 12;
detail.weightEquation = "10";
detail.exercisePlanId = exercisePlan.exercisePlanId;
//list.add(detail);
ExercisePlanDetail newObjectToSave = await client.saveExercisePlanDetail(detail);
List<ExercisePlanDetail> list2 = await client.getExercisePlanDetail(exercisePlan.exercisePlanId);
expect(list2.length, 3);
expect(list2.last.weightEquation, "10");
await client.deleteExercisePlanDetail(newObjectToSave.exercisePlanDetailId);
});
}