WT 1.1.17 FAQ,

This commit is contained in:
bossanyit
2021-05-15 15:14:07 +02:00
parent ae51cb6716
commit 07868c6b8e
30 changed files with 812 additions and 168 deletions
+33
View File
@@ -0,0 +1,33 @@
import 'dart:async';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/faq.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
part 'faq_event.dart';
part 'faq_state.dart';
class FaqBloc extends Bloc<FaqEvent, FaqState> {
List<Faq>? faqs;
FaqBloc() : super(FaqInitial()) {
faqs = Cache().getFaqs();
}
@override
Stream<FaqState> mapEventToState(
FaqEvent event,
) async* {
try {
if (event is FaqLoad) {
yield FaqLoading();
yield FaqReady();
} else if (event is FaqClickDetail) {
yield FaqLoading();
yield FaqReady();
}
} on Exception catch (e) {
yield FaqError(message: e.toString());
}
}
}
+20
View File
@@ -0,0 +1,20 @@
part of 'faq_bloc.dart';
abstract class FaqEvent extends Equatable {
const FaqEvent();
@override
List<Object> get props => [];
}
class FaqLoad extends FaqEvent {
const FaqLoad();
}
class FaqClickDetail extends FaqEvent {
final String name;
const FaqClickDetail({required this.name});
@override
List<Object> get props => [name];
}
+28
View File
@@ -0,0 +1,28 @@
part of 'faq_bloc.dart';
abstract class FaqState extends Equatable {
const FaqState();
@override
List<Object> get props => [];
}
class FaqInitial extends FaqState {
const FaqInitial();
}
class FaqLoading extends FaqState {
const FaqLoading();
}
class FaqReady extends FaqState {
const FaqReady();
}
class FaqError extends FaqState {
final String message;
const FaqError({required this.message});
@override
List<Object> get props => [message];
}
+6 -11
View File
@@ -21,6 +21,7 @@ import 'package:aitrainer_app/view/exercise_execute_plan_add_page.dart';
import 'package:aitrainer_app/view/exercise_log_page.dart';
import 'package:aitrainer_app/view/exercise_plan_custom_page.dart';
import 'package:aitrainer_app/view/exercise_plan_custom_detail_add_page.dart';
import 'package:aitrainer_app/view/faq_page.dart';
import 'package:aitrainer_app/view/login.dart';
import 'package:aitrainer_app/view/exercise_new_page.dart';
import 'package:aitrainer_app/view/mydevelopment_body_page.dart';
@@ -137,7 +138,9 @@ Future<Null> main() async {
final WorkoutTreeRepository menuTreeRepository = WorkoutTreeRepository();
WidgetsFlutterBinding.ensureInitialized();
FlutterUxcam.startWithKey("wvdstyoml4tiwfd");
if (!isInDebugMode) {
FlutterUxcam.startWithKey("wvdstyoml4tiwfd");
}
print(" -- FireBase init..");
await FirebaseApi().initializeFlutterFire();
@@ -187,18 +190,9 @@ Future<void> initThirdParty() async {
if (!isInDebugMode) {
await Flurry.initialize(androidKey: "JNYCTCWBT34FM3J8TV36", iosKey: "3QBG7BSMGPDH24S8TRQP", enableLog: true);
/* SetupOptions options = (new SetupOptionsBuilder('682883e5cd71a46160c4f6ed070530ee593f49c6')
..Fps = 2
..StartNewSession = true)
.build();
Smartlook.setupAndStartRecording(options);
Smartlook.enableCrashlytics(true);
Smartlook.setEventTrackingMode(EventTrackingMode.FULL_TRACKING); */
PushNotificationsManager().init();
FlutterUxcam.optIntoSchematicRecordings();
}
FlutterUxcam.optIntoSchematicRecordings();
}
class WorkoutTestApp extends StatelessWidget {
@@ -268,6 +262,7 @@ class WorkoutTestApp extends StatelessWidget {
'testSetExecute': (context) => TestSetExecute(),
'testSetNew': (context) => TestSetNew(),
'testSetControl': (context) => TestSetControl(),
'faqPage': (context) => FaqPage(),
},
initialRoute: 'home',
title: 'WorkoutTest',
+5
View File
@@ -9,6 +9,7 @@ import 'package:aitrainer_app/model/exercise_plan_detail.dart';
import 'package:aitrainer_app/model/exercise_plan_template.dart';
import 'package:aitrainer_app/model/exercise_tree.dart';
import 'package:aitrainer_app/model/exercise.dart';
import 'package:aitrainer_app/model/faq.dart';
import 'package:aitrainer_app/model/model_change.dart';
import 'package:aitrainer_app/model/product.dart' as wt_product;
import 'package:aitrainer_app/model/product.dart';
@@ -143,6 +144,7 @@ class Cache with Logging {
List<CustomerActivity>? _customerActivities;
List<Tutorial>? _tutorials;
List<Description>? _descriptions;
List<Faq>? _faqs;
LinkedHashMap<int, ExercisePlanDetail> _myExercisesPlanDetails = LinkedHashMap<int, ExercisePlanDetail>();
@@ -684,4 +686,7 @@ class Cache with Logging {
List<Description>? getDescriptions() => this._descriptions;
setDescriptions(List<Description>? value) => this._descriptions = value;
List<Faq>? getFaqs() => this._faqs;
setFaqs(List<Faq>? value) => this._faqs = value;
}
+39
View File
@@ -0,0 +1,39 @@
import 'dart:collection';
import 'package:aitrainer_app/util/app_language.dart';
class Faq {
late int faqId;
late String name;
late String description;
int? sort;
HashMap<String, String> nameTranslations = HashMap();
HashMap<String, String> descriptionTranslations = HashMap();
Faq.fromJson(Map json) {
this.faqId = json['faqId'];
this.name = json['name'];
this.description = json['description'];
this.sort = json['sort'];
nameTranslations['en'] = name;
descriptionTranslations['en'] = description;
if (json['translations'] != null && json['translations'].length > 0) {
json['translations'].forEach((translation) {
nameTranslations[translation['languageCode']] = translation['nameTranslation'];
descriptionTranslations[translation['languageCode']] = translation['descriptionTranslation'];
});
}
}
Map<String, dynamic> toJson() => {
"faqId": this.faqId,
"name": this.name,
"description": this.description,
"nameTranslation": this.nameTranslations.toString(),
};
@override
String toString() => this.toJson().toString();
}
+2 -1
View File
@@ -51,9 +51,10 @@ class APIClient with Common, Logging {
var uri = Uri.parse(url);
HttpClient client = new HttpClient();
client.badCertificateCallback = ((X509Certificate cert, String host, int port) => true);
final HttpClientRequest request = await client.getUrl(uri);
final HttpClientRequest request = await client.postUrl(uri);
request.headers.set('Content-Type', 'application/json');
request.headers.set('Authorization', 'Bearer $authToken');
request.contentLength = body.length;
request.write(body);
HttpClientResponse result = await request.close();
trace(" ------------post response code: " + result.statusCode.toString());
+6
View File
@@ -13,6 +13,7 @@ import 'package:aitrainer_app/model/exercise_plan_template.dart';
import 'package:aitrainer_app/model/exercise_tree.dart';
import 'package:aitrainer_app/model/exercise_tree_parents.dart';
import 'package:aitrainer_app/model/exercise_type.dart';
import 'package:aitrainer_app/model/faq.dart';
import 'package:aitrainer_app/model/product.dart';
import 'package:aitrainer_app/model/product_test.dart';
import 'package:aitrainer_app/model/property.dart';
@@ -80,6 +81,11 @@ class PackageApi {
final List<Description>? descriptions = json.map((description) => Description.fromJson(description)).toList();
//print("Description: $descriptions");
Cache().setDescriptions(descriptions);
} else if (headRecord[0] == "Faq") {
final Iterable json = jsonDecode(headRecord[1]);
final List<Faq>? faqs = json.map((faq) => Faq.fromJson(faq)).toList();
//print("Faq: $faqs");
Cache().setFaqs(faqs);
}
});
+5 -1
View File
@@ -46,7 +46,11 @@ enum TrackingEvent {
test_set_edit,
test_set_new,
tutorial_step,
tutorial_finished
tutorial_finished,
tutorial_activate,
terms_of_use,
data_privacy,
faq
}
T enumFromString<T>(Iterable<T> values, String value) {
+10 -9
View File
@@ -71,7 +71,7 @@ class AccountPage extends StatelessWidget with Trans {
Icon(Icons.arrow_forward_ios),
]),
style: TextButton.styleFrom(
backgroundColor: Colors.white,
backgroundColor: Colors.white38,
onSurface: Colors.grey,
),
onPressed: () => {
@@ -92,7 +92,7 @@ class AccountPage extends StatelessWidget with Trans {
Icon(Icons.arrow_forward_ios),
]),
style: TextButton.styleFrom(
backgroundColor: Colors.white,
backgroundColor: Colors.white38,
onSurface: Colors.grey,
),
onPressed: () => {
@@ -114,7 +114,7 @@ class AccountPage extends StatelessWidget with Trans {
Icon(Icons.arrow_forward_ios),
]),
style: TextButton.styleFrom(
backgroundColor: Colors.white,
backgroundColor: Colors.white38,
onSurface: Colors.grey,
),
onPressed: () => {
@@ -132,7 +132,7 @@ class AccountPage extends StatelessWidget with Trans {
subtitle: Text(t("Body Type")),
title: TextButton(
style: TextButton.styleFrom(
backgroundColor: Colors.white,
backgroundColor: Colors.white38,
onSurface: Colors.grey,
),
child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
@@ -162,12 +162,13 @@ class AccountPage extends StatelessWidget with Trans {
subtitle: Text(t("These equipments and devices are available")),
title: TextButton(
style: TextButton.styleFrom(
backgroundColor: Colors.white,
backgroundColor: Colors.white38,
onSurface: Colors.grey,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [Text(t("Available Devices"), style: TextStyle(color: Colors.orange)), Icon(Icons.arrow_forward_ios)]),
child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Text(t("Available Devices"), style: TextStyle(color: Colors.blue)),
Icon(Icons.arrow_forward_ios),
]),
onPressed: () => {
if (Cache().userLoggedIn != null)
{
@@ -195,7 +196,7 @@ class AccountPage extends StatelessWidget with Trans {
leading: Icon(Icons.input),
title: TextButton(
style: TextButton.styleFrom(
backgroundColor: Colors.white,
backgroundColor: Colors.white38,
onSurface: Colors.grey,
),
child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
+1 -13
View File
@@ -109,6 +109,7 @@ class _CustomerGoalPage extends State<CustomerGoalPage> with Trans {
Text(
t("Set Your Primary Goal"),
maxLines: 2,
textAlign: TextAlign.center,
style: GoogleFonts.archivoBlack(
color: Colors.orange,
fontSize: 30,
@@ -139,19 +140,6 @@ class _CustomerGoalPage extends State<CustomerGoalPage> with Trans {
Divider(),
getItem(changeBloc, Goals.explosiveness),
Divider(),
/* ElevatedButton(
style: ElevatedButton.styleFrom(
onPrimary: Colors.white,
primary: Colors.orange,
),
child: Text(fulldata ? t("Save") : t("Next")),
onPressed: () => {
//changingViewModel.saveCustomer(),
changeBloc.add(CustomerSave()),
Navigator.of(context).pop(),
if (!fulldata) {Navigator.of(context).pushNamed("customerFitnessPage", arguments: changeBloc.customerRepository)}
},
) */
],
),
));
+217 -99
View File
@@ -2,6 +2,7 @@ import 'dart:collection';
import 'package:aitrainer_app/bloc/account/account_bloc.dart';
import 'package:aitrainer_app/bloc/customer_change/customer_change_bloc.dart';
import 'package:aitrainer_app/library/custom_icon_icons.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/util/enums.dart';
import 'package:aitrainer_app/util/trans.dart';
@@ -14,6 +15,7 @@ import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart';
import 'package:syncfusion_flutter_gauges/gauges.dart';
import 'package:toggle_switch/toggle_switch.dart';
@@ -49,43 +51,63 @@ class CustomerModifyPage extends StatelessWidget with Trans {
}
return Scaffold(
resizeToAvoidBottomInset: true,
appBar: _bar,
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_light_background.jpg'),
fit: BoxFit.fill,
alignment: Alignment.center,
),
resizeToAvoidBottomInset: true,
appBar: _bar,
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_light_background.jpg'),
fit: BoxFit.fill,
alignment: Alignment.center,
),
child: BlocConsumer<CustomerChangeBloc, CustomerChangeState>(
listener: (context, state) {
if (state is CustomerSaveError) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
backgroundColor: Colors.orange, content: Text(t(state.message), style: TextStyle(color: Colors.white))));
} else if (state is CustomerSaveSuccess) {
if (fulldata) {
Navigator.of(context).pop();
} else {
Navigator.of(context).pushNamed("customerGoalPage", arguments: customerBloc.customerRepository);
}
),
child: BlocConsumer<CustomerChangeBloc, CustomerChangeState>(
listener: (context, state) {
if (state is CustomerSaveError) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.orange, content: Text(t(state.message), style: TextStyle(color: Colors.white))));
} else if (state is CustomerSaveSuccess) {
if (fulldata) {
Navigator.of(context).pop();
} else {
Navigator.of(context).pushNamed("customerGoalPage", arguments: customerBloc.customerRepository);
}
},
builder: (context, state) {
return ModalProgressHUD(
child: loadForm(customerBloc),
inAsyncCall: state is CustomerChangeLoading,
opacity: 0.5,
color: Colors.black54,
progressIndicator: CircularProgressIndicator(),
);
},
)));
}
},
builder: (context, state) {
return ModalProgressHUD(
child: loadForm(customerBloc),
inAsyncCall: state is CustomerChangeLoading,
opacity: 0.5,
color: Colors.black54,
progressIndicator: CircularProgressIndicator(),
);
},
)),
floatingActionButton: FloatingActionButton.extended(
onPressed: () => {
//changingViewModel.saveCustomer(),
customerBloc.add(CustomerSave()),
//Navigator.of(context).pop(),
//if (!fulldata) {Navigator.of(context).pushNamed("customerFitnessPage", arguments: customerBloc.customerRepository)}
},
backgroundColor: Colors.orange[600],
icon: Icon(
CustomIcon.save,
size: 20,
),
label: Text(
fulldata ? t("Save") : t("Next"),
style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 12),
),
),
);
}));
}
Widget loadForm(CustomerChangeBloc customerBloc) {
double mediaWidth = MediaQuery.of(context).size.width * .4;
double mediaHeight = MediaQuery.of(context).size.height * .4;
return Form(
key: _scaffoldKey,
child: SingleChildScrollView(
@@ -182,83 +204,179 @@ class CustomerModifyPage extends StatelessWidget with Trans {
color: Colors.transparent,
),
Container(
padding: EdgeInsets.only(left: 15),
decoration: BoxDecoration(
color: Colors.white24,
border: Border.all(color: Colors.black, width: 0.4),
borderRadius: BorderRadius.all(Radius.circular(12))),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
flex: 2,
child: Text(t("Birth Year"),
style: GoogleFonts.inter(
fontWeight: FontWeight.normal,
fontSize: 18,
))),
NumberPickerWidget(
minValue: 1930,
maxValue: DateTime.now().year,
initalValue: customerBloc.year!.toInt(),
unit: " ",
color: Colors.indigo,
onChange: (value) => {customerBloc.add(CustomerBirthYearChange(year: value.toInt()))}),
SizedBox(width: 30),
],
)),
padding: EdgeInsets.only(left: 15),
decoration: BoxDecoration(
color: Colors.white24,
border: Border.all(color: Colors.black, width: 0.4),
borderRadius: BorderRadius.all(Radius.circular(12))),
child: Column(children: [
Text(t("Birth Year"),
style: GoogleFonts.inter(
fontWeight: FontWeight.normal,
fontSize: 18,
)),
SizedBox(
height: 20,
),
SfLinearGauge(
minimum: 1950,
maximum: 2020,
markerPointers: [
LinearWidgetPointer(
value: customerBloc.year!.toDouble(),
offset: 5,
position: LinearElementPosition.inside,
markerAlignment: LinearMarkerAlignment.center,
child: Container(
height: 14,
width: 44,
color: Colors.transparent,
child: Text(customerBloc.year!.toString(),
style: GoogleFonts.inter(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Colors.indigo,
)),
),
),
LinearShapePointer(
value: customerBloc.year!.toDouble(),
onValueChanged: (value) => {
customerBloc.add(CustomerBirthYearChange(year: value.toInt())),
},
),
],
orientation: LinearGaugeOrientation.horizontal,
majorTickStyle: LinearTickStyle(length: 20),
axisLabelStyle: TextStyle(fontSize: 12.0, color: Colors.black),
axisTrackStyle: LinearAxisTrackStyle(
color: Colors.cyan, edgeStyle: LinearEdgeStyle.bothFlat, thickness: 1.0, borderColor: Colors.grey)),
SizedBox(
height: 20,
),
]),
),
Divider(
color: Colors.transparent,
),
Container(
padding: EdgeInsets.only(left: 15),
decoration: BoxDecoration(
color: Colors.white24,
border: Border.all(color: Colors.black, width: 0.4),
borderRadius: BorderRadius.all(Radius.circular(12))),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Expanded(
flex: 4,
child: Text(t("Weight"), style: TextStyle(fontWeight: FontWeight.normal, fontSize: 18)),
),
NumberPickerWidget(
minValue: 0,
maxValue: 200,
initalValue: customerBloc.weight.toInt(),
unit: " ",
color: Colors.indigo,
onChange: (value) => {customerBloc.add(CustomerWeightChange(weight: value))}),
SizedBox(width: 30),
padding: EdgeInsets.only(left: 15),
decoration: BoxDecoration(
color: Colors.white24,
border: Border.all(color: Colors.black, width: 0.4),
borderRadius: BorderRadius.all(Radius.circular(12))),
child: Column(children: [
Text(t("Weight"),
style: GoogleFonts.inter(
fontWeight: FontWeight.normal,
fontSize: 18,
)),
SfRadialGauge(
axes: <RadialAxis>[
RadialAxis(
axisLineStyle: AxisLineStyle(
thickness: 0.1,
thicknessUnit: GaugeSizeUnit.factor,
gradient: const SweepGradient(colors: <Color>[Color(0xffb4f500), Colors.blue], stops: <double>[0.1, 0.9]),
),
minimum: 40,
maximum: 160,
pointers: [
WidgetPointer(
value: customerBloc.weight.toDouble(),
child: Container(
height: 55,
width: 60,
color: Colors.transparent,
child: Text(customerBloc.weight.toStringAsFixed(1),
style: GoogleFonts.inter(
fontSize: 14,
color: Colors.indigo,
)),
)),
NeedlePointer(
value: customerBloc.weight.toDouble(),
enableAnimation: true,
enableDragging: true,
onValueChanged: (value) => {customerBloc.add(CustomerWeightChange(weight: value))},
)
],
)
],
)),
),
]),
),
Divider(
color: Colors.transparent,
),
Container(
padding: EdgeInsets.only(left: 15),
decoration: BoxDecoration(
color: Colors.white24,
border: Border.all(color: Colors.black, width: 0.4),
borderRadius: BorderRadius.all(Radius.circular(12))),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
padding: EdgeInsets.only(left: 15),
decoration: BoxDecoration(
color: Colors.white24,
border: Border.all(color: Colors.black, width: 0.4),
borderRadius: BorderRadius.all(Radius.circular(12))),
child: Column(children: [
Text(t("Height"),
style: GoogleFonts.inter(
fontWeight: FontWeight.normal,
fontSize: 18,
)),
SizedBox(
height: 20,
),
Row(
children: [
Expanded(
flex: 4,
child: Text(t("Height"), style: TextStyle(fontWeight: FontWeight.normal, fontSize: 18)),
),
NumberPickerWidget(
minValue: 0,
maxValue: 230,
initalValue: customerBloc.height.toInt(),
unit: " ",
color: Colors.indigo[300]!,
onChange: (value) => {customerBloc.add(CustomerHeightChange(height: value.toInt()))}),
SizedBox(width: 30),
Cache().userLoggedIn!.sex == "m"
? Image.asset(
"asset/image/test_picto_m.png",
height: mediaHeight,
width: mediaWidth,
)
: Image.asset(
"asset/image/test_picto_w.png",
height: mediaHeight,
width: mediaWidth,
),
SfLinearGauge(
minimum: 140,
maximum: 220,
markerPointers: [
LinearWidgetPointer(
value: customerBloc.height,
offset: 5,
position: LinearElementPosition.inside,
markerAlignment: LinearMarkerAlignment.center,
child: Container(
height: 14,
width: 44,
color: Colors.transparent,
child: Text(customerBloc.height.toString(),
style: GoogleFonts.inter(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Colors.indigo,
)),
),
),
LinearShapePointer(
value: customerBloc.height,
onValueChanged: (value) => {
customerBloc.add(CustomerHeightChange(height: value.toInt())),
},
),
],
orientation: LinearGaugeOrientation.vertical,
majorTickStyle: LinearTickStyle(length: 20),
axisLabelStyle: TextStyle(fontSize: 12.0, color: Colors.black),
axisTrackStyle: LinearAxisTrackStyle(
color: Colors.cyan, edgeStyle: LinearEdgeStyle.bothFlat, thickness: 1.0, borderColor: Colors.grey)),
],
)),
),
SizedBox(
height: 20,
),
]),
),
Divider(
color: Colors.transparent,
),
@@ -277,7 +395,7 @@ class CustomerModifyPage extends StatelessWidget with Trans {
},
),
Divider(),
TextButton(
/* TextButton(
onPressed: () => {customerBloc.add(CustomerSave())},
child: Stack(
alignment: Alignment.center,
@@ -289,7 +407,7 @@ class CustomerModifyPage extends StatelessWidget with Trans {
),
],
),
),
), */
],
),
),
+2 -6
View File
@@ -18,12 +18,8 @@ import 'package:flutter/material.dart';
import 'package:aitrainer_app/widgets/treeview_parent_widget.dart';
import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart';
class ExerciseLogPage extends StatefulWidget {
@override
_ExerciseLogPage createState() => _ExerciseLogPage();
}
class _ExerciseLogPage extends State<ExerciseLogPage> with Trans, Common {
// ignore: must_be_immutable
class ExerciseLogPage extends StatelessWidget with Trans, Common {
@override
Widget build(BuildContext context) {
LinkedHashMap arguments = ModalRoute.of(context)!.settings.arguments as LinkedHashMap;
+170
View File
@@ -0,0 +1,170 @@
import 'package:aitrainer_app/bloc/faq/faq_bloc.dart';
import 'package:aitrainer_app/library/tree_view.dart';
import 'package:aitrainer_app/model/faq.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/treeview_parent_widget.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:modal_progress_hud_nsn/modal_progress_hud_nsn.dart';
// ignore: must_be_immutable
class FaqPage extends StatelessWidget with Trans {
@override
Widget build(BuildContext context) {
setContext(context);
return BlocProvider(
create: (context) => FaqBloc(),
child: BlocConsumer<FaqBloc, FaqState>(listener: (context, state) {
if (state is FaqError) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
}
}, builder: (context, state) {
final FaqBloc bloc = BlocProvider.of<FaqBloc>(context);
return ModalProgressHUD(
child: getFaqs(bloc),
inAsyncCall: state is FaqLoading,
opacity: 0.5,
color: Colors.black54,
progressIndicator: CircularProgressIndicator(),
);
}));
}
Widget getFaqs(FaqBloc bloc) {
return Scaffold(
appBar: AppBarNav(depth: 1),
body: Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_black_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
child: faqWidget(bloc),
),
);
}
Widget faqWidget(FaqBloc bloc) {
return TreeView(
startExpanded: false,
children: _getTreeChildren(bloc),
);
}
List<Widget> _getTreeChildren(FaqBloc bloc) {
List<Widget> listWidget = [];
Card explanation = Card(
color: Colors.white60,
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(" "),
Text(
t("FAQs"),
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
],
),
Divider(
color: Colors.transparent,
),
Text(
t("Here can you find the most frequently asked questions."),
style: TextStyle(fontSize: 12, fontWeight: FontWeight.normal),
),
],
)));
listWidget.add(explanation);
if (bloc.faqs != null) {
bloc.faqs!.forEach((element) {
print("Lang: ${AppLanguage().appLocal} faq: ${element.descriptionTranslations['hu']}");
listWidget.add(Container(
margin: const EdgeInsets.only(left: 4.0),
child: TreeViewChild(
startExpanded: false,
parent: TreeviewParentWidget(
text: element.nameTranslations[AppLanguage().appLocal.toString()] != null
? element.nameTranslations[AppLanguage().appLocal.toString()]!
: element.name,
fontSize: 18,
icon: Icon(Icons.question_answer),
color: Colors.blue[800],
),
children: _getChildList(bloc, element),
)));
});
}
return listWidget;
}
List<Widget> _getChildList(FaqBloc bloc, Faq faq) {
List<Widget> list = [];
list.add(
Card(
margin: EdgeInsets.only(left: 10, top: 5),
color: Colors.white54,
child: Container(
padding: const EdgeInsets.only(left: 15, top: 5, right: 5, bottom: 5),
child: Row(mainAxisAlignment: MainAxisAlignment.start, children: [
Flexible(
fit: FlexFit.tight,
flex: 20,
child: Html(
data: faq.descriptionTranslations[AppLanguage().appLocal.toString()] != null
? faq.descriptionTranslations[AppLanguage().appLocal.toString()]!
: faq.description,
//Optional parameters:
style: {
"p": Style(
color: Colors.black,
padding: const EdgeInsets.all(4),
),
"li": Style(
color: Colors.white,
//padding: const EdgeInsets.all(4),
),
"h2": Style(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: FontSize.larger,
//padding: const EdgeInsets.all(4),
),
"h1": Style(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: FontSize.larger,
alignment: Alignment.center,
padding: const EdgeInsets.all(4),
),
},
),
),
]),
)),
);
return list;
}
}
+1 -1
View File
@@ -277,7 +277,7 @@ class RegistrationPage extends StatelessWidget with Trans {
value: loginBloc.emailSubscription,
activeColor: Colors.indigo,
onChanged: (value) {
loginBloc.add(DataProtectionClicked(marked: value!));
loginBloc.add(EmailSubscriptionClicked(marked: value!));
},
controlAffinity: ListTileControlAffinity.leading, // <-- leading Checkbox
);
+99 -1
View File
@@ -13,8 +13,10 @@ import 'package:aitrainer_app/widgets/bottom_nav.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart';
import 'package:toggle_switch/toggle_switch.dart';
import 'package:url_launcher/url_launcher.dart';
// ignore: must_be_immutable
class SettingsPage extends StatelessWidget with Trans {
@@ -79,6 +81,10 @@ class SettingsPage extends StatelessWidget with Trans {
})),
getServer(settingsBloc),
getTuturialBasic(settingsBloc),
getTermsOfUse(),
getPrivacy(),
getFaq(),
getVersion(),
//getDevice(settingsBloc),
]);
}
@@ -138,7 +144,7 @@ class SettingsPage extends StatelessWidget with Trans {
ListTile getTuturialBasic(SettingsBloc settingsBloc) {
final TutorialBloc tutorialBloc = BlocProvider.of<TutorialBloc>(context);
return ListTile(
leading: Icon(CustomIcon.question_circle),
leading: Icon(Icons.not_started),
subtitle: Text(t("Activating the basic tutorial")),
title: ToggleSwitch(
minWidth: 120.0,
@@ -161,8 +167,100 @@ class SettingsPage extends StatelessWidget with Trans {
}
settingsBloc.add(SettingsActivateTutorial(activity: activity));
tutorialBloc.add(TutorialStart());
Track().track(TrackingEvent.tutorial_activate);
},
),
);
}
ListTile getTermsOfUse() {
return ListTile(
leading: Icon(CustomIcon.user_cog),
title: TextButton(
child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Text("Terms Of Use", style: TextStyle(color: Colors.black)),
Icon(
Icons.arrow_forward_ios,
color: Colors.indigo,
),
]),
style: TextButton.styleFrom(
backgroundColor: Colors.white70,
onSurface: Colors.grey,
),
onPressed: () => {
Track().track(TrackingEvent.terms_of_use),
_launchInBrowser("https://workouttest.com/terms-of-use/"),
},
),
);
}
ListTile getPrivacy() {
return ListTile(
leading: Icon(Icons.enhanced_encryption),
title: TextButton(
child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Text("Data Privacy", style: TextStyle(color: Colors.black)),
Icon(
Icons.arrow_forward_ios,
color: Colors.indigo,
),
]),
style: TextButton.styleFrom(
backgroundColor: Colors.white70,
onSurface: Colors.grey,
),
onPressed: () => {
Track().track(TrackingEvent.data_privacy),
_launchInBrowser("https://workouttest.com/privacy/"),
},
),
);
}
ListTile getFaq() {
return ListTile(
leading: Icon(CustomIcon.question),
title: TextButton(
child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Text("Frequently Asked Questions", style: TextStyle(color: Colors.indigo)),
Icon(
Icons.arrow_forward_ios,
color: Colors.indigo,
),
]),
style: TextButton.styleFrom(
backgroundColor: Colors.white70,
onSurface: Colors.grey,
),
onPressed: () => {
Navigator.of(context).pushNamed("faqPage"),
Track().track(TrackingEvent.faq),
},
),
);
}
Future<void> _launchInBrowser(String url) async {
if (await canLaunch(url)) {
await launch(
url,
forceSafariVC: false,
forceWebView: false,
);
} else {
throw 'Could not launch $url';
}
}
ListTile getVersion() {
final String version = Cache().packageInfo != null ? Cache().packageInfo!.version + "+" + Cache().packageInfo!.buildNumber : "";
return ListTile(
title: Text(
"Version: $version",
style: GoogleFonts.inter(fontSize: 12),
),
);
}
}
+78 -4
View File
@@ -5,6 +5,7 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:syncfusion_flutter_gauges/gauges.dart';
import 'app_bar.dart';
import 'package:keyboard_actions/keyboard_actions.dart';
@@ -136,7 +137,80 @@ class _BMIState extends State<BMI> with Trans {
],
),
Divider(color: Colors.transparent),
Stack(alignment: Alignment.center, children: [
SfRadialGauge(
enableLoadingAnimation: true,
animationDuration: 2500,
axes: <RadialAxis>[
RadialAxis(
axisLabelStyle: GaugeTextStyle(fontWeight: FontWeight.w500, fontSize: 12, color: Colors.white),
showLabels: true,
showAxisLine: true,
showTicks: true,
ticksPosition: ElementsPosition.outside,
labelsPosition: ElementsPosition.outside,
ranges: <GaugeRange>[
GaugeRange(
label: '<18,5',
labelStyle: GaugeTextStyle(fontSize: 20, color: Colors.white, fontWeight: FontWeight.bold),
startValue: 15,
endValue: 18.5,
sizeUnit: GaugeSizeUnit.factor,
startWidth: 0.45,
endWidth: 0.45,
color: Colors.blue),
GaugeRange(
label: '18,5 - 25',
labelStyle: GaugeTextStyle(fontSize: 20, color: Colors.white, fontWeight: FontWeight.bold),
startValue: 18.5,
endValue: 25,
sizeUnit: GaugeSizeUnit.factor,
startWidth: 0.45,
endWidth: 0.45,
color: Colors.green),
GaugeRange(
label: '25-30',
labelStyle: GaugeTextStyle(fontSize: 20, color: Colors.white, fontWeight: FontWeight.bold),
startValue: 25,
endValue: 30,
sizeUnit: GaugeSizeUnit.factor,
startWidth: 0.45,
endWidth: 0.45,
color: Colors.yellow),
GaugeRange(
label: '30-35',
labelStyle: GaugeTextStyle(fontSize: 20, color: Colors.white, fontWeight: FontWeight.bold),
startValue: 30,
endValue: 35,
sizeUnit: GaugeSizeUnit.factor,
startWidth: 0.45,
endWidth: 0.45,
color: Colors.orange),
GaugeRange(
label: '35<',
labelStyle: GaugeTextStyle(fontSize: 20, color: Colors.white, fontWeight: FontWeight.bold),
startValue: 35,
endValue: 40,
sizeUnit: GaugeSizeUnit.factor,
startWidth: 0.45,
endWidth: 0.45,
color: Colors.red[700])
],
minimum: 15,
maximum: 40,
pointers: [
NeedlePointer(
needleColor: Colors.grey,
value: widget.exerciseBloc.bmi,
enableAnimation: true,
knobStyle:
KnobStyle(color: Colors.white, borderColor: Color(0xFFDADADA), knobRadius: 0.06, borderWidth: 0.04),
)
],
)
],
),
/* Stack(alignment: Alignment.center, children: [
Container(
padding: EdgeInsets.only(left: 30, right: 30),
child: Image.asset(
@@ -147,7 +221,7 @@ class _BMIState extends State<BMI> with Trans {
top: widget.exerciseBloc.bmiTop,
left: widget.exerciseBloc.bmiLeft,
child:
Container() /* RotationAnimatedWidget.tween(
Container() RotationAnimatedWidget.tween(
enabled: true,
duration: const Duration(milliseconds: 1000),
rotationDisabled: Rotation.deg(),
@@ -155,9 +229,9 @@ class _BMIState extends State<BMI> with Trans {
child: Image.asset(
"asset/image/BMI_mutato.png",
width: 65,
)) */
))
)
]),
]), */
Divider(color: Colors.transparent),
Container(
padding: EdgeInsets.only(left: 65, right: 65),
+15 -4
View File
@@ -2,23 +2,34 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
// ignore: must_be_immutable
class TreeviewParentWidget extends StatelessWidget {
final String text;
final Color backgroundColor;
final Color? color;
final double? fontSize;
Icon? icon;
//final DateTime lastModified;
TreeviewParentWidget({required this.text, this.backgroundColor = Colors.white38, this.color});
TreeviewParentWidget({
required this.text,
this.backgroundColor = Colors.white38,
this.color,
this.fontSize = 24,
this.icon,
}) {
if (icon == null) {
icon = Icon(Icons.person);
}
}
@override
Widget build(BuildContext context) {
Widget parentWidget = Text(
this.text,
style: GoogleFonts.archivoBlack(fontSize: 24, color: color ?? Colors.blue[800]!, backgroundColor: Colors.transparent),
style: GoogleFonts.archivoBlack(fontSize: fontSize, color: color ?? Colors.blue[800]!, backgroundColor: Colors.transparent),
);
Icon icon = Icon(Icons.person);
return Card(
color: backgroundColor,
shadowColor: Colors.black54,