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 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-web
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!
TODO: Description + badge
TODO: Description
## Getting Started

@ -12,7 +12,7 @@ class VolumesList extends StatelessWidget {
// TODO: True message with variables and context aware
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(
@ -21,32 +21,32 @@ class VolumesList extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.center,
children: [
ContainerStatsActivities(volume["nbActivity"].toString(),
"Number of activities", Icons.numbers),
"Nombre Activitée(s)", Icons.numbers),
SizedBox(
width: media.width * 0.03,
),
ContainerStatsActivities(
"${Convertisseur.secondeIntoMinute(volume["durationActiviy"]).toStringAsFixed(0)} min",
"Total time",
"${Convertisseur.secondeIntoMinute(volume["durationActiviy"]).toStringAsFixed(2)} m",
"Temps Total",
Icons.timer),
SizedBox(
width: media.width * 0.03,
),
ContainerStatsActivities(
volume["bpmAvg"].toString(), "Average bpm", Icons.favorite),
volume["bpmAvg"].toString(), "Bpm Moyens", Icons.favorite),
SizedBox(
width: media.width * 0.03,
),
ContainerStatsActivities(
" ${Convertisseur.msIntoKmh(volume["speedAvg"]).toStringAsFixed(2)} km/h",
"Average speed",
"Vitesse Moyenne",
Icons.bolt),
SizedBox(
width: media.width * 0.03,
),
ContainerStatsActivities(
"${volume["denivelePositif"].toStringAsFixed(2)} m",
"Positive height difference",
"Dénivelé Positif",
Icons.hiking),
],
),

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

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

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

@ -13,7 +13,7 @@ class ProfileInfoUser extends StatelessWidget {
Expanded(
child: TitleSubtitleCell(
title: context.watch<User>().listActivity.length.toString(),
subtitle: "Number of activities",
subtitle: "Nombre d'activité",
),
),
const SizedBox(
@ -21,11 +21,8 @@ class ProfileInfoUser extends StatelessWidget {
),
Expanded(
child: TitleSubtitleCell(
title: context
.watch<User>()
.getTotalTimeAllActivity()
.toStringAsFixed(2),
subtitle: "Total activity time",
title: context.watch<User>().getTotalTimeAllActivity().toStringAsFixed(2),
subtitle: "Temps en activité",
),
),
const SizedBox(
@ -35,7 +32,7 @@ class ProfileInfoUser extends StatelessWidget {
child: TitleSubtitleCell(
title:
"${context.watch<User>().getTotalDenivelePositifAllActivity().toStringAsFixed(2)} + m",
subtitle: "Total positive height difference",
subtitle: "Total dénivelé positif",
),
),
const SizedBox(
@ -45,7 +42,7 @@ class ProfileInfoUser extends StatelessWidget {
child: TitleSubtitleCell(
title:
"${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,
children: [
Text(
"Others",
"Autre",
style: TextStyle(
color: TColor.black,
fontSize: 16,

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

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

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

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

@ -36,8 +36,75 @@ class _MobileGraphBpmAndSpeedByTime
width: double.maxFinite,
child: LineChart(
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,
minY: 0,
maxY: 110,

@ -33,7 +33,75 @@ class _WebGraphBpmAndSpeedByTime extends State<WebGraphBpmAndSpeedByTime> {
width: widget.media.width * 0.35,
child: LineChart(
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,
minY: -10,
maxY: 110,

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

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

@ -1,3 +1,4 @@
import 'package:flutter_svg/flutter_svg.dart';
import 'package:smartfit_app_mobile/common/colo_extension.dart';
import 'package:flutter/material.dart';
@ -6,11 +7,7 @@ class TodayTargetCell extends StatelessWidget {
final String icon;
final String value;
final String title;
const TodayTargetCell(
{super.key,
required this.icon,
required this.value,
required this.title});
const TodayTargetCell({super.key, required this.icon, required this.value, required this.title});
@override
Widget build(BuildContext context) {
@ -68,4 +65,3 @@ class TodayTargetCell extends StatelessWidget {
);
}
}

@ -270,18 +270,7 @@ class ActivityInfo {
// -- BPM -- //
int bpmSomme = 0;
int bpmNb = 0;
// -- Denivelé -- //
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;
bool bpmNotZero = false;
// --- Boucle -- //
for (int i = 1; i < csv.length; i++) {
//
@ -299,78 +288,12 @@ class ActivityInfo {
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 -- //
if (bpmNotZero) {
bpmAvg = bpmSomme ~/ bpmNb;
}
// -- Atitude -- //
if (altitudeNotZero) {
altitudeAvg = altitudeSomme / alititudeNb;
}
// -- Température -- //
if (temperatureNotZero) {
temperatureAvg = temperatureSomme ~/ temperatureNb;
}
// -- Vitesse -- //
if (vitesseNotZero) {
vitesseAvg = vitesseSomme / vitesseNb;
}
return this;
}

@ -193,16 +193,6 @@ class ApiWrapper {
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 {

@ -42,7 +42,4 @@ abstract class IDataStrategy {
// Update email, password, username
Future<Tuple2<bool, String>> modifAttribut(
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());
}
if (response.statusCode == 401) {
return const Tuple2<bool, String>(
false, "Wrong Password, enter it carrefully !");
return const Tuple2<bool, String>(false, "UNAUTHORIZED");
}
if (response.statusCode == 404) {
return const Tuple2<bool, String>(
false, "Account not found, please verify your credentials.");
return const Tuple2<bool, String>(false, "Not found the email");
}
} on SocketException catch (_) {
return const Tuple2(false, "No connection");
@ -138,12 +136,11 @@ class RequestApi implements IDataStrategy {
return Tuple2(true, json['token'].toString());
}
if (response.statusCode == 400) {
return const Tuple2(false,
"L'application rendontre une erreur inconnue, veuillez réessayer.");
return const Tuple2(false, "400 BAD REQUEST - Json mal formaté");
}
if (response.statusCode == 409) {
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 (_) {
return const Tuple2(false, "No connection");
@ -271,7 +268,6 @@ class RequestApi implements IDataStrategy {
headers: <String, String>{'Authorization': token});
if (response.statusCode == 200) {
Map<String, dynamic> json = jsonDecode(response.body);
return Tuple2(true, json);
}
if (response.statusCode == 400) {
@ -285,21 +281,4 @@ class RequestApi implements IDataStrategy {
}
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
static double secondeIntoMinute(double seconde) {
return (seconde / 60);
}
static double milisecondeIntoMinute(double miliseconde) {
return (miliseconde / 60000);
return seconde / 60;
}
static double msIntoKmh(double metreSeconde) {
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 {
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
String get marche => _marche;
String get velo => _velo;
String get generic => _generic;
List<String> allowedFieldWalking = List.empty(growable: true);
@ -62,16 +61,7 @@ class ManagerFile {
_fieldTemperature
];
allowedFieldGeneric = [
_fieldTimestamp,
_fieldPositionLatitue,
_fieldPositionLongitude,
_fieldDistance,
_fieldBPM,
_fieldSpeed,
_fieldAltitude,
_fieldTemperature
];
allowedFieldGeneric = [_fieldTimestamp, _fieldBPM];
allowedFieldCycling = [
_fieldTimestamp,
@ -159,8 +149,6 @@ class ManagerFile {
info.getDataWalking(csvData);
case (_velo):
info.getDataCycling(csvData);
case (_generic):
info.getDataGeneric(csvData);
default:
info.getDataGeneric(csvData);
}

@ -3,10 +3,7 @@ import 'dart:convert';
import 'package:flutter/material.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/manager_selected_activity.dart';
import 'package:smartfit_app_mobile/modele/utile/info_message.dart';
import 'package:tuple/tuple.dart';
class User extends ChangeNotifier {
String username = "VOID";
@ -94,27 +91,26 @@ class User extends ChangeNotifier {
return map;
}
Future<Tuple2<bool, ActivityInfo>> predictActivity(
DateTime date, String category, InfoMessage infoManager) async {
ApiWrapper wrapper = ApiWrapper();
Tuple2 result = await wrapper.getModeleAI(token, category, infoManager);
if (!result.item1) return Tuple2(false, ActivityInfo());
String model = result.item2["model"];
Map<String, dynamic> jsonMap = json.decode(model);
ActivityInfo predictActivity(DateTime date) {
// Appel pour avoir le model
String jsonString =
'{"coef": [270.63861280635473, 74.69699263779908, 1.9946527172333637, 0.03215810401413792, 0.3256805192289063], "intercept": [-335635.9890148213, -91874.0527070619, -2065.450392327813, -38.79838022998388, -291.590235396687]}';
Map<String, dynamic> jsonMap = json.decode(jsonString);
// Transformer la date
int dateMilli = date.millisecondsSinceEpoch;
ActivityInfo activityInfo = ActivityInfo();
activityInfo.bpmAvg =
(jsonMap["coef"][0] * dateMilli + jsonMap["intercept"][0]).toInt();
activityInfo.distance =
jsonMap["coef"][0] * dateMilli + jsonMap["intercept"][0];
activityInfo.timeOfActivity =
jsonMap["coef"][1] * dateMilli + jsonMap["intercept"][1];
activityInfo.vitesseAvg =
activityInfo.denivelePositif =
jsonMap["coef"][2] * dateMilli + jsonMap["intercept"][2];
activityInfo.distance =
activityInfo.vitesseAvg =
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);
List<FlSpot> bpmSecondes2 = List.from(bpmSecondes);
return DataHomeView(
normaliserPremierElement(bpmSecondes),
normaliserPremierElement(normaliserDeuxiemeElement(bpmSecondes2)),
normaliserPremierElement(normaliserDeuxiemeElement(vitesseSecondes)),
normaliserPremierElement(altitudeSeconde));
return DataHomeView(normaliserPremierElement(bpmSecondes), normaliserPremierElement(normaliserDeuxiemeElement(bpmSecondes2)),
normaliserPremierElement(normaliserDeuxiemeElement(vitesseSecondes)), normaliserPremierElement(altitudeSeconde));
}
List<FlSpot> normaliserDeuxiemeElement(List<FlSpot> liste) {
@ -43,7 +41,6 @@ class HomeViewUtil {
}
return liste;
}
List<FlSpot> normaliserPremierElement(List<FlSpot> liste) {
// Trouver le plus grand élément dans le premier élément de chaque FlSpot
double maxElement = 0.0;
@ -60,4 +57,5 @@ class HomeViewUtil {
}
return liste;
}
}

@ -5,6 +5,7 @@ import 'package:smartfit_app_mobile/modele/activity_saver.dart';
import 'package:smartfit_app_mobile/modele/helper.dart';
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:csv/csv.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
@ -90,10 +91,6 @@ class ListActivityUtile {
String csvString = const ListToCsvConverter().convert(resultData.item2);
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(
token,
byteCSV,

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

@ -36,7 +36,7 @@ class _MobileListActivity extends State<MobileListActivity> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Activity List",
"List Activités",
style: TextStyle(
color: TColor.black,
fontSize: 16,
@ -74,7 +74,7 @@ class _MobileListActivity extends State<MobileListActivity> {
setState(() {});
},
child: Text(
"Add",
"Ajouter",
style: TextStyle(
color: TColor.gray,
fontSize: 14,
@ -93,7 +93,7 @@ class _MobileListActivity extends State<MobileListActivity> {
children: [
const SizedBox(height: 20),
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(
color: TColor.gray,
fontSize: 11,

@ -36,7 +36,7 @@ class _WebListActivityState extends State<WebListActivity> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Activity List",
"List Activités",
style: TextStyle(
color: TColor.black,
fontSize: 16,
@ -73,7 +73,7 @@ class _WebListActivityState extends State<WebListActivity> {
}
},
child: Text(
"Add",
"Ajouter",
style: TextStyle(
color: TColor.gray,
fontSize: 14,
@ -92,7 +92,7 @@ class _WebListActivityState extends State<WebListActivity> {
children: [
const SizedBox(height: 20),
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(
color: TColor.gray,
fontSize: 11,

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

@ -49,7 +49,7 @@ class _NoActivityViewState extends State<NoActivityView> {
),
),
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,
style: TextStyle(color: TColor.gray, fontSize: 12),
),

@ -1,15 +1,8 @@
import 'package:flutter/material.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_widget/button/round_button.dart';
import 'package:smartfit_app_mobile/common_widget/container/workout_row/workout_row.dart';
import 'package:smartfit_app_mobile/modele/activity_info/activity_info.dart';
import 'package:smartfit_app_mobile/modele/convertisseur.dart';
import 'package:smartfit_app_mobile/modele/manager_file.dart';
import 'package:smartfit_app_mobile/modele/user.dart';
import 'package:smartfit_app_mobile/modele/utile/info_message.dart';
import 'package:tuple/tuple.dart';
class Prediction extends StatefulWidget {
const Prediction({Key? key}) : super(key: key);
@ -21,85 +14,61 @@ class Prediction extends StatefulWidget {
class _PredictionState extends State<Prediction> {
List<Map<String, dynamic>> lastWorkoutArr = [
{
"name": "Time",
"name": "Temps",
"image": "assets/img/time-icon2.svg",
"value": "..",
"value": "200 s",
},
{
"name": "Heart rate",
"name": "Rythme cardiaque",
"image": "assets/img/bpm2-icon.svg",
"value": "..",
"value": "120 BPM",
},
{
"name": "Speed",
"name": "Vitesse",
"image": "assets/img/vitesse2-icon.svg",
"value": "..",
"value": "3 m/s",
},
{
"name": "Distance",
"image": "assets/img/distance2-icon.svg",
"value": "..",
"value": "300 m",
}
];
final ManagerFile _managerFile = ManagerFile();
String selectedCategory = "Select an activity category";
@override
Widget build(BuildContext context) {
List<String> listCategory = [_managerFile.marche, _managerFile.velo];
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";
});
}
var media = MediaQuery.of(context).size;
return Scaffold(
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
padding: EdgeInsets.symmetric(horizontal: 20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 40),
SizedBox(height: 40),
Text(
"Prediction",
"Prédiction",
style: TextStyle(
color: TColor.black,
fontSize: 22,
fontWeight: FontWeight.w700,
),
),
const SizedBox(height: 20),
const Row(
children: [],
SizedBox(height: 20),
Row(
children: [
],
),
Container(
decoration: BoxDecoration(
color: TColor.lightGray,
boxShadow: [
BoxShadow(
color: const Color.fromARGB(255, 234, 234, 234)
.withOpacity(0.9),
color: Color.fromARGB(255, 234, 234, 234).withOpacity(0.9),
spreadRadius: 2,
blurRadius: 5,
offset: const Offset(0, 2),
offset: Offset(0, 2),
),
],
borderRadius: BorderRadius.circular(15),
@ -121,7 +90,7 @@ class _PredictionState extends State<Prediction> {
Expanded(
child: DropdownButtonHideUnderline(
child: DropdownButton(
items: listCategory
items: ["Walking", "Cycling"]
.map((name) => DropdownMenuItem(
value: name,
child: Text(
@ -133,14 +102,10 @@ class _PredictionState extends State<Prediction> {
),
))
.toList(),
onChanged: (value) {
setState(() {
selectedCategory = value!;
});
},
onChanged: (value) {},
isExpanded: true,
hint: Text(
selectedCategory,
"Choisir type d'activité",
style: TextStyle(
color: TColor.gray,
fontSize: 12,
@ -150,23 +115,25 @@ class _PredictionState extends State<Prediction> {
),
),
// Bouton "Valider" prenant 30% de la largeur du parent
],
),
),
const SizedBox(height: 20),
SizedBox(height: 20),
RoundButton(
title: "Save",
title: "Valider",
onPressed: () async {
prediction();
setState(() {});
}),
const SizedBox(height: 20),
SizedBox(height: 20),
ListView.builder(
padding: EdgeInsets.zero,
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: lastWorkoutArr.length,
itemBuilder: (context, index) {
var wObj = lastWorkoutArr[index];
var wObj =
lastWorkoutArr[index] as Map<String, dynamic> ?? {};
return InkWell(
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/other/entete_home_view.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/user.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
.watch<User>()
.managerSelectedActivity
.getMaxSpeedAllActivitySelected();
.getMaxAltitudeAllActivitySelected();
double minSpeed = context
.watch<User>()
.managerSelectedActivity
.getMinSpeedAllActivitySelected();
.getMinAltitudeAllActivitySelected();
return Scaffold(
backgroundColor: TColor.white,
@ -107,7 +106,7 @@ class _StatAtivities extends State<StatAtivities> {
height: media.width * 0.05,
),
Text(
"Activity Status",
"Status d'activité",
style: TextStyle(
color: TColor.black,
fontSize: 16,
@ -120,17 +119,17 @@ class _StatAtivities extends State<StatAtivities> {
mainAxisAlignment: MainAxisAlignment.center,
children: [
ContainerStatsActivities(
"$avgBpm BPM", "Average bpm", Icons.favorite),
"$avgBpm BPM", "Moyenne Bpm", Icons.favorite),
SizedBox(
width: media.width * 0.03,
),
ContainerStatsActivities(
"$maxBpm BPM", "Maximum bpm", Icons.trending_up),
"$maxBpm BPM", "Maximum Bpm", Icons.trending_up),
SizedBox(
width: media.width * 0.03,
),
ContainerStatsActivities(
"$minBpm BPM", "Minimum bpm", Icons.trending_down)
"$minBpm BPM", "Minimum Bpm", Icons.trending_down)
],
),
SizedBox(
@ -140,23 +139,17 @@ class _StatAtivities extends State<StatAtivities> {
mainAxisAlignment: MainAxisAlignment.center,
children: [
ContainerStatsActivities(
"${Convertisseur.msIntoKmh(avgSpeed).toStringAsFixed(0)} km/h",
"Average speed",
Icons.bolt),
"${avgSpeed.toStringAsFixed(2)} m/s", "Moyenne vitesse", Icons.bolt),
SizedBox(
width: media.width * 0.03,
),
ContainerStatsActivities(
"${Convertisseur.msIntoKmh(maxSpeed).toStringAsFixed(0)} km/h",
"Maximum speed",
Icons.trending_up),
"$maxSpeed m/s", "Maximum vitesse", Icons.trending_up),
SizedBox(
width: media.width * 0.03,
),
ContainerStatsActivities(
"${Convertisseur.msIntoKmh(minSpeed).toStringAsFixed(0)} km/h",
"Minimum speed",
Icons.trending_down)
"$minSpeed m/s", "Minimum vitesse", Icons.trending_down)
],
),
SizedBox(
@ -166,7 +159,7 @@ class _StatAtivities extends State<StatAtivities> {
mainAxisAlignment: MainAxisAlignment.center,
children: [
ContainerStatsActivities("$avgTemperature °C",
"Average Temperature", Icons.thermostat),
"Moyenne Temperature", Icons.thermostat),
SizedBox(
width: media.width * 0.03,
),
@ -186,19 +179,17 @@ class _StatAtivities extends State<StatAtivities> {
mainAxisAlignment: MainAxisAlignment.center,
children: [
ContainerStatsActivities(
"${avgAltitude.toStringAsFixed(2)} m",
"Average altitude",
Icons.landscape),
"${avgAltitude.toStringAsFixed(2)} m", "Moyenne Altitude", Icons.landscape),
SizedBox(
width: media.width * 0.03,
),
ContainerStatsActivities("$maxAltitude m",
"Maximum altitude", Icons.trending_up),
"Maximum Altitude", Icons.trending_up),
SizedBox(
width: media.width * 0.03,
),
ContainerStatsActivities("$minAltitude m",
"Minimum altitude", Icons.trending_down)
"Minimum Altitude", Icons.trending_down)
],
),
SizedBox(
@ -208,12 +199,12 @@ class _StatAtivities extends State<StatAtivities> {
mainAxisAlignment: MainAxisAlignment.center,
children: [
ContainerStatsActivities("$getTotalDistance m",
"Total distance", Icons.double_arrow),
"Distance Totale", Icons.double_arrow),
SizedBox(
width: media.width * 0.03,
),
ContainerStatsActivities("$totalSteps", "Total steps",
Icons.do_not_step_rounded),
ContainerStatsActivities(
"$totalSteps", "Total Pas", Icons.do_not_step_rounded),
],
),
SizedBox(
@ -223,14 +214,12 @@ class _StatAtivities extends State<StatAtivities> {
mainAxisAlignment: MainAxisAlignment.center,
children: [
ContainerStatsActivities(
"${Convertisseur.secondeIntoMinute(totalTime)} min",
"Total time",
Icons.timer),
"$totalTime s", "Temps Total", Icons.timer),
SizedBox(
width: media.width * 0.03,
),
ContainerStatsActivities("$totalCalories kCal",
"Burned calories", Icons.local_fire_department),
"Calories Dépensées", Icons.local_fire_department),
],
),
SizedBox(

@ -76,9 +76,11 @@ class _WebHomeView extends State<WebHomeView> {
height: media.width * 0.03,
),
Column(mainAxisAlignment: MainAxisAlignment.center, children: [
Column(mainAxisAlignment: MainAxisAlignment.center, children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Activity status",
"Status d'activité",
style: TextStyle(
color: TColor.black,
fontSize: 16,
@ -87,7 +89,8 @@ class _WebHomeView extends State<WebHomeView> {
SizedBox(
height: media.width * 0.02,
),
Row(mainAxisAlignment: MainAxisAlignment.center, children: [
Row(mainAxisAlignment: MainAxisAlignment.center,
children: [
BpmByTime(media, data),
SizedBox(
width: media.width * 0.01,
@ -98,7 +101,7 @@ class _WebHomeView extends State<WebHomeView> {
"${avgBpm.toString()} BPM",
"Minimum",
"Maximum",
"Average",
"Moyenne",
Icons.trending_down,
Icons.trending_up,
Icons.favorite_outline),
@ -107,9 +110,11 @@ class _WebHomeView extends State<WebHomeView> {
SizedBox(
height: media.width * 0.05,
),
Column(mainAxisAlignment: MainAxisAlignment.center, children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Heart rate and speed",
"Rythme cardique et vitesse",
style: TextStyle(
color: TColor.black,
fontSize: 16,
@ -118,7 +123,9 @@ class _WebHomeView extends State<WebHomeView> {
SizedBox(
height: media.width * 0.03,
),
Row(mainAxisAlignment: MainAxisAlignment.center, children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
GraphBpmAndSpeedByTime(media, data),
SizedBox(
height: media.width * 0.05,
@ -127,9 +134,9 @@ class _WebHomeView extends State<WebHomeView> {
"${double.parse(maxSpeed.toStringAsFixed(2))} m/s",
"${double.parse(avgSpeed.toStringAsFixed(2))} m/s",
"${avgBpm.toString()} BPM",
"Max speed",
"Moy speed",
"Avg bpm",
"Max vitesse",
"Moy vitesse",
"Moy Bpm",
Icons.trending_up,
Icons.bolt,
Icons.favorite_outline),
@ -157,7 +164,7 @@ class _WebHomeView extends State<WebHomeView> {
"${avgAltitude.toInt()} m",
"Minimum",
"Maximum",
"Average",
"Moyenne",
Icons.trending_down,
Icons.trending_up,
Icons.favorite_outline),
@ -166,6 +173,7 @@ class _WebHomeView extends State<WebHomeView> {
),
),
),
);
}
}

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

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

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

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

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

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

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

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

@ -27,21 +27,21 @@ class _OnBoardingViewState extends State<OnBoardingView> {
List pageArr = [
{
"title": "Achieve your goals",
"title": "Atteignez vos objectifs",
"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"
},
{
"title": "Persévérez",
"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"
},
{
"title": "Let us pilot, just put on your Suunto",
"title": "Laissez-nous piloter, mettez simplement votre Suunto",
"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"
},
];

@ -41,7 +41,7 @@ class _StartedViewState extends State<StartedView> {
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: RoundButton(
title: "Start",
title: "Commencer",
type: isChangeColor
? RoundButtonType.textGradient
: 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_info_user.dart';
import 'package:smartfit_app_mobile/common_widget/container/profile/profile_other.dart';
import 'package:smartfit_app_mobile/modele/api/api_wrapper.dart';
import 'package:smartfit_app_mobile/modele/user.dart';
import 'package:smartfit_app_mobile/modele/utile/info_message.dart';
import 'package:smartfit_app_mobile/view/login/signup_view.dart';
import 'package:tuple/tuple.dart';
class ProfileViewAllPlatforme extends StatefulWidget {
final bool offlineSave;
@ -30,32 +26,7 @@ class _ProfileViewAllPlatforme extends State<ProfileViewAllPlatforme> {
@override
Widget build(BuildContext context) {
ApiWrapper wrapper = ApiWrapper();
String username = context.watch<User>().username;
InfoMessage infoManager = InfoMessage();
void logOff() {
// Appel ici pour logOff
/*
if (!result.item1) {
// Affiché erreur
} else {
Navigator.push(context,
MaterialPageRoute(builder: (context) => const LoginView()));
}*/
}
void deleteUser() async {
// Ne marche pas !!
Tuple2 result = await wrapper.deleteUser(
Provider.of<User>(context, listen: false).token, infoManager);
if (!result.item1) {
// Affiché erreur
} else {
Navigator.push(context,
MaterialPageRoute(builder: (context) => const SignUpView()));
}
}
return Scaffold(
appBar: AppBar(
@ -88,6 +59,8 @@ class _ProfileViewAllPlatforme extends State<ProfileViewAllPlatforme> {
const SizedBox(
height: 25,
),
// TODO: Download/Delete (local) all users files on toggle ?
// TODO: Display size of download in Mo
Visibility(
visible: isNative,
child: const Column(
@ -99,39 +72,7 @@ class _ProfileViewAllPlatforme extends State<ProfileViewAllPlatforme> {
)
],
)),
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,
)
ProfileOther(widget.otherArr)
],
),
),

@ -35,7 +35,7 @@ class ContactUsView extends StatelessWidget {
),
),
title: Text(
"Contact us",
"Nous Contacter",
style: TextStyle(
color: TColor.black,
fontSize: 16,
@ -50,16 +50,17 @@ class ContactUsView extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SizedBox(height: media.width * 0.02),
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(
fontSize: 16,
),
),
SizedBox(height: media.width * 0.05),
const Text(
"Email address",
"Adresse e-mail",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
@ -73,7 +74,7 @@ class ContactUsView extends StatelessWidget {
),
SizedBox(height: media.width * 0.02),
const Text(
"Phone",
"Téléphone",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
@ -87,7 +88,7 @@ class ContactUsView extends StatelessWidget {
),
SizedBox(height: media.width * 0.02),
const Text(
"Address",
"Adresse",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
@ -101,14 +102,14 @@ class ContactUsView extends StatelessWidget {
),
SizedBox(height: media.width * 0.02),
const Text(
"Schedules",
"Heures de bureau",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
const Text(
"Monday - Friday : 9h00 - 18h00",
"Lundi - Vendredi : 9h00 - 18h00",
style: TextStyle(
fontSize: 16,
),

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

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

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

@ -14,24 +14,28 @@ class _MobileProfileView extends State<MobileProfileView> {
List accountArr = [
{
"image": "assets/img/p_personal.png",
"name": "Change your username",
"name": "Changer son pseudo",
"tag": "1"
},
{
"image": "assets/img/p_personal.png",
"name": "Change your email",
"name": "Changer son email",
"tag": "3"
},
{
"image": "assets/img/p_personal.png",
"name": "Change your password",
"name": "Changer son mot de passe",
"tag": "2"
},
];
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
Widget build(BuildContext context) {

@ -35,7 +35,7 @@ class PrivacyPolicyView extends StatelessWidget {
),
),
title: Text(
"Privacy policy",
"Politique de confidentialité",
style: TextStyle(
color: TColor.black,
fontSize: 16,
@ -51,7 +51,7 @@ class PrivacyPolicyView extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Text(
"SmartFit privacy policy",
"Politique de confidentialité de SmartFit",
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
@ -59,14 +59,14 @@ class PrivacyPolicyView extends StatelessWidget {
),
SizedBox(height: media.width * 0.02),
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(
fontSize: 16,
),
),
SizedBox(height: media.width * 0.05),
const Text(
"Collect and usage of your data",
"Collecte et Utilisation des Informations",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
@ -77,7 +77,7 @@ class PrivacyPolicyView extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
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(
fontSize: 16,
),
@ -87,31 +87,31 @@ class PrivacyPolicyView extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
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(
fontSize: 16,
),
),
Text(
"Sleep data",
"Données sur les habitudes de sommeil",
style: TextStyle(
fontSize: 16,
),
),
Text(
"GPS data",
"Informations de localisation (si l'option est activée par l'utilisateur)",
style: TextStyle(
fontSize: 16,
),
),
Text(
"Application parameters",
"Préférences de l'utilisateur concernant les paramètres de l'application",
style: TextStyle(
fontSize: 16,
),
),
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(
fontSize: 16,
),
@ -122,7 +122,7 @@ class PrivacyPolicyView extends StatelessWidget {
),
SizedBox(height: media.width * 0.05),
const Text(
"Information protection",
"Protection des Informations",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,

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

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

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

@ -14,24 +14,32 @@ class _WebProfileView extends State<WebProfileView> {
List accountArr = [
{
"image": "assets/img/p_personal.png",
"name": "Change your username",
"name": "Changer son pseudo ",
"tag": "1"
},
{
"image": "assets/img/p_personal.png",
"name": "Change your email",
"name": "Changer son email ",
"tag": "3"
},
{
"image": "assets/img/p_personal.png",
"name": "Changer your password",
"name": "Changer son mot de passe ",
"tag": "2"
},
];
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
Widget build(BuildContext context) {

@ -48,7 +48,7 @@ class _VolumesViews extends State<VolumesView> {
height: media.width * 0.05,
),
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(
color: TColor.black,
fontSize: 16,
@ -62,7 +62,7 @@ class _VolumesViews extends State<VolumesView> {
height: media.width * 0.03,
),
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(
color: TColor.black,
fontSize: 16,
@ -73,7 +73,7 @@ class _VolumesViews extends State<VolumesView> {
height: media.width * 0.03,
),
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(
color: TColor.black,
fontSize: 16,

@ -5,25 +5,17 @@
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:smartfit_app_mobile/main.dart';
import 'package:smartfit_app_mobile/modele/activity.dart';
import 'package:smartfit_app_mobile/modele/activity_info/activity_info.dart';
import 'package:smartfit_app_mobile/modele/api/api_wrapper.dart';
import 'package:smartfit_app_mobile/modele/api/request_api.dart';
import 'package:smartfit_app_mobile/modele/user.dart';
import 'package:smartfit_app_mobile/modele/utile/signup_user.dart';
import 'package:tuple/tuple.dart';
void main() {
testWidgets('Test login', (WidgetTester tester) async {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// 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('1'), findsNothing);
@ -33,40 +25,6 @@ void main() {
// Verify that our counter has incremented.
expect(find.text('0'), findsNothing);
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);
expect(find.text('1'), findsOneWidget);
});
}

Loading…
Cancel
Save