feat(favoritos): replace stacked group panels with chip-filtered reorderable list

Replaces the stacked per-group panel layout with a single
chip-filtered flat list. Chips read "{name} · {count}" (new ARB keys
favoriteGroupsChipLabel/favoritesFilterAllLabel), one per group plus
an "All" chip. Rows drag-reorder via a leading handle
(ReorderableDragStartListener, buildDefaultDragHandles: false) using
the modern onReorderItem callback rather than the now-@Deprecated
onReorder (Flutter 3.44 marks it obsolete).

EstadoRadio additions: listaFavoritosManual (a new memoized getter
returning the stored order untouched by the global ordenListas
setting - listaFavoritos itself always re-sorts by
name/quality on every read, which would silently discard any
drag-to-reorder), reordenarFavorito (thin wrapper over the
already-existing ServicioFavoritos.reordenar, previously unused
outside its own service test), and ordenarFavoritos (applies an
existing OrdenEmisoras criterion via ordenarEmisoras() and persists
the result as the new manual order, so the swap_vert sort action's
result also survives a restart). listaFavoritos itself is untouched,
so Android Auto's tree and the future Escuchar grid (WU5) are
unaffected by Favoritos' own manual order.

Group management: an "Manage lists" action chip pushes the existing
PantallaAjustesGruposFavoritos screen (Settings' own screen, reused
rather than duplicated) - a second entry point to the same screen.
Custom-station CTA: a new dashed-bordered card opens the add-station
form directly; that form was renamed from private _FormularioEmisora
to public FormularioEmisoraPersonalizada in
pantalla_ajustes_emisoras_personalizadas.dart so both screens share
one implementation. New ARB keys: favoriteGroupsManage,
customStationsAddCta.

Tests: pantalla_favoritos_plural_test.dart (the file tasks.md named)
never imported PantallaFavoritos - it only covers stationCount's ARB
plural formatting, unrelated to this screen. Left it untouched and
added test/pantallas/pantalla_favoritos_test.dart instead: 3
state-layer tests for the new EstadoRadio surface plus 6 widget
scenarios (empty-state CTA, chip filter, drag-reorder persistence,
sort action, group management + chip reactivity, custom-station
CTA). 604 -> 614 tests (2 skipped, unchanged). flutter analyze
unchanged at 1 pre-existing info.

Recorded in tasks.md with the test-file correction and the
design decisions this WU had to make on its own (no ADR covers
Favoritos' manual-order persistence).
This commit is contained in:
2026-07-28 23:49:06 +02:00
parent ebdde7df01
commit 504a13641f
21 changed files with 1011 additions and 126 deletions
+24
View File
@@ -1036,6 +1036,30 @@ abstract class AppLocalizations {
/// **'{stationName} eliminada de favoritos'**
String favoritesRemovedMessage(Object stationName);
/// No description provided for @favoritesFilterAllLabel.
///
/// In es, this message translates to:
/// **'Todas'**
String get favoritesFilterAllLabel;
/// No description provided for @favoriteGroupsChipLabel.
///
/// In es, this message translates to:
/// **'{groupName} · {count}'**
String favoriteGroupsChipLabel(Object groupName, int count);
/// No description provided for @favoriteGroupsManage.
///
/// In es, this message translates to:
/// **'Gestionar listas'**
String get favoriteGroupsManage;
/// No description provided for @customStationsAddCta.
///
/// In es, this message translates to:
/// **'Añadir emisora personalizada'**
String get customStationsAddCta;
/// No description provided for @alarmPostponedCurrentExecution.
///
/// In es, this message translates to:
+14
View File
@@ -533,6 +533,20 @@ class AppLocalizationsAr extends AppLocalizations {
return 'تمت إزالة $stationName من المفضلة';
}
@override
String get favoritesFilterAllLabel => 'Todas';
@override
String favoriteGroupsChipLabel(Object groupName, int count) {
return '$groupName · $count';
}
@override
String get favoriteGroupsManage => 'Gestionar listas';
@override
String get customStationsAddCta => 'Añadir emisora personalizada';
@override
String get alarmPostponedCurrentExecution => 'تم تأجيل المنبه لهذا التشغيل.';
+14
View File
@@ -536,6 +536,20 @@ class AppLocalizationsBn extends AppLocalizations {
return '$stationName প্রিয় থেকে সরানো হয়েছে';
}
@override
String get favoritesFilterAllLabel => 'Todas';
@override
String favoriteGroupsChipLabel(Object groupName, int count) {
return '$groupName · $count';
}
@override
String get favoriteGroupsManage => 'Gestionar listas';
@override
String get customStationsAddCta => 'Añadir emisora personalizada';
@override
String get alarmPostponedCurrentExecution =>
'এই চালনার জন্য অ্যালার্ম পিছিয়ে দেওয়া হয়েছে।';
+14
View File
@@ -539,6 +539,20 @@ class AppLocalizationsDe extends AppLocalizations {
return '$stationName aus Favoriten entfernt';
}
@override
String get favoritesFilterAllLabel => 'Todas';
@override
String favoriteGroupsChipLabel(Object groupName, int count) {
return '$groupName · $count';
}
@override
String get favoriteGroupsManage => 'Gestionar listas';
@override
String get customStationsAddCta => 'Añadir emisora personalizada';
@override
String get alarmPostponedCurrentExecution =>
'Alarm für diese Ausführung verschoben.';
+14
View File
@@ -533,6 +533,20 @@ class AppLocalizationsEn extends AppLocalizations {
return '$stationName removed from favorites';
}
@override
String get favoritesFilterAllLabel => 'All';
@override
String favoriteGroupsChipLabel(Object groupName, int count) {
return '$groupName · $count';
}
@override
String get favoriteGroupsManage => 'Manage lists';
@override
String get customStationsAddCta => 'Add custom station';
@override
String get alarmPostponedCurrentExecution =>
'Alarm postponed for this occurrence.';
+14
View File
@@ -537,6 +537,20 @@ class AppLocalizationsEs extends AppLocalizations {
return '$stationName eliminada de favoritos';
}
@override
String get favoritesFilterAllLabel => 'Todas';
@override
String favoriteGroupsChipLabel(Object groupName, int count) {
return '$groupName · $count';
}
@override
String get favoriteGroupsManage => 'Gestionar listas';
@override
String get customStationsAddCta => 'Añadir emisora personalizada';
@override
String get alarmPostponedCurrentExecution =>
'Alarma pospuesta para esta ejecución.';
+14
View File
@@ -541,6 +541,20 @@ class AppLocalizationsFr extends AppLocalizations {
return '$stationName retirée des favoris';
}
@override
String get favoritesFilterAllLabel => 'Todas';
@override
String favoriteGroupsChipLabel(Object groupName, int count) {
return '$groupName · $count';
}
@override
String get favoriteGroupsManage => 'Gestionar listas';
@override
String get customStationsAddCta => 'Añadir emisora personalizada';
@override
String get alarmPostponedCurrentExecution =>
'Alarme reportée pour cette exécution.';
+14
View File
@@ -534,6 +534,20 @@ class AppLocalizationsHi extends AppLocalizations {
return '$stationName पसंदीदा से हटाया गया';
}
@override
String get favoritesFilterAllLabel => 'Todas';
@override
String favoriteGroupsChipLabel(Object groupName, int count) {
return '$groupName · $count';
}
@override
String get favoriteGroupsManage => 'Gestionar listas';
@override
String get customStationsAddCta => 'Añadir emisora personalizada';
@override
String get alarmPostponedCurrentExecution =>
'इस चाल के लिए अलार्म स्थगित किया गया।';
+14
View File
@@ -535,6 +535,20 @@ class AppLocalizationsId extends AppLocalizations {
return '$stationName dihapus dari favorit';
}
@override
String get favoritesFilterAllLabel => 'Todas';
@override
String favoriteGroupsChipLabel(Object groupName, int count) {
return '$groupName · $count';
}
@override
String get favoriteGroupsManage => 'Gestionar listas';
@override
String get customStationsAddCta => 'Añadir emisora personalizada';
@override
String get alarmPostponedCurrentExecution =>
'Alarm ditunda untuk eksekusi ini.';
+14
View File
@@ -537,6 +537,20 @@ class AppLocalizationsIt extends AppLocalizations {
return '$stationName rimossa dai preferiti';
}
@override
String get favoritesFilterAllLabel => 'Todas';
@override
String favoriteGroupsChipLabel(Object groupName, int count) {
return '$groupName · $count';
}
@override
String get favoriteGroupsManage => 'Gestionar listas';
@override
String get customStationsAddCta => 'Añadir emisora personalizada';
@override
String get alarmPostponedCurrentExecution =>
'Sveglia posticipata per questa esecuzione.';
+14
View File
@@ -518,6 +518,20 @@ class AppLocalizationsJa extends AppLocalizations {
return '$stationName をお気に入りから削除しました';
}
@override
String get favoritesFilterAllLabel => 'Todas';
@override
String favoriteGroupsChipLabel(Object groupName, int count) {
return '$groupName · $count';
}
@override
String get favoriteGroupsManage => 'Gestionar listas';
@override
String get customStationsAddCta => 'Añadir emisora personalizada';
@override
String get alarmPostponedCurrentExecution => 'この実行のアラームを延期しました。';
+14
View File
@@ -536,6 +536,20 @@ class AppLocalizationsPt extends AppLocalizations {
return '$stationName removida dos favoritos';
}
@override
String get favoritesFilterAllLabel => 'Todas';
@override
String favoriteGroupsChipLabel(Object groupName, int count) {
return '$groupName · $count';
}
@override
String get favoriteGroupsManage => 'Gestionar listas';
@override
String get customStationsAddCta => 'Añadir emisora personalizada';
@override
String get alarmPostponedCurrentExecution =>
'Alarme adiado para esta execução.';
+14
View File
@@ -537,6 +537,20 @@ class AppLocalizationsRu extends AppLocalizations {
return '$stationName удалена из избранного';
}
@override
String get favoritesFilterAllLabel => 'Todas';
@override
String favoriteGroupsChipLabel(Object groupName, int count) {
return '$groupName · $count';
}
@override
String get favoriteGroupsManage => 'Gestionar listas';
@override
String get customStationsAddCta => 'Añadir emisora personalizada';
@override
String get alarmPostponedCurrentExecution =>
'Будильник отложен для этого запуска.';
+14
View File
@@ -516,6 +516,20 @@ class AppLocalizationsZh extends AppLocalizations {
return '$stationName 已从收藏中移除';
}
@override
String get favoritesFilterAllLabel => 'Todas';
@override
String favoriteGroupsChipLabel(Object groupName, int count) {
return '$groupName · $count';
}
@override
String get favoriteGroupsManage => 'Gestionar listas';
@override
String get customStationsAddCta => 'Añadir emisora personalizada';
@override
String get alarmPostponedCurrentExecution => '本次闹钟已推迟。';