Code

Update MenuRepository.kt — cache + network

In the code column — the new MenuRepository.kt. Compare it with lesson 5: there it was a single getMenu() going straight to the network. Now getMenu() returns the cache's Flow, and a new refresh() updates the cache from the network (clearAll + insertAll). The constructor now takes two things: (api, dao).

At the bottom of the file — the mappers between entity and domain (both have price: Double, so they're direct):

private fun MenuItemEntity.toDomain() = MenuItem(id, name, description, price, category, imageUrl)
private fun MenuItem.toEntity() = MenuItemEntity(id, name, description, price, category, imageUrl)

MenuViewModel now observes the cache AND kicks off refresh() (both in init):

init {
    observeMenu()   // subscribe to the cache Flow → Success immediately if the cache is full
    refresh()       // network → cache → the Flow updates itself
}

private fun observeMenu() = viewModelScope.launch {
    repository.getMenu().collect { items ->
        if (items.isNotEmpty()) _uiState.value = MenuUiState.Success(items)
    }
}

private fun refresh() = viewModelScope.launch {
    try { repository.refresh() }
    catch (e: Exception) {
        if (_uiState.value !is MenuUiState.Success)      // only show error if nothing cached
            _uiState.value = MenuUiState.Error(e.message ?: "Could not load menu")
    }
}

And Koin — the cache becomes a few singles, and MenuRepository gets the DAO:

// coreModule — DB and DAO
single { Room.databaseBuilder(get(), PicaDatabase::class.java, "pica.db").build() }
single { get<PicaDatabase>().menuDao() }

// menuModule — MenuRepository now takes PicaApi AND MenuDao
single { MenuRepository(get(), get()) }               // get() = PicaApi, get() = MenuDao

Verify.

1. Run online → the menu loads and is written to the cache.
2. Turn on airplane mode, close and reopen → the menu STILL shows (from the cache).
3. Back online → refresh() quietly updates if anything changed on the server.

Gotcha (main thread). If a DAO method isn't suspend or Flow, Room crashes:

java.lang.IllegalStateException: Cannot access database on the main thread
since it may potentially lock the UI for a long period of time.

Room forbids touching the DB on the main (UI) thread — a DB call can take a while and "freeze" the interface. The fix is Flow for reads and suspend for writes (exactly what our DAO does). Never write a synchronous @Query returning a List directly.