Navegación y flujo de pantallas
Modelo de estado
Sección titulada «Modelo de estado»Toda la navegación vive en dos variables de estado dentro de RacingCardsApp:
var current by rememberSaveable { mutableStateOf(Destination.Gallery) }var isEditingCard by rememberSaveable { mutableStateOf(false) }val cards = remember { mutableStateListOf<RacingCard>() }var selectedCard by remember { mutableStateOf<RacingCard?>(null) }current— cuál de las 3 tabs de la barra inferior está activa (Destination.Gallery,.Createo.Details).isEditingCard— un booleano que, cuando estrue, reemplaza cualquier pantalla actual porEditScreenen modo edición (no es una tab; es un overlay sobre la navegación normal).cards/selectedCard— el “backend en memoria”: la lista de cartas creadas y cuál está seleccionada para ver/editar.
El árbol de decisión que arma la pantalla visible es:
when { isEditingCard -> EditScreen(/* editar selectedCard */) else -> when (current) { Destination.Gallery -> GalleryScreen(...) Destination.Details -> DetailsScreen(...) Destination.Create -> EditScreen(/* isNewCard = true */) }}Es decir: EditScreen se reutiliza tanto para “Create” (tab, isNewCard = true) como para
“editar una carta existente” (isEditingCard = true, fuera del sistema de tabs).
Diagrama de estados
Sección titulada «Diagrama de estados»Estados de navegación de RacingCardsApp
stateDiagram-v2 [*] --> SystemSplash SystemSplash: Splash del sistema (Theme.Starting) LoadingScreen: LoadingScreen (Compose, ~1.1s) Gallery: Destination.Gallery Details: Destination.Details CreateNew: Destination.Create (EditScreen, isNewCard=true) RollOverlay: PerformanceRollOverlay (rifa de stats) EditExisting: isEditingCard=true (EditScreen) SystemSplash --> LoadingScreen LoadingScreen --> Gallery: delay(1100ms) Gallery --> Details: tap en una carta Gallery --> CreateNew: tab "Create" Details --> Gallery: back / eliminar Details --> EditExisting: tap en editar (lápiz) Details --> CreateNew: tab "Create" CreateNew --> Gallery: back CreateNew --> RollOverlay: check (guardar) RollOverlay --> Gallery: onFinished (carta guardada) EditExisting --> Details: back EditExisting --> Details: check (guardar, sin re-rifar stats)
Detalle del flujo “Create → Roll → Gallery”
Sección titulada «Detalle del flujo “Create → Roll → Gallery”»Crear una carta nueva es el flujo más largo de la app: el formulario no navega a otra pantalla al
guardar, sino que se transforma en la animación de rifa (rolling = true dentro del mismo
EditScreen), y sólo al terminar esa animación se llama a onSave, que es lo que efectivamente
navega de vuelta a la Gallery.
Secuencia: crear una carta nueva
sequenceDiagram actor U as Usuario participant App as RacingCardsApp participant Edit as EditScreen participant Roll as PerformanceRollOverlay participant Roller as PerformanceRoller U->>App: tap tab "Create" App->>Edit: EditScreen(card=blank, isNewCard=true) U->>Edit: completa nombre, clase, color, badge, foto U->>Edit: tap check (guardar) Edit->>Edit: rolling = true Edit->>Roller: rollStats() Roller-->>Edit: CardStats aleatorias Edit->>Roller: tierFor(stats) Roller-->>Edit: rareza "S".."D" Edit->>Roll: PerformanceRollOverlay(finalStats, finalTier) Roll->>Roll: anima cada stat (slot machine, ~4x cascada) Roll->>Roll: muestra chip de rareza + pulso del auto Roll->>App: onFinished() -> onSave(card) App->>App: cards.add(card); current = Gallery App-->>U: vuelve a Gallery con la carta nueva
Notas de implementación
Sección titulada «Notas de implementación»- No hay pila de navegación (back stack). Volver es siempre una transición explícita a un
destino fijo (
onBack = { current = Destination.Gallery }), no unpopBackStack(). Esto es posible porque el grafo de pantallas es plano: nunca hay más de un nivel de profundidad real. isEditingCardno es parte deDestinationa propósito: editar una carta existente puede iniciarse desde Details, así que modelarlo como una tab más obligaría a inventar un destino sin ícono en la barra inferior.- El tab Create está marcado con
isEmphasized = trueenDestination.kt, lo que le da un fondo circular amarillo permanente en la barra inferior — independiente de si está seleccionado — para que “crear” destaque como la acción principal de la app.
