mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-10 23:21:59 +01:00
drop the songs tab and the whole-library song queue
This commit is contained in:
@@ -9,6 +9,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.subtracks.data.model.Album
|
||||
import com.subtracks.data.model.Song
|
||||
import com.subtracks.data.model.Source
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.After
|
||||
import org.junit.Assert.assertEquals
|
||||
@@ -63,29 +64,6 @@ class LibraryDaoTest {
|
||||
assertEquals(listOf("Alpha"), dao.albumsByName(sourceId, starredFilter = 1, search = "").page().map { it.name })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun songSortsByTitleAndStarredFilter() =
|
||||
runTest {
|
||||
val sourceId = source()
|
||||
val dao = db.libraryDao()
|
||||
dao.upsertSongs(
|
||||
listOf(
|
||||
song(sourceId, "s1", "Zebra", starred = null),
|
||||
song(sourceId, "s2", "Apple", starred = 7),
|
||||
),
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
listOf("Apple", "Zebra"),
|
||||
dao.songsByTitle(sourceId, starredFilter = 0, search = "").page().map { it.song.title },
|
||||
)
|
||||
assertEquals(
|
||||
listOf("Zebra", "Apple"),
|
||||
dao.songsByTitleReversed(sourceId, starredFilter = 0, search = "").page().map { it.song.title },
|
||||
)
|
||||
assertEquals(listOf("Apple"), dao.songsByTitle(sourceId, starredFilter = 1, search = "").page().map { it.song.title })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun albumAddedAndStarredSortsAndSearch() =
|
||||
runTest {
|
||||
@@ -112,24 +90,21 @@ class LibraryDaoTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun songAddedSortOrdersByCreated() =
|
||||
fun albumSongsAreOrderedByDiscAndTrack() =
|
||||
runTest {
|
||||
val sourceId = source()
|
||||
val dao = db.libraryDao()
|
||||
dao.upsertSongs(
|
||||
listOf(
|
||||
song(sourceId, "s1", "Zebra", starred = null, created = 100),
|
||||
song(sourceId, "s2", "Apple", starred = null, created = 200),
|
||||
song(sourceId, "s2", "Second", starred = null, track = 2),
|
||||
song(sourceId, "s3", "Third", starred = null, track = 1, disc = 2),
|
||||
song(sourceId, "s1", "First", starred = null, track = 1),
|
||||
),
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
listOf("Apple", "Zebra"),
|
||||
dao.songsByAdded(sourceId, starredFilter = 0, search = "").page().map { it.song.title },
|
||||
)
|
||||
assertEquals(
|
||||
listOf("Zebra", "Apple"),
|
||||
dao.songsByAddedReversed(sourceId, starredFilter = 0, search = "").page().map { it.song.title },
|
||||
listOf("s1", "s2", "s3"),
|
||||
dao.songsByAlbum(sourceId, "al-1").first().map { it.id },
|
||||
)
|
||||
}
|
||||
|
||||
@@ -170,6 +145,8 @@ class LibraryDaoTest {
|
||||
title: String,
|
||||
starred: Long?,
|
||||
created: Long = 0,
|
||||
track: Long = 1,
|
||||
disc: Long = 1,
|
||||
) = Song(
|
||||
sourceId = sourceId,
|
||||
id = id,
|
||||
@@ -179,8 +156,8 @@ class LibraryDaoTest {
|
||||
album = "Album",
|
||||
artist = "Artist",
|
||||
duration = 200,
|
||||
track = 1,
|
||||
disc = 1,
|
||||
track = track,
|
||||
disc = disc,
|
||||
starred = starred,
|
||||
genre = null,
|
||||
created = created,
|
||||
|
||||
@@ -21,15 +21,19 @@ class UserPreferencesTest {
|
||||
val prefs = UserPreferences(store)
|
||||
|
||||
assertEquals(ListQuery("Name"), prefs.listQuery(LibraryListTab.Albums).first())
|
||||
assertEquals(ListQuery("Album"), prefs.listQuery(LibraryListTab.Songs).first())
|
||||
assertEquals(ListQuery("Name"), prefs.listQuery(LibraryListTab.Artists).first())
|
||||
|
||||
prefs.setListQuery(LibraryListTab.Albums, ListQuery("Added", descending = true, starred = StarredFilter.Starred))
|
||||
prefs.setListQuery(LibraryListTab.Artists, ListQuery("AlbumCount", descending = true))
|
||||
|
||||
assertEquals(
|
||||
ListQuery("Added", descending = true, starred = StarredFilter.Starred),
|
||||
prefs.listQuery(LibraryListTab.Albums).first(),
|
||||
)
|
||||
assertEquals(ListQuery("Album"), prefs.listQuery(LibraryListTab.Songs).first())
|
||||
assertEquals(
|
||||
ListQuery("AlbumCount", descending = true),
|
||||
prefs.listQuery(LibraryListTab.Artists).first(),
|
||||
)
|
||||
|
||||
file.delete()
|
||||
}
|
||||
|
||||
@@ -12,8 +12,6 @@ import com.subtracks.data.model.QueueEntry
|
||||
import com.subtracks.data.model.QueueKind
|
||||
import com.subtracks.data.model.Song
|
||||
import com.subtracks.data.model.Source
|
||||
import com.subtracks.data.prefs.SongSort
|
||||
import com.subtracks.data.prefs.StarredFilter
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.After
|
||||
import org.junit.Assert.assertEquals
|
||||
@@ -75,19 +73,6 @@ class QueueRepositoryTest {
|
||||
assertEquals(listOf("s2", "s3"), resolveAll(snapshot))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun theSongsEntryResolvesTheWholeLibraryInListOrder() =
|
||||
runTest {
|
||||
seedLibrary()
|
||||
db.libraryDao().upsertAlbums(listOf(album("al0", "Zeroth Album", "Aardvark")))
|
||||
db.libraryDao().upsertSongs(listOf(song("s0", "al0", track = 1, album = "Zeroth Album")))
|
||||
|
||||
val snapshot = repository.snapshotAfter(listOf(repository.songsEntry(1)))
|
||||
|
||||
assertEquals(6, snapshot.size)
|
||||
assertEquals(listOf("s0", "s1", "s2", "s3", "s4", "s5"), resolveAll(snapshot))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun windowSpansEntryBoundaries() =
|
||||
runTest {
|
||||
@@ -314,39 +299,6 @@ class QueueRepositoryTest {
|
||||
assertEquals(listOf("s2", "s3", "s1"), resolveAll(repository.snapshot()))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun theSongsEntryFollowsItsSortAndStarredFilter() =
|
||||
runTest {
|
||||
seedLibrary()
|
||||
db.libraryDao().upsertSongs(
|
||||
listOf(
|
||||
song("s1", "al1", track = 1, album = "First Album", title = "Charlie", starred = 5),
|
||||
song("s2", "al1", track = 2, album = "First Album", title = "Alpha"),
|
||||
song("s3", "al1", track = 3, album = "First Album", title = "Bravo", starred = 7),
|
||||
song("s4", "al2", track = 1, album = "Second Album", title = "Echo"),
|
||||
song("s5", "al2", track = 2, album = "Second Album", title = "Delta", starred = 3),
|
||||
),
|
||||
)
|
||||
|
||||
val byTitle =
|
||||
repository.snapshotAfter(
|
||||
listOf(repository.songsEntry(1, QueueSongQuery(SongSort.Title, descending = false, StarredFilter.Any))),
|
||||
)
|
||||
assertEquals(listOf("s2", "s3", "s1", "s5", "s4"), resolveAll(byTitle))
|
||||
|
||||
val starredOnly =
|
||||
repository.snapshotAfter(
|
||||
listOf(repository.songsEntry(1, QueueSongQuery(SongSort.Starred, descending = false, StarredFilter.Starred))),
|
||||
)
|
||||
assertEquals(listOf("s3", "s1", "s5"), resolveAll(starredOnly))
|
||||
|
||||
val unstarred =
|
||||
repository.snapshotAfter(
|
||||
listOf(repository.songsEntry(1, QueueSongQuery(SongSort.Album, descending = false, StarredFilter.NotStarred))),
|
||||
)
|
||||
assertEquals(listOf("s2", "s4"), resolveAll(unstarred))
|
||||
}
|
||||
|
||||
private suspend fun QueueRepository.snapshotAfter(entries: List<QueueEntry>): QueueSnapshot {
|
||||
replace(entries)
|
||||
return snapshot()
|
||||
|
||||
@@ -69,14 +69,7 @@ class SyncServiceTest {
|
||||
.allRows()
|
||||
.size,
|
||||
)
|
||||
assertEquals(
|
||||
2,
|
||||
db
|
||||
.libraryDao()
|
||||
.songs(1, 0, "")
|
||||
.allRows()
|
||||
.size,
|
||||
)
|
||||
assertEquals(2, db.libraryDao().songIds(1).size)
|
||||
assertEquals(
|
||||
1,
|
||||
db
|
||||
@@ -99,14 +92,7 @@ class SyncServiceTest {
|
||||
.allRows()
|
||||
.map { it.id },
|
||||
)
|
||||
assertEquals(
|
||||
listOf("s1"),
|
||||
db
|
||||
.libraryDao()
|
||||
.songs(1, 0, "")
|
||||
.allRows()
|
||||
.map { it.song.id },
|
||||
)
|
||||
assertEquals(listOf("s1"), db.libraryDao().songIds(1))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -106,19 +106,6 @@ class PlaybackControllerTest {
|
||||
assertEquals("cover-al1", runBlocking { controller.upcomingItem()?.coverArtId })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun playingTheSongsListQueuesTheWholeLibrary() {
|
||||
seedAlbum(60, sourceId = 1)
|
||||
|
||||
controller.playSongs(1, 30)
|
||||
await { handle.operations.contains("play") }
|
||||
|
||||
assertEquals(51, handle.itemCount)
|
||||
assertEquals(QueueContext(QueueKind.Songs, 1, ""), controller.state.value.context)
|
||||
assertTrue(controller.state.value.hasNext)
|
||||
assertTrue(controller.state.value.hasPrevious)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun advancingShiftsTheWindowAndKeepsItBounded() {
|
||||
seedAlbum(100, sourceId = 1)
|
||||
|
||||
@@ -107,13 +107,11 @@ class AppScreenshotTest {
|
||||
onTabSelected = {},
|
||||
albums = remember { flowOf(PagingData.from(albums)) },
|
||||
artists = remember { flowOf(PagingData.empty<Artist>()) },
|
||||
songs = remember { flowOf(PagingData.empty<SongListItem>()) },
|
||||
playlists = remember { flowOf(PagingData.empty<Playlist>()) },
|
||||
coverArt = { id, _ -> id?.let { CoverArtRef(it, "test:$it") } },
|
||||
onAlbumClick = {},
|
||||
onArtistClick = {},
|
||||
onPlaylistClick = {},
|
||||
onSongClick = {},
|
||||
onSync = {},
|
||||
onOpenSettings = {},
|
||||
artwork = artworkColorsFromSeed(Color.rgb(120, 80, 200)),
|
||||
@@ -133,13 +131,6 @@ class AppScreenshotTest {
|
||||
composeRule.onRoot().captureRoboImage("src/test/screenshots/library_artists.png")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun librarySongs() {
|
||||
setLibraryContent(LibraryTab.Songs)
|
||||
awaitText("Everything In Its Right Place")
|
||||
composeRule.onRoot().captureRoboImage("src/test/screenshots/library_songs.png")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun libraryPlaylists() {
|
||||
setLibraryContent(LibraryTab.Playlists)
|
||||
@@ -166,13 +157,11 @@ class AppScreenshotTest {
|
||||
onTabSelected = {},
|
||||
albums = remember { flowOf(PagingData.from(Fixtures.albums)) },
|
||||
artists = remember { flowOf(PagingData.from(Fixtures.artists)) },
|
||||
songs = remember { flowOf(PagingData.from(Fixtures.songItems)) },
|
||||
playlists = remember { flowOf(PagingData.from(Fixtures.playlists)) },
|
||||
coverArt = { id, _ -> id?.let { CoverArtRef(it, "test:$it") } },
|
||||
onAlbumClick = {},
|
||||
onArtistClick = {},
|
||||
onPlaylistClick = {},
|
||||
onSongClick = {},
|
||||
onSync = {},
|
||||
onOpenSettings = {},
|
||||
artwork = artwork,
|
||||
@@ -473,13 +462,11 @@ class AppScreenshotTest {
|
||||
onTabSelected = {},
|
||||
albums = remember { flowOf(PagingData.from(Fixtures.albums)) },
|
||||
artists = remember { flowOf(PagingData.from(Fixtures.artists)) },
|
||||
songs = remember { flowOf(PagingData.from(Fixtures.songItems)) },
|
||||
playlists = remember { flowOf(PagingData.from(Fixtures.playlists)) },
|
||||
coverArt = { id, _ -> id?.let { CoverArtRef(it, "test:$it") } },
|
||||
onAlbumClick = {},
|
||||
onArtistClick = {},
|
||||
onPlaylistClick = {},
|
||||
onSongClick = {},
|
||||
onSync = {},
|
||||
onOpenSettings = {},
|
||||
artwork = artworkColorsFromSeed(Color.rgb(120, 80, 200)),
|
||||
|
||||
@@ -14,7 +14,6 @@ import com.github.takahirom.roborazzi.captureRoboImage
|
||||
import com.subtracks.data.model.Album
|
||||
import com.subtracks.data.model.Artist
|
||||
import com.subtracks.data.model.Playlist
|
||||
import com.subtracks.data.model.SongListItem
|
||||
import com.subtracks.data.prefs.ListQuery
|
||||
import com.subtracks.ui.library.ALBUM_COVER_TAG
|
||||
import com.subtracks.ui.library.LibraryScreen
|
||||
@@ -44,13 +43,11 @@ class LibraryOptionsScreenshotTest {
|
||||
onTabSelected = {},
|
||||
albums = remember { flowOf(PagingData.from(albums())) },
|
||||
artists = remember { flowOf(PagingData.empty<Artist>()) },
|
||||
songs = remember { flowOf(PagingData.empty<SongListItem>()) },
|
||||
playlists = remember { flowOf(PagingData.empty<Playlist>()) },
|
||||
coverArt = { _, _ -> null },
|
||||
onAlbumClick = {},
|
||||
onArtistClick = {},
|
||||
onPlaylistClick = {},
|
||||
onSongClick = {},
|
||||
onSync = {},
|
||||
onOpenSettings = {},
|
||||
listQuery = ListQuery("Name"),
|
||||
|
||||
@@ -17,7 +17,6 @@ import com.github.takahirom.roborazzi.RobolectricDeviceQualifiers
|
||||
import com.subtracks.data.model.Album
|
||||
import com.subtracks.data.model.Artist
|
||||
import com.subtracks.data.model.Playlist
|
||||
import com.subtracks.data.model.SongListItem
|
||||
import com.subtracks.data.prefs.ListQuery
|
||||
import com.subtracks.data.prefs.StarredFilter
|
||||
import com.subtracks.ui.library.ALBUM_COVER_TAG
|
||||
@@ -50,13 +49,11 @@ class LibraryOptionsTest {
|
||||
onTabSelected = {},
|
||||
albums = remember { flowOf(PagingData.from(albums())) },
|
||||
artists = remember { flowOf(PagingData.empty<Artist>()) },
|
||||
songs = remember { flowOf(PagingData.empty<SongListItem>()) },
|
||||
playlists = remember { flowOf(PagingData.empty<Playlist>()) },
|
||||
coverArt = { _, _ -> null },
|
||||
onAlbumClick = {},
|
||||
onArtistClick = {},
|
||||
onPlaylistClick = {},
|
||||
onSongClick = {},
|
||||
onSync = {},
|
||||
onOpenSettings = {},
|
||||
listQuery = query,
|
||||
|
||||
@@ -23,7 +23,6 @@ import com.github.takahirom.roborazzi.RobolectricDeviceQualifiers
|
||||
import com.subtracks.data.model.Album
|
||||
import com.subtracks.data.model.Artist
|
||||
import com.subtracks.data.model.Playlist
|
||||
import com.subtracks.data.model.SongListItem
|
||||
import com.subtracks.ui.library.ALBUM_COVER_TAG
|
||||
import com.subtracks.ui.library.LibraryScreen
|
||||
import com.subtracks.ui.library.LibraryTab
|
||||
@@ -60,13 +59,11 @@ class LibraryScreenTest {
|
||||
onTabSelected = {},
|
||||
albums = remember { flowOf(PagingData.from(albums())) },
|
||||
artists = remember { flowOf(PagingData.empty<Artist>()) },
|
||||
songs = remember { flowOf(PagingData.empty<SongListItem>()) },
|
||||
playlists = remember { flowOf(PagingData.empty<Playlist>()) },
|
||||
coverArt = { _, _ -> null },
|
||||
onAlbumClick = {},
|
||||
onArtistClick = {},
|
||||
onPlaylistClick = {},
|
||||
onSongClick = {},
|
||||
onSync = { synced = true },
|
||||
onOpenSettings = { settingsOpened = true },
|
||||
)
|
||||
@@ -95,13 +92,11 @@ class LibraryScreenTest {
|
||||
onTabSelected = {},
|
||||
albums = remember { flowOf(PagingData.empty<Album>(settledLoadStates)) },
|
||||
artists = remember { flowOf(PagingData.empty<Artist>()) },
|
||||
songs = remember { flowOf(PagingData.empty<SongListItem>()) },
|
||||
playlists = remember { flowOf(PagingData.empty<Playlist>()) },
|
||||
coverArt = { _, _ -> null },
|
||||
onAlbumClick = {},
|
||||
onArtistClick = {},
|
||||
onPlaylistClick = {},
|
||||
onSongClick = {},
|
||||
onSync = { synced = true },
|
||||
onOpenSettings = {},
|
||||
)
|
||||
@@ -129,11 +124,6 @@ class LibraryScreenTest {
|
||||
collected += "artists"
|
||||
emit(PagingData.empty())
|
||||
}
|
||||
val songs =
|
||||
flow<PagingData<SongListItem>> {
|
||||
collected += "songs"
|
||||
emit(PagingData.empty())
|
||||
}
|
||||
val playlists =
|
||||
flow<PagingData<Playlist>> {
|
||||
collected += "playlists"
|
||||
@@ -146,13 +136,11 @@ class LibraryScreenTest {
|
||||
onTabSelected = {},
|
||||
albums = albums,
|
||||
artists = artists,
|
||||
songs = songs,
|
||||
playlists = playlists,
|
||||
coverArt = { _, _ -> null },
|
||||
onAlbumClick = {},
|
||||
onArtistClick = {},
|
||||
onPlaylistClick = {},
|
||||
onSongClick = {},
|
||||
onSync = {},
|
||||
onOpenSettings = {},
|
||||
)
|
||||
@@ -178,11 +166,6 @@ class LibraryScreenTest {
|
||||
collected += "artists"
|
||||
emit(PagingData.from(artists()))
|
||||
}
|
||||
val songs =
|
||||
flow<PagingData<SongListItem>> {
|
||||
collected += "songs"
|
||||
emit(PagingData.empty())
|
||||
}
|
||||
val playlists =
|
||||
flow<PagingData<Playlist>> {
|
||||
collected += "playlists"
|
||||
@@ -196,13 +179,11 @@ class LibraryScreenTest {
|
||||
onTabSelected = { selectedTab.value = it },
|
||||
albums = albums,
|
||||
artists = artists,
|
||||
songs = songs,
|
||||
playlists = playlists,
|
||||
coverArt = { _, _ -> null },
|
||||
onAlbumClick = {},
|
||||
onArtistClick = {},
|
||||
onPlaylistClick = {},
|
||||
onSongClick = {},
|
||||
onSync = {},
|
||||
onOpenSettings = {},
|
||||
)
|
||||
@@ -223,8 +204,7 @@ class LibraryScreenTest {
|
||||
|
||||
assertTrue("returning to a tab should render its content", collected.contains("albums"))
|
||||
assertTrue("the tab that was shown should collect its flow", collected.contains("artists"))
|
||||
assertFalse("inactive tabs should not collect their flows", collected.contains("songs"))
|
||||
assertFalse(collected.contains("playlists"))
|
||||
assertFalse("inactive tabs should not collect their flows", collected.contains("playlists"))
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -247,7 +227,7 @@ class LibraryScreenTest {
|
||||
composeRule.runOnIdle { pagerState.requestScrollToPage(1, step * 0.05f) }
|
||||
composeRule.waitForIdle()
|
||||
composeRule
|
||||
.onNodeWithContentDescription(LibraryTab.Songs.label)
|
||||
.onNodeWithContentDescription(LibraryTab.Playlists.label)
|
||||
.fetchSemanticsNode()
|
||||
.boundsInRoot.left
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ import com.github.takahirom.roborazzi.captureRoboImage
|
||||
import com.subtracks.data.model.Album
|
||||
import com.subtracks.data.model.Artist
|
||||
import com.subtracks.data.model.Playlist
|
||||
import com.subtracks.data.model.SongListItem
|
||||
import com.subtracks.data.prefs.ListQuery
|
||||
import com.subtracks.ui.library.ALBUM_COVER_TAG
|
||||
import com.subtracks.ui.library.LibraryScreen
|
||||
@@ -45,13 +44,11 @@ class LibrarySearchScreenshotTest {
|
||||
onTabSelected = {},
|
||||
albums = remember { flowOf(PagingData.from(albums())) },
|
||||
artists = remember { flowOf(PagingData.empty<Artist>()) },
|
||||
songs = remember { flowOf(PagingData.empty<SongListItem>()) },
|
||||
playlists = remember { flowOf(PagingData.empty<Playlist>()) },
|
||||
coverArt = { _, _ -> null },
|
||||
onAlbumClick = {},
|
||||
onArtistClick = {},
|
||||
onPlaylistClick = {},
|
||||
onSongClick = {},
|
||||
onSync = {},
|
||||
onOpenSettings = {},
|
||||
listQuery = ListQuery("Name"),
|
||||
|
||||
@@ -66,7 +66,7 @@ class QueueViewModelTest {
|
||||
@Test
|
||||
fun openingLoadsAWindowAtTheCursorAndExtendingGrowsIt() {
|
||||
runBlocking { seedSongs(200) }
|
||||
controller.playSongs(1, 100)
|
||||
controller.playAlbum(1, "al1", 100)
|
||||
await { controller.state.value.position == 100L }
|
||||
|
||||
viewModel.open()
|
||||
@@ -87,7 +87,7 @@ class QueueViewModelTest {
|
||||
@Test
|
||||
fun openingAtTheEndLoadsAWindowAndExtendsOlder() {
|
||||
runBlocking { seedSongs(200) }
|
||||
controller.playSongs(1, 199)
|
||||
controller.playAlbum(1, "al1", 199)
|
||||
await { controller.state.value.position == 199L }
|
||||
|
||||
viewModel.open()
|
||||
@@ -111,7 +111,7 @@ class QueueViewModelTest {
|
||||
@Test
|
||||
fun reopeningReusesRowIdentitySoComposeDoesNotCrossFadeTwoLists() {
|
||||
runBlocking { seedSongs(200) }
|
||||
controller.playSongs(1, 100)
|
||||
controller.playAlbum(1, "al1", 100)
|
||||
await { controller.state.value.position == 100L }
|
||||
|
||||
viewModel.open()
|
||||
@@ -128,7 +128,7 @@ class QueueViewModelTest {
|
||||
@Test
|
||||
fun reorderingMovesTheRowLocally() {
|
||||
runBlocking { seedSongs(200) }
|
||||
controller.playSongs(1, 100)
|
||||
controller.playAlbum(1, "al1", 100)
|
||||
await { controller.state.value.position == 100L }
|
||||
|
||||
viewModel.open()
|
||||
|
||||
Reference in New Issue
Block a user