fix(eq): split the equalizer body into 4 cards, add Restablecer a plano
Audit 11.10/11.8 (t4 lines 570-602): the prototype draws the explainer banner, the band sliders, "Salida activa + Guardar como preset + Restablecer a plano" and "Emisoras con ajuste propio" as 4 separate cards. The build nested everything in one outer PluriGlassSurface, so it read as a single merged block, and had no reset-to-flat action at all. Removes the outer wrapper from _CuerpoEcualizador. EcualizadorWidget already draws its own card (design ADR-5, unchanged); the explainer banner already has its own tinted background (unchanged); "Emisoras con ajuste propio" now wraps itself in its own PluriGlassSurface; a new _TarjetaSalidaYAcciones groups Salida activa with two tappable rows — "Guardar como preset" (relocated from a floating end-aligned button) and the new "Restablecer a plano", which applies PresetEcualizador.flat via the existing EstadoEcualizador.cambiarPreset — the same call the "Plano" preset chip already makes, not a new capability. The 5-slider band count, servicio_ecualizador.dart and preset_ecualizador.dart are untouched.
This commit is contained in:
@@ -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),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user