diff --git a/app/src/main/java/com/topjohnwu/magisk/Config.kt b/app/src/main/java/com/topjohnwu/magisk/Config.kt index 07595d902..2cbb18d56 100644 --- a/app/src/main/java/com/topjohnwu/magisk/Config.kt +++ b/app/src/main/java/com/topjohnwu/magisk/Config.kt @@ -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().getExternalFilesDir(null)!! + val downloadDirectory + get() = + Utils.ensureDownloadPath(downloadPath) ?: get().getExternalFilesDir(null)!! private const val SU_FINGERPRINT = "su_fingerprint" diff --git a/app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/PolicyRvItem.kt b/app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/PolicyRvItem.kt index fbb3b4e8b..c6f1593df 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/PolicyRvItem.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/PolicyRvItem.kt @@ -1,8 +1,6 @@ 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() { @@ -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(R.id.policy_expand_container) - .setRevealed(isExpanded.value) } fun toggleNotify(viewModel: SuperuserViewModel) { diff --git a/app/src/main/java/com/topjohnwu/magisk/redesign/module/ModuleFragment.kt b/app/src/main/java/com/topjohnwu/magisk/redesign/module/ModuleFragment.kt index 65d61900b..0905e9b8e 100644 --- a/app/src/main/java/com/topjohnwu/magisk/redesign/module/ModuleFragment.kt +++ b/app/src/main/java/com/topjohnwu/magisk/redesign/module/ModuleFragment.kt @@ -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(), @@ -67,13 +68,18 @@ class ModuleFragment : CompatFragment 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 // --- 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 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) } diff --git a/app/src/main/java/com/topjohnwu/magisk/redesign/settings/SettingsFragment.kt b/app/src/main/java/com/topjohnwu/magisk/redesign/settings/SettingsFragment.kt index 8ac1efad5..2fdcef756 100644 --- a/app/src/main/java/com/topjohnwu/magisk/redesign/settings/SettingsFragment.kt +++ b/app/src/main/java/com/topjohnwu/magisk/redesign/settings/SettingsFragment.kt @@ -1,9 +1,12 @@ 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() { @@ -19,6 +22,16 @@ class SettingsFragment : CompatFragment() { @@ -23,6 +26,16 @@ class SuperuserFragment : CompatFragment Unit) { + setOnLongClickListener { + listener() + true + } } \ No newline at end of file diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/PinchGestureCallback.kt b/app/src/main/java/com/topjohnwu/magisk/utils/PinchGestureCallback.kt new file mode 100644 index 000000000..f977546a3 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/utils/PinchGestureCallback.kt @@ -0,0 +1,24 @@ +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 diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/PinchZoomTouchListener.kt b/app/src/main/java/com/topjohnwu/magisk/utils/PinchZoomTouchListener.kt new file mode 100644 index 000000000..58e099709 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/utils/PinchZoomTouchListener.kt @@ -0,0 +1,66 @@ +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 diff --git a/app/src/main/res/drawable/ic_notifications_md2.xml b/app/src/main/res/drawable/ic_notifications_md2.xml new file mode 100644 index 000000000..c55141254 --- /dev/null +++ b/app/src/main/res/drawable/ic_notifications_md2.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_off.xml b/app/src/main/res/drawable/ic_off.xml new file mode 100644 index 000000000..377067b0d --- /dev/null +++ b/app/src/main/res/drawable/ic_off.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_module_md2.xml b/app/src/main/res/layout/fragment_module_md2.xml index 325c0fa3c..1d577a1c0 100644 --- a/app/src/main/res/layout/fragment_module_md2.xml +++ b/app/src/main/res/layout/fragment_module_md2.xml @@ -20,7 +20,7 @@ android:layout_height="match_parent"> - + android:layout_height="wrap_content" + android:orientation="vertical"> - + - + - + - + - + - + - - - + app:layout_constraintTop_toBottomOf="@+id/policy_package_name" + tools:visibility="visible"> - + - + + + + + + + diff --git a/app/src/main/res/values/strings_md2.xml b/app/src/main/res/values/strings_md2.xml index a7527f006..272950e7a 100644 --- a/app/src/main/res/values/strings_md2.xml +++ b/app/src/main/res/values/strings_md2.xml @@ -86,8 +86,8 @@ Restore Install from storage - Toggles logging - Toggles “toast” notifications + Logs + Notifications Revoke Filter by name