Updated policy items so listeners are not indirectly set to them and kept out of the instance of the parent object

This commit is contained in:
Viktor De Pasquale 2019-04-19 19:22:18 +02:00
parent ad80804461
commit ce693aa5e9
4 changed files with 80 additions and 55 deletions

View File

@ -11,6 +11,6 @@ import org.koin.dsl.module
val viewModelModules = module {
viewModel { MainViewModel() }
viewModel { HomeViewModel(get(), get()) }
viewModel { SuperuserViewModel(get(), get(), get()) }
viewModel { SuperuserViewModel(get(), get(), get(), get()) }
viewModel { HideViewModel(get(), get()) }
}

View File

@ -2,9 +2,14 @@ package com.topjohnwu.magisk.model.entity.recycler
import android.graphics.drawable.Drawable
import com.skoumal.teanity.databinding.ComparableRvItem
import com.skoumal.teanity.extensions.addOnPropertyChangedCallback
import com.skoumal.teanity.rxbus.RxBus
import com.skoumal.teanity.util.KObservableField
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.model.entity.Policy
import com.topjohnwu.magisk.model.events.PolicyEnableEvent
import com.topjohnwu.magisk.model.events.PolicyUpdateEvent
import com.topjohnwu.magisk.utils.inject
import com.topjohnwu.magisk.utils.toggle
class PolicyRvItem(val item: Policy, val icon: Drawable) : ComparableRvItem<PolicyRvItem>() {
@ -18,6 +23,25 @@ class PolicyRvItem(val item: Policy, val icon: Drawable) : ComparableRvItem<Poli
fun toggle() = isExpanded.toggle()
private val rxBus: RxBus by inject()
init {
isEnabled.addOnPropertyChangedCallback {
it ?: return@addOnPropertyChangedCallback
rxBus.post(PolicyEnableEvent(this@PolicyRvItem, it))
}
shouldNotify.addOnPropertyChangedCallback {
it ?: return@addOnPropertyChangedCallback
item.notification = it
rxBus.post(PolicyUpdateEvent.Notification(this@PolicyRvItem))
}
shouldLog.addOnPropertyChangedCallback {
it ?: return@addOnPropertyChangedCallback
item.logging = it
rxBus.post(PolicyUpdateEvent.Log(this@PolicyRvItem))
}
}
override fun contentSameAs(other: PolicyRvItem): Boolean = itemSameAs(other)
override fun itemSameAs(other: PolicyRvItem): Boolean = item.uid == other.item.uid
}

View File

@ -2,5 +2,12 @@ package com.topjohnwu.magisk.model.events
import com.skoumal.teanity.rxbus.RxBus
import com.topjohnwu.magisk.model.entity.recycler.HideProcessRvItem
import com.topjohnwu.magisk.model.entity.recycler.PolicyRvItem
class HideProcessEvent(val item: HideProcessRvItem) : RxBus.Event
class HideProcessEvent(val item: HideProcessRvItem) : RxBus.Event
class PolicyEnableEvent(val item: PolicyRvItem, val enable: Boolean) : RxBus.Event
sealed class PolicyUpdateEvent(val item: PolicyRvItem) : RxBus.Event {
class Notification(item: PolicyRvItem) : PolicyUpdateEvent(item)
class Log(item: PolicyRvItem) : PolicyUpdateEvent(item)
}

View File

@ -3,9 +3,9 @@ package com.topjohnwu.magisk.ui.superuser
import android.content.pm.PackageManager
import android.content.res.Resources
import com.skoumal.teanity.databinding.ComparableRvItem
import com.skoumal.teanity.extensions.addOnPropertyChangedCallback
import com.skoumal.teanity.extensions.applySchedulers
import com.skoumal.teanity.extensions.subscribeK
import com.skoumal.teanity.rxbus.RxBus
import com.skoumal.teanity.util.DiffObservableList
import com.skoumal.teanity.viewevents.SnackbarEvent
import com.topjohnwu.magisk.BR
@ -13,6 +13,8 @@ import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.data.database.MagiskDB
import com.topjohnwu.magisk.model.entity.Policy
import com.topjohnwu.magisk.model.entity.recycler.PolicyRvItem
import com.topjohnwu.magisk.model.events.PolicyEnableEvent
import com.topjohnwu.magisk.model.events.PolicyUpdateEvent
import com.topjohnwu.magisk.ui.base.MagiskViewModel
import com.topjohnwu.magisk.utils.FingerprintHelper
import com.topjohnwu.magisk.utils.toggle
@ -24,7 +26,8 @@ import me.tatarka.bindingcollectionadapter2.ItemBinding
class SuperuserViewModel(
private val database: MagiskDB,
private val packageManager: PackageManager,
private val resources: Resources
private val resources: Resources,
rxBus: RxBus
) : MagiskViewModel() {
val items = DiffObservableList(ComparableRvItem.callback)
@ -36,13 +39,20 @@ class SuperuserViewModel(
private var ignoreNext: PolicyRvItem? = null
init {
rxBus.register<PolicyEnableEvent>()
.subscribeK { togglePolicy(it.item, it.enable) }
.add()
rxBus.register<PolicyUpdateEvent>()
.subscribeK { updatePolicy(it) }
.add()
updatePolicies()
}
fun updatePolicies() {
Single.fromCallable { database.policyList }
.flattenAsFlowable { it }
.map { PolicyRvItem(it, it.info.loadIcon(packageManager)).setListeners() }
.map { PolicyRvItem(it, it.info.loadIcon(packageManager)) }
.toList()
.applySchedulers()
.applyViewModel(this)
@ -70,64 +80,48 @@ class SuperuserViewModel(
}
}
private fun PolicyRvItem.setListeners() = apply {
isEnabled.addOnPropertyChangedCallback {
it ?: return@addOnPropertyChangedCallback
if (ignoreNext == this) {
ignoreNext = null
return@addOnPropertyChangedCallback
}
fun updateState() {
item.policy = if (it) Policy.ALLOW else Policy.DENY
updatePolicy(item)
.map { it.policy == Policy.ALLOW }
.subscribeK {
val textId = if (it) R.string.su_snack_grant else R.string.su_snack_deny
val text = resources.getString(textId).format(item.appName)
SnackbarEvent(text).publish()
}
.add()
}
if (FingerprintHelper.useFingerprint()) {
withView {
FingerprintAuthDialog(this, { updateState() }, {
ignoreNext = this@setListeners
isEnabled.toggle()
}).show()
}
} else {
updateState()
}
private fun updatePolicy(it: PolicyUpdateEvent) = when (it) {
is PolicyUpdateEvent.Notification -> updatePolicy(it.item) {
val textId = if (it.logging) R.string.su_snack_notif_on else R.string.su_snack_notif_off
val text = resources.getString(textId).format(it.appName)
SnackbarEvent(text).publish()
}
shouldNotify.addOnPropertyChangedCallback {
it ?: return@addOnPropertyChangedCallback
item.notification = it
is PolicyUpdateEvent.Log -> updatePolicy(it.item) {
val textId =
if (it.notification) R.string.su_snack_log_on else R.string.su_snack_log_off
val text = resources.getString(textId).format(it.appName)
SnackbarEvent(text).publish()
}
}
updatePolicy(item)
.map { it.notification }
private fun updatePolicy(item: PolicyRvItem, onSuccess: (Policy) -> Unit) =
updatePolicy(item.item)
.subscribeK { onSuccess(it) }
.add()
private fun togglePolicy(item: PolicyRvItem, enable: Boolean) {
fun updateState() {
item.item.policy = if (enable) Policy.ALLOW else Policy.DENY
updatePolicy(item.item)
.map { it.policy == Policy.ALLOW }
.subscribeK {
val textId = if (it) R.string.su_snack_notif_on else R.string.su_snack_notif_off
val text = resources.getString(textId).format(item.appName)
val textId = if (it) R.string.su_snack_grant else R.string.su_snack_deny
val text = resources.getString(textId).format(item.item.appName)
SnackbarEvent(text).publish()
}
.add()
}
shouldLog.addOnPropertyChangedCallback {
it ?: return@addOnPropertyChangedCallback
item.logging = it
updatePolicy(item)
.map { it.logging }
.subscribeK {
val textId = if (it) R.string.su_snack_log_on else R.string.su_snack_log_off
val text = resources.getString(textId).format(item.appName)
SnackbarEvent(text).publish()
}
.add()
if (FingerprintHelper.useFingerprint()) {
withView {
FingerprintAuthDialog(this, { updateState() }, {
ignoreNext = item
item.isEnabled.toggle()
}).show()
}
} else {
updateState()
}
}