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:
@@ -543,8 +543,17 @@ class _PantallaBuscarState extends State<PantallaBuscar> {
|
|||||||
if (estado.cargando) {
|
if (estado.cargando) {
|
||||||
// S5-R6: shimmer placeholders instead of a bare spinner, consistent
|
// S5-R6: shimmer placeholders instead of a bare spinner, consistent
|
||||||
// with the loading pattern used by the home grid.
|
// 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(
|
return Padding(
|
||||||
padding: const EdgeInsets.all(PluriLayout.horizontal),
|
padding: const EdgeInsets.fromLTRB(
|
||||||
|
PluriLayout.rowHorizontal,
|
||||||
|
PluriLayout.sectionGap,
|
||||||
|
PluriLayout.rowHorizontal,
|
||||||
|
PluriLayout.rowHorizontal,
|
||||||
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@@ -579,8 +588,17 @@ class _PantallaBuscarState extends State<PantallaBuscar> {
|
|||||||
// across the app -- favorites, the discovery grid -- which this
|
// across the app -- favorites, the discovery grid -- which this
|
||||||
// item does not touch).
|
// item does not touch).
|
||||||
final query = _controller.text.trim();
|
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(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: PluriLayout.horizontal),
|
padding: const EdgeInsets.fromLTRB(
|
||||||
|
PluriLayout.horizontal,
|
||||||
|
PluriLayout.sectionGap,
|
||||||
|
PluriLayout.horizontal,
|
||||||
|
0,
|
||||||
|
),
|
||||||
child: _TarjetaSinResultados(
|
child: _TarjetaSinResultados(
|
||||||
titulo:
|
titulo:
|
||||||
sinFiltros
|
sinFiltros
|
||||||
@@ -616,7 +634,17 @@ class _PantallaBuscarState extends State<PantallaBuscar> {
|
|||||||
return ListView.builder(
|
return ListView.builder(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
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,
|
itemCount: total,
|
||||||
itemBuilder: (context, i) {
|
itemBuilder: (context, i) {
|
||||||
if (i >= resultados.length) {
|
if (i >= resultados.length) {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import 'package:pluriwave/servicios/servicio_audio.dart';
|
|||||||
import 'package:pluriwave/tema/pluriwave_theme.dart';
|
import 'package:pluriwave/tema/pluriwave_theme.dart';
|
||||||
import 'package:pluriwave/tema/pluriwave_tokens.dart';
|
import 'package:pluriwave/tema/pluriwave_tokens.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/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';
|
||||||
@@ -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(
|
testWidgets(
|
||||||
'tapping the favourite toggle on a search result adds it to favorites',
|
'tapping the favourite toggle on a search result adds it to favorites',
|
||||||
(tester) async {
|
(tester) async {
|
||||||
|
|||||||
Reference in New Issue
Block a user