💥 offline mode (enfin)

pull/4/head
remrem 1 year ago
commit 769139fa03

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

@ -0,0 +1,19 @@
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.48445 22.0001H1.00973C0.870493 22.0005 0.732683 21.9735 0.605006 21.9207C0.47733 21.8679 0.362566 21.7905 0.26797 21.6934C0.173374 21.5964 0.101003 21.4817 0.0554335 21.3566C0.00986404 21.2316 -0.0079129 21.0989 0.00322648 20.9671L0.481314 15.3044H7.47145C9.48445 22.0384 9.09695 20.6992 9.48445 22.0001Z" fill="#E2E2E2"/>
<path d="M13.0072 3.82618V12.4349H0.717834L1.35696 4.70618C1.37725 4.46598 1.49218 4.24191 1.67878 4.07876C1.86538 3.91561 2.1099 3.8254 2.36346 3.82618H2.9422C2.9422 5.94009 6.9682 10.5218 6.9682 10.5218C6.9682 10.5218 10.9942 5.94009 10.9942 3.82618H13.0072Z" fill="#E2E2E2"/>
<path d="M21.2706 12.4349H16.0267V3.82618H19.625C19.8785 3.8254 20.123 3.91561 20.3097 4.07876C20.4963 4.24191 20.6112 4.46598 20.6315 4.70618L21.2706 12.4349Z" fill="#E2E2E2"/>
<path d="M21.9852 21.0436C21.9852 21.2973 21.8792 21.5406 21.6904 21.7199C21.5016 21.8993 21.2456 22.0001 20.9787 22.0001H12.504L10.491 15.3044H21.5071C22.1311 22.7844 21.9852 20.5892 21.9852 21.0436Z" fill="#E2E2E2"/>
<path d="M9.48445 22.0001H1.00973C0.870493 22.0005 0.732683 21.9735 0.605006 21.9207C0.47733 21.8679 0.362566 21.7905 0.26797 21.6934C0.173374 21.5964 0.101003 21.4817 0.0554335 21.3566C0.00986404 21.2316 -0.0079129 21.0989 0.00322648 20.9671L0.481314 15.3044H7.47145C9.48445 22.0384 9.09695 20.6992 9.48445 22.0001Z" fill="#E2E2E2"/>
<path d="M13.0072 3.82618V12.4349H0.717834L1.35696 4.70618C1.37725 4.46598 1.49218 4.24191 1.67878 4.07876C1.86538 3.91561 2.1099 3.8254 2.36346 3.82618H2.9422C2.9422 5.94009 6.9682 10.5218 6.9682 10.5218C6.9682 10.5218 10.9942 5.94009 10.9942 3.82618H13.0072Z" fill="#E2E2E2"/>
<path d="M21.2706 12.4349H16.0267V3.82618H19.625C19.8785 3.8254 20.123 3.91561 20.3097 4.07876C20.4963 4.24191 20.6112 4.46598 20.6315 4.70618L21.2706 12.4349Z" fill="#E2E2E2"/>
<path d="M21.9852 21.0436C21.9852 21.2973 21.8792 21.5406 21.6904 21.7199C21.5016 21.8993 21.2456 22.0001 20.9787 22.0001H12.504L10.491 15.3044H21.5071C22.1311 22.7844 21.9852 20.5892 21.9852 21.0436Z" fill="#E2E2E2"/>
<path d="M12.504 22.0001H9.48446L7.47146 15.3044H0.481323L0.717851 12.4349H13.0072V3.82617H16.0267V12.4349H21.2706L21.5071 15.3044H10.491C12.504 22.0383 12.1165 20.6992 12.504 22.0001Z" fill="white"/>
<path d="M10.491 15.3044L12.2171 21.0436H9.19763L7.47148 15.3044H1.93573C2.03638 14.0992 1.98605 14.7353 2.17226 12.4349H13.0072V3.82617H16.0267V12.4349H21.2706L21.5071 15.3044H10.491Z" fill="white"/>
<path d="M13.0072 3.82617V12.4349H2.14709C2.25278 11.1675 2.14709 12.2531 2.68054 5.98791C3.63073 7.58863 4.72879 9.10591 5.96173 10.5218C5.96173 10.5218 6.158 10.297 6.46498 9.924C6.77196 10.297 6.96823 10.5218 6.96823 10.5218C6.96823 10.5218 10.9942 5.94008 10.9942 3.82617H13.0072Z" fill="#BBBBBB"/>
<path d="M9.19762 21.0436H2.51949C2.38026 21.044 2.24245 21.017 2.11477 20.9642C1.9871 20.9114 1.87233 20.834 1.77774 20.7369C1.68314 20.6398 1.61077 20.5251 1.5652 20.4001C1.51963 20.2751 1.50185 20.1424 1.51299 20.0105L1.93572 15.3044H7.47147L9.19762 21.0436Z" fill="#BBBBBB"/>
<path d="M21.9852 21.0436H12.2171L10.491 15.3044H21.5071C22.1311 22.7844 21.9852 20.5892 21.9852 21.0436Z" fill="#BBBBBB"/>
<path d="M21.2706 12.4349H16.0267V3.82618H19.625C19.8785 3.8254 20.123 3.91561 20.3097 4.07876C20.4963 4.24191 20.6112 4.46598 20.6315 4.70618L21.2706 12.4349Z" fill="#BBBBBB"/>
<path d="M10.9942 3.82609C10.9942 5.59087 8.12064 9.20174 6.9682 10.5217C6.9682 10.5217 2.9422 5.94 2.9422 3.82609C2.9422 2.81134 3.36637 1.83816 4.12139 1.12063C4.87641 0.403104 5.90044 0 6.9682 0C8.03596 0 9.05999 0.403104 9.81501 1.12063C10.57 1.83816 10.9942 2.81134 10.9942 3.82609Z" fill="#7B6F72"/>
<path d="M10.9942 3.82615C10.9942 5.29441 9.04661 7.95832 7.86397 9.44093C7.22987 8.69962 3.94869 4.78267 3.94869 2.86962C3.94638 2.08883 4.19963 1.32668 4.67336 0.688755C5.27683 0.290897 5.98333 0.0575021 6.71636 0.0138413C7.44938 -0.0298194 8.18101 0.117917 8.83203 0.441056C9.48305 0.764194 10.0287 1.25042 10.4098 1.84709C10.7909 2.44377 10.993 3.12815 10.9942 3.82615Z" fill="#ADA4A5"/>
<path d="M6.96825 5.26092C7.80206 5.26092 8.47799 4.61855 8.47799 3.82614C8.47799 3.03373 7.80206 2.39136 6.96825 2.39136C6.13443 2.39136 5.4585 3.03373 5.4585 3.82614C5.4585 4.61855 6.13443 5.26092 6.96825 5.26092Z" fill="#7B6F72"/>
</svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

@ -0,0 +1,81 @@
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.48445 22.0001H1.00973C0.870493 22.0005 0.732683 21.9735 0.605006 21.9207C0.47733 21.8679 0.362566 21.7905 0.26797 21.6934C0.173374 21.5964 0.101003 21.4817 0.0554335 21.3566C0.00986404 21.2316 -0.0079129 21.0989 0.00322648 20.9671L0.481314 15.3044H7.47145C9.48445 22.0384 9.09695 20.6992 9.48445 22.0001Z" fill="url(#paint0_linear_1054_2509)"/>
<path d="M13.0072 3.82618V12.4349H0.717834L1.35696 4.70618C1.37725 4.46598 1.49218 4.24191 1.67878 4.07876C1.86538 3.91561 2.1099 3.8254 2.36346 3.82618H2.9422C2.9422 5.94009 6.9682 10.5218 6.9682 10.5218C6.9682 10.5218 10.9942 5.94009 10.9942 3.82618H13.0072Z" fill="url(#paint1_linear_1054_2509)"/>
<path d="M21.2706 12.4349H16.0267V3.82618H19.625C19.8785 3.8254 20.123 3.91561 20.3097 4.07876C20.4963 4.24191 20.6112 4.46598 20.6315 4.70618L21.2706 12.4349Z" fill="url(#paint2_linear_1054_2509)"/>
<path d="M21.9852 21.0436C21.9852 21.2973 21.8792 21.5406 21.6904 21.7199C21.5016 21.8993 21.2456 22.0001 20.9787 22.0001H12.504L10.491 15.3044H21.5071C22.1311 22.7844 21.9852 20.5892 21.9852 21.0436Z" fill="url(#paint3_linear_1054_2509)"/>
<path d="M9.48445 22.0001H1.00973C0.870493 22.0005 0.732683 21.9735 0.605006 21.9207C0.47733 21.8679 0.362566 21.7905 0.26797 21.6934C0.173374 21.5964 0.101003 21.4817 0.0554335 21.3566C0.00986404 21.2316 -0.0079129 21.0989 0.00322648 20.9671L0.481314 15.3044H7.47145C9.48445 22.0384 9.09695 20.6992 9.48445 22.0001Z" fill="url(#paint4_linear_1054_2509)"/>
<path d="M13.0072 3.82618V12.4349H0.717834L1.35696 4.70618C1.37725 4.46598 1.49218 4.24191 1.67878 4.07876C1.86538 3.91561 2.1099 3.8254 2.36346 3.82618H2.9422C2.9422 5.94009 6.9682 10.5218 6.9682 10.5218C6.9682 10.5218 10.9942 5.94009 10.9942 3.82618H13.0072Z" fill="url(#paint5_linear_1054_2509)"/>
<path d="M21.2706 12.4349H16.0267V3.82618H19.625C19.8785 3.8254 20.123 3.91561 20.3097 4.07876C20.4963 4.24191 20.6112 4.46598 20.6315 4.70618L21.2706 12.4349Z" fill="url(#paint6_linear_1054_2509)"/>
<path d="M21.9852 21.0436C21.9852 21.2973 21.8792 21.5406 21.6904 21.7199C21.5016 21.8993 21.2456 22.0001 20.9787 22.0001H12.504L10.491 15.3044H21.5071C22.1311 22.7844 21.9852 20.5892 21.9852 21.0436Z" fill="url(#paint7_linear_1054_2509)"/>
<path d="M12.504 22.0001H9.48446L7.47146 15.3044H0.481323L0.717851 12.4349H13.0072V3.82617H16.0267V12.4349H21.2706L21.5071 15.3044H10.491C12.504 22.0383 12.1165 20.6992 12.504 22.0001Z" fill="white"/>
<path d="M10.491 15.3044L12.2171 21.0436H9.19763L7.47148 15.3044H1.93573C2.03638 14.0992 1.98605 14.7353 2.17226 12.4349H13.0072V3.82617H16.0267V12.4349H21.2706L21.5071 15.3044H10.491Z" fill="white"/>
<path d="M13.0072 3.82617V12.4349H2.14709C2.25278 11.1675 2.14709 12.2531 2.68054 5.98791C3.63073 7.58863 4.72879 9.10591 5.96173 10.5218C5.96173 10.5218 6.158 10.297 6.46498 9.924C6.77196 10.297 6.96823 10.5218 6.96823 10.5218C6.96823 10.5218 10.9942 5.94008 10.9942 3.82617H13.0072Z" fill="url(#paint8_linear_1054_2509)"/>
<path d="M9.19762 21.0436H2.51949C2.38026 21.044 2.24245 21.017 2.11477 20.9642C1.9871 20.9114 1.87233 20.834 1.77774 20.7369C1.68314 20.6398 1.61077 20.5251 1.5652 20.4001C1.51963 20.2751 1.50185 20.1424 1.51299 20.0105L1.93572 15.3044H7.47147L9.19762 21.0436Z" fill="url(#paint9_linear_1054_2509)"/>
<path d="M21.9852 21.0436H12.2171L10.491 15.3044H21.5071C22.1311 22.7844 21.9852 20.5892 21.9852 21.0436Z" fill="url(#paint10_linear_1054_2509)"/>
<path d="M21.2706 12.4349H16.0267V3.82618H19.625C19.8785 3.8254 20.123 3.91561 20.3097 4.07876C20.4963 4.24191 20.6112 4.46598 20.6315 4.70618L21.2706 12.4349Z" fill="url(#paint11_linear_1054_2509)"/>
<path d="M10.9942 3.82609C10.9942 5.59087 8.12064 9.20174 6.9682 10.5217C6.9682 10.5217 2.9422 5.94 2.9422 3.82609C2.9422 2.81134 3.36637 1.83816 4.12139 1.12063C4.87641 0.403104 5.90044 0 6.9682 0C8.03596 0 9.05999 0.403104 9.81501 1.12063C10.57 1.83816 10.9942 2.81134 10.9942 3.82609Z" fill="url(#paint12_linear_1054_2509)"/>
<path d="M10.9942 3.82615C10.9942 5.29441 9.04661 7.95832 7.86397 9.44093C7.22987 8.69962 3.94869 4.78267 3.94869 2.86962C3.94638 2.08883 4.19963 1.32668 4.67336 0.688755C5.27683 0.290897 5.98333 0.0575021 6.71636 0.0138413C7.44938 -0.0298194 8.18101 0.117917 8.83203 0.441056C9.48305 0.764194 10.0287 1.25042 10.4098 1.84709C10.7909 2.44377 10.993 3.12815 10.9942 3.82615Z" fill="url(#paint13_linear_1054_2509)"/>
<path d="M6.96825 5.26092C7.80206 5.26092 8.47799 4.61855 8.47799 3.82614C8.47799 3.03373 7.80206 2.39136 6.96825 2.39136C6.13443 2.39136 5.4585 3.03373 5.4585 3.82614C5.4585 4.61855 6.13443 5.26092 6.96825 5.26092Z" fill="url(#paint14_linear_1054_2509)"/>
<defs>
<linearGradient id="paint0_linear_1054_2509" x1="4.74223" y1="9.73951" x2="4.74223" y2="19.3617" gradientUnits="userSpaceOnUse">
<stop stop-color="#C58BF2"/>
<stop offset="1" stop-color="#B4C0FE"/>
</linearGradient>
<linearGradient id="paint1_linear_1054_2509" x1="6.86251" y1="-3.32874" x2="6.86251" y2="9.0427" gradientUnits="userSpaceOnUse">
<stop stop-color="#C58BF2"/>
<stop offset="1" stop-color="#B4C0FE"/>
</linearGradient>
<linearGradient id="paint2_linear_1054_2509" x1="18.6487" y1="-3.32874" x2="18.6487" y2="9.0427" gradientUnits="userSpaceOnUse">
<stop stop-color="#C58BF2"/>
<stop offset="1" stop-color="#B4C0FE"/>
</linearGradient>
<linearGradient id="paint3_linear_1054_2509" x1="16.2455" y1="9.73952" x2="16.2455" y2="19.3617" gradientUnits="userSpaceOnUse">
<stop stop-color="#C58BF2"/>
<stop offset="1" stop-color="#B4C0FE"/>
</linearGradient>
<linearGradient id="paint4_linear_1054_2509" x1="4.74223" y1="9.73951" x2="4.74223" y2="19.3617" gradientUnits="userSpaceOnUse">
<stop stop-color="#C58BF2"/>
<stop offset="1" stop-color="#B4C0FE"/>
</linearGradient>
<linearGradient id="paint5_linear_1054_2509" x1="6.86251" y1="-3.32874" x2="6.86251" y2="9.0427" gradientUnits="userSpaceOnUse">
<stop stop-color="#C58BF2"/>
<stop offset="1" stop-color="#B4C0FE"/>
</linearGradient>
<linearGradient id="paint6_linear_1054_2509" x1="18.6487" y1="-3.32874" x2="18.6487" y2="9.0427" gradientUnits="userSpaceOnUse">
<stop stop-color="#C58BF2"/>
<stop offset="1" stop-color="#B4C0FE"/>
</linearGradient>
<linearGradient id="paint7_linear_1054_2509" x1="16.2455" y1="9.73952" x2="16.2455" y2="19.3617" gradientUnits="userSpaceOnUse">
<stop stop-color="#C58BF2"/>
<stop offset="1" stop-color="#B4C0FE"/>
</linearGradient>
<linearGradient id="paint8_linear_1054_2509" x1="13.0072" y1="12.4349" x2="-1.41631" y2="11.0269" gradientUnits="userSpaceOnUse">
<stop stop-color="#6131AD"/>
<stop offset="1" stop-color="#D4B9FF"/>
</linearGradient>
<linearGradient id="paint9_linear_1054_2509" x1="9.19762" y1="21.0436" x2="-1.00048" y2="19.9865" gradientUnits="userSpaceOnUse">
<stop stop-color="#6131AD"/>
<stop offset="1" stop-color="#D4B9FF"/>
</linearGradient>
<linearGradient id="paint10_linear_1054_2509" x1="22" y1="21.0436" x2="6.93183" y2="18.7053" gradientUnits="userSpaceOnUse">
<stop stop-color="#6131AD"/>
<stop offset="1" stop-color="#D4B9FF"/>
</linearGradient>
<linearGradient id="paint11_linear_1054_2509" x1="21.2706" y1="12.4349" x2="14.2553" y2="12.1042" gradientUnits="userSpaceOnUse">
<stop stop-color="#6131AD"/>
<stop offset="1" stop-color="#D4B9FF"/>
</linearGradient>
<linearGradient id="paint12_linear_1054_2509" x1="10.9942" y1="10.5217" x2="0.236016" y2="9.88466" gradientUnits="userSpaceOnUse">
<stop stop-color="#6131AD"/>
<stop offset="1" stop-color="#D4B9FF"/>
</linearGradient>
<linearGradient id="paint13_linear_1054_2509" x1="15.5794" y1="4.72364" x2="4.80068" y2="4.34559" gradientUnits="userSpaceOnUse">
<stop stop-color="#C58BF2"/>
<stop offset="1" stop-color="#92A3FD"/>
</linearGradient>
<linearGradient id="paint14_linear_1054_2509" x1="8.478" y1="5.26092" x2="4.45619" y2="4.93345" gradientUnits="userSpaceOnUse">
<stop stop-color="#6131AD"/>
<stop offset="1" stop-color="#D4B9FF"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 7.7 KiB

@ -1,7 +1,11 @@
import 'package:smartfit_app_mobile/modele/activity_saver.dart';
import 'package:smartfit_app_mobile/modele/helper.dart';
import 'package:smartfit_app_mobile/main.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:smartfit_app_mobile/common_widget/container/workout_row.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';
@ -24,73 +28,112 @@ class _ListActivityWidget extends State<ListActivityWidget> {
@override
Widget build(BuildContext context) {
return Material(
color: Colors.transparent,
child: ListView.builder(
padding: EdgeInsets.zero,
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: Provider.of<User>(context, listen: true).listActivity.length,
itemBuilder: (context, index) {
ActivityOfUser activityObj =
Provider.of<User>(context, listen: true).listActivity[index];
Map<String, dynamic> activityMap;
// -- Si categorie == marche
if (activityObj.category == managerFile.marche) {
activityMap = activityObj.toMapWalking();
} else {
// -- Default -- //
activityMap = activityObj.toMapGeneric();
}
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;
}
return InkWell(
onTap: () {},
child: WorkoutRow(
wObj: activityMap,
onDelete: () 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);
}
Provider.of<User>(context, listen: false)
.removeActivity(activityObj);
}
},
onClick: () async {
if (!Provider.of<User>(context, listen: false)
.managerSelectedActivity
.fileNotSelected(activityObj.fileUuid)) {
Provider.of<User>(context, listen: false)
.managerSelectedActivity
.removeSelectedActivity(activityObj.fileUuid);
setState(() {});
return;
}
// TODO: Hein?
Provider.of<User>(context, listen: false).removeActivity(activityObj);
Provider.of<User>(context, listen: false).insertActivity(0, activityObj);
}
Tuple2<bool, String> result =
await _utile.getContentActivity(context, activityObj);
if (!result.item1) {
return;
}
// 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()) {
ActivitySaver actSaver = await ActivitySaver.create();
actSaver.deleteActivity(activityObj.fileUuid);
localDB.removeActivity(activityObj.fileUuid);
}
Provider.of<User>(context, listen: false).removeActivity(activityObj);
}
}
Provider.of<User>(context, listen: false)
.removeActivity(activityObj);
Provider.of<User>(context, listen: false)
.insertActivity(0, activityObj);
},
isSelected: !Provider.of<User>(context)
.managerSelectedActivity
.fileNotSelected(activityObj.fileUuid),
),
);
},
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),
),
);
}
},
),
],
),
);
}

@ -45,17 +45,7 @@ class ProfileEntete extends StatelessWidget {
],
),
),
SizedBox(
width: 70,
height: 25,
child: RoundButton(
title: "Editer",
type: RoundButtonType.bgGradient,
fontSize: 12,
fontWeight: FontWeight.w400,
onPressed: () {},
),
)
],
);
}

@ -21,7 +21,7 @@ class ProfileInfoUser extends StatelessWidget {
),
Expanded(
child: TitleSubtitleCell(
title: context.watch<User>().getTotalTimeAllActivity().toString(),
title: context.watch<User>().getTotalTimeAllActivity().toStringAsFixed(2),
subtitle: "Temps en activité",
),
),
@ -31,7 +31,7 @@ class ProfileInfoUser extends StatelessWidget {
Expanded(
child: TitleSubtitleCell(
title:
"${context.watch<User>().getTotalDenivelePositif().toString()} + m",
"${context.watch<User>().getTotalDenivelePositifAllActivity().toStringAsFixed(2)} + m",
subtitle: "Total dénivelé positif",
),
),
@ -41,7 +41,7 @@ class ProfileInfoUser extends StatelessWidget {
Expanded(
child: TitleSubtitleCell(
title:
"${context.watch<User>().getTotalDeniveleNegatif().toString()} - m",
"${context.watch<User>().getTotalDeniveleNegatifAllActivity().toStringAsFixed(2)} - m",
subtitle: "Total dénivelé négatif",
),
),

@ -0,0 +1,70 @@
import 'package:flutter/material.dart';
import 'package:smartfit_app_mobile/common/colo_extension.dart';
import 'package:smartfit_app_mobile/main.dart';
class ProfileSwitch extends StatefulWidget {
final String title;
final String description;
final String iconFilename;
const ProfileSwitch(this.title, this.description, this.iconFilename,
{super.key});
@override
State<ProfileSwitch> createState() => _ProfileSwitchState();
}
class _ProfileSwitchState extends State<ProfileSwitch> {
bool switchValue = localDB.getSaveLocally();
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
decoration: BoxDecoration(
color: TColor.white,
borderRadius: BorderRadius.circular(15),
boxShadow: const [BoxShadow(color: Colors.black12, blurRadius: 2)]),
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Text(
widget.title,
style: TextStyle(
color: TColor.black,
fontSize: 16,
fontWeight: FontWeight.w700,
),
),
const SizedBox(
height: 8,
),
SizedBox(
height: 30,
child:
Row(crossAxisAlignment: CrossAxisAlignment.center, children: [
Image.asset("assets/img/${widget.iconFilename}",
height: 28, width: 28, fit: BoxFit.contain),
const SizedBox(
width: 15,
),
Expanded(
child: Text(
widget.description,
style: TextStyle(
color: TColor.black,
fontSize: 12,
),
),
),
Switch(
value: switchValue,
activeColor: Colors.orange,
onChanged: (bool value) {
setState(() {
switchValue = value;
localDB.setSaveLocally(switchValue);
});
}),
]))
]));
}
}

@ -0,0 +1,118 @@
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 WorkoutRowGeneric extends StatelessWidget {
final Map wObj;
final bool isSelected;
final VoidCallback onDelete;
final VoidCallback onClick;
const WorkoutRowGeneric({
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(
"Temps : ${Convertisseur.secondeIntoMinute(wObj["time"]).toStringAsFixed(2)} m",
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,14 +1,15 @@
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 WorkoutRow extends StatelessWidget {
class WorkoutRowWalking extends StatelessWidget {
final Map wObj;
final bool isSelected;
final VoidCallback onDelete;
final VoidCallback onClick;
const WorkoutRow({
const WorkoutRowWalking({
Key? key,
required this.wObj,
required this.onDelete,
@ -74,14 +75,14 @@ class WorkoutRow extends StatelessWidget {
),
),
Text(
"Temps : ${wObj["time"].toString()}",
"Temps : ${Convertisseur.secondeIntoMinute(wObj["time"]).toStringAsFixed(2)} m",
style: TextStyle(
color: TColor.black,
fontSize: 12,
),
),
Text(
"Dénivelé positif : ${wObj["DenivelePositif"].toString()}",
"Vitesse moyenne : ${Convertisseur.msIntoKmh(wObj["VitesseAvg"]).toStringAsFixed(2)} km/h",
style: TextStyle(
color: TColor.black,
fontSize: 12,

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:responsive_builder/responsive_builder.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_altitude_by_time.dart';
import 'package:smartfit_app_mobile/common_widget/graph/web/web_altitude_by_time.dart';
import 'package:smartfit_app_mobile/modele/utile/home_view/data_home_view.dart';
@ -18,9 +19,10 @@ class GraphAltitudeByTime extends StatefulWidget {
class _GraphAltitudeByTime extends State<GraphAltitudeByTime> {
@override
Widget build(BuildContext context) {
final FuncBpmByTime funcBpm = FuncBpmByTime(widget.data);
return ScreenTypeLayout.builder(
mobile: (_) => MobileGraphAltitudeByTime(widget.media, widget.data),
desktop: (_) => WebGraphAltitudeByTime(widget.media, widget.data),
mobile: (_) => MobileGraphAltitudeByTime(widget.media, widget.data, funcBpm),
desktop: (_) => WebGraphAltitudeByTime(widget.media, widget.data, funcBpm),
);
}
}

@ -21,7 +21,7 @@ class _BpmByTime extends State<BpmByTime> {
final FuncBpmByTime funcBpm = FuncBpmByTime(widget.data);
return ScreenTypeLayout.builder(
mobile: (_) => MobileBpmByTime(widget.media, widget.data),
mobile: (_) => MobileBpmByTime(widget.media, widget.data, funcBpm),
desktop: (_) => WebBpmByTime(widget.media, widget.data, funcBpm),
);
}

@ -14,14 +14,14 @@ class FuncBpmAndSpeedByTime {
getTitlesWidget: rightTitleWidgets,
showTitles: true,
interval: 20,
reservedSize: 40,
reservedSize: 42,
);
SideTitles get leftTitles => SideTitles(
getTitlesWidget: leftTitleWidgets,
showTitles: true,
interval: 20,
reservedSize: 40,
reservedSize: 42,
);
SideTitles get bottomTitles => SideTitles(
getTitlesWidget: bottomTitleWidgets,
@ -79,7 +79,7 @@ class FuncBpmAndSpeedByTime {
return Text(text,
style: TextStyle(
color: TColor.gray,
fontSize: 12,
fontSize: 8,
),
textAlign: TextAlign.center);
}
@ -113,7 +113,7 @@ class FuncBpmAndSpeedByTime {
return Text(text,
style: TextStyle(
color: TColor.gray,
fontSize: 12,
fontSize: 8,
),
textAlign: TextAlign.center);
}
@ -148,7 +148,7 @@ class FuncBpmAndSpeedByTime {
return Text(text,
style: TextStyle(
color: TColor.gray,
fontSize: 12,
fontSize: 8,
),
textAlign: TextAlign.center);
}

@ -67,19 +67,19 @@ class FuncBpmByTime {
text = '0 s';
break;
case 20:
text = "${(interval).toStringAsFixed(2)} s";
text = "${(interval).toStringAsFixed(0)} s";
break;
case 40:
text = "${(interval * 2).toStringAsFixed(2)} s";
text = "${(interval * 2).toStringAsFixed(0)} s";
break;
case 60:
text = "${(interval * 3).toStringAsFixed(2)} s";
text = "${(interval * 3).toStringAsFixed(0)} s";
break;
case 80:
text = "${(interval * 4).toStringAsFixed(2)} s";
text = "${(interval * 4).toStringAsFixed(0)} s";
break;
case 100:
text = "${(interval * 5).toStringAsFixed(2)} s";
text = "${(interval * 5).toStringAsFixed(0)} s";
break;
default:
return Container();

@ -2,14 +2,16 @@ 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, {Key? key})
const MobileGraphAltitudeByTime(this.media, this.data, this.func, {Key? key})
: super(key: key);
@override
@ -70,20 +72,19 @@ class _MobileGraphAltitudeByTime extends State<MobileGraphAltitudeByTime> {
leftTitles: const AxisTitles(),
topTitles: const AxisTitles(),
bottomTitles: AxisTitles(
sideTitles: SideTitles(
reservedSize: 20,
showTitles: true,
getTitlesWidget: (value, meta) {
return Text(
"${double.parse((value / 10).toStringAsFixed(2))}s");
},
)),
sideTitles: widget.func.bottomTitles,
),
rightTitles: AxisTitles(
sideTitles: SideTitles(
reservedSize: 60,
showTitles: true,
getTitlesWidget: (value, meta) {
return Text("${double.parse(value.toStringAsFixed(2))} m");
return Text("${double.parse(value.toStringAsFixed(2))} m",
style: TextStyle(
color: TColor.gray,
fontSize: 12,
),
textAlign: TextAlign.center);
},
)),
))));

@ -111,27 +111,16 @@ class _MobileGraphBpmAndSpeedByTime
titlesData: FlTitlesData(
show: true,
leftTitles: AxisTitles(
sideTitles: widget.func.rightTitles,
sideTitles: widget.func.leftTitles,
),
topTitles: const AxisTitles(),
bottomTitles: AxisTitles(
sideTitles: SideTitles(
reservedSize: 20,
showTitles: true,
getTitlesWidget: (value, meta) {
return Text(
"${double.parse((value / 10).toStringAsFixed(2))}s");
},
)),
sideTitles: widget.func.bottomTitles,
),
rightTitles: AxisTitles(
sideTitles: SideTitles(
reservedSize: 70,
showTitles: true,
getTitlesWidget: (value, meta) {
return Text(
"${double.parse(value.toStringAsFixed(2))} BPM");
},
))),
sideTitles: widget.func.rightTitles,
),),
gridData: FlGridData(
drawVerticalLine: true,
drawHorizontalLine: true,

@ -1,13 +1,15 @@
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, {Key? key}) : super(key: key);
const MobileBpmByTime(this.media, this.data,this.func, {Key? key}) : super(key: key);
@override
State<MobileBpmByTime> createState() => _MobileBpmByTime();
@ -57,19 +59,19 @@ class _MobileBpmByTime extends State<MobileBpmByTime> {
leftTitles: const AxisTitles(),
topTitles: const AxisTitles(),
bottomTitles: AxisTitles(
sideTitles: SideTitles(
reservedSize: 20,
showTitles: true,
getTitlesWidget: (value, meta) {
return Text("${double.parse((value/10).toStringAsFixed(2))}s");
},
)),
sideTitles: widget.func.bottomTitles,
),
rightTitles: AxisTitles(
sideTitles: SideTitles(
reservedSize: 70,
showTitles: true,
getTitlesWidget: (value, meta) {
return Text("${double.parse(value.toStringAsFixed(2))} BPM");
return Text("${double.parse(value.toStringAsFixed(2))} BPM",
style: TextStyle(
color: TColor.gray,
fontSize: 12,
),
textAlign: TextAlign.center);
},
)),
))));

@ -2,14 +2,16 @@ 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, {Key? key})
const WebGraphAltitudeByTime(this.media, this.data, this.func, {Key? key})
: super(key: key);
@override
@ -69,20 +71,19 @@ class _WebGraphAltitudeByTime extends State<WebGraphAltitudeByTime> {
leftTitles: const AxisTitles(),
topTitles: const AxisTitles(),
bottomTitles: AxisTitles(
sideTitles: SideTitles(
reservedSize: 20,
showTitles: true,
getTitlesWidget: (value, meta) {
return Text(
"${double.parse((value / 10).toStringAsFixed(2))}s");
},
)),
sideTitles: widget.func.bottomTitles,
),
rightTitles: AxisTitles(
sideTitles: SideTitles(
reservedSize: 60,
showTitles: true,
getTitlesWidget: (value, meta) {
return Text("${double.parse(value.toStringAsFixed(2))} m");
return Text("${double.parse(value.toStringAsFixed(2))} m",
style: TextStyle(
color: TColor.gray,
fontSize: 12,
),
textAlign: TextAlign.center);
},
)),
))));

@ -9,7 +9,7 @@ class Steps extends StatelessWidget {
Widget build(BuildContext context) {
String steps = Provider.of<User>(context, listen: false)
.managerSelectedActivity
.getTimeAllActivitySelected()
.getStepsAllActivitySelected()
.toString();
return Padding(

@ -39,8 +39,8 @@ class MyApp extends StatelessWidget {
stdout.write("===== USER =====\n");
stdout.write("Username: ${user.username}\n");
stdout.write("Username: ${user.email}\n");
stdout.write("Username: ${user.token}\n");
stdout.write("Email: ${user.email}\n");
stdout.write("Token: ${user.token}\n");
viewToDisplay = const MainTabView();
}

@ -3,7 +3,7 @@ import 'package:smartfit_app_mobile/modele/activity_info/activity_info.dart';
class ActivityOfUser {
final ActivityInfo _activityInfo;
// A afficher
final String _categorie;
final String _category;
final String _fileUuid;
final String _nameFile;
// ------------ //
@ -14,7 +14,7 @@ class ActivityOfUser {
String get fileUuid => _fileUuid;
String get nameFile => _nameFile;
String get category => _categorie;
String get category => _category;
ActivityInfo get activityInfo => _activityInfo;
Map<String, int> get enteteCSV => _enteteCSV;
@ -29,9 +29,9 @@ class ActivityOfUser {
}
ActivityOfUser(
this._activityInfo, this._categorie, this._fileUuid, this._nameFile) {
this._activityInfo, this._category, this._fileUuid, this._nameFile) {
// Mettre dans une fonction appart
if (_categorie == "Walking") {
if (_category == "Walking") {
_imageName = "assets/img/workout1.svg";
} else {
// Mettre des conditions pour d'autre type d'activité
@ -43,7 +43,7 @@ class ActivityOfUser {
Map<String, dynamic> toMapGeneric() {
Map<String, dynamic> map = {
'categorie': _categorie,
'categorie': _category,
'image': _imageName,
'date': _activityInfo.startTime,
'time': _activityInfo.timeOfActivity,

@ -16,6 +16,7 @@ class ActivityInfo {
int bpmMax = 0;
int bpmMin = 300;
int bpmAvg = 0;
bool bpmNotZero = false;
// ----------- Denivelé ------------ //
double denivelePositif = 0.0;
double deniveleNegatif = 0.0;
@ -23,19 +24,22 @@ class ActivityInfo {
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 getData(List<List<String>> csv) {
ActivityInfo getDataWalking(List<List<String>> csv) {
// - Entete - //
Map<String, int> enteteCSV = getEntete(csv.first);
// ------------- Var tmp ---------- //
@ -63,6 +67,7 @@ class ActivityInfo {
int.parse(csv[i][enteteCSV["Value_${managerFile.fielBPM}"]!]);
bpmSomme += value;
bpmNb += 1;
bpmNotZero = true;
if (value > bpmMax) {
bpmMax = value;
}
@ -91,6 +96,7 @@ class ActivityInfo {
}
altitudeSomme += value;
alititudeNb += 1;
altitudeNotZero = true;
}
// ------------------------ Température ----------------------- //
@ -100,6 +106,7 @@ class ActivityInfo {
csv[i][enteteCSV["Value_${managerFile.fieldTemperature}"]!]);
temperatureSomme += value;
temperatureNb += 1;
temperatureNotZero = true;
if (value > temperatureMax) {
temperatureMax = value;
}
@ -114,6 +121,7 @@ class ActivityInfo {
double.parse(csv[i][enteteCSV["Value_${managerFile.fieldSpeed}"]!]);
vitesseSomme += value;
vitesseNb += 1;
vitesseNotZero = true;
if (value > vitesseMax) {
vitesseMax = value;
}
@ -124,13 +132,168 @@ class ActivityInfo {
}
// -- BPM -- //
bpmAvg = bpmSomme ~/ bpmNb;
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 -- //
altitudeAvg = altitudeSomme / alititudeNb;
if (altitudeNotZero) {
altitudeAvg = altitudeSomme / alititudeNb;
}
// -- Température -- //
temperatureAvg = temperatureSomme ~/ temperatureNb;
if (temperatureNotZero) {
temperatureAvg = temperatureSomme ~/ temperatureNb;
}
// -- Vitesse -- //
vitesseAvg = vitesseSomme / vitesseNb;
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;
bool bpmNotZero = false;
// --- 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;
}
}
}
// -- BPM -- //
if (bpmNotZero) {
bpmAvg = bpmSomme ~/ bpmNb;
}
return this;
}
@ -156,7 +319,9 @@ class ActivityInfo {
// -- Altitude -- //
"AltitudeMax": altitudeMax,
"AltitudeMin": altitudeMin,
"AltitudeAvg": altitudeAvg
"AltitudeAvg": altitudeAvg,
// -- Vitesse -- //
"VitesseAvg": vitesseAvg
};
}
@ -167,30 +332,106 @@ class ActivityInfo {
return;
}
// -- Ligne session -- //
startTime = DateTime.parse(map["startTime"]);
timeOfActivity = map["timeOfActivity"].toDouble();
distance = map["distance"].toDouble();
calories = map["calories"].toInt();
steps = map["steps"].toInt();
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 -- //
bpmAvg = map["bpmAvg"];
bpmMax = map["bpmMax"];
bpmMin = map["bpmMin"];
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é -- //
deniveleNegatif = map["deniveleNegatif"].toDouble();
denivelePositif = map["denivelePositif"].toDouble();
try {
deniveleNegatif = map["deniveleNegatif"];
} catch (e) {
print("Impossible de recup -> deniveleNegatif");
}
try {
denivelePositif = map["denivelePositif"];
} catch (e) {
print("Impossible de recup -> denivelePositif");
}
// -- Altitude -- //
altitudeMax = map["altitudeMax"].toDouble();
altitudeMin = map["altitudeMin"].toDouble();
altitudeAvg = map["altitudeAvg"].toDouble();
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 -- //
temperatureMax = map["temperatureMax"].toInt();
temperatureMin = map["temperatureMin"].toInt();
temperatureAvg = map["temperatureAvg"].toInt();
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 -- //
vitesseMax = map["vitesseMax"].toDouble();
vitesseMin = map["vitesseMin"].toDouble();
vitesseAvg = map["vitesseAvg"].toDouble();
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 -- //
@ -216,7 +457,7 @@ class ActivityInfo {
'vitesseMin': vitesseMin,
'vitesseAvg': vitesseAvg,
// Ligne session
'startTime': startTime.toString(),
'startTime': startTime.toIso8601String(),
'timeOfActivity': timeOfActivity,
'distance': distance,
'calories': calories,

@ -1,10 +1,9 @@
import 'dart:io';
import 'dart:typed_data';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as p;
import 'package:smartfit_app_mobile/modele/helper.dart';
import "package:path_provider/path_provider.dart";
import 'package:smartfit_app_mobile/main.dart';
class ActivitySaver {
String saveDirectory = "activities";
@ -12,21 +11,33 @@ class ActivitySaver {
ActivitySaver._create(this.applicationDocumentsDir);
static Future<ActivitySaver> create() async {
final appDir = await getApplicationDocumentsDirectory();
return ActivitySaver._create(appDir);
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");
}
File getActivity(String filename) {
void deleteActivity(String uuid) {
String filename = localDB.getActivityFilenameByUuid(uuid);
final file =
File(p.join(applicationDocumentsDir.path, saveDirectory, filename));
return file;
file.deleteSync();
}
static Future<ActivitySaver> create() async {
stdout.write("Activity Saver: Created\n");
final appDir = await getApplicationDocumentsDirectory();
return ActivitySaver._create(appDir);
}
}

@ -9,6 +9,7 @@ import 'package:email_validator/email_validator.dart';
import 'package:tuple/tuple.dart';
import 'dart:convert';
import 'package:crypto/crypto.dart';
import 'package:smartfit_app_mobile/main.dart';
import 'dart:io';
class ApiWrapper {
@ -34,9 +35,12 @@ class ApiWrapper {
if (await isOnline()) {
stdout.write("(API) ");
api = RequestApi();
} else {
} else if (localDB.getSaveLocally()) {
stdout.write("(LOCAL) ");
api = RequestLocal();
} else {
stdout.write("(API OFFLINE) ");
api = RequestApi();
}
}
@ -57,18 +61,27 @@ class ApiWrapper {
return res;
}
Future<Tuple2> getFile(String token, String fileUuid) async {
Future<Tuple2> getFile(
String token, String fileUuid, InfoMessage infoManager) async {
await init();
Tuple2 res = await api.getFile(token, fileUuid);
if (!res.item1) {
infoManager.displayMessage(noConnectionMessage, true);
}
stdout.write("getFile: ${res.item1}\n");
return res;
}
Future<Tuple2> getFiles(String token) async {
Future<Tuple2> getFiles(String token, InfoMessage infoManager) async {
await init();
Tuple2 res = await api.getFiles(token);
if (!res.item1) {
infoManager.displayMessage(noConnectionMessage, true);
}
stdout.write("getFiles: ${res.item1}\n");
return res;
}
@ -110,7 +123,7 @@ class ApiWrapper {
String hash = sha256.convert(utf8.encode(password)).toString();
Tuple2<bool, String> res = await api.connexion(email, hash);
stdout.write("login: ${res.item1}");
stdout.write("login: ${res.item1}\n");
if (res.item1) {
return Tuple2(true, res.item2);
} else {
@ -128,7 +141,7 @@ class ApiWrapper {
Tuple2<bool, String> res = await api.deleteUser(token);
stdout.write("deleteUser: ${res.item1}");
stdout.write("deleteUser: ${res.item1}\n");
return res;
}
@ -139,7 +152,7 @@ class ApiWrapper {
Tuple2<bool, String> res = await api.postUser(email, hash, username);
stdout.write("createUser: ${res.item1}");
stdout.write("createUser: ${res.item1}\n");
return res;
}
@ -149,7 +162,7 @@ class ApiWrapper {
if (handleOffline(infoManager)) return const Tuple2(false, "offline");
Tuple2<bool, String> res = await api.uploadFile(token, file);
stdout.write("uploadFile: ${res.item1}");
stdout.write("uploadFile: ${res.item1}\n");
return res;
}
@ -166,7 +179,9 @@ class ApiWrapper {
Tuple2<bool, String> res = await api.uploadFileByte(
token, contentFile, filename, category, date, activityInfo);
stdout.write("uploadFileByte: ${res.item1}");
if (!res.item1) infoManager.displayMessage(noConnectionMessage, true);
stdout.write("uploadFileByte: ${res.item1}\n");
return res;
}
@ -176,8 +191,9 @@ class ApiWrapper {
if (handleOffline(infoManager)) return false;
bool res = await api.deleteFile(token, fileUuid);
if (!res) infoManager.displayMessage(noConnectionMessage, true);
stdout.write("deleteFile: ${res}");
stdout.write("deleteFile: $res\n");
return res;
}
}

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

@ -0,0 +1,11 @@
class Convertisseur {
// Mettre que des trucs static
static double secondeIntoMinute(double seconde) {
return seconde / 60;
}
static double msIntoKmh(double metreSeconde) {
return metreSeconde * 3.6;
}
}

@ -14,7 +14,6 @@ class User {
@Entity()
class Activity {
int id;
@Unique()
String uuid;
String filename;
@ -23,3 +22,12 @@ class Activity {
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,8 +1,6 @@
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:csv/csv.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/objectbox.g.dart';
@ -14,7 +12,7 @@ class ObjectBox {
late final Store store;
late final Box userBox;
late final Box activityBox;
late final String activitiesSavePath = "activities";
late final Box configBox;
late final Directory applicationDocumentDir;
ObjectBox._create(this.store);
@ -29,6 +27,7 @@ class ObjectBox {
applicationDocumentDir = await getApplicationDocumentsDirectory();
userBox = store.box<User>();
activityBox = store.box<Activity>();
configBox = store.box<Config>();
}
// ===== USER =====
@ -73,8 +72,19 @@ class ObjectBox {
}
}
void removeActivity(int uuid) {
activityBox.remove(uuid);
// TODO: try catch
void removeActivity(String uuid) {
final Query query = activityBox.query(Activity_.uuid.equals(uuid)).build();
final Activity act = query.findFirst();
activityBox.remove(act.id);
}
String getActivityFilenameByUuid(String uuid) {
final Query query = activityBox.query(Activity_.uuid.equals(uuid)).build();
final Activity act = query.findFirst();
return act.filename;
}
List<Activity> getAllActivities() {
@ -87,21 +97,6 @@ class ObjectBox {
}
// ===== FIT Files =====
Future<void> saveActivityFile(List<List<dynamic>> activityFile) async {
String csv = const ListToCsvConverter().convert(activityFile);
Uint8List csvAsBytes = Uint8List.fromList(utf8.encode(csv));
final file =
await File(p.join(applicationDocumentDir.path, activitiesSavePath))
.create();
file.writeAsBytesSync(csvAsBytes);
}
File getActivityFile(String filename) {
final file =
File(p.join(applicationDocumentDir.path, activitiesSavePath, filename));
return file;
}
List<ActivityOfUser> loadActivities() {
List<dynamic> activityDBList = activityBox.getAll();
List<ActivityOfUser> userActivityList = List.empty(growable: true);
@ -114,4 +109,18 @@ class ObjectBox {
return userActivityList;
}
// ===== Config =====
void setSaveLocally(bool saveLocally) {
Config config = configBox.get(1);
config.saveLocally = saveLocally;
configBox.put(config);
stdout.write("(Config) setSaveLocally: $saveLocally\n");
}
bool getSaveLocally() {
Config config = configBox.get(1);
stdout.write("(Config) getSaveLocally: ${config.saveLocally}\n");
return config.saveLocally;
}
}

@ -1,5 +1,6 @@
import 'dart:convert';
import 'package:smartfit_app_mobile/modele/activity_info/activity_info.dart';
import 'package:smartfit_app_mobile/modele/activity_saver.dart';
import 'package:smartfit_app_mobile/modele/api/i_data_strategy.dart';
import 'package:smartfit_app_mobile/modele/local_db/model.dart';
import 'package:tuple/tuple.dart';
@ -18,7 +19,10 @@ class RequestLocal implements IDataStrategy {
// need to save file on request_api.upload() beforehand.
@override
Future<Tuple2> getFile(String token, String fileUuid) async {
return const Tuple2(true, "to implement");
ActivitySaver actSaver = await ActivitySaver.create();
Uint8List fileBytes = actSaver.getActivity(fileUuid);
return Tuple2(true, fileBytes);
}
@override

@ -113,7 +113,7 @@ class ManagerFile {
categorie =
_getCategoryById(int.parse(_getXfromListe(_sport, ligneSession)));
// -- Si la catégorie est pas prévu est est généric -- //
// -- Si la catégorie est pas prévu == généric -- //
switch (categorie) {
case (_marche):
fieldAllowed = allowedFieldWalking;
@ -137,15 +137,24 @@ class ManagerFile {
// ------ Remplir info avec la ligne session --------- //
info.startTime = DateTime.fromMillisecondsSinceEpoch(
int.parse(_getXfromListe(_startTime, ligneSession)));
info.timeOfActivity =
double.parse(_getXfromListe(_timeActivity, ligneSession));
info.distance = double.parse(_getXfromListe(_totalDistance, ligneSession));
info.calories = int.parse(_getXfromListe(_totalCalories, ligneSession));
info.steps = int.parse(_getXfromListe(_totalStep, ligneSession));
// ----------------------------------------------------- //
// -- Extraire les données en fonction de la catégorie -- //
switch (categorie) {
case (_marche):
info.getDataWalking(csvData);
case (_velo):
info.getDataCycling(csvData);
default:
info.getDataGeneric(csvData);
}
return Tuple4(true, csvData, info.getData(csvData), categorie);
//print("Fin : ManagerFile -> convertBytesFitFileIntoCSVListAndGetInfo ");
return Tuple4(true, csvData, info, categorie);
}
List<dynamic> _getLigneSession(List<Record> listRecord) {
@ -164,7 +173,7 @@ class ManagerFile {
return liste[i + 1].toString();
}
}
return "null";
return "0";
}
List<Map<String, Map<String, String>>> getDataOfListeOfRecord(

@ -37,7 +37,7 @@ class User extends ChangeNotifier {
// ------------ Walking -------------- //
// ---- Denivelé ---- //
double getTotalDenivelePositif() {
double getTotalDenivelePositifAllActivity() {
double totalDevPos = 0.0;
for (ActivityOfUser activity in listActivity) {
totalDevPos += activity.activityInfo.denivelePositif;
@ -45,7 +45,7 @@ class User extends ChangeNotifier {
return totalDevPos;
}
double getTotalDeniveleNegatif() {
double getTotalDeniveleNegatifAllActivity() {
double totalDevNeg = 0.0;
for (ActivityOfUser activity in listActivity) {
totalDevNeg += activity.activityInfo.deniveleNegatif;

@ -22,7 +22,7 @@ class HomeViewUtil {
List<FlSpot> bpmSecondes2 = List.from(bpmSecondes);
return DataHomeView(normaliserPremierElement(bpmSecondes), normaliserPremierElement(normaliserDeuxiemeElement(bpmSecondes2)),
normaliserPremierElement(normaliserDeuxiemeElement(vitesseSecondes)), altitudeSeconde);
normaliserPremierElement(normaliserDeuxiemeElement(vitesseSecondes)), normaliserPremierElement(altitudeSeconde));
}
List<FlSpot> normaliserDeuxiemeElement(List<FlSpot> liste) {

@ -11,8 +11,6 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:smartfit_app_mobile/modele/activity.dart';
import 'package:smartfit_app_mobile/modele/activity_info/activity_info.dart';
import 'package:smartfit_app_mobile/modele/api/i_data_strategy.dart';
import 'package:smartfit_app_mobile/modele/api/request_api.dart';
import 'package:smartfit_app_mobile/modele/manager_file.dart';
import 'package:smartfit_app_mobile/modele/user.dart';
import 'package:smartfit_app_mobile/modele/utile/info_message.dart';
@ -22,11 +20,12 @@ class ListActivityUtile {
final ApiWrapper api = ApiWrapper();
final ManagerFile _managerFile = ManagerFile();
Future<Tuple2<bool, String>> getContentActivity(
BuildContext context, ActivityOfUser activityOfUser) async {
Future<Tuple2<bool, String>> getContentActivity(BuildContext context,
ActivityOfUser activityOfUser, InfoMessage infoManager) async {
Tuple2 result = await api.getFile(
Provider.of<User>(context, listen: false).token,
activityOfUser.fileUuid);
activityOfUser.fileUuid,
infoManager);
if (result.item1 == false) {
return Tuple2(result.item1, result.item2);
}
@ -37,6 +36,14 @@ class ListActivityUtile {
// 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)) {
@ -46,10 +53,10 @@ class ListActivityUtile {
}
Future<Tuple2<bool, String>> getFiles(
String token, BuildContext context) async {
String token, BuildContext context, InfoMessage infoManager) async {
bool notZero = false;
Tuple2 result =
await api.getFiles(Provider.of<User>(context, listen: false).token);
Tuple2 result = await api.getFiles(
Provider.of<User>(context, listen: false).token, infoManager);
if (result.item1 == false) {
return Tuple2(result.item1, result.item2);
}
@ -68,18 +75,13 @@ class ListActivityUtile {
element["filename"].toString()));
// Save to local db
localDB.addActivity(db.Activity(
0,
element["uuid"],
element["filename"],
element["category"],
element["info"]
.toString())); // TODO: Do not remove toString(), it do not work w/o it, idk why
localDB.addActivity(db.Activity(0, element["uuid"], element["filename"],
element["category"], jsonEncode(element["info"])));
}
return const Tuple2(true, "Yeah");
}
Future<Tuple2<bool, String>> _addFile(Uint8List bytes, String filename,
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 =
@ -88,55 +90,58 @@ class ListActivityUtile {
String csvString = const ListToCsvConverter().convert(resultData.item2);
Uint8List byteCSV = Uint8List.fromList(utf8.encode(csvString));
// Save on local storage if plateform not browser
if (!Helper.isPlatformWeb()) {
ActivitySaver actSaver = await ActivitySaver.create();
actSaver.saveActivity(byteCSV, filename);
}
Tuple2<bool, String> result = await api.uploadFileByte(
token,
byteCSV,
filename,
resultData.item4,
resultData.item3.startTime,
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 window !! Jsp linux (mettre en format mobile) -- //
void addFileWeb(Uint8List? bytes, String token, String filename,
// --- 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);
await addFile(bytes, filename, token, infoManager);
if (!resultAdd.item1) {
//print("Message error");
return;
}
Tuple2<bool, String> resultGet = await getFiles(token, context);
Tuple2<bool, String> resultGet =
await getFiles(token, context, infoManager);
if (!resultGet.item1) {
//print("Message error");
return;
}
}
void addFileMobile(String path, String token, String filename,
Future<void> addFileMobile(String path, String token, String filename,
BuildContext context, InfoMessage infoManager) async {
Tuple2<bool, String> resultAdd = await _addFile(
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);
Tuple2<bool, String> resultGet =
await getFiles(token, context, infoManager);
if (!resultGet.item1) {
//print("Message error");
return;

@ -29,7 +29,7 @@ class _MobileListActivity extends State<MobileListActivity> {
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const SizedBox(height: 20),
Row(
@ -43,9 +43,13 @@ class _MobileListActivity extends State<MobileListActivity> {
fontWeight: FontWeight.w700),
),
TextButton(
onPressed: () => _utile.getFiles(
Provider.of<User>(context, listen: false).token,
context),
onPressed: () async {
await _utile.getFiles(
Provider.of<User>(context, listen: false).token,
context,
infoManager);
setState(() {});
},
child: Text("Get activity",
style: TextStyle(
color: TColor.gray,
@ -56,17 +60,18 @@ class _MobileListActivity extends State<MobileListActivity> {
FilePickerResult? result =
await FilePicker.platform.pickFiles();
if (result != null && result.files.isNotEmpty) {
// ignore: use_build_context_synchronously
_utile.addFileMobile(
await _utile.addFileMobile(
result.files.single.path!,
Provider.of<User>(context, listen: false).token,
result.files.first.name,
context,
infoManager);
setState(() {});
} else {
// msg d'erreur
// User canceled the picker
}
setState(() {});
},
child: Text(
"Ajouter",

@ -29,7 +29,7 @@ class _WebListActivityState extends State<WebListActivity> {
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const SizedBox(height: 20),
Row(
@ -43,9 +43,13 @@ class _WebListActivityState extends State<WebListActivity> {
fontWeight: FontWeight.w700),
),
TextButton(
onPressed: () => _utile.getFiles(
Provider.of<User>(context, listen: false).token,
context),
onPressed: () async {
await _utile.getFiles(
Provider.of<User>(context, listen: false).token,
context,
infoManager);
setState(() {});
},
child: Text("Get activity",
style: TextStyle(
color: TColor.gray,
@ -56,7 +60,7 @@ class _WebListActivityState extends State<WebListActivity> {
FilePickerResult? result =
await FilePicker.platform.pickFiles();
if (result != null && result.files.isNotEmpty) {
_utile.addFileWeb(
await _utile.addFileWeb(
result.files.first.bytes,
Provider.of<User>(context, listen: false).token,
result.files.first.name,
@ -78,6 +82,10 @@ class _WebListActivityState extends State<WebListActivity> {
)
],
),
Visibility(
visible: infoManager.isVisible,
child: Text(infoManager.message,
style: TextStyle(color: infoManager.messageColor))),
Provider.of<User>(context, listen: true).listActivity.isEmpty
? Column(
crossAxisAlignment: CrossAxisAlignment.start,

@ -47,7 +47,8 @@ class _MobileHomeView extends State<MobileHomeView> {
// -- Speed -- //
double maxSpeed = managerSelectedActivity.getMaxSpeedAllActivitySelected();
double avgSpeed = managerSelectedActivity.getAvgSpeedAllActivitySelected();
data.maxSpeed = maxSpeed;
data.time = context.watch<User>().managerSelectedActivity.getTimeAllActivitySelected();
return Scaffold(
backgroundColor: TColor.white,
body: SingleChildScrollView(

@ -172,6 +172,7 @@ class _WebLoginView extends State<WebLoginView> {
util.fillUser(context, infoUser.item2, result.item2);
localDB.userBox.put(User(0, infoUser.item2["username"],
infoUser.item2["email"], result.item2));
localDB.configBox.put(Config(0, false));
Navigator.push(
context,
MaterialPageRoute(

@ -92,8 +92,8 @@ class _MobileMainTabViewState extends State<MobileMainTabView> {
width: 40,
),
TabButton(
icon: "assets/img/Camera_tab.svg",
selectIcon: "assets/img/Camera_tab_select.svg",
icon: "assets/img/mapIcon.svg",
selectIcon: "assets/img/mapIcon_selected.svg",
isActive: selectTab == 2,
onTap: () {
selectTab = 2;

@ -76,8 +76,8 @@ class _WebMainTabViewState extends State<WebMainTabView> {
),
),
sideBarButton(
icon: "assets/img/icon_map.svg",
selectIcon: "assets/img/icon_map.svg",
icon: "assets/img/mapIcon.svg",
selectIcon: "assets/img/mapIcon_selected.svg",
index: 2,
onTap: () => updateTab(2, const MyMap()),
),

@ -1,5 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.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/view/map/mobile/mobile_my_map.dart';
import 'package:smartfit_app_mobile/view/map/my_map_osm.dart';
@ -13,6 +15,58 @@ class ChoseMap extends StatefulWidget {
class _ChoseMap extends State<ChoseMap> {
@override
Widget build(BuildContext context) {
var media = MediaQuery.of(context).size;
return Scaffold(
backgroundColor: TColor.white,
body: SafeArea(
child: Center(
// Utilisation du widget Center pour centrer verticalement
child: Container(
width: media.width,
padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 25),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize
.min, // Utilisation de MainAxisSize.min pour que la colonne prenne la hauteur minimale nécessaire
children: [
SizedBox(
height: media.height * 0.1,
),
SvgPicture.asset(
"assets/img/group.svg",
width: media.width * 0.75,
height: media.height * 0.4,
fit: BoxFit.fitWidth,
),
SizedBox(
height: media.height * 0.1,
),
RoundButton(
title: "Use map with google map",
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const MobileMyMaps()));
},
),
SizedBox(
height: media.height * 0.03,
),
RoundButton(
title : "Use map with Open Street Map",
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => const MyMapOSM()));
},
),
Spacer(),
],
),
),
),
),
);
return Scaffold(
backgroundColor: TColor.white,
body: SafeArea(
@ -20,20 +74,7 @@ class _ChoseMap extends State<ChoseMap> {
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
TextButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const MobileMyMaps()));
},
child: const Text("Use map with google map")),
TextButton(
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => const MyMapOSM()));
},
child: const Text("Use map with Open Street Map")),
const Text(
"Mettre une image la en mode une personne avec des jumelles")
],

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

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

@ -1,19 +1,19 @@
import 'package:smartfit_app_mobile/common_widget/container/profile/profile_switch.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:smartfit_app_mobile/common/colo_extension.dart';
import 'package:smartfit_app_mobile/common_widget/container/profile/profile_compte.dart';
import 'package:smartfit_app_mobile/common_widget/container/profile/profile_entete.dart';
import 'package:smartfit_app_mobile/common_widget/container/profile/profile_info_user.dart';
import 'package:smartfit_app_mobile/common_widget/container/profile/profile_notification.dart';
import 'package:smartfit_app_mobile/common_widget/container/profile/profile_other.dart';
import 'package:smartfit_app_mobile/modele/api/api_wrapper.dart';
import 'package:smartfit_app_mobile/modele/user.dart';
class ProfileViewAllPlatforme extends StatefulWidget {
final bool positive;
final bool offlineSave;
final List accountArr;
final List otherArr;
const ProfileViewAllPlatforme(this.positive, this.accountArr, this.otherArr,
const ProfileViewAllPlatforme(
this.offlineSave, this.accountArr, this.otherArr,
{super.key});
@override
@ -36,26 +36,6 @@ class _ProfileViewAllPlatforme extends State<ProfileViewAllPlatforme> {
style: TextStyle(
color: TColor.black, fontSize: 16, fontWeight: FontWeight.w700),
),
actions: [
InkWell(
onTap: () {},
child: Container(
margin: const EdgeInsets.all(8),
height: 20,
width: 20,
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(
@ -76,7 +56,10 @@ class _ProfileViewAllPlatforme extends State<ProfileViewAllPlatforme> {
const SizedBox(
height: 25,
),
ProfileNotification(widget.positive),
// TODO: Download/Delete (local) all users files on toggle ?
// TODO: Display size of download in Mo
const ProfileSwitch(
"Offline mode", "Save your files locally", "local_save.png"),
const SizedBox(
height: 25,
),

@ -62,6 +62,7 @@ dependencies:
path: ^1.8.3
flutter_map: ^5.0.0
latlong2: ^0.9.0
units_converter: ^2.1.1
dev_dependencies:
flutter_test:

Loading…
Cancel
Save