Skip to content

Commit a3e6d58

Browse files
authored
Remember the last program that was running (#123)
1 parent 7d156d0 commit a3e6d58

File tree

7 files changed

+45
-5
lines changed

7 files changed

+45
-5
lines changed

app/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ dependencies {
7373
implementation(libs.androidx.room.ktx)
7474
ksp(libs.androidx.room.compiler)
7575

76+
implementation(libs.androidx.datastore.preferences)
7677

7778
implementation(libs.androidx.core.ktx)
7879
implementation(libs.androidx.lifecycle.runtime.ktx)

app/src/main/java/com/emerjbl/ultra8/Ultra8Application.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package com.emerjbl.ultra8
22

33
import android.app.Application
4+
import android.content.Context
5+
import androidx.datastore.core.DataStore
6+
import androidx.datastore.preferences.core.Preferences
7+
import androidx.datastore.preferences.preferencesDataStore
48
import androidx.room.RoomDatabase
59
import com.emerjbl.ultra8.data.Chip8StateStore
610
import com.emerjbl.ultra8.data.ProgramStore
@@ -10,8 +14,11 @@ interface Provider {
1014
val chip8StateStore: Chip8StateStore
1115
val programStore: ProgramStore
1216
val db: RoomDatabase
17+
1318
}
1419

20+
val Context.preferences: DataStore<Preferences> by preferencesDataStore(name = "settings")
21+
1522
class Ultra8Application : Application() {
1623
val provider = object : Provider {
1724
override val chip8StateStore by lazy { Chip8StateStore(db.chip8StateDao()) }

app/src/main/java/com/emerjbl/ultra8/data/ProgramStore.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,18 @@ package com.emerjbl.ultra8.data
33
import android.content.Context
44
import android.net.Uri
55
import android.provider.MediaStore.MediaColumns
6+
import androidx.datastore.preferences.core.edit
7+
import androidx.datastore.preferences.core.stringPreferencesKey
68
import androidx.room.Dao
79
import androidx.room.Delete
810
import androidx.room.Entity
911
import androidx.room.PrimaryKey
1012
import androidx.room.Query
1113
import androidx.room.Upsert
14+
import com.emerjbl.ultra8.preferences
1215
import kotlinx.coroutines.Dispatchers
1316
import kotlinx.coroutines.flow.Flow
17+
import kotlinx.coroutines.flow.map
1418
import kotlinx.coroutines.withContext
1519

1620
/** A single program entry. */
@@ -55,6 +59,17 @@ class ProgramStore(
5559
) {
5660
fun programsFlow(): Flow<List<Program>> = programDao.allFlow()
5761

62+
val selectedProgram = context.preferences.data.map {
63+
(it[SELECTED_PROGRAM_KEY] ?: DEFAULT_PROGRAM_NAME)
64+
}
65+
66+
suspend fun setSelectedProgram(name: String) {
67+
context.preferences.edit {
68+
it[SELECTED_PROGRAM_KEY] = name
69+
}
70+
}
71+
72+
5873
suspend fun addForUri(uri: Uri): Program =
5974
withContext(Dispatchers.IO) {
6075
val name = withContext(Dispatchers.IO) {
@@ -87,4 +102,9 @@ class ProgramStore(
87102
programDao.updateCyclesPerTick(name, cyclesPerTick)
88103

89104
suspend fun remove(name: String) = programDao.remove(Program(name, false, 0))
105+
106+
companion object {
107+
private val SELECTED_PROGRAM_KEY = stringPreferencesKey("lastProgram")
108+
private const val DEFAULT_PROGRAM_NAME = "breakout"
109+
}
90110
}

app/src/main/java/com/emerjbl/ultra8/ui/screen/AppEntryPoint.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ fun AppEntryPoint() {
2828
val programs = topLevelViewModel.programs.collectAsState(emptyList())
2929
val selectedProgram = topLevelViewModel.selectedProgram.collectAsState("")
3030

31+
if (selectedProgram.value == "") {
32+
// TODO - Maybe show some splash screen kind of thing
33+
return
34+
}
3135
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
3236

3337
val windowFocused = LocalWindowInfo.current.isWindowFocused
@@ -55,8 +59,8 @@ fun AppEntryPoint() {
5559
scope.launch {
5660
drawerState.close()
5761
}
58-
if (topLevelViewModel.selectedProgram.value != program.name) {
59-
topLevelViewModel.selectedProgram.value = program.name
62+
if (selectedProgram.value != program.name) {
63+
topLevelViewModel.setSelectedProgram(program.name)
6064
navController.navigate(PlayGame(program.name))
6165
}
6266
},

app/src/main/java/com/emerjbl/ultra8/ui/screen/Ultra8NavHost.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ fun Ultra8NavHost(
1717
resetEvents: Flow<Unit>,
1818
onDrawerOpen: () -> Unit,
1919
) {
20-
NavHost(navController, startDestination = PlayGame("breakout")) {
20+
NavHost(navController, startDestination = PlayGame(selectedProgram)) {
2121
composable<PlayGame> { entry ->
2222
val routeProgram = entry.toRoute<PlayGame>().programName
2323
// During navigation, the previous route is still in composition for a few

app/src/main/java/com/emerjbl/ultra8/ui/viewmodel/TopLevelViewModel.kt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,26 @@ import com.emerjbl.ultra8.data.Program
1010
import com.emerjbl.ultra8.data.ProgramStore
1111
import kotlinx.coroutines.flow.Flow
1212
import kotlinx.coroutines.flow.MutableSharedFlow
13-
import kotlinx.coroutines.flow.MutableStateFlow
1413
import kotlinx.coroutines.launch
1514

1615
class TopLevelViewModel(
1716
private val programStore: ProgramStore,
1817
) : ViewModel() {
18+
1919
val programs: Flow<List<Program>> = programStore.programsFlow()
2020

2121
// Pass reset events from the navigation drawer down to gameplay children.
2222
// This is one case where I feel like it's OK to break unidirectional dataflow.
2323
// But I'll probably find a better approach eventually.
2424
val resetEvents = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
2525

26-
val selectedProgram = MutableStateFlow("")
26+
val selectedProgram = programStore.selectedProgram
27+
28+
fun setSelectedProgram(name: String) {
29+
viewModelScope.launch {
30+
programStore.setSelectedProgram(name)
31+
}
32+
}
2733

2834
fun removeProgram(name: String) {
2935
viewModelScope.launch {

gradle/libs.versions.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
[versions]
22
agp = "8.7.1"
3+
datastorePreferences = "1.1.1"
34
kotlin = "2.0.21"
45
coreKtx = "1.13.1"
56
junit = "4.13.2"
@@ -29,6 +30,7 @@ ksp = "2.0.21-1.0.25"
2930

3031
[libraries]
3132
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
33+
androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastorePreferences" }
3234
androidx-lifecycle-viewmodel-compose = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "lifecycleViewmodelCompose" }
3335
androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "roomRuntime" }
3436
androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "roomRuntime" }

0 commit comments

Comments
 (0)