wt1.1a flutter_bloc

This commit is contained in:
Bossanyi Tibor
2020-08-17 12:38:47 +02:00
parent 8363d7772f
commit ac1c6be8f3
90 changed files with 4281 additions and 2854 deletions
+28
View File
@@ -3,10 +3,16 @@ import 'dart:convert';
import 'package:aitrainer_app/localization/app_language.dart';
import 'package:aitrainer_app/model/auth.dart';
import 'package:aitrainer_app/model/exercise_type.dart';
import 'package:aitrainer_app/repository/user_repository.dart';
import 'package:flutter/cupertino.dart';
import 'package:intl/intl.dart';
class Common {
static const EMAIL_ERROR = "Please type a right email address here.";
static const PASSWORD_ERROR = "The password must have at least 8 characters.";
static String toJson( Map<String, String> map ) {
String rc = "{";
@@ -47,4 +53,26 @@ class Common {
List<int> bytes = text.toString().codeUnits;
return utf8.decode(bytes);
}
static double mediaSizeWidth( BuildContext context ) {
return MediaQuery.of(context).size.width;
}
static bool validateEmail(UserRepository userRepository) {
final String email = userRepository.user.email;
final RegExp _emailRegExp = RegExp(
r'^[a-zA-Z0-9._-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$',
);
return _emailRegExp.hasMatch(email);
}
static bool validatePassword(UserRepository userRepository) {
final password = userRepository.user.password;
final RegExp _passwordRegExp =
RegExp(r'^(?=.*[A-Za-z0-9])(?=.*\d)[A-Za-z\d]{7,}$');
return _passwordRegExp.hasMatch(password);
}
}
-61
View File
@@ -1,61 +0,0 @@
import 'package:aitrainer_app/util/loading_screen_state.dart';
import 'package:flutter/material.dart';
/// Loading Screen Widget that updates the screen once all inistializer methods
/// are called
// ignore: must_be_immutable
class LoadingScreen extends StatefulWidget {
/// List of methods that are called once the Loading Screen is rendered
/// for the first time. These are the methods that can update the messages
/// that are shown under the loading symbol
final List<dynamic> initializers;
/// The name of the application that is shown at the top of the loading screen
RichText title = RichText(text: TextSpan(text: 'AI Trainer'));
//final Text title;
/// The background colour which is used as a filler when the image doesn't
/// occupy the full screen
final Color backgroundColor;
/// The styling that is used with the text (messages) that are displayed under
/// the loader symbol
final TextStyle styleTextUnderTheLoader;
/// The Layout/Scaffold Widget that is loaded once all the initializer methods
/// have been executed
final dynamic navigateToWidget;
/// The colour that is used for the loader symbol
final Color loaderColor;
/// The image widget that is used as a background cover to the loading screen
final Image image;
/// The message that is displayed on the first load of the widget
final String initialMessage;
/// Constructor for the LoadingScreen widget with all the required
/// initializers
LoadingScreen(
{this.initializers,
this.navigateToWidget,
this.loaderColor,
this.image,
//this.title = Text("Welcome"),
this.backgroundColor = Colors.white,
this.styleTextUnderTheLoader = const TextStyle(
fontSize: 18.0, fontWeight: FontWeight.bold, color: Colors.black),
this.initialMessage})
// The Widget depends on the initializers and navigateToWidget to have a
// valid value. Thus we assert that the values passed are valid and
// not null
: assert(initializers != null && initializers.length > 0),
assert(navigateToWidget != null);
/// Bind the Widget to the custom State object
@override
LoadingScreenState createState() => LoadingScreenState();
}
-129
View File
@@ -1,129 +0,0 @@
import 'dart:core';
import 'dart:async';
import 'package:aitrainer_app/util/loading_screen.dart';
import 'package:aitrainer_app/widgets/home.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:aitrainer_app/util/message_state.dart';
/// The custom state that is used by the Loading Screen widget to handle the
/// messages that are provided by the initializer methods.
///
/// Note: Although the class is not exported from the package as not required by
/// the implementers using the package, the protected metatag is added to make
/// the code clearer.
@protected
class LoadingScreenState extends MessageState<LoadingScreen> {
/// Initialise the state
@override
void initState() {
super.initState();
/// If the LoadingScreen widget has an initial message set, then the default
/// message in the MessageState class needs to be updated
if (widget.initialMessage != null) {
initialMessage = widget.initialMessage;
}
/// We require the initializers to run after the loading screen is rendered
SchedulerBinding.instance.addPostFrameCallback((_) {
runInitTasks();
});
}
/// This method calls the initializers and once they complete redirects to
/// the widget provided in navigateAfterInit
@protected
Future runInitTasks() async {
print(" ----- runInitTasks");
/// Run each initializer method sequentially
Future.forEach(widget.initializers, (init) => init(this, callbackFunction)).whenComplete(() {
// When all the initializers has been called and terminated their
// execution. The screen is navigated to the next scaffolding widget
if (widget.navigateToWidget is String) {
// It's fairly safe to assume this is using the in-built material
// named route component
print(" ----- navigate to " + widget.navigateToWidget);
Navigator.of(context).pushReplacementNamed(widget.navigateToWidget);
} else if (widget.navigateToWidget is Widget) {
Navigator.of(context).pushReplacement(new MaterialPageRoute(
builder: (BuildContext context) => widget.navigateToWidget));
print(" ----- navigate to main ");
} else {
throw new ArgumentError(
'widget.navigateAfterSeconds must either be a String or Widget');
}
});
}
void callbackFunction() {
print("Call Home callback if widget");
if (widget.navigateToWidget is Widget) {
AitrainerHome home = widget.navigateToWidget as AitrainerHome;
home.callback();
}
}
/// Render the LoadingScreen widget
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: widget.backgroundColor,
body: new InkWell(
child: new Stack(
fit: StackFit.expand,
children: <Widget>[
/// Paint the area where the inner widgets are loaded with the
/// background to keep consistency with the screen background
new Container(
decoration: BoxDecoration(color: widget.backgroundColor),
),
/// Render the background image
new Container(
child: widget.image,
),
/// Render the Title widget, loader and messages below each other
new Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
new Expanded(
flex: 3,
child: new Container(
child: new Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
new Padding(
padding: const EdgeInsets.only(top: 30.0),
),
widget.title,
],
)),
),
Expanded(
flex: 1,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
/// Loader Animation Widget
CircularProgressIndicator(
valueColor: new AlwaysStoppedAnimation<Color>(
widget.loaderColor),
),
Padding(
padding: const EdgeInsets.only(top: 20.0),
),
Text(getMessage, style: widget.styleTextUnderTheLoader),
],
),
),
],
),
],
),
),
);
}
}
-93
View File
@@ -1,93 +0,0 @@
import 'dart:collection';
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/model/workout_tree.dart';
import 'package:flutter/material.dart';
class MenuTests {
LinkedHashMap tree = LinkedHashMap();
MenuTests(BuildContext context) {
this.tree['Cardio']= WorkoutTree(1, 0, AppLocalizations.of(context).translate("Cardio"),
'asset/menu/1.cardio.png',
Colors.white, 32, false,0);
this.tree['Aerobic']= WorkoutTree(2, 1, AppLocalizations.of(context).translate("Aerobic"),
'asset/menu/1.1.aerob.png',
Colors.white, 32, false,0);
this.tree['Cooper']= WorkoutTree(21, 2, AppLocalizations.of(context).translate("Cooper"),
'asset/menu/1.1.1.cooper.png',
Colors.white, 32, true,30);
this.tree['Anaerobic']= WorkoutTree(3, 1, AppLocalizations.of(context).translate("Anaerobic"),
'asset/menu/1.2.anaerob.png',
Colors.white, 32, false,0);
this.tree['300m']= WorkoutTree(22, 3, "300m",
'asset/menu/1.2.1.300m.png',
Colors.white, 32, true,31);
this.tree['400m']= WorkoutTree(24, 3, "400m",
'asset/menu/1.2.2.400m.png',
Colors.white, 32, true,32);
this.tree['Strength']= WorkoutTree(4, 0, AppLocalizations.of(context).translate("Strength"),
'asset/menu/2.strength.png',
Colors.white, 32, false,0);
this.tree['Endurance']= WorkoutTree(5, 4, AppLocalizations.of(context).translate("Endurance"),
'asset/menu/2.1.endurance.png',
Colors.white, 36, false,0);
this.tree['Pullups']= WorkoutTree(6, 5, AppLocalizations.of(context).translate("Pull Ups"),
'asset/menu/2.1.1.pull-ups.png',
Colors.white, 32, true,38);
this.tree['Pushups']= WorkoutTree(7, 5, AppLocalizations.of(context).translate("Pushups"),
'asset/menu/2.1.2.pushup.png',
Colors.white, 32, true,33);
this.tree['Situps']= WorkoutTree(10, 5, AppLocalizations.of(context).translate("Sit-ups"),
'asset/menu/2.1.3.sit-ups.png',
Colors.white, 32, true,36);
this.tree['Squats']= WorkoutTree(11, 5, AppLocalizations.of(context).translate("Squats"),
'asset/menu/2.1.4.squats.png',
Colors.white, 32, true,35);
this.tree['TimedPushups']= WorkoutTree(12, 5, AppLocalizations.of(context).translate("Timed Pushups"),
'asset/menu/2.1.5.timedpushup.png',
Colors.white, 32, true,34);
this.tree['Core']= WorkoutTree(43, 5, AppLocalizations.of(context).translate("Core"),
'asset/menu/2.1.6.core.png',
Colors.white, 32, true,45);
this.tree['1RM']= WorkoutTree(8, 4, AppLocalizations.of(context).translate("1RM"),
'asset/menu/2.2.1.1RM.png',
Colors.white, 32, false,0);
this.tree['Chestpress']= WorkoutTree(13, 8, AppLocalizations.of(context).translate("Chest Press"),
'asset/menu/2.2.1.1.chestpress.png',
Colors.white, 32, true,37);
this.tree['PullUps1rm']= WorkoutTree(14, 8, AppLocalizations.of(context).translate("Pull Ups"),
'asset/menu/2.2.1.2.pullups.png',
Colors.white, 32, true, 38);
this.tree['Biceps']= WorkoutTree(15, 8, AppLocalizations.of(context).translate("Biceps"),
'asset/menu/2.2.1.3.biceps.png',
Colors.white, 32, true, 39);
this.tree['Triceps']= WorkoutTree(16, 8, AppLocalizations.of(context).translate("Triceps"),
'asset/menu/2.2.1.4.triceps.png',
Colors.white, 32, true, 40);
this.tree['Shoulders']= WorkoutTree(17, 8, AppLocalizations.of(context).translate("Shoulders"),
'asset/menu/2.2.1.5.shoulders.png',
Colors.white, 32, true, 41);
this.tree['BodyCompositions']= WorkoutTree(9, 0, AppLocalizations.of(context).translate("Body Compositions"),
'asset/menu/3.bcs1.png',
Colors.white, 32, false,0);
this.tree['BMI']= WorkoutTree(18, 9, AppLocalizations.of(context).translate("BMI"),
'asset/menu/3.1.BMI.png',
Colors.white, 32, true,42);
this.tree['BMR']= WorkoutTree(19, 9, AppLocalizations.of(context).translate("BMR"),
'asset/menu/3.2.BMR.png',
Colors.white, 32, true, 43);
this.tree['Sizes']= WorkoutTree(20, 9, AppLocalizations.of(context).translate("Sizes"),
'asset/menu/3.3.sizes.png',
Colors.white, 32, true, 44);
}
LinkedHashMap getMenuItems() {
return this.tree;
}
}
-32
View File
@@ -1,32 +0,0 @@
import 'package:flutter/widgets.dart';
/// An extension class to the Flutter standard State. The class provides getter
/// and setters for updating the message section of the loading screen
///
/// Note: The class is marked as abstract to avoid IDE issues that expects
/// protected methods to be overloaded
abstract class MessageState<T extends StatefulWidget> extends State<T> {
/// The state variable that will hold the latest message that needs to be
/// displayed.
///
/// Note: Although Flutter standard allow member variables to be used from
/// instance object reference, this is not a best practice with OOP. OOP
/// design proposes that member variables should be accessed through getter
/// and setter methods.
@protected
String _message = 'Loading . . .';
/// The member variable is set as protected this it is not exposed to the
/// widget state class. As a workaround a protected setter is set so it is
/// not used outside the package
@protected
set initialMessage(String message) => _message = message;
/// Setter for the message variable
set setMessage(String message) => setState(() {
_message = message;
});
/// Getter for the message variable
String get getMessage => _message;
}
+20 -10
View File
@@ -1,6 +1,8 @@
import 'package:aitrainer_app/localization/app_language.dart';
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/service/api.dart';
import 'package:aitrainer_app/service/customer_service.dart';
import 'package:aitrainer_app/service/exercise_tree_service.dart';
import 'package:aitrainer_app/service/exercisetype_service.dart';
import 'package:devicelocale/devicelocale.dart';
import 'package:flutter/services.dart';
@@ -12,18 +14,24 @@ import '../push_notifications.dart';
class Session {
Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
Auth _auth = Auth();
SharedPreferences _sharedPreferences;
final AppLanguage appLanguage = AppLanguage();
fetchSessionAndNavigate(Function callback ) async {
fetchSessionAndNavigate( ) async {
print (" -- Session: await prefs..");
_sharedPreferences = await _prefs;
if ( _auth.firstLoad ) {
_fetchToken(_sharedPreferences, callback);
if ( Auth().firstLoad ) {
print (" -- Session: fetch locale..");
await appLanguage.fetchLocale();
await AppLocalizations.delegate.load(appLanguage.appLocal);
print (" -- Session: fetch token..");
await _fetchToken(_sharedPreferences);
initDeviceLocale();
appLanguage.fetchLocale();
PushNotificationsManager().init();
}
@@ -53,7 +61,7 @@ class Session {
/*
Auth flow of the user, see auth.dart
*/
_fetchToken(SharedPreferences prefs, Function callback) async {
_fetchToken(SharedPreferences prefs) async {
var responseJson = await APIClient.authenticateUser(
Auth.username,
@@ -71,6 +79,7 @@ class Session {
// registration
//Navigator.of(context).pushNamed('registration');
prefs.setBool(Auth.isRegisteredKey, true);
Auth().startPage = "registration";
} else {
DateTime now = DateTime.now();
DateTime lastStoreDate = DateTime.parse(
@@ -83,16 +92,17 @@ class Session {
prefs.get(Auth.isLoggedInKey) == false) {
print("************* Login");
//Navigator.of(context).pushNamed('login');
Auth().startPage = "login";
} else {
print("************** Store SharedPreferences");
// get API customer
await CustomerApi().getCustomer(prefs.getInt(Auth.customerIdKey));
Auth().startPage = "home";
}
await ExerciseTypeApi().getExerciseTypes("");
print("--- Session finished, call callback ");
callback();
await ExerciseTypeApi().getExerciseTypes();
await ExerciseTreeApi().getExerciseTree();
print("--- Session finished");
}
}