Skip to content

Commit b34f9e4

Browse files
change base bottom navigation from ViewPager2 to DynamicNavigationExtension
1 parent 4c133de commit b34f9e4

11 files changed

Lines changed: 196 additions & 21 deletions

File tree

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package com.smarttoolfactory.propertyfindar
2+
3+
import android.os.Bundle
4+
import android.view.View
5+
import android.widget.Toast
6+
import androidx.core.os.bundleOf
7+
import androidx.fragment.app.activityViewModels
8+
import androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment
9+
import androidx.navigation.fragment.findNavController
10+
import com.google.android.material.bottomnavigation.BottomNavigationView
11+
import com.smarttoolfactory.core.ui.fragment.DynamicNavigationFragment
12+
import com.smarttoolfactory.core.ui.fragment.navhost.BaseDynamicNavHostFragment
13+
import com.smarttoolfactory.core.util.observe
14+
import com.smarttoolfactory.core.util.setupWithNavController
15+
import com.smarttoolfactory.core.viewmodel.PropertyDetailNavigationVM
16+
import com.smarttoolfactory.propertyfindar.databinding.FragmentMainBottomNavBinding
17+
18+
/**
19+
* Alternative of MainFragment with only [BottomNavigationView]
20+
* that has [DynamicNavHostFragment]s as root fragment of each
21+
* tab with [BaseDynamicNavHostFragment]s that extend [DynamicNavHostFragment].
22+
*
23+
*
24+
*/
25+
class MainFragmentBottomNav : DynamicNavigationFragment<FragmentMainBottomNavBinding>() {
26+
27+
/**
28+
* ViewModel for navigating to property detail screen from Main Fragment
29+
*/
30+
private val propertyDetailNavigationVM by activityViewModels<PropertyDetailNavigationVM>()
31+
32+
override fun getLayoutRes(): Int = R.layout.fragment_main_bottom_nav
33+
34+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
35+
super.onViewCreated(view, savedInstanceState)
36+
37+
Toast.makeText(requireContext(), "MainFragmentBottomNav", Toast.LENGTH_SHORT).show()
38+
if (savedInstanceState == null) {
39+
setupBottomNavigationBar()
40+
} // Else, need to wait for onRestoreInstanceState
41+
42+
subscribePropertyDetailNavigation()
43+
}
44+
45+
override fun onViewStateRestored(savedInstanceState: Bundle?) {
46+
super.onViewStateRestored(savedInstanceState)
47+
// Now that BottomNavigationBar has restored its instance state
48+
// and its selectedItemId, we can proceed with setting up the
49+
// BottomNavigationBar with Navigation
50+
setupBottomNavigationBar()
51+
}
52+
53+
/**
54+
* Called on first creation and when restoring state.
55+
*/
56+
private fun setupBottomNavigationBar() {
57+
58+
val bottomNavigationView = dataBinding!!.bottomNav
59+
60+
val navGraphIds = listOf(
61+
R.navigation.nav_graph_dfm_home_start,
62+
R.navigation.nav_graph_dfm_favorites_start,
63+
R.navigation.nav_graph_dfm_notification_start,
64+
R.navigation.nav_graph_dfm_account_start
65+
)
66+
67+
// Setup the bottom navigation view with a list of navigation graphs
68+
val controller = bottomNavigationView.setupWithNavController(
69+
navGraphIds = navGraphIds,
70+
fragmentManager = childFragmentManager,
71+
containerId = R.id.nav_host_container,
72+
intent = requireActivity().intent
73+
)
74+
}
75+
76+
/**
77+
* Navigates to Property Detail fragment from this fragment that replacing main fragment
78+
* that contains [BottomNavigationView]
79+
*/
80+
private fun subscribePropertyDetailNavigation() {
81+
82+
viewLifecycleOwner.observe(propertyDetailNavigationVM.goToPropertyDetailFromMain) {
83+
84+
it.getContentIfNotHandled()?.let { propertyItem ->
85+
val bundle = bundleOf("property" to propertyItem)
86+
87+
findNavController()
88+
.navigate(
89+
R.id.action_mainFragment_to_propertyDetailFragment,
90+
bundle
91+
)
92+
}
93+
}
94+
}
95+
}

app/src/main/res/layout/activity_main.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
app:layout_constraintBottom_toBottomOf="parent"
1919

2020
app:defaultNavHost="true"
21-
app:navGraph="@navigation/nav_graph_main"/>
21+
app:navGraph="@navigation/nav_graph_main_bottom_nav"/>
2222

2323
</androidx.constraintlayout.widget.ConstraintLayout>
2424
</layout>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<layout xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:app="http://schemas.android.com/apk/res-auto">
4+
5+
<androidx.constraintlayout.widget.ConstraintLayout
6+
android:layout_width="match_parent"
7+
android:layout_height="match_parent">
8+
9+
<androidx.fragment.app.FragmentContainerView
10+
android:id="@+id/nav_host_container"
11+
android:layout_width="0dp"
12+
android:layout_height="0dp"
13+
app:layout_constraintBottom_toTopOf="@+id/bottomNav"
14+
app:layout_constraintLeft_toLeftOf="parent"
15+
app:layout_constraintRight_toRightOf="parent"
16+
app:layout_constraintTop_toTopOf="parent" />
17+
18+
<com.google.android.material.bottomnavigation.BottomNavigationView
19+
android:id="@+id/bottomNav"
20+
android:layout_width="match_parent"
21+
android:layout_height="wrap_content"
22+
app:layout_constraintBottom_toBottomOf="parent"
23+
app:menu="@menu/menu_bottom" />
24+
25+
</androidx.constraintlayout.widget.ConstraintLayout>
26+
27+
</layout>
28+
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:app="http://schemas.android.com/apk/res-auto"
4+
xmlns:tools="http://schemas.android.com/tools"
5+
android:id="@+id/nav_graph_main_bottom_bottom_nav"
6+
app:startDestination="@id/mainFragment">
7+
8+
9+
<fragment
10+
android:id="@+id/mainFragment"
11+
android:name="com.smarttoolfactory.propertyfindar.MainFragmentBottomNav"
12+
android:label="MainFragment"
13+
tools:layout="@layout/fragment_main">
14+
15+
<action
16+
android:id="@+id/action_mainFragment_to_propertyDetailFragment"
17+
app:destination="@id/nav_graph_property_detail"
18+
app:enterAnim="@anim/slide_in_right"
19+
app:exitAnim="@anim/slide_out_left"
20+
app:popEnterAnim="@anim/slide_in_left"
21+
app:popExitAnim="@anim/slide_out_right" />
22+
23+
</fragment>
24+
25+
26+
<!-- Property Detail dynamic feature module -->
27+
<include-dynamic
28+
android:id="@+id/nav_graph_property_detail"
29+
android:name="com.smarttoolfactory.property_detail"
30+
app:graphResName="nav_graph_property_detail"
31+
app:moduleName="property_detail">
32+
33+
<argument
34+
android:name="property"
35+
app:argType="com.smarttoolfactory.domain.model.PropertyItem" />
36+
37+
</include-dynamic>
38+
</navigation>

config/detekt/detekt.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,11 @@ complexity:
105105
TooManyFunctions:
106106
active: true
107107
excludes: ['**/test/**', '**/test-utils/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**']
108-
thresholdInFiles: 11
109-
thresholdInClasses: 11
110-
thresholdInInterfaces: 11
111-
thresholdInObjects: 11
112-
thresholdInEnums: 11
108+
thresholdInFiles: 12
109+
thresholdInClasses: 12
110+
thresholdInInterfaces: 12
111+
thresholdInObjects: 12
112+
thresholdInEnums: 12
113113
ignoreDeprecated: false
114114
ignorePrivate: false
115115
ignoreOverridden: false

features/home/src/main/java/com/smarttoolfactory/home/propertylist/flow/PropertyListFlowFragment.kt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ class PropertyListFlowFragment : DynamicNavigationFragment<FragmentPropertyListB
4040
}
4141

4242
override fun bindViews() {
43-
dataBinding.viewModel = viewModel
43+
dataBinding!!.viewModel = viewModel
4444

45-
dataBinding.recyclerView.apply {
45+
dataBinding!!.recyclerView.apply {
4646

4747
// Set Layout manager
4848
this.layoutManager =
@@ -58,7 +58,7 @@ class PropertyListFlowFragment : DynamicNavigationFragment<FragmentPropertyListB
5858
this.adapter = itemListAdapter
5959
}
6060

61-
val swipeRefreshLayout = dataBinding.swipeRefreshLayout
61+
val swipeRefreshLayout = dataBinding!!.swipeRefreshLayout
6262

6363
swipeRefreshLayout.setOnRefreshListener {
6464
swipeRefreshLayout.isRefreshing = false
@@ -150,4 +150,9 @@ class PropertyListFlowFragment : DynamicNavigationFragment<FragmentPropertyListB
150150
super.onPause()
151151
toolbarVM.queryBySort.removeObservers(viewLifecycleOwner)
152152
}
153+
154+
override fun onDestroyView() {
155+
dataBinding!!.swipeRefreshLayout.setOnRefreshListener(null)
156+
super.onDestroyView()
157+
}
153158
}

features/home/src/main/java/com/smarttoolfactory/home/propertylist/paged/PagedPropertyListFragment.kt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@ class PagedPropertyListFragment :
4848
}
4949

5050
override fun bindViews() {
51-
dataBinding.viewModel = viewModel
51+
dataBinding!!.viewModel = viewModel
5252

53-
dataBinding.recyclerView.apply {
53+
dataBinding!!.recyclerView.apply {
5454

5555
// Set Layout manager
5656
val linearLayoutManager =
@@ -75,7 +75,7 @@ class PagedPropertyListFragment :
7575
this.addOnScrollListener(endlessScrollListener)
7676
}
7777

78-
val swipeRefreshLayout = dataBinding.swipeRefreshLayout
78+
val swipeRefreshLayout = dataBinding!!.swipeRefreshLayout
7979

8080
swipeRefreshLayout.setOnRefreshListener {
8181
swipeRefreshLayout.isRefreshing = false
@@ -150,4 +150,9 @@ class PagedPropertyListFragment :
150150
override fun onScrollToBottom() {
151151
viewModel.getPropertyList()
152152
}
153+
154+
override fun onDestroyView() {
155+
dataBinding!!.swipeRefreshLayout.setOnRefreshListener(null)
156+
super.onDestroyView()
157+
}
153158
}

features/home/src/main/java/com/smarttoolfactory/home/propertylist/rxjava/PropertyListRxjava3Fragment.kt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@ class PropertyListRxjava3Fragment : DynamicNavigationFragment<FragmentPropertyLi
3939
}
4040

4141
override fun bindViews() {
42-
dataBinding.viewModel = viewModel
42+
dataBinding!!.viewModel = viewModel
4343

44-
dataBinding.recyclerView.apply {
44+
dataBinding!!.recyclerView.apply {
4545

4646
// Set Layout manager
4747
this.layoutManager =
@@ -57,7 +57,7 @@ class PropertyListRxjava3Fragment : DynamicNavigationFragment<FragmentPropertyLi
5757
this.adapter = itemListAdapter
5858
}
5959

60-
val swipeRefreshLayout = dataBinding.swipeRefreshLayout
60+
val swipeRefreshLayout = dataBinding!!.swipeRefreshLayout
6161

6262
swipeRefreshLayout.setOnRefreshListener {
6363
swipeRefreshLayout.isRefreshing = false
@@ -127,4 +127,9 @@ class PropertyListRxjava3Fragment : DynamicNavigationFragment<FragmentPropertyLi
127127
super.onPause()
128128
toolbarVM.queryBySort.removeObservers(viewLifecycleOwner)
129129
}
130+
131+
override fun onDestroyView() {
132+
dataBinding!!.swipeRefreshLayout.setOnRefreshListener(null)
133+
super.onDestroyView()
134+
}
130135
}

features/property_detail/src/main/java/com/smarttoolfactory/property_detail/PropertyDetailFragment.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class PropertyDetailFragment : DynamicNavigationFragment<FragmentPropertyDetailB
2727
override fun bindViews() {
2828
// Get Post from navigation component arguments
2929
val property = arguments?.get("property") as PropertyItem
30-
dataBinding.item = property
30+
dataBinding!!.item = property
3131
}
3232

3333
override fun onCreate(savedInstanceState: Bundle?) {

libraries/core/src/main/java/com/smarttoolfactory/core/ui/fragment/BaseDataBindingFragment.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ abstract class BaseDataBindingFragment<ViewBinding : ViewDataBinding> : Fragment
3333

3434
private var _dataBinding: ViewBinding? = null
3535

36-
lateinit var dataBinding: ViewBinding
36+
var dataBinding: ViewBinding? = null
3737

3838
/**
3939
* This method gets the layout id from the derived fragment to bind to that layout via data-binding
@@ -67,9 +67,9 @@ abstract class BaseDataBindingFragment<ViewBinding : ViewDataBinding> : Fragment
6767
* again, and when onDestroyView is called removes this binding to liveData
6868
* since it's bound to View instead of Fragment(this).
6969
*/
70-
dataBinding.lifecycleOwner = viewLifecycleOwner
70+
dataBinding!!.lifecycleOwner = viewLifecycleOwner
7171

72-
val rootView = dataBinding.root
72+
val rootView = dataBinding!!.root
7373

7474
// Get width and height of the fragment
7575
rootView.post {

0 commit comments

Comments
 (0)