You've already forked Magisk
mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-09-06 06:36:58 +00:00
Merge remote-tracking branch 'john/master' into feature/redesign
# Conflicts: # app/build.gradle # app/src/main/AndroidManifest.xml # app/src/main/java/com/topjohnwu/magisk/model/events/ViewEvents.kt # app/src/main/java/com/topjohnwu/magisk/model/navigation/MagiskNavigationEvent.kt # app/src/main/java/com/topjohnwu/magisk/ui/SplashActivity.kt # app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt # app/src/main/java/com/topjohnwu/magisk/view/MagiskDialog.kt # app/src/main/res/layout/dialog_magisk_base.xml
This commit is contained in:
@@ -4,15 +4,24 @@ import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.core.view.GravityCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.skoumal.teanity.extensions.addOnPropertyChangedCallback
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
import com.ncapdevi.fragnav.FragNavController
|
||||
import com.ncapdevi.fragnav.FragNavTransactionOptions
|
||||
import com.topjohnwu.magisk.ClassMap
|
||||
import com.topjohnwu.magisk.Config
|
||||
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.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.ui.base.MagiskActivity
|
||||
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
|
||||
@@ -23,15 +32,22 @@ import com.topjohnwu.magisk.ui.superuser.SuperuserFragment
|
||||
import com.topjohnwu.magisk.utils.Utils
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
import timber.log.Timber
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
|
||||
open class MainActivity : MagiskActivity<MainViewModel, ActivityMainBinding>() {
|
||||
open class MainActivity : BaseActivity<MainViewModel, ActivityMainBinding>(), Navigator,
|
||||
FragNavController.RootFragmentListener, FragNavController.TransactionListener {
|
||||
|
||||
override val layoutRes: Int = R.layout.activity_main
|
||||
override val viewModel: MainViewModel by viewModel()
|
||||
override val navHostId: Int = R.id.main_nav_host
|
||||
override val defaultPosition: Int = 0
|
||||
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<KClass<out Fragment>> = listOf(
|
||||
HomeFragment::class,
|
||||
@@ -43,10 +59,6 @@ open class MainActivity : MagiskActivity<MainViewModel, ActivityMainBinding>() {
|
||||
SettingsFragment::class
|
||||
)
|
||||
|
||||
/*override fun getDarkTheme(): Int {
|
||||
return R.style.AppTheme_Dark
|
||||
}*/
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
if (!SplashActivity.DONE) {
|
||||
startActivity(Intent(this, ClassMap[SplashActivity::class.java]))
|
||||
@@ -54,6 +66,13 @@ open class MainActivity : MagiskActivity<MainViewModel, ActivityMainBinding>() {
|
||||
}
|
||||
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
navigationController.apply {
|
||||
rootFragmentListener = this@MainActivity
|
||||
transactionListener = this@MainActivity
|
||||
initialize(defaultPosition, savedInstanceState)
|
||||
}
|
||||
|
||||
checkHideSection()
|
||||
setSupportActionBar(binding.mainInclude.mainToolbar)
|
||||
|
||||
@@ -68,6 +87,11 @@ open class MainActivity : MagiskActivity<MainViewModel, ActivityMainBinding>() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
navigationController.onSaveInstanceState(outState)
|
||||
}
|
||||
|
||||
override fun setTitle(title: CharSequence?) {
|
||||
supportActionBar?.title = title
|
||||
}
|
||||
@@ -76,25 +100,46 @@ open class MainActivity : MagiskActivity<MainViewModel, ActivityMainBinding>() {
|
||||
supportActionBar?.setTitle(titleId)
|
||||
}
|
||||
|
||||
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 onBackPressed() {
|
||||
if (binding.drawerLayout.isDrawerOpen(binding.navView)) {
|
||||
binding.drawerLayout.closeDrawer(binding.navView)
|
||||
} else {
|
||||
super.onBackPressed()
|
||||
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"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,4 +165,84 @@ open class MainActivity : MagiskActivity<MainViewModel, ActivityMainBinding>() {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@ 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
|
||||
import com.topjohnwu.magisk.ui.base.MagiskViewModel
|
||||
|
||||
|
||||
class MainViewModel : MagiskViewModel() {
|
||||
class MainViewModel : BaseViewModel() {
|
||||
|
||||
fun navPressed() = Navigation.Main.OPEN_NAV.publish()
|
||||
|
||||
|
||||
@@ -1,17 +1,24 @@
|
||||
package com.topjohnwu.magisk.ui
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.topjohnwu.magisk.*
|
||||
import com.topjohnwu.magisk.model.navigation.Navigation
|
||||
import com.topjohnwu.magisk.utils.Utils
|
||||
import com.topjohnwu.magisk.utils.wrap
|
||||
import com.topjohnwu.magisk.view.Notifications
|
||||
import com.topjohnwu.magisk.view.Shortcuts
|
||||
import com.topjohnwu.superuser.Shell
|
||||
|
||||
open class SplashActivity : AppCompatActivity() {
|
||||
open class SplashActivity : Activity() {
|
||||
|
||||
override fun attachBaseContext(base: Context) {
|
||||
super.attachBaseContext(base.wrap())
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
package com.topjohnwu.magisk.ui.base
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.children
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.preference.*
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.topjohnwu.magisk.R
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
abstract class BasePreferenceFragment : PreferenceFragmentCompat(),
|
||||
SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
protected val prefs: SharedPreferences by inject()
|
||||
protected val activity get() = requireActivity() as MagiskActivity<*, *>
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
val v = super.onCreateView(inflater, container, savedInstanceState)
|
||||
prefs.registerOnSharedPreferenceChangeListener(this)
|
||||
return v
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
prefs.unregisterOnSharedPreferenceChangeListener(this)
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
override fun onCreateAdapter(preferenceScreen: PreferenceScreen): RecyclerView.Adapter<*> {
|
||||
return object : PreferenceGroupAdapter(preferenceScreen) {
|
||||
@SuppressLint("RestrictedApi")
|
||||
override fun onBindViewHolder(holder: PreferenceViewHolder, position: Int) {
|
||||
super.onBindViewHolder(holder, position)
|
||||
when (val preference = getItem(position)) {
|
||||
is PreferenceCategory -> setZeroPaddingToLayoutChildren(holder.itemView)
|
||||
else -> holder.itemView.findViewById<View>(R.id.icon_frame)?.isVisible =
|
||||
preference.icon != null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setZeroPaddingToLayoutChildren(view: View) {
|
||||
(view as? ViewGroup)?.children?.forEach {
|
||||
setZeroPaddingToLayoutChildren(it)
|
||||
} ?: return
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
|
||||
view.setPaddingRelative(0, view.paddingTop, view.paddingEnd, view.paddingBottom)
|
||||
else
|
||||
view.setPadding(0, view.paddingTop, view.paddingRight, view.paddingBottom)
|
||||
}
|
||||
}
|
||||
@@ -1,242 +0,0 @@
|
||||
package com.topjohnwu.magisk.ui.base
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.res.Configuration
|
||||
import android.os.Bundle
|
||||
import androidx.annotation.CallSuper
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.collection.SparseArrayCompat
|
||||
import androidx.core.net.toUri
|
||||
import androidx.databinding.ViewDataBinding
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
import com.karumi.dexter.Dexter
|
||||
import com.karumi.dexter.MultiplePermissionsReport
|
||||
import com.karumi.dexter.PermissionToken
|
||||
import com.karumi.dexter.listener.PermissionRequest
|
||||
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
|
||||
import com.ncapdevi.fragnav.FragNavController
|
||||
import com.ncapdevi.fragnav.FragNavTransactionOptions
|
||||
import com.skoumal.teanity.view.TeanityActivity
|
||||
import com.skoumal.teanity.viewevents.ViewEvent
|
||||
import com.topjohnwu.magisk.Config
|
||||
import com.topjohnwu.magisk.extensions.set
|
||||
import com.topjohnwu.magisk.model.events.BackPressEvent
|
||||
import com.topjohnwu.magisk.model.events.PermissionEvent
|
||||
import com.topjohnwu.magisk.model.events.ViewActionEvent
|
||||
import com.topjohnwu.magisk.model.navigation.MagiskAnimBuilder
|
||||
import com.topjohnwu.magisk.model.navigation.MagiskNavigationEvent
|
||||
import com.topjohnwu.magisk.model.navigation.Navigator
|
||||
import com.topjohnwu.magisk.model.permissions.PermissionRequestBuilder
|
||||
import com.topjohnwu.magisk.utils.LocaleManager
|
||||
import com.topjohnwu.magisk.utils.Utils
|
||||
import com.topjohnwu.magisk.utils.currentLocale
|
||||
import timber.log.Timber
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
typealias RequestCallback = MagiskActivity<*, *>.(Int, Intent?) -> Unit
|
||||
|
||||
abstract class MagiskActivity<ViewModel : MagiskViewModel, Binding : ViewDataBinding> :
|
||||
TeanityActivity<ViewModel, Binding>(), FragNavController.RootFragmentListener,
|
||||
Navigator, FragNavController.TransactionListener {
|
||||
|
||||
override val numberOfRootFragments: Int get() = baseFragments.size
|
||||
override val baseFragments: List<KClass<out Fragment>> = listOf()
|
||||
private val resultCallbacks = SparseArrayCompat<RequestCallback>()
|
||||
|
||||
|
||||
protected open val defaultPosition: Int = 0
|
||||
|
||||
protected val navigationController get() = if (navHostId == 0) null else _navigationController
|
||||
private val _navigationController by lazy {
|
||||
if (navHostId == 0) throw IllegalStateException("Did you forget to override \"navHostId\"?")
|
||||
FragNavController(supportFragmentManager, navHostId)
|
||||
}
|
||||
|
||||
private val isRootFragment
|
||||
get() = navigationController?.let { it.currentStackIndex != defaultPosition } ?: false
|
||||
|
||||
init {
|
||||
val theme = if (Config.darkTheme) {
|
||||
AppCompatDelegate.MODE_NIGHT_YES
|
||||
} else {
|
||||
AppCompatDelegate.MODE_NIGHT_NO
|
||||
}
|
||||
AppCompatDelegate.setDefaultNightMode(theme)
|
||||
}
|
||||
|
||||
override fun applyOverrideConfiguration(config: Configuration?) {
|
||||
// Force applying our preferred local
|
||||
config?.setLocale(currentLocale)
|
||||
super.applyOverrideConfiguration(config)
|
||||
}
|
||||
|
||||
override fun attachBaseContext(base: Context) {
|
||||
super.attachBaseContext(LocaleManager.getLocaleContext(base))
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
navigationController?.apply {
|
||||
rootFragmentListener = this@MagiskActivity
|
||||
transactionListener = this@MagiskActivity
|
||||
initialize(defaultPosition, savedInstanceState)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
navigationController?.onSaveInstanceState(outState)
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
override fun onEventDispatched(event: ViewEvent) {
|
||||
super.onEventDispatched(event)
|
||||
when (event) {
|
||||
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 getRootFragment(index: Int) = baseFragments[index].java.newInstance()
|
||||
|
||||
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 onBackPressed() {
|
||||
val fragment = navigationController?.currentFrag as? MagiskFragment<*, *>
|
||||
|
||||
if (fragment?.onBackPressed() == true) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
navigationController?.popFragment() ?: throw UnsupportedOperationException()
|
||||
} catch (e: UnsupportedOperationException) {
|
||||
when {
|
||||
isRootFragment -> {
|
||||
val options = FragNavTransactionOptions.newBuilder()
|
||||
.transition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE)
|
||||
.build()
|
||||
navigationController?.switchTab(defaultPosition, options)
|
||||
}
|
||||
else -> super.onBackPressed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFragmentTransaction(
|
||||
fragment: Fragment?,
|
||||
transactionType: FragNavController.TransactionType
|
||||
) = Unit
|
||||
|
||||
override fun onTabTransaction(fragment: Fragment?, index: Int) = Unit
|
||||
|
||||
fun openUrl(url: String) = Utils.openLink(this, url.toUri())
|
||||
|
||||
fun withPermissions(vararg permissions: String, builder: PermissionRequestBuilder.() -> Unit) {
|
||||
val request = PermissionRequestBuilder().apply(builder).build()
|
||||
Dexter.withActivity(this)
|
||||
.withPermissions(*permissions)
|
||||
.withListener(object : MultiplePermissionsListener {
|
||||
override fun onPermissionsChecked(report: MultiplePermissionsReport) {
|
||||
if (report.areAllPermissionsGranted()) {
|
||||
request.onSuccess()
|
||||
} else {
|
||||
request.onFailure()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPermissionRationaleShouldBeShown(
|
||||
permissions: MutableList<PermissionRequest>,
|
||||
token: PermissionToken
|
||||
) = token.continuePermissionRequest()
|
||||
}).check()
|
||||
}
|
||||
|
||||
fun withExternalRW(builder: PermissionRequestBuilder.() -> Unit) {
|
||||
withPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE, builder = builder)
|
||||
}
|
||||
|
||||
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 fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
resultCallbacks[requestCode]?.apply {
|
||||
resultCallbacks.remove(requestCode)
|
||||
invoke(this@MagiskActivity, resultCode, data)
|
||||
}
|
||||
}
|
||||
|
||||
fun startActivityForResult(
|
||||
intent: Intent,
|
||||
requestCode: Int,
|
||||
listener: RequestCallback
|
||||
) {
|
||||
resultCallbacks[requestCode] = listener
|
||||
startActivityForResult(intent, requestCode)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package com.topjohnwu.magisk.ui.base
|
||||
|
||||
import androidx.annotation.CallSuper
|
||||
import androidx.databinding.ViewDataBinding
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.skoumal.teanity.view.TeanityFragment
|
||||
import com.skoumal.teanity.viewevents.ViewEvent
|
||||
import com.topjohnwu.magisk.model.events.BackPressEvent
|
||||
import com.topjohnwu.magisk.model.events.PermissionEvent
|
||||
import com.topjohnwu.magisk.model.events.ViewActionEvent
|
||||
import com.topjohnwu.magisk.model.navigation.MagiskNavigationEvent
|
||||
import com.topjohnwu.magisk.model.navigation.Navigator
|
||||
import com.topjohnwu.magisk.model.permissions.PermissionRequestBuilder
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
|
||||
abstract class MagiskFragment<ViewModel : MagiskViewModel, Binding : ViewDataBinding> :
|
||||
TeanityFragment<ViewModel, Binding>(), Navigator {
|
||||
|
||||
protected val activity get() = requireActivity() as MagiskActivity<*, *>
|
||||
|
||||
// We don't need nested fragments
|
||||
override val baseFragments: List<KClass<Fragment>> = listOf()
|
||||
|
||||
override fun navigateTo(event: MagiskNavigationEvent) = activity.navigateTo(event)
|
||||
|
||||
@CallSuper
|
||||
override fun onEventDispatched(event: ViewEvent) {
|
||||
super.onEventDispatched(event)
|
||||
when (event) {
|
||||
is BackPressEvent -> activity.onBackPressed()
|
||||
is MagiskNavigationEvent -> navigateTo(event)
|
||||
is ViewActionEvent -> event.action(requireActivity())
|
||||
is PermissionEvent -> activity.withPermissions(*event.permissions.toTypedArray()) {
|
||||
onSuccess { event.callback.onNext(true) }
|
||||
onFailure {
|
||||
event.callback.onNext(false)
|
||||
event.callback.onError(SecurityException("User refused permissions"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun withPermissions(vararg permissions: String, builder: PermissionRequestBuilder.() -> Unit) {
|
||||
activity.withPermissions(*permissions, builder = builder)
|
||||
}
|
||||
|
||||
fun openLink(url: String) = activity.openUrl(url)
|
||||
|
||||
open fun onBackPressed(): Boolean = false
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package com.topjohnwu.magisk.ui.base
|
||||
|
||||
import android.app.Activity
|
||||
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
|
||||
import com.skoumal.teanity.extensions.doOnSubscribeUi
|
||||
import com.skoumal.teanity.extensions.subscribeK
|
||||
import com.skoumal.teanity.util.KObservableField
|
||||
import com.skoumal.teanity.viewmodel.LoadingViewModel
|
||||
import com.topjohnwu.magisk.extensions.get
|
||||
import com.topjohnwu.magisk.model.events.BackPressEvent
|
||||
import com.topjohnwu.magisk.model.events.PermissionEvent
|
||||
import com.topjohnwu.magisk.model.events.ViewActionEvent
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.subjects.PublishSubject
|
||||
|
||||
|
||||
abstract class MagiskViewModel(
|
||||
initialState: State = State.LOADING
|
||||
) : LoadingViewModel(initialState) {
|
||||
|
||||
val isConnected = KObservableField(true)
|
||||
|
||||
init {
|
||||
ReactiveNetwork.observeNetworkConnectivity(get())
|
||||
.subscribeK { isConnected.value = it.available() }
|
||||
.add()
|
||||
}
|
||||
|
||||
fun withView(action: Activity.() -> Unit) {
|
||||
ViewActionEvent(action).publish()
|
||||
}
|
||||
|
||||
fun withPermissions(vararg permissions: String): Observable<Boolean> {
|
||||
val subject = PublishSubject.create<Boolean>()
|
||||
return subject.doOnSubscribeUi { PermissionEvent(permissions.toList(), subject).publish() }
|
||||
}
|
||||
|
||||
fun back() = BackPressEvent().publish()
|
||||
|
||||
}
|
||||
@@ -9,15 +9,21 @@ import androidx.core.net.toUri
|
||||
import com.topjohnwu.magisk.ClassMap
|
||||
import com.topjohnwu.magisk.Const
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.base.BaseActivity
|
||||
import com.topjohnwu.magisk.databinding.ActivityFlashBinding
|
||||
import com.topjohnwu.magisk.ui.base.MagiskActivity
|
||||
import com.topjohnwu.magisk.extensions.snackbar
|
||||
import com.topjohnwu.magisk.model.events.BackPressEvent
|
||||
import com.topjohnwu.magisk.model.events.PermissionEvent
|
||||
import com.topjohnwu.magisk.model.events.SnackbarEvent
|
||||
import com.topjohnwu.magisk.model.events.ViewEvent
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
import org.koin.core.parameter.parametersOf
|
||||
import java.io.File
|
||||
|
||||
open class FlashActivity : MagiskActivity<FlashViewModel, ActivityFlashBinding>() {
|
||||
open class FlashActivity : BaseActivity<FlashViewModel, ActivityFlashBinding>() {
|
||||
|
||||
override val layoutRes: Int = R.layout.activity_flash
|
||||
override val themeRes: Int = R.style.MagiskTheme_Flashing
|
||||
override val viewModel: FlashViewModel by viewModel {
|
||||
val uri = intent.data ?: let { finish(); Uri.EMPTY }
|
||||
val additionalUri = intent.getParcelableExtra(Const.Key.FLASH_DATA) ?: uri
|
||||
@@ -37,6 +43,21 @@ open class FlashActivity : MagiskActivity<FlashViewModel, ActivityFlashBinding>(
|
||||
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 PermissionEvent -> withPermissions(*event.permissions.toTypedArray()) {
|
||||
onSuccess { event.callback.onNext(true) }
|
||||
onFailure {
|
||||
event.callback.onNext(false)
|
||||
event.callback.onError(SecurityException("User refused permissions"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private fun intent(context: Context) = Intent(context, ClassMap[FlashActivity::class.java])
|
||||
|
||||
@@ -7,21 +7,20 @@ import android.net.Uri
|
||||
import android.os.Handler
|
||||
import androidx.core.os.postDelayed
|
||||
import androidx.databinding.ObservableArrayList
|
||||
import com.skoumal.teanity.databinding.ComparableRvItem
|
||||
import com.skoumal.teanity.extensions.subscribeK
|
||||
import com.skoumal.teanity.util.DiffObservableList
|
||||
import com.skoumal.teanity.util.KObservableField
|
||||
import com.skoumal.teanity.viewevents.SnackbarEvent
|
||||
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.databinding.ComparableRvItem
|
||||
import com.topjohnwu.magisk.extensions.*
|
||||
import com.topjohnwu.magisk.model.entity.recycler.ConsoleRvItem
|
||||
import com.topjohnwu.magisk.model.events.SnackbarEvent
|
||||
import com.topjohnwu.magisk.model.flash.FlashResultListener
|
||||
import com.topjohnwu.magisk.model.flash.Flashing
|
||||
import com.topjohnwu.magisk.model.flash.Patching
|
||||
import com.topjohnwu.magisk.ui.base.MagiskViewModel
|
||||
import com.topjohnwu.magisk.utils.DiffObservableList
|
||||
import com.topjohnwu.magisk.utils.KObservableField
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import me.tatarka.bindingcollectionadapter2.ItemBinding
|
||||
import java.io.File
|
||||
@@ -32,7 +31,7 @@ class FlashViewModel(
|
||||
installer: Uri,
|
||||
uri: Uri,
|
||||
private val resources: Resources
|
||||
) : MagiskViewModel(), FlashResultListener {
|
||||
) : BaseViewModel(), FlashResultListener {
|
||||
|
||||
val canShowReboot = Shell.rootAccess()
|
||||
val showRestartTitle = KObservableField(false)
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
package com.topjohnwu.magisk.ui.hide
|
||||
|
||||
import android.content.pm.ApplicationInfo
|
||||
import com.skoumal.teanity.databinding.ComparableRvItem
|
||||
import com.skoumal.teanity.extensions.addOnPropertyChangedCallback
|
||||
import com.skoumal.teanity.extensions.subscribeK
|
||||
import com.skoumal.teanity.rxbus.RxBus
|
||||
import com.skoumal.teanity.util.DiffObservableList
|
||||
import com.skoumal.teanity.util.KObservableField
|
||||
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.ui.base.MagiskViewModel
|
||||
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
|
||||
) : MagiskViewModel() {
|
||||
) : BaseViewModel() {
|
||||
|
||||
val query = KObservableField("")
|
||||
val isShowSystem = KObservableField(false)
|
||||
|
||||
@@ -6,11 +6,11 @@ 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 com.topjohnwu.magisk.ui.base.MagiskFragment
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
|
||||
class MagiskHideFragment : MagiskFragment<HideViewModel, FragmentMagiskHideBinding>(),
|
||||
class MagiskHideFragment : BaseFragment<HideViewModel, FragmentMagiskHideBinding>(),
|
||||
SearchView.OnQueryTextListener {
|
||||
|
||||
override val layoutRes: Int = R.layout.fragment_magisk_hide
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
package com.topjohnwu.magisk.ui.home
|
||||
|
||||
import android.content.Context
|
||||
import com.skoumal.teanity.extensions.subscribeK
|
||||
import com.skoumal.teanity.viewevents.ViewEvent
|
||||
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.inject
|
||||
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.ui.base.MagiskActivity
|
||||
import com.topjohnwu.magisk.ui.base.MagiskFragment
|
||||
import com.topjohnwu.magisk.utils.DynamicClassLoader
|
||||
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 : MagiskFragment<HomeViewModel, FragmentMagiskBinding>(),
|
||||
class HomeFragment : BaseFragment<HomeViewModel, FragmentMagiskBinding>(),
|
||||
SafetyNetHelper.Callback {
|
||||
|
||||
override val layoutRes: Int = R.layout.fragment_magisk
|
||||
@@ -33,13 +33,14 @@ class HomeFragment : MagiskFragment<HomeViewModel, FragmentMagiskBinding>(),
|
||||
|
||||
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 -> openLink(event.url)
|
||||
is OpenLinkEvent -> activity.openUrl(event.url)
|
||||
is ManagerInstallEvent -> installManager()
|
||||
is MagiskInstallEvent -> installMagisk()
|
||||
is UninstallEvent -> uninstall()
|
||||
@@ -62,7 +63,7 @@ class HomeFragment : MagiskFragment<HomeViewModel, FragmentMagiskBinding>(),
|
||||
return
|
||||
}
|
||||
|
||||
MagiskInstallDialog(requireActivity() as MagiskActivity<*, *>).show()
|
||||
MagiskInstallDialog(requireActivity() as BaseActivity<*, *>).show()
|
||||
}
|
||||
|
||||
private fun installManager() = ManagerInstallDialog(requireActivity()).show()
|
||||
@@ -94,7 +95,7 @@ class HomeFragment : MagiskFragment<HomeViewModel, FragmentMagiskBinding>(),
|
||||
private fun updateSafetyNet(dieOnError: Boolean) {
|
||||
Completable.fromAction {
|
||||
val loader = DynamicClassLoader(EXT_APK)
|
||||
val dex = DexFile.loadDex(EXT_APK.path, EXT_APK.parent, 0)
|
||||
val dex = DexFile.loadDex(EXT_APK.path, EXT_DEX.path, 0)
|
||||
|
||||
// Scan through the dex and find our helper class
|
||||
var helperClass: Class<*>? = null
|
||||
|
||||
@@ -1,21 +1,16 @@
|
||||
package com.topjohnwu.magisk.ui.home
|
||||
|
||||
import android.content.pm.PackageManager
|
||||
import com.skoumal.teanity.extensions.addOnPropertyChangedCallback
|
||||
import com.skoumal.teanity.extensions.doOnSubscribeUi
|
||||
import com.skoumal.teanity.extensions.subscribeK
|
||||
import com.skoumal.teanity.util.KObservableField
|
||||
import com.topjohnwu.magisk.*
|
||||
import com.topjohnwu.magisk.base.viewmodel.BaseViewModel
|
||||
import com.topjohnwu.magisk.data.repository.MagiskRepository
|
||||
import com.topjohnwu.magisk.extensions.get
|
||||
import com.topjohnwu.magisk.extensions.packageName
|
||||
import com.topjohnwu.magisk.extensions.res
|
||||
import com.topjohnwu.magisk.extensions.toggle
|
||||
import com.topjohnwu.magisk.extensions.*
|
||||
import com.topjohnwu.magisk.model.events.*
|
||||
import com.topjohnwu.magisk.model.observer.Observer
|
||||
import com.topjohnwu.magisk.ui.base.MagiskViewModel
|
||||
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
|
||||
@@ -31,7 +26,7 @@ enum class MagiskItem {
|
||||
|
||||
class HomeViewModel(
|
||||
private val magiskRepo: MagiskRepository
|
||||
) : MagiskViewModel(State.LOADED) {
|
||||
) : BaseViewModel(State.LOADED) {
|
||||
|
||||
val hasGMS = runCatching {
|
||||
get<PackageManager>().getPackageInfo("com.google.android.gms", 0); true
|
||||
@@ -43,10 +38,7 @@ class HomeViewModel(
|
||||
val isKeepVerity = KObservableField(Info.keepVerity)
|
||||
val isRecovery = KObservableField(Info.recovery)
|
||||
|
||||
private val _magiskState = KObservableField(MagiskState.LOADING)
|
||||
val magiskState = Observer(_magiskState, isConnected) {
|
||||
if (isConnected.value) _magiskState.value else MagiskState.UP_TO_DATE
|
||||
}
|
||||
val magiskState = KObservableField(MagiskState.LOADING)
|
||||
val magiskStateText = Observer(magiskState) {
|
||||
when (magiskState.value) {
|
||||
MagiskState.NOT_INSTALLED -> R.string.magisk_version_error.res()
|
||||
@@ -179,24 +171,28 @@ class HomeViewModel(
|
||||
}
|
||||
|
||||
fun refresh() {
|
||||
refreshVersions()
|
||||
|
||||
magiskRepo.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
|
||||
}
|
||||
.subscribeK {
|
||||
updateSelf()
|
||||
ensureEnv()
|
||||
refreshVersions()
|
||||
}
|
||||
|
||||
hasRoot.value = Shell.rootAccess()
|
||||
|
||||
val fetchUpdate = if (isConnected.value)
|
||||
magiskRepo.fetchUpdate().ignoreElement()
|
||||
else
|
||||
Completable.complete()
|
||||
|
||||
Completable.fromAction {
|
||||
Info.loadMagiskInfo()
|
||||
}.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
|
||||
}.subscribeK {
|
||||
updateSelf()
|
||||
ensureEnv()
|
||||
refreshVersions()
|
||||
}
|
||||
}
|
||||
|
||||
private fun refreshVersions() {
|
||||
@@ -211,7 +207,7 @@ class HomeViewModel(
|
||||
}
|
||||
|
||||
private fun updateSelf() {
|
||||
_magiskState.value = when (Info.magiskVersionCode) {
|
||||
magiskState.value = when (Info.magiskVersionCode) {
|
||||
in Int.MIN_VALUE until 0 -> MagiskState.NOT_INSTALLED
|
||||
!in Info.remote.magisk.versionCode..Int.MAX_VALUE -> MagiskState.OBSOLETE
|
||||
else -> MagiskState.UP_TO_DATE
|
||||
|
||||
@@ -6,14 +6,14 @@ import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import com.skoumal.teanity.viewevents.ViewEvent
|
||||
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.ui.base.MagiskFragment
|
||||
import com.topjohnwu.magisk.model.events.ViewEvent
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
|
||||
class LogFragment : MagiskFragment<LogViewModel, FragmentLogBinding>() {
|
||||
class LogFragment : BaseFragment<LogViewModel, FragmentLogBinding>() {
|
||||
|
||||
override val layoutRes: Int = R.layout.fragment_log
|
||||
override val viewModel: LogViewModel by viewModel()
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
package com.topjohnwu.magisk.ui.log
|
||||
|
||||
import android.content.res.Resources
|
||||
import com.skoumal.teanity.databinding.ComparableRvItem
|
||||
import com.skoumal.teanity.extensions.addOnPropertyChangedCallback
|
||||
import com.skoumal.teanity.extensions.doOnSubscribeUi
|
||||
import com.skoumal.teanity.extensions.subscribeK
|
||||
import com.skoumal.teanity.util.DiffObservableList
|
||||
import com.skoumal.teanity.util.KObservableField
|
||||
import com.skoumal.teanity.viewevents.SnackbarEvent
|
||||
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.ui.base.MagiskViewModel
|
||||
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
|
||||
@@ -30,7 +30,7 @@ import java.util.*
|
||||
class LogViewModel(
|
||||
private val resources: Resources,
|
||||
private val logRepo: LogRepository
|
||||
) : MagiskViewModel(), BindingViewPagerAdapter.PageTitles<ComparableRvItem<*>> {
|
||||
) : BaseViewModel(), BindingViewPagerAdapter.PageTitles<ComparableRvItem<*>> {
|
||||
|
||||
val itemsAdapter = BindingAdapter()
|
||||
val items = DiffObservableList(ComparableRvItem.callback)
|
||||
|
||||
@@ -1,17 +1,12 @@
|
||||
package com.topjohnwu.magisk.ui.module
|
||||
|
||||
import android.content.res.Resources
|
||||
import com.skoumal.teanity.databinding.ComparableRvItem
|
||||
import com.skoumal.teanity.extensions.addOnPropertyChangedCallback
|
||||
import com.skoumal.teanity.extensions.doOnSuccessUi
|
||||
import com.skoumal.teanity.extensions.subscribeK
|
||||
import com.skoumal.teanity.util.DiffObservableList
|
||||
import com.skoumal.teanity.util.KObservableField
|
||||
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.extensions.toSingle
|
||||
import com.topjohnwu.magisk.extensions.update
|
||||
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
|
||||
@@ -20,7 +15,8 @@ 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.ui.base.MagiskViewModel
|
||||
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
|
||||
@@ -29,7 +25,7 @@ class ModuleViewModel(
|
||||
private val resources: Resources,
|
||||
private val repoUpdater: RepoUpdater,
|
||||
private val repoDB: RepoDao
|
||||
) : MagiskViewModel() {
|
||||
) : BaseViewModel() {
|
||||
|
||||
val query = KObservableField("")
|
||||
|
||||
|
||||
@@ -8,19 +8,19 @@ import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.skoumal.teanity.viewevents.ViewEvent
|
||||
import com.topjohnwu.magisk.ClassMap
|
||||
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.model.events.OpenFilePickerEvent
|
||||
import com.topjohnwu.magisk.ui.base.MagiskFragment
|
||||
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 : MagiskFragment<ModuleViewModel, FragmentModulesBinding>() {
|
||||
class ModulesFragment : BaseFragment<ModuleViewModel, FragmentModulesBinding>() {
|
||||
|
||||
override val layoutRes: Int = R.layout.fragment_modules
|
||||
override val viewModel: ModuleViewModel by sharedViewModel()
|
||||
|
||||
@@ -6,9 +6,9 @@ import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.widget.SearchView
|
||||
import com.skoumal.teanity.viewevents.ViewEvent
|
||||
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
|
||||
@@ -16,12 +16,12 @@ 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.ui.base.MagiskFragment
|
||||
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 : MagiskFragment<ModuleViewModel, FragmentReposBinding>(),
|
||||
class ReposFragment : BaseFragment<ModuleViewModel, FragmentReposBinding>(),
|
||||
SearchView.OnQueryTextListener {
|
||||
|
||||
override val layoutRes: Int = R.layout.fragment_repos
|
||||
|
||||
@@ -13,21 +13,20 @@ import androidx.preference.ListPreference
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceCategory
|
||||
import androidx.preference.SwitchPreferenceCompat
|
||||
import com.skoumal.teanity.extensions.subscribeK
|
||||
import com.skoumal.teanity.util.KObservableField
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.Config
|
||||
import com.topjohnwu.magisk.Const
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.base.BasePreferenceFragment
|
||||
import com.topjohnwu.magisk.data.database.RepoDao
|
||||
import com.topjohnwu.magisk.databinding.CustomDownloadDialogBinding
|
||||
import com.topjohnwu.magisk.extensions.subscribeK
|
||||
import com.topjohnwu.magisk.extensions.toLangTag
|
||||
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.net.Networking
|
||||
import com.topjohnwu.magisk.ui.base.BasePreferenceFragment
|
||||
import com.topjohnwu.magisk.utils.*
|
||||
import com.topjohnwu.magisk.view.dialogs.FingerprintAuthDialog
|
||||
import com.topjohnwu.superuser.Shell
|
||||
@@ -204,7 +203,7 @@ class SettingsFragment : BasePreferenceFragment() {
|
||||
Shell.su("magiskhide --disable").submit()
|
||||
}
|
||||
Config.Key.LOCALE -> {
|
||||
LocaleManager.setLocale(activity.application)
|
||||
ResourceMgr.reload()
|
||||
activity.recreate()
|
||||
}
|
||||
Config.Key.CHECK_UPDATES -> Utils.scheduleUpdateCheck(activity)
|
||||
@@ -233,7 +232,7 @@ class SettingsFragment : BasePreferenceFragment() {
|
||||
val values = mutableListOf<String>()
|
||||
|
||||
names.add(
|
||||
LocaleManager.getString(defaultLocale, R.string.system_default)
|
||||
ResourceMgr.getString(defaultLocale, R.string.system_default)
|
||||
)
|
||||
values.add("")
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package com.topjohnwu.magisk.ui.superuser
|
||||
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.base.BaseFragment
|
||||
import com.topjohnwu.magisk.databinding.FragmentSuperuserBinding
|
||||
import com.topjohnwu.magisk.ui.base.MagiskFragment
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
|
||||
class SuperuserFragment :
|
||||
MagiskFragment<SuperuserViewModel, FragmentSuperuserBinding>() {
|
||||
BaseFragment<SuperuserViewModel, FragmentSuperuserBinding>() {
|
||||
|
||||
override val layoutRes: Int = R.layout.fragment_superuser
|
||||
override val viewModel: SuperuserViewModel by viewModel()
|
||||
|
||||
@@ -2,22 +2,22 @@ package com.topjohnwu.magisk.ui.superuser
|
||||
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.Resources
|
||||
import com.skoumal.teanity.databinding.ComparableRvItem
|
||||
import com.skoumal.teanity.extensions.applySchedulers
|
||||
import com.skoumal.teanity.extensions.subscribeK
|
||||
import com.skoumal.teanity.rxbus.RxBus
|
||||
import com.skoumal.teanity.util.DiffObservableList
|
||||
import com.skoumal.teanity.viewevents.SnackbarEvent
|
||||
import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.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.ui.base.MagiskViewModel
|
||||
import com.topjohnwu.magisk.model.events.SnackbarEvent
|
||||
import com.topjohnwu.magisk.utils.DiffObservableList
|
||||
import com.topjohnwu.magisk.utils.FingerprintHelper
|
||||
import com.topjohnwu.magisk.utils.RxBus
|
||||
import com.topjohnwu.magisk.view.dialogs.CustomAlertDialog
|
||||
import com.topjohnwu.magisk.view.dialogs.FingerprintAuthDialog
|
||||
import io.reactivex.Single
|
||||
@@ -29,7 +29,7 @@ class SuperuserViewModel(
|
||||
private val packageManager: PackageManager,
|
||||
private val resources: Resources,
|
||||
rxBus: RxBus
|
||||
) : MagiskViewModel() {
|
||||
) : BaseViewModel() {
|
||||
|
||||
val items = DiffObservableList(ComparableRvItem.callback)
|
||||
val itemBinding = ItemBinding.of<ComparableRvItem<*>> { itemBinding, _, item ->
|
||||
|
||||
@@ -5,19 +5,20 @@ import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import android.view.Window
|
||||
import com.skoumal.teanity.viewevents.ViewEvent
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.base.BaseActivity
|
||||
import com.topjohnwu.magisk.databinding.ActivityRequestBinding
|
||||
import com.topjohnwu.magisk.model.entity.MagiskPolicy
|
||||
import com.topjohnwu.magisk.model.events.DieEvent
|
||||
import com.topjohnwu.magisk.model.events.ViewEvent
|
||||
import com.topjohnwu.magisk.model.receiver.GeneralReceiver
|
||||
import com.topjohnwu.magisk.ui.base.MagiskActivity
|
||||
import com.topjohnwu.magisk.utils.SuLogger
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
|
||||
open class SuRequestActivity : MagiskActivity<SuRequestViewModel, ActivityRequestBinding>() {
|
||||
open class SuRequestActivity : BaseActivity<SuRequestViewModel, ActivityRequestBinding>() {
|
||||
|
||||
override val layoutRes: Int = R.layout.activity_request
|
||||
override val themeRes: Int = R.style.MagiskTheme_SU
|
||||
override val viewModel: SuRequestViewModel by viewModel()
|
||||
|
||||
override fun onBackPressed() {
|
||||
|
||||
@@ -9,21 +9,21 @@ import android.graphics.drawable.Drawable
|
||||
import android.hardware.fingerprint.FingerprintManager
|
||||
import android.os.CountDownTimer
|
||||
import android.text.TextUtils
|
||||
import com.skoumal.teanity.databinding.ComparableRvItem
|
||||
import com.skoumal.teanity.extensions.addOnPropertyChangedCallback
|
||||
import com.skoumal.teanity.util.DiffObservableList
|
||||
import com.skoumal.teanity.util.KObservableField
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.Config
|
||||
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.addOnPropertyChangedCallback
|
||||
import com.topjohnwu.magisk.extensions.now
|
||||
import com.topjohnwu.magisk.model.entity.MagiskPolicy
|
||||
import com.topjohnwu.magisk.model.entity.recycler.SpinnerRvItem
|
||||
import com.topjohnwu.magisk.model.entity.toPolicy
|
||||
import com.topjohnwu.magisk.model.events.DieEvent
|
||||
import com.topjohnwu.magisk.ui.base.MagiskViewModel
|
||||
import com.topjohnwu.magisk.utils.DiffObservableList
|
||||
import com.topjohnwu.magisk.utils.FingerprintHelper
|
||||
import com.topjohnwu.magisk.utils.KObservableField
|
||||
import com.topjohnwu.magisk.utils.SuConnector
|
||||
import me.tatarka.bindingcollectionadapter2.BindingListViewAdapter
|
||||
import me.tatarka.bindingcollectionadapter2.ItemBinding
|
||||
@@ -36,7 +36,7 @@ class SuRequestViewModel(
|
||||
private val policyDB: PolicyDao,
|
||||
private val timeoutPrefs: SharedPreferences,
|
||||
private val resources: Resources
|
||||
) : MagiskViewModel() {
|
||||
) : BaseViewModel() {
|
||||
|
||||
val icon = KObservableField<Drawable?>(null)
|
||||
val title = KObservableField("")
|
||||
|
||||
Reference in New Issue
Block a user