Estructura del proyecto
Paquetes
Sección titulada «Paquetes»com.omar.act4racingcards├── MainActivity.kt # única Activity: instala el splash y monta Compose├── RacingCardsApp.kt # composable raíz: Scaffold + bottom nav + estado de navegación├── model/│ ├── RacingCard.kt # RacingCard, CardStats, CardOptions│ └── PerformanceRoller.kt # rifa de estadísticas + cálculo de rareza├── navigation/│ └── Destination.kt # enum de las 3 tabs (Gallery, Create, Details)├── ui/│ ├── theme/ # Color.kt, Type.kt, Theme.kt, Dimens.kt — el sistema de diseño│ ├── components/ # composables reutilizables entre pantallas│ │ ├── CardComponents.kt # carta, chips, empty state, pickers…│ │ ├── Buttons.kt # PrimaryButton / SecondaryButton / TertiaryButton│ │ └── Inputs.kt # estilos compartidos de OutlinedTextField│ ├── loading/LoadingScreen.kt│ ├── gallery/GalleryScreen.kt│ ├── edit/│ │ ├── EditScreen.kt # formulario de Create/Edit│ │ └── PerformanceRollOverlay.kt # animación de rifa de estadísticas│ └── details/DetailsScreen.ktNo hay capa de datos ni ViewModel: model/ son data classes + un objeto de lógica pura
(PerformanceRoller), y todo el estado de UI vive directamente en los composables.
Sin ViewModel, sin Navigation Compose
Sección titulada «Sin ViewModel, sin Navigation Compose»A diferencia de una app Compose “de manual”, este proyecto no usa androidx.navigation ni
ViewModel. La navegación es un when sobre un enum guardado con rememberSaveable, y el
estado (la lista de cartas, la carta seleccionada) vive en el composable raíz RacingCardsApp y
se pasa hacia abajo por parámetros — el patrón de state hoisting puro de Compose.
Es una decisión razonable dado el tamaño actual de la app: 4 pantallas, sin persistencia, sin llamadas de red. Si el proyecto creciera (persistencia real, múltiples pantallas por flujo, deep links), sería el primer punto a revisar.
Grafo de dependencias entre capas
Sección titulada «Grafo de dependencias entre capas»Capas del proyecto
graph TD
subgraph entry["Entrada"]
MainActivity["MainActivity"]
end
subgraph app["Estado de navegación"]
RacingCardsApp["RacingCardsApp"]
Destination["navigation.Destination"]
end
subgraph screens["Pantallas"]
Loading["ui.loading.LoadingScreen"]
Gallery["ui.gallery.GalleryScreen"]
Edit["ui.edit.EditScreen"]
Roll["ui.edit.PerformanceRollOverlay"]
Details["ui.details.DetailsScreen"]
end
subgraph shared["Compartido"]
Components["ui.components.*"]
Theme["ui.theme.*"]
end
subgraph domain["Modelo"]
RacingCard["model.RacingCard / CardStats / CardOptions"]
Roller["model.PerformanceRoller"]
end
MainActivity --> Loading
MainActivity --> RacingCardsApp
RacingCardsApp --> Destination
RacingCardsApp --> Gallery
RacingCardsApp --> Edit
RacingCardsApp --> Details
Edit --> Roll
Gallery --> Components
Edit --> Components
Details --> Components
Roll --> Components
Components --> Theme
Loading --> Theme
Gallery --> RacingCard
Edit --> RacingCard
Edit --> Roller
Roll --> Roller
Details --> RacingCard
