2020-08-18 15:31:15 +02:00
|
|
|
package com.topjohnwu.magisk.arch
|
2020-01-12 20:56:03 +01:00
|
|
|
|
2020-07-08 10:26:45 +02:00
|
|
|
import android.Manifest
|
2020-01-12 20:56:03 +01:00
|
|
|
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
|
2020-01-12 20:56:03 +01:00
|
|
|
import androidx.lifecycle.LiveData
|
|
|
|
import androidx.lifecycle.MutableLiveData
|
|
|
|
import androidx.lifecycle.ViewModel
|
2020-07-10 13:19:18 +02:00
|
|
|
import androidx.lifecycle.viewModelScope
|
2020-03-17 17:28:09 +01:00
|
|
|
import androidx.navigation.NavDirections
|
2020-01-12 20:56:03 +01:00
|
|
|
import com.topjohnwu.magisk.BR
|
2020-07-17 10:27:35 +02:00
|
|
|
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
|
2020-07-08 10:50:28 +02:00
|
|
|
import kotlinx.coroutines.Job
|
2020-01-12 20:56:03 +01:00
|
|
|
|
|
|
|
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
|
2020-01-12 20:56:03 +01:00
|
|
|
|
|
|
|
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
|
2020-01-12 20:56:03 +01:00
|
|
|
|
2020-07-11 12:22:17 +02:00
|
|
|
val isConnected get() = Info.isConnected
|
2020-01-12 20:56:03 +01:00
|
|
|
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)
|
2020-01-12 20:56:03 +01:00
|
|
|
|
|
|
|
private val _viewEvents = MutableLiveData<ViewEvent>()
|
2020-07-08 10:50:28 +02:00
|
|
|
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) {
|
2020-01-12 20:56:03 +01:00
|
|
|
requestRefresh()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
init {
|
|
|
|
isConnected.addOnPropertyChangedCallback(refreshCallback)
|
|
|
|
}
|
|
|
|
|
|
|
|
/** This should probably never be called manually, it's called manually via delegate. */
|
|
|
|
@Synchronized
|
|
|
|
fun requestRefresh() {
|
2020-07-08 10:50:28 +02:00
|
|
|
if (runningJob?.isActive == true) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
runningJob = refresh()
|
2020-01-12 20:56:03 +01:00
|
|
|
}
|
|
|
|
|
2020-07-08 10:50:28 +02:00
|
|
|
protected open fun refresh(): Job? = null
|
2020-01-12 20:56:03 +01:00
|
|
|
|
|
|
|
@CallSuper
|
|
|
|
override fun onCleared() {
|
|
|
|
isConnected.removeOnPropertyChangedCallback(refreshCallback)
|
|
|
|
super.onCleared()
|
|
|
|
}
|
|
|
|
|
2020-08-22 14:27:30 +02:00
|
|
|
fun withPermission(permission: String, callback: (Boolean) -> Unit) {
|
|
|
|
PermissionEvent(permission, callback).publish()
|
2020-07-08 10:26:45 +02:00
|
|
|
}
|
|
|
|
|
2020-07-17 10:27:35 +02:00
|
|
|
fun withExternalRW(callback: () -> Unit) {
|
2020-08-22 14:27:30 +02:00
|
|
|
withPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) {
|
2020-07-17 10:27:35 +02:00
|
|
|
if (!it) {
|
|
|
|
SnackbarEvent(R.string.external_rw_permission_denied).publish()
|
|
|
|
} else {
|
|
|
|
callback()
|
|
|
|
}
|
|
|
|
}
|
2020-01-12 20:56:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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))
|
2020-03-17 17:28:09 +01:00
|
|
|
}
|
|
|
|
|
2020-01-12 20:56:03 +01:00
|
|
|
}
|