From d25152b8d1e8608aa9b6576948cfdd3b02891f99 Mon Sep 17 00:00:00 2001 From: TM Date: Mon, 17 Jun 2024 03:20:06 -0700 Subject: [PATCH] Update General Error Handling Implementation Include OFFLINE message in list of messages, with precedence over other messages. Pass offline value to state for use in other purposes. Include action handling for success/failure to click snackbar button. Implementation of Bookmark UNDO function. Moved implementations of onShowSnackbar and errorHandler closer to use case, removed unnecessary passed down parameters. --- .../apps/nowinandroid/ui/NiaAppStateTest.kt | 9 +-- .../samples/apps/nowinandroid/MainActivity.kt | 1 - .../nowinandroid/navigation/NiaNavHost.kt | 7 +-- .../samples/apps/nowinandroid/ui/NiaApp.kt | 55 +++++++++++-------- .../apps/nowinandroid/ui/NiaAppState.kt | 33 ++++------- .../ui/NiaAppScreenSizesScreenshotTests.kt | 1 - .../ui/SnackbarScreenshotTests.kt | 1 - .../core/data/util/ErrorMonitor.kt | 8 ++- .../core/data/util/SnackbarErrorMonitor.kt | 51 ++++++++++++++--- .../feature/bookmarks/BookmarksScreenTest.kt | 10 ++-- .../feature/bookmarks/BookmarksScreen.kt | 11 +--- .../navigation/BookmarksNavigation.kt | 2 +- 12 files changed, 107 insertions(+), 82 deletions(-) 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)