fix(alarmas): show which days a weekday alarm actually fires on
The alarms list showed a generic "Días" label for a diasSemana alarm instead of its actual configured days. Render the real recurrence (e.g. "Lun, Mié, Vie") by reusing the SAME per-day abbreviation the editor's own day-picker circles already use -- no new formatting scheme, no new ARB keys for the days themselves. Also surface fade/volume/vacation-pause state on the card, each only when it is a genuinely useful deviation from the common case: a fade badge when fadeInSegundos > 0 (reusing the existing alarmFadeInLabel key), a volume percentage when it differs from the 85% default, and a vacation-paused badge when the alarm is both configured to pause and a vacation range is currently active (mirrors the exact predicate ServicioProgramacionAlarmas already uses). One compact line, not a badge per field. Fixes a text-collision regression in pantalla_alarmas_editor_test.dart: opening the editor for an alarm whose own day now renders on its card (e.g. "Lun") made a bare find.text(weekday) ambiguous against the editor's day-picker circle with the same label -- scoped that finder to the BottomSheet subtree.
This commit is contained in:
+2
-1
@@ -840,5 +840,6 @@
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"alarmCardVacationPausedBadge": "متوقفة مؤقتًا بسبب الإجازة"
|
||||
}
|
||||
|
||||
+2
-1
@@ -840,5 +840,6 @@
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"alarmCardVacationPausedBadge": "ছুটির কারণে বিরত"
|
||||
}
|
||||
|
||||
+2
-1
@@ -840,5 +840,6 @@
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"alarmCardVacationPausedBadge": "Wegen Urlaub pausiert"
|
||||
}
|
||||
|
||||
+2
-1
@@ -840,5 +840,6 @@
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"alarmCardVacationPausedBadge": "Paused for vacation"
|
||||
}
|
||||
|
||||
+2
-1
@@ -799,5 +799,6 @@
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"alarmCardVacationPausedBadge": "Pausada por vacaciones"
|
||||
}
|
||||
|
||||
+2
-1
@@ -840,5 +840,6 @@
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"alarmCardVacationPausedBadge": "En pause pour les vacances"
|
||||
}
|
||||
|
||||
+2
-1
@@ -840,5 +840,6 @@
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"alarmCardVacationPausedBadge": "छुट्टी के कारण रोका गया"
|
||||
}
|
||||
|
||||
+2
-1
@@ -840,5 +840,6 @@
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"alarmCardVacationPausedBadge": "Dijeda karena liburan"
|
||||
}
|
||||
|
||||
+2
-1
@@ -840,5 +840,6 @@
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"alarmCardVacationPausedBadge": "In pausa per le vacanze"
|
||||
}
|
||||
|
||||
+2
-1
@@ -840,5 +840,6 @@
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"alarmCardVacationPausedBadge": "休暇のため一時停止中"
|
||||
}
|
||||
|
||||
+2
-1
@@ -840,5 +840,6 @@
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"alarmCardVacationPausedBadge": "Pausada por férias"
|
||||
}
|
||||
|
||||
+2
-1
@@ -840,5 +840,6 @@
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"alarmCardVacationPausedBadge": "Приостановлено на время отпуска"
|
||||
}
|
||||
|
||||
+2
-1
@@ -840,5 +840,6 @@
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"alarmCardVacationPausedBadge": "因假期已暂停"
|
||||
}
|
||||
|
||||
@@ -3067,6 +3067,12 @@ abstract class AppLocalizations {
|
||||
/// In es, this message translates to:
|
||||
/// **'Preset: {preset}'**
|
||||
String eqCustomActionPresetLabel(String preset);
|
||||
|
||||
/// No description provided for @alarmCardVacationPausedBadge.
|
||||
///
|
||||
/// In es, this message translates to:
|
||||
/// **'Pausada por vacaciones'**
|
||||
String get alarmCardVacationPausedBadge;
|
||||
}
|
||||
|
||||
class _AppLocalizationsDelegate
|
||||
|
||||
@@ -1687,4 +1687,7 @@ class AppLocalizationsAr extends AppLocalizations {
|
||||
String eqCustomActionPresetLabel(String preset) {
|
||||
return 'الإعداد المسبق: $preset';
|
||||
}
|
||||
|
||||
@override
|
||||
String get alarmCardVacationPausedBadge => 'متوقفة مؤقتًا بسبب الإجازة';
|
||||
}
|
||||
|
||||
@@ -1696,4 +1696,7 @@ class AppLocalizationsBn extends AppLocalizations {
|
||||
String eqCustomActionPresetLabel(String preset) {
|
||||
return 'প্রিসেট: $preset';
|
||||
}
|
||||
|
||||
@override
|
||||
String get alarmCardVacationPausedBadge => 'ছুটির কারণে বিরত';
|
||||
}
|
||||
|
||||
@@ -1709,4 +1709,7 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||
String eqCustomActionPresetLabel(String preset) {
|
||||
return 'Voreinstellung: $preset';
|
||||
}
|
||||
|
||||
@override
|
||||
String get alarmCardVacationPausedBadge => 'Wegen Urlaub pausiert';
|
||||
}
|
||||
|
||||
@@ -1689,4 +1689,7 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||
String eqCustomActionPresetLabel(String preset) {
|
||||
return 'Preset: $preset';
|
||||
}
|
||||
|
||||
@override
|
||||
String get alarmCardVacationPausedBadge => 'Paused for vacation';
|
||||
}
|
||||
|
||||
@@ -1703,4 +1703,7 @@ class AppLocalizationsEs extends AppLocalizations {
|
||||
String eqCustomActionPresetLabel(String preset) {
|
||||
return 'Preset: $preset';
|
||||
}
|
||||
|
||||
@override
|
||||
String get alarmCardVacationPausedBadge => 'Pausada por vacaciones';
|
||||
}
|
||||
|
||||
@@ -1712,4 +1712,7 @@ class AppLocalizationsFr extends AppLocalizations {
|
||||
String eqCustomActionPresetLabel(String preset) {
|
||||
return 'Préréglage : $preset';
|
||||
}
|
||||
|
||||
@override
|
||||
String get alarmCardVacationPausedBadge => 'En pause pour les vacances';
|
||||
}
|
||||
|
||||
@@ -1691,4 +1691,7 @@ class AppLocalizationsHi extends AppLocalizations {
|
||||
String eqCustomActionPresetLabel(String preset) {
|
||||
return 'प्रीसेट: $preset';
|
||||
}
|
||||
|
||||
@override
|
||||
String get alarmCardVacationPausedBadge => 'छुट्टी के कारण रोका गया';
|
||||
}
|
||||
|
||||
@@ -1699,4 +1699,7 @@ class AppLocalizationsId extends AppLocalizations {
|
||||
String eqCustomActionPresetLabel(String preset) {
|
||||
return 'Prasetel: $preset';
|
||||
}
|
||||
|
||||
@override
|
||||
String get alarmCardVacationPausedBadge => 'Dijeda karena liburan';
|
||||
}
|
||||
|
||||
@@ -1711,4 +1711,7 @@ class AppLocalizationsIt extends AppLocalizations {
|
||||
String eqCustomActionPresetLabel(String preset) {
|
||||
return 'Preset attivo: $preset';
|
||||
}
|
||||
|
||||
@override
|
||||
String get alarmCardVacationPausedBadge => 'In pausa per le vacanze';
|
||||
}
|
||||
|
||||
@@ -1642,4 +1642,7 @@ class AppLocalizationsJa extends AppLocalizations {
|
||||
String eqCustomActionPresetLabel(String preset) {
|
||||
return 'プリセット: $preset';
|
||||
}
|
||||
|
||||
@override
|
||||
String get alarmCardVacationPausedBadge => '休暇のため一時停止中';
|
||||
}
|
||||
|
||||
@@ -1699,4 +1699,7 @@ class AppLocalizationsPt extends AppLocalizations {
|
||||
String eqCustomActionPresetLabel(String preset) {
|
||||
return 'Predefinição: $preset';
|
||||
}
|
||||
|
||||
@override
|
||||
String get alarmCardVacationPausedBadge => 'Pausada por férias';
|
||||
}
|
||||
|
||||
@@ -1703,4 +1703,7 @@ class AppLocalizationsRu extends AppLocalizations {
|
||||
String eqCustomActionPresetLabel(String preset) {
|
||||
return 'Пресет: $preset';
|
||||
}
|
||||
|
||||
@override
|
||||
String get alarmCardVacationPausedBadge => 'Приостановлено на время отпуска';
|
||||
}
|
||||
|
||||
@@ -1634,4 +1634,7 @@ class AppLocalizationsZh extends AppLocalizations {
|
||||
String eqCustomActionPresetLabel(String preset) {
|
||||
return '预设:$preset';
|
||||
}
|
||||
|
||||
@override
|
||||
String get alarmCardVacationPausedBadge => '因假期已暂停';
|
||||
}
|
||||
|
||||
@@ -265,6 +265,26 @@ class _TarjetaAlarma extends StatelessWidget {
|
||||
? l10n.noStationUseInternalSound
|
||||
: localizedStationName(l10n, alarma.emisora!.nombre);
|
||||
|
||||
// Item 5: surfaces the genuinely useful fields that already exist on
|
||||
// the model, WITHOUT turning the row into clutter -- each is shown
|
||||
// only when it is a meaningful deviation from the common case.
|
||||
// Mirrors EXACTLY the pause predicate `impactoDeRango`/
|
||||
// `ServicioProgramacionAlarmas` already use
|
||||
// (`!sonarEnVacaciones` while `activa`), gated by whether a vacation
|
||||
// range is CURRENTLY active -- an alarm configured to pause but with
|
||||
// no active range right now is not actually paused by anything yet.
|
||||
final pausadaPorVacaciones =
|
||||
alarma.activa &&
|
||||
!alarma.sonarEnVacaciones &&
|
||||
estado.rangoVacacionesActivo() != null;
|
||||
final detalles = <String>[
|
||||
if (alarma.fadeInSegundos > 0)
|
||||
l10n.alarmFadeInLabel(alarma.fadeInSegundos),
|
||||
if ((alarma.volumen * 100).round() != 85)
|
||||
'${(alarma.volumen * 100).round()}%',
|
||||
if (pausadaPorVacaciones) l10n.alarmCardVacationPausedBadge,
|
||||
];
|
||||
|
||||
return Dismissible(
|
||||
key: ValueKey('tarjeta-alarma-${alarma.id}'),
|
||||
direction: DismissDirection.horizontal,
|
||||
@@ -309,14 +329,21 @@ class _TarjetaAlarma extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
_recurrenciaCorta(l10n, alarma),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withValues(alpha: 0.5),
|
||||
// Item 5: real day list can run longer than the
|
||||
// old generic "Días" label -- Flexible+ellipsis
|
||||
// keeps a long selection from overflowing the
|
||||
// Row instead of clipping visibly.
|
||||
Flexible(
|
||||
child: Text(
|
||||
_recurrenciaCorta(l10n, alarma),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: Theme.of(context).colorScheme
|
||||
.onSurface
|
||||
.withValues(alpha: 0.5),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -369,6 +396,25 @@ class _TarjetaAlarma extends StatelessWidget {
|
||||
),
|
||||
],
|
||||
),
|
||||
// Item 5: fade/volume/vacation-pause state, only
|
||||
// when each is a genuinely useful deviation from
|
||||
// the common case (see `detalles` above) -- a
|
||||
// single compact line, not a badge per field.
|
||||
if (detalles.isNotEmpty) ...[
|
||||
const SizedBox(height: 3),
|
||||
Text(
|
||||
detalles.join(' · '),
|
||||
key: ValueKey('tarjeta-alarma-detalles-${alarma.id}'),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withValues(alpha: 0.55),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -1668,16 +1714,39 @@ String _weekdayShort(AppLocalizations l10n, int day) => switch (day) {
|
||||
String _fechaCorta(AppLocalizations l10n, DateTime fecha) =>
|
||||
fechaCortaLocalizada(l10n.localeName, fecha);
|
||||
|
||||
/// Audit 7.4 (t4:339): a compact recurrence label next to the alarm card's
|
||||
/// giant time. Reuses the SAME generic labels the editor's own
|
||||
/// `TipoProgramacionAlarma` `SegmentedButton` already shows (`oneTimeOption`
|
||||
/// / `dailyOption` / `weekdaysOption`) rather than inventing a new, more
|
||||
/// specific ARB string -- honest given the space (12px, next to a 34px
|
||||
/// time) genuinely only fits a short word, not a full weekday list.
|
||||
/// Audit 7.4 (t4:339) / item 5: a compact recurrence label next to the
|
||||
/// alarm card's giant time. `diaria`/`unica` still show the SAME generic
|
||||
/// labels the editor's own `TipoProgramacionAlarma` `SegmentedButton`
|
||||
/// already uses (`dailyOption`/`oneTimeOption`) -- both are already fully
|
||||
/// specific (there is nothing more concrete to say than "every day"/"just
|
||||
/// once"). `diasSemana` now renders the alarm's ACTUAL configured days
|
||||
/// (e.g. "Lun, Mié, Vie") instead of the generic `weekdaysOption` ("Días"),
|
||||
/// reusing [_weekdayShort] (the SAME per-day abbreviation the editor's own
|
||||
/// day-picker circles already use) -- no new ARB keys, no second
|
||||
/// formatting scheme, and the resulting Text is wrapped in a
|
||||
/// `Flexible`+ellipsis at the call site so a long selection never
|
||||
/// overflows the row.
|
||||
String _recurrenciaCorta(AppLocalizations l10n, AlarmaMusical alarma) {
|
||||
return switch (alarma.tipoProgramacion) {
|
||||
TipoProgramacionAlarma.diaria => l10n.dailyOption,
|
||||
TipoProgramacionAlarma.diasSemana => l10n.weekdaysOption,
|
||||
TipoProgramacionAlarma.diasSemana => _diasSemanaCorto(
|
||||
l10n,
|
||||
alarma.diasSemana,
|
||||
),
|
||||
TipoProgramacionAlarma.unica => l10n.oneTimeOption,
|
||||
};
|
||||
}
|
||||
|
||||
/// The real, ordered day abbreviations for a `diasSemana` alarm (item 5),
|
||||
/// e.g. "Lun, Mié, Vie". [diasSemana] is re-sorted defensively (the editor
|
||||
/// always persists it sorted, but this does not rely on that). Falls back
|
||||
/// to the generic [AppLocalizations.weekdaysOption] label when
|
||||
/// [diasSemana] is empty -- the editor already blocks saving an empty
|
||||
/// selection in this mode, but a corrupt/legacy persisted record could
|
||||
/// still reach here, and showing nothing would be worse than the old
|
||||
/// generic label.
|
||||
String _diasSemanaCorto(AppLocalizations l10n, List<int> diasSemana) {
|
||||
if (diasSemana.isEmpty) return l10n.weekdaysOption;
|
||||
final ordenados = [...diasSemana]..sort();
|
||||
return ordenados.map((dia) => _weekdayShort(l10n, dia)).join(', ');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user