Commit cb96b536 authored by Viktor De Pasquale's avatar Viktor De Pasquale

Added fair amount of settings implemented from the UI side

Updated dialog to create recycler as it behaves better than regular listview
parent 627b4079
......@@ -5,7 +5,10 @@ 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.extensions.subscribeK
import com.topjohnwu.magisk.utils.asTransitive
import com.topjohnwu.magisk.utils.availableLocales
import com.topjohnwu.magisk.utils.currentLocale
// --- Customization
......@@ -13,6 +16,22 @@ object Customization : SettingsItem.Section() {
override val title = "Customization".asTransitive()
}
object Language : SettingsItem.Selector() {
override var value by dataObservable(0) {
Config.locale = entryValues.getOrNull(it)?.toString() ?: return@dataObservable
}
override val title = R.string.language.asTransitive()
init {
availableLocales.subscribeK { (names, values) ->
setValues(names, values)
val selectedLocale = currentLocale.getDisplayName(currentLocale)
value = names.indexOfFirst { it == selectedLocale }.let { if (it == -1) 0 else it }
}
}
}
object Redesign : SettingsItem.Toggle() {
override val title = "Redesign".asTransitive()
override val description =
......@@ -31,7 +50,6 @@ 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()
......@@ -51,8 +69,17 @@ object Restore : SettingsItem.Blank() {
fun HideOrRestore() =
if (get<Context>().packageName == BuildConfig.APPLICATION_ID) Hide else Restore
//todo new dialog
object DownloadPath
object UpdateChannel
//fixme this
object UpdateChannel : SettingsItem.Selector() {
override var value by dataObservable(Config.updateChannel) { Config.updateChannel = it }
}
//fixme new dialog
object UpdateChannelUrl
object UpdateChecker : SettingsItem.Toggle() {
override val title = R.string.settings_check_update_title.asTransitive()
override val description = R.string.settings_check_update_summary.asTransitive()
......@@ -95,9 +122,100 @@ object Superuser : SettingsItem.Section() {
override val title = R.string.superuser.asTransitive()
}
object AccessMode
object MultiuserMode
object MountNamespaceMode
object AutomaticResponse
object RequestTimeout
object SUNotification
\ No newline at end of file
object AccessMode : SettingsItem.Selector() {
override val title = R.string.superuser_access.asTransitive()
override var value by dataObservable(Config.rootMode) {
Config.rootMode = entryValues.getOrNull(it)
?.toString()
?.toInt() ?: return@dataObservable
}
init {
setValues(
resources.getStringArray(R.array.su_access),
resources.getStringArray(R.array.value_array)
)
}
}
object MultiuserMode : SettingsItem.Selector() {
override val title = R.string.multiuser_mode.asTransitive()
override var value by dataObservable(Config.suMultiuserMode) {
Config.suMultiuserMode = entryValues.getOrNull(it)
?.toString()
?.toInt() ?: return@dataObservable
}
init {
setValues(
resources.getStringArray(R.array.multiuser_mode),
resources.getStringArray(R.array.value_array)
)
}
}
object MountNamespaceMode : SettingsItem.Selector() {
override val title = R.string.mount_namespace_mode.asTransitive()
override var value by dataObservable(Config.suMntNamespaceMode) {
Config.suMntNamespaceMode = entryValues.getOrNull(it)
?.toString()
?.toInt() ?: return@dataObservable
}
init {
setValues(
resources.getStringArray(R.array.namespace),
resources.getStringArray(R.array.value_array)
)
}
}
object AutomaticResponse : SettingsItem.Selector() {
override val title = R.string.auto_response.asTransitive()
override var value by dataObservable(Config.suAutoReponse) {
Config.suAutoReponse = entryValues.getOrNull(it)
?.toString()
?.toInt() ?: return@dataObservable
}
init {
setValues(
resources.getStringArray(R.array.auto_response),
resources.getStringArray(R.array.value_array)
)
}
}
object RequestTimeout : SettingsItem.Selector() {
override val title = R.string.request_timeout.asTransitive()
override var value by dataObservable(-1) {
Config.suDefaultTimeout = entryValues.getOrNull(it)
?.toString()
?.toInt() ?: return@dataObservable
}
init {
setValues(
resources.getStringArray(R.array.request_timeout),
resources.getStringArray(R.array.request_timeout_value)
)
val currentValue = Config.suDefaultTimeout.toString()
value = entryValues.indexOfFirst { it == currentValue }
}
}
object SUNotification : SettingsItem.Selector() {
override val title = R.string.superuser_notification.asTransitive()
override var value by dataObservable(Config.suNotification) {
Config.suNotification = entryValues.getOrNull(it)
?.toString()
?.toInt() ?: return@dataObservable
}
init {
setValues(
resources.getStringArray(R.array.su_notification),
resources.getStringArray(R.array.value_array)
)
}
}
\ No newline at end of file
package com.topjohnwu.magisk.redesign.settings
import android.content.res.Resources
import android.view.MotionEvent
import android.view.View
import androidx.annotation.CallSuper
......@@ -17,6 +18,8 @@ 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 org.koin.core.KoinComponent
import org.koin.core.get
import kotlin.properties.ObservableProperty
import kotlin.reflect.KProperty
......@@ -25,15 +28,18 @@ class SettingsViewModel : CompatViewModel(), SettingsItem.Callback {
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
Customization,
Theme, Language, Redesign,
Manager,
ClearRepoCache, HideOrRestore(), UpdateChecker, SystemlessHosts, Biometrics,
Magisk,
SafeMode, MagiskHide,
Superuser,
AccessMode, MultiuserMode, MountNamespaceMode, AutomaticResponse, RequestTimeout,
SUNotification
)
override fun onItemPressed(view: View, item: SettingsItem) = when (item) {
......@@ -121,14 +127,49 @@ sealed class SettingsItem : ObservableItem<SettingsItem>() {
}
abstract class Selector : Value<Int>() {
abstract class Selector : Value<Int>(), KoinComponent {
override val layoutRes = R.layout.item_settings_selector
protected val resources get() = get<Resources>()
@Bindable
var entries: Array<out CharSequence> = arrayOf()
private set
@Bindable
var entryValues: Array<out CharSequence> = arrayOf()
private set
val selectedEntry
@Bindable get() = entries.getOrNull(value)
fun setValues(
entries: Array<out CharSequence>,
values: Array<out CharSequence>
) {
check(entries.size <= values.size) { "List sizes must match" }
this.entries = entries
this.entryValues = values
notifyChange(BR.entries)
notifyChange(BR.entryValues)
notifyChange(BR.selectedEntry)
}
override fun onPressed(view: View, callback: Callback) {
if (entries.isEmpty() || entryValues.isEmpty()) return
MagiskDialog(view.context)
//.applyAdapter()
super.onPressed(view, callback)
.applyTitle(title.getText(resources))
.applyButton(MagiskDialog.ButtonType.NEGATIVE) {
titleRes = android.R.string.cancel
}
.applyAdapter(entries) {
value = it
notifyChange(BR.selectedEntry)
super.onPressed(view, callback)
}
.reveal()
}
}
......
......@@ -8,13 +8,22 @@ import android.graphics.drawable.Drawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.appcompat.app.AlertDialog
import androidx.core.view.updateLayoutParams
import androidx.databinding.ViewDataBinding
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.databinding.ComparableRvItem
import com.topjohnwu.magisk.databinding.DialogMagiskBaseBinding
import com.topjohnwu.magisk.redesign.home.itemBindingOf
import com.topjohnwu.magisk.utils.KObservableField
import me.tatarka.bindingcollectionadapter2.BindingRecyclerViewAdapters
import me.tatarka.bindingcollectionadapter2.ItemBinding
class MagiskDialog @JvmOverloads constructor(
context: Context, theme: Int = 0
......@@ -138,20 +147,57 @@ class MagiskDialog @JvmOverloads constructor(
ButtonBuilder(button).apply(builder)
}
class DialogItem(
val item: CharSequence,
val position: Int
) : ComparableRvItem<DialogItem>() {
override val layoutRes = R.layout.item_list_single_line
override fun itemSameAs(other: DialogItem) = item == other.item
override fun contentSameAs(other: DialogItem) = itemSameAs(other)
}
interface ActualOnDialogClickListener {
fun onClick(position: Int)
}
fun applyAdapter(
list: Array<out CharSequence>,
listener: OnDialogClickListener
) = applyView(
RecyclerView(context).also {
it.isNestedScrollingEnabled = false
it.layoutManager = LinearLayoutManager(context)
val actualListener = object : ActualOnDialogClickListener {
override fun onClick(position: Int) {
listener(position)
dismiss()
}
}
val items = list.mapIndexed { i, it -> DialogItem(it, i) }
val binding = itemBindingOf<DialogItem> { it.bindExtra(BR.listener, actualListener) }
.let { ItemBinding.of(it) }
BindingRecyclerViewAdapters.setAdapter(it, binding, items, null, null, null, null)
}
)
fun cancellable(isCancellable: Boolean) = apply {
setCancelable(isCancellable)
}
fun <Binding : ViewDataBinding> applyView(binding: Binding, body: Binding.() -> Unit = {}) =
apply {
resetView()
this.binding.dialogBaseContainer.addView(binding.root)
binding.apply(body)
}
fun <Binding : ViewDataBinding> applyView(
binding: Binding,
body: Binding.() -> Unit = {}
) = applyView(binding.root).also { binding.apply(body) }
fun applyView(view: View) = apply {
resetView()
this.binding.dialogBaseContainer.addView(view)
binding.dialogBaseContainer.addView(view)
view.updateLayoutParams<ViewGroup.LayoutParams> {
width = ViewGroup.LayoutParams.MATCH_PARENT
height = ViewGroup.LayoutParams.WRAP_CONTENT
}
}
fun onDismiss(callback: OnDialogButtonClickListener) =
......@@ -203,4 +249,5 @@ class MagiskDialog @JvmOverloads constructor(
//endregion
}
typealias OnDialogButtonClickListener = (DialogInterface) -> Unit
\ No newline at end of file
typealias OnDialogButtonClickListener = (DialogInterface) -> Unit
typealias OnDialogClickListener = (position: Int) -> Unit
\ No newline at end of file
......@@ -93,6 +93,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constrainedHeight="true"
android:layout_marginTop="@dimen/l_50"
app:layout_constraintBottom_toTopOf="@+id/dialog_base_space"
app:layout_constraintLeft_toLeftOf="@+id/dialog_base_start"
app:layout_constraintRight_toRightOf="@+id/dialog_base_end"
......@@ -108,7 +109,6 @@
gone="@{data.message.length == 0}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/l_50"
android:gravity="center"
android:text="@{data.message}"
android:textAppearance="@style/AppearanceFoundation.Body"
......
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="item"
type="com.topjohnwu.magisk.view.MagiskDialog.DialogItem" />
<variable
name="listener"
type="com.topjohnwu.magisk.view.MagiskDialog.ActualOnDialogClickListener" />
</data>
<androidx.appcompat.widget.AppCompatTextView
android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?selectableItemBackground"
android:onClick="@{() -> listener.onClick(item.position)}"
android:paddingStart="@dimen/l1"
android:paddingTop="@dimen/l_75"
android:paddingEnd="@dimen/l1"
android:paddingBottom="@dimen/l_75"
android:text="@{item.item}"
android:textAppearance="@style/AppearanceFoundation.Body"
tools:text="@tools:sample/lorem" />
</layout>
\ No newline at end of file
......@@ -19,7 +19,7 @@
style="@style/WidgetFoundation.Card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="@{(view) -> callback.onItemPressed(view, item)}"
android:onClick="@{(view) -> item.onPressed(view, callback)}"
tools:layout_gravity="center">
<androidx.constraintlayout.widget.ConstraintLayout
......@@ -57,6 +57,7 @@
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="vertical"
android:layout_marginStart="@{item.icon == 0 ? (int) @dimen/l1 : 0}"
android:paddingTop="@dimen/l1"
android:paddingBottom="@dimen/l1"
app:layout_constraintBottom_toTopOf="@+id/selector_divider"
......@@ -69,7 +70,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="@{item.icon == 0 ? (int) @dimen/l1 : 0}"
android:gravity="start"
android:text="@{item.title}"
android:textAppearance="@style/AppearanceFoundation.Body"
......@@ -91,18 +91,23 @@
<View
android:id="@+id/selector_divider"
gone="@{item.selectedEntry == null}"
android:layout_width="match_parent"
android:layout_height="1.25dp"
android:background="?colorOnSurfaceVariant"
android:layout_height="1dp"
android:background="?colorSurface"
app:layout_constraintTop_toBottomOf="@+id/selector_text" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/selector_selection"
gone="@{item.selectedEntry == null}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/l1"
android:textAppearance="@style/AppearanceFoundation.Caption.Variant"
android:textStyle="bold"
android:layout_marginStart="@dimen/l1"
android:layout_marginTop="@dimen/l_75"
android:layout_marginEnd="@dimen/l1"
android:layout_marginBottom="@dimen/l_75"
android:text="@{item.selectedEntry}"
android:textAppearance="@style/AppearanceFoundation.Tiny.Variant"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="@+id/selector_text"
app:layout_constraintTop_toBottomOf="@+id/selector_divider"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment