WT 1.1.14 Tutorial, Sports, New goals

This commit is contained in:
bossanyit
2021-05-02 17:12:42 +02:00
parent 5fe8f76f48
commit c901b07bf8
65 changed files with 2472 additions and 620 deletions
+8 -4
View File
@@ -9,6 +9,7 @@ class DialogCommon extends StatefulWidget {
final VoidCallback? onCancel;
String? description2, description3;
final Image? img;
final bool warning;
DialogCommon(
{Key? key,
@@ -19,7 +20,8 @@ class DialogCommon extends StatefulWidget {
required this.text,
this.img,
required this.onTap,
required this.onCancel})
required this.onCancel,
this.warning = false})
: super(key: key) {
description2 = description2 ?? "";
description3 = description3 ?? "";
@@ -72,11 +74,11 @@ class _DialogPremiumState extends State<DialogCommon> with Trans {
alignment: AlignmentDirectional.topEnd,
children: [
Text(
widget.title + " ",
widget.title,
textAlign: TextAlign.center,
style: GoogleFonts.archivoBlack(
fontSize: 20,
color: Colors.yellow[400],
color: widget.warning ? Colors.red[800] : Colors.yellow[400],
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
@@ -173,7 +175,9 @@ class _DialogPremiumState extends State<DialogCommon> with Trans {
child: Stack(
alignment: Alignment.center,
children: [
Image.asset('asset/icon/gomb_orange_c.png', width: 100, height: 45),
widget.warning
? Image.asset('asset/icon/gomb_pink_b.png', width: 100, height: 45)
: Image.asset('asset/icon/gomb_orange_c.png', width: 100, height: 45),
Text(
t("OK"),
style: TextStyle(fontSize: 16, color: Colors.white),
+21 -9
View File
@@ -2,9 +2,11 @@ import 'package:aitrainer_app/bloc/session/session_bloc.dart';
import 'package:aitrainer_app/bloc/settings/settings_bloc.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/service/logging.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/view/login.dart';
import 'package:aitrainer_app/view/menu_page.dart';
import 'package:aitrainer_app/view/registration.dart';
import 'package:aitrainer_app/widgets/dialog_common.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
@@ -22,7 +24,7 @@ class AitrainerHome extends StatefulWidget {
}
}
class _HomePageState extends State<AitrainerHome> with Logging {
class _HomePageState extends State<AitrainerHome> with Logging, Trans {
GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
@override
@@ -50,16 +52,26 @@ class _HomePageState extends State<AitrainerHome> with Logging {
@override
Widget build(BuildContext context) {
setContext(context);
return Scaffold(
key: _scaffoldKey,
body: BlocConsumer<SessionBloc, SessionState>(listener: (context, state) {
if (state is SessionFailure) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(
state.message,
),
backgroundColor: Colors.orange,
));
showDialog(
context: context,
builder: (BuildContext context) {
return DialogCommon(
title: t("Error"),
descriptions: t(state.message),
text: "OK",
onTap: () => {
Navigator.of(context).pop(),
},
onCancel: () => {
Navigator.of(context).pop(),
},
);
});
}
}, builder: (context, state) {
if (state is SessionInitial) {
@@ -78,8 +90,8 @@ class _HomePageState extends State<AitrainerHome> with Logging {
}
} else {
log("home: unknown state");
//return MenuPage(parent: 0);
return LoginPage();
return MenuPage(parent: 0);
//return LoginPage();
}
}),
);
+57 -74
View File
@@ -1,8 +1,8 @@
import 'dart:collection';
import 'dart:ui';
import 'package:aitrainer_app/bloc/tutorial/tutorial_bloc.dart';
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';
@@ -14,6 +14,7 @@ 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:aitrainer_app/widgets/tutorial_widget.dart';
import 'package:badges/badges.dart';
import 'package:ezanimation/ezanimation.dart';
import 'package:flutter/cupertino.dart';
@@ -39,6 +40,7 @@ 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);
@@ -52,29 +54,52 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
animation.reverse();
}
});
animation.addListener(() {
//setState(() {});
});
animation.addListener(() {});
}
/// We require the initializers to run after the loading screen is rendered
SchedulerBinding.instance!.addPostFrameCallback((_) {
menuBloc.add(MenuCreate());
//runDelayedEvent();
});
super.initState();
}
Future runDelayedEvent() async {
print("runDelayedEvent start");
bool isFirst = false;
await Future.delayed(Duration(milliseconds: 600), () async {
if (tutorialBloc.isActive == false) {
print("Activate tutorial");
tutorialBloc.canActivate = true;
tutorialBloc.isActive = true;
tutorialBloc.menuBloc = menuBloc;
tutorialBloc.add(TutorialLoad());
tutorialBloc.init();
isFirst = true;
}
});
final bool canActivate = tutorialBloc.activateTutorial();
if (canActivate) {
if (!isFirst) {
TutorialWidget().tip(context);
}
}
}
@override
bool didUpdateWidget(MenuPageWidget oldWidget) {
super.didUpdateWidget(oldWidget);
scrollController.animateTo(5, duration: Duration(milliseconds: 300), curve: Curves.easeIn);
runDelayedEvent();
return true;
}
@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;
@@ -83,11 +108,12 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
widget.parent = 0;
}
return CustomScrollView(
// Must add scrollController to sliver root
controller: scrollController,
scrollDirection: Axis.vertical,
slivers: buildMenuColumn(widget.parent!, context, menuBloc, cWidth, cHeight));
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) {
@@ -151,19 +177,12 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
child: Stack(alignment: Alignment.bottomLeft, children: [
TextButton(
child: badgedIcon(workoutTree, cWidth, cHeight),
onPressed: () => menuClick(workoutTree, menuBloc, context),
onPressed: () => menuClick(workoutTree, menuBloc),
),
/* 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: 8, right: 15),
child: GestureDetector(
onTap: () => menuClick(workoutTree, menuBloc, context),
onTap: () => menuClick(workoutTree, menuBloc),
child: Text(
workoutTree.name,
maxLines: 4,
@@ -174,19 +193,6 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
])))));
});
}
/* 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),
@@ -273,7 +279,6 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
SliverAppBar getInfoWidget(BuildContext context, MenuBloc menuBloc) {
menuBloc.setContext(context);
menuBloc.setMenuInfo();
SliverAppBar sliverAppBar = SliverAppBar(
automaticallyImplyLeading: false,
@@ -286,28 +291,6 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
: 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) {
@@ -365,28 +348,28 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
return sliverAppBar;
}
void menuClick(WorkoutMenuTree workoutTree, MenuBloc menuBloc, BuildContext context) {
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))));
void menuClick(WorkoutMenuTree workoutTree, MenuBloc menuBloc) {
if (tutorialBloc.isActive) {
final String checkText = workoutTree.nameEnglish;
if (!tutorialBloc.checkAction(checkText)) {
return;
}
}
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 (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 {
menuBloc.add(MenuClickExercise(exerciseTypeId: workoutTree.id));
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);
}
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);
}
}
}
+152
View File
@@ -0,0 +1,152 @@
import 'package:aitrainer_app/bloc/tutorial/tutorial_bloc.dart';
import 'package:aitrainer_app/service/logging.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:flutter_html/style.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:aitrainer_app/library/super_tooltip.dart';
class TutorialWidget with Trans, Logging {
static final TutorialWidget _singleton = TutorialWidget._internal();
SuperTooltip? tooltip;
TutorialWidget._internal();
factory TutorialWidget() {
return _singleton;
}
void close() {
if (tooltip != null && tooltip!.isOpen) {
tooltip!.close();
}
}
void tip(BuildContext context) {
setContext(context);
var renderBox = context.findRenderObject() as RenderBox;
final overlay = Overlay.of(context)!.context.findRenderObject() as RenderBox?;
var targetGlobalCenter = renderBox.localToGlobal(renderBox.size.center(Offset.zero), ancestor: overlay);
final TutorialBloc bloc = BlocProvider.of<TutorialBloc>(context);
if (tooltip != null && tooltip!.isOpen) {
tooltip!.rebuild();
}
Rect? area;
if (bloc.action != null) {
area = bloc.action!.showBubble == true
? Rect.fromLTWH(targetGlobalCenter.dx - bloc.action!.bubbleX, targetGlobalCenter.dy - bloc.action!.bubbleY,
bloc.action!.bubbleWidth.toDouble(), bloc.action!.bubbleHeight.toDouble())
: null;
}
final double mediaSize = MediaQuery.of(context).size.width;
double fontSize = 14;
if (mediaSize > 400) {
fontSize = 15;
} else if (mediaSize < 375) {
fontSize = 13;
}
tooltip = SuperTooltip(
top: bloc.top,
left: bloc.left,
backgroundColor: Colors.black.withOpacity(0.7),
popupDirection: bloc.action == null || bloc.action!.direction == "up" ? TooltipDirection.up : TooltipDirection.down,
maxWidth: 390,
minWidth: 300,
minHeight: 100,
maxHeight: 300,
borderColor: Colors.orange,
borderWidth: 1.0,
minimumOutSidePadding: 20,
snapsFarAwayVertically: false,
showCloseButton: ShowCloseButton.inside,
closeButtonColor: Colors.grey,
dismissOnTapOutside: false,
outsideBackgroundColor: Colors.black.withOpacity(0.6),
hasShadow: true,
touchThrougArea: area,
onClose: () => bloc.add(TutorialFinished()),
custom: true,
touchThroughAreaShape: ClipAreaShape.oval,
content: new Material(
color: Colors.transparent,
child: Padding(
padding: const EdgeInsets.only(top: 20.0),
child: Stack(alignment: Alignment.bottomRight, children: [
SingleChildScrollView(
child: Html(
data: bloc.actualText! + "<p><br/> </p>",
//Optional parameters:
style: {
"p": Style(
color: Colors.white,
fontSize: FontSize(fontSize),
padding: const EdgeInsets.all(4),
),
"li": Style(
color: Colors.white,
fontSize: FontSize(fontSize),
padding: const EdgeInsets.only(left: 4),
),
"h2": Style(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: FontSize.larger,
//padding: const EdgeInsets.all(4),
),
"h1": Style(
color: Colors.yellow[400],
fontWeight: FontWeight.bold,
fontSize: FontSize.larger,
alignment: Alignment.center,
padding: const EdgeInsets.all(4),
),
},
)),
bloc.showCheckText
? bloc.checks.length > 1
? Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.transparent,
),
onPressed: () => {bloc.add(TutorialNext(text: bloc.checks[0]))},
child: Text("« " + t(bloc.checks[0]),
style: GoogleFonts.archivoBlack(color: Colors.orange[400]!, fontSize: fontSize)),
),
ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.transparent,
),
onPressed: () => {bloc.add(TutorialNext(text: bloc.checks[1]))},
child: Text(t(bloc.checks[1]) + " »",
style: GoogleFonts.archivoBlack(color: Colors.orange[400]!, fontSize: fontSize)),
),
],
)
: ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.transparent,
),
onPressed: () => {
//tooltip!.rebuild(context),
bloc.add(TutorialNext(text: bloc.checks[0])),
},
child: Text(t(bloc.checks[0]) + " »",
style: GoogleFonts.archivoBlack(color: Colors.orange[400]!, fontSize: fontSize)),
)
: Offstage(),
]),
)),
);
tooltip!.show(context);
}
}