diff --git a/.drone.yml b/.drone.yml
index 5208750..bad0485 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -10,8 +10,14 @@ trigger:
steps:
- name: build-apk
- image: ghcr.io/cirruslabs/flutter:3.13.9
+ image: ghcr.io/cirruslabs/flutter:3.16.3
commands:
+ - flutter clean
+ - flutter pub cache repair
+ - flutter pub get
+ - ls /drone/src/.dart_tool/
+ - dart run build_runner clean
+ - dart run build_runner build --delete-conflicting-outputs
- flutter build apk
- sfm_apk=sfm_$(date +"%Y_%m_%d_%H_%M_%S").apk
- cp ./build/app/outputs/flutter-apk/app-release.apk $sfm_apk
@@ -19,7 +25,7 @@ steps:
- cat upload.json | cut -d '"' -f 12
- name: build-web
- image: ghcr.io/cirruslabs/flutter:3.13.9
+ image: ghcr.io/cirruslabs/flutter:3.16.3
environment:
FIREBASE_TOKEN:
from_secret: firebase_token
@@ -41,4 +47,4 @@ steps:
- export PATH=$SONAR_SCANNER_HOME/bin:$PATH
- export SONAR_SCANNER_OPTS="-server"
- sonar-scanner -D sonar.projectKey=SmartFit_Mobile -D sonar.sources=./lib -D sonar.host.url=https://codefirst.iut.uca.fr/sonar -D sonar.login=$${SONAR_TOKEN}
- depends_on: [ build-apk, build-web ]
+ depends_on: [ build-apk,build-web ]
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/.metadata b/.metadata
index 3408c2c..b060b6a 100644
--- a/.metadata
+++ b/.metadata
@@ -4,7 +4,7 @@
# This file should be version controlled and should not be manually edited.
version:
- revision: "d211f42860350d914a5ad8102f9ec32764dc6d06"
+ revision: "db7ef5bf9f59442b0e200a90587e8fa5e0c6336a"
channel: "stable"
project_type: app
@@ -13,11 +13,11 @@ project_type: app
migration:
platforms:
- platform: root
- create_revision: d211f42860350d914a5ad8102f9ec32764dc6d06
- base_revision: d211f42860350d914a5ad8102f9ec32764dc6d06
+ create_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a
+ base_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a
- platform: linux
- create_revision: d211f42860350d914a5ad8102f9ec32764dc6d06
- base_revision: d211f42860350d914a5ad8102f9ec32764dc6d06
+ create_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a
+ base_revision: db7ef5bf9f59442b0e200a90587e8fa5e0c6336a
# User provided section
diff --git a/assets/img/bpm2-icon.svg b/assets/img/bpm2-icon.svg
new file mode 100644
index 0000000..5f0f5be
--- /dev/null
+++ b/assets/img/bpm2-icon.svg
@@ -0,0 +1,22 @@
+
diff --git a/assets/img/distance2-icon.svg b/assets/img/distance2-icon.svg
new file mode 100644
index 0000000..8791f12
--- /dev/null
+++ b/assets/img/distance2-icon.svg
@@ -0,0 +1,531 @@
+
\ No newline at end of file
diff --git a/assets/img/local_save.png b/assets/img/local_save.png
new file mode 100644
index 0000000..aec5b70
Binary files /dev/null and b/assets/img/local_save.png differ
diff --git a/assets/img/prediction.svg b/assets/img/prediction.svg
new file mode 100644
index 0000000..0b78190
--- /dev/null
+++ b/assets/img/prediction.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/img/prediction_selected.svg b/assets/img/prediction_selected.svg
new file mode 100644
index 0000000..e8b8e77
--- /dev/null
+++ b/assets/img/prediction_selected.svg
@@ -0,0 +1,9 @@
+
diff --git a/assets/img/time-icon2.svg b/assets/img/time-icon2.svg
new file mode 100644
index 0000000..1d793f3
--- /dev/null
+++ b/assets/img/time-icon2.svg
@@ -0,0 +1,703 @@
+
\ No newline at end of file
diff --git a/assets/img/vitesse2-icon.svg b/assets/img/vitesse2-icon.svg
new file mode 100644
index 0000000..ec7f96c
--- /dev/null
+++ b/assets/img/vitesse2-icon.svg
@@ -0,0 +1,297 @@
+
\ No newline at end of file
diff --git a/assets/img/volumes.svg b/assets/img/volumes.svg
new file mode 100644
index 0000000..031522a
--- /dev/null
+++ b/assets/img/volumes.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/img/volumes_selected.svg b/assets/img/volumes_selected.svg
new file mode 100644
index 0000000..452dd85
--- /dev/null
+++ b/assets/img/volumes_selected.svg
@@ -0,0 +1,9 @@
+
diff --git a/lib/common_widget/button/tab_button.dart b/lib/common_widget/button/tab_button.dart
index de8939d..b1b45e6 100644
--- a/lib/common_widget/button/tab_button.dart
+++ b/lib/common_widget/button/tab_button.dart
@@ -20,19 +20,19 @@ class TabButton extends StatelessWidget {
onTap: onTap,
child: Column(mainAxisSize: MainAxisSize.min, children: [
SvgPicture.asset(isActive ? selectIcon : icon,
- width: 28, height: 28, fit: BoxFit.fitWidth),
+ width: 15, height: 25, fit: BoxFit.fitWidth),
SizedBox(
- height: isActive ? 12: 8,
+ height: isActive ? 10: 6,
),
if(isActive)
Container(
- width: 4,
- height: 4,
+ width: 3,
+ height: 3,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: TColor.secondaryG,
),
- borderRadius: BorderRadius.circular(2)),
+ borderRadius: BorderRadius.circular(1.5)),
)
]),
);
diff --git a/lib/common_widget/container/list/list_activity_widget.dart b/lib/common_widget/container/list/list_activity_widget.dart
index 8d85253..e815b60 100644
--- a/lib/common_widget/container/list/list_activity_widget.dart
+++ b/lib/common_widget/container/list/list_activity_widget.dart
@@ -1,10 +1,15 @@
+import 'package:smartfit_app_mobile/modele/activity_saver.dart';
+import 'package:smartfit_app_mobile/modele/helper.dart';
+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';
import 'package:smartfit_app_mobile/common_widget/container/workout_row/workout_row_generic.dart';
import 'package:smartfit_app_mobile/common_widget/container/workout_row/workout_row_walking.dart';
import 'package:smartfit_app_mobile/modele/activity.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:smartfit_app_mobile/modele/utile/list_activity/list_activity_utile.dart';
import 'package:tuple/tuple.dart';
@@ -16,12 +21,14 @@ class ListActivityWidget extends StatefulWidget {
}
class _ListActivityWidget extends State {
+ final ApiWrapper api = ApiWrapper();
+ final InfoMessage infoManager = InfoMessage();
final ListActivityUtile _utile = ListActivityUtile();
final ManagerFile managerFile = ManagerFile();
@override
Widget build(BuildContext context) {
- void onClick(ActivityOfUser activityObj) async {
+ Future onClick(ActivityOfUser activityObj) async {
if (!Provider.of(context, listen: false)
.managerSelectedActivity
.fileNotSelected(activityObj.fileUuid)) {
@@ -33,19 +40,20 @@ class _ListActivityWidget extends State {
}
Tuple2 result =
- await _utile.getContentActivity(context, activityObj);
+ await _utile.getContentActivity(context, activityObj, infoManager);
if (!result.item1) {
return;
}
+ // TODO: Hein?
Provider.of(context, listen: false).removeActivity(activityObj);
Provider.of(context, listen: false).insertActivity(0, activityObj);
}
- void onDelete(ActivityOfUser activityObj) async {
- if (await _utile.deleteFileOnBDD(
- Provider.of(context, listen: false).token,
- activityObj.fileUuid)) {
+ // TODO: Understand :(
+ Future onDelete(ActivityOfUser activityObj) async {
+ if (await api.deleteFile(Provider.of(context, listen: false).token,
+ activityObj.fileUuid, infoManager)) {
if (!Provider.of(context, listen: false)
.managerSelectedActivity
.fileNotSelected(activityObj.fileUuid)) {
@@ -53,6 +61,11 @@ class _ListActivityWidget extends State {
.managerSelectedActivity
.removeSelectedActivity(activityObj.fileUuid);
}
+ if (!Helper.isPlatformWeb()) {
+ ActivitySaver actSaver = await ActivitySaver.create();
+ actSaver.deleteActivity(activityObj.fileUuid);
+ localDB.removeActivity(activityObj.fileUuid);
+ }
Provider.of(context, listen: false).removeActivity(activityObj);
}
}
@@ -65,41 +78,62 @@ class _ListActivityWidget extends State {
return Material(
color: Colors.transparent,
- child: ListView.builder(
- padding: EdgeInsets.zero,
- physics: const NeverScrollableScrollPhysics(),
- shrinkWrap: true,
- itemCount: Provider.of(context, listen: true).listActivity.length,
- itemBuilder: (context, index) {
- ActivityOfUser activityObj =
- Provider.of(context, listen: true).listActivity[index];
- Map activityMap;
- // -- Si categorie == marche
- if (activityObj.category == managerFile.marche) {
- activityMap = activityObj.toMapWalking();
- return InkWell(
- onTap: () {},
- child: WorkoutRowWalking(
- wObj: activityMap,
- onDelete: () => onDelete(activityObj),
- onClick: () => onClick(activityObj),
- isSelected: isSelected(activityObj),
- ),
- );
- } else {
- // -- Default -- //
- activityMap = activityObj.toMapGeneric();
- return InkWell(
- onTap: () {},
- child: WorkoutRowGeneric(
- wObj: activityMap,
- onDelete: () => onDelete(activityObj),
- onClick: () => onClick(activityObj),
- isSelected: isSelected(activityObj),
- ),
- );
- }
- },
+ child: Column(
+ children: [
+ Visibility(
+ visible: infoManager.isVisible,
+ child: Text(infoManager.message,
+ style: TextStyle(color: infoManager.messageColor))),
+ ListView.builder(
+ padding: EdgeInsets.zero,
+ physics: const NeverScrollableScrollPhysics(),
+ shrinkWrap: true,
+ itemCount:
+ Provider.of(context, listen: true).listActivity.length,
+ itemBuilder: (context, index) {
+ ActivityOfUser activityObj =
+ Provider.of(context, listen: true).listActivity[index];
+ Map activityMap;
+ // -- Si categorie == marche
+ if (activityObj.category == managerFile.marche) {
+ activityMap = activityObj.toMapWalking();
+ return InkWell(
+ onTap: () {},
+ child: WorkoutRowWalking(
+ wObj: activityMap,
+ onDelete: () async {
+ await onDelete(activityObj);
+ setState(() {});
+ },
+ onClick: () async {
+ await onClick(activityObj);
+ setState(() {});
+ },
+ isSelected: isSelected(activityObj),
+ ),
+ );
+ } else {
+ // -- Default -- //
+ activityMap = activityObj.toMapGeneric();
+ return InkWell(
+ onTap: () {},
+ child: WorkoutRowGeneric(
+ wObj: activityMap,
+ onDelete: () async {
+ await onDelete(activityObj);
+ setState(() {});
+ },
+ onClick: () async {
+ await onClick(activityObj);
+ setState(() {});
+ },
+ isSelected: isSelected(activityObj),
+ ),
+ );
+ }
+ },
+ ),
+ ],
),
);
}
diff --git a/lib/common_widget/container/list/volumes_list.dart b/lib/common_widget/container/list/volumes_list.dart
index 9c61566..b228b9a 100644
--- a/lib/common_widget/container/list/volumes_list.dart
+++ b/lib/common_widget/container/list/volumes_list.dart
@@ -10,6 +10,7 @@ class VolumesList extends StatelessWidget {
Widget build(BuildContext context) {
var media = MediaQuery.of(context).size;
+ // TODO: True message with variables and context aware
if (volume["nbActivity"] == 0) {
return const Text("Aucune activité ces x jours/mois/années");
}
diff --git a/lib/common_widget/container/profile/profile_switch.dart b/lib/common_widget/container/profile/profile_switch.dart
new file mode 100644
index 0000000..ccdbdff
--- /dev/null
+++ b/lib/common_widget/container/profile/profile_switch.dart
@@ -0,0 +1,70 @@
+import 'package:flutter/material.dart';
+import 'package:smartfit_app_mobile/common/colo_extension.dart';
+import 'package:smartfit_app_mobile/main.dart';
+
+class ProfileSwitch extends StatefulWidget {
+ final String title;
+ final String description;
+ final String iconFilename;
+
+ const ProfileSwitch(this.title, this.description, this.iconFilename,
+ {super.key});
+
+ @override
+ State createState() => _ProfileSwitchState();
+}
+
+class _ProfileSwitchState extends State {
+ bool switchValue = localDB.getSaveLocally();
+
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
+ decoration: BoxDecoration(
+ color: TColor.white,
+ borderRadius: BorderRadius.circular(15),
+ boxShadow: const [BoxShadow(color: Colors.black12, blurRadius: 2)]),
+ child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
+ Text(
+ widget.title,
+ style: TextStyle(
+ color: TColor.black,
+ fontSize: 16,
+ fontWeight: FontWeight.w700,
+ ),
+ ),
+ const SizedBox(
+ height: 8,
+ ),
+ SizedBox(
+ height: 30,
+ child:
+ Row(crossAxisAlignment: CrossAxisAlignment.center, children: [
+ Image.asset("assets/img/${widget.iconFilename}",
+ height: 28, width: 28, fit: BoxFit.contain),
+ const SizedBox(
+ width: 15,
+ ),
+ Expanded(
+ child: Text(
+ widget.description,
+ style: TextStyle(
+ color: TColor.black,
+ fontSize: 12,
+ ),
+ ),
+ ),
+ Switch(
+ value: switchValue,
+ activeColor: Colors.orange,
+ onChanged: (bool value) {
+ setState(() {
+ switchValue = value;
+ localDB.setSaveLocally(switchValue);
+ });
+ }),
+ ]))
+ ]));
+ }
+}
diff --git a/lib/common_widget/container/workout_row/workout_row.dart b/lib/common_widget/container/workout_row/workout_row.dart
new file mode 100644
index 0000000..491809d
--- /dev/null
+++ b/lib/common_widget/container/workout_row/workout_row.dart
@@ -0,0 +1,58 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/flutter_svg.dart';
+import 'package:simple_animation_progress_bar/simple_animation_progress_bar.dart';
+import 'package:smartfit_app_mobile/common/colo_extension.dart';
+
+class WorkoutRow extends StatelessWidget {
+ final Map wObj;
+ const WorkoutRow({super.key, required this.wObj});
+
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 2),
+ padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 15),
+ decoration: BoxDecoration(
+ color: TColor.white,
+ borderRadius: BorderRadius.circular(20),
+ boxShadow: const [BoxShadow(color: Colors.black12, blurRadius: 2)]),
+ child: Row(
+ children: [
+ ClipRRect(
+ borderRadius: BorderRadius.circular(30),
+ child: SvgPicture.asset(
+ wObj["image"].toString(),
+ width: 60,
+ height: 60,
+ fit: BoxFit.cover,
+ ),
+ ),
+
+ const SizedBox(width: 15,),
+ Expanded(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ wObj["name"].toString(),
+ style: TextStyle(
+ color: TColor.black,
+ fontSize: 15,
+ fontWeight: FontWeight.bold),
+ ),
+
+ Text(
+ "${ wObj["value"].toString()}",
+ style: TextStyle(
+ color: TColor.gray,
+ fontSize: 12,),
+ ),
+
+ const SizedBox(height: 4,),
+ ],
+ )),
+
+ ],
+ ));
+ }
+}
\ No newline at end of file
diff --git a/lib/main.dart b/lib/main.dart
index f2f81e1..d14e769 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,10 +1,27 @@
+import 'dart:io';
+import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
+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/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 DbImpl localDB;
+
+Future main() async {
+ WidgetsFlutterBinding.ensureInitialized();
+
+ if (!kIsWeb) {
+ DbImpl tmp = getDbImpl();
+ localDB = await tmp.create();
+ await localDB.init();
+ localDB.initConfig();
+ }
-void main() {
runApp(ChangeNotifierProvider(
create: (context) => User(), child: const MyApp()));
}
@@ -14,6 +31,26 @@ class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
+ Widget viewToDisplay = const SignUpView();
+
+ // Skip sign-up + fill provider if user already connected
+ if (!kIsWeb && localDB.hasUser()) {
+ final User user = localDB.getUser();
+ final userActivities = localDB.getAllActivities();
+
+ context.watch().username = user.username;
+ context.watch().email = user.email;
+ context.watch().token = user.token;
+ context.watch().listActivity = userActivities;
+
+ 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();
+ }
+
return MaterialApp(
title: 'SmartFit',
debugShowCheckedModeBanner: false,
@@ -35,9 +72,7 @@ class MyApp extends StatelessWidget {
// tested with just a hot reload.
primaryColor: TColor.primaryColor1,
fontFamily: "Poppins"),
- home: const SignUpView(),
- //home: const TestPage(),
- //home: const ProfileView(),
+ home: viewToDisplay,
);
}
}
diff --git a/lib/modele/activity_saver.dart b/lib/modele/activity_saver.dart
new file mode 100644
index 0000000..529e476
--- /dev/null
+++ b/lib/modele/activity_saver.dart
@@ -0,0 +1,43 @@
+import 'dart:io';
+import 'dart:typed_data';
+
+import 'package:path/path.dart' as p;
+import "package:path_provider/path_provider.dart";
+import 'package:smartfit_app_mobile/main.dart';
+
+class ActivitySaver {
+ String saveDirectory = "activities";
+ late final Directory applicationDocumentsDir;
+
+ ActivitySaver._create(this.applicationDocumentsDir);
+
+ Uint8List getActivity(String uuid) {
+ String filename = localDB.getActivityFilenameByUuid(uuid);
+
+ final file =
+ File(p.join(applicationDocumentsDir.path, saveDirectory, filename));
+ return file.readAsBytesSync();
+ }
+
+ Future saveActivity(Uint8List activityFile, String filename) async {
+ stdout.write("Creating activity file...\n");
+ final file = await File(
+ p.join(applicationDocumentsDir.path, saveDirectory, filename))
+ .create(recursive: true); // To create dir if not exists
+ file.writeAsBytesSync(activityFile);
+ stdout.write("Activity file created\n");
+ }
+
+ void deleteActivity(String uuid) {
+ String filename = localDB.getActivityFilenameByUuid(uuid);
+ final file =
+ File(p.join(applicationDocumentsDir.path, saveDirectory, filename));
+ file.deleteSync();
+ }
+
+ static Future create() async {
+ stdout.write("Activity Saver: Created\n");
+ final appDir = await getApplicationDocumentsDirectory();
+ return ActivitySaver._create(appDir);
+ }
+}
diff --git a/lib/modele/api/api_wrapper.dart b/lib/modele/api/api_wrapper.dart
index 67174a1..48ee173 100644
--- a/lib/modele/api/api_wrapper.dart
+++ b/lib/modele/api/api_wrapper.dart
@@ -1,22 +1,107 @@
+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';
+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 'dart:io';
import 'package:crypto/crypto.dart';
+import 'package:smartfit_app_mobile/main.dart';
+import 'package:http/http.dart' as http;
class ApiWrapper {
- IDataStrategy api = RequestApi();
+ late IDataStrategy api;
+ String noConnectionMessage =
+ "It seems like you are lost far away in the universe, no connection found :)";
- Future modifyUserInfo(String infoToModify, String value, String token,
+ // HELPERS
+ // TODO: Change check online for flutterWeb
+ Future isOnline() async {
+ try {
+ final http.Response res = await http
+ .head(Uri.https("example.com"))
+ .timeout(const Duration(seconds: 5));
+
+ if (res.statusCode == 200) {
+ return true;
+ }
+ } catch (_) {
+ return false;
+ }
+ return true;
+ }
+
+ Future init() async {
+ // TODO: Fait à la pisse en despi (je voulais juste dormir)
+ if (kIsWeb) {
+ api = RequestApi();
+ return;
+ }
+
+ if (await isOnline()) {
+ api = RequestApi();
+ } else if (!kIsWeb && localDB.getSaveLocally()) {
+ api = RequestLocal();
+ } else {
+ api = RequestApi();
+ }
+ }
+
+ 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);
+
+ return res;
+ }
+
+ Future getFile(
+ String token, String fileUuid, InfoMessage infoManager) async {
+ await init();
+ Tuple2 res = await api.getFile(token, fileUuid);
+
+ if (!res.item1) {
+ infoManager.displayMessage(noConnectionMessage, true);
+ }
+
+ return res;
+ }
+
+ Future getFiles(String token, InfoMessage infoManager) async {
+ await init();
+ Tuple2 res = await api.getFiles(token);
+
+ if (!res.item1) {
+ infoManager.displayMessage(noConnectionMessage, true);
+ }
+
+ return res;
+ }
+
+ // 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) {
+
+ if (res.item1) {
infoManager.displayMessage(
"${infoToModify.capitalize()} modified succesfully !", false);
return true;
@@ -34,17 +119,79 @@ 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);
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);
+
+ 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);
+
+ 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);
+ return res;
+ }
+
+ Future> uploadFileByte(
+ String token,
+ Uint8List contentFile,
+ String filename,
+ String category,
+ DateTime date,
+ ActivityInfo activityInfo,
+ InfoMessage infoManager) async {
+ await init();
+ if (handleOffline(infoManager)) return const Tuple2(false, "offline");
+
+ Tuple2 res = await api.uploadFileByte(
+ token, contentFile, filename, category, date, activityInfo);
+ if (!res.item1) infoManager.displayMessage(noConnectionMessage, true);
+
+ //stdout.write("uploadFileByte: ${res.item1}\n");
+ 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);
+ if (!res) infoManager.displayMessage(noConnectionMessage, true);
+
+ return res;
}
}
diff --git a/lib/modele/api/i_data_strategy.dart b/lib/modele/api/i_data_strategy.dart
index e4f1f51..54ea65d 100644
--- a/lib/modele/api/i_data_strategy.dart
+++ b/lib/modele/api/i_data_strategy.dart
@@ -15,11 +15,13 @@ 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,
@@ -28,21 +30,16 @@ abstract class IDataStrategy {
DateTime date,
ActivityInfo activityInfo);
- // 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 eb5b9fc..bf525af 100644
--- a/lib/modele/api/request_api.dart
+++ b/lib/modele/api/request_api.dart
@@ -19,85 +19,105 @@ class RequestApi implements IDataStrategy {
var request = http.Request('GET', url);
request.headers.addAll({'Authorization': token});
- var streamedResponse = await request.send();
- final response = await http.Response.fromStream(streamedResponse);
- // !! Crée un fichier comme ca avec les bytes !!
- //File("//").writeAsBytes(response.bodyBytes);
+ try {
+ var streamedResponse = await request.send();
+ final response = await http.Response.fromStream(streamedResponse);
- if (response.statusCode == 200) {
- return Tuple2(true, response.bodyBytes);
- }
- if ((response.statusCode == 401)) {
- return const Tuple2(false, "401 - UNAUTHORIZED");
- }
- if ((response.statusCode == 404)) {
- return const Tuple2(false, "404 - NOT FOUND");
+ if (response.statusCode == 200) {
+ return Tuple2(true, response.bodyBytes);
+ }
+ if ((response.statusCode == 401)) {
+ return const Tuple2(false, "401 - UNAUTHORIZED");
+ }
+ if ((response.statusCode == 404)) {
+ return const Tuple2(false, "404 - NOT FOUND");
+ }
+ // When Network Off
+ } on SocketException {
+ return const Tuple2(false, "No connection");
}
+
return const Tuple2(false, "Fail");
}
@override
- Future> deleteFile(String token, String fileUuid) async {
- final response = await http.delete(
- Uri.parse('$urlApi/user/files/$fileUuid'),
- headers: {'Authorization': token});
+ Future deleteFile(String token, String fileUuid) async {
+ try {
+ final response = await http.delete(
+ Uri.parse('$urlApi/user/files/$fileUuid'),
+ headers: {'Authorization': token});
- if (response.statusCode == 200) {
- return const Tuple2(true, "Successful");
- }
- if (response.statusCode == 401) {
- return const Tuple2(false, "401 - UNAUTHORIZED");
+ if (response.statusCode == 200) {
+ return true;
+ }
+ if (response.statusCode == 401) {
+ return false;
+ }
+ if (response.statusCode == 404) {
+ return false;
+ }
+ } on SocketException catch (_) {
+ return false;
}
- if (response.statusCode == 404) {
- return const Tuple2(false, "404 - NOT FOUND");
- }
- return const Tuple2(false, "Fail");
+ return false;
}
@override
Future> deleteUser(String token) async {
- final response = await http.delete(Uri.parse('$urlApi/user'),
- headers: {'Authorization': token});
- if (response.statusCode == 200) {
- return const Tuple2(true, "Successful");
- } else if (response.statusCode == 401) {
- return const Tuple2(
- false, "401 UNAUTHORIZED - Mauvais ou pas de token");
- } else if (response.statusCode == 404) {
- return const Tuple2(
- false, "404 NOT FOUND - Pas de compte lié");
+ try {
+ final response = await http.delete(Uri.parse('$urlApi/user'),
+ headers: {'Authorization': token});
+ if (response.statusCode == 200) {
+ return const Tuple2(true, "Successful");
+ } else if (response.statusCode == 401) {
+ return const Tuple2(
+ false, "401 UNAUTHORIZED - Mauvais ou pas de token");
+ } else if (response.statusCode == 404) {
+ return const Tuple2(
+ false, "404 NOT FOUND - Pas de compte lié");
+ }
+ } on SocketException catch (_) {
+ return const Tuple2(false, "No connection");
}
return const Tuple2(false, "Fail");
}
@override
Future getFiles(String token) async {
- final response = await http.get(Uri.parse('$urlApi/user/files'),
- headers: {'Authorization': token});
+ try {
+ final response = await http.get(Uri.parse('$urlApi/user/files'),
+ headers: {'Authorization': token});
- if (response.statusCode == 200) {
- return Tuple2(true,
- (json.decode(response.body) as List).cast