- Servicio: nuevo campo esRecurrente + migración DB v2 - Al marcar pagada una factura recurrente se genera la siguiente - Editar facturas existentes desde CrearFacturaScreen - Nuevo método actualizarFactura en FacturaProvider - padding inferior en listas de facturas y servicios (último item visible) - Nota de factura visible en subtítulo - Filtro Vencidas corregido - Monto pendiente total visible en dashboard - Botón undo para revertir factura pagada - Configuración de release signing (keystore) - Pantalla de política de privacidad en la app + PRIVACY_POLICY.md
104 lines
3.8 KiB
Dart
104 lines
3.8 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:provider/provider.dart';
|
|
import '../models/configuracion.dart';
|
|
import '../providers/configuracion_provider.dart';
|
|
import '../utils/currency_utils.dart';
|
|
import 'privacy_policy_screen.dart';
|
|
|
|
class ConfiguracionScreen extends StatefulWidget {
|
|
const ConfiguracionScreen({super.key});
|
|
|
|
@override
|
|
State<ConfiguracionScreen> createState() => _ConfiguracionScreenState();
|
|
}
|
|
|
|
class _ConfiguracionScreenState extends State<ConfiguracionScreen> {
|
|
late List<bool> _diasSeleccionados;
|
|
late String _moneda;
|
|
|
|
final List<Map<String, dynamic>> _opcionesDias = [
|
|
{'label': '7 días antes', 'value': 7},
|
|
{'label': '3 días antes', 'value': 3},
|
|
{'label': '1 día antes', 'value': 1},
|
|
{'label': 'Día de vencimiento', 'value': 0},
|
|
];
|
|
|
|
final List<CurrencyInfo> _monedas = CurrencyUtils.allCurrencies;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
final config = context.read<ConfiguracionProvider>().config;
|
|
final dias = config?.diasRecordatorio ?? '7,3,1,0';
|
|
final lista = dias.split(',').map((e) => int.tryParse(e.trim()) ?? 0).toList();
|
|
_diasSeleccionados = _opcionesDias.map((o) => lista.contains(o['value'])).toList();
|
|
_moneda = config?.moneda ?? 'USD';
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final provider = context.read<ConfiguracionProvider>();
|
|
|
|
return Scaffold(
|
|
appBar: AppBar(title: const Text('Configuración')),
|
|
body: ListView(
|
|
padding: const EdgeInsets.all(16),
|
|
children: [
|
|
Text('Recordatorios', style: Theme.of(context).textTheme.titleMedium),
|
|
const SizedBox(height: 8),
|
|
...List.generate(_opcionesDias.length, (i) {
|
|
return CheckboxListTile(
|
|
title: Text(_opcionesDias[i]['label'] as String),
|
|
value: _diasSeleccionados[i],
|
|
onChanged: (v) {
|
|
setState(() => _diasSeleccionados[i] = v ?? false);
|
|
},
|
|
);
|
|
}),
|
|
const SizedBox(height: 20),
|
|
Text('Moneda', style: Theme.of(context).textTheme.titleMedium),
|
|
const SizedBox(height: 8),
|
|
DropdownButtonFormField<String>(
|
|
value: _moneda,
|
|
decoration: const InputDecoration(border: OutlineInputBorder()),
|
|
items: _monedas.map((m) => DropdownMenuItem(value: m.code, child: Text(CurrencyUtils.getDisplayName(m.code)))).toList(),
|
|
onChanged: (v) => setState(() => _moneda = v!),
|
|
),
|
|
const SizedBox(height: 32),
|
|
const SizedBox(height: 16),
|
|
ListTile(
|
|
leading: const Icon(Icons.privacy_tip_outlined),
|
|
title: const Text('Política de privacidad'),
|
|
trailing: const Icon(Icons.chevron_right),
|
|
onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => const PrivacyPolicyScreen())),
|
|
),
|
|
const SizedBox(height: 16),
|
|
FilledButton(
|
|
onPressed: () async {
|
|
final diasStr = _opcionesDias
|
|
.asMap()
|
|
.entries
|
|
.where((e) => _diasSeleccionados[e.key])
|
|
.map((e) => e.value['value'].toString())
|
|
.join(',');
|
|
final config = Configuracion(
|
|
id: provider.config?.id,
|
|
diasRecordatorio: diasStr.isEmpty ? '0' : diasStr,
|
|
tema: provider.config?.tema ?? 'claro',
|
|
moneda: _moneda,
|
|
);
|
|
await provider.guardarConfiguracion(config);
|
|
if (context.mounted) {
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
const SnackBar(content: Text('Configuración guardada')),
|
|
);
|
|
}
|
|
},
|
|
child: const Text('Guardar configuración'),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|