11 Commits

Author SHA1 Message Date
5ee053272e Merge pull request 'hotfix/fix-upgrade' (#50) from hotfix/fix-upgrade into main
Reviewed-on: #50
2025-09-05 21:32:28 +00:00
1bb2612de3 add initialOrga as vide 2025-09-05 23:09:20 +02:00
86f81ff009 add marker red 2025-09-04 18:11:12 +02:00
9989aebc32 add zoom after click 2025-09-04 17:26:00 +02:00
35fc1cfa25 add zoomfit 2025-09-04 09:04:24 +02:00
692d55858c add selectecmode 2025-09-02 23:18:46 +02:00
59b16e5131 fix lat lng 2025-09-02 23:05:49 +02:00
89c5e1aa6c fix set mapbox token 2025-09-02 16:32:50 +02:00
f4fb846855 fix login 2025-09-02 14:25:19 +02:00
9a9287bd20 fix permissions 2025-09-02 13:58:39 +02:00
70545052c2 Merge pull request 'feature/notification-date' (#49) from feature/notification-date into main
Reviewed-on: #49
2025-08-27 21:53:17 +00:00
4 changed files with 138 additions and 27 deletions

View File

@@ -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

View File

@@ -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(),
); );
} }
} }

View File

@@ -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>();

View File

@@ -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 à lutilisateur
} }
} 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),