WT 1.1.18+4 A/B Test sales page

This commit is contained in:
bossanyit
2021-06-05 15:39:12 +02:00
parent d5deaf48a9
commit 0ca3b71c03
48 changed files with 734 additions and 1223 deletions
-227
View File
@@ -1,227 +0,0 @@
import 'dart:collection';
import 'package:aitrainer_app/bloc/exercise_execute_plan/exercise_execute_plan_bloc.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/workout_menu_tree.dart';
import 'package:aitrainer_app/library/tree_view.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar.dart';
import 'package:aitrainer_app/widgets/bottom_nav.dart';
import 'package:aitrainer_app/widgets/treeview_parent_widget.dart';
import 'package:flutter/cupertino.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';
class ExerciseExecutePage extends StatefulWidget {
@override
_ExerciseExecutePage createState() => _ExerciseExecutePage();
}
class _ExerciseExecutePage extends State<ExerciseExecutePage> with Trans {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
// ignore: close_sinks
late ExerciseExecutePlanBloc bloc;
@override
void initState() {
super.initState();
/// We require the initializers to run after the loading screen is rendered
SchedulerBinding.instance!.addPostFrameCallback((_) {
BlocProvider.of<ExerciseExecutePlanBloc>(context).add(ExerciseByPlanLoad());
});
}
@override
Widget build(BuildContext context) {
LinkedHashMap arguments = ModalRoute.of(context)!.settings.arguments as LinkedHashMap;
final int customerId = arguments['customerId'];
bloc = BlocProvider.of<ExerciseExecutePlanBloc>(context);
bloc.customerId = customerId;
setContext(context);
return Scaffold(
key: _scaffoldKey,
appBar: AppBarNav(depth: 1),
body: Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
image: DecorationImage(
image: customerId == Cache().userLoggedIn!.customerId
? AssetImage('asset/image/WT_black_background.jpg')
: AssetImage('asset/image/WT_light_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
child: BlocConsumer<ExerciseExecutePlanBloc, ExerciseExecutePlanState>(listener: (context, state) {
if (state is ExerciseByPlanError) {
//LoadingDialog.hide(context);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(
state.message,
),
backgroundColor: Colors.orange,
));
} else if (state is ExerciseByPlanLoading) {
//LoadingDialog.show(context);
}
}, builder: (context, state) {
if (state is ExerciseByPlanStateInitial || state is ExerciseByPlanLoading) {
return Container();
} else if (state is ExerciseByPlanReady) {
//LoadingDialog.hide(context);
return exerciseWidget(bloc);
} else {
return exerciseWidget(bloc);
}
})),
bottomNavigationBar: BottomNavigator(bottomNavIndex: 2),
);
}
Widget exerciseWidget(ExerciseExecutePlanBloc bloc) {
return TreeView(
startExpanded: false,
children: nodeExercisePlan(bloc),
);
}
List<Widget> nodeExercisePlan(ExerciseExecutePlanBloc bloc) {
List<Widget> exerciseTypes = [];
Card explanation = Card(
color: Colors.white38,
child: Container(
padding: EdgeInsets.only(left: 10, right: 5, top: 12, bottom: 8),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Row(
children: [
Icon(
Icons.info,
color: Colors.orangeAccent,
),
Text(" "),
Flexible(
child: Text(
t("Execute your active Exercise Plan!"),
style: GoogleFonts.archivoBlack(
fontSize: 20,
),
maxLines: 2,
),
),
],
),
Divider(
color: Colors.transparent,
),
Text(
t("Select the muscle type and tap on the exercise. One the next page enter the weight and repeat."),
style: TextStyle(fontSize: 12, fontWeight: FontWeight.normal),
),
],
)));
exerciseTypes.add(explanation);
if (bloc.selectedNumber == 0) {
exerciseTypes.add(Container(
child: Center(
child: Text(
t("Please define your Exercise Plan"),
style: GoogleFonts.inter(color: Colors.white),
))));
exerciseTypes.add(Container(
child: Center(
child: Text(
t("Go to: 'Training Plan' - 'Edit My Custom Plan'"),
style: GoogleFonts.inter(color: Colors.white),
))));
exerciseTypes.add(Container(
child: Center(
child: InkWell(
onTap: () {
final LinkedHashMap args = LinkedHashMap();
args['customerId'] = Cache().userLoggedIn!.customerId;
Navigator.of(context).pop();
Navigator.of(context).pushNamed('exercisePlanCustomPage', arguments: args);
},
child: Text(
t("Jump there »"),
style: GoogleFonts.inter(color: Colors.blue[200], decorationStyle: TextDecorationStyle.solid),
)))));
} else {
bloc.menuTreeRepository.sortedTree.forEach((name, list) {
exerciseTypes.add(Container(
margin: const EdgeInsets.only(left: 4.0),
child: TreeViewChild(
startExpanded: true,
parent: TreeviewParentWidget(text: name),
children: _getChildList(list, bloc),
)));
});
}
return exerciseTypes;
}
List<Widget> _getChildList(List<WorkoutMenuTree> listWorkoutTree, ExerciseExecutePlanBloc bloc) {
List<Widget> list = [];
listWorkoutTree.forEach((element) {
if (element.selected) {
list.add(TreeViewChild(
startExpanded: false,
parent: Card(
margin: EdgeInsets.only(left: 10, top: 5),
color: Colors.white54,
child: Container(
padding: const EdgeInsets.only(left: 5, top: 0, right: 5, bottom: 0),
child: Row(mainAxisAlignment: MainAxisAlignment.start, children: [
IconButton(
icon: element.executed
? Icon(Icons.check_box, color: Colors.green[200])
: Icon(
Icons.indeterminate_check_box,
color: Colors.blue.shade800,
),
onPressed: () => {addExerciseByPlanEvent(bloc, element)},
),
SizedBox(width: 20),
Flexible(
fit: FlexFit.tight,
child: InkWell(
child: Text(
element.name,
textAlign: TextAlign.start,
style: GoogleFonts.inter(fontSize: 17, color: Colors.black),
),
onTap: () => {addExerciseByPlanEvent(bloc, element)},
),
),
IconButton(
padding: EdgeInsets.all(0),
icon: Icon(
Icons.info,
color: Colors.black12,
),
onPressed: () {},
),
]),
)),
children: []));
}
});
return list;
}
void addExerciseByPlanEvent(ExerciseExecutePlanBloc bloc, WorkoutMenuTree workoutTree) {
LinkedHashMap args = LinkedHashMap();
args['blocExerciseByPlan'] = bloc;
args['customerId'] = bloc.customerId;
args['workoutTree'] = workoutTree;
Navigator.of(context).pushNamed("exerciseExecuteAddPage", arguments: args);
}
}
@@ -1,284 +0,0 @@
import 'dart:collection';
import 'package:aitrainer_app/bloc/exercise_execute_plan/exercise_execute_plan_bloc.dart';
import 'package:aitrainer_app/bloc/exercise_execute_plan_add/exercise_execute_plan_add_bloc.dart';
import 'package:aitrainer_app/library/custom_icon_icons.dart';
import 'package:aitrainer_app/util/app_language.dart';
import 'package:aitrainer_app/model/workout_menu_tree.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar.dart';
import 'package:aitrainer_app/widgets/number_picker.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart';
class ExerciseExecutePlanAddPage extends StatefulWidget {
_ExerciseExecuteAddPage createState() => _ExerciseExecuteAddPage();
}
class _ExerciseExecuteAddPage extends State<ExerciseExecutePlanAddPage> with Trans {
final ScrollController _controller = ScrollController();
double offset = 0;
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
LinkedHashMap arguments = ModalRoute.of(context)!.settings.arguments as LinkedHashMap;
// ignore: close_sinks
final ExerciseExecutePlanBloc planBloc = arguments['blocExerciseByPlan'];
final int customerId = arguments['customerId'];
final WorkoutMenuTree workoutTree = arguments['workoutTree'];
final ExerciseRepository exerciseRepository = ExerciseRepository();
setContext(context);
return BlocProvider(
create: (context) => ExerciseExecutePlanAddBloc(
exerciseRepository: exerciseRepository,
exercisePlanRepository: planBloc.exercisePlanRepository,
customerId: customerId,
workoutTree: workoutTree,
planBloc: planBloc)
..add(ExerciseExecutePlanAddLoad()),
child: BlocConsumer<ExerciseExecutePlanAddBloc, ExerciseExecutePlanAddState>(listener: (context, state) {
if (state is ExerciseExecutePlanAddError) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
}
}, builder: (context, state) {
// ignore: close_sinks
final exerciseBloc = BlocProvider.of<ExerciseExecutePlanAddBloc>(context);
if (state is ExerciseExecutePlanAddReady && _controller.hasClients) {
_controller.animateTo(exerciseBloc.scrollOffset, duration: Duration(milliseconds: 300), curve: Curves.easeIn);
}
return ModalProgressHUD(
child: getControlForm(exerciseBloc),
inAsyncCall: state is ExerciseExecutePlanAddLoading,
opacity: 0.5,
color: Colors.black54,
progressIndicator: CircularProgressIndicator(),
);
}));
}
Widget getControlForm(ExerciseExecutePlanAddBloc exerciseBloc) {
if (exerciseBloc.exerciseRepository.exerciseType == null || exerciseBloc.quantity == null) {
return Offstage();
}
String exerciseName = AppLanguage().appLocal == Locale("en")
? exerciseBloc.exerciseRepository.exerciseType!.name
: exerciseBloc.exerciseRepository.exerciseType!.nameTranslation;
return Form(
child: Scaffold(
resizeToAvoidBottomInset: true,
appBar: AppBarNav(depth: 1),
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_black_background.jpg'),
fit: BoxFit.fill,
alignment: Alignment.center,
),
),
child: Container(
padding: const EdgeInsets.only(top: 25, left: 25, right: 25),
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
physics: BouncingScrollPhysics(),
controller: _controller,
child: Column(mainAxisAlignment: MainAxisAlignment.spaceAround, children: <Widget>[
Text(
t("Save Exercise"),
style: GoogleFonts.inter(fontSize: 16, color: Colors.orange[50]),
),
Text(
exerciseName,
style: GoogleFonts.archivoBlack(
fontSize: 24,
color: Colors.orange[700],
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,
overflow: TextOverflow.fade,
maxLines: 3,
softWrap: true,
),
Divider(
color: Colors.transparent,
),
Divider(),
Column(
children: repeatExercises(exerciseBloc),
),
Divider(),
]),
))),
),
);
}
List<Column> repeatExercises(ExerciseExecutePlanAddBloc exerciseBloc) {
List<Column> listColumns = [];
for (int i = 0; i < exerciseBloc.countSteps; i++) {
Column col = Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Divider(
color: Colors.transparent,
),
RichText(
text: TextSpan(
style: GoogleFonts.inter(
fontSize: 16,
fontWeight: FontWeight.normal,
color: Colors.yellow[300],
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,
),
],
),
children: [
TextSpan(text: t("Execute the") + " "),
TextSpan(
text: (i + 1).toString() + ". ",
style: GoogleFonts.inter(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.yellow[600],
),
),
TextSpan(text: t("set!"))
]),
),
Divider(
color: Colors.transparent,
),
Row(mainAxisAlignment: MainAxisAlignment.start, children: [
exerciseBloc.exerciseRepository.exerciseType!.unitQuantityUnit == null
? Offstage()
: NumberPickerWidget(
minValue: 0,
maxValue: 1000,
fontSize: 16,
initalValue: exerciseBloc.unitQuantity!.toInt(),
unit: t(exerciseBloc.exerciseRepository.exerciseType!.unitQuantityUnit!),
color: Colors.yellow[50]!,
onChange: (value) => {exerciseBloc.add(ExerciseExecutePlanAddChangeUnitQuantity(quantity: value.toDouble()))}),
NumberPickerWidget(
minValue: 0,
maxValue: 200,
fontSize: 16,
initalValue: exerciseBloc.quantity!.toInt(),
unit: t(exerciseBloc.exerciseRepository.exerciseType!.unit), //t("repeat"),
color: Colors.yellow[50]!,
onChange: (value) => {exerciseBloc.add(ExerciseExecutePlanAddChangeQuantity(quantity: value.toDouble()))}),
]),
TextButton(
style: TextButton.styleFrom(
padding: EdgeInsets.all(0),
primary: Colors.white,
onSurface: Colors.blueAccent,
),
onPressed: () => {
if (exerciseBloc.step == i + 1) {exerciseBloc.add(ExerciseExecutePlanAddSubmit())},
if (i + 1 == exerciseBloc.countSteps) {Navigator.of(context).pop()}
},
child: exerciseBloc.step == i + 1
? Stack(
alignment: Alignment.center,
children: [
Image.asset('asset/icon/gomb_orange_c.png', width: 140, height: 60),
Text(
t("Save"),
style: TextStyle(fontSize: 16, color: Colors.white),
),
],
)
: Stack(
alignment: Alignment.center,
children: getButton(i + 1, exerciseBloc),
)),
/* Row(children: [
NumberPicker.horizontal(
highlightSelectedValue: (i + 1) == exerciseBloc.step,
initialValue: exerciseBloc.quantity.toInt(),
minValue: 0,
maxValue: 200,
step: 1,
textStyle: TextStyle(fontWeight: FontWeight.bold),
textStyleHighlighted: TextStyle(fontSize: 24, color: Colors.deepOrange, fontWeight: FontWeight.bold),
onChanged: (value) => {exerciseBloc.add(ExerciseExecutePlanAddChangeQuantity(quantity: value.toDouble()))},
listViewHeight: 80,
//decoration: _decoration,
),
Text(t("repeat")),
]), */
/* RaisedButton(
padding: EdgeInsets.all(0),
textColor: Colors.white,
color: exerciseBloc.step == i + 1 ? Colors.blue : Colors.black26,
focusColor: Colors.blueAccent,
onPressed: () => {
if (exerciseBloc.step == i + 1) {exerciseBloc.add(ExerciseExecutePlanAddSubmit())},
if (i + 1 == exerciseBloc.countSteps) {Navigator.of(context).pop()}
},
child: Text(
t("Save"),
style: TextStyle(fontSize: 12),
)), */
Divider(),
],
);
listColumns.add(col);
}
return listColumns;
}
List<Widget> getButton(int step, ExerciseExecutePlanAddBloc exerciseBloc) {
List<Widget> widgets = [];
if (step < exerciseBloc.step) {
widgets.add(Icon(
CustomIcon.check_circle,
color: Color(0xffb4f500),
size: 36,
));
} else {
widgets.add(Icon(
CustomIcon.question,
color: Colors.grey[700],
size: 36,
));
}
return widgets;
}
}
+1 -1
View File
@@ -220,7 +220,7 @@ class ExerciseLogPage extends StatelessWidget with Trans, Common {
return DialogPremium(
unlocked: Cache().hasPurchased,
unlockRound: 1,
unlockedText: t("Enjoy also this premium fetaure to show all old evaluation data of your successful exercises."),
unlockedText: t("Enjoy also this premium feature to show all old evaluation data of your successful exercises."),
function: "My Exercise Logs",
onTap: () => {Navigator.of(context).pop()},
onCancel: () => {Navigator.of(context).pop()},
+34 -19
View File
@@ -5,6 +5,7 @@ import 'package:aitrainer_app/repository/customer_repository.dart';
import 'package:aitrainer_app/repository/exercise_repository.dart';
import 'package:aitrainer_app/util/enums.dart';
import 'package:aitrainer_app/util/track.dart';
import 'package:aitrainer_app/widgets/dialog_common.dart';
import 'package:aitrainer_app/widgets/dialog_premium.dart';
import 'package:badges/badges.dart';
import 'package:google_fonts/google_fonts.dart';
@@ -93,29 +94,27 @@ class _MyDevelopmentPage extends State<MyDevelopmentPage> with Trans {
Navigator.of(context).pushNamed('mydevelopmentBodyPage', arguments: args)
}
else
{}
},
isLocked: true,
),
/* ImageButton(
width: imageWidth,
textAlignment: Alignment.topLeft,
text: t("My Sizes Development"),
style: GoogleFonts.robotoMono(
textStyle: TextStyle(
fontSize: 14, color: Colors.white, fontWeight: FontWeight.bold, backgroundColor: Colors.black54.withOpacity(0.4)),
),
image: "asset/image/testemfejl400x400.jpg",
left: 5,
onTap: () => {
if (Cache().userLoggedIn != null)
{
args['customerId'] = Cache().userLoggedIn.customerId,
Navigator.of(context).pushNamed('mydevelopmentSizesPage', arguments: args)
showDialog(
context: context,
builder: (BuildContext context) {
return DialogCommon(
warning: true,
title: t("Warning"),
descriptions: t("Please log in"),
description2:
t("because only that way can we show you the personalized development diagrams and analysises"),
text: "OK",
onTap: () => Navigator.of(context).popAndPushNamed("login"),
onCancel: () => {
Navigator.of(context).pop(),
},
);
})
}
},
isLocked: true,
), */
),
Badge(
padding: EdgeInsets.all(8),
position: BadgePosition.topEnd(top: -5, end: -3),
@@ -221,6 +220,22 @@ class _MyDevelopmentPage extends State<MyDevelopmentPage> with Trans {
args['customerRepository'] = customerRepository;
args['customerId'] = Cache().userLoggedIn!.customerId;
Navigator.of(context).pushNamed('exerciseLogPage', arguments: args);
} else {
showDialog(
context: context,
builder: (BuildContext context) {
return DialogCommon(
warning: true,
title: t("Warning"),
descriptions: t("Please log in"),
description2: t("because only that way can we show you your exercises, results and evaluations."),
text: "OK",
onTap: () => Navigator.of(context).popAndPushNamed("login"),
onCancel: () => {
Navigator.of(context).pop(),
},
);
});
}
}
}
+2 -3
View File
@@ -104,7 +104,7 @@ class RegistrationPage extends StatelessWidget with Trans {
child: Text(
t("Skip"),
textAlign: TextAlign.right,
style: GoogleFonts.inter(color: Colors.black, decoration: TextDecoration.underline),
style: GoogleFonts.inter(color: loginBloc.testColor, decoration: TextDecoration.underline),
)),
SizedBox(
height: 120,
@@ -203,7 +203,7 @@ class RegistrationPage extends StatelessWidget with Trans {
color: Colors.transparent,
),
getDataProtection(loginBloc),
getEmailSubscription(loginBloc),
loginBloc.emailCheckbox ? getEmailSubscription(loginBloc) : Offstage(),
Divider(
color: Colors.transparent,
),
@@ -220,7 +220,6 @@ class RegistrationPage extends StatelessWidget with Trans {
),
],
),
//Image.asset('asset/icon/gomb_zold_b-1.png', width: 100, height: 100),
onPressed: () => {loginBloc.add(RegistrationSubmit())}),
]),
Divider(
+177 -101
View File
@@ -62,6 +62,8 @@ class SalesPage extends StatelessWidget with Trans, Logging {
final salesText = bloc.salesText != null ? bloc.salesText! : "";
final String html = salesText;
log("start SalesPageBuild");
return Container(
decoration: BoxDecoration(
image: DecorationImage(
@@ -80,33 +82,70 @@ class SalesPage extends StatelessWidget with Trans, Logging {
"p": Style(
color: Colors.white,
fontSize: FontSize(16),
padding: const EdgeInsets.only(left: 20, right: 8, bottom: 4),
padding: const EdgeInsets.only(left: 10, right: 8, bottom: 4),
textShadow: <Shadow>[
Shadow(
offset: Offset(3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 6.0,
color: Colors.black54,
),
],
),
"strong": Style(
color: Colors.yellow[600],
color: Colors.orange[600],
fontSize: FontSize(16),
),
"h3": Style(
color: Colors.yellow[600],
color: Colors.orange[600],
fontSize: FontSize(16),
textAlign: TextAlign.center,
padding: const EdgeInsets.all(12),
),
"li": Style(
color: Colors.white,
fontSize: FontSize(14),
padding: const EdgeInsets.only(left: 20, bottom: 10, right: 8),
//before: "*",
display: Display.LIST_ITEM),
color: Colors.white,
fontSize: FontSize(16),
padding: const EdgeInsets.only(left: 10, bottom: 10, right: 8),
//before: "*",
textShadow: <Shadow>[
Shadow(
offset: Offset(3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 6.0,
color: Colors.black54,
),
],
//display: Display.LIST_ITEM,
),
"h2": Style(
color: Colors.yellow[600],
color: Colors.orange[600],
fontWeight: FontWeight.bold,
fontSize: FontSize(24),
textAlign: TextAlign.center,
textShadow: <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,
),
],
//padding: const EdgeInsets.all(4),
),
"h1": Style(
color: Colors.yellow[400],
color: Colors.orange[400],
fontWeight: FontWeight.bold,
fontSize: FontSize.larger,
alignment: Alignment.center,
@@ -115,100 +154,137 @@ class SalesPage extends StatelessWidget with Trans, Logging {
},
), // final Color bgrColor = Color(0xffb4f500);
//final Color bgrColorEnd = Colors.blue;
AnimatedButton(
child: Html(
data: bloc.salesButtonText,
//Optional parameters:
style: {
"p": Style(
color: Colors.black,
fontSize: FontSize(16),
padding: const EdgeInsets.all(4),
textAlign: TextAlign.center,
textShadow: [
Shadow(
offset: Offset(2.0, 2.0),
blurRadius: 6.0,
color: Colors.black54,
)
],
),
"li": Style(
color: Colors.white,
fontSize: FontSize(14),
padding: const EdgeInsets.only(left: 10, bottom: 10),
before: "*",
),
"h2": Style(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: FontSize.larger,
textAlign: TextAlign.center,
textShadow: [
Shadow(
offset: Offset(2.0, 2.0),
blurRadius: 12.0,
color: Colors.black54,
)
],
//padding: const EdgeInsets.all(4),
),
"h1": Style(
color: Colors.yellow[600],
fontWeight: FontWeight.bold,
fontSize: FontSize.xLarge,
alignment: Alignment.center,
padding: const EdgeInsets.all(4),
textAlign: TextAlign.center,
textShadow: [
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
)
],
),
},
),
duration: 600,
darkShadow: true,
blurRadius: 12,
animationCurve: Curves.easeIn,
height: 120,
width: 320,
onTap: () => bloc.add(SalesPurchase(productId: bloc.offeredProduct!.productId)),
//color: Color(0xffb4f500),
isMultiColor: true,
colors: [
Colors.blue,
Color(0xffb4f500),
Color(0xffb4f500),
],
Container(
padding: EdgeInsets.only(left: 55, right: 55),
child: Text(
t("Tap on the button below the reach all premium content!"),
textAlign: TextAlign.center,
style: GoogleFonts.inter(color: Colors.white, fontSize: 13),
)),
Divider(),
Row(
children: [0, 1].map((idx) {
return Expanded(
flex: 1,
child: Container(
margin: EdgeInsets.symmetric(horizontal: 10),
child: AnimatedButton(
duration: 600,
darkShadow: true,
blurRadius: 12,
animationCurve: Curves.easeIn,
height: 150,
width: 160,
onTap: () => bloc.add(SalesPurchase(productId: bloc.product2Display[idx].productId)),
isMultiColor: true,
colors: [
//Colors.blue,
//Color(0xffb4f500),
//Color(0xffb4f500),
Colors.white,
Colors.yellow[50]!,
Colors.yellow[300]!,
],
child: Html(
data: bloc.productText2Display[idx],
//Optional parameters:
style: {
"p": Style(
color: Colors.blue,
fontSize: FontSize(14),
padding: const EdgeInsets.only(left: 5, right: 8, bottom: 5),
textAlign: TextAlign.center,
),
"strong": Style(
color: Colors.red[800],
fontWeight: FontWeight.bold,
fontSize: FontSize(14),
),
"h3": Style(
color: Colors.yellow[600],
fontSize: FontSize(16),
textAlign: TextAlign.center,
padding: const EdgeInsets.all(12),
),
"li": Style(
color: Colors.white,
fontSize: FontSize(14),
padding: const EdgeInsets.only(left: 5, bottom: 10, right: 5),
//before: "*",
display: Display.LIST_ITEM),
"h2": Style(
color: Colors.blue[600],
fontWeight: FontWeight.bold,
fontSize: FontSize(16),
textAlign: TextAlign.center,
/* textShadow: <Shadow>[
Shadow(
offset: Offset(3.0, 3.0),
blurRadius: 4.0,
color: Colors.black54,
),
], */
),
"h1": Style(
color: Colors.blue[400],
fontWeight: FontWeight.bold,
fontSize: FontSize.larger,
alignment: Alignment.center,
padding: const EdgeInsets.all(4),
),
},
), // final Color bgr
)),
);
}).toList(),
),
getTrialDescription(),
//Divider(),
AnimatedButton(
child: Html(
data: "<p>" + t("View other alternatives") + "</p>",
//Optional parameters:
style: {
"p": Style(
color: Colors.black,
fontSize: FontSize(14),
padding: const EdgeInsets.all(4),
textAlign: TextAlign.center,
),
},
),
onTap: () => bloc.add(SalesChangeSubscription()),
width: 320,
blurRadius: 6,
isMultiColor: true,
colors: [
Colors.white,
Colors.yellow[300]!,
],
Html(
data: bloc.premiumFunctions,
//Optional parameters:
style: {
"p": Style(
color: Colors.white,
fontSize: FontSize(14),
padding: const EdgeInsets.only(left: 10, right: 8, bottom: 4),
),
"strong": Style(
color: Colors.orange[600],
fontSize: FontSize(14),
textShadow: <Shadow>[
Shadow(
offset: Offset(2.0, 2.0),
blurRadius: 4.0,
color: Colors.black54,
),
],
),
"li": Style(
color: Colors.white,
fontSize: FontSize(14),
padding: const EdgeInsets.only(left: 10, bottom: 3, right: 10),
),
"h2": Style(
color: Colors.yellow[600],
fontWeight: FontWeight.bold,
fontSize: FontSize(16),
textAlign: TextAlign.center,
textShadow: <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,
),
],
//padding: const EdgeInsets.all(4),
),
},
),
SizedBox(
+81 -32
View File
@@ -11,6 +11,7 @@ import 'package:aitrainer_app/util/app_language.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar.dart';
import 'package:aitrainer_app/widgets/dialog_common.dart';
import 'package:aitrainer_app/widgets/dialog_premium.dart';
import 'package:aitrainer_app/widgets/menu_image.dart';
import 'package:aitrainer_app/widgets/treeview_parent_widget.dart';
import 'package:flutter/cupertino.dart';
@@ -192,6 +193,8 @@ class TrainingPlanActivatePage extends StatelessWidget with Trans {
List<Widget> _getChildList(TrainingPlan plan, TrainingPlanBloc bloc) {
List<Widget> list = [];
bool restricted = (!plan.free && !Cache().hasPurchased);
list.add(Card(
margin: EdgeInsets.only(left: 10, top: 5),
color: Colors.white60,
@@ -236,48 +239,94 @@ class TrainingPlanActivatePage extends StatelessWidget with Trans {
),
child: Text(t("Start")),
onPressed: () {
if (Cache().myTrainingPlan != null) {
showCupertinoDialog(
useRootNavigator: true,
if (Cache().userLoggedIn == null) {
showDialog(
context: context,
builder: (_) => CupertinoAlertDialog(
title: Text(t("You have an active Training Plan")),
content: Column(children: [
Divider(),
Text(
t("Do you want to override it with"),
style: (TextStyle(color: Colors.blue)),
),
Text(
plan.nameTranslations[AppLanguage().appLocal.toString()]! + "?",
style: (TextStyle(color: Colors.blue[800], fontWeight: FontWeight.bold)),
),
]),
actions: [
TextButton(
child: Text(t("No")),
onPressed: () => Navigator.pop(context),
),
TextButton(
child: Text(t("Yes")),
onPressed: () {
Navigator.pop(context);
bloc.add(TrainingPlanActivate(trainingPlanId: plan.trainingPlanId));
},
)
],
));
builder: (BuildContext context) {
return DialogCommon(
warning: true,
title: t("Warning"),
descriptions: t("Please log in"),
description2: t("because only that way can we generated the training plan for you."),
text: "OK",
onTap: () => Navigator.of(context).popAndPushNamed("login"),
onCancel: () => {
Navigator.of(context).pop(),
},
);
});
} else {
bloc.add(TrainingPlanActivate(trainingPlanId: plan.trainingPlanId));
if (restricted) {
showDialog(
context: context,
builder: (BuildContext context) {
return DialogPremium(
unlocked: Cache().hasPurchased,
unlockRound: 1,
unlockedText: t("Enjoy also this premium feature") + " " + t("to activate all available training programs."),
function: "Training Programs",
onTap: () => {Navigator.of(context).pop()},
onCancel: () => {Navigator.of(context).pop()},
);
});
} else {
activate(plan, bloc);
}
}
},
)
),
restricted
? Container(
padding: EdgeInsets.only(bottom: 8),
child: Text(
t("This is a premium function"),
style: GoogleFonts.inter(color: Colors.blue[700]),
),
)
: Offstage(),
]),
)));
return list;
}
void activate(TrainingPlan plan, TrainingPlanBloc bloc) {
if (Cache().myTrainingPlan != null) {
showCupertinoDialog(
useRootNavigator: true,
context: context,
builder: (_) => CupertinoAlertDialog(
title: Text(t("You have an active Training Plan")),
content: Column(children: [
Divider(),
Text(
t("Do you want to override it with"),
style: (TextStyle(color: Colors.blue)),
),
Text(
plan.nameTranslations[AppLanguage().appLocal.toString()]! + "?",
style: (TextStyle(color: Colors.blue[800], fontWeight: FontWeight.bold)),
),
]),
actions: [
TextButton(
child: Text(t("No")),
onPressed: () => Navigator.pop(context),
),
TextButton(
child: Text(t("Yes")),
onPressed: () {
Navigator.pop(context);
bloc.add(TrainingPlanActivate(trainingPlanId: plan.trainingPlanId));
},
)
],
));
} else {
bloc.add(TrainingPlanActivate(trainingPlanId: plan.trainingPlanId));
}
}
Widget getPlanDetails(TrainingPlan plan, TrainingPlanBloc bloc) {
return SfDataGrid(
headerRowHeight: 30,
+1 -1
View File
@@ -123,7 +123,7 @@ class _ExercisePlanCustomPage extends State<TrainingPlanCustomPage> with Trans {
exerciseTypes.add(Container(
margin: const EdgeInsets.only(left: 4.0),
child: TreeViewChild(
startExpanded: false,
startExpanded: bloc.existsAddedExerciseTypeInTree(name),
parent: TreeviewParentWidget(text: name),
children: getTiles(list, bloc),
)));
+8 -3
View File
@@ -1,7 +1,6 @@
import 'package:aitrainer_app/bloc/training_plan/training_plan_bloc.dart';
import 'package:aitrainer_app/util/app_language.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar.dart';
import 'package:aitrainer_app/widgets/app_bar_min.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter/cupertino.dart';
@@ -111,6 +110,9 @@ class _ExercisePlanDetailAddPage extends State<TrainingPlanCustomAddPage> with T
}
Widget getForm(TrainingPlanBloc bloc) {
if (bloc.getMyDetail() == null) {
return Offstage();
}
String exerciseName = "";
exerciseName = bloc.getExerciseName(AppLanguage().appLocal);
@@ -124,7 +126,10 @@ class _ExercisePlanDetailAddPage extends State<TrainingPlanCustomAddPage> with T
return Form(
child: Scaffold(
resizeToAvoidBottomInset: true,
appBar: AppBarMin(back: true),
appBar: AppBarMin(
back: true,
onTap: () => Navigator.of(context).popAndPushNamed("myTrainingPlanCustom"),
),
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
@@ -139,7 +144,7 @@ class _ExercisePlanDetailAddPage extends State<TrainingPlanCustomAddPage> with T
config: _buildConfig(context),
child: Container(
child: SingleChildScrollView(
padding: const EdgeInsets.only(top: 25, left: 95, right: 95),
padding: EdgeInsets.only(top: 25, left: 95, right: 95),
scrollDirection: Axis.vertical,
child: Column(mainAxisAlignment: MainAxisAlignment.spaceAround, children: <Widget>[
Text(t('Save The Exercise To The Training Plan'),
+25 -7
View File
@@ -111,19 +111,37 @@ class MyTrainingPlans extends StatelessWidget with Trans, Logging {
left: 5,
textColor: color,
onTap: () {
if (Cache().userLoggedIn != null) {
if (route == "myTrainingPlanActivate") {
HashMap<String, dynamic> args = HashMap();
args['parentName'] = parentName;
Navigator.of(context).pushNamed(route, arguments: args);
} else if (route == "myTrainingPlanExecute") {
// if (Cache().userLoggedIn != null) {
if (route == "myTrainingPlanActivate") {
HashMap<String, dynamic> args = HashMap();
args['parentName'] = parentName;
Navigator.of(context).pushNamed(route, arguments: args);
} else if (route == "myTrainingPlanExecute") {
if (Cache().userLoggedIn != null) {
final TrainingPlanBloc bloc = BlocProvider.of<TrainingPlanBloc>(context);
bloc.setMyPlan(Cache().myTrainingPlan);
Navigator.of(context).pushNamed(route);
} else {
Navigator.of(context).pushNamed(route);
showDialog(
context: context,
builder: (BuildContext context) {
return DialogCommon(
warning: true,
title: t("Warning"),
descriptions: t("Please log in"),
description2: t("because only in that way can you begin to execute a training plan"),
text: "OK",
onTap: () => Navigator.of(context).pushNamed("login"),
onCancel: () => {
Navigator.of(context).pop(),
},
);
});
}
} else {
Navigator.of(context).pushNamed(route);
}
// }
},
isLocked: false,
);