Tweak code

This commit is contained in:
vfsfitvnm 2022-10-15 17:07:34 +02:00
parent 9a5ea69de4
commit df36075c3e
7 changed files with 132 additions and 160 deletions

View file

@ -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>>

View file

@ -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,63 +54,61 @@ 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
withContext(Dispatchers.IO) { LaunchedEffect(Unit) {
Innertube.albumPage(BrowseBody(browseId = browseId)) Database
}?.onSuccess { albumPage -> .album(browseId)
value = albumPage .combine(snapshotFlow { tabIndex }) { album, tabIndex -> album to tabIndex }
.collect { (currentAlbum, tabIndex) ->
album = currentAlbum
query { if (albumPage == null && (currentAlbum?.timestamp == null || tabIndex == 1)) {
Database.upsert( withContext(Dispatchers.IO) {
Album( Innertube.albumPage(BrowseBody(browseId = browseId))
id = browseId, ?.onSuccess { currentAlbumPage ->
title = albumPage.title, albumPage = currentAlbumPage
thumbnailUrl = albumPage.thumbnail?.url,
year = albumPage.year, Database.upsert(
authorsText = albumPage.authors?.joinToString("") { it.name ?: "" }, Album(
shareUrl = albumPage.url, id = browseId,
timestamp = System.currentTimeMillis(), title = currentAlbumPage.title,
bookmarkedAt = album?.bookmarkedAt thumbnailUrl = currentAlbumPage.thumbnail?.url,
), year = currentAlbumPage.year,
albumPage authorsText = currentAlbumPage.authors
.songsPage ?.joinToString("") { it.name ?: "" },
?.items shareUrl = currentAlbumPage.url,
?.map(Innertube.SongItem::asMediaItem) timestamp = System.currentTimeMillis(),
?.onEach(Database::insert) bookmarkedAt = album?.bookmarkedAt
?.mapIndexed { position, mediaItem -> ),
SongAlbumMap( currentAlbumPage
songId = mediaItem.mediaId, .songsPage
albumId = browseId, ?.items
position = position ?.map(Innertube.SongItem::asMediaItem)
) ?.onEach(Database::insert)
} ?: emptyList() ?.mapIndexed { position, mediaItem ->
) SongAlbumMap(
songId = mediaItem.mediaId,
albumId = browseId,
position = position
)
} ?: emptyList()
)
}
}
}
} }
}
} }
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
) )
) )

View file

@ -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( 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
withContext(Dispatchers.IO) { LaunchedEffect(Unit) {
Innertube.artistPage(BrowseBody(browseId = browseId)) Database
}?.onSuccess { artistPage -> .artist(browseId)
value = artistPage .combine(snapshotFlow { tabIndex }.map { it != 4 }) { artist, mustFetch -> artist to mustFetch }
.distinctUntilChanged()
.collect { (currentArtist, mustFetch) ->
artist = currentArtist
query { if (artistPage == null && (currentArtist?.timestamp == null || mustFetch)) {
Database.upsert( withContext(Dispatchers.IO) {
Artist( Innertube.artistPage(BrowseBody(browseId = browseId))
id = browseId, ?.onSuccess { currentArtistPage ->
name = artistPage.name, artistPage = currentArtistPage
thumbnailUrl = artistPage.thumbnail?.url,
timestamp = System.currentTimeMillis(), Database.upsert(
bookmarkedAt = artist?.bookmarkedAt 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) }, 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
) )
) )

View file

@ -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

View file

@ -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")

View file

@ -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))
} }
} }

View file

@ -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,