Replaced xml navigation with self-handled

This commit is contained in:
Viktor De Pasquale
2019-04-16 19:00:32 +02:00
parent 0e5417a13e
commit ebab126579
13 changed files with 311 additions and 67 deletions
@@ -3,23 +3,42 @@ package com.topjohnwu.magisk.ui
import android.content.Intent
import android.os.Bundle
import androidx.core.view.GravityCompat
import androidx.navigation.ui.setupWithNavController
import androidx.fragment.app.Fragment
import com.topjohnwu.magisk.ClassMap
import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.databinding.ActivityMainBinding
import com.topjohnwu.magisk.model.navigation.Navigation
import com.topjohnwu.magisk.ui.base.MagiskActivity
import com.topjohnwu.magisk.ui.hide.MagiskHideFragment
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 com.topjohnwu.net.Networking
import com.topjohnwu.superuser.Shell
import org.koin.androidx.viewmodel.ext.android.viewModel
import kotlin.reflect.KClass
import com.topjohnwu.magisk.ui.home.MagiskFragment as HomeFragment
open class MainActivity : MagiskActivity<MainViewModel, ActivityMainBinding>() {
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
override val baseFragments: List<KClass<out Fragment>> = listOf(
HomeFragment::class,
SuperuserFragment::class,
MagiskHideFragment::class,
ModulesFragment::class,
ReposFragment::class,
LogFragment::class,
SettingsFragment::class
)
/*override fun getDarkTheme(): Int {
return R.style.AppTheme_Dark
@@ -35,7 +54,6 @@ open class MainActivity : MagiskActivity<MainViewModel, ActivityMainBinding>() {
checkHideSection()
setSupportActionBar(binding.mainInclude.mainToolbar)
binding.navView.setupWithNavController(navController)
}
override fun onBackPressed() {
@@ -1,5 +1,7 @@
package com.topjohnwu.magisk.ui
import android.view.MenuItem
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.model.navigation.Navigation
import com.topjohnwu.magisk.ui.base.MagiskViewModel
@@ -8,4 +10,18 @@ class MainViewModel : MagiskViewModel() {
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
}
}
@@ -1,13 +1,126 @@
package com.topjohnwu.magisk.ui.base
import android.content.Intent
import android.os.Bundle
import androidx.annotation.CallSuper
import androidx.core.net.toUri
import androidx.databinding.ViewDataBinding
import androidx.fragment.app.Fragment
import com.ncapdevi.fragnav.FragNavController
import com.ncapdevi.fragnav.FragNavTransactionOptions
import com.skoumal.teanity.viewevents.ViewEvent
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.utils.Utils
import timber.log.Timber
import kotlin.reflect.KClass
abstract class MagiskActivity<ViewModel : MagiskViewModel, Binding : ViewDataBinding> :
MagiskLeanbackActivity<ViewModel, Binding>() {
MagiskLeanbackActivity<ViewModel, Binding>(), FragNavController.RootFragmentListener,
Navigator {
override val numberOfRootFragments: Int get() = baseFragments.size
override val baseFragments: List<KClass<out Fragment>> = listOf()
protected open val defaultPosition: Int = 0
protected val navigationController by lazy {
if (navHostId == 0) throw IllegalStateException("Did you forget to override \"navHostId\"?")
FragNavController(supportFragmentManager, navHostId)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
navigationController.apply {
rootFragmentListener = 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 MagiskNavigationEvent -> navigateTo(event)
}
}
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()
} catch (e: UnsupportedOperationException) {
super.onBackPressed()
}
}
fun openUrl(url: String) = Utils.openLink(this, url.toUri())
private fun FragNavTransactionOptions.Builder.customAnimations(options: MagiskAnimBuilder) =
customAnimations(options.enter, options.exit, options.popEnter, options.popExit)
}
@@ -1,16 +1,35 @@
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.navigation.MagiskNavigationEvent
import com.topjohnwu.magisk.model.navigation.Navigator
import kotlin.reflect.KClass
abstract class MagiskFragment<ViewModel : MagiskViewModel, Binding : ViewDataBinding> :
TeanityFragment<ViewModel, Binding>() {
TeanityFragment<ViewModel, Binding>(), Navigator {
protected val magiskActivity get() = activity as MagiskActivity<*, *>
fun openLink(url: String) {
magiskActivity.openUrl(url)
// We don't need nested fragments
override val baseFragments: List<KClass<Fragment>> = listOf()
override fun navigateTo(event: MagiskNavigationEvent) = magiskActivity.navigateTo(event)
@CallSuper
override fun onEventDispatched(event: ViewEvent) {
super.onEventDispatched(event)
when (event) {
is MagiskNavigationEvent -> navigateTo(event)
}
}
fun openLink(url: String) = magiskActivity.openUrl(url)
open fun onBackPressed(): Boolean = false
}