Files
SIB/old/lib/widgets/route_selection_bottom_sheet.dart

285 lines
9.6 KiB
Dart

import 'package:flutter/material.dart';
import '../services/app_state_service.dart';
class RouteSelectionBottomSheet extends StatefulWidget {
final String title;
final VoidCallback? onRouteChanged;
const RouteSelectionBottomSheet({
super.key,
this.title = 'Seleccionar Ruta',
this.onRouteChanged,
});
@override
State<RouteSelectionBottomSheet> createState() =>
_RouteSelectionBottomSheetState();
}
class _RouteSelectionBottomSheetState extends State<RouteSelectionBottomSheet> {
final AppStateService _appStateService = AppStateService();
bool _isRefreshing = false;
@override
void initState() {
super.initState();
_appStateService.addListener(_onStateChanged);
}
@override
void dispose() {
_appStateService.removeListener(_onStateChanged);
super.dispose();
}
void _onStateChanged() {
if (mounted) {
setState(() {});
}
}
Future<void> _onRouteSelected(String routeId) async {
try {
await _appStateService.selectRoute(routeId);
// Notify parent widget that route changed
widget.onRouteChanged?.call();
if (mounted) {
Navigator.pop(context);
// Show success message
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content:
Text('Ruta cambiada: ${_appStateService.selectedRouteName}'),
backgroundColor: Colors.green,
duration: const Duration(seconds: 2),
),
);
}
} catch (e) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Error seleccionando ruta: $e'),
backgroundColor: Colors.red,
duration: const Duration(seconds: 3),
),
);
}
}
}
Future<void> _refreshRoutes() async {
setState(() {
_isRefreshing = true;
});
try {
await _appStateService.refreshRoutes();
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Rutas actualizadas'),
backgroundColor: Colors.green,
duration: Duration(seconds: 2),
),
);
}
} catch (e) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Error actualizando rutas: $e'),
backgroundColor: Colors.red,
duration: const Duration(seconds: 3),
),
);
}
} finally {
if (mounted) {
setState(() {
_isRefreshing = false;
});
}
}
}
@override
Widget build(BuildContext context) {
final routes = _appStateService.allRoutes;
final selectedRouteId = _appStateService.selectedRouteId;
final isLoading = _appStateService.isLoadingRoutes || _isRefreshing;
final error = _appStateService.error;
return Container(
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
),
child: SafeArea(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// Handle
Container(
width: 40,
height: 4,
margin: const EdgeInsets.symmetric(vertical: 12),
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(2),
),
),
// Header
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Row(
children: [
Expanded(
child: Text(
widget.title,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Color(0xFF101820),
),
),
),
IconButton(
onPressed: _refreshRoutes,
icon: Icon(
Icons.refresh,
color: isLoading ? Colors.grey : const Color(0xFF101820),
),
),
],
),
),
const SizedBox(height: 16),
// Content
Flexible(
child: isLoading
? const Center(
child: Padding(
padding: EdgeInsets.all(40),
child: CircularProgressIndicator(
valueColor:
AlwaysStoppedAnimation<Color>(Color(0xFFFEE715)),
),
),
)
: error != null
? Padding(
padding: const EdgeInsets.all(20),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.error_outline,
color: Colors.red[600],
size: 48,
),
const SizedBox(height: 16),
Text(
error,
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.red[600],
fontSize: 16,
),
),
const SizedBox(height: 16),
ElevatedButton.icon(
onPressed: _refreshRoutes,
icon: const Icon(Icons.refresh),
label: const Text('Reintentar'),
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFFEE715),
foregroundColor: const Color(0xFF101820),
),
),
],
),
)
: routes.isEmpty
? const Padding(
padding: EdgeInsets.all(40),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.route_outlined,
color: Colors.grey,
size: 48,
),
SizedBox(height: 16),
Text(
'No hay rutas disponibles',
style: TextStyle(
fontSize: 16,
color: Colors.grey,
),
),
],
),
)
: ListView.builder(
shrinkWrap: true,
itemCount: routes.length,
itemBuilder: (context, index) {
final route = routes[index];
final isSelected = selectedRouteId == route.id;
return ListTile(
leading: Container(
width: 12,
height: 12,
decoration: BoxDecoration(
color: Color(int.parse(route.color
.replaceFirst('#', '0xFF'))),
shape: BoxShape.circle,
),
),
title: Text(
route.displayName,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
subtitle: route.direction.isNotEmpty
? Text(
route.direction,
style: TextStyle(
fontSize: 14,
color: Colors.grey[600],
),
)
: null,
trailing: isSelected
? const Icon(
Icons.check_circle,
color: Color(0xFFFEE715),
)
: null,
onTap: () => _onRouteSelected(route.id),
);
},
),
),
const SizedBox(height: 16),
],
),
),
);
}
}