|
|
@ -3,7 +3,10 @@ import 'dart:typed_data';
|
|
|
|
import 'package:csv/csv.dart';
|
|
|
|
import 'package:csv/csv.dart';
|
|
|
|
import 'package:fit_tool/fit_tool.dart';
|
|
|
|
import 'package:fit_tool/fit_tool.dart';
|
|
|
|
import 'package:path_provider/path_provider.dart';
|
|
|
|
import 'package:path_provider/path_provider.dart';
|
|
|
|
import 'package:smartfit_app_mobile/modele/data_file.dart';
|
|
|
|
import 'package:smartfit_app_mobile/modele/activity_info/activity_info.dart';
|
|
|
|
|
|
|
|
import 'package:smartfit_app_mobile/modele/activity_info/activity_info_generic.dart';
|
|
|
|
|
|
|
|
import 'package:smartfit_app_mobile/modele/activity_info/activity_info_walking.dart';
|
|
|
|
|
|
|
|
import 'package:tuple/tuple.dart';
|
|
|
|
|
|
|
|
|
|
|
|
class ManagerFile {
|
|
|
|
class ManagerFile {
|
|
|
|
// -- Field
|
|
|
|
// -- Field
|
|
|
@ -19,10 +22,10 @@ class ManagerFile {
|
|
|
|
final String _fieldTemperature = "temperature";
|
|
|
|
final String _fieldTemperature = "temperature";
|
|
|
|
|
|
|
|
|
|
|
|
// -- Not in CSV -- //
|
|
|
|
// -- Not in CSV -- //
|
|
|
|
final String _session = "session";
|
|
|
|
static const String _session = "session";
|
|
|
|
final String _startTime = "start_time";
|
|
|
|
static const String _startTime = "start_time";
|
|
|
|
final String _sport = "sport";
|
|
|
|
static const String _sport = "sport";
|
|
|
|
final String _timeActivity = "total_elapsed_time";
|
|
|
|
static const String _timeActivity = "total_elapsed_time";
|
|
|
|
|
|
|
|
|
|
|
|
// -- Getter field
|
|
|
|
// -- Getter field
|
|
|
|
String get fieldTimeStamp => _fieldTimestamp;
|
|
|
|
String get fieldTimeStamp => _fieldTimestamp;
|
|
|
@ -36,7 +39,14 @@ class ManagerFile {
|
|
|
|
String get fieldTotalCalories => _fieldTotalCalorie;
|
|
|
|
String get fieldTotalCalories => _fieldTotalCalorie;
|
|
|
|
String get fieldTemperature => _fieldTemperature;
|
|
|
|
String get fieldTemperature => _fieldTemperature;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// -- Categorie -- //
|
|
|
|
|
|
|
|
static const String _generic = "generic";
|
|
|
|
|
|
|
|
static const String _velo = "cycling";
|
|
|
|
|
|
|
|
static const String _marche = "walking";
|
|
|
|
|
|
|
|
|
|
|
|
List<String> allowedFieldWalking = List.empty(growable: true);
|
|
|
|
List<String> allowedFieldWalking = List.empty(growable: true);
|
|
|
|
|
|
|
|
List<String> allowedFieldGeneric = List.empty(growable: true);
|
|
|
|
|
|
|
|
List<String> allowedFieldCycling = List.empty(growable: true);
|
|
|
|
|
|
|
|
|
|
|
|
ManagerFile() {
|
|
|
|
ManagerFile() {
|
|
|
|
allowedFieldWalking = [
|
|
|
|
allowedFieldWalking = [
|
|
|
@ -51,71 +61,125 @@ class ManagerFile {
|
|
|
|
_fieldTotalCalorie,
|
|
|
|
_fieldTotalCalorie,
|
|
|
|
_fieldTemperature
|
|
|
|
_fieldTemperature
|
|
|
|
];
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
allowedFieldGeneric = [_fieldTimestamp, _fieldBPM];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
allowedFieldCycling = [
|
|
|
|
|
|
|
|
_fieldTimestamp,
|
|
|
|
|
|
|
|
_fieldPositionLatitue,
|
|
|
|
|
|
|
|
_fieldPositionLongitude,
|
|
|
|
|
|
|
|
_fieldDistance,
|
|
|
|
|
|
|
|
_fieldBPM,
|
|
|
|
|
|
|
|
_fieldSpeed,
|
|
|
|
|
|
|
|
_fieldAltitude,
|
|
|
|
|
|
|
|
_fieldTotalCalorie,
|
|
|
|
|
|
|
|
_fieldTemperature
|
|
|
|
|
|
|
|
];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DataFile convertBytesFitFileIntoCSVList(Uint8List bytes) {
|
|
|
|
// -- Read the byte of file CSV -- //
|
|
|
|
FitFile fitFile = FitFile.fromBytes(bytes);
|
|
|
|
List<List<dynamic>> convertByteIntoCSV(Uint8List bytes) {
|
|
|
|
|
|
|
|
return const CsvToListConverter().convert(utf8.decode(bytes));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ----------- Lire le fit et extarire les données qu'on choisi ----------- //
|
|
|
|
String _getCategoryById(int id) {
|
|
|
|
List<Map<String, Map<String, String>>> dataResult =
|
|
|
|
switch (id) {
|
|
|
|
List.empty(growable: true);
|
|
|
|
case 0:
|
|
|
|
// -- Start Time default -- //
|
|
|
|
return _generic;
|
|
|
|
String startTime = "2000-01-01";
|
|
|
|
case 2:
|
|
|
|
// -- Category Default -- //
|
|
|
|
return _velo;
|
|
|
|
String category = "Generic";
|
|
|
|
case 11:
|
|
|
|
// -- Time of activity default -- //
|
|
|
|
return _marche;
|
|
|
|
double timeActivity = 0.0;
|
|
|
|
default:
|
|
|
|
// -- Denivelé positif et négatif -- //
|
|
|
|
return _generic;
|
|
|
|
double denivelePositif = 0.0;
|
|
|
|
}
|
|
|
|
double deniveleNegatif = 0.0;
|
|
|
|
}
|
|
|
|
double lastDenivele = 0.0;
|
|
|
|
|
|
|
|
// --------------------------------------- //
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (Record element in fitFile.records) {
|
|
|
|
|
|
|
|
List listeField = element.toRow();
|
|
|
|
|
|
|
|
Map<String, Map<String, String>> ligneDataResult = {};
|
|
|
|
|
|
|
|
// -- Skip ligne whith no data -- //
|
|
|
|
|
|
|
|
bool skip = true;
|
|
|
|
|
|
|
|
// -- Session -- //
|
|
|
|
|
|
|
|
bool sesssionLigne = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (listeField[0] != "Data") {
|
|
|
|
// ------------- Get The path of application --- //
|
|
|
|
continue;
|
|
|
|
Future<String> get localPath async {
|
|
|
|
|
|
|
|
final directory = await getApplicationDocumentsDirectory();
|
|
|
|
|
|
|
|
return directory.path;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < listeField.length;) {
|
|
|
|
Tuple4<bool, List<List<String>>, ActivityInfo, String>
|
|
|
|
// -- Check si c'est une ligne session --//
|
|
|
|
convertBytesFitFileIntoCSVListAndGetInfo(Uint8List bytes) {
|
|
|
|
if (i == 0 && listeField[2] == _session) {
|
|
|
|
List<Record> fitFile = FitFile.fromBytes(bytes).records;
|
|
|
|
sesssionLigne = true;
|
|
|
|
String categorie;
|
|
|
|
}
|
|
|
|
List<String> fieldAllowed = [];
|
|
|
|
// -- Si ligne session && starttime -- //
|
|
|
|
ActivityInfo info;
|
|
|
|
if (sesssionLigne && listeField[i] == _startTime) {
|
|
|
|
// -- Chercher ligne session -- //
|
|
|
|
startTime =
|
|
|
|
List<dynamic> ligneSession = _getLigneSession(fitFile);
|
|
|
|
DateTime.fromMillisecondsSinceEpoch(listeField[i + 1] as int)
|
|
|
|
if (ligneSession.isEmpty) {
|
|
|
|
|
|
|
|
return Tuple4(false, List.empty(), ActivityInfoGeneric(), "");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
categorie =
|
|
|
|
|
|
|
|
_getCategoryById(int.parse(_getXfromListe(_sport, ligneSession)));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// -- Si la catégorie est pas prévu est est généric -- //
|
|
|
|
|
|
|
|
switch (categorie) {
|
|
|
|
|
|
|
|
case (_marche):
|
|
|
|
|
|
|
|
fieldAllowed = allowedFieldWalking;
|
|
|
|
|
|
|
|
info = ActivityInfoWalking();
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case (_generic):
|
|
|
|
|
|
|
|
fieldAllowed = allowedFieldGeneric;
|
|
|
|
|
|
|
|
info = ActivityInfoGeneric();
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
// A REMETRE EN GENERIC
|
|
|
|
|
|
|
|
//fieldAllowed = allowedFieldGeneric;
|
|
|
|
|
|
|
|
//info = ActivityInfoGeneric();
|
|
|
|
|
|
|
|
//categorie = _generic;
|
|
|
|
|
|
|
|
fieldAllowed = allowedFieldWalking;
|
|
|
|
|
|
|
|
info = ActivityInfoWalking();
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
List<List<String>> csvData = transformDataMapIntoCSV(
|
|
|
|
|
|
|
|
getDataOfListeOfRecord(fitFile, fieldAllowed), fieldAllowed);
|
|
|
|
|
|
|
|
// Remplir info avec la ligne session
|
|
|
|
|
|
|
|
info.startTime = DateTime.fromMillisecondsSinceEpoch(
|
|
|
|
|
|
|
|
int.parse(_getXfromListe(_startTime, ligneSession)))
|
|
|
|
.toIso8601String();
|
|
|
|
.toIso8601String();
|
|
|
|
}
|
|
|
|
|
|
|
|
// -- Si ligne session && sport -- //
|
|
|
|
return Tuple4(true, csvData, info.getData(csvData), categorie);
|
|
|
|
if (sesssionLigne && listeField[i] == _sport) {
|
|
|
|
|
|
|
|
category = _getCategoryById(listeField[i + 1] as int);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// -- Si ligne session && total_elapsed_time -- //
|
|
|
|
List<dynamic> _getLigneSession(List<Record> listRecord) {
|
|
|
|
if (sesssionLigne && listeField[i] == _timeActivity) {
|
|
|
|
for (int i = listRecord.length - 1; i != listRecord.length - 5; i--) {
|
|
|
|
timeActivity = listeField[i + 1];
|
|
|
|
List<dynamic> tmpListe = listRecord[i].toRow();
|
|
|
|
|
|
|
|
if (tmpListe[0] == "Data" && tmpListe[2] == _session) {
|
|
|
|
|
|
|
|
return tmpListe;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return List.empty();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Calcul denivelé positif et négatif
|
|
|
|
String _getXfromListe(String x, List<dynamic> liste) {
|
|
|
|
if (listeField[i] == _fieldAltitude) {
|
|
|
|
for (int i = 0; i < liste.length; i++) {
|
|
|
|
if (listeField[i + 1] > lastDenivele) {
|
|
|
|
if (liste[i] == x) {
|
|
|
|
denivelePositif += listeField[i + 1] - lastDenivele;
|
|
|
|
return liste[i + 1].toString();
|
|
|
|
} else {
|
|
|
|
}
|
|
|
|
deniveleNegatif += (listeField[i + 1] - lastDenivele) * -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lastDenivele = listeField[i + 1];
|
|
|
|
return "null";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//------//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (allowedFieldWalking.contains(listeField[i])) {
|
|
|
|
List<Map<String, Map<String, String>>> getDataOfListeOfRecord(
|
|
|
|
|
|
|
|
List<Record> listeRecord, List<String> allowedField) {
|
|
|
|
|
|
|
|
List<Map<String, Map<String, String>>> dataResult =
|
|
|
|
|
|
|
|
List.empty(growable: true);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (Record element in listeRecord) {
|
|
|
|
|
|
|
|
List listeField = element.toRow();
|
|
|
|
|
|
|
|
Map<String, Map<String, String>> ligneDataResult = {};
|
|
|
|
|
|
|
|
// -- Skip ligne whith no data -- //
|
|
|
|
|
|
|
|
bool skip = true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// -- Si ce n'est pas de la data on pass -- //
|
|
|
|
|
|
|
|
if (listeField[0] != "Data") {
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < listeField.length;) {
|
|
|
|
|
|
|
|
if (allowedField.contains(listeField[i])) {
|
|
|
|
Map<String, String> tmp = {};
|
|
|
|
Map<String, String> tmp = {};
|
|
|
|
tmp["Value"] = listeField[i + 1].toString();
|
|
|
|
tmp["Value"] = listeField[i + 1].toString();
|
|
|
|
tmp["Unite"] = listeField[i + 2].toString();
|
|
|
|
tmp["Unite"] = listeField[i + 2].toString();
|
|
|
@ -123,27 +187,33 @@ class ManagerFile {
|
|
|
|
i += 2;
|
|
|
|
i += 2;
|
|
|
|
skip = false;
|
|
|
|
skip = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// -- Pour boucler -- //
|
|
|
|
i += 1;
|
|
|
|
i += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!skip) {
|
|
|
|
if (!skip) {
|
|
|
|
dataResult.add(ligneDataResult);
|
|
|
|
dataResult.add(ligneDataResult);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// -------- FIN ---------- //
|
|
|
|
return dataResult;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
List<List<String>> transformDataMapIntoCSV(
|
|
|
|
|
|
|
|
List<Map<String, Map<String, String>>> listeMap,
|
|
|
|
|
|
|
|
List<String> fieldAllowed) {
|
|
|
|
// ------- Création du csv ----- //
|
|
|
|
// ------- Création du csv ----- //
|
|
|
|
// --- Création de l'entête -- //
|
|
|
|
// --- Création de l'entête -- //
|
|
|
|
List<String> enteteCSV = [];
|
|
|
|
List<String> enteteCSV = [];
|
|
|
|
for (String field in allowedFieldWalking) {
|
|
|
|
for (String field in fieldAllowed) {
|
|
|
|
enteteCSV.add("Value_$field");
|
|
|
|
enteteCSV.add("Value_$field");
|
|
|
|
enteteCSV.add("Unite_$field");
|
|
|
|
enteteCSV.add("Unite_$field");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
List<List<String>> csvData = List.empty(growable: true);
|
|
|
|
List<List<String>> csvData = List.empty(growable: true);
|
|
|
|
//
|
|
|
|
//
|
|
|
|
for (Map<String, Map<String, String>> ligne in dataResult) {
|
|
|
|
for (Map<String, Map<String, String>> ligne in listeMap) {
|
|
|
|
List<String> tmpLigne = List.empty(growable: true);
|
|
|
|
List<String> tmpLigne = List.empty(growable: true);
|
|
|
|
for (String field in allowedFieldWalking) {
|
|
|
|
for (String field in fieldAllowed) {
|
|
|
|
if (!ligne.containsKey(field)) {
|
|
|
|
if (!ligne.containsKey(field)) {
|
|
|
|
tmpLigne.add("null");
|
|
|
|
tmpLigne.add("null");
|
|
|
|
tmpLigne.add("null");
|
|
|
|
tmpLigne.add("null");
|
|
|
@ -156,97 +226,6 @@ class ManagerFile {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
csvData.insert(0, enteteCSV);
|
|
|
|
csvData.insert(0, enteteCSV);
|
|
|
|
// ------- FIN --------------- //
|
|
|
|
// ------- FIN --------------- //
|
|
|
|
return DataFile(csvData, category, startTime, denivelePositif,
|
|
|
|
return csvData;
|
|
|
|
deniveleNegatif, timeActivity);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// -- Read the byte of file CSV -- //
|
|
|
|
|
|
|
|
List<List<dynamic>> convertByteIntoCSV(Uint8List bytes) {
|
|
|
|
|
|
|
|
return const CsvToListConverter().convert(utf8.decode(bytes));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String _getCategoryById(int id) {
|
|
|
|
|
|
|
|
switch (id) {
|
|
|
|
|
|
|
|
case 0:
|
|
|
|
|
|
|
|
return "generic";
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
|
|
|
|
return "cycling";
|
|
|
|
|
|
|
|
case 11:
|
|
|
|
|
|
|
|
return "walking";
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
return "generic";
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ------------- Get The path of application --- //
|
|
|
|
|
|
|
|
Future<String> get localPath async {
|
|
|
|
|
|
|
|
final directory = await getApplicationDocumentsDirectory();
|
|
|
|
|
|
|
|
return directory.path;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
// ----- Read csv File ------- //
|
|
|
|
|
|
|
|
Future<List<dynamic>> readCSVFile(String path) async {
|
|
|
|
|
|
|
|
if (File(path).exists() == false) return List.empty();
|
|
|
|
|
|
|
|
final input = File(path).openRead();
|
|
|
|
|
|
|
|
final fields = await input
|
|
|
|
|
|
|
|
.transform(utf8.decoder)
|
|
|
|
|
|
|
|
.transform(const CsvToListConverter())
|
|
|
|
|
|
|
|
.toList();
|
|
|
|
|
|
|
|
return fields;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ----- Read a file FIT --- //
|
|
|
|
|
|
|
|
Future<List<dynamic>> readFitFile(String path) async {
|
|
|
|
|
|
|
|
if (File(path).existsSync() == false) return List.empty();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
final file = File(path);
|
|
|
|
|
|
|
|
final bytes = await file.readAsBytes();
|
|
|
|
|
|
|
|
final fitFile = FitFile.fromBytes(bytes);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return fitFile.toRows();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Future<List<dynamic>> readFitFileWhithFile(File file) async {
|
|
|
|
|
|
|
|
final bytes = await file.readAsBytes();
|
|
|
|
|
|
|
|
final fitFile = FitFile.fromBytes(bytes);
|
|
|
|
|
|
|
|
return fitFile.toRows();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
List<dynamic> readFitFileWeb(Uint8List bytes) {
|
|
|
|
|
|
|
|
final fitFile = FitFile.fromBytes(bytes);
|
|
|
|
|
|
|
|
return fitFile.toRows();
|
|
|
|
|
|
|
|
}*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
// --- A modifier si utilisé --- //
|
|
|
|
|
|
|
|
Future<bool> saveFileLocal(String nameFileWithExtension, String path) async {
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
final outFile = File("${await localPath}\\Files\\$nameFileWithExtension");
|
|
|
|
|
|
|
|
if (outFile.existsSync() == false) {
|
|
|
|
|
|
|
|
outFile.createSync(recursive: true);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
await outFile.writeAsString(await file.readAsString());
|
|
|
|
|
|
|
|
return true;*/
|
|
|
|
|
|
|
|
}*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
// -- Check si le fichier existe localement -- //
|
|
|
|
|
|
|
|
Future<bool> fileExist(String filname) async {
|
|
|
|
|
|
|
|
Directory directory = Directory("${await localPath}\\Files\\");
|
|
|
|
|
|
|
|
if (!directory.existsSync()) {
|
|
|
|
|
|
|
|
print("Le dossier n'existe pas !");
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
List<FileSystemEntity> files = directory.listSync();
|
|
|
|
|
|
|
|
for (FileSystemEntity file in files) {
|
|
|
|
|
|
|
|
if (file.path.split("\\").last == filname) {
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// --- Ligne utile --- //
|
|
|
|
|
|
|
|
//final csv = const ListToCsvConverter().convert(fitFile.toRows());
|
|
|
|
|
|
|
|
//await outFile.writeAsString(csv);*/
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|