modificaciones en el sistema
This commit is contained in:
@@ -1,112 +1,194 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'camion_estado.dart';
|
||||
|
||||
class TarjetaEtaWidget extends StatelessWidget {
|
||||
final String horaInicio;
|
||||
final String horaFin;
|
||||
final int minutosRestantes;
|
||||
final String estadoCamion;
|
||||
class TarjetaEtaWidget extends StatefulWidget {
|
||||
const TarjetaEtaWidget({super.key});
|
||||
|
||||
const TarjetaEtaWidget({
|
||||
super.key,
|
||||
required this.horaInicio,
|
||||
required this.horaFin,
|
||||
required this.minutosRestantes,
|
||||
required this.estadoCamion,
|
||||
});
|
||||
@override
|
||||
State<TarjetaEtaWidget> createState() => _TarjetaEtaWidgetState();
|
||||
}
|
||||
|
||||
Color _obtenerColorEstado() {
|
||||
return estadoCamion == 'retrasado' ? Colors.amber[700]! : Colors.green[700]!;
|
||||
class _TarjetaEtaWidgetState extends State<TarjetaEtaWidget> {
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
// Escucha cambios del estado global
|
||||
camionEstado.addListener(_actualizar);
|
||||
}
|
||||
|
||||
String _generarMensajeAccion() {
|
||||
if (estadoCamion == 'retrasado') {
|
||||
return 'El servicio presenta un ligero retraso por tráfico.';
|
||||
}
|
||||
if (minutosRestantes <= 5) {
|
||||
return '¡Saca tus residuos clasificados ahora mismo!';
|
||||
}
|
||||
return 'Prepara tus bolsas de residuos orgánicos e inorgánicos.';
|
||||
void _actualizar() {
|
||||
if (mounted) setState(() {});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
camionEstado.removeListener(_actualizar);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
// Color según etapa
|
||||
Color _colorEstado() {
|
||||
final id = camionEstado.positionId;
|
||||
if (id <= 1) return Colors.grey;
|
||||
if (id <= 3) return Colors.blue;
|
||||
if (id <= 5) return Colors.orange;
|
||||
if (id == 6) return Colors.green;
|
||||
return Colors.grey;
|
||||
}
|
||||
|
||||
// Icono según etapa
|
||||
IconData _iconoEstado() {
|
||||
final id = camionEstado.positionId;
|
||||
if (id <= 1) return Icons.schedule;
|
||||
if (id <= 3) return Icons.local_shipping;
|
||||
if (id <= 5) return Icons.directions_run;
|
||||
if (id == 6) return Icons.check_circle;
|
||||
return Icons.done_all;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final Color colorTema = _obtenerColorEstado();
|
||||
final id = camionEstado.positionId;
|
||||
final eta = CamionEstado.etaInfo[id]!;
|
||||
final etapa = CamionEstado.etapas[id]!;
|
||||
final color = _colorEstado();
|
||||
final minutos = eta['minutos'] as int;
|
||||
final label = eta['label'] as String;
|
||||
|
||||
return Card(
|
||||
elevation: 3,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [
|
||||
colorTema.withOpacity(0.05),
|
||||
colorTema.withOpacity(0.12),
|
||||
],
|
||||
),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Icon(Icons.local_shipping_rounded, color: colorTema, size: 24),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
estadoCamion == 'retrasado' ? 'Estado: Demorado' : 'Ruta en Progreso',
|
||||
style: TextStyle(
|
||||
color: colorTema,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 13,
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
Container(
|
||||
width: 8,
|
||||
height: 8,
|
||||
decoration: BoxDecoration(color: colorTema, shape: BoxShape.circle),
|
||||
),
|
||||
],
|
||||
elevation: 5,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: Column(
|
||||
children: [
|
||||
|
||||
// Icono animado según estado
|
||||
Icon(
|
||||
_iconoEstado(),
|
||||
size: 80,
|
||||
color: color,
|
||||
),
|
||||
|
||||
const SizedBox(height: 12),
|
||||
|
||||
const Text(
|
||||
'Camión de Recolección',
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
),
|
||||
|
||||
const SizedBox(height: 8),
|
||||
|
||||
// Etapa actual
|
||||
Text(
|
||||
etapa,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
color: color,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 8),
|
||||
|
||||
// Hora estimada
|
||||
if (id > 1 && id < 7)
|
||||
Text(
|
||||
'Llega en aproximadamente $minutosRestantes minutos',
|
||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||
'Llegará entre ${eta['horaInicio']} y ${eta['horaFin']}',
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(fontSize: 14, color: Colors.grey),
|
||||
),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Barra de progreso
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: LinearProgressIndicator(
|
||||
value: id / 8,
|
||||
minHeight: 10,
|
||||
backgroundColor: Colors.grey[200],
|
||||
valueColor: AlwaysStoppedAnimation<Color>(color),
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 12),
|
||||
|
||||
// Badge de minutos
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 20,
|
||||
vertical: 12,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: color.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
border: Border.all(color: color.withOpacity(0.3)),
|
||||
),
|
||||
child: Text(
|
||||
minutos > 0
|
||||
? 'Llega en aproximadamente $minutos minutos'
|
||||
: label,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: color,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.grey[800],
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'El camión llegará a tu zona entre las $horaInicio y las $horaFin.',
|
||||
style: TextStyle(fontSize: 14, color: Colors.grey[700]),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 10.0),
|
||||
child: Divider(color: Colors.black),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Icon(Icons.info_outline_rounded, color: colorTema, size: 18),
|
||||
const SizedBox(width: 6),
|
||||
Expanded(
|
||||
child: Text(
|
||||
_generarMensajeAccion(),
|
||||
style: TextStyle(
|
||||
color: colorTema,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 12,
|
||||
),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Botones iniciar / reiniciar
|
||||
Row(
|
||||
children: [
|
||||
|
||||
Expanded(
|
||||
child: ElevatedButton.icon(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: camionEstado.corriendo
|
||||
? Colors.grey
|
||||
: Colors.green,
|
||||
foregroundColor: Colors.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
),
|
||||
onPressed: camionEstado.corriendo
|
||||
? null
|
||||
: camionEstado.iniciarTimer,
|
||||
icon: const Icon(Icons.play_arrow),
|
||||
label: const Text('Iniciar'),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(width: 12),
|
||||
|
||||
Expanded(
|
||||
child: OutlinedButton.icon(
|
||||
style: OutlinedButton.styleFrom(
|
||||
foregroundColor: Colors.green,
|
||||
side: const BorderSide(color: Colors.green),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
),
|
||||
onPressed: camionEstado.reiniciar,
|
||||
icon: const Icon(Icons.refresh),
|
||||
label: const Text('Reiniciar'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user