Changed RoutesPage from ConsumerWidget to ConsumerStatefulWidget to request location permission when app launches. Permission is requested silently without blocking UI and silently logged on grant/denial. Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
215 lines
7.0 KiB
Dart
215 lines
7.0 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import '../models/delivery_route.dart';
|
|
import '../providers/providers.dart';
|
|
import '../utils/breakpoints.dart';
|
|
import '../components/collapsible_routes_sidebar.dart';
|
|
import '../components/dark_mode_map.dart';
|
|
import '../services/location_permission_service.dart';
|
|
import 'deliveries_page.dart';
|
|
import 'settings_page.dart';
|
|
|
|
class RoutesPage extends ConsumerStatefulWidget {
|
|
const RoutesPage({super.key});
|
|
|
|
@override
|
|
ConsumerState<RoutesPage> createState() => _RoutesPageState();
|
|
}
|
|
|
|
class _RoutesPageState extends ConsumerState<RoutesPage> {
|
|
late LocationPermissionService _permissionService;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_permissionService = LocationPermissionService();
|
|
_requestLocationPermissionOnce();
|
|
}
|
|
|
|
Future<void> _requestLocationPermissionOnce() async {
|
|
try {
|
|
final hasPermission = await _permissionService.hasLocationPermission();
|
|
if (!hasPermission && mounted) {
|
|
final result = await _permissionService.requestLocationPermission();
|
|
result.when(
|
|
granted: () {
|
|
debugPrint('Location permission granted');
|
|
},
|
|
denied: () {
|
|
debugPrint('Location permission denied');
|
|
},
|
|
permanentlyDenied: () {
|
|
debugPrint('Location permission permanently denied');
|
|
},
|
|
error: (message) {
|
|
debugPrint('Location permission error: $message');
|
|
},
|
|
);
|
|
}
|
|
} catch (e) {
|
|
debugPrint('Error requesting location permission: $e');
|
|
}
|
|
}
|
|
|
|
void _navigateToDeliveries(BuildContext context, DeliveryRoute route) {
|
|
Navigator.of(context).push(
|
|
MaterialPageRoute(
|
|
builder: (context) => DeliveriesPage(
|
|
routeFragmentId: route.id,
|
|
routeName: route.name,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
final routesData = ref.watch(deliveryRoutesProvider);
|
|
final allDeliveriesData = ref.watch(allDeliveriesProvider);
|
|
final userProfile = ref.watch(userProfileProvider);
|
|
|
|
return Scaffold(
|
|
appBar: AppBar(
|
|
title: const Text('Delivery Routes'),
|
|
elevation: 0,
|
|
actions: [
|
|
userProfile.when(
|
|
data: (profile) => PopupMenuButton<String>(
|
|
onSelected: (value) {
|
|
if (value == 'settings') {
|
|
Navigator.of(context).push(
|
|
MaterialPageRoute(
|
|
builder: (context) => const SettingsPage(),
|
|
),
|
|
);
|
|
}
|
|
},
|
|
itemBuilder: (BuildContext context) => [
|
|
PopupMenuItem(
|
|
value: 'profile',
|
|
child: Text(profile?.fullName ?? 'User'),
|
|
enabled: false,
|
|
),
|
|
const PopupMenuDivider(),
|
|
const PopupMenuItem(
|
|
value: 'settings',
|
|
child: Text('Settings'),
|
|
),
|
|
],
|
|
child: Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
|
child: Center(
|
|
child: Text(
|
|
profile?.fullName ?? 'User',
|
|
style: Theme.of(context).textTheme.titleSmall,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
loading: () => const Padding(
|
|
padding: EdgeInsets.all(16.0),
|
|
child: SizedBox(
|
|
width: 16,
|
|
height: 16,
|
|
child: CircularProgressIndicator(strokeWidth: 2),
|
|
),
|
|
),
|
|
error: (error, stackTrace) => const SizedBox(),
|
|
),
|
|
],
|
|
),
|
|
body: routesData.when(
|
|
data: (routes) {
|
|
if (routes.isEmpty) {
|
|
return const Center(
|
|
child: Text('No routes available'),
|
|
);
|
|
}
|
|
return allDeliveriesData.when(
|
|
data: (allDeliveries) {
|
|
return RefreshIndicator(
|
|
onRefresh: () async {
|
|
// ignore: unused_result
|
|
ref.refresh(deliveryRoutesProvider);
|
|
// ignore: unused_result
|
|
ref.refresh(allDeliveriesProvider);
|
|
},
|
|
child: context.isDesktop
|
|
? Row(
|
|
children: [
|
|
Expanded(
|
|
child: DarkModeMapComponent(
|
|
deliveries: allDeliveries,
|
|
selectedDelivery: null,
|
|
onDeliverySelected: null,
|
|
),
|
|
),
|
|
CollapsibleRoutesSidebar(
|
|
routes: routes,
|
|
selectedRoute: null,
|
|
onRouteSelected: (route) {
|
|
_navigateToDeliveries(context, route);
|
|
},
|
|
),
|
|
],
|
|
)
|
|
: Column(
|
|
children: [
|
|
Expanded(
|
|
child: DarkModeMapComponent(
|
|
deliveries: allDeliveries,
|
|
selectedDelivery: null,
|
|
onDeliverySelected: null,
|
|
),
|
|
),
|
|
CollapsibleRoutesSidebar(
|
|
routes: routes,
|
|
selectedRoute: null,
|
|
onRouteSelected: (route) {
|
|
_navigateToDeliveries(context, route);
|
|
},
|
|
),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
loading: () => const Center(
|
|
child: CircularProgressIndicator(),
|
|
),
|
|
error: (error, stackTrace) => Center(
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Text('Error loading deliveries: $error'),
|
|
const SizedBox(height: 16),
|
|
ElevatedButton(
|
|
onPressed: () => ref.refresh(allDeliveriesProvider),
|
|
child: const Text('Retry'),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
},
|
|
loading: () => const Center(
|
|
child: CircularProgressIndicator(),
|
|
),
|
|
error: (error, stackTrace) => Center(
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Text('Error: $error'),
|
|
const SizedBox(height: 16),
|
|
ElevatedButton(
|
|
onPressed: () => ref.refresh(deliveryRoutesProvider),
|
|
child: const Text('Retry'),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
}
|