workouttest_app/lib/widgets/exercise_save.dart
2021-07-05 22:10:32 +02:00

479 lines
17 KiB
Dart

import 'dart:async';
import 'package:aitrainer_app/bloc/tutorial/tutorial_bloc.dart';
import 'package:aitrainer_app/library/custom_icon_icons.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/time_picker.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: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_common.dart';
import 'dialog_html.dart';
// ignore: must_be_immutable
class ExerciseSave extends StatefulWidget {
final ValueChanged<double> onQuantityChanged;
final ValueChanged<double>? 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;
final double? weight;
final int? repeats;
final int? set;
final int? exerciseNr;
final int? originalQuantity;
ExerciseSave(
{required this.onQuantityChanged,
this.onUnitQuantityChanged,
this.onSubmit,
required this.hasUnitQuantity,
this.unitQuantityUnit,
required this.unit,
required this.exerciseName,
required this.exerciseDescription,
required this.exerciseTask,
required this.exerciseTypeId,
this.weight,
this.repeats,
this.set,
this.exerciseNr,
this.originalQuantity});
@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 = widget.weight == null
? "0"
: widget.weight! % widget.weight!.round() == 0
? widget.weight!.toStringAsFixed(0)
: widget.weight!.toStringAsFixed(1);
_controller2.text = widget.repeats == null ? "12" : widget.repeats!.toStringAsFixed(0);
_nodeText1.addListener(() {
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) => {
if (value > 0)
{
widget.onQuantityChanged((value / 1000)),
}
});
}
SchedulerBinding.instance!.addPostFrameCallback((_) {
final TutorialBloc bloc = BlocProvider.of<TutorialBloc>(context);
if (bloc.actualCheck == "directTest") {
Timer(
Duration(milliseconds: 2000),
() => {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return DialogCommon(
title: t("Attention"),
descriptions: t(widget.exerciseTask),
text: "OK",
onTap: () => Navigator.of(context).pop(),
onCancel: () => Navigator.of(context).pop(),
);
})
});
}
});
}
@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),
),
),
);
}
],
),
],
);
}
String getTimeGoal(int? originalQuantity) {
if (originalQuantity == null) {
return "";
} else if (originalQuantity == -1) {
return t("Goal") + ": Max";
} else {
int mins = (originalQuantity / 60).floor();
int secs = originalQuantity % 60;
String seconds = "";
if (secs > 0) {
seconds = secs.toStringAsFixed(0) + " " + t("secs");
}
return t("Goal") + ": " + mins.toStringAsFixed(0) + " " + t("mins") + " " + seconds;
}
}
Widget getExerciseWidget() {
return KeyboardActions(
config: _buildConfig(context),
child: Container(
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,
),
InkWell(
child: Text(
t("Exercise descripton") + " »",
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,
),
Text(
t(widget.exerciseTask),
style: GoogleFonts.inter(
fontSize: 14,
color: Colors.orange,
fontWeight: FontWeight.bold,
shadows: <Shadow>[
Shadow(
offset: Offset(2.0, 2.0),
blurRadius: 6.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
),
maxLines: 3,
textAlign: TextAlign.center,
overflow: TextOverflow.fade,
softWrap: true,
),
Divider(
color: Colors.transparent,
),
widget.unit == "second"
? Text(
getTimeGoal(widget.originalQuantity),
style: GoogleFonts.inter(
fontSize: 24,
color: Colors.yellow[400],
fontWeight: FontWeight.bold,
shadows: <Shadow>[
Shadow(
offset: Offset(2.0, 2.0),
blurRadius: 6.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
),
textAlign: TextAlign.center,
)
: Offstage(),
columnQuantityUnit(),
Divider(
color: Colors.transparent,
),
columnQuantity(),
Divider(
color: Colors.transparent,
),
widget.hasUnitQuantity
? Text(
widget.set == null || widget.exerciseNr == null
? t("Step") + ": " + "1/4"
: t("Step") + ": " + "${widget.exerciseNr}/${widget.set}",
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,
),
]),
)));
}
Widget columnQuantityUnit() {
Widget row = Padding(padding: const EdgeInsets.only(top: 10, left: 55, right: 55), child: Column());
if (widget.hasUnitQuantity) {
row = Padding(
padding: const EdgeInsets.only(top: 10, left: 55, right: 55),
child: Column(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [
TextFormField(
focusNode: _nodeText1,
controller: _controller1,
decoration: InputDecoration(
contentPadding: EdgeInsets.only(left: 25, top: 5, bottom: 5),
labelText: t(widget.unitQuantityUnit!),
labelStyle: GoogleFonts.inter(fontSize: 20, color: Colors.yellow[50]),
fillColor: Colors.black38,
filled: true,
border: OutlineInputBorder(
gapPadding: 8.0,
borderRadius: BorderRadius.circular(12.0),
borderSide: BorderSide(color: Colors.white12, width: 0.4),
),
),
keyboardType: TextInputType.numberWithOptions(decimal: true),
textInputAction: TextInputAction.done,
style: GoogleFonts.archivoBlack(fontSize: 80, color: Colors.yellow[300]),
onChanged: (value) {
if (value.isNotEmpty) {
value = value.replaceFirst(",", ".");
value = value.replaceAll(RegExp(r'[^0-9.]'), "");
widget.onUnitQuantityChanged!(double.parse(value));
}
}),
]));
}
return row;
}
Widget columnQuantity() {
if (widget.unit == "second") {
return Column(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [
Padding(
padding: const EdgeInsets.only(top: 10, left: 55, right: 55),
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: 35, fontFamily: 'Helvetica', fontWeight: FontWeight.bold, color: Colors.white),
),
),
]);
})),
Padding(
padding: const EdgeInsets.only(top: 10, left: 25, right: 25),
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(bottom: 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(horizontal: 5),
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: 5),
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: 5),
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),
},
)
]);
}
Widget row = Container(
padding: const EdgeInsets.only(top: 10, left: 55, right: 55),
child: 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) {
if (value.isNotEmpty) {
value = value.replaceFirst(",", ".");
value = value.replaceAll(RegExp(r'[^0-9.]'), "");
widget.onQuantityChanged(double.parse(value));
}
},
),
]));
return row;
}
}