Drop ViewModel
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
package it.vfsfitvnm.vimusic.utils
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import it.vfsfitvnm.vimusic.savers.ListSaver
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.drop
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
|
||||
|
||||
@Composable
|
||||
fun <T> produceSaveableListState(
|
||||
flowProvider: () -> Flow<List<T>>,
|
||||
stateSaver: ListSaver<T, List<Any?>>,
|
||||
): State<List<T>> {
|
||||
val state = rememberSaveable(stateSaver = stateSaver) {
|
||||
mutableStateOf(emptyList())
|
||||
}
|
||||
|
||||
var hasToRecollect by rememberSaveable {
|
||||
mutableStateOf(true)
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
flowProvider()
|
||||
.flowOn(Dispatchers.IO)
|
||||
.drop(if (hasToRecollect) 0 else 1)
|
||||
.collect {
|
||||
hasToRecollect = false
|
||||
state.value = it
|
||||
}
|
||||
}
|
||||
|
||||
return state
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun <T> produceSaveableListState(
|
||||
flowProvider: () -> Flow<List<T>>,
|
||||
stateSaver: ListSaver<T, List<Any?>>,
|
||||
key1: Any?,
|
||||
): State<List<T>> {
|
||||
val state = rememberSaveable(stateSaver = stateSaver) {
|
||||
mutableStateOf(emptyList())
|
||||
}
|
||||
|
||||
var hasToRecollect by rememberSaveable(key1) {
|
||||
// println("hasToRecollect: $sortBy, $sortOrder")
|
||||
mutableStateOf(true)
|
||||
}
|
||||
|
||||
LaunchedEffect(key1) {
|
||||
// println("[${System.currentTimeMillis()}] LaunchedEffect, $hasToRecollect, $sortBy, $sortOrder")
|
||||
flowProvider()
|
||||
.flowOn(Dispatchers.IO)
|
||||
.drop(if (hasToRecollect) 0 else 1)
|
||||
.collect {
|
||||
hasToRecollect = false
|
||||
// println("[${System.currentTimeMillis()}] collecting... ")
|
||||
state.value = it
|
||||
}
|
||||
}
|
||||
|
||||
return state
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun <T> produceSaveableListState(
|
||||
flowProvider: () -> Flow<List<T>>,
|
||||
stateSaver: ListSaver<T, List<Any?>>,
|
||||
key1: Any?,
|
||||
key2: Any?,
|
||||
): State<List<T>> {
|
||||
val state = rememberSaveable(stateSaver = stateSaver) {
|
||||
mutableStateOf(emptyList())
|
||||
}
|
||||
|
||||
// var hasToRecollect by rememberSaveable(key1, key2) {
|
||||
//// println("hasToRecollect: $sortBy, $sortOrder")
|
||||
// mutableStateOf(true)
|
||||
// }
|
||||
|
||||
LaunchedEffect(key1, key2) {
|
||||
// println("[${System.currentTimeMillis()}] LaunchedEffect, $hasToRecollect, $sortBy, $sortOrder")
|
||||
flowProvider()
|
||||
.flowOn(Dispatchers.IO)
|
||||
// .drop(if (hasToRecollect) 0 else 1)
|
||||
.collect {
|
||||
// hasToRecollect = false
|
||||
// println("[${System.currentTimeMillis()}] collecting... ")
|
||||
state.value = it
|
||||
}
|
||||
}
|
||||
|
||||
return state
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package it.vfsfitvnm.vimusic.utils
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.ProduceStateScope
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.saveable.Saver
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.experimental.ExperimentalTypeInference
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
|
||||
@OptIn(ExperimentalTypeInference::class)
|
||||
@Composable
|
||||
fun <T> produceSaveableState(
|
||||
initialValue: T,
|
||||
stateSaver: Saver<T, out Any>,
|
||||
@BuilderInference producer: suspend ProduceStateScope<T>.() -> Unit
|
||||
): State<T> {
|
||||
val result = rememberSaveable(stateSaver = stateSaver) { mutableStateOf(initialValue) }
|
||||
|
||||
var hasToFetch by rememberSaveable { mutableStateOf(true) }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
if (hasToFetch) {
|
||||
ProduceSaveableStateScope(result, coroutineContext).producer()
|
||||
hasToFetch = false
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalTypeInference::class)
|
||||
@Composable
|
||||
fun <T> produceSaveableState(
|
||||
initialValue: T,
|
||||
stateSaver: Saver<T, out Any>,
|
||||
key1: Any?,
|
||||
@BuilderInference producer: suspend ProduceStateScope<T>.() -> Unit
|
||||
): State<T> {
|
||||
val result = rememberSaveable(stateSaver = stateSaver) { mutableStateOf(initialValue) }
|
||||
|
||||
var hasToFetch by rememberSaveable(key1) { mutableStateOf(true) }
|
||||
|
||||
LaunchedEffect(key1) {
|
||||
if (hasToFetch) {
|
||||
ProduceSaveableStateScope(result, coroutineContext).producer()
|
||||
hasToFetch = false
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalTypeInference::class)
|
||||
@Composable
|
||||
fun <T> produceSaveableState(
|
||||
initialValue: T,
|
||||
stateSaver: Saver<T, out Any>,
|
||||
key1: Any?,
|
||||
key2: Any?,
|
||||
@BuilderInference producer: suspend ProduceStateScope<T>.() -> Unit
|
||||
): State<T> {
|
||||
val result = rememberSaveable(stateSaver = stateSaver) { mutableStateOf(initialValue) }
|
||||
|
||||
var hasToFetch by rememberSaveable(key1, key2) { mutableStateOf(true) }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
if (hasToFetch) {
|
||||
ProduceSaveableStateScope(result, coroutineContext).producer()
|
||||
hasToFetch = false
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalTypeInference::class)
|
||||
@Composable
|
||||
fun <T> produceSaveableRelaunchableState(
|
||||
initialValue: T,
|
||||
stateSaver: Saver<T, out Any>,
|
||||
key1: Any?,
|
||||
key2: Any?,
|
||||
@BuilderInference producer: suspend ProduceStateScope<T>.() -> Unit
|
||||
): Pair<State<T>, () -> Unit> {
|
||||
val result = rememberSaveable(stateSaver = stateSaver) { mutableStateOf(initialValue) }
|
||||
|
||||
var hasToFetch by rememberSaveable(key1, key2) { mutableStateOf(true) }
|
||||
|
||||
val relaunchableEffect = relaunchableEffect(key1, key2) {
|
||||
if (hasToFetch) {
|
||||
ProduceSaveableStateScope(result, coroutineContext).producer()
|
||||
hasToFetch = false
|
||||
}
|
||||
}
|
||||
|
||||
return result to {
|
||||
hasToFetch = true
|
||||
relaunchableEffect()
|
||||
}
|
||||
}
|
||||
|
||||
private class ProduceSaveableStateScope<T>(
|
||||
state: MutableState<T>,
|
||||
override val coroutineContext: CoroutineContext
|
||||
) : ProduceStateScope<T>, MutableState<T> by state {
|
||||
override suspend fun awaitDispose(onDispose: () -> Unit): Nothing {
|
||||
try {
|
||||
suspendCancellableCoroutine<Nothing> { }
|
||||
} finally {
|
||||
onDispose()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ val YouTube.Item.Song.asMediaItem: MediaItem
|
||||
.setMediaMetadata(
|
||||
MediaMetadata.Builder()
|
||||
.setTitle(info.name)
|
||||
.setArtist(authors.joinToString("") { it.name })
|
||||
.setArtist(authors?.joinToString("") { it.name })
|
||||
.setAlbumTitle(album?.name)
|
||||
.setArtworkUri(thumbnail?.url?.toUri())
|
||||
.setExtras(
|
||||
@@ -36,8 +36,8 @@ val YouTube.Item.Song.asMediaItem: MediaItem
|
||||
"videoId" to info.endpoint!!.videoId,
|
||||
"albumId" to album?.endpoint?.browseId,
|
||||
"durationText" to durationText,
|
||||
"artistNames" to authors.filter { it.endpoint != null }.map { it.name },
|
||||
"artistIds" to authors.mapNotNull { it.endpoint?.browseId },
|
||||
"artistNames" to authors?.filter { it.endpoint != null }?.map { it.name },
|
||||
"artistIds" to authors?.mapNotNull { it.endpoint?.browseId },
|
||||
)
|
||||
)
|
||||
.build()
|
||||
@@ -52,14 +52,14 @@ val YouTube.Item.Video.asMediaItem: MediaItem
|
||||
.setMediaMetadata(
|
||||
MediaMetadata.Builder()
|
||||
.setTitle(info.name)
|
||||
.setArtist(authors.joinToString("") { it.name })
|
||||
.setArtist(authors?.joinToString("") { it.name })
|
||||
.setArtworkUri(thumbnail?.url?.toUri())
|
||||
.setExtras(
|
||||
bundleOf(
|
||||
"videoId" to info.endpoint!!.videoId,
|
||||
"durationText" to durationText,
|
||||
"artistNames" to if (isOfficialMusicVideo) authors.filter { it.endpoint != null }.map { it.name } else null,
|
||||
"artistIds" to if (isOfficialMusicVideo) authors.mapNotNull { it.endpoint?.browseId } else null,
|
||||
"artistNames" to if (isOfficialMusicVideo) authors?.filter { it.endpoint != null }?.map { it.name } else null,
|
||||
"artistIds" to if (isOfficialMusicVideo) authors?.mapNotNull { it.endpoint?.browseId } else null,
|
||||
)
|
||||
)
|
||||
.build()
|
||||
|
||||
Reference in New Issue
Block a user