mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-10 15:11:58 +01:00
start the library on the stored tab instead of scrolling to it
The pager's settled-page collector reports its initial value, so a cold start wrote Albums back before the stored tab had been read - racing the very setting this branch added, able to pin the app to Albums and overwrite the choice. The screen waits for the stored tab before composing now, so the pager latches the right page and the initial report matches it, which also drops the spurious scroll and the search clear that came with it. The report is guarded anyway. The data layer no longer names a UI tab from a coincidentally same-named enum: it returns the raw stored value and the view model owns the Albums fallback.
This commit is contained in:
@@ -134,7 +134,7 @@ 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 }
|
||||
fun libraryTab(): Flow<String?> = store.data.map { prefs -> prefs[libraryTabKey] }
|
||||
|
||||
suspend fun setLibraryTab(tab: String) {
|
||||
store.edit { prefs -> prefs[libraryTabKey] = tab }
|
||||
|
||||
@@ -151,6 +151,8 @@ data class SortOption(
|
||||
|
||||
fun LibraryTab.listTab(): LibraryListTab = LibraryListTab.valueOf(name)
|
||||
|
||||
internal fun libraryTabFor(name: String?): LibraryTab = LibraryTab.entries.firstOrNull { it.name == name } ?: LibraryTab.Albums
|
||||
|
||||
fun sortOptionsFor(tab: LibraryTab): List<SortOption> =
|
||||
when (tab) {
|
||||
LibraryTab.Albums -> {
|
||||
@@ -195,8 +197,10 @@ fun LibraryRoute(
|
||||
viewModel: LibraryViewModel = koinViewModel(),
|
||||
playbackController: PlaybackController = koinInject(),
|
||||
) {
|
||||
val selectedTab by viewModel.selectedTab.collectAsStateWithLifecycle()
|
||||
var previousTabName by rememberSaveable { mutableStateOf(selectedTab.name) }
|
||||
// Wait for the stored tab before composing: the pager latches its initial page, so starting on
|
||||
// the default and scrolling to the stored one would flash and, worse, report the default back.
|
||||
val selectedTab = viewModel.selectedTab.collectAsStateWithLifecycle().value ?: return
|
||||
var previousTabName by remember { mutableStateOf(selectedTab.name) }
|
||||
val previousTab = LibraryTab.entries.firstOrNull { it.name == previousTabName } ?: LibraryTab.Albums
|
||||
val syncing by viewModel.syncing.collectAsStateWithLifecycle()
|
||||
val listTab = selectedTab.listTab()
|
||||
@@ -241,7 +245,7 @@ fun LibraryRoute(
|
||||
)
|
||||
LibraryScreen(
|
||||
selectedTab = selectedTab,
|
||||
onTabSelected = { viewModel.selectTab(it) },
|
||||
onTabSelected = { tab -> if (viewModel.selectedTab.value != tab) viewModel.selectTab(tab) },
|
||||
syncing = syncing,
|
||||
bottomInset = bottomInset,
|
||||
artwork = artwork,
|
||||
|
||||
@@ -135,11 +135,11 @@ class LibraryViewModel(
|
||||
|
||||
fun listQuery(tab: LibraryListTab): StateFlow<ListQuery> = listQueries.getValue(tab)
|
||||
|
||||
val selectedTab: StateFlow<LibraryTab> =
|
||||
val selectedTab: StateFlow<LibraryTab?> =
|
||||
userPreferences
|
||||
.libraryTab()
|
||||
.map { name -> LibraryTab.entries.firstOrNull { it.name == name } ?: LibraryTab.Albums }
|
||||
.stateIn(viewModelScope, SharingStarted.Eagerly, LibraryTab.Albums)
|
||||
.map(::libraryTabFor)
|
||||
.stateIn(viewModelScope, SharingStarted.Eagerly, null)
|
||||
|
||||
fun selectTab(tab: LibraryTab) {
|
||||
viewModelScope.launch { userPreferences.setLibraryTab(tab.name) }
|
||||
|
||||
@@ -10,6 +10,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import java.io.File
|
||||
@@ -32,6 +33,7 @@ class UserPreferencesTest {
|
||||
ListQuery("Added", descending = true, starred = StarredFilter.Starred, downloaded = true),
|
||||
)
|
||||
prefs.setListQuery(LibraryListTab.Artists, ListQuery("AlbumCount", descending = true))
|
||||
prefs.setListQuery(LibraryListTab.Playlists, ListQuery("Updated", starred = StarredFilter.NotStarred))
|
||||
|
||||
assertEquals(
|
||||
ListQuery("Added", descending = true, starred = StarredFilter.Starred, downloaded = true),
|
||||
@@ -41,30 +43,10 @@ class UserPreferencesTest {
|
||||
ListQuery("AlbumCount", descending = true),
|
||||
prefs.listQuery(LibraryListTab.Artists).first(),
|
||||
)
|
||||
|
||||
file.delete()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun everyTabsListQueryIsKeptIndependently() =
|
||||
runTest {
|
||||
val file = File.createTempFile("user-prefs", ".preferences_pb").apply { delete() }
|
||||
val store = PreferenceDataStoreFactory.create(scope = backgroundScope) { file }
|
||||
val prefs = UserPreferences(store)
|
||||
|
||||
prefs.setListQuery(LibraryListTab.Albums, ListQuery("Added", descending = true, downloaded = true))
|
||||
prefs.setListQuery(LibraryListTab.Artists, ListQuery("AlbumCount", starred = StarredFilter.NotStarred))
|
||||
prefs.setListQuery(LibraryListTab.Playlists, ListQuery("Updated", descending = true))
|
||||
|
||||
assertEquals(
|
||||
ListQuery("Added", descending = true, downloaded = true),
|
||||
prefs.listQuery(LibraryListTab.Albums).first(),
|
||||
ListQuery("Updated", starred = StarredFilter.NotStarred),
|
||||
prefs.listQuery(LibraryListTab.Playlists).first(),
|
||||
)
|
||||
assertEquals(
|
||||
ListQuery("AlbumCount", starred = StarredFilter.NotStarred),
|
||||
prefs.listQuery(LibraryListTab.Artists).first(),
|
||||
)
|
||||
assertEquals(ListQuery("Updated", descending = true), prefs.listQuery(LibraryListTab.Playlists).first())
|
||||
|
||||
file.delete()
|
||||
}
|
||||
@@ -76,7 +58,7 @@ class UserPreferencesTest {
|
||||
val store = PreferenceDataStoreFactory.create(scope = backgroundScope) { file }
|
||||
val prefs = UserPreferences(store)
|
||||
|
||||
assertEquals("Albums", prefs.libraryTab().first())
|
||||
assertNull(prefs.libraryTab().first())
|
||||
|
||||
prefs.setLibraryTab("Playlists")
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.subtracks.ui.library
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class LibraryTabTest {
|
||||
@Test
|
||||
fun theStoredNameMapsToItsTabAndAnythingElseToAlbums() {
|
||||
assertEquals(LibraryTab.Playlists, libraryTabFor("Playlists"))
|
||||
assertEquals(LibraryTab.Albums, libraryTabFor(null))
|
||||
assertEquals(LibraryTab.Albums, libraryTabFor("Books"))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user