diff --git a/lib/l10n/app_ar.arb b/lib/l10n/app_ar.arb index cd2ce2d..9fbdd84 100644 --- a/lib/l10n/app_ar.arb +++ b/lib/l10n/app_ar.arb @@ -711,6 +711,7 @@ "equalizerActiveOutputLabel": "المخرج النشط", "equalizerBaseExplainer": "هذا هو المعادل الأساسي: يُطبَّق على كل محطة لا تملك إعدادًا خاصًا بها. يُحدَّد معادل محطة معينة من شاشة تشغيلها الخاصة، وله الأولوية على هذا المعادل.", "equalizerSaveAsPresetAction": "حفظ كإعداد مسبق", + "equalizerResetToFlatAction": "إعادة الضبط إلى مسطح", "equalizerSavePresetConfirm": "حفظ", "equalizerSavePresetDialogTitle": "حفظ كإعداد مسبق", "equalizerSavePresetEmptyNameError": "أدخل اسمًا للإعداد المسبق.", diff --git a/lib/l10n/app_bn.arb b/lib/l10n/app_bn.arb index 5cb5c3e..753ba0c 100644 --- a/lib/l10n/app_bn.arb +++ b/lib/l10n/app_bn.arb @@ -711,6 +711,7 @@ "equalizerActiveOutputLabel": "সক্রিয় আউটপুট", "equalizerBaseExplainer": "এটি বেস ইকুয়ালাইজার: এটি নিজস্ব সেটিং নেই এমন সব স্টেশনে প্রযোজ্য। কোনো নির্দিষ্ট স্টেশনের নিজস্ব EQ তার প্লেব্যাক স্ক্রিন থেকে ঠিক করা হয় এবং এটির চেয়ে অগ্রাধিকার পায়।", "equalizerSaveAsPresetAction": "প্রিসেট হিসেবে সংরক্ষণ করুন", + "equalizerResetToFlatAction": "সমতলে পুনরায় সেট করুন", "equalizerSavePresetConfirm": "সংরক্ষণ করুন", "equalizerSavePresetDialogTitle": "প্রিসেট হিসেবে সংরক্ষণ করুন", "equalizerSavePresetEmptyNameError": "প্রিসেটের জন্য একটি নাম লিখুন।", diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 9c696c9..0135c1c 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -711,6 +711,7 @@ "equalizerActiveOutputLabel": "Aktiver Ausgang", "equalizerBaseExplainer": "Dies ist der Basis-Equalizer: Er gilt für alle Sender ohne eigene Einstellung. Der eigene EQ eines Senders wird auf dessen eigenem Wiedergabebildschirm festgelegt und hat Vorrang vor diesem hier.", "equalizerSaveAsPresetAction": "Als Preset speichern", + "equalizerResetToFlatAction": "Auf neutral zurücksetzen", "equalizerSavePresetConfirm": "Speichern", "equalizerSavePresetDialogTitle": "Als Preset speichern", "equalizerSavePresetEmptyNameError": "Gib einen Namen für das Preset ein.", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 974c148..3b63f2f 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -102,6 +102,7 @@ "equalizerStationsWithOwnEqSubtitle": "Ignore this base equalizer", "equalizerStationsWithOwnEqEmpty": "No stations have their own EQ yet.", "equalizerSaveAsPresetAction": "Save as preset", + "equalizerResetToFlatAction": "Reset to flat", "equalizerSavePresetDialogTitle": "Save as preset", "equalizerSavePresetNameLabel": "Preset name", "equalizerSavePresetEmptyNameError": "Enter a name for the preset.", diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 701838f..495b3db 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -102,6 +102,7 @@ "equalizerStationsWithOwnEqSubtitle": "Ignoran este ecualizador base", "equalizerStationsWithOwnEqEmpty": "Ninguna emisora tiene ajuste propio todavía.", "equalizerSaveAsPresetAction": "Guardar como preset", + "equalizerResetToFlatAction": "Restablecer a plano", "equalizerSavePresetDialogTitle": "Guardar como preset", "equalizerSavePresetNameLabel": "Nombre del preset", "equalizerSavePresetEmptyNameError": "Ingresá un nombre para el preset.", diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 308a4fa..bfbb86c 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -711,6 +711,7 @@ "equalizerActiveOutputLabel": "Sortie active", "equalizerBaseExplainer": "Voici l'égaliseur de base : il s'applique à toutes les stations sans réglage propre. L'EQ propre à une station est défini depuis son propre écran de lecture et prime sur celui-ci.", "equalizerSaveAsPresetAction": "Enregistrer comme Preset", + "equalizerResetToFlatAction": "Réinitialiser à plat", "equalizerSavePresetConfirm": "Enregistrer", "equalizerSavePresetDialogTitle": "Enregistrer comme Preset", "equalizerSavePresetEmptyNameError": "Saisissez un nom pour le Preset.", diff --git a/lib/l10n/app_hi.arb b/lib/l10n/app_hi.arb index 7188a1c..fd812b1 100644 --- a/lib/l10n/app_hi.arb +++ b/lib/l10n/app_hi.arb @@ -711,6 +711,7 @@ "equalizerActiveOutputLabel": "सक्रिय आउटपुट", "equalizerBaseExplainer": "यह बेस इक्वलाइज़र है: यह उन सभी स्टेशन पर लागू होता है जिनकी अपनी सेटिंग नहीं है। किसी खास स्टेशन का अपना EQ उसकी प्लेबैक स्क्रीन से तय होता है और इस पर प्राथमिकता रखता है।", "equalizerSaveAsPresetAction": "प्रीसेट के रूप में सहेजें", + "equalizerResetToFlatAction": "समतल पर रीसेट करें", "equalizerSavePresetConfirm": "सहेजें", "equalizerSavePresetDialogTitle": "प्रीसेट के रूप में सहेजें", "equalizerSavePresetEmptyNameError": "प्रीसेट के लिए एक नाम डालें।", diff --git a/lib/l10n/app_id.arb b/lib/l10n/app_id.arb index 0ba0d60..80fe6e8 100644 --- a/lib/l10n/app_id.arb +++ b/lib/l10n/app_id.arb @@ -711,6 +711,7 @@ "equalizerActiveOutputLabel": "Output aktif", "equalizerBaseExplainer": "Ini adalah equalizer dasar: berlaku untuk semua stasiun yang belum punya pengaturan sendiri. EQ khusus suatu stasiun diatur dari layar pemutarannya sendiri dan mengesampingkan yang ini.", "equalizerSaveAsPresetAction": "Simpan sebagai Preset", + "equalizerResetToFlatAction": "Setel ulang ke datar", "equalizerSavePresetConfirm": "Simpan", "equalizerSavePresetDialogTitle": "Simpan sebagai Preset", "equalizerSavePresetEmptyNameError": "Masukkan nama untuk Preset.", diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index a7decd8..0c41a0f 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -711,6 +711,7 @@ "equalizerActiveOutputLabel": "Uscita attiva", "equalizerBaseExplainer": "Questo è l'equalizzatore di base: si applica a tutte le emittenti senza un'impostazione propria. L'EQ di un'emittente specifica si imposta dalla sua schermata di riproduzione e ha la precedenza su questo.", "equalizerSaveAsPresetAction": "Salva come Preset", + "equalizerResetToFlatAction": "Ripristina piatto", "equalizerSavePresetConfirm": "Salva", "equalizerSavePresetDialogTitle": "Salva come Preset", "equalizerSavePresetEmptyNameError": "Inserisci un nome per il Preset.", diff --git a/lib/l10n/app_ja.arb b/lib/l10n/app_ja.arb index ed12162..b1ef025 100644 --- a/lib/l10n/app_ja.arb +++ b/lib/l10n/app_ja.arb @@ -711,6 +711,7 @@ "equalizerActiveOutputLabel": "アクティブな出力", "equalizerBaseExplainer": "これはベースイコライザーです。専用設定を持たないすべての局に適用されます。特定の局専用のEQはその局の再生画面から設定でき、こちらより優先されます。", "equalizerSaveAsPresetAction": "プリセットとして保存", + "equalizerResetToFlatAction": "フラットにリセット", "equalizerSavePresetConfirm": "保存", "equalizerSavePresetDialogTitle": "プリセットとして保存", "equalizerSavePresetEmptyNameError": "プリセットの名前を入力してください。", diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index c0f69f1..63f8348 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -711,6 +711,7 @@ "equalizerActiveOutputLabel": "Saída ativa", "equalizerBaseExplainer": "Este é o equalizador base: aplica-se a todas as estações sem ajuste próprio. O EQ próprio de uma estação é definido na sua própria tela de reprodução e tem prioridade sobre este.", "equalizerSaveAsPresetAction": "Salvar como Preset", + "equalizerResetToFlatAction": "Repor para plano", "equalizerSavePresetConfirm": "Salvar", "equalizerSavePresetDialogTitle": "Salvar como Preset", "equalizerSavePresetEmptyNameError": "Digite um nome para o Preset.", diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index 4e0f140..53a0ebe 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -711,6 +711,7 @@ "equalizerActiveOutputLabel": "Активный выход", "equalizerBaseExplainer": "Это базовый эквалайзер: он применяется ко всем станциям без собственной настройки. Свой EQ конкретной станции задаётся на экране её воспроизведения и имеет приоритет над этим.", "equalizerSaveAsPresetAction": "Сохранить как пресет", + "equalizerResetToFlatAction": "Сбросить на плоский", "equalizerSavePresetConfirm": "Сохранить", "equalizerSavePresetDialogTitle": "Сохранить как пресет", "equalizerSavePresetEmptyNameError": "Введите название пресета.", diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 8e997a1..5f226b8 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -711,6 +711,7 @@ "equalizerActiveOutputLabel": "当前输出", "equalizerBaseExplainer": "这是基础均衡器:适用于所有没有专属设置的电台。某个电台的专属EQ可在其自己的播放界面中设置,并优先于此设置生效。", "equalizerSaveAsPresetAction": "保存为预设", + "equalizerResetToFlatAction": "重置为平坦", "equalizerSavePresetConfirm": "保存", "equalizerSavePresetDialogTitle": "保存为预设", "equalizerSavePresetEmptyNameError": "请输入预设名称。", diff --git a/lib/l10n/gen/app_localizations.dart b/lib/l10n/gen/app_localizations.dart index 19440ae..c0bb7f7 100644 --- a/lib/l10n/gen/app_localizations.dart +++ b/lib/l10n/gen/app_localizations.dart @@ -538,6 +538,12 @@ abstract class AppLocalizations { /// **'Guardar como preset'** String get equalizerSaveAsPresetAction; + /// No description provided for @equalizerResetToFlatAction. + /// + /// In es, this message translates to: + /// **'Restablecer a plano'** + String get equalizerResetToFlatAction; + /// No description provided for @equalizerSavePresetDialogTitle. /// /// In es, this message translates to: diff --git a/lib/l10n/gen/app_localizations_ar.dart b/lib/l10n/gen/app_localizations_ar.dart index e849dba..46a3591 100644 --- a/lib/l10n/gen/app_localizations_ar.dart +++ b/lib/l10n/gen/app_localizations_ar.dart @@ -246,6 +246,9 @@ class AppLocalizationsAr extends AppLocalizations { @override String get equalizerSaveAsPresetAction => 'حفظ كإعداد مسبق'; + @override + String get equalizerResetToFlatAction => 'إعادة الضبط إلى مسطح'; + @override String get equalizerSavePresetDialogTitle => 'حفظ كإعداد مسبق'; diff --git a/lib/l10n/gen/app_localizations_bn.dart b/lib/l10n/gen/app_localizations_bn.dart index 30a16bd..3d828e1 100644 --- a/lib/l10n/gen/app_localizations_bn.dart +++ b/lib/l10n/gen/app_localizations_bn.dart @@ -250,6 +250,9 @@ class AppLocalizationsBn extends AppLocalizations { @override String get equalizerSaveAsPresetAction => 'প্রিসেট হিসেবে সংরক্ষণ করুন'; + @override + String get equalizerResetToFlatAction => 'সমতলে পুনরায় সেট করুন'; + @override String get equalizerSavePresetDialogTitle => 'প্রিসেট হিসেবে সংরক্ষণ করুন'; diff --git a/lib/l10n/gen/app_localizations_de.dart b/lib/l10n/gen/app_localizations_de.dart index e2276a3..72e4cea 100644 --- a/lib/l10n/gen/app_localizations_de.dart +++ b/lib/l10n/gen/app_localizations_de.dart @@ -250,6 +250,9 @@ class AppLocalizationsDe extends AppLocalizations { @override String get equalizerSaveAsPresetAction => 'Als Preset speichern'; + @override + String get equalizerResetToFlatAction => 'Auf neutral zurücksetzen'; + @override String get equalizerSavePresetDialogTitle => 'Als Preset speichern'; diff --git a/lib/l10n/gen/app_localizations_en.dart b/lib/l10n/gen/app_localizations_en.dart index cc164f8..8c00298 100644 --- a/lib/l10n/gen/app_localizations_en.dart +++ b/lib/l10n/gen/app_localizations_en.dart @@ -247,6 +247,9 @@ class AppLocalizationsEn extends AppLocalizations { @override String get equalizerSaveAsPresetAction => 'Save as preset'; + @override + String get equalizerResetToFlatAction => 'Reset to flat'; + @override String get equalizerSavePresetDialogTitle => 'Save as preset'; diff --git a/lib/l10n/gen/app_localizations_es.dart b/lib/l10n/gen/app_localizations_es.dart index 5b14e48..e05feb3 100644 --- a/lib/l10n/gen/app_localizations_es.dart +++ b/lib/l10n/gen/app_localizations_es.dart @@ -249,6 +249,9 @@ class AppLocalizationsEs extends AppLocalizations { @override String get equalizerSaveAsPresetAction => 'Guardar como preset'; + @override + String get equalizerResetToFlatAction => 'Restablecer a plano'; + @override String get equalizerSavePresetDialogTitle => 'Guardar como preset'; diff --git a/lib/l10n/gen/app_localizations_fr.dart b/lib/l10n/gen/app_localizations_fr.dart index 00a4797..52b41ce 100644 --- a/lib/l10n/gen/app_localizations_fr.dart +++ b/lib/l10n/gen/app_localizations_fr.dart @@ -251,6 +251,9 @@ class AppLocalizationsFr extends AppLocalizations { @override String get equalizerSaveAsPresetAction => 'Enregistrer comme Preset'; + @override + String get equalizerResetToFlatAction => 'Réinitialiser à plat'; + @override String get equalizerSavePresetDialogTitle => 'Enregistrer comme Preset'; diff --git a/lib/l10n/gen/app_localizations_hi.dart b/lib/l10n/gen/app_localizations_hi.dart index 3c8b7fd..9d7f824 100644 --- a/lib/l10n/gen/app_localizations_hi.dart +++ b/lib/l10n/gen/app_localizations_hi.dart @@ -249,6 +249,9 @@ class AppLocalizationsHi extends AppLocalizations { @override String get equalizerSaveAsPresetAction => 'प्रीसेट के रूप में सहेजें'; + @override + String get equalizerResetToFlatAction => 'समतल पर रीसेट करें'; + @override String get equalizerSavePresetDialogTitle => 'प्रीसेट के रूप में सहेजें'; diff --git a/lib/l10n/gen/app_localizations_id.dart b/lib/l10n/gen/app_localizations_id.dart index 106f059..3c1b6b3 100644 --- a/lib/l10n/gen/app_localizations_id.dart +++ b/lib/l10n/gen/app_localizations_id.dart @@ -249,6 +249,9 @@ class AppLocalizationsId extends AppLocalizations { @override String get equalizerSaveAsPresetAction => 'Simpan sebagai Preset'; + @override + String get equalizerResetToFlatAction => 'Setel ulang ke datar'; + @override String get equalizerSavePresetDialogTitle => 'Simpan sebagai Preset'; diff --git a/lib/l10n/gen/app_localizations_it.dart b/lib/l10n/gen/app_localizations_it.dart index dccb305..72b5966 100644 --- a/lib/l10n/gen/app_localizations_it.dart +++ b/lib/l10n/gen/app_localizations_it.dart @@ -250,6 +250,9 @@ class AppLocalizationsIt extends AppLocalizations { @override String get equalizerSaveAsPresetAction => 'Salva come Preset'; + @override + String get equalizerResetToFlatAction => 'Ripristina piatto'; + @override String get equalizerSavePresetDialogTitle => 'Salva come Preset'; diff --git a/lib/l10n/gen/app_localizations_ja.dart b/lib/l10n/gen/app_localizations_ja.dart index f3d206d..a236a8f 100644 --- a/lib/l10n/gen/app_localizations_ja.dart +++ b/lib/l10n/gen/app_localizations_ja.dart @@ -239,6 +239,9 @@ class AppLocalizationsJa extends AppLocalizations { @override String get equalizerSaveAsPresetAction => 'プリセットとして保存'; + @override + String get equalizerResetToFlatAction => 'フラットにリセット'; + @override String get equalizerSavePresetDialogTitle => 'プリセットとして保存'; diff --git a/lib/l10n/gen/app_localizations_pt.dart b/lib/l10n/gen/app_localizations_pt.dart index e73a879..11dec34 100644 --- a/lib/l10n/gen/app_localizations_pt.dart +++ b/lib/l10n/gen/app_localizations_pt.dart @@ -248,6 +248,9 @@ class AppLocalizationsPt extends AppLocalizations { @override String get equalizerSaveAsPresetAction => 'Salvar como Preset'; + @override + String get equalizerResetToFlatAction => 'Repor para plano'; + @override String get equalizerSavePresetDialogTitle => 'Salvar como Preset'; diff --git a/lib/l10n/gen/app_localizations_ru.dart b/lib/l10n/gen/app_localizations_ru.dart index 66f929c..070ac83 100644 --- a/lib/l10n/gen/app_localizations_ru.dart +++ b/lib/l10n/gen/app_localizations_ru.dart @@ -250,6 +250,9 @@ class AppLocalizationsRu extends AppLocalizations { @override String get equalizerSaveAsPresetAction => 'Сохранить как пресет'; + @override + String get equalizerResetToFlatAction => 'Сбросить на плоский'; + @override String get equalizerSavePresetDialogTitle => 'Сохранить как пресет'; diff --git a/lib/l10n/gen/app_localizations_zh.dart b/lib/l10n/gen/app_localizations_zh.dart index 9ac3ed4..3a0b352 100644 --- a/lib/l10n/gen/app_localizations_zh.dart +++ b/lib/l10n/gen/app_localizations_zh.dart @@ -238,6 +238,9 @@ class AppLocalizationsZh extends AppLocalizations { @override String get equalizerSaveAsPresetAction => '保存为预设'; + @override + String get equalizerResetToFlatAction => '重置为平坦'; + @override String get equalizerSavePresetDialogTitle => '保存为预设'; diff --git a/lib/pantallas/ajustes/pantalla_ajustes_ecualizador.dart b/lib/pantallas/ajustes/pantalla_ajustes_ecualizador.dart index 4d8c1e8..b899295 100644 --- a/lib/pantallas/ajustes/pantalla_ajustes_ecualizador.dart +++ b/lib/pantallas/ajustes/pantalla_ajustes_ecualizador.dart @@ -6,6 +6,7 @@ import 'package:provider/provider.dart'; import '../../estado/estado_ecualizador.dart'; import '../../estado/estado_radio.dart'; import '../../l10n/gen/app_localizations.dart'; +import '../../modelos/preset_ecualizador.dart'; import '../../tema/pluriwave_theme.dart'; import '../../widgets/ecualizador_widget.dart'; import '../../widgets/pluri_glass_surface.dart'; @@ -22,6 +23,15 @@ import '../../widgets/pluri_push_scaffold.dart'; /// base-vs-per-station explainer, the "Salida activa" summary row, the /// "Emisoras con ajuste propio" drill-down, and the "Guardar como preset" /// custom-preset flow — see `_CuerpoEcualizador` below. +/// +/// Audit 11.10/11.8 (t4 lines 570-602, item 19): the prototype draws 4 +/// SEPARATE cards (explainer banner / band sliders / "Salida activa + +/// Guardar como preset + Restablecer a plano" / "Emisoras con ajuste +/// propio"), not one shared glass surface wrapping everything — and adds +/// a "Restablecer a plano" action the build never had. `_CuerpoEcualizador` +/// no longer wraps its children in one outer `PluriGlassSurface`; each +/// section now either already draws its own background +/// ([EcualizadorWidget], unchanged) or gained one here. class PantallaAjustesEcualizador extends StatelessWidget { const PantallaAjustesEcualizador({super.key}); @@ -70,67 +80,66 @@ class _CuerpoEcualizadorState extends State<_CuerpoEcualizador> { emisoraActual != null && estado.emisoraActualEsFavorita; final usandoEqPropio = eq.emisoraActualTienePresetPropio; - return PluriGlassSurface( - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + SwitchListTile.adaptive( + contentPadding: EdgeInsets.zero, + title: Text(l10n.equalizerEnable), + subtitle: Text( + disponible + ? l10n.equalizerRealtimeSubtitle + : l10n.equalizerPendingSubtitle, + ), + value: eq.activo, + onChanged: eq.cambiarActivo, + ), + if (mostrarModoPorEmisora) ...[ + const SizedBox(height: 8), SwitchListTile.adaptive( contentPadding: EdgeInsets.zero, - title: Text(l10n.equalizerEnable), + title: Text(l10n.equalizerPerStationTitle), subtitle: Text( - disponible - ? l10n.equalizerRealtimeSubtitle - : l10n.equalizerPendingSubtitle, - ), - value: eq.activo, - onChanged: eq.cambiarActivo, - ), - if (mostrarModoPorEmisora) ...[ - const SizedBox(height: 8), - SwitchListTile.adaptive( - contentPadding: EdgeInsets.zero, - title: Text(l10n.equalizerPerStationTitle), - subtitle: Text( - usandoEqPropio - ? l10n.equalizerPerStationActive(emisoraActual.nombre) - : l10n.equalizerPerStationMain(emisoraActual.nombre), - ), - value: usandoEqPropio, - onChanged: - (usarPropio) => - eq.cambiarModoEmisoraActual(usarPropio: usarPropio), - ), - ], - const SizedBox(height: 12), - _BannerExplicacionBase(l10n: l10n), - const SizedBox(height: 8), - _FilaSalidaActiva(eq: eq, l10n: l10n), - const SizedBox(height: 4), - _FilaEmisorasConAjustePropio(eq: eq, estado: estado, l10n: l10n), - const SizedBox(height: 12), - PresetsEcualizadorWidget( - presetActual: eq.presetActual, - personalizados: eq.presetsPersonalizados, - onSeleccionar: (p) => eq.cambiarPreset(p), - ), - const SizedBox(height: 12), - EcualizadorWidget( - preset: eq.presetActual, - habilitado: eq.activo, - onCambio: (p) => eq.cambiarPreset(p), - ), - const SizedBox(height: 12), - Align( - alignment: Alignment.centerRight, - child: TextButton.icon( - key: const Key('eq-save-preset-action'), - onPressed: () => _abrirDialogoGuardarPreset(context, eq), - icon: const Icon(Icons.bookmark_add_outlined, size: 20), - label: Text(l10n.equalizerSaveAsPresetAction), + usandoEqPropio + ? l10n.equalizerPerStationActive(emisoraActual.nombre) + : l10n.equalizerPerStationMain(emisoraActual.nombre), ), + value: usandoEqPropio, + onChanged: + (usarPropio) => + eq.cambiarModoEmisoraActual(usarPropio: usarPropio), ), ], - ), + const SizedBox(height: 12), + // CARD 1 (t4 line 571) — already its own tinted Container. + _BannerExplicacionBase(l10n: l10n), + const SizedBox(height: 16), + // Bare row, no card (t4 lines 573-578) — unchanged. + PresetsEcualizadorWidget( + presetActual: eq.presetActual, + personalizados: eq.presetsPersonalizados, + onSeleccionar: (p) => eq.cambiarPreset(p), + ), + const SizedBox(height: 14), + // CARD 2 (t4 lines 580-590) — EcualizadorWidget already draws + // its own PluriGlassSurface (design ADR-5), unchanged here. + EcualizadorWidget( + preset: eq.presetActual, + habilitado: eq.activo, + onCambio: (p) => eq.cambiarPreset(p), + ), + const SizedBox(height: 14), + // CARD 3 (t4 lines 592-598): Salida activa / Guardar como + // preset / Restablecer a plano, grouped. + _TarjetaSalidaYAcciones( + eq: eq, + l10n: l10n, + onGuardarPreset: () => _abrirDialogoGuardarPreset(context, eq), + ), + const SizedBox(height: 14), + // CARD 4 (t4 lines 600-602) — its own PluriGlassSurface now. + _FilaEmisorasConAjustePropio(eq: eq, estado: estado, l10n: l10n), + ], ); }, ); @@ -204,7 +213,7 @@ class _FilaSalidaActiva extends StatelessWidget { return Padding( key: const Key('eq-active-output-row'), - padding: const EdgeInsets.symmetric(vertical: 4), + padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12), child: Row( children: [ const Icon(Icons.speaker_group_rounded, size: 20), @@ -230,9 +239,107 @@ class _FilaSalidaActiva extends StatelessWidget { } } +/// Audit 11.8 (t4 lines 592-598): groups "Salida activa", "Guardar como +/// preset" and the entirely-missing "Restablecer a plano" into ONE card — +/// the build previously drew the first as a bare row and the second as a +/// floating, right-aligned button at the bottom of the whole screen. +/// "Restablecer a plano" is not a new capability: `PresetEcualizador.flat` +/// is the SAME preset the "Plano" chip in [PresetsEcualizadorWidget] +/// already applies via `EstadoEcualizador.cambiarPreset` — this is just a +/// second, prototype-mandated entry point to it. +class _TarjetaSalidaYAcciones extends StatelessWidget { + const _TarjetaSalidaYAcciones({ + required this.eq, + required this.l10n, + required this.onGuardarPreset, + }); + + final EstadoEcualizador eq; + final AppLocalizations l10n; + final VoidCallback onGuardarPreset; + + @override + Widget build(BuildContext context) { + return PluriGlassSurface( + key: const Key('eq-card-output-actions'), + borderRadius: BorderRadius.circular(context.pluriTokens.radiusMd), + padding: EdgeInsets.zero, + child: Column( + children: [ + _FilaSalidaActiva(eq: eq, l10n: l10n), + const Divider(height: 1), + _FilaAccionTarjeta( + key: const Key('eq-save-preset-action'), + icon: Icons.bookmark_add_outlined, + label: l10n.equalizerSaveAsPresetAction, + trailing: const Icon(Icons.chevron_right_rounded, size: 19), + onTap: onGuardarPreset, + ), + const Divider(height: 1), + _FilaAccionTarjeta( + key: const Key('eq-reset-flat-action'), + icon: Icons.restart_alt_rounded, + label: l10n.equalizerResetToFlatAction, + onTap: () => eq.cambiarPreset(PresetEcualizador.flat), + ), + ], + ), + ); + } +} + +/// One tappable icon+label row inside [_TarjetaSalidaYAcciones] — shared +/// shape for "Guardar como preset" and "Restablecer a plano" (t4 lines +/// 595, 597: identical row layout, only "Guardar..." has a trailing +/// chevron since it opens a dialog rather than acting immediately). +class _FilaAccionTarjeta extends StatelessWidget { + const _FilaAccionTarjeta({ + super.key, + required this.icon, + required this.label, + required this.onTap, + this.trailing, + }); + + final IconData icon; + final String label; + final VoidCallback onTap; + final Widget? trailing; + + @override + Widget build(BuildContext context) { + return Material( + type: MaterialType.transparency, + child: InkWell( + onTap: onTap, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 13), + child: Row( + children: [ + Icon(icon, size: 21), + const SizedBox(width: 12), + Expanded( + child: Text( + label, + style: Theme.of(context).textTheme.bodyMedium, + ), + ), + if (trailing != null) trailing!, + ], + ), + ), + ), + ); + } +} + /// "Emisoras con ajuste propio" drill-down row (spec `eq-custom-presets` /// "Stations-With-Own-EQ Drill-Down"): sourced from the existing /// `presetsPorEmisora` map, no new state. +/// +/// Audit 11.10 (t4 lines 600-602): CARD 4 — now wraps itself in its own +/// `PluriGlassSurface` instead of being one more row inside a shared +/// glass block. class _FilaEmisorasConAjustePropio extends StatelessWidget { const _FilaEmisorasConAjustePropio({ required this.eq, @@ -247,48 +354,53 @@ class _FilaEmisorasConAjustePropio extends StatelessWidget { @override Widget build(BuildContext context) { final uuids = eq.presetsPorEmisora.keys.toList(); - return Material( - type: MaterialType.transparency, - child: InkWell( - key: const Key('eq-stations-own-eq-row'), - borderRadius: BorderRadius.circular(context.pluriTokens.radiusSm), - onTap: - () => PluriPushScaffold.push( - context, - (_) => _PantallaEmisorasConAjustePropio( - uuids: uuids, - nombrePorUuid: (uuid) => _resolverNombreEmisora(estado, uuid), - ), - ), - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: Row( - children: [ - const Icon(Icons.tune_rounded, size: 20), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - l10n.equalizerStationsWithOwnEqTitle, - style: Theme.of(context).textTheme.bodyMedium, - ), - Text( - l10n.equalizerStationsWithOwnEqSubtitle, - style: Theme.of(context).textTheme.bodySmall, - ), - ], + return PluriGlassSurface( + key: const Key('eq-card-stations-own-eq'), + borderRadius: BorderRadius.circular(context.pluriTokens.radiusMd), + padding: EdgeInsets.zero, + child: Material( + type: MaterialType.transparency, + child: InkWell( + key: const Key('eq-stations-own-eq-row'), + borderRadius: BorderRadius.circular(context.pluriTokens.radiusMd), + onTap: + () => PluriPushScaffold.push( + context, + (_) => _PantallaEmisorasConAjustePropio( + uuids: uuids, + nombrePorUuid: (uuid) => _resolverNombreEmisora(estado, uuid), ), ), - Text( - key: const Key('eq-stations-own-eq-count'), - '${uuids.length}', - style: Theme.of(context).textTheme.bodySmall, - ), - const SizedBox(width: 4), - const Icon(Icons.chevron_right_rounded, size: 20), - ], + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 13), + child: Row( + children: [ + const Icon(Icons.tune_rounded, size: 20), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + l10n.equalizerStationsWithOwnEqTitle, + style: Theme.of(context).textTheme.bodyMedium, + ), + Text( + l10n.equalizerStationsWithOwnEqSubtitle, + style: Theme.of(context).textTheme.bodySmall, + ), + ], + ), + ), + Text( + key: const Key('eq-stations-own-eq-count'), + '${uuids.length}', + style: Theme.of(context).textTheme.bodySmall, + ), + const SizedBox(width: 4), + const Icon(Icons.chevron_right_rounded, size: 20), + ], + ), ), ), ), diff --git a/test/pantallas/ajustes/pantalla_ajustes_ecualizador_test.dart b/test/pantallas/ajustes/pantalla_ajustes_ecualizador_test.dart index ac69d7a..d8c58ea 100644 --- a/test/pantallas/ajustes/pantalla_ajustes_ecualizador_test.dart +++ b/test/pantallas/ajustes/pantalla_ajustes_ecualizador_test.dart @@ -9,6 +9,8 @@ import 'package:pluriwave/modelos/dispositivo_audio.dart'; import 'package:pluriwave/modelos/emisora.dart'; import 'package:pluriwave/modelos/preset_ecualizador.dart'; import 'package:pluriwave/pantallas/ajustes/pantalla_ajustes_ecualizador.dart'; +import 'package:pluriwave/widgets/ecualizador_widget.dart'; +import 'package:pluriwave/widgets/pluri_glass_surface.dart'; import 'package:pluriwave/widgets/pluri_push_scaffold.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -249,6 +251,12 @@ void main() { equals('2'), ); + // Item 19's 4-card restructure made the page taller — the row now + // sits below the default 800x600 test viewport. + await tester.ensureVisible( + find.byKey(const Key('eq-stations-own-eq-row')), + ); + await tester.pumpAndSettle(); await tester.tap(find.byKey(const Key('eq-stations-own-eq-row'))); await tester.pumpAndSettle(); @@ -270,6 +278,12 @@ void main() { await tester.pumpWidget(buildScreen(estado)); await tester.pumpAndSettle(); + // Item 19's 4-card restructure made the page taller — the row now + // sits below the default 800x600 test viewport. + await tester.ensureVisible( + find.byKey(const Key('eq-stations-own-eq-row')), + ); + await tester.pumpAndSettle(); await tester.tap(find.byKey(const Key('eq-stations-own-eq-row'))); await tester.pumpAndSettle(); @@ -340,6 +354,99 @@ void main() { }, ); + testWidgets('visual fidelity (audit 11.10): the explainer banner and the ' + 'stations-with-own-EQ row are SEPARATE cards, not one shared glass ' + 'surface', (tester) async { + _suppressListTileInkAssertion(); + final estado = await crearEstado(); + addTearDown(estado.dispose); + + await tester.pumpWidget(buildScreen(estado)); + await tester.pumpAndSettle(); + + final explainerCard = find.ancestor( + of: find.byKey(const Key('eq-base-explainer-banner')), + matching: find.byType(PluriGlassSurface), + ); + expect( + find.descendant( + of: explainerCard, + matching: find.byKey(const Key('eq-stations-own-eq-row')), + ), + findsNothing, + reason: + 't4 lines 571/600-602: the prototype draws these as 2 of 4 ' + 'separate cards, not one merged block', + ); + // EcualizadorWidget already wraps itself in its own PluriGlassSurface + // (design ADR-5) — this stays true once the OUTER wrapper is gone. + expect( + find.descendant( + of: find.byType(EcualizadorWidget), + matching: find.byType(PluriGlassSurface), + ), + findsOneWidget, + ); + }); + + testWidgets( + 'visual fidelity (audit 11.8): Salida activa, Guardar como preset and ' + 'Restablecer a plano are grouped into ONE card', + (tester) async { + _suppressListTileInkAssertion(); + final estado = await crearEstado(); + addTearDown(estado.dispose); + + await tester.pumpWidget(buildScreen(estado)); + await tester.pumpAndSettle(); + + final outputCard = find.ancestor( + of: find.byKey(const Key('eq-active-output-row')), + matching: find.byType(PluriGlassSurface), + ); + expect(outputCard, findsOneWidget); + expect( + find.descendant( + of: outputCard, + matching: find.byKey(const Key('eq-save-preset-action')), + ), + findsOneWidget, + reason: 't4 lines 592-598: one grouped card for all 3 rows', + ); + expect( + find.descendant( + of: outputCard, + matching: find.byKey(const Key('eq-reset-flat-action')), + ), + findsOneWidget, + ); + }, + ); + + testWidgets( + 'visual fidelity (audit 11.8): tapping Restablecer a plano resets the ' + 'active preset to Flat', + (tester) async { + _suppressListTileInkAssertion(); + final estado = await crearEstado(); + addTearDown(estado.dispose); + await estado.ecualizador.cambiarPreset(PresetEcualizador.rock); + expect(estado.ecualizador.presetActual, PresetEcualizador.rock); + + await tester.pumpWidget(buildScreen(estado)); + await tester.pumpAndSettle(); + + await tester.ensureVisible( + find.byKey(const Key('eq-reset-flat-action')), + ); + await tester.pumpAndSettle(); + await tester.tap(find.byKey(const Key('eq-reset-flat-action'))); + await tester.pumpAndSettle(); + + expect(estado.ecualizador.presetActual, PresetEcualizador.flat); + }, + ); + testWidgets( 'Guardar como preset with a whitespace-only name shows the same validation message', (tester) async {