ComposeEverything is a reference app I keep adding to whenever I pick up a Compose pattern worth remembering — the goal is one repo where I can go look up how I wired something before, instead of re-deriving it from docs every time. It currently covers Room persistence, Navigation with typed arguments, and a ViewModel/Repository split, all in Material Design Compose UI.
Repository sitting between the ViewModel and Room
The task-manager module keeps the ViewModel free of DAO calls by routing everything through a thin repository. allTasks exposes the DAO's Flow straight through, so the UI recomposes automatically whenever the table changes — no manual refresh calls anywhere in the app:
class TaskRepository(private val taskDao: TaskDao) {
val allTasks: Flow<List<TaskEntity>> = taskDao.getAllTasks()
suspend fun insert(task: TaskEntity) {
taskDao.insertTask(task)
}
suspend fun update(task: TaskEntity) {
taskDao.updateTask(task)
}
suspend fun delete(task: TaskEntity) {
taskDao.deleteTask(task)
}
}
class TaskViewModel(private val repository: TaskRepository) : ViewModel() {
val allTasks = repository.allTasks
fun addTask(title: String, description: String) = viewModelScope.launch {
repository.insert(TaskEntity(title = title, description = description))
}
fun deleteTask(task: TaskEntity) = viewModelScope.launch {
repository.delete(task)
}
}
It's a small amount of ceremony for a task list, but it's the same shape I'd reach for on a production screen with a real backend behind the DAO — swapping Room for a network-backed repository later doesn't touch the ViewModel at all.
Passing real objects through Navigation, not just IDs
The Compose Navigation graph routes to a music player screen with three typed arguments pulled straight off the back stack entry, instead of stashing state in a shared ViewModel or a singleton:
composable(
route = "musicplayer/{song}/{artist}/{imageResId}",
arguments = listOf(
navArgument("song") { type = NavType.StringType },
navArgument("artist") { type = NavType.StringType },
navArgument("imageResId") { type = NavType.IntType }
)
) { backStackEntry ->
val song = backStackEntry.arguments?.getString("song")
val artist = backStackEntry.arguments?.getString("artist")
val imageResId = backStackEntry.arguments?.getInt("imageResId")
MusicPlayer(navController, song, artist, imageResId)
}
It keeps the destination screen a pure function of its arguments — reopen the app on that route and it renders correctly without anything else in memory.
The repo keeps growing as I run into new Compose APIs worth keeping around; full source for both modules is on GitHub.