Drop ViewModel

This commit is contained in:
vfsfitvnm
2022-09-26 14:52:39 +02:00
parent 29b4a8f5da
commit f981725062
69 changed files with 1269 additions and 2174 deletions

View File

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

View File

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

View File

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