fix(buscar): correct the gaps between the filter row and the results

Issue 3 (partial): the results area had no top gap against the filter
row in one state and reused the horizontal constant for a vertical axis
in another. Applies the 3-tier scale properly -- row tier for
background-less placeholders, card tier for card states.

The rest of the app's spacing review is still outstanding.
This commit is contained in:
2026-07-30 20:18:59 +02:00
parent 727e18737a
commit fc866d7ec9
2 changed files with 104 additions and 3 deletions
+31 -3
View File
@@ -543,8 +543,17 @@ class _PantallaBuscarState extends State<PantallaBuscar> {
if (estado.cargando) {
// S5-R6: shimmer placeholders instead of a bare spinner, consistent
// with the loading pattern used by the home grid.
// Issue 3 (feedback-pruebas): row tier (12), not card tier (16) --
// these are background-less row placeholders, same tier as the real
// results below; the top inset is the standard section gap rather
// than the horizontal constant reused for a vertical axis.
return Padding(
padding: const EdgeInsets.all(PluriLayout.horizontal),
padding: const EdgeInsets.fromLTRB(
PluriLayout.rowHorizontal,
PluriLayout.sectionGap,
PluriLayout.rowHorizontal,
PluriLayout.rowHorizontal,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -579,8 +588,17 @@ class _PantallaBuscarState extends State<PantallaBuscar> {
// across the app -- favorites, the discovery grid -- which this
// item does not touch).
final query = _controller.text.trim();
// Issue 3 (feedback-pruebas): this card-tier state had NO top gap at
// all against the filter row above it -- the standard section gap
// now matches the other two mutually-exclusive results-area states
// (loading, populated) above.
return Padding(
padding: const EdgeInsets.symmetric(horizontal: PluriLayout.horizontal),
padding: const EdgeInsets.fromLTRB(
PluriLayout.horizontal,
PluriLayout.sectionGap,
PluriLayout.horizontal,
0,
),
child: _TarjetaSinResultados(
titulo:
sinFiltros
@@ -616,7 +634,17 @@ class _PantallaBuscarState extends State<PantallaBuscar> {
return ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
padding: const EdgeInsets.all(PluriLayout.horizontal),
// Issue 3 (feedback-pruebas): row tier (12), not card tier (16) --
// `FilaEmisoraPlana` rows are documented as "flat, background-less"
// (audit 6.5) but this padding never got updated to match when Tier 1
// introduced the 3-tier scale. The top inset is the standard section
// gap, not the horizontal constant reused for a vertical axis.
padding: const EdgeInsets.fromLTRB(
PluriLayout.rowHorizontal,
PluriLayout.sectionGap,
PluriLayout.rowHorizontal,
PluriLayout.rowHorizontal,
),
itemCount: total,
itemBuilder: (context, i) {
if (i >= resultados.length) {
+73
View File
@@ -15,6 +15,7 @@ import 'package:pluriwave/servicios/servicio_audio.dart';
import 'package:pluriwave/tema/pluriwave_theme.dart';
import 'package:pluriwave/tema/pluriwave_tokens.dart';
import 'package:pluriwave/widgets/fila_emisora_plana.dart';
import 'package:pluriwave/widgets/pluri_layout.dart';
import 'package:pluriwave/widgets/tarjeta_emisora.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
@@ -835,6 +836,78 @@ void main() {
);
});
testWidgets('issue 3 (feedback-pruebas): the results list uses row-tier '
'horizontal padding (12), not the card-tier constant this "flat, '
'background-less row" was documented as needing but never got', (
tester,
) async {
_setLargeSurfaceSize(tester);
final estado = _crearEstado(
radio: FakeServicioRadio(
busqueda: [emisoraDemo(uuid: 'r-1', nombre: 'Radio Uno')],
),
);
addTearDown(estado.dispose);
await tester.runAsync(estado.inicializar);
await tester.pumpWidget(_conProviders(estado, _testApp()));
await _pumpStableFrame(tester);
await tester.enterText(find.byType(SearchBar), 'radio');
await tester.testTextInput.receiveAction(TextInputAction.done);
await _pumpStableFrame(tester);
final fila = find.byType(FilaEmisoraPlana);
expect(
tester.getTopLeft(fila).dx,
PluriLayout.rowHorizontal,
reason:
'issue 3: background-less rows are row tier (12), not card '
'tier (16)',
);
});
testWidgets('issue 3 (feedback-pruebas): the results list is topped by the '
'standard section gap, not the horizontal-inset constant reused for '
'a vertical axis', (tester) async {
_setLargeSurfaceSize(tester);
final estado = _crearEstado(
radio: FakeServicioRadio(
busqueda: [emisoraDemo(uuid: 'r-1', nombre: 'Radio Uno')],
),
);
addTearDown(estado.dispose);
await tester.runAsync(estado.inicializar);
await tester.pumpWidget(_conProviders(estado, _testApp()));
await _pumpStableFrame(tester);
await tester.enterText(find.byType(SearchBar), 'radio');
await tester.testTextInput.receiveAction(TextInputAction.done);
await _pumpStableFrame(tester);
// Reads the structural padding directly, rather than measuring a
// gap between two rendered widgets — the count row's own height is
// dictated by its taller PopupMenuButton (48dp touch target), so a
// position-based gap measurement against the count TEXT specifically
// would be thrown off by that unrelated vertical centring.
//
// Scoped to `shrinkWrap: true` — the OUTER page ListView is ALSO an
// ancestor of every `FilaEmisoraPlana`, but only `_resultados`'s OWN
// inner `ListView.builder` sets `shrinkWrap`.
final listaResultados = tester.widget<ListView>(
find.byWidgetPredicate((w) => w is ListView && w.shrinkWrap),
);
final padding = listaResultados.padding as EdgeInsets;
expect(
padding.top,
PluriLayout.sectionGap,
reason:
'issue 3: the results list must use the dedicated vertical '
'section gap above its first row, not the horizontal (16) '
'constant reused for a vertical axis',
);
});
testWidgets(
'tapping the favourite toggle on a search result adds it to favorites',
(tester) async {