import 'dart:async'; import 'dart:io'; 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: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 { const DeviceFlowMap( {super.key, required this.deviceName, required this.deviceAddress}); final String deviceName; final String deviceAddress; @override State createState() => _DeviceFlowMapState(); } class _DeviceFlowMapState extends State { MapController mapController = MapController( initPosition: GeoPoint(latitude: 47.4358055, longitude: 8.4737324), ); List scanResults = []; List geoPositions = []; Timer? timer; double progression = 0.0; int timeTakingPointSecond = 10; int updateInterval = 500; // Intervalle de mise à jour en millisecondes PreferenceSaved preferenceSaved = PreferenceSaved.empty(); @override void initState() { 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 Widget build(BuildContext context) { final bleProvider = Provider.of(context); scanResults = bleProvider.scanResults; return Scaffold( appBar: AppBar( title: const Text("Eagle Tr@cker", style: TextStyle(color: Colors.white)), backgroundColor: Colors.blue, leading: IconButton( icon: const Icon(Icons.arrow_back, color: Colors.white), onPressed: () { mapController.dispose(); Navigator.pop(context); }, ), ), body: Stack(children: [ OSMFlutter( controller: mapController, onMapIsReady: (bool value) async { if (value) { Future.delayed(const Duration(milliseconds: 500), () async { await mapController.currentLocation(); }); } }, 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: [ Text( 'Altitude: ${geoPositions.last.altitude.toStringAsFixed(2)} m', style: const TextStyle( 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, ), ), const SizedBox(height: 10), SizedBox( height: 10, width: 180, child: LinearProgressIndicator( value: progression / 100, backgroundColor: Colors.grey[300], valueColor: const AlwaysStoppedAnimation(Colors.blue), ), ), ], ), ), ), ]), floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, floatingActionButton: Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ FloatingActionButton( heroTag: 'actionFab1', backgroundColor: Colors.blue, onPressed: () { mapController.currentLocation(); }, child: const Icon(Icons.map_outlined, color: Colors.white), ), FloatingActionButton( heroTag: 'actionFab2', backgroundColor: Colors.blue, onPressed: () { showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: const Text('Réinitialiser les points'), content: const Text('Voulez-vous supprimer tous les points ?'), actions: [ TextButton( onPressed: () { geoPositions.clear(); Navigator.of(context).pop(); }, child: const Text('Annuler'), ), TextButton( onPressed: () { setState(() { geoPositions.clear(); }); Navigator.of(context).pop(); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Tous les points ont été supprimés'), ), ); }, child: const Text('Oui'), ), ], ); }, ); }, 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 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), ), ]), ); } }