Skip to content
Permalink
Browse files

Migrate MainActivity to use a nav host from architecture components.

The current nav graph only considers the elements in the nav drawer menu (navigation.xml).
The back button behavior has been moved to the respective fragments.
SessionDetails and launching the map from session details will be in a follow up CL.

Bug: 123673505
Change-Id: Ia9de6c804280e1b65e5be6a6d3f6961049860516
  • Loading branch information...
benbaxter authored and thagikura committed Mar 15, 2019
1 parent 2d5036f commit 2c3431369951824c42c8f5e20bb34fdaa0eae94d
@@ -69,7 +69,7 @@ buildscript {
materialVersion = '1.1.0-alpha04-cl237931928'
mockitoVersion = "2.8.9"
mockitoKotlinVersion = "1.5.0"
navigationVersion = "2.0.0-rc02"
navigationVersion = "2.0.0"
okhttpVersion = "3.10.0"
okioVersion = '1.14.0'
pageIndicatorVersion = "1.3.0"
@@ -22,12 +22,18 @@ import android.os.Bundle
import android.view.View
import android.widget.FrameLayout
import android.widget.Toast
import androidx.appcompat.widget.Toolbar
import androidx.core.view.GravityCompat
import androidx.core.view.updatePadding
import androidx.drawerlayout.widget.DrawerLayout
import androidx.drawerlayout.widget.DrawerLayout.DrawerListener
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.NavController
import androidx.navigation.findNavController
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupWithNavController
import com.firebase.ui.auth.IdpResponse
import com.google.android.material.navigation.NavigationView
import com.google.samples.apps.iosched.R
@@ -36,15 +42,8 @@ import com.google.samples.apps.iosched.shared.di.ExploreArEnabledFlag
import com.google.samples.apps.iosched.shared.di.FeedFeatureEnabledFlag
import com.google.samples.apps.iosched.shared.di.MapFeatureEnabledFlag
import com.google.samples.apps.iosched.shared.result.EventObserver
import com.google.samples.apps.iosched.shared.util.inTransaction
import com.google.samples.apps.iosched.shared.util.viewModelProvider
import com.google.samples.apps.iosched.ui.agenda.AgendaFragment
import com.google.samples.apps.iosched.ui.feed.FeedFragment
import com.google.samples.apps.iosched.ui.info.InfoFragment
import com.google.samples.apps.iosched.ui.map.MapFragment
import com.google.samples.apps.iosched.ui.messages.SnackbarMessageManager
import com.google.samples.apps.iosched.ui.schedule.ScheduleFragment
import com.google.samples.apps.iosched.ui.settings.SettingsFragment
import com.google.samples.apps.iosched.ui.signin.SignInDialogFragment
import com.google.samples.apps.iosched.ui.signin.SignOutDialogFragment
import com.google.samples.apps.iosched.util.HeightTopWindowInsetsListener
@@ -63,11 +62,19 @@ class MainActivity : DaggerAppCompatActivity(), NavigationHost, DrawerListener {
/** Key for an int extra defining the initial navigation target. */
const val EXTRA_NAVIGATION_ID = "extra.NAVIGATION_ID"

private const val FRAGMENT_ID = R.id.fragment_container
private const val NAV_ID_NONE = -1

private const val DIALOG_SIGN_IN = "dialog_sign_in"
private const val DIALOG_SIGN_OUT = "dialog_sign_out"

private val TOP_LEVEL_DESTINATIONS = setOf(
R.id.navigation_feed,
R.id.navigation_schedule,
R.id.navigation_map,
R.id.navigation_info,
R.id.navigation_agenda,
R.id.navigation_settings
)
}

@Inject
@@ -93,14 +100,15 @@ class MainActivity : DaggerAppCompatActivity(), NavigationHost, DrawerListener {

private lateinit var viewModel: MainActivityViewModel

private lateinit var content: FrameLayout
private lateinit var drawer: DrawerLayout
private lateinit var navigation: NavigationView
private lateinit var statusScrim: View

private lateinit var navHeaderBinding: NavigationHeaderBinding
private lateinit var content: FrameLayout
private lateinit var navController: NavController
private var navHostFragment: NavHostFragment? = null

private lateinit var statusScrim: View

private lateinit var currentFragment: MainNavigationFragment
private var currentNavId = NAV_ID_NONE
private var pendingNavId = NAV_ID_NONE

@@ -113,9 +121,6 @@ class MainActivity : DaggerAppCompatActivity(), NavigationHost, DrawerListener {

setContentView(R.layout.activity_main)

drawer = findViewById(R.id.drawer)
drawer.addDrawerListener(this)

content = findViewById(R.id.content_container)
content.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
@@ -126,11 +131,22 @@ class MainActivity : DaggerAppCompatActivity(), NavigationHost, DrawerListener {
statusScrim = findViewById(R.id.status_bar_scrim)
statusScrim.setOnApplyWindowInsetsListener(HeightTopWindowInsetsListener)

drawer = findViewById(R.id.drawer)
drawer.addDrawerListener(this)

navHeaderBinding = NavigationHeaderBinding.inflate(layoutInflater).apply {
viewModel = this@MainActivity.viewModel
lifecycleOwner = this@MainActivity
}

navHostFragment = supportFragmentManager
.findFragmentById(R.id.nav_host_fragment) as NavHostFragment?

navController = findNavController(R.id.nav_host_fragment)
navController.addOnDestinationChangedListener { _, destination, _ ->
currentNavId = destination.id
}

navigation = findViewById(R.id.navigation)
navigation.apply {
addHeaderView(navHeaderBinding.root)
@@ -143,6 +159,7 @@ class MainActivity : DaggerAppCompatActivity(), NavigationHost, DrawerListener {
navigateWhenDrawerClosed(it.itemId)
true
}
setupWithNavController(navController)
}

// Update the Navigation header view to pad itself down
@@ -155,11 +172,6 @@ class MainActivity : DaggerAppCompatActivity(), NavigationHost, DrawerListener {
val initialNavId = intent.getIntExtra(EXTRA_NAVIGATION_ID, R.id.navigation_schedule)
navigation.setCheckedItem(initialNavId) // doesn't trigger listener
navigateTo(initialNavId)
} else {
// Find the current fragment
currentFragment =
supportFragmentManager.findFragmentById(FRAGMENT_ID) as? MainNavigationFragment
?: throw IllegalStateException("Activity recreated, but no fragment found!")
}

viewModel.theme.observe(this, Observer(::updateForTheme))
@@ -181,6 +193,11 @@ class MainActivity : DaggerAppCompatActivity(), NavigationHost, DrawerListener {
})
}

override fun registerToolbarWithNavigation(toolbar: Toolbar) {
val appBarConfiguration = AppBarConfiguration(TOP_LEVEL_DESTINATIONS, drawer)
toolbar.setupWithNavController(navController, appBarConfiguration)
}

override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
super.onRestoreInstanceState(savedInstanceState)
currentNavId = navigation.checkedItem?.itemId ?: NAV_ID_NONE
@@ -205,7 +222,7 @@ class MainActivity : DaggerAppCompatActivity(), NavigationHost, DrawerListener {
override fun onBackPressed() {
if (drawer.isDrawerOpen(navigation)) {
closeDrawer()
} else if (!currentFragment.onBackPressed()) {
} else {
super.onBackPressed()
}
}
@@ -216,7 +233,13 @@ class MainActivity : DaggerAppCompatActivity(), NavigationHost, DrawerListener {

override fun onUserInteraction() {
super.onUserInteraction()
currentFragment.onUserInteraction()
getCurrentFragment()?.onUserInteraction()
}

private fun getCurrentFragment(): MainNavigationFragment? {
return navHostFragment
?.childFragmentManager
?.primaryNavigationFragment as MainNavigationFragment?
}

private fun navigateWhenDrawerClosed(navId: Int) {
@@ -230,31 +253,22 @@ class MainActivity : DaggerAppCompatActivity(), NavigationHost, DrawerListener {
}

private fun navigateTo(navId: Int) {
when (navId) {
currentNavId -> return // user tapped the current item
R.id.navigation_feed -> replaceFragment(FeedFragment())
R.id.navigation_schedule -> replaceFragment(ScheduleFragment())
R.id.navigation_map -> replaceFragment(MapFragment())
R.id.navigation_explore_ar -> {
// TODO: Launch the ArActivity. Need to resolve the AR module is installed at this
// moment
Toast.makeText(this, "Launching AR Activity",
Toast.LENGTH_SHORT).show()
return
}
R.id.navigation_info -> replaceFragment(InfoFragment())
R.id.navigation_agenda -> replaceFragment(AgendaFragment())
R.id.navigation_settings -> replaceFragment(SettingsFragment())
else -> return // not a valid nav ID
if (navId == currentNavId) {
return // user tapped the current item
}
currentNavId = navId
}

private fun replaceFragment(fragment: MainNavigationFragment) {
supportFragmentManager.inTransaction {
currentFragment = fragment
replace(FRAGMENT_ID, fragment)
// Handle launching new activities, otherwise assume the destination is handled by the nav
// graph.
if (navId == R.id.navigation_explore_ar) {
// TODO: Launch the ArActivity. Need to resolve the AR module is installed at this
// moment
Toast.makeText(
this, "Launching AR Activity",
Toast.LENGTH_SHORT
).show()
return
}

navController.navigate(navId)
}

private fun openSignInDialog() {
@@ -265,12 +279,6 @@ class MainActivity : DaggerAppCompatActivity(), NavigationHost, DrawerListener {
SignOutDialogFragment().show(supportFragmentManager, DIALOG_SIGN_OUT)
}

// -- NavigationHost overrides

override fun showNavigation() {
drawer.openDrawer(GravityCompat.START)
}

// -- DrawerListener overrides

override fun onDrawerClosed(drawerView: View) {
@@ -28,23 +28,15 @@ import dagger.android.support.DaggerFragment
*/
interface NavigationHost {

/** Called by MainNavigationFragment to show navigation UI to the user. */
fun showNavigation()
/** Called by MainNavigationFragment to setup it's toolbar with the navigation controller. */
fun registerToolbarWithNavigation(toolbar: Toolbar)
}

/**
* To be implemented by main navigation destinations shown by a [NavigationHost].
*/
interface NavigationDestination {

/**
* Called by the host when the Back button is pressed.
* @return True if the destination consumed (handled) the back press, false otherwise.
*/
fun onBackPressed(): Boolean {
return false
}

/** Called by the host when the user interacts with it. */
fun onUserInteraction() {}
}
@@ -75,9 +67,7 @@ open class MainNavigationFragment : DaggerFragment(), NavigationDestination {
val host = navigationHost ?: return
val mainToolbar: Toolbar = view.findViewById(R.id.toolbar) ?: return
mainToolbar.apply {
setNavigationOnClickListener {
host.showNavigation()
}
host.registerToolbarWithNavigation(this)
}
}
}
@@ -81,10 +81,4 @@ class MapActivity : DaggerAppCompatActivity() {

viewModel.theme.observe(this, Observer(::updateForTheme))
}

override fun onBackPressed() {
if (!fragment.onBackPressed()) {
super.onBackPressed()
}
}
}
@@ -26,6 +26,7 @@ import android.text.Html
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.activity.OnBackPressedCallback
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.core.view.isInvisible
@@ -87,6 +88,8 @@ class MapFragment : MainNavigationFragment() {
if (savedInstanceState != null) {
mapViewBundle = savedInstanceState.getBundle(MAPVIEW_BUNDLE_KEY)
}

requireActivity().addOnBackPressedCallback(this, OnBackPressedCallback { onBackPressed() })
}

override fun onCreateView(
@@ -270,14 +273,14 @@ class MapFragment : MainNavigationFragment() {
binding.clickable.isClickable = !desc.isEmpty()
}

override fun onBackPressed(): Boolean {
private fun onBackPressed(): Boolean {
if (::bottomSheetBehavior.isInitialized &&
bottomSheetBehavior.state == BottomSheetBehavior.STATE_EXPANDED
) {
bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
return true
}
return super.onBackPressed()
return false
}

override fun onSaveInstanceState(outState: Bundle) {
@@ -21,6 +21,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.activity.OnBackPressedCallback
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
@@ -105,6 +106,12 @@ class ScheduleFragment : MainNavigationFragment() {

private lateinit var binding: FragmentScheduleBinding

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

requireActivity().addOnBackPressedCallback(this, OnBackPressedCallback { onBackPressed() })
}

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@@ -344,7 +351,7 @@ class ScheduleFragment : MainNavigationFragment() {
}
}

override fun onBackPressed(): Boolean {
private fun onBackPressed(): Boolean {
if (::bottomSheetBehavior.isInitialized && bottomSheetBehavior.state == STATE_EXPANDED) {
// collapse or hide the sheet
if (bottomSheetBehavior.isHideable && bottomSheetBehavior.skipCollapsed) {
@@ -354,7 +361,7 @@ class ScheduleFragment : MainNavigationFragment() {
}
return true
}
return super.onBackPressed()
return false
}

override fun onUserInteraction() {
@@ -31,10 +31,13 @@
android:layout_height="match_parent"
android:fitsSystemWindows="true">

<FrameLayout
android:id="@+id/fragment_container"
<fragment
android:name="androidx.navigation.fragment.NavHostFragment"
android:id="@+id/nav_host_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph" />

<View
android:id="@+id/status_bar_scrim"

0 comments on commit 2c34313

Please sign in to comment.
You can’t perform that action at this time.