Added superuser screen implementation

* partially
This commit is contained in:
Viktor De Pasquale 2019-10-18 19:38:55 +02:00
parent a539ffb188
commit fcbf56e93a
18 changed files with 451 additions and 8 deletions

View File

@ -23,7 +23,7 @@ val redesignModule = module {
viewModel { RequestViewModel() } viewModel { RequestViewModel() }
viewModel { SafetynetViewModel() } viewModel { SafetynetViewModel() }
viewModel { SettingsViewModel() } viewModel { SettingsViewModel() }
viewModel { SuperuserViewModel() } viewModel { SuperuserViewModel(get(), get()) }
viewModel { ThemeViewModel() } viewModel { ThemeViewModel() }
viewModel { MainViewModel() } viewModel { MainViewModel() }

View File

@ -1,6 +1,9 @@
package com.topjohnwu.magisk.model.entity.recycler package com.topjohnwu.magisk.model.entity.recycler
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.view.View
import android.view.ViewGroup
import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.databinding.ComparableRvItem import com.topjohnwu.magisk.databinding.ComparableRvItem
import com.topjohnwu.magisk.extensions.addOnPropertyChangedCallback import com.topjohnwu.magisk.extensions.addOnPropertyChangedCallback
@ -11,10 +14,14 @@ import com.topjohnwu.magisk.model.events.PolicyEnableEvent
import com.topjohnwu.magisk.model.events.PolicyUpdateEvent import com.topjohnwu.magisk.model.events.PolicyUpdateEvent
import com.topjohnwu.magisk.utils.KObservableField import com.topjohnwu.magisk.utils.KObservableField
import com.topjohnwu.magisk.utils.RxBus import com.topjohnwu.magisk.utils.RxBus
import com.topjohnwu.magisk.utils.setRevealed
class PolicyRvItem(val item: MagiskPolicy, val icon: Drawable) : ComparableRvItem<PolicyRvItem>() { class PolicyRvItem(val item: MagiskPolicy, val icon: Drawable) : ComparableRvItem<PolicyRvItem>() {
override val layoutRes: Int = R.layout.item_policy override val layoutRes: Int = when {
Config.redesign -> R.layout.item_policy_md2
else -> R.layout.item_policy
}
val isExpanded = KObservableField(false) val isExpanded = KObservableField(false)
val isEnabled = KObservableField(item.policy == MagiskPolicy.ALLOW) val isEnabled = KObservableField(item.policy == MagiskPolicy.ALLOW)
@ -22,6 +29,22 @@ class PolicyRvItem(val item: MagiskPolicy, val icon: Drawable) : ComparableRvIte
val shouldLog = KObservableField(item.logging) val shouldLog = KObservableField(item.logging)
fun toggle() = isExpanded.toggle() fun toggle() = isExpanded.toggle()
fun toggleNotify() = shouldNotify.toggle()
fun toggleLog() = shouldLog.toggle()
fun toggleEnabled() {
if (isExpanded.value) {
return
}
isEnabled.toggle()
}
fun toggle(view: View) {
toggle()
(view.parent as ViewGroup)
.findViewById<View>(R.id.expand_layout)
.setRevealed(isExpanded.value)
}
private val rxBus: RxBus by inject() private val rxBus: RxBus by inject()

View File

@ -2,8 +2,11 @@ package com.topjohnwu.magisk.redesign.compat
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import android.view.ViewGroup
import androidx.databinding.OnRebindCallback
import androidx.databinding.ViewDataBinding import androidx.databinding.ViewDataBinding
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.transition.TransitionManager
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.base.BaseActivity import com.topjohnwu.magisk.base.BaseActivity
import com.topjohnwu.magisk.model.events.ViewEvent import com.topjohnwu.magisk.model.events.ViewEvent
@ -27,6 +30,13 @@ abstract class CompatActivity<ViewModel : CompatViewModel, Binding : ViewDataBin
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
binding.addOnRebindCallback(object : OnRebindCallback<Binding>() {
override fun onPreBind(binding: Binding): Boolean {
TransitionManager.beginDelayedTransition(binding.root as ViewGroup)
return super.onPreBind(binding)
}
})
delegate.onCreate() delegate.onCreate()
navigation?.onCreate(savedInstanceState) navigation?.onCreate(savedInstanceState)
} }

View File

@ -2,7 +2,10 @@ package com.topjohnwu.magisk.redesign.compat
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import android.view.ViewGroup
import androidx.databinding.OnRebindCallback
import androidx.databinding.ViewDataBinding import androidx.databinding.ViewDataBinding
import androidx.transition.TransitionManager
import com.topjohnwu.magisk.base.BaseFragment import com.topjohnwu.magisk.base.BaseFragment
import com.topjohnwu.magisk.model.events.ViewEvent import com.topjohnwu.magisk.model.events.ViewEvent
@ -19,6 +22,13 @@ abstract class CompatFragment<ViewModel : CompatViewModel, Binding : ViewDataBin
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
binding.addOnRebindCallback(object : OnRebindCallback<Binding>() {
override fun onPreBind(binding: Binding): Boolean {
TransitionManager.beginDelayedTransition(binding.root as ViewGroup)
return super.onPreBind(binding)
}
})
delegate.onCreate() delegate.onCreate()
} }

View File

@ -1,10 +1,55 @@
package com.topjohnwu.magisk.redesign.superuser package com.topjohnwu.magisk.redesign.superuser
import android.content.pm.PackageManager
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.data.database.PolicyDao
import com.topjohnwu.magisk.databinding.ComparableRvItem
import com.topjohnwu.magisk.extensions.applySchedulers
import com.topjohnwu.magisk.extensions.subscribeK
import com.topjohnwu.magisk.model.entity.recycler.PolicyRvItem
import com.topjohnwu.magisk.model.navigation.Navigation import com.topjohnwu.magisk.model.navigation.Navigation
import com.topjohnwu.magisk.redesign.compat.CompatViewModel import com.topjohnwu.magisk.redesign.compat.CompatViewModel
import com.topjohnwu.magisk.redesign.home.itemBindingOf
import com.topjohnwu.magisk.utils.DiffObservableList
class SuperuserViewModel : CompatViewModel() { class SuperuserViewModel(
private val db: PolicyDao,
private val packageManager: PackageManager
) : CompatViewModel() {
val items = diffListOf<PolicyRvItem>()
val itemBinding = itemBindingOf<PolicyRvItem> {
it.bindExtra(BR.viewModel, this)
}
override fun refresh() = db.fetchAll()
.flattenAsFlowable { it }
.parallel()
.map { PolicyRvItem(it, it.applicationInfo.loadIcon(packageManager)) }
.sequential()
.sorted { o1, o2 ->
compareBy<PolicyRvItem>(
{ it.item.appName.toLowerCase() },
{ it.item.packageName }
).compare(o1, o2)
}
.toList()
.map { it to items.calculateDiff(it) }
.applySchedulers()
.applyViewModel(this)
.subscribeK { items.update(it.first, it.second) }
fun hidePressed() = Navigation.hide().publish() fun hidePressed() = Navigation.hide().publish()
fun deletePressed(item: PolicyRvItem) {
TODO()
}
} }
inline fun <T : ComparableRvItem<T>> diffListOf(
vararg newItems: T
) = DiffObservableList(object : DiffObservableList.Callback<T> {
override fun areItemsTheSame(oldItem: T, newItem: T) = oldItem.genericItemSameAs(newItem)
override fun areContentsTheSame(oldItem: T, newItem: T) = oldItem.genericContentSameAs(newItem)
}).also { it.update(newItems.toList()) }

View File

@ -1,6 +1,10 @@
package com.topjohnwu.magisk.utils package com.topjohnwu.magisk.utils
import android.animation.Animator
import android.graphics.drawable.Drawable
import android.os.Build
import android.view.View import android.view.View
import android.view.ViewAnimationUtils
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.TextSwitcher import android.widget.TextSwitcher
import android.widget.TextView import android.widget.TextView
@ -9,6 +13,9 @@ import androidx.annotation.ColorInt
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.appcompat.widget.AppCompatImageView import androidx.appcompat.widget.AppCompatImageView
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.core.animation.doOnEnd
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import androidx.core.view.postDelayed import androidx.core.view.postDelayed
import androidx.core.view.updateLayoutParams import androidx.core.view.updateLayoutParams
import androidx.databinding.BindingAdapter import androidx.databinding.BindingAdapter
@ -16,18 +23,21 @@ import androidx.databinding.InverseBindingAdapter
import androidx.databinding.InverseBindingListener import androidx.databinding.InverseBindingListener
import androidx.drawerlayout.widget.DrawerLayout import androidx.drawerlayout.widget.DrawerLayout
import androidx.interpolator.view.animation.FastOutSlowInInterpolator import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager.widget.ViewPager import androidx.viewpager.widget.ViewPager
import com.google.android.material.floatingactionbutton.FloatingActionButton import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.navigation.NavigationView import com.google.android.material.navigation.NavigationView
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.extensions.drawableCompat
import com.topjohnwu.magisk.extensions.replaceRandomWithSpecial import com.topjohnwu.magisk.extensions.replaceRandomWithSpecial
import com.topjohnwu.magisk.extensions.subscribeK import com.topjohnwu.magisk.extensions.subscribeK
import com.topjohnwu.magisk.model.entity.state.IndeterminateState import com.topjohnwu.magisk.model.entity.state.IndeterminateState
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.disposables.Disposable import io.reactivex.disposables.Disposable
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import kotlin.math.hypot
@BindingAdapter("onNavigationClick") @BindingAdapter("onNavigationClick")
@ -292,3 +302,71 @@ fun View.setMargins(
fun RecyclerView.setNestedScrolling(enabled: Boolean) { fun RecyclerView.setNestedScrolling(enabled: Boolean) {
isNestedScrollingEnabled = enabled isNestedScrollingEnabled = enabled
} }
@BindingAdapter("isSelected")
fun View.isSelected(isSelected: Boolean) {
this.isSelected = isSelected
}
@BindingAdapter("reveal")
fun View.setRevealed(reveal: Boolean) {
val x = measuredWidth
val y = measuredHeight
val maxRadius = hypot(x.toDouble(), y.toDouble()).toFloat()
val start = if (reveal) 0f else maxRadius
val end = if (reveal) maxRadius else 0f
val anim = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
isInvisible = reveal
return
} else {
ViewAnimationUtils.createCircularReveal(this, x, 0, start, end).apply {
interpolator = FastOutSlowInInterpolator()
setTag(R.id.revealAnim, this)
doOnEnd { setTag(R.id.revealAnim, null) }
}
}
post {
isVisible = true
anim.start()
}
}
@BindingAdapter("revealFix")
fun View.setFixReveal(isRevealed: Boolean) {
(getTag(R.id.revealAnim) as? Animator)
?.doOnEnd { isInvisible = !isRevealed }
?.let { return }
isInvisible = !isRevealed
}
@BindingAdapter("dividerVertical", "dividerHorizontal", requireAll = false)
fun RecyclerView.setDividers(dividerVertical: Int, dividerHorizontal: Int) {
val horizontal = if (dividerHorizontal > 0) {
context.drawableCompat(dividerHorizontal)
} else {
null
}
val vertical = if (dividerVertical > 0) {
context.drawableCompat(dividerVertical)
} else {
null
}
setDividers(vertical, horizontal)
}
@BindingAdapter("dividerVertical", "dividerHorizontal", requireAll = false)
fun RecyclerView.setDividers(dividerVertical: Drawable?, dividerHorizontal: Drawable?) {
if (dividerHorizontal != null) {
DividerItemDecoration(context, LinearLayoutManager.HORIZONTAL).apply {
setDrawable(dividerHorizontal)
}.let { addItemDecoration(it) }
}
if (dividerVertical != null) {
DividerItemDecoration(context, LinearLayoutManager.VERTICAL).apply {
setDrawable(dividerVertical)
}.let { addItemDecoration(it) }
}
}

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?colorPrimary" android:state_selected="true" />
<item android:color="?colorDisabled" android:state_enabled="false" />
<item android:color="?colorError" />
</selector>

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt">
<aapt:attr name="android:drawable">
<vector
android:name="vector"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:name="path_2"
android:fillColor="#000"
android:pathData="M 16.6 5.6 L 18 7 L 12 13 L 6 7 L 7.4 5.6 L 12 10.2 L 16.6 5.6 M 12 19 L 12 16.2 L 7.4 11.6 L 6 13 Z M 12 19 L 12 16.2 L 16.6 11.6 L 18 13 Z"
android:strokeWidth="1" />
</vector>
</aapt:attr>
<target android:name="path_2">
<aapt:attr name="android:animation">
<objectAnimator
android:duration="500"
android:interpolator="@android:interpolator/fast_out_slow_in"
android:propertyName="pathData"
android:valueFrom="M 16.6 5.6 C 17.067 6.067 17.533 6.533 18 7 C 17 8 16 9 15 10 C 14 11 13 12 12 13 C 11 12 10 11 9 10 C 8 9 7 8 6 7 C 6.467 6.533 6.933 6.067 7.4 5.6 C 8.933 7.133 10.467 8.667 12 10.2 C 13.533 8.667 15.067 7.133 16.6 5.6 M 12 19 C 12 18.067 12 17.133 12 16.2 C 10.467 14.667 8.933 13.133 7.4 11.6 C 7.322 11.678 7.244 11.756 7.167 11.833 C 7.089 11.911 7.011 11.989 6.933 12.067 C 6.856 12.144 6.778 12.222 6.7 12.3 L 6.467 12.533 C 6.389 12.611 6.311 12.689 6.233 12.767 C 6.156 12.844 6.078 12.922 6 13 C 8 15 10 17 12 19 M 12 19 C 12 18.067 12 17.133 12 16.2 C 13.533 14.667 15.067 13.133 16.6 11.6 C 16.693 11.693 16.787 11.787 16.88 11.88 C 16.973 11.973 17.067 12.067 17.16 12.16 C 17.253 12.253 17.347 12.347 17.44 12.44 C 17.533 12.533 17.627 12.627 17.72 12.72 C 17.813 12.813 17.907 12.907 18 13 C 16 15 14 17 12 19"
android:valueTo="M 13.414 10.586 C 13.789 10.961 14 11.47 14 12 C 14 12.53 13.789 13.039 13.414 13.414 C 13.039 13.789 12.53 14 12 14 C 11.47 14 10.961 13.789 10.586 13.414 C 10.211 13.039 10 12.53 10 12 C 10 11.47 10.211 10.961 10.586 10.586 C 10.961 10.211 11.47 10 12 10 C 12.53 10 13.039 10.211 13.414 10.586 M 7.414 13.414 C 7.789 13.039 8 12.53 8 12 C 8 11.47 7.789 10.961 7.414 10.586 C 7.039 10.211 6.53 10 6 10 C 5.47 10 4.961 10.211 4.586 10.586 C 4.211 10.961 4 11.47 4 12 L 4 12 C 4 12.53 4.211 13.039 4.586 13.414 C 4.961 13.789 5.47 14 6 14 C 6.53 14 7.039 13.789 7.414 13.414 M 16.586 13.414 C 16.211 13.039 16 12.53 16 12 C 16 11.47 16.211 10.961 16.586 10.586 C 16.961 10.211 17.47 10 18 10 C 18.53 10 19.039 10.211 19.414 10.586 C 19.789 10.961 20 11.47 20 12 C 20 12.53 19.789 13.039 19.414 13.414 C 19.039 13.789 18.53 14 18 14 C 17.47 14 16.961 13.789 16.586 13.414"
android:valueType="pathType" />
</aapt:attr>
</target>
</animated-vector>

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt">
<aapt:attr name="android:drawable">
<vector
android:name="vector"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:name="path_3"
android:fillColor="#000"
android:pathData="M 16 12 C 16 11.47 16.211 10.961 16.586 10.586 C 16.961 10.211 17.47 10 18 10 C 18.53 10 19.039 10.211 19.414 10.586 C 19.789 10.961 20 11.47 20 12 C 20 12.53 19.789 13.039 19.414 13.414 C 19.039 13.789 18.53 14 18 14 C 17.47 14 16.961 13.789 16.586 13.414 C 16.211 13.039 16 12.53 16 12 M 10 12 C 10 11.47 10.211 10.961 10.586 10.586 C 10.961 10.211 11.47 10 12 10 C 12.53 10 13.039 10.211 13.414 10.586 C 13.789 10.961 14 11.47 14 12 C 14 12.53 13.789 13.039 13.414 13.414 C 13.039 13.789 12.53 14 12 14 C 11.47 14 10.961 13.789 10.586 13.414 C 10.211 13.039 10 12.53 10 12 M 4 12 C 4 11.47 4.211 10.961 4.586 10.586 C 4.961 10.211 5.47 10 6 10 C 6.53 10 7.039 10.211 7.414 10.586 C 7.789 10.961 8 11.47 8 12 C 8 12.53 7.789 13.039 7.414 13.414 C 7.039 13.789 6.53 14 6 14 C 5.47 14 4.961 13.789 4.586 13.414 C 4.211 13.039 4 12.53 4 12 Z"
android:strokeWidth="1" />
</vector>
</aapt:attr>
<target android:name="path_3">
<aapt:attr name="android:animation">
<objectAnimator
android:duration="500"
android:interpolator="@android:interpolator/fast_out_slow_in"
android:propertyName="pathData"
android:valueFrom="M 13.414 10.586 C 13.789 10.961 14 11.47 14 12 C 14 12.53 13.789 13.039 13.414 13.414 C 13.039 13.789 12.53 14 12 14 C 11.47 14 10.961 13.789 10.586 13.414 C 10.211 13.039 10 12.53 10 12 C 10 11.47 10.211 10.961 10.586 10.586 C 10.961 10.211 11.47 10 12 10 C 12.53 10 13.039 10.211 13.414 10.586 M 7.414 13.414 C 7.789 13.039 8 12.53 8 12 C 8 11.47 7.789 10.961 7.414 10.586 C 7.039 10.211 6.53 10 6 10 C 5.47 10 4.961 10.211 4.586 10.586 C 4.211 10.961 4 11.47 4 12 L 4 12 C 4 12.53 4.211 13.039 4.586 13.414 C 4.961 13.789 5.47 14 6 14 C 6.53 14 7.039 13.789 7.414 13.414 M 16.586 13.414 C 16.211 13.039 16 12.53 16 12 C 16 11.47 16.211 10.961 16.586 10.586 C 16.961 10.211 17.47 10 18 10 C 18.53 10 19.039 10.211 19.414 10.586 C 19.789 10.961 20 11.47 20 12 C 20 12.53 19.789 13.039 19.414 13.414 C 19.039 13.789 18.53 14 18 14 C 17.47 14 16.961 13.789 16.586 13.414"
android:valueTo="M 16.6 5.6 C 17.067 6.067 17.533 6.533 18 7 C 17 8 16 9 15 10 C 14 11 13 12 12 13 C 11 12 10 11 9 10 C 8 9 7 8 6 7 C 6.467 6.533 6.933 6.067 7.4 5.6 C 8.933 7.133 10.467 8.667 12 10.2 C 13.533 8.667 15.067 7.133 16.6 5.6 M 12 19 C 12 18.067 12 17.133 12 16.2 C 10.467 14.667 8.933 13.133 7.4 11.6 C 7.322 11.678 7.244 11.756 7.167 11.833 C 7.089 11.911 7.011 11.989 6.933 12.067 C 6.856 12.144 6.778 12.222 6.7 12.3 L 6.467 12.533 C 6.389 12.611 6.311 12.689 6.233 12.767 C 6.156 12.844 6.078 12.922 6 13 C 8 15 10 17 12 19 M 12 19 C 12 18.067 12 17.133 12 16.2 C 13.533 14.667 15.067 13.133 16.6 11.6 C 16.693 11.693 16.787 11.787 16.88 11.88 C 16.973 11.973 17.067 12.067 17.16 12.16 C 17.253 12.253 17.347 12.347 17.44 12.44 C 17.533 12.533 17.627 12.627 17.72 12.72 C 17.813 12.813 17.907 12.907 18 13 C 16 15 14 17 12 19"
android:valueType="pathType" />
</aapt:attr>
</target>
</animated-vector>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<animated-selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/expanded"
android:drawable="@drawable/ic_chevron_down_md2"
android:state_selected="true" />
<item
android:id="@+id/collapsed"
android:drawable="@drawable/ic_dots_md2" />
<transition
android:drawable="@drawable/avd_chevron_more"
android:fromId="@id/expanded"
android:toId="@id/collapsed" />
<transition
android:drawable="@drawable/avd_more_chevron"
android:fromId="@id/collapsed"
android:toId="@id/expanded" />
</animated-selector>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<size
android:width="@dimen/l1"
android:height="@dimen/l1" />
<solid android:color="@android:color/transparent" />
</shape>

View File

@ -0,0 +1,10 @@
<?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.59,5.59L18,7L12,13L6,7L7.41,5.59L12,10.17L16.59,5.59M16.59,11.59L18,13L12,19L6,13L7.41,11.59L12,16.17L16.59,11.59Z" />
</vector>

View File

@ -0,0 +1,10 @@
<?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,12A2,2 0 0,1 18,10A2,2 0 0,1 20,12A2,2 0 0,1 18,14A2,2 0 0,1 16,12M10,12A2,2 0 0,1 12,10A2,2 0 0,1 14,12A2,2 0 0,1 12,14A2,2 0 0,1 10,12M4,12A2,2 0 0,1 6,10A2,2 0 0,1 8,12A2,2 0 0,1 6,14A2,2 0 0,1 4,12Z" />
</vector>

View File

@ -70,7 +70,7 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_magisk_delete" app:srcCompat="@drawable/ic_magisk_delete"
app:tint="@color/color_primary_delete_transient" /> app:tint="@color/color_primary_error_transient" />
<androidx.appcompat.widget.AppCompatTextView <androidx.appcompat.widget.AppCompatTextView
android:id="@+id/home_magisk_title" android:id="@+id/home_magisk_title"

View File

@ -5,6 +5,8 @@
<data> <data>
<import type="com.topjohnwu.magisk.R" />
<variable <variable
name="viewModel" name="viewModel"
type="com.topjohnwu.magisk.redesign.superuser.SuperuserViewModel" /> type="com.topjohnwu.magisk.redesign.superuser.SuperuserViewModel" />
@ -20,9 +22,10 @@
android:paddingBottom="@{viewModel.insets.bottom + (int) @dimen/l2}" android:paddingBottom="@{viewModel.insets.bottom + (int) @dimen/l2}"
tools:layout_marginTop="24dp"> tools:layout_marginTop="24dp">
<androidx.constraintlayout.widget.ConstraintLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content"
android:orientation="vertical">
<com.google.android.material.card.MaterialCardView <com.google.android.material.card.MaterialCardView
style="?styleCardNormal" style="?styleCardNormal"
@ -72,7 +75,24 @@
</com.google.android.material.card.MaterialCardView> </com.google.android.material.card.MaterialCardView>
</androidx.constraintlayout.widget.ConstraintLayout> <androidx.recyclerview.widget.RecyclerView
dividerHorizontal="@{R.drawable.divider_l1}"
dividerVertical="@{R.drawable.divider_l1}"
itemBinding="@{viewModel.itemBinding}"
items="@{viewModel.items}"
nestedScrollingEnabled="@{false}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:orientation="vertical"
android:paddingStart="@dimen/l1"
android:paddingTop="@dimen/l1"
android:paddingBottom="@dimen/l1"
app:layoutManager="androidx.recyclerview.widget.StaggeredGridLayoutManager"
app:spanCount="2"
tools:listitem="@layout/item_policy_md2" />
</LinearLayout>
</androidx.core.widget.NestedScrollView> </androidx.core.widget.NestedScrollView>

View File

@ -0,0 +1,141 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="item"
type="com.topjohnwu.magisk.model.entity.recycler.PolicyRvItem" />
<variable
name="viewModel"
type="com.topjohnwu.magisk.redesign.superuser.SuperuserViewModel" />
</data>
<com.google.android.material.card.MaterialCardView
style="?styleCardNormal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:alpha="@{item.isEnabled() ? 1f : .5f}"
android:onClick="@{() -> item.toggleEnabled()}"
tools:layout_marginBottom="@dimen/l1"
tools:layout_marginEnd="@dimen/l1">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="@dimen/l2"
android:paddingBottom="@dimen/l2">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/app_icon"
style="?styleImageBig"
android:src="@{item.icon}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:srcCompat="@drawable/ic_logo" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/app_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_generic"
android:layout_marginTop="@dimen/l1"
android:layout_marginRight="@dimen/margin_generic"
android:ellipsize="middle"
android:gravity="center"
android:singleLine="true"
android:text="@{item.item.appName}"
android:textAppearance="?appearanceTextTitleNormal"
android:textIsSelectable="false"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/app_icon"
tools:text="@string/app_name" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/package_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ellipsize="middle"
android:gravity="center"
android:singleLine="true"
android:text="@{item.item.packageName}"
android:textAppearance="?appearanceTextCaptionVariant"
android:textColor="@android:color/tertiary_text_dark"
android:textIsSelectable="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@id/app_name"
app:layout_constraintStart_toStartOf="@id/app_name"
app:layout_constraintTop_toBottomOf="@id/app_name"
tools:text="com.topjohnwu.magisk" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/expand_layout"
revealFix="@{item.isExpanded()}"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?colorSurface"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/package_name">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/bell"
style="?styleIconNormal"
isSelected="@{item.shouldNotify}"
android:onClick="@{() -> item.toggleNotify()}"
app:layout_constraintBottom_toTopOf="@+id/delete"
app:layout_constraintEnd_toStartOf="@+id/bug"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
app:srcCompat="@drawable/ic_notifications"
app:tint="@color/color_error_primary_transient" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/bug"
style="?styleIconNormal"
isSelected="@{item.shouldLog}"
android:onClick="@{() -> item.toggleLog()}"
app:layout_constraintBottom_toBottomOf="@+id/bell"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/bell"
app:layout_constraintTop_toTopOf="@+id/bell"
app:srcCompat="@drawable/ic_bug_report"
app:tint="@color/color_error_primary_transient" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/delete"
style="?styleIconError"
android:onClick="@{() -> viewModel.deletePressed(item)}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/bell"
app:srcCompat="@drawable/ic_delete_md2" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.appcompat.widget.AppCompatImageView
style="?styleIconNormal"
isEnabled="@{item.isEnabled}"
isSelected="@{item.isExpanded}"
android:layout_gravity="top|end"
android:onClick="@{(view) -> item.toggle(view)}"
android:rotation="180"
app:srcCompat="@drawable/ic_more_collapse" />
</com.google.android.material.card.MaterialCardView>
</layout>

View File

@ -2,5 +2,6 @@
<resources> <resources>
<item name="recyclerScrollListener" type="id" /> <item name="recyclerScrollListener" type="id" />
<item name="revealAnim" type="id" />
</resources> </resources>