Tweak code
This commit is contained in:
parent
9a5ea69de4
commit
df36075c3e
7 changed files with 132 additions and 160 deletions
|
@ -153,9 +153,6 @@ interface Database {
|
||||||
@Query("SELECT * FROM Artist WHERE id = :id")
|
@Query("SELECT * FROM Artist WHERE id = :id")
|
||||||
fun artist(id: String): Flow<Artist?>
|
fun artist(id: String): Flow<Artist?>
|
||||||
|
|
||||||
@Query("SELECT timestamp FROM Artist WHERE id = :id")
|
|
||||||
fun artistTimestamp(id: String): Long?
|
|
||||||
|
|
||||||
@Query("SELECT * FROM Artist WHERE bookmarkedAt IS NOT NULL ORDER BY name DESC")
|
@Query("SELECT * FROM Artist WHERE bookmarkedAt IS NOT NULL ORDER BY name DESC")
|
||||||
fun artistsByNameDesc(): Flow<List<Artist>>
|
fun artistsByNameDesc(): Flow<List<Artist>>
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,13 @@ import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.saveable.rememberSaveableStateHolder
|
import androidx.compose.runtime.saveable.rememberSaveableStateHolder
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.runtime.snapshotFlow
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
@ -38,12 +41,11 @@ import it.vfsfitvnm.vimusic.ui.screens.searchresult.ItemsPage
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.px
|
import it.vfsfitvnm.vimusic.ui.styling.px
|
||||||
import it.vfsfitvnm.vimusic.utils.asMediaItem
|
import it.vfsfitvnm.vimusic.utils.asMediaItem
|
||||||
import it.vfsfitvnm.vimusic.utils.produceSaveableState
|
|
||||||
import it.vfsfitvnm.youtubemusic.Innertube
|
import it.vfsfitvnm.youtubemusic.Innertube
|
||||||
import it.vfsfitvnm.youtubemusic.models.bodies.BrowseBody
|
import it.vfsfitvnm.youtubemusic.models.bodies.BrowseBody
|
||||||
import it.vfsfitvnm.youtubemusic.requests.albumPage
|
import it.vfsfitvnm.youtubemusic.requests.albumPage
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.flowOn
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
@ExperimentalFoundationApi
|
@ExperimentalFoundationApi
|
||||||
|
@ -52,49 +54,44 @@ import kotlinx.coroutines.withContext
|
||||||
fun AlbumScreen(browseId: String) {
|
fun AlbumScreen(browseId: String) {
|
||||||
val saveableStateHolder = rememberSaveableStateHolder()
|
val saveableStateHolder = rememberSaveableStateHolder()
|
||||||
|
|
||||||
val (tabIndex, onTabChanged) = rememberSaveable {
|
var tabIndex by rememberSaveable {
|
||||||
mutableStateOf(0)
|
mutableStateOf(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
val album by produceSaveableState(
|
var album by rememberSaveable(stateSaver = nullableSaver(AlbumSaver)) {
|
||||||
initialValue = null,
|
mutableStateOf(null)
|
||||||
stateSaver = nullableSaver(AlbumSaver),
|
|
||||||
) {
|
|
||||||
Database
|
|
||||||
.album(browseId)
|
|
||||||
.flowOn(Dispatchers.IO)
|
|
||||||
.collect { value = it }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val innertubeAlbum by produceSaveableState(
|
var albumPage by rememberSaveable(stateSaver = nullableSaver(InnertubePlaylistOrAlbumPageSaver)) {
|
||||||
initialValue = null,
|
mutableStateOf(null)
|
||||||
stateSaver = nullableSaver(InnertubePlaylistOrAlbumPageSaver),
|
}
|
||||||
tabIndex > 0
|
|
||||||
) {
|
|
||||||
if (value != null || (tabIndex == 0 && withContext(Dispatchers.IO) {
|
|
||||||
Database.albumTimestamp(
|
|
||||||
browseId
|
|
||||||
)
|
|
||||||
} != null)) return@produceSaveableState
|
|
||||||
|
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
Database
|
||||||
|
.album(browseId)
|
||||||
|
.combine(snapshotFlow { tabIndex }) { album, tabIndex -> album to tabIndex }
|
||||||
|
.collect { (currentAlbum, tabIndex) ->
|
||||||
|
album = currentAlbum
|
||||||
|
|
||||||
|
if (albumPage == null && (currentAlbum?.timestamp == null || tabIndex == 1)) {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
Innertube.albumPage(BrowseBody(browseId = browseId))
|
Innertube.albumPage(BrowseBody(browseId = browseId))
|
||||||
}?.onSuccess { albumPage ->
|
?.onSuccess { currentAlbumPage ->
|
||||||
value = albumPage
|
albumPage = currentAlbumPage
|
||||||
|
|
||||||
query {
|
|
||||||
Database.upsert(
|
Database.upsert(
|
||||||
Album(
|
Album(
|
||||||
id = browseId,
|
id = browseId,
|
||||||
title = albumPage.title,
|
title = currentAlbumPage.title,
|
||||||
thumbnailUrl = albumPage.thumbnail?.url,
|
thumbnailUrl = currentAlbumPage.thumbnail?.url,
|
||||||
year = albumPage.year,
|
year = currentAlbumPage.year,
|
||||||
authorsText = albumPage.authors?.joinToString("") { it.name ?: "" },
|
authorsText = currentAlbumPage.authors
|
||||||
shareUrl = albumPage.url,
|
?.joinToString("") { it.name ?: "" },
|
||||||
|
shareUrl = currentAlbumPage.url,
|
||||||
timestamp = System.currentTimeMillis(),
|
timestamp = System.currentTimeMillis(),
|
||||||
bookmarkedAt = album?.bookmarkedAt
|
bookmarkedAt = album?.bookmarkedAt
|
||||||
),
|
),
|
||||||
albumPage
|
currentAlbumPage
|
||||||
.songsPage
|
.songsPage
|
||||||
?.items
|
?.items
|
||||||
?.map(Innertube.SongItem::asMediaItem)
|
?.map(Innertube.SongItem::asMediaItem)
|
||||||
|
@ -109,6 +106,9 @@ fun AlbumScreen(browseId: String) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RouteHandler(listenToGlobalEmitter = true) {
|
RouteHandler(listenToGlobalEmitter = true) {
|
||||||
|
@ -184,7 +184,7 @@ fun AlbumScreen(browseId: String) {
|
||||||
topIconButtonId = R.drawable.chevron_back,
|
topIconButtonId = R.drawable.chevron_back,
|
||||||
onTopIconButtonClick = pop,
|
onTopIconButtonClick = pop,
|
||||||
tabIndex = tabIndex,
|
tabIndex = tabIndex,
|
||||||
onTabChanged = onTabChanged,
|
onTabChanged = { tabIndex = it },
|
||||||
tabColumnContent = { Item ->
|
tabColumnContent = { Item ->
|
||||||
Item(0, "Songs", R.drawable.musical_notes)
|
Item(0, "Songs", R.drawable.musical_notes)
|
||||||
Item(1, "Other versions", R.drawable.disc)
|
Item(1, "Other versions", R.drawable.disc)
|
||||||
|
@ -208,11 +208,11 @@ fun AlbumScreen(browseId: String) {
|
||||||
initialPlaceholderCount = 1,
|
initialPlaceholderCount = 1,
|
||||||
continuationPlaceholderCount = 1,
|
continuationPlaceholderCount = 1,
|
||||||
emptyItemsText = "This album doesn't have any alternative version",
|
emptyItemsText = "This album doesn't have any alternative version",
|
||||||
itemsPageProvider = innertubeAlbum?.let {
|
itemsPageProvider = albumPage?.let {
|
||||||
({
|
({
|
||||||
Result.success(
|
Result.success(
|
||||||
Innertube.ItemsPage(
|
Innertube.ItemsPage(
|
||||||
items = innertubeAlbum?.otherVersions,
|
items = albumPage?.otherVersions,
|
||||||
continuation = null
|
continuation = null
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -8,8 +8,13 @@ import androidx.compose.foundation.combinedClickable
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.saveable.rememberSaveableStateHolder
|
import androidx.compose.runtime.saveable.rememberSaveableStateHolder
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.runtime.snapshotFlow
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
@ -45,7 +50,6 @@ import it.vfsfitvnm.vimusic.ui.styling.px
|
||||||
import it.vfsfitvnm.vimusic.utils.artistScreenTabIndexKey
|
import it.vfsfitvnm.vimusic.utils.artistScreenTabIndexKey
|
||||||
import it.vfsfitvnm.vimusic.utils.asMediaItem
|
import it.vfsfitvnm.vimusic.utils.asMediaItem
|
||||||
import it.vfsfitvnm.vimusic.utils.forcePlay
|
import it.vfsfitvnm.vimusic.utils.forcePlay
|
||||||
import it.vfsfitvnm.vimusic.utils.produceSaveableState
|
|
||||||
import it.vfsfitvnm.vimusic.utils.rememberPreference
|
import it.vfsfitvnm.vimusic.utils.rememberPreference
|
||||||
import it.vfsfitvnm.youtubemusic.Innertube
|
import it.vfsfitvnm.youtubemusic.Innertube
|
||||||
import it.vfsfitvnm.youtubemusic.models.bodies.BrowseBody
|
import it.vfsfitvnm.youtubemusic.models.bodies.BrowseBody
|
||||||
|
@ -54,7 +58,9 @@ import it.vfsfitvnm.youtubemusic.requests.artistPage
|
||||||
import it.vfsfitvnm.youtubemusic.requests.itemsPage
|
import it.vfsfitvnm.youtubemusic.requests.itemsPage
|
||||||
import it.vfsfitvnm.youtubemusic.utils.from
|
import it.vfsfitvnm.youtubemusic.utils.from
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.flowOn
|
import kotlinx.coroutines.flow.combine
|
||||||
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
@ExperimentalFoundationApi
|
@ExperimentalFoundationApi
|
||||||
|
@ -63,50 +69,44 @@ import kotlinx.coroutines.withContext
|
||||||
fun ArtistScreen(browseId: String) {
|
fun ArtistScreen(browseId: String) {
|
||||||
val saveableStateHolder = rememberSaveableStateHolder()
|
val saveableStateHolder = rememberSaveableStateHolder()
|
||||||
|
|
||||||
val (tabIndex, onTabIndexChanged) = rememberPreference(
|
var tabIndex by rememberPreference(artistScreenTabIndexKey, defaultValue = 0)
|
||||||
artistScreenTabIndexKey,
|
|
||||||
defaultValue = 0
|
|
||||||
)
|
|
||||||
|
|
||||||
val artist by produceSaveableState(
|
var artist by rememberSaveable(stateSaver = nullableSaver(ArtistSaver)) {
|
||||||
initialValue = null,
|
mutableStateOf(null)
|
||||||
stateSaver = nullableSaver(ArtistSaver),
|
|
||||||
) {
|
|
||||||
Database
|
|
||||||
.artist(browseId)
|
|
||||||
.flowOn(Dispatchers.IO)
|
|
||||||
.collect { value = it }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val youtubeArtist by produceSaveableState(
|
var artistPage by rememberSaveable(stateSaver = nullableSaver(InnertubeArtistPageSaver)) {
|
||||||
initialValue = null,
|
mutableStateOf(null)
|
||||||
stateSaver = nullableSaver(InnertubeArtistPageSaver),
|
}
|
||||||
tabIndex < 4
|
|
||||||
) {
|
|
||||||
if (value != null || (tabIndex == 4 && withContext(Dispatchers.IO) {
|
|
||||||
Database.artistTimestamp(
|
|
||||||
browseId
|
|
||||||
)
|
|
||||||
} != null)) return@produceSaveableState
|
|
||||||
|
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
Database
|
||||||
|
.artist(browseId)
|
||||||
|
.combine(snapshotFlow { tabIndex }.map { it != 4 }) { artist, mustFetch -> artist to mustFetch }
|
||||||
|
.distinctUntilChanged()
|
||||||
|
.collect { (currentArtist, mustFetch) ->
|
||||||
|
artist = currentArtist
|
||||||
|
|
||||||
|
if (artistPage == null && (currentArtist?.timestamp == null || mustFetch)) {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
Innertube.artistPage(BrowseBody(browseId = browseId))
|
Innertube.artistPage(BrowseBody(browseId = browseId))
|
||||||
}?.onSuccess { artistPage ->
|
?.onSuccess { currentArtistPage ->
|
||||||
value = artistPage
|
artistPage = currentArtistPage
|
||||||
|
|
||||||
query {
|
|
||||||
Database.upsert(
|
Database.upsert(
|
||||||
Artist(
|
Artist(
|
||||||
id = browseId,
|
id = browseId,
|
||||||
name = artistPage.name,
|
name = currentArtistPage.name,
|
||||||
thumbnailUrl = artistPage.thumbnail?.url,
|
thumbnailUrl = currentArtistPage.thumbnail?.url,
|
||||||
timestamp = System.currentTimeMillis(),
|
timestamp = System.currentTimeMillis(),
|
||||||
bookmarkedAt = artist?.bookmarkedAt
|
bookmarkedAt = currentArtist?.bookmarkedAt
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RouteHandler(listenToGlobalEmitter = true) {
|
RouteHandler(listenToGlobalEmitter = true) {
|
||||||
globalRoutes()
|
globalRoutes()
|
||||||
|
@ -181,7 +181,7 @@ fun ArtistScreen(browseId: String) {
|
||||||
topIconButtonId = R.drawable.chevron_back,
|
topIconButtonId = R.drawable.chevron_back,
|
||||||
onTopIconButtonClick = pop,
|
onTopIconButtonClick = pop,
|
||||||
tabIndex = tabIndex,
|
tabIndex = tabIndex,
|
||||||
onTabChanged = onTabIndexChanged,
|
onTabChanged = { tabIndex = it },
|
||||||
tabColumnContent = { Item ->
|
tabColumnContent = { Item ->
|
||||||
Item(0, "Overview", R.drawable.sparkles)
|
Item(0, "Overview", R.drawable.sparkles)
|
||||||
Item(1, "Songs", R.drawable.musical_notes)
|
Item(1, "Songs", R.drawable.musical_notes)
|
||||||
|
@ -193,13 +193,13 @@ fun ArtistScreen(browseId: String) {
|
||||||
saveableStateHolder.SaveableStateProvider(key = currentTabIndex) {
|
saveableStateHolder.SaveableStateProvider(key = currentTabIndex) {
|
||||||
when (currentTabIndex) {
|
when (currentTabIndex) {
|
||||||
0 -> ArtistOverview(
|
0 -> ArtistOverview(
|
||||||
youtubeArtistPage = youtubeArtist,
|
youtubeArtistPage = artistPage,
|
||||||
thumbnailContent = thumbnailContent,
|
thumbnailContent = thumbnailContent,
|
||||||
headerContent = headerContent,
|
headerContent = headerContent,
|
||||||
onAlbumClick = { albumRoute(it) },
|
onAlbumClick = { albumRoute(it) },
|
||||||
onViewAllSongsClick = { onTabIndexChanged(1) },
|
onViewAllSongsClick = { tabIndex = 1 },
|
||||||
onViewAllAlbumsClick = { onTabIndexChanged(2) },
|
onViewAllAlbumsClick = { tabIndex = 2 },
|
||||||
onViewAllSinglesClick = { onTabIndexChanged(3) },
|
onViewAllSinglesClick = { tabIndex = 3 },
|
||||||
)
|
)
|
||||||
|
|
||||||
1 -> {
|
1 -> {
|
||||||
|
@ -211,14 +211,14 @@ fun ArtistScreen(browseId: String) {
|
||||||
ItemsPage(
|
ItemsPage(
|
||||||
stateSaver = InnertubeSongsPageSaver,
|
stateSaver = InnertubeSongsPageSaver,
|
||||||
headerContent = headerContent,
|
headerContent = headerContent,
|
||||||
itemsPageProvider = youtubeArtist?.let {
|
itemsPageProvider = artistPage?.let {
|
||||||
({ continuation ->
|
({ continuation ->
|
||||||
continuation?.let {
|
continuation?.let {
|
||||||
Innertube.itemsPage(
|
Innertube.itemsPage(
|
||||||
body = ContinuationBody(continuation = continuation),
|
body = ContinuationBody(continuation = continuation),
|
||||||
fromMusicResponsiveListItemRenderer = Innertube.SongItem::from,
|
fromMusicResponsiveListItemRenderer = Innertube.SongItem::from,
|
||||||
)
|
)
|
||||||
} ?: youtubeArtist
|
} ?: artistPage
|
||||||
?.songsEndpoint
|
?.songsEndpoint
|
||||||
?.takeIf { it.browseId != null }
|
?.takeIf { it.browseId != null }
|
||||||
?.let { endpoint ->
|
?.let { endpoint ->
|
||||||
|
@ -232,7 +232,7 @@ fun ArtistScreen(browseId: String) {
|
||||||
}
|
}
|
||||||
?: Result.success(
|
?: Result.success(
|
||||||
Innertube.ItemsPage(
|
Innertube.ItemsPage(
|
||||||
items = youtubeArtist?.songs,
|
items = artistPage?.songs,
|
||||||
continuation = null
|
continuation = null
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -275,14 +275,14 @@ fun ArtistScreen(browseId: String) {
|
||||||
stateSaver = InnertubeAlbumsPageSaver,
|
stateSaver = InnertubeAlbumsPageSaver,
|
||||||
headerContent = headerContent,
|
headerContent = headerContent,
|
||||||
emptyItemsText = "This artist didn't release any album",
|
emptyItemsText = "This artist didn't release any album",
|
||||||
itemsPageProvider = youtubeArtist?.let {
|
itemsPageProvider = artistPage?.let {
|
||||||
({ continuation ->
|
({ continuation ->
|
||||||
continuation?.let {
|
continuation?.let {
|
||||||
Innertube.itemsPage(
|
Innertube.itemsPage(
|
||||||
body = ContinuationBody(continuation = continuation),
|
body = ContinuationBody(continuation = continuation),
|
||||||
fromMusicTwoRowItemRenderer = Innertube.AlbumItem::from,
|
fromMusicTwoRowItemRenderer = Innertube.AlbumItem::from,
|
||||||
)
|
)
|
||||||
} ?: youtubeArtist
|
} ?: artistPage
|
||||||
?.albumsEndpoint
|
?.albumsEndpoint
|
||||||
?.takeIf { it.browseId != null }
|
?.takeIf { it.browseId != null }
|
||||||
?.let { endpoint ->
|
?.let { endpoint ->
|
||||||
|
@ -296,7 +296,7 @@ fun ArtistScreen(browseId: String) {
|
||||||
}
|
}
|
||||||
?: Result.success(
|
?: Result.success(
|
||||||
Innertube.ItemsPage(
|
Innertube.ItemsPage(
|
||||||
items = youtubeArtist?.albums,
|
items = artistPage?.albums,
|
||||||
continuation = null
|
continuation = null
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -325,14 +325,14 @@ fun ArtistScreen(browseId: String) {
|
||||||
stateSaver = InnertubeAlbumsPageSaver,
|
stateSaver = InnertubeAlbumsPageSaver,
|
||||||
headerContent = headerContent,
|
headerContent = headerContent,
|
||||||
emptyItemsText = "This artist didn't release any single",
|
emptyItemsText = "This artist didn't release any single",
|
||||||
itemsPageProvider = youtubeArtist?.let {
|
itemsPageProvider = artistPage?.let {
|
||||||
({ continuation ->
|
({ continuation ->
|
||||||
continuation?.let {
|
continuation?.let {
|
||||||
Innertube.itemsPage(
|
Innertube.itemsPage(
|
||||||
body = ContinuationBody(continuation = continuation),
|
body = ContinuationBody(continuation = continuation),
|
||||||
fromMusicTwoRowItemRenderer = Innertube.AlbumItem::from,
|
fromMusicTwoRowItemRenderer = Innertube.AlbumItem::from,
|
||||||
)
|
)
|
||||||
} ?: youtubeArtist
|
} ?: artistPage
|
||||||
?.singlesEndpoint
|
?.singlesEndpoint
|
||||||
?.takeIf { it.browseId != null }
|
?.takeIf { it.browseId != null }
|
||||||
?.let { endpoint ->
|
?.let { endpoint ->
|
||||||
|
@ -346,7 +346,7 @@ fun ArtistScreen(browseId: String) {
|
||||||
}
|
}
|
||||||
?: Result.success(
|
?: Result.success(
|
||||||
Innertube.ItemsPage(
|
Innertube.ItemsPage(
|
||||||
items = youtubeArtist?.singles,
|
items = artistPage?.singles,
|
||||||
continuation = null
|
continuation = null
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -9,8 +9,11 @@ import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.combinedClickable
|
import androidx.compose.foundation.combinedClickable
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||||
|
import androidx.compose.foundation.layout.asPaddingValues
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.only
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
@ -29,11 +32,6 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import it.vfsfitvnm.vimusic.Database
|
import it.vfsfitvnm.vimusic.Database
|
||||||
import it.vfsfitvnm.vimusic.LocalPlayerAwareWindowInsets
|
import it.vfsfitvnm.vimusic.LocalPlayerAwareWindowInsets
|
||||||
import androidx.compose.foundation.layout.WindowInsetsSides
|
|
||||||
import androidx.compose.foundation.layout.asPaddingValues
|
|
||||||
import androidx.compose.foundation.layout.only
|
|
||||||
import androidx.compose.foundation.layout.asPaddingValues
|
|
||||||
import androidx.compose.foundation.layout.only
|
|
||||||
import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
|
import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
|
||||||
import it.vfsfitvnm.vimusic.R
|
import it.vfsfitvnm.vimusic.R
|
||||||
import it.vfsfitvnm.vimusic.enums.SongSortBy
|
import it.vfsfitvnm.vimusic.enums.SongSortBy
|
||||||
|
|
|
@ -21,10 +21,11 @@ import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.foundation.text.BasicText
|
import androidx.compose.foundation.text.BasicText
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.saveable.autoSaver
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
@ -47,7 +48,6 @@ import it.vfsfitvnm.vimusic.ui.styling.favoritesIcon
|
||||||
import it.vfsfitvnm.vimusic.utils.bold
|
import it.vfsfitvnm.vimusic.utils.bold
|
||||||
import it.vfsfitvnm.vimusic.utils.forceSeekToNext
|
import it.vfsfitvnm.vimusic.utils.forceSeekToNext
|
||||||
import it.vfsfitvnm.vimusic.utils.forceSeekToPrevious
|
import it.vfsfitvnm.vimusic.utils.forceSeekToPrevious
|
||||||
import it.vfsfitvnm.vimusic.utils.produceSaveableState
|
|
||||||
import it.vfsfitvnm.vimusic.utils.rememberRepeatMode
|
import it.vfsfitvnm.vimusic.utils.rememberRepeatMode
|
||||||
import it.vfsfitvnm.vimusic.utils.secondary
|
import it.vfsfitvnm.vimusic.utils.secondary
|
||||||
import it.vfsfitvnm.vimusic.utils.semiBold
|
import it.vfsfitvnm.vimusic.utils.semiBold
|
||||||
|
@ -76,16 +76,16 @@ fun Controls(
|
||||||
mutableStateOf<Long?>(null)
|
mutableStateOf<Long?>(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
val likedAt by produceSaveableState<Long?>(
|
var likedAt by rememberSaveable {
|
||||||
initialValue = null,
|
mutableStateOf<Long?>(null)
|
||||||
stateSaver = autoSaver(),
|
}
|
||||||
mediaId
|
|
||||||
) {
|
LaunchedEffect(mediaId) {
|
||||||
Database
|
Database
|
||||||
.likedAt(mediaId)
|
.likedAt(mediaId)
|
||||||
.flowOn(Dispatchers.IO)
|
.flowOn(Dispatchers.IO)
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
.collect { value = it }
|
.collect { likedAt = it }
|
||||||
}
|
}
|
||||||
|
|
||||||
val shouldBePlayingTransition = updateTransition(shouldBePlaying, label = "shouldBePlaying")
|
val shouldBePlayingTransition = updateTransition(shouldBePlaying, label = "shouldBePlaying")
|
||||||
|
|
|
@ -7,8 +7,11 @@ import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||||
|
import androidx.compose.foundation.layout.asPaddingValues
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.only
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
@ -22,8 +25,11 @@ import androidx.compose.material.ripple.rememberRipple
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.saveable.autoSaver
|
import androidx.compose.runtime.saveable.autoSaver
|
||||||
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.paint
|
import androidx.compose.ui.draw.paint
|
||||||
|
@ -41,9 +47,6 @@ import androidx.compose.ui.unit.dp
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import it.vfsfitvnm.vimusic.Database
|
import it.vfsfitvnm.vimusic.Database
|
||||||
import it.vfsfitvnm.vimusic.LocalPlayerAwareWindowInsets
|
import it.vfsfitvnm.vimusic.LocalPlayerAwareWindowInsets
|
||||||
import androidx.compose.foundation.layout.WindowInsetsSides
|
|
||||||
import androidx.compose.foundation.layout.asPaddingValues
|
|
||||||
import androidx.compose.foundation.layout.only
|
|
||||||
import it.vfsfitvnm.vimusic.R
|
import it.vfsfitvnm.vimusic.R
|
||||||
import it.vfsfitvnm.vimusic.models.SearchQuery
|
import it.vfsfitvnm.vimusic.models.SearchQuery
|
||||||
import it.vfsfitvnm.vimusic.query
|
import it.vfsfitvnm.vimusic.query
|
||||||
|
@ -57,7 +60,6 @@ import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.utils.align
|
import it.vfsfitvnm.vimusic.utils.align
|
||||||
import it.vfsfitvnm.vimusic.utils.center
|
import it.vfsfitvnm.vimusic.utils.center
|
||||||
import it.vfsfitvnm.vimusic.utils.medium
|
import it.vfsfitvnm.vimusic.utils.medium
|
||||||
import it.vfsfitvnm.vimusic.utils.produceSaveableOneShotState
|
|
||||||
import it.vfsfitvnm.vimusic.utils.produceSaveableState
|
import it.vfsfitvnm.vimusic.utils.produceSaveableState
|
||||||
import it.vfsfitvnm.vimusic.utils.secondary
|
import it.vfsfitvnm.vimusic.utils.secondary
|
||||||
import it.vfsfitvnm.youtubemusic.Innertube
|
import it.vfsfitvnm.youtubemusic.Innertube
|
||||||
|
@ -90,13 +92,15 @@ fun OnlineSearch(
|
||||||
.collect { value = it }
|
.collect { value = it }
|
||||||
}
|
}
|
||||||
|
|
||||||
val suggestionsResult by produceSaveableOneShotState(
|
var suggestionsResult by rememberSaveable(stateSaver = resultSaver(autoSaver<List<String>?>())) {
|
||||||
initialValue = null,
|
mutableStateOf(null)
|
||||||
stateSaver = resultSaver(autoSaver<List<String>?>()),
|
}
|
||||||
textFieldValue.text
|
|
||||||
) {
|
LaunchedEffect(textFieldValue.text) {
|
||||||
if (textFieldValue.text.isNotEmpty()) {
|
if (textFieldValue.text.isNotEmpty()) {
|
||||||
value = Innertube.searchSuggestions(SearchSuggestionsBody(input = textFieldValue.text))
|
delay(200)
|
||||||
|
suggestionsResult =
|
||||||
|
Innertube.searchSuggestions(SearchSuggestionsBody(input = textFieldValue.text))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,11 +7,9 @@ import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.ProduceStateScope
|
import androidx.compose.runtime.ProduceStateScope
|
||||||
import androidx.compose.runtime.State
|
import androidx.compose.runtime.State
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.saveable.Saver
|
import androidx.compose.runtime.saveable.Saver
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
import kotlin.experimental.ExperimentalTypeInference
|
import kotlin.experimental.ExperimentalTypeInference
|
||||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||||
|
@ -51,31 +49,6 @@ fun <T> produceSaveableState(
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun <T> produceSaveableOneShotState(
|
|
||||||
initialValue: T,
|
|
||||||
stateSaver: Saver<T, out Any>,
|
|
||||||
key1: Any?,
|
|
||||||
@BuilderInference producer: suspend ProduceStateScope<T>.() -> Unit
|
|
||||||
): State<T> {
|
|
||||||
val state = rememberSaveable(stateSaver = stateSaver) {
|
|
||||||
mutableStateOf(initialValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
var produced by rememberSaveable(key1) {
|
|
||||||
mutableStateOf(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
LaunchedEffect(key1) {
|
|
||||||
if (!produced) {
|
|
||||||
ProduceSaveableStateScope(state, coroutineContext).producer()
|
|
||||||
produced = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun <T> produceSaveableState(
|
fun <T> produceSaveableState(
|
||||||
initialValue: T,
|
initialValue: T,
|
||||||
|
|
Loading…
Add table
Reference in a new issue