address review: save the selected tab by name and drop the dead songIds query

This commit is contained in:
austinried
2026-10-04 00:29:59 +00:00
parent e3af5ed0ac
commit f05a1c79a8
5 changed files with 20 additions and 15 deletions
@@ -104,9 +104,6 @@ interface LibraryDao {
limit: Int, limit: Int,
): List<String> ): List<String>
@Query("SELECT id FROM songs WHERE sourceId = :sourceId")
suspend fun songIds(sourceId: Long): List<String>
@Query("SELECT id FROM songs WHERE sourceId = :sourceId AND id > :afterId ORDER BY id LIMIT :limit") @Query("SELECT id FROM songs WHERE sourceId = :sourceId AND id > :afterId ORDER BY id LIMIT :limit")
suspend fun songIdsAfter( suspend fun songIdsAfter(
sourceId: Long, sourceId: Long,
@@ -46,7 +46,7 @@ fun appModule(
single<PlayerConnection> { MediaSessionConnection(context.applicationContext, get()) } single<PlayerConnection> { MediaSessionConnection(context.applicationContext, get()) }
single { PlaybackController(get(), get(), get()) } single { PlaybackController(get(), get(), get()) }
viewModel { RootViewModel(get()) } viewModel { RootViewModel(get()) }
viewModel { LibraryViewModel(get(), get(), get(), get()) } viewModel { LibraryViewModel(get(), get(), get(), get(), get()) }
viewModel { SettingsViewModel(get(), get()) } viewModel { SettingsViewModel(get(), get()) }
viewModel { AddSourceViewModel(get(), get()) } viewModel { AddSourceViewModel(get(), get()) }
viewModel { params -> AlbumDetailViewModel(get(), get(), get(), params.get()) } viewModel { params -> AlbumDetailViewModel(get(), get(), get(), params.get()) }
@@ -186,14 +186,16 @@ fun LibraryRoute(
viewModel: LibraryViewModel = koinViewModel(), viewModel: LibraryViewModel = koinViewModel(),
playbackController: PlaybackController = koinInject(), playbackController: PlaybackController = koinInject(),
) { ) {
var selectedTab by rememberSaveable { mutableStateOf(LibraryTab.Albums) } var selectedTabName by rememberSaveable { mutableStateOf(LibraryTab.Albums.name) }
var previousTab by rememberSaveable { mutableStateOf(LibraryTab.Albums) } var previousTabName by rememberSaveable { mutableStateOf(LibraryTab.Albums.name) }
val selectedTab = LibraryTab.entries.firstOrNull { it.name == selectedTabName } ?: LibraryTab.Albums
val previousTab = LibraryTab.entries.firstOrNull { it.name == previousTabName } ?: LibraryTab.Albums
val syncing by viewModel.syncing.collectAsStateWithLifecycle() val syncing by viewModel.syncing.collectAsStateWithLifecycle()
val listTab = selectedTab.listTab() val listTab = selectedTab.listTab()
LaunchedEffect(selectedTab) { LaunchedEffect(selectedTab) {
if (previousTab != selectedTab) { if (previousTab != selectedTab) {
viewModel.setSearch(previousTab.listTab(), "") viewModel.setSearch(previousTab.listTab(), "")
previousTab = selectedTab previousTabName = selectedTab.name
} }
} }
val listQuery by viewModel.listQuery(listTab).collectAsStateWithLifecycle() val listQuery by viewModel.listQuery(listTab).collectAsStateWithLifecycle()
@@ -208,7 +210,6 @@ fun LibraryRoute(
val artwork = rememberArtworkColors(playbackController.coverArt(playback.item, thumbnail = true)) val artwork = rememberArtworkColors(playbackController.coverArt(playback.item, thumbnail = true))
val itemActions = val itemActions =
ItemActions( ItemActions(
playSong = { viewModel.playSong(it.id) },
playAlbum = { viewModel.playAlbum(it.id) }, playAlbum = { viewModel.playAlbum(it.id) },
shuffleAlbum = { viewModel.shuffleAlbum(it.id) }, shuffleAlbum = { viewModel.shuffleAlbum(it.id) },
playPlaylist = { viewModel.playPlaylist(it.id) }, playPlaylist = { viewModel.playPlaylist(it.id) },
@@ -219,7 +220,7 @@ fun LibraryRoute(
) )
LibraryScreen( LibraryScreen(
selectedTab = selectedTab, selectedTab = selectedTab,
onTabSelected = { selectedTab = it }, onTabSelected = { selectedTabName = it.name },
syncing = syncing, syncing = syncing,
bottomInset = bottomInset, bottomInset = bottomInset,
artwork = artwork, artwork = artwork,
@@ -18,6 +18,7 @@ import com.subtracks.data.repo.LibraryRepository
import com.subtracks.data.repo.SourceRepository import com.subtracks.data.repo.SourceRepository
import com.subtracks.data.sync.SyncManager import com.subtracks.data.sync.SyncManager
import com.subtracks.data.sync.SyncStatus import com.subtracks.data.sync.SyncStatus
import com.subtracks.playback.PlaybackController
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
@@ -35,6 +36,7 @@ class LibraryViewModel(
private val libraryRepository: LibraryRepository, private val libraryRepository: LibraryRepository,
private val sourceRepository: SourceRepository, private val sourceRepository: SourceRepository,
private val syncManager: SyncManager, private val syncManager: SyncManager,
private val playbackController: PlaybackController,
private val userPreferences: UserPreferences, private val userPreferences: UserPreferences,
) : ViewModel() { ) : ViewModel() {
private val listQueries: Map<LibraryListTab, StateFlow<ListQuery>> = private val listQueries: Map<LibraryListTab, StateFlow<ListQuery>> =
@@ -69,7 +69,7 @@ class SyncServiceTest {
.allRows() .allRows()
.size, .size,
) )
assertEquals(2, db.libraryDao().songIds(1).size) assertEquals(2, songIds(1).size)
assertEquals( assertEquals(
1, 1,
db db
@@ -92,7 +92,7 @@ class SyncServiceTest {
.allRows() .allRows()
.map { it.id }, .map { it.id },
) )
assertEquals(listOf("s1"), db.libraryDao().songIds(1)) assertEquals(listOf("s1"), songIds(1))
} }
@Test @Test
@@ -113,7 +113,7 @@ class SyncServiceTest {
assertEquals(2, db.libraryDao().artistIds(1).size) assertEquals(2, db.libraryDao().artistIds(1).size)
assertEquals(1, db.libraryDao().albumIds(1).size) assertEquals(1, db.libraryDao().albumIds(1).size)
assertEquals(1, db.libraryDao().songIds(1).size) assertEquals(1, songIds(1).size)
assertEquals(1, db.libraryDao().playlistIds(1).size) assertEquals(1, db.libraryDao().playlistIds(1).size)
assertEquals( assertEquals(
1, 1,
@@ -298,7 +298,7 @@ class SyncServiceTest {
SyncService(db, source).sync() SyncService(db, source).sync()
assertEquals((1..5).map { "a$it" }, db.libraryDao().artistIds(1).sorted()) assertEquals((1..5).map { "a$it" }, db.libraryDao().artistIds(1).sorted())
assertEquals((1..5).map { "s$it" }, db.libraryDao().songIds(1).sorted()) assertEquals((1..5).map { "s$it" }, songIds(1).sorted())
source.artists = (1..3).map { artist("a$it") } source.artists = (1..3).map { artist("a$it") }
source.songs = (1..3).map { song("s$it") } source.songs = (1..3).map { song("s$it") }
@@ -306,7 +306,7 @@ class SyncServiceTest {
SyncService(db, source).sync() SyncService(db, source).sync()
assertEquals((1..3).map { "a$it" }, db.libraryDao().artistIds(1).sorted()) assertEquals((1..3).map { "a$it" }, db.libraryDao().artistIds(1).sorted())
assertEquals((1..3).map { "s$it" }, db.libraryDao().songIds(1).sorted()) assertEquals((1..3).map { "s$it" }, songIds(1).sorted())
} }
@Test @Test
@@ -485,7 +485,7 @@ class SyncServiceTest {
SyncService(db, sourceOne).sync() SyncService(db, sourceOne).sync()
assertEquals(listOf("b1"), db.libraryDao().artistIds(2)) assertEquals(listOf("b1"), db.libraryDao().artistIds(2))
assertEquals(listOf("s2"), db.libraryDao().songIds(2)) assertEquals(listOf("s2"), songIds(2))
assertEquals(listOf("p2"), db.libraryDao().playlistIds(2)) assertEquals(listOf("p2"), db.libraryDao().playlistIds(2))
assertEquals( assertEquals(
1, 1,
@@ -587,6 +587,11 @@ class SyncServiceTest {
} }
} }
private suspend fun songIds(sourceId: Long): List<String> =
db
.libraryDao()
.songIdsAfter(sourceId, "", Int.MAX_VALUE)
private suspend fun storedDiscKeys(): List<DiscKey> = private suspend fun storedDiscKeys(): List<DiscKey> =
db db
.libraryDao() .libraryDao()