workouttest_app/lib/widgets/menu_page_widget.dart
2021-03-09 15:49:15 +01:00

447 lines
18 KiB
Dart

import 'dart:convert';
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_search_bar.dart';
import 'package:aitrainer_app/util/app_language.dart';
import 'package:aitrainer_app/util/app_localization.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/workout_menu_tree.dart';
import 'package:aitrainer_app/service/logging.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/dialog_common.dart';
import 'package:badges/badges.dart';
import 'package:ezanimation/ezanimation.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
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';
// ignore: must_be_immutable
class MenuPageWidget extends StatefulWidget {
int parent;
MenuPageWidget({this.parent});
@override
_MenuPageWidgetState createState() => _MenuPageWidgetState();
}
class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
final double baseWidth = 312;
final double baseHeight = 675.2;
MenuBloc menuBloc;
final scrollController = ScrollController();
final bool activeExercisePlan = Cache().activeExercisePlan != null;
final EzAnimation animation = EzAnimation(35.0, 10.0, Duration(seconds: 2), reverseCurve: Curves.linear);
@override
void initState() {
if (activeExercisePlan) {
animation.start();
animation.addStatusListener((status) {
if (status == AnimationStatus.completed || status == AnimationStatus.dismissed) {
animation.reverse();
}
});
animation.addListener(() {
setState(() {});
});
}
/// We require the initializers to run after the loading screen is rendered
SchedulerBinding.instance.addPostFrameCallback((_) {
menuBloc.add(MenuCreate());
});
super.initState();
}
@override
Widget build(BuildContext context) {
menuBloc = BlocProvider.of<MenuBloc>(context);
setContext(context);
double cWidth = MediaQuery.of(context).size.width;
double cHeight = MediaQuery.of(context).size.height;
return CustomScrollView(
// Must add scrollController to sliver root
controller: scrollController,
scrollDirection: Axis.vertical,
slivers: buildMenuColumn(widget.parent, context, menuBloc, cWidth, cHeight));
}
List<Widget> buildMenuColumn(int parent, BuildContext context, MenuBloc menuBloc, double cWidth, double cHeight) {
final List<Widget> slivers = List();
bool isChild = menuBloc.menuTreeRepository.isChildAndGym(menuBloc.parent);
if (!isChild) {
slivers.add(getInfoWidget(context, menuBloc));
} else {
slivers.add(getFilterWidget(parent, menuBloc));
slivers.add(getFilterElements(menuBloc));
}
final List<Widget> _columnChildren = List();
if (menuBloc.getFilteredBranch(menuBloc.parent).isEmpty) {
_columnChildren.add(Container(
padding: EdgeInsets.only(top: 15.0),
child: Center(
child: Stack(alignment: Alignment.bottomLeft, children: [
Text(AppLocalizations.of(context).translate("All Exercises has been filtered out"),
style: GoogleFonts.inter(color: Colors.white)),
]))));
} else {
menuBloc.getFilteredBranch(menuBloc.parent).forEach((treeName, value) {
WorkoutMenuTree workoutTree = value;
_columnChildren.add(Container(
padding: EdgeInsets.only(top: 15.0, left: cWidth * 0.04, right: cWidth * 0.04),
//height: (cHeight / 3) - cWidth * 0.16,
child: Badge(
padding: EdgeInsets.all(8),
position: BadgePosition.bottomEnd(end: 0),
animationDuration: Duration(milliseconds: 500),
animationType: BadgeAnimationType.slide,
badgeColor: Colors.orange[800],
showBadge: workoutTree.base,
badgeContent: Text(AppLocalizations.of(context).translate("base"),
style: TextStyle(
color: Colors.white,
fontSize: 12,
)),
child: Badge(
showBadge: workoutTree.nameEnglish == "One Rep Max" || workoutTree.nameEnglish == "Endurance",
animationDuration: Duration(milliseconds: 800),
animationType: BadgeAnimationType.fade,
badgeColor: Colors.blue[100],
badgeContent: GestureDetector(
onTap: () => {
showDialog(
context: context,
builder: (BuildContext context) {
return DialogHTML(
title: workoutTree.name,
htmlData: workoutTree.nameEnglish == "Endurance"
? AppLocalizations.of(context).translate("Endurance_desc")
: AppLocalizations.of(context).translate("OneRepMax_desc"),
);
})
},
child: Icon(Icons.info_outline_rounded)),
child: Stack(alignment: Alignment.bottomLeft, children: [
FlatButton(
child: badgedIcon(workoutTree, cWidth, cHeight),
padding: EdgeInsets.only(left: 0.0, bottom: 0),
onPressed: () => menuClick(workoutTree, menuBloc, context),
),
Container(
padding: EdgeInsets.only(left: 15, bottom: 15, right: 15),
child: GestureDetector(
onTap: () => menuClick(workoutTree, menuBloc, context),
child: Text(
workoutTree.name,
maxLines: 4,
style: GoogleFonts.archivoBlack(color: workoutTree.color, fontSize: workoutTree.fontSize, height: 1.1),
),
),
),
])))));
});
}
/* LiveSliverList sliverList = LiveSliverList(
// And attach root sliver scrollController to widgets
controller: scrollController,
itemCount: _columnChildren.length,
reAnimateOnVisibility: false,
showItemDuration: Duration(milliseconds: 100),
itemBuilder: (BuildContext context, int index, Animation<double> animation) => FadeTransition(
opacity: animation,
child: _columnChildren[index],
),
*/
//delegate: SliverChildListDelegate(_columnChildren),
SliverList sliverList = SliverList(
delegate: SliverChildListDelegate(_columnChildren),
);
slivers.add(sliverList);
return slivers;
}
SliverGrid getFilterWidget(int parent, MenuBloc menuBloc) {
SliverGrid sliverList = SliverGrid(
delegate: SliverChildListDelegate([
Column(mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [
Text(
AppLocalizations.of(context).translate("Equipment Filter"),
textAlign: TextAlign.center,
style: GoogleFonts.archivoBlack(
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,
),
],
),
),
])
]),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 1,
mainAxisSpacing: 5.0,
crossAxisSpacing: 5.0,
childAspectRatio: 9,
));
return sliverList;
}
SliverGrid getFilterElements(MenuBloc menuBloc) {
List<Widget> list = List();
menuBloc.exerciseDeviceRepository.getGymDevices().forEach((element) {
String deviceName = AppLanguage().appLocal == Locale('en') ? element.name : element.nameTranslation;
ChoiceChip chip = ChoiceChip(
labelPadding: EdgeInsets.only(right: 5),
avatar: Icon(
Icons.remove_circle_outline,
color: Colors.orange,
size: 18,
),
label: Text(deviceName),
labelStyle: TextStyle(fontSize: 9, color: Colors.black),
selectedColor: Colors.white,
selected: menuBloc.selectedDevice(element.exerciseDeviceId),
backgroundColor: Colors.blue[100],
shadowColor: Colors.black54,
onSelected: (value) => menuBloc.add(MenuFilterExerciseType(deviceId: element.exerciseDeviceId)),
);
list.add(chip);
});
SliverGrid sliverList = SliverGrid(
delegate: SliverChildListDelegate(list),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
mainAxisSpacing: 1.0,
crossAxisSpacing: 1.0,
childAspectRatio: 3,
));
return sliverList;
}
SliverAppBar getInfoWidget(BuildContext context, MenuBloc menuBloc) {
menuBloc.setContext(context);
menuBloc.setMenuInfo();
SliverAppBar sliverAppBar = SliverAppBar(
automaticallyImplyLeading: false,
backgroundColor: Colors.transparent,
title: Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [
SizedBox(
width: 10,
),
GestureDetector(
onTap: () => {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return DialogCommon(
title: menuBloc.infoTitle,
descriptions: menuBloc.infoText,
description2: menuBloc.infoText2,
description3: menuBloc.infoText3,
text: "OK",
onTap: () => {Navigator.of(context).pop()},
onCancel: () => {Navigator.of(context).pop()},
);
})
},
child: Icon(
CustomIcon.question_circle,
color: Colors.orange[400],
size: 40,
)),
MenuSearchBar(
listItems: menuBloc.menuTreeRepository.menuAsExercise,
onFind: (value) {
print("onFind: ${value.toJson()}");
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 {
Track().track(TrackingEvent.search, eventValue: value.exerciseType.name);
menuBloc.ability = ExerciseAbility.oneRepMax;
Navigator.of(context).pushNamed('exerciseNewPage', arguments: value.exerciseType);
}
},
),
activeExercisePlan
? GestureDetector(
onTap: () => showDialog(
context: context,
builder: (BuildContext context) {
return DialogCommon(
title: t("You have an acive Compact Test"),
descriptions: t("Press OK to continue!"),
text: "OK",
onTap: () => {
Navigator.of(context).pop(),
},
onCancel: () => {
Navigator.of(context).pop(),
},
);
}),
child: AnimatedBuilder(
animation: animation,
builder: (context, snapshot) {
return Center(
child: Container(
width: animation.value,
height: animation.value,
child: Image.asset("asset/image/pict_reps_volumen_db.png"),
),
);
}))
: Offstage(),
SizedBox(
width: 10,
),
]));
return sliverAppBar;
}
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));
} 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))));
} else {
if (workoutTree.exerciseType.name == "Custom" && Cache().userLoggedIn.admin == 1) {
Navigator.of(context).pushNamed('exerciseCustomPage', arguments: workoutTree.exerciseType);
} else {
Navigator.of(context).pushNamed('exerciseNewPage', arguments: workoutTree.exerciseType);
}
}
}
}
dynamic getShape(WorkoutMenuTree workoutTree) {
bool base = workoutTree.base;
dynamic returnCode = (base == true)
? RoundedRectangleBorder(
side: BorderSide(width: 6, color: Colors.orangeAccent), borderRadius: BorderRadius.all(Radius.circular(24.0)))
: RoundedRectangleBorder(
side: BorderSide(width: 1, color: Colors.transparent), borderRadius: BorderRadius.all(Radius.circular(8.0)));
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);
return Badge(
padding: EdgeInsets.all(8),
position: BadgePosition.topEnd(top: 3, end: 3),
animationDuration: Duration(milliseconds: 500),
animationType: BadgeAnimationType.slide,
badgeColor: Colors.red,
showBadge: show,
badgeContent: Text(counter.toString(),
style: TextStyle(
color: Colors.white,
fontSize: 16,
)),
child: buttonImage == null
? Container(
color: Colors.transparent,
)
: buttonImage,
);
}
@override
void dispose() {
super.dispose();
}
}