From 8295d36acee2395b554ff4790eb36a8baed00beb Mon Sep 17 00:00:00 2001 From: rem Date: Tue, 28 Nov 2023 16:19:01 +0100 Subject: [PATCH 01/20] :heavy_plus_sign: add objectbox dependency for local db --- pubspec.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/pubspec.yaml b/pubspec.yaml index 25c6942..58e0dcd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -57,6 +57,7 @@ dependencies: crypto: ^3.0.3 responsive_builder: ^0.7.0 universal_html: ^2.2.4 + objectbox: ^2.3.1 dev_dependencies: flutter_test: From e70129c6bac596cf65b9936fa2d988c29d0b7354 Mon Sep 17 00:00:00 2001 From: rem Date: Wed, 29 Nov 2023 14:46:08 +0100 Subject: [PATCH 02/20] just to merge master into me --- .gitignore | 4 ++++ lib/main.dart | 8 +++++++- lib/modele/local_db/model.dart | 23 +++++++++++++++++++++++ lib/modele/local_db/objectbox.dart | 25 +++++++++++++++++++++++++ pubspec.yaml | 4 ++++ 5 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 lib/modele/local_db/model.dart create mode 100644 lib/modele/local_db/objectbox.dart diff --git a/.gitignore b/.gitignore index db7fc69..08b1475 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,10 @@ # Firebase .firebase/ +# ObjectBox +objectbox-model.json +objectbox.g.dart + # IntelliJ related *.iml *.ipr diff --git a/lib/main.dart b/lib/main.dart index 9452bdc..7a6a677 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,12 +1,18 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:smartfit_app_mobile/modele/local_db/objectbox.dart'; import 'package:smartfit_app_mobile/modele/user.dart'; import 'package:smartfit_app_mobile/common/colo_extension.dart'; import 'package:smartfit_app_mobile/view/login/signup_view.dart'; -void main() { +late ObjectBox localDB; + +Future main() async { runApp(ChangeNotifierProvider( create: (context) => User(), child: const MyApp())); + + localDB = await ObjectBox.create(); + localDB.init(); } class MyApp extends StatelessWidget { diff --git a/lib/modele/local_db/model.dart b/lib/modele/local_db/model.dart new file mode 100644 index 0000000..d5b4d8e --- /dev/null +++ b/lib/modele/local_db/model.dart @@ -0,0 +1,23 @@ +import 'package:objectbox/objectbox.dart'; + +@Entity() +class User { + int id = 0; + String username; + String email; + String token; + + User(this.id, this.username, this.email, this.token); +} + +@Entity() +class Activity { + int id; + @Index() + String uuid; + String filename; + String category; + DateTime date; + + Activity(this.id, this.uuid, this.filename, this.category, this.date); +} diff --git a/lib/modele/local_db/objectbox.dart b/lib/modele/local_db/objectbox.dart new file mode 100644 index 0000000..950a4e0 --- /dev/null +++ b/lib/modele/local_db/objectbox.dart @@ -0,0 +1,25 @@ +import 'package:smartfit_app_mobile/objectbox.g.dart'; +import 'package:path/path.dart' as p; +import 'package:path_provider/path_provider.dart'; +import 'package:smartfit_app_mobile/modele/local_db/model.dart'; + +class ObjectBox { + late final Store store; + late final Box userBox; + late final Box activityBox; + + ObjectBox._create(this.store); + + static Future create() async { + final docsDir = await getApplicationDocumentsDirectory(); + // Future openStore() {...} is defined in the generated objectbox.g.dart + final store = + await openStore(directory: p.join(docsDir.path, "obx-example")); + return ObjectBox._create(store); + } + + init() { + userBox = store.box(); + activityBox = store.box(); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 58e0dcd..c1a5239 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -58,6 +58,8 @@ dependencies: responsive_builder: ^0.7.0 universal_html: ^2.2.4 objectbox: ^2.3.1 + objectbox_flutter_libs: any + path: ^1.8.3 dev_dependencies: flutter_test: @@ -69,6 +71,8 @@ dev_dependencies: # package. See that file for information about deactivating specific lint # rules and activating additional ones. flutter_lints: ^2.0.0 + build_runner: ^2.4.7 + objectbox_generator: any # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec From 49bc2bdd16af8edfb6a4ed6099d15bddef1055cf Mon Sep 17 00:00:00 2001 From: rem Date: Wed, 6 Dec 2023 13:33:47 +0100 Subject: [PATCH 03/20] :boom: local api in progress + lots of things --- .../container/list/list_activity.dart | 9 +- lib/main.dart | 24 ++- lib/modele/activity.dart | 4 + lib/modele/activity_saver.dart | 32 ++++ lib/modele/api/api_wrapper.dart | 142 +++++++++++++++++- lib/modele/api/i_data_strategy.dart | 17 +-- lib/modele/api/request_api.dart | 13 +- lib/modele/helper.dart | 10 ++ lib/modele/local_db/model.dart | 8 +- lib/modele/local_db/objectbox.dart | 94 +++++++++++- lib/modele/local_db/request_local.dart | 83 ++++++++++ .../list_activity/list_activity_utile.dart | 65 +++++--- .../utile/profile_view/profile_utile.dart | 10 -- .../activity/mobile/mobile_list_activity.dart | 10 +- lib/view/activity/web/web_list_activity.dart | 8 +- .../login/mobile/android_signup_view.dart | 53 ------- .../profile_view_allplatforme.dart | 5 +- .../profile/mobile/mobile_change_email.dart | 4 +- .../mobile/mobile_change_password.dart | 2 +- .../mobile/mobile_change_username.dart | 4 +- lib/view/profile/web/web_change_email.dart | 4 +- lib/view/profile/web/web_change_password.dart | 2 +- lib/view/profile/web/web_change_username.dart | 4 +- 23 files changed, 471 insertions(+), 136 deletions(-) create mode 100644 lib/modele/activity_saver.dart create mode 100644 lib/modele/helper.dart create mode 100644 lib/modele/local_db/request_local.dart delete mode 100644 lib/modele/utile/profile_view/profile_utile.dart diff --git a/lib/common_widget/container/list/list_activity.dart b/lib/common_widget/container/list/list_activity.dart index f04d84b..9ac84f8 100644 --- a/lib/common_widget/container/list/list_activity.dart +++ b/lib/common_widget/container/list/list_activity.dart @@ -1,7 +1,9 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:smartfit_app_mobile/common_widget/container/workout_row.dart'; +import 'package:smartfit_app_mobile/modele/api/api_wrapper.dart'; import 'package:smartfit_app_mobile/modele/user.dart'; +import 'package:smartfit_app_mobile/modele/utile/info_message.dart'; import 'package:smartfit_app_mobile/modele/utile/list_activity/list_activity_utile.dart'; import 'package:tuple/tuple.dart'; @@ -13,6 +15,8 @@ class ListActivity extends StatefulWidget { } class _ListActivity extends State { + final ApiWrapper api = ApiWrapper(); + final InfoMessage infoManager = InfoMessage(); final ListActivityUtile _utile = ListActivityUtile(); @override @@ -34,9 +38,10 @@ class _ListActivity extends State { child: WorkoutRow( wObj: activityMap, onDelete: () async { - if (await _utile.deleteFileOnBDD( + if (await api.deleteFile( Provider.of(context, listen: false).token, - activityObj.fileUuid)) { + activityObj.fileUuid, + infoManager)) { if (!Provider.of(context, listen: false) .managerSelectedActivity .fileNotSelected(activityObj.fileUuid)) { diff --git a/lib/main.dart b/lib/main.dart index 20564cd..233c2bb 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,6 @@ +import 'dart:io'; import 'package:flutter/material.dart'; +import 'package:smartfit_app_mobile/modele/local_db/model.dart' as db; import 'package:provider/provider.dart'; import 'package:smartfit_app_mobile/modele/local_db/objectbox.dart'; import 'package:smartfit_app_mobile/modele/user.dart'; @@ -12,7 +14,7 @@ Future main() async { // ObjectBox WidgetsFlutterBinding.ensureInitialized(); localDB = await ObjectBox.create(); - localDB.init(); + await localDB.init(); runApp(ChangeNotifierProvider( create: (context) => User(), child: const MyApp())); @@ -24,7 +26,24 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { Widget viewToDisplay = const SignUpView(); - if (localDB.hasUser()) viewToDisplay = const MainTabView(); + + // Skip sign-up + fill provider if user already connected + if (localDB.hasUser()) { + final db.User user = localDB.userBox.get(1); + final userActivities = localDB.loadActivities(); + + context.watch().username = user.username; + context.watch().email = user.email; + context.watch().token = user.token; + context.watch().listActivity = userActivities; + + stdout.write("===== USER =====\n"); + stdout.write("Username: ${user.username}\n"); + stdout.write("Username: ${user.email}\n"); + stdout.write("Username: ${user.token}\n"); + + viewToDisplay = const MainTabView(); + } return MaterialApp( title: 'SmartFit', @@ -48,7 +67,6 @@ class MyApp extends StatelessWidget { primaryColor: TColor.primaryColor1, fontFamily: "Poppins"), home: viewToDisplay, - //home: const ProfileView(), ); } } diff --git a/lib/modele/activity.dart b/lib/modele/activity.dart index 2252632..525f5ae 100644 --- a/lib/modele/activity.dart +++ b/lib/modele/activity.dart @@ -1,3 +1,5 @@ +import 'package:flutter/foundation.dart'; + class ActivityOfUser { // A afficher late String _categorie; @@ -12,6 +14,8 @@ class ActivityOfUser { String get fileUuid => _fileUuid; String get nameFile => _nameFile; + String get categorie => _categorie; + String get date => _date; Map get enteteCSV => _enteteCSV; // -- Getter/Setter -- Ancien // diff --git a/lib/modele/activity_saver.dart b/lib/modele/activity_saver.dart new file mode 100644 index 0000000..6f3ab68 --- /dev/null +++ b/lib/modele/activity_saver.dart @@ -0,0 +1,32 @@ +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:path_provider/path_provider.dart'; +import 'package:path/path.dart' as p; + +import 'package:smartfit_app_mobile/modele/helper.dart'; + +class ActivitySaver { + String saveDirectory = "activities"; + late final Directory applicationDocumentsDir; + + ActivitySaver._create(this.applicationDocumentsDir); + + static Future create() async { + final appDir = await getApplicationDocumentsDirectory(); + return ActivitySaver._create(appDir); + } + + Future saveActivity(Uint8List activityFile, String filename) async { + final file = await File( + p.join(applicationDocumentsDir.path, saveDirectory, filename)) + .create(recursive: true); // To create dir if not exists + file.writeAsBytesSync(activityFile); + } + + File getActivity(String filename) { + final file = + File(p.join(applicationDocumentsDir.path, saveDirectory, filename)); + return file; + } +} diff --git a/lib/modele/api/api_wrapper.dart b/lib/modele/api/api_wrapper.dart index 67174a1..bc6c49e 100644 --- a/lib/modele/api/api_wrapper.dart +++ b/lib/modele/api/api_wrapper.dart @@ -1,22 +1,91 @@ +import 'dart:typed_data'; + import 'package:smartfit_app_mobile/modele/api/i_data_strategy.dart'; import 'package:smartfit_app_mobile/modele/api/request_api.dart'; +import 'package:smartfit_app_mobile/modele/local_db/request_local.dart'; import 'package:smartfit_app_mobile/modele/utile/info_message.dart'; import 'package:email_validator/email_validator.dart'; import 'package:tuple/tuple.dart'; import 'dart:convert'; import 'package:crypto/crypto.dart'; +import 'dart:io'; class ApiWrapper { - IDataStrategy api = RequestApi(); + late IDataStrategy api; + String noConnectionMessage = + "It seems like you are lost far away in the universe, no connection found :)"; + + // HELPERS + Future isOnline() async { + try { + final result = await InternetAddress.lookup('example.com') + .timeout(const Duration(seconds: 2)); + if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) { + return true; + } + } on SocketException catch (_) { + return false; + } + return true; + } + + Future init() async { + if (await isOnline()) { + stdout.write("(API) "); + api = RequestApi(); + } else { + stdout.write("(LOCAL) "); + api = RequestLocal(); + } + } + + bool handleOffline(InfoMessage infoManager) { + if (api is RequestLocal) { + infoManager.displayMessage(noConnectionMessage, true); + return true; + } + return false; + } + + // BOTH (ONLINE + OFFLINE) + Future getUserInfo(String token) async { + await init(); + Tuple2 res = await api.getInfoUser(token); + + stdout.write("getUserInfo: ${res.item1}\n"); + return res; + } + + Future getFile(String token, String fileUuid) async { + await init(); + Tuple2 res = await api.getFile(token, fileUuid); + + stdout.write("getFile: ${res.item1}\n"); + return res; + } + + Future getFiles(String token) async { + await init(); + Tuple2 res = await api.getFiles(token); + + stdout.write("getFiles: ${res.item1}\n"); + return res; + } - Future modifyUserInfo(String infoToModify, String value, String token, + // ONLINE + Future updateUserInfo(String infoToModify, String value, String token, InfoMessage infoManager) async { + await init(); + if (handleOffline(infoManager)) return false; + if (infoToModify == 'email' && EmailValidator.validate(value) || infoToModify == 'password' || infoToModify == 'username') { Tuple2 res = await api.modifAttribut(token, infoToModify, value); - if (res.item1 == true) { + + stdout.write("updateUserInfo: ${res.item1}\n"); + if (res.item1) { infoManager.displayMessage( "${infoToModify.capitalize()} modified succesfully !", false); return true; @@ -34,17 +103,80 @@ class ApiWrapper { Future> login( String password, String email, InfoMessage infoManager) async { + await init(); + if (handleOffline(infoManager)) return const Tuple2(false, "offline"); + String hash = sha256.convert(utf8.encode(password)).toString(); Tuple2 res = await api.connexion(email, hash); + stdout.write("login: ${res.item1}"); if (res.item1) { - return Tuple2(true, res.item2); // return token + return Tuple2(true, res.item2); } else { infoManager.displayMessage( "Authentification failed! Enter your actual password carefully.", true); return const Tuple2(false, "An error occured during connexion!"); - } // need to be better + } + } + + Future> deleteUser( + String token, InfoMessage infoManager) async { + await init(); + if (handleOffline(infoManager)) return const Tuple2(false, "offline"); + + Tuple2 res = await api.deleteUser(token); + + stdout.write("deleteUser: ${res.item1}"); + return res; + } + + Future> createUser(String email, String hash, + String username, InfoMessage infoManager) async { + await init(); + if (handleOffline(infoManager)) return const Tuple2(false, "offline"); + + Tuple2 res = await api.postUser(email, hash, username); + + stdout.write("createUser: ${res.item1}"); + return res; + } + + Future> uploadFile( + String token, File file, InfoMessage infoManager) async { + await init(); + if (handleOffline(infoManager)) return const Tuple2(false, "offline"); + + Tuple2 res = await api.uploadFile(token, file); + stdout.write("uploadFile: ${res.item1}"); + return res; + } + + Future> uploadFileByte( + String token, + Uint8List contentFile, + String filename, + String category, + String date, + InfoMessage infoManager) async { + await init(); + if (handleOffline(infoManager)) return const Tuple2(false, "offline"); + + Tuple2 res = + await api.uploadFileByte(token, contentFile, filename, category, date); + stdout.write("uploadFileByte: ${res.item1}"); + return res; + } + + Future deleteFile( + String token, String fileUuid, InfoMessage infoManager) async { + await init(); + if (handleOffline(infoManager)) return false; + + bool res = await api.deleteFile(token, fileUuid); + + stdout.write("deleteFile: ${res}"); + return res; } } diff --git a/lib/modele/api/i_data_strategy.dart b/lib/modele/api/i_data_strategy.dart index 8e620a6..7435b6a 100644 --- a/lib/modele/api/i_data_strategy.dart +++ b/lib/modele/api/i_data_strategy.dart @@ -14,29 +14,26 @@ abstract class IDataStrategy { // Get Token validate Future> connexion(String email, String hash); - // Get all files for user + // Get all files for user (LOCAL OK) Future getFiles(String token); // Upload file on BDD Future> uploadFile(String token, File file); + + // Upload file as bytes Future> uploadFileByte(String token, Uint8List contentFile, String nameFile, String category, String date); - // Get one file by id + // Get one file by id (LOCAL OK) Future getFile(String token, String fileUuid); // Delete one file on BDD - Future> deleteFile(String token, String fileUuid); + Future deleteFile(String token, String fileUuid); + // Get info on user (LOCAL OK) Future getInfoUser(String token); - /* -> Modification attribut - // Update email - Future updateEmail(String token, String email); - - // Update username - Future updateUsername(String token, String username); - */ + // Update email, password, username Future> modifAttribut( String token, String nameAttribut, String newValue); } diff --git a/lib/modele/api/request_api.dart b/lib/modele/api/request_api.dart index b10b3cc..dd64366 100644 --- a/lib/modele/api/request_api.dart +++ b/lib/modele/api/request_api.dart @@ -36,21 +36,21 @@ class RequestApi extends IDataStrategy { } @override - Future> deleteFile(String token, String fileUuid) async { + Future deleteFile(String token, String fileUuid) async { final response = await http.delete( Uri.parse('$urlApi/user/files/$fileUuid'), headers: {'Authorization': token}); if (response.statusCode == 200) { - return const Tuple2(true, "Successful"); + return true; } if (response.statusCode == 401) { - return const Tuple2(false, "401 - UNAUTHORIZED"); + return false; } if (response.statusCode == 404) { - return const Tuple2(false, "404 - NOT FOUND"); + return false; } - return const Tuple2(false, "Fail"); + return false; } @override @@ -227,7 +227,6 @@ class RequestApi extends IDataStrategy { Future getInfoUser(String token) async { final response = await http.get(Uri.parse('$urlApi/user/info'), headers: {'Authorization': token}); - if (response.statusCode == 200) { Map json = jsonDecode(response.body); return Tuple2(true, json); @@ -238,6 +237,6 @@ class RequestApi extends IDataStrategy { if (response.statusCode == 401) { return const Tuple2(false, "401 - UNAUTHORIZED"); } - return const Tuple2(false, "Fail "); + return const Tuple2(false, "Fail"); } } diff --git a/lib/modele/helper.dart b/lib/modele/helper.dart new file mode 100644 index 0000000..b03f24a --- /dev/null +++ b/lib/modele/helper.dart @@ -0,0 +1,10 @@ +import 'package:flutter/foundation.dart'; + +class Helper { + static bool isPlatformWeb() { + if (kIsWeb) { + return true; + } + return false; + } +} diff --git a/lib/modele/local_db/model.dart b/lib/modele/local_db/model.dart index d5b4d8e..0598328 100644 --- a/lib/modele/local_db/model.dart +++ b/lib/modele/local_db/model.dart @@ -2,6 +2,7 @@ import 'package:objectbox/objectbox.dart'; @Entity() class User { + @Id() int id = 0; String username; String email; @@ -13,11 +14,14 @@ class User { @Entity() class Activity { int id; - @Index() + + @Unique() String uuid; String filename; String category; DateTime date; + String info; - Activity(this.id, this.uuid, this.filename, this.category, this.date); + Activity( + this.id, this.uuid, this.filename, this.category, this.date, this.info); } diff --git a/lib/modele/local_db/objectbox.dart b/lib/modele/local_db/objectbox.dart index 6df6818..c600cb7 100644 --- a/lib/modele/local_db/objectbox.dart +++ b/lib/modele/local_db/objectbox.dart @@ -1,3 +1,9 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:csv/csv.dart'; +import 'package:smartfit_app_mobile/modele/activity.dart'; import 'package:smartfit_app_mobile/objectbox.g.dart'; import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; @@ -7,23 +13,103 @@ class ObjectBox { late final Store store; late final Box userBox; late final Box activityBox; + late final String activitiesSavePath = "activities"; + late final Directory applicationDocumentDir; ObjectBox._create(this.store); static Future create() async { final docsDir = await getApplicationDocumentsDirectory(); - // Future openStore() {...} is defined in the generated objectbox.g.dart - final store = - await openStore(directory: p.join(docsDir.path, "obx-example")); + final store = await openStore(directory: p.join(docsDir.path, "database")); return ObjectBox._create(store); } - init() { + init() async { + applicationDocumentDir = await getApplicationDocumentsDirectory(); userBox = store.box(); activityBox = store.box(); } + // ===== USER ===== bool hasUser() { return !userBox.isEmpty(); } + + void setUserMail(String email) { + User user = userBox.get(1); + user.email = email; + userBox.put(user); + } + + void setUserName(String username) { + User user = userBox.get(1); + user.username = username; + userBox.put(user); + } + + void setUserToken(String token) { + User user = userBox.get(1); + user.token = token; + userBox.put(user); + } + + void deleteUser() { + userBox.removeAll(); + } + + void addUser(String username, String email, String token) { + userBox.put(User(1, username, email, token)); + } + + // ===== Activity ===== + void addActivity(Activity newActivity) { + try { + activityBox.put(newActivity); + } on ObjectBoxException { + print("Activity already exists"); + } catch (e) { + print("Unknown exception"); + } + } + + void removeActivity(int uuid) { + activityBox.remove(uuid); + } + + List getAllActivities() { + // TODO: Transform db.Activity to ActivityOfUser + throw Exception("Not implemented yet"); + } + + void removeAllActivities() { + activityBox.removeAll(); + } + + // ===== FIT Files ===== + Future saveActivityFile(List> activityFile) async { + String csv = const ListToCsvConverter().convert(activityFile); + Uint8List csvAsBytes = Uint8List.fromList(utf8.encode(csv)); + final file = + await File(p.join(applicationDocumentDir.path, activitiesSavePath)) + .create(); + file.writeAsBytesSync(csvAsBytes); + } + + File getActivityFile(String filename) { + final file = + File(p.join(applicationDocumentDir.path, activitiesSavePath, filename)); + return file; + } + + List loadActivities() { + List activityDBList = activityBox.getAll(); + List userActivityList = List.empty(growable: true); + + for (Activity act in activityDBList) { + userActivityList.add(ActivityOfUser( + act.date.toString(), act.category, act.uuid, act.filename)); + } + + return userActivityList; + } } diff --git a/lib/modele/local_db/request_local.dart b/lib/modele/local_db/request_local.dart new file mode 100644 index 0000000..755eada --- /dev/null +++ b/lib/modele/local_db/request_local.dart @@ -0,0 +1,83 @@ +import 'dart:convert'; +import 'package:smartfit_app_mobile/modele/api/i_data_strategy.dart'; +import 'package:smartfit_app_mobile/modele/local_db/model.dart'; +import 'package:tuple/tuple.dart'; +import 'dart:io'; +import 'dart:typed_data'; +import 'package:smartfit_app_mobile/main.dart'; + +class RequestLocal implements IDataStrategy { + @override + Future getInfoUser(String token) async { + final User user = localDB.userBox.get(1); + Map json = {"email": user.email, "username": user.username}; + return Tuple2(true, jsonEncode(json)); + } + + // need to save file on request_api.upload() beforehand. + @override + Future getFile(String token, String fileUuid) async { + return const Tuple2(true, "to implement"); + } + + @override + Future getFiles(String token) async { + final List activities = localDB.activityBox.getAll(); + List> jsonList = List.empty(growable: true); + + for (Activity act in activities) { + Map json = { + "uuid": act.uuid, + "filename": act.filename, + "category": act.category, + "creation_date": act.date, + "info": act.info + }; + jsonList.add(json); + } + + return Tuple2(true, jsonEncode(activities)); + } + + @override + Future> modifAttribut( + String token, String nameAttribut, String newValue) async { + return const Tuple2(false, "not implemented"); + } + + @override + Future> postUser( + String email, String hash, String username) async { + return const Tuple2(false, "not implemented"); + } + + @override + Future> deleteUser(String token) async { + return const Tuple2(false, "not implemented"); + } + + @override + Future> connexion(String email, String hash) async { + return const Tuple2(false, "not implemented"); + } + + @override + Future> uploadFile(String token, File file) async { + return const Tuple2(false, "not implemented"); + } + + @override + Future> uploadFileByte( + String token, + Uint8List contentFile, + String nameFile, + String category, + String date) async { + return const Tuple2(false, "not implemented"); + } + + @override + Future deleteFile(String token, String fileUuid) async { + throw Exception("Not Implemented"); + } +} diff --git a/lib/modele/utile/list_activity/list_activity_utile.dart b/lib/modele/utile/list_activity/list_activity_utile.dart index 025b580..6ab88e4 100644 --- a/lib/modele/utile/list_activity/list_activity_utile.dart +++ b/lib/modele/utile/list_activity/list_activity_utile.dart @@ -1,3 +1,8 @@ +import 'package:smartfit_app_mobile/main.dart'; +import 'package:smartfit_app_mobile/modele/api/api_wrapper.dart'; +import 'package:smartfit_app_mobile/modele/activity_saver.dart'; +import 'package:smartfit_app_mobile/modele/helper.dart'; +import 'package:smartfit_app_mobile/modele/local_db/model.dart' as db; import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; @@ -5,19 +10,18 @@ import 'package:csv/csv.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:smartfit_app_mobile/modele/activity.dart'; -import 'package:smartfit_app_mobile/modele/api/i_data_strategy.dart'; -import 'package:smartfit_app_mobile/modele/api/request_api.dart'; import 'package:smartfit_app_mobile/modele/manager_file.dart'; import 'package:smartfit_app_mobile/modele/user.dart'; +import 'package:smartfit_app_mobile/modele/utile/info_message.dart'; import 'package:tuple/tuple.dart'; class ListActivityUtile { - final IDataStrategy _strategy = RequestApi(); + final ApiWrapper api = ApiWrapper(); final ManagerFile _managerFile = ManagerFile(); Future> getContentActivity( BuildContext context, ActivityOfUser activityOfUser) async { - Tuple2 result = await _strategy.getFile( + Tuple2 result = await api.getFile( Provider.of(context, listen: false).token, activityOfUser.fileUuid); if (result.item1 == false) { @@ -27,6 +31,9 @@ class ListActivityUtile { activityOfUser.contentActivity = List.from(_managerFile.convertByteIntoCSV(result.item2)); + // TODO: Not sure this line as an utility + // localDB.saveActivityFile(activityOfUser.contentActivity); + Provider.of(context, listen: false) .managerSelectedActivity .addSelectedActivity(activityOfUser); @@ -36,13 +43,13 @@ class ListActivityUtile { Future> getFiles( String token, BuildContext context) async { bool notZero = false; - Tuple2 result = await _strategy - .getFiles(Provider.of(context, listen: false).token); + Tuple2 result = + await api.getFiles(Provider.of(context, listen: false).token); if (result.item1 == false) { return Tuple2(result.item1, result.item2); } - for (Map element in result.item2) { + for (var element in result.item2) { if (!notZero) { Provider.of(context, listen: false).listActivity.clear(); notZero = true; @@ -52,6 +59,16 @@ class ListActivityUtile { element["category"].toString(), element["uuid"].toString(), element["filename"].toString())); + + // Save to local db + localDB.addActivity(db.Activity( + 0, + element["uuid"], + element["filename"], + element["category"], + DateTime.parse(element["creation_date"]), + element["info"] + .toString())); // Do not remove toString(), it do not work w/o it, idk why } /* if (notZero) { @@ -60,41 +77,39 @@ class ListActivityUtile { return const Tuple2(true, "Yeah"); } - Future> addFile( - Uint8List bytes, String filename, String token) async { + Future> addFile(Uint8List bytes, String filename, + String token, InfoMessage infoManager) async { // -- Transormer le fit en CSV List> csv = _managerFile.convertBytesFitFileIntoCSVList(bytes); String csvString = const ListToCsvConverter().convert(csv); Uint8List byteCSV = Uint8List.fromList(utf8.encode(csvString)); - // --- Save Local - // --- Api + + // Save on local storage if plateform not browser + if (!Helper.isPlatformWeb()) { + ActivitySaver actSaver = await ActivitySaver.create(); + actSaver.saveActivity(byteCSV, filename); + } + String categoryActivity = filename.split("_").first.toLowerCase(); String dateActivity = filename.split("_")[1].split("T").first; - Tuple2 result = await _strategy.uploadFileByte( - token, byteCSV, filename, categoryActivity, dateActivity); + Tuple2 result = await api.uploadFileByte( + token, byteCSV, filename, categoryActivity, dateActivity, infoManager); if (result.item1 == false) { return Tuple2(false, result.item2); } return const Tuple2(true, "Yeah"); } - Future deleteFileOnBDD(String token, String fileUuid) async { - Tuple2 result = await _strategy.deleteFile(token, fileUuid); - if (!result.item1) { - return false; - } - return true; - } - - void addFileMobile( - String path, String token, String filename, BuildContext context) async { - Tuple2 resultAdd = - await addFile(await File(path).readAsBytes(), filename, token); + void addFileMobile(String path, String token, String filename, + BuildContext context, InfoMessage infoManager) async { + Tuple2 resultAdd = await addFile( + await File(path).readAsBytes(), filename, token, infoManager); if (!resultAdd.item1) { //print("Message error"); return; } + // TODO: What is that ? Tuple2 resultGet = await getFiles(token, context); if (!resultGet.item1) { //print("Message error"); diff --git a/lib/modele/utile/profile_view/profile_utile.dart b/lib/modele/utile/profile_view/profile_utile.dart deleted file mode 100644 index e1ee3fa..0000000 --- a/lib/modele/utile/profile_view/profile_utile.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'package:smartfit_app_mobile/modele/api/i_data_strategy.dart'; -import 'package:smartfit_app_mobile/modele/api/request_api.dart'; - -class ProfileUtil { - final IDataStrategy _dataStrategy = RequestApi(); - - void modifyDataUser(String token, String attribut, String newUsername) { - _dataStrategy.modifAttribut(token, attribut, newUsername); - } -} diff --git a/lib/view/activity/mobile/mobile_list_activity.dart b/lib/view/activity/mobile/mobile_list_activity.dart index 91edcb0..d1e5e6b 100644 --- a/lib/view/activity/mobile/mobile_list_activity.dart +++ b/lib/view/activity/mobile/mobile_list_activity.dart @@ -4,6 +4,7 @@ import 'package:provider/provider.dart'; import 'package:smartfit_app_mobile/common/colo_extension.dart'; import 'package:smartfit_app_mobile/common_widget/container/list/list_activity.dart'; import 'package:smartfit_app_mobile/modele/user.dart'; +import 'package:smartfit_app_mobile/modele/utile/info_message.dart'; import 'package:smartfit_app_mobile/modele/utile/list_activity/list_activity_utile.dart'; class MobileListActivity extends StatefulWidget { @@ -16,6 +17,7 @@ class MobileListActivity extends StatefulWidget { class _MobileListActivity extends State { FilePickerResult? result; final ListActivityUtile _utile = ListActivityUtile(); + final InfoMessage infoManager = InfoMessage(); @override Widget build(BuildContext context) { @@ -60,9 +62,9 @@ class _MobileListActivity extends State { result.files.single.path!, Provider.of(context, listen: false).token, result.files.single.name, - context); + context, + infoManager); } else { - print("Picker"); // msg d'erreur // User canceled the picker } @@ -77,6 +79,10 @@ class _MobileListActivity extends State { ) ], ), + Visibility( + visible: infoManager.isVisible, + child: Text(infoManager.message, + style: TextStyle(color: infoManager.messageColor))), Provider.of(context, listen: true).listActivity.isEmpty ? Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/view/activity/web/web_list_activity.dart b/lib/view/activity/web/web_list_activity.dart index 9e7efe4..d072362 100644 --- a/lib/view/activity/web/web_list_activity.dart +++ b/lib/view/activity/web/web_list_activity.dart @@ -1,15 +1,13 @@ import 'dart:typed_data'; import 'package:flutter/material.dart'; +import 'package:smartfit_app_mobile/modele/utile/info_message.dart'; import 'package:smartfit_app_mobile/modele/utile/list_activity/list_activity_utile.dart'; import 'package:smartfit_app_mobile/view/activity/list_activity.dart'; import 'package:tuple/tuple.dart'; import 'package:universal_html/html.dart' as html; - import 'package:file_picker/file_picker.dart'; import 'package:provider/provider.dart'; import 'package:smartfit_app_mobile/common/colo_extension.dart'; -import 'package:smartfit_app_mobile/modele/api/i_data_strategy.dart'; -import 'package:smartfit_app_mobile/modele/api/request_api.dart'; import 'package:smartfit_app_mobile/modele/user.dart'; class WebListActivity extends StatefulWidget { @@ -21,8 +19,8 @@ class WebListActivity extends StatefulWidget { class _WebListActivityState extends State { FilePickerResult? result; - IDataStrategy strategy = RequestApi(); final ListActivityUtile _utile = ListActivityUtile(); + final InfoMessage infoManager = InfoMessage(); void addFileWeb(html.File file, String token) async { final reader = html.FileReader(); @@ -32,7 +30,7 @@ class _WebListActivityState extends State { if (reader.readyState == html.FileReader.DONE) { Uint8List bytes = reader.result as Uint8List; Tuple2 resultAdd = - await _utile.addFile(bytes, file.name, token); + await _utile.addFile(bytes, file.name, token, infoManager); if (!resultAdd.item1) { return; } diff --git a/lib/view/login/mobile/android_signup_view.dart b/lib/view/login/mobile/android_signup_view.dart index a62a9db..7cffe61 100644 --- a/lib/view/login/mobile/android_signup_view.dart +++ b/lib/view/login/mobile/android_signup_view.dart @@ -228,59 +228,6 @@ class _MobileSignUpView extends State { SizedBox( height: media.width * 0.04, ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - GestureDetector( - onTap: () {}, - child: Container( - width: 50, - height: 50, - alignment: Alignment.center, - decoration: BoxDecoration( - color: TColor.white, - border: Border.all( - width: 1, - color: TColor.gray.withOpacity(0.4), - ), - borderRadius: BorderRadius.circular(15), - ), - child: Image.asset( - "assets/img/google.png", - width: 20, - height: 20, - ), - ), - ), - SizedBox( - width: media.width * 0.04, - ), - GestureDetector( - onTap: () {}, - child: Container( - width: 50, - height: 50, - alignment: Alignment.center, - decoration: BoxDecoration( - color: TColor.white, - border: Border.all( - width: 1, - color: TColor.gray.withOpacity(0.4), - ), - borderRadius: BorderRadius.circular(15), - ), - child: Image.asset( - "assets/img/suunto.png", - width: 35, - height: 35, - ), - ), - ) - ], - ), - SizedBox( - height: media.width * 0.04, - ), TextButton( onPressed: () { Navigator.push( diff --git a/lib/view/profile/all_platforme/profile_view_allplatforme.dart b/lib/view/profile/all_platforme/profile_view_allplatforme.dart index 0aab244..6f0df24 100644 --- a/lib/view/profile/all_platforme/profile_view_allplatforme.dart +++ b/lib/view/profile/all_platforme/profile_view_allplatforme.dart @@ -6,14 +6,15 @@ import 'package:smartfit_app_mobile/common_widget/container/profile/profile_ente import 'package:smartfit_app_mobile/common_widget/container/profile/profile_info_user.dart'; import 'package:smartfit_app_mobile/common_widget/container/profile/profile_notification.dart'; import 'package:smartfit_app_mobile/common_widget/container/profile/profile_other.dart'; +import 'package:smartfit_app_mobile/modele/api/api_wrapper.dart'; import 'package:smartfit_app_mobile/modele/user.dart'; class ProfileViewAllPlatforme extends StatefulWidget { - const ProfileViewAllPlatforme(this.positive, this.accountArr, this.otherArr, - {super.key}); final bool positive; final List accountArr; final List otherArr; + const ProfileViewAllPlatforme(this.positive, this.accountArr, this.otherArr, + {super.key}); @override State createState() => _ProfileViewAllPlatforme(); diff --git a/lib/view/profile/mobile/mobile_change_email.dart b/lib/view/profile/mobile/mobile_change_email.dart index b887896..36eba41 100644 --- a/lib/view/profile/mobile/mobile_change_email.dart +++ b/lib/view/profile/mobile/mobile_change_email.dart @@ -1,3 +1,4 @@ +import 'package:smartfit_app_mobile/main.dart'; import 'package:flutter/material.dart'; import 'package:smartfit_app_mobile/modele/api/api_wrapper.dart'; import 'package:smartfit_app_mobile/modele/user.dart'; @@ -110,7 +111,7 @@ class _MobileChangeEmailViewState extends State { RoundButton( title: "Confirmer", onPressed: () async { - bool res = await api.modifyUserInfo( + bool res = await api.updateUserInfo( 'email', controllerTextEmail.text, Provider.of(context, listen: false).token, @@ -118,6 +119,7 @@ class _MobileChangeEmailViewState extends State { if (res) { Provider.of(context, listen: false).email = controllerTextEmail.text; + localDB.setUserMail(controllerTextEmail.text); } setState(() {}); }), diff --git a/lib/view/profile/mobile/mobile_change_password.dart b/lib/view/profile/mobile/mobile_change_password.dart index a170eb2..66a9cfd 100644 --- a/lib/view/profile/mobile/mobile_change_password.dart +++ b/lib/view/profile/mobile/mobile_change_password.dart @@ -111,7 +111,7 @@ class _MobileChangePasswordViewState extends State { if (res.item1) { if (controllerNewPasswd.text == controllerNewPasswd2.text) { - await api.modifyUserInfo( + await api.updateUserInfo( 'password', sha256 .convert(utf8 diff --git a/lib/view/profile/mobile/mobile_change_username.dart b/lib/view/profile/mobile/mobile_change_username.dart index 3aa1367..3bdb747 100644 --- a/lib/view/profile/mobile/mobile_change_username.dart +++ b/lib/view/profile/mobile/mobile_change_username.dart @@ -1,3 +1,4 @@ +import 'package:smartfit_app_mobile/main.dart'; import 'package:provider/provider.dart'; import 'package:flutter/material.dart'; import 'package:smartfit_app_mobile/modele/api/api_wrapper.dart'; @@ -109,7 +110,7 @@ class _MobileChangeUsernameViewState extends State { RoundButton( title: "Confirmer", onPressed: () async { - bool res = await api.modifyUserInfo( + bool res = await api.updateUserInfo( 'username', controllerTextUsername.text, Provider.of(context, listen: false).token, @@ -117,6 +118,7 @@ class _MobileChangeUsernameViewState extends State { if (res) { Provider.of(context, listen: false) .username = controllerTextUsername.text; + localDB.setUserName(controllerTextUsername.text); } setState(() {}); }), diff --git a/lib/view/profile/web/web_change_email.dart b/lib/view/profile/web/web_change_email.dart index 6a7fe3c..2ee2205 100644 --- a/lib/view/profile/web/web_change_email.dart +++ b/lib/view/profile/web/web_change_email.dart @@ -1,3 +1,4 @@ +import 'package:smartfit_app_mobile/main.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:smartfit_app_mobile/modele/api/api_wrapper.dart'; @@ -108,7 +109,7 @@ class _WebChangeEmailViewState extends State { RoundButton( title: "Confirmer", onPressed: () async { - bool res = await apiWrapper.modifyUserInfo( + bool res = await apiWrapper.updateUserInfo( 'email', controllerTextEmail.text, Provider.of(context, listen: false).token, @@ -116,6 +117,7 @@ class _WebChangeEmailViewState extends State { if (res) { Provider.of(context, listen: false).email = controllerTextEmail.text; + localDB.setUserMail(controllerTextEmail.text); } setState(() {}); }), diff --git a/lib/view/profile/web/web_change_password.dart b/lib/view/profile/web/web_change_password.dart index 00ff54e..718468e 100644 --- a/lib/view/profile/web/web_change_password.dart +++ b/lib/view/profile/web/web_change_password.dart @@ -114,7 +114,7 @@ class _WebChangePasswordViewState extends State { if (res.item1) { if (controllerNewPasswd.text == controllerNewPasswd2.text) { - await api.modifyUserInfo( + await api.updateUserInfo( 'password', sha256 .convert(utf8 diff --git a/lib/view/profile/web/web_change_username.dart b/lib/view/profile/web/web_change_username.dart index f00c301..a785873 100644 --- a/lib/view/profile/web/web_change_username.dart +++ b/lib/view/profile/web/web_change_username.dart @@ -1,3 +1,4 @@ +import 'package:smartfit_app_mobile/main.dart'; import 'package:flutter/material.dart'; import 'package:smartfit_app_mobile/modele/user.dart'; import 'package:provider/provider.dart'; @@ -110,7 +111,7 @@ class _WebChangeUsernameViewState extends State { RoundButton( title: "Confirmer", onPressed: () async { - bool res = await api.modifyUserInfo( + bool res = await api.updateUserInfo( 'username', controllerTextUsername.text, Provider.of(context, listen: false).token, @@ -118,6 +119,7 @@ class _WebChangeUsernameViewState extends State { if (res) { Provider.of(context, listen: false) .username = controllerTextUsername.text; + localDB.setUserName(controllerTextUsername.text); } setState(() {}); }), From 73a2903d34a6e5ecf4ab2f2ab3f5a2b066bb1454 Mon Sep 17 00:00:00 2001 From: otbenjello Date: Thu, 7 Dec 2023 16:23:55 +0100 Subject: [PATCH 04/20] correction --- lib/view/home/web/web_homeview.dart | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/view/home/web/web_homeview.dart b/lib/view/home/web/web_homeview.dart index 2498fd0..a44b92d 100644 --- a/lib/view/home/web/web_homeview.dart +++ b/lib/view/home/web/web_homeview.dart @@ -63,11 +63,10 @@ class _WebHomeView extends State { return Scaffold( backgroundColor: TColor.white, body: SingleChildScrollView( - child: SafeArea( - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 50), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 30), child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, children: [ SizedBox( height: media.width * 0.03, @@ -76,9 +75,9 @@ class _WebHomeView extends State { SizedBox( height: media.width * 0.03, ), - Row(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Column(mainAxisAlignment: MainAxisAlignment.center, children: [ Column( - crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, children: [ Text( "Status d'activité", @@ -90,7 +89,8 @@ class _WebHomeView extends State { SizedBox( height: media.width * 0.02, ), - Row(children: [ + Row(mainAxisAlignment: MainAxisAlignment.center, + children: [ BpmByTime(media, data), SizedBox( width: media.width * 0.01, @@ -111,7 +111,7 @@ class _WebHomeView extends State { height: media.width * 0.05, ), Column( - crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, children: [ Text( "Rythme cardique et vitesse", @@ -124,7 +124,7 @@ class _WebHomeView extends State { height: media.width * 0.03, ), Row( - crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, children: [ GraphBpmAndSpeedByTime(media, data), SizedBox( @@ -156,7 +156,7 @@ class _WebHomeView extends State { fontSize: 16, fontWeight: FontWeight.w700), ), - Row(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Row(mainAxisAlignment: MainAxisAlignment.center, children: [ GraphAltitudeByTime(media, data), LigneContainerStats( "${minAltitude.toInt()} m", @@ -172,8 +172,8 @@ class _WebHomeView extends State { ], ), ), - ), ), + ); } } From e750bf8d5cf7c237c5a8d53c30807b763305d39f Mon Sep 17 00:00:00 2001 From: rem Date: Fri, 8 Dec 2023 13:33:59 +0100 Subject: [PATCH 05/20] Update '.drone.yml' --- .drone.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.drone.yml b/.drone.yml index 5208750..31e0c93 100644 --- a/.drone.yml +++ b/.drone.yml @@ -12,6 +12,7 @@ steps: - name: build-apk image: ghcr.io/cirruslabs/flutter:3.13.9 commands: + - flutter pub run build_runner build - flutter build apk - sfm_apk=sfm_$(date +"%Y_%m_%d_%H_%M_%S").apk - cp ./build/app/outputs/flutter-apk/app-release.apk $sfm_apk From 71601e2667b58bbcc61b95e81d5fbb886af2c371 Mon Sep 17 00:00:00 2001 From: rem Date: Fri, 8 Dec 2023 13:38:36 +0100 Subject: [PATCH 06/20] Update '.drone.yml' --- .drone.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index 31e0c93..8698c4e 100644 --- a/.drone.yml +++ b/.drone.yml @@ -12,7 +12,7 @@ steps: - name: build-apk image: ghcr.io/cirruslabs/flutter:3.13.9 commands: - - flutter pub run build_runner build + - dart run build_runner build - flutter build apk - sfm_apk=sfm_$(date +"%Y_%m_%d_%H_%M_%S").apk - cp ./build/app/outputs/flutter-apk/app-release.apk $sfm_apk From 2ab8c9207fbfd02eff207d2cceebbed1ad64d7ec Mon Sep 17 00:00:00 2001 From: rem Date: Fri, 8 Dec 2023 13:55:23 +0100 Subject: [PATCH 07/20] Update '.drone.yml' --- .drone.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.drone.yml b/.drone.yml index 8698c4e..a5327aa 100644 --- a/.drone.yml +++ b/.drone.yml @@ -12,6 +12,7 @@ steps: - name: build-apk image: ghcr.io/cirruslabs/flutter:3.13.9 commands: + - flutter clean - dart run build_runner build - flutter build apk - sfm_apk=sfm_$(date +"%Y_%m_%d_%H_%M_%S").apk From a01a2f328e6e64f04b49fe156266269503d92af0 Mon Sep 17 00:00:00 2001 From: rem Date: Mon, 11 Dec 2023 01:24:06 +0100 Subject: [PATCH 08/20] :ambulance: objectbox devs are losers --- lib/main.dart | 45 +++++---- lib/modele/api/api_wrapper.dart | 12 ++- lib/modele/local_db/db_dummy.dart | 95 +++++++++++++++++++ lib/modele/local_db/db_impl.dart | 31 ++++++ lib/modele/local_db/get_native_db.dart | 7 ++ lib/modele/local_db/get_web_db.dart | 7 ++ lib/modele/local_db/objectbox.dart | 78 ++++++++++----- lib/modele/local_db/request_local.dart | 15 +-- lib/modele/user.dart | 4 + .../list_activity/list_activity_utile.dart | 7 +- lib/view/login/mobile/android_login_view.dart | 6 +- lib/view/login/web/web_login_view.dart | 6 +- .../profile_view_allplatforme.dart | 10 +- .../profile/mobile/mobile_change_email.dart | 4 +- .../mobile/mobile_change_username.dart | 5 +- lib/view/profile/web/web_change_email.dart | 4 +- lib/view/profile/web/web_change_username.dart | 5 +- 17 files changed, 277 insertions(+), 64 deletions(-) create mode 100644 lib/modele/local_db/db_dummy.dart create mode 100644 lib/modele/local_db/db_impl.dart create mode 100644 lib/modele/local_db/get_native_db.dart create mode 100644 lib/modele/local_db/get_web_db.dart diff --git a/lib/main.dart b/lib/main.dart index 5495005..1277346 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,21 +1,26 @@ import 'dart:io'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:smartfit_app_mobile/modele/local_db/model.dart' as db; +import 'package:smartfit_app_mobile/modele/local_db/db_impl.dart'; +import 'package:smartfit_app_mobile/modele/local_db/get_web_db.dart' + if (dart.library.io) 'package:smartfit_app_mobile/modele/local_db/get_native_db.dart'; import 'package:provider/provider.dart'; -import 'package:smartfit_app_mobile/modele/local_db/objectbox.dart'; import 'package:smartfit_app_mobile/modele/user.dart'; import 'package:smartfit_app_mobile/common/colo_extension.dart'; import 'package:smartfit_app_mobile/view/login/signup_view.dart'; import 'package:smartfit_app_mobile/view/main_tab/main_tab_view.dart'; -late ObjectBox localDB; +late DbImpl localDB; Future main() async { - // ObjectBox WidgetsFlutterBinding.ensureInitialized(); - localDB = await ObjectBox.create(); - await localDB.init(); - localDB.configBox.put(db.Config(0, true)); + + if (!kIsWeb) { + DbImpl tmp = getDbImpl(); + localDB = await tmp.create(); + await localDB.init(); + localDB.initConfig(); + } runApp(ChangeNotifierProvider( create: (context) => User(), child: const MyApp())); @@ -29,21 +34,23 @@ class MyApp extends StatelessWidget { Widget viewToDisplay = const SignUpView(); // Skip sign-up + fill provider if user already connected - if (localDB.hasUser()) { - final db.User user = localDB.userBox.get(1); - final userActivities = localDB.loadActivities(); + if (!kIsWeb) { + if (localDB.hasUser()) { + final User user = localDB.getUser(); + final userActivities = localDB.getAllActivities(); - context.watch().username = user.username; - context.watch().email = user.email; - context.watch().token = user.token; - context.watch().listActivity = userActivities; + context.watch().username = user.username; + context.watch().email = user.email; + context.watch().token = user.token; + context.watch().listActivity = userActivities; - stdout.write("===== USER =====\n"); - stdout.write("Username: ${user.username}\n"); - stdout.write("Email: ${user.email}\n"); - stdout.write("Token: ${user.token}\n"); + stdout.write("===== USER =====\n"); + stdout.write("Username: ${user.username}\n"); + stdout.write("Email: ${user.email}\n"); + stdout.write("Token: ${user.token}\n"); - viewToDisplay = const MainTabView(); + viewToDisplay = const MainTabView(); + } } return MaterialApp( diff --git a/lib/modele/api/api_wrapper.dart b/lib/modele/api/api_wrapper.dart index 2070a59..9ea6fd3 100644 --- a/lib/modele/api/api_wrapper.dart +++ b/lib/modele/api/api_wrapper.dart @@ -1,5 +1,6 @@ import 'dart:typed_data'; +import 'package:flutter/foundation.dart'; import 'package:smartfit_app_mobile/modele/activity_info/activity_info.dart'; import 'package:smartfit_app_mobile/modele/api/i_data_strategy.dart'; import 'package:smartfit_app_mobile/modele/api/request_api.dart'; @@ -18,6 +19,7 @@ class ApiWrapper { "It seems like you are lost far away in the universe, no connection found :)"; // HELPERS + // TODO: Change check online for flutterWeb Future isOnline() async { try { final result = await InternetAddress.lookup('example.com') @@ -27,15 +29,23 @@ class ApiWrapper { } } on SocketException catch (_) { return false; + } on UnsupportedError catch (_) { + return true; } return true; } Future init() async { + // TODO: Fait à la pisse en despi (je voulais juste dormir) + if (kIsWeb) { + api = RequestApi(); + return; + } + if (await isOnline()) { stdout.write("(API) "); api = RequestApi(); - } else if (localDB.getSaveLocally()) { + } else if (!kIsWeb && localDB.getSaveLocally()) { stdout.write("(LOCAL) "); api = RequestLocal(); } else { diff --git a/lib/modele/local_db/db_dummy.dart b/lib/modele/local_db/db_dummy.dart new file mode 100644 index 0000000..d214cc2 --- /dev/null +++ b/lib/modele/local_db/db_dummy.dart @@ -0,0 +1,95 @@ +import 'package:smartfit_app_mobile/modele/activity.dart'; +import 'package:smartfit_app_mobile/modele/local_db/db_impl.dart'; +import 'package:smartfit_app_mobile/modele/user.dart'; + +class DbDummy implements DbImpl { + DbDummy._create(); + DbDummy(); + @override + Future create() async { + return DbDummy._create(); + } + + @override + Future init() { + throw Exception(); + } + + // ==== USER ==== + @override + void addUser(String username, String email, String token) { + throw Exception(); + } + + @override + User getUser() { + throw Exception(); + } + + @override + bool hasUser() { + throw Exception(); + } + + @override + void deleteUser() { + throw Exception(); + } + + @override + void setUserMail(String email) { + throw Exception(); + } + + @override + void setUserName(String username) { + throw Exception(); + } + + @override + void setUserToken(String token) { + throw Exception(); + } + + // ==== ACTIVITY ==== + @override + void addActivity(String uuid, String filename, String category, String info) { + throw Exception(); + } + + @override + void removeActivity(String uuid) { + throw Exception(); + } + + @override + void removeAllActivities() { + throw Exception(); + } + + @override + String getActivityFilenameByUuid(String uuid) { + throw Exception(); + } + + @override + List getAllActivities() { + throw Exception(); + } + + // ==== CONFIG ==== + @override + void initConfig() { + throw Exception(); + } + + @override + void setSaveLocally(bool saveLocally) { + throw Exception(); + } + + @override + bool getSaveLocally() { + throw Exception(); + } +} diff --git a/lib/modele/local_db/db_impl.dart b/lib/modele/local_db/db_impl.dart new file mode 100644 index 0000000..cc15d1f --- /dev/null +++ b/lib/modele/local_db/db_impl.dart @@ -0,0 +1,31 @@ +import 'package:smartfit_app_mobile/modele/user.dart'; +import 'package:smartfit_app_mobile/modele/activity.dart'; + +abstract class DbImpl { + DbImpl._create(); + + Future create(); + + Future init(); + + // ==== USER ==== + void addUser(String username, String email, String token); + User getUser(); + bool hasUser(); + void deleteUser(); + void setUserMail(String email); + void setUserName(String username); + void setUserToken(String token); + + // ==== ACTIVITY ==== + void addActivity(String uuid, String filename, String category, String info); + void removeActivity(String uuid); + void removeAllActivities(); + String getActivityFilenameByUuid(String uuid); + List getAllActivities(); + + // ==== CONFIG ==== + void initConfig(); + void setSaveLocally(bool saveLocally); + bool getSaveLocally(); +} diff --git a/lib/modele/local_db/get_native_db.dart b/lib/modele/local_db/get_native_db.dart new file mode 100644 index 0000000..62a2750 --- /dev/null +++ b/lib/modele/local_db/get_native_db.dart @@ -0,0 +1,7 @@ +import 'package:smartfit_app_mobile/modele/local_db/db_impl.dart'; +import 'package:smartfit_app_mobile/modele/local_db/objectbox.dart'; + +DbImpl getDbImpl() { + DbImpl db = ObjectBox(); + return db; +} diff --git a/lib/modele/local_db/get_web_db.dart b/lib/modele/local_db/get_web_db.dart new file mode 100644 index 0000000..85cb326 --- /dev/null +++ b/lib/modele/local_db/get_web_db.dart @@ -0,0 +1,7 @@ +import 'package:smartfit_app_mobile/modele/local_db/db_impl.dart'; +import 'package:smartfit_app_mobile/modele/local_db/db_dummy.dart'; + +DbImpl getDbImpl() { + DbImpl db = DbDummy(); + return db; +} diff --git a/lib/modele/local_db/objectbox.dart b/lib/modele/local_db/objectbox.dart index 1faca92..8245880 100644 --- a/lib/modele/local_db/objectbox.dart +++ b/lib/modele/local_db/objectbox.dart @@ -1,14 +1,16 @@ import 'dart:convert'; import 'dart:io'; +import 'package:smartfit_app_mobile/modele/user.dart'; import 'package:smartfit_app_mobile/modele/activity.dart'; import 'package:smartfit_app_mobile/modele/activity_info/activity_info.dart'; import 'package:smartfit_app_mobile/objectbox.g.dart'; import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; -import 'package:smartfit_app_mobile/modele/local_db/model.dart'; +import 'package:smartfit_app_mobile/modele/local_db/model.dart' as db; +import 'package:smartfit_app_mobile/modele/local_db/db_impl.dart'; -class ObjectBox { +class ObjectBox implements DbImpl { late final Store store; late final Box userBox; late final Box activityBox; @@ -17,54 +19,75 @@ class ObjectBox { ObjectBox._create(this.store); - static Future create() async { + ObjectBox(); + + @override + Future create() async { final docsDir = await getApplicationDocumentsDirectory(); final store = await openStore(directory: p.join(docsDir.path, "database")); return ObjectBox._create(store); } - init() async { + @override + Future init() async { applicationDocumentDir = await getApplicationDocumentsDirectory(); - userBox = store.box(); - activityBox = store.box(); - configBox = store.box(); + userBox = store.box(); + activityBox = store.box(); + configBox = store.box(); } // ===== USER ===== + @override bool hasUser() { return !userBox.isEmpty(); } + @override + User getUser() { + db.User userRes = userBox.get(1); + + return User.create(userRes.username, userRes.email, userRes.token); + } + + @override void setUserMail(String email) { - User user = userBox.get(1); + db.User user = userBox.get(1); user.email = email; userBox.put(user); } + @override void setUserName(String username) { - User user = userBox.get(1); + db.User user = userBox.get(1); user.username = username; userBox.put(user); } + @override void setUserToken(String token) { - User user = userBox.get(1); + db.User user = userBox.get(1); user.token = token; userBox.put(user); } + @override void deleteUser() { userBox.removeAll(); } + @override void addUser(String username, String email, String token) { - userBox.put(User(0, username, email, token)); + userBox.put(db.User(0, username, email, token)); } // ===== Activity ===== - void addActivity(Activity newActivity) { + @override + void addActivity(String uuid, String filename, String category, String info) { + db.Activity act = + db.Activity(0, uuid, filename, category, jsonEncode(info)); + try { - activityBox.put(newActivity); + activityBox.put(act); } on ObjectBoxException { print("Activity already exists"); } catch (e) { @@ -73,35 +96,34 @@ class ObjectBox { } // TODO: try catch + @override void removeActivity(String uuid) { final Query query = activityBox.query(Activity_.uuid.equals(uuid)).build(); - final Activity act = query.findFirst(); + final db.Activity act = query.findFirst(); activityBox.remove(act.id); } + @override String getActivityFilenameByUuid(String uuid) { final Query query = activityBox.query(Activity_.uuid.equals(uuid)).build(); - final Activity act = query.findFirst(); + final db.Activity act = query.findFirst(); return act.filename; } - List getAllActivities() { - // TODO: Transform db.Activity to ActivityOfUser - throw Exception("Not implemented yet"); - } - + @override void removeAllActivities() { activityBox.removeAll(); } // ===== FIT Files ===== - List loadActivities() { + @override + List getAllActivities() { List activityDBList = activityBox.getAll(); List userActivityList = List.empty(growable: true); - for (Activity act in activityDBList) { + for (db.Activity act in activityDBList) { ActivityInfo actInfo = ActivityInfo.fromJson(jsonDecode(act.info)); userActivityList .add(ActivityOfUser(actInfo, act.category, act.uuid, act.filename)); @@ -111,15 +133,23 @@ class ObjectBox { } // ===== Config ===== + @override + void initConfig() { + db.Config config = db.Config(0, true); + configBox.put(config); + } + + @override void setSaveLocally(bool saveLocally) { - Config config = configBox.get(1); + db.Config config = configBox.get(1); config.saveLocally = saveLocally; configBox.put(config); stdout.write("(Config) setSaveLocally: $saveLocally\n"); } + @override bool getSaveLocally() { - Config config = configBox.get(1); + db.Config config = configBox.get(1); stdout.write("(Config) getSaveLocally: ${config.saveLocally}\n"); return config.saveLocally; } diff --git a/lib/modele/local_db/request_local.dart b/lib/modele/local_db/request_local.dart index 4e9bad3..b10bd5f 100644 --- a/lib/modele/local_db/request_local.dart +++ b/lib/modele/local_db/request_local.dart @@ -1,9 +1,10 @@ import 'dart:convert'; +import 'package:smartfit_app_mobile/modele/activity.dart'; import 'package:smartfit_app_mobile/modele/activity_info/activity_info.dart'; import 'package:smartfit_app_mobile/modele/activity_saver.dart'; import 'package:smartfit_app_mobile/modele/api/i_data_strategy.dart'; -import 'package:smartfit_app_mobile/modele/local_db/model.dart'; import 'package:tuple/tuple.dart'; +import 'package:smartfit_app_mobile/modele/user.dart'; import 'dart:io'; import 'dart:typed_data'; import 'package:smartfit_app_mobile/main.dart'; @@ -11,7 +12,7 @@ import 'package:smartfit_app_mobile/main.dart'; class RequestLocal implements IDataStrategy { @override Future getInfoUser(String token) async { - final User user = localDB.userBox.get(1); + final User user = localDB.getUser(); Map json = {"email": user.email, "username": user.username}; return Tuple2(true, jsonEncode(json)); } @@ -27,15 +28,15 @@ class RequestLocal implements IDataStrategy { @override Future getFiles(String token) async { - final List activities = localDB.activityBox.getAll(); + final List activities = localDB.getAllActivities(); List> jsonList = List.empty(growable: true); - for (Activity act in activities) { + for (ActivityOfUser act in activities) { Map json = { - "uuid": act.uuid, - "filename": act.filename, + "uuid": act.fileUuid, + "filename": act.nameFile, "category": act.category, - "info": act.info + "info": act.activityInfo }; jsonList.add(json); } diff --git a/lib/modele/user.dart b/lib/modele/user.dart index d2129d8..79f68e4 100644 --- a/lib/modele/user.dart +++ b/lib/modele/user.dart @@ -9,6 +9,10 @@ class User extends ChangeNotifier { List listActivity = List.empty(growable: true); ManagerSelectedActivity managerSelectedActivity = ManagerSelectedActivity(); + User(); + + User.create(String username, String email, String token); + void addActivity(ActivityOfUser activity) { listActivity.add(activity); notifyListeners(); diff --git a/lib/modele/utile/list_activity/list_activity_utile.dart b/lib/modele/utile/list_activity/list_activity_utile.dart index e2570a6..4b06c67 100644 --- a/lib/modele/utile/list_activity/list_activity_utile.dart +++ b/lib/modele/utile/list_activity/list_activity_utile.dart @@ -1,8 +1,8 @@ +import 'package:flutter/foundation.dart'; import 'package:smartfit_app_mobile/main.dart'; import 'package:smartfit_app_mobile/modele/api/api_wrapper.dart'; import 'package:smartfit_app_mobile/modele/activity_saver.dart'; import 'package:smartfit_app_mobile/modele/helper.dart'; -import 'package:smartfit_app_mobile/modele/local_db/model.dart' as db; import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; @@ -74,8 +74,9 @@ class ListActivityUtile { element["filename"].toString())); // Save to local db - localDB.addActivity(db.Activity(0, element["uuid"], element["filename"], - element["category"], jsonEncode(element["info"]))); + if (!kIsWeb) + localDB.addActivity(element["uuid"], element["filename"], + element["category"], jsonEncode(element["info"])); } return const Tuple2(true, "Yeah"); } diff --git a/lib/view/login/mobile/android_login_view.dart b/lib/view/login/mobile/android_login_view.dart index f7edbfc..e3d5dd3 100644 --- a/lib/view/login/mobile/android_login_view.dart +++ b/lib/view/login/mobile/android_login_view.dart @@ -1,3 +1,4 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:smartfit_app_mobile/common/colo_extension.dart'; @@ -165,8 +166,9 @@ class _MobileLoginView extends State { "Impossible de récupéré les données de l'utilisateur - {$infoUser.item2}"); } else { util.fillUser(context, infoUser.item2, result.item2); - localDB.addUser(infoUser.item2["username"], - infoUser.item2["email"], result.item2); + if (!kIsWeb) + localDB.addUser(infoUser.item2["username"], + infoUser.item2["email"], result.item2); Navigator.push( context, MaterialPageRoute( diff --git a/lib/view/login/web/web_login_view.dart b/lib/view/login/web/web_login_view.dart index ccd7910..899bdad 100644 --- a/lib/view/login/web/web_login_view.dart +++ b/lib/view/login/web/web_login_view.dart @@ -1,3 +1,4 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:smartfit_app_mobile/common/colo_extension.dart'; @@ -170,8 +171,9 @@ class _WebLoginView extends State { "Impossible de récupéré les données de l'utilisateur - {$infoUser.item2}"); } else { util.fillUser(context, infoUser.item2, result.item2); - localDB.addUser(infoUser.item2["username"], - infoUser.item2["email"], result.item2); + if (!kIsWeb) + localDB.addUser(infoUser.item2["username"], + infoUser.item2["email"], result.item2); Navigator.push( context, MaterialPageRoute( diff --git a/lib/view/profile/all_platforme/profile_view_allplatforme.dart b/lib/view/profile/all_platforme/profile_view_allplatforme.dart index d6e6d6c..64d0514 100644 --- a/lib/view/profile/all_platforme/profile_view_allplatforme.dart +++ b/lib/view/profile/all_platforme/profile_view_allplatforme.dart @@ -1,3 +1,4 @@ +import 'package:flutter/foundation.dart'; import 'package:smartfit_app_mobile/common_widget/container/profile/profile_switch.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -21,6 +22,8 @@ class ProfileViewAllPlatforme extends StatefulWidget { } class _ProfileViewAllPlatforme extends State { + bool isNative = !kIsWeb; + @override Widget build(BuildContext context) { String username = context.watch().username; @@ -58,8 +61,11 @@ class _ProfileViewAllPlatforme extends State { ), // TODO: Download/Delete (local) all users files on toggle ? // TODO: Display size of download in Mo - const ProfileSwitch( - "Offline mode", "Save your files locally", "local_save.png"), + Visibility( + visible: isNative, + child: const ProfileSwitch("Offline mode", + "Save your files locally", "local_save.png"), + ), const SizedBox( height: 25, ), diff --git a/lib/view/profile/mobile/mobile_change_email.dart b/lib/view/profile/mobile/mobile_change_email.dart index 36eba41..b82edf7 100644 --- a/lib/view/profile/mobile/mobile_change_email.dart +++ b/lib/view/profile/mobile/mobile_change_email.dart @@ -1,3 +1,4 @@ +import 'package:flutter/foundation.dart'; import 'package:smartfit_app_mobile/main.dart'; import 'package:flutter/material.dart'; import 'package:smartfit_app_mobile/modele/api/api_wrapper.dart'; @@ -119,7 +120,8 @@ class _MobileChangeEmailViewState extends State { if (res) { Provider.of(context, listen: false).email = controllerTextEmail.text; - localDB.setUserMail(controllerTextEmail.text); + if (!kIsWeb) + localDB.setUserMail(controllerTextEmail.text); } setState(() {}); }), diff --git a/lib/view/profile/mobile/mobile_change_username.dart b/lib/view/profile/mobile/mobile_change_username.dart index 3bdb747..c494cf9 100644 --- a/lib/view/profile/mobile/mobile_change_username.dart +++ b/lib/view/profile/mobile/mobile_change_username.dart @@ -1,3 +1,4 @@ +import 'package:flutter/foundation.dart'; import 'package:smartfit_app_mobile/main.dart'; import 'package:provider/provider.dart'; import 'package:flutter/material.dart'; @@ -118,7 +119,9 @@ class _MobileChangeUsernameViewState extends State { if (res) { Provider.of(context, listen: false) .username = controllerTextUsername.text; - localDB.setUserName(controllerTextUsername.text); + if (!kIsWeb) + localDB + .setUserName(controllerTextUsername.text); } setState(() {}); }), diff --git a/lib/view/profile/web/web_change_email.dart b/lib/view/profile/web/web_change_email.dart index 2ee2205..1818559 100644 --- a/lib/view/profile/web/web_change_email.dart +++ b/lib/view/profile/web/web_change_email.dart @@ -1,3 +1,4 @@ +import 'package:flutter/foundation.dart'; import 'package:smartfit_app_mobile/main.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -117,7 +118,8 @@ class _WebChangeEmailViewState extends State { if (res) { Provider.of(context, listen: false).email = controllerTextEmail.text; - localDB.setUserMail(controllerTextEmail.text); + if (!kIsWeb) + localDB.setUserMail(controllerTextEmail.text); } setState(() {}); }), diff --git a/lib/view/profile/web/web_change_username.dart b/lib/view/profile/web/web_change_username.dart index a785873..25ee3be 100644 --- a/lib/view/profile/web/web_change_username.dart +++ b/lib/view/profile/web/web_change_username.dart @@ -1,3 +1,4 @@ +import 'package:flutter/foundation.dart'; import 'package:smartfit_app_mobile/main.dart'; import 'package:flutter/material.dart'; import 'package:smartfit_app_mobile/modele/user.dart'; @@ -119,7 +120,9 @@ class _WebChangeUsernameViewState extends State { if (res) { Provider.of(context, listen: false) .username = controllerTextUsername.text; - localDB.setUserName(controllerTextUsername.text); + if (!kIsWeb) + localDB + .setUserName(controllerTextUsername.text); } setState(() {}); }), From ffc6d9300841d030c6db8d10aeefa72881fb5e27 Mon Sep 17 00:00:00 2001 From: otbenjello Date: Mon, 11 Dec 2023 09:37:22 +0100 Subject: [PATCH 09/20] nav_bar_update --- IA/categoryByData.py | 2 +- IA/distanceByTime.py | 2 +- assets/img/prediction.svg | 3 +++ assets/img/prediction_selected.svg | 9 +++++++ assets/img/volumes.svg | 3 +++ assets/img/volumes_selected.svg | 9 +++++++ lib/common_widget/button/tab_button.dart | 10 ++++---- .../main_tab/mobile/mobile_main_tab_view.dart | 25 +++++++++++++------ lib/view/main_tab/web/web_main_tab_view.dart | 25 ++++++++++++++----- 9 files changed, 68 insertions(+), 20 deletions(-) create mode 100644 assets/img/prediction.svg create mode 100644 assets/img/prediction_selected.svg create mode 100644 assets/img/volumes.svg create mode 100644 assets/img/volumes_selected.svg diff --git a/IA/categoryByData.py b/IA/categoryByData.py index 9983408..ce4e39f 100644 --- a/IA/categoryByData.py +++ b/IA/categoryByData.py @@ -5,7 +5,7 @@ from sklearn.model_selection import train_test_split from sklearn.linear_model import LinearRegression # Load data from CSV -df = pd.read_csv("data\\data_emple.csv") +df = pd.read_csv("data//data_emple.csv") category = df.iloc[0:len(df),0].values diff --git a/IA/distanceByTime.py b/IA/distanceByTime.py index 7bd2410..47e420a 100644 --- a/IA/distanceByTime.py +++ b/IA/distanceByTime.py @@ -3,7 +3,7 @@ import numpy as np import matplotlib.pyplot as plt from sklearn.linear_model import LinearRegression from sklearn.model_selection import train_test_split -df = pd.read_csv("data\\data_emple.csv") +df = pd.read_csv("data//data_emple.csv") distance = df.iloc[0:len(df),1].values.reshape(-1, 1) time = df.iloc[0:len(df),2].values.reshape(-1, 1) diff --git a/assets/img/prediction.svg b/assets/img/prediction.svg new file mode 100644 index 0000000..0b78190 --- /dev/null +++ b/assets/img/prediction.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/img/prediction_selected.svg b/assets/img/prediction_selected.svg new file mode 100644 index 0000000..e8b8e77 --- /dev/null +++ b/assets/img/prediction_selected.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/assets/img/volumes.svg b/assets/img/volumes.svg new file mode 100644 index 0000000..031522a --- /dev/null +++ b/assets/img/volumes.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/img/volumes_selected.svg b/assets/img/volumes_selected.svg new file mode 100644 index 0000000..452dd85 --- /dev/null +++ b/assets/img/volumes_selected.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/lib/common_widget/button/tab_button.dart b/lib/common_widget/button/tab_button.dart index de8939d..b1b45e6 100644 --- a/lib/common_widget/button/tab_button.dart +++ b/lib/common_widget/button/tab_button.dart @@ -20,19 +20,19 @@ class TabButton extends StatelessWidget { onTap: onTap, child: Column(mainAxisSize: MainAxisSize.min, children: [ SvgPicture.asset(isActive ? selectIcon : icon, - width: 28, height: 28, fit: BoxFit.fitWidth), + width: 15, height: 25, fit: BoxFit.fitWidth), SizedBox( - height: isActive ? 12: 8, + height: isActive ? 10: 6, ), if(isActive) Container( - width: 4, - height: 4, + width: 3, + height: 3, decoration: BoxDecoration( gradient: LinearGradient( colors: TColor.secondaryG, ), - borderRadius: BorderRadius.circular(2)), + borderRadius: BorderRadius.circular(1.5)), ) ]), ); diff --git a/lib/view/main_tab/mobile/mobile_main_tab_view.dart b/lib/view/main_tab/mobile/mobile_main_tab_view.dart index e8ebcef..7b42663 100644 --- a/lib/view/main_tab/mobile/mobile_main_tab_view.dart +++ b/lib/view/main_tab/mobile/mobile_main_tab_view.dart @@ -30,7 +30,7 @@ class _MobileMainTabViewState extends State { height: 70, child: InkWell( onTap: () { - selectTab = 4; + selectTab = 10; currentTab = const ListActivity(); if (mounted) { setState(() {}); @@ -90,8 +90,8 @@ class _MobileMainTabViewState extends State { } }), TabButton( - icon: "assets/img/Activity_tab.svg", - selectIcon: "assets/img/Activity_tab_select.svg", + icon: "assets/img/volumes.svg", + selectIcon: "assets/img/volumes_selected.svg", isActive: selectTab == 2, onTap: () { selectTab = 2; @@ -104,8 +104,8 @@ class _MobileMainTabViewState extends State { width: 40, ), TabButton( - icon: "assets/img/mapIcon.svg", - selectIcon: "assets/img/mapIcon_selected.svg", + icon: "assets/img/prediction.svg", + selectIcon: "assets/img/prediction_selected.svg", isActive: selectTab == 3, onTap: () { selectTab = 3; @@ -115,11 +115,22 @@ class _MobileMainTabViewState extends State { } }), TabButton( - icon: "assets/img/Profile_tab.svg", - selectIcon: "assets/img/Profile_tab_select.svg", + icon: "assets/img/mapIcon.svg", + selectIcon: "assets/img/mapIcon_selected.svg", isActive: selectTab == 4, onTap: () { selectTab = 4; + currentTab = const MyMap(); + if (mounted) { + setState(() {}); + } + }), + TabButton( + icon: "assets/img/Profile_tab.svg", + selectIcon: "assets/img/Profile_tab_select.svg", + isActive: selectTab == 5, + onTap: () { + selectTab = 5; currentTab = const ProfileView(); if (mounted) { setState(() {}); diff --git a/lib/view/main_tab/web/web_main_tab_view.dart b/lib/view/main_tab/web/web_main_tab_view.dart index 759558e..8db932e 100644 --- a/lib/view/main_tab/web/web_main_tab_view.dart +++ b/lib/view/main_tab/web/web_main_tab_view.dart @@ -6,6 +6,7 @@ import 'package:smartfit_app_mobile/view/activity/activity.dart'; import 'package:smartfit_app_mobile/view/home/home_view.dart'; import 'package:smartfit_app_mobile/view/map/my_map.dart'; import 'package:smartfit_app_mobile/view/profile/profile_view.dart'; +import 'package:smartfit_app_mobile/view/volumes/volumes_view.dart'; class WebMainTabView extends StatefulWidget { const WebMainTabView({Key? key}) : super(key: key); @@ -15,7 +16,7 @@ class WebMainTabView extends StatefulWidget { } class _WebMainTabViewState extends State { - int selectTab = 4; // Définissez l'onglet initial ici + int selectTab = 10; // Définissez l'onglet initial ici late Widget currentTab; @override @@ -49,9 +50,15 @@ class _WebMainTabViewState extends State { index: 1, onTap: () => updateTab(1, const Activity()), ), + sideBarButton( + icon: "assets/img/volumes.svg", + selectIcon: "assets/img/volumes_selected.svg", + index: 2, + onTap: () => updateTab(2, const VolumesView()), + ), InkWell( onTap: () { - updateTab(4, const ListActivity()); + updateTab(10, const ListActivity()); }, child: Container( width: 65, @@ -75,17 +82,23 @@ class _WebMainTabViewState extends State { ), ), ), + sideBarButton( + icon: "assets/img/prediction.svg", + selectIcon: "assets/img/prediction_selected.svg", + index: 3, + onTap: () => updateTab(3, const MyMap()), + ), sideBarButton( icon: "assets/img/mapIcon.svg", selectIcon: "assets/img/mapIcon_selected.svg", - index: 2, - onTap: () => updateTab(2, const MyMap()), + index: 4, + onTap: () => updateTab(4, const MyMap()), ), sideBarButton( icon: "assets/img/Profile_tab.svg", selectIcon: "assets/img/Profile_tab_select.svg", - index: 3, - onTap: () => updateTab(3, const ProfileView()), + index: 5, + onTap: () => updateTab(5, const ProfileView()), ), ], ), From bbc4e4fb04f82af077fdab8ed88de2cd30f10e8e Mon Sep 17 00:00:00 2001 From: rem Date: Mon, 11 Dec 2023 10:21:15 +0100 Subject: [PATCH 10/20] :boom: offline done --- lib/modele/api/api_wrapper.dart | 31 ++++++------------- .../profile_view_allplatforme.dart | 17 +++++----- 2 files changed, 19 insertions(+), 29 deletions(-) diff --git a/lib/modele/api/api_wrapper.dart b/lib/modele/api/api_wrapper.dart index 9ea6fd3..48ee173 100644 --- a/lib/modele/api/api_wrapper.dart +++ b/lib/modele/api/api_wrapper.dart @@ -1,5 +1,3 @@ -import 'dart:typed_data'; - import 'package:flutter/foundation.dart'; import 'package:smartfit_app_mobile/modele/activity_info/activity_info.dart'; import 'package:smartfit_app_mobile/modele/api/i_data_strategy.dart'; @@ -9,9 +7,10 @@ import 'package:smartfit_app_mobile/modele/utile/info_message.dart'; import 'package:email_validator/email_validator.dart'; import 'package:tuple/tuple.dart'; import 'dart:convert'; +import 'dart:io'; import 'package:crypto/crypto.dart'; import 'package:smartfit_app_mobile/main.dart'; -import 'dart:io'; +import 'package:http/http.dart' as http; class ApiWrapper { late IDataStrategy api; @@ -22,15 +21,15 @@ class ApiWrapper { // TODO: Change check online for flutterWeb Future isOnline() async { try { - final result = await InternetAddress.lookup('example.com') - .timeout(const Duration(seconds: 2)); - if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) { + final http.Response res = await http + .head(Uri.https("example.com")) + .timeout(const Duration(seconds: 5)); + + if (res.statusCode == 200) { return true; } - } on SocketException catch (_) { + } catch (_) { return false; - } on UnsupportedError catch (_) { - return true; } return true; } @@ -43,13 +42,10 @@ class ApiWrapper { } if (await isOnline()) { - stdout.write("(API) "); api = RequestApi(); } else if (!kIsWeb && localDB.getSaveLocally()) { - stdout.write("(LOCAL) "); api = RequestLocal(); } else { - stdout.write("(API OFFLINE) "); api = RequestApi(); } } @@ -67,7 +63,6 @@ class ApiWrapper { await init(); Tuple2 res = await api.getInfoUser(token); - stdout.write("getUserInfo: ${res.item1}\n"); return res; } @@ -80,7 +75,6 @@ class ApiWrapper { infoManager.displayMessage(noConnectionMessage, true); } - stdout.write("getFile: ${res.item1}\n"); return res; } @@ -92,7 +86,6 @@ class ApiWrapper { infoManager.displayMessage(noConnectionMessage, true); } - stdout.write("getFiles: ${res.item1}\n"); return res; } @@ -108,7 +101,6 @@ class ApiWrapper { Tuple2 res = await api.modifAttribut(token, infoToModify, value); - stdout.write("updateUserInfo: ${res.item1}\n"); if (res.item1) { infoManager.displayMessage( "${infoToModify.capitalize()} modified succesfully !", false); @@ -133,7 +125,6 @@ class ApiWrapper { String hash = sha256.convert(utf8.encode(password)).toString(); Tuple2 res = await api.connexion(email, hash); - stdout.write("login: ${res.item1}\n"); if (res.item1) { return Tuple2(true, res.item2); } else { @@ -151,7 +142,6 @@ class ApiWrapper { Tuple2 res = await api.deleteUser(token); - stdout.write("deleteUser: ${res.item1}\n"); return res; } @@ -162,7 +152,6 @@ class ApiWrapper { Tuple2 res = await api.postUser(email, hash, username); - stdout.write("createUser: ${res.item1}\n"); return res; } @@ -172,7 +161,6 @@ class ApiWrapper { if (handleOffline(infoManager)) return const Tuple2(false, "offline"); Tuple2 res = await api.uploadFile(token, file); - stdout.write("uploadFile: ${res.item1}\n"); return res; } @@ -191,7 +179,7 @@ class ApiWrapper { token, contentFile, filename, category, date, activityInfo); if (!res.item1) infoManager.displayMessage(noConnectionMessage, true); - stdout.write("uploadFileByte: ${res.item1}\n"); + //stdout.write("uploadFileByte: ${res.item1}\n"); return res; } @@ -203,7 +191,6 @@ class ApiWrapper { bool res = await api.deleteFile(token, fileUuid); if (!res) infoManager.displayMessage(noConnectionMessage, true); - stdout.write("deleteFile: $res\n"); return res; } } diff --git a/lib/view/profile/all_platforme/profile_view_allplatforme.dart b/lib/view/profile/all_platforme/profile_view_allplatforme.dart index 64d0514..4406961 100644 --- a/lib/view/profile/all_platforme/profile_view_allplatforme.dart +++ b/lib/view/profile/all_platforme/profile_view_allplatforme.dart @@ -62,13 +62,16 @@ class _ProfileViewAllPlatforme extends State { // TODO: Download/Delete (local) all users files on toggle ? // TODO: Display size of download in Mo Visibility( - visible: isNative, - child: const ProfileSwitch("Offline mode", - "Save your files locally", "local_save.png"), - ), - const SizedBox( - height: 25, - ), + visible: isNative, + child: const Column( + children: [ + ProfileSwitch("Offline mode", "Save your files locally", + "local_save.png"), + SizedBox( + height: 25, + ) + ], + )), ProfileOther(widget.otherArr) ], ), From 7fc300c05065dc67645296d1b4645a69bc9c1374 Mon Sep 17 00:00:00 2001 From: rem Date: Mon, 11 Dec 2023 11:55:29 +0100 Subject: [PATCH 11/20] :bug: works again --- lib/main.dart | 26 +++++++++---------- lib/modele/local_db/objectbox.dart | 5 ++-- lib/modele/local_db/request_local.dart | 2 +- lib/modele/user.dart | 2 +- .../list_activity/list_activity_utile.dart | 3 ++- 5 files changed, 18 insertions(+), 20 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 1277346..d14e769 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -34,23 +34,21 @@ class MyApp extends StatelessWidget { Widget viewToDisplay = const SignUpView(); // Skip sign-up + fill provider if user already connected - if (!kIsWeb) { - if (localDB.hasUser()) { - final User user = localDB.getUser(); - final userActivities = localDB.getAllActivities(); + if (!kIsWeb && localDB.hasUser()) { + final User user = localDB.getUser(); + final userActivities = localDB.getAllActivities(); - context.watch().username = user.username; - context.watch().email = user.email; - context.watch().token = user.token; - context.watch().listActivity = userActivities; + context.watch().username = user.username; + context.watch().email = user.email; + context.watch().token = user.token; + context.watch().listActivity = userActivities; - stdout.write("===== USER =====\n"); - stdout.write("Username: ${user.username}\n"); - stdout.write("Email: ${user.email}\n"); - stdout.write("Token: ${user.token}\n"); + stdout.write("===== USER =====\n"); + stdout.write("Username: ${user.username}\n"); + stdout.write("Email: ${user.email}\n"); + stdout.write("Token: ${user.token}\n"); - viewToDisplay = const MainTabView(); - } + viewToDisplay = const MainTabView(); } return MaterialApp( diff --git a/lib/modele/local_db/objectbox.dart b/lib/modele/local_db/objectbox.dart index 8245880..3029be3 100644 --- a/lib/modele/local_db/objectbox.dart +++ b/lib/modele/local_db/objectbox.dart @@ -45,7 +45,6 @@ class ObjectBox implements DbImpl { @override User getUser() { db.User userRes = userBox.get(1); - return User.create(userRes.username, userRes.email, userRes.token); } @@ -83,8 +82,7 @@ class ObjectBox implements DbImpl { // ===== Activity ===== @override void addActivity(String uuid, String filename, String category, String info) { - db.Activity act = - db.Activity(0, uuid, filename, category, jsonEncode(info)); + db.Activity act = db.Activity(0, uuid, filename, category, info); try { activityBox.put(act); @@ -125,6 +123,7 @@ class ObjectBox implements DbImpl { for (db.Activity act in activityDBList) { ActivityInfo actInfo = ActivityInfo.fromJson(jsonDecode(act.info)); + userActivityList .add(ActivityOfUser(actInfo, act.category, act.uuid, act.filename)); } diff --git a/lib/modele/local_db/request_local.dart b/lib/modele/local_db/request_local.dart index b10bd5f..a8fcb26 100644 --- a/lib/modele/local_db/request_local.dart +++ b/lib/modele/local_db/request_local.dart @@ -41,7 +41,7 @@ class RequestLocal implements IDataStrategy { jsonList.add(json); } - return Tuple2(true, jsonEncode(activities)); + return Tuple2(true, jsonList); } @override diff --git a/lib/modele/user.dart b/lib/modele/user.dart index 79f68e4..c0126ce 100644 --- a/lib/modele/user.dart +++ b/lib/modele/user.dart @@ -11,7 +11,7 @@ class User extends ChangeNotifier { User(); - User.create(String username, String email, String token); + User.create(this.username, this.email, this.token); void addActivity(ActivityOfUser activity) { listActivity.add(activity); diff --git a/lib/modele/utile/list_activity/list_activity_utile.dart b/lib/modele/utile/list_activity/list_activity_utile.dart index 4b06c67..dd79aa0 100644 --- a/lib/modele/utile/list_activity/list_activity_utile.dart +++ b/lib/modele/utile/list_activity/list_activity_utile.dart @@ -74,9 +74,10 @@ class ListActivityUtile { element["filename"].toString())); // Save to local db - if (!kIsWeb) + if (!kIsWeb) { localDB.addActivity(element["uuid"], element["filename"], element["category"], jsonEncode(element["info"])); + } } return const Tuple2(true, "Yeah"); } From 7c9f68ba9d3cc7104ac929b7bc2a951facfd242e Mon Sep 17 00:00:00 2001 From: rem Date: Mon, 11 Dec 2023 11:06:57 +0100 Subject: [PATCH 12/20] remove code-analysis depends on build-apk because of errors in CI --- .drone.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index a5327aa..e613715 100644 --- a/.drone.yml +++ b/.drone.yml @@ -43,4 +43,4 @@ steps: - export PATH=$SONAR_SCANNER_HOME/bin:$PATH - export SONAR_SCANNER_OPTS="-server" - sonar-scanner -D sonar.projectKey=SmartFit_Mobile -D sonar.sources=./lib -D sonar.host.url=https://codefirst.iut.uca.fr/sonar -D sonar.login=$${SONAR_TOKEN} - depends_on: [ build-apk, build-web ] + depends_on: [ build-web ] From 84718c8bd52c864197e5e37f97b06f6b7fc64949 Mon Sep 17 00:00:00 2001 From: rem Date: Mon, 11 Dec 2023 11:10:40 +0100 Subject: [PATCH 13/20] :construction_worker: debug apk build --- .drone.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.drone.yml b/.drone.yml index e613715..725e48b 100644 --- a/.drone.yml +++ b/.drone.yml @@ -13,6 +13,7 @@ steps: image: ghcr.io/cirruslabs/flutter:3.13.9 commands: - flutter clean + - dart run build_runner clean - dart run build_runner build - flutter build apk - sfm_apk=sfm_$(date +"%Y_%m_%d_%H_%M_%S").apk From 3a21285ff8b760e1f82d042ab94f30a3db96ffec Mon Sep 17 00:00:00 2001 From: rem Date: Mon, 11 Dec 2023 11:12:55 +0100 Subject: [PATCH 14/20] :construction_worker: debug apk build --- .drone.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index 725e48b..2d79dce 100644 --- a/.drone.yml +++ b/.drone.yml @@ -14,7 +14,7 @@ steps: commands: - flutter clean - dart run build_runner clean - - dart run build_runner build + - dart run build_runner build --delete-conflicting-outputs - flutter build apk - sfm_apk=sfm_$(date +"%Y_%m_%d_%H_%M_%S").apk - cp ./build/app/outputs/flutter-apk/app-release.apk $sfm_apk From abda0403f0e3ebbb1238b8f23bb5308608d3b2b1 Mon Sep 17 00:00:00 2001 From: rem Date: Mon, 11 Dec 2023 11:14:33 +0100 Subject: [PATCH 15/20] Update '.drone.yml' --- .drone.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.drone.yml b/.drone.yml index 2d79dce..6235022 100644 --- a/.drone.yml +++ b/.drone.yml @@ -13,6 +13,7 @@ steps: image: ghcr.io/cirruslabs/flutter:3.13.9 commands: - flutter clean + - flutter pub cache repair - dart run build_runner clean - dart run build_runner build --delete-conflicting-outputs - flutter build apk From 88ef9aaba38a44f15b153579859f214415494c13 Mon Sep 17 00:00:00 2001 From: rem Date: Mon, 11 Dec 2023 11:17:05 +0100 Subject: [PATCH 16/20] :construction_worker: debug apk build --- .drone.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.drone.yml b/.drone.yml index 6235022..05d01f2 100644 --- a/.drone.yml +++ b/.drone.yml @@ -10,7 +10,7 @@ trigger: steps: - name: build-apk - image: ghcr.io/cirruslabs/flutter:3.13.9 + image: ghcr.io/cirruslabs/flutter:3.16.3 commands: - flutter clean - flutter pub cache repair @@ -23,7 +23,7 @@ steps: - cat upload.json | cut -d '"' -f 12 - name: build-web - image: ghcr.io/cirruslabs/flutter:3.13.9 + image: ghcr.io/cirruslabs/flutter:3.16.3 environment: FIREBASE_TOKEN: from_secret: firebase_token From 31ac327002021eb698f9c4631de317b22250228d Mon Sep 17 00:00:00 2001 From: rem Date: Mon, 11 Dec 2023 11:19:26 +0100 Subject: [PATCH 17/20] :construction_worker: debug apk build --- .drone.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.drone.yml b/.drone.yml index 05d01f2..a127784 100644 --- a/.drone.yml +++ b/.drone.yml @@ -14,6 +14,7 @@ steps: commands: - flutter clean - flutter pub cache repair + - ls /drone/src/.dart_tool/pub/bin/build_runner/ - dart run build_runner clean - dart run build_runner build --delete-conflicting-outputs - flutter build apk From 5a5da634b7fb5cbdfc72e1710f8bf77a7f77974e Mon Sep 17 00:00:00 2001 From: rem Date: Mon, 11 Dec 2023 11:20:25 +0100 Subject: [PATCH 18/20] :construction_worker: debug apk build --- .drone.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index a127784..9f6c43d 100644 --- a/.drone.yml +++ b/.drone.yml @@ -14,7 +14,8 @@ steps: commands: - flutter clean - flutter pub cache repair - - ls /drone/src/.dart_tool/pub/bin/build_runner/ + - flutter pub get + - ls /drone/src/.dart_tool/ - dart run build_runner clean - dart run build_runner build --delete-conflicting-outputs - flutter build apk From e42a1e724ac0c519b7b38be4cc61b47d7fbfc19d Mon Sep 17 00:00:00 2001 From: rem Date: Mon, 11 Dec 2023 11:23:07 +0100 Subject: [PATCH 19/20] :green_heart: fix apk build + add code-analysis depends on apk-build --- .drone.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index 9f6c43d..bad0485 100644 --- a/.drone.yml +++ b/.drone.yml @@ -47,4 +47,4 @@ steps: - export PATH=$SONAR_SCANNER_HOME/bin:$PATH - export SONAR_SCANNER_OPTS="-server" - sonar-scanner -D sonar.projectKey=SmartFit_Mobile -D sonar.sources=./lib -D sonar.host.url=https://codefirst.iut.uca.fr/sonar -D sonar.login=$${SONAR_TOKEN} - depends_on: [ build-web ] + depends_on: [ build-apk,build-web ] From a6b104981725d0511ff3e20b68f3ed4f17478d6b Mon Sep 17 00:00:00 2001 From: otbenjello Date: Mon, 11 Dec 2023 16:01:44 +0100 Subject: [PATCH 20/20] page prediction --- assets/img/bpm2-icon.svg | 22 + assets/img/distance2-icon.svg | 531 +++++++++++++ assets/img/time-icon2.svg | 703 ++++++++++++++++++ assets/img/vitesse2-icon.svg | 297 ++++++++ .../container/workout_row/workout_row.dart | 58 ++ lib/modele/local_db/objectbox.dart | 3 +- lib/view/home/prediction_view.dart | 147 ++++ .../main_tab/mobile/mobile_main_tab_view.dart | 3 +- lib/view/main_tab/web/web_main_tab_view.dart | 3 +- 9 files changed, 1763 insertions(+), 4 deletions(-) create mode 100644 assets/img/bpm2-icon.svg create mode 100644 assets/img/distance2-icon.svg create mode 100644 assets/img/time-icon2.svg create mode 100644 assets/img/vitesse2-icon.svg create mode 100644 lib/common_widget/container/workout_row/workout_row.dart create mode 100644 lib/view/home/prediction_view.dart diff --git a/assets/img/bpm2-icon.svg b/assets/img/bpm2-icon.svg new file mode 100644 index 0000000..5f0f5be --- /dev/null +++ b/assets/img/bpm2-icon.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/img/distance2-icon.svg b/assets/img/distance2-icon.svg new file mode 100644 index 0000000..8791f12 --- /dev/null +++ b/assets/img/distance2-icon.svg @@ -0,0 +1,531 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/img/time-icon2.svg b/assets/img/time-icon2.svg new file mode 100644 index 0000000..1d793f3 --- /dev/null +++ b/assets/img/time-icon2.svg @@ -0,0 +1,703 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/img/vitesse2-icon.svg b/assets/img/vitesse2-icon.svg new file mode 100644 index 0000000..ec7f96c --- /dev/null +++ b/assets/img/vitesse2-icon.svg @@ -0,0 +1,297 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib/common_widget/container/workout_row/workout_row.dart b/lib/common_widget/container/workout_row/workout_row.dart new file mode 100644 index 0000000..491809d --- /dev/null +++ b/lib/common_widget/container/workout_row/workout_row.dart @@ -0,0 +1,58 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:simple_animation_progress_bar/simple_animation_progress_bar.dart'; +import 'package:smartfit_app_mobile/common/colo_extension.dart'; + +class WorkoutRow extends StatelessWidget { + final Map wObj; + const WorkoutRow({super.key, required this.wObj}); + + @override + Widget build(BuildContext context) { + return Container( + margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 2), + padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 15), + decoration: BoxDecoration( + color: TColor.white, + borderRadius: BorderRadius.circular(20), + boxShadow: const [BoxShadow(color: Colors.black12, blurRadius: 2)]), + child: Row( + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(30), + child: SvgPicture.asset( + wObj["image"].toString(), + width: 60, + height: 60, + fit: BoxFit.cover, + ), + ), + + const SizedBox(width: 15,), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + wObj["name"].toString(), + style: TextStyle( + color: TColor.black, + fontSize: 15, + fontWeight: FontWeight.bold), + ), + + Text( + "${ wObj["value"].toString()}", + style: TextStyle( + color: TColor.gray, + fontSize: 12,), + ), + + const SizedBox(height: 4,), + ], + )), + + ], + )); + } +} \ No newline at end of file diff --git a/lib/modele/local_db/objectbox.dart b/lib/modele/local_db/objectbox.dart index 8245880..1254879 100644 --- a/lib/modele/local_db/objectbox.dart +++ b/lib/modele/local_db/objectbox.dart @@ -1,10 +1,9 @@ import 'dart:convert'; import 'dart:io'; - +import 'package:objectbox/objectbox.dart'; import 'package:smartfit_app_mobile/modele/user.dart'; import 'package:smartfit_app_mobile/modele/activity.dart'; import 'package:smartfit_app_mobile/modele/activity_info/activity_info.dart'; -import 'package:smartfit_app_mobile/objectbox.g.dart'; import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; import 'package:smartfit_app_mobile/modele/local_db/model.dart' as db; diff --git a/lib/view/home/prediction_view.dart b/lib/view/home/prediction_view.dart new file mode 100644 index 0000000..71c0641 --- /dev/null +++ b/lib/view/home/prediction_view.dart @@ -0,0 +1,147 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:smartfit_app_mobile/common/colo_extension.dart'; +import 'package:smartfit_app_mobile/common_widget/button/round_button.dart'; +import 'package:smartfit_app_mobile/common_widget/container/workout_row/workout_row.dart'; + +class Prediction extends StatefulWidget { + const Prediction({Key? key}) : super(key: key); + + @override + State createState() => _PredictionState(); +} + +class _PredictionState extends State { + List> lastWorkoutArr = [ + { + "name": "Temps", + "image": "assets/img/time-icon2.svg", + "value": "200 s", + }, + { + "name": "Rythme cardiaque", + "image": "assets/img/bpm2-icon.svg", + "value": "120 BPM", + }, + { + "name": "Vitesse", + "image": "assets/img/vitesse2-icon.svg", + "value": "3 m/s", + }, + { + "name": "Distance", + "image": "assets/img/distance2-icon.svg", + "value": "300 m", + } + ]; + + @override + Widget build(BuildContext context) { + var media = MediaQuery.of(context).size; + + return Scaffold( + body: Padding( + padding: EdgeInsets.symmetric(horizontal: 20.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 40), + Text( + "Prédiction", + style: TextStyle( + color: TColor.black, + fontSize: 22, + fontWeight: FontWeight.w700, + ), + ), + SizedBox(height: 20), + Row( + children: [ + + ], + ), + Container( + decoration: BoxDecoration( + color: TColor.lightGray, + boxShadow: [ + BoxShadow( + color: Color.fromARGB(255, 234, 234, 234).withOpacity(0.9), + spreadRadius: 2, + blurRadius: 5, + offset: Offset(0, 2), + ), + ], + borderRadius: BorderRadius.circular(15), + ), + child: Row( + children: [ + Container( + alignment: Alignment.center, + width: 50, + height: 50, + padding: const EdgeInsets.symmetric(horizontal: 15), + child: SvgPicture.asset( + "assets/img/Profile_tab.svg", + width: 20, + height: 20, + fit: BoxFit.contain, + ), + ), + Expanded( + child: DropdownButtonHideUnderline( + child: DropdownButton( + items: ["Walking", "Cycling"] + .map((name) => DropdownMenuItem( + value: name, + child: Text( + name, + style: TextStyle( + color: TColor.gray, + fontSize: 14, + ), + ), + )) + .toList(), + onChanged: (value) {}, + isExpanded: true, + hint: Text( + "Choisir type d'activité", + style: TextStyle( + color: TColor.gray, + fontSize: 12, + ), + ), + ), + ), + ), + // Bouton "Valider" prenant 30% de la largeur du parent + + ], + ), + ), + SizedBox(height: 20), + RoundButton( + title: "Valider", + onPressed: () async { + setState(() {}); + }), + SizedBox(height: 20), + ListView.builder( + padding: EdgeInsets.zero, + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: lastWorkoutArr.length, + itemBuilder: (context, index) { + var wObj = + lastWorkoutArr[index] as Map ?? {}; + return InkWell( + child: WorkoutRow(wObj: wObj), + ); + }, + ), + ], + ), + ), + ); + } +} diff --git a/lib/view/main_tab/mobile/mobile_main_tab_view.dart b/lib/view/main_tab/mobile/mobile_main_tab_view.dart index 7b42663..11b381e 100644 --- a/lib/view/main_tab/mobile/mobile_main_tab_view.dart +++ b/lib/view/main_tab/mobile/mobile_main_tab_view.dart @@ -4,6 +4,7 @@ import 'package:smartfit_app_mobile/common_widget/button/tab_button.dart'; import 'package:smartfit_app_mobile/view/activity/activity.dart'; import 'package:smartfit_app_mobile/view/home/home_view.dart'; import 'package:flutter/material.dart'; +import 'package:smartfit_app_mobile/view/home/prediction_view.dart'; import 'package:smartfit_app_mobile/view/map/my_map.dart'; import 'package:smartfit_app_mobile/view/profile/profile_view.dart'; import 'package:smartfit_app_mobile/view/volumes/volumes_view.dart'; @@ -109,7 +110,7 @@ class _MobileMainTabViewState extends State { isActive: selectTab == 3, onTap: () { selectTab = 3; - currentTab = const MyMap(); + currentTab = const Prediction(); if (mounted) { setState(() {}); } diff --git a/lib/view/main_tab/web/web_main_tab_view.dart b/lib/view/main_tab/web/web_main_tab_view.dart index 8db932e..133ab4f 100644 --- a/lib/view/main_tab/web/web_main_tab_view.dart +++ b/lib/view/main_tab/web/web_main_tab_view.dart @@ -4,6 +4,7 @@ import 'package:smartfit_app_mobile/common_widget/button/tab_button.dart'; import 'package:smartfit_app_mobile/view/activity/list_activity.dart'; import 'package:smartfit_app_mobile/view/activity/activity.dart'; import 'package:smartfit_app_mobile/view/home/home_view.dart'; +import 'package:smartfit_app_mobile/view/home/prediction_view.dart'; import 'package:smartfit_app_mobile/view/map/my_map.dart'; import 'package:smartfit_app_mobile/view/profile/profile_view.dart'; import 'package:smartfit_app_mobile/view/volumes/volumes_view.dart'; @@ -86,7 +87,7 @@ class _WebMainTabViewState extends State { icon: "assets/img/prediction.svg", selectIcon: "assets/img/prediction_selected.svg", index: 3, - onTap: () => updateTab(3, const MyMap()), + onTap: () => updateTab(3, const Prediction()), ), sideBarButton( icon: "assets/img/mapIcon.svg",