workouttest_app/lib/widgets/menu_page_widget.dart
2021-09-05 22:11:45 +02:00

473 lines
18 KiB
Dart

import 'dart:collection';
import 'dart:ui';
import 'package:aitrainer_app/bloc/training_plan/training_plan_bloc.dart';
import 'package:aitrainer_app/model/exercise_ability.dart';
import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
import 'package:aitrainer_app/repository/training_plan_repository.dart';
import 'package:aitrainer_app/util/enums.dart';
import 'package:aitrainer_app/util/track.dart';
import 'package:aitrainer_app/widgets/dialog_trial.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';
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:firebase_dynamic_links/firebase_dynamic_links.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';
// 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;
late MenuBloc menuBloc;
//late TutorialBloc tutorialBloc;
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 || Cache().myTrainingPlan != null) {
animation.start();
animation.addStatusListener((status) {
if (status == AnimationStatus.completed || status == AnimationStatus.dismissed) {
animation.reverse();
}
});
animation.addListener(() {});
}
/// We require the initializers to run after the loading screen is rendered
SchedulerBinding.instance!.addPostFrameCallback((_) {
menuBloc.add(MenuCreate());
});
super.initState();
}
@override
bool didUpdateWidget(MenuPageWidget oldWidget) {
super.didUpdateWidget(oldWidget);
scrollController.animateTo(5, duration: Duration(milliseconds: 300), curve: Curves.easeIn);
runDelayedEvent();
return true;
}
Future runDelayedEvent() async {
await Future.delayed(Duration(milliseconds: 3000), () async {
if (Cache().userLoggedIn != null) {
await initDynamicLinks();
}
if (Cache().canTrial()) {
showDialog(
context: context,
builder: (BuildContext context) {
return DialogTrialWidget(
title: t("10 days Premium for free"),
description: t("Would you like to try all premium functions for 10 days, without any subscription or bank card data?"),
widget: Column(children: [
Text(
t("If you click to 'Yes', all premium functions will be available right now."),
style: GoogleFonts.inter(color: Colors.white),
),
Divider(),
Text(
t("If you click to 'No', you can use all basic functions, and you will loose the oppurtunity to try the premium functions for free."),
style: GoogleFonts.inter(color: Colors.white),
),
]),
onCancel: () => {
Navigator.of(context).pop(),
menuBloc.add(MenuStartTrial(start: DateTime.parse("1900-01-01 00:00:00"))),
},
onTap: () => {Navigator.of(context).pop(), menuBloc.add(MenuStartTrial(start: DateTime.now()))},
);
});
}
});
}
Future<void> initDynamicLinks() async {
FirebaseDynamicLinks.instance.onLink(onSuccess: (PendingDynamicLinkData? dynamicLink) async {
final Uri? deepLink = dynamicLink?.link;
print("DeepLink: $deepLink");
if (deepLink != null) {
// ignore: unawaited_futures
final String deepLinkPath = deepLink.path.replaceFirst("/", "");
Navigator.pushNamed(context, deepLinkPath);
}
}, onError: (OnLinkErrorException e) async {
print('onLinkError');
print(e.message);
});
final PendingDynamicLinkData? data = await FirebaseDynamicLinks.instance.getInitialLink();
final Uri? deepLink = data?.link;
print("Pending DeepLink: $deepLink");
if (deepLink != null) {
// ignore: unawaited_futures
final String deepLinkPath = deepLink.path.replaceFirst("/", "");
Navigator.pushNamed(context, deepLinkPath);
}
}
@override
Widget build(BuildContext context) {
menuBloc = BlocProvider.of<MenuBloc>(context);
//tutorialBloc = BlocProvider.of<TutorialBloc>(context);
setContext(context);
double cWidth = MediaQuery.of(context).size.width;
double cHeight = MediaQuery.of(context).size.height;
if (widget.parent == null) {
widget.parent = 0;
}
return Stack(children: [
CustomScrollView(
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 = [];
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 = [];
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: Stack(alignment: Alignment.bottomLeft, children: [
TextButton(
child: badgedIcon(workoutTree, cWidth, cHeight),
onPressed: () => menuClick(workoutTree, menuBloc),
),
Container(
padding: EdgeInsets.only(left: 15, bottom: 8, right: 15),
child: GestureDetector(
onTap: () => menuClick(workoutTree, menuBloc),
child: Text(
workoutTree.name,
maxLines: 4,
style: GoogleFonts.archivoBlack(color: workoutTree.color, fontSize: workoutTree.fontSize, height: 1.1),
),
),
),
]))));
});
}
_columnChildren.add(SizedBox(
height: 50,
));
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 = [];
int index = 0;
menuBloc.exerciseDeviceRepository.getGymDevices().forEach((element) {
String deviceName = AppLanguage().appLocal == Locale('en') ? element.name : element.nameTranslation;
ChoiceChip chip = ChoiceChip(
labelPadding: EdgeInsets.only(right: 3),
avatar: Icon(
Icons.remove_circle_outline,
color: Colors.orange,
size: 10,
),
label: Text(deviceName),
labelStyle: TextStyle(fontSize: 9, color: Colors.indigo),
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);
if (index == 4) {
list.add(Divider());
}
index++;
});
SliverGrid sliverList = SliverGrid(
delegate: SliverChildListDelegate(list),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4,
mainAxisSpacing: 1.5,
crossAxisSpacing: 1.5,
childAspectRatio: 2.5,
));
return sliverList;
}
SliverAppBar getInfoWidget(BuildContext context, MenuBloc menuBloc) {
menuBloc.setContext(context);
SliverAppBar sliverAppBar = SliverAppBar(
automaticallyImplyLeading: false,
backgroundColor: Colors.transparent,
title: Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [
!activeExercisePlan
? SizedBox(
width: 50,
)
: SizedBox(
width: 10,
),
MenuSearchBar(
listItems: menuBloc.menuTreeRepository.menuAsExercise,
onFind: (value) {
if (Cache().userLoggedIn == null) {
ScaffoldMessenger.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);
}
},
),
Cache().activeExercisePlan != null
? GestureDetector(
onTap: () => showDialog(
context: context,
builder: (BuildContext context) {
return DialogCommon(
title: t("You have an active Test Set!"),
descriptions: Cache().activeExercisePlan!.name,
description2: t("Press OK to continue"),
text: "OK",
onTap: () => {
Navigator.of(context).pop(),
if (Cache().activeExercisePlan != null)
{
Navigator.of(context).popAndPushNamed("testSetExecute"),
}
},
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(),
activeExercisePlan
? SizedBox(
width: 10,
)
: Offstage(),
]));
return sliverAppBar;
}
void menuClick(WorkoutMenuTree workoutTree, MenuBloc menuBloc) {
/* if (tutorialBloc.isActive) {
final String checkText = workoutTree.nameEnglish;
if (!tutorialBloc.checkAction(checkText)) {
return;
}
} */
print("ability: ${menuBloc.ability} tree: $workoutTree parent: ${workoutTree.parent}");
if (workoutTree.child == false) {
if (menuBloc.ability != null && 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 if (menuBloc.ability != null && ExerciseAbility.training.equalsTo(menuBloc.ability!) && workoutTree.parent != 0) {
HashMap<String, dynamic> args = HashMap();
args['parentName'] = workoutTree.internalName;
Navigator.of(context).pushNamed("myTrainingPlanActivate", arguments: args);
menuBloc.add(MenuTreeDown(item: workoutTree, parent: workoutTree.id));
} else if (workoutTree.internalName == "training_execute") {
/* Cache().myTrainingPlan = null;
Cache().deleteMyTrainingPlan(); */
if (Cache().myTrainingPlan != null) {
final TrainingPlanBloc bloc = BlocProvider.of<TrainingPlanBloc>(context);
bloc.setMyPlan(Cache().myTrainingPlan);
Navigator.of(context).pushNamed("myTrainingPlanExecute");
} else {
showDialog(
context: context,
builder: (BuildContext context) {
return DialogCommon(
title: t("No selected Training Plan"),
descriptions: t("Based on your initial data, we will generate the personalized training plan for you."),
text: "OK",
onTap: () {
TrainingPlanRepository trainingPlanRepository = TrainingPlanRepository();
trainingPlanRepository.generateTrainingPlan();
final TrainingPlanBloc bloc = BlocProvider.of<TrainingPlanBloc>(context);
bloc.setMyPlan(Cache().myTrainingPlan);
Future.delayed(Duration(milliseconds: 1000), () async {
Navigator.of(context).pushNamed("myTrainingPlanExecute");
});
},
onCancel: () => {
Navigator.of(context).pop(),
},
);
});
}
} else {
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 {
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 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 = MenuImage(imageName: workoutMenuTree.imageName, workoutTreeId: workoutMenuTree.id);
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,
);
}
@override
void dispose() {
scrollController.dispose();
super.dispose();
}
}