First commit
This commit is contained in:
parent
92957a1903
commit
27d8f55d7e
|
|
@ -3,6 +3,8 @@ PODS:
|
||||||
- Flutter (1.0.0)
|
- Flutter (1.0.0)
|
||||||
- flutter_blue_plus (0.0.1):
|
- flutter_blue_plus (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
|
- flutter_email_sender (0.0.1):
|
||||||
|
- Flutter
|
||||||
- flutter_osm_plugin (0.0.1):
|
- flutter_osm_plugin (0.0.1):
|
||||||
- Alamofire
|
- Alamofire
|
||||||
- Flutter
|
- Flutter
|
||||||
|
|
@ -11,6 +13,9 @@ PODS:
|
||||||
- Yams
|
- Yams
|
||||||
- geolocator_apple (1.2.0):
|
- geolocator_apple (1.2.0):
|
||||||
- Flutter
|
- Flutter
|
||||||
|
- path_provider_foundation (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
- FlutterMacOS
|
||||||
- permission_handler_apple (9.3.0):
|
- permission_handler_apple (9.3.0):
|
||||||
- Flutter
|
- Flutter
|
||||||
- Polyline (5.1.0)
|
- Polyline (5.1.0)
|
||||||
|
|
@ -25,8 +30,10 @@ PODS:
|
||||||
DEPENDENCIES:
|
DEPENDENCIES:
|
||||||
- Flutter (from `Flutter`)
|
- Flutter (from `Flutter`)
|
||||||
- flutter_blue_plus (from `.symlinks/plugins/flutter_blue_plus/ios`)
|
- flutter_blue_plus (from `.symlinks/plugins/flutter_blue_plus/ios`)
|
||||||
|
- flutter_email_sender (from `.symlinks/plugins/flutter_email_sender/ios`)
|
||||||
- flutter_osm_plugin (from `.symlinks/plugins/flutter_osm_plugin/ios`)
|
- flutter_osm_plugin (from `.symlinks/plugins/flutter_osm_plugin/ios`)
|
||||||
- geolocator_apple (from `.symlinks/plugins/geolocator_apple/ios`)
|
- geolocator_apple (from `.symlinks/plugins/geolocator_apple/ios`)
|
||||||
|
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||||
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
||||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||||
|
|
@ -43,10 +50,14 @@ EXTERNAL SOURCES:
|
||||||
:path: Flutter
|
:path: Flutter
|
||||||
flutter_blue_plus:
|
flutter_blue_plus:
|
||||||
:path: ".symlinks/plugins/flutter_blue_plus/ios"
|
:path: ".symlinks/plugins/flutter_blue_plus/ios"
|
||||||
|
flutter_email_sender:
|
||||||
|
:path: ".symlinks/plugins/flutter_email_sender/ios"
|
||||||
flutter_osm_plugin:
|
flutter_osm_plugin:
|
||||||
:path: ".symlinks/plugins/flutter_osm_plugin/ios"
|
:path: ".symlinks/plugins/flutter_osm_plugin/ios"
|
||||||
geolocator_apple:
|
geolocator_apple:
|
||||||
:path: ".symlinks/plugins/geolocator_apple/ios"
|
:path: ".symlinks/plugins/geolocator_apple/ios"
|
||||||
|
path_provider_foundation:
|
||||||
|
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
||||||
permission_handler_apple:
|
permission_handler_apple:
|
||||||
:path: ".symlinks/plugins/permission_handler_apple/ios"
|
:path: ".symlinks/plugins/permission_handler_apple/ios"
|
||||||
shared_preferences_foundation:
|
shared_preferences_foundation:
|
||||||
|
|
@ -58,8 +69,10 @@ SPEC CHECKSUMS:
|
||||||
Alamofire: f36a35757af4587d8e4f4bfa223ad10be2422b8c
|
Alamofire: f36a35757af4587d8e4f4bfa223ad10be2422b8c
|
||||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||||
flutter_blue_plus: 4837da7d00cf5d441fdd6635b3a57f936778ea96
|
flutter_blue_plus: 4837da7d00cf5d441fdd6635b3a57f936778ea96
|
||||||
|
flutter_email_sender: 10a22605f92809a11ef52b2f412db806c6082d40
|
||||||
flutter_osm_plugin: a661df71d2a3d1698ee410dd2272c8536f9e46f4
|
flutter_osm_plugin: a661df71d2a3d1698ee410dd2272c8536f9e46f4
|
||||||
geolocator_apple: 6cbaf322953988e009e5ecb481f07efece75c450
|
geolocator_apple: 6cbaf322953988e009e5ecb481f07efece75c450
|
||||||
|
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||||
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
|
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
|
||||||
Polyline: 2a1f29f87f8d9b7de868940f4f76deb8c678a5b1
|
Polyline: 2a1f29f87f8d9b7de868940f4f76deb8c678a5b1
|
||||||
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,13 @@ class GeoPosition {
|
||||||
final double latitude;
|
final double latitude;
|
||||||
final double longitude;
|
final double longitude;
|
||||||
final double altitude;
|
final double altitude;
|
||||||
|
final double speed;
|
||||||
|
|
||||||
GeoPosition({
|
GeoPosition({
|
||||||
required this.latitude,
|
required this.latitude,
|
||||||
required this.longitude,
|
required this.longitude,
|
||||||
required this.altitude,
|
required this.altitude,
|
||||||
|
this.speed = 0.0,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory GeoPosition.fromJson(Map<String, dynamic> json) {
|
factory GeoPosition.fromJson(Map<String, dynamic> json) {
|
||||||
|
|
@ -14,6 +16,16 @@ class GeoPosition {
|
||||||
latitude: json['latitude'],
|
latitude: json['latitude'],
|
||||||
longitude: json['longitude'],
|
longitude: json['longitude'],
|
||||||
altitude: json['altitude'],
|
altitude: json['altitude'],
|
||||||
|
speed: json['speed'],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'latitude': latitude,
|
||||||
|
'longitude': longitude,
|
||||||
|
'altitude': altitude,
|
||||||
|
'speed': speed,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
37
lib/class/preferenceSaved.dart
Normal file
37
lib/class/preferenceSaved.dart
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
class PreferenceSaved {
|
||||||
|
int timeTakingPointSecond = 0;
|
||||||
|
|
||||||
|
PreferenceSaved({required this.timeTakingPointSecond});
|
||||||
|
|
||||||
|
PreferenceSaved.empty();
|
||||||
|
|
||||||
|
PreferenceSaved.fromJson(Map<String, dynamic> json) {
|
||||||
|
timeTakingPointSecond = json['timeTakingPointSecond'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
|
data['timeTakingPointSecond'] = timeTakingPointSecond;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<PreferenceSaved> restoreLocal() async {
|
||||||
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
final String? encodedData = prefs.getString('preferenceSaved');
|
||||||
|
if (encodedData != null) {
|
||||||
|
final Map<String, dynamic> decodedData = jsonDecode(encodedData);
|
||||||
|
return PreferenceSaved.fromJson(decodedData);
|
||||||
|
}
|
||||||
|
return PreferenceSaved(timeTakingPointSecond: 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> saveLocal(PreferenceSaved preferenceSaved) async {
|
||||||
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
final String encodedData = jsonEncode(preferenceSaved.toJson());
|
||||||
|
await prefs.setString('preferenceSaved', encodedData);
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
|
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
|
||||||
import 'package:flutter_osm_plugin/flutter_osm_plugin.dart';
|
import 'package:flutter_osm_plugin/flutter_osm_plugin.dart';
|
||||||
|
import 'package:eagletracker/class/BLEProvider.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class DeviceAdvertizinScan extends StatefulWidget {
|
class DeviceAdvertizinScan extends StatefulWidget {
|
||||||
const DeviceAdvertizinScan(
|
const DeviceAdvertizinScan(
|
||||||
|
|
@ -25,48 +27,46 @@ class _DeviceAdvertizinScanState extends State<DeviceAdvertizinScan> {
|
||||||
initPosition: GeoPoint(latitude: 47.4358055, longitude: 8.4737324),
|
initPosition: GeoPoint(latitude: 47.4358055, longitude: 8.4737324),
|
||||||
);
|
);
|
||||||
|
|
||||||
@override
|
String value = 'Aucune valeur reçue';
|
||||||
void initState() {
|
|
||||||
tecTakingPoint.text = '5';
|
|
||||||
FlutterBluePlus.startScan();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
FlutterBluePlus.stopScan();
|
|
||||||
print('Page disposed');
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
String value = 'Aucune valeur trouvée';
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
FlutterBluePlus.onScanResults.listen((results) {
|
final bleProvider = Provider.of<BLEProvider>(context);
|
||||||
setState(() {
|
scanResults = bleProvider.scanResults;
|
||||||
if (results.length > 0) value = results[0].advertisementData.toString();
|
|
||||||
});
|
if (scanResults
|
||||||
});
|
.where((element) =>
|
||||||
|
element.advertisementData.manufacturerData.isNotEmpty &&
|
||||||
|
element.device.remoteId.toString() == widget.remoteId)
|
||||||
|
.isNotEmpty) {
|
||||||
|
value = scanResults
|
||||||
|
.where((element) =>
|
||||||
|
element.device.remoteId.toString() == widget.remoteId)
|
||||||
|
.map((e) => e.advertisementData.toString())
|
||||||
|
.first;
|
||||||
|
|
||||||
|
// Faites quelque chose avec la variable 'value' ici
|
||||||
|
}
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text("Valeur de la trame publicitaire",
|
title:
|
||||||
style: const TextStyle(color: Colors.white)),
|
const Text("Eagle Tr@cker", style: TextStyle(color: Colors.white)),
|
||||||
backgroundColor: Colors.blue,
|
backgroundColor: Colors.blue,
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
icon: const Icon(Icons.arrow_back, color: Colors.white),
|
icon: const Icon(Icons.arrow_back, color: Colors.white),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
Navigator.pop(context);
|
||||||
SnackBar(
|
|
||||||
content: Text(
|
|
||||||
'(debug) Vous devez redémarrer l application et réaliser un nouveau scan pour voir les nouvelles valeurs (FlutterBluePlus.startScan())'),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: Column(
|
body: Column(
|
||||||
children: [
|
children: [
|
||||||
|
const Padding(
|
||||||
|
padding: EdgeInsets.all(16.0),
|
||||||
|
child: Text('Lecture de la trame publicitaire',
|
||||||
|
style: TextStyle(fontSize: 18.0, fontWeight: FontWeight.bold)),
|
||||||
|
),
|
||||||
Container(
|
Container(
|
||||||
alignment: Alignment.topCenter,
|
alignment: Alignment.topCenter,
|
||||||
child: Column(
|
child: Column(
|
||||||
|
|
@ -80,17 +80,17 @@ class _DeviceAdvertizinScanState extends State<DeviceAdvertizinScan> {
|
||||||
margin: const EdgeInsets.all(10),
|
margin: const EdgeInsets.all(10),
|
||||||
child:
|
child:
|
||||||
//Text centré
|
//Text centré
|
||||||
Center(
|
const Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
"La trame publicitaire est en cours de réception et actualisée en temps réel.",
|
"La trame publicitaire est en cours de réception et actualisée en temps réel.",
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.green,
|
color: Colors.green,
|
||||||
),
|
),
|
||||||
textAlign: TextAlign.center),
|
textAlign: TextAlign.center),
|
||||||
)),
|
)),
|
||||||
Container(
|
Container(
|
||||||
margin: const EdgeInsets.all(10),
|
margin: const EdgeInsets.all(10),
|
||||||
child: CircularProgressIndicator()),
|
child: const CircularProgressIndicator()),
|
||||||
Container(
|
Container(
|
||||||
margin: const EdgeInsets.all(10),
|
margin: const EdgeInsets.all(10),
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,19 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
|
||||||
import 'package:flutter_osm_plugin/flutter_osm_plugin.dart';
|
import 'package:flutter_osm_plugin/flutter_osm_plugin.dart';
|
||||||
|
import 'package:eagletracker/class/BLEProvider.dart';
|
||||||
|
import 'package:eagletracker/class/geoPosition.dart';
|
||||||
|
import 'package:eagletracker/class/preferenceSaved.dart';
|
||||||
|
import 'package:eagletracker/function.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class DeviceFlowMap extends StatefulWidget {
|
class DeviceFlowMap extends StatefulWidget {
|
||||||
const DeviceFlowMap(
|
const DeviceFlowMap(
|
||||||
{super.key,
|
{super.key, required this.deviceName, required this.deviceAddress});
|
||||||
required this.title,
|
|
||||||
required this.deviceName,
|
|
||||||
required this.deviceAddress});
|
|
||||||
|
|
||||||
final String title;
|
|
||||||
final String deviceName;
|
final String deviceName;
|
||||||
final String deviceAddress;
|
final String deviceAddress;
|
||||||
|
|
||||||
|
|
@ -17,22 +22,66 @@ class DeviceFlowMap extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _DeviceFlowMapState extends State<DeviceFlowMap> {
|
class _DeviceFlowMapState extends State<DeviceFlowMap> {
|
||||||
TextEditingController tecTakingPoint = TextEditingController();
|
|
||||||
MapController mapController = MapController(
|
MapController mapController = MapController(
|
||||||
initPosition: GeoPoint(latitude: 47.4358055, longitude: 8.4737324),
|
initPosition: GeoPoint(latitude: 47.4358055, longitude: 8.4737324),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
List<ScanResult> scanResults = [];
|
||||||
|
List<GeoPosition> geoPositions = [];
|
||||||
|
|
||||||
|
Timer? timer;
|
||||||
|
double progression = 0.0;
|
||||||
|
int timeTakingPointSecond = 10;
|
||||||
|
int updateInterval = 500; // Intervalle de mise à jour en millisecondes
|
||||||
|
|
||||||
|
PreferenceSaved preferenceSaved = PreferenceSaved.empty();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
tecTakingPoint.text = '5';
|
super.initState();
|
||||||
|
|
||||||
|
//Positions de test
|
||||||
|
geoPositions = [
|
||||||
|
GeoPosition(latitude: 1.0, longitude: 2.0, altitude: 100.0, speed: 10.0),
|
||||||
|
GeoPosition(latitude: 3.0, longitude: 4.0, altitude: 200.0, speed: 20.0),
|
||||||
|
];
|
||||||
|
|
||||||
|
restoreLocal().then((value) {
|
||||||
|
setState(() {
|
||||||
|
preferenceSaved = value;
|
||||||
|
timeTakingPointSecond = preferenceSaved.timeTakingPointSecond;
|
||||||
|
|
||||||
|
if (timeTakingPointSecond > 0) {
|
||||||
|
int totalUpdates = (timeTakingPointSecond * 1000) ~/ updateInterval;
|
||||||
|
|
||||||
|
timer = Timer.periodic(Duration(milliseconds: updateInterval),
|
||||||
|
(Timer timer) {
|
||||||
|
setState(() {
|
||||||
|
progression = (timer.tick % totalUpdates) / totalUpdates * 100.0;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
print('Erreur: timeTakingPointSecond doit être supérieur à zéro.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
timer?.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final bleProvider = Provider.of<BLEProvider>(context);
|
||||||
|
scanResults = bleProvider.scanResults;
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(widget.deviceName,
|
title:
|
||||||
style: const TextStyle(color: Colors.white)),
|
const Text("Eagle Tr@cker", style: TextStyle(color: Colors.white)),
|
||||||
backgroundColor: Colors.blue,
|
backgroundColor: Colors.blue,
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
icon: const Icon(Icons.arrow_back, color: Colors.white),
|
icon: const Icon(Icons.arrow_back, color: Colors.white),
|
||||||
|
|
@ -41,92 +90,118 @@ class _DeviceFlowMapState extends State<DeviceFlowMap> {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
actions: [
|
),
|
||||||
IconButton(
|
body: Stack(children: [
|
||||||
icon: Icon(Icons.settings, color: Colors.white),
|
OSMFlutter(
|
||||||
onPressed: () {
|
controller: mapController,
|
||||||
showDialog(
|
onMapIsReady: (bool value) async {
|
||||||
context: context,
|
if (value) {
|
||||||
builder: (BuildContext context) {
|
Future.delayed(const Duration(milliseconds: 500), () async {
|
||||||
return AlertDialog(
|
await mapController.currentLocation();
|
||||||
title: const Text('Paramètres'),
|
});
|
||||||
content: Column(
|
}
|
||||||
|
},
|
||||||
|
osmOption: OSMOption(
|
||||||
|
zoomOption: const ZoomOption(
|
||||||
|
initZoom: 14,
|
||||||
|
minZoomLevel: 3,
|
||||||
|
maxZoomLevel: 19,
|
||||||
|
stepZoom: 1.0,
|
||||||
|
),
|
||||||
|
userLocationMarker: UserLocationMaker(
|
||||||
|
personMarker: const MarkerIcon(
|
||||||
|
icon: Icon(
|
||||||
|
Icons.place_rounded,
|
||||||
|
color: Colors.red,
|
||||||
|
size: 48,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
directionArrowMarker: const MarkerIcon(
|
||||||
|
icon: Icon(
|
||||||
|
Icons.place_rounded,
|
||||||
|
size: 48,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
Positioned(
|
||||||
|
top: 10,
|
||||||
|
right: 10,
|
||||||
|
child: Container(
|
||||||
|
width: 200,
|
||||||
|
padding: const EdgeInsets.all(10),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Nom: ${widget.deviceName}',
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.black,
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
geoPositions.isNotEmpty
|
||||||
|
? Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const Text('Temps de prise de point (en secondes)'),
|
Text(
|
||||||
TextField(
|
'Altitude: ${geoPositions.last.altitude.toStringAsFixed(2)} m',
|
||||||
controller: tecTakingPoint,
|
style: const TextStyle(
|
||||||
keyboardType: TextInputType.number,
|
color: Colors.black,
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'Vitesse: ${geoPositions.last.speed.toStringAsFixed(2)} km/h',
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.black,
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
)
|
||||||
|
: const Text(
|
||||||
|
'Aucune valeur',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.black,
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
actions: <Widget>[
|
const SizedBox(height: 10),
|
||||||
TextButton(
|
SizedBox(
|
||||||
onPressed: () {
|
height: 10,
|
||||||
Navigator.of(context).pop();
|
width: 180,
|
||||||
},
|
child: LinearProgressIndicator(
|
||||||
child: const Text('Annuler'),
|
value: progression / 100,
|
||||||
),
|
backgroundColor: Colors.grey[300],
|
||||||
TextButton(
|
valueColor:
|
||||||
onPressed: () {
|
const AlwaysStoppedAnimation<Color>(Colors.blue),
|
||||||
Navigator.of(context).pop();
|
),
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(
|
|
||||||
content: Text('Paramètres enregistrés'),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
child: const Text('Enregistrer'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
})
|
|
||||||
],
|
|
||||||
),
|
|
||||||
body: OSMFlutter(
|
|
||||||
controller: mapController,
|
|
||||||
osmOption: OSMOption(
|
|
||||||
userTrackingOption: UserTrackingOption(
|
|
||||||
enableTracking: true,
|
|
||||||
unFollowUser: false,
|
|
||||||
),
|
|
||||||
zoomOption: ZoomOption(
|
|
||||||
initZoom: 14,
|
|
||||||
minZoomLevel: 3,
|
|
||||||
maxZoomLevel: 19,
|
|
||||||
stepZoom: 1.0,
|
|
||||||
),
|
|
||||||
userLocationMarker: UserLocationMaker(
|
|
||||||
personMarker: MarkerIcon(
|
|
||||||
icon: Icon(
|
|
||||||
Icons.location_history_rounded,
|
|
||||||
color: Colors.red,
|
|
||||||
size: 48,
|
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
directionArrowMarker: MarkerIcon(
|
|
||||||
icon: Icon(
|
|
||||||
Icons.double_arrow,
|
|
||||||
size: 48,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
)),
|
),
|
||||||
|
),
|
||||||
|
]),
|
||||||
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
|
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
|
||||||
floatingActionButton:
|
floatingActionButton:
|
||||||
Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [
|
Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [
|
||||||
FloatingActionButton(
|
FloatingActionButton(
|
||||||
heroTag: 'mapFab',
|
heroTag: 'actionFab1',
|
||||||
backgroundColor: Colors.blue,
|
backgroundColor: Colors.blue,
|
||||||
onPressed: () {},
|
onPressed: () {
|
||||||
child: Icon(Icons.map_outlined, color: Colors.white),
|
mapController.currentLocation();
|
||||||
),
|
},
|
||||||
FloatingActionButton(
|
child: const Icon(Icons.map_outlined, color: Colors.white),
|
||||||
heroTag: 'mapFab2',
|
),
|
||||||
|
FloatingActionButton(
|
||||||
|
heroTag: 'actionFab2',
|
||||||
backgroundColor: Colors.blue,
|
backgroundColor: Colors.blue,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
//Alert for ask to delete piont ?=
|
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
|
|
@ -137,12 +212,17 @@ class _DeviceFlowMapState extends State<DeviceFlowMap> {
|
||||||
actions: <Widget>[
|
actions: <Widget>[
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
geoPositions.clear();
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
child: const Text('Annuler'),
|
child: const Text('Annuler'),
|
||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
geoPositions.clear();
|
||||||
|
});
|
||||||
|
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
|
@ -159,7 +239,53 @@ class _DeviceFlowMapState extends State<DeviceFlowMap> {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: const Icon(Icons.delete_sharp, color: Colors.white),
|
child: const Icon(Icons.delete_sharp, color: Colors.white),
|
||||||
)
|
),
|
||||||
|
FloatingActionButton(
|
||||||
|
heroTag: 'actionFab3',
|
||||||
|
backgroundColor: Colors.blue,
|
||||||
|
onPressed: () async {
|
||||||
|
if (geoPositions.isEmpty) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
const SnackBar(
|
||||||
|
content: Text('Aucune position à envoyer'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
File csvFile = await generateCsv(geoPositions);
|
||||||
|
|
||||||
|
sendEmailWithAttachment(csvFile);
|
||||||
|
},
|
||||||
|
child: const Icon(Icons.mail, color: Colors.white),
|
||||||
|
),
|
||||||
|
FloatingActionButton(
|
||||||
|
heroTag: 'actionFab4',
|
||||||
|
backgroundColor: Colors.blue,
|
||||||
|
onPressed: () {
|
||||||
|
List<GeoPoint> linedsPoints = [];
|
||||||
|
|
||||||
|
for (var geoPosition in geoPositions) {
|
||||||
|
GeoPoint geoPoint = GeoPoint(
|
||||||
|
latitude: geoPosition.latitude,
|
||||||
|
longitude: geoPosition.longitude,
|
||||||
|
);
|
||||||
|
|
||||||
|
linedsPoints.add(geoPoint);
|
||||||
|
|
||||||
|
mapController.clearAllRoads();
|
||||||
|
|
||||||
|
if (linedsPoints.length > 1 &&
|
||||||
|
linedsPoints.toSet().length == linedsPoints.length) {
|
||||||
|
mapController.drawRoadManually(
|
||||||
|
linedsPoints,
|
||||||
|
const RoadOption(roadColor: Colors.red),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: const Icon(Icons.draw, color: Colors.white),
|
||||||
|
),
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
|
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
|
||||||
import 'package:gps_map_flowpoint/class/devicesSaved.dart';
|
import 'package:eagletracker/class/BLEProvider.dart';
|
||||||
import 'package:gps_map_flowpoint/deviceAdvertizinScan.dart';
|
import 'package:eagletracker/class/devicesSaved.dart' as DevicesSaved;
|
||||||
import 'package:gps_map_flowpoint/deviceFlowMap.dart';
|
import 'package:eagletracker/class/preferenceSaved.dart' as PreferenceSaved;
|
||||||
|
import 'package:eagletracker/deviceAdvertizinScan.dart';
|
||||||
|
import 'package:eagletracker/deviceFlowMap.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class DeviceSelection extends StatefulWidget {
|
class DeviceSelection extends StatefulWidget {
|
||||||
const DeviceSelection({super.key, required this.title});
|
const DeviceSelection({super.key});
|
||||||
|
|
||||||
final String title;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<DeviceSelection> createState() => _DeviceSelectionState();
|
State<DeviceSelection> createState() => _DeviceSelectionState();
|
||||||
|
|
@ -18,14 +19,28 @@ class _DeviceSelectionState extends State<DeviceSelection> {
|
||||||
TextEditingController tecSearch = TextEditingController();
|
TextEditingController tecSearch = TextEditingController();
|
||||||
bool isScanning = false;
|
bool isScanning = false;
|
||||||
|
|
||||||
List<DevicesSaved> devicesSaved = [];
|
List<DevicesSaved.DevicesSaved> devicesSaved = [];
|
||||||
|
PreferenceSaved.PreferenceSaved preferenceSaved =
|
||||||
|
PreferenceSaved.PreferenceSaved.empty();
|
||||||
|
|
||||||
|
TextEditingController tecTimeTakingPointSecond = TextEditingController();
|
||||||
|
|
||||||
// Initialize Bluetooth scanning and subscription in initState
|
// Initialize Bluetooth scanning and subscription in initState
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
restoreLocal().then((value) {
|
|
||||||
print(value.length);
|
isScanning = true;
|
||||||
|
|
||||||
|
PreferenceSaved.restoreLocal().then((value) {
|
||||||
|
setState(() {
|
||||||
|
preferenceSaved = value;
|
||||||
|
tecTimeTakingPointSecond.text =
|
||||||
|
preferenceSaved.timeTakingPointSecond.toString();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
DevicesSaved.restoreLocal().then((value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
devicesSaved = value;
|
devicesSaved = value;
|
||||||
});
|
});
|
||||||
|
|
@ -36,15 +51,15 @@ class _DeviceSelectionState extends State<DeviceSelection> {
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: Text("Bluetooth non activé"),
|
title: const Text("Bluetooth non activé"),
|
||||||
content: Text(
|
content: const Text(
|
||||||
"Le Bluetooth n'est pas activé sur cet appareil. Veillez l'activer pour continuer."),
|
"Le Bluetooth n'est pas activé sur cet appareil. Veillez l'activer pour continuer."),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
child: Text("OK"),
|
child: const Text("OK"),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
@ -52,19 +67,13 @@ class _DeviceSelectionState extends State<DeviceSelection> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
FlutterBluePlus.onScanResults.listen(
|
|
||||||
(results) {
|
|
||||||
setState(() {
|
|
||||||
scanResults = results;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onError: (e) => print(e),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final bleProvider = Provider.of<BLEProvider>(context);
|
||||||
|
scanResults = bleProvider.scanResults;
|
||||||
|
|
||||||
// Filtered list of devices
|
// Filtered list of devices
|
||||||
List<ScanResult> filteredDevices = scanResults
|
List<ScanResult> filteredDevices = scanResults
|
||||||
.where((result) => result.device.platformName
|
.where((result) => result.device.platformName
|
||||||
|
|
@ -73,26 +82,74 @@ class _DeviceSelectionState extends State<DeviceSelection> {
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
//Saved devices list is connected ?
|
//Saved devices list is connected ?
|
||||||
devicesSaved.forEach((element) {
|
for (var element in devicesSaved) {
|
||||||
element.connected = scanResults
|
element.connected = scanResults
|
||||||
.where((result) => result.device.remoteId.str == element.remoteId)
|
.where((result) => result.device.remoteId.str == element.remoteId)
|
||||||
.length >
|
.isNotEmpty;
|
||||||
0;
|
}
|
||||||
});
|
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Icons.settings, color: Colors.white),
|
||||||
|
onPressed: () {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: const Text('Paramètres'),
|
||||||
|
content: SizedBox(
|
||||||
|
height: 100,
|
||||||
|
child: Column(children: [
|
||||||
|
const Text('Capture des points (secondes)'),
|
||||||
|
TextField(
|
||||||
|
controller: tecTimeTakingPointSecond,
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
actions: <Widget>[
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
child: const Text('Annuler'),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
|
||||||
|
preferenceSaved.timeTakingPointSecond =
|
||||||
|
int.parse(tecTimeTakingPointSecond.text);
|
||||||
|
|
||||||
|
PreferenceSaved.saveLocal(preferenceSaved);
|
||||||
|
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
const SnackBar(
|
||||||
|
content: Text('Paramètres enregistrés'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: const Text('Enregistrer'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
})
|
||||||
|
],
|
||||||
backgroundColor: Colors.blue,
|
backgroundColor: Colors.blue,
|
||||||
title: Text("Eagle Tr@cker", style: TextStyle(color: Colors.white)),
|
title:
|
||||||
|
const Text("Eagle Tr@cker", style: TextStyle(color: Colors.white)),
|
||||||
),
|
),
|
||||||
body: Column(
|
body: Column(
|
||||||
children: [
|
children: [
|
||||||
//List of devices saved in local storage by card
|
devicesSaved.isNotEmpty
|
||||||
devicesSaved.length > 0
|
|
||||||
? Column(
|
? Column(
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
const Padding(
|
||||||
padding: const EdgeInsets.all(16.0),
|
padding: EdgeInsets.all(16.0),
|
||||||
child: Text('Appareils sauvegardés',
|
child: Text('Appareils sauvegardés',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 18.0, fontWeight: FontWeight.bold)),
|
fontSize: 18.0, fontWeight: FontWeight.bold)),
|
||||||
|
|
@ -101,82 +158,82 @@ class _DeviceSelectionState extends State<DeviceSelection> {
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
itemCount: devicesSaved.length,
|
itemCount: devicesSaved.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
DevicesSaved device = devicesSaved[index];
|
DevicesSaved.DevicesSaved device = devicesSaved[index];
|
||||||
return Card(
|
return Container(
|
||||||
child: ListTile(
|
margin:
|
||||||
title: Row(children: [
|
const EdgeInsets.only(left: 10, right: 10.0),
|
||||||
Icon(Icons.circle,
|
child: Card(
|
||||||
color: devicesSaved[index].connected
|
child: ListTile(
|
||||||
? Colors.green
|
title: Row(children: [
|
||||||
: Colors.orange,
|
Icon(Icons.circle,
|
||||||
size: 10.0),
|
color: devicesSaved[index].connected
|
||||||
Text(device.deviceName)
|
? Colors.green
|
||||||
]),
|
: Colors.orange,
|
||||||
subtitle: Text(device.deviceAddress),
|
size: 10.0),
|
||||||
trailing: Row(
|
Text(device.deviceName)
|
||||||
mainAxisSize: MainAxisSize.min,
|
]),
|
||||||
children: [
|
subtitle: Text(device.deviceAddress),
|
||||||
GestureDetector(
|
trailing: Row(
|
||||||
onTap: () async {
|
mainAxisSize: MainAxisSize.min,
|
||||||
devicesSaved.removeAt(index);
|
children: [
|
||||||
await saveLocal(devicesSaved);
|
GestureDetector(
|
||||||
setState(() {
|
onTap: () async {
|
||||||
devicesSaved = devicesSaved;
|
devicesSaved.removeAt(index);
|
||||||
});
|
await DevicesSaved.saveLocal(
|
||||||
},
|
devicesSaved);
|
||||||
child: Icon(Icons.delete)),
|
setState(() {
|
||||||
GestureDetector(
|
devicesSaved = devicesSaved;
|
||||||
onTap: () {
|
});
|
||||||
//Stop scanning when a device is selected
|
},
|
||||||
FlutterBluePlus.stopScan();
|
child: const Icon(Icons.delete)),
|
||||||
setState(() {
|
GestureDetector(
|
||||||
isScanning = false;
|
onTap: () {
|
||||||
});
|
if (checkIsScanning(
|
||||||
Navigator.push(
|
context, isScanning)) {
|
||||||
context,
|
Navigator.push(
|
||||||
MaterialPageRoute(
|
context,
|
||||||
builder: (context) =>
|
MaterialPageRoute(
|
||||||
DeviceAdvertizinScan(
|
builder: (context) =>
|
||||||
|
DeviceAdvertizinScan(
|
||||||
|
deviceName:
|
||||||
|
device.deviceName,
|
||||||
|
deviceAddress:
|
||||||
|
device.deviceAddress,
|
||||||
|
remoteId: device.remoteId,
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: const Icon(Icons.info_outline),
|
||||||
|
),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
if (checkIsScanning(
|
||||||
|
context, isScanning)) {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => DeviceFlowMap(
|
||||||
deviceName: device.deviceName,
|
deviceName: device.deviceName,
|
||||||
deviceAddress:
|
deviceAddress:
|
||||||
device.deviceAddress,
|
device.deviceAddress,
|
||||||
remoteId: device.remoteId,
|
),
|
||||||
)),
|
),
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
child: Icon(Icons.info_outline),
|
},
|
||||||
|
child: const Icon(Icons.map_outlined),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
GestureDetector(
|
)));
|
||||||
onTap: () {
|
|
||||||
//Stop scanning when a device is selected
|
|
||||||
FlutterBluePlus.stopScan();
|
|
||||||
setState(() {
|
|
||||||
isScanning = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => DeviceFlowMap(
|
|
||||||
title: 'GPS Map Flowpoint',
|
|
||||||
deviceName: device.deviceName,
|
|
||||||
deviceAddress: device.deviceAddress,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
child: Icon(Icons.map_outlined),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
));
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
: Container(),
|
: Container(),
|
||||||
Padding(
|
const Padding(
|
||||||
padding: const EdgeInsets.all(16.0),
|
padding: EdgeInsets.all(16.0),
|
||||||
child: Text('Recherche d\' appareils BLE',
|
child: Text('Recherche d\' appareils BLE',
|
||||||
style: TextStyle(fontSize: 18.0, fontWeight: FontWeight.bold)),
|
style: TextStyle(fontSize: 18.0, fontWeight: FontWeight.bold)),
|
||||||
),
|
),
|
||||||
|
|
@ -184,7 +241,7 @@ class _DeviceSelectionState extends State<DeviceSelection> {
|
||||||
padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
controller: tecSearch,
|
controller: tecSearch,
|
||||||
decoration: InputDecoration(
|
decoration: const InputDecoration(
|
||||||
hintText: 'Rechercher un appareil par nom',
|
hintText: 'Rechercher un appareil par nom',
|
||||||
prefixIcon: Icon(Icons.search),
|
prefixIcon: Icon(Icons.search),
|
||||||
),
|
),
|
||||||
|
|
@ -193,7 +250,7 @@ class _DeviceSelectionState extends State<DeviceSelection> {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 16.0),
|
const SizedBox(height: 16.0),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
itemCount: filteredDevices.length,
|
itemCount: filteredDevices.length,
|
||||||
|
|
@ -206,13 +263,12 @@ class _DeviceSelectionState extends State<DeviceSelection> {
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
if (devicesSaved
|
if (devicesSaved
|
||||||
.where((element) =>
|
.where((element) =>
|
||||||
element.deviceAddress ==
|
element.deviceAddress ==
|
||||||
result.device.remoteId.str)
|
result.device.remoteId.str)
|
||||||
.length >
|
.isNotEmpty) {
|
||||||
0) {
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
const SnackBar(
|
||||||
content:
|
content:
|
||||||
Text('Cet appareil est déjà sauvegardé'),
|
Text('Cet appareil est déjà sauvegardé'),
|
||||||
),
|
),
|
||||||
|
|
@ -220,64 +276,55 @@ class _DeviceSelectionState extends State<DeviceSelection> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
devicesSaved.add(DevicesSaved(
|
devicesSaved.add(DevicesSaved.DevicesSaved(
|
||||||
deviceName: result.device.platformName,
|
deviceName: result.device.platformName,
|
||||||
deviceAddress: result.device.remoteId.str,
|
deviceAddress: result.device.remoteId.str,
|
||||||
remoteId: result.device.remoteId.str,
|
remoteId: result.device.remoteId.str,
|
||||||
));
|
));
|
||||||
await saveLocal(devicesSaved);
|
await DevicesSaved.saveLocal(devicesSaved);
|
||||||
setState(() {
|
setState(() {
|
||||||
devicesSaved = devicesSaved;
|
devicesSaved = devicesSaved;
|
||||||
});
|
});
|
||||||
;
|
;
|
||||||
},
|
},
|
||||||
child: Icon(Icons.add),
|
child: const Icon(Icons.add),
|
||||||
),
|
),
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
//Stop scanning when a device is selected
|
if (checkIsScanning(context, isScanning)) {
|
||||||
FlutterBluePlus.stopScan();
|
Navigator.push(
|
||||||
setState(() {
|
context,
|
||||||
isScanning = false;
|
MaterialPageRoute(
|
||||||
});
|
builder: (context) => DeviceAdvertizinScan(
|
||||||
Navigator.push(
|
deviceName: result.device.platformName,
|
||||||
context,
|
deviceAddress: result.device.remoteId.str,
|
||||||
MaterialPageRoute(
|
remoteId: result.device.remoteId.str,
|
||||||
builder: (context) => DeviceAdvertizinScan(
|
),
|
||||||
deviceName: result.device.platformName,
|
|
||||||
deviceAddress: result.device.remoteId.str,
|
|
||||||
remoteId: result.device.remoteId.str,
|
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
);
|
}
|
||||||
},
|
},
|
||||||
child: Icon(Icons.info_outline),
|
child: const Icon(Icons.info_outline),
|
||||||
),
|
),
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
//Stop scanning when a device is selected
|
if (checkIsScanning(context, isScanning)) return;
|
||||||
FlutterBluePlus.stopScan();
|
|
||||||
setState(() {
|
|
||||||
isScanning = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => DeviceFlowMap(
|
builder: (context) => DeviceFlowMap(
|
||||||
title: 'GPS Map Flowpoint',
|
|
||||||
deviceName: result.device.platformName,
|
deviceName: result.device.platformName,
|
||||||
deviceAddress: result.device.remoteId.str,
|
deviceAddress: result.device.remoteId.str,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: Icon(Icons.map_outlined),
|
child: const Icon(Icons.map_outlined),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
title: Row(children: [
|
title: Row(children: [
|
||||||
Icon(Icons.circle, color: Colors.green, size: 10.0),
|
const Icon(Icons.circle, color: Colors.green, size: 10.0),
|
||||||
Text(result.device.platformName)
|
Text(result.device.platformName)
|
||||||
]),
|
]),
|
||||||
subtitle: Text(result.device.remoteId.str),
|
subtitle: Text(result.device.remoteId.str),
|
||||||
|
|
@ -290,14 +337,12 @@ class _DeviceSelectionState extends State<DeviceSelection> {
|
||||||
floatingActionButton: FloatingActionButton(
|
floatingActionButton: FloatingActionButton(
|
||||||
backgroundColor: Colors.blue,
|
backgroundColor: Colors.blue,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
print('Scanning');
|
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
isScanning = !isScanning;
|
isScanning = !isScanning;
|
||||||
if (isScanning) {
|
if (isScanning) {
|
||||||
FlutterBluePlus.startScan();
|
bleProvider.startScan();
|
||||||
} else {
|
} else {
|
||||||
FlutterBluePlus.stopScan();
|
bleProvider.stopScan();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
@ -307,3 +352,16 @@ class _DeviceSelectionState extends State<DeviceSelection> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool checkIsScanning(BuildContext context, bool isScanning) {
|
||||||
|
if (!isScanning) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
const SnackBar(
|
||||||
|
content: Text('Vous devez activer le scan pour continuer'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
42
lib/function.dart
Normal file
42
lib/function.dart
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:csv/csv.dart';
|
||||||
|
import 'package:flutter_email_sender/flutter_email_sender.dart';
|
||||||
|
import 'package:eagletracker/class/geoPosition.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
|
||||||
|
Future<File> generateCsv(List<GeoPosition> positions) async {
|
||||||
|
List<List<dynamic>> csvData = [
|
||||||
|
['latitude', 'longitude', 'altitude', 'spped'] // Header
|
||||||
|
];
|
||||||
|
|
||||||
|
for (var position in positions) {
|
||||||
|
csvData.add([position.latitude, position.longitude, position.altitude]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Directory appDocumentsDirectory = await getApplicationDocumentsDirectory();
|
||||||
|
String appDocumentsPath = appDocumentsDirectory.path;
|
||||||
|
|
||||||
|
String csvFilePath = '$appDocumentsPath/positions.csv';
|
||||||
|
File csvFile = File(csvFilePath);
|
||||||
|
|
||||||
|
String csvContent = const ListToCsvConverter().convert(csvData);
|
||||||
|
await csvFile.writeAsString(csvContent);
|
||||||
|
|
||||||
|
return csvFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendEmailWithAttachment(File csvFile) async {
|
||||||
|
final Email email = Email(
|
||||||
|
subject: 'Eagle Tr@cker - Positions',
|
||||||
|
body: 'Veuillez trouver ci-joint le fichier CSV contenant les positions.',
|
||||||
|
recipients: [],
|
||||||
|
attachmentPaths: [csvFile.path],
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await FlutterEmailSender.send(email);
|
||||||
|
} catch (error) {
|
||||||
|
throw 'Failed to send email: $error';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:gps_map_flowpoint/class/BLEProvider.dart';
|
import 'package:eagletracker/class/BLEProvider.dart';
|
||||||
import 'package:gps_map_flowpoint/deviceSelection.dart';
|
import 'package:eagletracker/deviceSelection.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
|
@ -9,7 +9,7 @@ void main() {
|
||||||
providers: [
|
providers: [
|
||||||
ChangeNotifierProvider(create: (_) => BLEProvider()),
|
ChangeNotifierProvider(create: (_) => BLEProvider()),
|
||||||
],
|
],
|
||||||
child: MyApp(),
|
child: const MyApp(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -22,12 +22,12 @@ class MyApp extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
title: 'GPS Map Flowpoint',
|
title: 'Eagle Tr@cker',
|
||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
|
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
|
||||||
useMaterial3: true,
|
useMaterial3: true,
|
||||||
),
|
),
|
||||||
home: const DeviceSelection(title: 'GPS Map Flowpoint'),
|
home: const DeviceSelection(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,14 @@ import Foundation
|
||||||
|
|
||||||
import flutter_blue_plus
|
import flutter_blue_plus
|
||||||
import geolocator_apple
|
import geolocator_apple
|
||||||
|
import path_provider_foundation
|
||||||
import shared_preferences_foundation
|
import shared_preferences_foundation
|
||||||
import url_launcher_macos
|
import url_launcher_macos
|
||||||
|
|
||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
FlutterBluePlusPlugin.register(with: registry.registrar(forPlugin: "FlutterBluePlusPlugin"))
|
FlutterBluePlusPlugin.register(with: registry.registrar(forPlugin: "FlutterBluePlusPlugin"))
|
||||||
GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin"))
|
GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin"))
|
||||||
|
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||||
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
46
pubspec.lock
46
pubspec.lock
|
|
@ -49,6 +49,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.3"
|
version: "3.0.3"
|
||||||
|
csv:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: csv
|
||||||
|
sha256: c6aa2679b2a18cb57652920f674488d89712efaf4d3fdf2e537215b35fc19d6c
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.0.0"
|
||||||
cupertino_icons:
|
cupertino_icons:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -110,6 +118,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.32.7"
|
version: "1.32.7"
|
||||||
|
flutter_email_sender:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_email_sender
|
||||||
|
sha256: fb515d4e073d238d0daf1d765e5318487b6396d46b96e0ae9745dbc9a133f97a
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.0.3"
|
||||||
flutter_lints:
|
flutter_lints:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
|
|
@ -304,6 +320,30 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.0"
|
version: "1.9.0"
|
||||||
|
path_provider:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: path_provider
|
||||||
|
sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.3"
|
||||||
|
path_provider_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_android
|
||||||
|
sha256: bca87b0165ffd7cdb9cad8edd22d18d2201e886d9a9f19b4fb3452ea7df3a72a
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.6"
|
||||||
|
path_provider_foundation:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_foundation
|
||||||
|
sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.0"
|
||||||
path_provider_linux:
|
path_provider_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -542,13 +582,13 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.2"
|
version: "1.3.2"
|
||||||
url_launcher:
|
url_launcher:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: url_launcher
|
name: url_launcher
|
||||||
sha256: "6ce1e04375be4eed30548f10a315826fd933c1e493206eab82eed01f438c8d2e"
|
sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.2.6"
|
version: "6.3.0"
|
||||||
url_launcher_android:
|
url_launcher_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
name: gps_map_flowpoint
|
name: eagletracker
|
||||||
description: "A new Flutter project."
|
description: "A new Flutter project."
|
||||||
# The following line prevents the package from being accidentally published to
|
# The following line prevents the package from being accidentally published to
|
||||||
# pub.dev using `flutter pub publish`. This is preferred for private packages.
|
# pub.dev using `flutter pub publish`. This is preferred for private packages.
|
||||||
|
|
@ -40,6 +40,10 @@ dependencies:
|
||||||
geolocator: ^12.0.0
|
geolocator: ^12.0.0
|
||||||
shared_preferences: ^2.2.3
|
shared_preferences: ^2.2.3
|
||||||
provider: ^6.1.2
|
provider: ^6.1.2
|
||||||
|
csv: ^6.0.0
|
||||||
|
url_launcher: ^6.3.0
|
||||||
|
path_provider: ^2.1.3
|
||||||
|
flutter_email_sender: ^6.0.3
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user