Compare commits

..

No commits in common. 'master' and 'offline' have entirely different histories.

@ -19,6 +19,10 @@ steps:
- dart run build_runner clean - dart run build_runner clean
- dart run build_runner build --delete-conflicting-outputs - dart run build_runner build --delete-conflicting-outputs
- flutter build apk - 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
- curl -F "file=@$sfm_apk" https://anonfiles.me/api/v1/upload > upload.json
- cat upload.json | cut -d '"' -f 12
- name: build-web - name: build-web
image: ghcr.io/cirruslabs/flutter:3.16.3 image: ghcr.io/cirruslabs/flutter:3.16.3

@ -1,38 +0,0 @@
name: Flutter CI
on:
push:
branches: [ master ]
jobs:
build-apk-web-sonarqube:
runs-on: ubuntu-latest
container: ghcr.io/cirruslabs/flutter:3.16.4
steps:
- uses: actions/checkout@v3
- name: Build flutter apk
run: |
flutter clean
flutter pub cache repair
flutter pub get
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
curl -F "file=@$sfm_apk" https://anonfiles.me/api/v1/upload > upload.json
cat upload.json | cut -d '"' -f 12
- name: Build flutter web
run: |
flutter build web --web-renderer canvaskit
curl -sL https://firebase.tools | bash
- name: Code analysis
run: |
export SONAR_SCANNER_VERSION=5.0.1.3006
export SONAR_SCANNER_HOME=$HOME/.sonar/sonar-scanner-$SONAR_SCANNER_VERSION-linux
curl --create-dirs -sSLo $HOME/.sonar/sonar-scanner.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-$SONAR_SCANNER_VERSION-linux.zip
unzip -o $HOME/.sonar/sonar-scanner.zip -d $HOME/.sonar/
export PATH=$SONAR_SCANNER_HOME/bin:$PATH
export SONAR_SCANNER_OPTS="-server"

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

@ -12,7 +12,7 @@ class VolumesList extends StatelessWidget {
// TODO: True message with variables and context aware // TODO: True message with variables and context aware
if (volume["nbActivity"] == 0) { if (volume["nbActivity"] == 0) {
return const Text("No activity the last x days/month/year"); return const Text("Aucune activité ces x jours/mois/années");
} }
return SingleChildScrollView( return SingleChildScrollView(
@ -21,32 +21,32 @@ class VolumesList extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
ContainerStatsActivities(volume["nbActivity"].toString(), ContainerStatsActivities(volume["nbActivity"].toString(),
"Number of activities", Icons.numbers), "Nombre Activitée(s)", Icons.numbers),
SizedBox( SizedBox(
width: media.width * 0.03, width: media.width * 0.03,
), ),
ContainerStatsActivities( ContainerStatsActivities(
"${Convertisseur.secondeIntoMinute(volume["durationActiviy"]).toStringAsFixed(0)} min", "${Convertisseur.secondeIntoMinute(volume["durationActiviy"]).toStringAsFixed(2)} m",
"Total time", "Temps Total",
Icons.timer), Icons.timer),
SizedBox( SizedBox(
width: media.width * 0.03, width: media.width * 0.03,
), ),
ContainerStatsActivities( ContainerStatsActivities(
volume["bpmAvg"].toString(), "Average bpm", Icons.favorite), volume["bpmAvg"].toString(), "Bpm Moyens", Icons.favorite),
SizedBox( SizedBox(
width: media.width * 0.03, width: media.width * 0.03,
), ),
ContainerStatsActivities( ContainerStatsActivities(
" ${Convertisseur.msIntoKmh(volume["speedAvg"]).toStringAsFixed(2)} km/h", " ${Convertisseur.msIntoKmh(volume["speedAvg"]).toStringAsFixed(2)} km/h",
"Average speed", "Vitesse Moyenne",
Icons.bolt), Icons.bolt),
SizedBox( SizedBox(
width: media.width * 0.03, width: media.width * 0.03,
), ),
ContainerStatsActivities( ContainerStatsActivities(
"${volume["denivelePositif"].toStringAsFixed(2)} m", "${volume["denivelePositif"].toStringAsFixed(2)} m",
"Positive height difference", "Dénivelé Positif",
Icons.hiking), Icons.hiking),
], ],
), ),

@ -38,7 +38,7 @@ class MobileLigneContainerStats extends StatelessWidget {
child: Row( child: Row(
children: [ children: [
const Text( const Text(
'Stats', 'Statistiques',
style: TextStyle( style: TextStyle(
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w800, fontWeight: FontWeight.w800,

@ -22,7 +22,7 @@ class ProfileCompte extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"Account", "Compte",
style: TextStyle( style: TextStyle(
color: TColor.black, color: TColor.black,
fontSize: 16, fontSize: 16,

@ -35,7 +35,7 @@ class ProfileEntete extends StatelessWidget {
), ),
), ),
Text( Text(
"Running", "Course à pied",
style: TextStyle( style: TextStyle(
color: TColor.gray, color: TColor.gray,
fontSize: 12, fontSize: 12,

@ -13,7 +13,7 @@ class ProfileInfoUser extends StatelessWidget {
Expanded( Expanded(
child: TitleSubtitleCell( child: TitleSubtitleCell(
title: context.watch<User>().listActivity.length.toString(), title: context.watch<User>().listActivity.length.toString(),
subtitle: "Number of activities", subtitle: "Nombre d'activité",
), ),
), ),
const SizedBox( const SizedBox(
@ -21,11 +21,8 @@ class ProfileInfoUser extends StatelessWidget {
), ),
Expanded( Expanded(
child: TitleSubtitleCell( child: TitleSubtitleCell(
title: context title: context.watch<User>().getTotalTimeAllActivity().toStringAsFixed(2),
.watch<User>() subtitle: "Temps en activité",
.getTotalTimeAllActivity()
.toStringAsFixed(2),
subtitle: "Total activity time",
), ),
), ),
const SizedBox( const SizedBox(
@ -35,7 +32,7 @@ class ProfileInfoUser extends StatelessWidget {
child: TitleSubtitleCell( child: TitleSubtitleCell(
title: title:
"${context.watch<User>().getTotalDenivelePositifAllActivity().toStringAsFixed(2)} + m", "${context.watch<User>().getTotalDenivelePositifAllActivity().toStringAsFixed(2)} + m",
subtitle: "Total positive height difference", subtitle: "Total dénivelé positif",
), ),
), ),
const SizedBox( const SizedBox(
@ -45,7 +42,7 @@ class ProfileInfoUser extends StatelessWidget {
child: TitleSubtitleCell( child: TitleSubtitleCell(
title: title:
"${context.watch<User>().getTotalDeniveleNegatifAllActivity().toStringAsFixed(2)} - m", "${context.watch<User>().getTotalDeniveleNegatifAllActivity().toStringAsFixed(2)} - m",
subtitle: "Total negative height difference", subtitle: "Total dénivelé négatif",
), ),
), ),
], ],

@ -21,7 +21,7 @@ class ProfileOther extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"Others", "Autre",
style: TextStyle( style: TextStyle(
color: TColor.black, color: TColor.black,
fontSize: 16, fontSize: 16,

@ -37,7 +37,7 @@ class WebLigneContainerStats extends StatelessWidget {
child: Column( child: Column(
children: [ children: [
const Text( const Text(
'Stats', 'Statistiques',
style: TextStyle( style: TextStyle(
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w800, fontWeight: FontWeight.w800,

@ -27,33 +27,32 @@ class WorkoutRow extends StatelessWidget {
fit: BoxFit.cover, fit: BoxFit.cover,
), ),
), ),
const SizedBox(
width: 15, const SizedBox(width: 15,),
),
Expanded( Expanded(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
wObj["name"].toString(), wObj["name"].toString(),
style: TextStyle( style: TextStyle(
color: TColor.black, color: TColor.black,
fontSize: 15, fontSize: 15,
fontWeight: FontWeight.bold), fontWeight: FontWeight.bold),
), ),
Text( Text(
wObj["value"].toString(), "${ wObj["value"].toString()}",
style: TextStyle( style: TextStyle(
color: TColor.gray, color: TColor.gray,
fontSize: 12, fontSize: 12,),
),
),
const SizedBox(
height: 4,
), ),
const SizedBox(height: 4,),
], ],
)), )),
], ],
)); ));
} }
} }

@ -75,7 +75,7 @@ class WorkoutRowGeneric extends StatelessWidget {
), ),
), ),
Text( Text(
"Time : ${Convertisseur.secondeIntoMinute(wObj["time"]).toStringAsFixed(2)} m", "Temps : ${Convertisseur.secondeIntoMinute(wObj["time"]).toStringAsFixed(2)} m",
style: TextStyle( style: TextStyle(
color: TColor.black, color: TColor.black,
fontSize: 12, fontSize: 12,

@ -75,14 +75,14 @@ class WorkoutRowWalking extends StatelessWidget {
), ),
), ),
Text( Text(
"Time : ${Convertisseur.secondeIntoMinute(wObj["time"]).toStringAsFixed(0)} minutes", "Temps : ${Convertisseur.secondeIntoMinute(wObj["time"]).toStringAsFixed(2)} m",
style: TextStyle( style: TextStyle(
color: TColor.black, color: TColor.black,
fontSize: 12, fontSize: 12,
), ),
), ),
Text( Text(
"Average speed : ${Convertisseur.msIntoKmh(wObj["VitesseAvg"]).toStringAsFixed(2)} km/h", "Vitesse moyenne : ${Convertisseur.msIntoKmh(wObj["VitesseAvg"]).toStringAsFixed(2)} km/h",
style: TextStyle( style: TextStyle(
color: TColor.black, color: TColor.black,
fontSize: 12, fontSize: 12,

@ -36,8 +36,75 @@ class _MobileGraphBpmAndSpeedByTime
width: double.maxFinite, width: double.maxFinite,
child: LineChart( child: LineChart(
LineChartData( LineChartData(
showingTooltipIndicators:
widget.func.showingTooltipOnSpots.map((index) {
return ShowingTooltipIndicators([
LineBarSpot(
widget.func.tooltipsOnBar,
widget.func.lineBarsData.indexOf(widget.func.tooltipsOnBar),
widget.func.tooltipsOnBar.spots[index],
),
]);
}).toList(),
lineTouchData: LineTouchData(
enabled: true,
handleBuiltInTouches: false,
touchCallback: (FlTouchEvent event, LineTouchResponse? response) {
if (response == null || response.lineBarSpots == null) {
return;
}
if (event is FlTapUpEvent) {
final spotIndex = response.lineBarSpots!.first.spotIndex;
widget.func.showingTooltipOnSpots.clear();
setState(() {
widget.func.showingTooltipOnSpots.add(spotIndex);
});
}
},
mouseCursorResolver:
(FlTouchEvent event, LineTouchResponse? response) {
if (response == null || response.lineBarSpots == null) {
return SystemMouseCursors.basic;
}
return SystemMouseCursors.click;
},
getTouchedSpotIndicator:
(LineChartBarData barData, List<int> spotIndexes) {
return spotIndexes.map((index) {
return TouchedSpotIndicatorData(
const FlLine(
color: Colors.transparent,
),
FlDotData(
show: true,
getDotPainter: (spot, percent, barData, index) =>
FlDotCirclePainter(
radius: 3,
color: Colors.white,
strokeWidth: 3,
strokeColor: TColor.secondaryColor1,
),
),
);
}).toList();
},
touchTooltipData: LineTouchTooltipData(
tooltipBgColor: TColor.secondaryColor1,
tooltipRoundedRadius: 20,
getTooltipItems: (List<LineBarSpot> lineBarsSpot) {
return lineBarsSpot.map((lineBarSpot) {
return LineTooltipItem(
"Seconde ${lineBarSpot.x.toInt() / 10} ",
const TextStyle(
color: Colors.white,
fontSize: 10,
fontWeight: FontWeight.bold,
),
);
}).toList();
},
),
),
lineBarsData: widget.func.lineBarsData1, lineBarsData: widget.func.lineBarsData1,
minY: 0, minY: 0,
maxY: 110, maxY: 110,
@ -46,7 +113,7 @@ class _MobileGraphBpmAndSpeedByTime
leftTitles: AxisTitles( leftTitles: AxisTitles(
sideTitles: widget.func.leftTitles, sideTitles: widget.func.leftTitles,
), ),
topTitles: const AxisTitles(), topTitles: const AxisTitles(),
bottomTitles: AxisTitles( bottomTitles: AxisTitles(
sideTitles: widget.func.bottomTitles, sideTitles: widget.func.bottomTitles,
), ),

@ -33,7 +33,75 @@ class _WebGraphBpmAndSpeedByTime extends State<WebGraphBpmAndSpeedByTime> {
width: widget.media.width * 0.35, width: widget.media.width * 0.35,
child: LineChart( child: LineChart(
LineChartData( LineChartData(
showingTooltipIndicators:
widget.func.showingTooltipOnSpots.map((index) {
return ShowingTooltipIndicators([
LineBarSpot(
widget.func.tooltipsOnBar,
widget.func.lineBarsData.indexOf(widget.func.tooltipsOnBar),
widget.func.tooltipsOnBar.spots[index],
),
]);
}).toList(),
lineTouchData: LineTouchData(
enabled: true,
handleBuiltInTouches: false,
touchCallback: (FlTouchEvent event, LineTouchResponse? response) {
if (response == null || response.lineBarSpots == null) {
return;
}
if (event is FlTapUpEvent) {
final spotIndex = response.lineBarSpots!.first.spotIndex;
widget.func.showingTooltipOnSpots.clear();
setState(() {
widget.func.showingTooltipOnSpots.add(spotIndex);
});
}
},
mouseCursorResolver:
(FlTouchEvent event, LineTouchResponse? response) {
if (response == null || response.lineBarSpots == null) {
return SystemMouseCursors.basic;
}
return SystemMouseCursors.click;
},
getTouchedSpotIndicator:
(LineChartBarData barData, List<int> spotIndexes) {
return spotIndexes.map((index) {
return TouchedSpotIndicatorData(
const FlLine(
color: Colors.transparent,
),
FlDotData(
show: true,
getDotPainter: (spot, percent, barData, index) =>
FlDotCirclePainter(
radius: 3,
color: Colors.white,
strokeWidth: 3,
strokeColor: TColor.secondaryColor1,
),
),
);
}).toList();
},
touchTooltipData: LineTouchTooltipData(
tooltipBgColor: TColor.secondaryColor1,
tooltipRoundedRadius: 20,
getTooltipItems: (List<LineBarSpot> lineBarsSpot) {
return lineBarsSpot.map((lineBarSpot) {
return LineTooltipItem(
"Seconde ${lineBarSpot.x.toInt() / 10} ",
const TextStyle(
color: Colors.white,
fontSize: 10,
fontWeight: FontWeight.bold,
),
);
}).toList();
},
),
),
lineBarsData: widget.func.lineBarsData1, lineBarsData: widget.func.lineBarsData1,
minY: -10, minY: -10,
maxY: 110, maxY: 110,

@ -16,7 +16,7 @@ class EnteteHomeView extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"Welcome,", "Bienvenue,",
style: TextStyle(color: TColor.gray, fontSize: 12), style: TextStyle(color: TColor.gray, fontSize: 12),
), ),
Text( Text(

@ -1,6 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:smartfit_app_mobile/modele/convertisseur.dart';
import 'package:smartfit_app_mobile/modele/user.dart'; import 'package:smartfit_app_mobile/modele/user.dart';
import 'package:smartfit_app_mobile/common/colo_extension.dart'; import 'package:smartfit_app_mobile/common/colo_extension.dart';
@ -20,11 +19,10 @@ class Stats extends StatelessWidget {
.activityInfo .activityInfo
.bpmAvg .bpmAvg
.toString(); .toString();
String time = Convertisseur.secondeIntoMinute( String time = Provider.of<User>(context, listen: false)
Provider.of<User>(context, listen: false) .managerSelectedActivity
.managerSelectedActivity .getTimeAllActivitySelected()
.getTimeAllActivitySelected()) .toString();
.toStringAsFixed(0);
return Column( return Column(
children: [ children: [
Padding( Padding(
@ -32,7 +30,7 @@ class Stats extends StatelessWidget {
child: Row( child: Row(
children: [ children: [
const Text( const Text(
'Stats', 'Statistiques',
style: TextStyle( style: TextStyle(
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w800, fontWeight: FontWeight.w800,
@ -59,7 +57,7 @@ class Stats extends StatelessWidget {
iconBackground: const Color(0xff6131AD), iconBackground: const Color(0xff6131AD),
time: '+5s', time: '+5s',
label: 'Time', label: 'Time',
value: '$time min', value: '$time s',
), ),
const SizedBox(width: 15), const SizedBox(width: 15),
InfoStat( InfoStat(

@ -1,3 +1,4 @@
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:smartfit_app_mobile/common/colo_extension.dart'; import 'package:smartfit_app_mobile/common/colo_extension.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -6,11 +7,7 @@ class TodayTargetCell extends StatelessWidget {
final String icon; final String icon;
final String value; final String value;
final String title; final String title;
const TodayTargetCell( const TodayTargetCell({super.key, required this.icon, required this.value, required this.title});
{super.key,
required this.icon,
required this.value,
required this.title});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -24,7 +21,7 @@ class TodayTargetCell extends StatelessWidget {
child: Row( child: Row(
children: [ children: [
SvgPicture.asset( SvgPicture.asset(
icon, icon,
width: 40, width: 40,
height: 40, height: 40,
), ),
@ -67,5 +64,4 @@ class TodayTargetCell extends StatelessWidget {
), ),
); );
} }
} }

@ -270,18 +270,7 @@ class ActivityInfo {
// -- BPM -- // // -- BPM -- //
int bpmSomme = 0; int bpmSomme = 0;
int bpmNb = 0; int bpmNb = 0;
// -- Denivelé -- // bool bpmNotZero = false;
double lastDenivele = 0.0;
// -- Altitude -- //
double altitudeSomme = 0;
int alititudeNb = 0;
// -- Température -- //
int temperatureSomme = 0;
int temperatureNb = 0;
// -- Vitesse -- //
double vitesseSomme = 0.0;
int vitesseNb = 0;
// --- Boucle -- // // --- Boucle -- //
for (int i = 1; i < csv.length; i++) { for (int i = 1; i < csv.length; i++) {
// //
@ -299,78 +288,12 @@ class ActivityInfo {
bpmMin = value; bpmMin = value;
} }
} }
/// ------------------ Denivele et Altitude --------------- //
if (!isNull(enteteCSV["Value_${managerFile.fieldAltitude}"]!, csv[i])) {
double value = double.parse(
csv[i][enteteCSV["Value_${managerFile.fieldAltitude}"]!]);
// -- Denivelé -- //
if (value > lastDenivele) {
denivelePositif += value - lastDenivele;
} else {
deniveleNegatif += (value - lastDenivele) * -1;
}
lastDenivele = value;
// -- Altitude -- //
if (value > altitudeMax) {
altitudeMax = value;
}
if (value < altitudeMin) {
altitudeMin = value;
}
altitudeSomme += value;
alititudeNb += 1;
altitudeNotZero = true;
}
// ------------------------ Température ----------------------- //
if (!isNull(
enteteCSV["Value_${managerFile.fieldTemperature}"]!, csv[i])) {
int value = int.parse(
csv[i][enteteCSV["Value_${managerFile.fieldTemperature}"]!]);
temperatureSomme += value;
temperatureNb += 1;
temperatureNotZero = true;
if (value > temperatureMax) {
temperatureMax = value;
}
if (value < temperatureMin) {
temperatureMin = value;
}
}
// ------------------------ Vitesse -----------------------------//
if (!isNull(enteteCSV["Value_${managerFile.fieldSpeed}"]!, csv[i])) {
double value =
double.parse(csv[i][enteteCSV["Value_${managerFile.fieldSpeed}"]!]);
vitesseSomme += value;
vitesseNb += 1;
vitesseNotZero = true;
if (value > vitesseMax) {
vitesseMax = value;
}
if (value < vitesseMin) {
vitesseMin = value;
}
}
} }
// -- BPM -- // // -- BPM -- //
if (bpmNotZero) { if (bpmNotZero) {
bpmAvg = bpmSomme ~/ bpmNb; bpmAvg = bpmSomme ~/ bpmNb;
} }
// -- Atitude -- //
if (altitudeNotZero) {
altitudeAvg = altitudeSomme / alititudeNb;
}
// -- Température -- //
if (temperatureNotZero) {
temperatureAvg = temperatureSomme ~/ temperatureNb;
}
// -- Vitesse -- //
if (vitesseNotZero) {
vitesseAvg = vitesseSomme / vitesseNb;
}
return this; return this;
} }

@ -193,16 +193,6 @@ class ApiWrapper {
return res; return res;
} }
Future<Tuple2> getModeleAI(
String token, String category, InfoMessage infoManager) async {
await init();
if (handleOffline(infoManager)) return const Tuple2(false, "offline");
Tuple2 res = await api.getModeleAI(token, category);
if (!res.item1) infoManager.displayMessage(noConnectionMessage, true);
return res;
}
} }
extension StringExtension on String { extension StringExtension on String {

@ -42,7 +42,4 @@ abstract class IDataStrategy {
// Update email, password, username // Update email, password, username
Future<Tuple2<bool, String>> modifAttribut( Future<Tuple2<bool, String>> modifAttribut(
String token, String nameAttribut, String newValue); String token, String nameAttribut, String newValue);
//
Future<Tuple2> getModeleAI(String token, String category);
} }

@ -111,12 +111,10 @@ class RequestApi implements IDataStrategy {
return Tuple2<bool, String>(true, json['token'].toString()); return Tuple2<bool, String>(true, json['token'].toString());
} }
if (response.statusCode == 401) { if (response.statusCode == 401) {
return const Tuple2<bool, String>( return const Tuple2<bool, String>(false, "UNAUTHORIZED");
false, "Wrong Password, enter it carrefully !");
} }
if (response.statusCode == 404) { if (response.statusCode == 404) {
return const Tuple2<bool, String>( return const Tuple2<bool, String>(false, "Not found the email");
false, "Account not found, please verify your credentials.");
} }
} on SocketException catch (_) { } on SocketException catch (_) {
return const Tuple2(false, "No connection"); return const Tuple2(false, "No connection");
@ -138,12 +136,11 @@ class RequestApi implements IDataStrategy {
return Tuple2(true, json['token'].toString()); return Tuple2(true, json['token'].toString());
} }
if (response.statusCode == 400) { if (response.statusCode == 400) {
return const Tuple2(false, return const Tuple2(false, "400 BAD REQUEST - Json mal formaté");
"L'application rendontre une erreur inconnue, veuillez réessayer.");
} }
if (response.statusCode == 409) { if (response.statusCode == 409) {
return const Tuple2( return const Tuple2(
false, "Un compte est déjà enregistré avec cet email!"); false, "409 CONFLICT - Déja un compte avec cet email");
} }
} on SocketException catch (_) { } on SocketException catch (_) {
return const Tuple2(false, "No connection"); return const Tuple2(false, "No connection");
@ -271,7 +268,6 @@ class RequestApi implements IDataStrategy {
headers: <String, String>{'Authorization': token}); headers: <String, String>{'Authorization': token});
if (response.statusCode == 200) { if (response.statusCode == 200) {
Map<String, dynamic> json = jsonDecode(response.body); Map<String, dynamic> json = jsonDecode(response.body);
return Tuple2(true, json); return Tuple2(true, json);
} }
if (response.statusCode == 400) { if (response.statusCode == 400) {
@ -285,21 +281,4 @@ class RequestApi implements IDataStrategy {
} }
return const Tuple2(false, "Fail"); return const Tuple2(false, "Fail");
} }
@override
Future<Tuple2> getModeleAI(String token, String category) async {
try {
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);
return Tuple2(true, json);
} else {
return const Tuple2(false, "Fail");
}
} on SocketException catch (_) {
return const Tuple2(false, "No connection");
}
}
} }

@ -2,18 +2,10 @@ class Convertisseur {
// Mettre que des trucs static // Mettre que des trucs static
static double secondeIntoMinute(double seconde) { static double secondeIntoMinute(double seconde) {
return (seconde / 60); return seconde / 60;
}
static double milisecondeIntoMinute(double miliseconde) {
return (miliseconde / 60000);
} }
static double msIntoKmh(double metreSeconde) { static double msIntoKmh(double metreSeconde) {
return metreSeconde * 3.6; return metreSeconde * 3.6;
} }
static double millisecondeIntoSeconde(double milliseconde) {
return (milliseconde / 1000);
}
} }

@ -86,9 +86,4 @@ class RequestLocal implements IDataStrategy {
Future<bool> deleteFile(String token, String fileUuid) async { Future<bool> deleteFile(String token, String fileUuid) async {
throw Exception("Not Implemented"); throw Exception("Not Implemented");
} }
@override
Future<Tuple2> getModeleAI(String token, String category) async {
return const Tuple2(false, "Not implemented");
}
} }

@ -43,7 +43,6 @@ class ManagerFile {
// -- Getter categorie // -- Getter categorie
String get marche => _marche; String get marche => _marche;
String get velo => _velo;
String get generic => _generic; String get generic => _generic;
List<String> allowedFieldWalking = List.empty(growable: true); List<String> allowedFieldWalking = List.empty(growable: true);
@ -62,16 +61,7 @@ class ManagerFile {
_fieldTemperature _fieldTemperature
]; ];
allowedFieldGeneric = [ allowedFieldGeneric = [_fieldTimestamp, _fieldBPM];
_fieldTimestamp,
_fieldPositionLatitue,
_fieldPositionLongitude,
_fieldDistance,
_fieldBPM,
_fieldSpeed,
_fieldAltitude,
_fieldTemperature
];
allowedFieldCycling = [ allowedFieldCycling = [
_fieldTimestamp, _fieldTimestamp,
@ -159,8 +149,6 @@ class ManagerFile {
info.getDataWalking(csvData); info.getDataWalking(csvData);
case (_velo): case (_velo):
info.getDataCycling(csvData); info.getDataCycling(csvData);
case (_generic):
info.getDataGeneric(csvData);
default: default:
info.getDataGeneric(csvData); info.getDataGeneric(csvData);
} }

@ -3,10 +3,7 @@ import 'dart:convert';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:smartfit_app_mobile/modele/activity.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/activity_info/activity_info.dart';
import 'package:smartfit_app_mobile/modele/api/api_wrapper.dart';
import 'package:smartfit_app_mobile/modele/manager_selected_activity.dart'; import 'package:smartfit_app_mobile/modele/manager_selected_activity.dart';
import 'package:smartfit_app_mobile/modele/utile/info_message.dart';
import 'package:tuple/tuple.dart';
class User extends ChangeNotifier { class User extends ChangeNotifier {
String username = "VOID"; String username = "VOID";
@ -94,27 +91,26 @@ class User extends ChangeNotifier {
return map; return map;
} }
Future<Tuple2<bool, ActivityInfo>> predictActivity( ActivityInfo predictActivity(DateTime date) {
DateTime date, String category, InfoMessage infoManager) async { // Appel pour avoir le model
ApiWrapper wrapper = ApiWrapper(); String jsonString =
Tuple2 result = await wrapper.getModeleAI(token, category, infoManager); '{"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(jsonString);
if (!result.item1) return Tuple2(false, ActivityInfo());
String model = result.item2["model"];
Map<String, dynamic> jsonMap = json.decode(model);
// Transformer la date // Transformer la date
int dateMilli = date.millisecondsSinceEpoch; int dateMilli = date.millisecondsSinceEpoch;
ActivityInfo activityInfo = ActivityInfo(); ActivityInfo activityInfo = ActivityInfo();
activityInfo.bpmAvg = activityInfo.distance =
(jsonMap["coef"][0] * dateMilli + jsonMap["intercept"][0]).toInt(); jsonMap["coef"][0] * dateMilli + jsonMap["intercept"][0];
activityInfo.timeOfActivity = activityInfo.timeOfActivity =
jsonMap["coef"][1] * dateMilli + jsonMap["intercept"][1]; jsonMap["coef"][1] * dateMilli + jsonMap["intercept"][1];
activityInfo.vitesseAvg = activityInfo.denivelePositif =
jsonMap["coef"][2] * dateMilli + jsonMap["intercept"][2]; jsonMap["coef"][2] * dateMilli + jsonMap["intercept"][2];
activityInfo.distance = activityInfo.vitesseAvg =
jsonMap["coef"][3] * dateMilli + jsonMap["intercept"][3]; jsonMap["coef"][3] * dateMilli + jsonMap["intercept"][3];
activityInfo.bpmAvg =
jsonMap["coef"][4] * dateMilli + jsonMap["intercept"][4];
return Tuple2(true, activityInfo); return activityInfo;
} }
} }

@ -20,11 +20,9 @@ class HomeViewUtil {
.getXWithTime(managerFile.fieldAltitude); .getXWithTime(managerFile.fieldAltitude);
List<FlSpot> bpmSecondes2 = List.from(bpmSecondes); List<FlSpot> bpmSecondes2 = List.from(bpmSecondes);
return DataHomeView(
normaliserPremierElement(bpmSecondes), return DataHomeView(normaliserPremierElement(bpmSecondes), normaliserPremierElement(normaliserDeuxiemeElement(bpmSecondes2)),
normaliserPremierElement(normaliserDeuxiemeElement(bpmSecondes2)), normaliserPremierElement(normaliserDeuxiemeElement(vitesseSecondes)), normaliserPremierElement(altitudeSeconde));
normaliserPremierElement(normaliserDeuxiemeElement(vitesseSecondes)),
normaliserPremierElement(altitudeSeconde));
} }
List<FlSpot> normaliserDeuxiemeElement(List<FlSpot> liste) { List<FlSpot> normaliserDeuxiemeElement(List<FlSpot> liste) {
@ -43,21 +41,21 @@ class HomeViewUtil {
} }
return liste; return liste;
} }
List<FlSpot> normaliserPremierElement(List<FlSpot> liste) { List<FlSpot> normaliserPremierElement(List<FlSpot> liste) {
// Trouver le plus grand élément dans le premier élément de chaque FlSpot // Trouver le plus grand élément dans le premier élément de chaque FlSpot
double maxElement = 0.0; double maxElement = 0.0;
for (var spot in liste) { for (var spot in liste) {
if (spot.x > maxElement) { if (spot.x > maxElement) {
maxElement = spot.x; 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,6 +5,7 @@ import 'package:smartfit_app_mobile/modele/activity_saver.dart';
import 'package:smartfit_app_mobile/modele/helper.dart'; import 'package:smartfit_app_mobile/modele/helper.dart';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'dart:typed_data';
import 'package:csv/csv.dart'; import 'package:csv/csv.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -90,10 +91,6 @@ class ListActivityUtile {
String csvString = const ListToCsvConverter().convert(resultData.item2); String csvString = const ListToCsvConverter().convert(resultData.item2);
Uint8List byteCSV = Uint8List.fromList(utf8.encode(csvString)); Uint8List byteCSV = Uint8List.fromList(utf8.encode(csvString));
/* -- Ne pas décomenter sinon web ne marche plus (Utilisé pour déboguer)
File x = await File("${await _managerFile.localPath}\\what")
.writeAsString(csvString);*/
Tuple2<bool, String> result = await api.uploadFileByte( Tuple2<bool, String> result = await api.uploadFileByte(
token, token,
byteCSV, byteCSV,

@ -17,8 +17,8 @@ class Activity extends StatelessWidget {
.activitySelected .activitySelected
.isEmpty .isEmpty
? ScreenTypeLayout.builder( ? ScreenTypeLayout.builder(
mobile: (_) => const NoActivityView("No activities selected"), mobile: (_) => const NoActivityView("Pas d'activité sélectionnée"),
desktop: (_) => const NoActivityView("No activities selected"), desktop: (_) => const NoActivityView("Pas d'activité sélectionnée"),
) )
: ScreenTypeLayout.builder( : ScreenTypeLayout.builder(
mobile: (_) => const MobileActivity(), mobile: (_) => const MobileActivity(),

@ -36,7 +36,7 @@ class _MobileListActivity extends State<MobileListActivity> {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
"Activity List", "List Activités",
style: TextStyle( style: TextStyle(
color: TColor.black, color: TColor.black,
fontSize: 16, fontSize: 16,
@ -74,7 +74,7 @@ class _MobileListActivity extends State<MobileListActivity> {
setState(() {}); setState(() {});
}, },
child: Text( child: Text(
"Add", "Ajouter",
style: TextStyle( style: TextStyle(
color: TColor.gray, color: TColor.gray,
fontSize: 14, fontSize: 14,
@ -93,7 +93,7 @@ class _MobileListActivity extends State<MobileListActivity> {
children: [ children: [
const SizedBox(height: 20), const SizedBox(height: 20),
Text( Text(
"You don't have any activity at the moment, please add an activity by cliking the 'Add' button", "Vous n'avez pas d'activités pour le moment, veuillez en ajouter.",
style: TextStyle( style: TextStyle(
color: TColor.gray, color: TColor.gray,
fontSize: 11, fontSize: 11,

@ -36,7 +36,7 @@ class _WebListActivityState extends State<WebListActivity> {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
"Activity List", "List Activités",
style: TextStyle( style: TextStyle(
color: TColor.black, color: TColor.black,
fontSize: 16, fontSize: 16,
@ -73,7 +73,7 @@ class _WebListActivityState extends State<WebListActivity> {
} }
}, },
child: Text( child: Text(
"Add", "Ajouter",
style: TextStyle( style: TextStyle(
color: TColor.gray, color: TColor.gray,
fontSize: 14, fontSize: 14,
@ -92,7 +92,7 @@ class _WebListActivityState extends State<WebListActivity> {
children: [ children: [
const SizedBox(height: 20), const SizedBox(height: 20),
Text( Text(
"You don't have any activity at the moment, please add an activity by cliking the 'Add' button", "Vous n'avez pas d'activités pour le moment, veuillez en ajouter.",
style: TextStyle( style: TextStyle(
color: TColor.gray, color: TColor.gray,
fontSize: 11, fontSize: 11,

@ -28,8 +28,10 @@ class _HomeViewState extends State<HomeView> {
: selectedActivitiesCount > 1 : selectedActivitiesCount > 1
? const StatAtivities() ? const StatAtivities()
: ScreenTypeLayout.builder( : ScreenTypeLayout.builder(
mobile: (_) => const NoActivityView("No activity selected"), mobile: (_) =>
desktop: (_) => const NoActivityView("No activity selected"), const NoActivityView("Pas d'activité sélectionnée"),
desktop: (_) =>
const NoActivityView("Pas d'activité sélectionnée"),
); );
} }
} }

@ -29,7 +29,6 @@ class _MobileHomeView extends State<MobileHomeView> {
context.watch<User>().managerSelectedActivity; context.watch<User>().managerSelectedActivity;
data = HomeViewUtil().initData(context); data = HomeViewUtil().initData(context);
// -- BPM -- // // -- BPM -- //
data.maxBPM = data.maxBPM =
managerSelectedActivity.activitySelected.first.activityInfo.bpmMax; managerSelectedActivity.activitySelected.first.activityInfo.bpmMax;
@ -37,6 +36,7 @@ class _MobileHomeView extends State<MobileHomeView> {
managerSelectedActivity.activitySelected.first.activityInfo.bpmMin; managerSelectedActivity.activitySelected.first.activityInfo.bpmMin;
int avgBpm = int avgBpm =
managerSelectedActivity.activitySelected.first.activityInfo.bpmAvg; managerSelectedActivity.activitySelected.first.activityInfo.bpmAvg;
// -- Altitude -- // // -- Altitude -- //
double minAltitude = double minAltitude =
managerSelectedActivity.activitySelected.first.activityInfo.altitudeMin; managerSelectedActivity.activitySelected.first.activityInfo.altitudeMin;
@ -48,12 +48,12 @@ class _MobileHomeView extends State<MobileHomeView> {
double maxSpeed = managerSelectedActivity.getMaxSpeedAllActivitySelected(); double maxSpeed = managerSelectedActivity.getMaxSpeedAllActivitySelected();
double avgSpeed = managerSelectedActivity.getAvgSpeedAllActivitySelected(); double avgSpeed = managerSelectedActivity.getAvgSpeedAllActivitySelected();
double minSpeed = managerSelectedActivity.getMinSpeedAllActivitySelected(); double minSpeed = managerSelectedActivity.getMinSpeedAllActivitySelected();
data.maxSpeed = maxSpeed; data.maxSpeed = maxSpeed;
data.time = context data.time = context
.watch<User>() .watch<User>()
.managerSelectedActivity .managerSelectedActivity
.getTimeAllActivitySelected(); .getTimeAllActivitySelected();
return Scaffold( return Scaffold(
backgroundColor: TColor.white, backgroundColor: TColor.white,
body: SingleChildScrollView( body: SingleChildScrollView(
@ -68,7 +68,7 @@ class _MobileHomeView extends State<MobileHomeView> {
height: media.width * 0.05, height: media.width * 0.05,
), ),
Text( Text(
"Activity Status", "Status d'activité",
style: TextStyle( style: TextStyle(
color: TColor.black, color: TColor.black,
fontSize: 16, fontSize: 16,
@ -87,7 +87,7 @@ class _MobileHomeView extends State<MobileHomeView> {
"${avgBpm.toString()} BPM", "${avgBpm.toString()} BPM",
"Minimum", "Minimum",
"Maximum", "Maximum",
"Average", "Moyenne",
Icons.trending_down, Icons.trending_down,
Icons.trending_up, Icons.trending_up,
Icons.favorite_outline), Icons.favorite_outline),
@ -95,7 +95,7 @@ class _MobileHomeView extends State<MobileHomeView> {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
"Heart rate and speed", "Rythme cardique et vitesse",
style: TextStyle( style: TextStyle(
color: TColor.black, color: TColor.black,
fontSize: 16, fontSize: 16,
@ -114,9 +114,9 @@ class _MobileHomeView extends State<MobileHomeView> {
"${double.parse(maxSpeed.toStringAsFixed(2))} m/s", "${double.parse(maxSpeed.toStringAsFixed(2))} m/s",
"${double.parse(minSpeed.toStringAsFixed(2))} m/s", "${double.parse(minSpeed.toStringAsFixed(2))} m/s",
"${double.parse(avgSpeed.toStringAsFixed(2))} m/s", "${double.parse(avgSpeed.toStringAsFixed(2))} m/s",
"Max speed", "Max vitesse",
"Min speed", "Min vitesse",
"Avg speed", "Moyenne vitesse",
Icons.trending_down, Icons.trending_down,
Icons.trending_up, Icons.trending_up,
Icons.trending_up), Icons.trending_up),
@ -140,9 +140,9 @@ class _MobileHomeView extends State<MobileHomeView> {
"${minAltitude.toInt()} M", "${minAltitude.toInt()} M",
"${maxAltitude.toInt()} M", "${maxAltitude.toInt()} M",
"${avgAltitude.toInt()} M", "${avgAltitude.toInt()} M",
"Minimum altitude", "Altitude minimum",
"Maximum altitude", "Altitude maximum",
"Average altitude", "Altitude moyenne",
Icons.trending_down, Icons.trending_down,
Icons.trending_up, Icons.trending_up,
Icons.favorite_outline), Icons.favorite_outline),

@ -49,7 +49,7 @@ class _NoActivityViewState extends State<NoActivityView> {
), ),
), ),
Text( Text(
"Please select an activity by clicking the magnifying glass below", "Veuillez sélectionner une activité en cliquant sur la loupe ci-dessous",
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle(color: TColor.gray, fontSize: 12), style: TextStyle(color: TColor.gray, fontSize: 12),
), ),

@ -1,15 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:provider/provider.dart';
import 'package:smartfit_app_mobile/common/colo_extension.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/button/round_button.dart';
import 'package:smartfit_app_mobile/common_widget/container/workout_row/workout_row.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';
import 'package:tuple/tuple.dart';
class Prediction extends StatefulWidget { class Prediction extends StatefulWidget {
const Prediction({Key? key}) : super(key: key); const Prediction({Key? key}) : super(key: key);
@ -21,85 +14,61 @@ class Prediction extends StatefulWidget {
class _PredictionState extends State<Prediction> { class _PredictionState extends State<Prediction> {
List<Map<String, dynamic>> lastWorkoutArr = [ List<Map<String, dynamic>> lastWorkoutArr = [
{ {
"name": "Time", "name": "Temps",
"image": "assets/img/time-icon2.svg", "image": "assets/img/time-icon2.svg",
"value": "..", "value": "200 s",
}, },
{ {
"name": "Heart rate", "name": "Rythme cardiaque",
"image": "assets/img/bpm2-icon.svg", "image": "assets/img/bpm2-icon.svg",
"value": "..", "value": "120 BPM",
}, },
{ {
"name": "Speed", "name": "Vitesse",
"image": "assets/img/vitesse2-icon.svg", "image": "assets/img/vitesse2-icon.svg",
"value": "..", "value": "3 m/s",
}, },
{ {
"name": "Distance", "name": "Distance",
"image": "assets/img/distance2-icon.svg", "image": "assets/img/distance2-icon.svg",
"value": "..", "value": "300 m",
} }
]; ];
final ManagerFile _managerFile = ManagerFile();
String selectedCategory = "Select an activity category";
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
List<String> listCategory = [_managerFile.marche, _managerFile.velo]; var media = MediaQuery.of(context).size;
void prediction() async {
InfoMessage tmp = InfoMessage();
/*
if (selectedCategory != _managerFile.marche ||
selectedCategory != _managerFile.velo) return;*/
Tuple2<bool, ActivityInfo> resultat =
await Provider.of<User>(context, listen: false)
.predictActivity(DateTime.now(), selectedCategory, tmp);
if (!resultat.item1) return;
setState(() {
lastWorkoutArr[0]["value"] =
"${Convertisseur.secondeIntoMinute(resultat.item2.timeOfActivity).toStringAsFixed(0)} min";
lastWorkoutArr[1]["value"] =
"${resultat.item2.bpmAvg.toStringAsFixed(2)} bpm";
lastWorkoutArr[2]["value"] =
"${Convertisseur.msIntoKmh(resultat.item2.vitesseAvg).toStringAsFixed(1)} km/h ";
lastWorkoutArr[3]["value"] =
"${resultat.item2.distance.toStringAsFixed(2)} m";
});
}
return Scaffold( return Scaffold(
body: Padding( body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0), padding: EdgeInsets.symmetric(horizontal: 20.0),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
const SizedBox(height: 40), SizedBox(height: 40),
Text( Text(
"Prediction", "Prédiction",
style: TextStyle( style: TextStyle(
color: TColor.black, color: TColor.black,
fontSize: 22, fontSize: 22,
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
), ),
), ),
const SizedBox(height: 20), SizedBox(height: 20),
const Row( Row(
children: [], children: [
],
), ),
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: TColor.lightGray, color: TColor.lightGray,
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
color: const Color.fromARGB(255, 234, 234, 234) color: Color.fromARGB(255, 234, 234, 234).withOpacity(0.9),
.withOpacity(0.9),
spreadRadius: 2, spreadRadius: 2,
blurRadius: 5, blurRadius: 5,
offset: const Offset(0, 2), offset: Offset(0, 2),
), ),
], ],
borderRadius: BorderRadius.circular(15), borderRadius: BorderRadius.circular(15),
@ -121,7 +90,7 @@ class _PredictionState extends State<Prediction> {
Expanded( Expanded(
child: DropdownButtonHideUnderline( child: DropdownButtonHideUnderline(
child: DropdownButton( child: DropdownButton(
items: listCategory items: ["Walking", "Cycling"]
.map((name) => DropdownMenuItem( .map((name) => DropdownMenuItem(
value: name, value: name,
child: Text( child: Text(
@ -133,14 +102,10 @@ class _PredictionState extends State<Prediction> {
), ),
)) ))
.toList(), .toList(),
onChanged: (value) { onChanged: (value) {},
setState(() {
selectedCategory = value!;
});
},
isExpanded: true, isExpanded: true,
hint: Text( hint: Text(
selectedCategory, "Choisir type d'activité",
style: TextStyle( style: TextStyle(
color: TColor.gray, color: TColor.gray,
fontSize: 12, fontSize: 12,
@ -150,23 +115,25 @@ class _PredictionState extends State<Prediction> {
), ),
), ),
// Bouton "Valider" prenant 30% de la largeur du parent // Bouton "Valider" prenant 30% de la largeur du parent
], ],
), ),
), ),
const SizedBox(height: 20), SizedBox(height: 20),
RoundButton( RoundButton(
title: "Save", title: "Valider",
onPressed: () async { onPressed: () async {
prediction(); setState(() {});
}), }),
const SizedBox(height: 20), SizedBox(height: 20),
ListView.builder( ListView.builder(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true, shrinkWrap: true,
itemCount: lastWorkoutArr.length, itemCount: lastWorkoutArr.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
var wObj = lastWorkoutArr[index]; var wObj =
lastWorkoutArr[index] as Map<String, dynamic> ?? {};
return InkWell( return InkWell(
child: WorkoutRow(wObj: wObj), child: WorkoutRow(wObj: wObj),
); );

@ -3,7 +3,6 @@ import 'package:provider/provider.dart';
import 'package:smartfit_app_mobile/common_widget/container/container_stats_activities.dart'; import 'package:smartfit_app_mobile/common_widget/container/container_stats_activities.dart';
import 'package:smartfit_app_mobile/common_widget/other/entete_home_view.dart'; import 'package:smartfit_app_mobile/common_widget/other/entete_home_view.dart';
import 'package:smartfit_app_mobile/common/colo_extension.dart'; import 'package:smartfit_app_mobile/common/colo_extension.dart';
import 'package:smartfit_app_mobile/modele/convertisseur.dart';
import 'package:smartfit_app_mobile/modele/manager_selected_activity.dart'; import 'package:smartfit_app_mobile/modele/manager_selected_activity.dart';
import 'package:smartfit_app_mobile/modele/user.dart'; import 'package:smartfit_app_mobile/modele/user.dart';
import 'package:smartfit_app_mobile/modele/utile/home_view/data_home_view.dart'; import 'package:smartfit_app_mobile/modele/utile/home_view/data_home_view.dart';
@ -84,11 +83,11 @@ class _StatAtivities extends State<StatAtivities> {
double maxSpeed = context double maxSpeed = context
.watch<User>() .watch<User>()
.managerSelectedActivity .managerSelectedActivity
.getMaxSpeedAllActivitySelected(); .getMaxAltitudeAllActivitySelected();
double minSpeed = context double minSpeed = context
.watch<User>() .watch<User>()
.managerSelectedActivity .managerSelectedActivity
.getMinSpeedAllActivitySelected(); .getMinAltitudeAllActivitySelected();
return Scaffold( return Scaffold(
backgroundColor: TColor.white, backgroundColor: TColor.white,
@ -107,7 +106,7 @@ class _StatAtivities extends State<StatAtivities> {
height: media.width * 0.05, height: media.width * 0.05,
), ),
Text( Text(
"Activity Status", "Status d'activité",
style: TextStyle( style: TextStyle(
color: TColor.black, color: TColor.black,
fontSize: 16, fontSize: 16,
@ -120,17 +119,17 @@ class _StatAtivities extends State<StatAtivities> {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
ContainerStatsActivities( ContainerStatsActivities(
"$avgBpm BPM", "Average bpm", Icons.favorite), "$avgBpm BPM", "Moyenne Bpm", Icons.favorite),
SizedBox( SizedBox(
width: media.width * 0.03, width: media.width * 0.03,
), ),
ContainerStatsActivities( ContainerStatsActivities(
"$maxBpm BPM", "Maximum bpm", Icons.trending_up), "$maxBpm BPM", "Maximum Bpm", Icons.trending_up),
SizedBox( SizedBox(
width: media.width * 0.03, width: media.width * 0.03,
), ),
ContainerStatsActivities( ContainerStatsActivities(
"$minBpm BPM", "Minimum bpm", Icons.trending_down) "$minBpm BPM", "Minimum Bpm", Icons.trending_down)
], ],
), ),
SizedBox( SizedBox(
@ -140,23 +139,17 @@ class _StatAtivities extends State<StatAtivities> {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
ContainerStatsActivities( ContainerStatsActivities(
"${Convertisseur.msIntoKmh(avgSpeed).toStringAsFixed(0)} km/h", "${avgSpeed.toStringAsFixed(2)} m/s", "Moyenne vitesse", Icons.bolt),
"Average speed",
Icons.bolt),
SizedBox( SizedBox(
width: media.width * 0.03, width: media.width * 0.03,
), ),
ContainerStatsActivities( ContainerStatsActivities(
"${Convertisseur.msIntoKmh(maxSpeed).toStringAsFixed(0)} km/h", "$maxSpeed m/s", "Maximum vitesse", Icons.trending_up),
"Maximum speed",
Icons.trending_up),
SizedBox( SizedBox(
width: media.width * 0.03, width: media.width * 0.03,
), ),
ContainerStatsActivities( ContainerStatsActivities(
"${Convertisseur.msIntoKmh(minSpeed).toStringAsFixed(0)} km/h", "$minSpeed m/s", "Minimum vitesse", Icons.trending_down)
"Minimum speed",
Icons.trending_down)
], ],
), ),
SizedBox( SizedBox(
@ -166,7 +159,7 @@ class _StatAtivities extends State<StatAtivities> {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
ContainerStatsActivities("$avgTemperature °C", ContainerStatsActivities("$avgTemperature °C",
"Average Temperature", Icons.thermostat), "Moyenne Temperature", Icons.thermostat),
SizedBox( SizedBox(
width: media.width * 0.03, width: media.width * 0.03,
), ),
@ -186,19 +179,17 @@ class _StatAtivities extends State<StatAtivities> {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
ContainerStatsActivities( ContainerStatsActivities(
"${avgAltitude.toStringAsFixed(2)} m", "${avgAltitude.toStringAsFixed(2)} m", "Moyenne Altitude", Icons.landscape),
"Average altitude",
Icons.landscape),
SizedBox( SizedBox(
width: media.width * 0.03, width: media.width * 0.03,
), ),
ContainerStatsActivities("$maxAltitude m", ContainerStatsActivities("$maxAltitude m",
"Maximum altitude", Icons.trending_up), "Maximum Altitude", Icons.trending_up),
SizedBox( SizedBox(
width: media.width * 0.03, width: media.width * 0.03,
), ),
ContainerStatsActivities("$minAltitude m", ContainerStatsActivities("$minAltitude m",
"Minimum altitude", Icons.trending_down) "Minimum Altitude", Icons.trending_down)
], ],
), ),
SizedBox( SizedBox(
@ -208,12 +199,12 @@ class _StatAtivities extends State<StatAtivities> {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
ContainerStatsActivities("$getTotalDistance m", ContainerStatsActivities("$getTotalDistance m",
"Total distance", Icons.double_arrow), "Distance Totale", Icons.double_arrow),
SizedBox( SizedBox(
width: media.width * 0.03, width: media.width * 0.03,
), ),
ContainerStatsActivities("$totalSteps", "Total steps", ContainerStatsActivities(
Icons.do_not_step_rounded), "$totalSteps", "Total Pas", Icons.do_not_step_rounded),
], ],
), ),
SizedBox( SizedBox(
@ -223,14 +214,12 @@ class _StatAtivities extends State<StatAtivities> {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
ContainerStatsActivities( ContainerStatsActivities(
"${Convertisseur.secondeIntoMinute(totalTime)} min", "$totalTime s", "Temps Total", Icons.timer),
"Total time",
Icons.timer),
SizedBox( SizedBox(
width: media.width * 0.03, width: media.width * 0.03,
), ),
ContainerStatsActivities("$totalCalories kCal", ContainerStatsActivities("$totalCalories kCal",
"Burned calories", Icons.local_fire_department), "Calories Dépensées", Icons.local_fire_department),
], ],
), ),
SizedBox( SizedBox(

@ -63,109 +63,117 @@ class _WebHomeView extends State<WebHomeView> {
return Scaffold( return Scaffold(
backgroundColor: TColor.white, backgroundColor: TColor.white,
body: SingleChildScrollView( body: SingleChildScrollView(
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 30), padding: const EdgeInsets.symmetric(horizontal: 30),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
SizedBox( SizedBox(
height: media.width * 0.03, height: media.width * 0.03,
), ),
const EnteteHomeView(), const EnteteHomeView(),
SizedBox( SizedBox(
height: media.width * 0.03, height: media.width * 0.03,
), ),
Column(mainAxisAlignment: MainAxisAlignment.center, children: [
Column(mainAxisAlignment: MainAxisAlignment.center, children: [ Column(mainAxisAlignment: MainAxisAlignment.center, children: [
Text( Column(
"Activity status", mainAxisAlignment: MainAxisAlignment.center,
style: TextStyle( children: [
color: TColor.black, Text(
fontSize: 16, "Status d'activité",
fontWeight: FontWeight.w700), style: TextStyle(
), color: TColor.black,
fontSize: 16,
fontWeight: FontWeight.w700),
),
SizedBox(
height: media.width * 0.02,
),
Row(mainAxisAlignment: MainAxisAlignment.center,
children: [
BpmByTime(media, data),
SizedBox(
width: media.width * 0.01,
),
LigneContainerStats(
"${minBpm.toString()} BPM",
"${maxBpm.toString()} BPM",
"${avgBpm.toString()} BPM",
"Minimum",
"Maximum",
"Moyenne",
Icons.trending_down,
Icons.trending_up,
Icons.favorite_outline),
]),
]),
SizedBox( SizedBox(
height: media.width * 0.02, height: media.width * 0.05,
), ),
Row(mainAxisAlignment: MainAxisAlignment.center, children: [ Column(
BpmByTime(media, data), mainAxisAlignment: MainAxisAlignment.center,
SizedBox( children: [
width: media.width * 0.01, Text(
), "Rythme cardique et vitesse",
LigneContainerStats( style: TextStyle(
"${minBpm.toString()} BPM", color: TColor.black,
"${maxBpm.toString()} BPM", fontSize: 16,
"${avgBpm.toString()} BPM", fontWeight: FontWeight.w700),
"Minimum", ),
"Maximum", SizedBox(
"Average", height: media.width * 0.03,
Icons.trending_down, ),
Icons.trending_up, Row(
Icons.favorite_outline), mainAxisAlignment: MainAxisAlignment.center,
]), children: [
GraphBpmAndSpeedByTime(media, data),
SizedBox(
height: media.width * 0.05,
),
LigneContainerStats(
"${double.parse(maxSpeed.toStringAsFixed(2))} m/s",
"${double.parse(avgSpeed.toStringAsFixed(2))} m/s",
"${avgBpm.toString()} BPM",
"Max vitesse",
"Moy vitesse",
"Moy Bpm",
Icons.trending_up,
Icons.bolt,
Icons.favorite_outline),
SizedBox(
height: media.width * 0.05,
),
]),
]),
]), ]),
SizedBox( SizedBox(
height: media.width * 0.05, height: media.width * 0.02,
), ),
Column(mainAxisAlignment: MainAxisAlignment.center, children: [ Text(
Text( "Altitude",
"Heart rate and speed", style: TextStyle(
style: TextStyle( color: TColor.black,
color: TColor.black, fontSize: 16,
fontSize: 16, fontWeight: FontWeight.w700),
fontWeight: FontWeight.w700), ),
), Row(mainAxisAlignment: MainAxisAlignment.center, children: [
SizedBox( GraphAltitudeByTime(media, data),
height: media.width * 0.03, LigneContainerStats(
), "${minAltitude.toInt()} m",
Row(mainAxisAlignment: MainAxisAlignment.center, children: [ "${maxAltitude.toInt()} m",
GraphBpmAndSpeedByTime(media, data), "${avgAltitude.toInt()} m",
SizedBox( "Minimum",
height: media.width * 0.05, "Maximum",
), "Moyenne",
LigneContainerStats( Icons.trending_down,
"${double.parse(maxSpeed.toStringAsFixed(2))} m/s", Icons.trending_up,
"${double.parse(avgSpeed.toStringAsFixed(2))} m/s", Icons.favorite_outline),
"${avgBpm.toString()} BPM",
"Max speed",
"Moy speed",
"Avg bpm",
Icons.trending_up,
Icons.bolt,
Icons.favorite_outline),
SizedBox(
height: media.width * 0.05,
),
]),
]), ]),
]), ],
SizedBox( ),
height: media.width * 0.02,
),
Text(
"Altitude",
style: TextStyle(
color: TColor.black,
fontSize: 16,
fontWeight: FontWeight.w700),
),
Row(mainAxisAlignment: MainAxisAlignment.center, children: [
GraphAltitudeByTime(media, data),
LigneContainerStats(
"${minAltitude.toInt()} m",
"${maxAltitude.toInt()} m",
"${avgAltitude.toInt()} m",
"Minimum",
"Maximum",
"Average",
Icons.trending_down,
Icons.trending_up,
Icons.favorite_outline),
]),
],
), ),
),
), ),
); );
} }
} }

@ -82,11 +82,11 @@ class _MobileLoginView extends State<MobileLoginView> {
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Text( Text(
"Welcome", "Bienvenue",
style: TextStyle(color: TColor.gray, fontSize: 16), style: TextStyle(color: TColor.gray, fontSize: 16),
), ),
Text( Text(
"Log in", "Se connecter",
style: TextStyle( style: TextStyle(
color: TColor.black, color: TColor.black,
fontSize: 20, fontSize: 20,
@ -109,7 +109,7 @@ class _MobileLoginView extends State<MobileLoginView> {
), ),
RoundTextField( RoundTextField(
controller: controllerTextPassword, controller: controllerTextPassword,
hitText: "Password", hitText: "Mot de passe",
icon: "assets/img/lock.svg", icon: "assets/img/lock.svg",
obscureText: _obscureText, obscureText: _obscureText,
rigtIcon: TextButton( rigtIcon: TextButton(
@ -129,7 +129,7 @@ class _MobileLoginView extends State<MobileLoginView> {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Text( Text(
"Password Lost ?", "Mot de passe oublié ?",
style: TextStyle( style: TextStyle(
color: TColor.gray, color: TColor.gray,
fontSize: 15, fontSize: 15,
@ -146,10 +146,10 @@ class _MobileLoginView extends State<MobileLoginView> {
style: TextStyle(color: TColor.red))), style: TextStyle(color: TColor.red))),
const Spacer(), const Spacer(),
RoundButton( RoundButton(
title: "Log in", title: "Se connecter",
onPressed: () async { onPressed: () async {
if (!emailValidate || !passwordValidate) { if (!emailValidate || !passwordValidate) {
_printMsgError("Fields are not valid!"); _printMsgError("Les champs renseigné ne sont pas valide");
return; return;
} }
Tuple2<bool, String> result = Tuple2<bool, String> result =
@ -163,7 +163,7 @@ class _MobileLoginView extends State<MobileLoginView> {
if (infoUser.item1 == false) { if (infoUser.item1 == false) {
//print("Erreur - Impossible de récupéré les données de l'utilisateur"); //print("Erreur - Impossible de récupéré les données de l'utilisateur");
_printMsgError( _printMsgError(
"Can't find user data! - {$infoUser.item2}"); "Impossible de récupéré les données de l'utilisateur - {$infoUser.item2}");
} else { } else {
util.fillUser(context, infoUser.item2, result.item2); util.fillUser(context, infoUser.item2, result.item2);
if (!kIsWeb) if (!kIsWeb)
@ -175,7 +175,7 @@ class _MobileLoginView extends State<MobileLoginView> {
builder: (context) => const MainTabView())); builder: (context) => const MainTabView()));
} }
} else { } else {
_printMsgError("Connection refused - ${result.item2}"); _printMsgError("Connexion refuser - ${result.item2}");
} }
}), }),
SizedBox( SizedBox(
@ -264,14 +264,14 @@ class _MobileLoginView extends State<MobileLoginView> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Text( Text(
"Don't have an account yet ?", "Vous n'avez pas toujours pas de compte ? ",
style: TextStyle( style: TextStyle(
color: TColor.black, color: TColor.black,
fontSize: 14, fontSize: 14,
), ),
), ),
Text( Text(
"Register", "Créer un compte",
style: TextStyle( style: TextStyle(
color: TColor.black, color: TColor.black,
fontSize: 14, fontSize: 14,

@ -98,11 +98,11 @@ class _MobileSignUpView extends State<MobileSignUpView> {
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Text( Text(
"Welcome,", "Bienvenue,",
style: TextStyle(color: TColor.gray, fontSize: 16), style: TextStyle(color: TColor.gray, fontSize: 16),
), ),
Text( Text(
"Register", "Créer un compte",
style: TextStyle( style: TextStyle(
color: TColor.black, color: TColor.black,
fontSize: 20, fontSize: 20,
@ -112,7 +112,7 @@ class _MobileSignUpView extends State<MobileSignUpView> {
height: media.width * 0.05, height: media.width * 0.05,
), ),
RoundTextField( RoundTextField(
hitText: "Username", hitText: "Prénom",
icon: "assets/img/user_text.svg", icon: "assets/img/user_text.svg",
controller: controllerUsername, controller: controllerUsername,
), ),
@ -129,7 +129,7 @@ class _MobileSignUpView extends State<MobileSignUpView> {
height: media.width * 0.04, height: media.width * 0.04,
), ),
RoundTextField( RoundTextField(
hitText: "Password", hitText: "Mot de passe",
icon: "assets/img/lock.svg", icon: "assets/img/lock.svg",
obscureText: _obscureText, obscureText: _obscureText,
controller: controllerTextPassword, controller: controllerTextPassword,
@ -164,7 +164,7 @@ class _MobileSignUpView extends State<MobileSignUpView> {
Padding( Padding(
padding: const EdgeInsets.only(top: 8), padding: const EdgeInsets.only(top: 8),
child: Text( child: Text(
"I accept to not break the app", "En continuant, vous acceptez notre Politique de\nconfidentialité et nos Conditions d'utilisation.",
style: TextStyle(color: TColor.gray, fontSize: 10), style: TextStyle(color: TColor.gray, fontSize: 10),
), ),
) )
@ -181,12 +181,12 @@ class _MobileSignUpView extends State<MobileSignUpView> {
height: media.width * 0.4, height: media.width * 0.4,
), ),
RoundButton( RoundButton(
title: "Register", title: "Créer un compte",
onPressed: () async { onPressed: () async {
if (!emailValidate || if (!emailValidate ||
!passwordValidate || !passwordValidate ||
!usernameValidate) { !usernameValidate) {
_printMsgError("Fields are not valid!"); _printMsgError("Les champs renseigné ne sont pas valide");
return; return;
} }
@ -215,7 +215,7 @@ class _MobileSignUpView extends State<MobileSignUpView> {
color: TColor.gray.withOpacity(0.5), color: TColor.gray.withOpacity(0.5),
)), )),
Text( Text(
" Or ", " Ou ",
style: TextStyle(color: TColor.black, fontSize: 12), style: TextStyle(color: TColor.black, fontSize: 12),
), ),
Expanded( Expanded(
@ -239,14 +239,14 @@ class _MobileSignUpView extends State<MobileSignUpView> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Text( Text(
"Already have an account ?", "Vous avez déjà un compte ? ",
style: TextStyle( style: TextStyle(
color: TColor.black, color: TColor.black,
fontSize: 14, fontSize: 14,
), ),
), ),
Text( Text(
"Log in", "Se connecter",
style: TextStyle( style: TextStyle(
color: TColor.black, color: TColor.black,
fontSize: 14, fontSize: 14,

@ -86,11 +86,11 @@ class _WebLoginView extends State<WebLoginView> {
height: media.width * 0.03, height: media.width * 0.03,
), ),
Text( Text(
"Welcome on SmartFit", "Bienvenue sur SmartFit",
style: TextStyle(color: TColor.gray, fontSize: 16), style: TextStyle(color: TColor.gray, fontSize: 16),
), ),
Text( Text(
"Log in", "Se connecter",
style: TextStyle( style: TextStyle(
color: TColor.black, color: TColor.black,
fontSize: 20, fontSize: 20,
@ -110,7 +110,7 @@ class _WebLoginView extends State<WebLoginView> {
), ),
RoundTextField( RoundTextField(
controller: controllerTextPassword, controller: controllerTextPassword,
hitText: "Password", hitText: "Mot de passe",
icon: "assets/img/lock.svg", icon: "assets/img/lock.svg",
obscureText: _obscureText, obscureText: _obscureText,
rigtIcon: TextButton( rigtIcon: TextButton(
@ -133,7 +133,7 @@ class _WebLoginView extends State<WebLoginView> {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Text( Text(
"Password lost ?", "Mot de passe oublié ?",
style: TextStyle( style: TextStyle(
color: TColor.gray, color: TColor.gray,
fontSize: 15, fontSize: 15,
@ -150,11 +150,11 @@ class _WebLoginView extends State<WebLoginView> {
style: TextStyle(color: TColor.red))), style: TextStyle(color: TColor.red))),
const Spacer(), const Spacer(),
RoundButton( RoundButton(
title: "Log in", title: "Se connecter",
onPressed: () async { onPressed: () async {
// TODO: utiliser la vrai validation // TODO: utiliser la vrai validation
if (!emailValidate || !passwordValidate) { if (!emailValidate || !passwordValidate) {
_printMsgError("Fields are not valid!"); _printMsgError("Les champs renseigné ne sont pas valide");
return; return;
} }
Tuple2<bool, String> result = Tuple2<bool, String> result =
@ -168,7 +168,7 @@ class _WebLoginView extends State<WebLoginView> {
if (infoUser.item1 == false) { if (infoUser.item1 == false) {
//print("Erreur - Impossible de récupéré les données de l'utilisateur"); //print("Erreur - Impossible de récupéré les données de l'utilisateur");
_printMsgError( _printMsgError(
"Can't find user data - {$infoUser.item2}"); "Impossible de récupéré les données de l'utilisateur - {$infoUser.item2}");
} else { } else {
util.fillUser(context, infoUser.item2, result.item2); util.fillUser(context, infoUser.item2, result.item2);
if (!kIsWeb) if (!kIsWeb)
@ -180,7 +180,7 @@ class _WebLoginView extends State<WebLoginView> {
builder: (context) => const MainTabView())); builder: (context) => const MainTabView()));
} }
} else { } else {
_printMsgError("Connection refused - ${result.item2}"); _printMsgError("Connexion refuser - ${result.item2}");
} }
}), }),
SizedBox( SizedBox(
@ -197,14 +197,14 @@ class _WebLoginView extends State<WebLoginView> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Text( Text(
"Don't have an account yet ? ", "Vous n'avez pas toujours pas de compte ? ",
style: TextStyle( style: TextStyle(
color: TColor.black, color: TColor.black,
fontSize: 14, fontSize: 14,
), ),
), ),
Text( Text(
"Register", "Créer un compte",
style: TextStyle( style: TextStyle(
color: TColor.black, color: TColor.black,
fontSize: 14, fontSize: 14,

@ -100,11 +100,11 @@ class _WebSignUpView extends State<WebSignUpView> {
height: media.width * 0.04, height: media.width * 0.04,
), ),
Text( Text(
"Welcome,", "Bienvenue,",
style: TextStyle(color: TColor.gray, fontSize: 16), style: TextStyle(color: TColor.gray, fontSize: 16),
), ),
Text( Text(
"Register", "Créer un compte",
style: TextStyle( style: TextStyle(
color: TColor.black, color: TColor.black,
fontSize: 20, fontSize: 20,
@ -114,7 +114,7 @@ class _WebSignUpView extends State<WebSignUpView> {
height: media.width * 0.05, height: media.width * 0.05,
), ),
RoundTextField( RoundTextField(
hitText: "Username", hitText: "Prénom",
icon: "assets/img/user_text.svg", icon: "assets/img/user_text.svg",
controller: controllerUsername, controller: controllerUsername,
), ),
@ -131,7 +131,7 @@ class _WebSignUpView extends State<WebSignUpView> {
height: media.width * 0.04, height: media.width * 0.04,
), ),
RoundTextField( RoundTextField(
hitText: "Password", hitText: "Mot de passe",
icon: "assets/img/lock.svg", icon: "assets/img/lock.svg",
obscureText: _obscureText, obscureText: _obscureText,
controller: controllerTextPassword, controller: controllerTextPassword,
@ -166,7 +166,7 @@ class _WebSignUpView extends State<WebSignUpView> {
Padding( Padding(
padding: const EdgeInsets.only(top: 8), padding: const EdgeInsets.only(top: 8),
child: Text( child: Text(
"Please don't break the app", "En continuant, vous acceptez notre Politique de\nconfidentialité et nos Conditions d'utilisation.",
style: TextStyle(color: TColor.gray, fontSize: 10), style: TextStyle(color: TColor.gray, fontSize: 10),
), ),
) )
@ -180,12 +180,12 @@ class _WebSignUpView extends State<WebSignUpView> {
height: media.width * 0.05, height: media.width * 0.05,
), ),
RoundButton( RoundButton(
title: "Register", title: "Créer un compte",
onPressed: () async { onPressed: () async {
if (!emailValidate || if (!emailValidate ||
!passwordValidate || !passwordValidate ||
!usernameValidate) { !usernameValidate) {
_printMsgError("Fields are not valid!"); _printMsgError("Les champs renseigné ne sont pas valide");
return; return;
} }
Tuple2<bool, String> result = await util.createUser( Tuple2<bool, String> result = await util.createUser(
@ -215,14 +215,14 @@ class _WebSignUpView extends State<WebSignUpView> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Text( Text(
"Already have an account ?", "Vous avez déjà un compte ? ",
style: TextStyle( style: TextStyle(
color: TColor.black, color: TColor.black,
fontSize: 14, fontSize: 14,
), ),
), ),
Text( Text(
"Log in", "Se connecter",
style: TextStyle( style: TextStyle(
color: TColor.black, color: TColor.black,
fontSize: 14, fontSize: 14,

@ -24,7 +24,7 @@ class _MobileMyMaps extends State<MobileMyMaps> {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: const Text("Google Map "), title: const Text("Carte Google Map "),
backgroundColor: TColor.secondaryColor1, backgroundColor: TColor.secondaryColor1,
), ),
body: _getMap()); body: _getMap());

@ -21,16 +21,16 @@ class _MyMapState extends State<MyMap> {
if (listSelected.isEmpty) { if (listSelected.isEmpty) {
return ScreenTypeLayout.builder( return ScreenTypeLayout.builder(
mobile: (_) => const NoActivityView("No activity selected"), mobile: (_) => const NoActivityView("Pas d'activité sélectionnée"),
desktop: (_) => const NoActivityView("No activity selected"), desktop: (_) => const NoActivityView("Pas d'activité sélectionnée"),
); );
} }
if (listSelected.length > 1) { if (listSelected.length > 1) {
return ScreenTypeLayout.builder( return ScreenTypeLayout.builder(
mobile: (_) => mobile: (_) => const NoActivityView(
const NoActivityView("Only one activity must be selected"), "Une seule activité doit être sélectionnée"),
desktop: (_) => desktop: (_) => const NoActivityView(
const NoActivityView("Only one activity must be selected"), "Une seule activité doit être sélectionnée"),
); );
} }
return ScreenTypeLayout.builder( return ScreenTypeLayout.builder(

@ -22,7 +22,7 @@ class _MyMapOSM extends State<MyMapOSM> {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: const Text("Open Street Map "), title: const Text("Carte Open Street Map "),
backgroundColor: TColor.secondaryColor1, backgroundColor: TColor.secondaryColor1,
), ),
body: FlutterMap( body: FlutterMap(

@ -25,7 +25,7 @@ class _WebMyMaps extends State<WebMyMaps> {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: const Text("Google Map "), title: const Text("Carte Google Map "),
backgroundColor: TColor.primaryColor1, backgroundColor: TColor.primaryColor1,
), ),
body: _getMap()); body: _getMap());

@ -27,21 +27,21 @@ class _OnBoardingViewState extends State<OnBoardingView> {
List pageArr = [ List pageArr = [
{ {
"title": "Achieve your goals", "title": "Atteignez vos objectifs",
"subtitle": "subtitle":
"Don't worry if you have trouble determining your goals. Thanks to the concrete analysis of your performances, we will help you achieve them.", "Ne vous inquiétez pas si vous avez du mal à déterminer vos objectifs. Grâce à l'analyse concrète de vos performances, nous vous aiderons à les atteindre.",
"image": "assets/img/on_1.svg" "image": "assets/img/on_1.svg"
}, },
{ {
"title": "Persévérez", "title": "Persévérez",
"subtitle": "subtitle":
"Continue to persevere to achieve your goals. The pain is only temporary. If you give up now, you will suffer forever.", "Continuez à persévérer pour atteindre vos objectifs. La douleur n'est que temporaire. Si vous abandonnez maintenant, vous souffrirez éternellement.",
"image": "assets/img/on_2.svg" "image": "assets/img/on_2.svg"
}, },
{ {
"title": "Let us pilot, just put on your Suunto", "title": "Laissez-nous piloter, mettez simplement votre Suunto",
"subtitle": "subtitle":
"Relax, we take charge by analyzing performance and statistics to help you achieve your goals.", "Détendez-vous, nous prenons les commandes en analysant performances et statistiques pour vous aider à atteindre vos objectifs.",
"image": "assets/img/on_3.svg" "image": "assets/img/on_3.svg"
}, },
]; ];

@ -41,7 +41,7 @@ class _StartedViewState extends State<StartedView> {
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 15), padding: const EdgeInsets.symmetric(horizontal: 15),
child: RoundButton( child: RoundButton(
title: "Start", title: "Commencer",
type: isChangeColor type: isChangeColor
? RoundButtonType.textGradient ? RoundButtonType.textGradient
: RoundButtonType.bgGradient, : RoundButtonType.bgGradient,

@ -7,11 +7,7 @@ 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_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_info_user.dart';
import 'package:smartfit_app_mobile/common_widget/container/profile/profile_other.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/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 { class ProfileViewAllPlatforme extends StatefulWidget {
final bool offlineSave; final bool offlineSave;
@ -30,32 +26,7 @@ class _ProfileViewAllPlatforme extends State<ProfileViewAllPlatforme> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
ApiWrapper wrapper = ApiWrapper();
String username = context.watch<User>().username; 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( return Scaffold(
appBar: AppBar( appBar: AppBar(
@ -88,6 +59,8 @@ class _ProfileViewAllPlatforme extends State<ProfileViewAllPlatforme> {
const SizedBox( const SizedBox(
height: 25, height: 25,
), ),
// TODO: Download/Delete (local) all users files on toggle ?
// TODO: Display size of download in Mo
Visibility( Visibility(
visible: isNative, visible: isNative,
child: const Column( child: const Column(
@ -99,39 +72,7 @@ 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('Log out',
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('Delete your account',
style: TextStyle(color: Colors.black)),
),
],
),
const SizedBox(
height: 25,
)
], ],
), ),
), ),

@ -35,7 +35,7 @@ class ContactUsView extends StatelessWidget {
), ),
), ),
title: Text( title: Text(
"Contact us", "Nous Contacter",
style: TextStyle( style: TextStyle(
color: TColor.black, color: TColor.black,
fontSize: 16, fontSize: 16,
@ -50,16 +50,17 @@ class ContactUsView extends StatelessWidget {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
SizedBox(height: media.width * 0.02), SizedBox(height: media.width * 0.02),
const Text( const Text(
"You can contact us with any questions, suggestions or issues regarding our SmartFit app.", "Vous pouvez nous contacter pour toute question, suggestion ou problème concernant notre application SmartFit.",
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
), ),
), ),
SizedBox(height: media.width * 0.05), SizedBox(height: media.width * 0.05),
const Text( const Text(
"Email address", "Adresse e-mail",
style: TextStyle( style: TextStyle(
fontSize: 20, fontSize: 20,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@ -73,7 +74,7 @@ class ContactUsView extends StatelessWidget {
), ),
SizedBox(height: media.width * 0.02), SizedBox(height: media.width * 0.02),
const Text( const Text(
"Phone", "Téléphone",
style: TextStyle( style: TextStyle(
fontSize: 20, fontSize: 20,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@ -87,7 +88,7 @@ class ContactUsView extends StatelessWidget {
), ),
SizedBox(height: media.width * 0.02), SizedBox(height: media.width * 0.02),
const Text( const Text(
"Address", "Adresse",
style: TextStyle( style: TextStyle(
fontSize: 20, fontSize: 20,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@ -101,14 +102,14 @@ class ContactUsView extends StatelessWidget {
), ),
SizedBox(height: media.width * 0.02), SizedBox(height: media.width * 0.02),
const Text( const Text(
"Schedules", "Heures de bureau",
style: TextStyle( style: TextStyle(
fontSize: 20, fontSize: 20,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
const Text( const Text(
"Monday - Friday : 9h00 - 18h00", "Lundi - Vendredi : 9h00 - 18h00",
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
), ),

@ -52,7 +52,7 @@ class _MobileChangeEmailViewState extends State<MobileChangeEmailView> {
), ),
), ),
title: Text( title: Text(
"Change your email", "Changer son e-mail",
style: TextStyle( style: TextStyle(
color: TColor.black, fontSize: 16, fontWeight: FontWeight.w700), color: TColor.black, fontSize: 16, fontWeight: FontWeight.w700),
), ),
@ -70,7 +70,7 @@ class _MobileChangeEmailViewState extends State<MobileChangeEmailView> {
Row( Row(
children: [ children: [
Text( Text(
"Current email : ", "Ancien e-mail : ",
style: TextStyle( style: TextStyle(
color: TColor.black, color: TColor.black,
fontSize: 16, fontSize: 16,
@ -95,7 +95,7 @@ class _MobileChangeEmailViewState extends State<MobileChangeEmailView> {
child: Column( child: Column(
children: [ children: [
RoundTextField( RoundTextField(
hitText: "New email", hitText: "Nouveau e-mail",
icon: "assets/img/user_text.svg", icon: "assets/img/user_text.svg",
keyboardType: TextInputType.text, keyboardType: TextInputType.text,
controller: controllerTextEmail, controller: controllerTextEmail,
@ -110,7 +110,7 @@ class _MobileChangeEmailViewState extends State<MobileChangeEmailView> {
height: media.width * 0.01, height: media.width * 0.01,
), ),
RoundButton( RoundButton(
title: "Confirm", title: "Confirmer",
onPressed: () async { onPressed: () async {
bool res = await api.updateUserInfo( bool res = await api.updateUserInfo(
'email', 'email',

@ -56,7 +56,7 @@ class _MobileChangePasswordViewState extends State<MobileChangePasswordView> {
), ),
), ),
title: Text( title: Text(
"Change your password", "Changer son Mot de passe",
style: TextStyle( style: TextStyle(
color: TColor.black, fontSize: 16, fontWeight: FontWeight.w700), color: TColor.black, fontSize: 16, fontWeight: FontWeight.w700),
), ),
@ -80,7 +80,7 @@ class _MobileChangePasswordViewState extends State<MobileChangePasswordView> {
children: [ children: [
SizedBox(height: media.width * 0.05), SizedBox(height: media.width * 0.05),
RoundTextField( RoundTextField(
hitText: "Current password", hitText: "Ancien mot de passe",
obscureText: true, obscureText: true,
icon: "assets/img/lock.svg", icon: "assets/img/lock.svg",
keyboardType: TextInputType.text, keyboardType: TextInputType.text,
@ -89,20 +89,20 @@ class _MobileChangePasswordViewState extends State<MobileChangePasswordView> {
SizedBox(height: media.width * 0.07), SizedBox(height: media.width * 0.07),
RoundTextField( RoundTextField(
controller: controllerNewPasswd, controller: controllerNewPasswd,
hitText: "New password", hitText: "Nouveau mot de passe",
icon: "assets/img/lock.svg", icon: "assets/img/lock.svg",
obscureText: true, obscureText: true,
), ),
SizedBox(height: media.width * 0.07), SizedBox(height: media.width * 0.07),
RoundTextField( RoundTextField(
controller: controllerNewPasswd2, controller: controllerNewPasswd2,
hitText: "Confirm new password", hitText: "Confirmer nouveau mot de passe",
icon: "assets/img/lock.svg", icon: "assets/img/lock.svg",
obscureText: true, obscureText: true,
), ),
SizedBox(height: media.width * 0.07), SizedBox(height: media.width * 0.07),
RoundButton( RoundButton(
title: "Confirm", title: "Confirmer",
onPressed: () async { onPressed: () async {
Tuple2<bool, String> res = await api.login( Tuple2<bool, String> res = await api.login(
controllerActualPasswd.text, controllerActualPasswd.text,

@ -53,7 +53,7 @@ class _MobileChangeUsernameViewState extends State<MobileChangeUsernameView> {
), ),
), ),
title: Text( title: Text(
"Change your username", "Changer son pseudo",
style: TextStyle( style: TextStyle(
color: TColor.black, fontSize: 16, fontWeight: FontWeight.w700), color: TColor.black, fontSize: 16, fontWeight: FontWeight.w700),
), ),
@ -71,7 +71,7 @@ class _MobileChangeUsernameViewState extends State<MobileChangeUsernameView> {
Row( Row(
children: [ children: [
Text( Text(
"Current username: ", "Ancien pseudo : ",
style: TextStyle( style: TextStyle(
color: TColor.black, color: TColor.black,
fontSize: 16, fontSize: 16,
@ -96,7 +96,7 @@ class _MobileChangeUsernameViewState extends State<MobileChangeUsernameView> {
child: Column( child: Column(
children: [ children: [
RoundTextField( RoundTextField(
hitText: "New username", hitText: "Nouveau pseudo",
icon: "assets/img/user_text.svg", icon: "assets/img/user_text.svg",
keyboardType: TextInputType.text, keyboardType: TextInputType.text,
controller: controllerTextUsername, controller: controllerTextUsername,
@ -109,7 +109,7 @@ class _MobileChangeUsernameViewState extends State<MobileChangeUsernameView> {
TextStyle(color: infoManager.messageColor))), TextStyle(color: infoManager.messageColor))),
SizedBox(height: media.width * 0.02), SizedBox(height: media.width * 0.02),
RoundButton( RoundButton(
title: "Confirm", title: "Confirmer",
onPressed: () async { onPressed: () async {
bool res = await api.updateUserInfo( bool res = await api.updateUserInfo(
'username', 'username',

@ -14,24 +14,28 @@ class _MobileProfileView extends State<MobileProfileView> {
List accountArr = [ List accountArr = [
{ {
"image": "assets/img/p_personal.png", "image": "assets/img/p_personal.png",
"name": "Change your username", "name": "Changer son pseudo",
"tag": "1" "tag": "1"
}, },
{ {
"image": "assets/img/p_personal.png", "image": "assets/img/p_personal.png",
"name": "Change your email", "name": "Changer son email",
"tag": "3" "tag": "3"
}, },
{ {
"image": "assets/img/p_personal.png", "image": "assets/img/p_personal.png",
"name": "Change your password", "name": "Changer son mot de passe",
"tag": "2" "tag": "2"
}, },
]; ];
List otherArr = [ List otherArr = [
{"image": "assets/img/p_contact.png", "name": "Contact us", "tag": "5"}, {"image": "assets/img/p_contact.png", "name": "Nous contacter", "tag": "5"},
{"image": "assets/img/p_privacy.png", "name": "Privacy policy", "tag": "6"}, {
"image": "assets/img/p_privacy.png",
"name": "Politique de confidentialité",
"tag": "6"
},
]; ];
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

@ -35,7 +35,7 @@ class PrivacyPolicyView extends StatelessWidget {
), ),
), ),
title: Text( title: Text(
"Privacy policy", "Politique de confidentialité",
style: TextStyle( style: TextStyle(
color: TColor.black, color: TColor.black,
fontSize: 16, fontSize: 16,
@ -51,7 +51,7 @@ class PrivacyPolicyView extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
const Text( const Text(
"SmartFit privacy policy", "Politique de confidentialité de SmartFit",
style: TextStyle( style: TextStyle(
fontSize: 24, fontSize: 24,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@ -59,14 +59,14 @@ class PrivacyPolicyView extends StatelessWidget {
), ),
SizedBox(height: media.width * 0.02), SizedBox(height: media.width * 0.02),
const Text( const Text(
"This Privacy Policy explains how SmartFit collects, uses, protects and shares your information when you use our SmartFit mobile application.", "Cette Politique de confidentialité explique comment SmartFit collecte, utilise, protège et partage vos informations lorsque vous utilisez notre application mobile SmartFit.",
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
), ),
), ),
SizedBox(height: media.width * 0.05), SizedBox(height: media.width * 0.05),
const Text( const Text(
"Collect and usage of your data", "Collecte et Utilisation des Informations",
style: TextStyle( style: TextStyle(
fontSize: 20, fontSize: 20,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@ -77,7 +77,7 @@ class PrivacyPolicyView extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"SmartFit collects data solely for the purpose of analyzing and displaying information about your physical activities based on data collected by your smartwatch. This information may include, but is not limited to:", "SmartFit recueille des données uniquement dans le but d'analyser et d'afficher des informations relatives à vos activités physiques à partir des données collectées par votre montre connectée. Ces informations peuvent inclure, sans toutefois s'y limiter :",
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
), ),
@ -87,31 +87,31 @@ class PrivacyPolicyView extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
" Physical activity data (such as heart rate, number of steps, distance traveled, etc.", "• Données d'activité physique (comme la fréquence cardiaque, le nombre de pas, la distance parcourue, etc.)",
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
), ),
), ),
Text( Text(
"Sleep data", "Données sur les habitudes de sommeil",
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
), ),
), ),
Text( Text(
"GPS data", "Informations de localisation (si l'option est activée par l'utilisateur)",
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
), ),
), ),
Text( Text(
"Application parameters", "Préférences de l'utilisateur concernant les paramètres de l'application",
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
), ),
), ),
Text( Text(
"This information is used to generate graphs, statistics and personalized recommendations to help you with your fitness goals.", "Ces informations sont utilisées pour générer des graphiques, des statistiques et des recommandations personnalisées afin de vous aider dans vos objectifs de remise en forme.",
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
), ),
@ -122,7 +122,7 @@ class PrivacyPolicyView extends StatelessWidget {
), ),
SizedBox(height: media.width * 0.05), SizedBox(height: media.width * 0.05),
const Text( const Text(
"Information protection", "Protection des Informations",
style: TextStyle( style: TextStyle(
fontSize: 20, fontSize: 20,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,

@ -52,7 +52,7 @@ class _WebChangeEmailViewState extends State<WebChangeEmailView> {
), ),
), ),
title: Text( title: Text(
"Change you email", "Changer son email",
style: TextStyle( style: TextStyle(
color: TColor.black, fontSize: 16, fontWeight: FontWeight.w700), color: TColor.black, fontSize: 16, fontWeight: FontWeight.w700),
), ),
@ -70,7 +70,7 @@ class _WebChangeEmailViewState extends State<WebChangeEmailView> {
Row( Row(
children: [ children: [
Text( Text(
"Current email: ", "Email actuel : ",
style: TextStyle( style: TextStyle(
color: TColor.black, color: TColor.black,
fontSize: 16, fontSize: 16,
@ -95,7 +95,7 @@ class _WebChangeEmailViewState extends State<WebChangeEmailView> {
child: Column( child: Column(
children: [ children: [
RoundTextField( RoundTextField(
hitText: "New email", hitText: "Nouveau email",
icon: "assets/img/user_text.svg", icon: "assets/img/user_text.svg",
keyboardType: TextInputType.text, keyboardType: TextInputType.text,
controller: controllerTextEmail, controller: controllerTextEmail,
@ -108,7 +108,7 @@ class _WebChangeEmailViewState extends State<WebChangeEmailView> {
TextStyle(color: infoManager.messageColor))), TextStyle(color: infoManager.messageColor))),
SizedBox(height: media.width * 0.03), SizedBox(height: media.width * 0.03),
RoundButton( RoundButton(
title: "Confirm", title: "Confirmer",
onPressed: () async { onPressed: () async {
bool res = await apiWrapper.updateUserInfo( bool res = await apiWrapper.updateUserInfo(
'email', 'email',

@ -55,7 +55,7 @@ class _WebChangePasswordViewState extends State<WebChangePasswordView> {
), ),
), ),
title: Text( title: Text(
"Change password", "Changer son Mot de passe",
style: TextStyle( style: TextStyle(
color: TColor.black, fontSize: 16, fontWeight: FontWeight.w700), color: TColor.black, fontSize: 16, fontWeight: FontWeight.w700),
), ),
@ -78,7 +78,7 @@ class _WebChangePasswordViewState extends State<WebChangePasswordView> {
child: Column( child: Column(
children: [ children: [
RoundTextField( RoundTextField(
hitText: "Current password", hitText: "Ancien mot de passe",
obscureText: true, obscureText: true,
icon: "assets/img/lock.svg", icon: "assets/img/lock.svg",
keyboardType: TextInputType.text, keyboardType: TextInputType.text,
@ -87,14 +87,14 @@ class _WebChangePasswordViewState extends State<WebChangePasswordView> {
SizedBox(height: media.width * 0.02), SizedBox(height: media.width * 0.02),
RoundTextField( RoundTextField(
controller: controllerNewPasswd, controller: controllerNewPasswd,
hitText: "New password", hitText: "Nouveau mot de passe",
icon: "assets/img/lock.svg", icon: "assets/img/lock.svg",
obscureText: true, obscureText: true,
), ),
SizedBox(height: media.width * 0.02), SizedBox(height: media.width * 0.02),
RoundTextField( RoundTextField(
controller: controllerNewPasswd2, controller: controllerNewPasswd2,
hitText: "Confirm new password", hitText: "Confirmer nouveau mot de passe",
icon: "assets/img/lock.svg", icon: "assets/img/lock.svg",
obscureText: true, obscureText: true,
), ),
@ -105,7 +105,7 @@ class _WebChangePasswordViewState extends State<WebChangePasswordView> {
TextStyle(color: infoManager.messageColor))), TextStyle(color: infoManager.messageColor))),
SizedBox(height: media.width * 0.04), SizedBox(height: media.width * 0.04),
RoundButton( RoundButton(
title: "Confirm", title: "Confirmer",
onPressed: () async { onPressed: () async {
Tuple2<bool, String> res = await api.login( Tuple2<bool, String> res = await api.login(
controllerActualPasswd.text, controllerActualPasswd.text,

@ -52,7 +52,7 @@ class _WebChangeUsernameViewState extends State<WebChangeUsernameView> {
), ),
), ),
title: Text( title: Text(
"Change your username", "Changer son pseudo",
style: TextStyle( style: TextStyle(
color: TColor.black, fontSize: 16, fontWeight: FontWeight.w700), color: TColor.black, fontSize: 16, fontWeight: FontWeight.w700),
), ),
@ -70,7 +70,7 @@ class _WebChangeUsernameViewState extends State<WebChangeUsernameView> {
Row( Row(
children: [ children: [
Text( Text(
"Current username: ", "Ancien pseudo : ",
style: TextStyle( style: TextStyle(
color: TColor.black, color: TColor.black,
fontSize: 16, fontSize: 16,
@ -95,7 +95,7 @@ class _WebChangeUsernameViewState extends State<WebChangeUsernameView> {
child: Column( child: Column(
children: [ children: [
RoundTextField( RoundTextField(
hitText: "New username", hitText: "Nouveau pseudo",
icon: "assets/img/user_text.svg", icon: "assets/img/user_text.svg",
keyboardType: TextInputType.text, keyboardType: TextInputType.text,
controller: controllerTextUsername, controller: controllerTextUsername,
@ -110,7 +110,7 @@ class _WebChangeUsernameViewState extends State<WebChangeUsernameView> {
TextStyle(color: infoManager.messageColor))), TextStyle(color: infoManager.messageColor))),
SizedBox(height: media.width * 0.04), SizedBox(height: media.width * 0.04),
RoundButton( RoundButton(
title: "Confirm", title: "Confirmer",
onPressed: () async { onPressed: () async {
bool res = await api.updateUserInfo( bool res = await api.updateUserInfo(
'username', 'username',

@ -14,24 +14,32 @@ class _WebProfileView extends State<WebProfileView> {
List accountArr = [ List accountArr = [
{ {
"image": "assets/img/p_personal.png", "image": "assets/img/p_personal.png",
"name": "Change your username", "name": "Changer son pseudo ",
"tag": "1" "tag": "1"
}, },
{ {
"image": "assets/img/p_personal.png", "image": "assets/img/p_personal.png",
"name": "Change your email", "name": "Changer son email ",
"tag": "3" "tag": "3"
}, },
{ {
"image": "assets/img/p_personal.png", "image": "assets/img/p_personal.png",
"name": "Changer your password", "name": "Changer son mot de passe ",
"tag": "2" "tag": "2"
}, },
]; ];
List otherArr = [ List otherArr = [
{"image": "assets/img/p_contact.png", "name": "Contact us !", "tag": "5"}, {
{"image": "assets/img/p_privacy.png", "name": "Privacy policy", "tag": "6"}, "image": "assets/img/p_contact.png",
"name": "Nous contacter !!",
"tag": "5"
},
{
"image": "assets/img/p_privacy.png",
"name": "Politique de confidentialité",
"tag": "6"
},
]; ];
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

@ -48,7 +48,7 @@ class _VolumesViews extends State<VolumesView> {
height: media.width * 0.05, height: media.width * 0.05,
), ),
Text( Text(
"Last week: ${date.day}/${date.month}/${date.year} - ${date.subtract(const Duration(days: 7)).day}/${date.subtract(const Duration(days: 7)).month}/${date.subtract(const Duration(days: 7)).year}", "Derniere semaine : ${date.day}/${date.month}/${date.year} - ${date.subtract(const Duration(days: 7)).day}/${date.subtract(const Duration(days: 7)).month}/${date.subtract(const Duration(days: 7)).year}",
style: TextStyle( style: TextStyle(
color: TColor.black, color: TColor.black,
fontSize: 16, fontSize: 16,
@ -62,7 +62,7 @@ class _VolumesViews extends State<VolumesView> {
height: media.width * 0.03, height: media.width * 0.03,
), ),
Text( Text(
"Last month: ${date.day}/${date.month}/${date.year} - ${date.subtract(const Duration(days: 30)).day}/${date.subtract(const Duration(days: 30)).month}/${date.subtract(const Duration(days: 30)).year}", "Dernier Mois : ${date.day}/${date.month}/${date.year} - ${date.subtract(const Duration(days: 30)).day}/${date.subtract(const Duration(days: 30)).month}/${date.subtract(const Duration(days: 30)).year}",
style: TextStyle( style: TextStyle(
color: TColor.black, color: TColor.black,
fontSize: 16, fontSize: 16,
@ -73,7 +73,7 @@ class _VolumesViews extends State<VolumesView> {
height: media.width * 0.03, height: media.width * 0.03,
), ),
Text( Text(
"Last year: ${date.day}/${date.month}/${date.year} - ${date.subtract(const Duration(days: 366)).day}/${date.subtract(const Duration(days: 366)).month}/${date.subtract(const Duration(days: 366)).year}", "Dernière année : ${date.day}/${date.month}/${date.year} - ${date.subtract(const Duration(days: 366)).day}/${date.subtract(const Duration(days: 366)).month}/${date.subtract(const Duration(days: 366)).year}",
style: TextStyle( style: TextStyle(
color: TColor.black, color: TColor.black,
fontSize: 16, fontSize: 16,

@ -5,25 +5,17 @@
// gestures. You can also use WidgetTester to find child widgets in the widget // 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. // 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:flutter_test/flutter_test.dart';
import 'package:smartfit_app_mobile/main.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() { void main() {
testWidgets('Test login', (WidgetTester tester) async { testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame. // Build our app and trigger a frame.
//await tester.pumpWidget(const MyApp()); await tester.pumpWidget(const MyApp());
//expect(find.text('Se connecter'), findsOneWidget); // Verify that our counter starts at 0.
/*
expect(find.text('0'), findsOneWidget); expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing); expect(find.text('1'), findsNothing);
@ -33,40 +25,6 @@ void main() {
// Verify that our counter has incremented. // Verify that our counter has incremented.
expect(find.text('0'), findsNothing); 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