Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use jetpack navigation for BottomNavigationView #1140

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ plugins {
kotlin("kapt")

id("kotlin-android-extensions")
id("androidx.navigation.safeargs.kotlin")
}
android {
compileSdkVersion(Versions.compileSdkVersion)
Expand Down Expand Up @@ -82,6 +83,8 @@ dependencies {

implementation(Dependencies.fragment_ktx)

implementation(Dependencies.navigation_fragment)
implementation(Dependencies.navigation_ui)
implementation(Dependencies.viewPager2)
implementation(Dependencies.swipe_refresh_layout)
}
Original file line number Diff line number Diff line change
@@ -1,27 +1,24 @@
package org.systers.mentorship.view.activities

import android.content.Intent
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.widget.Toast
import com.google.android.material.bottomnavigation.BottomNavigationView
import androidx.activity.OnBackPressedCallback
import androidx.navigation.findNavController
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.onNavDestinationSelected
import androidx.navigation.ui.setupWithNavController
import kotlinx.android.synthetic.main.activity_main.*
import org.systers.mentorship.R
import org.systers.mentorship.utils.PreferenceManager
import org.systers.mentorship.view.fragments.HomeFragment
import org.systers.mentorship.view.fragments.MembersFragment
import org.systers.mentorship.view.fragments.ProfileFragment
import org.systers.mentorship.view.fragments.RelationPagerFragment
import org.systers.mentorship.view.fragments.RequestsFragment

/**
* This activity has the bottom navigation which allows the user to switch between fragments
*/
class MainActivity : BaseActivity() {

private var atHome = true

private val TOAST_DURATION = 4000
private var mLastPress: Long = 0
private lateinit var exitToast: Toast
Expand All @@ -32,96 +29,59 @@ class MainActivity : BaseActivity() {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
bottomNavigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)
bottomNavigation.setOnNavigationItemReselectedListener { }

if (savedInstanceState == null) {
showHomeFragment()
} else {
atHome = savedInstanceState.getBoolean("atHome")
}
}
val navHostFragment =
supportFragmentManager.findFragmentById(R.id.contentFrame) as NavHostFragment
val navController = navHostFragment.navController
// Specify top-level destinations
val appBarConfiguration = AppBarConfiguration(
setOf(
R.id.navigation_home,
R.id.navigation_profile,
R.id.navigation_relation,
R.id.navigation_members,
R.id.navigation_requests
)
)
// Setup toolbar to automatically show title based on label specified in nav graph
collapsingToolbarLayout.setupWithNavController(toolbar, navController, appBarConfiguration)
// Setup bottom nav to automatically handle navigation based on nav graph and bottom nav menu
bottomNavigation.setupWithNavController(navController)

private val mOnNavigationItemSelectedListener =
BottomNavigationView.OnNavigationItemSelectedListener { item ->
when (item.itemId) {
R.id.navigation_home -> {
replaceFragment(R.id.contentFrame, HomeFragment.newInstance(),
R.string.fragment_title_home)
atHome = true
return@OnNavigationItemSelectedListener true
}
R.id.navigation_profile -> {
replaceFragment(R.id.contentFrame, ProfileFragment.newInstance(),
R.string.fragment_title_profile)
atHome = false
return@OnNavigationItemSelectedListener true
}
R.id.navigation_relation -> {
replaceFragment(R.id.contentFrame, RelationPagerFragment.newInstance(),
R.string.fragment_title_relation)
atHome = false
return@OnNavigationItemSelectedListener true
}
R.id.navigation_members -> {
replaceFragment(R.id.contentFrame, MembersFragment.newInstance(),
R.string.fragment_title_members)
atHome = false
return@OnNavigationItemSelectedListener true
}
R.id.navigation_requests -> {
replaceFragment(R.id.contentFrame, RequestsFragment.newInstance(),
R.string.fragment_title_requests)
atHome = false
return@OnNavigationItemSelectedListener true
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
if (navController.currentDestination?.id == R.id.navigation_home) {
val currentTime = System.currentTimeMillis()
if (currentTime - mLastPress > TOAST_DURATION) {
exitToast = Toast.makeText(
baseContext,
getString(R.string.exit_toast),
Toast.LENGTH_LONG
)
exitToast.show()
mLastPress = currentTime
} else {
exitToast.cancel() // Hide toast on App exit
isEnabled = false
onBackPressed()
}
} else {
isEnabled = false
onBackPressed()
isEnabled = true
}
false
}
})
}

override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.main_menu, menu)
return true
}

override fun onOptionsItemSelected(item: MenuItem) =
when (item.itemId) {
R.id.menu_settings -> {
startActivity(Intent(this, SettingsActivity::class.java))
true
}
else -> false
}

private fun showHomeFragment() {
atHome = true
bottomNavigation.selectedItemId = R.id.navigation_home
replaceFragment(R.id.contentFrame, HomeFragment.newInstance(), R.string.fragment_title_home)
}

override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)

outState.putBoolean("atHome", atHome)
}

private fun showToast() {
val currentTime = System.currentTimeMillis()
if (currentTime - mLastPress > TOAST_DURATION) {
exitToast = Toast.makeText(baseContext, getString(R.string.exit_toast), Toast.LENGTH_LONG)
exitToast.show()
mLastPress = currentTime
} else {
exitToast.cancel() // Hide toast on App exit
super.onBackPressed()
}
return super.onCreateOptionsMenu(menu)
}

override fun onBackPressed() {
if (!atHome) {
showHomeFragment()
} else {
showToast()
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val navController = findNavController(R.id.contentFrame)
return item.onNavDestinationSelected(navController) || super.onOptionsItemSelected(item)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ class SettingsActivity : BaseActivity() {

supportActionBar?.title = getString(R.string.settings)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowHomeEnabled(true)

tvLogout.setOnClickListener {
val builder = AlertDialog.Builder(this)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,6 @@ class HomeFragment : BaseFragment() {
private lateinit var achievementsAdapter: AchievementsAdapter

companion object {
/**
* Creates an instance of HomeFragment
*/
fun newInstance() = HomeFragment()
val TAG: String = HomeFragment::class.java.simpleName
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,6 @@ import org.systers.mentorship.viewmodels.MembersViewModel
*/
class MembersFragment : BaseFragment() {

companion object {
/**
* Creates an instance of [MembersFragment]
*/
fun newInstance() = MembersFragment()
}

private var memberListInitialized = false

private val membersViewModel: MembersViewModel by viewModels()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@ import org.systers.mentorship.viewmodels.ProfileViewModel
class ProfileFragment : BaseFragment() {

companion object {
/**
* Creates an instance of ProfileFragment
*/
fun newInstance() = ProfileFragment()
val TAG: String = ProfileFragment::class.java.simpleName
}

Expand Down Expand Up @@ -73,7 +69,7 @@ class ProfileFragment : BaseFragment() {
editProfileFragment.setOnDismissListener {
fetchNewest()
}
fragmentManager?.let { editProfileFragment.show(it, getString(R.string.fragment_title_edit_profile)) }
childFragmentManager.let { editProfileFragment.show(it, getString(R.string.fragment_title_edit_profile)) }
}
true
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ class RelationPagerFragment : BaseFragment() {
baseActivity.tlMentorshipRelation.removeAllTabs()
tvFindPeopleBtn.setOnClickListener {
baseActivity.bottomNavigation.selectedItemId = R.id.navigation_members
baseActivity.replaceFragment(R.id.contentFrame, MembersFragment.newInstance(), R.string.navigation_title_members)
}
} else {
tvNoCurrentRelation.visibility = View.GONE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,7 @@ import org.systers.mentorship.viewmodels.RequestsViewModel
class RequestsFragment : BaseFragment() {

companion object {
/**
* Creates an instance of [RequestsFragment]
*/
fun newInstance() = RequestsFragment()

val TAG = RelationFragment::class.java.simpleName
val TAG = RequestsFragment::class.java.simpleName
}

private val requestsViewModel: RequestsViewModel by viewModels()
Expand Down
5 changes: 4 additions & 1 deletion app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,10 @@
android:fillViewport="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior">

<FrameLayout
<androidx.fragment.app.FragmentContainerView
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/main_navigation"
app:defaultNavHost="true"
android:id="@+id/contentFrame"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
Expand Down
45 changes: 45 additions & 0 deletions app/src/main/res/navigation/main_navigation.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<navigation
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main_navigation"
app:startDestination="@id/navigation_home">

<fragment
android:id="@+id/navigation_home"
android:name="org.systers.mentorship.view.fragments.HomeFragment"
tools:layout="@layout/fragment_home"
android:label="@string/fragment_title_home" />

<fragment
android:id="@+id/navigation_profile"
android:name="org.systers.mentorship.view.fragments.ProfileFragment"
tools:layout="@layout/fragment_profile"
android:label="@string/fragment_title_profile" />

<fragment
android:id="@+id/navigation_relation"
android:name="org.systers.mentorship.view.fragments.RelationPagerFragment"
tools:layout="@layout/fragment_relation_pager"
android:label="@string/fragment_title_relation" />

<fragment
android:id="@+id/navigation_members"
android:name="org.systers.mentorship.view.fragments.MembersFragment"
tools:layout="@layout/fragment_members"
android:label="@string/fragment_title_members" />

<fragment
android:id="@+id/navigation_requests"
android:name="org.systers.mentorship.view.fragments.RequestsFragment"
tools:layout="@layout/fragment_requests"
android:label="@string/fragment_title_requests" />

<activity
android:id="@+id/menu_settings"
android:name="org.systers.mentorship.view.activities.SettingsActivity"
android:label="@string/settings"
tools:layout="@layout/activity_settings" />

</navigation>
7 changes: 3 additions & 4 deletions app/src/main/res/values-v21/styles.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@
<item name="android:windowContentTransitions">true</item>
</style>

<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
<style
name="AppTheme.NoActionBar"
parent="Theme.MaterialComponents.Light.NoActionBar" />
</resources>
7 changes: 3 additions & 4 deletions app/src/main/res/values/styles.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@
<item name="android:windowAnimationStyle">@style/CustomActivityAnimation</item>
</style>

<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
<style
name="AppTheme.NoActionBar"
parent="Theme.MaterialComponents.Light.NoActionBar" />

<style
name="FilterTheme"
Expand Down
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ buildscript {
dependencies {
classpath(Dependencies.gradle_build_tool)
classpath(Dependencies.kotlin_gradle_plugin)
classpath(Dependencies.navigation_safe_args_plugin)

// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
Expand Down
4 changes: 4 additions & 0 deletions buildSrc/src/main/kotlin/Dependencies.kt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ object Versions {
const val appCompat = "1.0.2"
const val circleImageView = "3.0.1"
const val fragmentKtx = "1.2.5"
const val navigationVersion = "2.3.5"
}

/**
Expand Down Expand Up @@ -67,4 +68,7 @@ object Dependencies {
const val fragment_ktx = "androidx.fragment:fragment-ktx:${Versions.fragmentKtx}"
const val viewPager2 = "androidx.viewpager2:viewpager2:${Versions.viewPager2}"
const val swipe_refresh_layout = "androidx.swiperefreshlayout:swiperefreshlayout:${Versions.swipeRefreshLayout}"
const val navigation_fragment = "androidx.navigation:navigation-fragment-ktx:${Versions.navigationVersion}"
const val navigation_ui = "androidx.navigation:navigation-ui-ktx:${Versions.navigationVersion}"
const val navigation_safe_args_plugin = "androidx.navigation:navigation-safe-args-gradle-plugin:${Versions.navigationVersion}"
}