mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-26 12:17:39 +00:00
Updated superuser fragment to new arch
Fixed theme issues along the way
This commit is contained in:
parent
8a8441c875
commit
bcd1064e94
@ -10,4 +10,5 @@ val applicationModule = module {
|
|||||||
single { RxBus() }
|
single { RxBus() }
|
||||||
single { get<Context>().resources }
|
single { get<Context>().resources }
|
||||||
single { get<Context>() as App }
|
single { get<Context>() as App }
|
||||||
|
single { get<Context>().packageManager }
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
package com.topjohnwu.magisk.di
|
package com.topjohnwu.magisk.di
|
||||||
|
|
||||||
|
import com.topjohnwu.magisk.App
|
||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
|
|
||||||
|
|
||||||
val databaseModule = module {}
|
val databaseModule = module {
|
||||||
|
single { get<App>().DB }
|
||||||
|
}
|
||||||
|
@ -2,6 +2,7 @@ package com.topjohnwu.magisk.di
|
|||||||
|
|
||||||
import com.topjohnwu.magisk.ui.MainViewModel
|
import com.topjohnwu.magisk.ui.MainViewModel
|
||||||
import com.topjohnwu.magisk.ui.home.HomeViewModel
|
import com.topjohnwu.magisk.ui.home.HomeViewModel
|
||||||
|
import com.topjohnwu.magisk.ui.superuser.SuperuserViewModel
|
||||||
import org.koin.androidx.viewmodel.dsl.viewModel
|
import org.koin.androidx.viewmodel.dsl.viewModel
|
||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
|
|
||||||
@ -9,4 +10,5 @@ import org.koin.dsl.module
|
|||||||
val viewModelModules = module {
|
val viewModelModules = module {
|
||||||
viewModel { MainViewModel() }
|
viewModel { MainViewModel() }
|
||||||
viewModel { HomeViewModel(get(), get()) }
|
viewModel { HomeViewModel(get(), get()) }
|
||||||
|
viewModel { SuperuserViewModel(get(), get(), get()) }
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.topjohnwu.magisk.model.entity.recycler
|
||||||
|
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import com.skoumal.teanity.databinding.ComparableRvItem
|
||||||
|
import com.skoumal.teanity.util.KObservableField
|
||||||
|
import com.topjohnwu.magisk.R
|
||||||
|
import com.topjohnwu.magisk.model.entity.Policy
|
||||||
|
import com.topjohnwu.magisk.utils.toggle
|
||||||
|
|
||||||
|
class PolicyRvItem(val item: Policy, val icon: Drawable) : ComparableRvItem<PolicyRvItem>() {
|
||||||
|
|
||||||
|
override val layoutRes: Int = R.layout.item_policy
|
||||||
|
|
||||||
|
val isExpanded = KObservableField(false)
|
||||||
|
val isEnabled = KObservableField(item.policy == Policy.ALLOW)
|
||||||
|
val shouldNotify = KObservableField(item.notification)
|
||||||
|
val shouldLog = KObservableField(item.logging)
|
||||||
|
|
||||||
|
fun toggle() = isExpanded.toggle()
|
||||||
|
|
||||||
|
override fun contentSameAs(other: PolicyRvItem): Boolean = itemSameAs(other)
|
||||||
|
override fun itemSameAs(other: PolicyRvItem): Boolean = item.uid == other.item.uid
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package com.topjohnwu.magisk.model.events
|
package com.topjohnwu.magisk.model.events
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
import com.skoumal.teanity.viewevents.ViewEvent
|
import com.skoumal.teanity.viewevents.ViewEvent
|
||||||
|
|
||||||
|
|
||||||
@ -15,3 +16,5 @@ class UninstallEvent : ViewEvent()
|
|||||||
class EnvFixEvent : ViewEvent()
|
class EnvFixEvent : ViewEvent()
|
||||||
|
|
||||||
class UpdateSafetyNetEvent : ViewEvent()
|
class UpdateSafetyNetEvent : ViewEvent()
|
||||||
|
|
||||||
|
class ViewActionEvent(val action: Activity.() -> Unit) : ViewEvent()
|
@ -11,6 +11,7 @@ import com.ncapdevi.fragnav.FragNavController
|
|||||||
import com.ncapdevi.fragnav.FragNavTransactionOptions
|
import com.ncapdevi.fragnav.FragNavTransactionOptions
|
||||||
import com.skoumal.teanity.viewevents.ViewEvent
|
import com.skoumal.teanity.viewevents.ViewEvent
|
||||||
import com.topjohnwu.magisk.Config
|
import com.topjohnwu.magisk.Config
|
||||||
|
import com.topjohnwu.magisk.model.events.ViewActionEvent
|
||||||
import com.topjohnwu.magisk.model.navigation.MagiskAnimBuilder
|
import com.topjohnwu.magisk.model.navigation.MagiskAnimBuilder
|
||||||
import com.topjohnwu.magisk.model.navigation.MagiskNavigationEvent
|
import com.topjohnwu.magisk.model.navigation.MagiskNavigationEvent
|
||||||
import com.topjohnwu.magisk.model.navigation.Navigator
|
import com.topjohnwu.magisk.model.navigation.Navigator
|
||||||
@ -62,6 +63,7 @@ abstract class MagiskActivity<ViewModel : MagiskViewModel, Binding : ViewDataBin
|
|||||||
super.onEventDispatched(event)
|
super.onEventDispatched(event)
|
||||||
when (event) {
|
when (event) {
|
||||||
is MagiskNavigationEvent -> navigateTo(event)
|
is MagiskNavigationEvent -> navigateTo(event)
|
||||||
|
is ViewActionEvent -> event.action(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import androidx.databinding.ViewDataBinding
|
|||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import com.skoumal.teanity.view.TeanityFragment
|
import com.skoumal.teanity.view.TeanityFragment
|
||||||
import com.skoumal.teanity.viewevents.ViewEvent
|
import com.skoumal.teanity.viewevents.ViewEvent
|
||||||
|
import com.topjohnwu.magisk.model.events.ViewActionEvent
|
||||||
import com.topjohnwu.magisk.model.navigation.MagiskNavigationEvent
|
import com.topjohnwu.magisk.model.navigation.MagiskNavigationEvent
|
||||||
import com.topjohnwu.magisk.model.navigation.Navigator
|
import com.topjohnwu.magisk.model.navigation.Navigator
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
@ -25,6 +26,7 @@ abstract class MagiskFragment<ViewModel : MagiskViewModel, Binding : ViewDataBin
|
|||||||
super.onEventDispatched(event)
|
super.onEventDispatched(event)
|
||||||
when (event) {
|
when (event) {
|
||||||
is MagiskNavigationEvent -> navigateTo(event)
|
is MagiskNavigationEvent -> navigateTo(event)
|
||||||
|
is ViewActionEvent -> event.action(requireActivity())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package com.topjohnwu.magisk.ui.base
|
package com.topjohnwu.magisk.ui.base
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
import com.skoumal.teanity.viewmodel.LoadingViewModel
|
import com.skoumal.teanity.viewmodel.LoadingViewModel
|
||||||
|
import com.topjohnwu.magisk.model.events.ViewActionEvent
|
||||||
import com.topjohnwu.magisk.utils.Event
|
import com.topjohnwu.magisk.utils.Event
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
@ -10,4 +12,8 @@ abstract class MagiskViewModel : LoadingViewModel(), Event.AutoListener {
|
|||||||
override fun onEvent(event: Int) = Timber.i("Event of $event was not handled")
|
override fun onEvent(event: Int) = Timber.i("Event of $event was not handled")
|
||||||
override fun getListeningEvents(): IntArray = intArrayOf()
|
override fun getListeningEvents(): IntArray = intArrayOf()
|
||||||
|
|
||||||
|
fun withView(action: Activity.() -> Unit) {
|
||||||
|
ViewActionEvent(action).publish()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,63 +0,0 @@
|
|||||||
package com.topjohnwu.magisk.ui.superuser;
|
|
||||||
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import com.topjohnwu.magisk.R;
|
|
||||||
import com.topjohnwu.magisk.model.adapters.PolicyAdapter;
|
|
||||||
import com.topjohnwu.magisk.model.entity.Policy;
|
|
||||||
import com.topjohnwu.magisk.ui.base.BaseFragment;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
import butterknife.BindView;
|
|
||||||
|
|
||||||
public class SuperuserFragment extends BaseFragment {
|
|
||||||
|
|
||||||
@BindView(R.id.recyclerView) RecyclerView recyclerView;
|
|
||||||
@BindView(R.id.empty_rv) TextView emptyRv;
|
|
||||||
|
|
||||||
private PackageManager pm;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
|
||||||
View view = inflater.inflate(R.layout.fragment_superuser, container, false);
|
|
||||||
unbinder = new SuperuserFragment_ViewBinding(this, view);
|
|
||||||
|
|
||||||
pm = requireActivity().getPackageManager();
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStart() {
|
|
||||||
super.onStart();
|
|
||||||
requireActivity().setTitle(getString(R.string.superuser));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
displayPolicyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void displayPolicyList() {
|
|
||||||
List<Policy> policyList = app.getDB().getPolicyList();
|
|
||||||
|
|
||||||
if (policyList.size() == 0) {
|
|
||||||
emptyRv.setVisibility(View.VISIBLE);
|
|
||||||
recyclerView.setVisibility(View.GONE);
|
|
||||||
} else {
|
|
||||||
recyclerView.setAdapter(new PolicyAdapter(policyList, app.getDB(), pm));
|
|
||||||
emptyRv.setVisibility(View.GONE);
|
|
||||||
recyclerView.setVisibility(View.VISIBLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,24 @@
|
|||||||
|
package com.topjohnwu.magisk.ui.superuser
|
||||||
|
|
||||||
|
import com.topjohnwu.magisk.R
|
||||||
|
import com.topjohnwu.magisk.databinding.FragmentSuperuserBinding
|
||||||
|
import com.topjohnwu.magisk.ui.base.MagiskFragment
|
||||||
|
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||||
|
|
||||||
|
class SuperuserFragment :
|
||||||
|
MagiskFragment<SuperuserViewModel, FragmentSuperuserBinding>() {
|
||||||
|
|
||||||
|
override val layoutRes: Int = R.layout.fragment_superuser
|
||||||
|
override val viewModel: SuperuserViewModel by viewModel()
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
magiskActivity.supportActionBar?.title = getString(R.string.superuser)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
viewModel.updatePolicies()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,146 @@
|
|||||||
|
package com.topjohnwu.magisk.ui.superuser
|
||||||
|
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.content.res.Resources
|
||||||
|
import com.skoumal.teanity.databinding.ComparableRvItem
|
||||||
|
import com.skoumal.teanity.extensions.addOnPropertyChangedCallback
|
||||||
|
import com.skoumal.teanity.extensions.applySchedulers
|
||||||
|
import com.skoumal.teanity.util.DiffObservableList
|
||||||
|
import com.skoumal.teanity.viewevents.SnackbarEvent
|
||||||
|
import com.topjohnwu.magisk.BR
|
||||||
|
import com.topjohnwu.magisk.R
|
||||||
|
import com.topjohnwu.magisk.data.database.MagiskDB
|
||||||
|
import com.topjohnwu.magisk.model.entity.Policy
|
||||||
|
import com.topjohnwu.magisk.model.entity.recycler.PolicyRvItem
|
||||||
|
import com.topjohnwu.magisk.ui.base.MagiskViewModel
|
||||||
|
import com.topjohnwu.magisk.utils.FingerprintHelper
|
||||||
|
import com.topjohnwu.magisk.utils.toggle
|
||||||
|
import com.topjohnwu.magisk.view.dialogs.CustomAlertDialog
|
||||||
|
import com.topjohnwu.magisk.view.dialogs.FingerprintAuthDialog
|
||||||
|
import io.reactivex.Single
|
||||||
|
import me.tatarka.bindingcollectionadapter2.ItemBinding
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
class SuperuserViewModel(
|
||||||
|
private val database: MagiskDB,
|
||||||
|
private val packageManager: PackageManager,
|
||||||
|
private val resources: Resources
|
||||||
|
) : MagiskViewModel() {
|
||||||
|
|
||||||
|
val items = DiffObservableList(ComparableRvItem.callback)
|
||||||
|
val itemBinding = ItemBinding.of<ComparableRvItem<*>> { itemBinding, _, item ->
|
||||||
|
item.bind(itemBinding)
|
||||||
|
itemBinding.bindExtra(BR.viewModel, this@SuperuserViewModel)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var ignoreNext: PolicyRvItem? = null
|
||||||
|
|
||||||
|
init {
|
||||||
|
updatePolicies()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updatePolicies() {
|
||||||
|
Single.fromCallable { database.policyList }
|
||||||
|
.flattenAsFlowable { it }
|
||||||
|
.map { PolicyRvItem(it, it.info.loadIcon(packageManager)).setListeners() }
|
||||||
|
.toList()
|
||||||
|
.applySchedulers()
|
||||||
|
.applyViewModel(this)
|
||||||
|
.subscribe({
|
||||||
|
items.update(it)
|
||||||
|
}, Timber::e)
|
||||||
|
.add()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deletePressed(item: PolicyRvItem) {
|
||||||
|
fun updateState() = deletePolicy(item.item)
|
||||||
|
.subscribe({
|
||||||
|
items.remove(item)
|
||||||
|
}, Timber::e)
|
||||||
|
.add()
|
||||||
|
|
||||||
|
withView {
|
||||||
|
if (FingerprintHelper.useFingerprint()) {
|
||||||
|
FingerprintAuthDialog(this) { updateState() }.show()
|
||||||
|
} else {
|
||||||
|
CustomAlertDialog(this)
|
||||||
|
.setTitle(R.string.su_revoke_title)
|
||||||
|
.setMessage(getString(R.string.su_revoke_msg, item.item.appName))
|
||||||
|
.setPositiveButton(R.string.yes) { _, _ -> updateState() }
|
||||||
|
.setNegativeButton(R.string.no_thanks, null)
|
||||||
|
.setCancelable(true)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun PolicyRvItem.setListeners() = apply {
|
||||||
|
isEnabled.addOnPropertyChangedCallback {
|
||||||
|
it ?: return@addOnPropertyChangedCallback
|
||||||
|
|
||||||
|
if (ignoreNext == this) {
|
||||||
|
ignoreNext = null
|
||||||
|
return@addOnPropertyChangedCallback
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateState() {
|
||||||
|
item.policy = if (it) Policy.ALLOW else Policy.DENY
|
||||||
|
|
||||||
|
updatePolicy(item)
|
||||||
|
.map { it.policy == Policy.ALLOW }
|
||||||
|
.subscribe({
|
||||||
|
val textId = if (it) R.string.su_snack_grant else R.string.su_snack_deny
|
||||||
|
val text = resources.getString(textId).format(item.appName)
|
||||||
|
SnackbarEvent(text).publish()
|
||||||
|
}, Timber::e)
|
||||||
|
.add()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FingerprintHelper.useFingerprint()) {
|
||||||
|
withView {
|
||||||
|
FingerprintAuthDialog(this, { updateState() }, {
|
||||||
|
ignoreNext = this@setListeners
|
||||||
|
isEnabled.toggle()
|
||||||
|
}).show()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
updateState()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shouldNotify.addOnPropertyChangedCallback {
|
||||||
|
it ?: return@addOnPropertyChangedCallback
|
||||||
|
item.notification = it
|
||||||
|
|
||||||
|
updatePolicy(item)
|
||||||
|
.map { it.notification }
|
||||||
|
.subscribe({
|
||||||
|
val textId = if (it) R.string.su_snack_notif_on else R.string.su_snack_notif_off
|
||||||
|
val text = resources.getString(textId).format(item.appName)
|
||||||
|
SnackbarEvent(text).publish()
|
||||||
|
}, Timber::e)
|
||||||
|
.add()
|
||||||
|
}
|
||||||
|
shouldLog.addOnPropertyChangedCallback {
|
||||||
|
it ?: return@addOnPropertyChangedCallback
|
||||||
|
item.logging = it
|
||||||
|
|
||||||
|
updatePolicy(item)
|
||||||
|
.map { it.logging }
|
||||||
|
.subscribe({
|
||||||
|
val textId = if (it) R.string.su_snack_log_on else R.string.su_snack_log_off
|
||||||
|
val text = resources.getString(textId).format(item.appName)
|
||||||
|
SnackbarEvent(text).publish()
|
||||||
|
}, Timber::e)
|
||||||
|
.add()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updatePolicy(policy: Policy) =
|
||||||
|
Single.fromCallable { database.updatePolicy(policy); policy }
|
||||||
|
.applySchedulers()
|
||||||
|
|
||||||
|
private fun deletePolicy(policy: Policy) =
|
||||||
|
Single.fromCallable { database.deletePolicy(policy); policy }
|
||||||
|
.applySchedulers()
|
||||||
|
|
||||||
|
}
|
@ -1,11 +1,42 @@
|
|||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="viewModel"
|
||||||
|
type="com.topjohnwu.magisk.ui.superuser.SuperuserViewModel" />
|
||||||
|
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/superuser_content"
|
||||||
|
dividerColor="@{@android:color/transparent}"
|
||||||
|
dividerSize="@{@dimen/margin_generic}"
|
||||||
|
gone="@{!viewModel.loaded}"
|
||||||
|
itemBinding="@{viewModel.itemBinding}"
|
||||||
|
items="@{viewModel.items}"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical">
|
android:clipToPadding="false"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="@dimen/margin_generic"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
tools:listitem="@layout/item_policy" />
|
||||||
|
|
||||||
<TextView
|
<ProgressBar
|
||||||
android:id="@+id/empty_rv"
|
style="@style/Widget.Progress"
|
||||||
|
gone="@{!viewModel.loading}"
|
||||||
|
android:layout_gravity="center" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
|
android:id="@+id/superuser_empty"
|
||||||
|
gone="@{!viewModel.loaded || viewModel.items.size > 0}"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
@ -13,14 +44,10 @@
|
|||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:text="@string/no_apps_found"
|
android:text="@string/no_apps_found"
|
||||||
android:textSize="20sp"
|
android:textSize="20sp"
|
||||||
android:textStyle="italic"
|
android:textStyle="italic" />
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
</FrameLayout>
|
||||||
android:id="@+id/recyclerView"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
</layout>
|
||||||
android:dividerHeight="@dimen/card_divider_space"
|
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
213
app/src/main/res/layout/item_policy.xml
Normal file
213
app/src/main/res/layout/item_policy.xml
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
<?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.ui.superuser.SuperuserViewModel" />
|
||||||
|
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
style="@style/Widget.Card"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:foreground="?attr/selectableItemBackground"
|
||||||
|
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||||
|
android:onClick="@{() -> item.toggle()}"
|
||||||
|
app:cardCornerRadius="@dimen/radius_generic"
|
||||||
|
app:cardElevation="2dp"
|
||||||
|
app:cardPreventCornerOverlap="true">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:animateLayoutChanges="true"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:padding="@dimen/margin_generic_half">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
|
android:id="@+id/app_icon"
|
||||||
|
android:layout_width="50dp"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:gravity="end"
|
||||||
|
android:src="@{item.icon}"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/app_name"
|
||||||
|
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_marginRight="@dimen/margin_generic"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:text="@{item.item.appName}"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
|
android:textIsSelectable="false"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/package_name"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/master_switch"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/app_icon"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintVertical_chainStyle="packed"
|
||||||
|
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="end"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:text="@{item.item.packageName}"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||||
|
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.appcompat.widget.SwitchCompat
|
||||||
|
android:id="@+id/master_switch"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:checked="@={item.isEnabled}"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/app_name"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/expand_layout"
|
||||||
|
gone="@{!item.isExpanded}"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingBottom="@dimen/margin_generic_half"
|
||||||
|
android:paddingTop="@dimen/margin_generic_half"
|
||||||
|
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"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:tint="@color/icon_grey"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/notification_switch"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:srcCompat="@drawable/ic_notifications" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.SwitchCompat
|
||||||
|
android:id="@+id/notification_switch"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:checked="@={item.shouldNotify}"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/guideline"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/bell"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.Guideline
|
||||||
|
android:id="@+id/guideline"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:layout_constraintGuide_percent="0.4" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
|
android:id="@+id/bug"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:tint="@color/icon_grey"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/logging_switch"
|
||||||
|
app:layout_constraintStart_toStartOf="@+id/guideline"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:srcCompat="@drawable/ic_bug_report" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.SwitchCompat
|
||||||
|
android:id="@+id/logging_switch"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:checked="@={item.shouldLog}"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/guideline2"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/bug"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.Guideline
|
||||||
|
android:id="@+id/guideline2"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:layout_constraintGuide_percent="0.8" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
|
android:id="@+id/more_info"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="?android:attr/selectableItemBackground"
|
||||||
|
android:tint="@color/icon_grey"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/delete"
|
||||||
|
app:layout_constraintStart_toStartOf="@id/guideline2"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:srcCompat="@drawable/ic_more" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
|
android:id="@+id/delete"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="?android:attr/selectableItemBackground"
|
||||||
|
android:onClick="@{() -> viewModel.deletePressed(item)}"
|
||||||
|
android:tint="@color/icon_grey"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/more_info"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:srcCompat="@drawable/ic_delete" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
</layout>
|
@ -9,6 +9,7 @@
|
|||||||
<item name="imageColorTint">@color/dark_secondary_text</item>
|
<item name="imageColorTint">@color/dark_secondary_text</item>
|
||||||
<item name="colorControl">?android:attr/textColorSecondary</item>
|
<item name="colorControl">?android:attr/textColorSecondary</item>
|
||||||
<item name="colorAccentFallback">@color/accentFallback</item>
|
<item name="colorAccentFallback">@color/accentFallback</item>
|
||||||
|
<item name="android:windowBackground">@android:color/black</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
@ -10,6 +10,7 @@
|
|||||||
<item name="colorAccent">@color/colorSecondary</item>
|
<item name="colorAccent">@color/colorSecondary</item>
|
||||||
<item name="colorSecondary">@color/colorSecondary</item>
|
<item name="colorSecondary">@color/colorSecondary</item>
|
||||||
<item name="colorSecondaryVariant">@color/colorSecondaryDark</item>
|
<item name="colorSecondaryVariant">@color/colorSecondaryDark</item>
|
||||||
|
<item name="android:windowBackground">@android:color/white</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="ThemeFoundation.Colored.ExtraProps" />
|
<style name="ThemeFoundation.Colored.ExtraProps" />
|
||||||
|
Loading…
x
Reference in New Issue
Block a user