From 8295d36acee2395b554ff4790eb36a8baed00beb Mon Sep 17 00:00:00 2001 From: rem Date: Tue, 28 Nov 2023 16:19:01 +0100 Subject: [PATCH 1/3] :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: -- 2.36.3 From e70129c6bac596cf65b9936fa2d988c29d0b7354 Mon Sep 17 00:00:00 2001 From: rem Date: Wed, 29 Nov 2023 14:46:08 +0100 Subject: [PATCH 2/3] 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 -- 2.36.3 From 49bc2bdd16af8edfb6a4ed6099d15bddef1055cf Mon Sep 17 00:00:00 2001 From: rem Date: Wed, 6 Dec 2023 13:33:47 +0100 Subject: [PATCH 3/3] :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(() {}); }), -- 2.36.3