Compare commits
No commits in common. 'master' and 'profile' have entirely different histories.
@ -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"
|
|
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 974 B |
Before Width: | Height: | Size: 6.6 KiB |
Before Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.5 KiB |
@ -1,25 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:responsive_builder/responsive_builder.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common_widget/container/mobile/mobile_container_stats_activities.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common_widget/container/web/web_container_stats_activities.dart';
|
|
||||||
|
|
||||||
class ContainerStatsActivities extends StatelessWidget {
|
|
||||||
const ContainerStatsActivities(
|
|
||||||
this.value,
|
|
||||||
this.designation,
|
|
||||||
this.icon, {
|
|
||||||
Key? key,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
final String value;
|
|
||||||
final String designation;
|
|
||||||
final IconData icon;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return ScreenTypeLayout.builder(
|
|
||||||
mobile: (_) => MobileContainerStatsActivities(value, designation, icon),
|
|
||||||
desktop: (_) => WebContainerStatsActivities(value, designation, icon),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,140 +0,0 @@
|
|||||||
import 'package:smartfit_app_mobile/main.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/activity_saver.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/helper.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/api/api_wrapper.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common_widget/container/workout_row/workout_row_generic.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common_widget/container/workout_row/workout_row_walking.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/activity.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/manager_file.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/user.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/utile/info_message.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/utile/list_activity/list_activity_utile.dart';
|
|
||||||
import 'package:tuple/tuple.dart';
|
|
||||||
|
|
||||||
class ListActivityWidget extends StatefulWidget {
|
|
||||||
const ListActivityWidget({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<ListActivityWidget> createState() => _ListActivityWidget();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _ListActivityWidget extends State<ListActivityWidget> {
|
|
||||||
final ApiWrapper api = ApiWrapper();
|
|
||||||
final InfoMessage infoManager = InfoMessage();
|
|
||||||
final ListActivityUtile _utile = ListActivityUtile();
|
|
||||||
final ManagerFile managerFile = ManagerFile();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
Future<void> onClick(ActivityOfUser activityObj) async {
|
|
||||||
if (!Provider.of<User>(context, listen: false)
|
|
||||||
.managerSelectedActivity
|
|
||||||
.fileNotSelected(activityObj.fileUuid)) {
|
|
||||||
Provider.of<User>(context, listen: false)
|
|
||||||
.managerSelectedActivity
|
|
||||||
.removeSelectedActivity(activityObj.fileUuid);
|
|
||||||
setState(() {});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Tuple2<bool, String> result =
|
|
||||||
await _utile.getContentActivity(context, activityObj, infoManager);
|
|
||||||
if (!result.item1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Hein?
|
|
||||||
Provider.of<User>(context, listen: false).removeActivity(activityObj);
|
|
||||||
Provider.of<User>(context, listen: false).insertActivity(0, activityObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Understand :(
|
|
||||||
Future<void> onDelete(ActivityOfUser activityObj) async {
|
|
||||||
if (await api.deleteFile(Provider.of<User>(context, listen: false).token,
|
|
||||||
activityObj.fileUuid, infoManager)) {
|
|
||||||
if (!Provider.of<User>(context, listen: false)
|
|
||||||
.managerSelectedActivity
|
|
||||||
.fileNotSelected(activityObj.fileUuid)) {
|
|
||||||
Provider.of<User>(context, listen: false)
|
|
||||||
.managerSelectedActivity
|
|
||||||
.removeSelectedActivity(activityObj.fileUuid);
|
|
||||||
}
|
|
||||||
if (!Helper.isPlatformWeb() && localDB.getSaveLocally()) {
|
|
||||||
ActivitySaver actSaver = await ActivitySaver.create();
|
|
||||||
actSaver.deleteActivity(activityObj.fileUuid);
|
|
||||||
localDB.removeActivity(activityObj.fileUuid);
|
|
||||||
}
|
|
||||||
Provider.of<User>(context, listen: false).removeActivity(activityObj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isSelected(ActivityOfUser activityObj) {
|
|
||||||
return !Provider.of<User>(context)
|
|
||||||
.managerSelectedActivity
|
|
||||||
.fileNotSelected(activityObj.fileUuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Material(
|
|
||||||
color: Colors.transparent,
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Visibility(
|
|
||||||
visible: infoManager.isVisible,
|
|
||||||
child: Text(infoManager.message,
|
|
||||||
style: TextStyle(color: infoManager.messageColor))),
|
|
||||||
ListView.builder(
|
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
|
||||||
shrinkWrap: true,
|
|
||||||
itemCount:
|
|
||||||
Provider.of<User>(context, listen: true).listActivity.length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
ActivityOfUser activityObj =
|
|
||||||
Provider.of<User>(context, listen: true).listActivity[index];
|
|
||||||
Map<String, dynamic> activityMap;
|
|
||||||
// -- Si categorie == marche
|
|
||||||
if (activityObj.category == managerFile.marche) {
|
|
||||||
activityMap = activityObj.toMapWalking();
|
|
||||||
return InkWell(
|
|
||||||
onTap: () {},
|
|
||||||
child: WorkoutRowWalking(
|
|
||||||
wObj: activityMap,
|
|
||||||
onDelete: () async {
|
|
||||||
await onDelete(activityObj);
|
|
||||||
setState(() {});
|
|
||||||
},
|
|
||||||
onClick: () async {
|
|
||||||
await onClick(activityObj);
|
|
||||||
setState(() {});
|
|
||||||
},
|
|
||||||
isSelected: isSelected(activityObj),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// -- Default -- //
|
|
||||||
activityMap = activityObj.toMapGeneric();
|
|
||||||
return InkWell(
|
|
||||||
onTap: () {},
|
|
||||||
child: WorkoutRowGeneric(
|
|
||||||
wObj: activityMap,
|
|
||||||
onDelete: () async {
|
|
||||||
await onDelete(activityObj);
|
|
||||||
setState(() {});
|
|
||||||
},
|
|
||||||
onClick: () async {
|
|
||||||
await onClick(activityObj);
|
|
||||||
setState(() {});
|
|
||||||
},
|
|
||||||
isSelected: isSelected(activityObj),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common_widget/container/container_stats_activities.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/convertisseur.dart';
|
|
||||||
|
|
||||||
class VolumesList extends StatelessWidget {
|
|
||||||
final Map<String, dynamic> volume;
|
|
||||||
|
|
||||||
const VolumesList({super.key, required this.volume});
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
var media = MediaQuery.of(context).size;
|
|
||||||
|
|
||||||
// TODO: True message with variables and context aware
|
|
||||||
if (volume["nbActivity"] == 0) {
|
|
||||||
return const Text("No activity the last x days/month/year");
|
|
||||||
}
|
|
||||||
|
|
||||||
return SingleChildScrollView(
|
|
||||||
scrollDirection: Axis.horizontal,
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
ContainerStatsActivities(volume["nbActivity"].toString(),
|
|
||||||
"Number of activities", Icons.numbers),
|
|
||||||
SizedBox(
|
|
||||||
width: media.width * 0.03,
|
|
||||||
),
|
|
||||||
ContainerStatsActivities(
|
|
||||||
"${Convertisseur.secondeIntoMinute(volume["durationActiviy"]).toStringAsFixed(0)} min",
|
|
||||||
"Total time",
|
|
||||||
Icons.timer),
|
|
||||||
SizedBox(
|
|
||||||
width: media.width * 0.03,
|
|
||||||
),
|
|
||||||
ContainerStatsActivities(
|
|
||||||
volume["bpmAvg"].toString(), "Average bpm", Icons.favorite),
|
|
||||||
SizedBox(
|
|
||||||
width: media.width * 0.03,
|
|
||||||
),
|
|
||||||
ContainerStatsActivities(
|
|
||||||
" ${Convertisseur.msIntoKmh(volume["speedAvg"]).toStringAsFixed(2)} km/h",
|
|
||||||
"Average speed",
|
|
||||||
Icons.bolt),
|
|
||||||
SizedBox(
|
|
||||||
width: media.width * 0.03,
|
|
||||||
),
|
|
||||||
ContainerStatsActivities(
|
|
||||||
"${volume["denivelePositif"].toStringAsFixed(2)} m",
|
|
||||||
"Positive height difference",
|
|
||||||
Icons.hiking),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,65 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common_widget/stats.dart';
|
|
||||||
|
|
||||||
class MobileContainerStats extends StatelessWidget {
|
|
||||||
const MobileContainerStats(this.value, this.designation, this.icon, {Key? key})
|
|
||||||
: super(key: key);
|
|
||||||
|
|
||||||
final String value;
|
|
||||||
final String designation;
|
|
||||||
final IconData icon;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container(
|
|
||||||
height: 100,
|
|
||||||
width: 100,
|
|
||||||
padding: const EdgeInsets.all(8),
|
|
||||||
margin: const EdgeInsets.symmetric(vertical: 5),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.white,
|
|
||||||
borderRadius: BorderRadius.circular(15),
|
|
||||||
border: Border.all(
|
|
||||||
color: const Color(0xffe1e1e1),
|
|
||||||
),
|
|
||||||
boxShadow: const [
|
|
||||||
BoxShadow(
|
|
||||||
color: Colors.black12,
|
|
||||||
offset: Offset(3, 3),
|
|
||||||
blurRadius: 3,
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
child: Stack(
|
|
||||||
children: [
|
|
||||||
StatIcon(
|
|
||||||
icon: icon,
|
|
||||||
iconColor: TColor.white,
|
|
||||||
iconBackground: TColor.secondaryColor1,
|
|
||||||
sizeIcon: 12,
|
|
||||||
),
|
|
||||||
Align(
|
|
||||||
alignment: Alignment.bottomLeft,
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
designation,
|
|
||||||
style: const TextStyle(fontSize: 10),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
value,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w800,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,70 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common_widget/stats.dart';
|
|
||||||
|
|
||||||
class MobileContainerStatsActivities extends StatelessWidget {
|
|
||||||
const MobileContainerStatsActivities(
|
|
||||||
this.value,
|
|
||||||
this.designation,
|
|
||||||
this.icon, {
|
|
||||||
Key? key,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
final String value;
|
|
||||||
final String designation;
|
|
||||||
final IconData icon;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
var media = MediaQuery.of(context).size;
|
|
||||||
|
|
||||||
return Container(
|
|
||||||
height: media.width * 0.33,
|
|
||||||
width: media.width * 0.28,
|
|
||||||
padding: const EdgeInsets.all(8),
|
|
||||||
margin: const EdgeInsets.symmetric(vertical: 5),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.white,
|
|
||||||
borderRadius: BorderRadius.circular(15),
|
|
||||||
border: Border.all(
|
|
||||||
color: const Color(0xffe1e1e1),
|
|
||||||
),
|
|
||||||
boxShadow: const [
|
|
||||||
BoxShadow(
|
|
||||||
color: Colors.black12,
|
|
||||||
offset: Offset(3, 3),
|
|
||||||
blurRadius: 3,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment:
|
|
||||||
CrossAxisAlignment.center, // Centrer horizontalement
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
|
|
||||||
children: [
|
|
||||||
StatIcon(
|
|
||||||
icon: icon,
|
|
||||||
iconColor: TColor.white,
|
|
||||||
iconBackground: TColor.secondaryColor1,
|
|
||||||
sizeIcon: 30.0,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 10), // Espacement entre l'icône et le texte
|
|
||||||
Text(
|
|
||||||
designation,
|
|
||||||
style: const TextStyle(fontSize: 12),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
value,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 17,
|
|
||||||
fontWeight: FontWeight.w800,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,73 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common_widget/container/container_stats.dart';
|
|
||||||
|
|
||||||
class MobileLigneContainerStats extends StatelessWidget {
|
|
||||||
const MobileLigneContainerStats(
|
|
||||||
this.value1,
|
|
||||||
this.value2,
|
|
||||||
this.value3,
|
|
||||||
this.designation1,
|
|
||||||
this.designation2,
|
|
||||||
this.designation3,
|
|
||||||
this.icon1,
|
|
||||||
this.icon2,
|
|
||||||
this.icon3,
|
|
||||||
{Key? key})
|
|
||||||
: super(key: key);
|
|
||||||
|
|
||||||
final String value1;
|
|
||||||
final String value2;
|
|
||||||
final String value3;
|
|
||||||
|
|
||||||
final String designation1;
|
|
||||||
final String designation2;
|
|
||||||
final String designation3;
|
|
||||||
|
|
||||||
final IconData icon1;
|
|
||||||
final IconData icon2;
|
|
||||||
final IconData icon3;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Column(
|
|
||||||
children: [
|
|
||||||
const Divider(height: 30),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 30),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
const Text(
|
|
||||||
'Stats',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 14,
|
|
||||||
fontWeight: FontWeight.w800,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
Icon(
|
|
||||||
Icons.pie_chart_rounded,
|
|
||||||
size: 15,
|
|
||||||
color: TColor.secondaryColor1,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
SingleChildScrollView(
|
|
||||||
scrollDirection: Axis.horizontal,
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
ContainerStats(value1, designation1, icon1),
|
|
||||||
const SizedBox(width: 20),
|
|
||||||
ContainerStats(value2, designation2, icon2),
|
|
||||||
const SizedBox(width: 20),
|
|
||||||
ContainerStats(value3, designation3, icon3),
|
|
||||||
],
|
|
||||||
)),
|
|
||||||
const Divider(height: 30),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,75 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common_widget/setting_row.dart';
|
|
||||||
import 'package:smartfit_app_mobile/view/profile/change_email.dart';
|
|
||||||
import 'package:smartfit_app_mobile/view/profile/change_password.dart';
|
|
||||||
import 'package:smartfit_app_mobile/view/profile/change_username.dart';
|
|
||||||
|
|
||||||
class ProfileCompte extends StatelessWidget {
|
|
||||||
const ProfileCompte(this.accountArr, {super.key});
|
|
||||||
|
|
||||||
final List accountArr;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: TColor.white,
|
|
||||||
borderRadius: BorderRadius.circular(15),
|
|
||||||
boxShadow: const [BoxShadow(color: Colors.black12, blurRadius: 2)]),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
"Account",
|
|
||||||
style: TextStyle(
|
|
||||||
color: TColor.black,
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w700,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 8,
|
|
||||||
),
|
|
||||||
ListView.builder(
|
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
|
||||||
shrinkWrap: true,
|
|
||||||
itemCount: accountArr.length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
var iObj = accountArr[index];
|
|
||||||
return SettingRow(
|
|
||||||
icon: iObj["image"]!,
|
|
||||||
title: iObj["name"]!,
|
|
||||||
onPressed: () {
|
|
||||||
if (iObj["tag"] == "1") {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => const ChangeUsernameView(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else if (iObj["tag"] == "2") {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => const ChangePasswordView(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => const ChangeEmailView(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,50 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
|
||||||
|
|
||||||
class ProfileEntete extends StatelessWidget {
|
|
||||||
const ProfileEntete(this.username, {super.key});
|
|
||||||
|
|
||||||
final String username;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Row(
|
|
||||||
children: [
|
|
||||||
ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(30),
|
|
||||||
child: Image.asset(
|
|
||||||
"assets/img/u1.png",
|
|
||||||
width: 50,
|
|
||||||
height: 50,
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
width: 15,
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
username,
|
|
||||||
style: TextStyle(
|
|
||||||
color: TColor.black,
|
|
||||||
fontSize: 14,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
"Running",
|
|
||||||
style: TextStyle(
|
|
||||||
color: TColor.gray,
|
|
||||||
fontSize: 12,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,54 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common_widget/title_subtitle_cell.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/user.dart';
|
|
||||||
|
|
||||||
class ProfileInfoUser extends StatelessWidget {
|
|
||||||
const ProfileInfoUser({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: TitleSubtitleCell(
|
|
||||||
title: context.watch<User>().listActivity.length.toString(),
|
|
||||||
subtitle: "Number of activities",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
width: 15,
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: TitleSubtitleCell(
|
|
||||||
title: context
|
|
||||||
.watch<User>()
|
|
||||||
.getTotalTimeAllActivity()
|
|
||||||
.toStringAsFixed(2),
|
|
||||||
subtitle: "Total activity time",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
width: 15,
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: TitleSubtitleCell(
|
|
||||||
title:
|
|
||||||
"${context.watch<User>().getTotalDenivelePositifAllActivity().toStringAsFixed(2)} + m",
|
|
||||||
subtitle: "Total positive height difference",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
width: 15,
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: TitleSubtitleCell(
|
|
||||||
title:
|
|
||||||
"${context.watch<User>().getTotalDeniveleNegatifAllActivity().toStringAsFixed(2)} - m",
|
|
||||||
subtitle: "Total negative height difference",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,117 +0,0 @@
|
|||||||
import 'package:animated_toggle_switch/animated_toggle_switch.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
|
||||||
|
|
||||||
class ProfileNotification extends StatefulWidget {
|
|
||||||
const ProfileNotification(this.positive, {Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
final bool positive;
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<ProfileNotification> createState() => _ProfileNotification();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _ProfileNotification extends State<ProfileNotification> {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
bool check = widget.positive;
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: TColor.white,
|
|
||||||
borderRadius: BorderRadius.circular(15),
|
|
||||||
boxShadow: const [BoxShadow(color: Colors.black12, blurRadius: 2)]),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
"Notification",
|
|
||||||
style: TextStyle(
|
|
||||||
color: TColor.black,
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w700,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 8,
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: 30,
|
|
||||||
child:
|
|
||||||
Row(crossAxisAlignment: CrossAxisAlignment.center, children: [
|
|
||||||
Image.asset("assets/img/p_notification.png",
|
|
||||||
height: 15, width: 15, fit: BoxFit.contain),
|
|
||||||
const SizedBox(
|
|
||||||
width: 15,
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
"Push Notifications",
|
|
||||||
style: TextStyle(
|
|
||||||
color: TColor.black,
|
|
||||||
fontSize: 12,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
CustomAnimatedToggleSwitch<bool>(
|
|
||||||
current: check,
|
|
||||||
values: const [false, true],
|
|
||||||
spacing: 0.0,
|
|
||||||
indicatorSize: const Size.square(25.0),
|
|
||||||
animationDuration: const Duration(milliseconds: 200),
|
|
||||||
animationCurve: Curves.linear,
|
|
||||||
onChanged: (b) => setState(() => check = b),
|
|
||||||
iconBuilder: (context, local, global) {
|
|
||||||
return const SizedBox();
|
|
||||||
},
|
|
||||||
cursors: const ToggleCursors(
|
|
||||||
defaultCursor: SystemMouseCursors.click),
|
|
||||||
onTap: (_) => setState(() => check = !check),
|
|
||||||
iconsTappable: false,
|
|
||||||
wrapperBuilder: (context, global, child) {
|
|
||||||
return Stack(
|
|
||||||
alignment: Alignment.center,
|
|
||||||
children: [
|
|
||||||
Positioned(
|
|
||||||
left: 10.0,
|
|
||||||
right: 10.0,
|
|
||||||
height: 20.0,
|
|
||||||
child: DecoratedBox(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
gradient:
|
|
||||||
LinearGradient(colors: TColor.secondaryG),
|
|
||||||
borderRadius:
|
|
||||||
const BorderRadius.all(Radius.circular(50.0)),
|
|
||||||
),
|
|
||||||
)),
|
|
||||||
child,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
foregroundIndicatorBuilder: (context, global) {
|
|
||||||
return SizedBox.fromSize(
|
|
||||||
size: const Size(5, 5),
|
|
||||||
child: DecoratedBox(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: TColor.white,
|
|
||||||
borderRadius:
|
|
||||||
const BorderRadius.all(Radius.circular(50.0)),
|
|
||||||
boxShadow: const [
|
|
||||||
BoxShadow(
|
|
||||||
color: Colors.black38,
|
|
||||||
spreadRadius: 0.05,
|
|
||||||
blurRadius: 1.1,
|
|
||||||
offset: Offset(0.0, 0.8))
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,70 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common_widget/setting_row.dart';
|
|
||||||
import 'package:smartfit_app_mobile/view/profile/contact_us_view.dart';
|
|
||||||
import 'package:smartfit_app_mobile/view/profile/policy_view.dart';
|
|
||||||
|
|
||||||
class ProfileOther extends StatelessWidget {
|
|
||||||
const ProfileOther(this.otherArr, {super.key});
|
|
||||||
|
|
||||||
final List otherArr;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: TColor.white,
|
|
||||||
borderRadius: BorderRadius.circular(15),
|
|
||||||
boxShadow: const [BoxShadow(color: Colors.black12, blurRadius: 2)]),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
"Others",
|
|
||||||
style: TextStyle(
|
|
||||||
color: TColor.black,
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w700,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 8,
|
|
||||||
),
|
|
||||||
ListView.builder(
|
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
shrinkWrap: true,
|
|
||||||
itemCount: otherArr.length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
var iObj = otherArr[index] as Map? ?? {};
|
|
||||||
return SettingRow(
|
|
||||||
icon: iObj["image"].toString(),
|
|
||||||
title: iObj["name"].toString(),
|
|
||||||
onPressed: () {
|
|
||||||
if (iObj["tag"] == "6") {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => const PrivacyPolicyView(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else if (iObj["tag"] == "5") {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => const ContactUsView(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// Autre logique si nécessaire pour d'autres éléments de la liste
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,70 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
|
||||||
import 'package:smartfit_app_mobile/main.dart';
|
|
||||||
|
|
||||||
class ProfileSwitch extends StatefulWidget {
|
|
||||||
final String title;
|
|
||||||
final String description;
|
|
||||||
final String iconFilename;
|
|
||||||
|
|
||||||
const ProfileSwitch(this.title, this.description, this.iconFilename,
|
|
||||||
{super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<ProfileSwitch> createState() => _ProfileSwitchState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _ProfileSwitchState extends State<ProfileSwitch> {
|
|
||||||
bool switchValue = localDB.getSaveLocally();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: TColor.white,
|
|
||||||
borderRadius: BorderRadius.circular(15),
|
|
||||||
boxShadow: const [BoxShadow(color: Colors.black12, blurRadius: 2)]),
|
|
||||||
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
|
||||||
Text(
|
|
||||||
widget.title,
|
|
||||||
style: TextStyle(
|
|
||||||
color: TColor.black,
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w700,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 8,
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: 30,
|
|
||||||
child:
|
|
||||||
Row(crossAxisAlignment: CrossAxisAlignment.center, children: [
|
|
||||||
Image.asset("assets/img/${widget.iconFilename}",
|
|
||||||
height: 28, width: 28, fit: BoxFit.contain),
|
|
||||||
const SizedBox(
|
|
||||||
width: 15,
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
widget.description,
|
|
||||||
style: TextStyle(
|
|
||||||
color: TColor.black,
|
|
||||||
fontSize: 12,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Switch(
|
|
||||||
value: switchValue,
|
|
||||||
activeColor: Colors.orange,
|
|
||||||
onChanged: (bool value) {
|
|
||||||
setState(() {
|
|
||||||
switchValue = value;
|
|
||||||
localDB.setSaveLocally(switchValue);
|
|
||||||
});
|
|
||||||
}),
|
|
||||||
]))
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,65 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common_widget/stats.dart';
|
|
||||||
|
|
||||||
class WebContainerStats extends StatelessWidget {
|
|
||||||
const WebContainerStats(this.value, this.designation, this.icon, {Key? key})
|
|
||||||
: super(key: key);
|
|
||||||
|
|
||||||
final String value;
|
|
||||||
final String designation;
|
|
||||||
final IconData icon;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container(
|
|
||||||
height: 80,
|
|
||||||
width: 70,
|
|
||||||
padding: const EdgeInsets.all(8),
|
|
||||||
margin: const EdgeInsets.symmetric(vertical: 5),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.white,
|
|
||||||
borderRadius: BorderRadius.circular(15),
|
|
||||||
border: Border.all(
|
|
||||||
color: const Color(0xffe1e1e1),
|
|
||||||
),
|
|
||||||
boxShadow: const [
|
|
||||||
BoxShadow(
|
|
||||||
color: Colors.black12,
|
|
||||||
offset: Offset(3, 3),
|
|
||||||
blurRadius: 3,
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
child: Stack(
|
|
||||||
children: [
|
|
||||||
StatIcon(
|
|
||||||
icon: icon,
|
|
||||||
iconColor: TColor.white,
|
|
||||||
iconBackground: TColor.secondaryColor1,
|
|
||||||
sizeIcon: 8.0,
|
|
||||||
),
|
|
||||||
Align(
|
|
||||||
alignment: Alignment.bottomLeft,
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
designation,
|
|
||||||
style: const TextStyle(fontSize: 8),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
value,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
fontWeight: FontWeight.w800,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,70 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common_widget/stats.dart';
|
|
||||||
|
|
||||||
class WebContainerStatsActivities extends StatelessWidget {
|
|
||||||
const WebContainerStatsActivities(
|
|
||||||
this.value,
|
|
||||||
this.designation,
|
|
||||||
this.icon, {
|
|
||||||
Key? key,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
final String value;
|
|
||||||
final String designation;
|
|
||||||
final IconData icon;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
var media = MediaQuery.of(context).size;
|
|
||||||
|
|
||||||
return Container(
|
|
||||||
height: media.width * 0.2,
|
|
||||||
width: media.width * 0.28,
|
|
||||||
padding: const EdgeInsets.all(8),
|
|
||||||
margin: const EdgeInsets.symmetric(vertical: 5),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.white,
|
|
||||||
borderRadius: BorderRadius.circular(15),
|
|
||||||
border: Border.all(
|
|
||||||
color: const Color(0xffe1e1e1),
|
|
||||||
),
|
|
||||||
boxShadow: const [
|
|
||||||
BoxShadow(
|
|
||||||
color: Colors.black12,
|
|
||||||
offset: Offset(3, 3),
|
|
||||||
blurRadius: 3,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment:
|
|
||||||
CrossAxisAlignment.center, // Centrer horizontalement
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
|
|
||||||
children: [
|
|
||||||
StatIcon(
|
|
||||||
icon: icon,
|
|
||||||
iconColor: TColor.white,
|
|
||||||
iconBackground: TColor.secondaryColor1,
|
|
||||||
sizeIcon: 40.0,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 40), // Espacement entre l'icône et le texte
|
|
||||||
Text(
|
|
||||||
designation,
|
|
||||||
style: const TextStyle(fontSize: 15),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
value,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 20,
|
|
||||||
fontWeight: FontWeight.w800,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,72 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common_widget/container/container_stats.dart';
|
|
||||||
|
|
||||||
class WebLigneContainerStats extends StatelessWidget {
|
|
||||||
const WebLigneContainerStats(
|
|
||||||
this.value1,
|
|
||||||
this.value2,
|
|
||||||
this.value3,
|
|
||||||
this.designation1,
|
|
||||||
this.designation2,
|
|
||||||
this.designation3,
|
|
||||||
this.icon1,
|
|
||||||
this.icon2,
|
|
||||||
this.icon3,
|
|
||||||
{Key? key})
|
|
||||||
: super(key: key);
|
|
||||||
|
|
||||||
final String value1;
|
|
||||||
final String value2;
|
|
||||||
final String value3;
|
|
||||||
|
|
||||||
final String designation1;
|
|
||||||
final String designation2;
|
|
||||||
final String designation3;
|
|
||||||
|
|
||||||
final IconData icon1;
|
|
||||||
final IconData icon2;
|
|
||||||
final IconData icon3;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Column(
|
|
||||||
children: [
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 5),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
const Text(
|
|
||||||
'Stats',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 14,
|
|
||||||
fontWeight: FontWeight.w800,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
Icon(
|
|
||||||
Icons.pie_chart_rounded,
|
|
||||||
size: 15,
|
|
||||||
color: TColor.secondaryColor1,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
SingleChildScrollView(
|
|
||||||
scrollDirection: Axis.horizontal,
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
ContainerStats(value1, designation1, icon1),
|
|
||||||
const SizedBox(width: 20),
|
|
||||||
ContainerStats(value2, designation2, icon2),
|
|
||||||
const SizedBox(width: 20),
|
|
||||||
ContainerStats(value3, designation3, icon3),
|
|
||||||
],
|
|
||||||
)),
|
|
||||||
const Divider(height: 30),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,59 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
|
||||||
import 'package:simple_animation_progress_bar/simple_animation_progress_bar.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
|
||||||
|
|
||||||
class WorkoutRow extends StatelessWidget {
|
|
||||||
final Map wObj;
|
|
||||||
const WorkoutRow({super.key, required this.wObj});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container(
|
|
||||||
margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 2),
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 15),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: TColor.white,
|
|
||||||
borderRadius: BorderRadius.circular(20),
|
|
||||||
boxShadow: const [BoxShadow(color: Colors.black12, blurRadius: 2)]),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(30),
|
|
||||||
child: SvgPicture.asset(
|
|
||||||
wObj["image"].toString(),
|
|
||||||
width: 60,
|
|
||||||
height: 60,
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
width: 15,
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
wObj["name"].toString(),
|
|
||||||
style: TextStyle(
|
|
||||||
color: TColor.black,
|
|
||||||
fontSize: 15,
|
|
||||||
fontWeight: FontWeight.bold),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
wObj["value"].toString(),
|
|
||||||
style: TextStyle(
|
|
||||||
color: TColor.gray,
|
|
||||||
fontSize: 12,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 4,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)),
|
|
||||||
],
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,125 +0,0 @@
|
|||||||
import 'package:flutter_svg/svg.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/convertisseur.dart';
|
|
||||||
|
|
||||||
class WorkoutRowWalking extends StatelessWidget {
|
|
||||||
final Map wObj;
|
|
||||||
final bool isSelected;
|
|
||||||
final VoidCallback onDelete;
|
|
||||||
final VoidCallback onClick;
|
|
||||||
|
|
||||||
const WorkoutRowWalking({
|
|
||||||
Key? key,
|
|
||||||
required this.wObj,
|
|
||||||
required this.onDelete,
|
|
||||||
required this.onClick,
|
|
||||||
required this.isSelected,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return InkWell(
|
|
||||||
onTap: onClick,
|
|
||||||
child: Container(
|
|
||||||
margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 2),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
border: Border.all(
|
|
||||||
color: isSelected
|
|
||||||
? const Color.fromARGB(255, 144, 252, 148)
|
|
||||||
: Colors.transparent,
|
|
||||||
width: 2.0,
|
|
||||||
),
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
),
|
|
||||||
child: Material(
|
|
||||||
color: isSelected
|
|
||||||
? const Color.fromARGB(255, 240, 255, 240)
|
|
||||||
: Colors.transparent,
|
|
||||||
child: InkWell(
|
|
||||||
borderRadius:
|
|
||||||
BorderRadius.circular(10), // Utiliser le même borderRadius
|
|
||||||
splashColor: const Color.fromARGB(255, 42, 94, 44)
|
|
||||||
.withOpacity(0.3), // Couleur du fond au survol
|
|
||||||
onTap: onClick,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 15),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
child: SvgPicture.asset(
|
|
||||||
wObj["image"].toString(),
|
|
||||||
width: 60,
|
|
||||||
height: 60,
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 15),
|
|
||||||
Expanded(
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
"Type : ${wObj["categorie"].toString()}",
|
|
||||||
style: TextStyle(
|
|
||||||
color: TColor.black,
|
|
||||||
fontSize: 12,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
"Date : ${wObj["date"].toString()}",
|
|
||||||
style: TextStyle(
|
|
||||||
color: TColor.black,
|
|
||||||
fontSize: 12,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
"Time : ${Convertisseur.secondeIntoMinute(wObj["time"]).toStringAsFixed(0)} minutes",
|
|
||||||
style: TextStyle(
|
|
||||||
color: TColor.black,
|
|
||||||
fontSize: 12,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
"Average speed : ${Convertisseur.msIntoKmh(wObj["VitesseAvg"]).toStringAsFixed(2)} km/h",
|
|
||||||
style: TextStyle(
|
|
||||||
color: TColor.black,
|
|
||||||
fontSize: 12,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
|
||||||
children: [
|
|
||||||
IconButton(
|
|
||||||
onPressed: onClick,
|
|
||||||
icon: Image.asset(
|
|
||||||
"assets/img/next_icon.png",
|
|
||||||
width: 30,
|
|
||||||
height: 30,
|
|
||||||
fit: BoxFit.contain,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
IconButton(
|
|
||||||
onPressed: onDelete,
|
|
||||||
icon: Image.asset(
|
|
||||||
"assets/img/corbeille.png",
|
|
||||||
width: 30,
|
|
||||||
height: 30,
|
|
||||||
fit: BoxFit.contain,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,28 +1,213 @@
|
|||||||
|
import 'package:fl_chart/fl_chart.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:responsive_builder/responsive_builder.dart';
|
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
||||||
import 'package:smartfit_app_mobile/common_widget/graph/data_for_graph/func_bpm_by_time.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common_widget/graph/mobile/mobile_bpm_by_time.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common_widget/graph/web/web_bpm_by_time.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';
|
||||||
|
|
||||||
class BpmByTime extends StatefulWidget {
|
class GraphBpmByTime extends StatefulWidget {
|
||||||
final Size media;
|
final Size media;
|
||||||
final DataHomeView data;
|
final DataHomeView data;
|
||||||
|
|
||||||
const BpmByTime(this.media, this.data, {Key? key}) : super(key: key);
|
const GraphBpmByTime(this.media, this.data, {Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<BpmByTime> createState() => _BpmByTime();
|
State<GraphBpmByTime> createState() => _GraphBpmByTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _BpmByTime extends State<BpmByTime> {
|
class _GraphBpmByTime extends State<GraphBpmByTime> {
|
||||||
|
TextEditingController bpmController = TextEditingController();
|
||||||
|
|
||||||
|
// Il faut chercher à le suprimer
|
||||||
|
List<int> showingTooltipOnSpots = [0];
|
||||||
|
|
||||||
|
List<LineChartBarData> get lineBarsData1 => [
|
||||||
|
lineChartBarData1_1,
|
||||||
|
lineChartBarData1_2,
|
||||||
|
];
|
||||||
|
|
||||||
|
LineChartBarData get lineChartBarData1_1 => LineChartBarData(
|
||||||
|
isCurved: true,
|
||||||
|
gradient: LinearGradient(colors: [
|
||||||
|
TColor.primaryColor2.withOpacity(0.5),
|
||||||
|
TColor.primaryColor1.withOpacity(0.5),
|
||||||
|
]),
|
||||||
|
barWidth: 4,
|
||||||
|
isStrokeCapRound: true,
|
||||||
|
dotData: const FlDotData(show: false),
|
||||||
|
belowBarData: BarAreaData(show: false),
|
||||||
|
spots: widget.data.vitesseSecondes,
|
||||||
|
);
|
||||||
|
|
||||||
|
LineChartBarData get lineChartBarData1_2 => LineChartBarData(
|
||||||
|
isCurved: true,
|
||||||
|
gradient: LinearGradient(colors: [
|
||||||
|
TColor.secondaryColor2.withOpacity(0.5),
|
||||||
|
TColor.secondaryColor1.withOpacity(0.5),
|
||||||
|
]),
|
||||||
|
barWidth: 2,
|
||||||
|
isStrokeCapRound: true,
|
||||||
|
dotData: const FlDotData(show: false),
|
||||||
|
belowBarData: BarAreaData(
|
||||||
|
show: false,
|
||||||
|
),
|
||||||
|
spots: widget.data.bpmSecondes2,
|
||||||
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final FuncBpmByTime funcBpm = FuncBpmByTime(widget.data);
|
Size media = MediaQuery.of(context).size;
|
||||||
|
|
||||||
|
final lineBarsData = [
|
||||||
|
LineChartBarData(
|
||||||
|
spots: widget.data.bpmSecondes,
|
||||||
|
isCurved: false,
|
||||||
|
barWidth: 2,
|
||||||
|
belowBarData: BarAreaData(
|
||||||
|
show: true,
|
||||||
|
gradient: LinearGradient(colors: [
|
||||||
|
TColor.secondaryColor1.withOpacity(0.4),
|
||||||
|
TColor.secondaryColor2.withOpacity(0.1),
|
||||||
|
], begin: Alignment.topCenter, end: Alignment.bottomCenter),
|
||||||
|
),
|
||||||
|
dotData: const FlDotData(show: false),
|
||||||
|
gradient: LinearGradient(
|
||||||
|
colors: TColor.secondaryG,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
final tooltipsOnBar = lineBarsData[0];
|
||||||
|
|
||||||
return ScreenTypeLayout.builder(
|
return ClipRRect(
|
||||||
mobile: (_) => MobileBpmByTime(widget.media, widget.data, funcBpm),
|
borderRadius: BorderRadius.circular(25),
|
||||||
desktop: (_) => WebBpmByTime(widget.media, widget.data, funcBpm),
|
child: Container(
|
||||||
|
height: media.height * 0.3,
|
||||||
|
width: double.maxFinite,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: TColor.primaryColor2.withOpacity(0.3),
|
||||||
|
borderRadius: BorderRadius.circular(25),
|
||||||
|
),
|
||||||
|
child: Stack(
|
||||||
|
alignment: Alignment.topLeft,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 20),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Rythme cardiaque",
|
||||||
|
style: TextStyle(
|
||||||
|
color: TColor.black,
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w700),
|
||||||
|
),
|
||||||
|
TextField(
|
||||||
|
controller: bpmController,
|
||||||
|
readOnly: true,
|
||||||
|
style: TextStyle(
|
||||||
|
color: TColor.primaryColor1.withOpacity(0.8),
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
fontSize: 18),
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
border: InputBorder
|
||||||
|
.none, // Ajoutez cette ligne pour supprimer la bordure
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
LineChart(
|
||||||
|
LineChartData(
|
||||||
|
showingTooltipIndicators: showingTooltipOnSpots.map((index) {
|
||||||
|
return ShowingTooltipIndicators([
|
||||||
|
LineBarSpot(
|
||||||
|
tooltipsOnBar,
|
||||||
|
lineBarsData.indexOf(tooltipsOnBar),
|
||||||
|
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;
|
||||||
|
showingTooltipOnSpots.clear();
|
||||||
|
setState(() {
|
||||||
|
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(
|
||||||
|
FlLine(
|
||||||
|
color: TColor.secondaryColor1,
|
||||||
|
),
|
||||||
|
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) {
|
||||||
|
bpmController.text = "${lineBarSpot.y} BPM";
|
||||||
|
return LineTooltipItem(
|
||||||
|
"Seconde ${lineBarSpot.x.toInt() / 10}",
|
||||||
|
const TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 10,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
lineBarsData: lineBarsData,
|
||||||
|
minY: 50,
|
||||||
|
maxY: 250,
|
||||||
|
titlesData: const FlTitlesData(
|
||||||
|
show: false,
|
||||||
|
),
|
||||||
|
gridData: const FlGridData(show: false),
|
||||||
|
borderData: FlBorderData(
|
||||||
|
show: true,
|
||||||
|
border: Border.all(
|
||||||
|
color: Colors.transparent,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,188 +0,0 @@
|
|||||||
import 'package:fl_chart/fl_chart.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/utile/home_view/data_home_view.dart';
|
|
||||||
|
|
||||||
class FuncBpmAndSpeedByTime {
|
|
||||||
final DataHomeView data;
|
|
||||||
|
|
||||||
FuncBpmAndSpeedByTime(this.data);
|
|
||||||
|
|
||||||
List<int> showingTooltipOnSpots = [0];
|
|
||||||
|
|
||||||
SideTitles get rightTitles => SideTitles(
|
|
||||||
getTitlesWidget: rightTitleWidgets,
|
|
||||||
showTitles: true,
|
|
||||||
interval: 20,
|
|
||||||
reservedSize: 42,
|
|
||||||
);
|
|
||||||
|
|
||||||
SideTitles get leftTitles => SideTitles(
|
|
||||||
getTitlesWidget: leftTitleWidgets,
|
|
||||||
showTitles: true,
|
|
||||||
interval: 20,
|
|
||||||
reservedSize: 42,
|
|
||||||
);
|
|
||||||
SideTitles get bottomTitles => SideTitles(
|
|
||||||
getTitlesWidget: bottomTitleWidgets,
|
|
||||||
showTitles: true,
|
|
||||||
interval: 20,
|
|
||||||
reservedSize: 20,
|
|
||||||
);
|
|
||||||
|
|
||||||
late final lineBarsData = [
|
|
||||||
LineChartBarData(
|
|
||||||
spots: data.bpmSecondes,
|
|
||||||
isCurved: false,
|
|
||||||
barWidth: 2,
|
|
||||||
belowBarData: BarAreaData(
|
|
||||||
show: true,
|
|
||||||
gradient: LinearGradient(colors: [
|
|
||||||
TColor.secondaryColor1.withOpacity(0.4),
|
|
||||||
TColor.secondaryColor2.withOpacity(0.1),
|
|
||||||
], begin: Alignment.topCenter, end: Alignment.bottomCenter),
|
|
||||||
),
|
|
||||||
dotData: const FlDotData(show: false),
|
|
||||||
gradient: LinearGradient(
|
|
||||||
colors: TColor.secondaryG,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
];
|
|
||||||
late final tooltipsOnBar = lineBarsData[0];
|
|
||||||
|
|
||||||
Widget rightTitleWidgets(double value, TitleMeta meta) {
|
|
||||||
double interval = data.maxBPM / 5;
|
|
||||||
String text;
|
|
||||||
switch (value.toInt()) {
|
|
||||||
case 0:
|
|
||||||
text = '0 BPM';
|
|
||||||
break;
|
|
||||||
case 20:
|
|
||||||
text = "${(interval).toStringAsFixed(2)} BPM";
|
|
||||||
break;
|
|
||||||
case 40:
|
|
||||||
text = "${(interval * 2).toStringAsFixed(2)} BPM";
|
|
||||||
break;
|
|
||||||
case 60:
|
|
||||||
text = "${(interval * 3).toStringAsFixed(2)} BPM";
|
|
||||||
break;
|
|
||||||
case 80:
|
|
||||||
text = "${(interval * 4).toStringAsFixed(2)} BPM";
|
|
||||||
break;
|
|
||||||
case 100:
|
|
||||||
text = "${interval * 5} BPM";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return Container();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Text(text,
|
|
||||||
style: TextStyle(
|
|
||||||
color: TColor.gray,
|
|
||||||
fontSize: 8,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget bottomTitleWidgets(double value, TitleMeta meta) {
|
|
||||||
double interval = data.time / 5;
|
|
||||||
String text;
|
|
||||||
switch (value) {
|
|
||||||
case 0:
|
|
||||||
text = '0 s';
|
|
||||||
break;
|
|
||||||
case 20:
|
|
||||||
text = "${(interval).toStringAsFixed(2)} s";
|
|
||||||
break;
|
|
||||||
case 40:
|
|
||||||
text = "${(interval * 2).toStringAsFixed(2)} s";
|
|
||||||
break;
|
|
||||||
case 60:
|
|
||||||
text = "${(interval * 3).toStringAsFixed(2)} s";
|
|
||||||
break;
|
|
||||||
case 80:
|
|
||||||
text = "${(interval * 4).toStringAsFixed(2)} s";
|
|
||||||
break;
|
|
||||||
case 100:
|
|
||||||
text = "${(interval * 5).toStringAsFixed(2)} s";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return Container();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Text(text,
|
|
||||||
style: TextStyle(
|
|
||||||
color: TColor.gray,
|
|
||||||
fontSize: 8,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget leftTitleWidgets(double value, TitleMeta meta) {
|
|
||||||
double interval = data.maxSpeed / 5;
|
|
||||||
|
|
||||||
String text;
|
|
||||||
switch (value.toInt()) {
|
|
||||||
case 0:
|
|
||||||
text = '0 m/s';
|
|
||||||
break;
|
|
||||||
case 20:
|
|
||||||
text = "${(interval / 5).toStringAsFixed(2)} m/s";
|
|
||||||
break;
|
|
||||||
case 40:
|
|
||||||
text = "${(interval * 2).toStringAsFixed(2)} m/s";
|
|
||||||
break;
|
|
||||||
case 60:
|
|
||||||
text = "${(interval * 3).toStringAsFixed(2)} m/s";
|
|
||||||
break;
|
|
||||||
case 80:
|
|
||||||
text = "${(interval * 4).toStringAsFixed(2)} m/s";
|
|
||||||
break;
|
|
||||||
case 100:
|
|
||||||
text = "${(interval * 5).toStringAsFixed(2)} m/s";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return Container();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Text(text,
|
|
||||||
style: TextStyle(
|
|
||||||
color: TColor.gray,
|
|
||||||
fontSize: 8,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<LineChartBarData> get lineBarsData1 => [
|
|
||||||
lineChartBarData1_1,
|
|
||||||
lineChartBarData1_2,
|
|
||||||
];
|
|
||||||
|
|
||||||
LineChartBarData get lineChartBarData1_1 => LineChartBarData(
|
|
||||||
isCurved: true,
|
|
||||||
gradient: LinearGradient(colors: [
|
|
||||||
TColor.primaryColor2.withOpacity(0.5),
|
|
||||||
TColor.primaryColor1.withOpacity(0.5),
|
|
||||||
]),
|
|
||||||
barWidth: 4,
|
|
||||||
isStrokeCapRound: true,
|
|
||||||
dotData: const FlDotData(show: false),
|
|
||||||
belowBarData: BarAreaData(show: false),
|
|
||||||
spots: data.vitesseSecondes,
|
|
||||||
);
|
|
||||||
|
|
||||||
LineChartBarData get lineChartBarData1_2 => LineChartBarData(
|
|
||||||
isCurved: true,
|
|
||||||
gradient: LinearGradient(colors: [
|
|
||||||
TColor.secondaryColor2.withOpacity(0.5),
|
|
||||||
TColor.secondaryColor1.withOpacity(0.5),
|
|
||||||
]),
|
|
||||||
barWidth: 2,
|
|
||||||
isStrokeCapRound: true,
|
|
||||||
dotData: const FlDotData(show: false),
|
|
||||||
belowBarData: BarAreaData(
|
|
||||||
show: false,
|
|
||||||
),
|
|
||||||
spots: data.bpmSecondes2,
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,95 +0,0 @@
|
|||||||
import 'package:fl_chart/fl_chart.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/utile/home_view/data_home_view.dart';
|
|
||||||
|
|
||||||
class FuncBpmByTime {
|
|
||||||
final DataHomeView data;
|
|
||||||
|
|
||||||
FuncBpmByTime(this.data);
|
|
||||||
|
|
||||||
SideTitles get rightTitles => SideTitles(
|
|
||||||
getTitlesWidget: rightTitleWidgets,
|
|
||||||
showTitles: true,
|
|
||||||
interval: 20,
|
|
||||||
reservedSize: 40,
|
|
||||||
);
|
|
||||||
|
|
||||||
SideTitles get bottomTitles => SideTitles(
|
|
||||||
getTitlesWidget: bottomTitleWidgets,
|
|
||||||
showTitles: true,
|
|
||||||
interval: 20,
|
|
||||||
reservedSize: 20,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget rightTitleWidgets(double value, TitleMeta meta) {
|
|
||||||
int minBpm = data.minBPM;
|
|
||||||
int maxBpm = data.maxBPM;
|
|
||||||
double interval = (maxBpm - minBpm) / 5;
|
|
||||||
|
|
||||||
String text;
|
|
||||||
switch (value.toInt()) {
|
|
||||||
case 0:
|
|
||||||
text = "${(minBpm).toStringAsFixed(2)} BPM";
|
|
||||||
break;
|
|
||||||
case 20:
|
|
||||||
text = "${(minBpm + interval).toStringAsFixed(2)} BPM";
|
|
||||||
break;
|
|
||||||
case 40:
|
|
||||||
text = "${(minBpm + interval * 2).toStringAsFixed(2)} BPM";
|
|
||||||
break;
|
|
||||||
case 60:
|
|
||||||
text = "${(minBpm + interval * 3).toStringAsFixed(2)} BPM";
|
|
||||||
break;
|
|
||||||
case 80:
|
|
||||||
text = "${(minBpm + interval * 4).toStringAsFixed(2)} BPM";
|
|
||||||
break;
|
|
||||||
case 100:
|
|
||||||
text = "${(maxBpm).toStringAsFixed(2)} BPM";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return Container();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Text(text,
|
|
||||||
style: TextStyle(
|
|
||||||
color: TColor.gray,
|
|
||||||
fontSize: 12,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget bottomTitleWidgets(double value, TitleMeta meta) {
|
|
||||||
double interval = data.time / 5;
|
|
||||||
String text;
|
|
||||||
switch (value) {
|
|
||||||
case 0:
|
|
||||||
text = '0 s';
|
|
||||||
break;
|
|
||||||
case 20:
|
|
||||||
text = "${(interval).toStringAsFixed(0)} s";
|
|
||||||
break;
|
|
||||||
case 40:
|
|
||||||
text = "${(interval * 2).toStringAsFixed(0)} s";
|
|
||||||
break;
|
|
||||||
case 60:
|
|
||||||
text = "${(interval * 3).toStringAsFixed(0)} s";
|
|
||||||
break;
|
|
||||||
case 80:
|
|
||||||
text = "${(interval * 4).toStringAsFixed(0)} s";
|
|
||||||
break;
|
|
||||||
case 100:
|
|
||||||
text = "${(interval * 5).toStringAsFixed(0)} s";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return Container();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Text(text,
|
|
||||||
style: TextStyle(
|
|
||||||
color: TColor.gray,
|
|
||||||
fontSize: 12,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,92 +0,0 @@
|
|||||||
import 'package:fl_chart/fl_chart.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common_widget/graph/data_for_graph/func_bpm_by_time.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/user.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/utile/home_view/data_home_view.dart';
|
|
||||||
|
|
||||||
class MobileGraphAltitudeByTime extends StatefulWidget {
|
|
||||||
final Size media;
|
|
||||||
final DataHomeView data;
|
|
||||||
final FuncBpmByTime func;
|
|
||||||
|
|
||||||
const MobileGraphAltitudeByTime(this.media, this.data, this.func, {Key? key})
|
|
||||||
: super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<MobileGraphAltitudeByTime> createState() =>
|
|
||||||
_MobileGraphAltitudeByTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _MobileGraphAltitudeByTime extends State<MobileGraphAltitudeByTime> {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final double maxY = context
|
|
||||||
.watch<User>()
|
|
||||||
.managerSelectedActivity
|
|
||||||
.activitySelected
|
|
||||||
.first
|
|
||||||
.activityInfo
|
|
||||||
.altitudeMax +
|
|
||||||
2;
|
|
||||||
final double minY = context
|
|
||||||
.watch<User>()
|
|
||||||
.managerSelectedActivity
|
|
||||||
.activitySelected
|
|
||||||
.first
|
|
||||||
.activityInfo
|
|
||||||
.altitudeMin -
|
|
||||||
2;
|
|
||||||
|
|
||||||
final lineBarsData = [
|
|
||||||
LineChartBarData(
|
|
||||||
spots: widget.data.altitudeSeconde,
|
|
||||||
isCurved: false,
|
|
||||||
gradient: LinearGradient(
|
|
||||||
colors: TColor.primaryG,
|
|
||||||
),
|
|
||||||
dotData: const FlDotData(show: false))
|
|
||||||
];
|
|
||||||
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsets.only(left: 15),
|
|
||||||
height: widget.media.width * 0.3,
|
|
||||||
width: double.maxFinite,
|
|
||||||
child: LineChart(LineChartData(
|
|
||||||
lineBarsData: lineBarsData,
|
|
||||||
borderData: FlBorderData(show: false),
|
|
||||||
maxY: maxY,
|
|
||||||
minY: minY,
|
|
||||||
gridData: FlGridData(
|
|
||||||
drawVerticalLine: false,
|
|
||||||
drawHorizontalLine: true,
|
|
||||||
horizontalInterval: (maxY - minY) / 5,
|
|
||||||
getDrawingHorizontalLine: (value) {
|
|
||||||
return FlLine(
|
|
||||||
color: TColor.gray.withOpacity(0.15),
|
|
||||||
strokeWidth: 1,
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
titlesData: FlTitlesData(
|
|
||||||
leftTitles: const AxisTitles(),
|
|
||||||
topTitles: const AxisTitles(),
|
|
||||||
bottomTitles: AxisTitles(
|
|
||||||
sideTitles: widget.func.bottomTitles,
|
|
||||||
),
|
|
||||||
rightTitles: AxisTitles(
|
|
||||||
sideTitles: SideTitles(
|
|
||||||
reservedSize: 60,
|
|
||||||
showTitles: true,
|
|
||||||
getTitlesWidget: (value, meta) {
|
|
||||||
return Text("${double.parse(value.toStringAsFixed(2))} m",
|
|
||||||
style: TextStyle(
|
|
||||||
color: TColor.gray,
|
|
||||||
fontSize: 12,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center);
|
|
||||||
},
|
|
||||||
)),
|
|
||||||
))));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,77 +0,0 @@
|
|||||||
import 'package:fl_chart/fl_chart.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common_widget/graph/data_for_graph/func_bpm_and_speed_by_time.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/utile/home_view/data_home_view.dart';
|
|
||||||
|
|
||||||
class MobileGraphBpmAndSpeedByTime extends StatefulWidget {
|
|
||||||
final Size media;
|
|
||||||
final DataHomeView data;
|
|
||||||
final FuncBpmAndSpeedByTime func;
|
|
||||||
|
|
||||||
const MobileGraphBpmAndSpeedByTime(this.media, this.data, this.func,
|
|
||||||
{Key? key})
|
|
||||||
: super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<MobileGraphBpmAndSpeedByTime> createState() =>
|
|
||||||
_MobileGraphBpmAndSpeedByTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _MobileGraphBpmAndSpeedByTime
|
|
||||||
extends State<MobileGraphBpmAndSpeedByTime> {
|
|
||||||
TextEditingController bpmController = TextEditingController();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final double maxY = widget.data.maxBPM + 2;
|
|
||||||
final double minY = widget.data.minBPM - 2;
|
|
||||||
final double maxX =
|
|
||||||
widget.data.bpmSecondes[widget.data.bpmSecondes.length - 1].x;
|
|
||||||
const double minX = 0.0;
|
|
||||||
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsets.only(left: 15),
|
|
||||||
height: widget.media.width * 0.3,
|
|
||||||
width: double.maxFinite,
|
|
||||||
child: LineChart(
|
|
||||||
LineChartData(
|
|
||||||
|
|
||||||
|
|
||||||
lineBarsData: widget.func.lineBarsData1,
|
|
||||||
minY: 0,
|
|
||||||
maxY: 110,
|
|
||||||
titlesData: FlTitlesData(
|
|
||||||
show: true,
|
|
||||||
leftTitles: AxisTitles(
|
|
||||||
sideTitles: widget.func.leftTitles,
|
|
||||||
),
|
|
||||||
topTitles: const AxisTitles(),
|
|
||||||
bottomTitles: AxisTitles(
|
|
||||||
sideTitles: widget.func.bottomTitles,
|
|
||||||
),
|
|
||||||
rightTitles: AxisTitles(
|
|
||||||
sideTitles: widget.func.rightTitles,
|
|
||||||
|
|
||||||
),),
|
|
||||||
gridData: FlGridData(
|
|
||||||
drawVerticalLine: true,
|
|
||||||
drawHorizontalLine: true,
|
|
||||||
horizontalInterval: (maxY - minY) / 5,
|
|
||||||
verticalInterval: (maxX - minX) / 4,
|
|
||||||
getDrawingHorizontalLine: (value) {
|
|
||||||
return FlLine(
|
|
||||||
color: TColor.gray.withOpacity(0.15),
|
|
||||||
strokeWidth: 1,
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
borderData: FlBorderData(
|
|
||||||
show: true,
|
|
||||||
border: Border.all(
|
|
||||||
color: Colors.transparent,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,79 +0,0 @@
|
|||||||
import 'package:fl_chart/fl_chart.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common_widget/graph/data_for_graph/func_bpm_by_time.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/utile/home_view/data_home_view.dart';
|
|
||||||
|
|
||||||
class MobileBpmByTime extends StatefulWidget {
|
|
||||||
final Size media;
|
|
||||||
final DataHomeView data;
|
|
||||||
final FuncBpmByTime func;
|
|
||||||
|
|
||||||
const MobileBpmByTime(this.media, this.data,this.func, {Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<MobileBpmByTime> createState() => _MobileBpmByTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _MobileBpmByTime extends State<MobileBpmByTime> {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final double maxY = widget.data.maxBPM + 2;
|
|
||||||
final double minY = widget.data.minBPM - 2;
|
|
||||||
final double maxX =
|
|
||||||
widget.data.bpmSecondes[widget.data.bpmSecondes.length - 1].x;
|
|
||||||
const double minX = 0.0;
|
|
||||||
final lineBarsData = [
|
|
||||||
LineChartBarData(
|
|
||||||
spots: widget.data.bpmSecondes,
|
|
||||||
isCurved: true,
|
|
||||||
gradient: LinearGradient(
|
|
||||||
colors: TColor.primaryG,
|
|
||||||
),
|
|
||||||
dotData: const FlDotData(show: false))
|
|
||||||
];
|
|
||||||
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsets.only(left: 15),
|
|
||||||
height: widget.media.width * 0.4,
|
|
||||||
width: double.maxFinite,
|
|
||||||
child: LineChart(LineChartData(
|
|
||||||
lineBarsData: lineBarsData,
|
|
||||||
borderData: FlBorderData(show: false),
|
|
||||||
maxY: maxY,
|
|
||||||
minY: minY,
|
|
||||||
maxX: maxX,
|
|
||||||
minX: minX,
|
|
||||||
gridData: FlGridData(
|
|
||||||
drawVerticalLine: true,
|
|
||||||
drawHorizontalLine: true,
|
|
||||||
horizontalInterval: (maxY - minY) / 5,
|
|
||||||
verticalInterval: (maxX - minX) / 4,
|
|
||||||
getDrawingHorizontalLine: (value) {
|
|
||||||
return FlLine(
|
|
||||||
color: TColor.gray.withOpacity(0.15),
|
|
||||||
strokeWidth: 1,
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
titlesData: FlTitlesData(
|
|
||||||
leftTitles: const AxisTitles(),
|
|
||||||
topTitles: const AxisTitles(),
|
|
||||||
bottomTitles: AxisTitles(
|
|
||||||
sideTitles: widget.func.bottomTitles,
|
|
||||||
),
|
|
||||||
rightTitles: AxisTitles(
|
|
||||||
sideTitles: SideTitles(
|
|
||||||
reservedSize: 70,
|
|
||||||
showTitles: true,
|
|
||||||
getTitlesWidget: (value, meta) {
|
|
||||||
return Text("${double.parse(value.toStringAsFixed(2))} BPM",
|
|
||||||
style: TextStyle(
|
|
||||||
color: TColor.gray,
|
|
||||||
fontSize: 12,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center);
|
|
||||||
},
|
|
||||||
)),
|
|
||||||
))));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,91 +0,0 @@
|
|||||||
import 'package:fl_chart/fl_chart.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common_widget/graph/data_for_graph/func_bpm_by_time.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/user.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/utile/home_view/data_home_view.dart';
|
|
||||||
|
|
||||||
class WebGraphAltitudeByTime extends StatefulWidget {
|
|
||||||
final Size media;
|
|
||||||
final DataHomeView data;
|
|
||||||
final FuncBpmByTime func;
|
|
||||||
|
|
||||||
const WebGraphAltitudeByTime(this.media, this.data, this.func, {Key? key})
|
|
||||||
: super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<WebGraphAltitudeByTime> createState() => _WebGraphAltitudeByTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _WebGraphAltitudeByTime extends State<WebGraphAltitudeByTime> {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final double maxY = context
|
|
||||||
.watch<User>()
|
|
||||||
.managerSelectedActivity
|
|
||||||
.activitySelected
|
|
||||||
.first
|
|
||||||
.activityInfo
|
|
||||||
.altitudeMax +
|
|
||||||
2;
|
|
||||||
final double minY = context
|
|
||||||
.watch<User>()
|
|
||||||
.managerSelectedActivity
|
|
||||||
.activitySelected
|
|
||||||
.first
|
|
||||||
.activityInfo
|
|
||||||
.altitudeMin -
|
|
||||||
2;
|
|
||||||
|
|
||||||
final lineBarsData = [
|
|
||||||
LineChartBarData(
|
|
||||||
spots: widget.data.altitudeSeconde,
|
|
||||||
isCurved: false,
|
|
||||||
gradient: LinearGradient(
|
|
||||||
colors: TColor.primaryG,
|
|
||||||
),
|
|
||||||
dotData: const FlDotData(show: false))
|
|
||||||
];
|
|
||||||
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsets.only(left: 15),
|
|
||||||
height: widget.media.width * 0.20,
|
|
||||||
width: widget.media.width * 0.35,
|
|
||||||
child: LineChart(LineChartData(
|
|
||||||
lineBarsData: lineBarsData,
|
|
||||||
borderData: FlBorderData(show: false),
|
|
||||||
maxY: maxY,
|
|
||||||
minY: minY,
|
|
||||||
gridData: FlGridData(
|
|
||||||
drawVerticalLine: false,
|
|
||||||
drawHorizontalLine: true,
|
|
||||||
horizontalInterval: (maxY - minY) / 5,
|
|
||||||
getDrawingHorizontalLine: (value) {
|
|
||||||
return FlLine(
|
|
||||||
color: TColor.gray.withOpacity(0.15),
|
|
||||||
strokeWidth: 1,
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
titlesData: FlTitlesData(
|
|
||||||
leftTitles: const AxisTitles(),
|
|
||||||
topTitles: const AxisTitles(),
|
|
||||||
bottomTitles: AxisTitles(
|
|
||||||
sideTitles: widget.func.bottomTitles,
|
|
||||||
),
|
|
||||||
rightTitles: AxisTitles(
|
|
||||||
sideTitles: SideTitles(
|
|
||||||
reservedSize: 60,
|
|
||||||
showTitles: true,
|
|
||||||
getTitlesWidget: (value, meta) {
|
|
||||||
return Text("${double.parse(value.toStringAsFixed(2))} m",
|
|
||||||
style: TextStyle(
|
|
||||||
color: TColor.gray,
|
|
||||||
fontSize: 12,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center);
|
|
||||||
},
|
|
||||||
)),
|
|
||||||
))));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,72 +0,0 @@
|
|||||||
import 'package:fl_chart/fl_chart.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common_widget/graph/data_for_graph/func_bpm_and_speed_by_time.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/utile/home_view/data_home_view.dart';
|
|
||||||
|
|
||||||
class WebGraphBpmAndSpeedByTime extends StatefulWidget {
|
|
||||||
final Size media;
|
|
||||||
final DataHomeView data;
|
|
||||||
final FuncBpmAndSpeedByTime func;
|
|
||||||
|
|
||||||
const WebGraphBpmAndSpeedByTime(this.media, this.data, this.func, {Key? key})
|
|
||||||
: super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<WebGraphBpmAndSpeedByTime> createState() =>
|
|
||||||
_WebGraphBpmAndSpeedByTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _WebGraphBpmAndSpeedByTime extends State<WebGraphBpmAndSpeedByTime> {
|
|
||||||
TextEditingController bpmController = TextEditingController();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final double maxY = widget.data.maxBPM + 2;
|
|
||||||
final double minY = widget.data.minBPM - 2;
|
|
||||||
final double maxX =
|
|
||||||
widget.data.bpmSecondes[widget.data.bpmSecondes.length - 1].x;
|
|
||||||
const double minX = 0.0;
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsets.only(left: 15),
|
|
||||||
height: widget.media.width * 0.20,
|
|
||||||
width: widget.media.width * 0.35,
|
|
||||||
child: LineChart(
|
|
||||||
LineChartData(
|
|
||||||
|
|
||||||
lineBarsData: widget.func.lineBarsData1,
|
|
||||||
minY: -10,
|
|
||||||
maxY: 110,
|
|
||||||
titlesData: FlTitlesData(
|
|
||||||
show: true,
|
|
||||||
leftTitles: AxisTitles(
|
|
||||||
sideTitles: widget.func.leftTitles,
|
|
||||||
),
|
|
||||||
topTitles: const AxisTitles(),
|
|
||||||
bottomTitles:AxisTitles(
|
|
||||||
sideTitles: widget.func.bottomTitles,
|
|
||||||
),
|
|
||||||
rightTitles: AxisTitles(
|
|
||||||
sideTitles: widget.func.rightTitles,
|
|
||||||
),),
|
|
||||||
gridData: FlGridData(
|
|
||||||
drawVerticalLine: true,
|
|
||||||
drawHorizontalLine: true,
|
|
||||||
horizontalInterval: (maxY - minY) / 5,
|
|
||||||
verticalInterval: (maxX - minX) / 5 ,
|
|
||||||
getDrawingHorizontalLine: (value) {
|
|
||||||
return FlLine(
|
|
||||||
color: TColor.gray.withOpacity(0.15),
|
|
||||||
strokeWidth: 1,
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
borderData: FlBorderData(
|
|
||||||
show: true,
|
|
||||||
border: Border.all(
|
|
||||||
color: Colors.transparent,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,70 +0,0 @@
|
|||||||
import 'package:fl_chart/fl_chart.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common/colo_extension.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common_widget/graph/data_for_graph/func_bpm_by_time.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/utile/home_view/data_home_view.dart';
|
|
||||||
|
|
||||||
class WebBpmByTime extends StatefulWidget {
|
|
||||||
final Size media;
|
|
||||||
final DataHomeView data;
|
|
||||||
final FuncBpmByTime func;
|
|
||||||
|
|
||||||
const WebBpmByTime(this.media, this.data, this.func, {Key? key})
|
|
||||||
: super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<WebBpmByTime> createState() => _WebBpmByTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _WebBpmByTime extends State<WebBpmByTime> {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final lineBarsData = [
|
|
||||||
LineChartBarData(
|
|
||||||
spots: widget.data.bpmSecondes,
|
|
||||||
isCurved: true,
|
|
||||||
gradient: LinearGradient(
|
|
||||||
colors: TColor.primaryG,
|
|
||||||
),
|
|
||||||
dotData: const FlDotData(show: false))
|
|
||||||
];
|
|
||||||
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsets.only(left: 15),
|
|
||||||
height: widget.media.width * 0.20,
|
|
||||||
width: widget.media.width * 0.35,
|
|
||||||
child: LineChart(LineChartData(
|
|
||||||
lineBarsData: lineBarsData,
|
|
||||||
minY: widget.data.minBPM.toDouble() * 0.95,
|
|
||||||
borderData: FlBorderData(show: false),
|
|
||||||
gridData: FlGridData(
|
|
||||||
drawVerticalLine: true,
|
|
||||||
drawHorizontalLine: true,
|
|
||||||
getDrawingHorizontalLine: (value) {
|
|
||||||
return FlLine(
|
|
||||||
color: TColor.gray.withOpacity(0.15),
|
|
||||||
strokeWidth: 1,
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
titlesData: FlTitlesData(
|
|
||||||
leftTitles: const AxisTitles(),
|
|
||||||
topTitles: const AxisTitles(),
|
|
||||||
bottomTitles: AxisTitles(
|
|
||||||
sideTitles: widget.func.bottomTitles,
|
|
||||||
),
|
|
||||||
rightTitles: AxisTitles(
|
|
||||||
sideTitles: SideTitles(
|
|
||||||
reservedSize: 70,
|
|
||||||
showTitles: true,
|
|
||||||
getTitlesWidget: (value, meta) {
|
|
||||||
return Text("${double.parse(value.toStringAsFixed(2))} BPM",
|
|
||||||
style: TextStyle(
|
|
||||||
color: TColor.gray,
|
|
||||||
fontSize: 12,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center);
|
|
||||||
},
|
|
||||||
)),
|
|
||||||
))));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,545 +0,0 @@
|
|||||||
import 'dart:convert';
|
|
||||||
|
|
||||||
import 'package:smartfit_app_mobile/modele/manager_file.dart';
|
|
||||||
|
|
||||||
class ActivityInfo {
|
|
||||||
ManagerFile managerFile = ManagerFile();
|
|
||||||
ActivityInfo();
|
|
||||||
|
|
||||||
// -- Time -- // Ne pas calculer (Ligne session)
|
|
||||||
DateTime startTime = DateTime.now();
|
|
||||||
double timeOfActivity = 0.0;
|
|
||||||
double distance = 0.0;
|
|
||||||
int calories = 0;
|
|
||||||
int steps = 0;
|
|
||||||
// ----------- BPM ------------ //
|
|
||||||
int bpmMax = 0;
|
|
||||||
int bpmMin = 300;
|
|
||||||
int bpmAvg = 0;
|
|
||||||
bool bpmNotZero = false;
|
|
||||||
// ----------- Denivelé ------------ //
|
|
||||||
double denivelePositif = 0.0;
|
|
||||||
double deniveleNegatif = 0.0;
|
|
||||||
// ----------- Altitude ------------ //
|
|
||||||
double altitudeMax = 0.0;
|
|
||||||
double altitudeMin = 30000.0;
|
|
||||||
double altitudeAvg = 0.0;
|
|
||||||
bool altitudeNotZero = false;
|
|
||||||
// ----------- Température --------- //
|
|
||||||
int temperatureMax = 0;
|
|
||||||
int temperatureMin = 3000;
|
|
||||||
int temperatureAvg = 0;
|
|
||||||
bool temperatureNotZero = false;
|
|
||||||
// ----------- Vitesse ------------- //
|
|
||||||
double vitesseMax = 0.0;
|
|
||||||
double vitesseMin = 999999.0;
|
|
||||||
double vitesseAvg = 0.0;
|
|
||||||
bool vitesseNotZero = false;
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------- //
|
|
||||||
|
|
||||||
// -- Fonction pour lire le csv et remplir la classe -- //
|
|
||||||
ActivityInfo getDataWalking(List<List<String>> csv) {
|
|
||||||
// - Entete - //
|
|
||||||
Map<String, int> enteteCSV = getEntete(csv.first);
|
|
||||||
// ------------- Var tmp ---------- //
|
|
||||||
// -- 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;
|
|
||||||
|
|
||||||
// --- Boucle -- //
|
|
||||||
for (int i = 1; i < csv.length; i++) {
|
|
||||||
//
|
|
||||||
// ---------------------- BPM ---------------------- //
|
|
||||||
if (!isNull(enteteCSV["Value_${managerFile.fielBPM}"]!, csv[i])) {
|
|
||||||
int value =
|
|
||||||
int.parse(csv[i][enteteCSV["Value_${managerFile.fielBPM}"]!]);
|
|
||||||
bpmSomme += value;
|
|
||||||
bpmNb += 1;
|
|
||||||
bpmNotZero = true;
|
|
||||||
if (value > bpmMax) {
|
|
||||||
bpmMax = value;
|
|
||||||
}
|
|
||||||
if (value < bpmMin) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- Fonction pour lire le csv et remplir la classe -- //
|
|
||||||
ActivityInfo getDataCycling(List<List<String>> csv) {
|
|
||||||
// - Entete - //
|
|
||||||
Map<String, int> enteteCSV = getEntete(csv.first);
|
|
||||||
// ------------- Var tmp ---------- //
|
|
||||||
// -- 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;
|
|
||||||
|
|
||||||
// --- Boucle -- //
|
|
||||||
for (int i = 1; i < csv.length; i++) {
|
|
||||||
//
|
|
||||||
// ---------------------- BPM ---------------------- //
|
|
||||||
if (!isNull(enteteCSV["Value_${managerFile.fielBPM}"]!, csv[i])) {
|
|
||||||
int value =
|
|
||||||
int.parse(csv[i][enteteCSV["Value_${managerFile.fielBPM}"]!]);
|
|
||||||
bpmSomme += value;
|
|
||||||
bpmNb += 1;
|
|
||||||
bpmNotZero = true;
|
|
||||||
if (value > bpmMax) {
|
|
||||||
bpmMax = value;
|
|
||||||
}
|
|
||||||
if (value < bpmMin) {
|
|
||||||
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;
|
|
||||||
vitesseNotZero = 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- Fonction pour lire le csv et remplir la classe -- //
|
|
||||||
ActivityInfo getDataGeneric(List<List<String>> csv) {
|
|
||||||
// - Entete - //
|
|
||||||
Map<String, int> enteteCSV = getEntete(csv.first);
|
|
||||||
// ------------- Var tmp ---------- //
|
|
||||||
// -- 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;
|
|
||||||
|
|
||||||
// --- Boucle -- //
|
|
||||||
for (int i = 1; i < csv.length; i++) {
|
|
||||||
//
|
|
||||||
// ---------------------- BPM ---------------------- //
|
|
||||||
if (!isNull(enteteCSV["Value_${managerFile.fielBPM}"]!, csv[i])) {
|
|
||||||
int value =
|
|
||||||
int.parse(csv[i][enteteCSV["Value_${managerFile.fielBPM}"]!]);
|
|
||||||
bpmSomme += value;
|
|
||||||
bpmNb += 1;
|
|
||||||
bpmNotZero = true;
|
|
||||||
if (value > bpmMax) {
|
|
||||||
bpmMax = value;
|
|
||||||
}
|
|
||||||
if (value < bpmMin) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------ Fonction utile ------------------- //
|
|
||||||
Map<String, int> getEntete(List<dynamic> content) {
|
|
||||||
Map<String, int> enteteCSV = {};
|
|
||||||
for (int i = 0; i < content.length; i++) {
|
|
||||||
enteteCSV.addAll({content[i]: i});
|
|
||||||
}
|
|
||||||
return enteteCSV;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isNull(int colonne, List<dynamic> ligne) {
|
|
||||||
return ligne[colonne] == "null";
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------- Pour print ----------------- //
|
|
||||||
Map<String, dynamic> toMapWalking() {
|
|
||||||
return {
|
|
||||||
// -- Denivelé -- //
|
|
||||||
"DenivelePositif": denivelePositif,
|
|
||||||
"DeniveleNegatif": denivelePositif,
|
|
||||||
// -- Altitude -- //
|
|
||||||
"AltitudeMax": altitudeMax,
|
|
||||||
"AltitudeMin": altitudeMin,
|
|
||||||
"AltitudeAvg": altitudeAvg,
|
|
||||||
// -- Vitesse -- //
|
|
||||||
"VitesseAvg": vitesseAvg
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------- JSON --------- //
|
|
||||||
// -- Lecture -- //
|
|
||||||
ActivityInfo.fromJson(Map<String, dynamic>? map) {
|
|
||||||
if (map == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// -- Ligne session -- //
|
|
||||||
try {
|
|
||||||
startTime = DateTime.parse(map["startTime"]);
|
|
||||||
} catch (e) {
|
|
||||||
print("Impossible de recup -> startTime");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
timeOfActivity = map["timeOfActivity"];
|
|
||||||
} catch (e) {
|
|
||||||
print("Impossible de recup -> timeOfActivity");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
distance = map["distance"].toDouble();
|
|
||||||
} catch (e) {
|
|
||||||
print("Impossible de recup -> distance");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
calories = map["calories"];
|
|
||||||
} catch (e) {
|
|
||||||
print("Impossible de recup -> calories");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
steps = map["steps"];
|
|
||||||
} catch (e) {
|
|
||||||
print("Impossible de recup -> steps");
|
|
||||||
}
|
|
||||||
// -- BPM -- //
|
|
||||||
try {
|
|
||||||
bpmAvg = map["bpmAvg"];
|
|
||||||
} catch (e) {
|
|
||||||
print("Impossible de recup -> ");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
bpmMax = map["bpmMax"];
|
|
||||||
} catch (e) {
|
|
||||||
print("Impossible de recup -> ");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
bpmMin = map["bpmMin"];
|
|
||||||
} catch (e) {
|
|
||||||
print("Impossible de recup -> ");
|
|
||||||
}
|
|
||||||
// -- Denivelé -- //
|
|
||||||
try {
|
|
||||||
deniveleNegatif = map["deniveleNegatif"];
|
|
||||||
} catch (e) {
|
|
||||||
print("Impossible de recup -> deniveleNegatif");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
denivelePositif = map["denivelePositif"];
|
|
||||||
} catch (e) {
|
|
||||||
print("Impossible de recup -> denivelePositif");
|
|
||||||
}
|
|
||||||
// -- Altitude -- //
|
|
||||||
try {
|
|
||||||
altitudeMax = map["altitudeMax"];
|
|
||||||
} catch (e) {
|
|
||||||
print("Impossible de recup -> altitudeMax");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
altitudeMin = map["altitudeMin"];
|
|
||||||
} catch (e) {
|
|
||||||
print("Impossible de recup -> altitudeMin");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
altitudeAvg = map["altitudeAvg"];
|
|
||||||
} catch (e) {
|
|
||||||
print("Impossible de recup -> altitudeAvg");
|
|
||||||
}
|
|
||||||
// -- Température -- //
|
|
||||||
try {
|
|
||||||
temperatureMax = map["temperatureMax"];
|
|
||||||
} catch (e) {
|
|
||||||
print("Impossible de recup -> temperatureMax");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
temperatureMin = map["temperatureMin"];
|
|
||||||
} catch (e) {
|
|
||||||
print("Impossible de recup -> temperatureMin");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
temperatureAvg = map["temperatureAvg"];
|
|
||||||
} catch (e) {
|
|
||||||
print("Impossible de recup -> temperatureAvg");
|
|
||||||
}
|
|
||||||
// -- Vitesse -- //
|
|
||||||
try {
|
|
||||||
vitesseMax = map["vitesseMax"].toDouble();
|
|
||||||
} catch (e) {
|
|
||||||
print("Impossible de recup -> vitesseMax");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
vitesseMin = map["vitesseMin"].toDouble();
|
|
||||||
} catch (e) {
|
|
||||||
print("Impossible de recup -> vitesseMin");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
vitesseAvg = map["vitesseAvg"].toDouble();
|
|
||||||
} catch (e) {
|
|
||||||
print("Impossible de recup -> vitesseAvg");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- Ecriture -- //
|
|
||||||
String toJson() {
|
|
||||||
Map<String, dynamic> jsonMap = {
|
|
||||||
// -- BPM -- //
|
|
||||||
'bpmAvg': bpmAvg,
|
|
||||||
'bpmMax': bpmMax,
|
|
||||||
'bpmMin': bpmMin,
|
|
||||||
// -- Denivelé -- //
|
|
||||||
'denivelePositif': denivelePositif,
|
|
||||||
'deniveleNegatif': deniveleNegatif,
|
|
||||||
// -- Altitude -- //
|
|
||||||
'altitudeMax': altitudeMax,
|
|
||||||
'altitudeMin': altitudeMin,
|
|
||||||
'altitudeAvg': altitudeAvg,
|
|
||||||
// -- Température -- //
|
|
||||||
'temperatureMax': temperatureMax,
|
|
||||||
'temperatureMin': temperatureMin,
|
|
||||||
'temperatureAvg': temperatureAvg,
|
|
||||||
// -- Vitesse -- //
|
|
||||||
'vitesseMax': vitesseMax,
|
|
||||||
'vitesseMin': vitesseMin,
|
|
||||||
'vitesseAvg': vitesseAvg,
|
|
||||||
// Ligne session
|
|
||||||
'startTime': startTime.toIso8601String(),
|
|
||||||
'timeOfActivity': timeOfActivity,
|
|
||||||
'distance': distance,
|
|
||||||
'calories': calories,
|
|
||||||
'steps': steps
|
|
||||||
};
|
|
||||||
return jsonEncode(jsonMap);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
import 'dart:io';
|
|
||||||
import 'dart:typed_data';
|
|
||||||
|
|
||||||
import 'package:path/path.dart' as p;
|
|
||||||
import "package:path_provider/path_provider.dart";
|
|
||||||
import 'package:smartfit_app_mobile/main.dart';
|
|
||||||
|
|
||||||
class ActivitySaver {
|
|
||||||
String saveDirectory = "activities";
|
|
||||||
late final Directory applicationDocumentsDir;
|
|
||||||
|
|
||||||
ActivitySaver._create(this.applicationDocumentsDir);
|
|
||||||
|
|
||||||
Uint8List getActivity(String uuid) {
|
|
||||||
String filename = localDB.getActivityFilenameByUuid(uuid);
|
|
||||||
|
|
||||||
final file =
|
|
||||||
File(p.join(applicationDocumentsDir.path, saveDirectory, filename));
|
|
||||||
return file.readAsBytesSync();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> saveActivity(Uint8List activityFile, String filename) async {
|
|
||||||
stdout.write("Creating activity file...\n");
|
|
||||||
final file = await File(
|
|
||||||
p.join(applicationDocumentsDir.path, saveDirectory, filename))
|
|
||||||
.create(recursive: true); // To create dir if not exists
|
|
||||||
file.writeAsBytesSync(activityFile);
|
|
||||||
stdout.write("Activity file created\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void deleteActivity(String uuid) {
|
|
||||||
String filename = localDB.getActivityFilenameByUuid(uuid);
|
|
||||||
final file =
|
|
||||||
File(p.join(applicationDocumentsDir.path, saveDirectory, filename));
|
|
||||||
file.deleteSync();
|
|
||||||
}
|
|
||||||
|
|
||||||
static Future<ActivitySaver> create() async {
|
|
||||||
stdout.write("Activity Saver: Created\n");
|
|
||||||
final appDir = await getApplicationDocumentsDirectory();
|
|
||||||
return ActivitySaver._create(appDir);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
class Convertisseur {
|
|
||||||
// Mettre que des trucs static
|
|
||||||
|
|
||||||
static double secondeIntoMinute(double seconde) {
|
|
||||||
return (seconde / 60);
|
|
||||||
}
|
|
||||||
|
|
||||||
static double milisecondeIntoMinute(double miliseconde) {
|
|
||||||
return (miliseconde / 60000);
|
|
||||||
}
|
|
||||||
|
|
||||||
static double msIntoKmh(double metreSeconde) {
|
|
||||||
return metreSeconde * 3.6;
|
|
||||||
}
|
|
||||||
|
|
||||||
static double millisecondeIntoSeconde(double milliseconde) {
|
|
||||||
return (milliseconde / 1000);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
import 'package:flutter/foundation.dart';
|
|
||||||
|
|
||||||
class Helper {
|
|
||||||
static bool isPlatformWeb() {
|
|
||||||
if (kIsWeb) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,95 +0,0 @@
|
|||||||
import 'package:smartfit_app_mobile/modele/activity.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/local_db/db_impl.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/user.dart';
|
|
||||||
|
|
||||||
class DbDummy implements DbImpl {
|
|
||||||
DbDummy._create();
|
|
||||||
DbDummy();
|
|
||||||
@override
|
|
||||||
Future<DbDummy> create() async {
|
|
||||||
return DbDummy._create();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> init() {
|
|
||||||
throw Exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==== USER ====
|
|
||||||
@override
|
|
||||||
void addUser(String username, String email, String token) {
|
|
||||||
throw Exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
User getUser() {
|
|
||||||
throw Exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool hasUser() {
|
|
||||||
throw Exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void deleteUser() {
|
|
||||||
throw Exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void setUserMail(String email) {
|
|
||||||
throw Exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void setUserName(String username) {
|
|
||||||
throw Exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void setUserToken(String token) {
|
|
||||||
throw Exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==== ACTIVITY ====
|
|
||||||
@override
|
|
||||||
void addActivity(String uuid, String filename, String category, String info) {
|
|
||||||
throw Exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void removeActivity(String uuid) {
|
|
||||||
throw Exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void removeAllActivities() {
|
|
||||||
throw Exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getActivityFilenameByUuid(String uuid) {
|
|
||||||
throw Exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<ActivityOfUser> getAllActivities() {
|
|
||||||
throw Exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==== CONFIG ====
|
|
||||||
@override
|
|
||||||
void initConfig() {
|
|
||||||
throw Exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void setSaveLocally(bool saveLocally) {
|
|
||||||
throw Exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool getSaveLocally() {
|
|
||||||
throw Exception();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
import 'package:smartfit_app_mobile/modele/user.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/activity.dart';
|
|
||||||
|
|
||||||
abstract class DbImpl {
|
|
||||||
DbImpl._create();
|
|
||||||
|
|
||||||
Future<DbImpl> create();
|
|
||||||
|
|
||||||
Future<void> init();
|
|
||||||
|
|
||||||
// ==== USER ====
|
|
||||||
void addUser(String username, String email, String token);
|
|
||||||
User getUser();
|
|
||||||
bool hasUser();
|
|
||||||
void deleteUser();
|
|
||||||
void setUserMail(String email);
|
|
||||||
void setUserName(String username);
|
|
||||||
void setUserToken(String token);
|
|
||||||
|
|
||||||
// ==== ACTIVITY ====
|
|
||||||
void addActivity(String uuid, String filename, String category, String info);
|
|
||||||
void removeActivity(String uuid);
|
|
||||||
void removeAllActivities();
|
|
||||||
String getActivityFilenameByUuid(String uuid);
|
|
||||||
List<ActivityOfUser> getAllActivities();
|
|
||||||
|
|
||||||
// ==== CONFIG ====
|
|
||||||
void initConfig();
|
|
||||||
void setSaveLocally(bool saveLocally);
|
|
||||||
bool getSaveLocally();
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
import 'package:smartfit_app_mobile/modele/local_db/db_impl.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/local_db/objectbox.dart';
|
|
||||||
|
|
||||||
DbImpl getDbImpl() {
|
|
||||||
DbImpl db = ObjectBox();
|
|
||||||
return db;
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
import 'package:smartfit_app_mobile/modele/local_db/db_impl.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/local_db/db_dummy.dart';
|
|
||||||
|
|
||||||
DbImpl getDbImpl() {
|
|
||||||
DbImpl db = DbDummy();
|
|
||||||
return db;
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
import 'package:objectbox/objectbox.dart';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
class User {
|
|
||||||
@Id()
|
|
||||||
int id = 0;
|
|
||||||
String username;
|
|
||||||
String email;
|
|
||||||
String token;
|
|
||||||
|
|
||||||
User(this.id, this.username, this.email, this.token);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
class Activity {
|
|
||||||
int id;
|
|
||||||
@Unique()
|
|
||||||
String uuid;
|
|
||||||
String filename;
|
|
||||||
String category;
|
|
||||||
String info;
|
|
||||||
|
|
||||||
Activity(this.id, this.uuid, this.filename, this.category, this.info);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
class Config {
|
|
||||||
@Id()
|
|
||||||
int id = 0;
|
|
||||||
bool saveLocally;
|
|
||||||
|
|
||||||
Config(this.id, this.saveLocally);
|
|
||||||
}
|
|
@ -1,154 +0,0 @@
|
|||||||
import 'dart:convert';
|
|
||||||
import 'dart:io';
|
|
||||||
import 'package:smartfit_app_mobile/objectbox.g.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/user.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/activity.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/activity_info/activity_info.dart';
|
|
||||||
import 'package:path/path.dart' as p;
|
|
||||||
import 'package:path_provider/path_provider.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/local_db/model.dart' as db;
|
|
||||||
import 'package:smartfit_app_mobile/modele/local_db/db_impl.dart';
|
|
||||||
|
|
||||||
class ObjectBox implements DbImpl {
|
|
||||||
late final Store store;
|
|
||||||
late final Box userBox;
|
|
||||||
late final Box activityBox;
|
|
||||||
late final Box configBox;
|
|
||||||
late final Directory applicationDocumentDir;
|
|
||||||
|
|
||||||
ObjectBox._create(this.store);
|
|
||||||
|
|
||||||
ObjectBox();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<ObjectBox> create() async {
|
|
||||||
final docsDir = await getApplicationDocumentsDirectory();
|
|
||||||
final store = await openStore(directory: p.join(docsDir.path, "database"));
|
|
||||||
return ObjectBox._create(store);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> init() async {
|
|
||||||
applicationDocumentDir = await getApplicationDocumentsDirectory();
|
|
||||||
userBox = store.box<db.User>();
|
|
||||||
activityBox = store.box<db.Activity>();
|
|
||||||
configBox = store.box<db.Config>();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== USER =====
|
|
||||||
@override
|
|
||||||
bool hasUser() {
|
|
||||||
return !userBox.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
User getUser() {
|
|
||||||
db.User userRes = userBox.get(1);
|
|
||||||
return User.create(userRes.username, userRes.email, userRes.token);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void setUserMail(String email) {
|
|
||||||
db.User user = userBox.get(1);
|
|
||||||
user.email = email;
|
|
||||||
userBox.put(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void setUserName(String username) {
|
|
||||||
db.User user = userBox.get(1);
|
|
||||||
user.username = username;
|
|
||||||
userBox.put(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void setUserToken(String token) {
|
|
||||||
db.User user = userBox.get(1);
|
|
||||||
user.token = token;
|
|
||||||
userBox.put(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void deleteUser() {
|
|
||||||
userBox.removeAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void addUser(String username, String email, String token) {
|
|
||||||
userBox.put(db.User(0, username, email, token));
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== Activity =====
|
|
||||||
@override
|
|
||||||
void addActivity(String uuid, String filename, String category, String info) {
|
|
||||||
db.Activity act = db.Activity(0, uuid, filename, category, info);
|
|
||||||
|
|
||||||
try {
|
|
||||||
activityBox.put(act);
|
|
||||||
} on ObjectBoxException {
|
|
||||||
print("Activity already exists");
|
|
||||||
} catch (e) {
|
|
||||||
print("Unknown exception");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: try catch
|
|
||||||
@override
|
|
||||||
void removeActivity(String uuid) {
|
|
||||||
final Query query = activityBox.query(Activity_.uuid.equals(uuid)).build();
|
|
||||||
final db.Activity act = query.findFirst();
|
|
||||||
|
|
||||||
activityBox.remove(act.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String getActivityFilenameByUuid(String uuid) {
|
|
||||||
final Query query = activityBox.query(Activity_.uuid.equals(uuid)).build();
|
|
||||||
final db.Activity act = query.findFirst();
|
|
||||||
|
|
||||||
return act.filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void removeAllActivities() {
|
|
||||||
activityBox.removeAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== FIT Files =====
|
|
||||||
@override
|
|
||||||
List<ActivityOfUser> getAllActivities() {
|
|
||||||
List<dynamic> activityDBList = activityBox.getAll();
|
|
||||||
List<ActivityOfUser> userActivityList = List.empty(growable: true);
|
|
||||||
|
|
||||||
for (db.Activity act in activityDBList) {
|
|
||||||
ActivityInfo actInfo = ActivityInfo.fromJson(jsonDecode(act.info));
|
|
||||||
|
|
||||||
userActivityList
|
|
||||||
.add(ActivityOfUser(actInfo, act.category, act.uuid, act.filename));
|
|
||||||
}
|
|
||||||
|
|
||||||
return userActivityList;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== Config =====
|
|
||||||
@override
|
|
||||||
void initConfig() {
|
|
||||||
db.Config config = db.Config(0, true);
|
|
||||||
configBox.put(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void setSaveLocally(bool saveLocally) {
|
|
||||||
db.Config config = configBox.get(1);
|
|
||||||
config.saveLocally = saveLocally;
|
|
||||||
configBox.put(config);
|
|
||||||
stdout.write("(Config) setSaveLocally: $saveLocally\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool getSaveLocally() {
|
|
||||||
db.Config config = configBox.get(1);
|
|
||||||
stdout.write("(Config) getSaveLocally: ${config.saveLocally}\n");
|
|
||||||
return config.saveLocally;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,94 +0,0 @@
|
|||||||
import 'dart:convert';
|
|
||||||
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_saver.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/api/i_data_strategy.dart';
|
|
||||||
import 'package:tuple/tuple.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/user.dart';
|
|
||||||
import 'dart:io';
|
|
||||||
import 'dart:typed_data';
|
|
||||||
import 'package:smartfit_app_mobile/main.dart';
|
|
||||||
|
|
||||||
class RequestLocal implements IDataStrategy {
|
|
||||||
@override
|
|
||||||
Future<Tuple2> getInfoUser(String token) async {
|
|
||||||
final User user = localDB.getUser();
|
|
||||||
Map<String, String> json = {"email": user.email, "username": user.username};
|
|
||||||
return Tuple2(true, jsonEncode(json));
|
|
||||||
}
|
|
||||||
|
|
||||||
// need to save file on request_api.upload() beforehand.
|
|
||||||
@override
|
|
||||||
Future<Tuple2> getFile(String token, String fileUuid) async {
|
|
||||||
ActivitySaver actSaver = await ActivitySaver.create();
|
|
||||||
Uint8List fileBytes = actSaver.getActivity(fileUuid);
|
|
||||||
|
|
||||||
return Tuple2(true, fileBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<Tuple2> getFiles(String token) async {
|
|
||||||
final List<ActivityOfUser> activities = localDB.getAllActivities();
|
|
||||||
List<Map<String, dynamic>> jsonList = List.empty(growable: true);
|
|
||||||
|
|
||||||
for (ActivityOfUser act in activities) {
|
|
||||||
Map<String, dynamic> json = {
|
|
||||||
"uuid": act.fileUuid,
|
|
||||||
"filename": act.nameFile,
|
|
||||||
"category": act.category,
|
|
||||||
"info": act.activityInfo
|
|
||||||
};
|
|
||||||
jsonList.add(json);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Tuple2(true, jsonList);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<Tuple2<bool, String>> modifAttribut(
|
|
||||||
String token, String nameAttribut, String newValue) async {
|
|
||||||
return const Tuple2(false, "not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<Tuple2<bool, String>> postUser(
|
|
||||||
String email, String hash, String username) async {
|
|
||||||
return const Tuple2(false, "not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<Tuple2<bool, String>> deleteUser(String token) async {
|
|
||||||
return const Tuple2(false, "not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<Tuple2<bool, String>> connexion(String email, String hash) async {
|
|
||||||
return const Tuple2(false, "not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<Tuple2<bool, String>> uploadFile(String token, File file) async {
|
|
||||||
return const Tuple2(false, "not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<Tuple2<bool, String>> uploadFileByte(
|
|
||||||
String token,
|
|
||||||
Uint8List contentFile,
|
|
||||||
String nameFile,
|
|
||||||
String category,
|
|
||||||
DateTime date,
|
|
||||||
ActivityInfo activityInfo) async {
|
|
||||||
return const Tuple2(false, "not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<bool> deleteFile(String token, String fileUuid) async {
|
|
||||||
throw Exception("Not Implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<Tuple2> getModeleAI(String token, String category) async {
|
|
||||||
return const Tuple2(false, "Not implemented");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,362 +0,0 @@
|
|||||||
import 'package:fl_chart/fl_chart.dart';
|
|
||||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
|
||||||
import 'package:smartfit_app_mobile/common_widget/graph/graph.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/activity.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/manager_file.dart';
|
|
||||||
import 'package:latlong2/latlong.dart' as osm;
|
|
||||||
|
|
||||||
class ManagerSelectedActivity {
|
|
||||||
final ManagerFile _managerFile = ManagerFile();
|
|
||||||
List<ActivityOfUser> activitySelected = List.empty(growable: true);
|
|
||||||
|
|
||||||
bool addSelectedActivity(ActivityOfUser activityOfUser) {
|
|
||||||
if (activitySelected.isNotEmpty &&
|
|
||||||
activityOfUser.category != activitySelected.first.category) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
activitySelected.add(activityOfUser);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool removeSelectedActivity(String fileUuid) {
|
|
||||||
for (ActivityOfUser activityOfUser in activitySelected) {
|
|
||||||
if (activityOfUser.fileUuid == fileUuid) {
|
|
||||||
activitySelected.remove(activityOfUser);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- Function utile ---- //
|
|
||||||
// -- func utile -- //
|
|
||||||
bool fileNotSelected(String fileUuid) {
|
|
||||||
for (ActivityOfUser activityOfUser in activitySelected) {
|
|
||||||
if (activityOfUser.fileUuid == fileUuid) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool _notNull(int indexActivitySelected, int ligne, int colonne) {
|
|
||||||
if (activitySelected[indexActivitySelected].contentActivity[ligne]
|
|
||||||
[colonne] ==
|
|
||||||
"null") {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// ------------------- Fonction pour calcul --------- //
|
|
||||||
// ----------------- X WithTime ------------ //
|
|
||||||
|
|
||||||
List<FlSpot> getXWithTime(String field) {
|
|
||||||
List<FlSpot> result = List.empty(growable: true);
|
|
||||||
int firstTimestamp = 0;
|
|
||||||
|
|
||||||
for (int c = 0; c < activitySelected.length; c++) {
|
|
||||||
for (int i = 0; i < activitySelected[c].contentActivity.length; i++) {
|
|
||||||
if (_notNull(c, i, activitySelected[c].enteteCSV["Value_$field"]!)) {
|
|
||||||
if (firstTimestamp == 0) {
|
|
||||||
firstTimestamp = activitySelected[c].contentActivity[i][
|
|
||||||
activitySelected[c]
|
|
||||||
.enteteCSV["Value_${_managerFile.fieldTimeStamp}"]!];
|
|
||||||
}
|
|
||||||
result.add(FlSpot(
|
|
||||||
(((activitySelected[c].contentActivity[i][
|
|
||||||
activitySelected[c].enteteCSV[
|
|
||||||
"Value_${_managerFile.fieldTimeStamp}"]!]) -
|
|
||||||
firstTimestamp) ~/
|
|
||||||
100)
|
|
||||||
.toDouble(),
|
|
||||||
activitySelected[c]
|
|
||||||
.contentActivity[i]
|
|
||||||
[activitySelected[c].enteteCSV["Value_$field"]!]
|
|
||||||
.toDouble()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------------------------//
|
|
||||||
|
|
||||||
// ----------------- BPM ------------------ //
|
|
||||||
int getBpmMaxAllActivitieSelected() {
|
|
||||||
int max = 0;
|
|
||||||
for (ActivityOfUser activityOfUser in activitySelected) {
|
|
||||||
if (activityOfUser.activityInfo.bpmMax > max) {
|
|
||||||
max = activityOfUser.activityInfo.bpmMax;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return max;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getBpmMinAllActivitieSelected() {
|
|
||||||
int min = 999;
|
|
||||||
for (ActivityOfUser activityOfUser in activitySelected) {
|
|
||||||
if (activityOfUser.activityInfo.bpmMax < min) {
|
|
||||||
min = activityOfUser.activityInfo.bpmMin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return min;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getBpmAvgAllActivitieSelected() {
|
|
||||||
int somme = 0;
|
|
||||||
for (ActivityOfUser activityOfUser in activitySelected) {
|
|
||||||
somme += activityOfUser.activityInfo.bpmAvg;
|
|
||||||
}
|
|
||||||
if (somme != 0) {
|
|
||||||
return somme ~/ activitySelected.length;
|
|
||||||
}
|
|
||||||
return somme;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------ Fin BPM ------------------- //
|
|
||||||
// ------------------ Altitude ------------------ //
|
|
||||||
double getMaxAltitudeAllActivitySelected() {
|
|
||||||
double max = 0.0;
|
|
||||||
for (ActivityOfUser activityOfUser in activitySelected) {
|
|
||||||
if (activityOfUser.activityInfo.altitudeMax > max) {
|
|
||||||
max = activityOfUser.activityInfo.altitudeMax;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return max;
|
|
||||||
}
|
|
||||||
|
|
||||||
double getMinAltitudeAllActivitySelected() {
|
|
||||||
double min = 99999.0;
|
|
||||||
for (ActivityOfUser activityOfUser in activitySelected) {
|
|
||||||
if (activityOfUser.activityInfo.altitudeMax < min) {
|
|
||||||
min = activityOfUser.activityInfo.altitudeMin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return min;
|
|
||||||
}
|
|
||||||
|
|
||||||
double getAvgAltitudeAllActivitySelected() {
|
|
||||||
double somme = 0;
|
|
||||||
for (ActivityOfUser activityOfUser in activitySelected) {
|
|
||||||
somme += activityOfUser.activityInfo.altitudeAvg;
|
|
||||||
}
|
|
||||||
return somme / activitySelected.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------ Fin Altitude ------------------- //
|
|
||||||
// ------------------ Denivelé ----------------------- //
|
|
||||||
|
|
||||||
double getTotalDenivelePositifAllActivitySelected() {
|
|
||||||
double somme = 0;
|
|
||||||
for (ActivityOfUser activityOfUser in activitySelected) {
|
|
||||||
somme += activityOfUser.activityInfo.denivelePositif;
|
|
||||||
}
|
|
||||||
return somme;
|
|
||||||
}
|
|
||||||
|
|
||||||
double getTotalDeniveleNegatifAllActivitySelected() {
|
|
||||||
double somme = 0;
|
|
||||||
for (ActivityOfUser activityOfUser in activitySelected) {
|
|
||||||
somme += activityOfUser.activityInfo.denivelePositif;
|
|
||||||
}
|
|
||||||
return somme;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------ Fin Denivelé ------------------- //
|
|
||||||
// ------------------ Température -------------------- //
|
|
||||||
int getAvgTemperatureAllActivitySelected() {
|
|
||||||
int somme = 0;
|
|
||||||
for (ActivityOfUser activityOfUser in activitySelected) {
|
|
||||||
somme += activityOfUser.activityInfo.temperatureAvg;
|
|
||||||
}
|
|
||||||
return somme ~/ activitySelected.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getMaxTemperatureAllActivitySelected() {
|
|
||||||
int max = 0;
|
|
||||||
for (ActivityOfUser activityOfUser in activitySelected) {
|
|
||||||
if (activityOfUser.activityInfo.temperatureMax > max) {
|
|
||||||
max = activityOfUser.activityInfo.temperatureMax;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return max;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getMinTemperatureAllActivitySelected() {
|
|
||||||
int min = 0;
|
|
||||||
for (ActivityOfUser activityOfUser in activitySelected) {
|
|
||||||
if (activityOfUser.activityInfo.temperatureMin > min) {
|
|
||||||
min = activityOfUser.activityInfo.temperatureMin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return min;
|
|
||||||
}
|
|
||||||
// -------------------------- FIN Température ---------------------- //
|
|
||||||
|
|
||||||
// ---------------------- Distance ---------------------- //
|
|
||||||
|
|
||||||
double getDistanceAllActivitySelected() {
|
|
||||||
double somme = 0;
|
|
||||||
for (ActivityOfUser activityOfUser in activitySelected) {
|
|
||||||
somme += activityOfUser.activityInfo.distance;
|
|
||||||
}
|
|
||||||
return somme;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------- FIN Distance ---------------------- //
|
|
||||||
|
|
||||||
// ---------------------- Calories ---------------------- //
|
|
||||||
int getCalorieAllActivitySelected() {
|
|
||||||
int somme = 0;
|
|
||||||
for (ActivityOfUser activityOfUser in activitySelected) {
|
|
||||||
somme += activityOfUser.activityInfo.calories;
|
|
||||||
}
|
|
||||||
return somme;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------- FIN Calories ---------------------- //
|
|
||||||
// ---------------------- Step ------------------------------//
|
|
||||||
|
|
||||||
int getStepsAllActivitySelected() {
|
|
||||||
int somme = 0;
|
|
||||||
for (ActivityOfUser activityOfUser in activitySelected) {
|
|
||||||
somme += activityOfUser.activityInfo.steps;
|
|
||||||
}
|
|
||||||
return somme;
|
|
||||||
}
|
|
||||||
// ----------------------- FIN Step ------------------------ //
|
|
||||||
|
|
||||||
// ------------------------- Time ----------------------------- //
|
|
||||||
|
|
||||||
double getTimeAllActivitySelected() {
|
|
||||||
double somme = 0;
|
|
||||||
for (ActivityOfUser activityOfUser in activitySelected) {
|
|
||||||
somme += activityOfUser.activityInfo.timeOfActivity;
|
|
||||||
}
|
|
||||||
return somme;
|
|
||||||
}
|
|
||||||
// ---------------------------- FIN time -------------------- //
|
|
||||||
|
|
||||||
// -------------------------- Speed ---------------------- //
|
|
||||||
|
|
||||||
// -- CSV -- //
|
|
||||||
List<DataPoint> getSpeedWithTimeActivity() {
|
|
||||||
List<DataPoint> result = List.empty(growable: true);
|
|
||||||
int firstTimestamp = 0;
|
|
||||||
|
|
||||||
for (int c = 0; c < activitySelected.length; c++) {
|
|
||||||
for (int i = 0; i < activitySelected[c].contentActivity.length; i++) {
|
|
||||||
if (_notNull(
|
|
||||||
c,
|
|
||||||
i,
|
|
||||||
activitySelected[c]
|
|
||||||
.enteteCSV["Value_${_managerFile.fieldTimeStamp}"]!) &&
|
|
||||||
_notNull(
|
|
||||||
c,
|
|
||||||
i,
|
|
||||||
activitySelected[c]
|
|
||||||
.enteteCSV["Value_${_managerFile.fieldSpeed}"]!)) {
|
|
||||||
if (firstTimestamp == 0) {
|
|
||||||
firstTimestamp = activitySelected[c].contentActivity[i][
|
|
||||||
activitySelected[c]
|
|
||||||
.enteteCSV["Value_${_managerFile.fieldTimeStamp}"]!];
|
|
||||||
}
|
|
||||||
result.add(DataPoint(
|
|
||||||
(((activitySelected[c].contentActivity[i][
|
|
||||||
activitySelected[c].enteteCSV[
|
|
||||||
"Value_${_managerFile.fieldTimeStamp}"]!]) -
|
|
||||||
firstTimestamp) ~/
|
|
||||||
100)
|
|
||||||
.toDouble(),
|
|
||||||
activitySelected[c]
|
|
||||||
.contentActivity[i][activitySelected[c]
|
|
||||||
.enteteCSV["Value_${_managerFile.fieldSpeed}"]!]
|
|
||||||
.toDouble()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
double getMaxSpeedAllActivitySelected() {
|
|
||||||
double max = 0.00;
|
|
||||||
for (ActivityOfUser activityOfUser in activitySelected) {
|
|
||||||
if (activityOfUser.activityInfo.vitesseMax > max) {
|
|
||||||
max = activityOfUser.activityInfo.vitesseMax;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return max;
|
|
||||||
}
|
|
||||||
|
|
||||||
double getMinSpeedAllActivitySelected() {
|
|
||||||
double min = 99999.9;
|
|
||||||
for (ActivityOfUser activityOfUser in activitySelected) {
|
|
||||||
if (activityOfUser.activityInfo.vitesseMin < min) {
|
|
||||||
min = activityOfUser.activityInfo.vitesseMin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return min;
|
|
||||||
}
|
|
||||||
|
|
||||||
double getAvgSpeedAllActivitySelected() {
|
|
||||||
double somme = 0.0;
|
|
||||||
for (ActivityOfUser activityOfUser in activitySelected) {
|
|
||||||
somme += activityOfUser.activityInfo.vitesseAvg;
|
|
||||||
}
|
|
||||||
return somme / activitySelected.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------- FIN Speed ---------------------- //
|
|
||||||
|
|
||||||
// -------------------------- Localisation ------------------- //
|
|
||||||
|
|
||||||
// Retourne les positions (Fichier CSV)
|
|
||||||
// Utilisable que si qu'une seule activité à été utilisé !!!
|
|
||||||
List<LatLng> getPosition() {
|
|
||||||
List<LatLng> list = List.empty(growable: true);
|
|
||||||
|
|
||||||
for (int i = 0; i < activitySelected[0].contentActivity.length; i++) {
|
|
||||||
if (_notNull(
|
|
||||||
0,
|
|
||||||
i,
|
|
||||||
activitySelected[0]
|
|
||||||
.enteteCSV["Value_${_managerFile.fieldPositionLatitude}"]!) &&
|
|
||||||
_notNull(
|
|
||||||
0,
|
|
||||||
i,
|
|
||||||
activitySelected[0].enteteCSV[
|
|
||||||
"Value_${_managerFile.fieldPositionLongitude}"]!)) {
|
|
||||||
list.add(LatLng(
|
|
||||||
activitySelected[0].contentActivity[i][activitySelected[0]
|
|
||||||
.enteteCSV["Value_${_managerFile.fieldPositionLatitude}"]!],
|
|
||||||
activitySelected[0].contentActivity[i][activitySelected[0]
|
|
||||||
.enteteCSV["Value_${_managerFile.fieldPositionLongitude}"]!]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<osm.LatLng> getPositionOSM() {
|
|
||||||
List<osm.LatLng> list = List.empty(growable: true);
|
|
||||||
|
|
||||||
for (int i = 0; i < activitySelected[0].contentActivity.length; i++) {
|
|
||||||
if (_notNull(
|
|
||||||
0,
|
|
||||||
i,
|
|
||||||
activitySelected[0]
|
|
||||||
.enteteCSV["Value_${_managerFile.fieldPositionLatitude}"]!) &&
|
|
||||||
_notNull(
|
|
||||||
0,
|
|
||||||
i,
|
|
||||||
activitySelected[0].enteteCSV[
|
|
||||||
"Value_${_managerFile.fieldPositionLongitude}"]!)) {
|
|
||||||
list.add(osm.LatLng(
|
|
||||||
activitySelected[0].contentActivity[i][activitySelected[0]
|
|
||||||
.enteteCSV["Value_${_managerFile.fieldPositionLatitude}"]!],
|
|
||||||
activitySelected[0].contentActivity[i][activitySelected[0]
|
|
||||||
.enteteCSV["Value_${_managerFile.fieldPositionLongitude}"]!]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,6 @@
|
|||||||
|
class AttributUser {
|
||||||
|
final String _email = "email";
|
||||||
|
final String _username = "username";
|
||||||
|
String get email => _email;
|
||||||
|
String get username => _username;
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
class AttributFileFit {
|
||||||
|
// Ajouter une variable privé qui contient le champs + un getter
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:smartfit_app_mobile/modele/api/i_data_strategy.dart';
|
||||||
|
import 'package:smartfit_app_mobile/modele/api/request_api.dart';
|
||||||
|
import 'package:smartfit_app_mobile/modele/manager_file.dart';
|
||||||
|
import 'package:smartfit_app_mobile/modele/user.dart';
|
||||||
|
import 'package:tuple/tuple.dart';
|
||||||
|
|
||||||
|
class ListActivityUtile {
|
||||||
|
final IDataStrategy _strategy = RequestApi();
|
||||||
|
final ManagerFile _managerFile = ManagerFile();
|
||||||
|
|
||||||
|
Future<void> getContentOnTheFirstFileMobile(BuildContext context) async {
|
||||||
|
Tuple2 result = await _strategy.getFile(
|
||||||
|
Provider.of<User>(context, listen: false).token,
|
||||||
|
Provider.of<User>(context, listen: false).listActivity[0].fileUuid);
|
||||||
|
if (result.item1 == false) {
|
||||||
|
//Erreur
|
||||||
|
//print(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
File file = File(
|
||||||
|
"${await _managerFile.localPath}/${Provider.of<User>(context, listen: false).listActivity[0].nameFile}");
|
||||||
|
await file.create();
|
||||||
|
await file.writeAsBytes(result.item2);
|
||||||
|
Provider.of<User>(context, listen: false).listActivity[0].contentActivity =
|
||||||
|
await _managerFile.readFitFileWhithFile(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> getContentOnTheFirstFileWeb(BuildContext context) async {
|
||||||
|
User user = Provider.of<User>(context, listen: false);
|
||||||
|
Tuple2 result =
|
||||||
|
await _strategy.getFile(user.token, user.listActivity[0].fileUuid);
|
||||||
|
if (result.item1 == false) {
|
||||||
|
//Erreur
|
||||||
|
//print(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Provider.of<User>(context, listen: false).listActivity[0].contentActivity =
|
||||||
|
await _managerFile.readFitFileWeb(result.item2);
|
||||||
|
}
|
||||||
|
}
|
@ -1,154 +0,0 @@
|
|||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:smartfit_app_mobile/main.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/api/api_wrapper.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/activity_saver.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/helper.dart';
|
|
||||||
import 'dart:convert';
|
|
||||||
import 'dart:io';
|
|
||||||
import 'package:csv/csv.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/activity.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/activity_info/activity_info.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/manager_file.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/user.dart';
|
|
||||||
import 'package:smartfit_app_mobile/modele/utile/info_message.dart';
|
|
||||||
import 'package:tuple/tuple.dart';
|
|
||||||
|
|
||||||
class ListActivityUtile {
|
|
||||||
final ApiWrapper api = ApiWrapper();
|
|
||||||
final ManagerFile _managerFile = ManagerFile();
|
|
||||||
|
|
||||||
Future<Tuple2<bool, String>> getContentActivity(BuildContext context,
|
|
||||||
ActivityOfUser activityOfUser, InfoMessage infoManager) async {
|
|
||||||
Tuple2 result = await api.getFile(
|
|
||||||
Provider.of<User>(context, listen: false).token,
|
|
||||||
activityOfUser.fileUuid,
|
|
||||||
infoManager);
|
|
||||||
if (result.item1 == false) {
|
|
||||||
return Tuple2(result.item1, result.item2);
|
|
||||||
}
|
|
||||||
|
|
||||||
activityOfUser.contentActivity =
|
|
||||||
List.from(_managerFile.convertByteIntoCSV(result.item2));
|
|
||||||
|
|
||||||
// TODO: Not sure this line as an utility
|
|
||||||
// localDB.saveActivityFile(activityOfUser.contentActivity);
|
|
||||||
|
|
||||||
// TODO: Check if file exists, right now it overwrites each time
|
|
||||||
// TODO: Make ActivitySaver member of the class
|
|
||||||
if (!Helper.isPlatformWeb() && localDB.getSaveLocally()) {
|
|
||||||
ActivitySaver actSaver = await ActivitySaver.create();
|
|
||||||
actSaver.saveActivity(result.item2,
|
|
||||||
localDB.getActivityFilenameByUuid(activityOfUser.fileUuid));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Provider.of<User>(context, listen: false)
|
|
||||||
.managerSelectedActivity
|
|
||||||
.addSelectedActivity(activityOfUser)) {
|
|
||||||
return const Tuple2(false, "Pas de même categorie");
|
|
||||||
}
|
|
||||||
return const Tuple2(true, "Yeah");
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<Tuple2<bool, String>> getFiles(
|
|
||||||
String token, BuildContext context, InfoMessage infoManager) async {
|
|
||||||
bool notZero = false;
|
|
||||||
Tuple2 result = await api.getFiles(
|
|
||||||
Provider.of<User>(context, listen: false).token, infoManager);
|
|
||||||
if (result.item1 == false) {
|
|
||||||
return Tuple2(result.item1, result.item2);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var element in result.item2) {
|
|
||||||
if (!notZero) {
|
|
||||||
Provider.of<User>(context, listen: false).listActivity.clear();
|
|
||||||
notZero = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Provider.of<User>(context, listen: false).addActivity(ActivityOfUser(
|
|
||||||
ActivityInfo.fromJson(element["info"]),
|
|
||||||
element["category"].toString(),
|
|
||||||
element["uuid"].toString(),
|
|
||||||
element["filename"].toString()));
|
|
||||||
|
|
||||||
// Save to local db
|
|
||||||
if (!kIsWeb) {
|
|
||||||
localDB.addActivity(element["uuid"], element["filename"],
|
|
||||||
element["category"], jsonEncode(element["info"]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return const Tuple2(true, "Yeah");
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<Tuple2<bool, String>> addFile(Uint8List bytes, String filename,
|
|
||||||
String token, InfoMessage infoManager) async {
|
|
||||||
// -- Transormer le fit en CSV
|
|
||||||
Tuple4<bool, List<List<String>>, ActivityInfo, String> resultData =
|
|
||||||
_managerFile.convertBytesFitFileIntoCSVListAndGetInfo(bytes);
|
|
||||||
|
|
||||||
String csvString = const ListToCsvConverter().convert(resultData.item2);
|
|
||||||
Uint8List byteCSV = Uint8List.fromList(utf8.encode(csvString));
|
|
||||||
|
|
||||||
/* -- 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,
|
|
||||||
filename,
|
|
||||||
resultData.item4, // category
|
|
||||||
resultData.item3.startTime, // activityInfo
|
|
||||||
resultData.item3,
|
|
||||||
infoManager);
|
|
||||||
if (result.item1 == false) {
|
|
||||||
return Tuple2(false, result.item2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save on local storage if plateform not browser
|
|
||||||
if (!Helper.isPlatformWeb() && localDB.getSaveLocally()) {
|
|
||||||
ActivitySaver actSaver = await ActivitySaver.create();
|
|
||||||
actSaver.saveActivity(byteCSV, filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
return const Tuple2(true, "Yeah");
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Ne marche pas sous windows !! Jsp linux (mettre en format mobile) -- //
|
|
||||||
Future<void> addFileWeb(Uint8List? bytes, String token, String filename,
|
|
||||||
BuildContext context, InfoMessage infoManager) async {
|
|
||||||
if (bytes == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Tuple2<bool, String> resultAdd =
|
|
||||||
await addFile(bytes, filename, token, infoManager);
|
|
||||||
if (!resultAdd.item1) {
|
|
||||||
//print("Message error");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Tuple2<bool, String> resultGet =
|
|
||||||
await getFiles(token, context, infoManager);
|
|
||||||
if (!resultGet.item1) {
|
|
||||||
//print("Message error");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> addFileMobile(String path, String token, String filename,
|
|
||||||
BuildContext context, InfoMessage infoManager) async {
|
|
||||||
Tuple2<bool, String> resultAdd = await addFile(
|
|
||||||
await File(path).readAsBytes(), filename, token, infoManager);
|
|
||||||
if (!resultAdd.item1) {
|
|
||||||
//print("Message error");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// TODO: What is that ?
|
|
||||||
Tuple2<bool, String> resultGet =
|
|
||||||
await getFiles(token, context, infoManager);
|
|
||||||
if (!resultGet.item1) {
|
|
||||||
//print("Message error");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,10 @@
|
|||||||
|
import 'package:smartfit_app_mobile/modele/api/i_data_strategy.dart';
|
||||||
|
import 'package:smartfit_app_mobile/modele/api/request_api.dart';
|
||||||
|
|
||||||
|
class ProfileUtil {
|
||||||
|
final IDataStrategy _dataStrategy = RequestApi();
|
||||||
|
|
||||||
|
void modifyDataUser(String token, String attribut, String newUsername) {
|
||||||
|
_dataStrategy.modifAttribut(token, attribut, newUsername);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,430 @@
|
|||||||
|
import 'package:fl_chart/fl_chart.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import '../../common/colo_extension.dart';
|
||||||
|
import '../../common_widget/today_target_cell.dart';
|
||||||
|
|
||||||
|
class ActivityTrackerView extends StatefulWidget {
|
||||||
|
const ActivityTrackerView({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ActivityTrackerView> createState() => _ActivityTrackerViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ActivityTrackerViewState extends State<ActivityTrackerView> {
|
||||||
|
int touchedIndex = -1;
|
||||||
|
|
||||||
|
List latestArr = [
|
||||||
|
{
|
||||||
|
"image": "assets/img/workout1.svg",
|
||||||
|
"title": "Drinking 300ml Water",
|
||||||
|
"time": "About 1 minutes ago"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"image": "assets/img/workout1.svg",
|
||||||
|
"title": "Eat Snack (Fitbar)",
|
||||||
|
"time": "About 3 hours ago"
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
var media = MediaQuery.of(context).size;
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
backgroundColor: TColor.white,
|
||||||
|
centerTitle: true,
|
||||||
|
elevation: 0,
|
||||||
|
leading: InkWell(
|
||||||
|
onTap: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
margin: const EdgeInsets.all(8),
|
||||||
|
height: 40,
|
||||||
|
width: 40,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: TColor.lightGray,
|
||||||
|
borderRadius: BorderRadius.circular(10)),
|
||||||
|
child: Image.asset(
|
||||||
|
"assets/img/black_btn.png",
|
||||||
|
width: 15,
|
||||||
|
height: 15,
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
"Suivi d'activité",
|
||||||
|
style: TextStyle(
|
||||||
|
color: TColor.black, fontSize: 16, fontWeight: FontWeight.w700),
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
InkWell(
|
||||||
|
onTap: () {},
|
||||||
|
child: Container(
|
||||||
|
margin: const EdgeInsets.all(8),
|
||||||
|
height: 40,
|
||||||
|
width: 40,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: TColor.lightGray,
|
||||||
|
borderRadius: BorderRadius.circular(10)),
|
||||||
|
child: Image.asset(
|
||||||
|
"assets/img/more_btn.png",
|
||||||
|
width: 15,
|
||||||
|
height: 15,
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
backgroundColor: TColor.white,
|
||||||
|
body: SingleChildScrollView(
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 25, horizontal: 25),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding:
|
||||||
|
const EdgeInsets.symmetric(vertical: 15, horizontal: 15),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
gradient: LinearGradient(colors: [
|
||||||
|
TColor.primaryColor2.withOpacity(0.3),
|
||||||
|
TColor.primaryColor1.withOpacity(0.3)
|
||||||
|
]),
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Objectif d'aujourd'hui",
|
||||||
|
style: TextStyle(
|
||||||
|
color: TColor.black,
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w700),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: 30,
|
||||||
|
height: 30,
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
gradient: LinearGradient(
|
||||||
|
colors: TColor.primaryG,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
child: MaterialButton(
|
||||||
|
onPressed: () {},
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
height: 30,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(25)),
|
||||||
|
textColor: TColor.primaryColor1,
|
||||||
|
minWidth: double.maxFinite,
|
||||||
|
elevation: 0,
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: const Icon(
|
||||||
|
Icons.add,
|
||||||
|
color: Colors.white,
|
||||||
|
size: 15,
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 15,
|
||||||
|
),
|
||||||
|
const Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: TodayTargetCell(
|
||||||
|
icon: "assets/img/workout1.svg",
|
||||||
|
value: "800",
|
||||||
|
title: "Calories",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: 15,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: TodayTargetCell(
|
||||||
|
icon: "assets/img/workout1.svg",
|
||||||
|
value: "2400",
|
||||||
|
title: "Nombre pas",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: media.width * 0.1,
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Activité journalière",
|
||||||
|
style: TextStyle(
|
||||||
|
color: TColor.black,
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w700),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 30,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
gradient: LinearGradient(colors: TColor.primaryG),
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
),
|
||||||
|
child: DropdownButtonHideUnderline(
|
||||||
|
child: DropdownButton(
|
||||||
|
items: ["Semaine", "Mois"]
|
||||||
|
.map((name) => DropdownMenuItem(
|
||||||
|
value: name,
|
||||||
|
child: Text(
|
||||||
|
name,
|
||||||
|
style: TextStyle(
|
||||||
|
color: TColor.gray, fontSize: 14),
|
||||||
|
),
|
||||||
|
))
|
||||||
|
.toList(),
|
||||||
|
onChanged: (value) {},
|
||||||
|
icon: Icon(Icons.expand_more, color: TColor.white),
|
||||||
|
hint: Text(
|
||||||
|
"Semaine",
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(color: TColor.white, fontSize: 12),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: media.width * 0.05,
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: media.width * 0.5,
|
||||||
|
padding:
|
||||||
|
const EdgeInsets.symmetric(vertical: 15, horizontal: 0),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: TColor.white,
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
boxShadow: const [
|
||||||
|
BoxShadow(color: Colors.black12, blurRadius: 3)
|
||||||
|
]),
|
||||||
|
child: BarChart(BarChartData(
|
||||||
|
barTouchData: BarTouchData(
|
||||||
|
touchTooltipData: BarTouchTooltipData(
|
||||||
|
tooltipBgColor: Colors.grey,
|
||||||
|
tooltipHorizontalAlignment: FLHorizontalAlignment.right,
|
||||||
|
tooltipMargin: 10,
|
||||||
|
getTooltipItem: (group, groupIndex, rod, rodIndex) {
|
||||||
|
String weekDay;
|
||||||
|
switch (group.x) {
|
||||||
|
case 0:
|
||||||
|
weekDay = 'Monday';
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
weekDay = 'Tuesday';
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
weekDay = 'Wednesday';
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
weekDay = 'Thursday';
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
weekDay = 'Friday';
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
weekDay = 'Saturday';
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
weekDay = 'Sunday';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw Error();
|
||||||
|
}
|
||||||
|
return BarTooltipItem(
|
||||||
|
'$weekDay\n',
|
||||||
|
const TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 14,
|
||||||
|
),
|
||||||
|
children: <TextSpan>[
|
||||||
|
TextSpan(
|
||||||
|
text: (rod.toY - 1).toString(),
|
||||||
|
style: TextStyle(
|
||||||
|
color: TColor.white,
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
touchCallback: (FlTouchEvent event, barTouchResponse) {
|
||||||
|
setState(() {
|
||||||
|
if (!event.isInterestedForInteractions ||
|
||||||
|
barTouchResponse == null ||
|
||||||
|
barTouchResponse.spot == null) {
|
||||||
|
touchedIndex = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
touchedIndex =
|
||||||
|
barTouchResponse.spot!.touchedBarGroupIndex;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
titlesData: FlTitlesData(
|
||||||
|
show: true,
|
||||||
|
rightTitles: AxisTitles(
|
||||||
|
sideTitles: SideTitles(showTitles: false),
|
||||||
|
),
|
||||||
|
topTitles: AxisTitles(
|
||||||
|
sideTitles: SideTitles(showTitles: false),
|
||||||
|
),
|
||||||
|
bottomTitles: AxisTitles(
|
||||||
|
sideTitles: SideTitles(
|
||||||
|
showTitles: true,
|
||||||
|
getTitlesWidget: getTitles,
|
||||||
|
reservedSize: 38,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
leftTitles: AxisTitles(
|
||||||
|
sideTitles: SideTitles(
|
||||||
|
showTitles: false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
borderData: FlBorderData(
|
||||||
|
show: false,
|
||||||
|
),
|
||||||
|
barGroups: showingGroups(),
|
||||||
|
gridData: FlGridData(show: false),
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: media.width * 0.05,
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: media.width * 0.1,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget getTitles(double value, TitleMeta meta) {
|
||||||
|
var style = TextStyle(
|
||||||
|
color: TColor.gray,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
fontSize: 12,
|
||||||
|
);
|
||||||
|
Widget text;
|
||||||
|
switch (value.toInt()) {
|
||||||
|
case 0:
|
||||||
|
text = Text('Dim', style: style);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
text = Text('Lun', style: style);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
text = Text('Mar', style: style);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
text = Text('Mer', style: style);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
text = Text('Jeu', style: style);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
text = Text('Ven', style: style);
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
text = Text('Sam', style: style);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
text = Text('', style: style);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return SideTitleWidget(
|
||||||
|
axisSide: meta.axisSide,
|
||||||
|
space: 16,
|
||||||
|
child: text,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<BarChartGroupData> showingGroups() => List.generate(7, (i) {
|
||||||
|
switch (i) {
|
||||||
|
case 0:
|
||||||
|
return makeGroupData(0, 5, TColor.primaryG,
|
||||||
|
isTouched: i == touchedIndex);
|
||||||
|
case 1:
|
||||||
|
return makeGroupData(1, 10.5, TColor.secondaryG,
|
||||||
|
isTouched: i == touchedIndex);
|
||||||
|
case 2:
|
||||||
|
return makeGroupData(2, 5, TColor.primaryG,
|
||||||
|
isTouched: i == touchedIndex);
|
||||||
|
case 3:
|
||||||
|
return makeGroupData(3, 7.5, TColor.secondaryG,
|
||||||
|
isTouched: i == touchedIndex);
|
||||||
|
case 4:
|
||||||
|
return makeGroupData(4, 15, TColor.primaryG,
|
||||||
|
isTouched: i == touchedIndex);
|
||||||
|
case 5:
|
||||||
|
return makeGroupData(5, 5.5, TColor.secondaryG,
|
||||||
|
isTouched: i == touchedIndex);
|
||||||
|
case 6:
|
||||||
|
return makeGroupData(6, 8.5, TColor.primaryG,
|
||||||
|
isTouched: i == touchedIndex);
|
||||||
|
default:
|
||||||
|
return throw Error();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
BarChartGroupData makeGroupData(
|
||||||
|
int x,
|
||||||
|
double y,
|
||||||
|
List<Color> barColor, {
|
||||||
|
bool isTouched = false,
|
||||||
|
double width = 22,
|
||||||
|
List<int> showTooltips = const [],
|
||||||
|
}) {
|
||||||
|
return BarChartGroupData(
|
||||||
|
x: x,
|
||||||
|
barRods: [
|
||||||
|
BarChartRodData(
|
||||||
|
toY: isTouched ? y + 1 : y,
|
||||||
|
gradient: LinearGradient(
|
||||||
|
colors: barColor,
|
||||||
|
begin: Alignment.topCenter,
|
||||||
|
end: Alignment.bottomCenter),
|
||||||
|
width: width,
|
||||||
|
borderSide: isTouched
|
||||||
|
? const BorderSide(color: Colors.green)
|
||||||
|
: const BorderSide(color: Colors.white, width: 0),
|
||||||
|
backDrawRodData: BackgroundBarChartRodData(
|
||||||
|
show: true,
|
||||||
|
toY: 20,
|
||||||
|
color: TColor.lightGray,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
showingTooltipIndicators: showTooltips,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,180 +0,0 @@
|
|||||||
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);
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<Prediction> createState() => _PredictionState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _PredictionState extends State<Prediction> {
|
|
||||||
List<Map<String, dynamic>> lastWorkoutArr = [
|
|
||||||
{
|
|
||||||
"name": "Time",
|
|
||||||
"image": "assets/img/time-icon2.svg",
|
|
||||||
"value": "..",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Heart rate",
|
|
||||||
"image": "assets/img/bpm2-icon.svg",
|
|
||||||
"value": "..",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Speed",
|
|
||||||
"image": "assets/img/vitesse2-icon.svg",
|
|
||||||
"value": "..",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Distance",
|
|
||||||
"image": "assets/img/distance2-icon.svg",
|
|
||||||
"value": "..",
|
|
||||||
}
|
|
||||||
];
|
|
||||||
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";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return Scaffold(
|
|
||||||
body: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20.0),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
const SizedBox(height: 40),
|
|
||||||
Text(
|
|
||||||
"Prediction",
|
|
||||||
style: TextStyle(
|
|
||||||
color: TColor.black,
|
|
||||||
fontSize: 22,
|
|
||||||
fontWeight: FontWeight.w700,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
const Row(
|
|
||||||
children: [],
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: TColor.lightGray,
|
|
||||||
boxShadow: [
|
|
||||||
BoxShadow(
|
|
||||||
color: const Color.fromARGB(255, 234, 234, 234)
|
|
||||||
.withOpacity(0.9),
|
|
||||||
spreadRadius: 2,
|
|
||||||
blurRadius: 5,
|
|
||||||
offset: const Offset(0, 2),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
borderRadius: BorderRadius.circular(15),
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
alignment: Alignment.center,
|
|
||||||
width: 50,
|
|
||||||
height: 50,
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
|
||||||
child: SvgPicture.asset(
|
|
||||||
"assets/img/Profile_tab.svg",
|
|
||||||
width: 20,
|
|
||||||
height: 20,
|
|
||||||
fit: BoxFit.contain,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: DropdownButtonHideUnderline(
|
|
||||||
child: DropdownButton(
|
|
||||||
items: listCategory
|
|
||||||
.map((name) => DropdownMenuItem(
|
|
||||||
value: name,
|
|
||||||
child: Text(
|
|
||||||
name,
|
|
||||||
style: TextStyle(
|
|
||||||
color: TColor.gray,
|
|
||||||
fontSize: 14,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
))
|
|
||||||
.toList(),
|
|
||||||
onChanged: (value) {
|
|
||||||
setState(() {
|
|
||||||
selectedCategory = value!;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
isExpanded: true,
|
|
||||||
hint: Text(
|
|
||||||
selectedCategory,
|
|
||||||
style: TextStyle(
|
|
||||||
color: TColor.gray,
|
|
||||||
fontSize: 12,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// Bouton "Valider" prenant 30% de la largeur du parent
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
RoundButton(
|
|
||||||
title: "Save",
|
|
||||||
onPressed: () async {
|
|
||||||
prediction();
|
|
||||||
}),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
ListView.builder(
|
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
|
||||||
shrinkWrap: true,
|
|
||||||
itemCount: lastWorkoutArr.length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
var wObj = lastWorkoutArr[index];
|
|
||||||
return InkWell(
|
|
||||||
child: WorkoutRow(wObj: wObj),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,246 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
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';
|
|
||||||
import 'package:smartfit_app_mobile/modele/utile/home_view/home_view_util.dart';
|
|
||||||
|
|
||||||
class StatAtivities extends StatefulWidget {
|
|
||||||
const StatAtivities({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<StatAtivities> createState() => _StatAtivities();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _StatAtivities extends State<StatAtivities> {
|
|
||||||
late DataHomeView data;
|
|
||||||
TextEditingController bpmController = TextEditingController();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
var media = MediaQuery.of(context).size;
|
|
||||||
data = HomeViewUtil().initData(context);
|
|
||||||
ManagerSelectedActivity managerSelectedActivity =
|
|
||||||
context.watch<User>().managerSelectedActivity;
|
|
||||||
|
|
||||||
// -- BPM -- //
|
|
||||||
int maxBpm = managerSelectedActivity.getBpmMaxAllActivitieSelected();
|
|
||||||
int minBpm = managerSelectedActivity.getBpmMinAllActivitieSelected();
|
|
||||||
int avgBpm = managerSelectedActivity.getBpmAvgAllActivitieSelected();
|
|
||||||
// -- Altitude -- //
|
|
||||||
double maxAltitude =
|
|
||||||
managerSelectedActivity.getMaxAltitudeAllActivitySelected();
|
|
||||||
double minAltitude =
|
|
||||||
managerSelectedActivity.getMinAltitudeAllActivitySelected();
|
|
||||||
double avgAltitude =
|
|
||||||
managerSelectedActivity.getAvgAltitudeAllActivitySelected();
|
|
||||||
|
|
||||||
// -- Température -- //
|
|
||||||
double avgTemperature = context
|
|
||||||
.watch<User>()
|
|
||||||
.managerSelectedActivity
|
|
||||||
.getAvgTemperatureAllActivitySelected()
|
|
||||||
.toDouble();
|
|
||||||
double maxTemperature = context
|
|
||||||
.watch<User>()
|
|
||||||
.managerSelectedActivity
|
|
||||||
.getMaxTemperatureAllActivitySelected()
|
|
||||||
.toDouble();
|
|
||||||
double minTemperature = context
|
|
||||||
.watch<User>()
|
|
||||||
.managerSelectedActivity
|
|
||||||
.getMinTemperatureAllActivitySelected()
|
|
||||||
.toDouble();
|
|
||||||
// ----- Distance ---- //
|
|
||||||
double getTotalDistance = context
|
|
||||||
.watch<User>()
|
|
||||||
.managerSelectedActivity
|
|
||||||
.getDistanceAllActivitySelected();
|
|
||||||
// ---- Calories --- //
|
|
||||||
int totalCalories = context
|
|
||||||
.watch<User>()
|
|
||||||
.managerSelectedActivity
|
|
||||||
.getCalorieAllActivitySelected();
|
|
||||||
// --- Steps --- //
|
|
||||||
int totalSteps = context
|
|
||||||
.watch<User>()
|
|
||||||
.managerSelectedActivity
|
|
||||||
.getStepsAllActivitySelected();
|
|
||||||
// -- Time -- //
|
|
||||||
double totalTime = context
|
|
||||||
.watch<User>()
|
|
||||||
.managerSelectedActivity
|
|
||||||
.getTimeAllActivitySelected();
|
|
||||||
|
|
||||||
// -- Speed -- //
|
|
||||||
double avgSpeed = context
|
|
||||||
.watch<User>()
|
|
||||||
.managerSelectedActivity
|
|
||||||
.getAvgSpeedAllActivitySelected();
|
|
||||||
double maxSpeed = context
|
|
||||||
.watch<User>()
|
|
||||||
.managerSelectedActivity
|
|
||||||
.getMaxSpeedAllActivitySelected();
|
|
||||||
double minSpeed = context
|
|
||||||
.watch<User>()
|
|
||||||
.managerSelectedActivity
|
|
||||||
.getMinSpeedAllActivitySelected();
|
|
||||||
|
|
||||||
return Scaffold(
|
|
||||||
backgroundColor: TColor.white,
|
|
||||||
body: SingleChildScrollView(
|
|
||||||
child: SafeArea(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
height: media.width * 0.03,
|
|
||||||
),
|
|
||||||
const EnteteHomeView(),
|
|
||||||
SizedBox(
|
|
||||||
height: media.width * 0.05,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
"Activity Status",
|
|
||||||
style: TextStyle(
|
|
||||||
color: TColor.black,
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w700),
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: media.width * 0.03,
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
ContainerStatsActivities(
|
|
||||||
"$avgBpm BPM", "Average bpm", Icons.favorite),
|
|
||||||
SizedBox(
|
|
||||||
width: media.width * 0.03,
|
|
||||||
),
|
|
||||||
ContainerStatsActivities(
|
|
||||||
"$maxBpm BPM", "Maximum bpm", Icons.trending_up),
|
|
||||||
SizedBox(
|
|
||||||
width: media.width * 0.03,
|
|
||||||
),
|
|
||||||
ContainerStatsActivities(
|
|
||||||
"$minBpm BPM", "Minimum bpm", Icons.trending_down)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: media.width * 0.03,
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
ContainerStatsActivities(
|
|
||||||
"${Convertisseur.msIntoKmh(avgSpeed).toStringAsFixed(0)} km/h",
|
|
||||||
"Average speed",
|
|
||||||
Icons.bolt),
|
|
||||||
SizedBox(
|
|
||||||
width: media.width * 0.03,
|
|
||||||
),
|
|
||||||
ContainerStatsActivities(
|
|
||||||
"${Convertisseur.msIntoKmh(maxSpeed).toStringAsFixed(0)} km/h",
|
|
||||||
"Maximum speed",
|
|
||||||
Icons.trending_up),
|
|
||||||
SizedBox(
|
|
||||||
width: media.width * 0.03,
|
|
||||||
),
|
|
||||||
ContainerStatsActivities(
|
|
||||||
"${Convertisseur.msIntoKmh(minSpeed).toStringAsFixed(0)} km/h",
|
|
||||||
"Minimum speed",
|
|
||||||
Icons.trending_down)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: media.width * 0.03,
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
ContainerStatsActivities("$avgTemperature °C",
|
|
||||||
"Average Temperature", Icons.thermostat),
|
|
||||||
SizedBox(
|
|
||||||
width: media.width * 0.03,
|
|
||||||
),
|
|
||||||
ContainerStatsActivities("$maxTemperature °C",
|
|
||||||
"Maximum Temperature", Icons.trending_up),
|
|
||||||
SizedBox(
|
|
||||||
width: media.width * 0.03,
|
|
||||||
),
|
|
||||||
ContainerStatsActivities("$minTemperature °C",
|
|
||||||
"Minimum Temperature", Icons.trending_down)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: media.width * 0.03,
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
ContainerStatsActivities(
|
|
||||||
"${avgAltitude.toStringAsFixed(2)} m",
|
|
||||||
"Average altitude",
|
|
||||||
Icons.landscape),
|
|
||||||
SizedBox(
|
|
||||||
width: media.width * 0.03,
|
|
||||||
),
|
|
||||||
ContainerStatsActivities("$maxAltitude m",
|
|
||||||
"Maximum altitude", Icons.trending_up),
|
|
||||||
SizedBox(
|
|
||||||
width: media.width * 0.03,
|
|
||||||
),
|
|
||||||
ContainerStatsActivities("$minAltitude m",
|
|
||||||
"Minimum altitude", Icons.trending_down)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: media.width * 0.03,
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
ContainerStatsActivities("$getTotalDistance m",
|
|
||||||
"Total distance", Icons.double_arrow),
|
|
||||||
SizedBox(
|
|
||||||
width: media.width * 0.03,
|
|
||||||
),
|
|
||||||
ContainerStatsActivities("$totalSteps", "Total steps",
|
|
||||||
Icons.do_not_step_rounded),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: media.width * 0.03,
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
ContainerStatsActivities(
|
|
||||||
"${Convertisseur.secondeIntoMinute(totalTime)} min",
|
|
||||||
"Total time",
|
|
||||||
Icons.timer),
|
|
||||||
SizedBox(
|
|
||||||
width: media.width * 0.03,
|
|
||||||
),
|
|
||||||
ContainerStatsActivities("$totalCalories kCal",
|
|
||||||
"Burned calories", Icons.local_fire_department),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: media.width * 0.03,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|