ionic-planb-logistic-app-fl.../lib/pages/routes_page.dart
Jean-Philippe Brule 3f31a509e0 Implement premium UI/UX refinements for Apple-like polish
Add three major UI components with animations and dark mode support:

- PremiumRouteCard: Enhanced route cards with left accent bar, delivery count badge, animated hover effects (1.02x scale), and dynamic shadow elevation
- DarkModeMapComponent: Google Maps integration with dark theme styling, custom info panels, navigation buttons, and delivery status indicators
- DeliveryListItem: Animated list items with staggered entrance animations, status badges with icons, contact indicators, and hover states

Updates:
- RoutesPage: Now uses PremiumRouteCard with improved visual hierarchy
- DeliveriesPage: Integrated DarkModeMapComponent and DeliveryListItem with proper theme awareness
- Animation system: Leverages existing AppAnimations constants for 200ms fast interactions and easeOut curves

Design philosophy:
- Element separation through left accent bars (status-coded)
- Elevation and shadow for depth (0.1-0.3 opacity)
- Staggered animations for list items (50ms delays)
- Dark mode optimized for evening use (reduced brightness)
- Responsive hover states with tactile feedback

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-15 14:41:32 -05:00

156 lines
4.8 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 '../utils/responsive.dart';
import '../components/premium_route_card.dart';
import 'deliveries_page.dart';
import 'settings_page.dart';
class RoutesPage extends ConsumerWidget {
const RoutesPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final routesData = ref.watch(deliveryRoutesProvider);
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 RefreshIndicator(
onRefresh: () async {
// ignore: unused_result
ref.refresh(deliveryRoutesProvider);
},
child: context.isDesktop
? _buildDesktopGrid(context, routes)
: _buildMobileList(context, routes),
);
},
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'),
),
],
),
),
),
);
}
Widget _buildMobileList(BuildContext context, List<DeliveryRoute> routes) {
final spacing = ResponsiveSpacing.md(context);
return ListView.builder(
padding: EdgeInsets.all(ResponsiveSpacing.md(context)),
itemCount: routes.length,
itemBuilder: (context, index) {
final route = routes[index];
return Padding(
padding: EdgeInsets.only(bottom: spacing),
child: _buildRouteCard(context, route),
);
},
);
}
Widget _buildDesktopGrid(BuildContext context, List<DeliveryRoute> routes) {
final spacing = ResponsiveSpacing.lg(context);
final columns = context.isTablet ? 2 : 3;
return GridView.builder(
padding: EdgeInsets.all(spacing),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: columns,
crossAxisSpacing: spacing,
mainAxisSpacing: spacing,
childAspectRatio: 1.2,
),
itemCount: routes.length,
itemBuilder: (context, index) {
final route = routes[index];
return _buildRouteCard(context, route);
},
);
}
Widget _buildRouteCard(BuildContext context, DeliveryRoute route) {
return PremiumRouteCard(
route: route,
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => DeliveriesPage(
routeFragmentId: route.id,
routeName: route.name,
),
),
);
},
);
}
}