First commit
This commit is contained in:
parent
92957a1903
commit
27d8f55d7e
|
|
@ -3,6 +3,8 @@ PODS:
|
|||
- Flutter (1.0.0)
|
||||
- flutter_blue_plus (0.0.1):
|
||||
- Flutter
|
||||
- flutter_email_sender (0.0.1):
|
||||
- Flutter
|
||||
- flutter_osm_plugin (0.0.1):
|
||||
- Alamofire
|
||||
- Flutter
|
||||
|
|
@ -11,6 +13,9 @@ PODS:
|
|||
- Yams
|
||||
- geolocator_apple (1.2.0):
|
||||
- Flutter
|
||||
- path_provider_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- permission_handler_apple (9.3.0):
|
||||
- Flutter
|
||||
- Polyline (5.1.0)
|
||||
|
|
@ -25,8 +30,10 @@ PODS:
|
|||
DEPENDENCIES:
|
||||
- Flutter (from `Flutter`)
|
||||
- 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`)
|
||||
- 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`)
|
||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||
|
|
@ -43,10 +50,14 @@ EXTERNAL SOURCES:
|
|||
:path: Flutter
|
||||
flutter_blue_plus:
|
||||
:path: ".symlinks/plugins/flutter_blue_plus/ios"
|
||||
flutter_email_sender:
|
||||
:path: ".symlinks/plugins/flutter_email_sender/ios"
|
||||
flutter_osm_plugin:
|
||||
:path: ".symlinks/plugins/flutter_osm_plugin/ios"
|
||||
geolocator_apple:
|
||||
:path: ".symlinks/plugins/geolocator_apple/ios"
|
||||
path_provider_foundation:
|
||||
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
||||
permission_handler_apple:
|
||||
:path: ".symlinks/plugins/permission_handler_apple/ios"
|
||||
shared_preferences_foundation:
|
||||
|
|
@ -58,8 +69,10 @@ SPEC CHECKSUMS:
|
|||
Alamofire: f36a35757af4587d8e4f4bfa223ad10be2422b8c
|
||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||
flutter_blue_plus: 4837da7d00cf5d441fdd6635b3a57f936778ea96
|
||||
flutter_email_sender: 10a22605f92809a11ef52b2f412db806c6082d40
|
||||
flutter_osm_plugin: a661df71d2a3d1698ee410dd2272c8536f9e46f4
|
||||
geolocator_apple: 6cbaf322953988e009e5ecb481f07efece75c450
|
||||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
|
||||
Polyline: 2a1f29f87f8d9b7de868940f4f76deb8c678a5b1
|
||||
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
||||
|
|
|
|||
|
|
@ -2,11 +2,13 @@ class GeoPosition {
|
|||
final double latitude;
|
||||
final double longitude;
|
||||
final double altitude;
|
||||
final double speed;
|
||||
|
||||
GeoPosition({
|
||||
required this.latitude,
|
||||
required this.longitude,
|
||||
required this.altitude,
|
||||
this.speed = 0.0,
|
||||
});
|
||||
|
||||
factory GeoPosition.fromJson(Map<String, dynamic> json) {
|
||||
|
|
@ -14,6 +16,16 @@ class GeoPosition {
|
|||
latitude: json['latitude'],
|
||||
longitude: json['longitude'],
|
||||
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_blue_plus/flutter_blue_plus.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 {
|
||||
const DeviceAdvertizinScan(
|
||||
|
|
@ -25,48 +27,46 @@ class _DeviceAdvertizinScanState extends State<DeviceAdvertizinScan> {
|
|||
initPosition: GeoPoint(latitude: 47.4358055, longitude: 8.4737324),
|
||||
);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
tecTakingPoint.text = '5';
|
||||
FlutterBluePlus.startScan();
|
||||
}
|
||||
String value = 'Aucune valeur reçue';
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
FlutterBluePlus.stopScan();
|
||||
print('Page disposed');
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
String value = 'Aucune valeur trouvée';
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
FlutterBluePlus.onScanResults.listen((results) {
|
||||
setState(() {
|
||||
if (results.length > 0) value = results[0].advertisementData.toString();
|
||||
});
|
||||
});
|
||||
final bleProvider = Provider.of<BLEProvider>(context);
|
||||
scanResults = bleProvider.scanResults;
|
||||
|
||||
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(
|
||||
appBar: AppBar(
|
||||
title: Text("Valeur de la trame publicitaire",
|
||||
style: const TextStyle(color: Colors.white)),
|
||||
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: () {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
'(debug) Vous devez redémarrer l application et réaliser un nouveau scan pour voir les nouvelles valeurs (FlutterBluePlus.startScan())'),
|
||||
),
|
||||
);
|
||||
return;
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
),
|
||||
body: Column(
|
||||
children: [
|
||||
const Padding(
|
||||
padding: EdgeInsets.all(16.0),
|
||||
child: Text('Lecture de la trame publicitaire',
|
||||
style: TextStyle(fontSize: 18.0, fontWeight: FontWeight.bold)),
|
||||
),
|
||||
Container(
|
||||
alignment: Alignment.topCenter,
|
||||
child: Column(
|
||||
|
|
@ -80,17 +80,17 @@ class _DeviceAdvertizinScanState extends State<DeviceAdvertizinScan> {
|
|||
margin: const EdgeInsets.all(10),
|
||||
child:
|
||||
//Text centré
|
||||
Center(
|
||||
const Center(
|
||||
child: Text(
|
||||
"La trame publicitaire est en cours de réception et actualisée en temps réel.",
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
color: Colors.green,
|
||||
),
|
||||
textAlign: TextAlign.center),
|
||||
)),
|
||||
Container(
|
||||
margin: const EdgeInsets.all(10),
|
||||
child: CircularProgressIndicator()),
|
||||
child: const CircularProgressIndicator()),
|
||||
Container(
|
||||
margin: const EdgeInsets.all(10),
|
||||
alignment: Alignment.center,
|
||||
|
|
|
|||
|
|
@ -1,14 +1,19 @@
|
|||
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.title,
|
||||
required this.deviceName,
|
||||
required this.deviceAddress});
|
||||
{super.key, required this.deviceName, required this.deviceAddress});
|
||||
|
||||
final String title;
|
||||
final String deviceName;
|
||||
final String deviceAddress;
|
||||
|
||||
|
|
@ -17,22 +22,66 @@ class DeviceFlowMap extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _DeviceFlowMapState extends State<DeviceFlowMap> {
|
||||
TextEditingController tecTakingPoint = TextEditingController();
|
||||
MapController mapController = MapController(
|
||||
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
|
||||
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
|
||||
Widget build(BuildContext context) {
|
||||
final bleProvider = Provider.of<BLEProvider>(context);
|
||||
scanResults = bleProvider.scanResults;
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(widget.deviceName,
|
||||
style: const TextStyle(color: Colors.white)),
|
||||
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),
|
||||
|
|
@ -41,92 +90,118 @@ class _DeviceFlowMapState extends State<DeviceFlowMap> {
|
|||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: Icon(Icons.settings, color: Colors.white),
|
||||
onPressed: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: const Text('Paramètres'),
|
||||
content: Column(
|
||||
),
|
||||
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: [
|
||||
const Text('Temps de prise de point (en secondes)'),
|
||||
TextField(
|
||||
controller: tecTakingPoint,
|
||||
keyboardType: TextInputType.number,
|
||||
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,
|
||||
),
|
||||
),
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: const Text('Annuler'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
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,
|
||||
const SizedBox(height: 10),
|
||||
SizedBox(
|
||||
height: 10,
|
||||
width: 180,
|
||||
child: LinearProgressIndicator(
|
||||
value: progression / 100,
|
||||
backgroundColor: Colors.grey[300],
|
||||
valueColor:
|
||||
const AlwaysStoppedAnimation<Color>(Colors.blue),
|
||||
),
|
||||
),
|
||||
),
|
||||
directionArrowMarker: MarkerIcon(
|
||||
icon: Icon(
|
||||
Icons.double_arrow,
|
||||
size: 48,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)),
|
||||
),
|
||||
),
|
||||
]),
|
||||
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
|
||||
floatingActionButton:
|
||||
Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [
|
||||
FloatingActionButton(
|
||||
heroTag: 'mapFab',
|
||||
backgroundColor: Colors.blue,
|
||||
onPressed: () {},
|
||||
child: Icon(Icons.map_outlined, color: Colors.white),
|
||||
),
|
||||
FloatingActionButton(
|
||||
heroTag: 'mapFab2',
|
||||
heroTag: 'actionFab1',
|
||||
backgroundColor: Colors.blue,
|
||||
onPressed: () {
|
||||
mapController.currentLocation();
|
||||
},
|
||||
child: const Icon(Icons.map_outlined, color: Colors.white),
|
||||
),
|
||||
FloatingActionButton(
|
||||
heroTag: 'actionFab2',
|
||||
backgroundColor: Colors.blue,
|
||||
onPressed: () {
|
||||
//Alert for ask to delete piont ?=
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
|
|
@ -137,12 +212,17 @@ class _DeviceFlowMapState extends State<DeviceFlowMap> {
|
|||
actions: <Widget>[
|
||||
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(
|
||||
|
|
@ -159,7 +239,53 @@ class _DeviceFlowMapState extends State<DeviceFlowMap> {
|
|||
);
|
||||
},
|
||||
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_blue_plus/flutter_blue_plus.dart';
|
||||
import 'package:gps_map_flowpoint/class/devicesSaved.dart';
|
||||
import 'package:gps_map_flowpoint/deviceAdvertizinScan.dart';
|
||||
import 'package:gps_map_flowpoint/deviceFlowMap.dart';
|
||||
import 'package:eagletracker/class/BLEProvider.dart';
|
||||
import 'package:eagletracker/class/devicesSaved.dart' as DevicesSaved;
|
||||
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 {
|
||||
const DeviceSelection({super.key, required this.title});
|
||||
|
||||
final String title;
|
||||
const DeviceSelection({super.key});
|
||||
|
||||
@override
|
||||
State<DeviceSelection> createState() => _DeviceSelectionState();
|
||||
|
|
@ -18,14 +19,28 @@ class _DeviceSelectionState extends State<DeviceSelection> {
|
|||
TextEditingController tecSearch = TextEditingController();
|
||||
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
|
||||
@override
|
||||
void 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(() {
|
||||
devicesSaved = value;
|
||||
});
|
||||
|
|
@ -36,15 +51,15 @@ class _DeviceSelectionState extends State<DeviceSelection> {
|
|||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: Text("Bluetooth non activé"),
|
||||
content: Text(
|
||||
title: const Text("Bluetooth non activé"),
|
||||
content: const Text(
|
||||
"Le Bluetooth n'est pas activé sur cet appareil. Veillez l'activer pour continuer."),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
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
|
||||
Widget build(BuildContext context) {
|
||||
final bleProvider = Provider.of<BLEProvider>(context);
|
||||
scanResults = bleProvider.scanResults;
|
||||
|
||||
// Filtered list of devices
|
||||
List<ScanResult> filteredDevices = scanResults
|
||||
.where((result) => result.device.platformName
|
||||
|
|
@ -73,26 +82,74 @@ class _DeviceSelectionState extends State<DeviceSelection> {
|
|||
.toList();
|
||||
|
||||
//Saved devices list is connected ?
|
||||
devicesSaved.forEach((element) {
|
||||
for (var element in devicesSaved) {
|
||||
element.connected = scanResults
|
||||
.where((result) => result.device.remoteId.str == element.remoteId)
|
||||
.length >
|
||||
0;
|
||||
});
|
||||
.where((result) => result.device.remoteId.str == element.remoteId)
|
||||
.isNotEmpty;
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
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,
|
||||
title: Text("Eagle Tr@cker", style: TextStyle(color: Colors.white)),
|
||||
title:
|
||||
const Text("Eagle Tr@cker", style: TextStyle(color: Colors.white)),
|
||||
),
|
||||
body: Column(
|
||||
children: [
|
||||
//List of devices saved in local storage by card
|
||||
devicesSaved.length > 0
|
||||
devicesSaved.isNotEmpty
|
||||
? Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
const Padding(
|
||||
padding: EdgeInsets.all(16.0),
|
||||
child: Text('Appareils sauvegardés',
|
||||
style: TextStyle(
|
||||
fontSize: 18.0, fontWeight: FontWeight.bold)),
|
||||
|
|
@ -101,82 +158,82 @@ class _DeviceSelectionState extends State<DeviceSelection> {
|
|||
shrinkWrap: true,
|
||||
itemCount: devicesSaved.length,
|
||||
itemBuilder: (context, index) {
|
||||
DevicesSaved device = devicesSaved[index];
|
||||
return Card(
|
||||
child: ListTile(
|
||||
title: Row(children: [
|
||||
Icon(Icons.circle,
|
||||
color: devicesSaved[index].connected
|
||||
? Colors.green
|
||||
: Colors.orange,
|
||||
size: 10.0),
|
||||
Text(device.deviceName)
|
||||
]),
|
||||
subtitle: Text(device.deviceAddress),
|
||||
trailing: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
devicesSaved.removeAt(index);
|
||||
await saveLocal(devicesSaved);
|
||||
setState(() {
|
||||
devicesSaved = devicesSaved;
|
||||
});
|
||||
},
|
||||
child: Icon(Icons.delete)),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
//Stop scanning when a device is selected
|
||||
FlutterBluePlus.stopScan();
|
||||
setState(() {
|
||||
isScanning = false;
|
||||
});
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
DeviceAdvertizinScan(
|
||||
DevicesSaved.DevicesSaved device = devicesSaved[index];
|
||||
return Container(
|
||||
margin:
|
||||
const EdgeInsets.only(left: 10, right: 10.0),
|
||||
child: Card(
|
||||
child: ListTile(
|
||||
title: Row(children: [
|
||||
Icon(Icons.circle,
|
||||
color: devicesSaved[index].connected
|
||||
? Colors.green
|
||||
: Colors.orange,
|
||||
size: 10.0),
|
||||
Text(device.deviceName)
|
||||
]),
|
||||
subtitle: Text(device.deviceAddress),
|
||||
trailing: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
devicesSaved.removeAt(index);
|
||||
await DevicesSaved.saveLocal(
|
||||
devicesSaved);
|
||||
setState(() {
|
||||
devicesSaved = devicesSaved;
|
||||
});
|
||||
},
|
||||
child: const Icon(Icons.delete)),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
if (checkIsScanning(
|
||||
context, isScanning)) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
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,
|
||||
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(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
const Padding(
|
||||
padding: EdgeInsets.all(16.0),
|
||||
child: Text('Recherche d\' appareils BLE',
|
||||
style: TextStyle(fontSize: 18.0, fontWeight: FontWeight.bold)),
|
||||
),
|
||||
|
|
@ -184,7 +241,7 @@ class _DeviceSelectionState extends State<DeviceSelection> {
|
|||
padding: const EdgeInsets.all(16.0),
|
||||
child: TextFormField(
|
||||
controller: tecSearch,
|
||||
decoration: InputDecoration(
|
||||
decoration: const InputDecoration(
|
||||
hintText: 'Rechercher un appareil par nom',
|
||||
prefixIcon: Icon(Icons.search),
|
||||
),
|
||||
|
|
@ -193,7 +250,7 @@ class _DeviceSelectionState extends State<DeviceSelection> {
|
|||
},
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16.0),
|
||||
const SizedBox(height: 16.0),
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: filteredDevices.length,
|
||||
|
|
@ -206,13 +263,12 @@ class _DeviceSelectionState extends State<DeviceSelection> {
|
|||
GestureDetector(
|
||||
onTap: () async {
|
||||
if (devicesSaved
|
||||
.where((element) =>
|
||||
element.deviceAddress ==
|
||||
result.device.remoteId.str)
|
||||
.length >
|
||||
0) {
|
||||
.where((element) =>
|
||||
element.deviceAddress ==
|
||||
result.device.remoteId.str)
|
||||
.isNotEmpty) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
const SnackBar(
|
||||
content:
|
||||
Text('Cet appareil est déjà sauvegardé'),
|
||||
),
|
||||
|
|
@ -220,64 +276,55 @@ class _DeviceSelectionState extends State<DeviceSelection> {
|
|||
return;
|
||||
}
|
||||
|
||||
devicesSaved.add(DevicesSaved(
|
||||
devicesSaved.add(DevicesSaved.DevicesSaved(
|
||||
deviceName: result.device.platformName,
|
||||
deviceAddress: result.device.remoteId.str,
|
||||
remoteId: result.device.remoteId.str,
|
||||
));
|
||||
await saveLocal(devicesSaved);
|
||||
await DevicesSaved.saveLocal(devicesSaved);
|
||||
setState(() {
|
||||
devicesSaved = devicesSaved;
|
||||
});
|
||||
;
|
||||
},
|
||||
child: Icon(Icons.add),
|
||||
child: const Icon(Icons.add),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
//Stop scanning when a device is selected
|
||||
FlutterBluePlus.stopScan();
|
||||
setState(() {
|
||||
isScanning = false;
|
||||
});
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => DeviceAdvertizinScan(
|
||||
deviceName: result.device.platformName,
|
||||
deviceAddress: result.device.remoteId.str,
|
||||
remoteId: result.device.remoteId.str,
|
||||
if (checkIsScanning(context, isScanning)) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
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(
|
||||
onTap: () {
|
||||
//Stop scanning when a device is selected
|
||||
FlutterBluePlus.stopScan();
|
||||
setState(() {
|
||||
isScanning = false;
|
||||
});
|
||||
|
||||
if (checkIsScanning(context, isScanning)) return;
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => DeviceFlowMap(
|
||||
title: 'GPS Map Flowpoint',
|
||||
deviceName: result.device.platformName,
|
||||
deviceAddress: result.device.remoteId.str,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Icon(Icons.map_outlined),
|
||||
child: const Icon(Icons.map_outlined),
|
||||
),
|
||||
],
|
||||
),
|
||||
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)
|
||||
]),
|
||||
subtitle: Text(result.device.remoteId.str),
|
||||
|
|
@ -290,14 +337,12 @@ class _DeviceSelectionState extends State<DeviceSelection> {
|
|||
floatingActionButton: FloatingActionButton(
|
||||
backgroundColor: Colors.blue,
|
||||
onPressed: () {
|
||||
print('Scanning');
|
||||
|
||||
setState(() {
|
||||
isScanning = !isScanning;
|
||||
if (isScanning) {
|
||||
FlutterBluePlus.startScan();
|
||||
bleProvider.startScan();
|
||||
} 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:gps_map_flowpoint/class/BLEProvider.dart';
|
||||
import 'package:gps_map_flowpoint/deviceSelection.dart';
|
||||
import 'package:eagletracker/class/BLEProvider.dart';
|
||||
import 'package:eagletracker/deviceSelection.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
void main() {
|
||||
|
|
@ -9,7 +9,7 @@ void main() {
|
|||
providers: [
|
||||
ChangeNotifierProvider(create: (_) => BLEProvider()),
|
||||
],
|
||||
child: MyApp(),
|
||||
child: const MyApp(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -22,12 +22,12 @@ class MyApp extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
debugShowCheckedModeBanner: false,
|
||||
title: 'GPS Map Flowpoint',
|
||||
title: 'Eagle Tr@cker',
|
||||
theme: ThemeData(
|
||||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
|
||||
useMaterial3: true,
|
||||
),
|
||||
home: const DeviceSelection(title: 'GPS Map Flowpoint'),
|
||||
home: const DeviceSelection(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,12 +7,14 @@ import Foundation
|
|||
|
||||
import flutter_blue_plus
|
||||
import geolocator_apple
|
||||
import path_provider_foundation
|
||||
import shared_preferences_foundation
|
||||
import url_launcher_macos
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
FlutterBluePlusPlugin.register(with: registry.registrar(forPlugin: "FlutterBluePlusPlugin"))
|
||||
GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin"))
|
||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
||||
}
|
||||
|
|
|
|||
46
pubspec.lock
46
pubspec.lock
|
|
@ -49,6 +49,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
@ -110,6 +118,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
|
|
@ -304,6 +320,30 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -542,13 +582,13 @@ packages:
|
|||
source: hosted
|
||||
version: "1.3.2"
|
||||
url_launcher:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: url_launcher
|
||||
sha256: "6ce1e04375be4eed30548f10a315826fd933c1e493206eab82eed01f438c8d2e"
|
||||
sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.2.6"
|
||||
version: "6.3.0"
|
||||
url_launcher_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
name: gps_map_flowpoint
|
||||
name: eagletracker
|
||||
description: "A new Flutter project."
|
||||
# The following line prevents the package from being accidentally published to
|
||||
# pub.dev using `flutter pub publish`. This is preferred for private packages.
|
||||
|
|
@ -40,6 +40,10 @@ dependencies:
|
|||
geolocator: ^12.0.0
|
||||
shared_preferences: ^2.2.3
|
||||
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:
|
||||
flutter_test:
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user