Skip to content

Commit

Permalink
Merge pull request #12681 from nlebeck/taskviewmodel-refactor
Browse files Browse the repository at this point in the history
Refactor `TaskViewModel` to track task-related state in a single `MutableLiveData` instance
  • Loading branch information
AdmiralCurtiss committed Apr 12, 2024
2 parents b623a36 + d7836ef commit 3a0720d
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 34 deletions.
Expand Up @@ -102,10 +102,7 @@ class UserDataActivity : AppCompatActivity() {
dialog.show(supportFragmentManager, UserDataImportWarningDialog.TAG)
} else if (requestCode == REQUEST_CODE_EXPORT && resultCode == RESULT_OK) {
taskViewModel.clear()
taskViewModel.task = {
val resultResource = exportUserData(data!!.data!!)
taskViewModel.setResult(resultResource)
}
taskViewModel.task = { exportUserData(data!!.data!!) }

val arguments = Bundle()
arguments.putInt(TaskDialog.KEY_TITLE, R.string.export_in_progress)
Expand Down
Expand Up @@ -34,14 +34,11 @@ class TaskDialog : DialogFragment() {
val progressMessage = requireArguments().getInt(KEY_MESSAGE)
if (progressMessage != 0) dialog.setMessage(resources.getString(progressMessage))

viewModel.isComplete.observe(this) { complete: Boolean ->
if (complete && viewModel.result.value != null) {
viewModel.result.observe(this) { result: Int? ->
if (result != null) {
dialog.dismiss()
val notificationArguments = Bundle()
notificationArguments.putInt(
TaskCompleteDialog.KEY_MESSAGE,
viewModel.result.value!!
)
notificationArguments.putInt(TaskCompleteDialog.KEY_MESSAGE, result)

val taskCompleteDialog = TaskCompleteDialog()
taskCompleteDialog.arguments = notificationArguments
Expand Down
Expand Up @@ -32,10 +32,8 @@ class UserDataImportWarningDialog : DialogFragment() {
taskArguments.putBoolean(TaskDialog.KEY_CANCELLABLE, false)

taskViewModel.task = {
taskViewModel.setResult(
(requireActivity() as UserDataActivity).importUserData(
requireArguments().getString(KEY_URI_RESULT)!!.toUri()
)
(requireActivity() as UserDataActivity).importUserData(
requireArguments().getString(KEY_URI_RESULT)!!.toUri()
)
}

Expand Down
Expand Up @@ -5,52 +5,73 @@ package org.dolphinemu.dolphinemu.model
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.map
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.*

/**
* A [ViewModel] associated with a task that runs on [Dispatchers.IO] and yields an integer result.
*/
class TaskViewModel : ViewModel() {
/** Represents the execution state of the task associated with this [TaskViewModel]. */
private interface State {
/** Returns true if the task has started running and false otherwise. */
fun hasStarted() : Boolean

/** Returns the task's result if it has completed or null otherwise. */
fun result() : Int?
}

private class NotStartedState : State {
override fun hasStarted() : Boolean { return false; }
override fun result() : Int? { return null; }
}

private class RunningState : State {
override fun hasStarted() : Boolean { return true; }
override fun result() : Int? { return null; }
}

private class CompletedState(private val result: Int) : State {
override fun hasStarted() : Boolean { return true; }
override fun result() : Int { return result; }
}

var cancelled = false
var mustRestartApp = false

private val _result = MutableLiveData<Int>()
val result: LiveData<Int> get() = _result
private val state = MutableLiveData<State>(NotStartedState())

private val _isComplete = MutableLiveData<Boolean>()
val isComplete: LiveData<Boolean> get() = _isComplete

private val _isRunning = MutableLiveData<Boolean>()
val isRunning: LiveData<Boolean> get() = _isRunning
/** Yields the result of [task] if it has completed or null otherwise. */
val result: LiveData<Int?> get() = state.map {
state -> state.result()
}

lateinit var task: () -> Unit
lateinit var task: () -> Int
var onResultDismiss: (() -> Unit)? = null

init {
clear()
}

fun clear() {
_result.value = 0
_isComplete.value = false
state.value = NotStartedState()
cancelled = false
mustRestartApp = false
onResultDismiss = null
_isRunning.value = false
}

fun runTask() {
if (isRunning.value == true) return
_isRunning.value = true
if (state.value!!.hasStarted()) {
return
}
state.value = RunningState()

viewModelScope.launch {
withContext(Dispatchers.IO) {
task.invoke()
_isRunning.postValue(false)
_isComplete.postValue(true)
val result = task.invoke()
state.postValue(CompletedState(result))
}
}
}

fun setResult(result: Int) {
_result.postValue(result)
}
}

0 comments on commit 3a0720d

Please sign in to comment.