Magisk/app/src/main/java/com/topjohnwu/magisk/arch/BaseViewModel.kt

106 lines
3.1 KiB
Kotlin
Raw Normal View History

2020-08-18 15:31:15 +02:00
package com.topjohnwu.magisk.arch
2020-07-08 10:26:45 +02:00
import android.Manifest
import androidx.annotation.CallSuper
import androidx.databinding.Bindable
2020-07-09 13:49:14 +02:00
import androidx.databinding.Observable
2020-07-12 23:37:07 +02:00
import androidx.databinding.PropertyChangeRegistry
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
2020-07-10 13:19:18 +02:00
import androidx.lifecycle.viewModelScope
import androidx.navigation.NavDirections
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R
2020-01-13 15:01:46 +01:00
import com.topjohnwu.magisk.core.Info
2021-05-10 05:45:53 +02:00
import com.topjohnwu.magisk.events.BackPressEvent
import com.topjohnwu.magisk.events.NavigationEvent
import com.topjohnwu.magisk.events.PermissionEvent
import com.topjohnwu.magisk.events.SnackbarEvent
2020-07-12 12:17:50 +02:00
import com.topjohnwu.magisk.utils.ObservableHost
2020-07-15 10:21:57 +02:00
import com.topjohnwu.magisk.utils.set
import kotlinx.coroutines.Job
abstract class BaseViewModel(
2020-07-09 13:49:14 +02:00
initialState: State = State.LOADING
2021-04-18 13:46:11 +02:00
) : ViewModel(), ObservableHost {
2020-07-12 23:37:07 +02:00
override var callbacks: PropertyChangeRegistry? = null
enum class State {
LOADED, LOADING, LOADING_FAILED
}
2020-07-12 12:17:50 +02:00
@get:Bindable
val loading get() = state == State.LOADING
@get:Bindable
val loaded get() = state == State.LOADED
@get:Bindable
val loadFailed get() = state == State.LOADING_FAILED
val isConnected get() = Info.isConnected
val viewEvents: LiveData<ViewEvent> get() = _viewEvents
2020-07-15 10:21:57 +02:00
var state= initialState
set(value) = set(value, field, { field = it }, BR.loading, BR.loaded, BR.loadFailed)
private val _viewEvents = MutableLiveData<ViewEvent>()
private var runningJob: Job? = null
2020-07-09 13:49:14 +02:00
private val refreshCallback = object : Observable.OnPropertyChangedCallback() {
override fun onPropertyChanged(sender: Observable?, propertyId: Int) {
requestRefresh()
}
}
init {
isConnected.addOnPropertyChangedCallback(refreshCallback)
}
/** This should probably never be called manually, it's called manually via delegate. */
@Synchronized
fun requestRefresh() {
if (runningJob?.isActive == true) {
return
}
runningJob = refresh()
}
protected open fun refresh(): Job? = null
@CallSuper
override fun onCleared() {
isConnected.removeOnPropertyChangedCallback(refreshCallback)
super.onCleared()
}
fun withPermission(permission: String, callback: (Boolean) -> Unit) {
PermissionEvent(permission, callback).publish()
2020-07-08 10:26:45 +02:00
}
fun withExternalRW(callback: () -> Unit) {
withPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) {
if (!it) {
SnackbarEvent(R.string.external_rw_permission_denied).publish()
} else {
callback()
}
}
}
fun back() = BackPressEvent().publish()
fun <Event : ViewEvent> Event.publish() {
_viewEvents.postValue(this)
}
2020-08-18 15:03:12 +02:00
fun <Event : ViewEventWithScope> Event.publish() {
2020-07-10 13:19:18 +02:00
scope = viewModelScope
_viewEvents.postValue(this)
}
2021-03-16 12:58:02 +01:00
fun NavDirections.navigate() {
2020-08-19 12:27:12 +02:00
_viewEvents.postValue(NavigationEvent(this))
}
}