Files
hackathon-acapulquitos-boys…/lib/features/routes/presentation/widgets/eta_card.dart

225 lines
6.1 KiB
Dart

// lib/features/routes/presentation/widgets/eta_card.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../providers/routes_provider.dart';
import '../../data/repositories/routes_repository.dart';
class ETACard extends ConsumerWidget {
final String routeId;
final double userLat;
final double userLng;
const ETACard({
super.key,
required this.routeId,
required this.userLat,
required this.userLng,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
final etaAsync = ref.watch(
etaProvider((routeId: routeId, lat: userLat, lng: userLng)),
);
return etaAsync.when(
loading: () => const _ETACardSkeleton(),
error: (e, _) => _ETACardError(error: e.toString()),
data: (eta) => _ETACardContent(eta: eta),
);
}
}
class _ETACardContent extends StatelessWidget {
final ETAResult eta;
const _ETACardContent({required this.eta});
@override
Widget build(BuildContext context) {
final color = _colorPorETA(eta.etaMinutos);
return Card(
elevation: 4,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header con ruta
Row(
children: [
Icon(Icons.local_shipping, color: color, size: 28),
const SizedBox(width: 12),
Expanded(
child: Text(
eta.routeName,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
),
_StatusChip(etaMinutos: eta.etaMinutos),
],
),
const SizedBox(height: 20),
// Ventana horaria — el "túnel" de privacidad
Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 20),
decoration: BoxDecoration(
color: color.withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: color.withOpacity(0.3)),
),
child: Column(
children: [
Text(
eta.ventana,
style: TextStyle(
fontSize: 28,
fontWeight: FontWeight.w800,
color: color,
letterSpacing: 1,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 4),
Text(
'Ventana de llegada estimada',
style: TextStyle(
fontSize: 12,
color: Colors.grey[600],
),
),
],
),
),
const SizedBox(height: 16),
// Mensaje accionable
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(
Icons.info_outline,
size: 18,
color: Colors.grey[600],
),
const SizedBox(width: 8),
Expanded(
child: Text(
eta.mensaje,
style: TextStyle(
fontSize: 13,
color: Colors.grey[700],
),
),
),
],
),
const SizedBox(height: 12),
// Badge de privacidad
Row(
children: [
Icon(Icons.lock_outline, size: 14, color: Colors.grey[500]),
const SizedBox(width: 4),
Text(
'No compartimos tu ubicación exacta',
style: TextStyle(fontSize: 11, color: Colors.grey[500]),
),
],
),
],
),
),
);
}
Color _colorPorETA(int minutos) {
if (minutos <= 5) return Colors.red;
if (minutos <= 15) return Colors.orange;
return const Color(0xFF1B5E20);
}
}
class _StatusChip extends StatelessWidget {
final int etaMinutos;
const _StatusChip({required this.etaMinutos});
@override
Widget build(BuildContext context) {
final (label, color) = switch (etaMinutos) {
<= 0 => ('Llegando', Colors.red),
<= 10 => ('¡Pronto!', Colors.orange),
_ => ('En camino', const Color(0xFF2E7D32)),
};
return Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
decoration: BoxDecoration(
color: color.withOpacity(0.1),
borderRadius: BorderRadius.circular(20),
border: Border.all(color: color.withOpacity(0.4)),
),
child: Text(
label,
style: TextStyle(
fontSize: 12,
color: color,
fontWeight: FontWeight.w600,
),
),
);
}
}
class _ETACardSkeleton extends StatelessWidget {
const _ETACardSkeleton();
@override
Widget build(BuildContext context) {
return const Card(
child: Padding(
padding: EdgeInsets.all(20),
child: Center(
child: CircularProgressIndicator(),
),
),
);
}
}
class _ETACardError extends StatelessWidget {
final String error;
const _ETACardError({required this.error});
@override
Widget build(BuildContext context) {
return Card(
child: Padding(
padding: const EdgeInsets.all(20),
child: Row(
children: [
const Icon(Icons.error_outline, color: Colors.red),
const SizedBox(width: 12),
Expanded(
child: Text(
'No se pudo calcular el ETA: $error',
style: const TextStyle(color: Colors.red, fontSize: 13),
),
),
],
),
),
);
}
}