Make MangaCoverViewModel collect manga only while subscribed (#3716)
Assisted-by: Claude:claude-opus-5
This commit is contained in:
@@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.ui.manga
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.compose.material3.SnackbarHostState
|
import androidx.compose.material3.SnackbarHostState
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import androidx.lifecycle.viewmodel.CreationExtras
|
import androidx.lifecycle.viewmodel.CreationExtras
|
||||||
import androidx.lifecycle.viewmodel.initializer
|
import androidx.lifecycle.viewmodel.initializer
|
||||||
@@ -19,10 +20,14 @@ import eu.kanade.tachiyomi.data.saver.Location
|
|||||||
import eu.kanade.tachiyomi.util.editCover
|
import eu.kanade.tachiyomi.util.editCover
|
||||||
import eu.kanade.tachiyomi.util.system.getBitmapOrNull
|
import eu.kanade.tachiyomi.util.system.getBitmapOrNull
|
||||||
import eu.kanade.tachiyomi.util.system.toShareIntent
|
import eu.kanade.tachiyomi.util.system.toShareIntent
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import kotlinx.coroutines.flow.WhileSubscribed
|
||||||
|
import kotlinx.coroutines.flow.flowOn
|
||||||
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import mihon.core.viewmodel.StateViewModel
|
|
||||||
import tachiyomi.core.common.i18n.stringResource
|
import tachiyomi.core.common.i18n.stringResource
|
||||||
import tachiyomi.core.common.util.lang.launchIO
|
import tachiyomi.core.common.util.lang.launchIO
|
||||||
import tachiyomi.core.common.util.lang.withIOContext
|
import tachiyomi.core.common.util.lang.withIOContext
|
||||||
@@ -33,6 +38,7 @@ import tachiyomi.domain.manga.model.Manga
|
|||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
|
||||||
class MangaCoverViewModel(
|
class MangaCoverViewModel(
|
||||||
private val mangaId: Long,
|
private val mangaId: Long,
|
||||||
@@ -42,7 +48,7 @@ class MangaCoverViewModel(
|
|||||||
private val updateManga: UpdateManga = Injekt.get(),
|
private val updateManga: UpdateManga = Injekt.get(),
|
||||||
|
|
||||||
val snackbarHostState: SnackbarHostState = SnackbarHostState(),
|
val snackbarHostState: SnackbarHostState = SnackbarHostState(),
|
||||||
) : StateViewModel<Manga?>(null) {
|
) : ViewModel() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val MANGA_ID_KEY = CreationExtras.Key<Long>()
|
val MANGA_ID_KEY = CreationExtras.Key<Long>()
|
||||||
@@ -56,12 +62,9 @@ class MangaCoverViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
val state: StateFlow<Manga?> = getManga.subscribe(mangaId)
|
||||||
viewModelScope.launchIO {
|
.flowOn(Dispatchers.IO)
|
||||||
getManga.subscribe(mangaId)
|
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5.seconds), null)
|
||||||
.collect { newManga -> mutableState.update { newManga } }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun saveCover(context: Context) {
|
fun saveCover(context: Context) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
@@ -147,7 +150,6 @@ class MangaCoverViewModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun deleteCustomCover(context: Context) {
|
fun deleteCustomCover(context: Context) {
|
||||||
val mangaId = state.value?.id ?: return
|
|
||||||
viewModelScope.launchIO {
|
viewModelScope.launchIO {
|
||||||
try {
|
try {
|
||||||
coverCache.deleteCustomCover(mangaId)
|
coverCache.deleteCustomCover(mangaId)
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import androidx.activity.result.contract.ActivityResultContracts
|
|||||||
import androidx.compose.foundation.layout.systemBarsPadding
|
import androidx.compose.foundation.layout.systemBarsPadding
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
|
||||||
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
|
||||||
@@ -250,7 +249,7 @@ class MangaScreen(
|
|||||||
set(MangaCoverViewModel.MANGA_ID_KEY, successState.manga.id)
|
set(MangaCoverViewModel.MANGA_ID_KEY, successState.manga.id)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
val manga by sm.state.collectAsState()
|
val manga by sm.state.collectAsStateWithLifecycle()
|
||||||
if (manga != null) {
|
if (manga != null) {
|
||||||
val getContent = rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) {
|
val getContent = rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) {
|
||||||
if (it == null) return@rememberLauncherForActivityResult
|
if (it == null) return@rememberLauncherForActivityResult
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class MangaRepositoryImpl(
|
|||||||
.awaitAsOne()
|
.awaitAsOne()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMangaByIdAsFlow(id: Long): Flow<Manga> {
|
override fun getMangaByIdAsFlow(id: Long): Flow<Manga> {
|
||||||
return database.mangasQueries
|
return database.mangasQueries
|
||||||
.getMangaById(id, MangaMapper::mapManga)
|
.getMangaById(id, MangaMapper::mapManga)
|
||||||
.subscribeToOne()
|
.subscribeToOne()
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class GetManga(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun subscribe(id: Long): Flow<Manga> {
|
fun subscribe(id: Long): Flow<Manga> {
|
||||||
return mangaRepository.getMangaByIdAsFlow(id)
|
return mangaRepository.getMangaByIdAsFlow(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ interface MangaRepository {
|
|||||||
|
|
||||||
suspend fun getMangaById(id: Long): Manga
|
suspend fun getMangaById(id: Long): Manga
|
||||||
|
|
||||||
suspend fun getMangaByIdAsFlow(id: Long): Flow<Manga>
|
fun getMangaByIdAsFlow(id: Long): Flow<Manga>
|
||||||
|
|
||||||
suspend fun getMangaByUrlAndSourceId(url: String, sourceId: Long): Manga?
|
suspend fun getMangaByUrlAndSourceId(url: String, sourceId: Long): Manga?
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user