Skip to content

Commit 0c47ace

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

File tree

35 files changed

+998
-689
lines changed

35 files changed

+998
-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: 80 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
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.DetailsViewModel
15+
import co.nimblehq.sample.compose.ui.screens.list.ListScreen
16+
import co.nimblehq.sample.compose.ui.screens.login.LoginOrRegisterScreen
17+
import co.nimblehq.sample.compose.ui.screens.login.LoginScreen
18+
import co.nimblehq.sample.compose.ui.screens.search.SearchScreen
1419
import co.nimblehq.sample.compose.util.LocalResultEventBus
1520
import co.nimblehq.sample.compose.util.ResultEffect
1621
import dagger.Module
@@ -26,48 +31,91 @@ object MainActivityModule {
2631

2732
@Provides
2833
@ActivityRetainedScoped
29-
fun provideNavigator(): Navigator = NavigatorImpl(startDestination = MainDestination.Home)
34+
fun provideNavigator(): Navigator = NavigatorImpl(startDestination = ListScreen)
3035

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

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

46-
HomeScreen(
47-
viewModel = hiltViewModel(),
48-
navigator = navigator
84+
DetailsScreen(
85+
viewModel = viewModel,
86+
navigateToLoginOrRegister = { navigator.goTo(LoginOrRegisterScreen) },
87+
onClickBack = navigator::goBack
4988
)
5089
}
5190

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

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

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

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)