fix(favoritos): stop the header padding from doubling up
Issue 3 (feedback-pruebas): ReorderableListView.padding wrapped header/rows/footer with a single horizontal value (16), which doubled up on top of PluriRootHeader's own internal inset -- landing the title at 36px instead of the 20px every other root uses -- while also applying card-tier padding to the flat FilaEmisoraPlana rows (row tier, matching the same widget's fix on Buscar) and leaving the populated-state top gap at an unwired 4 that didn't match this same screen's own empty state (0) or the footer CTA's prototype value (8). Zeroes the list-level padding and gives the header, chip strip, rows, and footer CTA their own correctly-tiered insets instead.
This commit is contained in:
@@ -174,12 +174,18 @@ class _PantallaFavoritosState extends State<PantallaFavoritos> {
|
|||||||
|
|
||||||
return ReorderableListView(
|
return ReorderableListView(
|
||||||
buildDefaultDragHandles: false,
|
buildDefaultDragHandles: false,
|
||||||
padding: const EdgeInsets.fromLTRB(
|
// Issue 3 (feedback-pruebas): zero horizontal here, matching every
|
||||||
PluriLayout.horizontal,
|
// other root's PluriLayout.pageListPadding convention (Alarmas,
|
||||||
4,
|
// Ajustes, and this screen's OWN empty-state branch above).
|
||||||
PluriLayout.horizontal,
|
// ReorderableListView.padding wraps header/children/footer UNIFORMLY,
|
||||||
PluriLayout.bottomChromeInset,
|
// so a single horizontal value here can never be simultaneously right
|
||||||
),
|
// for PluriRootHeader (self-padded, wants none), the reorderable rows
|
||||||
|
// (want row tier, applied per item below) and the footer CTA (wants
|
||||||
|
// card tier, applied on the footer's own Padding below). The previous
|
||||||
|
// `PluriLayout.horizontal` doubled up on top of PluriRootHeader's own
|
||||||
|
// internal inset, pushing "Favorites" in by 36px instead of the 20px
|
||||||
|
// every other root uses for its title.
|
||||||
|
padding: const EdgeInsets.only(bottom: PluriLayout.bottomChromeInset),
|
||||||
header: Padding(
|
header: Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 12),
|
padding: const EdgeInsets.only(bottom: 12),
|
||||||
child: Column(
|
child: Column(
|
||||||
@@ -224,17 +230,39 @@ class _PantallaFavoritosState extends State<PantallaFavoritos> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
_FilaChipsGrupos(
|
// Issue 3 (feedback-pruebas): t4:218 draws this chip strip at
|
||||||
|
// title-tier (20px) horizontal inset, directly on the page
|
||||||
|
// background -- it now needs its OWN inset since the list's
|
||||||
|
// padding no longer supplies one.
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: PluriLayout.titleHorizontal,
|
||||||
|
),
|
||||||
|
child: _FilaChipsGrupos(
|
||||||
grupos: gruposVisibles,
|
grupos: gruposVisibles,
|
||||||
favoritos: favoritos,
|
favoritos: favoritos,
|
||||||
seleccionado: seleccionEfectiva,
|
seleccionado: seleccionEfectiva,
|
||||||
onSeleccionar: (id) => setState(() => _grupoSeleccionadoId = id),
|
onSeleccionar:
|
||||||
|
(id) => setState(() => _grupoSeleccionadoId = id),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
footer: Padding(
|
footer: Padding(
|
||||||
padding: const EdgeInsets.only(top: 4),
|
// Issue 3 (feedback-pruebas): card tier (16, matching every other
|
||||||
|
// screen's dashed CTA) now that the list's own padding no longer
|
||||||
|
// supplies it, plus t4:234's 8px gap above the CTA
|
||||||
|
// (PluriLayout.compactGap) instead of the previous unwired literal
|
||||||
|
// 4 -- the ONLY state of this screen with a nonzero top gap before
|
||||||
|
// its own content used a value that matched neither this screen's
|
||||||
|
// own empty-state branch nor the prototype.
|
||||||
|
padding: const EdgeInsets.fromLTRB(
|
||||||
|
PluriLayout.horizontal,
|
||||||
|
PluriLayout.compactGap,
|
||||||
|
PluriLayout.horizontal,
|
||||||
|
0,
|
||||||
|
),
|
||||||
child: _CtaEmisoraPersonalizada(
|
child: _CtaEmisoraPersonalizada(
|
||||||
onTap: _abrirFormularioEmisoraPersonalizada,
|
onTap: _abrirFormularioEmisoraPersonalizada,
|
||||||
),
|
),
|
||||||
@@ -244,8 +272,17 @@ class _PantallaFavoritosState extends State<PantallaFavoritos> {
|
|||||||
_onReorder(filtrados, favoritos, oldIndex, newIndex),
|
_onReorder(filtrados, favoritos, oldIndex, newIndex),
|
||||||
children: [
|
children: [
|
||||||
for (var i = 0; i < filtrados.length; i++)
|
for (var i = 0; i < filtrados.length; i++)
|
||||||
_FilaFavorito(
|
// Issue 3 (feedback-pruebas): row tier (12), not card tier -- the
|
||||||
|
// key moves to this wrapper (ReorderableListView identifies each
|
||||||
|
// child by its own top-level key) since FilaEmisoraPlana rows are
|
||||||
|
// documented (audit 4.3) as flat, background-less rows, the same
|
||||||
|
// tier Buscar's results list already uses for the same widget.
|
||||||
|
Padding(
|
||||||
key: ValueKey(filtrados[i].uuid),
|
key: ValueKey(filtrados[i].uuid),
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: PluriLayout.rowHorizontal,
|
||||||
|
),
|
||||||
|
child: _FilaFavorito(
|
||||||
index: i,
|
index: i,
|
||||||
emisora: filtrados[i],
|
emisora: filtrados[i],
|
||||||
grupos: gruposVisibles,
|
grupos: gruposVisibles,
|
||||||
@@ -254,6 +291,7 @@ class _PantallaFavoritosState extends State<PantallaFavoritos> {
|
|||||||
orElse: () => gruposVisibles.first,
|
orElse: () => gruposVisibles.first,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -343,7 +381,6 @@ class _FilaChipsGrupos extends StatelessWidget {
|
|||||||
|
|
||||||
class _FilaFavorito extends StatelessWidget {
|
class _FilaFavorito extends StatelessWidget {
|
||||||
const _FilaFavorito({
|
const _FilaFavorito({
|
||||||
super.key,
|
|
||||||
required this.index,
|
required this.index,
|
||||||
required this.emisora,
|
required this.emisora,
|
||||||
required this.grupos,
|
required this.grupos,
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ import 'package:pluriwave/l10n/gen/app_localizations.dart';
|
|||||||
import 'package:pluriwave/pantallas/ajustes/pantalla_ajustes_grupos_favoritos.dart';
|
import 'package:pluriwave/pantallas/ajustes/pantalla_ajustes_grupos_favoritos.dart';
|
||||||
import 'package:pluriwave/pantallas/pantalla_favoritos.dart';
|
import 'package:pluriwave/pantallas/pantalla_favoritos.dart';
|
||||||
import 'package:pluriwave/widgets/fila_emisora_plana.dart';
|
import 'package:pluriwave/widgets/fila_emisora_plana.dart';
|
||||||
|
import 'package:pluriwave/widgets/pluri_layout.dart';
|
||||||
import 'package:pluriwave/widgets/pluri_push_scaffold.dart';
|
import 'package:pluriwave/widgets/pluri_push_scaffold.dart';
|
||||||
|
import 'package:pluriwave/widgets/pluri_root_header.dart';
|
||||||
import 'package:pluriwave/widgets/tarjeta_emisora.dart';
|
import 'package:pluriwave/widgets/tarjeta_emisora.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
@@ -546,6 +548,106 @@ void main() {
|
|||||||
expect(inactivo.backgroundColor, const Color(0xFF102532));
|
expect(inactivo.backgroundColor, const Color(0xFF102532));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
group('Issue 3 (feedback-pruebas): spacing tiers', () {
|
||||||
|
testWidgets('the header title sits at title-tier inset (20px) -- '
|
||||||
|
'ReorderableListView.padding used to double up on top of '
|
||||||
|
"PluriRootHeader's own internal inset", (tester) async {
|
||||||
|
setLargeSurface(tester);
|
||||||
|
_suppressListTileInkAssertion();
|
||||||
|
final estado = await crearEstadoConFavoritos();
|
||||||
|
addTearDown(estado.dispose);
|
||||||
|
final l10n = lookupAppLocalizations(const Locale('en'));
|
||||||
|
|
||||||
|
await tester.pumpWidget(buildScreen(estado));
|
||||||
|
await pumpStable(tester);
|
||||||
|
|
||||||
|
final titulo = find.descendant(
|
||||||
|
of: find.byType(PluriRootHeader),
|
||||||
|
matching: find.text(l10n.favoritesTitle),
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
tester.getTopLeft(titulo).dx,
|
||||||
|
PluriLayout.titleHorizontal,
|
||||||
|
reason:
|
||||||
|
'PluriRootHeader already supplies its own 20px inset; the '
|
||||||
|
'previous ReorderableListView.padding of 16 doubled up on top '
|
||||||
|
'of it, landing the title at 36px instead of 20px -- the ONE '
|
||||||
|
"root screen whose header didn't match Alarmas/Ajustes",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'the header sits at the SAME horizontal position whether the list is '
|
||||||
|
'empty or populated -- two mutually-exclusive states of the same '
|
||||||
|
'header must not read differently',
|
||||||
|
(tester) async {
|
||||||
|
setLargeSurface(tester);
|
||||||
|
final l10n = lookupAppLocalizations(const Locale('en'));
|
||||||
|
|
||||||
|
final vacio = await crearEstadoVacio();
|
||||||
|
addTearDown(vacio.dispose);
|
||||||
|
await tester.pumpWidget(buildScreen(vacio));
|
||||||
|
await pumpStable(tester);
|
||||||
|
final dxVacio =
|
||||||
|
tester
|
||||||
|
.getTopLeft(
|
||||||
|
find.descendant(
|
||||||
|
of: find.byType(PluriRootHeader),
|
||||||
|
matching: find.text(l10n.favoritesTitle),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.dx;
|
||||||
|
|
||||||
|
_suppressListTileInkAssertion();
|
||||||
|
final conFavoritos = await crearEstadoConFavoritos();
|
||||||
|
addTearDown(conFavoritos.dispose);
|
||||||
|
await tester.pumpWidget(buildScreen(conFavoritos));
|
||||||
|
await pumpStable(tester);
|
||||||
|
final dxConFavoritos =
|
||||||
|
tester
|
||||||
|
.getTopLeft(
|
||||||
|
find.descendant(
|
||||||
|
of: find.byType(PluriRootHeader),
|
||||||
|
matching: find.text(l10n.favoritesTitle),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.dx;
|
||||||
|
|
||||||
|
expect(
|
||||||
|
dxConFavoritos,
|
||||||
|
dxVacio,
|
||||||
|
reason:
|
||||||
|
'the empty and populated branches of this screen must render '
|
||||||
|
'the SAME header inset -- they previously did not (0 vs 16 '
|
||||||
|
'extra px of list-level padding)',
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'each favourite row uses row-tier horizontal inset (12), not the '
|
||||||
|
'card-tier constant a background-less row was never meant to carry',
|
||||||
|
(tester) async {
|
||||||
|
setLargeSurface(tester);
|
||||||
|
_suppressListTileInkAssertion();
|
||||||
|
final estado = await crearEstadoConFavoritos();
|
||||||
|
addTearDown(estado.dispose);
|
||||||
|
|
||||||
|
await tester.pumpWidget(buildScreen(estado));
|
||||||
|
await pumpStable(tester);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
tester.getTopLeft(find.byType(FilaEmisoraPlana).first).dx,
|
||||||
|
PluriLayout.rowHorizontal,
|
||||||
|
reason:
|
||||||
|
'audit 4.3: background-less rows are row tier (12), matching '
|
||||||
|
'the same widget already fixed on Buscar -- not card tier '
|
||||||
|
'(16)',
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void setLargeSurface(WidgetTester tester) {
|
void setLargeSurface(WidgetTester tester) {
|
||||||
|
|||||||
Reference in New Issue
Block a user