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

View File

@ -33,7 +33,7 @@ if (keystorePropertiesFile.exists()) {
}
android {
compileSdkVersion 30
compileSdkVersion 28
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
@ -46,7 +46,7 @@ android {
defaultConfig {
applicationId "com.aitrainer.aitrainer_app"
minSdkVersion 18
targetSdkVersion 30
targetSdkVersion 29
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
multiDexEnabled true

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

View File

@ -71,9 +71,6 @@
"Save": "Save",
"Delete": "Delete",
"Endurance_desc":"<p>The essence of the endurance test is also to suggest the right WEIGHT and number of REPETATIONS for you. It is very important to do the test properly with the requested repetition! If your goal is to maintain long-term strength or you are an athlete, be sure to complete our endurance module as well.</p><p><b>Why endurance?</b></p><p>It improves the oxygen and nutrients supply of the muscles therefore you will be able to move more weights on a longer distance (e.g.: push-ups or pull-ups). It has less weight gain effect, it rather results a more athletic and strong physique if you exercise in a long term.</p>",
"OneRepMax_desc":"<p>Knowing the maximum of one repetition which also known as 1RM, can be important to you in calculating the right WEIGHT and REPEAT for you. Execute the test correctly!</p><p>This way we can suggest the weights and repetitions that are best for you later. If building muscle or strength is your goal, it is essential to do the 1RM tests!</p><p><b>What is 1RM?</b></p><p>This is the weight what you are able to move at once properly. Upon the maximum weight exercise is performed correctly, we can derive the weight and number of repetitions which fits to your goals.</p>",
"Name": "Name",
"Exercise": "Exercise",
"Quantity": "Quantity",

View File

@ -83,9 +83,6 @@
"Execute the": "Hajtsd végre a(z)",
"set!":"sorozatot!",
"Endurance_desc":"<p>Erőállóképességi teszt lényege, ahogy az 1RM tesztnél is, hogy a Neked megfelelő SÚLY és ISMÉTLÉS számot tudjuk javasolni. </p><p>Nagyon fontos, hogy szabályosan és a kért ismétléssel dolgozz!</p><p> Ha a célod a hosszabb távú erő fenntartása, netán sportoló vagy, akkor feltétlen teszteld az erőállóképességi modulunkat is.</p><br/><h2>Miért az erőállóképesség?</h2><p>Javítja az izmok oxigén és tápanyagellátottságát és ezáltal képes leszel egyre nagyobb súlyok egyre hosszabbtávon való megmozgatására. Például egyre több fekvőtámaszra és húzódzkodásra. </p><p>Kevésbé tömegnövelő hatású, ámbár atlétikus és nagyon erős testalkatot kölcsönöz, ha hosszútávon gyakorlod.</p>",
"OneRepMax_desc":"<p>Az egy ismétléses maximum, vagy más néven 1RM ismerete számodra fontos lehet a Neked megfelelő SÚLY és ISMÉTLÉS kiszámításában. <p>Végezd el szabályosan(!) a tesztet, hogy a Neked legmegfelelőbb súlyokat és ismétléseket tudjuk javasolni a későbbiekben.</p> <p>Ha a célod az izom, vagy az erőnövelés, akkor feltétlen csináld meg az 1RM teszteket!</p><br/><h2>Mi az 1RM?</h2><p>Az a súly, amit egyetlen egyszer lennél képes szabályosan megmozgatni. Az egyszer szabályosan végrehajtott maximális súlyú gyakorlatból származtatjuk a céloknak megfelelő súly és ismétlésszámokat.</p>",
"Name": "Vezetéknév",
"Exercise": "Gyakorlat",
"Quantity": "Mennyiség",

View File

@ -218,6 +218,8 @@ PODS:
- sqflite (0.0.2):
- Flutter
- FMDB (>= 2.7.5)
- url_launcher (0.0.1):
- Flutter
- UXCam (3.3.4)
- video_player (0.0.1):
- Flutter
@ -250,6 +252,7 @@ DEPENDENCIES:
- sentry_flutter (from `.symlinks/plugins/sentry_flutter/ios`)
- shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
- sqflite (from `.symlinks/plugins/sqflite/ios`)
- url_launcher (from `.symlinks/plugins/url_launcher/ios`)
- video_player (from `.symlinks/plugins/video_player/ios`)
- wakelock (from `.symlinks/plugins/wakelock/ios`)
- webview_flutter (from `.symlinks/plugins/webview_flutter/ios`)
@ -332,6 +335,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/shared_preferences/ios"
sqflite:
:path: ".symlinks/plugins/sqflite/ios"
url_launcher:
:path: ".symlinks/plugins/url_launcher/ios"
video_player:
:path: ".symlinks/plugins/video_player/ios"
wakelock:
@ -390,6 +395,7 @@ SPEC CHECKSUMS:
sentry_flutter: 5b3c6d717db5b7482504a313c831b318297d4d37
shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef
UXCam: c2c00873595ab89be227f197213dc3679ff88ae5
video_player: 9cc823b1d9da7e8427ee591e8438bfbcde500e6e
wakelock: b0843b2479edbf6504d8d262c2959446f35373aa

View File

@ -388,7 +388,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = 2;
DEVELOPMENT_TEAM = SFJJBDCU6Z;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
@ -531,7 +531,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = 2;
DEVELOPMENT_TEAM = SFJJBDCU6Z;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
@ -566,7 +566,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = 2;
DEVELOPMENT_TEAM = SFJJBDCU6Z;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (

View File

@ -38,10 +38,8 @@
<string>NO</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>fbapi</string>
<string>fb-messenger-share-api</string>
<string>fbauth2</string>
<string>fbshareextension</string>
<string>https</string>
<string>http</string>
</array>
<key>LSMinimumSystemVersion</key>
<string>11.0</string>

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());
}
}
}

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];
}

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];
}

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',

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
lib/model/faq.dart Normal file
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();
}

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());

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);
}
});

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) {

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: [

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)}
},
) */
],
),
));

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 {
),
],
),
),
), */
],
),
),

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
lib/view/faq_page.dart Normal file
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;
}
}

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
);

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),
),
);
}
}

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),

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,

View File

@ -1132,6 +1132,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
syncfusion_flutter_core:
dependency: transitive
description:
name: syncfusion_flutter_core
url: "https://pub.dartlang.org"
source: hosted
version: "19.1.63"
syncfusion_flutter_gauges:
dependency: "direct main"
description:
name: syncfusion_flutter_gauges
url: "https://pub.dartlang.org"
source: hosted
version: "19.1.63"
synchronized:
dependency: transitive
description:
@ -1202,6 +1216,48 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
url_launcher:
dependency: "direct main"
description:
name: url_launcher
url: "https://pub.dartlang.org"
source: hosted
version: "6.0.3"
url_launcher_linux:
dependency: transitive
description:
name: url_launcher_linux
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
url_launcher_macos:
dependency: transitive
description:
name: url_launcher_macos
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
url_launcher_platform_interface:
dependency: transitive
description:
name: url_launcher_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
url_launcher_web:
dependency: transitive
description:
name: url_launcher_web
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
url_launcher_windows:
dependency: transitive
description:
name: url_launcher_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
uuid:
dependency: transitive
description:

View File

@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.1.17+77
version: 1.1.17+79
environment:
sdk: ">=2.12.0 <3.0.0"
@ -57,6 +57,7 @@ dependencies:
convex_bottom_bar: ^3.0.0
flutter_app_badger: ^1.2.0
#super_tooltip: ^1.0.1
url_launcher: ^6.0.3
firebase_core: ^1.1.0
firebase_analytics: ^8.0.2
@ -64,6 +65,8 @@ dependencies:
flutter_local_notifications: ^5.0.0
firebase_auth: ^1.1.2
firebase_remote_config: ^0.10.0-dev.2
syncfusion_flutter_gauges: ^19.1.63
flutter_facebook_auth: ^3.3.2
google_sign_in: ^5.0.1
@ -176,10 +179,10 @@ flutter:
- asset/image/woman_sizes.png
- asset/image/weight_loss.jpg
- asset/image/merleg.png
- asset/image/BMI_graph_C.png
- asset/image/BMI_mutato.png
- asset/image/haken.png
- asset/image/kupa.png
- asset/image/test_picto_m.png
- asset/image/test_picto_w.png
- asset/image/pict_calorie.png
- asset/image/pict_development_by_bodypart_percent.png