|
@@ -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,49 +69,43 @@ import kotlinx.coroutines.withContext
|
|
fun ArtistScreen(browseId: String) {
|
|
fun ArtistScreen(browseId: String) {
|
|
val saveableStateHolder = rememberSaveableStateHolder()
|
|
val saveableStateHolder = rememberSaveableStateHolder()
|
|
|
|
|
|
- val (tabIndex, onTabIndexChanged) = rememberPreference(
|
|
|
|
- artistScreenTabIndexKey,
|
|
|
|
- defaultValue = 0
|
|
|
|
- )
|
|
|
|
|
|
+ var tabIndex by rememberPreference(artistScreenTabIndexKey, defaultValue = 0)
|
|
|
|
|
|
- val artist by produceSaveableState(
|
|
|
|
- initialValue = null,
|
|
|
|
- stateSaver = nullableSaver(ArtistSaver),
|
|
|
|
- ) {
|
|
|
|
- Database
|
|
|
|
- .artist(browseId)
|
|
|
|
- .flowOn(Dispatchers.IO)
|
|
|
|
- .collect { value = it }
|
|
|
|
|
|
+ var artist by rememberSaveable(stateSaver = nullableSaver(ArtistSaver)) {
|
|
|
|
+ mutableStateOf(null)
|
|
}
|
|
}
|
|
|
|
|
|
- val youtubeArtist by produceSaveableState(
|
|
|
|
- initialValue = null,
|
|
|
|
- stateSaver = nullableSaver(InnertubeArtistPageSaver),
|
|
|
|
- tabIndex < 4
|
|
|
|
- ) {
|
|
|
|
- if (value != null || (tabIndex == 4 && withContext(Dispatchers.IO) {
|
|
|
|
- Database.artistTimestamp(
|
|
|
|
- browseId
|
|
|
|
- )
|
|
|
|
- } != null)) return@produceSaveableState
|
|
|
|
|
|
+ var artistPage by rememberSaveable(stateSaver = nullableSaver(InnertubeArtistPageSaver)) {
|
|
|
|
+ mutableStateOf(null)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ LaunchedEffect(Unit) {
|
|
|
|
+ Database
|
|
|
|
+ .artist(browseId)
|
|
|
|
+ .combine(snapshotFlow { tabIndex }.map { it != 4 }) { artist, mustFetch -> artist to mustFetch }
|
|
|
|
+ .distinctUntilChanged()
|
|
|
|
+ .collect { (currentArtist, mustFetch) ->
|
|
|
|
+ artist = currentArtist
|
|
|
|
|
|
- withContext(Dispatchers.IO) {
|
|
|
|
- Innertube.artistPage(BrowseBody(browseId = browseId))
|
|
|
|
- }?.onSuccess { artistPage ->
|
|
|
|
- value = artistPage
|
|
|
|
|
|
+ if (artistPage == null && (currentArtist?.timestamp == null || mustFetch)) {
|
|
|
|
+ withContext(Dispatchers.IO) {
|
|
|
|
+ Innertube.artistPage(BrowseBody(browseId = browseId))
|
|
|
|
+ ?.onSuccess { currentArtistPage ->
|
|
|
|
+ artistPage = currentArtistPage
|
|
|
|
|
|
- query {
|
|
|
|
- Database.upsert(
|
|
|
|
- Artist(
|
|
|
|
- id = browseId,
|
|
|
|
- name = artistPage.name,
|
|
|
|
- thumbnailUrl = artistPage.thumbnail?.url,
|
|
|
|
- timestamp = System.currentTimeMillis(),
|
|
|
|
- bookmarkedAt = artist?.bookmarkedAt
|
|
|
|
- )
|
|
|
|
- )
|
|
|
|
|
|
+ Database.upsert(
|
|
|
|
+ Artist(
|
|
|
|
+ id = browseId,
|
|
|
|
+ name = currentArtistPage.name,
|
|
|
|
+ thumbnailUrl = currentArtistPage.thumbnail?.url,
|
|
|
|
+ timestamp = System.currentTimeMillis(),
|
|
|
|
+ bookmarkedAt = currentArtist?.bookmarkedAt
|
|
|
|
+ )
|
|
|
|
+ )
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- }
|
|
|
|
}
|
|
}
|
|
|
|
|
|
RouteHandler(listenToGlobalEmitter = true) {
|
|
RouteHandler(listenToGlobalEmitter = true) {
|
|
@@ -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) },
|
|
|
|
- onViewAllAlbumsClick = { onTabIndexChanged(2) },
|
|
|
|
- onViewAllSinglesClick = { onTabIndexChanged(3) },
|
|
|
|
|
|
+ onViewAllSongsClick = { tabIndex = 1 },
|
|
|
|
+ onViewAllAlbumsClick = { tabIndex = 2 },
|
|
|
|
+ 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
|
|
)
|
|
)
|
|
)
|
|
)
|