Files
hackathon-heavy-gears-7cc00…/lib/notificaciones_service.dart
2026-05-23 05:54:34 -06:00

406 lines
15 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'camion_estado.dart';
// ─── INSTANCIA GLOBAL ───────────────────────────────────────────
final FlutterLocalNotificationsPlugin notificationsPlugin =
FlutterLocalNotificationsPlugin();
// ─── INICIALIZAR ────────────────────────────────────────────────
Future<void> initNotifications() async {
const AndroidInitializationSettings androidSettings =
AndroidInitializationSettings('@mipmap/ic_launcher');
const InitializationSettings settings =
InitializationSettings(android: androidSettings);
await notificationsPlugin.initialize(settings);
}
// ─── ENVIAR NOTIFICACIÓN ────────────────────────────────────────
Future<void> enviarNotificacion({
required int id,
required String titulo,
required String cuerpo,
}) async {
const AndroidNotificationDetails androidDetails = AndroidNotificationDetails(
'canal_camion',
'Camión Recolector',
channelDescription: 'Notificaciones del camión recolector',
importance: Importance.max,
priority: Priority.high,
icon: '@mipmap/ic_launcher',
);
const NotificationDetails details =
NotificationDetails(android: androidDetails);
await notificationsPlugin.show(id, titulo, cuerpo, details);
}
// ════════════════════════════════════════════════════════════════
// PANTALLA
// ════════════════════════════════════════════════════════════════
class AlertasNotificacionesScreen extends StatefulWidget {
final bool notificarInicioRuta;
final bool notificarAproximacion;
final bool notificarRetrasosFallas;
const AlertasNotificacionesScreen({
super.key,
required this.notificarInicioRuta,
required this.notificarAproximacion,
required this.notificarRetrasosFallas,
});
@override
State<AlertasNotificacionesScreen> createState() =>
_AlertasNotificacionesScreenState();
}
class _AlertasNotificacionesScreenState
extends State<AlertasNotificacionesScreen> {
late bool notificarInicioRuta;
late bool notificarCamionCerca;
late bool notificarRetrasos;
bool privacidadActiva = true;
@override
void initState() {
super.initState();
notificarInicioRuta = widget.notificarInicioRuta;
notificarCamionCerca = widget.notificarAproximacion;
notificarRetrasos = widget.notificarRetrasosFallas;
// Sincroniza switches con el estado global
camionEstado.notificarInicioRuta = notificarInicioRuta;
camionEstado.notificarCamionCerca = notificarCamionCerca;
camionEstado.notificarRetrasos = notificarRetrasos;
// Escucha cambios del camión para actualizar UI
camionEstado.addListener(_actualizar);
}
void _actualizar() {
if (mounted) setState(() {});
}
@override
void dispose() {
camionEstado.removeListener(_actualizar);
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[100],
appBar: AppBar(
title: const Text('Alertas y Notificaciones'),
backgroundColor: Colors.green,
foregroundColor: Colors.white,
),
body: ListView(
padding: const EdgeInsets.all(16),
children: [
// ── TARJETA SIMULADOR ─────────────────────────────
Card(
elevation: 4,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18),
),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Row(
children: [
Icon(Icons.local_shipping, color: Colors.green, size: 30),
SizedBox(width: 10),
Text(
'Estado del Camión',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
],
),
const SizedBox(height: 20),
// Barra de progreso
ClipRRect(
borderRadius: BorderRadius.circular(8),
child: LinearProgressIndicator(
value: camionEstado.positionId / 8,
minHeight: 12,
backgroundColor: Colors.green[100],
valueColor: const AlwaysStoppedAnimation<Color>(
Colors.green,
),
),
),
const SizedBox(height: 12),
// Etapa actual
Container(
width: double.infinity,
padding: const EdgeInsets.all(14),
decoration: BoxDecoration(
color: Colors.green[50],
borderRadius: BorderRadius.circular(12),
),
child: Text(
CamionEstado.etapas[camionEstado.positionId] ?? '',
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
),
const SizedBox(height: 8),
Text(
'Posición: ${camionEstado.positionId} / 8',
style: TextStyle(color: Colors.grey[600], fontSize: 13),
),
const SizedBox(height: 16),
// Botones — usan el timer global
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'),
),
),
],
),
],
),
),
),
const SizedBox(height: 20),
// ── TARJETA ALERTAS ───────────────────────────────
Card(
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18),
),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Row(
children: [
Icon(Icons.notifications_active,
color: Colors.green, size: 30),
SizedBox(width: 10),
Text(
'Configuración de Alertas',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
],
),
const SizedBox(height: 20),
SwitchListTile(
value: notificarInicioRuta,
activeColor: Colors.green,
title: const Text('Inicio de Ruta'),
subtitle: const Text(
'Recibir aviso cuando el camión inicie su recorrido.',
),
secondary: const Icon(Icons.route),
onChanged: (value) {
setState(() => notificarInicioRuta = value);
camionEstado.notificarInicioRuta = value;
},
),
const Divider(),
SwitchListTile(
value: notificarCamionCerca,
activeColor: Colors.green,
title: const Text('Camión Cercano'),
subtitle: const Text(
'Notificación cuando el camión esté próximo a tu domicilio.',
),
secondary: const Icon(Icons.local_shipping),
onChanged: (value) {
setState(() => notificarCamionCerca = value);
camionEstado.notificarCamionCerca = value;
},
),
const Divider(),
SwitchListTile(
value: notificarRetrasos,
activeColor: Colors.green,
title: const Text('Retrasos o Fallas'),
subtitle: const Text(
'Avisos por tráfico, retrasos o fallas mecánicas.',
),
secondary: const Icon(Icons.warning_amber_rounded),
onChanged: (value) {
setState(() => notificarRetrasos = value);
camionEstado.notificarRetrasos = value;
},
),
],
),
),
),
const SizedBox(height: 20),
// ── TARJETA PRIVACIDAD ────────────────────────────
Card(
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18),
),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Row(
children: [
Icon(Icons.security, color: Colors.redAccent, size: 30),
SizedBox(width: 10),
Text(
'Privacidad y Seguridad',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
],
),
const SizedBox(height: 20),
SwitchListTile(
value: privacidadActiva,
activeColor: Colors.green,
title: const Text('Protección Anti-Snooping'),
subtitle: const Text(
'Impide explorar rutas, domicilios o información de otros usuarios.',
),
secondary: const Icon(Icons.lock_outline),
onChanged: (value) =>
setState(() => privacidadActiva = value),
),
const SizedBox(height: 15),
Container(
padding: const EdgeInsets.all(14),
decoration: BoxDecoration(
color: Colors.green[50],
borderRadius: BorderRadius.circular(12),
),
child: const Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(Icons.verified_user, color: Colors.green),
SizedBox(width: 10),
Expanded(
child: Text(
'El sistema solo mostrará información relacionada con los domicilios registrados por el usuario autenticado.',
style: TextStyle(fontSize: 14),
),
),
],
),
),
],
),
),
),
const SizedBox(height: 25),
// ── BOTÓN GUARDAR ─────────────────────────────────
SizedBox(
height: 55,
child: ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green,
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
),
onPressed: () {
Navigator.pop(context, {
'inicio' : notificarInicioRuta,
'aproximacion': notificarCamionCerca,
'retrasos' : notificarRetrasos,
});
},
icon: const Icon(Icons.save),
label: const Text(
'Guardar Configuración',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
),
),
],
),
);
}
}