16
16
17
17
package com.esri.arcgismaps.kotlin.sampleviewer.navigation
18
18
19
+ import android.content.Context
20
+ import android.util.Log
21
+ import android.widget.Toast
19
22
import androidx.compose.runtime.Composable
20
- import androidx.compose.runtime.compositionLocalOf
21
- import androidx.compose.ui.platform.LocalInspectionMode
23
+ import androidx.compose.ui.platform.LocalContext
22
24
import androidx.navigation.NavGraph.Companion.findStartDestination
23
25
import androidx.navigation.NavHostController
24
26
import androidx.navigation.NavType
@@ -35,37 +37,28 @@ import com.esri.arcgismaps.kotlin.sampleviewer.ui.screens.sampleList.SampleListS
35
37
import com.esri.arcgismaps.kotlin.sampleviewer.ui.screens.search.SearchResults
36
38
import com.esri.arcgismaps.kotlin.sampleviewer.ui.screens.search.SearchScreen
37
39
38
- // Composition Local for the app wide navigation controller
39
- val LocalNavController = compositionLocalOf<NavHostController > {
40
- error(" LocalNavController not found" )
41
- }
42
-
43
40
/* *
44
41
* A composable function to host the navigation system.
45
42
*/
46
43
@Composable
47
- fun NavGraph () {
48
- val navController = if (LocalInspectionMode .current) {
49
- rememberNavController()
50
- } else {
51
- LocalNavController .current
52
- }
53
-
44
+ internal fun NavGraph () {
45
+ val context = LocalContext .current
46
+ val navController = rememberNavController()
54
47
NavHost (
55
48
navController = navController,
56
49
startDestination = Routes .HOME_SCREEN ,
57
50
) {
58
51
59
52
composable(Routes .HOME_SCREEN ) {
60
53
HomeCategoryScreen (
61
- navigateToSearch = { navController.navigate(Routes .SEARCH_SCREEN ) },
62
- navigateToAbout = { navController.navigate(Routes .ABOUT_SCREEN ) },
63
- navigateToCategory = { navController.navigate(Routes .createCategoryRoute(it)) }
54
+ onNavigateToSearch = { navController.navigate(Routes .SEARCH_SCREEN ) },
55
+ onNavigateToAbout = { navController.navigate(Routes .ABOUT_SCREEN ) },
56
+ onNavigateToCategory = { navController.navigate(Routes .createCategoryRoute(it)) }
64
57
)
65
58
}
66
59
67
60
composable(Routes .ABOUT_SCREEN ) {
68
- AboutScreen ()
61
+ AboutScreen (onBackPressed = { navController.pop() } )
69
62
}
70
63
71
64
composable(
@@ -76,13 +69,15 @@ fun NavGraph() {
76
69
if (! categoryNavEntry.isNullOrEmpty())
77
70
SampleListScreen (
78
71
categoryNavEntry = categoryNavEntry,
79
- navigateToInfo = { optionPosition, sample ->
72
+ onNavigateToInfo = { optionPosition, sample ->
80
73
navController.navigate(
81
74
Routes .createSampleInfoRoute(optionPosition, sample.name)
82
75
)
83
- })
76
+ },
77
+ onBackPressed = { navController.pop() }
78
+ )
84
79
else {
85
- navController.navigateToHome( )
80
+ navController.displayError( " categoryNavEntry is null/empty " , context )
86
81
}
87
82
}
88
83
@@ -100,17 +95,23 @@ fun NavGraph() {
100
95
val sampleNavEntry = DefaultSampleInfoRepository .getSampleByName(sampleNameNavEntry)
101
96
SampleInfoScreen (
102
97
sample = sampleNavEntry,
103
- optionPosition = optionPositionNavEntry
98
+ optionPosition = optionPositionNavEntry,
99
+ onBackPressed = { navController.pop() }
104
100
)
101
+ } else if (optionPositionNavEntry == null ) {
102
+ navController.displayError(" optionPositionNavEntry is null" , context)
105
103
} else {
106
- navController.navigateToHome( )
104
+ navController.displayError( " sampleNameNavEntry is null/empty " , context )
107
105
}
108
106
}
109
107
110
108
composable(Routes .SEARCH_SCREEN ) {
111
- SearchScreen (navigateToSearchResults = {
112
- navController.navigate(Routes .createSearchResultsRoute(it))
113
- })
109
+ SearchScreen (
110
+ onNavigateToSearchResults = {
111
+ navController.navigate(Routes .createSearchResultsRoute(it))
112
+ },
113
+ onBackPressed = { navController.pop() }
114
+ )
114
115
}
115
116
116
117
composable(
@@ -128,29 +129,52 @@ fun NavGraph() {
128
129
sample.name
129
130
)
130
131
)
131
- })
132
+ },
133
+ onBackPressed = { navController.pop() }
134
+ )
132
135
} else {
133
- navController.navigateToHome( )
136
+ navController.displayError( " queryNavEntry is null/empty " , context )
134
137
}
135
138
}
136
139
}
137
140
}
138
141
142
+
143
+ /* *
144
+ * Displays a Toast and a Log for the given [message] on route errors,
145
+ * then reset navigation to home screen.
146
+ */
147
+ private fun NavHostController.displayError (message : String , context : Context ) {
148
+ val exceptionTag = " InvalidRouteError"
149
+ Toast .makeText(context, " $exceptionTag : $message " , Toast .LENGTH_SHORT ).show()
150
+ Log .e(exceptionTag, message)
151
+ navigateToHome()
152
+ }
153
+
154
+ /* *
155
+ * Attempts to pop the controller's back stack. Checks if screen was navigated to
156
+ * another destination, or navigate to home if no items in stack.
157
+ */
158
+ private fun NavHostController.pop () {
159
+ if (! popBackStack()) {
160
+ navigateToHome()
161
+ }
162
+ }
163
+
139
164
/* *
140
165
* Navigates to the home screen, clearing the back stack and restoring the state.
141
166
*/
142
167
private fun NavHostController.navigateToHome () {
143
168
navigate(Routes .HOME_SCREEN ) {
144
- popUpTo(graph.findStartDestination().id) { saveState = false }
169
+ popUpTo(graph.findStartDestination().id)
145
170
launchSingleTop = true
146
- restoreState = false
147
171
}
148
172
}
149
173
150
174
/* *
151
175
* Navigation Routes for the application.
152
176
*/
153
- object Routes {
177
+ private object Routes {
154
178
private const val SAMPLE_LIST = " Sample List"
155
179
private const val SAMPLE_INFO = " Sample Info"
156
180
private const val SEARCH_RESULTS = " Search Results"
0 commit comments