Added (partially) settings screen

Most importantly added design and functionality backing for these items
This commit is contained in:
Viktor De Pasquale
2019-11-27 19:47:20 +01:00
parent 78d7c45be3
commit 73c4b21285
15 changed files with 699 additions and 145 deletions

View File

@@ -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

View File

@@ -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
}
}

View File

@@ -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) {
}

View File

@@ -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()