remember the library tab across restarts

The selected tab lived in rememberSaveable, which survives a rotation or a
process-death restore but not a cold start, so the app always came back on
Albums. It goes through DataStore now, like the per-tab sort and filters, which
were already durable - landing on a different tab than the one you had filtered
is what made the filters look reset.
This commit is contained in:
austinried
2026-10-04 00:30:04 +00:00
parent 684cc5a287
commit 270d749f0c
4 changed files with 37 additions and 4 deletions
@@ -134,6 +134,14 @@ class UserPreferences(
private fun listQueryKey(tab: LibraryListTab) = stringPreferencesKey("list_query_${tab.key}")
fun libraryTab(): Flow<String> = store.data.map { prefs -> prefs[libraryTabKey] ?: LibraryListTab.Albums.name }
suspend fun setLibraryTab(tab: String) {
store.edit { prefs -> prefs[libraryTabKey] = tab }
}
private val libraryTabKey = stringPreferencesKey("library_tab")
private fun encode(query: ListQuery) =
"${query.sort}|${if (query.descending) 1 else 0}|${query.starred.ordinal}|${if (query.downloaded) 1 else 0}"
@@ -195,9 +195,8 @@ fun LibraryRoute(
viewModel: LibraryViewModel = koinViewModel(),
playbackController: PlaybackController = koinInject(),
) {
var selectedTabName by rememberSaveable { mutableStateOf(LibraryTab.Albums.name) }
var previousTabName by rememberSaveable { mutableStateOf(LibraryTab.Albums.name) }
val selectedTab = LibraryTab.entries.firstOrNull { it.name == selectedTabName } ?: LibraryTab.Albums
val selectedTab by viewModel.selectedTab.collectAsStateWithLifecycle()
var previousTabName by rememberSaveable { mutableStateOf(selectedTab.name) }
val previousTab = LibraryTab.entries.firstOrNull { it.name == previousTabName } ?: LibraryTab.Albums
val syncing by viewModel.syncing.collectAsStateWithLifecycle()
val listTab = selectedTab.listTab()
@@ -242,7 +241,7 @@ fun LibraryRoute(
)
LibraryScreen(
selectedTab = selectedTab,
onTabSelected = { selectedTabName = it.name },
onTabSelected = { viewModel.selectTab(it) },
syncing = syncing,
bottomInset = bottomInset,
artwork = artwork,
@@ -135,6 +135,16 @@ class LibraryViewModel(
fun listQuery(tab: LibraryListTab): StateFlow<ListQuery> = listQueries.getValue(tab)
val selectedTab: StateFlow<LibraryTab> =
userPreferences
.libraryTab()
.map { name -> LibraryTab.entries.firstOrNull { it.name == name } ?: LibraryTab.Albums }
.stateIn(viewModelScope, SharingStarted.Eagerly, LibraryTab.Albums)
fun selectTab(tab: LibraryTab) {
viewModelScope.launch { userPreferences.setLibraryTab(tab.name) }
}
fun setListQuery(
tab: LibraryListTab,
query: ListQuery,
@@ -45,6 +45,22 @@ class UserPreferencesTest {
file.delete()
}
@Test
fun theSelectedLibraryTabRoundTrips() =
runTest {
val file = File.createTempFile("user-prefs", ".preferences_pb").apply { delete() }
val store = PreferenceDataStoreFactory.create(scope = backgroundScope) { file }
val prefs = UserPreferences(store)
assertEquals("Albums", prefs.libraryTab().first())
prefs.setLibraryTab("Playlists")
assertEquals("Playlists", prefs.libraryTab().first())
file.delete()
}
@Test
fun aListQueryStoredBeforeTheDownloadedFilterStillDecodes() =
runTest {