wt1.1a flutter_bloc
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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
@@ -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");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user