Initial commit
This commit is contained in:
123
lib/screens/calendario_screen.dart
Normal file
123
lib/screens/calendario_screen.dart
Normal file
@@ -0,0 +1,123 @@
|
||||
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(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user