128 lines
5.4 KiB
Dart
128 lines
5.4 KiB
Dart
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,
|
|
),
|
|
);
|
|
}),
|
|
);
|
|
}
|