Commit 8737be26 authored by Viktor De Pasquale's avatar Viktor De Pasquale

Updated policy (apps) layout to be more compact

Added pinch in to increase list span count / out to decrease
  The setting will be remembered across the whole app (every list that uses Staggered Grid)
Updated indication of whether the policy has root access enabled permitted or not
  Displays crossed out app logo if not permitted
parent eb929160
......@@ -55,6 +55,7 @@ object Config : PreferenceModel, DBConfig {
const val SAFETY = "safety_notice"
const val THEME_ORDINAL = "theme_ordinal"
const val BOOT_ID = "boot_id"
const val LIST_SPAN_COUNT = "list_span_count"
// system state
const val MAGISKHIDE = "magiskhide"
......@@ -109,8 +110,7 @@ object Config : PreferenceModel, DBConfig {
Value.CANARY_DEBUG_CHANNEL
else
Value.CANARY_CHANNEL
}
else Value.DEFAULT_CHANNEL
} else Value.DEFAULT_CHANNEL
var bootId by preference(Key.BOOT_ID, "")
......@@ -137,6 +137,7 @@ object Config : PreferenceModel, DBConfig {
@JvmStatic
var coreOnly by preference(Key.COREONLY, false)
var showSystemApp by preference(Key.SHOW_SYSTEM_APP, false)
var listSpanCount by preference(Key.LIST_SPAN_COUNT, 2)
var customChannelUrl by preference(Key.CUSTOM_CHANNEL, "")
var locale by preference(Key.LOCALE, "")
......@@ -149,8 +150,9 @@ object Config : PreferenceModel, DBConfig {
var keyStoreRaw by dbStrings(Key.KEYSTORE, "", true)
// Always return a path in external storage where we can write
val downloadDirectory get() =
Utils.ensureDownloadPath(downloadPath) ?: get<Context>().getExternalFilesDir(null)!!
val downloadDirectory
get() =
Utils.ensureDownloadPath(downloadPath) ?: get<Context>().getExternalFilesDir(null)!!
private const val SU_FINGERPRINT = "su_fingerprint"
......
package com.topjohnwu.magisk.model.entity.recycler
import android.graphics.drawable.Drawable
import android.view.View
import android.view.ViewGroup
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.databinding.ComparableRvItem
import com.topjohnwu.magisk.extensions.addOnPropertyChangedCallback
......@@ -14,8 +12,6 @@ import com.topjohnwu.magisk.model.events.PolicyUpdateEvent
import com.topjohnwu.magisk.redesign.superuser.SuperuserViewModel
import com.topjohnwu.magisk.utils.KObservableField
import com.topjohnwu.magisk.utils.RxBus
import com.topjohnwu.magisk.utils.rotationTo
import com.topjohnwu.magisk.utils.setRevealed
class PolicyRvItem(val item: MagiskPolicy, val icon: Drawable) : ComparableRvItem<PolicyRvItem>() {
......@@ -73,18 +69,15 @@ class PolicyItem(val item: MagiskPolicy, val icon: Drawable) : ComparableRvItem<
fun toggle(viewModel: SuperuserViewModel) {
if (isExpanded.value) {
toggle()
return
}
isEnabled.toggle()
viewModel.togglePolicy(this, isEnabled.value)
}
fun toggle(view: View) {
fun toggle() {
isExpanded.toggle()
view.rotationTo(if (isExpanded.value) 225 else 180)
(view.parent as ViewGroup)
.findViewById<View>(R.id.policy_expand_container)
.setRevealed(isExpanded.value)
}
fun toggleNotify(viewModel: SuperuserViewModel) {
......
......@@ -19,6 +19,7 @@ import com.topjohnwu.magisk.redesign.compat.CompatFragment
import com.topjohnwu.magisk.redesign.compat.hideKeyboard
import com.topjohnwu.magisk.utils.EndlessRecyclerScrollListener
import com.topjohnwu.magisk.utils.MotionRevealHelper
import com.topjohnwu.magisk.utils.PinchZoomTouchListener
import org.koin.androidx.viewmodel.ext.android.viewModel
class ModuleFragment : CompatFragment<ModuleViewModel, FragmentModuleMd2Binding>(),
......@@ -67,13 +68,18 @@ class ModuleFragment : CompatFragment<ModuleViewModel, FragmentModuleMd2Binding>
if (newState != RecyclerView.SCROLL_STATE_IDLE) hideKeyboard()
}
})
PinchZoomTouchListener.attachTo(binding.moduleFilterInclude.moduleFilterList)
PinchZoomTouchListener.attachTo(binding.moduleList)
}
override fun onDestroyView() {
listeners.forEach {
binding.moduleRemote.removeOnScrollListener(it)
binding.moduleList.removeOnScrollListener(it)
binding.moduleFilterInclude.moduleFilterList.removeOnScrollListener(it)
}
PinchZoomTouchListener.clear(binding.moduleList)
PinchZoomTouchListener.clear(binding.moduleFilterInclude.moduleFilterList)
super.onDestroyView()
}
......@@ -101,14 +107,14 @@ class ModuleFragment : CompatFragment<ModuleViewModel, FragmentModuleMd2Binding>
// ---
override fun onReselected() {
binding.moduleRemote
binding.moduleList
.takeIf {
(it.layoutManager as? StaggeredGridLayoutManager)?.let {
it.findFirstVisibleItemPositions(IntArray(it.spanCount)).min()
} ?: 0 > 10
}
?.also { it.scrollToPosition(10) }
.let { binding.moduleRemote }
.let { binding.moduleList }
.also { it.post { it.smoothScrollToPosition(0) } }
}
......@@ -117,11 +123,11 @@ class ModuleFragment : CompatFragment<ModuleViewModel, FragmentModuleMd2Binding>
override fun onPreBind(binding: FragmentModuleMd2Binding) = Unit
private fun setEndlessScroller() {
val lama = binding.moduleRemote.layoutManager ?: return
val lama = binding.moduleList.layoutManager ?: return
lama.isAutoMeasureEnabled = false
val listener = EndlessRecyclerScrollListener(lama, viewModel::loadRemote)
binding.moduleRemote.addOnScrollListener(listener)
binding.moduleList.addOnScrollListener(listener)
listeners.add(listener)
}
......
package com.topjohnwu.magisk.redesign.settings
import android.graphics.Insets
import android.os.Bundle
import android.view.View
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.databinding.FragmentSettingsMd2Binding
import com.topjohnwu.magisk.redesign.compat.CompatFragment
import com.topjohnwu.magisk.utils.PinchZoomTouchListener
import org.koin.androidx.viewmodel.ext.android.viewModel
class SettingsFragment : CompatFragment<SettingsViewModel, FragmentSettingsMd2Binding>() {
......@@ -19,6 +22,16 @@ class SettingsFragment : CompatFragment<SettingsViewModel, FragmentSettingsMd2Bi
activity.title = resources.getString(R.string.section_settings)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
PinchZoomTouchListener.attachTo(binding.settingsList)
}
override fun onDestroyView() {
PinchZoomTouchListener.clear(binding.settingsList)
super.onDestroyView()
}
override fun onResume() {
super.onResume()
viewModel.items.forEach { it.refresh() }
......
package com.topjohnwu.magisk.redesign.superuser
import android.graphics.Insets
import android.os.Bundle
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.databinding.FragmentSuperuserMd2Binding
import com.topjohnwu.magisk.model.navigation.Navigation
import com.topjohnwu.magisk.redesign.compat.CompatFragment
import com.topjohnwu.magisk.utils.PinchZoomTouchListener
import org.koin.androidx.viewmodel.ext.android.viewModel
class SuperuserFragment : CompatFragment<SuperuserViewModel, FragmentSuperuserMd2Binding>() {
......@@ -23,6 +26,16 @@ class SuperuserFragment : CompatFragment<SuperuserViewModel, FragmentSuperuserMd
setHasOptionsMenu(true)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
PinchZoomTouchListener.attachTo(binding.superuserList)
}
override fun onDestroyView() {
PinchZoomTouchListener.clear(binding.superuserList)
super.onDestroyView()
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_superuser_md2, menu)
}
......
......@@ -448,4 +448,12 @@ fun View.setRotationNotAnimated(rotation: Int) {
@BindingAdapter("android:text")
fun TextView.setTextSafe(text: Int) {
if (text == 0) this.text = null else setText(text)
}
@BindingAdapter("android:onLongClick")
fun View.setOnLongClickListenerBinding(listener: () -> Unit) {
setOnLongClickListener {
listener()
true
}
}
\ No newline at end of file
package com.topjohnwu.magisk.utils
import android.view.ScaleGestureDetector
abstract class PinchGestureCallback : ScaleGestureDetector.SimpleOnScaleGestureListener() {
private var startFactor: Float = 1f
override fun onScaleBegin(detector: ScaleGestureDetector?): Boolean {
startFactor = detector?.scaleFactor ?: 1f
return super.onScaleBegin(detector)
}
override fun onScaleEnd(detector: ScaleGestureDetector?) {
val endFactor = detector?.scaleFactor ?: 1f
if (endFactor > startFactor) onZoom()
else if (endFactor < startFactor) onPinch()
}
abstract fun onPinch()
abstract fun onZoom()
}
\ No newline at end of file
package com.topjohnwu.magisk.utils
import android.annotation.SuppressLint
import android.view.MotionEvent
import android.view.ScaleGestureDetector
import android.view.View
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.StaggeredGridLayoutManager
import androidx.transition.TransitionManager
import com.topjohnwu.magisk.Config
import kotlin.math.max
import kotlin.math.min
class PinchZoomTouchListener private constructor(
private val view: RecyclerView,
private val max: Int = 3,
private val min: Int = 1
) : View.OnTouchListener {
private val layoutManager
get() = view.layoutManager
private val pinchListener = object : PinchGestureCallback() {
override fun onPinch() = updateSpanCount(Config.listSpanCount + 1)
override fun onZoom() = updateSpanCount(Config.listSpanCount - 1)
}
private val gestureDetector by lazy { ScaleGestureDetector(view.context, pinchListener) }
init {
updateSpanCount(Config.listSpanCount, false)
}
@SuppressLint("ClickableViewAccessibility")
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
gestureDetector.onTouchEvent(event)
return false
}
private fun updateSpanCount(count: Int, animate: Boolean = true) {
if (animate) {
TransitionManager.beginDelayedTransition(view)
}
val boundCount = max(min, min(max, count))
when (val l = layoutManager) {
is StaggeredGridLayoutManager -> l.spanCount = boundCount
is GridLayoutManager -> l.spanCount = boundCount
else -> Unit
}
Config.listSpanCount = boundCount
}
companion object {
@SuppressLint("ClickableViewAccessibility")
fun attachTo(view: RecyclerView) = view.setOnTouchListener(PinchZoomTouchListener(view))
fun clear(view: View) = view.setOnTouchListener(null)
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?colorOnSurface"
android:pathData="M16,17H7V10.5C7,8 9,6 11.5,6C14,6 16,8 16,10.5M18,16V10.5C18,7.43 15.86,4.86 13,4.18V3.5A1.5,1.5 0 0,0 11.5,2A1.5,1.5 0 0,0 10,3.5V4.18C7.13,4.86 5,7.43 5,10.5V16L3,18V19H20V18M11.5,22A2,2 0 0,0 13.5,20H9.5A2,2 0 0,0 11.5,22Z" />
</vector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?colorError"
android:pathData="M22.11 21.46L2.39 1.73L1.11 3L4.06 5.95C2.78 7.63 2 9.72 2 12C2 17.5 6.5 22 12 22C14.28 22 16.37 21.23 18.05 19.94L20.84 22.73L22.11 21.46M12 20C7.58 20 4 16.42 4 12C4 10.27 4.56 8.68 5.5 7.38L16.62 18.5C15.32 19.45 13.73 20 12 20M8.17 4.97L6.72 3.5C8.25 2.56 10.06 2 12 2C17.5 2 22 6.5 22 12C22 13.94 21.44 15.75 20.5 17.28L19.03 15.83C19.65 14.69 20 13.39 20 12C20 7.58 16.42 4 12 4C10.61 4 9.31 4.35 8.17 4.97Z" />
</vector>
\ No newline at end of file
......@@ -20,7 +20,7 @@
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/module_remote"
android:id="@+id/module_list"
adapter="@{viewModel.adapter}"
dividerHorizontal="@{R.drawable.divider_l1}"
dividerVertical="@{R.drawable.divider_l1}"
......
......@@ -19,6 +19,7 @@
dividerVertical="@{R.drawable.divider_l_50}"
itemBinding="@{viewModel.itemBinding}"
items="@{viewModel.items}"
android:id="@+id/settings_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusableInTouchMode="false"
......
......@@ -25,6 +25,7 @@
items="@{viewModel.items}"
nestedScrollingEnabled="@{false}"
android:layout_width="match_parent"
android:id="@+id/superuser_list"
android:layout_height="match_parent"
android:clipToPadding="false"
android:orientation="vertical"
......
This diff is collapsed.
......@@ -86,8 +86,8 @@
<string name="module_state_restore">Restore</string>
<string name="module_action_install_external">Install from storage</string>
<string name="superuser_toggle_log">Toggles logging</string>
<string name="superuser_toggle_notification">Toggles “toast” notifications</string>
<string name="superuser_toggle_log">Logs</string>
<string name="superuser_toggle_notification">Notifications</string>
<string name="superuser_toggle_revoke">Revoke</string>
<string name="hide_filter_hint">Filter by name</string>
......
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