Make SettingsItems make much more sense
This commit is contained in:
parent
113eec59f9
commit
4c2570628d
@ -2,13 +2,10 @@ package com.topjohnwu.magisk.model.entity.recycler
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import androidx.annotation.ArrayRes
|
||||
import androidx.annotation.CallSuper
|
||||
import androidx.databinding.Bindable
|
||||
import androidx.databinding.ViewDataBinding
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
||||
import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.databinding.ObservableItem
|
||||
@ -30,30 +27,19 @@ sealed class SettingsItem : ObservableItem<SettingsItem>() {
|
||||
var isEnabled = true
|
||||
set(value) = set(value, field, { field = it }, BR.enabled)
|
||||
|
||||
protected open val isFullSpan get() = false
|
||||
|
||||
@CallSuper
|
||||
open fun onPressed(view: View, callback: Callback) {
|
||||
callback.onItemChanged(view, this)
|
||||
callback.onItemPressed(view, this)
|
||||
}
|
||||
|
||||
open fun refresh() {}
|
||||
|
||||
override fun onBindingBound(binding: ViewDataBinding) {
|
||||
super.onBindingBound(binding)
|
||||
if (isFullSpan) {
|
||||
val params = binding.root.layoutParams as? StaggeredGridLayoutManager.LayoutParams
|
||||
params?.isFullSpan = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun itemSameAs(other: SettingsItem) = this === other
|
||||
override fun contentSameAs(other: SettingsItem) = itemSameAs(other)
|
||||
|
||||
// ---
|
||||
|
||||
interface Callback {
|
||||
fun onItemPressed(view: View, item: SettingsItem, method: () -> Unit)
|
||||
fun onItemPressed(view: View, item: SettingsItem, callback: () -> Unit = {})
|
||||
fun onItemChanged(view: View, item: SettingsItem)
|
||||
}
|
||||
|
||||
@ -64,14 +50,38 @@ sealed class SettingsItem : ObservableItem<SettingsItem>() {
|
||||
@get:Bindable
|
||||
abstract var value: T
|
||||
|
||||
protected var callbackVars: Pair<View, Callback>? = null
|
||||
|
||||
@CallSuper
|
||||
override fun onPressed(view: View, callback: Callback) {
|
||||
callbackVars = view to callback
|
||||
callback.onItemPressed(view, this) {
|
||||
onPressed(view)
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun onPressed(view: View)
|
||||
|
||||
protected inline fun <reified T> setV(
|
||||
new: T, old: T, setter: (T) -> Unit, vararg fieldIds: Int) {
|
||||
set(new, old, setter, BR.value, *fieldIds)
|
||||
new: T, old: T, setter: (T) -> Unit, vararg fieldIds: Int, afterChanged: (T) -> Unit = {}) {
|
||||
set(new, old, setter, BR.value, *fieldIds) {
|
||||
afterChanged(it)
|
||||
callbackVars?.let { pair ->
|
||||
callbackVars = null
|
||||
pair.second.onItemChanged(pair.first, this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected inline fun <reified T> setV(
|
||||
new: T, old: T, setter: (T) -> Unit, afterChanged: (T) -> Unit = {}) {
|
||||
set(new, old, setter, BR.value, afterChanged = afterChanged)
|
||||
set(new, old, setter, BR.value) {
|
||||
afterChanged(it)
|
||||
callbackVars?.let { pair ->
|
||||
callbackVars = null
|
||||
pair.second.onItemChanged(pair.first, this)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,20 +89,9 @@ sealed class SettingsItem : ObservableItem<SettingsItem>() {
|
||||
|
||||
override val layoutRes = R.layout.item_settings_toggle
|
||||
|
||||
override fun onPressed(view: View, callback: Callback) {
|
||||
callback.onItemPressed(view, this) {
|
||||
value = !value
|
||||
super.onPressed(view, callback)
|
||||
}
|
||||
override fun onPressed(view: View) {
|
||||
value = !value
|
||||
}
|
||||
|
||||
fun onTouched(view: View, callback: Callback, event: MotionEvent): Boolean {
|
||||
if (event.action == MotionEvent.ACTION_UP) {
|
||||
onPressed(view, callback)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
abstract class Input : Value<String>(), KoinComponent {
|
||||
@ -103,29 +102,26 @@ sealed class SettingsItem : ObservableItem<SettingsItem>() {
|
||||
protected val resources get() = get<Resources>()
|
||||
protected abstract val intermediate: String?
|
||||
|
||||
override fun onPressed(view: View, callback: Callback) {
|
||||
callback.onItemPressed(view, this) {
|
||||
MagiskDialog(view.context)
|
||||
.applyTitle(title.getText(resources))
|
||||
.applyView(getView(view.context))
|
||||
.applyButton(MagiskDialog.ButtonType.POSITIVE) {
|
||||
titleRes = android.R.string.ok
|
||||
onClick {
|
||||
intermediate?.let { result ->
|
||||
preventDismiss = false
|
||||
value = result
|
||||
it.dismiss()
|
||||
super.onPressed(view, callback)
|
||||
return@onClick
|
||||
}
|
||||
preventDismiss = true
|
||||
override fun onPressed(view: View) {
|
||||
MagiskDialog(view.context)
|
||||
.applyTitle(title.getText(resources))
|
||||
.applyView(getView(view.context))
|
||||
.applyButton(MagiskDialog.ButtonType.POSITIVE) {
|
||||
titleRes = android.R.string.ok
|
||||
onClick {
|
||||
intermediate?.let { result ->
|
||||
preventDismiss = false
|
||||
value = result
|
||||
it.dismiss()
|
||||
return@onClick
|
||||
}
|
||||
preventDismiss = true
|
||||
}
|
||||
.applyButton(MagiskDialog.ButtonType.NEGATIVE) {
|
||||
titleRes = android.R.string.cancel
|
||||
}
|
||||
.reveal()
|
||||
}
|
||||
}
|
||||
.applyButton(MagiskDialog.ButtonType.NEGATIVE) {
|
||||
titleRes = android.R.string.cancel
|
||||
}
|
||||
.reveal()
|
||||
}
|
||||
|
||||
abstract fun getView(context: Context): View
|
||||
@ -150,7 +146,7 @@ sealed class SettingsItem : ObservableItem<SettingsItem>() {
|
||||
|
||||
protected inline fun <reified T> setS(
|
||||
new: T, old: T, setter: (T) -> Unit, afterChanged: (T) -> Unit = {}) {
|
||||
set(new, old, setter, BR.value, BR.selectedEntry, BR.description, afterChanged = afterChanged)
|
||||
setV(new, old, setter, BR.selectedEntry, BR.description, afterChanged = afterChanged)
|
||||
}
|
||||
|
||||
private fun Resources.getArrayOrEmpty(id: Int): Array<String> =
|
||||
@ -158,40 +154,29 @@ sealed class SettingsItem : ObservableItem<SettingsItem>() {
|
||||
|
||||
override fun onPressed(view: View, callback: Callback) {
|
||||
if (entries.isEmpty() || entryValues.isEmpty()) return
|
||||
callback.onItemPressed(view, this) {
|
||||
MagiskDialog(view.context)
|
||||
.applyTitle(title.getText(resources))
|
||||
.applyButton(MagiskDialog.ButtonType.NEGATIVE) {
|
||||
titleRes = android.R.string.cancel
|
||||
}
|
||||
.applyAdapter(entries) {
|
||||
value = it
|
||||
notifyPropertyChanged(BR.selectedEntry)
|
||||
super.onPressed(view, callback)
|
||||
}
|
||||
.reveal()
|
||||
}
|
||||
super.onPressed(view, callback)
|
||||
}
|
||||
|
||||
override fun onPressed(view: View) {
|
||||
MagiskDialog(view.context)
|
||||
.applyTitle(title.getText(resources))
|
||||
.applyButton(MagiskDialog.ButtonType.NEGATIVE) {
|
||||
titleRes = android.R.string.cancel
|
||||
}
|
||||
.applyAdapter(entries) {
|
||||
value = it
|
||||
}
|
||||
.reveal()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
abstract class Blank : SettingsItem() {
|
||||
|
||||
override val layoutRes = R.layout.item_settings_blank
|
||||
|
||||
override fun onPressed(view: View, callback: Callback) {
|
||||
callback.onItemPressed(view, this) {
|
||||
super.onPressed(view, callback)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
abstract class Section : SettingsItem() {
|
||||
|
||||
override val layoutRes = R.layout.item_settings_section
|
||||
override val isFullSpan get() = true
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -33,6 +33,12 @@ class SettingsViewModel(
|
||||
val itemBinding = itemBindingOf<SettingsItem> { it.bindExtra(BR.callback, this) }
|
||||
val items = diffListOf(createItems())
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
Language.loadLanguages(this)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createItems(): List<SettingsItem> {
|
||||
// Customization
|
||||
val list = mutableListOf(
|
||||
@ -44,9 +50,6 @@ class SettingsViewModel(
|
||||
// making theming a pain in the ass. Just forget about it
|
||||
list.remove(Theme)
|
||||
}
|
||||
viewModelScope.launch {
|
||||
Language.loadLanguages(this)
|
||||
}
|
||||
|
||||
// Manager
|
||||
list.addAll(listOf(
|
||||
@ -87,39 +90,34 @@ class SettingsViewModel(
|
||||
return list
|
||||
}
|
||||
|
||||
override fun onItemPressed(view: View, item: SettingsItem, method: () -> Unit) = when (item) {
|
||||
is DownloadPath -> withExternalRW(method)
|
||||
else -> method()
|
||||
override fun onItemPressed(view: View, item: SettingsItem, callback: () -> Unit) = when (item) {
|
||||
is DownloadPath -> withExternalRW(callback)
|
||||
is Biometrics -> authenticate(callback)
|
||||
is Theme -> SettingsFragmentDirections.actionSettingsFragmentToThemeFragment().publish()
|
||||
is ClearRepoCache -> clearRepoCache()
|
||||
is SystemlessHosts -> createHosts()
|
||||
is Restore -> restoreManager()
|
||||
else -> callback()
|
||||
}
|
||||
|
||||
override fun onItemChanged(view: View, item: SettingsItem) = when (item) {
|
||||
// use only instances you want, don't declare everything
|
||||
is Theme -> SettingsFragmentDirections.actionSettingsFragmentToThemeFragment().publish()
|
||||
is Language -> RecreateEvent().publish()
|
||||
|
||||
is UpdateChannel -> openUrlIfNecessary(view)
|
||||
is Biometrics -> authenticateOrRevert()
|
||||
is ClearRepoCache -> clearRepoCache()
|
||||
is SystemlessHosts -> createHosts()
|
||||
is Hide -> updateManager(hide = true)
|
||||
is Restore -> updateManager(hide = false)
|
||||
|
||||
is Hide -> PatchAPK.hideManager(view.context, item.value)
|
||||
else -> Unit
|
||||
}
|
||||
|
||||
private fun openUrlIfNecessary(view: View) {
|
||||
UpdateChannelUrl.refresh()
|
||||
if (UpdateChannelUrl.isEnabled && UpdateChannelUrl.value.isBlank()) {
|
||||
UpdateChannelUrl.onPressed(view, this@SettingsViewModel)
|
||||
UpdateChannelUrl.onPressed(view, this)
|
||||
}
|
||||
}
|
||||
|
||||
private fun authenticateOrRevert() {
|
||||
// immediately revert the preference
|
||||
Biometrics.value = !Biometrics.value
|
||||
private fun authenticate(callback: () -> Unit) {
|
||||
BiometricDialog {
|
||||
// allow the change on success
|
||||
onSuccess { Biometrics.value = !Biometrics.value }
|
||||
onSuccess { callback() }
|
||||
}.publish()
|
||||
}
|
||||
|
||||
@ -136,13 +134,9 @@ class SettingsViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateManager(hide: Boolean) {
|
||||
if (hide) {
|
||||
PatchAPK.hideManager(get(), Hide.value)
|
||||
} else {
|
||||
DownloadService(get()) {
|
||||
subject = DownloadSubject.Manager(Configuration.APK.Restore)
|
||||
}
|
||||
private fun restoreManager() {
|
||||
DownloadService(get()) {
|
||||
subject = DownloadSubject.Manager(Configuration.APK.Restore)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="@{item.enabled ? 1f : .5f}"
|
||||
android:onClick="@{(view) -> callback.onItemChanged(view, item)}"
|
||||
android:onClick="@{(view) -> item.onPressed(view, callback)}"
|
||||
tools:layout_gravity="center">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
@ -93,4 +93,4 @@
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
</layout>
|
||||
</layout>
|
||||
|
Loading…
Reference in New Issue
Block a user