mirror of
https://github.com/null2264/yokai.git
synced 2025-06-21 10:44:42 +00:00
refactor(extension/repo): Use ScreenModel instead of ViewModel
This commit is contained in:
parent
d655c3e09a
commit
d0d322fd67
3 changed files with 205 additions and 201 deletions
|
@ -1,22 +1,22 @@
|
||||||
package yokai.presentation.extension.repo
|
package yokai.presentation.extension.repo
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import cafe.adriel.voyager.navigator.Navigator
|
||||||
|
import cafe.adriel.voyager.transitions.CrossfadeTransition
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.BaseComposeController
|
import eu.kanade.tachiyomi.ui.base.controller.BaseComposeController
|
||||||
|
|
||||||
class ExtensionRepoController() :
|
class ExtensionRepoController(private val repoUrl: String? = null) : BaseComposeController() {
|
||||||
BaseComposeController() {
|
|
||||||
|
|
||||||
private var repoUrl: String? = null
|
|
||||||
|
|
||||||
constructor(repoUrl: String) : this() {
|
|
||||||
this.repoUrl = repoUrl
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun ScreenContent() {
|
override fun ScreenContent() {
|
||||||
ExtensionRepoScreen(
|
Navigator(
|
||||||
|
screen = ExtensionRepoScreen(
|
||||||
title = "Extension Repos",
|
title = "Extension Repos",
|
||||||
repoUrl = repoUrl,
|
repoUrl = repoUrl,
|
||||||
|
),
|
||||||
|
content = {
|
||||||
|
CrossfadeTransition(navigator = it)
|
||||||
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||||
import dev.icerock.moko.resources.compose.stringResource
|
import dev.icerock.moko.resources.compose.stringResource
|
||||||
import eu.kanade.tachiyomi.util.compose.LocalBackPress
|
import eu.kanade.tachiyomi.util.compose.LocalBackPress
|
||||||
import eu.kanade.tachiyomi.util.compose.LocalDialogHostState
|
import eu.kanade.tachiyomi.util.compose.LocalDialogHostState
|
||||||
|
@ -43,20 +43,23 @@ import yokai.presentation.component.EmptyScreen
|
||||||
import yokai.presentation.component.ToolTipButton
|
import yokai.presentation.component.ToolTipButton
|
||||||
import yokai.presentation.extension.repo.component.ExtensionRepoInput
|
import yokai.presentation.extension.repo.component.ExtensionRepoInput
|
||||||
import yokai.presentation.extension.repo.component.ExtensionRepoItem
|
import yokai.presentation.extension.repo.component.ExtensionRepoItem
|
||||||
|
import yokai.util.Screen
|
||||||
import android.R as AR
|
import android.R as AR
|
||||||
|
|
||||||
|
class ExtensionRepoScreen(
|
||||||
|
private val title: String,
|
||||||
|
private var repoUrl: String? = null,
|
||||||
|
): Screen() {
|
||||||
@Composable
|
@Composable
|
||||||
fun ExtensionRepoScreen(
|
override fun Content() {
|
||||||
title: String,
|
|
||||||
viewModel: ExtensionRepoViewModel = viewModel(),
|
|
||||||
repoUrl: String? = null,
|
|
||||||
) {
|
|
||||||
val onBackPress = LocalBackPress.currentOrThrow
|
val onBackPress = LocalBackPress.currentOrThrow
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val alertDialog = LocalDialogHostState.currentOrThrow
|
val alertDialog = LocalDialogHostState.currentOrThrow
|
||||||
val scope = rememberCoroutineScope()
|
|
||||||
|
|
||||||
val repoState by viewModel.repoState.collectAsState()
|
val scope = rememberCoroutineScope()
|
||||||
|
val screenModel = rememberScreenModel { ExtensionRepoScreenModel() }
|
||||||
|
val state by screenModel.state.collectAsState()
|
||||||
|
|
||||||
var inputText by remember { mutableStateOf("") }
|
var inputText by remember { mutableStateOf("") }
|
||||||
val listState = rememberLazyListState()
|
val listState = rememberLazyListState()
|
||||||
|
|
||||||
|
@ -74,14 +77,14 @@ fun ExtensionRepoScreen(
|
||||||
icon = Icons.Outlined.Refresh,
|
icon = Icons.Outlined.Refresh,
|
||||||
buttonClicked = {
|
buttonClicked = {
|
||||||
context.toast("Refreshing...") // TODO: Should be loading animation instead
|
context.toast("Refreshing...") // TODO: Should be loading animation instead
|
||||||
viewModel.refreshRepos()
|
screenModel.refreshRepos()
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
) { innerPadding ->
|
) { innerPadding ->
|
||||||
if (repoState is ExtensionRepoState.Loading) return@YokaiScaffold
|
if (state is ExtensionRepoScreenModel.State.Loading) return@YokaiScaffold
|
||||||
|
|
||||||
val repos = (repoState as ExtensionRepoState.Success).repos
|
val repos = (state as ExtensionRepoScreenModel.State.Success).repos
|
||||||
|
|
||||||
alertDialog.value?.invoke()
|
alertDialog.value?.invoke()
|
||||||
|
|
||||||
|
@ -96,7 +99,7 @@ fun ExtensionRepoScreen(
|
||||||
inputText = inputText,
|
inputText = inputText,
|
||||||
inputHint = stringResource(MR.strings.label_add_repo),
|
inputHint = stringResource(MR.strings.label_add_repo),
|
||||||
onInputChange = { inputText = it },
|
onInputChange = { inputText = it },
|
||||||
onAddClick = { viewModel.addRepo(it) },
|
onAddClick = { screenModel.addRepo(it) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +120,7 @@ fun ExtensionRepoScreen(
|
||||||
ExtensionRepoItem(
|
ExtensionRepoItem(
|
||||||
extensionRepo = repo,
|
extensionRepo = repo,
|
||||||
onDeleteClick = { repoToDelete ->
|
onDeleteClick = { repoToDelete ->
|
||||||
scope.launch { alertDialog.awaitExtensionRepoDeletePrompt(repoToDelete, viewModel) }
|
scope.launch { alertDialog.awaitExtensionRepoDeletePrompt(repoToDelete, screenModel) }
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -126,11 +129,14 @@ fun ExtensionRepoScreen(
|
||||||
}
|
}
|
||||||
|
|
||||||
LaunchedEffect(repoUrl) {
|
LaunchedEffect(repoUrl) {
|
||||||
repoUrl?.let { viewModel.addRepo(repoUrl) }
|
repoUrl?.let {
|
||||||
|
screenModel.addRepo(repoUrl!!)
|
||||||
|
repoUrl = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
viewModel.event.collectLatest { event ->
|
screenModel.event.collectLatest { event ->
|
||||||
when (event) {
|
when (event) {
|
||||||
is ExtensionRepoEvent.NoOp -> {}
|
is ExtensionRepoEvent.NoOp -> {}
|
||||||
is ExtensionRepoEvent.LocalizedMessage -> context.toast(event.stringRes)
|
is ExtensionRepoEvent.LocalizedMessage -> context.toast(event.stringRes)
|
||||||
|
@ -141,7 +147,7 @@ fun ExtensionRepoScreen(
|
||||||
alertDialog.awaitExtensionRepoReplacePrompt(
|
alertDialog.awaitExtensionRepoReplacePrompt(
|
||||||
oldRepo = event.dialog.oldRepo,
|
oldRepo = event.dialog.oldRepo,
|
||||||
newRepo = event.dialog.newRepo,
|
newRepo = event.dialog.newRepo,
|
||||||
onMigrate = { viewModel.replaceRepo(event.dialog.newRepo) },
|
onMigrate = { screenModel.replaceRepo(event.dialog.newRepo) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -151,7 +157,7 @@ fun ExtensionRepoScreen(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun DialogHostState.awaitExtensionRepoReplacePrompt(
|
private suspend fun DialogHostState.awaitExtensionRepoReplacePrompt(
|
||||||
oldRepo: ExtensionRepo,
|
oldRepo: ExtensionRepo,
|
||||||
newRepo: ExtensionRepo,
|
newRepo: ExtensionRepo,
|
||||||
onMigrate: () -> Unit,
|
onMigrate: () -> Unit,
|
||||||
|
@ -182,9 +188,9 @@ suspend fun DialogHostState.awaitExtensionRepoReplacePrompt(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun DialogHostState.awaitExtensionRepoDeletePrompt(
|
private suspend fun DialogHostState.awaitExtensionRepoDeletePrompt(
|
||||||
repoToDelete: String,
|
repoToDelete: String,
|
||||||
viewModel: ExtensionRepoViewModel,
|
screenModel: ExtensionRepoScreenModel,
|
||||||
): Unit = dialog { cont ->
|
): Unit = dialog { cont ->
|
||||||
AlertDialog(
|
AlertDialog(
|
||||||
containerColor = MaterialTheme.colorScheme.surface,
|
containerColor = MaterialTheme.colorScheme.surface,
|
||||||
|
@ -208,7 +214,7 @@ suspend fun DialogHostState.awaitExtensionRepoDeletePrompt(
|
||||||
confirmButton = {
|
confirmButton = {
|
||||||
TextButton(
|
TextButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
viewModel.deleteRepo(repoToDelete)
|
screenModel.deleteRepo(repoToDelete)
|
||||||
cont.cancel()
|
cont.cancel()
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
|
@ -230,3 +236,4 @@ suspend fun DialogHostState.awaitExtensionRepoDeletePrompt(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package yokai.presentation.extension.repo
|
package yokai.presentation.extension.repo
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.lifecycle.ViewModel
|
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import cafe.adriel.voyager.core.model.screenModelScope
|
||||||
import dev.icerock.moko.resources.StringResource
|
import dev.icerock.moko.resources.StringResource
|
||||||
import eu.kanade.tachiyomi.extension.ExtensionManager
|
import eu.kanade.tachiyomi.extension.ExtensionManager
|
||||||
import eu.kanade.tachiyomi.util.system.launchIO
|
import eu.kanade.tachiyomi.util.system.launchIO
|
||||||
|
@ -22,8 +22,7 @@ import yokai.domain.extension.repo.interactor.UpdateExtensionRepo
|
||||||
import yokai.domain.extension.repo.model.ExtensionRepo
|
import yokai.domain.extension.repo.model.ExtensionRepo
|
||||||
import yokai.i18n.MR
|
import yokai.i18n.MR
|
||||||
|
|
||||||
class ExtensionRepoViewModel :
|
class ExtensionRepoScreenModel : StateScreenModel<ExtensionRepoScreenModel.State>(State.Loading) {
|
||||||
ViewModel() {
|
|
||||||
|
|
||||||
private val extensionManager: ExtensionManager by injectLazy()
|
private val extensionManager: ExtensionManager by injectLazy()
|
||||||
|
|
||||||
|
@ -33,23 +32,20 @@ class ExtensionRepoViewModel :
|
||||||
private val replaceExtensionRepo: ReplaceExtensionRepo by injectLazy()
|
private val replaceExtensionRepo: ReplaceExtensionRepo by injectLazy()
|
||||||
private val updateExtensionRepo: UpdateExtensionRepo by injectLazy()
|
private val updateExtensionRepo: UpdateExtensionRepo by injectLazy()
|
||||||
|
|
||||||
private val mutableRepoState: MutableStateFlow<ExtensionRepoState> = MutableStateFlow(ExtensionRepoState.Loading)
|
|
||||||
val repoState: StateFlow<ExtensionRepoState> = mutableRepoState.asStateFlow()
|
|
||||||
|
|
||||||
private val internalEvent: MutableStateFlow<ExtensionRepoEvent> = MutableStateFlow(ExtensionRepoEvent.NoOp)
|
private val internalEvent: MutableStateFlow<ExtensionRepoEvent> = MutableStateFlow(ExtensionRepoEvent.NoOp)
|
||||||
val event: StateFlow<ExtensionRepoEvent> = internalEvent.asStateFlow()
|
val event: StateFlow<ExtensionRepoEvent> = internalEvent.asStateFlow()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
viewModelScope.launchIO {
|
screenModelScope.launchIO {
|
||||||
getExtensionRepo.subscribeAll().collectLatest { repos ->
|
getExtensionRepo.subscribeAll().collectLatest { repos ->
|
||||||
mutableRepoState.update { ExtensionRepoState.Success(repos = repos.toImmutableList()) }
|
mutableState.update { State.Success(repos = repos.toImmutableList()) }
|
||||||
extensionManager.refreshTrust()
|
extensionManager.refreshTrust()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addRepo(url: String) {
|
fun addRepo(url: String) {
|
||||||
viewModelScope.launchIO {
|
screenModelScope.launchIO {
|
||||||
when (val result = createExtensionRepo.await(url)) {
|
when (val result = createExtensionRepo.await(url)) {
|
||||||
is CreateExtensionRepo.Result.Success -> internalEvent.value = ExtensionRepoEvent.Success
|
is CreateExtensionRepo.Result.Success -> internalEvent.value = ExtensionRepoEvent.Success
|
||||||
is CreateExtensionRepo.Result.Error -> internalEvent.value = ExtensionRepoEvent.InvalidUrl
|
is CreateExtensionRepo.Result.Error -> internalEvent.value = ExtensionRepoEvent.InvalidUrl
|
||||||
|
@ -63,26 +59,41 @@ class ExtensionRepoViewModel :
|
||||||
}
|
}
|
||||||
|
|
||||||
fun replaceRepo(newRepo: ExtensionRepo) {
|
fun replaceRepo(newRepo: ExtensionRepo) {
|
||||||
viewModelScope.launchIO {
|
screenModelScope.launchIO {
|
||||||
replaceExtensionRepo.await(newRepo)
|
replaceExtensionRepo.await(newRepo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun refreshRepos() {
|
fun refreshRepos() {
|
||||||
val status = repoState.value
|
val status = state.value
|
||||||
|
|
||||||
if (status is ExtensionRepoState.Success) {
|
if (status is State.Success) {
|
||||||
viewModelScope.launchIO {
|
screenModelScope.launchIO {
|
||||||
updateExtensionRepo.awaitAll()
|
updateExtensionRepo.awaitAll()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun deleteRepo(url: String) {
|
fun deleteRepo(url: String) {
|
||||||
viewModelScope.launchIO {
|
screenModelScope.launchIO {
|
||||||
deleteExtensionRepo.await(url)
|
deleteExtensionRepo.await(url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sealed interface State {
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
data object Loading : State
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
data class Success(
|
||||||
|
val repos: ImmutableList<ExtensionRepo>,
|
||||||
|
) : State {
|
||||||
|
|
||||||
|
val isEmpty: Boolean
|
||||||
|
get() = repos.isEmpty()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class RepoDialog {
|
sealed class RepoDialog {
|
||||||
|
@ -98,17 +109,3 @@ sealed class ExtensionRepoEvent {
|
||||||
data object Success : ExtensionRepoEvent()
|
data object Success : ExtensionRepoEvent()
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class ExtensionRepoState {
|
|
||||||
|
|
||||||
@Immutable
|
|
||||||
data object Loading : ExtensionRepoState()
|
|
||||||
|
|
||||||
@Immutable
|
|
||||||
data class Success(
|
|
||||||
val repos: ImmutableList<ExtensionRepo>,
|
|
||||||
) : ExtensionRepoState() {
|
|
||||||
|
|
||||||
val isEmpty: Boolean
|
|
||||||
get() = repos.isEmpty()
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue