Skip to content

Commit f49138c

Browse files
committed
[#617] Refactor screen examples and add more complex examples for deeplink and navigation based on POC
1 parent 8d0ceae commit f49138c

File tree

35 files changed

+999
-689
lines changed

35 files changed

+999
-689
lines changed

sample-compose/app/src/androidTest/java/co/nimblehq/sample/compose/ui/screens/main/home/HomeScreenTest.kt

Lines changed: 0 additions & 94 deletions
This file was deleted.

sample-compose/app/src/main/AndroidManifest.xml

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,6 @@
2727
<category android:name="android.intent.category.LAUNCHER" />
2828
</intent-filter>
2929

30-
<intent-filter android:autoVerify="true">
31-
<action android:name="android.intent.action.VIEW" />
32-
33-
<category android:name="android.intent.category.DEFAULT" />
34-
<category android:name="android.intent.category.BROWSABLE" />
35-
36-
<data android:scheme="https" />
37-
<data android:host="android.nimblehq.co" />
38-
</intent-filter>
39-
4030
<intent-filter>
4131
<action android:name="android.intent.action.VIEW" />
4232

sample-compose/app/src/main/java/co/nimblehq/sample/compose/di/modules/main/MainActivityModule.kt

Lines changed: 81 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
11
package co.nimblehq.sample.compose.di.modules.main
22

3+
import android.content.Intent
4+
import android.net.Uri
35
import androidx.compose.ui.platform.LocalContext
6+
import androidx.core.net.toUri
47
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
5-
import co.nimblehq.sample.compose.R
6-
import co.nimblehq.sample.compose.extensions.showToast
78
import co.nimblehq.sample.compose.navigation.EntryProviderInstaller
89
import co.nimblehq.sample.compose.navigation.Navigator
910
import co.nimblehq.sample.compose.navigation.NavigatorImpl
10-
import co.nimblehq.sample.compose.ui.screens.main.MainDestination
11-
import co.nimblehq.sample.compose.ui.screens.main.home.HomeScreen
12-
import co.nimblehq.sample.compose.ui.screens.main.second.SecondScreen
13-
import co.nimblehq.sample.compose.ui.screens.main.third.ThirdScreen
11+
import co.nimblehq.sample.compose.ui.common.PATH_BASE
12+
import co.nimblehq.sample.compose.ui.common.PATH_SEARCH
13+
import co.nimblehq.sample.compose.ui.screens.details.DetailsScreen
14+
import co.nimblehq.sample.compose.ui.screens.details.DetailsScreenUi
15+
import co.nimblehq.sample.compose.ui.screens.details.DetailsViewModel
16+
import co.nimblehq.sample.compose.ui.screens.list.ListScreen
17+
import co.nimblehq.sample.compose.ui.screens.login.LoginOrRegisterScreen
18+
import co.nimblehq.sample.compose.ui.screens.login.LoginScreen
19+
import co.nimblehq.sample.compose.ui.screens.search.SearchScreen
1420
import co.nimblehq.sample.compose.util.LocalResultEventBus
1521
import co.nimblehq.sample.compose.util.ResultEffect
1622
import dagger.Module
@@ -26,48 +32,91 @@ object MainActivityModule {
2632

2733
@Provides
2834
@ActivityRetainedScoped
29-
fun provideNavigator(): Navigator = NavigatorImpl(startDestination = MainDestination.Home)
35+
fun provideNavigator(): Navigator = NavigatorImpl(startDestination = ListScreen)
3036

37+
@Suppress("LongMethod")
3138
@IntoSet
3239
@Provides
3340
fun provideEntryProviderInstaller(navigator: Navigator): EntryProviderInstaller =
3441
{
35-
entry<MainDestination.Home> {
36-
val eventBus = LocalResultEventBus.current
42+
entry<ListScreen> {
43+
ListScreen(
44+
viewModel = hiltViewModel(),
45+
onClickSearch = { navigator.goTo(SearchScreen) },
46+
onItemClick = { uiModel ->
47+
navigator.goTo(DetailsScreen.Details(uiModel.id.toIntOrNull() ?: 1))
48+
}
49+
)
50+
}
51+
52+
entry<SearchScreen> {
3753
val context = LocalContext.current
54+
SearchScreen(
55+
onClickCreateDeeplink = { username ->
56+
val intent = Intent(
57+
Intent.ACTION_VIEW,
58+
"$PATH_BASE/$PATH_SEARCH?${DetailsScreen.Search::username.name}=${Uri.encode(username)}".toUri()
59+
)
60+
context.startActivity(intent)
61+
},
62+
onClickBack = navigator::goBack
63+
)
64+
}
3865

39-
ResultEffect<Boolean> { isUpdated ->
40-
if (isUpdated) {
41-
context.showToast(context.getString(R.string.message_updated))
42-
}
43-
eventBus.removeResult<Boolean>()
66+
entry<DetailsScreen.Details> { key ->
67+
val viewModel = hiltViewModel<DetailsViewModel, DetailsViewModel.Factory>(
68+
// Note: We need a new ViewModel for every new DetailsScreen instance. Usually
69+
// we would need to supply a `key` String that is unique to the
70+
// instance, however, the ViewModelStoreNavEntryDecorator (supplied
71+
// above) does this for us, using `NavEntry.contentKey` to uniquely
72+
// identify the viewModel.
73+
//
74+
// tl;dr: Make sure you use rememberViewModelStoreNavEntryDecorator()
75+
// if you want a new ViewModel for each new navigation key instance.
76+
creationCallback = { factory -> factory.create(key) }
77+
)
78+
val eventBus = LocalResultEventBus.current
79+
80+
ResultEffect<String> { username ->
81+
viewModel.changeUsername(username)
82+
eventBus.removeResult<String>()
4483
}
4584

46-
HomeScreen(
47-
viewModel = hiltViewModel(),
48-
navigator = navigator
85+
DetailsScreenUi(
86+
viewModel = viewModel,
87+
navigateToLoginOrRegister = { navigator.goTo(LoginOrRegisterScreen) },
88+
onClickBack = navigator::goBack
4989
)
5090
}
5191

52-
entry<MainDestination.Second> { key ->
53-
val eventBus = LocalResultEventBus.current
92+
entry<DetailsScreen.Search> { key ->
93+
val viewModel = hiltViewModel<DetailsViewModel, DetailsViewModel.Factory>(
94+
creationCallback = { factory -> factory.create(key) }
95+
)
5496

55-
SecondScreen(
56-
id = key.id,
57-
navigator = navigator,
58-
viewModel = hiltViewModel(),
59-
onUpdate = {
60-
eventBus.sendResult<Boolean>(result = true)
61-
navigator.goBack()
62-
}
97+
DetailsScreenUi(
98+
viewModel = viewModel,
99+
navigateToLoginOrRegister = { navigator.goTo(LoginOrRegisterScreen) },
100+
onClickBack = navigator::goBack
63101
)
64102
}
65103

66-
entry<MainDestination.Third> { key ->
67-
ThirdScreen(
68-
model = key.model,
69-
navigator = navigator,
70-
viewModel = hiltViewModel()
104+
entry<LoginOrRegisterScreen> {
105+
LoginOrRegisterScreen(
106+
navigateToLogin = { navigator.goTo(LoginScreen) },
107+
navigateToRegister = { /* NO-OP */ },
108+
onClickBack = navigator::goBack
109+
)
110+
}
111+
112+
entry<LoginScreen> {
113+
val eventBus = LocalResultEventBus.current
114+
LoginScreen(
115+
navigateToDetails = { username ->
116+
eventBus.sendResult<String>(result = username)
117+
navigator.goBackToLast(DetailsScreen::class)
118+
},
119+
onClickBack = navigator::goBack
71120
)
72121
}
73122
}

sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/common/AppBar.kt

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
package co.nimblehq.sample.compose.ui.common
22

33
import androidx.annotation.StringRes
4+
import androidx.compose.foundation.layout.RowScope
5+
import androidx.compose.material.icons.Icons
6+
import androidx.compose.material.icons.filled.ArrowBack
47
import androidx.compose.material3.ExperimentalMaterial3Api
8+
import androidx.compose.material3.Icon
9+
import androidx.compose.material3.IconButton
510
import androidx.compose.material3.Text
611
import androidx.compose.material3.TopAppBar
712
import androidx.compose.material3.TopAppBarDefaults
@@ -18,10 +23,23 @@ import co.nimblehq.sample.compose.ui.theme.ComposeTheme
1823
fun AppBar(
1924
@StringRes title: Int,
2025
modifier: Modifier = Modifier,
26+
onClickBack: (() -> Unit)? = null,
27+
actions: @Composable RowScope.() -> Unit = {},
2128
) {
2229
TopAppBar(
2330
modifier = modifier,
2431
title = { Text(text = stringResource(title)) },
32+
navigationIcon = {
33+
if (onClickBack != null) {
34+
IconButton(onClick = onClickBack) {
35+
Icon(
36+
imageVector = Icons.Filled.ArrowBack,
37+
contentDescription = "Back"
38+
)
39+
}
40+
}
41+
},
42+
actions = actions,
2543
colors = TopAppBarDefaults.topAppBarColors().copy(
2644
containerColor = AppTheme.colors.topAppBarBackground
2745
)
@@ -31,5 +49,5 @@ fun AppBar(
3149
@Preview(showBackground = true)
3250
@Composable
3351
private fun AppBarPreview() {
34-
ComposeTheme { AppBar(R.string.home_title_bar) }
52+
ComposeTheme { AppBar(R.string.list_title) }
3553
}
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
11
package co.nimblehq.sample.compose.ui.common
22

3-
const val URL_SECOND_SCREEN = "https://sample.nimblehq.co/second?id={id}"
3+
import co.nimblehq.sample.compose.ui.screens.details.DetailsScreen
4+
5+
internal const val PATH_BASE = "android://android.nimblehq.co"
6+
internal const val PATH_SEARCH = "users/search"
7+
internal val URL_SEARCH =
8+
"$PATH_BASE/$PATH_SEARCH?${DetailsScreen.Search::username.name}={${DetailsScreen.Search::username.name}}"

sample-compose/app/src/main/java/co/nimblehq/sample/compose/ui/screens/MainActivity.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ import androidx.navigation3.ui.NavDisplay
1919
import co.nimblehq.sample.compose.extensions.setEdgeToEdgeConfig
2020
import co.nimblehq.sample.compose.navigation.EntryProviderInstaller
2121
import co.nimblehq.sample.compose.navigation.Navigator
22-
import co.nimblehq.sample.compose.ui.common.URL_SECOND_SCREEN
23-
import co.nimblehq.sample.compose.ui.screens.main.MainDestination
22+
import co.nimblehq.sample.compose.ui.common.URL_SEARCH
23+
import co.nimblehq.sample.compose.ui.screens.details.DetailsScreen
2424
import co.nimblehq.sample.compose.ui.theme.ComposeTheme
2525
import co.nimblehq.sample.compose.util.DeepLinkMatcher
2626
import co.nimblehq.sample.compose.util.DeepLinkPattern
@@ -43,7 +43,7 @@ class MainActivity : ComponentActivity() {
4343
lateinit var entryProviderScopes: Set<@JvmSuppressWildcards EntryProviderInstaller>
4444

4545
internal val deepLinkPatterns: List<DeepLinkPattern<out Any>> = listOf(
46-
DeepLinkPattern(MainDestination.Second.serializer(), URL_SECOND_SCREEN.toUri()),
46+
DeepLinkPattern(DetailsScreen.Search.serializer(), URL_SEARCH.toUri()),
4747
)
4848

4949
override fun onCreate(savedInstanceState: Bundle?) {

0 commit comments

Comments
 (0)