Compare commits
11 Commits
210da71d50
...
main
Author | SHA1 | Date | |
---|---|---|---|
5ee053272e | |||
1bb2612de3 | |||
86f81ff009 | |||
9989aebc32 | |||
35fc1cfa25 | |||
692d55858c | |||
59b16e5131 | |||
89c5e1aa6c | |||
f4fb846855 | |||
9a9287bd20 | |||
70545052c2 |
@@ -1,4 +1,7 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:label="covas_mobile_new"
|
android:label="covas_mobile_new"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
@@ -15,6 +18,7 @@
|
|||||||
android:theme="@style/LaunchTheme"
|
android:theme="@style/LaunchTheme"
|
||||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||||
android:hardwareAccelerated="true"
|
android:hardwareAccelerated="true"
|
||||||
|
android:enableOnBackInvokedCallback="true"
|
||||||
android:windowSoftInputMode="adjustResize">
|
android:windowSoftInputMode="adjustResize">
|
||||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||||
the Android process has started. This theme is visible to the user
|
the Android process has started. This theme is visible to the user
|
||||||
|
@@ -6,21 +6,28 @@ import 'pages/LoginDemo.dart';
|
|||||||
import 'locale_provider.dart'; // <-- à adapter selon ton arborescence
|
import 'locale_provider.dart'; // <-- à adapter selon ton arborescence
|
||||||
import 'package:covas_mobile/gen_l10n/app_localizations.dart';
|
import 'package:covas_mobile/gen_l10n/app_localizations.dart';
|
||||||
import 'classes/notification_service.dart';
|
import 'classes/notification_service.dart';
|
||||||
|
import 'classes/auth_service.dart';
|
||||||
|
import 'pages/ListItemMenu.dart';
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
await MobileAds.instance.initialize();
|
await MobileAds.instance.initialize();
|
||||||
await NotificationService.initialize();
|
await NotificationService.initialize();
|
||||||
|
final AuthService _authService = AuthService();
|
||||||
|
|
||||||
|
final loggedIn = await _authService.isLoggedIn();
|
||||||
|
|
||||||
runApp(
|
runApp(
|
||||||
ChangeNotifierProvider(
|
ChangeNotifierProvider(
|
||||||
create: (_) => LocaleProvider(),
|
create: (_) => LocaleProvider(),
|
||||||
child: MyApp(),
|
child: MyApp(isLoggedIn: loggedIn),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
|
final bool isLoggedIn;
|
||||||
|
const MyApp({Key? key, required this.isLoggedIn}) : super(key: key);
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final localeProvider = Provider.of<LocaleProvider>(
|
final localeProvider = Provider.of<LocaleProvider>(
|
||||||
@@ -30,7 +37,7 @@ class MyApp extends StatelessWidget {
|
|||||||
locale: localeProvider.locale, // <-- utilise la locale courante
|
locale: localeProvider.locale, // <-- utilise la locale courante
|
||||||
supportedLocales: L10n.all,
|
supportedLocales: L10n.all,
|
||||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||||
home: LoginDemo(),
|
home: isLoggedIn ? ListItemMenu() : LoginDemo(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -380,8 +380,8 @@ class _EditEventState extends State<EditEvent>
|
|||||||
|
|
||||||
imgUrl = widget.events!.imgUrl ?? "";
|
imgUrl = widget.events!.imgUrl ?? "";
|
||||||
inputDesc.text = widget.events!.description ?? "";
|
inputDesc.text = widget.events!.description ?? "";
|
||||||
initialTags = List<String>.from(widget.events!.tags as List);
|
initialTags = List<String>.from((widget.events?.tags as List?) ?? []);
|
||||||
initialOrga = List<String>.from(widget.events!.organizers as List);
|
initialOrga = List<String>.from((widget.events?.organizers as List?) ?? []);
|
||||||
}
|
}
|
||||||
|
|
||||||
final _formKey = GlobalKey<FormState>();
|
final _formKey = GlobalKey<FormState>();
|
||||||
|
@@ -105,6 +105,11 @@ class _MapboxPagesState extends State<MapboxPages> with ShowAlertDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _getUserLocation() async {
|
Future<void> _getUserLocation() async {
|
||||||
|
await dotenv.load(fileName: ".env");
|
||||||
|
|
||||||
|
// Set the access token globally
|
||||||
|
mapbox.MapboxOptions.setAccessToken(
|
||||||
|
dotenv.env['MAPBOX_ACCESS_TOKEN'] ?? '');
|
||||||
try {
|
try {
|
||||||
bool serviceEnabled = await geo.Geolocator.isLocationServiceEnabled();
|
bool serviceEnabled = await geo.Geolocator.isLocationServiceEnabled();
|
||||||
if (!serviceEnabled) return;
|
if (!serviceEnabled) return;
|
||||||
@@ -121,7 +126,7 @@ class _MapboxPagesState extends State<MapboxPages> with ShowAlertDialog {
|
|||||||
setState(() {
|
setState(() {
|
||||||
userPosition = mapbox.Point(
|
userPosition = mapbox.Point(
|
||||||
coordinates:
|
coordinates:
|
||||||
mapbox.Position(position.latitude, position.longitude));
|
mapbox.Position(position.longitude, position.latitude));
|
||||||
isUserPositionInitialized = true;
|
isUserPositionInitialized = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -134,19 +139,70 @@ class _MapboxPagesState extends State<MapboxPages> with ShowAlertDialog {
|
|||||||
Future<void> _fetchRoute(
|
Future<void> _fetchRoute(
|
||||||
mapbox.Point origin, mapbox.Point destination, String mode) async {
|
mapbox.Point origin, mapbox.Point destination, String mode) async {
|
||||||
final url = Uri.parse(
|
final url = Uri.parse(
|
||||||
'https://api.mapbox.com/directions/v5/mapbox/$mode/${origin.coordinates.lng},${origin.coordinates.lat};${destination.coordinates.lng},${destination.coordinates.lat}?geometries=geojson&access_token=${dotenv.env['MAPBOX_ACCESS_TOKEN']}',
|
'https://api.mapbox.com/directions/v5/mapbox/$mode/'
|
||||||
|
'${origin.coordinates.lng},${origin.coordinates.lat};'
|
||||||
|
'${destination.coordinates.lng},${destination.coordinates.lat}'
|
||||||
|
'?geometries=geojson&access_token=${dotenv.env['MAPBOX_ACCESS_TOKEN']}',
|
||||||
);
|
);
|
||||||
|
|
||||||
final response = await http.get(url);
|
final response = await http.get(url);
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
final data = jsonDecode(response.body);
|
final data = jsonDecode(response.body);
|
||||||
|
|
||||||
|
// Vérifie si 'routes' existe et contient au moins 1 élément
|
||||||
|
if (data['routes'] != null && (data['routes'] as List).isNotEmpty) {
|
||||||
final geometry = data['routes'][0]['geometry']['coordinates'];
|
final geometry = data['routes'][0]['geometry']['coordinates'];
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
routeCoordinates = (geometry as List)
|
routeCoordinates = (geometry as List)
|
||||||
.map<List<double>>((coord) => [coord[0], coord[1]])
|
.map<List<double>>((coord) => [coord[0], coord[1]])
|
||||||
.toList();
|
.toList();
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
debugPrint("⚠️ Aucune route trouvée entre ${origin} et $destination.");
|
||||||
|
// Optionnel : afficher un snackbar/toast à l’utilisateur
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
debugPrint("❌ Erreur API Mapbox: ${response.statusCode}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _zoomToFitRoute(List<List<double>> coordinates) async {
|
||||||
|
if (mapboxMap == null || coordinates.isEmpty) return;
|
||||||
|
|
||||||
|
double minLat = coordinates.first[1];
|
||||||
|
double maxLat = coordinates.first[1];
|
||||||
|
double minLng = coordinates.first[0];
|
||||||
|
double maxLng = coordinates.first[0];
|
||||||
|
|
||||||
|
for (var coord in coordinates) {
|
||||||
|
if (coord[1] < minLat) minLat = coord[1];
|
||||||
|
if (coord[1] > maxLat) maxLat = coord[1];
|
||||||
|
if (coord[0] < minLng) minLng = coord[0];
|
||||||
|
if (coord[0] > maxLng) maxLng = coord[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
final bounds = mapbox.CoordinateBounds(
|
||||||
|
southwest: mapbox.Point(coordinates: mapbox.Position(minLng, minLat)),
|
||||||
|
northeast: mapbox.Point(coordinates: mapbox.Position(maxLng, maxLat)),
|
||||||
|
infiniteBounds: true);
|
||||||
|
|
||||||
|
// Calculer une CameraOptions automatiquement à partir des bounds
|
||||||
|
final cameraOptions = await mapboxMap!.cameraForCoordinateBounds(
|
||||||
|
bounds,
|
||||||
|
mapbox.MbxEdgeInsets(
|
||||||
|
top: 50, left: 50, right: 50, bottom: 50), // marges
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
null,
|
||||||
|
null);
|
||||||
|
|
||||||
|
// Appliquer la caméra avec animation
|
||||||
|
await mapboxMap!.flyTo(
|
||||||
|
cameraOptions,
|
||||||
|
mapbox.MapAnimationOptions(duration: 1000),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _drawRouteAndMarkers() async {
|
Future<void> _drawRouteAndMarkers() async {
|
||||||
@@ -175,14 +231,12 @@ class _MapboxPagesState extends State<MapboxPages> with ShowAlertDialog {
|
|||||||
iconSize: 0.4,
|
iconSize: 0.4,
|
||||||
));
|
));
|
||||||
|
|
||||||
// Add event marker
|
// Ajoute directement la flèche rouge à la position de l’événement
|
||||||
final eventIcon = await _loadMarkerImage('images/marker-red.png');
|
final eventIcon = await _loadMarkerImage('images/marker-red.png');
|
||||||
await pointAnnotationManager!.create(mapbox.PointAnnotationOptions(
|
await pointAnnotationManager!.create(mapbox.PointAnnotationOptions(
|
||||||
geometry: mapbox.Point(
|
geometry: mapbox.Point(coordinates: mapbox.Position(longitude, latitude)),
|
||||||
coordinates: mapbox.Position(
|
|
||||||
destination.coordinates.lng, destination.coordinates.lat)),
|
|
||||||
image: eventIcon,
|
image: eventIcon,
|
||||||
iconSize: 0.4,
|
iconSize: 0.2,
|
||||||
));
|
));
|
||||||
|
|
||||||
// Fetch and draw route
|
// Fetch and draw route
|
||||||
@@ -196,6 +250,7 @@ class _MapboxPagesState extends State<MapboxPages> with ShowAlertDialog {
|
|||||||
lineColor: Colors.blue.value,
|
lineColor: Colors.blue.value,
|
||||||
lineWidth: 4.0,
|
lineWidth: 4.0,
|
||||||
));
|
));
|
||||||
|
await _zoomToFitRoute(routeCoordinates);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,9 +266,51 @@ class _MapboxPagesState extends State<MapboxPages> with ShowAlertDialog {
|
|||||||
drawer: MyDrawer(),
|
drawer: MyDrawer(),
|
||||||
body: isLoading
|
body: isLoading
|
||||||
? const Center(child: CircularProgressIndicator())
|
? const Center(child: CircularProgressIndicator())
|
||||||
: mapbox.MapWidget(
|
: Column(
|
||||||
onMapCreated: (controller) {
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
const Text("Mode : "),
|
||||||
|
DropdownButton<String>(
|
||||||
|
value: selectedMode,
|
||||||
|
items: const [
|
||||||
|
DropdownMenuItem(
|
||||||
|
value: 'driving', child: Text("🚗 Voiture")),
|
||||||
|
DropdownMenuItem(
|
||||||
|
value: 'walking', child: Text("🚶 Marche")),
|
||||||
|
DropdownMenuItem(
|
||||||
|
value: 'cycling', child: Text("🚴 Vélo")),
|
||||||
|
],
|
||||||
|
onChanged: (value) {
|
||||||
|
if (value != null) {
|
||||||
|
setState(() {
|
||||||
|
selectedMode = value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: mapbox.MapWidget(
|
||||||
|
onMapCreated: (controller) async {
|
||||||
mapboxMap = controller;
|
mapboxMap = controller;
|
||||||
|
|
||||||
|
// Crée un manager si nécessaire
|
||||||
|
pointAnnotationManager ??= await mapboxMap!.annotations
|
||||||
|
.createPointAnnotationManager();
|
||||||
|
|
||||||
|
// Ajoute directement la flèche rouge à la position de l’événement
|
||||||
|
final eventIcon =
|
||||||
|
await _loadMarkerImage('images/marker-red.png');
|
||||||
|
await pointAnnotationManager!
|
||||||
|
.create(mapbox.PointAnnotationOptions(
|
||||||
|
geometry: mapbox.Point(
|
||||||
|
coordinates: mapbox.Position(longitude, latitude)),
|
||||||
|
image: eventIcon,
|
||||||
|
iconSize: 0.2,
|
||||||
|
));
|
||||||
},
|
},
|
||||||
cameraOptions: mapbox.CameraOptions(
|
cameraOptions: mapbox.CameraOptions(
|
||||||
center: mapbox.Point(
|
center: mapbox.Point(
|
||||||
@@ -221,6 +318,9 @@ class _MapboxPagesState extends State<MapboxPages> with ShowAlertDialog {
|
|||||||
zoom: 14.0,
|
zoom: 14.0,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
floatingActionButton: FloatingActionButton(
|
floatingActionButton: FloatingActionButton(
|
||||||
onPressed: _drawRouteAndMarkers,
|
onPressed: _drawRouteAndMarkers,
|
||||||
child: const Icon(Icons.directions),
|
child: const Icon(Icons.directions),
|
||||||
|
Reference in New Issue
Block a user