WT1.1.10 compact test, paralell test
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import 'package:aitrainer_app/bloc/exercise_new/exercise_new_bloc.dart';
|
||||
import 'package:aitrainer_app/library/dropdown_search.dart';
|
||||
import 'package:aitrainer_app/util/app_localization.dart';
|
||||
import 'package:aitrainer_app/model/fitness_state.dart';
|
||||
import 'package:aitrainer_app/util/trans.dart';
|
||||
@@ -8,7 +9,6 @@ import 'package:flutter/widgets.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'app_bar.dart';
|
||||
import 'package:keyboard_actions/keyboard_actions.dart';
|
||||
import 'package:dropdown_search/dropdown_search.dart';
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class BMR extends StatefulWidget {
|
||||
|
||||
@@ -0,0 +1,292 @@
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
|
||||
import 'package:aitrainer_app/bloc/test_set_execute/test_set_execute_bloc.dart';
|
||||
import 'package:aitrainer_app/model/exercise_plan_detail.dart';
|
||||
import 'package:aitrainer_app/model/workout_menu_tree.dart';
|
||||
import 'package:aitrainer_app/util/enums.dart';
|
||||
import 'package:aitrainer_app/util/track.dart';
|
||||
import 'package:aitrainer_app/util/trans.dart';
|
||||
import 'package:aitrainer_app/widgets/dialog_widget.dart';
|
||||
import 'package:aitrainer_app/widgets/menu_search_bar.dart';
|
||||
import 'package:aitrainer_app/widgets/victory_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:modal_progress_hud/modal_progress_hud.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class BottomBarMultipleExercises extends StatefulWidget {
|
||||
bool isSet = false;
|
||||
final List<ExercisePlanDetail> details;
|
||||
int exerciseTypeId;
|
||||
|
||||
BottomBarMultipleExercises({this.details, this.isSet, this.exerciseTypeId});
|
||||
@override
|
||||
_BottomBarMultipleExercisesState createState() => _BottomBarMultipleExercisesState();
|
||||
}
|
||||
|
||||
class _BottomBarMultipleExercisesState extends State<BottomBarMultipleExercises> with Trans {
|
||||
final Color bgrColor = Color(0xffb4f500);
|
||||
final Color bgrColorEnd = Colors.blue;
|
||||
final Color active = Colors.black;
|
||||
final Color inactive = Colors.black26;
|
||||
ScrollController _controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
SchedulerBinding.instance.addPostFrameCallback((_) {
|
||||
_controller = ScrollController();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
setContext(context);
|
||||
// ignore: close_sinks
|
||||
final MenuBloc menuBloc = BlocProvider.of<MenuBloc>(context);
|
||||
// ignore: close_sinks
|
||||
final TestSetExecuteBloc bloc = BlocProvider.of<TestSetExecuteBloc>(context);
|
||||
bloc.menuBloc = menuBloc;
|
||||
bloc.setExerciseTypeId(widget.exerciseTypeId);
|
||||
bloc.add(TestSetExecuteLoad());
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topRight,
|
||||
end: Alignment.bottomLeft,
|
||||
stops: [0.1, 0.99],
|
||||
colors: [
|
||||
bgrColor,
|
||||
bgrColorEnd,
|
||||
],
|
||||
),
|
||||
),
|
||||
height: 90,
|
||||
child: BlocConsumer<TestSetExecuteBloc, TestSetExecuteState>(listener: (context, state) {
|
||||
if (state is TestSetExecuteError) {
|
||||
Scaffold.of(context)
|
||||
.showSnackBar(SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
|
||||
}
|
||||
}, builder: (context, state) {
|
||||
if (state is TestSetExecuteReady && bloc.exercisePlanDetails != null) {
|
||||
print("BottomBarMulti offset ${bloc.scrollOffset}");
|
||||
/* if (bloc.scrollOffset > 0 && _controller != null) {
|
||||
_controller.animateTo(bloc.scrollOffset, duration: Duration(milliseconds: 300), curve: Curves.easeIn);
|
||||
} */
|
||||
}
|
||||
return ModalProgressHUD(
|
||||
child: getWidget(bloc),
|
||||
inAsyncCall: state is TestSetExecuteLoading,
|
||||
opacity: 0.5,
|
||||
color: Colors.black54,
|
||||
progressIndicator: CircularProgressIndicator(),
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
Widget getWidget(TestSetExecuteBloc bloc) {
|
||||
return SingleChildScrollView(
|
||||
controller: _controller,
|
||||
padding: EdgeInsets.only(left: 10, right: 10, bottom: 5),
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Row(
|
||||
children: getChildren(bloc),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> getChildren(TestSetExecuteBloc bloc) {
|
||||
final List<Widget> list = List();
|
||||
if (!widget.isSet && !bloc.hasBegun()) {
|
||||
list.add(GestureDetector(
|
||||
onTap: () => newExercise(bloc),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(24.0),
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(top: 5),
|
||||
height: 60,
|
||||
color: Colors.transparent,
|
||||
child: Image.asset("asset/image/add_test.png"),
|
||||
))));
|
||||
list.add(
|
||||
SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
);
|
||||
if (bloc.isDone100) {
|
||||
Victory();
|
||||
}
|
||||
}
|
||||
|
||||
//if (bloc.miniTestSet && widget.isSet || bloc.paralellTest && !widget.isSet) {
|
||||
if (bloc.exercisePlanDetails != null) {
|
||||
bloc.exercisePlanDetails.forEach((element) {
|
||||
final bool highlighted = element.exerciseTypeId == widget.exerciseTypeId;
|
||||
list.add(getImageStack(element.exerciseType.nameTranslation, bloc, element.exerciseTypeId,
|
||||
bloc.getActualImageName(element.exerciseType.exerciseTypeId),
|
||||
highlighted: highlighted));
|
||||
});
|
||||
// }
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
void newExercise(TestSetExecuteBloc bloc) {
|
||||
HashMap ret = bloc.canAddNewExercise();
|
||||
if (ret['canAdd'] == false) {
|
||||
showCupertinoDialog(
|
||||
useRootNavigator: true,
|
||||
context: context,
|
||||
builder: (_) => CupertinoAlertDialog(
|
||||
insetAnimationDuration: Duration(milliseconds: 500),
|
||||
insetAnimationCurve: Curves.elasticInOut,
|
||||
title: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(12.0),
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: Text(
|
||||
t("You are about to add a new parallel test"),
|
||||
style: GoogleFonts.inter(color: Colors.grey[900]),
|
||||
))),
|
||||
content: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(12.0),
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: Column(children: [
|
||||
Divider(),
|
||||
Text(
|
||||
t(ret['message']),
|
||||
style: GoogleFonts.inter(color: Colors.grey[800]),
|
||||
),
|
||||
Divider(
|
||||
color: Colors.transparent,
|
||||
),
|
||||
Text(
|
||||
ret['message2'],
|
||||
style: GoogleFonts.inter(color: Colors.grey[800]),
|
||||
),
|
||||
]))),
|
||||
actions: [
|
||||
FlatButton(
|
||||
child: Text(t("No")),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
FlatButton(
|
||||
child: Text(t("Yes")),
|
||||
onPressed: () => {
|
||||
Navigator.pop(context),
|
||||
addNewExercise(bloc),
|
||||
},
|
||||
)
|
||||
],
|
||||
));
|
||||
} else {
|
||||
addNewExercise(bloc);
|
||||
}
|
||||
}
|
||||
|
||||
void addNewExercise(TestSetExecuteBloc bloc) {
|
||||
WorkoutMenuTree foundMenuItem;
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return DialogWidget(
|
||||
onTap: () => {
|
||||
if (foundMenuItem != null)
|
||||
{
|
||||
bloc.add(TestSetExecuteDeleteActive()),
|
||||
bloc.add(TestSetExecuteNewExercise(exerciseTypeId: widget.exerciseTypeId)),
|
||||
bloc.add(TestSetExecuteNewExercise(exerciseTypeId: foundMenuItem.exerciseTypeId)),
|
||||
Track().track(TrackingEvent.exercise_new_paralell, eventValue: foundMenuItem.exerciseType.name),
|
||||
},
|
||||
Navigator.pop(context),
|
||||
},
|
||||
title: t("Please select an exercise"),
|
||||
description: t("Add this exercise to execute it paralell"),
|
||||
widget: MenuSearchBar(
|
||||
showIcon: false,
|
||||
onFind: (workoutMenuTree) => foundMenuItem = workoutMenuTree,
|
||||
listItems: bloc.menuBloc.menuTreeRepository.menuAsExercise,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
List<Widget> imageSliders(TestSetExecuteBloc bloc) {
|
||||
List<Widget> list = List();
|
||||
final Widget widget = ClipRRect(
|
||||
borderRadius: BorderRadius.circular(24.0),
|
||||
child: GestureDetector(
|
||||
onTap: () => newExercise(bloc),
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: Image.asset("asset/image/add_test.png"),
|
||||
)));
|
||||
list.add(widget);
|
||||
return list;
|
||||
}
|
||||
|
||||
Widget getImageStack(String imageName, TestSetExecuteBloc bloc, int exerciseTypeId, String image, {highlighted = false}) {
|
||||
return Container(
|
||||
width: 120,
|
||||
child: Stack(alignment: Alignment.bottomLeft, fit: StackFit.loose, children: [
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 0, top: 10),
|
||||
child: Stack(alignment: Alignment.topRight, children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(12.0),
|
||||
child: Container(
|
||||
decoration: highlighted
|
||||
? BoxDecoration(
|
||||
border: Border.all(
|
||||
color: Colors.white,
|
||||
width: 3, //
|
||||
),
|
||||
)
|
||||
: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: Colors.transparent,
|
||||
width: 1, //
|
||||
),
|
||||
),
|
||||
height: 60,
|
||||
//color: Colors.transparent,
|
||||
child: Image.asset(image),
|
||||
)),
|
||||
!widget.isSet && !bloc.hasBegun()
|
||||
? Positioned(
|
||||
top: -8,
|
||||
child: GestureDetector(
|
||||
onTap: () => {
|
||||
print("Delete: $imageName"),
|
||||
bloc.add(TestSetExecuteDeleteExercise(exerciseTypeId: exerciseTypeId)),
|
||||
},
|
||||
child: Text(
|
||||
"X",
|
||||
style: GoogleFonts.archivoBlack(color: Colors.orange[900], fontSize: 20),
|
||||
)))
|
||||
: Offstage(),
|
||||
])),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 10, bottom: 5, right: 5),
|
||||
child: Text(
|
||||
imageName,
|
||||
maxLines: 2,
|
||||
style: GoogleFonts.archivoBlack(color: Color(0xffb4f500), fontSize: 10),
|
||||
),
|
||||
),
|
||||
]));
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:aitrainer_app/library/gradient_bottom_navigation_bar.dart';
|
||||
import 'package:aitrainer_app/util/app_localization.dart';
|
||||
import 'package:aitrainer_app/model/cache.dart';
|
||||
import 'package:aitrainer_app/service/logging.dart';
|
||||
@@ -6,7 +7,6 @@ import 'package:aitrainer_app/util/enums.dart';
|
||||
import 'package:aitrainer_app/util/track.dart';
|
||||
import 'package:aitrainer_app/util/trans.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:gradient_bottom_navigation_bar/gradient_bottom_navigation_bar.dart';
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class BottomNavigator extends StatefulWidget {
|
||||
|
||||
@@ -65,8 +65,9 @@ class _DialogPremiumState extends State<DialogCommon> with Trans {
|
||||
children: [
|
||||
Text(
|
||||
widget.title + " ",
|
||||
textAlign: TextAlign.center,
|
||||
style: GoogleFonts.archivoBlack(
|
||||
fontSize: 18,
|
||||
fontSize: 20,
|
||||
color: Colors.yellow[400],
|
||||
shadows: <Shadow>[
|
||||
Shadow(
|
||||
@@ -90,7 +91,8 @@ class _DialogPremiumState extends State<DialogCommon> with Trans {
|
||||
Text(
|
||||
widget.descriptions,
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 14,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
shadows: <Shadow>[
|
||||
Shadow(
|
||||
@@ -113,7 +115,7 @@ class _DialogPremiumState extends State<DialogCommon> with Trans {
|
||||
Text(
|
||||
widget.description2,
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 14,
|
||||
fontSize: 16,
|
||||
color: Colors.white,
|
||||
shadows: <Shadow>[
|
||||
Shadow(
|
||||
@@ -136,7 +138,7 @@ class _DialogPremiumState extends State<DialogCommon> with Trans {
|
||||
Text(
|
||||
widget.description3,
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 14,
|
||||
fontSize: 16,
|
||||
color: Colors.white,
|
||||
shadows: <Shadow>[
|
||||
Shadow(
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
import 'package:aitrainer_app/util/trans.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class DialogWidget extends StatefulWidget {
|
||||
final String title, description;
|
||||
final Widget widget;
|
||||
final VoidCallback onTap;
|
||||
final VoidCallback onCancel;
|
||||
|
||||
DialogWidget({Key key, this.title, this.description, this.widget, this.onTap, this.onCancel}) : super(key: key);
|
||||
|
||||
@override
|
||||
_DialogPremiumState createState() {
|
||||
return _DialogPremiumState();
|
||||
}
|
||||
}
|
||||
|
||||
class _DialogPremiumState extends State<DialogWidget> with Trans {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
setContext(context);
|
||||
return Dialog(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(31),
|
||||
),
|
||||
elevation: 0,
|
||||
backgroundColor: Colors.transparent,
|
||||
child: contentBox(context),
|
||||
);
|
||||
}
|
||||
|
||||
contentBox(context) {
|
||||
return Stack(alignment: AlignmentDirectional.topStart, children: [
|
||||
Stack(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 20, top: 24, right: 20, bottom: 30),
|
||||
margin: EdgeInsets.only(top: 30),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
boxShadow: [BoxShadow(color: Colors.black, offset: Offset(0, 10), blurRadius: 10)],
|
||||
image: DecorationImage(
|
||||
image: AssetImage('asset/image/WT_black_G_background.jpg'),
|
||||
fit: BoxFit.cover,
|
||||
alignment: Alignment.center,
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
Stack(
|
||||
alignment: AlignmentDirectional.topEnd,
|
||||
children: [
|
||||
Text(
|
||||
widget.title,
|
||||
textAlign: TextAlign.center,
|
||||
style: GoogleFonts.archivoBlack(
|
||||
fontSize: 20,
|
||||
color: Colors.yellow[400],
|
||||
shadows: <Shadow>[
|
||||
Shadow(
|
||||
offset: Offset(5.0, 5.0),
|
||||
blurRadius: 12.0,
|
||||
color: Colors.black54,
|
||||
),
|
||||
Shadow(
|
||||
offset: Offset(-3.0, 3.0),
|
||||
blurRadius: 12.0,
|
||||
color: Colors.black54,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: 35,
|
||||
),
|
||||
Text(
|
||||
widget.description,
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
shadows: <Shadow>[
|
||||
Shadow(
|
||||
offset: Offset(5.0, 5.0),
|
||||
blurRadius: 12.0,
|
||||
color: Colors.black54,
|
||||
),
|
||||
Shadow(
|
||||
offset: Offset(-3.0, 3.0),
|
||||
blurRadius: 12.0,
|
||||
color: Colors.black54,
|
||||
),
|
||||
],
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(
|
||||
height: 15,
|
||||
),
|
||||
widget.widget,
|
||||
SizedBox(
|
||||
height: 52,
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment.center,
|
||||
child: GestureDetector(
|
||||
onTap: widget.onTap ?? widget.onTap,
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
Image.asset('asset/icon/gomb_orange_c.png', width: 100, height: 45),
|
||||
Text(
|
||||
t("OK"),
|
||||
style: TextStyle(fontSize: 16, color: Colors.white),
|
||||
),
|
||||
],
|
||||
))),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
if (widget.onCancel == null) {
|
||||
Navigator.of(context).pop();
|
||||
} else {
|
||||
widget.onCancel();
|
||||
}
|
||||
},
|
||||
child: CircleAvatar(
|
||||
backgroundColor: Colors.transparent,
|
||||
radius: 28,
|
||||
child: Text(
|
||||
"X",
|
||||
style: GoogleFonts.archivoBlack(fontSize: 32, color: Colors.white54),
|
||||
),
|
||||
)),
|
||||
]);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,394 @@
|
||||
import 'package:aitrainer_app/library/custom_icon_icons.dart';
|
||||
import 'package:aitrainer_app/util/trans.dart';
|
||||
import 'package:aitrainer_app/widgets/time_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:keyboard_actions/keyboard_actions.dart';
|
||||
import 'package:keyboard_actions/keyboard_actions_config.dart';
|
||||
import 'package:stop_watch_timer/stop_watch_timer.dart';
|
||||
import 'package:wakelock/wakelock.dart';
|
||||
|
||||
import 'dialog_html.dart';
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class ExerciseSave extends StatefulWidget {
|
||||
final ValueChanged<dynamic> onQuantityChanged;
|
||||
final ValueChanged<dynamic> onUnitQuantityChanged;
|
||||
final VoidCallback onSubmit;
|
||||
final bool hasUnitQuantity;
|
||||
final String unitQuantityUnit;
|
||||
final String unit;
|
||||
final String exerciseName;
|
||||
final String exerciseDescription;
|
||||
final String exerciseTask;
|
||||
final int exerciseTypeId;
|
||||
|
||||
ExerciseSave(
|
||||
{this.onQuantityChanged,
|
||||
this.onUnitQuantityChanged,
|
||||
this.onSubmit,
|
||||
this.hasUnitQuantity,
|
||||
this.unitQuantityUnit,
|
||||
this.unit,
|
||||
this.exerciseName,
|
||||
this.exerciseDescription,
|
||||
this.exerciseTask,
|
||||
this.exerciseTypeId});
|
||||
@override
|
||||
_ExerciseSaveState createState() => _ExerciseSaveState();
|
||||
}
|
||||
|
||||
class _ExerciseSaveState extends State<ExerciseSave> with Trans {
|
||||
final FocusNode _nodeText1 = FocusNode();
|
||||
final FocusNode _nodeText2 = FocusNode();
|
||||
final _controller1 = TextEditingController();
|
||||
final _controller2 = TextEditingController();
|
||||
final StopWatchTimer stopWatchTimer = StopWatchTimer(
|
||||
isLapHours: false,
|
||||
);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
setContext(context);
|
||||
return getExerciseWidget();
|
||||
}
|
||||
|
||||
//@override
|
||||
initState() {
|
||||
super.initState();
|
||||
_controller1.text = "30";
|
||||
_controller2.text = "12";
|
||||
_nodeText1.addListener(() {
|
||||
if (_nodeText1.hasFocus) {
|
||||
_controller1.selection = TextSelection(baseOffset: 0, extentOffset: _controller1.text.length);
|
||||
}
|
||||
});
|
||||
_nodeText2.addListener(() {
|
||||
if (_nodeText2.hasFocus) {
|
||||
_controller2.selection = TextSelection(baseOffset: 0, extentOffset: _controller2.text.length);
|
||||
}
|
||||
});
|
||||
if (widget.unit == "second") {
|
||||
stopWatchTimer.rawTime.listen((value) => widget.onQuantityChanged((value / 1000).toString()));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
dispose() {
|
||||
_controller1.dispose();
|
||||
stopWatchTimer.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
KeyboardActionsConfig _buildConfig(BuildContext context) {
|
||||
return KeyboardActionsConfig(
|
||||
keyboardActionsPlatform: KeyboardActionsPlatform.ALL,
|
||||
keyboardBarColor: Colors.grey[200],
|
||||
keyboardSeparatorColor: Colors.black26,
|
||||
nextFocus: true,
|
||||
actions: [
|
||||
KeyboardActionsItem(focusNode: _nodeText2, toolbarButtons: [
|
||||
(node) {
|
||||
return GestureDetector(
|
||||
onTap: () => node.unfocus(),
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
color: Colors.orange[500],
|
||||
child: Text(
|
||||
t("Done"),
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
]),
|
||||
KeyboardActionsItem(
|
||||
focusNode: _nodeText1,
|
||||
toolbarButtons: [
|
||||
//button 2
|
||||
(node) {
|
||||
return GestureDetector(
|
||||
onTap: () => node.unfocus(),
|
||||
child: Container(
|
||||
color: Colors.orange,
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
t("Done"),
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget getExerciseWidget() {
|
||||
return KeyboardActions(
|
||||
config: _buildConfig(context),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(top: 10, left: 55, right: 55),
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
widget.exerciseName,
|
||||
style: GoogleFonts.archivoBlack(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 24,
|
||||
color: Colors.white,
|
||||
shadows: <Shadow>[
|
||||
Shadow(
|
||||
offset: Offset(5.0, 5.0),
|
||||
blurRadius: 12.0,
|
||||
color: Colors.black54,
|
||||
),
|
||||
Shadow(
|
||||
offset: Offset(-3.0, 3.0),
|
||||
blurRadius: 12.0,
|
||||
color: Colors.black54,
|
||||
),
|
||||
],
|
||||
),
|
||||
overflow: TextOverflow.fade,
|
||||
maxLines: 4,
|
||||
softWrap: true,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(
|
||||
height: 15,
|
||||
),
|
||||
Text(
|
||||
widget.exerciseDescription,
|
||||
style: GoogleFonts.inter(fontSize: 12, color: Colors.yellow[300]),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.fade,
|
||||
softWrap: true,
|
||||
),
|
||||
InkWell(
|
||||
child: Text(
|
||||
t("More »"),
|
||||
style: GoogleFonts.inter(fontSize: 12, color: Colors.blue[200]),
|
||||
),
|
||||
onTap: () => {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return DialogHTML(title: widget.exerciseName, htmlData: '<p>' + widget.exerciseDescription + '</p>');
|
||||
})
|
||||
},
|
||||
),
|
||||
Divider(
|
||||
color: Colors.transparent,
|
||||
),
|
||||
widget.hasUnitQuantity
|
||||
? Text(
|
||||
t(widget.exerciseTask),
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 14,
|
||||
color: Colors.orange,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
maxLines: 3,
|
||||
textAlign: TextAlign.center,
|
||||
overflow: TextOverflow.fade,
|
||||
softWrap: true,
|
||||
)
|
||||
: Offstage(),
|
||||
Divider(
|
||||
color: Colors.transparent,
|
||||
),
|
||||
columnQuantityUnit(),
|
||||
Divider(
|
||||
color: Colors.transparent,
|
||||
),
|
||||
columnQuantity(),
|
||||
Divider(
|
||||
color: Colors.transparent,
|
||||
),
|
||||
widget.hasUnitQuantity
|
||||
? Text(
|
||||
t("Step") + ": " + "1/4",
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 22,
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
maxLines: 3,
|
||||
textAlign: TextAlign.center,
|
||||
overflow: TextOverflow.fade,
|
||||
softWrap: true,
|
||||
)
|
||||
: Offstage(),
|
||||
Divider(
|
||||
color: Colors.transparent,
|
||||
),
|
||||
Divider(
|
||||
color: Colors.transparent,
|
||||
),
|
||||
FlatButton(
|
||||
onPressed: () {
|
||||
widget.onSubmit();
|
||||
/* showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return Victory(
|
||||
victory: true,
|
||||
);
|
||||
}); */
|
||||
},
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
Image.asset('asset/icon/gomb_orange_c.png', width: 140, height: 60),
|
||||
Text(
|
||||
t("Save"),
|
||||
style: TextStyle(fontSize: 16, color: Colors.white),
|
||||
),
|
||||
],
|
||||
)),
|
||||
]),
|
||||
)));
|
||||
}
|
||||
|
||||
Column columnQuantityUnit() {
|
||||
Column row = Column();
|
||||
if (widget.hasUnitQuantity) {
|
||||
row = Column(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [
|
||||
TextFormField(
|
||||
focusNode: _nodeText1,
|
||||
controller: _controller1,
|
||||
decoration: InputDecoration(
|
||||
contentPadding: EdgeInsets.only(left: 25, top: 5, bottom: 5),
|
||||
labelText: t(widget.unitQuantityUnit),
|
||||
labelStyle: GoogleFonts.inter(fontSize: 20, color: Colors.yellow[50]),
|
||||
fillColor: Colors.black38,
|
||||
filled: true,
|
||||
border: OutlineInputBorder(
|
||||
gapPadding: 8.0,
|
||||
borderRadius: BorderRadius.circular(12.0),
|
||||
borderSide: BorderSide(color: Colors.white12, width: 0.4),
|
||||
),
|
||||
),
|
||||
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
||||
textInputAction: TextInputAction.done,
|
||||
style: GoogleFonts.archivoBlack(fontSize: 80, color: Colors.yellow[300]),
|
||||
onChanged: (value) => widget.onUnitQuantityChanged(value)),
|
||||
]);
|
||||
}
|
||||
return row;
|
||||
}
|
||||
|
||||
Column columnQuantity() {
|
||||
if (widget.unit == "second") {
|
||||
return Column(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 0),
|
||||
child: StreamBuilder<int>(
|
||||
stream: stopWatchTimer.rawTime,
|
||||
initialData: stopWatchTimer.rawTime.value,
|
||||
builder: (context, snap) {
|
||||
final value = snap.data;
|
||||
final displayTime = StopWatchTimer.getDisplayTime(value, hours: false);
|
||||
return Column(children: <Widget>[
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Text(
|
||||
displayTime,
|
||||
style: const TextStyle(fontSize: 40, fontFamily: 'Helvetica', fontWeight: FontWeight.bold, color: Colors.white),
|
||||
),
|
||||
),
|
||||
]);
|
||||
})),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(2),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
child: IconButton(
|
||||
padding: const EdgeInsets.all(2),
|
||||
color: Colors.white70,
|
||||
onPressed: () async {
|
||||
stopWatchTimer.onExecute.add(StopWatchExecute.start);
|
||||
Wakelock.enable(); // prevent sleep the phone
|
||||
},
|
||||
icon: Icon(CustomIcon.play_1),
|
||||
iconSize: 40,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
child: IconButton(
|
||||
padding: const EdgeInsets.all(2),
|
||||
iconSize: 40,
|
||||
color: Colors.white70,
|
||||
onPressed: () async {
|
||||
stopWatchTimer.onExecute.add(StopWatchExecute.stop);
|
||||
Wakelock.disable();
|
||||
},
|
||||
icon: Icon(CustomIcon.stop),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
child: IconButton(
|
||||
padding: const EdgeInsets.all(2),
|
||||
iconSize: 40,
|
||||
color: Colors.white70,
|
||||
onPressed: () async {
|
||||
stopWatchTimer.onExecute.add(StopWatchExecute.reset);
|
||||
},
|
||||
icon: Icon(CustomIcon.creative_commons_zero),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Divider(),
|
||||
Divider(),
|
||||
Text(t("Or type the time manually:"), style: GoogleFonts.inter(color: Colors.white)),
|
||||
TimePickerWidget(onChange: (value) => widget.onQuantityChanged((value).toString()))
|
||||
]);
|
||||
}
|
||||
Column row = Column(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [
|
||||
TextFormField(
|
||||
focusNode: _nodeText2,
|
||||
controller: _controller2,
|
||||
decoration: InputDecoration(
|
||||
contentPadding: EdgeInsets.only(left: 25, top: 5, bottom: 5),
|
||||
labelText: t(widget.unit),
|
||||
labelStyle: GoogleFonts.inter(fontSize: 20, color: Colors.orange[50], decorationColor: Colors.black12),
|
||||
fillColor: Colors.black38,
|
||||
filled: true,
|
||||
border: OutlineInputBorder(
|
||||
gapPadding: 8.0,
|
||||
borderRadius: BorderRadius.circular(12.0),
|
||||
borderSide: BorderSide(color: Colors.black26, width: 0.4),
|
||||
),
|
||||
),
|
||||
keyboardType: TextInputType.number,
|
||||
textInputAction: TextInputAction.next,
|
||||
style: GoogleFonts.archivoBlack(fontSize: 80, color: Colors.orange[200]),
|
||||
onChanged: (value) {
|
||||
widget.onQuantityChanged(value);
|
||||
},
|
||||
),
|
||||
]);
|
||||
|
||||
return row;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:aitrainer_app/library/image_cache.dart' as wt;
|
||||
import 'package:transparent_image/transparent_image.dart';
|
||||
|
||||
class MenuImage extends StatelessWidget {
|
||||
final int workoutTreeId;
|
||||
final String imageName;
|
||||
const MenuImage({this.workoutTreeId, this.imageName});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (workoutTreeId == null) {
|
||||
return Offstage();
|
||||
}
|
||||
String imageString = this.getImage(workoutTreeId, imageName);
|
||||
Widget widget;
|
||||
if (imageString != null) {
|
||||
widget = ClipRRect(
|
||||
borderRadius: BorderRadius.circular(24.0),
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: FadeInImage(
|
||||
fadeInDuration: Duration(milliseconds: 100),
|
||||
image: MemoryImage(base64Decode(imageString)),
|
||||
placeholder: MemoryImage(kTransparentImage),
|
||||
),
|
||||
));
|
||||
} else {
|
||||
if (imageName.contains("https")) {
|
||||
if (!wt.ImageCache().existsImageInMap(workoutTreeId, imageName)) {
|
||||
widget = ClipRRect(
|
||||
borderRadius: BorderRadius.circular(24.0),
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: FadeInImage(
|
||||
fadeInDuration: Duration(milliseconds: 500),
|
||||
image: NetworkImage(imageName),
|
||||
placeholder: MemoryImage(kTransparentImage),
|
||||
),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
widget = ClipRRect(
|
||||
borderRadius: BorderRadius.circular(24.0),
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: Image.asset(imageName),
|
||||
));
|
||||
}
|
||||
}
|
||||
if (widget == null) {
|
||||
return Offstage();
|
||||
}
|
||||
return widget;
|
||||
}
|
||||
|
||||
String getImage(int id, String name) {
|
||||
String imageString;
|
||||
if (name.contains("http")) {
|
||||
imageString = wt.ImageCache().getImageString(id, name);
|
||||
}
|
||||
return imageString;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:collection';
|
||||
import 'dart:ui';
|
||||
import 'package:aitrainer_app/model/exercise_ability.dart';
|
||||
import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
|
||||
import 'package:aitrainer_app/library/custom_icon_icons.dart';
|
||||
import 'package:aitrainer_app/util/enums.dart';
|
||||
import 'package:aitrainer_app/util/track.dart';
|
||||
import 'package:aitrainer_app/widgets/menu_image.dart';
|
||||
import 'package:aitrainer_app/widgets/menu_search_bar.dart';
|
||||
import 'package:aitrainer_app/util/app_language.dart';
|
||||
import 'package:aitrainer_app/util/app_localization.dart';
|
||||
@@ -21,8 +22,6 @@ import 'package:flutter/painting.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:transparent_image/transparent_image.dart';
|
||||
import 'package:aitrainer_app/library/image_cache.dart' as wt;
|
||||
|
||||
import 'dialog_html.dart';
|
||||
|
||||
@@ -144,8 +143,15 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
|
||||
padding: EdgeInsets.only(left: 0.0, bottom: 0),
|
||||
onPressed: () => menuClick(workoutTree, menuBloc, context),
|
||||
),
|
||||
/* Container(
|
||||
padding: EdgeInsets.only(left: 5, bottom: 5, right: 5),
|
||||
height: 80,
|
||||
child: Container(
|
||||
color: Colors.black.withOpacity(0.2),
|
||||
),
|
||||
), */
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 15, bottom: 15, right: 15),
|
||||
padding: EdgeInsets.only(left: 15, bottom: 8, right: 15),
|
||||
child: GestureDetector(
|
||||
onTap: () => menuClick(workoutTree, menuBloc, context),
|
||||
child: Text(
|
||||
@@ -285,7 +291,6 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
|
||||
MenuSearchBar(
|
||||
listItems: menuBloc.menuTreeRepository.menuAsExercise,
|
||||
onFind: (value) {
|
||||
print("onFind: ${value.toJson()}");
|
||||
if (Cache().userLoggedIn == null) {
|
||||
Scaffold.of(context).showSnackBar(SnackBar(
|
||||
backgroundColor: Colors.orange,
|
||||
@@ -303,11 +308,12 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return DialogCommon(
|
||||
title: t("You have an acive Compact Test"),
|
||||
descriptions: t("Press OK to continue!"),
|
||||
title: t("You have an active Test Set!"),
|
||||
descriptions: t("Press OK to continue"),
|
||||
text: "OK",
|
||||
onTap: () => {
|
||||
Navigator.of(context).pop(),
|
||||
Navigator.of(context).pushNamed("testSetExecute"),
|
||||
},
|
||||
onCancel: () => {
|
||||
Navigator.of(context).pop(),
|
||||
@@ -334,18 +340,22 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
|
||||
}
|
||||
|
||||
void menuClick(WorkoutMenuTree workoutTree, MenuBloc menuBloc, BuildContext context) {
|
||||
if (workoutTree.child == false) {
|
||||
if (ExerciseAbility.mini_test.equalsTo(menuBloc.ability) && workoutTree.parent != 0) {
|
||||
Navigator.of(context).pushNamed('testSetEdit', arguments: workoutTree.nameEnglish);
|
||||
}
|
||||
menuBloc.add(MenuTreeDown(item: workoutTree, parent: workoutTree.id));
|
||||
if (Cache().userLoggedIn == null) {
|
||||
Scaffold.of(context).showSnackBar(SnackBar(
|
||||
backgroundColor: Colors.orange,
|
||||
content: Text(AppLocalizations.of(context).translate('Please log in'), style: TextStyle(color: Colors.white))));
|
||||
} else {
|
||||
menuBloc.add(MenuClickExercise(exerciseTypeId: workoutTree.id));
|
||||
if (Cache().userLoggedIn == null) {
|
||||
Scaffold.of(context).showSnackBar(SnackBar(
|
||||
backgroundColor: Colors.orange,
|
||||
content: Text(AppLocalizations.of(context).translate('Please log in'), style: TextStyle(color: Colors.white))));
|
||||
if (workoutTree.child == false) {
|
||||
if (ExerciseAbility.mini_test_set.equalsTo(menuBloc.ability) && workoutTree.parent != 0) {
|
||||
HashMap args = HashMap();
|
||||
args['templateName'] = workoutTree.nameEnglish;
|
||||
args['templateNameTranslation'] = workoutTree.name;
|
||||
Navigator.of(context).pushNamed('testSetEdit', arguments: args);
|
||||
}
|
||||
menuBloc.add(MenuTreeDown(item: workoutTree, parent: workoutTree.id));
|
||||
} else {
|
||||
menuBloc.add(MenuClickExercise(exerciseTypeId: workoutTree.id));
|
||||
|
||||
if (workoutTree.exerciseType.name == "Custom" && Cache().userLoggedIn.admin == 1) {
|
||||
Navigator.of(context).pushNamed('exerciseCustomPage', arguments: workoutTree.exerciseType);
|
||||
} else {
|
||||
@@ -365,60 +375,11 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
Widget _getButtonImage(WorkoutMenuTree workoutTree, double cWidth, double cHeight) {
|
||||
//print("_getButtonImage " + workoutTree.imageName);
|
||||
String imageString = menuBloc.getImage(workoutTree.id, workoutTree.imageName);
|
||||
Widget widget;
|
||||
if (imageString != null) {
|
||||
print(" -- get Image from MEMORY " + workoutTree.imageName);
|
||||
widget = ClipRRect(
|
||||
borderRadius: BorderRadius.circular(24.0),
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: FadeInImage(
|
||||
fadeInDuration: Duration(milliseconds: 100),
|
||||
image: MemoryImage(base64Decode(imageString)),
|
||||
placeholder: MemoryImage(kTransparentImage),
|
||||
),
|
||||
));
|
||||
} else {
|
||||
if (workoutTree.imageName.contains("https")) {
|
||||
if (!wt.ImageCache().existsImageInMap(workoutTree.id, workoutTree.imageName)) {
|
||||
print(" -- get Image from network " + workoutTree.imageName);
|
||||
widget = ClipRRect(
|
||||
borderRadius: BorderRadius.circular(24.0),
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: FadeInImage(
|
||||
fadeInDuration: Duration(milliseconds: 500),
|
||||
image: NetworkImage(workoutTree.imageName),
|
||||
placeholder: MemoryImage(kTransparentImage),
|
||||
),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
//print(" -- get Image from asset " + workoutTree.imageName);
|
||||
widget = ClipRRect(
|
||||
borderRadius: BorderRadius.circular(24.0),
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: Image.asset(workoutTree.imageName),
|
||||
/* FadeInImage(
|
||||
fadeInDuration: Duration(milliseconds: 50),
|
||||
image: AssetImage(workoutTree.imageName),
|
||||
placeholder: MemoryImage(kTransparentImage),
|
||||
), */
|
||||
));
|
||||
}
|
||||
}
|
||||
return widget;
|
||||
}
|
||||
|
||||
Widget badgedIcon(WorkoutMenuTree workoutMenuTree, double cWidth, double cHeight) {
|
||||
String badgeKey = workoutMenuTree.nameEnglish;
|
||||
bool show = Cache().getBadges()[badgeKey] != null;
|
||||
int counter = Cache().getBadges()[badgeKey] != null ? Cache().getBadges()[badgeKey] : 0;
|
||||
Widget buttonImage = _getButtonImage(workoutMenuTree, cWidth, cHeight);
|
||||
Widget buttonImage = MenuImage(imageName: workoutMenuTree.imageName, workoutTreeId: workoutMenuTree.id);
|
||||
return Badge(
|
||||
padding: EdgeInsets.all(8),
|
||||
position: BadgePosition.topEnd(top: 3, end: 3),
|
||||
@@ -441,6 +402,7 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
scrollController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import 'dart:async';
|
||||
|
||||
import 'package:aitrainer_app/model/workout_menu_tree.dart';
|
||||
import 'package:aitrainer_app/util/trans.dart';
|
||||
import 'package:dropdown_search/dropdown_search.dart';
|
||||
import 'package:aitrainer_app/library/dropdown_search.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
|
||||
@@ -23,26 +23,31 @@ class SearchBarStream {
|
||||
}
|
||||
}
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class MenuSearchBar extends StatelessWidget {
|
||||
final List listItems;
|
||||
final Function(WorkoutMenuTree) onFind;
|
||||
|
||||
const MenuSearchBar({@required this.listItems, this.onFind});
|
||||
bool showIcon;
|
||||
MenuSearchBar({@required this.listItems, this.onFind, this.showIcon = true});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnimatedSearch(
|
||||
listItems: listItems,
|
||||
onFind: onFind,
|
||||
showIcon: showIcon,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class AnimatedSearch extends StatefulWidget {
|
||||
final List listItems;
|
||||
final Function(WorkoutMenuTree) onFind;
|
||||
bool showIcon = true;
|
||||
|
||||
AnimatedSearch({this.listItems, this.onFind, this.showIcon});
|
||||
|
||||
AnimatedSearch({this.listItems, this.onFind});
|
||||
@override
|
||||
_AnimatedSearch createState() => _AnimatedSearch();
|
||||
}
|
||||
@@ -81,7 +86,7 @@ class _AnimatedSearch extends State<AnimatedSearch> {
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
AnimateExpansion(
|
||||
animate: !isSearching,
|
||||
animate: widget.showIcon ? !isSearching : false,
|
||||
axisAlignment: 1.0,
|
||||
child: IconButton(
|
||||
onPressed: () => {
|
||||
@@ -98,7 +103,7 @@ class _AnimatedSearch extends State<AnimatedSearch> {
|
||||
),
|
||||
)),
|
||||
AnimateExpansion(
|
||||
animate: isSearching,
|
||||
animate: widget.showIcon ? isSearching : true,
|
||||
axisAlignment: -1.0,
|
||||
child: Search(
|
||||
listItems: widget.listItems,
|
||||
|
||||
@@ -25,7 +25,6 @@ class _TimePickerWidgetState extends State<TimePickerWidget> with Trans {
|
||||
currentTimeInMin = x.toDouble();
|
||||
}
|
||||
seconds = currentTimeInMin * 60 + currentTimeInSec + currentTimeInDec / 100;
|
||||
//print("sec" + seconds.toStringAsFixed(2));
|
||||
setState(() {});
|
||||
widget.onChange(seconds);
|
||||
},
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
import 'package:confetti/confetti.dart';
|
||||
import 'package:ezanimation/ezanimation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/scheduler.dart';
|
||||
|
||||
class VictoryConfetti extends StatefulWidget {
|
||||
@override
|
||||
_VictoryConfettiState createState() => _VictoryConfettiState();
|
||||
}
|
||||
|
||||
class _VictoryConfettiState extends State<VictoryConfetti> {
|
||||
ConfettiController _controllerBottomCenter;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_controllerBottomCenter = ConfettiController(duration: const Duration(seconds: 2));
|
||||
SchedulerBinding.instance.addPostFrameCallback((_) {
|
||||
Future.delayed(Duration(milliseconds: 500)).then((value) => _controllerBottomCenter.play());
|
||||
});
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controllerBottomCenter.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Path drawStar(Size size) {
|
||||
// Method to convert degree to radians
|
||||
double degToRad(double deg) => deg * (pi / 180.0);
|
||||
|
||||
const numberOfPoints = 5;
|
||||
final halfWidth = size.width / 2;
|
||||
final externalRadius = halfWidth;
|
||||
final internalRadius = halfWidth / 2.5;
|
||||
final degreesPerStep = degToRad(360 / numberOfPoints);
|
||||
final halfDegreesPerStep = degreesPerStep / 2;
|
||||
final path = Path();
|
||||
final fullAngle = degToRad(360);
|
||||
path.moveTo(size.width, halfWidth);
|
||||
|
||||
for (double step = 0; step < fullAngle; step += degreesPerStep) {
|
||||
path.lineTo(halfWidth + externalRadius * cos(step), halfWidth + externalRadius * sin(step));
|
||||
path.lineTo(halfWidth + internalRadius * cos(step + halfDegreesPerStep), halfWidth + internalRadius * sin(step + halfDegreesPerStep));
|
||||
}
|
||||
path.close();
|
||||
return path;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
child: Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: ConfettiWidget(
|
||||
confettiController: _controllerBottomCenter,
|
||||
blastDirectionality: BlastDirectionality.explosive, // don't specify a direction, blast randomly
|
||||
numberOfParticles: 20,
|
||||
colors: const [Colors.green, Colors.blue, Colors.pink, Colors.orange, Colors.purple], // manually specify the colors to be used
|
||||
createParticlePath: drawStar, // define a custom shape/path.
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class Victory extends StatefulWidget {
|
||||
final bool victory;
|
||||
const Victory({this.victory});
|
||||
@override
|
||||
_VictoryState createState() => _VictoryState();
|
||||
}
|
||||
|
||||
class _VictoryState extends State<Victory> {
|
||||
final EzAnimation animation = EzAnimation(1.0, 200.0, Duration(seconds: 3), reverseCurve: null);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
animation.start();
|
||||
animation.addStatusListener((status) {
|
||||
if (status == AnimationStatus.completed) {
|
||||
setState(() {});
|
||||
}
|
||||
});
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
child: AnimatedBuilder(
|
||||
animation: animation,
|
||||
builder: (context, snapshot) {
|
||||
return Center(
|
||||
child: Container(
|
||||
width: animation.value,
|
||||
height: animation.value,
|
||||
child: Row(children: [
|
||||
VictoryConfetti(),
|
||||
widget.victory ? Image.asset("asset/image/WT_cup_victory400.png") : Offstage(),
|
||||
]),
|
||||
),
|
||||
);
|
||||
}));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user