wt1.1.2 new treeview, bar chart for muscle development

This commit is contained in:
Bossanyi Tibor
2020-09-27 18:42:28 +02:00
parent 4a193e085f
commit 89c06123d2
43 changed files with 2135 additions and 514 deletions
+30 -29
View File
@@ -3,7 +3,7 @@ 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/model/workout_tree.dart';
import 'package:aitrainer_app/model/workout_menu_tree.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/splash.dart';
@@ -25,7 +25,7 @@ class _ExerciseAddByPlanPage extends State<ExerciseAddByPlanPage> with Trans {
// ignore: close_sinks
final ExerciseByPlanBloc bloc = arguments['blocExerciseByPlan'];
final int customerId = arguments['customerId'];
final WorkoutTree workoutTree = arguments['workoutTree'];
final WorkoutMenuTree workoutTree = arguments['workoutTree'];
final ExerciseRepository exerciseRepository = ExerciseRepository();
setContext(context);
@@ -136,38 +136,15 @@ class _ExerciseAddByPlanPage extends State<ExerciseAddByPlanPage> with Trans {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Divider(color: Colors.transparent,),
Text("Execute the " + (i+1).toString() + ". set!",
Text(t("Execute the") + " " + (i+1).toString() + t(". 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: t("The number of the exercise"),
labelStyle: TextStyle(fontSize: 12, color: Colors.deepOrange, fontWeight: FontWeight.normal),
labelText: t("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,
fontSize: 18,
color: Colors.black54,
fontWeight: FontWeight.bold),
inputFormatters: [
@@ -178,11 +155,35 @@ class _ExerciseAddByPlanPage extends State<ExerciseAddByPlanPage> with Trans {
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),
fontSize: 14, color: Colors.black54, fontWeight: FontWeight.w100),
labelStyle: TextStyle(fontSize: 14, color: Colors.deepOrange, fontWeight: FontWeight.normal),
labelText: exerciseBloc.exerciseRepository.exerciseType.unitQuantityUnit,
),
),
TextFieldBlocBuilder(
readOnly: exerciseBloc.step != i+1,
textFieldBloc: exerciseBloc.quantity1Field,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 18,
color: Colors.deepOrange,
fontWeight: FontWeight.bold),
inputFormatters: [
WhitelistingTextInputFormatter(RegExp(r"[\d.]"))
],
decoration: InputDecoration(
fillColor: Colors.white,
filled: false,
hintStyle: TextStyle(
fontSize: 14, color: Colors.black54, fontWeight: FontWeight.w100),
hintText: t("The number of the exercise"),
labelStyle: TextStyle(fontSize: 14, color: Colors.deepOrange, fontWeight: FontWeight.normal),
labelText: t("Please repeat with") + " "+ exerciseBloc.unitQuantity1Field.value + " " +
exerciseBloc.exerciseRepository.exerciseType.unitQuantityUnit + " " +
exerciseBloc.exercisePlanRepository.getActualPlanDetail().repeats.toString() + " " + t("times!"),
),
),
RaisedButton(
padding: EdgeInsets.all(0),
+146 -118
View File
@@ -1,23 +1,25 @@
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/model/workout_menu_tree.dart';
import 'package:aitrainer_app/treeview/tree_view.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar_common.dart';
import 'package:aitrainer_app/widgets/bottom_nav.dart';
import 'package:aitrainer_app/widgets/exercise_type_widget.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> {
class _ExerciseByPlanPage extends State<ExerciseByPlanPage> with Trans {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
// ignore: close_sinks
ExerciseByPlanBloc bloc;
@@ -38,21 +40,24 @@ class _ExerciseByPlanPage extends State<ExerciseByPlanPage> {
final int customerId = arguments['customerId'];
bloc = BlocProvider.of<ExerciseByPlanBloc>(context);
bloc.customerId = customerId;
setContext(context);
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,
),
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) {
),
child: BlocConsumer<ExerciseByPlanBloc, ExerciseByPlanState>(
listener: (context, state) {
if (state is ExerciseByPlanError) {
Scaffold.of(context).showSnackBar(SnackBar(
content: Text(
@@ -64,124 +69,147 @@ class _ExerciseByPlanPage extends State<ExerciseByPlanPage> {
LoadingDialog();
}
},
// ignore: missing_return
builder: (context, state) {
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) {
} else {
return exerciseWidget(bloc);
}
})));
})),
bottomNavigationBar: BottomNavigator(bottomNavIndex: 2),
);
}
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,
return TreeView(
startExpanded: false,
children: nodeExercisePlan(bloc),
);
}
List<Node> nodeExercisePlan(ExerciseByPlanBloc bloc) {
List<Node> nodes = List<Node>();
Node actualNode;
List<Widget> nodeExercisePlan(ExerciseByPlanBloc bloc) {
List<Widget> exerciseTypes = List();
bool isEnglish = AppLanguage().appLocal == Locale("en");
Card explanation = Card(
color: Colors.white38,
child: Container(
padding: EdgeInsets.only(left: 10, right: 5, top: 12, bottom: 8),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Row(
children: [
Icon(
Icons.info,
color: Colors.orangeAccent,
),
Text(" "),
Flexible(
child:
Text(
t("Execute your active Exercise Plan!"),
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
),
],
),
Divider(
color: Colors.transparent,
),
Text(
t("Select the muscle type and tap on the exercise. One the next page enter the weight and repeat."),
style: TextStyle(fontSize: 12, fontWeight: FontWeight.normal),
),
],
)));
exerciseTypes.add(explanation);
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);
}
exerciseTypes.add(
Container(
margin: const EdgeInsets.only(left: 4.0),
child: TreeViewChild(
startExpanded: true,
parent: ExerciseTypeWidget(exerciseTypeName: name), //_getExerciseWidget(exerciseTypeName: name),
children: _getChildList(list, bloc),
)));
});
return nodes;
return exerciseTypes;
}
List<Widget> _getChildList(List<WorkoutMenuTree> listWorkoutTree, ExerciseByPlanBloc bloc) {
List<Widget> list = List();
listWorkoutTree.forEach((element) {
if ( element.selected) {
list.add(
TreeViewChild(
startExpanded: false,
parent:
Card(
margin: EdgeInsets.only(left: 10, top: 5),
color: Colors.white54,
child: Container(
padding: const EdgeInsets.only(left: 5, top: 0, right: 5, bottom: 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
IconButton(
icon: element.executed ? Icon(Icons.check_box, color: Colors.green):
Icon(Icons.indeterminate_check_box, color: Colors.blue.shade800,),
onPressed: () => {
addExerciseByPlanEvent(bloc, element)
},
),
SizedBox(width: 20),
Flexible(
child:
InkWell(
child:
Text(
element.name,
textAlign: TextAlign.start,
style: TextStyle(fontSize: 12, color: Colors.black),
),
onTap: () => {
addExerciseByPlanEvent(bloc, element)
},
),
),
IconButton(
padding: EdgeInsets.all(0),
icon: Icon(Icons.description, color: Colors.black12,),
onPressed: () {
},
),
]),
)
),
children: [
]
)
);
}
});
return list;
}
void addExerciseByPlanEvent(ExerciseByPlanBloc bloc, WorkoutMenuTree workoutTree) {
LinkedHashMap args = LinkedHashMap();
args['blocExerciseByPlan'] = bloc;
args['customerId'] = bloc.customerId;
args['workoutTree'] = workoutTree;
Navigator.of(context).pushNamed("exerciseAddByPlanPage", arguments: args);
}
}
-2
View File
@@ -4,7 +4,6 @@ import 'package:aitrainer_app/localization/app_language.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/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar_common.dart';
@@ -21,7 +20,6 @@ class _ExerciseLogPage extends State<ExerciseLogPage> with Trans {
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'];
setContext(context);
@@ -2,6 +2,7 @@ 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/model/exercise_plan_detail.dart';
import 'package:aitrainer_app/repository/exercise_plan_repository.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar_common.dart';
@@ -34,8 +35,8 @@ class _ExercisePlanDetailAddPage extends State<ExercisePlanDetailAddPage> with T
String exerciseName = "";
if (bloc != null) {
exerciseName = AppLanguage().appLocal == Locale("en")
? bloc.exercisePlanRepository.actualPlanDetail.exerciseType.name
: bloc.exercisePlanRepository.actualPlanDetail.exerciseType.nameTranslation;
? bloc.exercisePlanRepository.getActualPlanDetail().exerciseType.name
: bloc.exercisePlanRepository.getActualPlanDetail().exerciseType.nameTranslation;
}
return Form(
@@ -118,9 +119,10 @@ class _ExercisePlanDetailAddPage extends State<ExercisePlanDetailAddPage> with T
color: Colors.red.shade300,
focusColor: Colors.white,
onPressed: () => {
print("Remove " + bloc.exercisePlanRepository.actualPlanDetail.exerciseType.name),
print("Remove " + bloc.exercisePlanRepository.getActualPlanDetail().exerciseType.name),
bloc.exercisePlanRepository.getActualPlanDetail().change = ExercisePlanDetailChange.delete,
planBloc.add(ExercisePlanRemoveExercise(
exercisePlanDetail: bloc.exercisePlanRepository.actualPlanDetail)),
exercisePlanDetail: bloc.exercisePlanRepository.getActualPlanDetail() )),
Navigator.of(context).pop(),
},
child: Text(t(
+148 -123
View File
@@ -1,24 +1,26 @@
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/model/workout_menu_tree.dart';
import 'package:aitrainer_app/treeview/tree_view.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar_common.dart';
import 'package:aitrainer_app/widgets/bottom_nav.dart';
import 'package:aitrainer_app/widgets/exercise_type_widget.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> {
class _ExercisePlanCustomPage extends State<ExercisePlanCustomPage> with Trans {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
// ignore: close_sinks
ExercisePlanBloc bloc;
@@ -36,10 +38,10 @@ class _ExercisePlanCustomPage extends State<ExercisePlanCustomPage> {
@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;
setContext(context);
return Scaffold(
key: _scaffoldKey,
@@ -54,135 +56,158 @@ class _ExercisePlanCustomPage extends State<ExercisePlanCustomPage> {
alignment: Alignment.center,
),
),
child: BlocConsumer<ExercisePlanBloc, ExercisePlanState>(listener: (context, state) {
if (state is ExercisePlanError) {
Scaffold.of(context).showSnackBar(SnackBar(
content: Text(
state.message,
),
backgroundColor: Colors.orange,
));
} else if (state is ExercisePlanLoading) {
LoadingDialog();
}
},
child: BlocConsumer<ExercisePlanBloc, ExercisePlanState>(
listener: (context, state) {
if (state is ExercisePlanError) {
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) {
builder: (context, state) {
if (state is ExercisePlanReady) {
return exerciseWidget(bloc);
}
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();
}
})));
}
)
),
bottomNavigationBar: BottomNavigator(bottomNavIndex: 2),
);
}
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,
return TreeView(
startExpanded: false,
children: _getTreeChildren(bloc),
);
}
List<Node> nodeExercisePlan(ExercisePlanBloc bloc) {
List<Node> nodes = List<Node>();
Node actualNode;
bool isEnglish = AppLanguage().appLocal == Locale("en");
List<Widget> _getTreeChildren(ExercisePlanBloc bloc) {
List<Widget> exerciseTypes = List();
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;
Card explanation = Card(
color: Colors.white60,
child: Container(
padding: EdgeInsets.only(left: 10, right: 5, top: 12, bottom: 8),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Row(
children: [
Icon(
Icons.info,
color: Colors.orangeAccent,
),
Text(" "),
Text(
t("Custom Exercise Plan"),
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
],
),
Divider(
color: Colors.transparent,
),
Text(
t("Select manually the exercises what you would like to have in your plan. At the end don't forget to save."),
style: TextStyle(fontSize: 12, fontWeight: FontWeight.normal),
),
String exerciseLabel = isEnglish
? treeItem.name
: treeItem.exerciseType == null ? treeItem.name : treeItem.exerciseType.nameTranslation;
],
)
)
);
exerciseTypes.add(explanation);
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);
}
bloc.menuTreeRepository.sortedTree.forEach((name, list) {
exerciseTypes.add(Container(
margin: const EdgeInsets.only(left: 4.0),
child: TreeViewChild(
startExpanded: true,
parent: ExerciseTypeWidget(exerciseTypeName: name),
children: _getChildList(list, bloc),
)));
});
return nodes;
return exerciseTypes;
}
List<Widget> _getChildList(List<WorkoutMenuTree> listWorkoutTree, ExercisePlanBloc bloc) {
List<Widget> list = List();
listWorkoutTree.forEach((element) {
list.add(
TreeViewChild(
startExpanded: false,
parent:
Card(
margin: EdgeInsets.only(left: 10, top: 5),
color: Colors.white54,
child: Container(
padding: const EdgeInsets.only(left: 5, top: 0, right: 5, bottom: 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
IconButton(
icon: element.selected ? Icon(Icons.check, color: Colors.greenAccent.shade700,) : Icon(Icons.add, color: Colors.blue.shade400,),
onPressed: () => {
bloc.add(ExercisePlanUpdateUI(workoutTree: element)),
Navigator.of(context).pushNamed("exercisePlanDetailAdd", arguments: bloc),
},
),
SizedBox(width: 20),
Flexible(
child:
InkWell(
child:
Text(
element.name,
textAlign: TextAlign.start,
style: TextStyle(fontSize: 12, color: Colors.black),
),
onTap: () => {
bloc.add(ExercisePlanUpdateUI(workoutTree: element)),
Navigator.of(context).pushNamed("exercisePlanDetailAdd", arguments: bloc),
},
),
),
InkWell(
child:
element.selected && bloc.exercisePlanRepository.exercisePlanDetails[element.exerciseTypeId].change != null ?
Text(bloc.exercisePlanRepository.exercisePlanDetails[element.exerciseTypeId].repeats.toString() +
" x " + bloc.exercisePlanRepository.exercisePlanDetails[element.exerciseTypeId].weightEquation +
" " + element.exerciseType.unitQuantityUnit, style: TextStyle(fontSize: 9, color: Colors.green),) : Text(""),
onTap: () => {
bloc.add(ExercisePlanUpdateUI(workoutTree: element)),
Navigator.of(context).pushNamed("exercisePlanDetailAdd", arguments: bloc),
},
),
IconButton(
padding: EdgeInsets.all(0),
icon: Icon(Icons.description, color: Colors.black12,),
onPressed: () {
},
),
]),
)
),
children: [
]
)
);
});
return list;
}
}
+322
View File
@@ -0,0 +1,322 @@
import 'dart:collection';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/exercise_type_widget.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:aitrainer_app/util/common.dart';
import 'package:aitrainer_app/bloc/development_by_muscle/development_by_muscle_bloc.dart';
import 'package:aitrainer_app/model/workout_menu_tree.dart';
import 'package:aitrainer_app/treeview/tree_view.dart';
import 'package:aitrainer_app/widgets/app_bar_common.dart';
import 'package:aitrainer_app/widgets/bottom_nav.dart';
import 'package:aitrainer_app/widgets/splash.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_form_bloc/flutter_form_bloc.dart';
class MyDevelopmentMusclePage extends StatefulWidget {
@override
_MyDevelopmentMuscleState createState() => _MyDevelopmentMuscleState();
}
class _MyDevelopmentMuscleState extends State<MyDevelopmentMusclePage> with Common, Trans {
// ignore: close_sinks
DevelopmentByMuscleBloc bloc;
double cWidth;
@override
void initState() {
super.initState();
/// We require the initializers to run after the loading screen is rendered
SchedulerBinding.instance.addPostFrameCallback((_) {
BlocProvider.of<DevelopmentByMuscleBloc>(context).add(DevelopmentByMuscleLoad());
});
}
@override
Widget build(BuildContext context) {
bloc = BlocProvider.of<DevelopmentByMuscleBloc>(context);
cWidth = mediaSizeWidth(context);
setContext(context);
return Scaffold(
appBar: AppBarCommonNav(),
body: Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_menu_dark.png'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
child: BlocConsumer<DevelopmentByMuscleBloc, DevelopmentByMuscleState>(
listener: (context, state) {
if (state is DevelopmentByMuscleErrorState) {
Scaffold.of(context).showSnackBar(SnackBar(
content: Text(
state.message,
),
backgroundColor: Colors.orange,
));
} else if (state is DevelopmentByMuscleLoadingState) {
LoadingDialog();
}
},
builder: (context, state) {
if (state is DevelopmentByMuscleStateInitial) {
return Container();
} else {
return TreeView(
startExpanded: false,
children: _getTreeChildren(bloc.workoutTreeRepository.sortedTree, bloc),
);
}
;
},
),
),
bottomNavigationBar: BottomNavigator(bottomNavIndex: 1),
);
}
List<Widget> _getTreeChildren(SplayTreeMap tree, DevelopmentByMuscleBloc bloc) {
List<Widget> exerciseTypes = List();
Card explanation = Card(
color: Colors.white60,
child: Container(
padding: EdgeInsets.only(left: 10, right: 5, top: 12),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Row(
children: [
Icon(
Icons.info,
color: Colors.orangeAccent,
),
Text(" "),
Text(
t("My Development By Muscle"),
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
],
),
Divider(
color: Colors.transparent,
),
Text(
t("Here you see you development in the last period."),
style: TextStyle(fontSize: 12, fontWeight: FontWeight.normal),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
ChoiceChip(
avatar: Icon(Icons.bubble_chart,),
label: Text(t('Sum Of Mass')),
labelStyle: TextStyle(fontSize: 9,color: Colors.black),
selectedColor: Colors.lightBlueAccent,
selected: bloc.diagramType == DiagramType.sumMass,
onSelected: (value) => {
bloc.add(DevelopmentByMuscleDiagramTypeChange(diagramType: DiagramType.sumMass))
},
),
ChoiceChip(
avatar: Icon(Icons.accessibility_new),
label: Text(t('One Max Rep')),
labelStyle: TextStyle(fontSize: 9,color: Colors.black),
selectedColor: Colors.lightBlueAccent,
selected: bloc.diagramType == DiagramType.oneRepMax,
onSelected: (value) => {
bloc.add(DevelopmentByMuscleDiagramTypeChange(diagramType: DiagramType.oneRepMax))
},
),
ChoiceChip(
avatar: Icon(Icons.perm_device_information),
label: Text(t('Percent')),
labelStyle: TextStyle(fontSize: 9,color: Colors.black),
selectedColor: Colors.lightBlueAccent,
selected: bloc.diagramType == DiagramType.percent,
onSelected: (value) => {
bloc.add(DevelopmentByMuscleDiagramTypeChange(diagramType: DiagramType.percent))
},
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
ChoiceChip(
avatar: Icon(Icons.timer),
label: Text(t('Detailed')),
labelStyle: TextStyle(fontSize: 9, color: Colors.black),
disabledColor: Colors.black26,
selectedColor: Colors.greenAccent,
selected: bloc.dateRate == DateRate.daily,
onSelected: (value) => {
bloc.add(DevelopmentByMuscleDateRateChange(dateRate: DateRate.daily))
},
),
ChoiceChip(
avatar: Icon(Icons.timer),
label: Text(t('Weekly')),
labelStyle: TextStyle(fontSize: 9, color: Colors.black),
selectedColor: Colors.greenAccent,
disabledColor: Colors.white12,
tooltip: "Heti bontás",
selected: bloc.dateRate == DateRate.weekly,
onSelected: (value) => {
bloc.add(DevelopmentByMuscleDateRateChange(dateRate: DateRate.weekly))
},
),
ChoiceChip(
avatar: Icon(Icons.timer),
label: Text(t('Monthly')),
labelStyle: TextStyle(fontSize: 9, color: Colors.black),
selectedColor: Colors.greenAccent,
disabledColor: Colors.black26,
selected: bloc.dateRate == DateRate.monthly,
onSelected: (value) => {
bloc.add(DevelopmentByMuscleDateRateChange(dateRate: DateRate.monthly))
},
),
ChoiceChip(
avatar: Icon(Icons.timer),
label: Text(t('Yearly')),
labelStyle: TextStyle(fontSize: 9, color: Colors.black),
selectedColor: Colors.greenAccent,
disabledColor: Colors.white70,
selected: bloc.dateRate == DateRate.yearly,
onSelected: (value) => {
bloc.add(DevelopmentByMuscleDateRateChange(dateRate: DateRate.yearly))
},
),
],
)
],
)
)
);
exerciseTypes.add(explanation);
tree.forEach((name, list) {
List<WorkoutMenuTree> listWorkoutMenuTree = list;
exerciseTypes.add(Container(
margin: const EdgeInsets.only(left: 4.0),
child: TreeViewChild(
startExpanded: true,
parent: _getExerciseWidget(exerciseTypeName: name),
children: _getChildList(list, bloc),
)));
});
return exerciseTypes;
}
Widget _getExerciseWidget({@required String exerciseTypeName, List<WorkoutMenuTree> list}) {
return ExerciseTypeWidget(exerciseTypeName: exerciseTypeName);
}
List<Widget> _getChildList(List<WorkoutMenuTree> listWorkoutTree, DevelopmentByMuscleBloc bloc) {
List<Widget> list = List();
listWorkoutTree.forEach((element) {
bool hasNoData = (bloc.listChartData[element.exerciseTypeId] == null);
String unit = " kg";
if ( bloc.diagramType == DiagramType.percent) {
unit = " %";
}
list.add(SizedBox(
width: cWidth * 0.85,
height: hasNoData ? 0 : 200,
child: Container(
padding: const EdgeInsets.only(left:5, top:5, right:5, bottom: 5),
color: Colors.white70,
child: Column(mainAxisSize: MainAxisSize.min, children: [
hasNoData
? Container()
: Text(
element.exerciseType.nameTranslation,
style: TextStyle(color: Colors.deepOrange),
),
hasNoData
? Container(
//child: Text("no data for " + element.exerciseType.nameTranslation),
)
: Expanded(
//fit: FlexFit.loose,
child: BarChart(
BarChartData(
alignment: BarChartAlignment.spaceAround,
barTouchData: BarTouchData(
touchTooltipData: BarTouchTooltipData(
tooltipBgColor: Colors.white70,
getTooltipItem: (group, groupIndex, rod, rodIndex) {
return BarTooltipItem(
rod.y.toStringAsFixed(0) + unit,
TextStyle(color: Colors.black54, fontSize: 12, fontWeight: FontWeight.bold),
);
}),
),
titlesData: FlTitlesData(
show: true,
bottomTitles: SideTitles(
showTitles: true,
textStyle: TextStyle(fontSize: 8, color: Colors.blueGrey),
getTitles: (double value) {
var date = new DateTime.fromMillisecondsSinceEpoch(value.toInt());
//String strDate = DateFormat('MM.dd.', AppLanguage().appLocal.toString()).format(date);
String strDate = bloc.getDatePart(date);
return strDate;
},
),
leftTitles: SideTitles(
showTitles: true,
textStyle: TextStyle(fontSize: 8, color: Colors.blueGrey),
interval: bloc.listChartData[element.exerciseTypeId] == null
? 100
: bloc.listChartData[element.exerciseTypeId].interval,
margin: 10,
getTitles: (double value) {
return value.toStringAsFixed(0) + unit;
})),
borderData: FlBorderData(
show: false,
),
gridData: FlGridData(
show: true,
checkToShowHorizontalLine: (value) =>
value % bloc.listChartData[element.exerciseTypeId].gridInterval == 0,
getDrawingHorizontalLine: (value) {
return FlLine(
color: Colors.black26,
strokeWidth: 0.5,
);
},
),
groupsSpace: 2,
barGroups: bloc.listChartData[element.exerciseTypeId] == null
? []
: bloc.listChartData[element.exerciseTypeId].data,
),
swapAnimationDuration: Duration(milliseconds: 1200),
),
)
]),
),
));
});
return list;
}
}
+5 -2
View File
@@ -8,6 +8,7 @@ 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';
import 'package:flutter_bloc/flutter_bloc.dart';
class MyDevelopmentPage extends StatefulWidget {
@override
@@ -84,10 +85,10 @@ class _MyDevelopmentPage extends State<MyDevelopmentPage> with Trans {
fit: StackFit.passthrough,
overflow: Overflow.clip,
children: [
Image.asset('asset/image/lock.png',
/*Image.asset('asset/image/lock.png',
height: 40,
width: 40,
),
),*/
FlatButton(
padding: EdgeInsets.all(20),
textColor: Colors.white,
@@ -95,6 +96,8 @@ class _MyDevelopmentPage extends State<MyDevelopmentPage> with Trans {
focusColor: Colors.blueAccent,
onPressed: () =>
{
Navigator.of(context).pushNamed('mydevelopmentMusclePage',
arguments: args)
},
child: Text(t("Development Of Muscles"),
style: TextStyle(fontSize: 18),)