Merge branch 'master' into othmane6

othmane6
Othmane BENJELLOUN 1 year ago
commit 7fa743edc6

@ -1,5 +1,5 @@
# SmartFit Web and Mobile!
TODO: Description
TODO: Description + badge
## Getting Started

@ -1,6 +1,6 @@
import 'package:smartfit_app_mobile/main.dart';
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';
@ -61,7 +61,7 @@ class _ListActivityWidget extends State<ListActivityWidget> {
.managerSelectedActivity
.removeSelectedActivity(activityObj.fileUuid);
}
if (!Helper.isPlatformWeb()) {
if (!Helper.isPlatformWeb() && localDB.getSaveLocally()) {
ActivitySaver actSaver = await ActivitySaver.create();
actSaver.deleteActivity(activityObj.fileUuid);
localDB.removeActivity(activityObj.fileUuid);

@ -267,7 +267,8 @@ class RequestApi implements IDataStrategy {
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);
Map<String,dynamic> json = jsonDecode(response.body);
return Tuple2(true, json);
}
if (response.statusCode == 400) {
@ -285,7 +286,8 @@ class RequestApi implements IDataStrategy {
@override
Future<Tuple2> getModeleAI(String token, String category) async {
try {
final response = await http.post(Uri.parse('$urlApi/user/IA/$category'));
final response = await http.get(Uri.parse('$urlApi/user/ai/$category'),
headers: <String, String>{'Authorization': token});
if (response.statusCode == 200) {
Map<String, dynamic> json = jsonDecode(response.body);

@ -2,7 +2,11 @@ class Convertisseur {
// Mettre que des trucs static
static double secondeIntoMinute(double seconde) {
return seconde / 60;
return (seconde / 60);
}
static double milisecondeIntoMinute(double miliseconde) {
return (miliseconde / 60000);
}
static double msIntoKmh(double metreSeconde) {

@ -100,25 +100,20 @@ class User extends ChangeNotifier {
Tuple2 result = await wrapper.getModeleAI(token, category, infoManager);
if (!result.item1) return Tuple2(false, ActivityInfo());
// Appel pour avoir le model
//String jsonString =
// '{"coef": [270.63861280635473, 74.69699263779908, 1.9946527172333637, 0.03215810401413792, 0.3256805192289063], "intercept": [-335635.9890148213, -91874.0527070619, -2065.450392327813, -38.79838022998388, -291.590235396687]}';
Map<String, dynamic> jsonMap = json.decode(result.item2);
String model = result.item2["model"];
Map<String, dynamic> jsonMap = json.decode(model);
// Transformer la date
int dateMilli = date.millisecondsSinceEpoch;
ActivityInfo activityInfo = ActivityInfo();
activityInfo.distance =
jsonMap["coef"][0] * dateMilli + jsonMap["intercept"][0];
activityInfo.bpmAvg =
(jsonMap["coef"][0] * dateMilli + jsonMap["intercept"][0]).toInt();
activityInfo.timeOfActivity =
jsonMap["coef"][1] * dateMilli + jsonMap["intercept"][1];
activityInfo.denivelePositif =
jsonMap["coef"][2] * dateMilli + jsonMap["intercept"][2];
activityInfo.vitesseAvg =
jsonMap["coef"][2] * dateMilli + jsonMap["intercept"][2];
activityInfo.distance =
jsonMap["coef"][3] * dateMilli + jsonMap["intercept"][3];
activityInfo.bpmAvg =
jsonMap["coef"][4] * dateMilli + jsonMap["intercept"][4];
return Tuple2(true, activityInfo);
}

@ -20,9 +20,11 @@ class HomeViewUtil {
.getXWithTime(managerFile.fieldAltitude);
List<FlSpot> bpmSecondes2 = List.from(bpmSecondes);
return DataHomeView(normaliserPremierElement(bpmSecondes), normaliserPremierElement(normaliserDeuxiemeElement(bpmSecondes2)),
normaliserPremierElement(normaliserDeuxiemeElement(vitesseSecondes)), normaliserPremierElement(altitudeSeconde));
return DataHomeView(
normaliserPremierElement(bpmSecondes),
normaliserPremierElement(normaliserDeuxiemeElement(bpmSecondes2)),
normaliserPremierElement(normaliserDeuxiemeElement(vitesseSecondes)),
normaliserPremierElement(altitudeSeconde));
}
List<FlSpot> normaliserDeuxiemeElement(List<FlSpot> liste) {
@ -41,21 +43,21 @@ class HomeViewUtil {
}
return liste;
}
List<FlSpot> normaliserPremierElement(List<FlSpot> liste) {
// Trouver le plus grand élément dans le premier élément de chaque FlSpot
double maxElement = 0.0;
for (var spot in liste) {
if (spot.x > maxElement) {
maxElement = spot.x;
// Trouver le plus grand élément dans le premier élément de chaque FlSpot
double maxElement = 0.0;
for (var spot in liste) {
if (spot.x > maxElement) {
maxElement = spot.x;
}
}
// Calculer le facteur de normalisation
double normalisationFactor = maxElement != 0.0 ? 100 / maxElement : 1.0;
// Mettre à jour tous les premiers éléments de la liste
for (int i = 0; i < liste.length; i++) {
liste[i] = FlSpot(liste[i].x * normalisationFactor, liste[i].y);
}
return liste;
}
// Calculer le facteur de normalisation
double normalisationFactor = maxElement != 0.0 ? 100 / maxElement : 1.0;
// Mettre à jour tous les premiers éléments de la liste
for (int i = 0; i < liste.length; i++) {
liste[i] = FlSpot(liste[i].x * normalisationFactor, liste[i].y);
}
return liste;
}
}

@ -5,7 +5,6 @@ import 'package:smartfit_app_mobile/modele/activity_saver.dart';
import 'package:smartfit_app_mobile/modele/helper.dart';
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:csv/csv.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
@ -91,6 +90,9 @@ class ListActivityUtile {
String csvString = const ListToCsvConverter().convert(resultData.item2);
Uint8List byteCSV = Uint8List.fromList(utf8.encode(csvString));
File x = await File("${await _managerFile.localPath}\\what")
.writeAsString(csvString);
Tuple2<bool, String> result = await api.uploadFileByte(
token,
byteCSV,

@ -29,6 +29,7 @@ class _MobileHomeView extends State<MobileHomeView> {
context.watch<User>().managerSelectedActivity;
data = HomeViewUtil().initData(context);
// -- BPM -- //
data.maxBPM =
managerSelectedActivity.activitySelected.first.activityInfo.bpmMax;
@ -36,7 +37,6 @@ class _MobileHomeView extends State<MobileHomeView> {
managerSelectedActivity.activitySelected.first.activityInfo.bpmMin;
int avgBpm =
managerSelectedActivity.activitySelected.first.activityInfo.bpmAvg;
// -- Altitude -- //
double minAltitude =
managerSelectedActivity.activitySelected.first.activityInfo.altitudeMin;
@ -48,12 +48,12 @@ class _MobileHomeView extends State<MobileHomeView> {
double maxSpeed = managerSelectedActivity.getMaxSpeedAllActivitySelected();
double avgSpeed = managerSelectedActivity.getAvgSpeedAllActivitySelected();
double minSpeed = managerSelectedActivity.getMinSpeedAllActivitySelected();
data.maxSpeed = maxSpeed;
data.time = context
.watch<User>()
.managerSelectedActivity
.getTimeAllActivitySelected();
return Scaffold(
backgroundColor: TColor.white,
body: SingleChildScrollView(

@ -5,6 +5,7 @@ import 'package:smartfit_app_mobile/common/colo_extension.dart';
import 'package:smartfit_app_mobile/common_widget/button/round_button.dart';
import 'package:smartfit_app_mobile/common_widget/container/workout_row/workout_row.dart';
import 'package:smartfit_app_mobile/modele/activity_info/activity_info.dart';
import 'package:smartfit_app_mobile/modele/convertisseur.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';
@ -45,14 +46,15 @@ class _PredictionState extends State<Prediction> {
@override
Widget build(BuildContext context) {
var media = MediaQuery.of(context).size;
List<String> listCategory = [_managerFile.marche, _managerFile.velo];
void prediction() async {
InfoMessage tmp = InfoMessage();
setState(() {
lastWorkoutArr[0]["value"] = "null";
});
/*
if (selectedCategory != _managerFile.marche ||
selectedCategory != _managerFile.velo) return;*/
Tuple2<bool, ActivityInfo> resultat =
await Provider.of<User>(context, listen: false)
.predictActivity(DateTime.now(), selectedCategory, tmp);
@ -154,7 +156,6 @@ class _PredictionState extends State<Prediction> {
title: "Valider",
onPressed: () async {
prediction();
setState(() {});
}),
const SizedBox(height: 20),
ListView.builder(
@ -163,7 +164,7 @@ class _PredictionState extends State<Prediction> {
shrinkWrap: true,
itemCount: lastWorkoutArr.length,
itemBuilder: (context, index) {
var wObj = lastWorkoutArr[index] as Map<String, dynamic> ?? {};
var wObj = lastWorkoutArr[index];
return InkWell(
child: WorkoutRow(wObj: wObj),
);

@ -7,7 +7,11 @@ import 'package:smartfit_app_mobile/common_widget/container/profile/profile_comp
import 'package:smartfit_app_mobile/common_widget/container/profile/profile_entete.dart';
import 'package:smartfit_app_mobile/common_widget/container/profile/profile_info_user.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';
import 'package:smartfit_app_mobile/modele/utile/info_message.dart';
import 'package:smartfit_app_mobile/view/login/signup_view.dart';
import 'package:tuple/tuple.dart';
class ProfileViewAllPlatforme extends StatefulWidget {
final bool offlineSave;
@ -26,7 +30,32 @@ class _ProfileViewAllPlatforme extends State<ProfileViewAllPlatforme> {
@override
Widget build(BuildContext context) {
ApiWrapper wrapper = ApiWrapper();
String username = context.watch<User>().username;
InfoMessage infoManager = InfoMessage();
void logOff() {
// Appel ici pour logOff
/*
if (!result.item1) {
// Affiché erreur
} else {
Navigator.push(context,
MaterialPageRoute(builder: (context) => const LoginView()));
}*/
}
void deleteUser() async {
// Ne marche pas !!
Tuple2 result = await wrapper.deleteUser(
Provider.of<User>(context, listen: false).token, infoManager);
if (!result.item1) {
// Affiché erreur
} else {
Navigator.push(context,
MaterialPageRoute(builder: (context) => const SignUpView()));
}
}
return Scaffold(
appBar: AppBar(
@ -59,8 +88,6 @@ 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
Visibility(
visible: isNative,
child: const Column(
@ -72,7 +99,39 @@ class _ProfileViewAllPlatforme extends State<ProfileViewAllPlatforme> {
)
],
)),
ProfileOther(widget.otherArr)
ProfileOther(widget.otherArr),
const SizedBox(
height: 25,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextButton(
style: TextButton.styleFrom(
backgroundColor: TColor.primaryColor1,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8))),
onPressed: logOff,
child: const Text('Déconnexion',
style: TextStyle(color: Colors.black)),
),
const SizedBox(
width: 25,
),
TextButton(
style: TextButton.styleFrom(
backgroundColor: TColor.primaryColor1,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8))),
onPressed: deleteUser,
child: const Text('Supprimer son compte',
style: TextStyle(color: Colors.black)),
),
],
),
const SizedBox(
height: 25,
)
],
),
),

@ -5,17 +5,25 @@
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:smartfit_app_mobile/main.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/api_wrapper.dart';
import 'package:smartfit_app_mobile/modele/api/request_api.dart';
import 'package:smartfit_app_mobile/modele/user.dart';
import 'package:smartfit_app_mobile/modele/utile/signup_user.dart';
import 'package:tuple/tuple.dart';
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
testWidgets('Test login', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(const MyApp());
//await tester.pumpWidget(const MyApp());
// Verify that our counter starts at 0.
//expect(find.text('Se connecter'), findsOneWidget);
/*
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
@ -25,6 +33,40 @@ void main() {
// Verify that our counter has incremented.
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
expect(find.text('1'), findsOneWidget);*/
});
// Ce n'est pas possible de faire des test http =>
//To test code that needs an HttpClient, provide your own HttpClient
//implementation to the code under test, so that your test can
//consistently provide a testable response to the code under test.
/*
test("Unit Test -- Create and delete User", () async {
final SignUp utilSignUp = SignUp();
final RequestApi requestApi = RequestApi();
Tuple2 result =
await utilSignUp.createUser("test@gmail.com", "test", "test");
expect(result.item1, true);
Tuple2 delete = await requestApi.deleteUser(result.item2);
expect(delete.item1, true);
});*/
test("User", () {
User user = User();
ActivityOfUser activityOfUser =
ActivityOfUser(ActivityInfo(), "CATEGORIE", "0000", "NAMEFILE");
expect(user.listActivity.length, 0);
user.addActivity(activityOfUser);
expect(user.listActivity.length, 1);
user.removeActivity(activityOfUser);
expect(user.listActivity.length, 0);
});
}

Loading…
Cancel
Save