From 9094cf7ce3f15242b9b166f4d6d8005880da781b Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sun, 12 Jan 2020 16:07:30 +0800 Subject: [PATCH] Replace old design with redesign (p2) --- app/src/main/java/a/g.java | 4 +- .../main/java/com/topjohnwu/magisk/Hacks.kt | 6 +- .../topjohnwu/magisk/di/ViewModelsModule.kt | 12 - .../model/entity/recycler/HideRvItem.kt | 85 --- .../magisk/model/entity/recycler/LogRvItem.kt | 72 +-- .../model/entity/recycler/ModuleRvItem.kt | 70 +-- .../model/entity/recycler/PolicyRvItem.kt | 45 +- .../topjohnwu/magisk/model/events/RxEvents.kt | 10 +- .../magisk/model/navigation/Navigation.kt | 10 +- .../magisk/redesign/home/HomeViewModel.kt | 5 +- .../redesign/safetynet/SafetynetViewModel.kt | 8 +- .../com/topjohnwu/magisk/ui/MainActivity.kt | 252 --------- .../com/topjohnwu/magisk/ui/MainViewModel.kt | 29 - .../topjohnwu/magisk/ui/hide/HideViewModel.kt | 96 ---- .../magisk/ui/hide/MagiskHideFragment.kt | 71 --- .../topjohnwu/magisk/ui/home/HomeFragment.kt | 132 ----- .../topjohnwu/magisk/ui/home/HomeViewModel.kt | 259 --------- .../topjohnwu/magisk/ui/log/LogFragment.kt | 57 -- .../topjohnwu/magisk/ui/log/LogViewModel.kt | 120 ----- .../magisk/ui/module/ModuleViewModel.kt | 111 ---- .../magisk/ui/module/ModulesFragment.kt | 99 ---- .../magisk/ui/module/ReposFragment.kt | 116 ---- .../magisk/ui/settings/SettingsFragment.kt | 347 ------------ .../magisk/ui/superuser/SuperuserFragment.kt | 25 - .../magisk/ui/superuser/SuperuserViewModel.kt | 151 ------ .../com/topjohnwu/magisk/view/Shortcuts.kt | 13 - app/src/main/res/layout/activity_main.xml | 38 -- .../main/res/layout/activity_main_content.xml | 46 -- .../main/res/layout/custom_channel_dialog.xml | 24 - .../res/layout/custom_download_dialog.xml | 46 -- .../main/res/layout/dialog_custom_name.xml | 46 -- app/src/main/res/layout/fragment_home_md2.xml | 4 +- app/src/main/res/layout/fragment_log.xml | 37 -- app/src/main/res/layout/fragment_magisk.xml | 503 ------------------ .../main/res/layout/fragment_magisk_hide.xml | 36 -- app/src/main/res/layout/fragment_modules.xml | 70 --- app/src/main/res/layout/fragment_repos.xml | 56 -- .../main/res/layout/fragment_superuser.xml | 53 -- .../main/res/layout/include_update_card.xml | 151 ------ app/src/main/res/layout/item_hide_app.xml | 126 ----- app/src/main/res/layout/item_hide_process.xml | 57 -- app/src/main/res/layout/item_module.xml | 149 ------ app/src/main/res/layout/item_page_log.xml | 37 -- .../main/res/layout/item_page_magisk_log.xml | 56 -- app/src/main/res/layout/item_policy.xml | 211 -------- app/src/main/res/layout/item_repo.xml | 130 ----- .../main/res/layout/item_superuser_log.xml | 84 --- .../res/layout/item_superuser_log_entry.xml | 112 ---- app/src/main/res/menu/drawer.xml | 59 -- app/src/main/res/menu/menu_log.xml | 24 - app/src/main/res/menu/menu_magiskhide.xml | 16 - 51 files changed, 22 insertions(+), 4354 deletions(-) delete mode 100644 app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.kt delete mode 100644 app/src/main/java/com/topjohnwu/magisk/ui/MainViewModel.kt delete mode 100644 app/src/main/java/com/topjohnwu/magisk/ui/hide/HideViewModel.kt delete mode 100644 app/src/main/java/com/topjohnwu/magisk/ui/hide/MagiskHideFragment.kt delete mode 100644 app/src/main/java/com/topjohnwu/magisk/ui/home/HomeFragment.kt delete mode 100644 app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt delete mode 100644 app/src/main/java/com/topjohnwu/magisk/ui/log/LogFragment.kt delete mode 100644 app/src/main/java/com/topjohnwu/magisk/ui/log/LogViewModel.kt delete mode 100644 app/src/main/java/com/topjohnwu/magisk/ui/module/ModuleViewModel.kt delete mode 100644 app/src/main/java/com/topjohnwu/magisk/ui/module/ModulesFragment.kt delete mode 100644 app/src/main/java/com/topjohnwu/magisk/ui/module/ReposFragment.kt delete mode 100644 app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt delete mode 100644 app/src/main/java/com/topjohnwu/magisk/ui/superuser/SuperuserFragment.kt delete mode 100644 app/src/main/java/com/topjohnwu/magisk/ui/superuser/SuperuserViewModel.kt delete mode 100644 app/src/main/res/layout/activity_main.xml delete mode 100644 app/src/main/res/layout/activity_main_content.xml delete mode 100644 app/src/main/res/layout/custom_channel_dialog.xml delete mode 100644 app/src/main/res/layout/custom_download_dialog.xml delete mode 100644 app/src/main/res/layout/dialog_custom_name.xml delete mode 100644 app/src/main/res/layout/fragment_log.xml delete mode 100644 app/src/main/res/layout/fragment_magisk.xml delete mode 100644 app/src/main/res/layout/fragment_magisk_hide.xml delete mode 100644 app/src/main/res/layout/fragment_modules.xml delete mode 100644 app/src/main/res/layout/fragment_repos.xml delete mode 100644 app/src/main/res/layout/fragment_superuser.xml delete mode 100644 app/src/main/res/layout/include_update_card.xml delete mode 100644 app/src/main/res/layout/item_hide_app.xml delete mode 100644 app/src/main/res/layout/item_hide_process.xml delete mode 100644 app/src/main/res/layout/item_module.xml delete mode 100644 app/src/main/res/layout/item_page_log.xml delete mode 100644 app/src/main/res/layout/item_page_magisk_log.xml delete mode 100644 app/src/main/res/layout/item_policy.xml delete mode 100644 app/src/main/res/layout/item_repo.xml delete mode 100644 app/src/main/res/layout/item_superuser_log.xml delete mode 100644 app/src/main/res/layout/item_superuser_log_entry.xml delete mode 100644 app/src/main/res/menu/drawer.xml delete mode 100644 app/src/main/res/menu/menu_log.xml delete mode 100644 app/src/main/res/menu/menu_magiskhide.xml diff --git a/app/src/main/java/a/g.java b/app/src/main/java/a/g.java index ceaf4ff41..168ceb9fb 100644 --- a/app/src/main/java/a/g.java +++ b/app/src/main/java/a/g.java @@ -2,11 +2,11 @@ package a; import android.content.Context; -import com.topjohnwu.magisk.model.update.UpdateCheckService; - import androidx.annotation.NonNull; import androidx.work.WorkerParameters; +import com.topjohnwu.magisk.model.update.UpdateCheckService; + public class g extends w { /* Stub */ public g(@NonNull Context context, @NonNull WorkerParameters workerParams) { diff --git a/app/src/main/java/com/topjohnwu/magisk/Hacks.kt b/app/src/main/java/com/topjohnwu/magisk/Hacks.kt index 18bdf85c7..df21b4d2c 100644 --- a/app/src/main/java/com/topjohnwu/magisk/Hacks.kt +++ b/app/src/main/java/com/topjohnwu/magisk/Hacks.kt @@ -18,13 +18,12 @@ import com.topjohnwu.magisk.extensions.forceGetDeclaredField import com.topjohnwu.magisk.model.download.DownloadService import com.topjohnwu.magisk.model.receiver.GeneralReceiver import com.topjohnwu.magisk.model.update.UpdateCheckService -import com.topjohnwu.magisk.ui.MainActivity +import com.topjohnwu.magisk.redesign.MainActivity import com.topjohnwu.magisk.ui.SplashActivity import com.topjohnwu.magisk.ui.flash.FlashActivity import com.topjohnwu.magisk.ui.surequest.SuRequestActivity import com.topjohnwu.magisk.utils.refreshLocale import com.topjohnwu.magisk.utils.updateConfig -import com.topjohnwu.magisk.redesign.MainActivity as RedesignActivity fun AssetManager.addAssetPath(path: String) { DynAPK.addAssetPath(this, path) @@ -150,8 +149,7 @@ object ClassMap { GeneralReceiver::class.java to a.h::class.java, DownloadService::class.java to a.j::class.java, SuRequestActivity::class.java to a.m::class.java, - ProcessPhoenix::class.java to a.r::class.java, - RedesignActivity::class.java to a.b::class.java + ProcessPhoenix::class.java to a.r::class.java ) operator fun get(c: Class<*>) = map.getOrElse(c) { c } diff --git a/app/src/main/java/com/topjohnwu/magisk/di/ViewModelsModule.kt b/app/src/main/java/com/topjohnwu/magisk/di/ViewModelsModule.kt index b76c897f0..8df400983 100644 --- a/app/src/main/java/com/topjohnwu/magisk/di/ViewModelsModule.kt +++ b/app/src/main/java/com/topjohnwu/magisk/di/ViewModelsModule.kt @@ -1,25 +1,13 @@ package com.topjohnwu.magisk.di import android.net.Uri -import com.topjohnwu.magisk.ui.MainViewModel import com.topjohnwu.magisk.ui.flash.FlashViewModel -import com.topjohnwu.magisk.ui.hide.HideViewModel -import com.topjohnwu.magisk.ui.home.HomeViewModel -import com.topjohnwu.magisk.ui.log.LogViewModel -import com.topjohnwu.magisk.ui.module.ModuleViewModel -import com.topjohnwu.magisk.ui.superuser.SuperuserViewModel import com.topjohnwu.magisk.ui.surequest.SuRequestViewModel import org.koin.androidx.viewmodel.dsl.viewModel import org.koin.dsl.module val viewModelModules = module { - viewModel { MainViewModel() } - viewModel { HomeViewModel(get()) } - viewModel { SuperuserViewModel(get(), get(), get(), get()) } - viewModel { HideViewModel(get(), get()) } - viewModel { ModuleViewModel(get(), get(), get()) } - viewModel { LogViewModel(get(), get()) } viewModel { (action: String, file: Uri, additional: Uri) -> FlashViewModel(action, file, additional, get()) } diff --git a/app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/HideRvItem.kt b/app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/HideRvItem.kt index 6a32beb51..30befa36e 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/HideRvItem.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/HideRvItem.kt @@ -5,20 +5,13 @@ import android.view.ViewGroup import com.topjohnwu.magisk.R import com.topjohnwu.magisk.databinding.ComparableRvItem import com.topjohnwu.magisk.extensions.addOnPropertyChangedCallback -import com.topjohnwu.magisk.extensions.inject import com.topjohnwu.magisk.extensions.startAnimations import com.topjohnwu.magisk.extensions.toggle -import com.topjohnwu.magisk.model.entity.HideAppInfo -import com.topjohnwu.magisk.model.entity.HideTarget import com.topjohnwu.magisk.model.entity.ProcessHideApp import com.topjohnwu.magisk.model.entity.StatefulProcess -import com.topjohnwu.magisk.model.entity.state.IndeterminateState -import com.topjohnwu.magisk.model.events.HideProcessEvent import com.topjohnwu.magisk.model.observer.Observer import com.topjohnwu.magisk.redesign.hide.HideViewModel -import com.topjohnwu.magisk.utils.DiffObservableList import com.topjohnwu.magisk.utils.KObservableField -import com.topjohnwu.magisk.utils.RxBus import kotlin.math.roundToInt class HideItem(val item: ProcessHideApp) : ComparableRvItem() { @@ -86,81 +79,3 @@ class HideProcessItem(val item: StatefulProcess) : ComparableRvItem) : - ComparableRvItem() { - - override val layoutRes: Int = R.layout.item_hide_app - - val packageName = item.info.packageName.orEmpty() - val items = DiffObservableList(callback).also { - val items = item.processes.map { - val isHidden = targets.any { target -> - packageName == target.packageName && it == target.process - } - HideProcessRvItem(packageName, it, isHidden) - } - it.update(items) - } - val isHiddenState = KObservableField(currentState) - val isExpanded = KObservableField(false) - - private val itemsProcess get() = items.filterIsInstance() - - private val currentState - get() = when (itemsProcess.count { it.isHidden.value }) { - items.size -> IndeterminateState.CHECKED - in 1 until items.size -> IndeterminateState.INDETERMINATE - else -> IndeterminateState.UNCHECKED - } - - init { - itemsProcess.forEach { - it.isHidden.addOnPropertyChangedCallback { isHiddenState.value = currentState } - } - } - - fun toggle() { - val desiredState = when (isHiddenState.value) { - IndeterminateState.INDETERMINATE, - IndeterminateState.UNCHECKED -> true - IndeterminateState.CHECKED -> false - } - itemsProcess.forEach { it.isHidden.value = desiredState } - isHiddenState.value = currentState - } - - fun toggleExpansion() { - if (items.size <= 1) return - isExpanded.toggle() - } - - override fun contentSameAs(other: HideRvItem): Boolean = items.all { other.items.contains(it) } - override fun itemSameAs(other: HideRvItem): Boolean = item.info == other.item.info - -} - -class HideProcessRvItem( - val packageName: String, - val process: String, - isHidden: Boolean -) : ComparableRvItem() { - - override val layoutRes: Int = R.layout.item_hide_process - - val isHidden = KObservableField(isHidden) - - private val rxBus: RxBus by inject() - - init { - this.isHidden.addOnPropertyChangedCallback { - rxBus.post(HideProcessEvent(this@HideProcessRvItem)) - } - } - - fun toggle() = isHidden.toggle() - - override fun contentSameAs(other: HideProcessRvItem): Boolean = itemSameAs(other) - override fun itemSameAs(other: HideProcessRvItem): Boolean = - packageName == other.packageName && process == other.process -} \ No newline at end of file diff --git a/app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/LogRvItem.kt b/app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/LogRvItem.kt index c4aef525a..fe919e39a 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/LogRvItem.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/LogRvItem.kt @@ -3,79 +3,9 @@ package com.topjohnwu.magisk.model.entity.recycler import androidx.databinding.Bindable import com.topjohnwu.magisk.BR import com.topjohnwu.magisk.R -import com.topjohnwu.magisk.databinding.ComparableRvItem import com.topjohnwu.magisk.extensions.timeDateFormat -import com.topjohnwu.magisk.extensions.timeFormatMedium import com.topjohnwu.magisk.extensions.toTime -import com.topjohnwu.magisk.extensions.toggle import com.topjohnwu.magisk.model.entity.MagiskLog -import com.topjohnwu.magisk.model.entity.WrappedMagiskLog -import com.topjohnwu.magisk.utils.DiffObservableList -import com.topjohnwu.magisk.utils.KObservableField - -class LogRvItem : ComparableRvItem() { - override val layoutRes: Int = R.layout.item_page_log - - val items = DiffObservableList(callback) - - fun update(list: List) { - list.firstOrNull()?.isExpanded?.value = true - items.update(list) - } - - //two of these will never be present, safe to assume it's unique - override fun contentSameAs(other: LogRvItem): Boolean = false - - override fun itemSameAs(other: LogRvItem): Boolean = false -} - -class LogItemRvItem( - item: WrappedMagiskLog -) : ComparableRvItem() { - override val layoutRes: Int = R.layout.item_superuser_log - - val date = item.time.toTime(timeFormatMedium) - val items: List> = item.items.map { LogItemEntryRvItem(it) } - val isExpanded = KObservableField(false) - - fun toggle() = isExpanded.toggle() - - override fun contentSameAs(other: LogItemRvItem): Boolean { - if (items.size != other.items.size) return false - return items.all { it in other.items } - } - - override fun itemSameAs(other: LogItemRvItem): Boolean = date == other.date -} - -class LogItemEntryRvItem(val item: MagiskLog) : ComparableRvItem() { - override val layoutRes: Int = R.layout.item_superuser_log_entry - - val isExpanded = KObservableField(false) - - fun toggle() = isExpanded.toggle() - - override fun contentSameAs(other: LogItemEntryRvItem) = item == other.item - - override fun itemSameAs(other: LogItemEntryRvItem) = item.appName == other.item.appName -} - -class MagiskLogRvItem : ComparableRvItem() { - override val layoutRes: Int = R.layout.item_page_magisk_log - - val items = DiffObservableList(callback) - - fun update(list: List) { - items.update(list) - } - - //two of these will never be present, safe to assume it's unique - override fun contentSameAs(other: MagiskLogRvItem): Boolean = false - - override fun itemSameAs(other: MagiskLogRvItem): Boolean = false -} - -// --- class LogItem(val item: MagiskLog) : ObservableItem() { @@ -106,4 +36,4 @@ class LogItem(val item: MagiskLog) : ObservableItem() { item.time == other.item.time && isTop == other.isTop && isBottom == other.isBottom -} \ No newline at end of file +} diff --git a/app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/ModuleRvItem.kt b/app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/ModuleRvItem.kt index 3d4bb21a7..1a8a2f2c3 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/ModuleRvItem.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/entity/recycler/ModuleRvItem.kt @@ -1,7 +1,5 @@ package com.topjohnwu.magisk.model.entity.recycler -import android.content.res.Resources -import androidx.annotation.StringRes import androidx.databinding.Bindable import androidx.databinding.Observable import androidx.databinding.PropertyChangeRegistry @@ -10,77 +8,11 @@ import androidx.recyclerview.widget.StaggeredGridLayoutManager import com.topjohnwu.magisk.BR import com.topjohnwu.magisk.R import com.topjohnwu.magisk.databinding.ComparableRvItem -import com.topjohnwu.magisk.extensions.addOnPropertyChangedCallback -import com.topjohnwu.magisk.extensions.get -import com.topjohnwu.magisk.extensions.toggle import com.topjohnwu.magisk.model.entity.module.Module import com.topjohnwu.magisk.model.entity.module.Repo import com.topjohnwu.magisk.redesign.module.ModuleViewModel import com.topjohnwu.magisk.utils.KObservableField -class ModuleRvItem(val item: Module) : ComparableRvItem() { - - override val layoutRes: Int = R.layout.item_module - - val lastActionNotice = KObservableField("") - val isChecked = KObservableField(item.enable) - val isDeletable = KObservableField(item.remove) - - init { - isChecked.addOnPropertyChangedCallback { - when (it) { - true -> { - item.enable = true - notice(R.string.disable_file_removed) - } - false -> { - item.enable = false - notice(R.string.disable_file_created) - } - } - } - isDeletable.addOnPropertyChangedCallback { - when (it) { - true -> { - item.remove = true - notice(R.string.remove_file_created) - } - false -> { - item.remove = false - notice(R.string.remove_file_deleted) - } - } - } - when { - item.updated -> notice(R.string.update_file_created) - item.remove -> notice(R.string.remove_file_created) - } - } - - fun toggle() = isChecked.toggle() - fun toggleDelete() = isDeletable.toggle() - - private fun notice(@StringRes info: Int) { - lastActionNotice.value = get().getString(info) - } - - override fun contentSameAs(other: ModuleRvItem): Boolean = item.version == other.item.version - && item.versionCode == other.item.versionCode - && item.description == other.item.description - && item.name == other.item.name - - override fun itemSameAs(other: ModuleRvItem): Boolean = item.id == other.item.id -} - -class RepoRvItem(val item: Repo) : ComparableRvItem() { - - override val layoutRes: Int = R.layout.item_repo - - override fun contentSameAs(other: RepoRvItem): Boolean = item == other.item - - override fun itemSameAs(other: RepoRvItem): Boolean = item.id == other.item.id -} - object SafeModeNotice : ComparableRvItem() { override val layoutRes = R.layout.item_safe_mode_notice @@ -227,4 +159,4 @@ abstract class ObservableItem : ComparableRvItem(), Observable { fun notifyChange(id: Int) = list.notifyChange(this, id) -} \ No newline at end of file +} 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 c6f1593df..6d12c729e 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 @@ -3,54 +3,11 @@ package com.topjohnwu.magisk.model.entity.recycler import android.graphics.drawable.Drawable import com.topjohnwu.magisk.R import com.topjohnwu.magisk.databinding.ComparableRvItem -import com.topjohnwu.magisk.extensions.addOnPropertyChangedCallback -import com.topjohnwu.magisk.extensions.inject import com.topjohnwu.magisk.extensions.toggle import com.topjohnwu.magisk.model.entity.MagiskPolicy -import com.topjohnwu.magisk.model.events.PolicyEnableEvent 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 - -class PolicyRvItem(val item: MagiskPolicy, val icon: Drawable) : ComparableRvItem() { - - override val layoutRes = R.layout.item_policy - - val isExpanded = KObservableField(false) - val isEnabled = KObservableField(item.policy == MagiskPolicy.ALLOW) - val shouldNotify = KObservableField(item.notification) - val shouldLog = KObservableField(item.logging) - - fun toggle() = isExpanded.toggle() - - private val rxBus: RxBus by inject() - - private val currentStateItem - get() = item.copy( - policy = if (isEnabled.value) MagiskPolicy.ALLOW else MagiskPolicy.DENY, - notification = shouldNotify.value, - logging = shouldLog.value - ) - - init { - isEnabled.addOnPropertyChangedCallback { - it ?: return@addOnPropertyChangedCallback - rxBus.post(PolicyEnableEvent(this@PolicyRvItem, it)) - } - shouldNotify.addOnPropertyChangedCallback { - it ?: return@addOnPropertyChangedCallback - rxBus.post(PolicyUpdateEvent.Notification(currentStateItem)) - } - shouldLog.addOnPropertyChangedCallback { - it ?: return@addOnPropertyChangedCallback - rxBus.post(PolicyUpdateEvent.Log(currentStateItem)) - } - } - - override fun contentSameAs(other: PolicyRvItem): Boolean = itemSameAs(other) - override fun itemSameAs(other: PolicyRvItem): Boolean = item.uid == other.item.uid -} class PolicyItem(val item: MagiskPolicy, val icon: Drawable) : ComparableRvItem() { override val layoutRes = R.layout.item_policy_md2 @@ -93,4 +50,4 @@ class PolicyItem(val item: MagiskPolicy, val icon: Drawable) : ComparableRvItem< override fun contentSameAs(other: PolicyItem) = itemSameAs(other) override fun itemSameAs(other: PolicyItem) = item.uid == other.item.uid -} \ No newline at end of file +} diff --git a/app/src/main/java/com/topjohnwu/magisk/model/events/RxEvents.kt b/app/src/main/java/com/topjohnwu/magisk/model/events/RxEvents.kt index c3171db84..2e67b8c35 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/events/RxEvents.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/events/RxEvents.kt @@ -1,19 +1,11 @@ package com.topjohnwu.magisk.model.events import com.topjohnwu.magisk.model.entity.MagiskPolicy -import com.topjohnwu.magisk.model.entity.recycler.HideProcessRvItem -import com.topjohnwu.magisk.model.entity.recycler.ModuleRvItem -import com.topjohnwu.magisk.model.entity.recycler.PolicyRvItem import com.topjohnwu.magisk.utils.RxBus -class HideProcessEvent(val item: HideProcessRvItem) : RxBus.Event - -class PolicyEnableEvent(val item: PolicyRvItem, val enable: Boolean) : RxBus.Event sealed class PolicyUpdateEvent(val item: MagiskPolicy) : RxBus.Event { class Notification(item: MagiskPolicy) : PolicyUpdateEvent(item) class Log(item: MagiskPolicy) : PolicyUpdateEvent(item) } -class ModuleUpdatedEvent(val item: ModuleRvItem) : RxBus.Event - -data class SafetyNetResult(val responseCode: Int) : RxBus.Event \ No newline at end of file +data class SafetyNetResult(val responseCode: Int) : RxBus.Event diff --git a/app/src/main/java/com/topjohnwu/magisk/model/navigation/Navigation.kt b/app/src/main/java/com/topjohnwu/magisk/model/navigation/Navigation.kt index 11091b728..1675df86b 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/navigation/Navigation.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/navigation/Navigation.kt @@ -10,12 +10,11 @@ import com.topjohnwu.magisk.redesign.hide.HideFragment import com.topjohnwu.magisk.redesign.home.HomeFragment import com.topjohnwu.magisk.redesign.install.InstallFragment import com.topjohnwu.magisk.redesign.log.LogFragment +import com.topjohnwu.magisk.redesign.module.ModuleFragment import com.topjohnwu.magisk.redesign.safetynet.SafetynetFragment import com.topjohnwu.magisk.redesign.settings.SettingsFragment import com.topjohnwu.magisk.redesign.superuser.SuperuserFragment import com.topjohnwu.magisk.redesign.theme.ThemeFragment -import com.topjohnwu.magisk.ui.module.ModulesFragment -import com.topjohnwu.magisk.ui.module.ReposFragment object Navigation { @@ -36,14 +35,10 @@ object Navigation { fun modules() = MagiskNavigationEvent { navDirections { - destination = ModulesFragment::class + destination = ModuleFragment::class } } - fun repos() = MagiskNavigationEvent { - navDirections { destination = ReposFragment::class } - } - fun hide() = MagiskNavigationEvent { navDirections { destination = HideFragment::class @@ -77,7 +72,6 @@ object Navigation { fun fromSection(section: String) = when (section) { "superuser" -> superuser() "modules" -> modules() - "downloads" -> repos() "magiskhide" -> hide() "log" -> log() "settings" -> settings() diff --git a/app/src/main/java/com/topjohnwu/magisk/redesign/home/HomeViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/redesign/home/HomeViewModel.kt index 509c42de8..07b57f127 100644 --- a/app/src/main/java/com/topjohnwu/magisk/redesign/home/HomeViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/redesign/home/HomeViewModel.kt @@ -24,12 +24,15 @@ import com.topjohnwu.magisk.model.navigation.Navigation import com.topjohnwu.magisk.model.observer.Observer import com.topjohnwu.magisk.redesign.compat.CompatViewModel import com.topjohnwu.magisk.redesign.compat.itemBindingOf -import com.topjohnwu.magisk.ui.home.MagiskState import com.topjohnwu.magisk.utils.KObservableField import com.topjohnwu.superuser.Shell import me.tatarka.bindingcollectionadapter2.BR import kotlin.math.roundToInt +enum class MagiskState { + NOT_INSTALLED, UP_TO_DATE, OBSOLETE, LOADING +} + class HomeViewModel( private val repoMagisk: MagiskRepository ) : CompatViewModel() { diff --git a/app/src/main/java/com/topjohnwu/magisk/redesign/safetynet/SafetynetViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/redesign/safetynet/SafetynetViewModel.kt index 41b2d349b..7c0900f2a 100644 --- a/app/src/main/java/com/topjohnwu/magisk/redesign/safetynet/SafetynetViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/redesign/safetynet/SafetynetViewModel.kt @@ -7,11 +7,15 @@ import com.topjohnwu.magisk.extensions.subscribeK import com.topjohnwu.magisk.model.events.SafetyNetResult import com.topjohnwu.magisk.model.events.UpdateSafetyNetEvent import com.topjohnwu.magisk.redesign.compat.CompatViewModel -import com.topjohnwu.magisk.ui.home.SafetyNetState.* +import com.topjohnwu.magisk.redesign.safetynet.SafetyNetState.* import com.topjohnwu.magisk.utils.KObservableField import com.topjohnwu.magisk.utils.RxBus import com.topjohnwu.magisk.utils.SafetyNetHelper +enum class SafetyNetState { + LOADING, PASS, FAILED, IDLE +} + class SafetynetViewModel( rxBus: RxBus ) : CompatViewModel() { @@ -89,4 +93,4 @@ class SafetynetViewModel( private var safetyNetResult = -1 } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.kt b/app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.kt deleted file mode 100644 index e1d83a2a5..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.kt +++ /dev/null @@ -1,252 +0,0 @@ -package com.topjohnwu.magisk.ui - -import android.content.Intent -import android.os.Bundle -import androidx.appcompat.app.AlertDialog -import androidx.core.view.GravityCompat -import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentTransaction -import com.ncapdevi.fragnav.FragNavController -import com.ncapdevi.fragnav.FragNavTransactionOptions -import com.topjohnwu.magisk.Const -import com.topjohnwu.magisk.Const.Key.OPEN_SECTION -import com.topjohnwu.magisk.Info -import com.topjohnwu.magisk.R -import com.topjohnwu.magisk.base.BaseActivity -import com.topjohnwu.magisk.base.BaseFragment -import com.topjohnwu.magisk.databinding.ActivityMainBinding -import com.topjohnwu.magisk.extensions.addOnPropertyChangedCallback -import com.topjohnwu.magisk.extensions.snackbar -import com.topjohnwu.magisk.intent -import com.topjohnwu.magisk.model.events.* -import com.topjohnwu.magisk.model.navigation.MagiskAnimBuilder -import com.topjohnwu.magisk.model.navigation.MagiskNavigationEvent -import com.topjohnwu.magisk.model.navigation.Navigation -import com.topjohnwu.magisk.model.navigation.Navigator -import com.topjohnwu.magisk.ui.hide.MagiskHideFragment -import com.topjohnwu.magisk.ui.home.HomeFragment -import com.topjohnwu.magisk.ui.log.LogFragment -import com.topjohnwu.magisk.ui.module.ModulesFragment -import com.topjohnwu.magisk.ui.module.ReposFragment -import com.topjohnwu.magisk.ui.settings.SettingsFragment -import com.topjohnwu.magisk.ui.superuser.SuperuserFragment -import com.topjohnwu.magisk.utils.Utils -import org.koin.androidx.viewmodel.ext.android.viewModel -import timber.log.Timber -import kotlin.reflect.KClass - -open class MainActivity : BaseActivity(), Navigator, - FragNavController.RootFragmentListener, FragNavController.TransactionListener { - - override val layoutRes: Int = R.layout.activity_main - override val viewModel: MainViewModel by viewModel() - private val navHostId: Int = R.id.main_nav_host - private val defaultPosition: Int = 0 - - private val navigationController by lazy { - FragNavController(supportFragmentManager, navHostId) - } - private val isRootFragment get() = - navigationController.currentStackIndex != defaultPosition - - override val baseFragments: List> = listOf( - HomeFragment::class, - SuperuserFragment::class, - MagiskHideFragment::class, - ModulesFragment::class, - ReposFragment::class, - LogFragment::class, - SettingsFragment::class - ) - - override fun onCreate(savedInstanceState: Bundle?) { - if (!SplashActivity.DONE) { - startActivity(intent()) - finish() - } - - super.onCreate(savedInstanceState) - - if (Info.env.isUnsupported && !viewModel.shownUnsupportedDialog) { - viewModel.shownUnsupportedDialog = true - AlertDialog.Builder(this) - .setTitle(R.string.unsupport_magisk_title) - .setMessage(getString(R.string.unsupport_magisk_msg, Const.Version.MIN_VERSION)) - .setPositiveButton(android.R.string.ok, null) - .show() - } - - navigationController.apply { - rootFragmentListener = this@MainActivity - transactionListener = this@MainActivity - initialize(defaultPosition, savedInstanceState) - } - - checkHideSection() - setSupportActionBar(binding.mainInclude.mainToolbar) - - viewModel.isConnected.addOnPropertyChangedCallback { - checkHideSection() - } - - if (savedInstanceState == null) { - intent.getStringExtra(OPEN_SECTION)?.let { - onEventDispatched(Navigation.fromSection(it)) - } - } - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - navigationController.onSaveInstanceState(outState) - } - - override fun setTitle(title: CharSequence?) { - supportActionBar?.title = title - } - - override fun setTitle(titleId: Int) { - supportActionBar?.setTitle(titleId) - } - - override fun onBackPressed() { - if (binding.drawerLayout.isDrawerOpen(binding.navView)) { - binding.drawerLayout.closeDrawer(binding.navView) - } else { - val fragment = navigationController.currentFrag as? BaseFragment<*, *> - - if (fragment?.onBackPressed() == true) { - return - } - - try { - navigationController.popFragment() - } catch (e: UnsupportedOperationException) { - when { - isRootFragment -> { - val options = FragNavTransactionOptions.newBuilder() - .transition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE) - .build() - navigationController.switchTab(defaultPosition, options) - } - else -> super.onBackPressed() - } - } - } - } - - override fun onEventDispatched(event: ViewEvent) { - super.onEventDispatched(event) - when (event) { - is SnackbarEvent -> snackbar(snackbarView, event.message(this), event.length, event.f) - is BackPressEvent -> onBackPressed() - is MagiskNavigationEvent -> navigateTo(event) - is ViewActionEvent -> event.action(this) - is PermissionEvent -> withPermissions(*event.permissions.toTypedArray()) { - onSuccess { event.callback.onNext(true) } - onFailure { - event.callback.onNext(false) - event.callback.onError(SecurityException("User refused permissions")) - } - } - } - } - - override fun onSimpleEventDispatched(event: Int) { - super.onSimpleEventDispatched(event) - when (event) { - Navigation.Main.OPEN_NAV -> openNav() - } - } - - private fun openNav() = binding.drawerLayout.openDrawer(GravityCompat.START) - - private fun checkHideSection() { - val menu = binding.navView.menu - menu.findItem(R.id.magiskHideFragment).isVisible = Info.env.isActive && Info.env.magiskHide - menu.findItem(R.id.modulesFragment).isVisible = Info.env.isActive - menu.findItem(R.id.reposFragment).isVisible = Info.isConnected.value && Info.env.isActive - menu.findItem(R.id.logFragment).isVisible = Info.env.isActive - menu.findItem(R.id.superuserFragment).isVisible = Utils.showSuperUser() - } - - private fun FragNavTransactionOptions.Builder.customAnimations(options: MagiskAnimBuilder) = - customAnimations(options.enter, options.exit, options.popEnter, options.popExit).apply { - if (!options.anySet) { - transition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) - } - } - - override val numberOfRootFragments: Int get() = baseFragments.size - - override fun getRootFragment(index: Int) = baseFragments[index].java.newInstance() - - override fun onTabTransaction(fragment: Fragment?, index: Int) { - val fragmentId = when (fragment) { - is HomeFragment -> R.id.magiskFragment - is SuperuserFragment -> R.id.superuserFragment - is MagiskHideFragment -> R.id.magiskHideFragment - is ModulesFragment -> R.id.modulesFragment - is ReposFragment -> R.id.reposFragment - is LogFragment -> R.id.logFragment - is SettingsFragment -> R.id.settings - else -> return - } - binding.navView.setCheckedItem(fragmentId) - } - - override fun navigateTo(event: MagiskNavigationEvent) { - val directions = event.navDirections - - navigationController.defaultTransactionOptions = FragNavTransactionOptions.newBuilder() - .customAnimations(event.animOptions) - .build() - - navigationController.currentStack - ?.indexOfFirst { it.javaClass == event.navOptions.popUpTo } - ?.let { if (it == -1) null else it } // invalidate if class is not found - ?.let { if (event.navOptions.inclusive) it + 1 else it } - ?.let { navigationController.popFragments(it) } - - when (directions.isActivity) { - true -> navigateToActivity(event) - else -> navigateToFragment(event) - } - } - - private fun navigateToActivity(event: MagiskNavigationEvent) { - val destination = event.navDirections.destination?.java ?: let { - Timber.e("Cannot navigate to null destination") - return - } - val options = event.navOptions - - Intent(this, destination) - .putExtras(event.navDirections.args) - .apply { - if (options.singleTop) addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP) - if (options.clearTask) addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) - } - .let { startActivity(it) } - } - - private fun navigateToFragment(event: MagiskNavigationEvent) { - val destination = event.navDirections.destination?.java ?: let { - Timber.e("Cannot navigate to null destination") - return - } - - when (val index = baseFragments.indexOfFirst { it.java.name == destination.name }) { - -1 -> destination.newInstance() - .apply { arguments = event.navDirections.args } - .let { navigationController.pushFragment(it) } - // When it's desired that fragments of same class are put on top of one another edit this - else -> navigationController.switchTab(index) - } - } - - override fun onFragmentTransaction( - fragment: Fragment?, - transactionType: FragNavController.TransactionType - ) = Unit -} diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/MainViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/MainViewModel.kt deleted file mode 100644 index 8bb5bf5a1..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/ui/MainViewModel.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.topjohnwu.magisk.ui - -import android.view.MenuItem -import com.topjohnwu.magisk.R -import com.topjohnwu.magisk.base.viewmodel.BaseViewModel -import com.topjohnwu.magisk.model.navigation.Navigation - - -class MainViewModel : BaseViewModel() { - - var shownUnsupportedDialog = false - - fun navPressed() = Navigation.Main.OPEN_NAV.publish() - - fun navigationItemPressed(item: MenuItem): Boolean { - when (item.itemId) { - R.id.magiskFragment -> Navigation.home() - R.id.superuserFragment -> Navigation.superuser() - R.id.magiskHideFragment -> Navigation.hide() - R.id.modulesFragment -> Navigation.modules() - R.id.reposFragment -> Navigation.repos() - R.id.logFragment -> Navigation.log() - R.id.settings -> Navigation.settings() - else -> null - }?.publish()?.let { return@navigationItemPressed true } - return false - } - -} diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/hide/HideViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/hide/HideViewModel.kt deleted file mode 100644 index 2640abcad..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/ui/hide/HideViewModel.kt +++ /dev/null @@ -1,96 +0,0 @@ -package com.topjohnwu.magisk.ui.hide - -import android.content.pm.ApplicationInfo -import com.topjohnwu.magisk.BR -import com.topjohnwu.magisk.base.viewmodel.BaseViewModel -import com.topjohnwu.magisk.data.repository.MagiskRepository -import com.topjohnwu.magisk.databinding.ComparableRvItem -import com.topjohnwu.magisk.extensions.addOnPropertyChangedCallback -import com.topjohnwu.magisk.extensions.subscribeK -import com.topjohnwu.magisk.extensions.toSingle -import com.topjohnwu.magisk.extensions.update -import com.topjohnwu.magisk.model.entity.recycler.HideProcessRvItem -import com.topjohnwu.magisk.model.entity.recycler.HideRvItem -import com.topjohnwu.magisk.model.entity.state.IndeterminateState -import com.topjohnwu.magisk.model.events.HideProcessEvent -import com.topjohnwu.magisk.utils.DiffObservableList -import com.topjohnwu.magisk.utils.KObservableField -import com.topjohnwu.magisk.utils.RxBus -import me.tatarka.bindingcollectionadapter2.OnItemBind -import timber.log.Timber - -class HideViewModel( - private val magiskRepo: MagiskRepository, - rxBus: RxBus -) : BaseViewModel() { - - val query = KObservableField("") - val isShowSystem = KObservableField(false) - - private val allItems = mutableListOf>() - val items = DiffObservableList(ComparableRvItem.callback) - val itemBinding = OnItemBind> { itemBinding, _, item -> - item.bind(itemBinding) - itemBinding.bindExtra(BR.viewModel, this@HideViewModel) - } - - init { - rxBus.register() - .subscribeK { toggleItem(it.item) } - .add() - - isShowSystem.addOnPropertyChangedCallback { query() } - query.addOnPropertyChangedCallback { query() } - - refresh() - } - - fun refresh() { - // fetching this for every item is nonsensical, so we add .cache() so the response is all - // the same for every single mapped item, it only actually executes the whole thing the - // first time around. - val hideTargets = magiskRepo.fetchHideTargets().cache() - - magiskRepo.fetchApps() - .flattenAsFlowable { it } - .map { HideRvItem(it, hideTargets.blockingGet()) } - .toList() - .map { - it.sortedWith(compareBy( - { it.isHiddenState.value }, - { it.item.name.toLowerCase() }, - { it.packageName } - )) - } - .doOnSuccess { allItems.update(it) } - .flatMap { queryRaw() } - .applyViewModel(this) - .subscribeK(onError = Timber::e) { items.update(it.first, it.second) } - .add() - } - - private fun query() = queryRaw() - .subscribeK { items.update(it.first, it.second) } - .add() - - private fun queryRaw( - showSystem: Boolean = isShowSystem.value, - query: String = this.query.value - ) = allItems.toSingle() - .map { it.filterIsInstance() } - .flattenAsFlowable { it } - .filter { - it.item.name.contains(query, ignoreCase = true) || - it.item.processes.any { it.contains(query, ignoreCase = true) } - } - .filter { - showSystem || (it.isHiddenState.value != IndeterminateState.UNCHECKED) || - (it.item.info.flags and ApplicationInfo.FLAG_SYSTEM == 0) - } - .toList() - .map { it to items.calculateDiff(it) } - - private fun toggleItem(item: HideProcessRvItem) = - magiskRepo.toggleHide(item.isHidden.value, item.packageName, item.process) - -} diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/hide/MagiskHideFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/hide/MagiskHideFragment.kt deleted file mode 100644 index f9d4c67f3..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/ui/hide/MagiskHideFragment.kt +++ /dev/null @@ -1,71 +0,0 @@ -package com.topjohnwu.magisk.ui.hide - -import android.view.Menu -import android.view.MenuInflater -import android.view.MenuItem -import android.widget.SearchView -import com.topjohnwu.magisk.Config -import com.topjohnwu.magisk.R -import com.topjohnwu.magisk.base.BaseFragment -import com.topjohnwu.magisk.databinding.FragmentMagiskHideBinding -import org.koin.androidx.viewmodel.ext.android.viewModel - -class MagiskHideFragment : BaseFragment(), - SearchView.OnQueryTextListener { - - override val layoutRes: Int = R.layout.fragment_magisk_hide - override val viewModel: HideViewModel by viewModel() - - override fun onStart() { - super.onStart() - setHasOptionsMenu(true) - requireActivity().setTitle(R.string.magiskhide) - } - - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { - inflater.inflate(R.menu.menu_magiskhide, menu) - menu.apply { - val query = viewModel.query.value - val searchItem = menu.findItem(R.id.app_search) - val searchView = searchItem.actionView as? SearchView - - searchView?.run { - setOnQueryTextListener(this@MagiskHideFragment) - setQuery(query, false) - } - - if (query.isNotBlank()) { - searchItem.expandActionView() - searchView?.isIconified = false - } else { - searchItem.collapseActionView() - searchView?.isIconified = true - } - - val showSystem = Config.showSystemApp - - findItem(R.id.show_system).isChecked = showSystem - viewModel.isShowSystem.value = showSystem - } - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - if (item.itemId == R.id.show_system) { - val showSystem = !item.isChecked - item.isChecked = showSystem - Config.showSystemApp = showSystem - viewModel.isShowSystem.value = showSystem - } - return true - } - - override fun onQueryTextSubmit(query: String?): Boolean { - viewModel.query.value = query.orEmpty() - return false - } - - override fun onQueryTextChange(query: String?): Boolean { - viewModel.query.value = query.orEmpty() - return false - } -} diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeFragment.kt deleted file mode 100644 index d9cd0df8b..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeFragment.kt +++ /dev/null @@ -1,132 +0,0 @@ -package com.topjohnwu.magisk.ui.home - -import android.content.Context -import com.topjohnwu.magisk.BuildConfig -import com.topjohnwu.magisk.Const -import com.topjohnwu.magisk.Info -import com.topjohnwu.magisk.R -import com.topjohnwu.magisk.base.BaseActivity -import com.topjohnwu.magisk.base.BaseFragment -import com.topjohnwu.magisk.data.repository.MagiskRepository -import com.topjohnwu.magisk.databinding.FragmentMagiskBinding -import com.topjohnwu.magisk.extensions.DynamicClassLoader -import com.topjohnwu.magisk.extensions.openUrl -import com.topjohnwu.magisk.extensions.subscribeK -import com.topjohnwu.magisk.extensions.writeTo -import com.topjohnwu.magisk.model.events.* -import com.topjohnwu.magisk.utils.SafetyNetHelper -import com.topjohnwu.magisk.view.MarkDownWindow -import com.topjohnwu.magisk.view.dialogs.* -import com.topjohnwu.superuser.Shell -import dalvik.system.DexFile -import io.reactivex.Completable -import org.koin.android.ext.android.inject -import org.koin.androidx.viewmodel.ext.android.viewModel -import java.io.File -import java.lang.reflect.InvocationHandler - -class HomeFragment : BaseFragment(), - SafetyNetHelper.Callback { - - override val layoutRes: Int = R.layout.fragment_magisk - override val viewModel: HomeViewModel by viewModel() - - private val magiskRepo: MagiskRepository by inject() - private val EXT_APK by lazy { File("${activity.filesDir.parent}/snet", "snet.jar") } - private val EXT_DEX by lazy { File(EXT_APK.parent, "snet.dex") } - - override fun onResponse(responseCode: Int) = viewModel.finishSafetyNetCheck(responseCode) - - override fun onEventDispatched(event: ViewEvent) { - super.onEventDispatched(event) - when (event) { - is OpenLinkEvent -> activity.openUrl(event.url) - is ManagerInstallEvent -> installManager() - is MagiskInstallEvent -> installMagisk() - is UninstallEvent -> uninstall() - is ManagerChangelogEvent -> changelogManager() - is EnvFixEvent -> fixEnv() - is UpdateSafetyNetEvent -> updateSafetyNet(false) - } - } - - override fun onStart() { - super.onStart() - setHasOptionsMenu(true) - requireActivity().setTitle(R.string.magisk) - } - - private fun installMagisk() { - // Show Manager update first - if (Info.remote.app.versionCode > BuildConfig.VERSION_CODE) { - installManager() - return - } - - MagiskInstallDialog(requireActivity() as BaseActivity<*, *>).show() - } - - private fun installManager() = ManagerInstallDialog(requireActivity()).show() - private fun uninstall() = UninstallDialog(requireActivity()).show() - private fun fixEnv() = EnvFixDialog(requireActivity()).show() - - private fun changelogManager() = MarkDownWindow - .show(requireActivity(), null, resources.openRawResource(R.raw.changelog)) - - private fun downloadSafetyNet(requiresUserInput: Boolean = true) { - fun download() = magiskRepo.fetchSafetynet() - .map { it.byteStream().writeTo(EXT_APK) } - .subscribeK { updateSafetyNet(true) } - - if (!requiresUserInput) { - download() - return - } - - CustomAlertDialog(requireActivity()) - .setTitle(R.string.proprietary_title) - .setMessage(R.string.proprietary_notice) - .setCancelable(false) - .setPositiveButton(android.R.string.yes) { _, _ -> download() } - .setNegativeButton(android.R.string.no) { _, _ -> viewModel.finishSafetyNetCheck(-2) } - .show() - } - - private fun updateSafetyNet(dieOnError: Boolean) { - Completable.fromAction { - val loader = DynamicClassLoader(EXT_APK) - val dex = DexFile.loadDex(EXT_APK.path, EXT_DEX.path, 0) - - // Scan through the dex and find our helper class - var helperClass: Class<*>? = null - for (className in dex.entries()) { - if (className.startsWith("x.")) { - val cls = loader.loadClass(className) - if (InvocationHandler::class.java.isAssignableFrom(cls)) { - helperClass = cls - break - } - } - } - helperClass ?: throw Exception() - - val helper = helperClass.getMethod("get", - Class::class.java, Context::class.java, Any::class.java) - .invoke(null, SafetyNetHelper::class.java, activity, this) as SafetyNetHelper - - if (helper.version < Const.SNET_EXT_VER) - throw Exception() - - helper.attest() - }.subscribeK(onError = { - if (dieOnError) { - viewModel.finishSafetyNetCheck(-1) - } else { - Shell.sh("rm -rf " + EXT_APK.parent).exec() - EXT_APK.parentFile?.mkdir() - downloadSafetyNet(!dieOnError) - } - }) - } -} - diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt deleted file mode 100644 index 2b8fc887f..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt +++ /dev/null @@ -1,259 +0,0 @@ -package com.topjohnwu.magisk.ui.home - -import android.content.pm.PackageManager -import com.topjohnwu.magisk.* -import com.topjohnwu.magisk.base.viewmodel.BaseViewModel -import com.topjohnwu.magisk.data.repository.MagiskRepository -import com.topjohnwu.magisk.extensions.* -import com.topjohnwu.magisk.model.events.* -import com.topjohnwu.magisk.model.observer.Observer -import com.topjohnwu.magisk.utils.KObservableField -import com.topjohnwu.magisk.utils.SafetyNetHelper -import com.topjohnwu.superuser.Shell -import io.reactivex.Completable - -enum class SafetyNetState { - LOADING, PASS, FAILED, IDLE -} - -enum class MagiskState { - NOT_INSTALLED, UP_TO_DATE, OBSOLETE, LOADING -} - -enum class MagiskItem { - MANAGER, MAGISK -} - -class HomeViewModel( - private val magiskRepo: MagiskRepository -) : BaseViewModel(State.LOADED) { - - val hasGMS = runCatching { - get().getPackageInfo("com.google.android.gms", 0); true - }.getOrElse { false } - - val isAdvancedExpanded = KObservableField(false) - - val isForceEncryption = KObservableField(Info.keepEnc) - val isKeepVerity = KObservableField(Info.keepVerity) - val isRecovery = KObservableField(Info.recovery) - - val magiskState = KObservableField(MagiskState.LOADING) - val magiskStateText = Observer(magiskState) { - when (magiskState.value) { - MagiskState.NOT_INSTALLED -> R.string.magisk_version_error.res() - MagiskState.UP_TO_DATE -> R.string.magisk_up_to_date.res() - MagiskState.LOADING -> R.string.checking_for_updates.res() - MagiskState.OBSOLETE -> R.string.magisk_update_title.res() - } - } - val magiskCurrentVersion = KObservableField("") - val magiskLatestVersion = KObservableField("") - val magiskAdditionalInfo = Observer(magiskState) { - if (Config.coreOnly) - R.string.core_only_enabled.res() - else - "" - } - - private val _managerState = KObservableField(MagiskState.LOADING) - val managerState = Observer(_managerState, isConnected) { - if (isConnected.value) _managerState.value else MagiskState.UP_TO_DATE - } - val managerStateText = Observer(managerState) { - when (managerState.value) { - MagiskState.NOT_INSTALLED -> R.string.invalid_update_channel.res() - MagiskState.UP_TO_DATE -> R.string.manager_up_to_date.res() - MagiskState.LOADING -> R.string.checking_for_updates.res() - MagiskState.OBSOLETE -> R.string.manager_update_title.res() - } - } - val managerCurrentVersion = KObservableField("") - val managerLatestVersion = KObservableField("") - val managerAdditionalInfo = Observer(managerState) { - if (packageName != BuildConfig.APPLICATION_ID) - "($packageName)" - else - "" - } - - val safetyNetTitle = KObservableField(R.string.safetyNet_check_text.res()) - val ctsState = KObservableField(SafetyNetState.IDLE) - val basicIntegrityState = KObservableField(SafetyNetState.IDLE) - val safetyNetState = Observer(ctsState, basicIntegrityState) { - val cts = ctsState.value - val basic = basicIntegrityState.value - val states = listOf(cts, basic) - - when { - states.any { it == SafetyNetState.LOADING } -> State.LOADING - states.any { it == SafetyNetState.IDLE } -> State.LOADING - else -> State.LOADED - } - } - - val isActive = KObservableField(false) - - private var shownDialog = false - - init { - isForceEncryption.addOnPropertyChangedCallback { - Info.keepEnc = it ?: return@addOnPropertyChangedCallback - } - isKeepVerity.addOnPropertyChangedCallback { - Info.keepVerity = it ?: return@addOnPropertyChangedCallback - } - isRecovery.addOnPropertyChangedCallback { - Info.recovery = it ?: return@addOnPropertyChangedCallback - } - isConnected.addOnPropertyChangedCallback { - if (it == true) refresh(false) - } - - refresh(false) - } - - fun paypalPressed() = OpenLinkEvent(Const.Url.PAYPAL_URL).publish() - fun patreonPressed() = OpenLinkEvent(Const.Url.PATREON_URL).publish() - fun twitterPressed() = OpenLinkEvent(Const.Url.TWITTER_URL).publish() - fun githubPressed() = OpenLinkEvent(Const.Url.SOURCE_CODE_URL).publish() - fun xdaPressed() = OpenLinkEvent(Const.Url.XDA_THREAD).publish() - fun uninstallPressed() = UninstallEvent().publish() - - fun advancedPressed() = isAdvancedExpanded.toggle() - - fun installPressed(item: MagiskItem) = when (item) { - MagiskItem.MANAGER -> ManagerInstallEvent().publish() - MagiskItem.MAGISK -> MagiskInstallEvent().publish() - } - - fun cardPressed(item: MagiskItem) = when (item) { - MagiskItem.MANAGER -> ManagerChangelogEvent().publish() - MagiskItem.MAGISK -> MagiskChangelogEvent().publish() - } - - fun safetyNetPressed() { - ctsState.value = SafetyNetState.LOADING - basicIntegrityState.value = SafetyNetState.LOADING - safetyNetTitle.value = R.string.checking_safetyNet_status.res() - - UpdateSafetyNetEvent().publish() - } - - fun finishSafetyNetCheck(response: Int) = when { - response and 0x0F == 0 -> { - val hasCtsPassed = response and SafetyNetHelper.CTS_PASS != 0 - val hasBasicIntegrityPassed = response and SafetyNetHelper.BASIC_PASS != 0 - safetyNetTitle.value = R.string.safetyNet_check_success.res() - ctsState.value = if (hasCtsPassed) { - SafetyNetState.PASS - } else { - SafetyNetState.FAILED - } - basicIntegrityState.value = if (hasBasicIntegrityPassed) { - SafetyNetState.PASS - } else { - SafetyNetState.FAILED - } - } - response == -2 -> { - ctsState.value = SafetyNetState.IDLE - basicIntegrityState.value = SafetyNetState.IDLE - } - else -> { - ctsState.value = SafetyNetState.IDLE - basicIntegrityState.value = SafetyNetState.IDLE - safetyNetTitle.value = when (response) { - SafetyNetHelper.RESPONSE_ERR -> R.string.safetyNet_res_invalid.res() - else -> R.string.safetyNet_api_error.res() - } - } - } - - @JvmOverloads - fun refresh(invalidate: Boolean = true) { - if (invalidate) - Info.envRef.invalidate() - - isActive.value = Info.env.isActive - - val fetchUpdate = if (isConnected.value) - magiskRepo.fetchUpdate().ignoreElement() - else - Completable.complete() - - Completable.fromAction { - // Ensure value is ready - Info.env - }.andThen(fetchUpdate) - .applyViewModel(this) - .doOnSubscribeUi { - magiskState.value = MagiskState.LOADING - _managerState.value = MagiskState.LOADING - ctsState.value = SafetyNetState.IDLE - basicIntegrityState.value = SafetyNetState.IDLE - safetyNetTitle.value = R.string.safetyNet_check_text.res() - }.subscribeK { - updateSelf() - ensureEnv() - refreshVersions() - } - } - - private fun refreshVersions() { - magiskCurrentVersion.value = if (magiskState.value != MagiskState.NOT_INSTALLED) { - VERSION_FMT.format(Info.env.magiskVersionString, Info.env.magiskVersionCode) - } else { - "" - } - - managerCurrentVersion.value = if (isRunningAsStub) MGR_VER_FMT - .format(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE, Info.stub!!.version) - else - VERSION_FMT.format(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE) - } - - private fun updateSelf() { - magiskState.value = when (Info.env.magiskVersionCode) { - in Int.MIN_VALUE .. 0 -> MagiskState.NOT_INSTALLED - in 1 until Info.remote.magisk.versionCode -> MagiskState.OBSOLETE - else -> MagiskState.UP_TO_DATE - } - - magiskLatestVersion.value = - VERSION_FMT.format(Info.remote.magisk.version, Info.remote.magisk.versionCode) - - _managerState.value = when (Info.remote.app.versionCode) { - in Int.MIN_VALUE .. 0 -> MagiskState.NOT_INSTALLED //wrong update channel - in (BuildConfig.VERSION_CODE + 1) .. Int.MAX_VALUE -> MagiskState.OBSOLETE - else -> { - if (Info.stub?.version ?: Int.MAX_VALUE < Info.remote.stub.versionCode) - MagiskState.OBSOLETE - else - MagiskState.UP_TO_DATE - } - } - - managerLatestVersion.value = MGR_VER_FMT - .format(Info.remote.app.version, Info.remote.app.versionCode, Info.remote.stub.versionCode) - } - - private fun ensureEnv() { - val invalidStates = - listOf(MagiskState.NOT_INSTALLED, MagiskState.LOADING) - - // Don't bother checking env when magisk is not installed, loading or already has been shown - if (invalidStates.any { it == magiskState.value } || shownDialog) return - - if (!Shell.su("env_check").exec().isSuccess) { - shownDialog = true - EnvFixEvent().publish() - } - } - - companion object { - private const val VERSION_FMT = "%s (%d)" - private const val MGR_VER_FMT = "%s (%d) (%d)" - } - -} diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/log/LogFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/log/LogFragment.kt deleted file mode 100644 index 24f0e1db2..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/ui/log/LogFragment.kt +++ /dev/null @@ -1,57 +0,0 @@ -package com.topjohnwu.magisk.ui.log - - -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.base.BaseFragment -import com.topjohnwu.magisk.databinding.FragmentLogBinding -import com.topjohnwu.magisk.model.events.PageChangedEvent -import com.topjohnwu.magisk.model.events.ViewEvent -import org.koin.androidx.viewmodel.ext.android.viewModel - -class LogFragment : BaseFragment() { - - override val layoutRes: Int = R.layout.fragment_log - override val viewModel: LogViewModel by viewModel() - - override fun onEventDispatched(event: ViewEvent) { - super.onEventDispatched(event) - when (event) { - is PageChangedEvent -> activity.invalidateOptionsMenu() - } - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - binding.logTabs.setupWithViewPager(binding.logContainer, true) - } - - override fun onStart() { - super.onStart() - setHasOptionsMenu(true) - activity.setTitle(R.string.log) - } - - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { - inflater.inflate(R.menu.menu_log, menu) - menu.findItem(R.id.menu_save).isVisible = viewModel.currentPage.value == 1 - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - when (item.itemId) { - R.id.menu_save -> activity.withExternalRW { - onSuccess { - viewModel.saveLog() - } - } - R.id.menu_clear -> viewModel.clearLog() - R.id.menu_refresh -> viewModel.refresh() - } - return true - } - -} diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/log/LogViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/log/LogViewModel.kt deleted file mode 100644 index d3d50e3fd..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/ui/log/LogViewModel.kt +++ /dev/null @@ -1,120 +0,0 @@ -package com.topjohnwu.magisk.ui.log - -import android.content.res.Resources -import com.topjohnwu.magisk.BR -import com.topjohnwu.magisk.Config -import com.topjohnwu.magisk.Const -import com.topjohnwu.magisk.R -import com.topjohnwu.magisk.base.viewmodel.BaseViewModel -import com.topjohnwu.magisk.data.repository.LogRepository -import com.topjohnwu.magisk.databinding.ComparableRvItem -import com.topjohnwu.magisk.extensions.addOnPropertyChangedCallback -import com.topjohnwu.magisk.extensions.doOnSubscribeUi -import com.topjohnwu.magisk.extensions.subscribeK -import com.topjohnwu.magisk.model.binding.BindingAdapter -import com.topjohnwu.magisk.model.entity.recycler.ConsoleRvItem -import com.topjohnwu.magisk.model.entity.recycler.LogItemRvItem -import com.topjohnwu.magisk.model.entity.recycler.LogRvItem -import com.topjohnwu.magisk.model.entity.recycler.MagiskLogRvItem -import com.topjohnwu.magisk.model.events.PageChangedEvent -import com.topjohnwu.magisk.model.events.SnackbarEvent -import com.topjohnwu.magisk.utils.DiffObservableList -import com.topjohnwu.magisk.utils.KObservableField -import com.topjohnwu.superuser.Shell -import me.tatarka.bindingcollectionadapter2.BindingViewPagerAdapter -import me.tatarka.bindingcollectionadapter2.OnItemBind -import timber.log.Timber -import java.io.File -import java.util.* - -class LogViewModel( - private val resources: Resources, - private val logRepo: LogRepository -) : BaseViewModel(), BindingViewPagerAdapter.PageTitles> { - - val itemsAdapter = BindingAdapter() - val items = DiffObservableList(ComparableRvItem.callback) - val itemBinding = OnItemBind> { itemBinding, _, item -> - item.bind(itemBinding) - itemBinding.bindExtra(BR.viewModel, this@LogViewModel) - } - val currentPage = KObservableField(0) - private val currentItem get() = items[currentPage.value] - - private val logItem get() = items[0] as LogRvItem - private val magiskLogItem get() = items[1] as MagiskLogRvItem - - val scrollPosition = KObservableField(0) - - init { - currentPage.addOnPropertyChangedCallback { - it ?: return@addOnPropertyChangedCallback - PageChangedEvent().publish() - } - - items.addAll(listOf(LogRvItem(), MagiskLogRvItem())) - refresh() - } - - override fun getPageTitle(position: Int, item: ComparableRvItem<*>?) = when (item) { - is LogRvItem -> resources.getString(R.string.superuser) - is MagiskLogRvItem -> resources.getString(R.string.magisk) - else -> "" - } - - fun scrollDownPressed() { - scrollPosition.value = magiskLogItem.items.size - 1 - } - - fun refresh() { - fetchLogs().subscribeK { logItem.update(it) } - fetchMagiskLog().subscribeK { magiskLogItem.update(it) } - } - - fun saveLog() { - val now = Calendar.getInstance() - val filename = "magisk_log_%04d%02d%02d_%02d%02d%02d.log".format( - now.get(Calendar.YEAR), now.get(Calendar.MONTH) + 1, - now.get(Calendar.DAY_OF_MONTH), now.get(Calendar.HOUR_OF_DAY), - now.get(Calendar.MINUTE), now.get(Calendar.SECOND) - ) - - val logFile = File(Config.downloadDirectory, filename) - runCatching { - logFile.createNewFile() - }.onFailure { - Timber.e(it) - return - } - - Shell.su("cat ${Const.MAGISK_LOG} > $logFile").submit { - SnackbarEvent(logFile.path).publish() - } - } - - fun clearLog() = when (currentItem) { - is LogRvItem -> clearLogs { refresh() } - is MagiskLogRvItem -> clearMagiskLogs { refresh() } - else -> Unit - } - - private fun clearLogs(callback: () -> Unit) = logRepo.clearLogs() - .doOnSubscribeUi(callback) - .subscribeK { SnackbarEvent(R.string.logs_cleared).publish() } - .add() - - private fun clearMagiskLogs(callback: () -> Unit) = logRepo.clearMagiskLogs() - .doOnComplete(callback) - .subscribeK { SnackbarEvent(R.string.logs_cleared).publish() } - .add() - - private fun fetchLogs() = logRepo.fetchLogs() - .flattenAsFlowable { it } - .map { LogItemRvItem(it) } - .toList() - - private fun fetchMagiskLog() = logRepo.fetchMagiskLogs() - .map { ConsoleRvItem(it) } - .toList() - -} diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/module/ModuleViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/module/ModuleViewModel.kt deleted file mode 100644 index 1ac4ed62b..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/ui/module/ModuleViewModel.kt +++ /dev/null @@ -1,111 +0,0 @@ -package com.topjohnwu.magisk.ui.module - -import android.content.res.Resources -import com.topjohnwu.magisk.BR -import com.topjohnwu.magisk.R -import com.topjohnwu.magisk.base.viewmodel.BaseViewModel -import com.topjohnwu.magisk.data.database.RepoDao -import com.topjohnwu.magisk.databinding.ComparableRvItem -import com.topjohnwu.magisk.extensions.* -import com.topjohnwu.magisk.model.entity.module.Module -import com.topjohnwu.magisk.model.entity.recycler.ModuleRvItem -import com.topjohnwu.magisk.model.entity.recycler.RepoRvItem -import com.topjohnwu.magisk.model.entity.recycler.SectionRvItem -import com.topjohnwu.magisk.model.events.InstallModuleEvent -import com.topjohnwu.magisk.model.events.OpenChangelogEvent -import com.topjohnwu.magisk.model.events.OpenFilePickerEvent -import com.topjohnwu.magisk.tasks.RepoUpdater -import com.topjohnwu.magisk.utils.DiffObservableList -import com.topjohnwu.magisk.utils.KObservableField -import io.reactivex.Single -import io.reactivex.disposables.Disposable -import me.tatarka.bindingcollectionadapter2.OnItemBind - -class ModuleViewModel( - private val resources: Resources, - private val repoUpdater: RepoUpdater, - private val repoDB: RepoDao -) : BaseViewModel() { - - val query = KObservableField("") - - private val allItems = mutableListOf>() - - val itemsInstalled = DiffObservableList(ComparableRvItem.callback) - val itemsRemote = DiffObservableList(ComparableRvItem.callback) - val itemBinding = OnItemBind> { itemBinding, _, item -> - item.bind(itemBinding) - itemBinding.bindExtra(BR.viewModel, this@ModuleViewModel) - } - - private var queryDisposable: Disposable? = null - - init { - query.addOnPropertyChangedCallback { - queryDisposable?.dispose() - queryDisposable = query() - } - refresh(false) - } - - fun fabPressed() = OpenFilePickerEvent().publish() - fun repoPressed(item: RepoRvItem) = OpenChangelogEvent(item.item).publish() - fun downloadPressed(item: RepoRvItem) = InstallModuleEvent(item.item).publish() - - fun refresh(force: Boolean) { - Single.fromCallable { Module.loadModules() } - .flattenAsFlowable { it } - .map { ModuleRvItem(it) } - .toList() - .map { it to itemsInstalled.calculateDiff(it) } - .doOnSuccessUi { itemsInstalled.update(it.first, it.second) } - .flatMap { repoUpdater(force) } - .flattenAsFlowable { repoDB.repos } - .map { RepoRvItem(it) } - .toList() - .doOnSuccess { allItems.update(it) } - .flatMap { queryRaw() } - .applyViewModel(this) - .subscribeK { itemsRemote.update(it.first, it.second) } - } - - private fun query() = queryRaw() - .subscribeK { itemsRemote.update(it.first, it.second) } - - private fun queryRaw(query: String = this.query.value) = allItems.toSingle() - .map { it.filterIsInstance() } - .flattenAsFlowable { it } - .filter { - it.item.name.contains(query, ignoreCase = true) || - it.item.author.contains(query, ignoreCase = true) || - it.item.description.contains(query, ignoreCase = true) - } - .toList() - .map { if (query.isEmpty()) it.divide() else it } - .map { it to itemsRemote.calculateDiff(it) } - - private fun List.divide(): List> { - val installed = itemsInstalled.filterIsInstance() - - fun > List.withTitle(text: Int) = - if (isEmpty()) this else listOf(SectionRvItem(resources.getString(text))) + this - - val groupedItems = groupBy { repo -> - installed.firstOrNull { it.item.id == repo.item.id }?.let { - if (it.item.versionCode < repo.item.versionCode) MODULE_UPDATABLE - else MODULE_INSTALLED - } ?: MODULE_REMOTE - } - - return groupedItems.getOrElse(MODULE_UPDATABLE) { listOf() }.withTitle(R.string.update_available) + - groupedItems.getOrElse(MODULE_INSTALLED) { listOf() }.withTitle(R.string.installed) + - groupedItems.getOrElse(MODULE_REMOTE) { listOf() }.withTitle(R.string.not_installed) - } - - companion object { - protected const val MODULE_INSTALLED = 0 - protected const val MODULE_REMOTE = 1 - protected const val MODULE_UPDATABLE = 2 - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/module/ModulesFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/module/ModulesFragment.kt deleted file mode 100644 index ba2520707..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/ui/module/ModulesFragment.kt +++ /dev/null @@ -1,99 +0,0 @@ -package com.topjohnwu.magisk.ui.module - -import android.app.Activity -import android.content.Intent -import android.os.Bundle -import android.view.Menu -import android.view.MenuInflater -import android.view.MenuItem -import android.view.View -import androidx.recyclerview.widget.RecyclerView -import com.topjohnwu.magisk.Const -import com.topjohnwu.magisk.R -import com.topjohnwu.magisk.base.BaseFragment -import com.topjohnwu.magisk.databinding.FragmentModulesBinding -import com.topjohnwu.magisk.extensions.reboot -import com.topjohnwu.magisk.intent -import com.topjohnwu.magisk.model.events.OpenFilePickerEvent -import com.topjohnwu.magisk.model.events.ViewEvent -import com.topjohnwu.magisk.ui.flash.FlashActivity -import com.topjohnwu.superuser.Shell -import org.koin.androidx.viewmodel.ext.android.sharedViewModel - -class ModulesFragment : BaseFragment() { - - override val layoutRes: Int = R.layout.fragment_modules - override val viewModel: ModuleViewModel by sharedViewModel() - - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - if (requestCode == Const.ID.FETCH_ZIP && resultCode == Activity.RESULT_OK && data != null) { - // Get the URI of the selected file - val intent = activity.intent() - intent.setData(data.data).putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_ZIP) - startActivity(intent) - } - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - binding.modulesContent.addOnScrollListener(object : RecyclerView.OnScrollListener() { - override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { - binding.modulesRefreshLayout.isEnabled = recyclerView.getChildAt(0).top >= 0 - } - }) - } - - override fun onEventDispatched(event: ViewEvent) { - super.onEventDispatched(event) - when (event) { - is OpenFilePickerEvent -> selectFile() - } - } - - override fun onStart() { - super.onStart() - setHasOptionsMenu(true) - requireActivity().setTitle(R.string.modules) - } - - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { - inflater.inflate(R.menu.menu_reboot, menu) - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - when (item.itemId) { - R.id.reboot -> { - reboot() - return true - } - R.id.reboot_recovery -> { - Shell.su("/system/bin/reboot recovery").submit() - return true - } - R.id.reboot_bootloader -> { - reboot("bootloader") - return true - } - R.id.reboot_download -> { - reboot("download") - return true - } - R.id.reboot_edl -> { - reboot("edl") - return true - } - else -> return false - } - } - - private fun selectFile() { - activity.withExternalRW { - onSuccess { - val intent = Intent(Intent.ACTION_GET_CONTENT) - intent.type = "application/zip" - startActivityForResult(intent, Const.ID.FETCH_ZIP) - } - } - } -} diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/module/ReposFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/module/ReposFragment.kt deleted file mode 100644 index 70ebb78c5..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/ui/module/ReposFragment.kt +++ /dev/null @@ -1,116 +0,0 @@ -package com.topjohnwu.magisk.ui.module - -import android.annotation.SuppressLint -import android.app.AlertDialog -import android.view.Menu -import android.view.MenuInflater -import android.view.MenuItem -import android.widget.SearchView -import com.topjohnwu.magisk.Config -import com.topjohnwu.magisk.R -import com.topjohnwu.magisk.base.BaseFragment -import com.topjohnwu.magisk.databinding.FragmentReposBinding -import com.topjohnwu.magisk.model.download.DownloadService -import com.topjohnwu.magisk.model.entity.internal.Configuration -import com.topjohnwu.magisk.model.entity.internal.DownloadSubject -import com.topjohnwu.magisk.model.entity.module.Repo -import com.topjohnwu.magisk.model.events.InstallModuleEvent -import com.topjohnwu.magisk.model.events.OpenChangelogEvent -import com.topjohnwu.magisk.model.events.ViewEvent -import com.topjohnwu.magisk.view.MarkDownWindow -import com.topjohnwu.magisk.view.dialogs.CustomAlertDialog -import org.koin.androidx.viewmodel.ext.android.sharedViewModel - -class ReposFragment : BaseFragment(), - SearchView.OnQueryTextListener { - - override val layoutRes: Int = R.layout.fragment_repos - override val viewModel: ModuleViewModel by sharedViewModel() - - override fun onStart() { - super.onStart() - setHasOptionsMenu(true) - requireActivity().setTitle(R.string.downloads) - } - - override fun onEventDispatched(event: ViewEvent) { - super.onEventDispatched(event) - when (event) { - is OpenChangelogEvent -> openChangelog(event.item) - is InstallModuleEvent -> installModule(event.item) - } - } - - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { - inflater.inflate(R.menu.menu_repo, menu) - - val query = viewModel.query.value - val searchItem = menu.findItem(R.id.repo_search) - val searchView = searchItem.actionView as? SearchView - - searchView?.run { - setOnQueryTextListener(this@ReposFragment) - setQuery(query, false) - } - - if (query.isNotBlank()) { - searchItem.expandActionView() - searchView?.isIconified = false - } else { - searchItem.collapseActionView() - searchView?.isIconified = true - } - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - if (item.itemId == R.id.repo_sort) { - AlertDialog.Builder(activity) - .setTitle(R.string.sorting_order) - .setSingleChoiceItems( - R.array.sorting_orders, - Config.repoOrder - ) { d, which -> - Config.repoOrder = which - viewModel.refresh(false) - d.dismiss() - }.show() - } - return true - } - - override fun onQueryTextSubmit(p0: String?): Boolean { - viewModel.query.value = p0.orEmpty() - return false - } - - override fun onQueryTextChange(p0: String?): Boolean { - viewModel.query.value = p0.orEmpty() - return false - } - - private fun openChangelog(item: Repo) { - MarkDownWindow.show(requireActivity(), null, item.readme) - } - - @SuppressLint("MissingPermission") - private fun installModule(item: Repo) { - val context = activity - - fun download(install: Boolean) = context.withExternalRW { - onSuccess { - DownloadService(context) { - val config = if (install) Configuration.Flash.Primary else Configuration.Download - subject = DownloadSubject.Module(item, config) - } - } - } - - CustomAlertDialog(context) - .setTitle(context.getString(R.string.repo_install_title, item.name)) - .setMessage(context.getString(R.string.repo_install_msg, item.downloadFilename)) - .setCancelable(true) - .setPositiveButton(R.string.install) { _, _ -> download(true) } - .setNeutralButton(R.string.download) { _, _ -> download(false) } - .show() - } -} diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt deleted file mode 100644 index 399874402..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt +++ /dev/null @@ -1,347 +0,0 @@ -package com.topjohnwu.magisk.ui.settings - -import android.content.SharedPreferences -import android.os.Build -import android.os.Bundle -import android.os.Environment -import android.view.LayoutInflater -import android.widget.EditText -import android.widget.Toast -import androidx.appcompat.app.AlertDialog -import androidx.databinding.DataBindingUtil -import androidx.preference.ListPreference -import androidx.preference.Preference -import androidx.preference.PreferenceCategory -import androidx.preference.SwitchPreferenceCompat -import com.topjohnwu.magisk.* -import com.topjohnwu.magisk.base.BasePreferenceFragment -import com.topjohnwu.magisk.data.database.RepoDao -import com.topjohnwu.magisk.databinding.CustomDownloadDialogBinding -import com.topjohnwu.magisk.databinding.DialogCustomNameBinding -import com.topjohnwu.magisk.extensions.subscribeK -import com.topjohnwu.magisk.model.download.DownloadService -import com.topjohnwu.magisk.model.entity.internal.Configuration -import com.topjohnwu.magisk.model.entity.internal.DownloadSubject -import com.topjohnwu.magisk.model.observer.Observer -import com.topjohnwu.magisk.utils.* -import com.topjohnwu.superuser.Shell -import io.reactivex.Completable -import org.koin.android.ext.android.inject -import java.io.File - -class SettingsFragment : BasePreferenceFragment() { - - private val repoDB: RepoDao by inject() - - private lateinit var updateChannel: ListPreference - private lateinit var autoRes: ListPreference - private lateinit var suNotification: ListPreference - private lateinit var requestTimeout: ListPreference - private lateinit var rootConfig: ListPreference - private lateinit var multiuserConfig: ListPreference - private lateinit var nsConfig: ListPreference - - override fun onStart() { - super.onStart() - setHasOptionsMenu(true) - requireActivity().setTitle(R.string.settings) - } - - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - preferenceManager.setStorageDeviceProtected() - setPreferencesFromResource(R.xml.app_settings, rootKey) - - findPreference("redesign_cat")?.isVisible = BuildConfig.DEBUG - - // Get preferences - updateChannel = findPreference(Config.Key.UPDATE_CHANNEL)!! - rootConfig = findPreference(Config.Key.ROOT_ACCESS)!! - autoRes = findPreference(Config.Key.SU_AUTO_RESPONSE)!! - requestTimeout = findPreference(Config.Key.SU_REQUEST_TIMEOUT)!! - suNotification = findPreference(Config.Key.SU_NOTIFICATION)!! - multiuserConfig = findPreference(Config.Key.SU_MULTIUSER_MODE)!! - nsConfig = findPreference(Config.Key.SU_MNT_NS)!! - val reauth = findPreference(Config.Key.SU_REAUTH)!! - val biometric = findPreference(Config.Key.SU_BIOMETRIC)!! - val generalCategory = findPreference("general")!! - val magiskCategory = findPreference("magisk")!! - val suCategory = findPreference("superuser")!! - val hideManager = findPreference("hide")!! - val restoreManager = findPreference("restore")!! - - // Remove/Disable entries - - // Only show canary channels if user is already on canary channel - // or the user have already chosen canary channel - if (!Utils.isCanary && Config.updateChannel < Config.Value.CANARY_CHANNEL) { - // Remove the last 2 entries - val entries = updateChannel.entries - updateChannel.entries = entries.copyOf(entries.size - 2) - } - - // Remove dangerous settings in secondary user - if (Const.USER_ID > 0) { - suCategory.removePreference(multiuserConfig) - } - - // Remove re-authentication option on Android O, it will not work - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - suCategory.removePreference(reauth) - } - - // Disable biometric option if not possible - if (!BiometricHelper.isSupported) { - biometric.isEnabled = false - biometric.isChecked = false - biometric.setSummary(R.string.no_biometric) - } - - if (Const.USER_ID == 0 && Info.isConnected.value && Info.env.isActive) { - if (activity.packageName == BuildConfig.APPLICATION_ID) { - generalCategory.removePreference(restoreManager) - hideManager.setOnPreferenceClickListener { - showManagerNameDialog { - PatchAPK.hideManager(requireContext(), it) - } - true - } - } else { - generalCategory.removePreference(hideManager) - restoreManager.setOnPreferenceClickListener { - DownloadService(requireContext()) { - subject = DownloadSubject.Manager(Configuration.APK.Restore) - } - true - } - } - } else { - // Remove if not primary user, no connection, or no root - generalCategory.removePreference(restoreManager) - generalCategory.removePreference(hideManager) - } - - if (!Utils.showSuperUser()) { - preferenceScreen.removePreference(suCategory) - } - - if (!Info.env.isActive) { - preferenceScreen.removePreference(magiskCategory) - generalCategory.removePreference(hideManager) - } - - findPreference("clear")?.also { - if (Info.env.isActive) { - it.setOnPreferenceClickListener { - Completable.fromAction { repoDB.clear() }.subscribeK { - Utils.toast(R.string.repo_cache_cleared, Toast.LENGTH_SHORT) - } - true - } - } else { - generalCategory.removePreference(it) - } - } - - findPreference("hosts")?.setOnPreferenceClickListener { - Shell.su("add_hosts_module").submit { - Utils.toast(R.string.settings_hosts_toast, Toast.LENGTH_SHORT) - } - true - } - - findPreference(Config.Key.DOWNLOAD_PATH)?.apply { - summary = Config.downloadPath - setOnPreferenceClickListener { pref -> - activity.withExternalRW { - onSuccess { - showDownloadDialog { - Config.downloadPath = it - pref.summary = it - } - } - } - true - } - } - - updateChannel.setOnPreferenceChangeListener { _, value -> - val channel = value.toString().toInt() - val previous = Config.updateChannel - - if (channel == Config.Value.CUSTOM_CHANNEL) { - showUrlDialog(Config.customChannelUrl, { - Config.updateChannel = previous - }, { - Config.customChannelUrl = it - }) - } - true - } - - setLocalePreference(findPreference(Config.Key.LOCALE)!!) - - setSummary() - } - - override fun onSharedPreferenceChanged(prefs: SharedPreferences, key: String) { - fun getStrInt() = prefs.getString(key, null)?.toInt() ?: 0 - - when (key) { - Config.Key.ROOT_ACCESS -> Config.rootMode = getStrInt() - Config.Key.SU_MULTIUSER_MODE -> Config.suMultiuserMode = getStrInt() - Config.Key.SU_MNT_NS -> Config.suMntNamespaceMode = getStrInt() - Config.Key.DARK_THEME -> requireActivity().recreate() - Config.Key.COREONLY -> { - if (prefs.getBoolean(key, false)) { - runCatching { - Const.MAGISK_DISABLE_FILE.createNewFile() - } - } else { - Const.MAGISK_DISABLE_FILE.delete() - } - Utils.toast(R.string.settings_reboot_toast, Toast.LENGTH_LONG) - } - Config.Key.MAGISKHIDE -> if (prefs.getBoolean(key, false)) { - Shell.su("magiskhide --enable").submit() - } else { - Shell.su("magiskhide --disable").submit() - } - Config.Key.LOCALE -> { - refreshLocale() - activity.recreate() - } - Config.Key.CHECK_UPDATES -> Utils.scheduleUpdateCheck(activity) - } - setSummary(key) - } - - override fun onPreferenceTreeClick(preference: Preference): Boolean { - when (preference.key) { - Config.Key.SU_BIOMETRIC -> { - val checked = (preference as SwitchPreferenceCompat).isChecked - preference.isChecked = !checked - BiometricHelper.authenticate(requireActivity()) { - preference.isChecked = checked - Config.suBiometric = checked - } - } - } - return true - } - - private fun setLocalePreference(lp: ListPreference) { - lp.isEnabled = false - availableLocales.subscribeK { (names, values) -> - lp.isEnabled = true - lp.entries = names - lp.entryValues = values - lp.summary = currentLocale.getDisplayName(currentLocale) - } - } - - private fun setSummary(key: String) { - when (key) { - Config.Key.ROOT_ACCESS -> rootConfig.summary = resources - .getStringArray(R.array.su_access)[Config.rootMode] - Config.Key.SU_MULTIUSER_MODE -> multiuserConfig.summary = resources - .getStringArray(R.array.multiuser_summary)[Config.suMultiuserMode] - Config.Key.SU_MNT_NS -> nsConfig.summary = resources - .getStringArray(R.array.namespace_summary)[Config.suMntNamespaceMode] - Config.Key.UPDATE_CHANNEL -> { - var ch = Config.updateChannel - ch = if (ch < 0) Config.Value.STABLE_CHANNEL else ch - updateChannel.summary = resources - .getStringArray(R.array.update_channel)[ch] - } - Config.Key.SU_AUTO_RESPONSE -> autoRes.summary = resources - .getStringArray(R.array.auto_response)[Config.suAutoReponse] - Config.Key.SU_NOTIFICATION -> suNotification.summary = resources - .getStringArray(R.array.su_notification)[Config.suNotification] - Config.Key.SU_REQUEST_TIMEOUT -> requestTimeout.summary = - getString(R.string.request_timeout_summary, Config.suDefaultTimeout) - } - } - - private fun setSummary() { - setSummary(Config.Key.ROOT_ACCESS) - setSummary(Config.Key.SU_MULTIUSER_MODE) - setSummary(Config.Key.SU_MNT_NS) - setSummary(Config.Key.UPDATE_CHANNEL) - setSummary(Config.Key.SU_AUTO_RESPONSE) - setSummary(Config.Key.SU_NOTIFICATION) - setSummary(Config.Key.SU_REQUEST_TIMEOUT) - } - - private inline fun showUrlDialog( - initialValue: String, - crossinline onCancel: () -> Unit = {}, - crossinline onSuccess: (String) -> Unit - ) { - val v = LayoutInflater - .from(requireActivity()) - .inflate(R.layout.custom_channel_dialog, null) - - val url = v.findViewById(R.id.custom_url).apply { - setText(initialValue) - } - - AlertDialog.Builder(requireActivity()) - .setTitle(R.string.settings_update_custom) - .setView(v) - .setPositiveButton(android.R.string.ok) { _, _ -> onSuccess(url.text.toString()) } - .setNegativeButton(android.R.string.cancel) { _, _ -> onCancel() } - .setOnCancelListener { onCancel() } - .show() - } - - inner class DownloadDialogData(initialValue: String) { - val text = KObservableField(initialValue) - val path = Observer(text) { - File(Environment.getExternalStorageDirectory(), text.value).absolutePath - } - } - - private inline fun showDownloadDialog( - initialValue: String = Config.downloadPath, - crossinline onSuccess: (String) -> Unit - ) { - val data = DownloadDialogData(initialValue) - val binding: CustomDownloadDialogBinding = DataBindingUtil - .inflate(layoutInflater, R.layout.custom_download_dialog, null, false) - binding.also { it.data = data } - - AlertDialog.Builder(requireActivity()) - .setTitle(R.string.settings_download_path_title) - .setView(binding.root) - .setPositiveButton(android.R.string.ok) { _, _ -> - Utils.ensureDownloadPath(data.text.value)?.let { onSuccess(data.text.value) } - ?: Utils.toast(R.string.settings_download_path_error, Toast.LENGTH_SHORT) - } - .setNegativeButton(android.R.string.cancel, null) - .show() - } - - private inline fun showManagerNameDialog( - crossinline onSuccess: (String) -> Unit - ) { - val data = ManagerNameData() - val view = DialogCustomNameBinding - .inflate(LayoutInflater.from(requireContext())) - .also { it.data = data } - - AlertDialog.Builder(requireActivity()) - .setTitle(R.string.settings_app_name) - .setView(view.root) - .setPositiveButton(android.R.string.ok) { _, _ -> - if (view.dialogNameInput.error.isNullOrBlank()) { - onSuccess(data.name.value) - } - } - .setNegativeButton(android.R.string.cancel, null) - .show() - } - - inner class ManagerNameData { - val name = KObservableField(resources.getString(R.string.re_app_name)) - } -} diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/superuser/SuperuserFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/superuser/SuperuserFragment.kt deleted file mode 100644 index 00386b01e..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/ui/superuser/SuperuserFragment.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.topjohnwu.magisk.ui.superuser - -import com.topjohnwu.magisk.R -import com.topjohnwu.magisk.base.BaseFragment -import com.topjohnwu.magisk.databinding.FragmentSuperuserBinding -import org.koin.androidx.viewmodel.ext.android.viewModel - -class SuperuserFragment : - BaseFragment() { - - override val layoutRes: Int = R.layout.fragment_superuser - override val viewModel: SuperuserViewModel by viewModel() - - override fun onStart() { - super.onStart() - setHasOptionsMenu(true) - requireActivity().setTitle(R.string.superuser) - } - - override fun onResume() { - super.onResume() - viewModel.updatePolicies() - } - -} diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/superuser/SuperuserViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/superuser/SuperuserViewModel.kt deleted file mode 100644 index 57f24bcc5..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/ui/superuser/SuperuserViewModel.kt +++ /dev/null @@ -1,151 +0,0 @@ -package com.topjohnwu.magisk.ui.superuser - -import android.content.pm.PackageManager -import android.content.res.Resources -import com.topjohnwu.magisk.BR -import com.topjohnwu.magisk.R -import com.topjohnwu.magisk.base.viewmodel.BaseViewModel -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.extensions.toggle -import com.topjohnwu.magisk.model.entity.MagiskPolicy -import com.topjohnwu.magisk.model.entity.recycler.PolicyRvItem -import com.topjohnwu.magisk.model.events.PolicyEnableEvent -import com.topjohnwu.magisk.model.events.PolicyUpdateEvent -import com.topjohnwu.magisk.model.events.SnackbarEvent -import com.topjohnwu.magisk.utils.BiometricHelper -import com.topjohnwu.magisk.utils.DiffObservableList -import com.topjohnwu.magisk.utils.RxBus -import com.topjohnwu.magisk.view.dialogs.CustomAlertDialog -import io.reactivex.Single -import io.reactivex.disposables.Disposable -import me.tatarka.bindingcollectionadapter2.ItemBinding - -class SuperuserViewModel( - private val policyDB: PolicyDao, - private val packageManager: PackageManager, - private val resources: Resources, - rxBus: RxBus -) : BaseViewModel() { - - val items = DiffObservableList(ComparableRvItem.callback) - val itemBinding = ItemBinding.of> { itemBinding, _, item -> - item.bind(itemBinding) - itemBinding.bindExtra(BR.viewModel, this@SuperuserViewModel) - } - - private var ignoreNext: PolicyRvItem? = null - private var fetchTask: Disposable? = null - - init { - rxBus.register() - .filter { - val isIgnored = it.item == ignoreNext - if (isIgnored) ignoreNext = null - !isIgnored - } - .subscribeK { togglePolicy(it.item, it.enable) } - .add() - rxBus.register() - .subscribeK { updatePolicy(it) } - .add() - - updatePolicies() - } - - fun updatePolicies() { - if (fetchTask?.isDisposed?.not() == true) return - fetchTask = policyDB.fetchAll() - .flattenAsFlowable { it } - .map { PolicyRvItem(it, it.applicationInfo.loadIcon(packageManager)) } - .toList() - .map { - it.sortedWith(compareBy( - { it.item.appName.toLowerCase() }, - { it.item.packageName } - )) - } - .map { it to items.calculateDiff(it) } - .applySchedulers() - .applyViewModel(this) - .subscribeK { items.update(it.first, it.second) } - } - - fun deletePressed(item: PolicyRvItem) { - fun updateState() = deletePolicy(item.item) - .map { items.filterIsInstance().toMutableList() } - .map { it.removeAll { it.item.packageName == item.item.packageName }; it } - .map { it to items.calculateDiff(it) } - .subscribeK { items.update(it.first, it.second) } - .add() - - withView { - if (BiometricHelper.isEnabled) { - BiometricHelper.authenticate(this) { updateState() } - } else { - CustomAlertDialog(this) - .setTitle(R.string.su_revoke_title) - .setMessage(getString(R.string.su_revoke_msg, item.item.appName)) - .setPositiveButton(android.R.string.yes) { _, _ -> updateState() } - .setNegativeButton(android.R.string.no, null) - .setCancelable(true) - .show() - } - } - } - - private fun updatePolicy(it: PolicyUpdateEvent) = when (it) { - is PolicyUpdateEvent.Notification -> updatePolicy(it.item) { - val textId = - if (it.notification) R.string.su_snack_notif_on else R.string.su_snack_notif_off - val text = resources.getString(textId).format(it.appName) - SnackbarEvent(text).publish() - } - is PolicyUpdateEvent.Log -> updatePolicy(it.item) { - val textId = - if (it.logging) R.string.su_snack_log_on else R.string.su_snack_log_off - val text = resources.getString(textId).format(it.appName) - SnackbarEvent(text).publish() - } - } - - private fun updatePolicy(item: MagiskPolicy, onSuccess: (MagiskPolicy) -> Unit) = - updatePolicy(item) - .subscribeK { onSuccess(it) } - .add() - - private fun togglePolicy(item: PolicyRvItem, enable: Boolean) { - fun updateState() { - val app = item.item.copy(policy = if (enable) MagiskPolicy.ALLOW else MagiskPolicy.DENY) - - updatePolicy(app) - .map { it.policy == MagiskPolicy.ALLOW } - .subscribeK { - val textId = if (it) R.string.su_snack_grant else R.string.su_snack_deny - val text = resources.getString(textId).format(item.item.appName) - SnackbarEvent(text).publish() - } - .add() - } - - if (BiometricHelper.isEnabled) { - withView { - BiometricHelper.authenticate(this, onError = { - ignoreNext = item - item.isEnabled.toggle() - }) { updateState() } - } - } else { - updateState() - } - } - - private fun updatePolicy(policy: MagiskPolicy) = - policyDB.update(policy).andThen(Single.just(policy)) - - private fun deletePolicy(policy: MagiskPolicy) = - policyDB.delete(policy.uid).andThen(Single.just(policy)) - -} diff --git a/app/src/main/java/com/topjohnwu/magisk/view/Shortcuts.kt b/app/src/main/java/com/topjohnwu/magisk/view/Shortcuts.kt index 829cb5e8c..d8bfa7e0a 100644 --- a/app/src/main/java/com/topjohnwu/magisk/view/Shortcuts.kt +++ b/app/src/main/java/com/topjohnwu/magisk/view/Shortcuts.kt @@ -77,19 +77,6 @@ object Shortcuts { .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) ) .setIcon(getIcon(R.drawable.sc_extension)) - .setRank(3) - .build() - ) - shortCuts.add( - ShortcutInfo.Builder(context, "downloads") - .setShortLabel(context.getString(R.string.downloads)) - .setIntent( - Intent(intent) - .putExtra(Const.Key.OPEN_SECTION, "downloads") - .setAction(Intent.ACTION_VIEW) - .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) - ) - .setIcon(getIcon(R.drawable.sc_cloud_download)) .setRank(2) .build() ) diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml deleted file mode 100644 index f2300aafb..000000000 --- a/app/src/main/res/layout/activity_main.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/activity_main_content.xml b/app/src/main/res/layout/activity_main_content.xml deleted file mode 100644 index ab5775c0d..000000000 --- a/app/src/main/res/layout/activity_main_content.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/custom_channel_dialog.xml b/app/src/main/res/layout/custom_channel_dialog.xml deleted file mode 100644 index 95aab1637..000000000 --- a/app/src/main/res/layout/custom_channel_dialog.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/custom_download_dialog.xml b/app/src/main/res/layout/custom_download_dialog.xml deleted file mode 100644 index f182f8ff0..000000000 --- a/app/src/main/res/layout/custom_download_dialog.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/dialog_custom_name.xml b/app/src/main/res/layout/dialog_custom_name.xml deleted file mode 100644 index 45d4ffafd..000000000 --- a/app/src/main/res/layout/dialog_custom_name.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_home_md2.xml b/app/src/main/res/layout/fragment_home_md2.xml index 023cec564..0c8209012 100644 --- a/app/src/main/res/layout/fragment_home_md2.xml +++ b/app/src/main/res/layout/fragment_home_md2.xml @@ -17,7 +17,7 @@ - + @@ -801,4 +801,4 @@ - \ No newline at end of file + diff --git a/app/src/main/res/layout/fragment_log.xml b/app/src/main/res/layout/fragment_log.xml deleted file mode 100644 index a07621cc6..000000000 --- a/app/src/main/res/layout/fragment_log.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_magisk.xml b/app/src/main/res/layout/fragment_magisk.xml deleted file mode 100644 index 70b580dca..000000000 --- a/app/src/main/res/layout/fragment_magisk.xml +++ /dev/null @@ -1,503 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/fragment_magisk_hide.xml b/app/src/main/res/layout/fragment_magisk_hide.xml deleted file mode 100644 index 81b380f88..000000000 --- a/app/src/main/res/layout/fragment_magisk_hide.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/fragment_modules.xml b/app/src/main/res/layout/fragment_modules.xml deleted file mode 100644 index 7439ca496..000000000 --- a/app/src/main/res/layout/fragment_modules.xml +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/fragment_repos.xml b/app/src/main/res/layout/fragment_repos.xml deleted file mode 100644 index f1c605ae8..000000000 --- a/app/src/main/res/layout/fragment_repos.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_superuser.xml b/app/src/main/res/layout/fragment_superuser.xml deleted file mode 100644 index c67588746..000000000 --- a/app/src/main/res/layout/fragment_superuser.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/include_update_card.xml b/app/src/main/res/layout/include_update_card.xml deleted file mode 100644 index cc4bb272f..000000000 --- a/app/src/main/res/layout/include_update_card.xml +++ /dev/null @@ -1,151 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/item_hide_app.xml b/app/src/main/res/layout/item_hide_app.xml deleted file mode 100644 index a3512e113..000000000 --- a/app/src/main/res/layout/item_hide_app.xml +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/item_hide_process.xml b/app/src/main/res/layout/item_hide_process.xml deleted file mode 100644 index d0dfd0597..000000000 --- a/app/src/main/res/layout/item_hide_process.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/item_module.xml b/app/src/main/res/layout/item_module.xml deleted file mode 100644 index 51b46f9a0..000000000 --- a/app/src/main/res/layout/item_module.xml +++ /dev/null @@ -1,149 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/item_page_log.xml b/app/src/main/res/layout/item_page_log.xml deleted file mode 100644 index eff2e06b5..000000000 --- a/app/src/main/res/layout/item_page_log.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/item_page_magisk_log.xml b/app/src/main/res/layout/item_page_magisk_log.xml deleted file mode 100644 index b2f4f8c91..000000000 --- a/app/src/main/res/layout/item_page_magisk_log.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/item_policy.xml b/app/src/main/res/layout/item_policy.xml deleted file mode 100644 index e076a6538..000000000 --- a/app/src/main/res/layout/item_policy.xml +++ /dev/null @@ -1,211 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/item_repo.xml b/app/src/main/res/layout/item_repo.xml deleted file mode 100644 index efada5183..000000000 --- a/app/src/main/res/layout/item_repo.xml +++ /dev/null @@ -1,130 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/item_superuser_log.xml b/app/src/main/res/layout/item_superuser_log.xml deleted file mode 100644 index 332d1d30f..000000000 --- a/app/src/main/res/layout/item_superuser_log.xml +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/item_superuser_log_entry.xml b/app/src/main/res/layout/item_superuser_log_entry.xml deleted file mode 100644 index da660d8fc..000000000 --- a/app/src/main/res/layout/item_superuser_log_entry.xml +++ /dev/null @@ -1,112 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/menu/drawer.xml b/app/src/main/res/menu/drawer.xml deleted file mode 100644 index 6710d2ddc..000000000 --- a/app/src/main/res/menu/drawer.xml +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/menu/menu_log.xml b/app/src/main/res/menu/menu_log.xml deleted file mode 100644 index 7fc9e341b..000000000 --- a/app/src/main/res/menu/menu_log.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/menu/menu_magiskhide.xml b/app/src/main/res/menu/menu_magiskhide.xml deleted file mode 100644 index 6a44ae6cf..000000000 --- a/app/src/main/res/menu/menu_magiskhide.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - \ No newline at end of file