Actualizacion del programa

This commit is contained in:
2026-05-23 01:40:39 -06:00
parent 458af32fcf
commit c6a1a67469
132 changed files with 11009 additions and 168 deletions

View File

@@ -0,0 +1,127 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../core/app_colors.dart';
import '../../database/db_helper.dart';
import '../../services/auth_service.dart';
class NotificationHistoryScreen extends StatefulWidget {
const NotificationHistoryScreen({super.key});
@override State<NotificationHistoryScreen> createState() => _NotificationHistoryScreenState();
}
class _NotificationHistoryScreenState extends State<NotificationHistoryScreen> {
List<Map<String, dynamic>> _notifs = [];
bool _loading = true;
@override
void initState() { super.initState(); _load(); }
Future<void> _load() async {
final auth = context.read<AuthService>();
if (auth.currentUser == null) return;
final n = await DbHelper.getNotifHistory(auth.currentUser!.id!);
await DbHelper.markAllNotifsRead(auth.currentUser!.id!);
if (mounted) setState(() { _notifs = n; _loading = false; });
}
Color _color(String type) {
switch (type) {
case 'truckProximity':
case 'truckApproaching15min': return AppColors.naranjaAlerta;
case 'routeCompleted':
case 'reviewPrompt': return AppColors.verdeExito;
case 'routeCancelled': return AppColors.rojoError;
case 'gpsLost': return Colors.red.shade800;
case 'truckStopped': return AppColors.naranjaAlerta;
default: return AppColors.azulInfo;
}
}
IconData _icon(String type) {
switch (type) {
case 'truckProximity':
case 'truckApproaching15min': return Icons.warning_amber_rounded;
case 'routeCompleted': return Icons.check_circle;
case 'reviewPrompt': return Icons.star;
case 'routeCancelled': return Icons.cancel;
case 'gpsLost': return Icons.gps_off;
default: return Icons.notifications;
}
}
String _timeAgo(String fechaStr) {
final f = DateTime.tryParse(fechaStr);
if (f == null) return '';
final diff = DateTime.now().difference(f);
if (diff.inMinutes < 1) return 'Ahora';
if (diff.inMinutes < 60) return 'Hace ${diff.inMinutes} min';
if (diff.inHours < 24) return 'Hace ${diff.inHours}h';
return '${f.day}/${f.month}/${f.year}';
}
@override
Widget build(BuildContext context) => Scaffold(
backgroundColor: AppColors.grisFondo,
appBar: AppBar(
backgroundColor: AppColors.guindaPrimary, foregroundColor: Colors.white,
title: const Text('Historial de Alertas'),
bottom: PreferredSize(preferredSize: const Size.fromHeight(4),
child: Container(height: 4, color: AppColors.dorado)),
actions: [
TextButton(
onPressed: () async {
await DbHelper.markAllNotifsRead(
context.read<AuthService>().currentUser!.id!);
setState(() {});
},
child: const Text('Marcar leídas', style: TextStyle(color: AppColors.dorado, fontSize: 12)),
),
],
),
body: _loading
? const Center(child: CircularProgressIndicator())
: _notifs.isEmpty
? Center(child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
Icon(Icons.notifications_none, color: Colors.grey.shade400, size: 64),
const SizedBox(height: 12),
Text('Sin alertas registradas', style: TextStyle(color: Colors.grey.shade500)),
]))
: ListView.builder(
padding: const EdgeInsets.all(12),
itemCount: _notifs.length,
itemBuilder: (_, i) {
final n = _notifs[i];
final isUnread = (n['leida'] as int?) == 0;
final color = _color(n['event_type'] ?? '');
return Container(
margin: const EdgeInsets.only(bottom: 8),
decoration: BoxDecoration(
color: isUnread ? color.withOpacity(0.05) : Colors.white,
borderRadius: BorderRadius.circular(10),
border: Border.all(
color: isUnread ? color.withOpacity(0.3) : Colors.grey.shade200),
),
child: ListTile(
leading: CircleAvatar(
backgroundColor: color.withOpacity(0.15),
child: Icon(_icon(n['event_type'] ?? ''), color: color, size: 20),
),
title: Text(n['title'] ?? '', style: TextStyle(
fontWeight: isUnread ? FontWeight.bold : FontWeight.normal,
fontSize: 13)),
subtitle: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Text(n['body'] ?? '', style: const TextStyle(fontSize: 11), maxLines: 2,
overflow: TextOverflow.ellipsis),
const SizedBox(height: 2),
Text('${n['route_id']} · ${_timeAgo(n['fecha'] ?? '')}',
style: TextStyle(fontSize: 10, color: color.withOpacity(0.7))),
]),
trailing: isUnread
? Container(width: 8, height: 8,
decoration: BoxDecoration(color: color, shape: BoxShape.circle))
: null,
),
);
}),
);
}