fix(ui): unify scroll and improve playback switching
Build & Deploy Pluriwave / Análisis de código (push) Successful in 12s
Build & Deploy Pluriwave / Build APK + AAB release (push) Successful in 1m17s

This commit is contained in:
2026-05-20 23:44:14 +02:00
parent 34022e0814
commit 10520fef48
5 changed files with 138 additions and 191 deletions
+22 -12
View File
@@ -67,7 +67,8 @@ class _PantallaBuscarState extends State<PantallaBuscar> {
final estado = context.watch<EstadoRadio>();
final theme = Theme.of(context);
return Column(
return ListView(
padding: const EdgeInsets.fromLTRB(0, 0, 0, 124),
children: [
PluriScreenHeader(
title: 'Buscar senal',
@@ -125,7 +126,7 @@ class _PantallaBuscarState extends State<PantallaBuscar> {
_buscar();
},
),
Expanded(child: _resultados(estado, theme)),
_resultados(estado, theme),
],
);
}
@@ -144,7 +145,7 @@ class _PantallaBuscarState extends State<PantallaBuscar> {
children: [
Expanded(
child: Text(
pais == null ? 'Emisoras cercanas' : 'Emisoras cercanas ? $pais',
pais == null ? 'Emisoras cercanas' : 'Emisoras cercanas - $pais',
style: theme.textTheme.labelLarge?.copyWith(
fontWeight: FontWeight.w900,
),
@@ -247,7 +248,10 @@ class _PantallaBuscarState extends State<PantallaBuscar> {
Widget _resultados(EstadoRadio estado, ThemeData theme) {
if (estado.cargandoBusqueda) {
return const Center(child: CircularProgressIndicator());
return const SizedBox(
height: 220,
child: Center(child: CircularProgressIndicator()),
);
}
final resultados = estado.resultadosBusqueda;
@@ -257,18 +261,24 @@ class _PantallaBuscarState extends State<PantallaBuscar> {
_controller.text.isEmpty &&
_paisSeleccionado == null &&
_idiomaSeleccionado == null;
return PluriEmptyState(
glyph: PluriIconGlyph.search,
title: sinFiltros ? 'Busca una emisora' : 'Sin resultados',
subtitle: sinFiltros
? 'Usa la barra superior o los chips para descubrir senales de todo el mundo.'
: 'Proba quitar filtros o escribir otro nombre para encontrar una senal activa.',
return SizedBox(
height: 260,
child: PluriEmptyState(
glyph: PluriIconGlyph.search,
title: sinFiltros ? 'Busca una emisora' : 'Sin resultados',
subtitle: sinFiltros
? 'Usa la barra superior o los chips para descubrir senales de todo el mundo.'
: 'Proba quitar filtros o escribir otro nombre para encontrar una senal activa.',
),
);
}
final total = resultados.length + (estado.hayMasBusqueda ? 1 : 0);
return ListView.separated(
padding: const EdgeInsets.fromLTRB(16, 16, 16, 120),
itemCount: resultados.length + (estado.hayMasBusqueda ? 1 : 0),
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
padding: const EdgeInsets.fromLTRB(16, 16, 16, 16),
itemCount: total,
separatorBuilder: (_, __) => const SizedBox(height: 10),
itemBuilder: (context, i) {
if (i >= resultados.length) {
+18 -14
View File
@@ -18,7 +18,8 @@ class PantallaFavoritos extends StatelessWidget {
final favoritos = estado.listaFavoritos;
if (favoritos.isEmpty) {
return const Column(
return ListView(
padding: EdgeInsets.fromLTRB(0, 0, 0, 124),
children: [
PluriScreenHeader(
title: 'Favoritos',
@@ -29,7 +30,8 @@ class PantallaFavoritos extends StatelessWidget {
label: 'Coleccion',
),
),
Expanded(
SizedBox(
height: 320,
child: PluriEmptyState(
glyph: PluriIconGlyph.favorites,
title: 'Sin favoritos aun',
@@ -40,20 +42,22 @@ class PantallaFavoritos extends StatelessWidget {
);
}
return Column(
children: [
PluriScreenHeader(
title: 'Favoritos',
subtitle: 'Reordena tu coleccion y deja arriba las radios que mas importan.',
glyph: PluriIconGlyph.favorites,
trailing: PluriStatusPill(
icon: Icons.library_music_rounded,
label: '${favoritos.length} guardadas',
return CustomScrollView(
slivers: [
SliverToBoxAdapter(
child: PluriScreenHeader(
title: 'Favoritos',
subtitle: 'Reordena tu coleccion y deja arriba las radios que mas importan.',
glyph: PluriIconGlyph.favorites,
trailing: PluriStatusPill(
icon: Icons.library_music_rounded,
label: '${favoritos.length} guardadas',
),
),
),
Expanded(
child: ReorderableListView.builder(
padding: const EdgeInsets.fromLTRB(12, 4, 12, 122),
SliverPadding(
padding: const EdgeInsets.fromLTRB(12, 4, 12, 124),
sliver: SliverReorderableList(
proxyDecorator: (child, index, animation) => ScaleTransition(
scale: Tween<double>(begin: 1, end: 1.03).animate(animation),
child: child,
-59
View File
@@ -48,7 +48,6 @@ class _PantallaInicioState extends State<PantallaInicio> {
child: CustomScrollView(
slivers: [
SliverToBoxAdapter(child: _heroHeader(context, estado)),
const SliverToBoxAdapter(child: _AuroraWaveBanner()),
SliverToBoxAdapter(child: _seccionCercanas(estado, theme)),
SliverToBoxAdapter(child: _seccionTendencias(estado, theme)),
SliverToBoxAdapter(child: _chipGeneros(context, theme)),
@@ -312,64 +311,6 @@ class _PantallaInicioState extends State<PantallaInicio> {
}
class _AuroraWaveBanner extends StatelessWidget {
const _AuroraWaveBanner();
@override
Widget build(BuildContext context) {
final t = context.pluriTokens;
return Padding(
padding: EdgeInsets.fromLTRB(t.spacingMd, 4, t.spacingMd, 8),
child: ClipRRect(
borderRadius: BorderRadius.circular(t.radiusLg),
child: Stack(
alignment: Alignment.centerLeft,
children: [
Image.asset(
'assets/images/aurora_wave_banner.png',
height: 108,
width: double.infinity,
fit: BoxFit.cover,
errorBuilder: (_, __, ___) => const SizedBox.shrink(),
),
Container(
height: 108,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Colors.black.withValues(alpha: 0.58),
Colors.transparent,
],
),
),
),
Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
'Live spectrum',
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w900,
),
),
const SizedBox(height: 4),
Text(
'Ondas aurora en tiempo real',
style: Theme.of(context).textTheme.bodySmall,
),
],
),
),
],
),
),
);
}
}
class _ChipShimmer extends StatelessWidget {
final ThemeData theme;
const _ChipShimmer({required this.theme});