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 { SafetynetViewModel() }
viewModel { SettingsViewModel() }
viewModel { SuperuserViewModel() }
viewModel { SuperuserViewModel(get(), get()) }
viewModel { ThemeViewModel() }
viewModel { MainViewModel() }

View File

@@ -1,6 +1,9 @@
package com.topjohnwu.magisk.model.entity.recycler
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.databinding.ComparableRvItem
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.utils.KObservableField
import com.topjohnwu.magisk.utils.RxBus
import com.topjohnwu.magisk.utils.setRevealed
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 isEnabled = KObservableField(item.policy == MagiskPolicy.ALLOW)
@@ -22,6 +29,22 @@ class PolicyRvItem(val item: MagiskPolicy, val icon: Drawable) : ComparableRvIte
val shouldLog = KObservableField(item.logging)
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()

View File

@@ -2,8 +2,11 @@ package com.topjohnwu.magisk.redesign.compat
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import androidx.databinding.OnRebindCallback
import androidx.databinding.ViewDataBinding
import androidx.fragment.app.Fragment
import androidx.transition.TransitionManager
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.base.BaseActivity
import com.topjohnwu.magisk.model.events.ViewEvent
@@ -27,6 +30,13 @@ abstract class CompatActivity<ViewModel : CompatViewModel, Binding : ViewDataBin
override fun onCreate(savedInstanceState: Bundle?) {
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()
navigation?.onCreate(savedInstanceState)
}

View File

@@ -2,7 +2,10 @@ package com.topjohnwu.magisk.redesign.compat
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import androidx.databinding.OnRebindCallback
import androidx.databinding.ViewDataBinding
import androidx.transition.TransitionManager
import com.topjohnwu.magisk.base.BaseFragment
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?) {
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()
}

View File

@@ -1,10 +1,55 @@
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.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 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
import android.animation.Animator
import android.graphics.drawable.Drawable
import android.os.Build
import android.view.View
import android.view.ViewAnimationUtils
import android.view.ViewGroup
import android.widget.TextSwitcher
import android.widget.TextView
@@ -9,6 +13,9 @@ import androidx.annotation.ColorInt
import androidx.annotation.DrawableRes
import androidx.appcompat.widget.AppCompatImageView
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.updateLayoutParams
import androidx.databinding.BindingAdapter
@@ -16,18 +23,21 @@ import androidx.databinding.InverseBindingAdapter
import androidx.databinding.InverseBindingListener
import androidx.drawerlayout.widget.DrawerLayout
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager.widget.ViewPager
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.navigation.NavigationView
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.extensions.drawableCompat
import com.topjohnwu.magisk.extensions.replaceRandomWithSpecial
import com.topjohnwu.magisk.extensions.subscribeK
import com.topjohnwu.magisk.model.entity.state.IndeterminateState
import io.reactivex.Observable
import io.reactivex.disposables.Disposable
import java.util.concurrent.TimeUnit
import kotlin.math.hypot
@BindingAdapter("onNavigationClick")
@@ -291,4 +301,72 @@ fun View.setMargins(
@BindingAdapter("nestedScrollingEnabled")
fun RecyclerView.setNestedScrolling(enabled: Boolean) {
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) }
}
}