diff --git a/assets/generated/pluriwave-asset-sheet.png b/assets/generated/pluriwave-asset-sheet.png new file mode 100644 index 0000000..fa8d6a9 Binary files /dev/null and b/assets/generated/pluriwave-asset-sheet.png differ diff --git a/assets/icons/pluri_favorites.png b/assets/icons/pluri_favorites.png new file mode 100644 index 0000000..f4db54a Binary files /dev/null and b/assets/icons/pluri_favorites.png differ diff --git a/assets/icons/pluri_home.png b/assets/icons/pluri_home.png new file mode 100644 index 0000000..7bcdd5c Binary files /dev/null and b/assets/icons/pluri_home.png differ diff --git a/assets/icons/pluri_player.png b/assets/icons/pluri_player.png new file mode 100644 index 0000000..6e53898 Binary files /dev/null and b/assets/icons/pluri_player.png differ diff --git a/assets/icons/pluri_search.png b/assets/icons/pluri_search.png new file mode 100644 index 0000000..a7c3495 Binary files /dev/null and b/assets/icons/pluri_search.png differ diff --git a/assets/icons/pluri_settings.png b/assets/icons/pluri_settings.png new file mode 100644 index 0000000..f607d59 Binary files /dev/null and b/assets/icons/pluri_settings.png differ diff --git a/assets/icons/pluriwave_app_mark.png b/assets/icons/pluriwave_app_mark.png new file mode 100644 index 0000000..a321006 Binary files /dev/null and b/assets/icons/pluriwave_app_mark.png differ diff --git a/assets/images/aurora_wave_banner.png b/assets/images/aurora_wave_banner.png new file mode 100644 index 0000000..b4dc033 Binary files /dev/null and b/assets/images/aurora_wave_banner.png differ diff --git a/assets/images/station_art_aurora.png b/assets/images/station_art_aurora.png new file mode 100644 index 0000000..3a34f4f Binary files /dev/null and b/assets/images/station_art_aurora.png differ diff --git a/assets/images/station_art_cosmic.png b/assets/images/station_art_cosmic.png new file mode 100644 index 0000000..f206a45 Binary files /dev/null and b/assets/images/station_art_cosmic.png differ diff --git a/assets/images/station_art_nova.png b/assets/images/station_art_nova.png new file mode 100644 index 0000000..a41ab10 Binary files /dev/null and b/assets/images/station_art_nova.png differ diff --git a/assets/images/station_art_pulse.png b/assets/images/station_art_pulse.png new file mode 100644 index 0000000..e8faca8 Binary files /dev/null and b/assets/images/station_art_pulse.png differ diff --git a/lib/pantallas/pantalla_favoritos.dart b/lib/pantallas/pantalla_favoritos.dart index df8334a..e7b1647 100644 --- a/lib/pantallas/pantalla_favoritos.dart +++ b/lib/pantallas/pantalla_favoritos.dart @@ -56,6 +56,7 @@ class PantallaFavoritos extends StatelessWidget { scale: Tween(begin: 1, end: 1.03).animate(animation), child: child, ), + // ignore: deprecated_member_use onReorder: (oldIndex, newIndex) async { if (newIndex > oldIndex) newIndex--; final emisora = favoritos[oldIndex]; diff --git a/lib/pantallas/pantalla_inicio.dart b/lib/pantallas/pantalla_inicio.dart index a04275b..53c79f5 100644 --- a/lib/pantallas/pantalla_inicio.dart +++ b/lib/pantallas/pantalla_inicio.dart @@ -46,6 +46,7 @@ class _PantallaInicioState extends State { child: CustomScrollView( slivers: [ SliverToBoxAdapter(child: _heroHeader(context, estado)), + const SliverToBoxAdapter(child: _AuroraWaveBanner()), SliverToBoxAdapter(child: _seccionTendencias(estado, theme)), SliverToBoxAdapter(child: _chipGeneros(context, theme)), if (estado.error != null) @@ -238,6 +239,65 @@ class _PantallaInicioState extends State { } } + +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}); diff --git a/lib/widgets/pluri_icon.dart b/lib/widgets/pluri_icon.dart index 41dc9b2..9220f94 100644 --- a/lib/widgets/pluri_icon.dart +++ b/lib/widgets/pluri_icon.dart @@ -24,21 +24,34 @@ class PluriIcon extends StatelessWidget { @override Widget build(BuildContext context) { final tokens = context.pluriTokens; - final icon = Icon( - _resolveData(), - size: size, - color: _resolveColor(context, tokens), - ); + final asset = _resolveAsset(); + final resolvedColor = _resolveColor(context, tokens); + final icon = asset == null + ? Icon(_resolveData(), size: size, color: resolvedColor) + : Opacity( + opacity: variant == PluriIconVariant.outline ? 0.78 : 1, + child: Image.asset( + asset, + width: size, + height: size, + fit: BoxFit.contain, + errorBuilder: (_, __, ___) => Icon( + _resolveData(), + size: size, + color: resolvedColor, + ), + ), + ); final child = variant == PluriIconVariant.activeGlow ? Container( - width: size + 12, - height: size + 12, + width: size + 14, + height: size + 14, decoration: BoxDecoration( shape: BoxShape.circle, boxShadow: [ BoxShadow( color: tokens.glowColor, - blurRadius: 14, + blurRadius: 18, spreadRadius: 1, ), ], @@ -55,6 +68,18 @@ class PluriIcon extends StatelessWidget { ); } + + + String? _resolveAsset() { + return switch (glyph) { + PluriIconGlyph.home => 'assets/icons/pluri_home.png', + PluriIconGlyph.search => 'assets/icons/pluri_search.png', + PluriIconGlyph.favorites => 'assets/icons/pluri_favorites.png', + PluriIconGlyph.player => 'assets/icons/pluri_player.png', + PluriIconGlyph.settings => 'assets/icons/pluri_settings.png', + }; + } + Color _resolveColor(BuildContext context, PluriWaveTokens tokens) { if (variant == PluriIconVariant.activeGlow) return tokens.electricMagenta; if (variant == PluriIconVariant.filled) return Theme.of(context).colorScheme.onSurface; diff --git a/lib/widgets/pluri_premium_widgets.dart b/lib/widgets/pluri_premium_widgets.dart index 38e158f..bc5712e 100644 --- a/lib/widgets/pluri_premium_widgets.dart +++ b/lib/widgets/pluri_premium_widgets.dart @@ -38,6 +38,19 @@ class PluriScreenHeader extends StatelessWidget { top: -42, child: _Orb(color: t.electricMagenta.withValues(alpha: 0.38), size: 128), ), + Positioned( + right: 10, + top: 10, + child: Opacity( + opacity: 0.18, + child: Image.asset( + 'assets/icons/pluriwave_app_mark.png', + width: 120, + height: 120, + errorBuilder: (_, __, ___) => const SizedBox.shrink(), + ), + ), + ), Positioned( right: 44, bottom: -54, diff --git a/lib/widgets/tarjeta_emisora.dart b/lib/widgets/tarjeta_emisora.dart index fe21889..0257996 100644 --- a/lib/widgets/tarjeta_emisora.dart +++ b/lib/widgets/tarjeta_emisora.dart @@ -293,25 +293,48 @@ class _TarjetaEmisoraState extends State { } Widget _iconoFallback(double size) { - final t = context.pluriTokens; - return DecoratedBox( - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [t.deepViolet, t.electricMagenta.withValues(alpha: 0.8)], + final art = _fallbackArtFor(widget.emisora.uuid); + return Stack( + fit: StackFit.expand, + children: [ + Image.asset( + art, + fit: BoxFit.cover, + errorBuilder: (_, __, ___) => DecoratedBox( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + context.pluriTokens.deepViolet, + context.pluriTokens.electricMagenta.withValues(alpha: 0.8), + ], + ), + ), + ), ), - ), - child: Center( - child: PluriIcon( - glyph: PluriIconGlyph.player, - variant: PluriIconVariant.filled, - size: size, - semanticLabel: 'Icono de emisora', + Center( + child: PluriIcon( + glyph: PluriIconGlyph.player, + variant: PluriIconVariant.activeGlow, + size: size, + semanticLabel: 'Icono de emisora', + ), ), - ), + ], ); } + + String _fallbackArtFor(String seed) { + const arts = [ + 'assets/images/station_art_aurora.png', + 'assets/images/station_art_cosmic.png', + 'assets/images/station_art_pulse.png', + 'assets/images/station_art_nova.png', + ]; + final index = seed.codeUnits.fold(0, (a, b) => a + b) % arts.length; + return arts[index]; + } } class _LiveBadge extends StatelessWidget { diff --git a/pubspec.yaml b/pubspec.yaml index fcc181d..5069c0f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -63,3 +63,4 @@ flutter: - assets/images/ - assets/icons/ - assets/mockups/ + - assets/generated/