Files
home-control/lib/screens/calendario_screen.dart
2026-06-14 15:03:29 -04:00

124 lines
5.3 KiB
Dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:intl/intl.dart';
import 'package:table_calendar/table_calendar.dart';
import '../providers/factura_provider.dart';
import '../providers/servicio_provider.dart';
import '../providers/configuracion_provider.dart';
class CalendarioScreen extends StatefulWidget {
const CalendarioScreen({super.key});
@override
State<CalendarioScreen> createState() => _CalendarioScreenState();
}
class _CalendarioScreenState extends State<CalendarioScreen> {
DateTime _focusedDay = DateTime.now();
DateTime? _selectedDay;
Map<DateTime, List<Map<String, dynamic>>> _eventos = {};
@override
void initState() {
super.initState();
_cargarEventos();
}
void _cargarEventos() {
final facturaProv = context.read<FacturaProvider>();
final servicioProv = context.read<ServicioProvider>();
facturaProv.cargarFacturas().then((_) {
_construirEventos(facturaProv, servicioProv);
});
}
void _construirEventos(FacturaProvider facturaProv, ServicioProvider servicioProv) {
final eventos = <DateTime, List<Map<String, dynamic>>>{};
for (final f in facturaProv.facturas) {
final fecha = DateTime.tryParse(f.fechaVencimiento);
if (fecha == null) continue;
final servicio = servicioProv.servicios.where((s) => s.id == f.servicioId).firstOrNull;
final day = DateTime(fecha.year, fecha.month, fecha.day);
eventos.putIfAbsent(day, () => []).add({
'servicio': servicio?.nombre ?? 'Desconocido',
'monto': f.monto,
'estado': f.estado,
'color': Color(servicio?.color ?? 0xFF6200EE),
});
}
setState(() => _eventos = eventos);
}
@override
Widget build(BuildContext context) {
context.watch<FacturaProvider>();
context.watch<ServicioProvider>();
final configProv = context.watch<ConfiguracionProvider>();
final symbol = configProv.config?.moneda == 'USD' ? '\$' : configProv.config?.moneda == 'EUR' ? '' : 'MX\$';
return Scaffold(
appBar: AppBar(title: const Text('Calendario de pagos')),
body: Column(
children: [
TableCalendar(
firstDay: DateTime(2024),
lastDay: DateTime(2035),
focusedDay: _focusedDay,
selectedDayPredicate: (day) => isSameDay(_selectedDay, day),
eventLoader: (day) {
final d = DateTime(day.year, day.month, day.day);
return _eventos[d] ?? [];
},
calendarStyle: CalendarStyle(
todayDecoration: BoxDecoration(color: Theme.of(context).colorScheme.primary.withValues(alpha: 0.5), shape: BoxShape.circle),
selectedDecoration: BoxDecoration(color: Theme.of(context).colorScheme.primary, shape: BoxShape.circle),
markerDecoration: BoxDecoration(color: Theme.of(context).colorScheme.secondary, shape: BoxShape.circle),
),
headerStyle: const HeaderStyle(formatButtonVisible: false, titleCentered: true),
onDaySelected: (selected, focused) {
setState(() {
_selectedDay = selected;
_focusedDay = focused;
});
},
onPageChanged: (focused) => _focusedDay = focused,
calendarBuilders: CalendarBuilders(
markerBuilder: (context, date, events) {
if (events.isEmpty) return null;
final pendientes = events.where((e) => (e as Map)['estado'] == 'Pendiente').length;
final pagadas = events.where((e) => (e as Map)['estado'] == 'Pagada').length;
return Row(
mainAxisSize: MainAxisSize.min,
children: [
if (pendientes > 0)
Container(margin: const EdgeInsets.only(right: 2), width: 6, height: 6, decoration: BoxDecoration(color: Colors.red, shape: BoxShape.circle)),
if (pagadas > 0)
Container(width: 6, height: 6, decoration: BoxDecoration(color: Colors.green, shape: BoxShape.circle)),
],
);
},
),
),
const Divider(),
Expanded(
child: _selectedDay == null || (_eventos[DateTime(_selectedDay!.year, _selectedDay!.month, _selectedDay!.day)]?.isEmpty ?? true)
? Center(child: Text('Sin facturas en esta fecha', style: Theme.of(context).textTheme.bodyLarge))
: ListView(
children: (_eventos[DateTime(_selectedDay!.year, _selectedDay!.month, _selectedDay!.day)] ?? []).map((e) {
return Card(
child: ListTile(
leading: CircleAvatar(backgroundColor: e['color'] as Color, child: Text((e['servicio'] as String).substring(0, 2).toUpperCase(), style: const TextStyle(color: Colors.white, fontSize: 12))),
title: Text(e['servicio'] as String),
subtitle: Text('$symbol${NumberFormat('#,##0.00').format(e['monto'])}'),
trailing: Chip(label: Text(e['estado'] as String, style: TextStyle(fontSize: 12, color: e['estado'] == 'Pagada' ? Colors.green : Colors.orange))),
),
);
}).toList(),
),
),
],
),
);
}
}