mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-12-30 15:26:09 +00:00
Added (partially) settings screen
Most importantly added design and functionality backing for these items
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
package com.topjohnwu.magisk.redesign.settings
|
||||
|
||||
import android.content.Context
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.Config
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.extensions.get
|
||||
import com.topjohnwu.magisk.utils.asTransitive
|
||||
|
||||
// --- Customization
|
||||
|
||||
object Customization : SettingsItem.Section() {
|
||||
override val title = "Customization".asTransitive()
|
||||
}
|
||||
|
||||
object Redesign : SettingsItem.Toggle() {
|
||||
override val title = "Redesign".asTransitive()
|
||||
override val description =
|
||||
"Select this to disable redesign. App will automatically shut down".asTransitive()
|
||||
override var value: Boolean by dataObservable(Config.redesign) { Config.redesign = it }
|
||||
}
|
||||
|
||||
object Theme : SettingsItem.Blank() {
|
||||
override val icon = R.drawable.ic_paint
|
||||
override val title = R.string.section_theme.asTransitive()
|
||||
}
|
||||
|
||||
// --- Manager
|
||||
|
||||
object Manager : SettingsItem.Section() {
|
||||
override val title = R.string.manager.asTransitive()
|
||||
}
|
||||
|
||||
object Language
|
||||
object ClearRepoCache : SettingsItem.Blank() {
|
||||
override val title = R.string.settings_clear_cache_title.asTransitive()
|
||||
override val description = R.string.settings_clear_cache_summary.asTransitive()
|
||||
}
|
||||
|
||||
object Hide : SettingsItem.Blank() {
|
||||
override val title = R.string.settings_hide_manager_title.asTransitive()
|
||||
override val description = R.string.settings_hide_manager_summary.asTransitive()
|
||||
}
|
||||
|
||||
object Restore : SettingsItem.Blank() {
|
||||
override val title = R.string.settings_restore_manager_title.asTransitive()
|
||||
override val description = R.string.settings_restore_manager_summary.asTransitive()
|
||||
}
|
||||
|
||||
@Suppress("FunctionName")
|
||||
fun HideOrRestore() =
|
||||
if (get<Context>().packageName == BuildConfig.APPLICATION_ID) Hide else Restore
|
||||
|
||||
object DownloadPath
|
||||
object UpdateChannel
|
||||
object UpdateChecker : SettingsItem.Toggle() {
|
||||
override val title = R.string.settings_check_update_title.asTransitive()
|
||||
override val description = R.string.settings_check_update_summary.asTransitive()
|
||||
override var value by dataObservable(Config.checkUpdate) { Config.checkUpdate = it }
|
||||
}
|
||||
|
||||
// check whether is module already installed beforehand?
|
||||
object SystemlessHosts : SettingsItem.Blank() {
|
||||
override val title = R.string.settings_hosts_title.asTransitive()
|
||||
override val description = R.string.settings_hosts_summary.asTransitive()
|
||||
}
|
||||
|
||||
object Biometrics : SettingsItem.Toggle() {
|
||||
override val title = R.string.settings_su_biometric_title.asTransitive()
|
||||
override val description = R.string.settings_su_biometric_summary.asTransitive()
|
||||
override var value by dataObservable(Config.suBiometric) { Config.suBiometric = it }
|
||||
}
|
||||
|
||||
// --- Magisk
|
||||
|
||||
object Magisk : SettingsItem.Section() {
|
||||
override val title = R.string.magisk.asTransitive()
|
||||
}
|
||||
|
||||
object SafeMode : SettingsItem.Toggle() {
|
||||
override val title = R.string.settings_core_only_title.asTransitive()
|
||||
override val description = R.string.settings_core_only_summary.asTransitive()
|
||||
override var value by dataObservable(Config.coreOnly) { Config.coreOnly = it }
|
||||
}
|
||||
|
||||
object MagiskHide : SettingsItem.Toggle() {
|
||||
override val title = R.string.magiskhide.asTransitive()
|
||||
override val description = R.string.settings_magiskhide_summary.asTransitive()
|
||||
override var value by dataObservable(Config.magiskHide) { Config.magiskHide = it }
|
||||
}
|
||||
|
||||
// --- Superuser
|
||||
|
||||
object Superuser : SettingsItem.Section() {
|
||||
override val title = R.string.superuser.asTransitive()
|
||||
}
|
||||
|
||||
object AccessMode
|
||||
object MultiuserMode
|
||||
object MountNamespaceMode
|
||||
object AutomaticResponse
|
||||
object RequestTimeout
|
||||
object SUNotification
|
||||
@@ -1,26 +1,149 @@
|
||||
package com.topjohnwu.magisk.redesign.settings
|
||||
|
||||
import com.topjohnwu.magisk.Config
|
||||
import com.topjohnwu.magisk.extensions.addOnPropertyChangedCallback
|
||||
import com.topjohnwu.magisk.extensions.toggle
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
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.model.entity.recycler.ObservableItem
|
||||
import com.topjohnwu.magisk.model.events.DieEvent
|
||||
import com.topjohnwu.magisk.model.navigation.Navigation
|
||||
import com.topjohnwu.magisk.redesign.compat.CompatViewModel
|
||||
import com.topjohnwu.magisk.utils.KObservableField
|
||||
import com.topjohnwu.magisk.redesign.home.itemBindingOf
|
||||
import com.topjohnwu.magisk.redesign.module.adapterOf
|
||||
import com.topjohnwu.magisk.redesign.superuser.diffListOf
|
||||
import com.topjohnwu.magisk.utils.TransitiveText
|
||||
import com.topjohnwu.magisk.view.MagiskDialog
|
||||
import kotlin.properties.ObservableProperty
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
class SettingsViewModel : CompatViewModel() {
|
||||
class SettingsViewModel : CompatViewModel(), SettingsItem.Callback {
|
||||
|
||||
val redesign = KObservableField(Config.redesign)
|
||||
val adapter = adapterOf<SettingsItem>()
|
||||
val itemBinding = itemBindingOf<SettingsItem> { it.bindExtra(BR.callback, this) }
|
||||
val items = diffListOf(
|
||||
// General
|
||||
// Customization
|
||||
Customization, Theme, Redesign,
|
||||
// Manager
|
||||
Manager, ClearRepoCache, HideOrRestore(), UpdateChecker, SystemlessHosts, Biometrics,
|
||||
// Magisk
|
||||
Magisk, SafeMode, MagiskHide,
|
||||
// Superuser
|
||||
Superuser
|
||||
)
|
||||
|
||||
init {
|
||||
//todo make observable preference
|
||||
redesign.addOnPropertyChangedCallback {
|
||||
Config.redesign = redesign.value
|
||||
DieEvent().publish()
|
||||
override fun onItemPressed(view: View, item: SettingsItem) = when (item) {
|
||||
// use only instances you want, don't declare everything
|
||||
Theme -> Navigation.theme().publish()
|
||||
Redesign -> DieEvent().publish()
|
||||
else -> Unit
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sealed class SettingsItem : ObservableItem<SettingsItem>() {
|
||||
|
||||
@Bindable
|
||||
open val icon: Int = 0
|
||||
@Bindable
|
||||
open val title: TransitiveText = TransitiveText.empty
|
||||
@Bindable
|
||||
open val description: TransitiveText = TransitiveText.empty
|
||||
|
||||
protected open val isFullSpan: Boolean = false
|
||||
|
||||
@CallSuper
|
||||
open fun onPressed(view: View, callback: Callback) {
|
||||
callback.onItemPressed(view, this)
|
||||
|
||||
// notify only after the callback invocation; callback can invalidate the backing data,
|
||||
// which wouldn't be recognized with reverse approach
|
||||
notifyChange(BR.icon)
|
||||
notifyChange(BR.title)
|
||||
notifyChange(BR.description)
|
||||
}
|
||||
|
||||
override fun onBindingBound(binding: ViewDataBinding) {
|
||||
super.onBindingBound(binding)
|
||||
if (isFullSpan) {
|
||||
val params = binding.root.layoutParams as? StaggeredGridLayoutManager.LayoutParams
|
||||
params?.isFullSpan = true
|
||||
}
|
||||
}
|
||||
|
||||
fun toggle(item: KObservableField<Boolean>) = item.toggle()
|
||||
fun themePressed() = Navigation.theme().publish()
|
||||
override fun itemSameAs(other: SettingsItem) = this === other
|
||||
override fun contentSameAs(other: SettingsItem) = itemSameAs(other)
|
||||
|
||||
// ---
|
||||
|
||||
interface Callback {
|
||||
fun onItemPressed(view: View, item: SettingsItem)
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
abstract class Value<T> : SettingsItem() {
|
||||
|
||||
abstract var value: T
|
||||
@Bindable get
|
||||
|
||||
protected inline fun dataObservable(
|
||||
initialValue: T,
|
||||
crossinline setter: (T) -> Unit
|
||||
) = object : ObservableProperty<T>(initialValue) {
|
||||
override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) {
|
||||
setter(newValue)
|
||||
notifyChange(BR.value)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
abstract class Toggle : Value<Boolean>() {
|
||||
|
||||
override val layoutRes = R.layout.item_settings_toggle
|
||||
|
||||
override fun onPressed(view: View, callback: Callback) {
|
||||
value = !value
|
||||
super.onPressed(view, callback)
|
||||
}
|
||||
|
||||
fun onTouched(view: View, callback: Callback, event: MotionEvent): Boolean {
|
||||
if (event.action == MotionEvent.ACTION_UP) {
|
||||
onPressed(view, callback)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
abstract class Selector : Value<Int>() {
|
||||
|
||||
override val layoutRes = R.layout.item_settings_selector
|
||||
|
||||
override fun onPressed(view: View, callback: Callback) {
|
||||
MagiskDialog(view.context)
|
||||
//.applyAdapter()
|
||||
super.onPressed(view, callback)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
abstract class Blank : SettingsItem() {
|
||||
|
||||
override val layoutRes = R.layout.item_settings_blank
|
||||
|
||||
}
|
||||
|
||||
abstract class Section : SettingsItem() {
|
||||
|
||||
override val layoutRes = R.layout.item_settings_section
|
||||
override val isFullSpan = true
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -296,18 +296,24 @@ fun TextSwitcher.setTextBinding(text: CharSequence) {
|
||||
"android:layout_marginTop",
|
||||
"android:layout_marginRight",
|
||||
"android:layout_marginBottom",
|
||||
"android:layout_marginStart",
|
||||
"android:layout_marginEnd",
|
||||
requireAll = false
|
||||
)
|
||||
fun View.setMargins(
|
||||
marginLeft: Int?,
|
||||
marginTop: Int?,
|
||||
marginRight: Int?,
|
||||
marginBottom: Int?
|
||||
marginBottom: Int?,
|
||||
marginStart: Int?,
|
||||
marginEnd: Int?
|
||||
) = updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
marginLeft?.let { leftMargin = it }
|
||||
marginTop?.let { topMargin = it }
|
||||
marginRight?.let { rightMargin = it }
|
||||
marginBottom?.let { bottomMargin = it }
|
||||
marginStart?.let { this.marginStart = it }
|
||||
marginEnd?.let { this.marginEnd = it }
|
||||
}
|
||||
|
||||
@BindingAdapter("nestedScrollingEnabled")
|
||||
@@ -455,9 +461,4 @@ fun View.setRotationNotAnimated(rotation: Int) {
|
||||
@BindingAdapter("android:text")
|
||||
fun TextView.setTextSafe(text: Int) {
|
||||
if (text == 0) this.text = null else setText(text)
|
||||
}
|
||||
|
||||
@BindingAdapter("android:theme")
|
||||
fun View.setThemeCompat(theme: Int) {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.topjohnwu.magisk.utils
|
||||
|
||||
import android.content.res.Resources
|
||||
import android.widget.TextView
|
||||
import androidx.databinding.BindingAdapter
|
||||
import androidx.databinding.InverseBindingAdapter
|
||||
|
||||
sealed class TransitiveText {
|
||||
|
||||
abstract val isEmpty: Boolean
|
||||
abstract fun getText(resources: Resources): CharSequence
|
||||
|
||||
// ---
|
||||
|
||||
class String(
|
||||
private val value: CharSequence
|
||||
) : TransitiveText() {
|
||||
|
||||
override val isEmpty = value.isEmpty()
|
||||
override fun getText(resources: Resources) = value
|
||||
|
||||
}
|
||||
|
||||
class Res(
|
||||
private val value: Int,
|
||||
private vararg val params: Any
|
||||
) : TransitiveText() {
|
||||
|
||||
override val isEmpty = value == 0
|
||||
override fun getText(resources: Resources) =
|
||||
resources.getString(value, *params)
|
||||
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
companion object {
|
||||
val empty = String("")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
fun Int.asTransitive(vararg params: Any) = TransitiveText.Res(this, *params)
|
||||
fun CharSequence.asTransitive() = TransitiveText.String(this)
|
||||
|
||||
|
||||
@BindingAdapter("android:text")
|
||||
fun TextView.setText(text: TransitiveText) {
|
||||
this.text = text.getText(resources)
|
||||
}
|
||||
|
||||
@InverseBindingAdapter(attribute = "android:text", event = "android:textAttrChanged")
|
||||
fun TextView.getTransitiveText() = text.asTransitive()
|
||||
Reference in New Issue
Block a user