feat(ui): add premium PluriWave redesign
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
# Apply Progress: premium-award-ui-icons-code-review
|
||||
|
||||
## Status
|
||||
|
||||
Partial apply completed in automatic multi-agent mode.
|
||||
|
||||
## Completed
|
||||
|
||||
- Planned and persisted hybrid SDD artifacts: proposal, spec, design, tasks, state.
|
||||
- Added premium foundations:
|
||||
- `lib/tema/pluriwave_tokens.dart`
|
||||
- `lib/tema/pluriwave_motion.dart`
|
||||
- `lib/tema/pluriwave_theme.dart`
|
||||
- `lib/widgets/pluri_icon.dart`
|
||||
- `lib/widgets/pluri_glass_surface.dart`
|
||||
- `lib/widgets/pluri_wave_scaffold.dart`
|
||||
- Connected app theme and primary navigation to PluriWave premium foundations in `lib/app.dart`.
|
||||
- Hardened app error stream subscription in `lib/app.dart` with a single cancelable `StreamSubscription`.
|
||||
- Hardened audio visualizer stream subscriptions in `lib/widgets/visualizador_audio.dart`.
|
||||
- Fixed persistent favorites reorder by reindexing the full list in a DB transaction.
|
||||
- Reduced stale favorite state by deriving favorite UI from `EstadoRadio` in station card and player.
|
||||
- Made player prefer effective `estado.emisoraActual ?? widget.emisora`.
|
||||
- Made timer cancellation await audio stop when requested.
|
||||
- Added/updated tests for premium foundations, visualizer lifecycle, favorite reorder, and favorite sync.
|
||||
|
||||
## Verification
|
||||
|
||||
- ✅ Sub-agent reported `flutter test test/widgets/pluriwave_foundations_test.dart` passed.
|
||||
- ✅ Sub-agent reported `flutter test test/estado/estado_radio_test.dart -r compact` passed.
|
||||
- ✅ Sub-agent reported `flutter test test/widget_test.dart -r compact` passed.
|
||||
- ⚠️ Full `flutter test` timed out in this environment.
|
||||
- ⚠️ Local `dart format` and focused Flutter test commands later timed out/hung; stale Dart/Flutter processes were stopped.
|
||||
- 🚫 No `flutter build` was executed.
|
||||
|
||||
## Remaining
|
||||
|
||||
- Run full `flutter test` in CI/local with a longer timeout.
|
||||
- Run `dart format` once Dart tooling is responsive.
|
||||
- Continue premium screen refresh across Inicio/Buscar/Favoritos/Reproductor/Ajustes.
|
||||
- Generate or integrate validated icon/mockup assets through the asset pipeline.
|
||||
- Verify accessibility semantics/tap targets after screen integration.
|
||||
|
||||
## Continuation 2026-05-20
|
||||
|
||||
### Completed in this continuation
|
||||
|
||||
- Premium component refresh:
|
||||
- `lib/widgets/tarjeta_emisora.dart`
|
||||
- `lib/widgets/mini_reproductor.dart`
|
||||
- Premium screen refresh:
|
||||
- `lib/pantallas/pantalla_inicio.dart`
|
||||
- `lib/pantallas/pantalla_buscar.dart`
|
||||
- `lib/pantallas/pantalla_favoritos.dart`
|
||||
- `lib/pantallas/pantalla_ajustes.dart`
|
||||
- Premium player/EQ refresh:
|
||||
- `lib/pantallas/pantalla_reproductor.dart`
|
||||
- `lib/widgets/ecualizador_widget.dart`
|
||||
- Persisted dedicated mockup/icon prompts:
|
||||
- `openspec/changes/premium-award-ui-icons-code-review/mockup-prompts.md`
|
||||
- Static verification found a critical unsafe `Dismissible` + async Provider removal in Favorites; fixed by replacing swipe-dismiss with explicit delete action.
|
||||
|
||||
### Verification in continuation
|
||||
|
||||
- ✅ Sub-agent reported `flutter test test/estado/estado_radio_test.dart` passed with 8 tests.
|
||||
- ✅ Static `git diff --check` completed without whitespace errors.
|
||||
- ⚠️ `dart format`, `dart analyze`, and focused Flutter tests continued to timeout in this environment.
|
||||
- 🚫 No `flutter build` executed.
|
||||
|
||||
### Remaining
|
||||
|
||||
- Run `dart format` and full `flutter test` in responsive local/CI tooling.
|
||||
- Optional: implement optimistic favorite reorder for smoother premium UX.
|
||||
- Optional: remove double glass nesting around Ajustes/EQ if visual QA shows heaviness.
|
||||
- Generate actual raster mockup/icon assets using `mockup-prompts.md` and validate before integration.
|
||||
@@ -0,0 +1,264 @@
|
||||
# Design: premium-award-ui-icons-code-review
|
||||
|
||||
## Objetivo
|
||||
|
||||
Elevar PluriWave a una maqueta/UI premium de nivel award: radio global, audio vivo, favoritos, búsqueda, reproductor, EQ y ajustes con una dirección visual propia: **“Ondas vivas globales”**.
|
||||
|
||||
La UI debe sentirse como lujo digital oscuro: vidrio profundo, ondas concéntricas, energía magenta/coral y una familia de iconos propia. Primero fundamentos: **tokens, tema, componentes e iconografía**. Nada de maquillaje suelto arriba de widgets existentes.
|
||||
|
||||
## Contexto técnico verificado
|
||||
|
||||
- App Flutter/Dart con `Provider` + `ChangeNotifier`.
|
||||
- Tema actual en `lib/app.dart` usa Material 3 dark + `ColorScheme.fromSeed`.
|
||||
- Navegación actual usa `Icons.*` de Material.
|
||||
- Assets declarados: `assets/images/` y `assets/icons/`.
|
||||
- Tests existentes bajo `test/`.
|
||||
- Riesgo actual a hardenear: `_PaginaPrincipalState.didChangeDependencies()` escucha `errorStream` sin guardar/cancelar suscripción local; debe moverse a `initState` con `StreamSubscription` y cancelarse en `dispose`.
|
||||
|
||||
## Dirección de arte
|
||||
|
||||
### Concepto
|
||||
|
||||
**Ondas vivas globales**: PluriWave conecta emisoras del mundo a través de ondas sonoras visibles, como una red orbital sobre vidrio oscuro.
|
||||
|
||||
Visualmente:
|
||||
- Fondo oscuro violeta-negro.
|
||||
- Esferas/global waves con gradientes controlados.
|
||||
- Superficies glassmorphism sobrias, no “neón barato”.
|
||||
- Brillos premium: pocos, intencionales, con blur suave.
|
||||
- Iconos coherentes: ondas concéntricas + geometría redondeada.
|
||||
|
||||
### Paleta base
|
||||
|
||||
Definir tokens, no colores hardcodeados.
|
||||
|
||||
```dart
|
||||
voidBlack: #07040F
|
||||
deepViolet: #140722
|
||||
midnightPurple: #211039
|
||||
royalViolet: #6E35FF
|
||||
electricMagenta: #FF2BD6
|
||||
warmCoral: #FF7A59
|
||||
softRose: #FFD0E8
|
||||
auroraCyan: #35E8FF
|
||||
glassWhite: rgba(255,255,255,0.08)
|
||||
glassStroke: rgba(255,255,255,0.16)
|
||||
dangerCoral: #FF5A6A
|
||||
successMint: #5FFFCB
|
||||
```
|
||||
|
||||
### Gradientes
|
||||
|
||||
- `heroGlobalWave`: deep violet → royal violet → magenta.
|
||||
- `activeGlow`: electric magenta → warm coral.
|
||||
- `glassSurface`: white 10% → white 4%.
|
||||
- `playerOrb`: royal violet → magenta → coral.
|
||||
- `eqSpectrum`: cyan → magenta → coral.
|
||||
|
||||
### Tipografía
|
||||
|
||||
Mantener Inter si ya está instalado, pero con escala propia:
|
||||
|
||||
- Display: hero/player titles.
|
||||
- Title: cards, screen headers.
|
||||
- Body: station metadata.
|
||||
- Label: chips, nav, settings.
|
||||
|
||||
Decisión: tipografía sobria. El lujo viene de composición, contraste y ritmo, no de fuentes extravagantes.
|
||||
|
||||
## Tokens y tema
|
||||
|
||||
Crear capa de tema propia:
|
||||
|
||||
```text
|
||||
lib/tema/pluriwave_tokens.dart
|
||||
lib/tema/pluriwave_theme.dart
|
||||
lib/tema/pluriwave_motion.dart
|
||||
```
|
||||
|
||||
Usar `ThemeExtension` para colores premium, gradientes, radios, blur/elevation/glow, spacing y duraciones de motion.
|
||||
|
||||
Tokens sugeridos:
|
||||
|
||||
```text
|
||||
spacing: 4, 8, 12, 16, 20, 24, 32
|
||||
radius: 12, 16, 20, 28, 999
|
||||
stroke: 1, 1.5, 2
|
||||
blur: 12, 20, 32
|
||||
glow: subtle, active, hero
|
||||
motion: fast 120ms, base 220ms, expressive 420ms
|
||||
```
|
||||
|
||||
Regla: cualquier pantalla/componente nuevo consume tokens. No hardcodear paleta en widgets.
|
||||
|
||||
## Sistema de componentes
|
||||
|
||||
### App shell
|
||||
|
||||
- `PluriWaveScaffold`.
|
||||
- Fondo premium persistente: gradiente oscuro base, ondas radiales sutiles, puntos/orbitas globales con opacidad baja.
|
||||
- Respeta safe areas.
|
||||
- Evita rebuilds caros del fondo.
|
||||
|
||||
### Superficies
|
||||
|
||||
- `PluriGlassSurface`: color glass tokenizado, borde translúcido, blur moderado, sombra/glow opcional.
|
||||
- Variantes: `subtle`, `elevated`, `active`, `danger`.
|
||||
|
||||
### Navegación
|
||||
|
||||
- Reemplazar Material Icons por `PluriIcon`.
|
||||
- Bottom nav glass flotante.
|
||||
- Estado activo: icono filled, glow magenta/coral, label con contraste alto.
|
||||
- Estado inactivo: outline, baja opacidad, pero accesible.
|
||||
|
||||
### Tarjeta de emisora
|
||||
|
||||
- `PluriStationCard` con nombre, país/idioma/tag, estado reproduciendo, favorito y mini onda/visualizer.
|
||||
- Variantes: compacta, destacada, reorderable favorite.
|
||||
- Debe tener semantics claros: estación, país, acción reproducir, favorito.
|
||||
|
||||
### Mini reproductor
|
||||
|
||||
- Glass pill persistente.
|
||||
- Orb/onda animada cuando reproduce.
|
||||
- Botón play/pause con `PluriIcon.playerOrb`.
|
||||
- Evitar animaciones pesadas; envolver visualizer en `RepaintBoundary`.
|
||||
|
||||
### Reproductor
|
||||
|
||||
- Pantalla hero con globo/orbe de ondas, metadata de emisora, controles primarios, acceso EQ, favorito y timer.
|
||||
- La jerarquía debe hacer obvio qué está sonando.
|
||||
|
||||
### EQ
|
||||
|
||||
- `PluriEqPanel`.
|
||||
- Sliders con onda/spectrum.
|
||||
- Presets como chips premium.
|
||||
- Toggle “preset propio de esta emisora”.
|
||||
- Estado unavailable accesible cuando EQ no está disponible.
|
||||
|
||||
### Estados vacíos/error
|
||||
|
||||
- No usar pantallas muertas.
|
||||
- Empty state con icono propio + copy corto.
|
||||
- Error offline con acción retry.
|
||||
- Loading con shimmer sutil.
|
||||
|
||||
## Pantallas
|
||||
|
||||
### Inicio
|
||||
- Hero “PluriWave” con globo de ondas.
|
||||
- Sección Tendencias.
|
||||
- Sección Populares.
|
||||
- Accesos rápidos por país/tag.
|
||||
- Mini reproductor siempre abajo si hay emisora activa.
|
||||
|
||||
### Buscar
|
||||
- Search premium con chips: país, idioma, tag.
|
||||
- Loading controlado.
|
||||
- Evitar stale results: la última búsqueda gana.
|
||||
|
||||
### Favoritos
|
||||
- Lista reorderable.
|
||||
- Drag handle propio.
|
||||
- Persistencia de orden.
|
||||
- Si falla persistencia: rollback visual y snackbar.
|
||||
- Evitar duplicados por `uuid`.
|
||||
|
||||
### Reproductor
|
||||
- Foco absoluto en la emisora actual.
|
||||
- Controles grandes y accesibles.
|
||||
- Visualizer vivo, pero pausado/reducido si accesibilidad reduce motion.
|
||||
|
||||
### Ajustes
|
||||
- Cards agrupadas: audio/EQ, import/export, timer, app info.
|
||||
- Iconos propios por grupo.
|
||||
|
||||
## Sistema de iconos
|
||||
|
||||
Crear `PluriIcon` como contrato visual propio, con variantes `outline`, `filled`, `activeGlow`.
|
||||
|
||||
Iconos core:
|
||||
|
||||
```text
|
||||
homeWave, searchOrbit, heartSignal, playerOrb, eqConstellation,
|
||||
settingsPrism, sleepMoonWave, globeRadio, stationTower,
|
||||
importWave, exportWave, timerRing, errorPulse
|
||||
```
|
||||
|
||||
Geometría:
|
||||
- Grid base 24x24.
|
||||
- Stroke 2px.
|
||||
- Caps y joins redondeados.
|
||||
- Motivo común: ondas concéntricas/orbitas.
|
||||
- Filled no debe ser solo outline pintado.
|
||||
- Active glow se logra con composición, no con bitmap borroso incontrolable.
|
||||
|
||||
Implementación recomendada:
|
||||
- Core UI icons: code-native Flutter widgets/painters o assets vectoriales controlados.
|
||||
- Assets generados por IA: usar para hero, mockups, marketing, splash o iconos complejos, pasando por pipeline de validación.
|
||||
- Tradeoff: los iconos code-native son menos “ilustración AI”, pero ganan recolor, accesibilidad, consistencia y tests.
|
||||
|
||||
## Prompt para mockup premium
|
||||
|
||||
```text
|
||||
Create a premium mobile app UI mockup for "PluriWave", a global radio streaming app.
|
||||
Art direction: living global audio waves, luxury dark glass, deep violet black background, electric magenta, royal violet, warm coral highlights, subtle cyan accents.
|
||||
The app includes home, search, favorites, now playing, equalizer, and settings surfaces.
|
||||
Use elegant glassmorphism, restrained glow, layered depth, rounded premium cards, orbiting wave motifs, global radio map energy, custom wave-based icons, outline and filled active icon states.
|
||||
Make it look like an award-winning product design case study, polished, editorial, cinematic, high-end digital luxury.
|
||||
No fake brand logos, no illegible paragraphs, minimal readable labels only: Inicio, Buscar, Favoritos, Ajustes, PluriWave.
|
||||
Vertical smartphone composition, 9:16, crisp details, professional product mockup, dark premium UI, controlled highlights, no clutter.
|
||||
```
|
||||
|
||||
## Prompt para icon sheet
|
||||
|
||||
```text
|
||||
Generate a 4x4 icon sheet for a premium global radio app called PluriWave.
|
||||
Style: custom icon family, rounded geometry, concentric audio waves, globe/orbit motifs, deep violet strokes with electric magenta and warm coral active accents.
|
||||
Icons: home wave, search orbit, heart signal, player orb, equalizer constellation, settings prism, sleep moon wave, globe radio, station tower, import wave, export wave, timer ring, error pulse, favorite filled, play filled, pause filled.
|
||||
Each icon must be centered in its own cell, isolated, same visual weight, no text.
|
||||
Use pure chroma green #00FF00 as the full background, with thick #00FF00 gutters and outer border between every icon.
|
||||
No icon, shadow, glow, or stroke may touch or cross gutters.
|
||||
Clean high-resolution sheet, sharp edges, premium app icon design, consistent family.
|
||||
```
|
||||
|
||||
Negative prompt:
|
||||
|
||||
```text
|
||||
No text, no letters, no logos, no watermark, no overlapping cells, no cropped icons, no icons touching borders, no inconsistent perspective, no messy neon, no excessive glow, no background other than pure #00FF00.
|
||||
```
|
||||
|
||||
## Asset pipeline
|
||||
|
||||
Pipeline obligatorio:
|
||||
|
||||
```text
|
||||
generate → detect gutters → crop cells → chroma-to-alpha → trim transparent bounds → center subject → pad to target canvas → export PNG/WebP → generate contact sheet → validate
|
||||
```
|
||||
|
||||
Validaciones:
|
||||
- No píxeles #00FF00 residuales.
|
||||
- Ningún subject toca borde.
|
||||
- Bounding box razonable: no menor a 45% ni mayor a 82% del canvas.
|
||||
- Centro visual estable.
|
||||
- Familia coherente en peso, radio, glow y escala.
|
||||
- Rechazar sheet malo; no “arreglar a mano” crops rotos.
|
||||
|
||||
## Hardening técnico
|
||||
|
||||
### Listener leaks
|
||||
Mover listeners de UI desde `didChangeDependencies` a `initState` cuando no dependan de InheritedWidget dinámico, guardar `StreamSubscription`, cancelar en `dispose`.
|
||||
|
||||
### Estado stale
|
||||
Para búsqueda/carga async: usar request id incremental o token de última operación, ignorar respuestas viejas, limpiar loading solo si la respuesta corresponde al request vigente, evitar `notifyListeners` después de dispose.
|
||||
|
||||
### Favoritos reorder
|
||||
Persistir orden explícito, reorder optimista con rollback si falla, nunca duplicar `uuid`, tests para reorder, remove, import/export y estado actual.
|
||||
|
||||
### Accesibilidad
|
||||
Labels semánticos en iconos, tap targets mínimos 48x48, contraste suficiente, reducir/parar animaciones si `MediaQuery.disableAnimations` o reduced motion, no comunicar estado activo solo con color/glow.
|
||||
|
||||
### Performance
|
||||
`const` donde aplique, `RepaintBoundary` en visualizers/glows animados, blur limitado y tokenizado, precache de assets críticos, evitar rebuilds globales innecesarios del player/nav.
|
||||
@@ -0,0 +1,38 @@
|
||||
# Mockup / Asset Prompts
|
||||
|
||||
## Premium product mockup prompt
|
||||
|
||||
```text
|
||||
Create a premium mobile app UI mockup for "PluriWave", a global radio streaming app.
|
||||
Art direction: living global audio waves, luxury dark glass, deep violet black background, electric magenta, royal violet, warm coral highlights, subtle cyan accents.
|
||||
Show an award-winning app case study composition with five coherent surfaces: Inicio, Buscar, Favoritos, Reproductor, Ajustes.
|
||||
Design language: elegant glassmorphism, restrained glow, layered depth, rounded premium cards, orbiting wave motifs, global radio map energy, custom wave-based icons, outline and filled active icon states.
|
||||
The Reproductor screen is the hero: cinematic orb/global wave artwork, clear station metadata, premium playback controls, equalizer entry, favorites, timer.
|
||||
Use only short readable Spanish labels: PluriWave, Inicio, Buscar, Favoritos, Ajustes, En vivo, Ecualizador.
|
||||
Vertical smartphone product mockup, 9:16, crisp details, high-end digital luxury, professional design award quality, no clutter.
|
||||
```
|
||||
|
||||
## Icon sheet prompt
|
||||
|
||||
```text
|
||||
Generate a 4x4 icon sheet for a premium global radio app called PluriWave.
|
||||
Style: custom app icon family, rounded geometry, consistent 2px optical stroke, concentric audio waves, globe/orbit motifs, deep violet strokes with electric magenta and warm coral active accents.
|
||||
Icons in row-major order: home wave, search orbit, heart signal, player orb, equalizer constellation, settings prism, sleep moon wave, globe radio, station tower, import wave, export wave, timer ring, error pulse, favorite filled, play filled, pause filled.
|
||||
Each icon must be centered in its own cell, isolated, same visual weight, no text.
|
||||
Use pure chroma green #00FF00 as the full background, with thick #00FF00 gutters and outer border between every icon.
|
||||
No icon, shadow, glow, or stroke may touch or cross gutters.
|
||||
Clean high-resolution sheet, sharp edges, premium app icon design, consistent family.
|
||||
```
|
||||
|
||||
## Negative prompt
|
||||
|
||||
```text
|
||||
No text, no letters, no logos, no watermark, no overlapping cells, no cropped icons, no icons touching borders, no inconsistent perspective, no messy neon, no excessive glow, no background other than pure #00FF00.
|
||||
```
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- Mockup conveys one coherent product, not isolated random screens.
|
||||
- Dark glass surfaces remain legible and accessible.
|
||||
- Icon family has consistent stroke, radius, optical weight, and center alignment.
|
||||
- Any generated icon sheet MUST pass the validate pipeline before integration.
|
||||
@@ -0,0 +1,75 @@
|
||||
# Proposal: Premium award UI, icons, and code-review hardening
|
||||
|
||||
## Intent
|
||||
|
||||
Elevar PluriWave a una UI premium coherente y “award-ready” sin caer en maquillaje visual. Primero se deben corregir defectos de lifecycle/estado que hoy degradan confiabilidad; después se aplica un sistema visual propio: “Ondas vivas globales”.
|
||||
|
||||
## Scope
|
||||
|
||||
### In Scope
|
||||
- Hardening previo: listeners, streams, favoritos, reproductor, timer y errores.
|
||||
- Sistema visual token-first: violeta profundo, magenta eléctrico, coral cálido, vidrio oscuro y glow controlado.
|
||||
- Sistema de iconos propios para navegación, reproducción, favoritos, búsqueda, ajustes y estados.
|
||||
- Mockup/refresh de Inicio, Buscar, Reproductor, Favoritos y Ajustes.
|
||||
- Tests Strict TDD con `flutter test`; sin build.
|
||||
|
||||
### Out of Scope
|
||||
- Reemplazar Provider/ChangeNotifier.
|
||||
- Rediseñar backend/API de radios.
|
||||
- Branding completo externo a la app.
|
||||
- Release packaging o `flutter build`.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
- `ui-technical-hardening`: estabilidad previa a la capa premium.
|
||||
- `premium-visual-system`: tokens, superficies, motion y composición visual.
|
||||
- `premium-icon-system`: iconografía propia con estados outline/filled/active glow.
|
||||
- `premium-screen-refresh`: aplicación coherente en las cinco pantallas principales.
|
||||
|
||||
### Modified Capabilities
|
||||
- None; no existing OpenSpec source specs exist yet.
|
||||
|
||||
## Approach
|
||||
|
||||
Primero cerrar deuda crítica verificada: subscriptions cancelables, favorito global consistente, reorder persistente, reproductor desacoplado de snapshots viejos y errores observables. Luego introducir tokens visuales reutilizables e iconos propios, aplicándolos pantalla por pantalla con el Reproductor como referencia fuerte.
|
||||
|
||||
## Affected Areas
|
||||
|
||||
| Area | Impact | Description |
|
||||
|---|---|---|
|
||||
| `lib/app.dart` | Modified | Listener único/cancelable para errores. |
|
||||
| `lib/widgets/visualizador_audio.dart` | Modified | Stream subscriptions seguras. |
|
||||
| `lib/servicios/servicio_favoritos.dart` | Modified | Reordenado persistente completo. |
|
||||
| `lib/pantallas/pantalla_favoritos.dart` | Modified | UX reorder consistente. |
|
||||
| `lib/widgets/tarjeta_emisora.dart` | Modified | Favorito derivado del estado global. |
|
||||
| `lib/pantallas/pantalla_reproductor.dart` | Modified | UI premium y estado de reproducción confiable. |
|
||||
| `assets/icons/` | New | Iconos propios premium. |
|
||||
| `test/` | Modified | Cobertura de hardening y UI behavior. |
|
||||
|
||||
## Risks
|
||||
|
||||
| Risk | Likelihood | Mitigation |
|
||||
|---|---:|---|
|
||||
| UI linda pero frágil | High | Hardening MUST precede visual rollout. |
|
||||
| Iconos inconsistentes | Med | Definir geometría/estados antes de integrarlos. |
|
||||
| Glow/motion excesivo | Med | Tokens, límites de contraste y reduced motion. |
|
||||
|
||||
## Rollback Plan
|
||||
|
||||
Revertir commits del cambio. Los assets nuevos y tokens pueden eliminarse sin migración de datos. Hardening debe revertirse solo si sus tests también se ajustan.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Flutter/Material existente.
|
||||
- `flutter_test`.
|
||||
- Assets locales bajo `assets/icons`.
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- [ ] No listeners duplicados ni stream leaks verificados por tests.
|
||||
- [ ] Favoritos y orden se mantienen consistentes.
|
||||
- [ ] Reproductor usa estado actual confiable.
|
||||
- [ ] Las cinco pantallas comparten lenguaje premium.
|
||||
- [ ] Iconos propios reemplazan Material genérico en puntos clave.
|
||||
- [ ] `flutter test` valida el cambio; no se ejecuta build.
|
||||
@@ -0,0 +1,98 @@
|
||||
# Spec: Premium award UI, icons, and code-review hardening
|
||||
|
||||
## Requirement: Hardening before premium UI
|
||||
|
||||
The system MUST correct lifecycle and state-integrity defects before premium visual work is considered complete.
|
||||
|
||||
### Scenario: hardening gate precedes visual rollout
|
||||
- GIVEN premium UI work starts
|
||||
- WHEN implementation tasks are planned
|
||||
- THEN tests for listener lifecycle, favorite consistency, reorder persistence, playback state, timer cancellation, and error reporting MUST be written first
|
||||
- AND premium UI tasks SHALL NOT be marked complete until those tests pass with `flutter test`
|
||||
|
||||
### Scenario: failures are observable
|
||||
- GIVEN an async operation fails in playback, favorites, or loading
|
||||
- WHEN the failure reaches app state
|
||||
- THEN the system MUST expose a user-visible or test-observable error path
|
||||
- AND it MUST NOT silently swallow the failure without state feedback
|
||||
|
||||
## Requirement: Lifecycle-safe subscriptions
|
||||
|
||||
The system MUST own and cancel every stream subscription/listener created by widgets or app shell.
|
||||
|
||||
### Scenario: app error stream is subscribed once
|
||||
- GIVEN dependencies change more than once
|
||||
- WHEN one error message is emitted
|
||||
- THEN the app MUST show at most one SnackBar for that message
|
||||
|
||||
### Scenario: visualizer disposes cleanly
|
||||
- GIVEN an audio visualizer or playback indicator is removed
|
||||
- WHEN `estadoStream` emits later
|
||||
- THEN no disposed widget SHALL call `setState`
|
||||
- AND its subscription MUST be cancelled
|
||||
|
||||
## Requirement: Consistent favorites and ordering
|
||||
|
||||
The system MUST derive favorite UI from global state and persist complete ordering after reorder.
|
||||
|
||||
### Scenario: reorder persists full list order
|
||||
- GIVEN favorites `[A, B, C]`
|
||||
- WHEN the user moves `A` after `C`
|
||||
- THEN persisted favorites MUST reload as `[B, C, A]`
|
||||
- AND every item SHALL have a deterministic order
|
||||
|
||||
### Scenario: favorite state stays in sync
|
||||
- GIVEN the same station appears in card and player surfaces
|
||||
- WHEN favorite is toggled from either surface
|
||||
- THEN all visible favorite icons MUST reflect the updated global state
|
||||
|
||||
## Requirement: Playback source of truth
|
||||
|
||||
The player MUST reconcile route input with `EstadoRadio` current playback state and MUST NOT keep acting on stale station snapshots.
|
||||
|
||||
### Scenario: active station changes while player is open
|
||||
- GIVEN the player was opened for station `A`
|
||||
- AND global playback changes to station `B`
|
||||
- WHEN controls or favorite actions render
|
||||
- THEN they MUST target the effective current station
|
||||
- AND labels/artwork/actions SHALL remain consistent
|
||||
|
||||
## Requirement: Premium visual system
|
||||
|
||||
The system MUST define reusable visual tokens for “Ondas vivas globales”: deep violet, electric magenta, warm coral, dark glass surfaces, subtle neumorphism, controlled glow, radius, spacing, and motion.
|
||||
|
||||
### Scenario: screens consume tokens
|
||||
- GIVEN a premium screen is rendered
|
||||
- WHEN colors, surfaces, shadows, or motion are applied
|
||||
- THEN they MUST come from shared tokens or theme extensions
|
||||
- AND one-off hardcoded styling SHOULD be avoided
|
||||
|
||||
## Requirement: Premium icon system
|
||||
|
||||
The app MUST use custom PluriWave iconography for primary navigation, playback, favorite, search, settings, live/error/loading, and radio fallback states.
|
||||
|
||||
### Scenario: icon states are coherent
|
||||
- GIVEN an icon supports inactive, selected, and active playback states
|
||||
- WHEN each state is displayed
|
||||
- THEN outline, filled, and glow variants MUST preserve the same rounded wave geometry
|
||||
- AND tappable icons MUST keep accessible labels
|
||||
|
||||
## Requirement: Five-screen premium refresh
|
||||
|
||||
Inicio, Buscar, Reproductor, Favoritos, and Ajustes MUST share the premium language, with Reproductor as the strongest reference composition.
|
||||
|
||||
### Scenario: mockup scope is implemented coherently
|
||||
- GIVEN the five primary screens are reviewed together
|
||||
- WHEN navigation moves between them
|
||||
- THEN tokens, icon style, hierarchy, empty states, and loading states SHALL feel like one product
|
||||
- AND no primary screen SHOULD fall back to generic Material-only presentation
|
||||
|
||||
## Requirement: Accessibility and verification
|
||||
|
||||
The system MUST preserve accessibility while adding premium visuals.
|
||||
|
||||
### Scenario: premium visuals remain usable
|
||||
- GIVEN large text, reduced motion, or high-contrast needs
|
||||
- WHEN premium UI is rendered
|
||||
- THEN content MUST remain readable and controls MUST remain reachable
|
||||
- AND verification MUST use `flutter test`, never `flutter build`
|
||||
@@ -0,0 +1,16 @@
|
||||
change: premium-award-ui-icons-code-review
|
||||
status: applying
|
||||
mode: automatic
|
||||
artifact_store: hybrid
|
||||
created: 2026-05-20
|
||||
updated: 2026-05-20
|
||||
phases:
|
||||
explore: completed
|
||||
proposal: completed
|
||||
specs: completed
|
||||
design: completed
|
||||
tasks: completed
|
||||
apply: partial
|
||||
verify: partial-static
|
||||
archive: pending
|
||||
next_recommended: run-format-and-full-tests
|
||||
@@ -0,0 +1,95 @@
|
||||
# Tasks: premium-award-ui-icons-code-review
|
||||
|
||||
## Fase 0 — Guardrails
|
||||
|
||||
- [x] No ejecutar build.
|
||||
- [ ] No revertir cambios ajenos.
|
||||
- [ ] Verificar estado inicial con `git status --short`.
|
||||
- [ ] Ejecutar baseline de tests permitido: `flutter test`.
|
||||
- [ ] Registrar fallos existentes antes de tocar código si los hubiera.
|
||||
|
||||
## Fase 1 — Tokens y tema
|
||||
|
||||
- [x] Crear tests para validar tokens premium mínimos.
|
||||
- [x] Crear `lib/tema/pluriwave_tokens.dart`.
|
||||
- [x] Crear `lib/tema/pluriwave_theme.dart`.
|
||||
- [x] Crear `lib/tema/pluriwave_motion.dart`.
|
||||
- [x] Reemplazar `ColorScheme.fromSeed` genérico por tema PluriWave tokenizado.
|
||||
- [x] Mantener Material 3, pero con identidad propia.
|
||||
- [x] Asegurar que widgets existentes sigan usando `Theme.of(context)`.
|
||||
- [ ] Ejecutar `flutter test`.
|
||||
|
||||
## Fase 2 — Sistema de iconos
|
||||
|
||||
- [x] Definir contrato `PluriIcon`.
|
||||
- [x] Definir enum/id de iconos core.
|
||||
- [x] Implementar variantes `outline`, `filled`, `activeGlow`.
|
||||
- [x] Agregar semantics labels obligatorios.
|
||||
- [x] Reemplazar iconos de bottom navigation por `PluriIcon`.
|
||||
- [ ] Agregar tests de variante activa, labels semánticos, tap targets y ausencia de regresión en navegación.
|
||||
- [ ] Ejecutar `flutter test`.
|
||||
|
||||
## Fase 3 — Asset pipeline
|
||||
|
||||
- [x] Persistir prompts de mockup/icon sheet en documentación del cambio.
|
||||
- [ ] Generar sheet con gutters chroma #00FF00.
|
||||
- [ ] Implementar o usar pipeline: detectar gutters, crop, chroma-to-alpha, trim, center, pad, export, contact sheet, validate.
|
||||
- [ ] Rechazar sheets con edge-touching, gutters contaminados o escala inconsistente.
|
||||
- [ ] Exportar assets finales a `assets/icons/` o `assets/images/`.
|
||||
- [ ] Actualizar `pubspec.yaml` solo si hace falta declarar subcarpetas nuevas.
|
||||
- [ ] Ejecutar `flutter test`.
|
||||
|
||||
## Fase 4 — Componentes premium
|
||||
|
||||
- [x] Crear `PluriWaveScaffold`.
|
||||
- [x] Crear `PluriGlassSurface`.
|
||||
- [x] Crear fondo premium reutilizable con ondas/global aura.
|
||||
- [x] Refactorizar `tarjeta_emisora` hacia tarjeta premium tokenizada.
|
||||
- [x] Refactorizar `mini_reproductor` con glass pill y estado activo.
|
||||
- [x] Refactorizar `visualizador_audio` con `RepaintBoundary`.
|
||||
- [x] Refactorizar `ecualizador_widget` con tokens y estados accesibles.
|
||||
- [ ] Agregar widget tests para componentes críticos.
|
||||
- [ ] Ejecutar `flutter test`.
|
||||
|
||||
## Fase 5 — Pantallas
|
||||
|
||||
- [x] Actualizar `PantallaInicio` con hero global wave, tendencias y populares.
|
||||
- [x] Actualizar `PantallaBuscar` con search premium, chips y stale-state guard.
|
||||
- [x] Actualizar `PantallaFavoritos` con diseño reorderable.
|
||||
- [x] Actualizar `PantallaReproductor` con player hero, controles premium y EQ entry point.
|
||||
- [x] Actualizar `PantallaAjustes` con cards agrupadas e iconos propios.
|
||||
- [ ] Agregar/actualizar tests de pantallas existentes.
|
||||
- [ ] Ejecutar `flutter test`.
|
||||
|
||||
## Fase 6 — Hardening técnico
|
||||
|
||||
- [x] Corregir listener leak en `lib/app.dart`: mover escucha de `errorStream` fuera de `didChangeDependencies`, guardar `StreamSubscription`, cancelar en `dispose`.
|
||||
- [ ] Agregar test que falle si se registran listeners duplicados.
|
||||
- [ ] Implementar control de stale async state en búsquedas/cargas.
|
||||
- [ ] Agregar tests de “última búsqueda gana”.
|
||||
- [x] Implementar reorder persistente de favoritos.
|
||||
- [ ] Agregar tests de reorder exitoso, rollback ante error, no duplicados por `uuid` y favorito actual correcto.
|
||||
- [ ] Ejecutar `flutter test`.
|
||||
|
||||
## Fase 7 — Accesibilidad y polish
|
||||
|
||||
- [ ] Revisar contraste de tokens principales.
|
||||
- [ ] Asegurar labels semánticos en controles principales.
|
||||
- [ ] Asegurar tap targets mínimos 48x48.
|
||||
- [ ] Soportar reduced motion / disable animations.
|
||||
- [ ] Evitar que glow/color sea la única señal de estado.
|
||||
- [ ] Agregar tests de semantics para nav, player, favoritos y EQ.
|
||||
- [ ] Ejecutar `flutter test`.
|
||||
|
||||
## Fase 8 — Persistencia SDD híbrida
|
||||
|
||||
- [x] Persistir `proposal.md`, `spec.md`, `design.md`, `tasks.md` en openspec.
|
||||
- [x] Guardar equivalentes en Engram con topic keys:
|
||||
- `sdd/premium-award-ui-icons-code-review/proposal`
|
||||
- `sdd/premium-award-ui-icons-code-review/spec`
|
||||
- `sdd/premium-award-ui-icons-code-review/design`
|
||||
- `sdd/premium-award-ui-icons-code-review/tasks`
|
||||
- [x] Marcar siguiente fase recomendada: `sdd-verify`.
|
||||
- [x] No ejecutar build.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user