refactor(state): extract recording and search state, scope screen rebuilds
- New EstadoGrabacion owns the recording service, subscription, directory/size preferences and open-file actions - New EstadoBusqueda owns search, nearby stations, pagination and the min-bitrate filter - New orden_emisoras.dart with the OrdenEmisoras enum, shared sorter and list identity memoization so context.select comparisons work on derived lists - Large screens (inicio, buscar, favoritos, ajustes, reproductor) consume scoped selects/dedicated notifiers instead of root context.watch<EstadoRadio>, so audio buffer events no longer rebuild whole screens - Remove all 15 TODO(S4b) compat members from EstadoRadio; consumers use the dedicated providers. EstadoRadio drops from ~1121 to 753 lines, keeping playback/stations/favorites orchestration - 8 new tests including a rebuild-scoping probe (110 total green), flutter analyze clean
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:pluriwave/estado/estado_busqueda.dart';
|
||||
|
||||
import '../helpers/fakes.dart';
|
||||
|
||||
/// S4-R3: EstadoBusqueda owns search query, results and loading state
|
||||
/// previously in EstadoRadio.
|
||||
void main() {
|
||||
test('actualizar la búsqueda notifica a los listeners', () async {
|
||||
final busqueda = EstadoBusqueda(
|
||||
radio: FakeServicioRadio(
|
||||
busqueda: [emisoraDemo(uuid: 'b-1', nombre: 'Resultado Uno')],
|
||||
),
|
||||
);
|
||||
addTearDown(busqueda.dispose);
|
||||
|
||||
var notificaciones = 0;
|
||||
busqueda.addListener(() => notificaciones++);
|
||||
|
||||
await busqueda.buscar(nombre: 'uno');
|
||||
|
||||
// At least once for the loading flag and once for the results.
|
||||
expect(notificaciones, greaterThanOrEqualTo(2));
|
||||
expect(busqueda.cargando, isFalse);
|
||||
expect(busqueda.resultados.map((e) => e.uuid), contains('b-1'));
|
||||
});
|
||||
|
||||
test('cargarMas pagina resultados y acota memoria', () async {
|
||||
final emisoras = List.generate(
|
||||
70,
|
||||
(i) => emisoraDemo(uuid: 'page-$i', nombre: 'Page $i'),
|
||||
);
|
||||
final busqueda = EstadoBusqueda(
|
||||
radio: FakeServicioRadio(busqueda: emisoras),
|
||||
);
|
||||
addTearDown(busqueda.dispose);
|
||||
|
||||
await busqueda.buscar(nombre: 'page');
|
||||
expect(busqueda.resultados, hasLength(30));
|
||||
expect(busqueda.hayMas, isTrue);
|
||||
|
||||
await busqueda.cargarMas();
|
||||
expect(busqueda.resultados, hasLength(60));
|
||||
|
||||
await busqueda.cargarMas();
|
||||
expect(busqueda.resultados, hasLength(70));
|
||||
expect(busqueda.hayMas, isFalse);
|
||||
});
|
||||
|
||||
test(
|
||||
'resultados conserva identidad entre lecturas sin cambios (S4-R5)',
|
||||
() async {
|
||||
final busqueda = EstadoBusqueda(
|
||||
radio: FakeServicioRadio(
|
||||
busqueda: [emisoraDemo(uuid: 'b-1', nombre: 'Resultado Uno')],
|
||||
),
|
||||
);
|
||||
addTearDown(busqueda.dispose);
|
||||
|
||||
await busqueda.buscar(nombre: 'uno');
|
||||
|
||||
// Identity-stable getters let `context.select` skip rebuilds when the
|
||||
// underlying data did not change.
|
||||
expect(identical(busqueda.resultados, busqueda.resultados), isTrue);
|
||||
},
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user