WT 1.1.14 Tutorial, Sports, New goals
This commit is contained in:
@@ -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
@@ -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();
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user