From 8295d36acee2395b554ff4790eb36a8baed00beb Mon Sep 17 00:00:00 2001 From: rem Date: Tue, 28 Nov 2023 16:19:01 +0100 Subject: [PATCH 1/7] :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 2/7] 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 3/7] :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 e750bf8d5cf7c237c5a8d53c30807b763305d39f Mon Sep 17 00:00:00 2001 From: rem Date: Fri, 8 Dec 2023 13:33:59 +0100 Subject: [PATCH 4/7] 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 5/7] 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 6/7] 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 7/7] :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(() {}); }),