Merge pull request 'offline' (#4) from offline into master
continuous-integration/drone/push Build is failing Details

Reviewed-on: #4
pull/5/head^2
remrem 1 year ago
commit ed3664d561

4
.gitignore vendored

@ -14,6 +14,10 @@
# Firebase
.firebase/
# ObjectBox
objectbox-model.json
objectbox.g.dart
# IntelliJ related
*.iml
*.ipr

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

@ -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<ListActivityWidget> {
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<void> onClick(ActivityOfUser activityObj) async {
if (!Provider.of<User>(context, listen: false)
.managerSelectedActivity
.fileNotSelected(activityObj.fileUuid)) {
@ -33,19 +40,20 @@ class _ListActivityWidget extends State<ListActivityWidget> {
}
Tuple2<bool, String> result =
await _utile.getContentActivity(context, activityObj);
await _utile.getContentActivity(context, activityObj, infoManager);
if (!result.item1) {
return;
}
// TODO: Hein?
Provider.of<User>(context, listen: false).removeActivity(activityObj);
Provider.of<User>(context, listen: false).insertActivity(0, activityObj);
}
void onDelete(ActivityOfUser activityObj) async {
if (await _utile.deleteFileOnBDD(
Provider.of<User>(context, listen: false).token,
activityObj.fileUuid)) {
// TODO: Understand :(
Future<void> onDelete(ActivityOfUser activityObj) async {
if (await api.deleteFile(Provider.of<User>(context, listen: false).token,
activityObj.fileUuid, infoManager)) {
if (!Provider.of<User>(context, listen: false)
.managerSelectedActivity
.fileNotSelected(activityObj.fileUuid)) {
@ -53,6 +61,11 @@ class _ListActivityWidget extends State<ListActivityWidget> {
.managerSelectedActivity
.removeSelectedActivity(activityObj.fileUuid);
}
if (!Helper.isPlatformWeb()) {
ActivitySaver actSaver = await ActivitySaver.create();
actSaver.deleteActivity(activityObj.fileUuid);
localDB.removeActivity(activityObj.fileUuid);
}
Provider.of<User>(context, listen: false).removeActivity(activityObj);
}
}
@ -65,41 +78,62 @@ class _ListActivityWidget extends State<ListActivityWidget> {
return Material(
color: Colors.transparent,
child: ListView.builder(
padding: EdgeInsets.zero,
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: Provider.of<User>(context, listen: true).listActivity.length,
itemBuilder: (context, index) {
ActivityOfUser activityObj =
Provider.of<User>(context, listen: true).listActivity[index];
Map<String, dynamic> 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<User>(context, listen: true).listActivity.length,
itemBuilder: (context, index) {
ActivityOfUser activityObj =
Provider.of<User>(context, listen: true).listActivity[index];
Map<String, dynamic> 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),
),
);
}
},
),
],
),
);
}

@ -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");
}

@ -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<ProfileSwitch> createState() => _ProfileSwitchState();
}
class _ProfileSwitchState extends State<ProfileSwitch> {
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);
});
}),
]))
]));
}
}

@ -1,10 +1,22 @@
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';
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;
Future<void> main() async {
// ObjectBox
WidgetsFlutterBinding.ensureInitialized();
localDB = await ObjectBox.create();
await localDB.init();
localDB.configBox.put(db.Config(0, true));
void main() {
runApp(ChangeNotifierProvider(
create: (context) => User(), child: const MyApp()));
}
@ -14,6 +26,26 @@ class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
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();
context.watch<User>().username = user.username;
context.watch<User>().email = user.email;
context.watch<User>().token = user.token;
context.watch<User>().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 +67,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,
);
}
}

@ -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<void> 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<ActivitySaver> create() async {
stdout.write("Activity Saver: Created\n");
final appDir = await getApplicationDocumentsDirectory();
return ActivitySaver._create(appDir);
}
}

@ -1,22 +1,105 @@
import 'dart:typed_data';
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 'package:crypto/crypto.dart';
import 'package:smartfit_app_mobile/main.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<bool> 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<void> init() async {
if (await isOnline()) {
stdout.write("(API) ");
api = RequestApi();
} else if (localDB.getSaveLocally()) {
stdout.write("(LOCAL) ");
api = RequestLocal();
} else {
stdout.write("(API OFFLINE) ");
api = RequestApi();
}
}
bool handleOffline(InfoMessage infoManager) {
if (api is RequestLocal) {
infoManager.displayMessage(noConnectionMessage, true);
return true;
}
return false;
}
// BOTH (ONLINE + OFFLINE)
Future<Tuple2> getUserInfo(String token) async {
await init();
Tuple2 res = await api.getInfoUser(token);
stdout.write("getUserInfo: ${res.item1}\n");
return res;
}
Future<Tuple2> getFile(
String token, String fileUuid, InfoMessage infoManager) async {
await init();
Tuple2 res = await api.getFile(token, fileUuid);
if (!res.item1) {
infoManager.displayMessage(noConnectionMessage, true);
}
Future<bool> modifyUserInfo(String infoToModify, String value, String token,
stdout.write("getFile: ${res.item1}\n");
return res;
}
Future<Tuple2> getFiles(String token, InfoMessage infoManager) async {
await init();
Tuple2 res = await api.getFiles(token);
if (!res.item1) {
infoManager.displayMessage(noConnectionMessage, true);
}
stdout.write("getFiles: ${res.item1}\n");
return res;
}
// ONLINE
Future<bool> 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<bool, String> 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 +117,84 @@ class ApiWrapper {
Future<Tuple2<bool, String>> 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<bool, String> res = await api.connexion(email, hash);
stdout.write("login: ${res.item1}\n");
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<Tuple2<bool, String>> deleteUser(
String token, InfoMessage infoManager) async {
await init();
if (handleOffline(infoManager)) return const Tuple2(false, "offline");
Tuple2<bool, String> res = await api.deleteUser(token);
stdout.write("deleteUser: ${res.item1}\n");
return res;
}
Future<Tuple2<bool, String>> createUser(String email, String hash,
String username, InfoMessage infoManager) async {
await init();
if (handleOffline(infoManager)) return const Tuple2(false, "offline");
Tuple2<bool, String> res = await api.postUser(email, hash, username);
stdout.write("createUser: ${res.item1}\n");
return res;
}
Future<Tuple2<bool, String>> uploadFile(
String token, File file, InfoMessage infoManager) async {
await init();
if (handleOffline(infoManager)) return const Tuple2(false, "offline");
Tuple2<bool, String> res = await api.uploadFile(token, file);
stdout.write("uploadFile: ${res.item1}\n");
return res;
}
Future<Tuple2<bool, String>> 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<bool, String> 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<bool> 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);
stdout.write("deleteFile: $res\n");
return res;
}
}

@ -15,11 +15,13 @@ abstract class IDataStrategy {
// Get Token validate
Future<Tuple2<bool, String>> connexion(String email, String hash);
// Get all files for user
// Get all files for user (LOCAL OK)
Future<Tuple2> getFiles(String token);
// Upload file on BDD
Future<Tuple2<bool, String>> uploadFile(String token, File file);
// Upload file as bytes
Future<Tuple2<bool, String>> 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<Tuple2> getFile(String token, String fileUuid);
// Delete one file on BDD
Future<Tuple2<bool, String>> deleteFile(String token, String fileUuid);
Future<bool> deleteFile(String token, String fileUuid);
// Get info on user (LOCAL OK)
Future<Tuple2> getInfoUser(String token);
/* -> Modification attribut
// Update email
Future<void> updateEmail(String token, String email);
// Update username
Future<void> updateUsername(String token, String username);
*/
// Update email, password, username
Future<Tuple2<bool, String>> modifAttribut(
String token, String nameAttribut, String newValue);
}

@ -19,85 +19,105 @@ class RequestApi implements IDataStrategy {
var request = http.Request('GET', url);
request.headers.addAll(<String, String>{'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<Tuple2<bool, String>> deleteFile(String token, String fileUuid) async {
final response = await http.delete(
Uri.parse('$urlApi/user/files/$fileUuid'),
headers: <String, String>{'Authorization': token});
Future<bool> deleteFile(String token, String fileUuid) async {
try {
final response = await http.delete(
Uri.parse('$urlApi/user/files/$fileUuid'),
headers: <String, String>{'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<Tuple2<bool, String>> deleteUser(String token) async {
final response = await http.delete(Uri.parse('$urlApi/user'),
headers: <String, String>{'Authorization': token});
if (response.statusCode == 200) {
return const Tuple2<bool, String>(true, "Successful");
} else if (response.statusCode == 401) {
return const Tuple2<bool, String>(
false, "401 UNAUTHORIZED - Mauvais ou pas de token");
} else if (response.statusCode == 404) {
return const Tuple2<bool, String>(
false, "404 NOT FOUND - Pas de compte lié");
try {
final response = await http.delete(Uri.parse('$urlApi/user'),
headers: <String, String>{'Authorization': token});
if (response.statusCode == 200) {
return const Tuple2<bool, String>(true, "Successful");
} else if (response.statusCode == 401) {
return const Tuple2<bool, String>(
false, "401 UNAUTHORIZED - Mauvais ou pas de token");
} else if (response.statusCode == 404) {
return const Tuple2<bool, String>(
false, "404 NOT FOUND - Pas de compte lié");
}
} on SocketException catch (_) {
return const Tuple2<bool, String>(false, "No connection");
}
return const Tuple2<bool, String>(false, "Fail");
}
@override
Future<Tuple2> getFiles(String token) async {
final response = await http.get(Uri.parse('$urlApi/user/files'),
headers: <String, String>{'Authorization': token});
try {
final response = await http.get(Uri.parse('$urlApi/user/files'),
headers: <String, String>{'Authorization': token});
if (response.statusCode == 200) {
return Tuple2(true,
(json.decode(response.body) as List).cast<Map<String, dynamic>>());
}
if (response.statusCode == 401) {
return const Tuple2(false, "401 - UNAUTHORIZED");
if (response.statusCode == 200) {
return Tuple2(true,
(json.decode(response.body) as List).cast<Map<String, dynamic>>());
}
if (response.statusCode == 401) {
return const Tuple2(false, "401 - UNAUTHORIZED");
}
} on SocketException catch (_) {
return const Tuple2(false, "No connection");
}
return const Tuple2(false, "Fail");
}
@override
Future<Tuple2<bool, String>> connexion(String email, String hash) async {
final response =
await http.get(Uri.parse('$urlApi/user/login/$email/$hash'));
if (response.statusCode == 200) {
Map<String, dynamic> json = jsonDecode(response.body);
return Tuple2<bool, String>(true, json['token'].toString());
}
if (response.statusCode == 401) {
return const Tuple2<bool, String>(false, "UNAUTHORIZED");
}
if (response.statusCode == 404) {
return const Tuple2<bool, String>(false, "Not found the email");
try {
final response =
await http.get(Uri.parse('$urlApi/user/login/$email/$hash'));
if (response.statusCode == 200) {
Map<String, dynamic> json = jsonDecode(response.body);
return Tuple2<bool, String>(true, json['token'].toString());
}
if (response.statusCode == 401) {
return const Tuple2<bool, String>(false, "UNAUTHORIZED");
}
if (response.statusCode == 404) {
return const Tuple2<bool, String>(false, "Not found the email");
}
} on SocketException catch (_) {
return const Tuple2(false, "No connection");
}
return const Tuple2(false, "Fail");
}
@ -107,19 +127,23 @@ class RequestApi implements IDataStrategy {
String email, String hash, String username) async {
var body = {"email": email, "hash": hash, "username": username};
var header = {"Content-Type": "application/json"};
final response = await http.post(Uri.parse('$urlApi/user'),
headers: header, body: jsonEncode(body));
try {
final response = await http.post(Uri.parse('$urlApi/user'),
headers: header, body: jsonEncode(body));
if (response.statusCode == 200) {
Map<String, dynamic> json = jsonDecode(response.body);
return Tuple2(true, json['token'].toString());
}
if (response.statusCode == 400) {
return const Tuple2(false, "400 BAD REQUEST - Json mal formaté");
}
if (response.statusCode == 409) {
return const Tuple2(
false, "409 CONFLICT - Déja un compte avec cet email");
if (response.statusCode == 200) {
Map<String, dynamic> json = jsonDecode(response.body);
return Tuple2(true, json['token'].toString());
}
if (response.statusCode == 400) {
return const Tuple2(false, "400 BAD REQUEST - Json mal formaté");
}
if (response.statusCode == 409) {
return const Tuple2(
false, "409 CONFLICT - Déja un compte avec cet email");
}
} on SocketException catch (_) {
return const Tuple2(false, "No connection");
}
return const Tuple2(false, "Fail");
}
@ -127,25 +151,28 @@ class RequestApi implements IDataStrategy {
@override
Future<Tuple2<bool, String>> modifAttribut(
String token, String nameAttribut, String newValue) async {
final response = await http.put(Uri.parse('$urlApi/user/$nameAttribut'),
headers: <String, String>{
'Authorization': token,
"Content-Type": "application/json"
},
body: jsonEncode(<String, String>{nameAttribut: newValue}));
if (response.statusCode == 200) {
//Map<String, dynamic> json = jsonDecode(response.body);
return const Tuple2(true, "200 - OK");
}
if (response.statusCode == 400) {
return const Tuple2(false, "400 - BAD REQUEST");
}
if (response.statusCode == 401) {
return const Tuple2(false, "400 - UNAUTHORIZED");
} else {
return const Tuple2(false, "Fail");
try {
final response = await http.put(Uri.parse('$urlApi/user/$nameAttribut'),
headers: <String, String>{
'Authorization': token,
"Content-Type": "application/json"
},
body: jsonEncode(<String, String>{nameAttribut: newValue}));
if (response.statusCode == 200) {
//Map<String, dynamic> json = jsonDecode(response.body);
return const Tuple2(true, "200 - OK");
}
if (response.statusCode == 400) {
return const Tuple2(false, "400 - BAD REQUEST");
}
if (response.statusCode == 401) {
return const Tuple2(false, "400 - UNAUTHORIZED");
}
} on SocketException catch (_) {
return const Tuple2(false, "No connection");
}
return const Tuple2(false, "Fail");
}
// -- Priviligié uploadFileByte -- //
@ -169,19 +196,23 @@ class RequestApi implements IDataStrategy {
request.fields["SmartFit_Category"] = categoryActivity;
request.fields["SmartFit_Date"] = dateActivity;
final response = await request.send();
try {
final response = await request.send();
if (response.statusCode == 200) {
return const Tuple2(true, "Successful");
}
if (response.statusCode == 400) {
return const Tuple2(false, "400 - BAD REQUEST");
}
if (response.statusCode == 401) {
return const Tuple2(false, "401 - UNAUTHORIZED");
}
if (response.statusCode == 409) {
return const Tuple2(false, "409 - CONFLICT");
if (response.statusCode == 200) {
return const Tuple2(true, "Successful");
}
if (response.statusCode == 400) {
return const Tuple2(false, "400 - BAD REQUEST");
}
if (response.statusCode == 401) {
return const Tuple2(false, "401 - UNAUTHORIZED");
}
if (response.statusCode == 409) {
return const Tuple2(false, "409 - CONFLICT");
}
} on SocketException catch (_) {
return const Tuple2(false, "No connection");
}
return const Tuple2(false, "Fail ");
}
@ -209,38 +240,45 @@ class RequestApi implements IDataStrategy {
request.fields["SmartFit_Date"] = date.toString();
request.fields["info"] = activityInfo.toJson();
final response = await request.send();
try {
final response = await request.send();
if (response.statusCode == 200) {
return const Tuple2(true, "Successful");
}
if (response.statusCode == 400) {
return const Tuple2(false, "400 - BAD REQUEST");
}
if (response.statusCode == 401) {
return const Tuple2(false, "401 - UNAUTHORIZED");
}
if (response.statusCode == 409) {
return const Tuple2(false, "409 - CONFLICT");
if (response.statusCode == 200) {
return const Tuple2(true, "Successful");
}
if (response.statusCode == 400) {
return const Tuple2(false, "400 - BAD REQUEST");
}
if (response.statusCode == 401) {
return const Tuple2(false, "401 - UNAUTHORIZED");
}
if (response.statusCode == 409) {
return const Tuple2(false, "409 - CONFLICT");
}
} on SocketException catch (_) {
return const Tuple2(false, "No connection");
}
return const Tuple2(false, "Fail ");
}
@override
Future<Tuple2> getInfoUser(String token) async {
final response = await http.get(Uri.parse('$urlApi/user/info'),
headers: <String, String>{'Authorization': token});
if (response.statusCode == 200) {
Map<String, dynamic> json = jsonDecode(response.body);
return Tuple2(true, json);
}
if (response.statusCode == 400) {
return const Tuple2(false, "400 - BAD REQUEST");
try {
final response = await http.get(Uri.parse('$urlApi/user/info'),
headers: <String, String>{'Authorization': token});
if (response.statusCode == 200) {
Map<String, dynamic> json = jsonDecode(response.body);
return Tuple2(true, json);
}
if (response.statusCode == 400) {
return const Tuple2(false, "400 - BAD REQUEST");
}
if (response.statusCode == 401) {
return const Tuple2(false, "401 - UNAUTHORIZED");
}
} on SocketException catch (_) {
return const Tuple2(false, "No connection");
}
if (response.statusCode == 401) {
return const Tuple2(false, "401 - UNAUTHORIZED");
}
return const Tuple2(false, "Fail ");
return const Tuple2(false, "Fail");
}
}

@ -0,0 +1,10 @@
import 'package:flutter/foundation.dart';
class Helper {
static bool isPlatformWeb() {
if (kIsWeb) {
return true;
}
return false;
}
}

@ -0,0 +1,33 @@
import 'package:objectbox/objectbox.dart';
@Entity()
class User {
@Id()
int id = 0;
String username;
String email;
String token;
User(this.id, this.username, this.email, this.token);
}
@Entity()
class Activity {
int id;
@Unique()
String uuid;
String filename;
String category;
String info;
Activity(this.id, this.uuid, this.filename, this.category, this.info);
}
@Entity()
class Config {
@Id()
int id = 0;
bool saveLocally;
Config(this.id, this.saveLocally);
}

@ -0,0 +1,126 @@
import 'dart:convert';
import 'dart:io';
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';
class ObjectBox {
late final Store store;
late final Box userBox;
late final Box activityBox;
late final Box configBox;
late final Directory applicationDocumentDir;
ObjectBox._create(this.store);
static Future<ObjectBox> create() async {
final docsDir = await getApplicationDocumentsDirectory();
final store = await openStore(directory: p.join(docsDir.path, "database"));
return ObjectBox._create(store);
}
init() async {
applicationDocumentDir = await getApplicationDocumentsDirectory();
userBox = store.box<User>();
activityBox = store.box<Activity>();
configBox = store.box<Config>();
}
// ===== 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(0, username, email, token));
}
// ===== Activity =====
void addActivity(Activity newActivity) {
try {
activityBox.put(newActivity);
} on ObjectBoxException {
print("Activity already exists");
} catch (e) {
print("Unknown exception");
}
}
// TODO: try catch
void removeActivity(String uuid) {
final Query query = activityBox.query(Activity_.uuid.equals(uuid)).build();
final Activity act = query.findFirst();
activityBox.remove(act.id);
}
String getActivityFilenameByUuid(String uuid) {
final Query query = activityBox.query(Activity_.uuid.equals(uuid)).build();
final Activity act = query.findFirst();
return act.filename;
}
List<Activity> getAllActivities() {
// TODO: Transform db.Activity to ActivityOfUser
throw Exception("Not implemented yet");
}
void removeAllActivities() {
activityBox.removeAll();
}
// ===== FIT Files =====
List<ActivityOfUser> loadActivities() {
List<dynamic> activityDBList = activityBox.getAll();
List<ActivityOfUser> userActivityList = List.empty(growable: true);
for (Activity act in activityDBList) {
ActivityInfo actInfo = ActivityInfo.fromJson(jsonDecode(act.info));
userActivityList
.add(ActivityOfUser(actInfo, act.category, act.uuid, act.filename));
}
return userActivityList;
}
// ===== Config =====
void setSaveLocally(bool saveLocally) {
Config config = configBox.get(1);
config.saveLocally = saveLocally;
configBox.put(config);
stdout.write("(Config) setSaveLocally: $saveLocally\n");
}
bool getSaveLocally() {
Config config = configBox.get(1);
stdout.write("(Config) getSaveLocally: ${config.saveLocally}\n");
return config.saveLocally;
}
}

@ -0,0 +1,88 @@
import 'dart:convert';
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 'dart:io';
import 'dart:typed_data';
import 'package:smartfit_app_mobile/main.dart';
class RequestLocal implements IDataStrategy {
@override
Future<Tuple2> getInfoUser(String token) async {
final User user = localDB.userBox.get(1);
Map<String, String> json = {"email": user.email, "username": user.username};
return Tuple2(true, jsonEncode(json));
}
// need to save file on request_api.upload() beforehand.
@override
Future<Tuple2> getFile(String token, String fileUuid) async {
ActivitySaver actSaver = await ActivitySaver.create();
Uint8List fileBytes = actSaver.getActivity(fileUuid);
return Tuple2(true, fileBytes);
}
@override
Future<Tuple2> getFiles(String token) async {
final List<dynamic> activities = localDB.activityBox.getAll();
List<Map<String, dynamic>> jsonList = List.empty(growable: true);
for (Activity act in activities) {
Map<String, dynamic> json = {
"uuid": act.uuid,
"filename": act.filename,
"category": act.category,
"info": act.info
};
jsonList.add(json);
}
return Tuple2(true, jsonEncode(activities));
}
@override
Future<Tuple2<bool, String>> modifAttribut(
String token, String nameAttribut, String newValue) async {
return const Tuple2(false, "not implemented");
}
@override
Future<Tuple2<bool, String>> postUser(
String email, String hash, String username) async {
return const Tuple2(false, "not implemented");
}
@override
Future<Tuple2<bool, String>> deleteUser(String token) async {
return const Tuple2(false, "not implemented");
}
@override
Future<Tuple2<bool, String>> connexion(String email, String hash) async {
return const Tuple2(false, "not implemented");
}
@override
Future<Tuple2<bool, String>> uploadFile(String token, File file) async {
return const Tuple2(false, "not implemented");
}
@override
Future<Tuple2<bool, String>> uploadFileByte(
String token,
Uint8List contentFile,
String nameFile,
String category,
DateTime date,
ActivityInfo activityInfo) async {
return const Tuple2(false, "not implemented");
}
@override
Future<bool> deleteFile(String token, String fileUuid) async {
throw Exception("Not Implemented");
}
}

@ -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';
@ -6,21 +11,21 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.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/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<Tuple2<bool, String>> getContentActivity(
BuildContext context, ActivityOfUser activityOfUser) async {
Tuple2 result = await _strategy.getFile(
Future<Tuple2<bool, String>> getContentActivity(BuildContext context,
ActivityOfUser activityOfUser, InfoMessage infoManager) async {
Tuple2 result = await api.getFile(
Provider.of<User>(context, listen: false).token,
activityOfUser.fileUuid);
activityOfUser.fileUuid,
infoManager);
if (result.item1 == false) {
return Tuple2(result.item1, result.item2);
}
@ -28,6 +33,17 @@ class ListActivityUtile {
activityOfUser.contentActivity =
List.from(_managerFile.convertByteIntoCSV(result.item2));
// TODO: Not sure this line as an utility
// localDB.saveActivityFile(activityOfUser.contentActivity);
// TODO: Check if file exists, right now it overwrites each time
// TODO: Make ActivitySaver member of the class
if (!Helper.isPlatformWeb() && localDB.getSaveLocally()) {
ActivitySaver actSaver = await ActivitySaver.create();
actSaver.saveActivity(result.item2,
localDB.getActivityFilenameByUuid(activityOfUser.fileUuid));
}
if (!Provider.of<User>(context, listen: false)
.managerSelectedActivity
.addSelectedActivity(activityOfUser)) {
@ -37,15 +53,15 @@ class ListActivityUtile {
}
Future<Tuple2<bool, String>> getFiles(
String token, BuildContext context) async {
String token, BuildContext context, InfoMessage infoManager) async {
bool notZero = false;
Tuple2 result = await _strategy
.getFiles(Provider.of<User>(context, listen: false).token);
Tuple2 result = await api.getFiles(
Provider.of<User>(context, listen: false).token, infoManager);
if (result.item1 == false) {
return Tuple2(result.item1, result.item2);
}
for (Map<String, dynamic> element in result.item2) {
for (var element in result.item2) {
if (!notZero) {
Provider.of<User>(context, listen: false).listActivity.clear();
notZero = true;
@ -56,75 +72,75 @@ 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"], jsonEncode(element["info"])));
}
return const Tuple2(true, "Yeah");
}
Future<Tuple2<bool, String>> _addFile(
Uint8List bytes, String filename, String token) async {
Future<Tuple2<bool, String>> addFile(Uint8List bytes, String filename,
String token, InfoMessage infoManager) async {
// -- Transormer le fit en CSV
Tuple4<bool, List<List<String>>, ActivityInfo, String> resultData =
_managerFile.convertBytesFitFileIntoCSVListAndGetInfo(bytes);
String csvString = const ListToCsvConverter().convert(resultData.item2);
Uint8List byteCSV = Uint8List.fromList(utf8.encode(csvString));
// --- Save Local
// --- Api
/*
ManagerFile x = ManagerFile();
await File("${await x.localPath}\\test.csv").writeAsString(csvString);
print("${await x.localPath}\\test.csv");*/
Tuple2<bool, String> result = await _strategy.uploadFileByte(
Tuple2<bool, String> result = await api.uploadFileByte(
token,
byteCSV,
filename,
resultData.item4,
resultData.item3.startTime,
resultData.item3);
// resultData.item4 == category
// resultData.item3 == ActivityInfo
resultData.item4, // category
resultData.item3.startTime, // activityInfo
resultData.item3,
infoManager);
if (result.item1 == false) {
return Tuple2(false, result.item2);
}
return const Tuple2(true, "Yeah");
}
Future<bool> deleteFileOnBDD(String token, String fileUuid) async {
Tuple2<bool, String> result = await _strategy.deleteFile(token, fileUuid);
if (!result.item1) {
return false;
// Save on local storage if plateform not browser
if (!Helper.isPlatformWeb() && localDB.getSaveLocally()) {
ActivitySaver actSaver = await ActivitySaver.create();
actSaver.saveActivity(byteCSV, filename);
}
return true;
return const Tuple2(true, "Yeah");
}
// --- Ne marche pas sous window !! Jsp linux (mettre en format mobile) -- //
void addFileWeb(Uint8List? bytes, String token, String filename,
BuildContext context) async {
// --- Ne marche pas sous windows !! Jsp linux (mettre en format mobile) -- //
Future<void> addFileWeb(Uint8List? bytes, String token, String filename,
BuildContext context, InfoMessage infoManager) async {
if (bytes == null) {
return;
}
Tuple2<bool, String> resultAdd = await _addFile(bytes, filename, token);
Tuple2<bool, String> resultAdd =
await addFile(bytes, filename, token, infoManager);
if (!resultAdd.item1) {
//print("Message error");
return;
}
Tuple2<bool, String> resultGet = await getFiles(token, context);
Tuple2<bool, String> resultGet =
await getFiles(token, context, infoManager);
if (!resultGet.item1) {
//print("Message error");
return;
}
}
Future<void> addFileMobile(
String path, String token, String filename, BuildContext context) async {
Tuple2<bool, String> resultAdd =
await _addFile(await File(path).readAsBytes(), filename, token);
Future<void> addFileMobile(String path, String token, String filename,
BuildContext context, InfoMessage infoManager) async {
Tuple2<bool, String> resultAdd = await addFile(
await File(path).readAsBytes(), filename, token, infoManager);
if (!resultAdd.item1) {
//print("Message error");
return;
}
Tuple2<bool, String> resultGet = await getFiles(token, context);
// TODO: What is that ?
Tuple2<bool, String> resultGet =
await getFiles(token, context, infoManager);
if (!resultGet.item1) {
//print("Message error");
return;

@ -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);
}
}

@ -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_widget.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 {
@ -15,6 +16,7 @@ class MobileListActivity extends StatefulWidget {
class _MobileListActivity extends State<MobileListActivity> {
final ListActivityUtile _utile = ListActivityUtile();
final InfoMessage infoManager = InfoMessage();
@override
Widget build(BuildContext context) {
@ -27,7 +29,7 @@ class _MobileListActivity extends State<MobileListActivity> {
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const SizedBox(height: 20),
Row(
@ -41,9 +43,13 @@ class _MobileListActivity extends State<MobileListActivity> {
fontWeight: FontWeight.w700),
),
TextButton(
onPressed: () => _utile.getFiles(
Provider.of<User>(context, listen: false).token,
context),
onPressed: () async {
await _utile.getFiles(
Provider.of<User>(context, listen: false).token,
context,
infoManager);
setState(() {});
},
child: Text("Get activity",
style: TextStyle(
color: TColor.gray,
@ -54,16 +60,18 @@ class _MobileListActivity extends State<MobileListActivity> {
FilePickerResult? result =
await FilePicker.platform.pickFiles();
if (result != null && result.files.isNotEmpty) {
// ignore: use_build_context_synchronously
_utile.addFileMobile(
await _utile.addFileMobile(
result.files.single.path!,
Provider.of<User>(context, listen: false).token,
result.files.first.name,
context);
context,
infoManager);
setState(() {});
} else {
// msg d'erreur
// User canceled the picker
}
setState(() {});
},
child: Text(
"Ajouter",
@ -75,6 +83,10 @@ class _MobileListActivity extends State<MobileListActivity> {
)
],
),
Visibility(
visible: infoManager.isVisible,
child: Text(infoManager.message,
style: TextStyle(color: infoManager.messageColor))),
Provider.of<User>(context, listen: true).listActivity.isEmpty
? Column(
crossAxisAlignment: CrossAxisAlignment.start,

@ -1,12 +1,10 @@
import 'package:flutter/material.dart';
import 'package:smartfit_app_mobile/common_widget/container/list/list_activity_widget.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/common_widget/container/list/list_activity_widget.dart';
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 {
@ -18,8 +16,8 @@ class WebListActivity extends StatefulWidget {
class _WebListActivityState extends State<WebListActivity> {
FilePickerResult? result;
IDataStrategy strategy = RequestApi();
final ListActivityUtile _utile = ListActivityUtile();
final InfoMessage infoManager = InfoMessage();
@override
Widget build(BuildContext context) {
@ -31,7 +29,7 @@ class _WebListActivityState extends State<WebListActivity> {
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const SizedBox(height: 20),
Row(
@ -45,9 +43,13 @@ class _WebListActivityState extends State<WebListActivity> {
fontWeight: FontWeight.w700),
),
TextButton(
onPressed: () => _utile.getFiles(
Provider.of<User>(context, listen: false).token,
context),
onPressed: () async {
await _utile.getFiles(
Provider.of<User>(context, listen: false).token,
context,
infoManager);
setState(() {});
},
child: Text("Get activity",
style: TextStyle(
color: TColor.gray,
@ -58,31 +60,17 @@ class _WebListActivityState extends State<WebListActivity> {
FilePickerResult? result =
await FilePicker.platform.pickFiles();
if (result != null && result.files.isNotEmpty) {
_utile.addFileWeb(
await _utile.addFileWeb(
result.files.first.bytes,
Provider.of<User>(context, listen: false).token,
result.files.first.name,
context);
context,
infoManager);
} else {
print("Picker");
// msg d'erreur
// User canceled the picker
}
/*
html.FileUploadInputElement uploadInput =
html.FileUploadInputElement();
uploadInput.click();
uploadInput.onChange.listen((e) {
final files = uploadInput.files;
if (files != null && files.isNotEmpty) {
addFileWeb(
files[0],
Provider.of<User>(context, listen: false)
.token); // Lecture du fichier sélectionné
}
});*/
},
child: Text(
"Ajouter",
@ -94,6 +82,10 @@ class _WebListActivityState extends State<WebListActivity> {
)
],
),
Visibility(
visible: infoManager.isVisible,
child: Text(infoManager.message,
style: TextStyle(color: infoManager.messageColor))),
Provider.of<User>(context, listen: true).listActivity.isEmpty
? Column(
crossAxisAlignment: CrossAxisAlignment.start,

@ -1,10 +1,11 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:smartfit_app_mobile/modele/utile/login_user.dart';
import 'package:smartfit_app_mobile/view/main_tab/main_tab_view.dart';
import 'package:smartfit_app_mobile/common/colo_extension.dart';
import 'package:smartfit_app_mobile/common_widget/button/round_button.dart';
import 'package:smartfit_app_mobile/common_widget/text_field/round_text_field.dart';
import 'package:smartfit_app_mobile/main.dart';
import 'package:smartfit_app_mobile/modele/utile/login_user.dart';
import 'package:smartfit_app_mobile/view/main_tab/main_tab_view.dart';
import 'package:tuple/tuple.dart';
class MobileLoginView extends StatefulWidget {
@ -164,7 +165,8 @@ class _MobileLoginView extends State<MobileLoginView> {
"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);
Navigator.push(
context,
MaterialPageRoute(

@ -228,59 +228,6 @@ class _MobileSignUpView extends State<MobileSignUpView> {
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(

@ -1,10 +1,11 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:smartfit_app_mobile/modele/utile/login_user.dart';
import 'package:smartfit_app_mobile/view/main_tab/main_tab_view.dart';
import 'package:smartfit_app_mobile/common/colo_extension.dart';
import 'package:smartfit_app_mobile/common_widget/button/round_button.dart';
import 'package:smartfit_app_mobile/common_widget/text_field/round_text_field.dart';
import 'package:smartfit_app_mobile/main.dart';
import 'package:smartfit_app_mobile/modele/utile/login_user.dart';
import 'package:smartfit_app_mobile/view/main_tab/main_tab_view.dart';
import 'package:tuple/tuple.dart';
class WebLoginView extends StatefulWidget {
@ -150,6 +151,7 @@ class _WebLoginView extends State<WebLoginView> {
RoundButton(
title: "Se connecter",
onPressed: () async {
// TODO: utiliser la vrai validation
if (!emailValidate || !passwordValidate) {
_printMsgError("Les champs renseigné ne sont pas valide");
return;
@ -168,6 +170,8 @@ class _WebLoginView extends State<WebLoginView> {
"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);
Navigator.push(
context,
MaterialPageRoute(

@ -1,3 +1,4 @@
import 'package:smartfit_app_mobile/common_widget/container/profile/profile_switch.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:smartfit_app_mobile/common/colo_extension.dart';
@ -8,11 +9,12 @@ import 'package:smartfit_app_mobile/common_widget/container/profile/profile_othe
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 bool offlineSave;
final List accountArr;
final List otherArr;
const ProfileViewAllPlatforme(
this.offlineSave, this.accountArr, this.otherArr,
{super.key});
@override
State<ProfileViewAllPlatforme> createState() => _ProfileViewAllPlatforme();
@ -54,6 +56,13 @@ class _ProfileViewAllPlatforme extends State<ProfileViewAllPlatforme> {
const SizedBox(
height: 25,
),
// 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"),
const SizedBox(
height: 25,
),
ProfileOther(widget.otherArr)
],
),

@ -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<MobileChangeEmailView> {
RoundButton(
title: "Confirmer",
onPressed: () async {
bool res = await api.modifyUserInfo(
bool res = await api.updateUserInfo(
'email',
controllerTextEmail.text,
Provider.of<User>(context, listen: false).token,
@ -118,6 +119,7 @@ class _MobileChangeEmailViewState extends State<MobileChangeEmailView> {
if (res) {
Provider.of<User>(context, listen: false).email =
controllerTextEmail.text;
localDB.setUserMail(controllerTextEmail.text);
}
setState(() {});
}),

@ -111,7 +111,7 @@ class _MobileChangePasswordViewState extends State<MobileChangePasswordView> {
if (res.item1) {
if (controllerNewPasswd.text ==
controllerNewPasswd2.text) {
await api.modifyUserInfo(
await api.updateUserInfo(
'password',
sha256
.convert(utf8

@ -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<MobileChangeUsernameView> {
RoundButton(
title: "Confirmer",
onPressed: () async {
bool res = await api.modifyUserInfo(
bool res = await api.updateUserInfo(
'username',
controllerTextUsername.text,
Provider.of<User>(context, listen: false).token,
@ -117,6 +118,7 @@ class _MobileChangeUsernameViewState extends State<MobileChangeUsernameView> {
if (res) {
Provider.of<User>(context, listen: false)
.username = controllerTextUsername.text;
localDB.setUserName(controllerTextUsername.text);
}
setState(() {});
}),

@ -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<WebChangeEmailView> {
RoundButton(
title: "Confirmer",
onPressed: () async {
bool res = await apiWrapper.modifyUserInfo(
bool res = await apiWrapper.updateUserInfo(
'email',
controllerTextEmail.text,
Provider.of<User>(context, listen: false).token,
@ -116,6 +117,7 @@ class _WebChangeEmailViewState extends State<WebChangeEmailView> {
if (res) {
Provider.of<User>(context, listen: false).email =
controllerTextEmail.text;
localDB.setUserMail(controllerTextEmail.text);
}
setState(() {});
}),

@ -114,7 +114,7 @@ class _WebChangePasswordViewState extends State<WebChangePasswordView> {
if (res.item1) {
if (controllerNewPasswd.text ==
controllerNewPasswd2.text) {
await api.modifyUserInfo(
await api.updateUserInfo(
'password',
sha256
.convert(utf8

@ -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<WebChangeUsernameView> {
RoundButton(
title: "Confirmer",
onPressed: () async {
bool res = await api.modifyUserInfo(
bool res = await api.updateUserInfo(
'username',
controllerTextUsername.text,
Provider.of<User>(context, listen: false).token,
@ -118,6 +119,7 @@ class _WebChangeUsernameViewState extends State<WebChangeUsernameView> {
if (res) {
Provider.of<User>(context, listen: false)
.username = controllerTextUsername.text;
localDB.setUserName(controllerTextUsername.text);
}
setState(() {});
}),

@ -56,6 +56,10 @@ dependencies:
tuple: ^2.0.2
crypto: ^3.0.3
responsive_builder: ^0.7.0
universal_html: ^2.2.4
objectbox: ^2.3.1
objectbox_flutter_libs: any
path: ^1.8.3
flutter_map: ^5.0.0
latlong2: ^0.9.0
units_converter: ^2.1.1
@ -70,6 +74,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

Loading…
Cancel
Save