Rename youtube-music module to innertube and rewrite it
This commit is contained in:
@@ -61,12 +61,13 @@ import it.vfsfitvnm.vimusic.utils.color
|
||||
import it.vfsfitvnm.vimusic.utils.enqueue
|
||||
import it.vfsfitvnm.vimusic.utils.forcePlayAtIndex
|
||||
import it.vfsfitvnm.vimusic.utils.forcePlayFromBeginning
|
||||
import it.vfsfitvnm.vimusic.utils.medium
|
||||
import it.vfsfitvnm.vimusic.utils.produceSaveableState
|
||||
import it.vfsfitvnm.vimusic.utils.secondary
|
||||
import it.vfsfitvnm.vimusic.utils.semiBold
|
||||
import it.vfsfitvnm.vimusic.utils.thumbnail
|
||||
import it.vfsfitvnm.youtubemusic.YouTube
|
||||
import it.vfsfitvnm.youtubemusic.Innertube
|
||||
import it.vfsfitvnm.youtubemusic.models.bodies.BrowseBody
|
||||
import it.vfsfitvnm.youtubemusic.requests.albumPage
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.withContext
|
||||
@@ -88,19 +89,21 @@ fun AlbumOverview(
|
||||
withContext(Dispatchers.IO) {
|
||||
Database.album(browseId).collect { album ->
|
||||
if (album?.timestamp == null) {
|
||||
YouTube.album(browseId)?.onSuccess { youtubeAlbum ->
|
||||
Innertube.albumPage(BrowseBody(browseId = browseId))?.onSuccess { albumPage ->
|
||||
Database.upsert(
|
||||
Album(
|
||||
id = browseId,
|
||||
title = youtubeAlbum.title,
|
||||
thumbnailUrl = youtubeAlbum.thumbnail?.url,
|
||||
year = youtubeAlbum.year,
|
||||
authorsText = youtubeAlbum.authors?.joinToString("") { it.name ?: "" },
|
||||
shareUrl = youtubeAlbum.url,
|
||||
title = albumPage.title,
|
||||
thumbnailUrl = albumPage.thumbnail?.url,
|
||||
year = albumPage.year,
|
||||
authorsText = albumPage.authors?.joinToString("") { it.name ?: "" },
|
||||
shareUrl = albumPage.url,
|
||||
timestamp = System.currentTimeMillis()
|
||||
),
|
||||
youtubeAlbum.songs
|
||||
?.map(YouTube.Item.Song::asMediaItem)
|
||||
albumPage
|
||||
.songsPage
|
||||
?.items
|
||||
?.map(Innertube.SongItem::asMediaItem)
|
||||
?.onEach(Database::insert)
|
||||
?.mapIndexed { position, mediaItem ->
|
||||
SongAlbumMap(
|
||||
|
||||
@@ -8,7 +8,6 @@ import androidx.compose.foundation.lazy.LazyItemScope
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.text.BasicText
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.SideEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
@@ -26,19 +25,19 @@ import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||
import it.vfsfitvnm.vimusic.utils.center
|
||||
import it.vfsfitvnm.vimusic.utils.produceSaveableRelaunchableOneShotState
|
||||
import it.vfsfitvnm.vimusic.utils.secondary
|
||||
import it.vfsfitvnm.youtubemusic.YouTube
|
||||
import it.vfsfitvnm.youtubemusic.Innertube
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@ExperimentalAnimationApi
|
||||
@Composable
|
||||
inline fun <T : YouTube.Item> ArtistContent(
|
||||
inline fun <T : Innertube.Item> ArtistContent(
|
||||
artist: Artist?,
|
||||
youtubeArtist: YouTube.Artist?,
|
||||
youtubeArtistPage: Innertube.ArtistPage?,
|
||||
isLoading: Boolean,
|
||||
isError: Boolean,
|
||||
stateSaver: ListSaver<T, List<Any?>>,
|
||||
crossinline itemsProvider: suspend (String?) -> Result<Pair<String?, List<T>?>>?,
|
||||
crossinline itemsPageProvider: suspend (String?) -> Result<Innertube.ItemsPage<T>?>?,
|
||||
crossinline bookmarkIconContent: @Composable () -> Unit,
|
||||
crossinline shareIconContent: @Composable () -> Unit,
|
||||
crossinline itemContent: @Composable LazyItemScope.(T) -> Unit,
|
||||
@@ -61,18 +60,18 @@ inline fun <T : YouTube.Item> ArtistContent(
|
||||
val (continuationState, fetch) = produceSaveableRelaunchableOneShotState(
|
||||
initialValue = null,
|
||||
stateSaver = autoSaver<String?>(),
|
||||
youtubeArtist
|
||||
youtubeArtistPage
|
||||
) {
|
||||
if (youtubeArtist == null) return@produceSaveableRelaunchableOneShotState
|
||||
if (youtubeArtistPage == null) return@produceSaveableRelaunchableOneShotState
|
||||
|
||||
println("loading... $value")
|
||||
|
||||
isLoadingItems = true
|
||||
withContext(Dispatchers.IO) {
|
||||
itemsProvider(value)?.onSuccess { (continuation, newItems) ->
|
||||
value = continuation
|
||||
newItems?.let {
|
||||
items = items.plus(it).distinctBy(YouTube.Item::key)
|
||||
itemsPageProvider(value)?.onSuccess { itemsPage ->
|
||||
value = itemsPage?.continuation
|
||||
itemsPage?.items?.let {
|
||||
items = items.plus(it).distinctBy(Innertube.Item::key)
|
||||
}
|
||||
isErrorItems = false
|
||||
isLoadingItems = false
|
||||
@@ -105,7 +104,7 @@ inline fun <T : YouTube.Item> ArtistContent(
|
||||
|
||||
items(
|
||||
items = items,
|
||||
key = YouTube.Item::key,
|
||||
key = Innertube.Item::key,
|
||||
itemContent = itemContent
|
||||
)
|
||||
|
||||
|
||||
@@ -57,14 +57,14 @@ import it.vfsfitvnm.vimusic.utils.forcePlay
|
||||
import it.vfsfitvnm.vimusic.utils.secondary
|
||||
import it.vfsfitvnm.vimusic.utils.semiBold
|
||||
import it.vfsfitvnm.vimusic.utils.thumbnail
|
||||
import it.vfsfitvnm.youtubemusic.YouTube
|
||||
import it.vfsfitvnm.youtubemusic.Innertube
|
||||
import it.vfsfitvnm.youtubemusic.models.NavigationEndpoint
|
||||
|
||||
@ExperimentalAnimationApi
|
||||
@Composable
|
||||
fun ArtistOverview(
|
||||
artist: Artist?,
|
||||
youtubeArtist: YouTube.Artist?,
|
||||
youtubeArtistPage: Innertube.ArtistPage?,
|
||||
isLoading: Boolean,
|
||||
isError: Boolean,
|
||||
onViewAllSongsClick: () -> Unit,
|
||||
@@ -100,7 +100,7 @@ fun ArtistOverview(
|
||||
when {
|
||||
artist != null -> {
|
||||
Header(title = artist.name ?: "Unknown") {
|
||||
youtubeArtist?.radioEndpoint?.let { radioEndpoint ->
|
||||
youtubeArtistPage?.radioEndpoint?.let { radioEndpoint ->
|
||||
SecondaryTextButton(
|
||||
text = "Start radio",
|
||||
onClick = {
|
||||
@@ -130,8 +130,8 @@ fun ArtistOverview(
|
||||
)
|
||||
|
||||
when {
|
||||
youtubeArtist != null -> {
|
||||
youtubeArtist.songs?.let { songs ->
|
||||
youtubeArtistPage != null -> {
|
||||
youtubeArtistPage.songs?.let { songs ->
|
||||
Row(
|
||||
verticalAlignment = Alignment.Bottom,
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
@@ -144,7 +144,7 @@ fun ArtistOverview(
|
||||
modifier = sectionTextModifier
|
||||
)
|
||||
|
||||
youtubeArtist.songsEndpoint?.let {
|
||||
youtubeArtistPage.songsEndpoint?.let {
|
||||
BasicText(
|
||||
text = "View all",
|
||||
style = typography.xs.secondary,
|
||||
@@ -174,7 +174,7 @@ fun ArtistOverview(
|
||||
}
|
||||
}
|
||||
|
||||
youtubeArtist.albums?.let { albums ->
|
||||
youtubeArtistPage.albums?.let { albums ->
|
||||
Row(
|
||||
verticalAlignment = Alignment.Bottom,
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
@@ -187,7 +187,7 @@ fun ArtistOverview(
|
||||
modifier = sectionTextModifier
|
||||
)
|
||||
|
||||
youtubeArtist.albumsEndpoint?.let {
|
||||
youtubeArtistPage.albumsEndpoint?.let {
|
||||
BasicText(
|
||||
text = "View all",
|
||||
style = typography.xs.secondary,
|
||||
@@ -207,7 +207,7 @@ fun ArtistOverview(
|
||||
) {
|
||||
items(
|
||||
items = albums,
|
||||
key = YouTube.Item.Album::key
|
||||
key = Innertube.AlbumItem::key
|
||||
) { album ->
|
||||
AlternativeAlbumItem(
|
||||
album = album,
|
||||
@@ -224,7 +224,7 @@ fun ArtistOverview(
|
||||
}
|
||||
}
|
||||
|
||||
youtubeArtist.singles?.let { singles ->
|
||||
youtubeArtistPage.singles?.let { singles ->
|
||||
Row(
|
||||
verticalAlignment = Alignment.Bottom,
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
@@ -237,7 +237,7 @@ fun ArtistOverview(
|
||||
modifier = sectionTextModifier
|
||||
)
|
||||
|
||||
youtubeArtist.singlesEndpoint?.let {
|
||||
youtubeArtistPage.singlesEndpoint?.let {
|
||||
BasicText(
|
||||
text = "View all",
|
||||
style = typography.xs.secondary,
|
||||
@@ -257,7 +257,7 @@ fun ArtistOverview(
|
||||
) {
|
||||
items(
|
||||
items = singles,
|
||||
key = YouTube.Item.Album::key
|
||||
key = Innertube.AlbumItem::key
|
||||
) { album ->
|
||||
AlternativeAlbumItem(
|
||||
album = album,
|
||||
@@ -330,7 +330,7 @@ fun ArtistOverview(
|
||||
}
|
||||
}
|
||||
|
||||
youtubeArtist?.shuffleEndpoint?.let { shuffleEndpoint ->
|
||||
youtubeArtistPage?.shuffleEndpoint?.let { shuffleEndpoint ->
|
||||
PrimaryButton(
|
||||
iconId = R.drawable.shuffle,
|
||||
onClick = {
|
||||
|
||||
@@ -26,14 +26,13 @@ import it.vfsfitvnm.vimusic.R
|
||||
import it.vfsfitvnm.vimusic.models.PartialArtist
|
||||
import it.vfsfitvnm.vimusic.query
|
||||
import it.vfsfitvnm.vimusic.savers.ArtistSaver
|
||||
import it.vfsfitvnm.vimusic.savers.YouTubeAlbumListSaver
|
||||
import it.vfsfitvnm.vimusic.savers.YouTubeArtistPageSaver
|
||||
import it.vfsfitvnm.vimusic.savers.YouTubeSongListSaver
|
||||
import it.vfsfitvnm.vimusic.savers.InnertubeAlbumItemListSaver
|
||||
import it.vfsfitvnm.vimusic.savers.InnertubeArtistPageSaver
|
||||
import it.vfsfitvnm.vimusic.savers.InnertubeSongItemListSaver
|
||||
import it.vfsfitvnm.vimusic.savers.nullableSaver
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.Scaffold
|
||||
import it.vfsfitvnm.vimusic.ui.screens.albumRoute
|
||||
import it.vfsfitvnm.vimusic.ui.screens.globalRoutes
|
||||
import it.vfsfitvnm.vimusic.ui.screens.searchresult.SearchResult
|
||||
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
|
||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||
import it.vfsfitvnm.vimusic.ui.styling.px
|
||||
@@ -47,7 +46,12 @@ import it.vfsfitvnm.vimusic.utils.forcePlay
|
||||
import it.vfsfitvnm.vimusic.utils.produceSaveableLazyOneShotState
|
||||
import it.vfsfitvnm.vimusic.utils.produceSaveableState
|
||||
import it.vfsfitvnm.vimusic.utils.rememberPreference
|
||||
import it.vfsfitvnm.youtubemusic.YouTube
|
||||
import it.vfsfitvnm.youtubemusic.Innertube
|
||||
import it.vfsfitvnm.youtubemusic.models.bodies.BrowseBody
|
||||
import it.vfsfitvnm.youtubemusic.models.bodies.ContinuationBody
|
||||
import it.vfsfitvnm.youtubemusic.requests.artistPage
|
||||
import it.vfsfitvnm.youtubemusic.requests.itemsPage
|
||||
import it.vfsfitvnm.youtubemusic.utils.from
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
@@ -72,22 +76,22 @@ fun ArtistScreen(browseId: String) {
|
||||
|
||||
val youtubeArtist by produceSaveableLazyOneShotState(
|
||||
initialValue = null,
|
||||
stateSaver = nullableSaver(YouTubeArtistPageSaver)
|
||||
stateSaver = nullableSaver(InnertubeArtistPageSaver)
|
||||
) {
|
||||
println("${System.currentTimeMillis()}, computing lazyEffect (youtubeArtistResult = ${value?.name})!")
|
||||
|
||||
isLoading = true
|
||||
withContext(Dispatchers.IO) {
|
||||
YouTube.artist(browseId)?.onSuccess { youtubeArtist ->
|
||||
value = youtubeArtist
|
||||
Innertube.artistPage(browseId)?.onSuccess { artistPage ->
|
||||
value = artistPage
|
||||
|
||||
query {
|
||||
Database.upsert(
|
||||
PartialArtist(
|
||||
id = browseId,
|
||||
name = youtubeArtist.name,
|
||||
thumbnailUrl = youtubeArtist.thumbnail?.url,
|
||||
info = youtubeArtist.description,
|
||||
name = artistPage.name,
|
||||
thumbnailUrl = artistPage.thumbnail?.url,
|
||||
info = artistPage.description,
|
||||
timestamp = System.currentTimeMillis()
|
||||
)
|
||||
)
|
||||
@@ -136,10 +140,13 @@ fun ArtistScreen(browseId: String) {
|
||||
colorFilter = ColorFilter.tint(LocalAppearance.current.colorPalette.accent),
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
val bookmarkedAt = if (artist?.bookmarkedAt == null) System.currentTimeMillis() else null
|
||||
val bookmarkedAt =
|
||||
if (artist?.bookmarkedAt == null) System.currentTimeMillis() else null
|
||||
|
||||
query {
|
||||
artist?.copy(bookmarkedAt = bookmarkedAt)?.let(Database::update)
|
||||
artist
|
||||
?.copy(bookmarkedAt = bookmarkedAt)
|
||||
?.let(Database::update)
|
||||
}
|
||||
}
|
||||
.padding(all = 4.dp)
|
||||
@@ -194,7 +201,7 @@ fun ArtistScreen(browseId: String) {
|
||||
when (currentTabIndex) {
|
||||
0 -> ArtistOverview(
|
||||
artist = artist,
|
||||
youtubeArtist = youtubeArtist,
|
||||
youtubeArtistPage = youtubeArtist,
|
||||
isLoading = isLoading,
|
||||
isError = isError,
|
||||
bookmarkIconContent = bookmarkIconContent,
|
||||
@@ -204,6 +211,7 @@ fun ArtistScreen(browseId: String) {
|
||||
onViewAllAlbumsClick = { onTabIndexChanged(2) },
|
||||
onViewAllSinglesClick = { onTabIndexChanged(3) },
|
||||
)
|
||||
|
||||
1 -> {
|
||||
val binder = LocalPlayerServiceBinder.current
|
||||
val thumbnailSizeDp = Dimensions.thumbnails.song
|
||||
@@ -211,20 +219,26 @@ fun ArtistScreen(browseId: String) {
|
||||
|
||||
ArtistContent(
|
||||
artist = artist,
|
||||
youtubeArtist = youtubeArtist,
|
||||
youtubeArtistPage = youtubeArtist,
|
||||
isLoading = isLoading,
|
||||
isError = isError,
|
||||
stateSaver = YouTubeSongListSaver,
|
||||
stateSaver = InnertubeSongItemListSaver,
|
||||
bookmarkIconContent = bookmarkIconContent,
|
||||
shareIconContent = shareIconContent,
|
||||
itemsProvider = { continuation ->
|
||||
youtubeArtist
|
||||
itemsPageProvider = { continuation ->
|
||||
continuation?.let {
|
||||
Innertube.itemsPage(
|
||||
body = ContinuationBody(continuation = continuation),
|
||||
fromMusicResponsiveListItemRenderer = Innertube.SongItem::from,
|
||||
)
|
||||
} ?: youtubeArtist
|
||||
?.songsEndpoint
|
||||
?.browseId
|
||||
?.let { browseId ->
|
||||
YouTube.items(browseId, continuation, YouTube.Item.Song::from)?.map { result ->
|
||||
result?.continuation to result?.items
|
||||
}
|
||||
Innertube.itemsPage(
|
||||
body = BrowseBody(browseId = browseId),
|
||||
fromMusicResponsiveListItemRenderer = Innertube.SongItem::from,
|
||||
)
|
||||
}
|
||||
},
|
||||
itemContent = { song ->
|
||||
@@ -243,25 +257,33 @@ fun ArtistScreen(browseId: String) {
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
2 -> {
|
||||
val thumbnailSizeDp = 108.dp
|
||||
val thumbnailSizePx = thumbnailSizeDp.px
|
||||
|
||||
ArtistContent(
|
||||
artist = artist,
|
||||
youtubeArtist = youtubeArtist,
|
||||
youtubeArtistPage = youtubeArtist,
|
||||
isLoading = isLoading,
|
||||
isError = isError,
|
||||
stateSaver = YouTubeAlbumListSaver,
|
||||
stateSaver = InnertubeAlbumItemListSaver,
|
||||
bookmarkIconContent = bookmarkIconContent,
|
||||
shareIconContent = shareIconContent,
|
||||
itemsProvider = {
|
||||
youtubeArtist
|
||||
?.albumsEndpoint
|
||||
?.let { endpoint ->
|
||||
YouTube.items2(browseId, endpoint.params, YouTube.Item.Album::from)?.map { result ->
|
||||
result?.continuation to result?.items
|
||||
}
|
||||
itemsPageProvider = { continuation ->
|
||||
continuation?.let {
|
||||
Innertube.itemsPage(
|
||||
body = ContinuationBody(continuation = continuation),
|
||||
fromMusicTwoRowItemRenderer = Innertube.AlbumItem::from,
|
||||
)
|
||||
} ?: youtubeArtist
|
||||
?.songsEndpoint
|
||||
?.browseId
|
||||
?.let { browseId ->
|
||||
Innertube.itemsPage(
|
||||
body = BrowseBody(browseId = browseId),
|
||||
fromMusicTwoRowItemRenderer = Innertube.AlbumItem::from,
|
||||
)
|
||||
}
|
||||
},
|
||||
itemContent = { album ->
|
||||
@@ -282,25 +304,33 @@ fun ArtistScreen(browseId: String) {
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
3 -> {
|
||||
val thumbnailSizeDp = 108.dp
|
||||
val thumbnailSizePx = thumbnailSizeDp.px
|
||||
|
||||
ArtistContent(
|
||||
artist = artist,
|
||||
youtubeArtist = youtubeArtist,
|
||||
youtubeArtistPage = youtubeArtist,
|
||||
isLoading = isLoading,
|
||||
isError = isError,
|
||||
stateSaver = YouTubeAlbumListSaver,
|
||||
stateSaver = InnertubeAlbumItemListSaver,
|
||||
bookmarkIconContent = bookmarkIconContent,
|
||||
shareIconContent = shareIconContent,
|
||||
itemsProvider = {
|
||||
youtubeArtist
|
||||
?.singlesEndpoint
|
||||
?.let { endpoint ->
|
||||
YouTube.items2(browseId, endpoint.params, YouTube.Item.Album::from)?.map { result ->
|
||||
result?.continuation to result?.items
|
||||
}
|
||||
itemsPageProvider = { continuation ->
|
||||
continuation?.let {
|
||||
Innertube.itemsPage(
|
||||
body = ContinuationBody(continuation = continuation),
|
||||
fromMusicTwoRowItemRenderer = Innertube.AlbumItem::from,
|
||||
)
|
||||
} ?: youtubeArtist
|
||||
?.songsEndpoint
|
||||
?.browseId
|
||||
?.let { browseId ->
|
||||
Innertube.itemsPage(
|
||||
body = BrowseBody(browseId = browseId),
|
||||
fromMusicTwoRowItemRenderer = Innertube.AlbumItem::from,
|
||||
)
|
||||
}
|
||||
},
|
||||
itemContent = { album ->
|
||||
@@ -321,6 +351,7 @@ fun ArtistScreen(browseId: String) {
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
4 -> ArtistLocalSongsList(
|
||||
browseId = browseId,
|
||||
artist = artist,
|
||||
|
||||
@@ -34,7 +34,7 @@ import it.vfsfitvnm.vimusic.Database
|
||||
import it.vfsfitvnm.vimusic.LocalPlayerAwarePaddingValues
|
||||
import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
|
||||
import it.vfsfitvnm.vimusic.savers.DetailedSongSaver
|
||||
import it.vfsfitvnm.vimusic.savers.YouTubeRelatedSaver
|
||||
import it.vfsfitvnm.vimusic.savers.InnertubeRelatedPageSaver
|
||||
import it.vfsfitvnm.vimusic.savers.nullableSaver
|
||||
import it.vfsfitvnm.vimusic.savers.resultSaver
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.Header
|
||||
@@ -60,8 +60,10 @@ import it.vfsfitvnm.vimusic.utils.produceSaveableState
|
||||
import it.vfsfitvnm.vimusic.utils.secondary
|
||||
import it.vfsfitvnm.vimusic.utils.semiBold
|
||||
import it.vfsfitvnm.vimusic.utils.thumbnail
|
||||
import it.vfsfitvnm.youtubemusic.YouTube
|
||||
import it.vfsfitvnm.youtubemusic.Innertube
|
||||
import it.vfsfitvnm.youtubemusic.models.NavigationEndpoint
|
||||
import it.vfsfitvnm.youtubemusic.models.bodies.NextBody
|
||||
import it.vfsfitvnm.youtubemusic.requests.relatedPage
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
@@ -88,30 +90,13 @@ fun QuickPicks(
|
||||
.collect { value = it }
|
||||
}
|
||||
|
||||
val relatedResult by produceSaveableOneShotState(
|
||||
val relatedPageResult by produceSaveableOneShotState(
|
||||
initialValue = null,
|
||||
stateSaver = resultSaver(nullableSaver(YouTubeRelatedSaver)),
|
||||
stateSaver = resultSaver(nullableSaver(InnertubeRelatedPageSaver)),
|
||||
trending?.id
|
||||
) {
|
||||
trending?.id?.let { trendingVideoId ->
|
||||
value = YouTube.related(trendingVideoId)?.map { related ->
|
||||
related?.copy(
|
||||
albums = related.albums?.map { album ->
|
||||
album.copy(
|
||||
authors = trending?.artists?.map { info ->
|
||||
YouTube.Info(
|
||||
name = info.name,
|
||||
endpoint = NavigationEndpoint.Endpoint.Browse(
|
||||
browseId = info.id,
|
||||
params = null,
|
||||
browseEndpointContextSupportedConfigs = null
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
value = Innertube.relatedPage(NextBody(videoId = trendingVideoId))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +125,7 @@ fun QuickPicks(
|
||||
) {
|
||||
Header(title = "Quick picks")
|
||||
|
||||
relatedResult?.getOrNull()?.let { related ->
|
||||
relatedPageResult?.getOrNull()?.let { related ->
|
||||
LazyHorizontalGrid(
|
||||
rows = GridCells.Fixed(4),
|
||||
modifier = Modifier
|
||||
@@ -171,7 +156,7 @@ fun QuickPicks(
|
||||
|
||||
items(
|
||||
items = related.songs ?: emptyList(),
|
||||
key = YouTube.Item.Song::key
|
||||
key = Innertube.SongItem::key
|
||||
) { song ->
|
||||
SmallSongItem(
|
||||
song = song,
|
||||
@@ -204,7 +189,7 @@ fun QuickPicks(
|
||||
) {
|
||||
items(
|
||||
items = related.albums ?: emptyList(),
|
||||
key = YouTube.Item.Album::key
|
||||
key = Innertube.AlbumItem::key
|
||||
) { album ->
|
||||
AlbumItem(
|
||||
album = album,
|
||||
@@ -235,7 +220,7 @@ fun QuickPicks(
|
||||
) {
|
||||
items(
|
||||
items = related.artists ?: emptyList(),
|
||||
key = YouTube.Item.Artist::key,
|
||||
key = Innertube.ArtistItem::key,
|
||||
) { artist ->
|
||||
ArtistItem(
|
||||
artist = artist,
|
||||
@@ -268,7 +253,7 @@ fun QuickPicks(
|
||||
) {
|
||||
items(
|
||||
items = related.playlists ?: emptyList(),
|
||||
key = YouTube.Item.Playlist::key,
|
||||
key = Innertube.PlaylistItem::key,
|
||||
) { playlist ->
|
||||
PlaylistItem(
|
||||
playlist = playlist,
|
||||
@@ -284,7 +269,7 @@ fun QuickPicks(
|
||||
)
|
||||
}
|
||||
}
|
||||
} ?: relatedResult?.exceptionOrNull()?.let {
|
||||
} ?: relatedPageResult?.exceptionOrNull()?.let {
|
||||
BasicText(
|
||||
text = "An error has occurred",
|
||||
style = typography.s.secondary.center,
|
||||
|
||||
@@ -34,6 +34,7 @@ import it.vfsfitvnm.vimusic.models.DetailedSong
|
||||
import it.vfsfitvnm.vimusic.models.SongPlaylistMap
|
||||
import it.vfsfitvnm.vimusic.query
|
||||
import it.vfsfitvnm.vimusic.savers.PlaylistWithSongsSaver
|
||||
import it.vfsfitvnm.vimusic.savers.nullableSaver
|
||||
import it.vfsfitvnm.vimusic.transaction
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.ConfirmationDialog
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.Header
|
||||
@@ -50,7 +51,9 @@ import it.vfsfitvnm.vimusic.utils.enqueue
|
||||
import it.vfsfitvnm.vimusic.utils.forcePlayAtIndex
|
||||
import it.vfsfitvnm.vimusic.utils.forcePlayFromBeginning
|
||||
import it.vfsfitvnm.vimusic.utils.produceSaveableState
|
||||
import it.vfsfitvnm.youtubemusic.YouTube
|
||||
import it.vfsfitvnm.youtubemusic.Innertube
|
||||
import it.vfsfitvnm.youtubemusic.models.bodies.BrowseBody
|
||||
import it.vfsfitvnm.youtubemusic.requests.playlistPage
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.runBlocking
|
||||
@@ -68,7 +71,7 @@ fun LocalPlaylistSongList(
|
||||
|
||||
val playlistWithSongs by produceSaveableState(
|
||||
initialValue = null,
|
||||
stateSaver = PlaylistWithSongsSaver
|
||||
stateSaver = nullableSaver(PlaylistWithSongsSaver)
|
||||
) {
|
||||
Database
|
||||
.playlistWithSongs(playlistId)
|
||||
@@ -165,13 +168,16 @@ fun LocalPlaylistSongList(
|
||||
transaction {
|
||||
runBlocking(Dispatchers.IO) {
|
||||
withContext(Dispatchers.IO) {
|
||||
YouTube.playlist(browseId)?.map { it.next() }
|
||||
// TODO: fetch all songs!
|
||||
Innertube.playlistPage(BrowseBody(browseId = browseId))
|
||||
}
|
||||
}?.getOrNull()?.let { remotePlaylist ->
|
||||
Database.clearPlaylist(playlistId)
|
||||
|
||||
remotePlaylist.songs
|
||||
?.map(YouTube.Item.Song::asMediaItem)
|
||||
remotePlaylist.
|
||||
songsPage
|
||||
?.items
|
||||
?.map(Innertube.SongItem::asMediaItem)
|
||||
?.onEach(Database::insert)
|
||||
?.mapIndexed { position, mediaItem ->
|
||||
SongPlaylistMap(
|
||||
|
||||
@@ -69,7 +69,9 @@ import it.vfsfitvnm.vimusic.utils.medium
|
||||
import it.vfsfitvnm.vimusic.utils.relaunchableEffect
|
||||
import it.vfsfitvnm.vimusic.utils.rememberPreference
|
||||
import it.vfsfitvnm.vimusic.utils.verticalFadingEdge
|
||||
import it.vfsfitvnm.youtubemusic.YouTube
|
||||
import it.vfsfitvnm.youtubemusic.Innertube
|
||||
import it.vfsfitvnm.youtubemusic.models.bodies.NextBody
|
||||
import it.vfsfitvnm.youtubemusic.requests.lyrics
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
@@ -134,8 +136,7 @@ fun Lyrics(
|
||||
duration = duration / 1000
|
||||
)?.map { it?.value }
|
||||
} else {
|
||||
YouTube.next(mediaId, null)
|
||||
?.map { nextResult -> nextResult.lyrics()?.getOrNull() }
|
||||
Innertube.lyrics(NextBody(videoId = mediaId))
|
||||
}?.map { newLyrics ->
|
||||
onLyricsUpdate(isShowingSynchronizedLyrics, mediaId, newLyrics ?: "")
|
||||
state = state.copy(isLoading = false)
|
||||
|
||||
@@ -40,7 +40,9 @@ import it.vfsfitvnm.vimusic.ui.styling.overlay
|
||||
import it.vfsfitvnm.vimusic.utils.color
|
||||
import it.vfsfitvnm.vimusic.utils.medium
|
||||
import it.vfsfitvnm.vimusic.utils.rememberVolume
|
||||
import it.vfsfitvnm.youtubemusic.YouTube
|
||||
import it.vfsfitvnm.youtubemusic.Innertube
|
||||
import it.vfsfitvnm.youtubemusic.models.bodies.PlayerBody
|
||||
import it.vfsfitvnm.youtubemusic.requests.player
|
||||
import kotlin.math.roundToInt
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
@@ -195,7 +197,7 @@ fun StatsForNerds(
|
||||
onClick = {
|
||||
query {
|
||||
runBlocking(Dispatchers.IO) {
|
||||
YouTube.player(mediaId)
|
||||
Innertube.player(PlayerBody(videoId = mediaId))
|
||||
?.map { response ->
|
||||
response.streamingData?.adaptiveFormats
|
||||
?.findLast { format ->
|
||||
|
||||
@@ -27,7 +27,9 @@ fun PlaylistScreen(browseId: String) {
|
||||
}
|
||||
) { currentTabIndex ->
|
||||
saveableStateHolder.SaveableStateProvider(key = currentTabIndex) {
|
||||
PlaylistSongList(browseId = browseId)
|
||||
when (currentTabIndex) {
|
||||
0 -> PlaylistSongList(browseId = browseId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
|
||||
import it.vfsfitvnm.vimusic.R
|
||||
import it.vfsfitvnm.vimusic.models.Playlist
|
||||
import it.vfsfitvnm.vimusic.models.SongPlaylistMap
|
||||
import it.vfsfitvnm.vimusic.savers.YouTubePlaylistOrAlbumSaver
|
||||
import it.vfsfitvnm.vimusic.savers.InnertubePlaylistOrAlbumPageSaver
|
||||
import it.vfsfitvnm.vimusic.savers.resultSaver
|
||||
import it.vfsfitvnm.vimusic.transaction
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.Header
|
||||
@@ -58,11 +58,12 @@ import it.vfsfitvnm.vimusic.utils.center
|
||||
import it.vfsfitvnm.vimusic.utils.enqueue
|
||||
import it.vfsfitvnm.vimusic.utils.forcePlayAtIndex
|
||||
import it.vfsfitvnm.vimusic.utils.forcePlayFromBeginning
|
||||
import it.vfsfitvnm.vimusic.utils.medium
|
||||
import it.vfsfitvnm.vimusic.utils.produceSaveableOneShotState
|
||||
import it.vfsfitvnm.vimusic.utils.produceSaveableState
|
||||
import it.vfsfitvnm.vimusic.utils.secondary
|
||||
import it.vfsfitvnm.youtubemusic.YouTube
|
||||
import it.vfsfitvnm.youtubemusic.Innertube
|
||||
import it.vfsfitvnm.youtubemusic.models.bodies.BrowseBody
|
||||
import it.vfsfitvnm.youtubemusic.requests.playlistPage
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.withContext
|
||||
@@ -76,12 +77,13 @@ fun PlaylistSongList(
|
||||
val binder = LocalPlayerServiceBinder.current
|
||||
val context = LocalContext.current
|
||||
|
||||
val playlistResult by produceSaveableOneShotState(
|
||||
val playlistPageResult by produceSaveableOneShotState(
|
||||
initialValue = null,
|
||||
stateSaver = resultSaver(YouTubePlaylistOrAlbumSaver),
|
||||
stateSaver = resultSaver(InnertubePlaylistOrAlbumPageSaver),
|
||||
) {
|
||||
value = withContext(Dispatchers.IO) {
|
||||
YouTube.playlist(browseId)?.map { it.next() }
|
||||
// TODO: fetch all songs!
|
||||
Innertube.playlistPage(BrowseBody(browseId = browseId))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +104,7 @@ fun PlaylistSongList(
|
||||
val songThumbnailSizeDp = Dimensions.thumbnails.song
|
||||
val songThumbnailSizePx = songThumbnailSizeDp.px
|
||||
|
||||
playlistResult?.getOrNull()?.let { playlist ->
|
||||
playlistPageResult?.getOrNull()?.let { playlist ->
|
||||
LazyColumn(
|
||||
contentPadding = LocalPlayerAwarePaddingValues.current,
|
||||
modifier = Modifier
|
||||
@@ -117,9 +119,9 @@ fun PlaylistSongList(
|
||||
Header(title = playlist.title ?: "Unknown") {
|
||||
SecondaryTextButton(
|
||||
text = "Enqueue",
|
||||
isEnabled = playlist.songs?.isNotEmpty() == true,
|
||||
isEnabled = playlist.songsPage?.items?.isNotEmpty() == true,
|
||||
onClick = {
|
||||
playlist.songs?.map(YouTube.Item.Song::asMediaItem)?.let { mediaItems ->
|
||||
playlist.songsPage?.items?.map(Innertube.SongItem::asMediaItem)?.let { mediaItems ->
|
||||
binder?.player?.enqueue(mediaItems)
|
||||
}
|
||||
}
|
||||
@@ -147,8 +149,8 @@ fun PlaylistSongList(
|
||||
)
|
||||
)
|
||||
|
||||
playlist.songs
|
||||
?.map(YouTube.Item.Song::asMediaItem)
|
||||
playlist.songsPage?.items
|
||||
?.map(Innertube.SongItem::asMediaItem)
|
||||
?.onEach(Database::insert)
|
||||
?.mapIndexed { index, mediaItem ->
|
||||
SongPlaylistMap(
|
||||
@@ -196,13 +198,13 @@ fun PlaylistSongList(
|
||||
}
|
||||
}
|
||||
|
||||
itemsIndexed(items = playlist.songs ?: emptyList()) { index, song ->
|
||||
itemsIndexed(items = playlist.songsPage?.items ?: emptyList()) { index, song ->
|
||||
SongItem(
|
||||
title = song.info?.name,
|
||||
authors = (song.authors ?: playlist.authors)?.joinToString("") { it.name ?: "" },
|
||||
durationText = song.durationText,
|
||||
onClick = {
|
||||
playlist.songs?.map(YouTube.Item.Song::asMediaItem)?.let { mediaItems ->
|
||||
playlist.songsPage?.items?.map(Innertube.SongItem::asMediaItem)?.let { mediaItems ->
|
||||
binder?.stopRadio()
|
||||
binder?.player?.forcePlayAtIndex(mediaItems, index)
|
||||
}
|
||||
@@ -226,15 +228,15 @@ fun PlaylistSongList(
|
||||
|
||||
PrimaryButton(
|
||||
iconId = R.drawable.shuffle,
|
||||
isEnabled = playlist.songs?.isNotEmpty() == true,
|
||||
isEnabled = playlist.songsPage?.items?.isNotEmpty() == true,
|
||||
onClick = {
|
||||
playlist.songs?.map(YouTube.Item.Song::asMediaItem)?.let { mediaItems ->
|
||||
playlist.songsPage?.items?.map(Innertube.SongItem::asMediaItem)?.let { mediaItems ->
|
||||
binder?.stopRadio()
|
||||
binder?.player?.forcePlayFromBeginning(mediaItems.shuffled())
|
||||
}
|
||||
}
|
||||
)
|
||||
} ?: playlistResult?.exceptionOrNull()?.let {
|
||||
} ?: playlistPageResult?.exceptionOrNull()?.let {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
|
||||
@@ -20,6 +20,7 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.saveable.autoSaver
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.paint
|
||||
@@ -41,7 +42,7 @@ import it.vfsfitvnm.vimusic.R
|
||||
import it.vfsfitvnm.vimusic.models.SearchQuery
|
||||
import it.vfsfitvnm.vimusic.query
|
||||
import it.vfsfitvnm.vimusic.savers.SearchQueryListSaver
|
||||
import it.vfsfitvnm.vimusic.savers.StringListResultSaver
|
||||
import it.vfsfitvnm.vimusic.savers.resultSaver
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.Header
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.SecondaryTextButton
|
||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||
@@ -51,7 +52,9 @@ import it.vfsfitvnm.vimusic.utils.medium
|
||||
import it.vfsfitvnm.vimusic.utils.produceSaveableOneShotState
|
||||
import it.vfsfitvnm.vimusic.utils.produceSaveableState
|
||||
import it.vfsfitvnm.vimusic.utils.secondary
|
||||
import it.vfsfitvnm.youtubemusic.YouTube
|
||||
import it.vfsfitvnm.youtubemusic.Innertube
|
||||
import it.vfsfitvnm.youtubemusic.models.bodies.SearchSuggestionsBody
|
||||
import it.vfsfitvnm.youtubemusic.requests.searchSuggestions
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
@@ -80,11 +83,11 @@ fun OnlineSearch(
|
||||
|
||||
val suggestionsResult by produceSaveableOneShotState(
|
||||
initialValue = null,
|
||||
stateSaver = StringListResultSaver,
|
||||
stateSaver = resultSaver(autoSaver<List<String>?>()),
|
||||
key1 = textFieldValue.text
|
||||
) {
|
||||
if (textFieldValue.text.isNotEmpty()) {
|
||||
value = YouTube.getSearchSuggestions(textFieldValue.text)
|
||||
value = Innertube.searchSuggestions(SearchSuggestionsBody(input = textFieldValue.text))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.SideEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.saveable.autoSaver
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
@@ -23,23 +24,28 @@ import androidx.compose.ui.input.pointer.pointerInput
|
||||
import com.valentinilk.shimmer.shimmer
|
||||
import it.vfsfitvnm.vimusic.LocalPlayerAwarePaddingValues
|
||||
import it.vfsfitvnm.vimusic.savers.ListSaver
|
||||
import it.vfsfitvnm.vimusic.savers.StringResultSaver
|
||||
import it.vfsfitvnm.vimusic.savers.resultSaver
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.Header
|
||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||
import it.vfsfitvnm.vimusic.utils.center
|
||||
import it.vfsfitvnm.vimusic.utils.medium
|
||||
import it.vfsfitvnm.vimusic.utils.produceSaveableRelaunchableOneShotState
|
||||
import it.vfsfitvnm.vimusic.utils.secondary
|
||||
import it.vfsfitvnm.youtubemusic.YouTube
|
||||
import it.vfsfitvnm.youtubemusic.Innertube
|
||||
import it.vfsfitvnm.youtubemusic.models.MusicShelfRenderer
|
||||
import it.vfsfitvnm.youtubemusic.models.bodies.ContinuationBody
|
||||
import it.vfsfitvnm.youtubemusic.models.bodies.SearchBody
|
||||
import it.vfsfitvnm.youtubemusic.requests.searchPage
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@ExperimentalAnimationApi
|
||||
@Composable
|
||||
inline fun <T : YouTube.Item> SearchResult(
|
||||
inline fun <T : Innertube.Item> SearchResult(
|
||||
query: String,
|
||||
filter: String,
|
||||
stateSaver: ListSaver<T, List<Any?>>,
|
||||
noinline fromMusicShelfRendererContent: (MusicShelfRenderer.Content) -> T?,
|
||||
crossinline onSearchAgain: () -> Unit,
|
||||
crossinline itemContent: @Composable LazyItemScope.(T) -> Unit,
|
||||
noinline itemShimmer: @Composable BoxScope.() -> Unit,
|
||||
@@ -52,21 +58,30 @@ inline fun <T : YouTube.Item> SearchResult(
|
||||
|
||||
val (continuationResultState, fetch) = produceSaveableRelaunchableOneShotState(
|
||||
initialValue = null,
|
||||
stateSaver = StringResultSaver
|
||||
stateSaver = resultSaver(autoSaver<String?>())
|
||||
) {
|
||||
val token = value?.getOrNull()
|
||||
|
||||
value = null
|
||||
|
||||
value = withContext(Dispatchers.IO) {
|
||||
YouTube.search(query, filter, token)
|
||||
}?.map { searchResult ->
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
(searchResult.items as List<T>?)?.let {
|
||||
items = items.plus(it).distinctBy(YouTube.Item::key)
|
||||
if (token == null) {
|
||||
Innertube.searchPage(
|
||||
body = SearchBody(query = query, params = filter),
|
||||
fromMusicShelfRendererContent = fromMusicShelfRendererContent
|
||||
)
|
||||
} else {
|
||||
Innertube.searchPage(
|
||||
body = ContinuationBody(continuation = token),
|
||||
fromMusicShelfRendererContent = fromMusicShelfRendererContent
|
||||
)
|
||||
}
|
||||
}?.map { itemsPage ->
|
||||
itemsPage?.items?.let {
|
||||
items = items.plus(it).distinctBy(Innertube.Item::key)
|
||||
}
|
||||
|
||||
searchResult.continuation
|
||||
itemsPage?.continuation
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +109,7 @@ inline fun <T : YouTube.Item> SearchResult(
|
||||
|
||||
items(
|
||||
items = items,
|
||||
key = YouTube.Item::key,
|
||||
key = Innertube.Item::key,
|
||||
itemContent = itemContent
|
||||
)
|
||||
|
||||
|
||||
@@ -13,16 +13,15 @@ import androidx.compose.ui.unit.dp
|
||||
import it.vfsfitvnm.route.RouteHandler
|
||||
import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
|
||||
import it.vfsfitvnm.vimusic.R
|
||||
import it.vfsfitvnm.vimusic.savers.YouTubeAlbumListSaver
|
||||
import it.vfsfitvnm.vimusic.savers.YouTubeArtistListSaver
|
||||
import it.vfsfitvnm.vimusic.savers.YouTubePlaylistListSaver
|
||||
import it.vfsfitvnm.vimusic.savers.YouTubeSongListSaver
|
||||
import it.vfsfitvnm.vimusic.savers.YouTubeVideoListSaver
|
||||
import it.vfsfitvnm.vimusic.savers.InnertubeAlbumItemListSaver
|
||||
import it.vfsfitvnm.vimusic.savers.InnertubeArtistItemListSaver
|
||||
import it.vfsfitvnm.vimusic.savers.InnertubePlaylistItemListSaver
|
||||
import it.vfsfitvnm.vimusic.savers.InnertubeSongItemListSaver
|
||||
import it.vfsfitvnm.vimusic.savers.InnertubeVideoItemListSaver
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.Scaffold
|
||||
import it.vfsfitvnm.vimusic.ui.screens.albumRoute
|
||||
import it.vfsfitvnm.vimusic.ui.screens.artistRoute
|
||||
import it.vfsfitvnm.vimusic.ui.screens.globalRoutes
|
||||
import it.vfsfitvnm.vimusic.ui.screens.playlist.PlaylistScreen
|
||||
import it.vfsfitvnm.vimusic.ui.screens.playlistRoute
|
||||
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
|
||||
import it.vfsfitvnm.vimusic.ui.styling.px
|
||||
@@ -40,7 +39,8 @@ import it.vfsfitvnm.vimusic.utils.asMediaItem
|
||||
import it.vfsfitvnm.vimusic.utils.forcePlay
|
||||
import it.vfsfitvnm.vimusic.utils.rememberPreference
|
||||
import it.vfsfitvnm.vimusic.utils.searchResultScreenTabIndexKey
|
||||
import it.vfsfitvnm.youtubemusic.YouTube
|
||||
import it.vfsfitvnm.youtubemusic.Innertube
|
||||
import it.vfsfitvnm.youtubemusic.utils.from
|
||||
|
||||
@ExperimentalFoundationApi
|
||||
@ExperimentalAnimationApi
|
||||
@@ -52,12 +52,6 @@ fun SearchResultScreen(query: String, onSearchAgain: () -> Unit) {
|
||||
RouteHandler(listenToGlobalEmitter = true) {
|
||||
globalRoutes()
|
||||
|
||||
playlistRoute { browseId ->
|
||||
PlaylistScreen(
|
||||
browseId = browseId ?: "browseId cannot be null"
|
||||
)
|
||||
}
|
||||
|
||||
host {
|
||||
Scaffold(
|
||||
topIconButtonId = R.drawable.chevron_back,
|
||||
@@ -74,12 +68,12 @@ fun SearchResultScreen(query: String, onSearchAgain: () -> Unit) {
|
||||
}
|
||||
) { tabIndex ->
|
||||
val searchFilter = when (tabIndex) {
|
||||
0 -> YouTube.Item.Song.Filter
|
||||
1 -> YouTube.Item.Album.Filter
|
||||
2 -> YouTube.Item.Artist.Filter
|
||||
3 -> YouTube.Item.Video.Filter
|
||||
4 -> YouTube.Item.CommunityPlaylist.Filter
|
||||
5 -> YouTube.Item.FeaturedPlaylist.Filter
|
||||
0 -> Innertube.SearchFilter.Song
|
||||
1 -> Innertube.SearchFilter.Album
|
||||
2 -> Innertube.SearchFilter.Artist
|
||||
3 -> Innertube.SearchFilter.Video
|
||||
4 -> Innertube.SearchFilter.CommunityPlaylist
|
||||
5 -> Innertube.SearchFilter.FeaturedPlaylist
|
||||
else -> error("unreachable")
|
||||
}.value
|
||||
|
||||
@@ -94,7 +88,8 @@ fun SearchResultScreen(query: String, onSearchAgain: () -> Unit) {
|
||||
query = query,
|
||||
filter = searchFilter,
|
||||
onSearchAgain = onSearchAgain,
|
||||
stateSaver = YouTubeSongListSaver,
|
||||
stateSaver = InnertubeSongItemListSaver,
|
||||
fromMusicShelfRendererContent = Innertube.SongItem.Companion::from,
|
||||
itemContent = { song ->
|
||||
SmallSongItem(
|
||||
song = song,
|
||||
@@ -119,8 +114,9 @@ fun SearchResultScreen(query: String, onSearchAgain: () -> Unit) {
|
||||
SearchResult(
|
||||
query = query,
|
||||
filter = searchFilter,
|
||||
stateSaver = YouTubeAlbumListSaver,
|
||||
stateSaver = InnertubeAlbumItemListSaver,
|
||||
onSearchAgain = onSearchAgain,
|
||||
fromMusicShelfRendererContent = Innertube.AlbumItem.Companion::from,
|
||||
itemContent = { album ->
|
||||
AlbumItem(
|
||||
album = album,
|
||||
@@ -148,8 +144,9 @@ fun SearchResultScreen(query: String, onSearchAgain: () -> Unit) {
|
||||
SearchResult(
|
||||
query = query,
|
||||
filter = searchFilter,
|
||||
stateSaver = YouTubeArtistListSaver,
|
||||
stateSaver = InnertubeArtistItemListSaver,
|
||||
onSearchAgain = onSearchAgain,
|
||||
fromMusicShelfRendererContent = Innertube.ArtistItem.Companion::from,
|
||||
itemContent = { artist ->
|
||||
ArtistItem(
|
||||
artist = artist,
|
||||
@@ -176,8 +173,9 @@ fun SearchResultScreen(query: String, onSearchAgain: () -> Unit) {
|
||||
SearchResult(
|
||||
query = query,
|
||||
filter = searchFilter,
|
||||
stateSaver = YouTubeVideoListSaver,
|
||||
stateSaver = InnertubeVideoItemListSaver,
|
||||
onSearchAgain = onSearchAgain,
|
||||
fromMusicShelfRendererContent = Innertube.VideoItem.Companion::from,
|
||||
itemContent = { video ->
|
||||
VideoItem(
|
||||
video = video,
|
||||
@@ -206,8 +204,9 @@ fun SearchResultScreen(query: String, onSearchAgain: () -> Unit) {
|
||||
SearchResult(
|
||||
query = query,
|
||||
filter = searchFilter,
|
||||
stateSaver = YouTubePlaylistListSaver,
|
||||
stateSaver = InnertubePlaylistItemListSaver,
|
||||
onSearchAgain = onSearchAgain,
|
||||
fromMusicShelfRendererContent = Innertube.PlaylistItem.Companion::from,
|
||||
itemContent = { playlist ->
|
||||
PlaylistItem(
|
||||
playlist = playlist,
|
||||
|
||||
Reference in New Issue
Block a user