feat(app): add onboarding and harden alarms
This commit is contained in:
+228
-126
@@ -1,4 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../estado/estado_alarmas.dart';
|
||||
@@ -58,7 +58,10 @@ class PantallaAlarmas extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _abrirEditor(BuildContext context, {AlarmaMusical? alarma}) async {
|
||||
Future<void> _abrirEditor(
|
||||
BuildContext context, {
|
||||
AlarmaMusical? alarma,
|
||||
}) async {
|
||||
await showModalBottomSheet<void>(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
@@ -77,6 +80,10 @@ class _PanelProximaAlarma extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final proxima = estado.proximaAlarma;
|
||||
final activasSinProxima =
|
||||
estado.alarmas
|
||||
.where((a) => a.activa && a.proximaEjecucion == null)
|
||||
.length;
|
||||
return PluriGlassSurface(
|
||||
glowColor: const Color(0xFFFFB86B).withValues(alpha: 0.28),
|
||||
child: Row(
|
||||
@@ -88,7 +95,11 @@ class _PanelProximaAlarma extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
proxima == null ? 'Sin alarmas activas' : 'Próxima alarma',
|
||||
proxima == null
|
||||
? activasSinProxima > 0
|
||||
? 'Alarmas activas sin próxima ejecución'
|
||||
: 'Sin alarmas activas'
|
||||
: 'Próxima alarma',
|
||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||
fontWeight: FontWeight.w900,
|
||||
),
|
||||
@@ -96,7 +107,9 @@ class _PanelProximaAlarma extends StatelessWidget {
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
proxima == null
|
||||
? 'Creá una alarma y PluriWave calculará la siguiente ejecución automáticamente.'
|
||||
? activasSinProxima > 0
|
||||
? 'Hay $activasSinProxima alarma(s) activas, pero ahora mismo no tienen una fecha futura válida. Revisá fecha, días y vacaciones.'
|
||||
: 'Creá una alarma y PluriWave calculará la siguiente ejecución automáticamente.'
|
||||
: '${proxima.nombre} · ${_fechaHora(proxima.proximaEjecucion!)}',
|
||||
),
|
||||
],
|
||||
@@ -125,7 +138,10 @@ class _TarjetaAlarma extends StatelessWidget {
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
const _AssetIcon('assets/icons/alarmas/alarm_music.png', size: 64),
|
||||
const _AssetIcon(
|
||||
'assets/icons/alarmas/alarm_music.png',
|
||||
size: 64,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
@@ -133,7 +149,9 @@ class _TarjetaAlarma extends StatelessWidget {
|
||||
children: [
|
||||
Text(
|
||||
_hora(alarma),
|
||||
style: Theme.of(context).textTheme.headlineMedium?.copyWith(
|
||||
style: Theme.of(
|
||||
context,
|
||||
).textTheme.headlineMedium?.copyWith(
|
||||
fontWeight: FontWeight.w900,
|
||||
letterSpacing: -1,
|
||||
),
|
||||
@@ -153,13 +171,20 @@ class _TarjetaAlarma extends StatelessWidget {
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
children: [
|
||||
_InfoChip(icon: Icons.repeat_rounded, label: _programacion(alarma)),
|
||||
_InfoChip(icon: Icons.snooze_rounded, label: '${alarma.snoozeMinutos} min'),
|
||||
_InfoChip(
|
||||
icon: Icons.repeat_rounded,
|
||||
label: _programacion(alarma),
|
||||
),
|
||||
_InfoChip(
|
||||
icon: Icons.snooze_rounded,
|
||||
label: '${alarma.snoozeMinutos} min',
|
||||
),
|
||||
_InfoChip(
|
||||
icon: Icons.beach_access_rounded,
|
||||
label: alarma.sonarEnVacaciones
|
||||
? 'Suena en vacaciones'
|
||||
: 'Pausa en vacaciones',
|
||||
label:
|
||||
alarma.sonarEnVacaciones
|
||||
? 'Suena en vacaciones'
|
||||
: 'Pausa en vacaciones',
|
||||
),
|
||||
_InfoChip(
|
||||
icon: Icons.volume_up_rounded,
|
||||
@@ -171,7 +196,8 @@ class _TarjetaAlarma extends StatelessWidget {
|
||||
if (alarma.proximaEjecucion != null)
|
||||
_NoticeLine(
|
||||
icon: Icons.event_available_rounded,
|
||||
text: 'Siguiente ejecución: ${_fechaHora(alarma.proximaEjecucion!)}',
|
||||
text:
|
||||
'Siguiente ejecución: ${_fechaHora(alarma.proximaEjecucion!)}',
|
||||
)
|
||||
else
|
||||
const _NoticeLine(
|
||||
@@ -182,7 +208,8 @@ class _TarjetaAlarma extends StatelessWidget {
|
||||
const SizedBox(height: 6),
|
||||
_NoticeLine(
|
||||
icon: Icons.skip_next_rounded,
|
||||
text: 'Una ejecución fue omitida: ${_fechaHora(excepcion.ejecucion)}.',
|
||||
text:
|
||||
'Una ejecución fue omitida: ${_fechaHora(excepcion.ejecucion)}.',
|
||||
),
|
||||
],
|
||||
if (mensajeVacaciones != null) ...[
|
||||
@@ -203,31 +230,32 @@ class _TarjetaAlarma extends StatelessWidget {
|
||||
TextButton.icon(
|
||||
icon: const Icon(Icons.skip_next_rounded),
|
||||
label: const Text('Omitir siguiente'),
|
||||
onPressed: alarma.proximaEjecucion == null
|
||||
? null
|
||||
: () async {
|
||||
await estado.saltarProxima(alarma.id);
|
||||
if (context.mounted) {
|
||||
final alarmas =
|
||||
context.read<EstadoAlarmas>().alarmas;
|
||||
AlarmaMusical? actualizada;
|
||||
for (final item in alarmas) {
|
||||
if (item.id == alarma.id) {
|
||||
actualizada = item;
|
||||
break;
|
||||
onPressed:
|
||||
alarma.proximaEjecucion == null
|
||||
? null
|
||||
: () async {
|
||||
await estado.saltarProxima(alarma.id);
|
||||
if (context.mounted) {
|
||||
final alarmas =
|
||||
context.read<EstadoAlarmas>().alarmas;
|
||||
AlarmaMusical? actualizada;
|
||||
for (final item in alarmas) {
|
||||
if (item.id == alarma.id) {
|
||||
actualizada = item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
actualizada?.proximaEjecucion == null
|
||||
? 'Alarma omitida. No queda próxima ejecución.'
|
||||
: 'Alarma omitida. Volverá el ${_fechaHora(actualizada!.proximaEjecucion!)}.',
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
actualizada?.proximaEjecucion == null
|
||||
? 'Alarma omitida. No queda próxima ejecución.'
|
||||
: 'Alarma omitida. Volverá el ${_fechaHora(actualizada!.proximaEjecucion!)}.',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
const Spacer(),
|
||||
IconButton(
|
||||
@@ -305,7 +333,10 @@ class _EditorAlarmaSheetState extends State<_EditorAlarmaSheet> {
|
||||
_nombreController = TextEditingController(
|
||||
text: alarma?.nombre ?? 'Despertador musical',
|
||||
);
|
||||
_hora = TimeOfDay(hour: alarma?.hora ?? ahora.hour, minute: alarma?.minuto ?? ahora.minute);
|
||||
_hora = TimeOfDay(
|
||||
hour: alarma?.hora ?? ahora.hour,
|
||||
minute: alarma?.minuto ?? ahora.minute,
|
||||
);
|
||||
_fecha = alarma?.fechaUnica ?? ahora;
|
||||
_tipo = alarma?.tipoProgramacion ?? TipoProgramacionAlarma.unica;
|
||||
_diasSemana = {...alarma?.diasSemana ?? const <int>[]};
|
||||
@@ -332,7 +363,9 @@ class _EditorAlarmaSheetState extends State<_EditorAlarmaSheet> {
|
||||
if (mounted) context.read<EstadoRadio>().cargarFavoritos();
|
||||
});
|
||||
}
|
||||
if (_emisora == null && widget.alarma == null && radio.emisoraPreferida != null) {
|
||||
if (_emisora == null &&
|
||||
widget.alarma == null &&
|
||||
radio.emisoraPreferida != null) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (mounted && _emisora == null) {
|
||||
setState(() => _emisora = radio.emisoraPreferida);
|
||||
@@ -352,7 +385,10 @@ class _EditorAlarmaSheetState extends State<_EditorAlarmaSheet> {
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
const _AssetIcon('assets/icons/alarmas/alarm_music.png', size: 58),
|
||||
const _AssetIcon(
|
||||
'assets/icons/alarmas/alarm_music.png',
|
||||
size: 58,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Text(
|
||||
@@ -390,7 +426,10 @@ class _EditorAlarmaSheetState extends State<_EditorAlarmaSheet> {
|
||||
icon: Icons.event_rounded,
|
||||
label: 'Fecha',
|
||||
value: _fechaCorta(_fecha),
|
||||
onTap: _tipo == TipoProgramacionAlarma.unica ? _elegirFecha : null,
|
||||
onTap:
|
||||
_tipo == TipoProgramacionAlarma.unica
|
||||
? _elegirFecha
|
||||
: null,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -398,12 +437,22 @@ class _EditorAlarmaSheetState extends State<_EditorAlarmaSheet> {
|
||||
const SizedBox(height: 12),
|
||||
SegmentedButton<TipoProgramacionAlarma>(
|
||||
segments: const [
|
||||
ButtonSegment(value: TipoProgramacionAlarma.unica, label: Text('Una vez')),
|
||||
ButtonSegment(value: TipoProgramacionAlarma.diaria, label: Text('Diaria')),
|
||||
ButtonSegment(value: TipoProgramacionAlarma.diasSemana, label: Text('Días')),
|
||||
ButtonSegment(
|
||||
value: TipoProgramacionAlarma.unica,
|
||||
label: Text('Una vez'),
|
||||
),
|
||||
ButtonSegment(
|
||||
value: TipoProgramacionAlarma.diaria,
|
||||
label: Text('Diaria'),
|
||||
),
|
||||
ButtonSegment(
|
||||
value: TipoProgramacionAlarma.diasSemana,
|
||||
label: Text('Días'),
|
||||
),
|
||||
],
|
||||
selected: {_tipo},
|
||||
onSelectionChanged: (value) => setState(() => _tipo = value.first),
|
||||
onSelectionChanged:
|
||||
(value) => setState(() => _tipo = value.first),
|
||||
),
|
||||
if (_tipo == TipoProgramacionAlarma.diasSemana) ...[
|
||||
const SizedBox(height: 10),
|
||||
@@ -414,15 +463,21 @@ class _EditorAlarmaSheetState extends State<_EditorAlarmaSheet> {
|
||||
FilterChip(
|
||||
label: Text(_diaCorto(i)),
|
||||
selected: _diasSemana.contains(i),
|
||||
onSelected: (selected) => setState(() {
|
||||
selected ? _diasSemana.add(i) : _diasSemana.remove(i);
|
||||
}),
|
||||
onSelected:
|
||||
(selected) => setState(() {
|
||||
selected
|
||||
? _diasSemana.add(i)
|
||||
: _diasSemana.remove(i);
|
||||
}),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 14),
|
||||
_SectionLabel(icon: 'assets/icons/alarmas/snooze_wave.png', text: 'Postponer'),
|
||||
_SectionLabel(
|
||||
icon: 'assets/icons/alarmas/snooze_wave.png',
|
||||
text: 'Postponer',
|
||||
),
|
||||
SegmentedButton<int>(
|
||||
segments: const [
|
||||
ButtonSegment(value: 3, label: Text('3 min')),
|
||||
@@ -430,10 +485,14 @@ class _EditorAlarmaSheetState extends State<_EditorAlarmaSheet> {
|
||||
ButtonSegment(value: 10, label: Text('10 min')),
|
||||
],
|
||||
selected: {_snooze},
|
||||
onSelectionChanged: (value) => setState(() => _snooze = value.first),
|
||||
onSelectionChanged:
|
||||
(value) => setState(() => _snooze = value.first),
|
||||
),
|
||||
const SizedBox(height: 14),
|
||||
_SectionLabel(icon: 'assets/icons/alarmas/fallback_sound.png', text: 'Sonido y volumen'),
|
||||
_SectionLabel(
|
||||
icon: 'assets/icons/alarmas/fallback_sound.png',
|
||||
text: 'Sonido y volumen',
|
||||
),
|
||||
Slider(
|
||||
value: _volumen,
|
||||
min: 0.25,
|
||||
@@ -444,13 +503,27 @@ class _EditorAlarmaSheetState extends State<_EditorAlarmaSheet> {
|
||||
),
|
||||
DropdownButtonFormField<SonidoInternoAlarma>(
|
||||
initialValue: _sonidoInterno,
|
||||
decoration: const InputDecoration(labelText: 'Sonido seguro interno'),
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Sonido seguro interno',
|
||||
),
|
||||
items: const [
|
||||
DropdownMenuItem(value: SonidoInternoAlarma.amanecer, child: Text('Amanecer cálido')),
|
||||
DropdownMenuItem(value: SonidoInternoAlarma.campanaSuave, child: Text('Campana suave')),
|
||||
DropdownMenuItem(value: SonidoInternoAlarma.pulsoDigital, child: Text('Pulso digital')),
|
||||
DropdownMenuItem(
|
||||
value: SonidoInternoAlarma.amanecer,
|
||||
child: Text('Amanecer cálido'),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
value: SonidoInternoAlarma.campanaSuave,
|
||||
child: Text('Campana suave'),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
value: SonidoInternoAlarma.pulsoDigital,
|
||||
child: Text('Pulso digital'),
|
||||
),
|
||||
],
|
||||
onChanged: (value) => setState(() => _sonidoInterno = value ?? _sonidoInterno),
|
||||
onChanged:
|
||||
(value) => setState(
|
||||
() => _sonidoInterno = value ?? _sonidoInterno,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
DropdownButtonFormField<String>(
|
||||
@@ -474,13 +547,14 @@ class _EditorAlarmaSheetState extends State<_EditorAlarmaSheet> {
|
||||
),
|
||||
),
|
||||
],
|
||||
onChanged: (uuid) => setState(() {
|
||||
if (uuid == null || uuid.isEmpty) {
|
||||
_emisora = null;
|
||||
return;
|
||||
}
|
||||
_emisora = favoritas.firstWhere((e) => e.uuid == uuid);
|
||||
}),
|
||||
onChanged:
|
||||
(uuid) => setState(() {
|
||||
if (uuid == null || uuid.isEmpty) {
|
||||
_emisora = null;
|
||||
return;
|
||||
}
|
||||
_emisora = favoritas.firstWhere((e) => e.uuid == uuid);
|
||||
}),
|
||||
),
|
||||
if (favoritas.isEmpty) ...[
|
||||
const SizedBox(height: 6),
|
||||
@@ -493,7 +567,8 @@ class _EditorAlarmaSheetState extends State<_EditorAlarmaSheet> {
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: FilledButton.tonalIcon(
|
||||
onPressed: () => setState(() => _emisora = radio.emisoraActual),
|
||||
onPressed:
|
||||
() => setState(() => _emisora = radio.emisoraActual),
|
||||
icon: const Icon(Icons.add_task_rounded),
|
||||
label: const Text('Usar emisora actual'),
|
||||
),
|
||||
@@ -503,10 +578,16 @@ class _EditorAlarmaSheetState extends State<_EditorAlarmaSheet> {
|
||||
SwitchListTile.adaptive(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
value: _sonarEnVacaciones,
|
||||
onChanged: (value) => setState(() => _sonarEnVacaciones = value),
|
||||
secondary: const _AssetIcon('assets/icons/alarmas/vacation_wave.png', size: 42),
|
||||
onChanged:
|
||||
(value) => setState(() => _sonarEnVacaciones = value),
|
||||
secondary: const _AssetIcon(
|
||||
'assets/icons/alarmas/vacation_wave.png',
|
||||
size: 42,
|
||||
),
|
||||
title: const Text('Sonar durante vacaciones'),
|
||||
subtitle: const Text('Si lo apagás, la próxima ejecución saltará al primer día válido.'),
|
||||
subtitle: const Text(
|
||||
'Si lo apagás, la próxima ejecución saltará al primer día válido.',
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
FilledButton.icon(
|
||||
@@ -556,24 +637,26 @@ class _EditorAlarmaSheetState extends State<_EditorAlarmaSheet> {
|
||||
diasSemana: _diasSemana.toList()..sort(),
|
||||
))
|
||||
.copyWith(
|
||||
nombre: _nombreController.text.trim().isEmpty
|
||||
? 'Despertador musical'
|
||||
: _nombreController.text.trim(),
|
||||
hora: _hora.hour,
|
||||
minuto: _hora.minute,
|
||||
tipoProgramacion: _tipo,
|
||||
diasSemana: _tipo == TipoProgramacionAlarma.diasSemana
|
||||
? (_diasSemana.toList()..sort())
|
||||
: const [],
|
||||
fechaUnica: _tipo == TipoProgramacionAlarma.unica ? _fecha : null,
|
||||
limpiarFechaUnica: _tipo != TipoProgramacionAlarma.unica,
|
||||
emisora: _emisora,
|
||||
sonarEnVacaciones: _sonarEnVacaciones,
|
||||
snoozeMinutos: _snooze,
|
||||
volumen: _volumen,
|
||||
sonidoInterno: _sonidoInterno,
|
||||
activa: true,
|
||||
);
|
||||
nombre:
|
||||
_nombreController.text.trim().isEmpty
|
||||
? 'Despertador musical'
|
||||
: _nombreController.text.trim(),
|
||||
hora: _hora.hour,
|
||||
minuto: _hora.minute,
|
||||
tipoProgramacion: _tipo,
|
||||
diasSemana:
|
||||
_tipo == TipoProgramacionAlarma.diasSemana
|
||||
? (_diasSemana.toList()..sort())
|
||||
: const [],
|
||||
fechaUnica: _tipo == TipoProgramacionAlarma.unica ? _fecha : null,
|
||||
limpiarFechaUnica: _tipo != TipoProgramacionAlarma.unica,
|
||||
emisora: _emisora,
|
||||
sonarEnVacaciones: _sonarEnVacaciones,
|
||||
snoozeMinutos: _snooze,
|
||||
volumen: _volumen,
|
||||
sonidoInterno: _sonidoInterno,
|
||||
activa: true,
|
||||
);
|
||||
await estado.guardarAlarma(alarma);
|
||||
if (mounted) Navigator.pop(context);
|
||||
}
|
||||
@@ -600,13 +683,21 @@ class _AccesoDiagnostico extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final diag = estado.diagnostico;
|
||||
return TextButton.icon(
|
||||
icon: const _AssetIcon('assets/icons/alarmas/android_reliability.png', size: 28),
|
||||
icon: const _AssetIcon(
|
||||
'assets/icons/alarmas/android_reliability.png',
|
||||
size: 28,
|
||||
),
|
||||
label: Text(
|
||||
diag == null
|
||||
? 'Revisar fiabilidad Android'
|
||||
: 'Fiabilidad: exactas ${diag.puedeProgramarExactas ? 'OK' : 'pendiente'} · notificaciones ${diag.notificacionesPermitidas ? 'OK' : 'pendiente'}',
|
||||
),
|
||||
onPressed: estado.cargarDiagnostico,
|
||||
onPressed: () async {
|
||||
if (diag != null && !diag.puedeProgramarExactas) {
|
||||
await estado.android.solicitarPermisoAlarmasExactas();
|
||||
}
|
||||
await estado.cargarDiagnostico();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -627,7 +718,10 @@ class _PanelVacaciones extends StatelessWidget {
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
const _AssetIcon('assets/icons/alarmas/vacation_wave.png', size: 48),
|
||||
const _AssetIcon(
|
||||
'assets/icons/alarmas/vacation_wave.png',
|
||||
size: 48,
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Text(
|
||||
@@ -723,9 +817,9 @@ class _EditorVacacionesSheetState extends State<_EditorVacacionesSheet> {
|
||||
children: [
|
||||
Text(
|
||||
'Nuevo rango de vacaciones',
|
||||
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||
fontWeight: FontWeight.w900,
|
||||
),
|
||||
style: Theme.of(
|
||||
context,
|
||||
).textTheme.titleLarge?.copyWith(fontWeight: FontWeight.w900),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TextField(
|
||||
@@ -811,7 +905,8 @@ class _AssetIcon extends StatelessWidget {
|
||||
width: size,
|
||||
height: size,
|
||||
fit: BoxFit.contain,
|
||||
errorBuilder: (_, __, ___) => Icon(Icons.music_note_rounded, size: size * 0.65),
|
||||
errorBuilder:
|
||||
(_, __, ___) => Icon(Icons.music_note_rounded, size: size * 0.65),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -857,7 +952,12 @@ class _SectionLabel extends StatelessWidget {
|
||||
children: [
|
||||
_AssetIcon(icon, size: 34),
|
||||
const SizedBox(width: 8),
|
||||
Text(text, style: Theme.of(context).textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w800)),
|
||||
Text(
|
||||
text,
|
||||
style: Theme.of(
|
||||
context,
|
||||
).textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w800),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -918,9 +1018,11 @@ String _hora(AlarmaMusical alarma) =>
|
||||
|
||||
String _programacion(AlarmaMusical alarma) {
|
||||
return switch (alarma.tipoProgramacion) {
|
||||
TipoProgramacionAlarma.unica => 'Una vez · ${_fechaCorta(alarma.fechaUnica ?? DateTime.now())}',
|
||||
TipoProgramacionAlarma.unica =>
|
||||
'Una vez · ${_fechaCorta(alarma.fechaUnica ?? DateTime.now())}',
|
||||
TipoProgramacionAlarma.diaria => 'Diaria',
|
||||
TipoProgramacionAlarma.diasSemana => 'Días: ${alarma.diasSemana.map(_diaCorto).join(', ')}',
|
||||
TipoProgramacionAlarma.diasSemana =>
|
||||
'Días: ${alarma.diasSemana.map(_diaCorto).join(', ')}',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -934,39 +1036,39 @@ String _fechaCorta(DateTime fecha) =>
|
||||
'${fecha.day.toString().padLeft(2, '0')}/${fecha.month.toString().padLeft(2, '0')}/${fecha.year}';
|
||||
|
||||
String _diaCorto(int dia) => switch (dia) {
|
||||
DateTime.monday => 'Lun',
|
||||
DateTime.tuesday => 'Mar',
|
||||
DateTime.wednesday => 'Mié',
|
||||
DateTime.thursday => 'Jue',
|
||||
DateTime.friday => 'Vie',
|
||||
DateTime.saturday => 'Sáb',
|
||||
DateTime.sunday => 'Dom',
|
||||
_ => '?',
|
||||
};
|
||||
DateTime.monday => 'Lun',
|
||||
DateTime.tuesday => 'Mar',
|
||||
DateTime.wednesday => 'Mié',
|
||||
DateTime.thursday => 'Jue',
|
||||
DateTime.friday => 'Vie',
|
||||
DateTime.saturday => 'Sáb',
|
||||
DateTime.sunday => 'Dom',
|
||||
_ => '?',
|
||||
};
|
||||
|
||||
String _diaLargo(int dia) => switch (dia) {
|
||||
DateTime.monday => 'lunes',
|
||||
DateTime.tuesday => 'martes',
|
||||
DateTime.wednesday => 'miércoles',
|
||||
DateTime.thursday => 'jueves',
|
||||
DateTime.friday => 'viernes',
|
||||
DateTime.saturday => 'sábado',
|
||||
DateTime.sunday => 'domingo',
|
||||
_ => 'día',
|
||||
};
|
||||
DateTime.monday => 'lunes',
|
||||
DateTime.tuesday => 'martes',
|
||||
DateTime.wednesday => 'miércoles',
|
||||
DateTime.thursday => 'jueves',
|
||||
DateTime.friday => 'viernes',
|
||||
DateTime.saturday => 'sábado',
|
||||
DateTime.sunday => 'domingo',
|
||||
_ => 'día',
|
||||
};
|
||||
|
||||
String _mes(int mes) => switch (mes) {
|
||||
1 => 'enero',
|
||||
2 => 'febrero',
|
||||
3 => 'marzo',
|
||||
4 => 'abril',
|
||||
5 => 'mayo',
|
||||
6 => 'junio',
|
||||
7 => 'julio',
|
||||
8 => 'agosto',
|
||||
9 => 'septiembre',
|
||||
10 => 'octubre',
|
||||
11 => 'noviembre',
|
||||
12 => 'diciembre',
|
||||
_ => 'mes',
|
||||
};
|
||||
1 => 'enero',
|
||||
2 => 'febrero',
|
||||
3 => 'marzo',
|
||||
4 => 'abril',
|
||||
5 => 'mayo',
|
||||
6 => 'junio',
|
||||
7 => 'julio',
|
||||
8 => 'agosto',
|
||||
9 => 'septiembre',
|
||||
10 => 'octubre',
|
||||
11 => 'noviembre',
|
||||
12 => 'diciembre',
|
||||
_ => 'mes',
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user