diff --git a/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppStateTest.kt b/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppStateTest.kt index 3d3dd12b1..4835db660 100644 --- a/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppStateTest.kt +++ b/app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppStateTest.kt @@ -76,7 +76,6 @@ class NiaAppStateTest { NiaAppState( navController = navController, coroutineScope = backgroundScope, - networkMonitor = networkMonitor, errorMonitor = errorMonitor, userNewsResourceRepository = userNewsResourceRepository, timeZoneMonitor = timeZoneMonitor, @@ -99,7 +98,6 @@ class NiaAppStateTest { fun niaAppState_destinations() = runTest { composeTestRule.setContent { state = rememberNiaAppState( - networkMonitor = networkMonitor, errorMonitor = errorMonitor, userNewsResourceRepository = userNewsResourceRepository, timeZoneMonitor = timeZoneMonitor, @@ -118,7 +116,6 @@ class NiaAppStateTest { state = NiaAppState( navController = NavHostController(LocalContext.current), coroutineScope = backgroundScope, - networkMonitor = networkMonitor, errorMonitor = errorMonitor, userNewsResourceRepository = userNewsResourceRepository, timeZoneMonitor = timeZoneMonitor, @@ -129,7 +126,7 @@ class NiaAppStateTest { networkMonitor.setConnected(false) assertEquals( true, - state.isOffline.value, + state.isOfflineState.value, ) } @@ -139,7 +136,6 @@ class NiaAppStateTest { state = NiaAppState( navController = NavHostController(LocalContext.current), coroutineScope = backgroundScope, - networkMonitor = networkMonitor, errorMonitor = errorMonitor, userNewsResourceRepository = userNewsResourceRepository, timeZoneMonitor = timeZoneMonitor, @@ -160,14 +156,13 @@ class NiaAppStateTest { state = NiaAppState( navController = NavHostController(LocalContext.current), coroutineScope = backgroundScope, - networkMonitor = networkMonitor, errorMonitor = errorMonitor, userNewsResourceRepository = userNewsResourceRepository, timeZoneMonitor = timeZoneMonitor, ) } - val id = state.addErrorMessage("Test Error Message 1") + val id = state.addShortErrorMessage("Test Error Message 1") backgroundScope.launch { state.snackbarMessage.collect() } diff --git a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/MainActivity.kt b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/MainActivity.kt index 8316931e2..8041170ee 100644 --- a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/MainActivity.kt +++ b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/MainActivity.kt @@ -136,7 +136,6 @@ class MainActivity : ComponentActivity() { } val appState = rememberNiaAppState( - networkMonitor = networkMonitor, errorMonitor = errorMonitor, userNewsResourceRepository = userNewsResourceRepository, timeZoneMonitor = timeZoneMonitor, diff --git a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/navigation/NiaNavHost.kt b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/navigation/NiaNavHost.kt index 8c6393eb7..7eea53ab3 100644 --- a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/navigation/NiaNavHost.kt +++ b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/navigation/NiaNavHost.kt @@ -38,12 +38,11 @@ import com.google.samples.apps.nowinandroid.ui.interests2pane.interestsListDetai @Composable fun NiaNavHost( appState: NiaAppState, - onShowSnackbar: suspend (String, String?) -> Boolean, - errorHandler: (String) -> Unit, modifier: Modifier = Modifier, startDestination: String = FOR_YOU_ROUTE, ) { val navController = appState.navController + NavHost( navController = navController, startDestination = startDestination, @@ -52,13 +51,13 @@ fun NiaNavHost( forYouScreen(onTopicClick = navController::navigateToInterests) bookmarksScreen( onTopicClick = navController::navigateToInterests, - onShowSnackbar = onShowSnackbar, + onShowSnackbar = { message, label, actionSuccess, actionFailure -> appState.addLongErrorMessage(error = message, label = label, successAction = actionSuccess, failureAction = actionFailure) }, ) searchScreen( onBackClick = navController::popBackStack, onInterestsClick = { appState.navigateToTopLevelDestination(INTERESTS) }, onTopicClick = navController::navigateToInterests, - errorHandler = errorHandler, + errorHandler = { message -> appState.addShortErrorMessage(message) }, ) interestsListDetailScreen() } diff --git a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/NiaApp.kt b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/NiaApp.kt index e9a26c825..f696a64f8 100644 --- a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/NiaApp.kt +++ b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/NiaApp.kt @@ -30,6 +30,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarDuration import androidx.compose.material3.SnackbarDuration.Indefinite import androidx.compose.material3.SnackbarDuration.Short import androidx.compose.material3.SnackbarHost @@ -42,6 +43,7 @@ import androidx.compose.material3.adaptive.WindowAdaptiveInfo import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.SideEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -62,6 +64,8 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavDestination import androidx.navigation.NavDestination.Companion.hierarchy import com.google.samples.apps.nowinandroid.R +import com.google.samples.apps.nowinandroid.core.data.util.ErrorMessage +import com.google.samples.apps.nowinandroid.core.data.util.MessageDuration import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaBackground import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaGradientBackground import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaNavigationSuiteScaffold @@ -95,30 +99,24 @@ fun NiaApp( ) { val snackbarHostState = remember { SnackbarHostState() } - val isOffline by appState.isOffline.collectAsStateWithLifecycle() + val offlineMessage = stringResource(R.string.not_connected) + SideEffect { + appState.offlineMessage = offlineMessage + } + val snackbarMessage by appState.snackbarMessage.collectAsStateWithLifecycle() - // If user is not connected to the internet show a snack bar to inform them. - val notConnectedMessage = stringResource(R.string.not_connected) - LaunchedEffect(isOffline) { - if (isOffline) { - snackbarHostState.showSnackbar( - message = notConnectedMessage, - duration = Indefinite, - ) - } - } LaunchedEffect(snackbarMessage) { snackbarMessage?.let { val snackBarResult = snackbarHostState.showSnackbar( message = it.message, - actionLabel = "Continue", - duration = Indefinite, + actionLabel = it.label, + duration = snackbarDurationOf(it.duration), ) == ActionPerformed - if (snackBarResult) { - appState.clearErrorMessage(it.id) - } + handleSnackbarResult(snackBarResult, it) + // Remove Message from Queue + appState.clearErrorMessage(it.id) } } @@ -243,14 +241,6 @@ internal fun NiaApp( ) { NiaNavHost( appState = appState, - onShowSnackbar = { message, action -> - snackbarHostState.showSnackbar( - message = message, - actionLabel = action, - duration = Short, - ) == ActionPerformed - }, - errorHandler = { message -> appState.addErrorMessage(message) }, ) } @@ -284,3 +274,20 @@ private fun NavDestination?.isTopLevelDestinationInHierarchy(destination: TopLev this?.hierarchy?.any { it.route?.contains(destination.name, true) ?: false } ?: false + +private fun snackbarDurationOf(duration: MessageDuration?): SnackbarDuration { + return when (duration) { + MessageDuration.Short -> SnackbarDuration.Short + MessageDuration.Long -> SnackbarDuration.Long + MessageDuration.Indefinite -> SnackbarDuration.Indefinite + else -> SnackbarDuration.Short + } +} + +private fun handleSnackbarResult(snackBarResult: Boolean, message: ErrorMessage) { + if (snackBarResult) { + message.actionPerformed?.invoke() + } else { + message.actionNotPerformed?.invoke() + } +} diff --git a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppState.kt b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppState.kt index 1fb1427a4..ec6833acd 100644 --- a/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppState.kt +++ b/app/src/main/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppState.kt @@ -29,8 +29,8 @@ import androidx.navigation.compose.rememberNavController import androidx.navigation.navOptions import androidx.tracing.trace import com.google.samples.apps.nowinandroid.core.data.repository.UserNewsResourceRepository +import com.google.samples.apps.nowinandroid.core.data.util.ErrorMessage import com.google.samples.apps.nowinandroid.core.data.util.ErrorMonitor -import com.google.samples.apps.nowinandroid.core.data.util.NetworkMonitor import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneMonitor import com.google.samples.apps.nowinandroid.core.ui.TrackDisposableJank import com.google.samples.apps.nowinandroid.feature.bookmarks.navigation.BOOKMARKS_ROUTE @@ -48,13 +48,11 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.datetime.TimeZone @Composable fun rememberNiaAppState( - networkMonitor: NetworkMonitor, errorMonitor: ErrorMonitor, userNewsResourceRepository: UserNewsResourceRepository, timeZoneMonitor: TimeZoneMonitor, @@ -65,7 +63,6 @@ fun rememberNiaAppState( return remember( navController, coroutineScope, - networkMonitor, errorMonitor, userNewsResourceRepository, timeZoneMonitor, @@ -73,7 +70,6 @@ fun rememberNiaAppState( NiaAppState( navController = navController, coroutineScope = coroutineScope, - networkMonitor = networkMonitor, errorMonitor = errorMonitor, userNewsResourceRepository = userNewsResourceRepository, timeZoneMonitor = timeZoneMonitor, @@ -85,7 +81,6 @@ fun rememberNiaAppState( class NiaAppState( val navController: NavHostController, coroutineScope: CoroutineScope, - networkMonitor: NetworkMonitor, errorMonitor: ErrorMonitor, userNewsResourceRepository: UserNewsResourceRepository, timeZoneMonitor: TimeZoneMonitor, @@ -102,21 +97,17 @@ class NiaAppState( else -> null } - val isOffline = networkMonitor.isOnline - .map(Boolean::not) - .stateIn( - scope = coroutineScope, - started = SharingStarted.WhileSubscribed(5_000), - initialValue = false, - ) - - val snackbarMessage = errorMessages - .map { it.firstOrNull() } - .stateIn( - scope = coroutineScope, - started = SharingStarted.WhileSubscribed(5_000), - initialValue = null, - ) + val isOfflineState: StateFlow = isOffline.stateIn( + scope = coroutineScope, + started = SharingStarted.WhileSubscribed(5_000), + initialValue = false, + ) + + val snackbarMessage: StateFlow = errorMessage.stateIn( + scope = coroutineScope, + started = SharingStarted.WhileSubscribed(5_000), + initialValue = null, + ) /** * Map of top level destinations to be used in the TopBar, BottomBar and NavRail. The key is the diff --git a/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppScreenSizesScreenshotTests.kt b/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppScreenSizesScreenshotTests.kt index a118d2566..5168dbfb0 100644 --- a/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppScreenSizesScreenshotTests.kt +++ b/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppScreenSizesScreenshotTests.kt @@ -138,7 +138,6 @@ class NiaAppScreenSizesScreenshotTests { ) { NiaTheme { val fakeAppState = rememberNiaAppState( - networkMonitor = networkMonitor, errorMonitor = errorMonitor, userNewsResourceRepository = userNewsResourceRepository, timeZoneMonitor = timeZoneMonitor, diff --git a/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/SnackbarScreenshotTests.kt b/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/SnackbarScreenshotTests.kt index b5c2675d9..81fc869e6 100644 --- a/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/SnackbarScreenshotTests.kt +++ b/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/SnackbarScreenshotTests.kt @@ -218,7 +218,6 @@ class SnackbarScreenshotTests { BoxWithConstraints { NiaTheme { val appState = rememberNiaAppState( - networkMonitor = networkMonitor, errorMonitor = errorMonitor, userNewsResourceRepository = userNewsResourceRepository, timeZoneMonitor = timeZoneMonitor, diff --git a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/util/ErrorMonitor.kt b/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/util/ErrorMonitor.kt index 02e689507..d27f7114a 100644 --- a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/util/ErrorMonitor.kt +++ b/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/util/ErrorMonitor.kt @@ -22,7 +22,11 @@ import kotlinx.coroutines.flow.Flow * Interface for handling error messages. */ interface ErrorMonitor { - fun addErrorMessage(error: String): String? + fun addShortErrorMessage(error: String, label: String? = null, successAction: (() -> Unit)? = null, failureAction: (() -> Unit)? = null): String? + fun addLongErrorMessage(error: String, label: String? = null, successAction: (() -> Unit)? = null, failureAction: (() -> Unit)? = null): String? + fun addIndefiniteErrorMessage(error: String, label: String? = null, successAction: (() -> Unit)? = null, failureAction: (() -> Unit)? = null): String? fun clearErrorMessage(id: String) - val errorMessages: Flow> + val errorMessage: Flow + val isOffline: Flow + var offlineMessage: String? } diff --git a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/util/SnackbarErrorMonitor.kt b/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/util/SnackbarErrorMonitor.kt index 5ee0ebe37..f1fa4afbd 100644 --- a/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/util/SnackbarErrorMonitor.kt +++ b/core/data/src/main/kotlin/com/google/samples/apps/nowinandroid/core/data/util/SnackbarErrorMonitor.kt @@ -18,6 +18,8 @@ package com.google.samples.apps.nowinandroid.core.data.util import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.update import java.util.UUID import javax.inject.Inject @@ -26,12 +28,25 @@ import javax.inject.Inject * Interface implementation for handling general errors. */ -class SnackbarErrorMonitor @Inject constructor() : ErrorMonitor { +class SnackbarErrorMonitor @Inject constructor(val networkMonitor: NetworkMonitor) : ErrorMonitor { /** * List of [ErrorMessage] to be shown to the user, via Snackbar. */ - private val _errorMessages = MutableStateFlow>(emptyList()) - override val errorMessages: Flow> = _errorMessages + private val errorMessages = MutableStateFlow>(emptyList()) + + override val isOffline = networkMonitor.isOnline + .map(Boolean::not) + + override var offlineMessage: String? = null + + override val errorMessage: Flow = combine(errorMessages, isOffline) { messages, isOffline -> + // Offline Error Message takes precedence over other messages + if (isOffline) { + ErrorMessage(offlineMessage ?: "You are offline", duration = MessageDuration.Indefinite) + } else { + messages.firstOrNull() + } + } /** * Creates an [ErrorMessage] from String value and adds it to the list. @@ -41,20 +56,32 @@ class SnackbarErrorMonitor @Inject constructor() : ErrorMonitor { * Returns the ID of the new [ErrorMessage] if success * Returns null if [error] is Blank */ - override fun addErrorMessage(error: String): String? { + private fun addErrorMessage(error: String, label: String?, duration: MessageDuration?, actionPerformed: (() -> Unit)?, actionNotPerformed: (() -> Unit)?): String? { if (error.isNotBlank()) { - val newError = ErrorMessage(error) - _errorMessages.update { it + newError } + val newError = ErrorMessage(error, label = label, duration = duration, actionPerformed = actionPerformed, actionNotPerformed = actionNotPerformed) + errorMessages.update { it + newError } return newError.id } return null } + override fun addShortErrorMessage(error: String, label: String?, successAction: (() -> Unit)?, failureAction: (() -> Unit)?): String? { + return addErrorMessage(error, label, MessageDuration.Short, successAction, failureAction) + } + + override fun addLongErrorMessage(error: String, label: String?, successAction: (() -> Unit)?, failureAction: (() -> Unit)?): String? { + return addErrorMessage(error, label, MessageDuration.Long, successAction, failureAction) + } + + override fun addIndefiniteErrorMessage(error: String, label: String?, successAction: (() -> Unit)?, failureAction: (() -> Unit)?): String? { + return addErrorMessage(error, label, MessageDuration.Indefinite, successAction, failureAction) + } + /** * Removes the [ErrorMessage] with the specified [id] from the list. */ override fun clearErrorMessage(id: String) { - _errorMessages.update { it.filter { item -> item.id != id } } + errorMessages.update { it.filter { item -> item.id != id } } } } @@ -64,4 +91,14 @@ class SnackbarErrorMonitor @Inject constructor() : ErrorMonitor { data class ErrorMessage( val message: String, val id: String = UUID.randomUUID().toString(), + val label: String? = null, + val duration: MessageDuration? = MessageDuration.Short, + val actionPerformed: (() -> Unit)? = null, + val actionNotPerformed: (() -> Unit)? = null, ) + +enum class MessageDuration { + Short, + Long, + Indefinite, +} diff --git a/feature/bookmarks/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksScreenTest.kt b/feature/bookmarks/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksScreenTest.kt index 40f54e4a7..2247a3e25 100644 --- a/feature/bookmarks/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksScreenTest.kt +++ b/feature/bookmarks/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksScreenTest.kt @@ -55,7 +55,7 @@ class BookmarksScreenTest { composeTestRule.setContent { BookmarksScreen( feedState = NewsFeedUiState.Loading, - onShowSnackbar = { _, _ -> false }, + onShowSnackbar = { _, _, _, _ -> Unit }, removeFromBookmarks = {}, onTopicClick = {}, onNewsResourceViewed = {}, @@ -76,7 +76,7 @@ class BookmarksScreenTest { feedState = NewsFeedUiState.Success( userNewsResourcesTestData.take(2), ), - onShowSnackbar = { _, _ -> false }, + onShowSnackbar = { _, _, _, _ -> Unit }, removeFromBookmarks = {}, onTopicClick = {}, onNewsResourceViewed = {}, @@ -117,7 +117,7 @@ class BookmarksScreenTest { feedState = NewsFeedUiState.Success( userNewsResourcesTestData.take(2), ), - onShowSnackbar = { _, _ -> false }, + onShowSnackbar = { _, _, _, _ -> Unit }, removeFromBookmarks = { newsResourceId -> assertEquals(userNewsResourcesTestData[0].id, newsResourceId) removeFromBookmarksCalled = true @@ -152,7 +152,7 @@ class BookmarksScreenTest { composeTestRule.setContent { BookmarksScreen( feedState = NewsFeedUiState.Success(emptyList()), - onShowSnackbar = { _, _ -> false }, + onShowSnackbar = { _, _, _, _ -> Unit }, removeFromBookmarks = {}, onTopicClick = {}, onNewsResourceViewed = {}, @@ -181,7 +181,7 @@ class BookmarksScreenTest { CompositionLocalProvider(LocalLifecycleOwner provides testLifecycleOwner) { BookmarksScreen( feedState = NewsFeedUiState.Success(emptyList()), - onShowSnackbar = { _, _ -> false }, + onShowSnackbar = { _, _, _, _ -> Unit }, removeFromBookmarks = {}, onTopicClick = {}, onNewsResourceViewed = {}, diff --git a/feature/bookmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksScreen.kt b/feature/bookmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksScreen.kt index 7c229c5ea..664bb4f7c 100644 --- a/feature/bookmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksScreen.kt +++ b/feature/bookmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksScreen.kt @@ -78,7 +78,7 @@ import com.google.samples.apps.nowinandroid.core.ui.newsFeed @Composable internal fun BookmarksRoute( onTopicClick: (String) -> Unit, - onShowSnackbar: suspend (String, String?) -> Boolean, + onShowSnackbar: (String, String?, (() -> Unit)?, (() -> Unit)?) -> Unit, modifier: Modifier = Modifier, viewModel: BookmarksViewModel = hiltViewModel(), ) { @@ -103,7 +103,7 @@ internal fun BookmarksRoute( @Composable internal fun BookmarksScreen( feedState: NewsFeedUiState, - onShowSnackbar: suspend (String, String?) -> Boolean, + onShowSnackbar: (String, String?, (() -> Unit)?, (() -> Unit)?) -> Unit, removeFromBookmarks: (String) -> Unit, onNewsResourceViewed: (String) -> Unit, onTopicClick: (String) -> Unit, @@ -117,12 +117,7 @@ internal fun BookmarksScreen( LaunchedEffect(shouldDisplayUndoBookmark) { if (shouldDisplayUndoBookmark) { - val snackBarResult = onShowSnackbar(bookmarkRemovedMessage, undoText) - if (snackBarResult) { - undoBookmarkRemoval() - } else { - clearUndoState() - } + onShowSnackbar(bookmarkRemovedMessage, undoText, { undoBookmarkRemoval() }, { clearUndoState() }) } } diff --git a/feature/bookmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/navigation/BookmarksNavigation.kt b/feature/bookmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/navigation/BookmarksNavigation.kt index 13d0baef0..049eaff6f 100644 --- a/feature/bookmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/navigation/BookmarksNavigation.kt +++ b/feature/bookmarks/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/bookmarks/navigation/BookmarksNavigation.kt @@ -28,7 +28,7 @@ fun NavController.navigateToBookmarks(navOptions: NavOptions) = navigate(BOOKMAR fun NavGraphBuilder.bookmarksScreen( onTopicClick: (String) -> Unit, - onShowSnackbar: suspend (String, String?) -> Boolean, + onShowSnackbar: (String, String?, (() -> Unit)?, (() -> Unit)?) -> Unit, ) { composable(route = BOOKMARKS_ROUTE) { BookmarksRoute(onTopicClick, onShowSnackbar)