Aitrainer_app 1.1.1

test menu, customer modification, exercise save images, localization
This commit is contained in:
Bossanyi Tibor 2020-07-07 16:53:03 +02:00
parent 79142b92f2
commit 2177db10ea
80 changed files with 2751 additions and 553 deletions

View File

Before

Width:  |  Height:  |  Size: 3.0 MiB

After

Width:  |  Height:  |  Size: 3.0 MiB

BIN
asset/image/WT_OK.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

BIN
asset/image/WT_login.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

BIN
asset/image/WT_menu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

BIN
asset/image/dots.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

BIN
asset/menu/1.1.1.cooper.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 781 KiB

BIN
asset/menu/1.1.aerob.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

BIN
asset/menu/1.2.1.300m.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
asset/menu/1.2.2.400m.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

BIN
asset/menu/1.2.anaerob.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
asset/menu/1.cardio.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

BIN
asset/menu/2.1.2.pushup.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
asset/menu/2.1.4.squats.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

BIN
asset/menu/2.1.6.core.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

BIN
asset/menu/2.2.1.1RM.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

BIN
asset/menu/2.strength.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 KiB

BIN
asset/menu/3.1.BMI.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

BIN
asset/menu/3.2.BMR.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

BIN
asset/menu/3.3.sizes.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

BIN
asset/menu/3.bcs1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

79
i18n/en.json Normal file

File diff suppressed because one or more lines are too long

79
i18n/hu.json Normal file
View File

@ -0,0 +1,79 @@
{
"Customers And Exercises": "Ügyfelek és gyakorlatok",
"Home": "Főoldal",
"Customers": "Ügyfelek",
"Exercises": "Gyakorlatok",
"TRAINING!": "EDZÉS!",
"Login": "Bejelentkezés",
"Logout": "Kijelentkezés",
"Change Language": "Nyelv",
"Password too short": "A jelszó min. 6 karakterből álljon",
"Please type an email address": "Kérlek írj be egy email címet",
"SignUp": "Regisztráció",
"Privacy": "Adatkezelés",
"Change App Language": "Nyelvválasztás",
"English": "Angol",
"Hungarian": "Magyar",
"Events": "Események",
"Account": "Fiók",
"Settings": "Beállítások",
"Profile": "Személyes adatok",
"Selected Language": "Választott nyelv",
"gdpr_text": "",
"Please select an exercise": "Válassz ki egy gyakorlatot",
"Cardio": "Kardió",
"400m": "400m",
"300m": "300m",
"Aerobic": "Aerob",
"Anaerobic": "Anaerob",
"Cooper": "Cooper teszt",
"Strength": "Erő",
"Endurance": "Erő állóképesség",
"Pushups": "Fekvőtámasz",
"Timed Pushups": "Fekvőtámasz időre",
"Core": "Core (plank)",
"Squats": "Guggolás",
"Sit-ups": "Felülés",
"1RM": "1RM - Maxerő",
"Chest Press": "Fekvenyomás",
"Pull Ups": "Húzódszkodás",
"Biceps": "Bicepsz",
"Triceps": "Tricepsz",
"Shoulders": "Vállak",
"Body Compositions": "Testformálás",
"BMI": "Testtömegindex",
"BMR": "Alapanyagcsere érték",
"Sizes": "Méretek",
"Save Exercise": "gyakorlat mentése",
"Save": "Save",
"Name": "Név",
"Exercise": "Gyakorlat",
"Quantity": "Mennyiség",
"Unit": "Egység",
"Exercise date and time": "A gyakorlat időpontja",
"Please type the right quantity 0-1000": "Kérlek írj be egy helyes számot 0-10000 között",
"repeat": "ismétlés",
"meter": "meter",
"percent": "százalék",
"kg": "kg",
"lbs": "lbs",
"second": "másodperc",
"Email": "Email",
"Password": "Jelszó",
"Password (Leave empty if you don't want to change)":"Jelszó (hagyd üresen, ha nem akarod megváltoztatni)",
"First Name": "Keresztnév",
"Birth Year": "Születési év",
"Weight": "Tömeg",
"Gender": "Nemed",
"Man": "Férfi",
"Woman": "Nő",
"Next": "Tovább",
"Select a gender": "Válaszd ki a nemet",
"Goal Settings": "Cél"
}

View File

@ -29,8 +29,6 @@
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>

View File

@ -0,0 +1,55 @@
import 'package:flutter/cupertino.dart';
import 'package:shared_preferences/shared_preferences.dart';
class AppLanguage extends ChangeNotifier {
static final AppLanguage _singleton = AppLanguage._internal();
Locale _appLocale = Locale('en');
factory AppLanguage() {
return _singleton;
}
AppLanguage._internal();
static Future<AppLanguage> getInstance() async {
return _singleton;
}
Locale get appLocal => _appLocale ?? Locale("en");
fetchLocale() async {
var prefs = await SharedPreferences.getInstance();
if (prefs.getString('language_code') == null) {
_appLocale = Locale('en');
}
_appLocale = Locale(prefs.getString('language_code'));
print(" ---- Fetched lang: " + _appLocale.toString());
}
getLocale(SharedPreferences prefs) {
if (prefs.getString('language_code') == null) {
_appLocale = Locale('en');
}
_appLocale = Locale(prefs.getString('language_code'));
}
void changeLanguage(Locale type) async {
var prefs = await SharedPreferences.getInstance();
if (_appLocale == type) {
return;
}
if (type == Locale("hu")) {
_appLocale = Locale("hu");
await prefs.setString('language_code', 'hu');
await prefs.setString('countryCode', 'HU');
} else {
_appLocale = Locale("en");
await prefs.setString('language_code', 'en');
await prefs.setString('countryCode', 'US');
}
print(" ---- Stored lang: " + _appLocale.toString());
notifyListeners();
}
}

View File

@ -0,0 +1,70 @@
import 'dart:convert';
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
class AppLocalizations {
Locale locale;
AppLocalizations(this.locale);
// Helper method to keep the code in the widgets concise
// Localizations are accessed using an InheritedWidget "of" syntax
static AppLocalizations of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}
// Static member to have a simple access to the delegate from the MaterialApp
static const LocalizationsDelegate<AppLocalizations> delegate =
_AppLocalizationsDelegate();
Map<String, String> _localizedStrings;
setLocale(Locale locale) {
this.locale = locale;
}
Future<bool> load() async {
// Load the language JSON file from the "lang" folder
String jsonString =
await rootBundle.loadString('i18n/${locale.languageCode}.json');
Map<String, dynamic> jsonMap = json.decode(jsonString);
_localizedStrings = jsonMap.map((key, value) {
return MapEntry(key, value.toString());
});
return true;
}
// This method will be called from every widget which needs a localized text
String translate(String key) {
return _localizedStrings[key];
}
}
class _AppLocalizationsDelegate
extends LocalizationsDelegate<AppLocalizations> {
// This delegate instance will never change (it doesn't even have fields!)
// It can provide a constant constructor.
const _AppLocalizationsDelegate();
@override
bool isSupported(Locale locale) {
// Include all of your supported language codes here
return ['en', 'hu'].contains(locale.languageCode);
}
@override
Future<AppLocalizations> load(Locale locale) async {
// AppLocalizations class is where the JSON loading actually runs
AppLocalizations localizations = new AppLocalizations(locale);
await localizations.load();
return localizations;
}
@override
bool shouldReload(_AppLocalizationsDelegate old) => false;
}

View File

@ -1,33 +1,43 @@
import 'package:aitrainer_app/model/auth.dart';
import 'package:aitrainer_app/service/api.dart';
import 'package:aitrainer_app/service/customer_service.dart';
import 'package:aitrainer_app/view/account.dart';
import 'package:aitrainer_app/view/customer_bodytype_page.dart';
import 'package:aitrainer_app/view/customer_fitness_page.dart';
import 'package:aitrainer_app/view/customer_goal_page.dart';
import 'package:aitrainer_app/view/customer_modify_page.dart';
import 'package:aitrainer_app/view/customer_new_page.dart';
import 'package:aitrainer_app/view/customer_welcome_page.dart';
import 'package:aitrainer_app/view/gdpr.dart';
import 'package:aitrainer_app/view/login.dart';
import 'package:aitrainer_app/view/exercise_new_page.dart';
import 'package:aitrainer_app/view/exercise_type_modify_page.dart';
import 'package:aitrainer_app/view/exercise_type_new_page.dart';
import 'package:aitrainer_app/view/menu_page.dart';
import 'package:aitrainer_app/view/registration.dart';
import 'package:aitrainer_app/view/settings.dart';
import 'package:aitrainer_app/viewmodel/customer_changing_view_model.dart';
import 'package:aitrainer_app/viewmodel/exercise_changing_view_model.dart';
import 'package:aitrainer_app/widgets/home.dart';
import 'package:aitrainer_app/widgets/loading.dart';
import 'package:flutter/material.dart';
import 'package:aitrainer_app/view/customer_list_page.dart';
import 'package:aitrainer_app/view/exercise_type_list_page.dart';
import 'package:aitrainer_app/widgets/nav_drawer.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:provider/provider.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:aitrainer_app/localization/app_localization.dart';
void main() {
runApp(
MultiProvider(
// Initialize the model in the builder. That way, Provider
// can own Models's lifecycle, making sure to call `dispose`
// when not needed anymore.
providers: [
ChangeNotifierProvider(create: (context) => ExerciseChangingViewModel(null)),
],
child: AitrainerApp(),
runApp(
MultiProvider(
// Initialize the model in the builder. That way, Provider
// can own Models's lifecycle, making sure to call `dispose`
// when not needed anymore.
providers: [
ChangeNotifierProvider(create: (context) => ExerciseChangingViewModel(null)),
ChangeNotifierProvider(create: (context) => CustomerChangingViewModel(null)),
],
child: AitrainerApp(),
),
);
}
@ -36,308 +46,54 @@ class AitrainerApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
return MaterialApp(
localizationsDelegates: [
// ... app-specific localization delegate[s] here
GlobalMaterialLocalizations.delegate,
AppLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: [
const Locale('en'), // English
const Locale('hu'), // Hungarian
const Locale('en', "US"), // English
const Locale('hu', "HU"), // Hungarian
// ... other locales the app supports
],
routes: {
'home': (context) => AitrainerHome(),
'loading': (context) => LoadingScreenMain(),
'customersPage': (context) => CustomerListPage(),
'customerNewPage': (context) => CustomerNewPage(),
'customerModifyPage': (context) => CustomerModifyPage(),
'customerGoalPage': (context) => CustomerGoalPage(),
'customerFitnessPage': (context) => CustomerFitnessPage(),
'customerBodyTypePage': (context) => CustomerBodyTypePage(),
'customerWelcomePage': (context) => CustomerWelcomePage(),
'exerciseTypeListPage': (context) => ExerciseTypeListPage(),
'exerciseTypeNewPage': (context) => ExerciseTypeNewPage(),
'exerciseTypeModifyPage': (context) => ExerciseTypeModifyPage(),
'exerciseNewPage': (context) => ExerciseNewPage(),
'login': (context) => LoginPage(),
'registration': (context) => RegistrationPage(),
'gdpr': (context) => Gdpr(),
'menu_page': (context) => MenuPage(),
'account': (context) => AccountPage(),
'settings': (context) => SettingsPage(),
},
initialRoute: 'home',
title: 'Aitrainer Demo',
initialRoute: 'loading',
title: 'Aitrainer',
theme: ThemeData(
primarySwatch: Colors.green,
),
home: AitrainerHome(),
);
}
}
class AitrainerHome extends StatefulWidget {
static final String routeName = 'home';
@override
State<StatefulWidget> createState() {
return new _HomePageState();
}
}
class _HomePageState extends State<AitrainerHome> {
GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
Auth _auth = Auth();
SharedPreferences _sharedPreferences;
var _authToken;
@override
void initState() {
super.initState();
_fetchSessionAndNavigate();
}
_fetchSessionAndNavigate() async {
_sharedPreferences = await _prefs;
String authToken = Auth.getToken(_sharedPreferences);
var customerId = _sharedPreferences.getInt(Auth.customerIdKey);
if ( _auth.firstLoad ) {
_fetchToken(_sharedPreferences);
}
}
/*
Auth flow of the user, see auth.dart
*/
_fetchToken(SharedPreferences prefs) async {
var responseJson = await APIClient.authenticateUser(
Auth.username,
Auth.password
);
if(responseJson['error'] != null) {
showSnackBar(_scaffoldKey, responseJson['error']);
print("************** Here big error - no authentication");
} else if (responseJson['token'] != null) {
prefs.setString(Auth.authTokenKey, responseJson['token']);
Auth auth = Auth();
auth.authToken = responseJson['token'];
if ( prefs.get(Auth.customerIdKey) == null ) {
print("************** Registration");
// registration
Navigator.of(context).pushNamed('registration');
prefs.setBool(Auth.isRegisteredKey, true);
} else {
DateTime now = DateTime.now();
DateTime lastStoreDate = DateTime.parse( prefs.get(Auth.lastStoreDateKey) );
DateTime minStoreDate = now.add(Duration(days: -10));
if ( lastStoreDate == null ||
lastStoreDate.difference(minStoreDate) > Duration(days: 10) ||
prefs.get(Auth.isLoggedInKey) == null ||
prefs.get(Auth.isLoggedInKey) == false ) {
print("************* Login");
Navigator.of(context).pushNamed('login');
} else {
print("************** Store SharedPreferences");
// get API customer
await CustomerApi().getCustomer( prefs.getInt(Auth.customerIdKey));
}
}
setState(() {
_auth.firstLoad = false;
_authToken = auth.authToken;
_sharedPreferences.setString(Auth.authTokenKey, _authToken);
});
}
}
static showSnackBar(GlobalKey<ScaffoldState> scaffoldKey, String message) {
scaffoldKey.currentState.showSnackBar(
new SnackBar(
content: new Text(message ?? 'You are offline'),
brightness: Brightness.light,
//primarySwatch: Colors.transparent,
fontFamily: 'Arial',
textTheme: TextTheme(
bodyText1: TextStyle(fontSize: 14.0),
)
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
drawer: NavDrawer(),
appBar: AppBar(
title: Text('Home'),
backgroundColor: Colors.transparent
),
body: Image.asset('asset/WT01_loading_layers.png',
fit: BoxFit.fill,
height: double.infinity,
width: double.infinity,
alignment: Alignment.center,
),
home: LoadingScreenMain(),
);
}
}
/*
class CustomerScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
drawer: NavDrawer(),
appBar: AppBar(
title: Text('Customers'),
),
body: Center(
child: CustomerListPage(),
),
);
}
}
*/
/* class AitrainerApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "AITRAINER customers",
home:
ChangeNotifierProvider(
create: (context) => CustomerListViewModel(),
child: CustomerListPage(),
)
);
}
}
*/
/*
// #docregion MyApp
class MyApp extends StatelessWidget {
// #docregion build
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Startup Name Generator',
theme: ThemeData( // Add the 3 lines from here...
primaryColor: Colors.white,
),
home: RandomWords(),
);
}
// #enddocregion build
}
// #enddocregion MyApp
// #docregion RWS-var
class RandomWordsState extends State<RandomWords> {
final _suggestions = <WordPair>[];
final _biggerFont = const TextStyle(fontSize: 18.0);
final Set<WordPair> _saved = Set<WordPair>();
// #enddocregion RWS-var
// #docregion _buildSuggestions
Widget _buildSuggestions() {
return ListView.builder(
padding: const EdgeInsets.all(16.0),
itemBuilder: /*1*/ (context, i) {
if (i.isOdd) return Divider(); /*2*/
final index = i ~/ 2; /*3*/
if (index >= _suggestions.length) {
_suggestions.addAll(generateWordPairs().take(10)); /*4*/
}
return _buildRow(_suggestions[index]);
});
}
// #enddocregion _buildSuggestions
// #docregion _buildRow
Widget _buildRow(WordPair pair) {
final bool alreadySaved = _saved.contains(pair);
return ListTile(
title: Text(
pair.asPascalCase,
style: _biggerFont,
),
trailing: Icon( // Add the lines from here...
alreadySaved ? Icons.favorite : Icons.favorite_border,
color: alreadySaved ? Colors.red : null,
),
onTap: () { // Add 9 lines from here...
setState(() {
if (alreadySaved) {
_saved.remove(pair);
} else {
_saved.add(pair);
}
});
},
);
}
// #enddocregion _buildRow
// #docregion RWS-build
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Startup Name Generator'),
actions: <Widget>[ // Add 3 lines from here...
IconButton(icon: Icon(Icons.list), onPressed: _pushSaved),
],
),
body: _buildSuggestions(),
);
}
void _pushSaved() {
Navigator.of(context).push(
MaterialPageRoute<void>( // Add 20 lines from here...
builder: (BuildContext context) {
final Iterable<ListTile> tiles = _saved.map(
(WordPair pair) {
return ListTile(
title: Text(
pair.asPascalCase,
style: _biggerFont,
),
);
},
);
final List<Widget> divided = ListTile
.divideTiles(
context: context,
tiles: tiles,
).toList();
return Scaffold( // Add 6 lines from here...
appBar: AppBar(
title: Text('Saved Suggestions'),
),
body: ListView(children: divided),
);
},
),
);
}
// #enddocregion RWS-build
// #docregion RWS-var
}
// #enddocregion RWS-var
class RandomWords extends StatefulWidget {
@override
RandomWordsState createState() => new RandomWordsState();
}
*/

View File

@ -1,5 +1,7 @@
import 'package:aitrainer_app/model/customer.dart';
import 'package:aitrainer_app/service/exercisetype_service.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:aitrainer_app/model/exercise_type.dart';
enum SharePrefsChange {
login,
@ -40,6 +42,7 @@ class Auth {
String authToken = "";
Customer userLoggedIn;
bool firstLoad = true;
List<ExerciseType> _exerciseTypes;
factory Auth() {
return _singleton;
@ -79,6 +82,7 @@ class Auth {
//firstLoad = true;
Future<SharedPreferences> prefs = SharedPreferences.getInstance();
setPreferences(prefs, SharePrefsChange.logout, 0);
}
setPreferences(Future<SharedPreferences> prefs,
@ -93,13 +97,24 @@ class Auth {
sharedPreferences.setInt(Auth.customerIdKey, customerId);
sharedPreferences.setBool(Auth.isRegisteredKey, true);
sharedPreferences.setBool(Auth.isLoggedInKey, true);
await ExerciseTypeApi().getExerciseTypes("");
} else if ( type == SharePrefsChange.login ) {
sharedPreferences.setInt(Auth.customerIdKey, customerId);
sharedPreferences.setBool(Auth.isLoggedInKey, true);
} else if ( type == SharePrefsChange.login ) {
await ExerciseTypeApi().getExerciseTypes("");
} else if ( type == SharePrefsChange.logout ) {
sharedPreferences.setBool(Auth.isLoggedInKey, false);
sharedPreferences.setInt(Auth.customerIdKey, 0);
//sharedPreferences.setInt(Auth.customerIdKey, 0);
sharedPreferences.setString(authTokenKey, "");
}
}
void setExerciseTypes( List<ExerciseType> exerciseTypes) {
this._exerciseTypes = exerciseTypes;
}
List<ExerciseType> getExerciseTypes() {
return this._exerciseTypes;
}
}

View File

@ -7,18 +7,46 @@ class Customer {
String active;
int customerId;
String password;
int birthYear;
int weight;
String goal;
String fitnessLevel;
String bodyType;
int admin;
int dataPolicyAllowed;
Customer({this.customerId, this.name, this.firstName, this.email, this.sex, this.age, this.active, this.password});
Customer({this.customerId,
this.name,
this.firstName,
this.email,
this.sex,
this.age,
this.active,
this.password,
this.birthYear,
this.bodyType,
this.fitnessLevel,
this.goal,
this.weight,
this.admin,
this.dataPolicyAllowed
});
Customer.fromJson(Map json) {
this.customerId = json['customer_id'];
this.customerId = json['customerId'];
this.name = json['name'];
this.firstName = json['firstname'];
this.email = json['email'];
this.sex = json['sex'];
this.age = json['age'];
this.active = json['active'];
this.birthYear = json['birthYear'];
this.bodyType = json['bodyType'];
this.fitnessLevel = json['fitnessLevel'];
this.goal = json['goal'];
this.weight = json['weight'];
this.admin = json['admin'];
}
Map<String, dynamic> toJson() =>
@ -30,5 +58,12 @@ class Customer {
"sex": sex,
"active": 'Y',
"password": password,
"birthYear": birthYear,
"bodyType": bodyType,
"fitnessLevel": fitnessLevel,
"goal": goal,
"weight": weight,
"admin": admin,
"dataPolicyAllowed": dataPolicyAllowed,
};
}
}

View File

@ -4,18 +4,22 @@ class Exercise {
int exerciseId;
int exerciseTypeId;
int customerId;
int quantity;
DateTime datetimeExercise;
double quantity;
String unit;
double unitQuantity;
DateTime dateAdd;
Exercise({this.exerciseTypeId, this.customerId, this.quantity, this.datetimeExercise});
Exercise({this.exerciseTypeId, this.customerId, this.quantity, this.dateAdd});
Exercise.fromJson(Map json) {
this.exerciseTypeId = json['exerciseTypeId'];
this.customerId = json['customerId'];
this.quantity = json['quantity'];
this.datetimeExercise = json['datetimeExercise'];
this.unit = json['unit'];
this.unitQuantity = json['unitQuantity'];
this.dateAdd = DateTime.parse( json['dateAdd'] );
}
Map<String, dynamic> toJson() =>
@ -23,7 +27,8 @@ class Exercise {
"exerciseTypeId": exerciseTypeId,
"customerId": customerId,
"quantity": quantity,
"datetimeExercise": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.datetimeExercise),
"unit": unit,
"unitQuantity": unitQuantity,
"dateAdd": DateFormat('yyyy-MM-dd HH:mm:ss').format(this.dateAdd),
};
}

View File

@ -5,6 +5,9 @@ class ExerciseType {
String name;
String description;
BinaryCodec video;
String unit;
String unitQuantity;
String unitQuantityUnit;
ExerciseType({this.name, this.description});
@ -12,11 +15,17 @@ class ExerciseType {
this.exerciseTypeId = json['exerciseTypeId'];
this.name = json['name'];
this.description = json['description'];
this.unit = json['unit'];
this.unitQuantity = json['unitQuantity'];
this.unitQuantityUnit = json['unitQuantityUnit'];
}
Map<String, dynamic> toJson() =>
{
"name": name,
"description": description,
"unit": unit,
"unitQuantity": unitQuantity,
"unitQuantityUnit": unitQuantityUnit
};
}

View File

@ -0,0 +1,16 @@
import 'dart:collection';
import 'dart:ui';
class WorkoutTree {
int id;
int parent;
String name; // is also the key
String imageName;
Color color;
double fontSize;
bool child;
int exercise_type_id;
WorkoutTree(this.id, this.parent, this.name, this.imageName, this.color, this.fontSize, this.child, this.exercise_type_id);
}

View File

@ -7,11 +7,18 @@ class APIClient extends ChangeNotifier {
Future<String> get(String endPoint, String param) async {
final url = Auth.getBaseUrl() + endPoint + param;
Auth auth = Auth();
String authToken = Auth().getAuthToken();
if ( authToken.length == 0 ) {
var responseJson = await APIClient.authenticateUser(
Auth.username,
Auth.password
);
authToken = responseJson['token'];
}
final response = await http.get(url,
headers: {
'Content-Type': 'application/json',
'Authorization' : "Bearer " + auth.getAuthToken() }
'Authorization' : "Bearer " + authToken }
);
notifyListeners();
if(response.statusCode == 200) {
@ -24,11 +31,18 @@ class APIClient extends ChangeNotifier {
Future<String> post(String endPoint, String body) async {
final url = Auth.getBaseUrl() + endPoint;
print(" ------------ http/post endpoint $endPoint body $body - url: $url ");
Auth auth = Auth();
String authToken = Auth().getAuthToken();
if ( authToken.length == 0 ) {
var responseJson = await APIClient.authenticateUser(
Auth.username,
Auth.password
);
authToken = responseJson['token'];
}
final response = await http.post(url,
headers: {
'Content-Type': 'application/json',
'Authorization' : "Bearer " + auth.getAuthToken()
'Authorization' : "Bearer " + authToken
},
body: body
);
@ -59,7 +73,8 @@ class APIClient extends ChangeNotifier {
return responseJson;
} catch (exception) {
return { "error" : "Network error, try again later"};
return { "error" : "Network error, try again later "
+ exception.toString()};
}
}

View File

@ -37,9 +37,8 @@ class CustomerApi {
final String responseBody = await _client.post(
"registration",
body);
Auth auth = Auth();
Customer customer = Customer.fromJson(jsonDecode(responseBody));
auth.afterRegistration(customer);
Auth().afterRegistration(customer);
}
@ -49,9 +48,8 @@ class CustomerApi {
final String responseBody = await _client.post(
"login",
body);
Auth auth = Auth();
Customer customer = Customer.fromJson(jsonDecode(responseBody));
auth.afterRegistration(customer);
Auth().afterRegistration(customer);
}
Future<void> getCustomer(int customerId) async {
@ -60,8 +58,7 @@ class CustomerApi {
final String responseBody = await _client.get(
"customers/"+customerId.toString(),
body);
Auth auth = Auth();
Customer customer = Customer.fromJson(jsonDecode(responseBody));
auth.afterRegistration(customer);
Auth().afterRegistration(customer);
}
}

View File

@ -30,4 +30,12 @@ class ExerciseApi {
body);
}
Future<List<Exercise>> getExercisesByCustomer(int customerId ) async {
final body = await _client.get("exercises/customer/", customerId.toString() );
final Iterable json = jsonDecode(body);
final List<Exercise> exercises = json.map( (exercise) => Exercise.fromJson(exercise) ).toList();
return exercises;
}
}

View File

@ -1,4 +1,5 @@
import 'dart:convert';
import 'package:aitrainer_app/model/auth.dart';
import 'package:aitrainer_app/model/exercise_type.dart';
import 'package:aitrainer_app/service/api.dart';
@ -10,7 +11,7 @@ class ExerciseTypeApi {
final body = await _client.get("exercise_type", param);
final Iterable json = jsonDecode(body);
final List<ExerciseType> exerciseTypes = json.map( (exerciseType) => ExerciseType.fromJson(exerciseType) ).toList();
Auth().setExerciseTypes(exerciseTypes);
return exerciseTypes;
}

View File

@ -1,5 +1,7 @@
import 'dart:collection';
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:intl/intl.dart';
class Common {
@ -13,4 +15,29 @@ class Common {
return rc;
}
static ExerciseType getExerciseType( int exerciseTypeId ) {
ExerciseType returnElement = null;
List<ExerciseType> listExerciseType = Auth().getExerciseTypes();
if ( listExerciseType != null ) {
for ( var element in listExerciseType ) {
if (exerciseTypeId == element.exerciseTypeId) {
returnElement = element;
break;
}
};
}
return returnElement;
}
static String getDateLocale( DateTime datetime, bool timeDisplay ) {
AppLanguage appLanguage = AppLanguage();
var date = datetime;
String dateName = DateFormat(DateFormat.YEAR_MONTH_DAY, appLanguage.appLocal.toString()).format(date.toUtc());
if ( timeDisplay ) {
dateName += " " +DateFormat(DateFormat.HOUR_MINUTE, appLanguage.appLocal.toString()).format(date.toUtc());
}
return dateName;
}
}

View File

@ -0,0 +1,61 @@
import 'package:aitrainer_app/util/loading_screen_state.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
/// Loading Screen Widget that updates the screen once all inistializer methods
/// are called
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();
}

View File

@ -0,0 +1,131 @@
import 'dart:core';
import 'dart:async';
import 'file:///D:/projects/aitrainer/src/aitrainer_app/lib/util/loading_screen.dart';
import 'package:aitrainer_app/localization/app_language.dart';
import 'package:aitrainer_app/localization/app_localization.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
lib/util/menu_tests.dart Normal file
View File

@ -0,0 +1,93 @@
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, 48, false,0);
this.tree['Aerobic']= WorkoutTree(2, 1, AppLocalizations.of(context).translate("Aerobic"),
'asset/menu/1.1.aerob.png',
Colors.white, 48, false,0);
this.tree['Cooper']= WorkoutTree(21, 2, AppLocalizations.of(context).translate("Cooper"),
'asset/menu/1.1.1.cooper.png',
Colors.white, 48, true,30);
this.tree['Anaerobic']= WorkoutTree(3, 1, AppLocalizations.of(context).translate("Anaerobic"),
'asset/menu/1.2.anaerob.png',
Colors.white, 48, false,0);
this.tree['300m']= WorkoutTree(22, 3, "300m",
'asset/menu/1.2.1.300m.png',
Colors.white, 48, true,31);
this.tree['400m']= WorkoutTree(24, 3, "400m",
'asset/menu/1.2.2.400m.png',
Colors.white, 48, true,32);
this.tree['Strength']= WorkoutTree(4, 0, AppLocalizations.of(context).translate("Strength"),
'asset/menu/2.strength.png',
Colors.white, 48, 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, 48, true,38);
this.tree['Pushups']= WorkoutTree(7, 5, AppLocalizations.of(context).translate("Pushups"),
'asset/menu/2.1.2.pushup.png',
Colors.white, 48, true,33);
this.tree['Situps']= WorkoutTree(10, 5, AppLocalizations.of(context).translate("Sit-ups"),
'asset/menu/2.1.3.sit-ups.png',
Colors.white, 48, true,36);
this.tree['Squats']= WorkoutTree(11, 5, AppLocalizations.of(context).translate("Squats"),
'asset/menu/2.1.4.squats.png',
Colors.white, 48, 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, 48, true,45);
this.tree['1RM']= WorkoutTree(8, 4, AppLocalizations.of(context).translate("1RM"),
'asset/menu/2.2.1.1RM.png',
Colors.white, 48, false,0);
this.tree['Chestpress']= WorkoutTree(13, 8, AppLocalizations.of(context).translate("Chest Press"),
'asset/menu/2.2.1.1.chestpress.png',
Colors.white, 48, true,37);
this.tree['PullUps1rm']= WorkoutTree(14, 8, AppLocalizations.of(context).translate("Pull Ups"),
'asset/menu/2.2.1.2.pullups.png',
Colors.white, 48, true, 38);
this.tree['Biceps']= WorkoutTree(15, 8, AppLocalizations.of(context).translate("Biceps"),
'asset/menu/2.2.1.3.biceps.png',
Colors.white, 48, true, 39);
this.tree['Triceps']= WorkoutTree(16, 8, AppLocalizations.of(context).translate("Triceps"),
'asset/menu/2.2.1.4.triceps.png',
Colors.white, 48, true, 40);
this.tree['Shoulders']= WorkoutTree(17, 8, AppLocalizations.of(context).translate("Shoulders"),
'asset/menu/2.2.1.5.shoulders.png',
Colors.white, 48, true, 41);
this.tree['BodyCompositions']= WorkoutTree(9, 0, AppLocalizations.of(context).translate("Body Compositions"),
'asset/menu/3.bcs1.png',
Colors.white, 40, 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,0);
this.tree['Sizes']= WorkoutTree(20, 9, AppLocalizations.of(context).translate("Sizes"),
'asset/menu/3.3.sizes.png',
Colors.black, 48, true,0);
}
LinkedHashMap getMenuItems() {
return this.tree;
}
}

View File

@ -0,0 +1,32 @@
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;
}

74
lib/util/session.dart Normal file
View File

@ -0,0 +1,74 @@
import 'package:aitrainer_app/localization/app_language.dart';
import 'package:aitrainer_app/service/api.dart';
import 'package:aitrainer_app/service/customer_service.dart';
import 'package:aitrainer_app/service/exercisetype_service.dart';
import 'package:aitrainer_app/viewmodel/exercise_type_changing_view_model.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:aitrainer_app/model/auth.dart';
class Session {
Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
Auth _auth = Auth();
SharedPreferences _sharedPreferences;
final AppLanguage appLanguage = AppLanguage();
fetchSessionAndNavigate(Function callback ) async {
_sharedPreferences = await _prefs;
if ( _auth.firstLoad ) {
_fetchToken(_sharedPreferences, callback);
appLanguage.fetchLocale();
}
}
/*
Auth flow of the user, see auth.dart
*/
_fetchToken(SharedPreferences prefs, Function callback) async {
var responseJson = await APIClient.authenticateUser(
Auth.username,
Auth.password
);
print("--- Lang: " + appLanguage.appLocal.toString());
if(responseJson['error'] != null) {
print("************** Here big error - no authentication");
} else if (responseJson['token'] != null) {
prefs.setString(Auth.authTokenKey, responseJson['token']);
Auth auth = Auth();
auth.authToken = responseJson['token'];
if (prefs.get(Auth.customerIdKey) == null) {
print("************** Registration");
// registration
//Navigator.of(context).pushNamed('registration');
prefs.setBool(Auth.isRegisteredKey, true);
} else {
DateTime now = DateTime.now();
DateTime lastStoreDate = DateTime.parse(
prefs.get(Auth.lastStoreDateKey));
DateTime minStoreDate = now.add(Duration(days: -10));
if (lastStoreDate == null ||
lastStoreDate.difference(minStoreDate) > Duration(days: 10) ||
prefs.get(Auth.isLoggedInKey) == null ||
prefs.get(Auth.isLoggedInKey) == false) {
print("************* Login");
//Navigator.of(context).pushNamed('login');
} else {
print("************** Store SharedPreferences");
// get API customer
await CustomerApi().getCustomer(prefs.getInt(Auth.customerIdKey));
}
await ExerciseTypeApi().getExerciseTypes("");
print("--- Session finished, call callback ");
callback();
}
}
}
}

248
lib/view/account.dart Normal file
View File

@ -0,0 +1,248 @@
import 'package:aitrainer_app/localization/app_language.dart';
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/model/auth.dart';
import 'package:aitrainer_app/util/common.dart';
import 'package:aitrainer_app/viewmodel/exercise_changing_view_model.dart';
import 'package:aitrainer_app/viewmodel/exercise_view_model.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:aitrainer_app/viewmodel/user_view_model.dart';
import 'package:aitrainer_app/widgets/bottom_nav.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:provider/provider.dart';
class AccountPage extends StatefulWidget{
_AccountPagePageState _state;
_AccountPagePageState createState() {
_state = new _AccountPagePageState();
return _state;
}
}
class _AccountPagePageState extends State<AccountPage> {
final UserViewModel user = UserViewModel();
final AppLanguage appLanguage = AppLanguage();
final Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
final BottomNavigator bottomNav = BottomNavigator();
bool _loggedIn = Auth().userLoggedIn != null && Auth().userLoggedIn.email.length > 0;
Future<List<ExerciseViewModel>> _exercises;
ExerciseChangingViewModel model;
@override
void initState() {
super.initState();
model = Provider.of<ExerciseChangingViewModel>(context, listen: false);
if ( Auth().userLoggedIn != null ) {
_exercises = model.getExercisesByCustomer(Auth().userLoggedIn.customerId);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(AppLocalizations.of(context).translate('Account')),
backgroundColor: Colors.transparent,
),
body: Container(
foregroundDecoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_long_logo.png'),
//fit: BoxFit.scaleDown,
scale: 1.2,
alignment: Alignment.topRight,
),
),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_light_background.png'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
child:
ListView(
padding: EdgeInsets.only(top: 135),
children: <Widget>[
ListTile(
leading: Icon(Icons.perm_identity),
subtitle: Text(
AppLocalizations.of(context).translate("Profile")),
title: FlatButton(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(_loggedIn ? Auth().userLoggedIn.email + " " +
Auth().userLoggedIn.name + " " +
Auth().userLoggedIn.firstName : "",
style: TextStyle(color: Colors.blue)),
Icon(Icons.arrow_forward_ios),
]),
textColor: Colors.grey,
color: Colors.white,
onPressed: () {
if (_loggedIn) {
Navigator.of(context).pushNamed('customerModifyPage');
print("Profile");
}
},
),
),
ListTile(
leading: Icon(Icons.language),
title: Text(appLanguage.appLocal == Locale('en') ?
AppLocalizations.of(context).translate("English") :
AppLocalizations.of(context).translate("Hungarian")),
subtitle: Text(AppLocalizations.of(context).translate(
"Selected Language")),
),
loginOut(),
exercises( model ),
]
)
),
bottomNavigationBar: bottomNav.buildBottomNavigator(context, widget._state)
);
}
ListTile loginOut() {
ListTile element = ListTile();
String text = "Logout";
Color buttonColor = Colors.orange;
if ( ! _loggedIn ) {
text = "Login";
buttonColor = Colors.blue;
}
element = ListTile(
enabled: true,
leading: Icon(Icons.input),
title: FlatButton(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(AppLocalizations.of(context).translate(text),
style: TextStyle(
color: buttonColor
)),
Icon(Icons.arrow_forward_ios),
]),
textColor: buttonColor,
color: Colors.white,
onPressed: () {
setState(() {
if ( ! _loggedIn) {
print("Login");
Navigator.of(context).pushNamed("login");
} else {
print("Logout");
_loggedIn = false;
Auth().logout();
}
});
},
),
);
return element;
}
ListTile exercises( ExerciseChangingViewModel model ) {
ListTile element = ListTile();
if ( Auth().userLoggedIn == null ) {
return element;
}
element = ListTile(
title: Text(AppLocalizations.of(context).translate("Exercises")),
subtitle: Column(
children: [
FutureBuilder<List<ExerciseViewModel>>(
future: _exercises,
builder: (context, snapshot) {
if (snapshot.hasData) {
return getExercises( model );//CustomerListWidget(customers: _exerciseViewModel.exerciseList);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
// By default, show a loading spinner.
return CircularProgressIndicator();
}
),]
));
return element;
}
Widget getExercises( ExerciseChangingViewModel model ) {
List<ExerciseViewModel> exercises = model.exerciseList;
Column element = Column();
if (exercises.length > 0) {
List<Column> rows = List();
exercises.forEach((exercise) {
String exerciseName = AppLocalizations.of(context).translate(
Common.getExerciseType(exercise.getExercise().exerciseTypeId).name);
String quantity = exercise.getExercise().quantity.toString() + " " +
AppLocalizations.of(context).translate(exercise.getExercise().unit);
String unitQuantity = "";
String unitQuantityUnit = "";
String date = Common.getDateLocale(exercise.getExercise().dateAdd, false);
if (exercise.getExercise().unitQuantity != null) {
unitQuantity = exercise.getExercise().unitQuantity.toString();
unitQuantityUnit = AppLocalizations.of(context).translate(
Common.getExerciseType(exercise.getExercise().exerciseTypeId).unitQuantityUnit);
}
TableRow row = TableRow(
children: [
Text(date),
Text(exerciseName),
Text(quantity),
Text(unitQuantity + " " + unitQuantityUnit),
]
);
Table table = Table(
defaultColumnWidth: FractionColumnWidth(0.28),
children: [row],
);
Column col = Column(
children: [
table,
Row(
children: [
Text(" "),
]
)
],
);
rows.add(col);
});
element = Column(
children: rows,
);
}
return element;
}
}

View File

@ -0,0 +1,81 @@
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/viewmodel/customer_changing_view_model.dart';
import 'package:flutter/material.dart';
// ignore: must_be_immutable
class CustomerBodyTypePage extends StatefulWidget{
_CustomerBodyTypePageState _state;
_CustomerBodyTypePageState createState() {
_state = _CustomerBodyTypePageState();
return _state;
}
}
class GenderItem {
GenderItem(this.dbValue,this.name);
final String dbValue;
String name;
}
class _CustomerBodyTypePageState extends State<CustomerBodyTypePage> {
@override
Widget build(BuildContext context) {
final CustomerChangingViewModel changingViewModel = ModalRoute.of(context).settings.arguments;
return Scaffold(
appBar: AppBar(
title: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Image.asset(
'asset/image/WT_long_logo.png',
fit: BoxFit.cover,
height: 65.0,
),
],
),
backgroundColor: Colors.transparent,
),
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_light_background.png'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
child: Center(
child: Column(
children: [
Divider(),
InkWell(
child: Text("Your Body Type",
style: TextStyle(color: Colors.orange,
fontSize: 50, fontFamily: 'Arial',
fontWeight: FontWeight.w900 ),),
highlightColor: Colors.white,
),
RaisedButton(
color: Colors.orange,
textColor: Colors.white,
child: InkWell(
child: Text(AppLocalizations.of(context).translate("Next"))),
onPressed: () => {
//changingViewModel.saveCustomer(),
Navigator.of(context).pop(),
Navigator.of(context).pushNamed("customerWelcomePage", arguments: changingViewModel)
},
)
],
),
)
),
);
}
}

View File

@ -0,0 +1,80 @@
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/viewmodel/customer_changing_view_model.dart';
import 'package:flutter/material.dart';
// ignore: must_be_immutable
class CustomerFitnessPage extends StatefulWidget{
_CustomerFitnessPageState _state;
_CustomerFitnessPageState createState() {
_state = _CustomerFitnessPageState();
return _state;
}
}
class GenderItem {
GenderItem(this.dbValue,this.name);
final String dbValue;
String name;
}
class _CustomerFitnessPageState extends State<CustomerFitnessPage> {
@override
Widget build(BuildContext context) {
final CustomerChangingViewModel changingViewModel = ModalRoute.of(context).settings.arguments;
return Scaffold(
appBar: AppBar(
title: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Image.asset(
'asset/image/WT_long_logo.png',
fit: BoxFit.cover,
height: 65.0,
),
],
),
backgroundColor: Colors.transparent,
),
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_light_background.png'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
child: Center(
child: Column(
children: [
Divider(),
InkWell(
child: Text("Your Fitness State",
style: TextStyle(color: Colors.orange,
fontSize: 50, fontFamily: 'Arial',
fontWeight: FontWeight.w900 ),),
highlightColor: Colors.white,
),
RaisedButton(
color: Colors.orange,
textColor: Colors.white,
child: InkWell(
child: Text(AppLocalizations.of(context).translate("Next"))),
onPressed: () => {
//changingViewModel.saveCustomer(),
Navigator.of(context).pop(),
Navigator.of(context).pushNamed("customerBodyTypePage", arguments: changingViewModel)
},
)
],
),
)
),
);
}
}

View File

@ -0,0 +1,124 @@
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/viewmodel/customer_changing_view_model.dart';
import 'package:flutter/material.dart';
// ignore: must_be_immutable
class CustomerGoalPage extends StatefulWidget{
_CustomerGoalPageState _state;
_CustomerGoalPageState createState() {
_state = _CustomerGoalPageState();
return _state;
}
}
class GenderItem {
GenderItem(this.dbValue,this.name);
final String dbValue;
String name;
}
class _CustomerGoalPageState extends State<CustomerGoalPage> {
@override
Widget build(BuildContext context) {
final CustomerChangingViewModel changingViewModel = ModalRoute.of(context).settings.arguments;
return Scaffold(
appBar: AppBar(
title: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Image.asset(
'asset/image/WT_long_logo.png',
fit: BoxFit.cover,
height: 65.0,
),
],
),
backgroundColor: Colors.transparent,
),
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_light_background.png'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
child: Center(
child: Column(
children: [
Divider(),
InkWell(
child: Text("Set Your Goals",
style: TextStyle(color: Colors.orange,
fontSize: 50, fontFamily: 'Arial',
fontWeight: FontWeight.w900 ),),
highlightColor: Colors.white,
),
Stack(
alignment: Alignment.bottomLeft,
overflow: Overflow.visible,
children: [
FlatButton(
child: Image.asset("asset/image/WT_gain_muscle.png", height: 250,),
padding: EdgeInsets.all(0.0),
onPressed:() =>
{
print("gain muscle"),
changingViewModel.customer.setGoal("gain_muscle"),
}
),
InkWell(
child: Text("Gain Muscle",
style: TextStyle(color: Colors.white,
fontSize: 36, fontFamily: 'Arial',
fontWeight: FontWeight.w900 ),),
highlightColor: Colors.white,
)
]
),
Stack(
alignment: Alignment.bottomLeft,
overflow: Overflow.visible,
children: [
FlatButton(
child: Image.asset("asset/image/WT_weight_loss.png", height: 220,),
padding: EdgeInsets.all(0.0),
onPressed:() =>
{
print("weight_loss"),
changingViewModel.customer.setGoal("weight_loss"),
}
),
InkWell(
child: Text("Loose Weight",
style: TextStyle(color: Colors.white,
fontSize: 36, fontFamily: 'Arial',
fontWeight: FontWeight.w900 ),),
highlightColor: Colors.white,
)
]
),
RaisedButton(
color: Colors.orange,
textColor: Colors.white,
child: InkWell(
child: Text(AppLocalizations.of(context).translate("Next"))),
onPressed: () => {
//changingViewModel.saveCustomer(),
Navigator.of(context).pop(),
Navigator.of(context).pushNamed("customerFitnessPage", arguments: changingViewModel)
},
)
],
),
)
),
);
}
}

View File

@ -1,29 +1,277 @@
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/model/auth.dart';
import 'package:aitrainer_app/viewmodel/customer_changing_view_model.dart';
import 'package:aitrainer_app/viewmodel/customer_view_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:aitrainer_app/widgets/nav_drawer.dart';
import 'package:flutter/services.dart';
class CustomerModifyPage extends StatefulWidget{
_CustomerModifyPageState createState() => _CustomerModifyPageState();
_CustomerModifyPageState _state;
_CustomerModifyPageState createState() {
_state = _CustomerModifyPageState();
return _state;
}
}
class _CustomerModifyPageState extends State {
//final _formKey = GlobalKey<FormState>();
class GenderItem {
GenderItem(this.dbValue,this.name);
final String dbValue;
String name;
}
class _CustomerModifyPageState extends State<CustomerModifyPage> {
final _formKey = GlobalKey<FormState>();
GenderItem selectedGender;
List<GenderItem> genders;
@override
void initState() {
super.initState();
genders = [
GenderItem("m", "Man"),
GenderItem("w", "Woman"),
];
selectedGender = genders[0];
}
@override
Widget build(BuildContext context) {
final CustomerViewModel model = CustomerViewModel();
model.customer = Auth().userLoggedIn;
final CustomerChangingViewModel customerChangeModel =
CustomerChangingViewModel(model);
customerChangeModel.customer.customer.sex = selectedGender.dbValue;
// we cannot initialize the translations in the initState
genders.forEach((GenderItem element) {
if ( element.dbValue == "m") {
element.name = AppLocalizations.of(context).translate("Man");
}
if ( element.dbValue == "w") {
element.name = AppLocalizations.of(context).translate("Woman");
}
});
return Scaffold(
drawer: NavDrawer(),
resizeToAvoidBottomInset: true,
appBar: AppBar(
title: Text('Modify customer'),
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text("Profil"),
Image.asset(
'asset/image/WT_long_logo.png',
fit: BoxFit.cover,
height: 65.0,
),
],
),
//title: Text(AppLocalizations.of(context).translate('Settings')),
backgroundColor: Colors.transparent,
),
body: Center(
child: Text('Modify customer'),
),
floatingActionButton: FloatingActionButton(
onPressed: () => {},
child: Icon(Icons.save,),
mini: true,
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_light_background.png'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
child: Form(
key: _formKey,
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
padding: EdgeInsets.only(top: 40, left: 25, right: 45, bottom:100),
child: Container(
alignment: Alignment.center,
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: TextFormField(
style: TextStyle(fontSize: 12),
decoration: InputDecoration(
fillColor: Colors.white24,
filled: true,
labelText: AppLocalizations.of(context).translate('Email'),
),
initialValue: customerChangeModel.customer.customer.email,
onFieldSubmitted: (input) => customerChangeModel.customer.setEmail(input)
)
)
],
),
Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: TextFormField(
style: TextStyle(fontSize: 12),
obscureText: true,
decoration: InputDecoration(
fillColor: Colors.white24,
filled: true,
labelText: AppLocalizations.of(context).translate('Password (Leave empty if you don\'t want to change)' ),
),
initialValue: customerChangeModel.customer.customer.password,
onFieldSubmitted: (input) => customerChangeModel.customer.setPassword(input)
)
)
],
),
Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: TextFormField(
style: TextStyle(fontSize: 12),
decoration: InputDecoration(
fillColor: Colors.white24,
filled: true,
labelText: AppLocalizations.of(context).translate('Name'),
),
initialValue: customerChangeModel.customer.customer.name,
onFieldSubmitted: (input) => customerChangeModel.customer.setName(input)
)
)
],
),
Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: TextFormField(
style: TextStyle(fontSize: 12),
decoration: InputDecoration(
fillColor: Colors.white24,
filled: true,
labelText: AppLocalizations.of(context).translate('First Name'),
),
keyboardType: TextInputType.emailAddress,
initialValue: customerChangeModel.customer.customer.firstName,
onFieldSubmitted: (input) => customerChangeModel.customer.setFirstName(input)
)
)
],
),
Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: TextFormField(
style: TextStyle(fontSize: 12),
decoration: InputDecoration(
fillColor: Colors.white24,
filled: true,
labelText: AppLocalizations.of(context).translate('Birth Year'),
),
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
WhitelistingTextInputFormatter.digitsOnly
],
initialValue: customerChangeModel.customer.customer.birthYear.toString(),
onFieldSubmitted: (input) => customerChangeModel.customer.setBirthYear(int.parse(input))
)
)
],
),
Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: TextFormField(
style: TextStyle(fontSize: 12),
decoration: InputDecoration(
fillColor: Colors.white24,
filled: true,
labelText: AppLocalizations.of(context).translate('Weight'),
),
inputFormatters: <TextInputFormatter>[
WhitelistingTextInputFormatter.digitsOnly
],
initialValue: customerChangeModel.customer.customer.weight.toString(),
keyboardType: TextInputType.number,
onFieldSubmitted: (input) => customerChangeModel.customer.setWeight(int.parse(input)),
)
)
],
),
Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: DropdownButtonHideUnderline(
child: DropdownButton<GenderItem>(
hint: Text(AppLocalizations.of(context).translate('Select a gender')),
style: TextStyle(fontSize: 12, color: Colors.black),
focusColor: Colors.white24,
value: selectedGender,
items: genders.map((GenderItem gender){
return DropdownMenuItem<GenderItem>(
value: gender,
child: Text(gender.name)
);
}).toList(),
onChanged:(GenderItem gender) => {
setState(() {
selectedGender = gender;
customerChangeModel.customer.setSex(gender.dbValue);
print ("Gender " + gender.name);
})
//model.customer.sex =
},
)
)
)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Expanded(
child: RaisedButton(
color: Colors.orange,
textColor: Colors.white,
child: InkWell(
child: Text(AppLocalizations.of(context).translate("Next"))),
onPressed: () => {
customerChangeModel.saveCustomer(),
Navigator.of(context).pushNamed("customerGoalPage", arguments: customerChangeModel)
},
)
)
],
),
],
),
),
),
)
)
);
}
}

View File

@ -68,7 +68,7 @@ class _CustomerNewPageState extends State {
validator: (input) => (int.parse(input) < 99 && int.parse(input) > 0) ?
null :
"Please type the right age 0-99",
onChanged: (input) => customer.setAge(int.parse(input)),
onChanged: (input) => customer.setBirthYear(int.parse(input)),
),
RadioListTile(
title: const Text('Man'),

View File

@ -0,0 +1,75 @@
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/viewmodel/customer_changing_view_model.dart';
import 'package:flutter/material.dart';
// ignore: must_be_immutable
class CustomerWelcomePage extends StatefulWidget{
_CustomerWelcomePageState _state;
_CustomerWelcomePageState createState() {
_state = _CustomerWelcomePageState();
return _state;
}
}
class GenderItem {
GenderItem(this.dbValue,this.name);
final String dbValue;
String name;
}
class _CustomerWelcomePageState extends State<CustomerWelcomePage> {
@override
Widget build(BuildContext context) {
final CustomerChangingViewModel changingViewModel = ModalRoute.of(context).settings.arguments;
return Scaffold(
appBar: AppBar(
title: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Image.asset(
'asset/image/WT_long_logo.png',
fit: BoxFit.cover,
height: 65.0,
),
],
),
backgroundColor: Colors.transparent,
),
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_welcome.png'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
child: Center(
child: Column(
children: [
Divider(),
RaisedButton(
color: Colors.orange,
textColor: Colors.white,
child: InkWell(
child: Text(AppLocalizations.of(context).translate("Next"))),
onPressed: () => {
Navigator.of(context).pop(),
Navigator.of(context).pushNamed("home", arguments: changingViewModel)
},
)
],
),
)
),
);
}
}

View File

@ -1,108 +1,226 @@
import 'package:aitrainer_app/localization/app_language.dart';
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/viewmodel/exercise_changing_view_model.dart';
import 'package:aitrainer_app/widgets/nav_drawer.dart';
import 'package:intl/intl.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:datetime_picker_formfield/datetime_picker_formfield.dart';
//import 'package:datetime_picker_formfield/datetime_picker_formfield.dart';
class ExerciseNewPage extends StatefulWidget{
_ExerciseNewPageState createState() => _ExerciseNewPageState();
}
class _ExerciseNewPageState extends State {
final List excluded = [43,44];
final _formKey = GlobalKey<FormState>();
final format = DateFormat("yyyy-MM-dd HH:mm");
@override
Widget build(BuildContext context) {
ExerciseChangingViewModel model = Provider.of<ExerciseChangingViewModel>(context, listen: false);
model.createNewModel();
return Scaffold(
drawer: NavDrawer(),
appBar: AppBar(
title: Text('New exercise'),
),
body: Center(
child: Form(
key: _formKey,
child: Column(
children: <Widget>[
TextFormField(
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Name',
),
readOnly: true,
initialValue: model != null && model.customer != null ? model.customer.name + " " + model.customer.firstName : "Please select a customer",
),
TextFormField(
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Exercise',
),
readOnly: true,
initialValue: model != null && model.exerciseType != null ? model.exerciseType.name : "Please select an exercise",
),
TextFormField(
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Quantity',
),
validator: (input) => (int.parse(input) < 1000 && int.parse(input) > 0) ?
null :
"Please type the right quantity 0-1000",
onChanged: (input) => model.exerciseViewModel.setQuantity(int.parse(input)),
),
Text('Exercise date and time'),
DateTimeField(
format: format,
initialValue: DateTime.now(),
onShowPicker: (context, currentValue) async {
final date = await showDatePicker(
context: context,
firstDate: DateTime(1900),
initialDate: DateTime.now(),
lastDate: DateTime(2100),
builder: (context, child) => Localizations.override(
context: context,
locale: Locale('hu'),
child: child,
),
);
if (date != null) {
final time = await showTimePicker(
context: context,
initialTime:
TimeOfDay.fromDateTime(currentValue ?? DateTime.now()),
builder: (context, child) => Localizations.override(
context: context,
locale: Locale('hu'),
child: child,
),
);
return DateTimeField.combine(date, time);
} else {
return currentValue;
}
},
onChanged: (input) => model.exerciseViewModel.setDatetimeExercise(input),
),
]),
)
),
floatingActionButton: FloatingActionButton(
onPressed: () => {
if (_formKey.currentState.validate()) {
//model = ExerciseChangingViewModel(model.exerciseViewModel),
model.addExercise(),
Navigator.pop(context),
return Consumer<ExerciseChangingViewModel>(
builder: (context, model, child ) {
String exerciseName = "";
String customerName = "";
if ( model != null ) {
if ( model.exerciseViewModel == null ) {
model.createNewModel();
}
},
child: Icon(Icons.save,),
mini: true,
)
);
model.exerciseViewModel.createNew();
customerName = model != null && model.customer != null
? model.customer.name + " " +
model.customer.firstName
: "Please select a customer";
exerciseName = model != null &&
model.exerciseType != null
? model.exerciseType.name
: "Please select an exercise";
}
AppLanguage appLanguage = AppLanguage();
var date = DateTime.now();
String dateName = DateFormat(DateFormat.YEAR_MONTH_DAY, appLanguage.appLocal.toString()).format(date.toUtc()) +
" " +DateFormat(DateFormat.HOUR_MINUTE, appLanguage.appLocal.toString()).format(date.toUtc());
return Form(
key: _formKey,
autovalidate: true,
child: Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colors.deepOrange),
onPressed: () => {
Navigator.of(context).pop()
},
),
title: Text(AppLocalizations.of(context).translate(exerciseName) + " " +
AppLocalizations.of(context).translate('Save Exercise'),
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.deepOrange)),
backgroundColor: Colors.white70,
),
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_login.png'),
fit: BoxFit.cover,
//height: double.infinity,
//width: double.infinity,
alignment: Alignment.center,
),
),
child: Container(
padding: const EdgeInsets.only (top: 65, left:25, right: 100),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
columnQuantityUnit(model),
columnQuantity(model),
Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
new InkWell(
child: new Text(dateName,
style: TextStyle( fontSize: 16,color: Colors.blue)),
),
ButtonTheme(
minWidth: 30.0,
height: 30.0,
child: FlatButton(
padding: EdgeInsets.only(bottom: 0),
color: Colors.transparent,
splashColor: Colors.black26,
child: Row(
children: [
Icon(Icons.arrow_forward_ios, color: Colors.orange,)
]),
onPressed:() { print("date change");},
)),
],
),
new InkWell(
child: new Text(AppLocalizations.of(context).translate('Exercise date and time'),
style: TextStyle( fontSize: 16)),
),
]),
RaisedButton(
textColor: Colors.white,
color: Colors.deepOrange,
focusColor: Colors.white,
onPressed: () =>
{
if (_formKey.currentState.validate()) {
//model = ExerciseChangingViewModel(model.exerciseViewModel),
if ( ! excluded.contains(model.exerciseType.exerciseTypeId) ) {
model.addExercise(),
},
Navigator.pop(context),
}
},
child: Text("Save", style: TextStyle(fontSize: 16),)
),
]),
)
),
),
);
});
}
Column columnQuantityUnit( ExerciseChangingViewModel model) {
Column column = Column();
if ( model.exerciseType != null && model.exerciseType.unitQuantity == "1") {
column = Column(
children: [
TextFormField(
autovalidate: true,
textAlign: TextAlign.center,
initialValue: "0",
style: TextStyle(fontSize: 30,
color: Colors.lightBlue,
fontWeight: FontWeight.bold),
validator: (input) {
return validateNumberInput(input);
},
onFieldSubmitted: (input) => {
print ("UnitQuantity value $input"),
model.exerciseViewModel.setUnitQuantity(
double.parse(input))
},
),
new InkWell(
child: new Text(AppLocalizations.of(context).translate(
model.exerciseType.unitQuantityUnit),
style: TextStyle(fontSize: 16)),
),
]);
};
return column;
}
Column columnQuantity( ExerciseChangingViewModel model) {
Column column = Column();
column = Column(
children: [
TextFormField(
autovalidate: true,
textAlign: TextAlign.center,
initialValue: "0",
style: TextStyle(fontSize: 60,
color: Colors.deepOrange,
fontWeight: FontWeight.bold),
validator: (input) {
return validateNumberInput(input);
},
onFieldSubmitted: (input) =>
{
print ("Quantity value $input"),
model.exerciseViewModel.setQuantity(
double.parse(input)),
model.exerciseViewModel.setUnit(model.exerciseType.unit)
}
),
new InkWell(
child: new Text(AppLocalizations.of(context).translate(model.exerciseType.unit),
style: TextStyle(fontSize: 16)),
),
]);
return column;
}
String validateNumberInput( input ) {
String error = AppLocalizations.of(context).translate("Please type the right quantity 0-10000");
dynamic rc = ( input != null && input.length > 0);
if ( ! rc ) {
return null;
}
rc = double.tryParse(input);
if ( rc == null ) {
return error;
}
if ( ! ( double.parse(input) < 10000 && double.parse(input) > 0) ) {
return error;
}
return null;
}
}

39
lib/view/gdpr.dart Normal file
View File

@ -0,0 +1,39 @@
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class Gdpr extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
padding: const EdgeInsets.only (left:15, right: 15),
child: ListView(
children: <Widget>[
new InkWell(
child: new Text(
AppLocalizations.of(context).translate('gdpr_text'),
),
customBorder: Border.all(color:Colors.teal, width:1),
),
Spacer(flex:2),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
FlatButton(
textColor: Colors.black,
onPressed: () { },
)
],
)
],
)
)
);
}
}

View File

@ -1,9 +1,12 @@
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/model/auth.dart';
import 'package:aitrainer_app/viewmodel/exercise_changing_view_model.dart';
import 'package:aitrainer_app/viewmodel/user_changing_view_model.dart';
import 'package:aitrainer_app/viewmodel/user_view_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:aitrainer_app/widgets/nav_drawer.dart';
import 'package:provider/provider.dart';
class LoginPage extends StatefulWidget{
_LoginPageState createState() => _LoginPageState();
@ -11,71 +14,126 @@ class LoginPage extends StatefulWidget{
class _LoginPageState extends State {
final UserViewModel user = UserViewModel();
bool _obscureText = true;
final bool _obscureText = true;
final _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
UserChangingViewModel model = UserChangingViewModel(user);
ExerciseChangingViewModel exerciseModel = Provider.of<ExerciseChangingViewModel>(context, listen: false);
user.createNew();
return Scaffold(
drawer: NavDrawer(),
appBar: AppBar(
title: Text('Login'),
),
body: Center(
child: Form(
key: _formKey,
child: Column(
children: <Widget>[
TextFormField(
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Email',
icon: const Padding(
padding:const EdgeInsets.only(left: 20.0, top: 50.0),
child: const Icon(Icons.people)
)
),
validator: (String input) {
RegExp exp = new RegExp(r"[\w._]+\@[\w._]+.[a-z]+",
caseSensitive: false,
multiLine: false,);
String ret = exp.hasMatch(input) == true ?
null:
"Please type an email address";
return ret;
},
onChanged: (input) => user.setEmail(input),
),
new TextFormField(
decoration: const InputDecoration(
labelText: 'Password',
icon: const Padding(
padding: const EdgeInsets.only(left: 20.0, top: 15.0),
child: const Icon(Icons.lock))),
validator: (val) => val.length < 6 ? 'Password too short.' : null,
obscureText: _obscureText,
onChanged: (input) => user.setPassword(input),
),
new InkWell(
child: new Text('SignUp'),
onTap: () => Navigator.of(context).pushNamed('registration'),
),
new FloatingActionButton(
child: Icon(Icons.cloud_done,),
onPressed:() => {
if (_formKey.currentState.validate()) {
model = UserChangingViewModel(user),
model.getUser(),
Navigator.pop(context),
}
})
])
),
),
return Scaffold(
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_login.png'),
fit: BoxFit.cover,
//height: double.infinity,
//width: double.infinity,
alignment: Alignment.center,
),
),
child: Form(
key: _formKey,
child: Container(
padding: const EdgeInsets.only (left: 25, right: 100),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Spacer(flex: 4),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
new InkWell(
child: new Text(
AppLocalizations.of(context).translate(
'Login'),
style: TextStyle(fontWeight: FontWeight.bold,
fontSize: 24)),
),
],
),
TextFormField(
decoration: InputDecoration(
fillColor: Colors.white,
filled: true,
labelText: 'Email',
),
validator: (String input) {
RegExp exp = new RegExp(r"[\w._]+\@[\w._]+.[a-z]+",
caseSensitive: false,
multiLine: false,);
String ret = exp.hasMatch(input) == true ?
null :
AppLocalizations.of(context).translate(
'Please type an email address');
return ret;
},
onChanged: (input) => user.setEmail(input),
),
Spacer(flex: 1),
new TextFormField(
decoration: const InputDecoration(
filled: true,
labelText: "Password",
fillColor: Colors.white,
focusColor: Colors.white,
),
validator: (val) => val.length < 6
? AppLocalizations.of(context).translate(
'Password too short')
: null,
obscureText: _obscureText,
onChanged: (input) => user.setPassword(input),
),
Spacer(flex: 1),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[ new FlatButton(
child: Image.asset('asset/image/WT_OK.png',
width: 100,
height: 100
),
onPressed: () =>
{
if (_formKey.currentState.validate()) {
model = UserChangingViewModel(user),
model.getUser(),
exerciseModel.setCustomer(
Auth().userLoggedIn),
Navigator.pop(context),
}
}),
]),
Spacer(flex: 2),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
new InkWell(
child: new Text(
AppLocalizations.of(context).translate(
'SignUp')),
onTap: () =>
Navigator.of(context).pushNamed(
'registration'),
),
Spacer(flex: 1),
new InkWell(
child: new Text(
AppLocalizations.of(context).translate(
'Privacy')),
onTap: () =>
Navigator.of(context).pushNamed('gdpr'),
),
Spacer(flex: 2),
]),
Spacer(flex: 2),
])
),
),
)
);
}
}

154
lib/view/menu_page.dart Normal file
View File

@ -0,0 +1,154 @@
import 'package:aitrainer_app/model/auth.dart';
import 'package:aitrainer_app/model/exercise_type.dart';
import 'package:aitrainer_app/model/workout_tree.dart';
import 'package:aitrainer_app/util/common.dart';
import 'package:aitrainer_app/util/menu_tests.dart';
import 'package:aitrainer_app/viewmodel/exercise_changing_view_model.dart';
import 'package:aitrainer_app/widgets/bottom_nav.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'dart:collection';
import 'package:provider/provider.dart';
// ignore: must_be_immutable
class MenuPage extends StatefulWidget {
_MenuPageState _state;
static const routeName = '/menu_page';
int parent;
MenuPage({this.parent});
@override
_MenuPageState createState() {
_state = new _MenuPageState();
return _state;
}
}
class _MenuPageState extends State<MenuPage> {
final BottomNavigator bottomNav = BottomNavigator();
@override
Widget build(BuildContext context) {
final MenuTests menu = MenuTests(context);
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.transparent,
title: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Image.asset(
'asset/image/WT_long_logo.png',
fit: BoxFit.cover,
height: 65.0,
),
],
),
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colors.black),
onPressed: () => {
this.setState(() {
widget.parent = 0;
},
)},
),
),
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_menu_dark.png'),
fit: BoxFit.fill,
alignment: Alignment.center,
),
),
child: CustomScrollView(
scrollDirection: Axis.vertical,
slivers: <Widget>[
buildMenuColumn(widget.parent, context, menu)
]
)
),
);
}
SliverList buildMenuColumn(int parent, BuildContext context, MenuTests menu) {
LinkedHashMap tree = menu.getMenuItems();
List<Widget> _columnChildren = List();
ExerciseType exerciseType;
ExerciseChangingViewModel model = Provider.of<ExerciseChangingViewModel>(context, listen: false);
tree.forEach((treeName, value) {
WorkoutTree workoutTree = value as WorkoutTree;
if ( workoutTree.parent == parent ) {
_columnChildren.add(
Container(
padding: EdgeInsets.only(top: 16.0),
child: Center(
child: Stack(
alignment: Alignment.bottomLeft,
overflow: Overflow.visible,
children: [
FlatButton(
child: _getButtonImage(workoutTree),
padding: EdgeInsets.all(0.0),
onPressed:() =>
{
print("Hi!, Menu clicked " + workoutTree.id.toString()),
if ( workoutTree.child == false ) {
this.setState(() {
widget.parent = workoutTree.id;
},
),
} else {
exerciseType = Common.getExerciseType(workoutTree.exercise_type_id),
model.setExerciseType(exerciseType),
model.setCustomer(Auth().userLoggedIn),
if ( Auth().userLoggedIn == null ) {
Scaffold.of(context)
. showSnackBar(SnackBar(content: Text('Please log in')))
} else {
Navigator.of(context).pushNamed('exerciseNewPage'),
}
}
}
),
InkWell(
child: Text(workoutTree.name, style: TextStyle(color: workoutTree.color, fontSize: workoutTree.fontSize, fontFamily: 'Arial', fontWeight: FontWeight.w900 ),),
highlightColor: workoutTree.color,
)]))));
}
});
//_columnChildren.add(Spacer(flex: 3));
SliverList sliverList =
SliverList(
delegate: SliverChildListDelegate(
_columnChildren
)
);
return sliverList;
}
dynamic _getButtonImage(WorkoutTree workoutTree) {
dynamic image;
if ( workoutTree.imageName.startsWith("http") ) {
image = FadeInImage.assetNetwork(
image: workoutTree.imageName,
placeholder: 'asset/image/dots.gif',
//imageScale: 0.1,
height: 180,
placeholderScale: 0.1,
);
} else {
image = Image.asset(workoutTree.imageName, height: 180,);
}
return image;
}
}

View File

@ -1,4 +1,5 @@
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/viewmodel/user_changing_view_model.dart';
import 'package:aitrainer_app/viewmodel/user_view_model.dart';
import 'package:flutter/material.dart';
@ -19,66 +20,102 @@ class _RegistrationPageState extends State {
Widget build(BuildContext context) {
UserChangingViewModel model = UserChangingViewModel(user);
user.createNew();
return Scaffold(
drawer: NavDrawer(),
appBar: AppBar(
title: Text('Registration'),
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_login.png'),
fit: BoxFit.cover,
//height: double.infinity,
//width: double.infinity,
alignment: Alignment.center,
),
),
body: Center(
child: Form(
key: _formKey,
child: Column(
child: Form(
key: _formKey,
child: Container(
padding: const EdgeInsets.only (left:25, right: 100),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Spacer(flex:4),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
new InkWell(
child: new Text(AppLocalizations.of(context).translate('SignUp'),
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 24)),
),
],
),
TextFormField(
decoration: InputDecoration(
border: OutlineInputBorder(),
fillColor: Colors.white,
filled:true,
labelText: 'Email',
icon: const Padding(
padding:const EdgeInsets.only(left: 20.0, top: 50.0),
child: const Icon(Icons.people)
)
),
/* validator: (String input) {
RegExp exp = new RegExp(r"[\w._]+\@[\w._]+.[a-z]+",
caseSensitive: false,
multiLine: false,);
String ret = exp.hasMatch(input) == true ?
null:
"Please type an email address";
return ret;
},*/
validator: (String input) {
RegExp exp = new RegExp(r"[\w._]+\@[\w._]+.[a-z]+",
caseSensitive: false,
multiLine: false,);
String ret = exp.hasMatch(input) == true ?
null:
AppLocalizations.of(context).translate('Please type an email address');
return ret;
},
onChanged: (input) => user.setEmail(input),
),
Spacer(flex:1),
new TextFormField(
decoration: const InputDecoration(
labelText: 'Password',
icon: const Padding(
padding: const EdgeInsets.only(left: 20.0, top: 15.0),
child: const Icon(Icons.lock))),
/* validator: (String input) {
String rc = input.length < 4 ? 'Password too short.' : null;
return rc;
}, */
onChanged: (input) => user.setPassword(input),
filled:true,
labelText: "Password",
fillColor: Colors.white,
focusColor: Colors.white,
),
validator: (val) => val.length < 6 ? AppLocalizations.of(context).translate('Password too short') : null,
obscureText: _obscureText,
onChanged: (input) => user.setPassword(input),
),
new InkWell(
child: new Text('I have an account'),
onTap: () => Navigator.of(context).pushNamed('login'),
),
new FloatingActionButton(
child: Icon(Icons.cloud_done,),
onPressed:() => {
if (_formKey.currentState.validate()) {
model = UserChangingViewModel(user),
model.addUser(),
Navigator.pop(context),
}
}
)
])
),
Spacer(flex:1),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[ new FlatButton(
child: Image.asset('asset/image/WT_OK.png',
width: 100,
height:100
),
onPressed:() => {
if (_formKey.currentState.validate()) {
model = UserChangingViewModel(user),
model.addUser(),
Navigator.of(context).pushNamed("customerModifyPage",)
}
}),
]),
Spacer(flex:2),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
new InkWell(
child: new Text(AppLocalizations.of(context).translate('Login')),
onTap: () => Navigator.of(context).pushNamed('login'),
),
Spacer(flex:1),
new InkWell(
child: new Text(AppLocalizations.of(context).translate('Privacy')),
onTap: () => Navigator.of(context).pushNamed('gdpr'),
),
Spacer(flex:2),
]),
Spacer(flex:2),
])
),
),
),
);
}

103
lib/view/settings.dart Normal file
View File

@ -0,0 +1,103 @@
import 'package:aitrainer_app/localization/app_language.dart';
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/widgets/bottom_nav.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
class SettingsPage extends StatefulWidget{
_SettingsPageState _state;
_SettingsPageState createState() {
_state = new _SettingsPageState();
return _state;
}
}
class _SettingsPageState extends State<SettingsPage> {
final AppLanguage appLanguage = AppLanguage();
Locale _locale;
final _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
BottomNavigator bottomNav = BottomNavigator();
_locale = appLanguage.appLocal;
return Scaffold(
appBar: AppBar(
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(AppLocalizations.of(context).translate('Settings')),
Image.asset(
'asset/image/WT_long_logo.png',
fit: BoxFit.cover,
height: 65.0,
),
],
),
//title: Text(AppLocalizations.of(context).translate('Settings')),
backgroundColor: Colors.transparent,
),
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_light_background.png'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
child: Form(
key: _formKey,
child:
ListView(
padding: EdgeInsets.only(top: 150),
children: <Widget>[
ListTile(
leading: Icon(Icons.language),
subtitle: Text(AppLocalizations.of(context).translate("Change App Language")),
title: DropdownButton(
value: _locale == Locale('en') ? AppLocalizations.of(context).translate("English") : AppLocalizations.of(context).translate("Hungarian"),
items: [AppLocalizations.of(context).translate("English"), AppLocalizations.of(context).translate("Hungarian")]
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged:(String lang) => _changeLanguage(lang),
)
),
]
),
),
),
bottomNavigationBar: bottomNav.buildBottomNavigator(context, widget._state)
);
}
_changeLanguage( String lang ) {
setState(() {
switch ( lang ) {
case "English":
case "Angol":
_locale = Locale('en');
break;
case "Hungarian":
case "Magyar":
_locale = Locale('hu');
break;
}
appLanguage.changeLanguage(_locale);
AppLocalizations.of(context).setLocale(_locale);
AppLocalizations.of(context).load();
});
}
}

View File

@ -19,7 +19,7 @@ class CustomerChangingViewModel extends ChangeNotifier {
}
Future<void> saveCustomer() async {
this.customer = customer;
//this.customer = customer;
final Customer modelCustomer = customer.getCustomer();
await CustomerApi().saveCustomer(modelCustomer);
}

View File

@ -18,8 +18,8 @@ class CustomerViewModel {
return this.customer.sex == "m" ? "Man" : "Woman";
}
int get age {
return this.customer.age;
int get birthYear {
return this.birthYear;
}
setName(String name) {
@ -29,18 +29,39 @@ class CustomerViewModel {
this.customer.firstName = firstName;
}
setPassword( String password ) {
this.customer.password = password;
}
setEmail(String email) {
this.customer.email = email;
}
setAge(int age) {
this.customer.age = age;
}
setSex(String sex) {
this.customer.sex = sex;
}
setWeight( int weight) {
this.customer.weight = weight;
}
setBirthYear( int birthYear ) {
this.customer.birthYear = birthYear;
}
setFitnessLevel( String level ) {
this.customer.fitnessLevel = level;
}
setGoal( String goal ) {
this.customer.goal = goal;
}
setBodyType(String bodyType) {
this.customer.bodyType = bodyType;
}
createNew() {
this.customer = Customer();
}

View File

@ -9,6 +9,7 @@ import 'exercise_view_model.dart';
class ExerciseChangingViewModel with ChangeNotifier {
Customer customer;
ExerciseType exerciseType;
List<ExerciseViewModel> exerciseList = List<ExerciseViewModel>();
ExerciseViewModel exerciseViewModel = ExerciseViewModel();
@ -20,10 +21,12 @@ class ExerciseChangingViewModel with ChangeNotifier {
setCustomer(Customer customer) {
this.customer = customer;
notifyListeners();
}
setExerciseType( ExerciseType exerciseType) {
this.exerciseType = exerciseType;
notifyListeners();
}
setQuantity(int quantity) {
@ -31,7 +34,7 @@ class ExerciseChangingViewModel with ChangeNotifier {
}
addExercise() async {
this.exerciseViewModel = exerciseViewModel;
// this.exerciseViewModel = exerciseViewModel;
final Exercise modelExercise = exerciseViewModel.getExercise();
modelExercise.customerId = this.customer.customerId;
modelExercise.exerciseTypeId = this.exerciseType.exerciseTypeId;
@ -43,4 +46,11 @@ class ExerciseChangingViewModel with ChangeNotifier {
exerciseViewModel.createNew();
}
Future<List<ExerciseViewModel>> getExercisesByCustomer( int customerId ) async {
final results = await ExerciseApi().getExercisesByCustomer(customerId);
this.exerciseList = results.map((item) => ExerciseViewModel(exercise: item)).toList();
notifyListeners();
return this.exerciseList;
}
}

View File

@ -6,15 +6,23 @@ class ExerciseViewModel {
createNew() {
this.exercise = Exercise();
exercise.datetimeExercise = DateTime.now();
exercise.dateAdd = DateTime.now();
}
setQuantity(int quantity) {
setQuantity(double quantity) {
this.exercise.quantity = quantity;
}
setUnitQuantity(double unitQuantity) {
this.exercise.unitQuantity = unitQuantity;
}
setUnit( String unit) {
this.exercise.unit = unit;
}
setDatetimeExercise(DateTime datetimeExercise) {
this.exercise.datetimeExercise = datetimeExercise;
this.exercise.dateAdd = datetimeExercise;
}
Exercise getExercise() {

View File

@ -0,0 +1,58 @@
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:flutter/material.dart';
class BottomNavigator {
BottomNavigationBar buildBottomNavigator(BuildContext context, State state) {
return BottomNavigationBar(
currentIndex: 0, // this will be set when a new tab is tapped
backgroundColor: Colors.black12,
selectedItemColor: Colors.yellow,
unselectedItemColor: Colors.lightGreen,
type: BottomNavigationBarType.shifting,
showSelectedLabels: true,
items: [
BottomNavigationBarItem(
backgroundColor: Colors.black12,
icon: new Icon(Icons.home, color: Colors.lightGreen),
activeIcon: new Icon(Icons.home, color: Colors.yellow,),
title: new Text(AppLocalizations.of(context).translate("Home")),
),
BottomNavigationBarItem(
icon: new Icon(Icons.event, color: Colors.lightGreen),
activeIcon: new Icon(Icons.event, color: Colors.yellow,),
title: new Text(AppLocalizations.of(context).translate("Events")),
),
BottomNavigationBarItem(
icon: Icon(Icons.person, color: Colors.lightGreen,),
activeIcon: new Icon(Icons.person, color: Colors.yellow,),
title: Text(AppLocalizations.of(context).translate("Account"))
),
BottomNavigationBarItem(
icon: Icon(Icons.settings, color: Colors.lightGreen),
activeIcon: new Icon(Icons.settings, color: Colors.yellow,),
title: Text(AppLocalizations.of(context).translate("Settings"))
)
],
onTap:(index) {
// ignore: invalid_use_of_protected_member
switch (index) {
case 0:
Navigator.of(context).pop();
Navigator.of(context).pushNamed('home');
break;
case 2:
Navigator.of(context).pop();
Navigator.of(context).pushNamed('account');
break;
case 3:
Navigator.of(context).pop();
Navigator.of(context).pushNamed('settings');
break;
}
}
);
}
}

View File

@ -36,7 +36,7 @@ class _CustomerListWidget extends State<CustomerListWidget> {
visible: customer.visibleDetails,
child: Row(
children: <Widget>[
Text(customer.age.toString() + " years, " + customer.sex),
Text(customer.birthYear.toString() + " years, " + customer.sex),
new RaisedButton(
child: new Text('Modify'),
color: Color.fromRGBO(244, 122, 22, 0.9),

57
lib/widgets/home.dart Normal file
View File

@ -0,0 +1,57 @@
import 'package:aitrainer_app/localization/app_language.dart';
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/view/menu_page.dart';
import 'package:aitrainer_app/widgets/bottom_nav.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'bottom_nav.dart';
import 'nav_drawer.dart';
class AitrainerHome extends StatefulWidget {
_HomePageState _state;
@override
State<StatefulWidget> createState() {
_state = new _HomePageState();
return _state;
}
void callback() {
_state.setLangNoContext();
}
}
class _HomePageState extends State<AitrainerHome> {
GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
final AppLanguage appLanguage = AppLanguage();
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
MenuPage menu = MenuPage();
BottomNavigator bottomNav = BottomNavigator();
return Scaffold(
key: _scaffoldKey,
drawer: NavDrawer(),
body:Container(
child: MenuPage(parent: 0),
),
bottomNavigationBar: bottomNav.buildBottomNavigator(context, widget._state)
);
}
void setLangNoContext() {
print("--- Callback ");
setState(() {
final AppLanguage appLanguage = AppLanguage();
AppLocalizations.of(context).setLocale(appLanguage.appLocal);
AppLocalizations.of(context).load();
print("--- Lang for context reloaded");
});
}
}

55
lib/widgets/loading.dart Normal file
View File

@ -0,0 +1,55 @@
import 'package:aitrainer_app/util/message_state.dart';
import 'package:aitrainer_app/util/session.dart';
import 'package:aitrainer_app/view/menu_page.dart';
import 'package:aitrainer_app/widgets/bottom_nav.dart';
import 'package:aitrainer_app/widgets/home.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'file:///D:/projects/aitrainer/src/aitrainer_app/lib/util/loading_screen.dart';
class LoadingScreenMain extends StatefulWidget {
@override
LoadingScreenMainState createState() => LoadingScreenMainState();
}
class LoadingScreenMainState extends State<LoadingScreenMain> {
@override
Widget build(BuildContext context) {
Image _backgroundImage = Image.asset('asset/WT01_loading_layers.png',
fit: BoxFit.cover,
height: double.infinity,
width: double.infinity,
alignment: Alignment.center,
);
dynamic _timer = <dynamic>[TimeMessages.timer];
return Scaffold(
body: LoadingScreen(
initializers: _timer,
navigateToWidget: AitrainerHome(),
loaderColor: Colors.yellow,
image: _backgroundImage,
backgroundColor: Colors.black,
styleTextUnderTheLoader: TextStyle(
fontSize: 14.0,
fontWeight: FontWeight.bold,
color: Colors.lightGreenAccent),
)
);
}
}
class TimeMessages {
static Future timer(MessageState state, Function callback) async {
//while (true) {
await Future.delayed(Duration(seconds: 4), () {
state.setMessage = DateTime.now().toIso8601String();
print("---- TimeMessages initializer");
Session session = Session();
session.fetchSessionAndNavigate(callback);
});
//}
}
}

View File

@ -1,8 +1,25 @@
import 'package:aitrainer_app/localization/app_language.dart';
import 'package:aitrainer_app/localization/app_localization.dart';
import 'package:aitrainer_app/model/auth.dart';
import 'package:flutter/material.dart';
class NavDrawer extends StatelessWidget {
class NavDrawer extends StatefulWidget {
@override
_NawDrawerWidget createState() => _NawDrawerWidget();
}
class _NawDrawerWidget extends State<NavDrawer> {
final Auth auth = Auth();
final AppLanguage appLanguage = AppLanguage();
Locale _locale;
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return Drawer(
@ -11,49 +28,64 @@ class NavDrawer extends StatelessWidget {
children: <Widget>[
DrawerHeader(
child: Text(
'Customers And Exercises',
AppLocalizations.of(context).translate('Customers And Exercises'),
style: TextStyle(color: Colors.blue, fontSize: 25),
),
),
ListTile(
leading: Icon(Icons.home),
title: Text('Home'),
title: Text( AppLocalizations.of(context).translate('Home')),
onTap: () => Navigator.of(context).pushNamed('home'),
),
ListTile(
leading: Icon(Icons.people),
title: Text('Customers'),
//onTap: () => navigateToPage(context, 'customersPage'),
title: Text( AppLocalizations.of(context).translate('Customers')),
onTap: () => Navigator.of(context).pushNamed('customersPage'),
),
ListTile(
leading: Icon(Icons.directions_run),
title: Text('Exercises'),
onTap: () => Navigator.of(context).pushNamed('exerciseTypeListPage'),
title: Text(AppLocalizations.of(context).translate('Exercises')),
onTap: () =>
Navigator.of(context).pushNamed('exerciseTypeListPage'),
),
ListTile(
leading: Icon(Icons.arrow_upward),
title: Text("TRAINING!"),
title: Text(AppLocalizations.of(context).translate("TRAINING!")),
onTap: () => Navigator.of(context).pushNamed('exerciseNewPage'),
),
ListTile(
leading: Icon(Icons.perm_identity),
title: Text('Login'),
title: Text(AppLocalizations.of(context).translate('Login')),
onTap: () => Navigator.of(context).pushNamed('login'),
),
ListTile(
leading: Icon(Icons.cancel),
title: Text("Logout"),
onTap: () => {
auth.logout(),
Navigator.of(context).pushNamed('home'),
}
leading: Icon(Icons.cancel),
title: Text(AppLocalizations.of(context).translate('Logout')),
onTap: () =>
{
auth.logout(),
Navigator.of(context).pushNamed('home'),
}
),
ListTile(
leading: Icon(Icons.hearing),
title: Text(AppLocalizations.of(context).translate('Change Language')),
onTap: () => _tapped(),
),
],
),
);
}
void _tapped() => {
/* _locale = Locale("hu"),
appLanguage.changeLanguage(_locale),
AppLocalizations.of(context).setLocale(_locale),
AppLocalizations.of(context).load() */
};
}

View File

@ -56,8 +56,44 @@ flutter:
# To add assets to your application, add an assets section, like this:
assets:
- asset/WT01_loading_layers.png
# - images/a_dot_ham.jpeg
- asset/image/WT_menu_welcome.png
- asset/image/WT_menu_backround.png
- asset/image/WT_menu.png
- asset/image/WT_login.png
- asset/image/WT_OK.png
- asset/image/dots.gif
- asset/image/WT_long_logo.png
- asset/image/WT_light_background.png
- asset/image/WT_menu_dark.png
- asset/image/WT_gain_muscle.png
- asset/image/WT_weight_loss.png
- asset/image/WT_welcome.png
- asset/menu/1.cardio.png
- asset/menu/1.1.aerob.png
- asset/menu/1.2.anaerob.png
- asset/menu/1.1.1.cooper.png
- asset/menu/1.2.1.300m.png
- asset/menu/1.2.2.400m.png
- asset/menu/2.strength.png
- asset/menu/2.1.endurance.png
- asset/menu/2.1.1.pull-ups.png
- asset/menu/2.1.2.pushup.png
- asset/menu/2.1.3.sit-ups.png
- asset/menu/2.1.4.squats.png
- asset/menu/2.1.5.timedpushup.png
- asset/menu/2.1.6.core.png
- asset/menu/2.2.1.1RM.png
- asset/menu/2.2.1.1.chestpress.png
- asset/menu/2.2.1.2.pullups.png
- asset/menu/2.2.1.3.biceps.png
- asset/menu/2.2.1.4.triceps.png
- asset/menu/2.2.1.5.shoulders.png
- asset/menu/3.bcs1.png
- asset/menu/3.1.BMI.png
- asset/menu/3.2.BMR.png
- asset/menu/3.3.sizes.png
- i18n/en.json
- i18n/hu.json
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware.