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 ...@@ -5,7 +5,10 @@ import com.topjohnwu.magisk.BuildConfig
import com.topjohnwu.magisk.Config import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.extensions.get import com.topjohnwu.magisk.extensions.get
import com.topjohnwu.magisk.extensions.subscribeK
import com.topjohnwu.magisk.utils.asTransitive import com.topjohnwu.magisk.utils.asTransitive
import com.topjohnwu.magisk.utils.availableLocales
import com.topjohnwu.magisk.utils.currentLocale
// --- Customization // --- Customization
...@@ -13,6 +16,22 @@ object Customization : SettingsItem.Section() { ...@@ -13,6 +16,22 @@ object Customization : SettingsItem.Section() {
override val title = "Customization".asTransitive() 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() { object Redesign : SettingsItem.Toggle() {
override val title = "Redesign".asTransitive() override val title = "Redesign".asTransitive()
override val description = override val description =
...@@ -31,7 +50,6 @@ object Manager : SettingsItem.Section() { ...@@ -31,7 +50,6 @@ object Manager : SettingsItem.Section() {
override val title = R.string.manager.asTransitive() override val title = R.string.manager.asTransitive()
} }
object Language
object ClearRepoCache : SettingsItem.Blank() { object ClearRepoCache : SettingsItem.Blank() {
override val title = R.string.settings_clear_cache_title.asTransitive() override val title = R.string.settings_clear_cache_title.asTransitive()
override val description = R.string.settings_clear_cache_summary.asTransitive() override val description = R.string.settings_clear_cache_summary.asTransitive()
...@@ -51,8 +69,17 @@ object Restore : SettingsItem.Blank() { ...@@ -51,8 +69,17 @@ object Restore : SettingsItem.Blank() {
fun HideOrRestore() = fun HideOrRestore() =
if (get<Context>().packageName == BuildConfig.APPLICATION_ID) Hide else Restore if (get<Context>().packageName == BuildConfig.APPLICATION_ID) Hide else Restore
//todo new dialog
object DownloadPath 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() { object UpdateChecker : SettingsItem.Toggle() {
override val title = R.string.settings_check_update_title.asTransitive() override val title = R.string.settings_check_update_title.asTransitive()
override val description = R.string.settings_check_update_summary.asTransitive() override val description = R.string.settings_check_update_summary.asTransitive()
...@@ -95,9 +122,100 @@ object Superuser : SettingsItem.Section() { ...@@ -95,9 +122,100 @@ object Superuser : SettingsItem.Section() {
override val title = R.string.superuser.asTransitive() override val title = R.string.superuser.asTransitive()
} }
object AccessMode object AccessMode : SettingsItem.Selector() {
object MultiuserMode override val title = R.string.superuser_access.asTransitive()
object MountNamespaceMode override var value by dataObservable(Config.rootMode) {
object AutomaticResponse Config.rootMode = entryValues.getOrNull(it)
object RequestTimeout ?.toString()
object SUNotification ?.toInt() ?: return@dataObservable
\ No newline at end of file }
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 package com.topjohnwu.magisk.redesign.settings
import android.content.res.Resources
import android.view.MotionEvent import android.view.MotionEvent
import android.view.View import android.view.View
import androidx.annotation.CallSuper import androidx.annotation.CallSuper
...@@ -17,6 +18,8 @@ import com.topjohnwu.magisk.redesign.module.adapterOf ...@@ -17,6 +18,8 @@ import com.topjohnwu.magisk.redesign.module.adapterOf
import com.topjohnwu.magisk.redesign.superuser.diffListOf import com.topjohnwu.magisk.redesign.superuser.diffListOf
import com.topjohnwu.magisk.utils.TransitiveText import com.topjohnwu.magisk.utils.TransitiveText
import com.topjohnwu.magisk.view.MagiskDialog import com.topjohnwu.magisk.view.MagiskDialog
import org.koin.core.KoinComponent
import org.koin.core.get
import kotlin.properties.ObservableProperty import kotlin.properties.ObservableProperty
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
...@@ -25,15 +28,18 @@ class SettingsViewModel : CompatViewModel(), SettingsItem.Callback { ...@@ -25,15 +28,18 @@ class SettingsViewModel : CompatViewModel(), SettingsItem.Callback {
val adapter = adapterOf<SettingsItem>() val adapter = adapterOf<SettingsItem>()
val itemBinding = itemBindingOf<SettingsItem> { it.bindExtra(BR.callback, this) } val itemBinding = itemBindingOf<SettingsItem> { it.bindExtra(BR.callback, this) }
val items = diffListOf( val items = diffListOf(
// General Customization,
// Customization Theme, Language, Redesign,
Customization, Theme, Redesign,
// Manager Manager,
Manager, ClearRepoCache, HideOrRestore(), UpdateChecker, SystemlessHosts, Biometrics, ClearRepoCache, HideOrRestore(), UpdateChecker, SystemlessHosts, Biometrics,
// Magisk
Magisk, SafeMode, MagiskHide, Magisk,
// Superuser SafeMode, MagiskHide,
Superuser
Superuser,
AccessMode, MultiuserMode, MountNamespaceMode, AutomaticResponse, RequestTimeout,
SUNotification
) )
override fun onItemPressed(view: View, item: SettingsItem) = when (item) { override fun onItemPressed(view: View, item: SettingsItem) = when (item) {
...@@ -121,14 +127,49 @@ sealed class SettingsItem : ObservableItem<SettingsItem>() { ...@@ -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 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) { override fun onPressed(view: View, callback: Callback) {
if (entries.isEmpty() || entryValues.isEmpty()) return
MagiskDialog(view.context) MagiskDialog(view.context)
//.applyAdapter() .applyTitle(title.getText(resources))
super.onPressed(view, callback) .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 ...@@ -8,13 +8,22 @@ import android.graphics.drawable.Drawable
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.core.view.updateLayoutParams
import androidx.databinding.ViewDataBinding import androidx.databinding.ViewDataBinding
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.topjohnwu.magisk.BR 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.databinding.DialogMagiskBaseBinding
import com.topjohnwu.magisk.redesign.home.itemBindingOf
import com.topjohnwu.magisk.utils.KObservableField import com.topjohnwu.magisk.utils.KObservableField
import me.tatarka.bindingcollectionadapter2.BindingRecyclerViewAdapters
import me.tatarka.bindingcollectionadapter2.ItemBinding
class MagiskDialog @JvmOverloads constructor( class MagiskDialog @JvmOverloads constructor(
context: Context, theme: Int = 0 context: Context, theme: Int = 0
...@@ -138,20 +147,57 @@ class MagiskDialog @JvmOverloads constructor( ...@@ -138,20 +147,57 @@ class MagiskDialog @JvmOverloads constructor(
ButtonBuilder(button).apply(builder) 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 { fun cancellable(isCancellable: Boolean) = apply {
setCancelable(isCancellable) setCancelable(isCancellable)
} }
fun <Binding : ViewDataBinding> applyView(binding: Binding, body: Binding.() -> Unit = {}) = fun <Binding : ViewDataBinding> applyView(
apply { binding: Binding,
resetView() body: Binding.() -> Unit = {}
this.binding.dialogBaseContainer.addView(binding.root) ) = applyView(binding.root).also { binding.apply(body) }
binding.apply(body)
}
fun applyView(view: View) = apply { fun applyView(view: View) = apply {
resetView() 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) = fun onDismiss(callback: OnDialogButtonClickListener) =
...@@ -203,4 +249,5 @@ class MagiskDialog @JvmOverloads constructor( ...@@ -203,4 +249,5 @@ class MagiskDialog @JvmOverloads constructor(
//endregion //endregion
} }
typealias OnDialogButtonClickListener = (DialogInterface) -> Unit typealias OnDialogButtonClickListener = (DialogInterface) -> Unit
\ No newline at end of file typealias OnDialogClickListener = (position: Int) -> Unit
\ No newline at end of file
...@@ -93,6 +93,7 @@ ...@@ -93,6 +93,7 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_constrainedHeight="true" app:layout_constrainedHeight="true"
android:layout_marginTop="@dimen/l_50"
app:layout_constraintBottom_toTopOf="@+id/dialog_base_space" app:layout_constraintBottom_toTopOf="@+id/dialog_base_space"
app:layout_constraintLeft_toLeftOf="@+id/dialog_base_start" app:layout_constraintLeft_toLeftOf="@+id/dialog_base_start"
app:layout_constraintRight_toRightOf="@+id/dialog_base_end" app:layout_constraintRight_toRightOf="@+id/dialog_base_end"
...@@ -108,7 +109,6 @@ ...@@ -108,7 +109,6 @@
gone="@{data.message.length == 0}" gone="@{data.message.length == 0}"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="@dimen/l_50"
android:gravity="center" android:gravity="center"
android:text="@{data.message}" android:text="@{data.message}"
android:textAppearance="@style/AppearanceFoundation.Body" 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 @@ ...@@ -19,7 +19,7 @@
style="@style/WidgetFoundation.Card" style="@style/WidgetFoundation.Card"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:onClick="@{(view) -> callback.onItemPressed(view, item)}" android:onClick="@{(view) -> item.onPressed(view, callback)}"
tools:layout_gravity="center"> tools:layout_gravity="center">
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
...@@ -57,6 +57,7 @@ ...@@ -57,6 +57,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center_vertical" android:gravity="center_vertical"
android:orientation="vertical" android:orientation="vertical"
android:layout_marginStart="@{item.icon == 0 ? (int) @dimen/l1 : 0}"
android:paddingTop="@dimen/l1" android:paddingTop="@dimen/l1"
android:paddingBottom="@dimen/l1" android:paddingBottom="@dimen/l1"
app:layout_constraintBottom_toTopOf="@+id/selector_divider" app:layout_constraintBottom_toTopOf="@+id/selector_divider"
...@@ -69,7 +70,6 @@ ...@@ -69,7 +70,6 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:layout_marginStart="@{item.icon == 0 ? (int) @dimen/l1 : 0}"
android:gravity="start" android:gravity="start"
android:text="@{item.title}" android:text="@{item.title}"
android:textAppearance="@style/AppearanceFoundation.Body" android:textAppearance="@style/AppearanceFoundation.Body"
...@@ -91,18 +91,23 @@ ...@@ -91,18 +91,23 @@
<View <View
android:id="@+id/selector_divider" android:id="@+id/selector_divider"
gone="@{item.selectedEntry == null}"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="1.25dp" android:layout_height="1dp"
android:background="?colorOnSurfaceVariant" android:background="?colorSurface"
app:layout_constraintTop_toBottomOf="@+id/selector_text" /> app:layout_constraintTop_toBottomOf="@+id/selector_text" />
<androidx.appcompat.widget.AppCompatTextView <androidx.appcompat.widget.AppCompatTextView
android:id="@+id/selector_selection" android:id="@+id/selector_selection"
gone="@{item.selectedEntry == null}"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="@dimen/l1" android:layout_marginStart="@dimen/l1"
android:textAppearance="@style/AppearanceFoundation.Caption.Variant" android:layout_marginTop="@dimen/l_75"
android:textStyle="bold" 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_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="@+id/selector_text" app:layout_constraintStart_toStartOf="@+id/selector_text"
app:layout_constraintTop_toBottomOf="@+id/selector_divider" 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