package com.topjohnwu.magisk.arch import android.Manifest.permission.REQUEST_INSTALL_PACKAGES import android.Manifest.permission.WRITE_EXTERNAL_STORAGE import android.annotation.SuppressLint import android.os.Bundle import androidx.databinding.PropertyChangeRegistry import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import androidx.navigation.NavDirections import com.topjohnwu.magisk.R import com.topjohnwu.magisk.databinding.ObservableHost import com.topjohnwu.magisk.events.BackPressEvent import com.topjohnwu.magisk.events.NavigationEvent import com.topjohnwu.magisk.events.PermissionEvent import com.topjohnwu.magisk.events.SnackbarEvent import kotlinx.coroutines.Job abstract class BaseViewModel : ViewModel(), ObservableHost { override var callbacks: PropertyChangeRegistry? = null val viewEvents: LiveData get() = _viewEvents private val _viewEvents = MutableLiveData() private var runningJob: Job? = null open fun onSaveState(state: Bundle) {} open fun onRestoreState(state: Bundle) {} /** 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 open fun onNetworkChanged(network: Boolean) {} fun withPermission(permission: String, callback: (Boolean) -> Unit) { PermissionEvent(permission, callback).publish() } inline fun withExternalRW(crossinline callback: () -> Unit) { withPermission(WRITE_EXTERNAL_STORAGE) { if (!it) { SnackbarEvent(R.string.external_rw_permission_denied).publish() } else { callback() } } } @SuppressLint("InlinedApi") inline fun withInstallPermission(crossinline callback: () -> Unit) { withPermission(REQUEST_INSTALL_PACKAGES) { if (!it) { SnackbarEvent(R.string.install_unknown_denied).publish() } else { callback() } } } fun back() = BackPressEvent().publish() fun Event.publish() { _viewEvents.postValue(this) } fun Event.publish() { scope = viewModelScope _viewEvents.postValue(this) } fun NavDirections.navigate(pop: Boolean = false) { _viewEvents.postValue(NavigationEvent(this, pop)) } }