-
Notifications
You must be signed in to change notification settings - Fork 927
PM-28492: Replace Authenticator Toasts with Snackbars #6180
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,6 @@ | ||
| package com.bitwarden.authenticator.ui.authenticator.feature.itemlisting | ||
|
|
||
| import android.Manifest | ||
| import android.widget.Toast | ||
| import androidx.compose.foundation.Image | ||
| import androidx.compose.foundation.layout.Arrangement | ||
| import androidx.compose.foundation.layout.Column | ||
|
|
@@ -30,8 +29,6 @@ import androidx.compose.runtime.setValue | |
| import androidx.compose.ui.Alignment | ||
| import androidx.compose.ui.Modifier | ||
| import androidx.compose.ui.input.nestedscroll.nestedScroll | ||
| import androidx.compose.ui.platform.LocalContext | ||
| import androidx.compose.ui.platform.LocalResources | ||
| import androidx.compose.ui.platform.testTag | ||
| import androidx.compose.ui.res.stringResource | ||
| import androidx.compose.ui.text.style.TextAlign | ||
|
|
@@ -96,8 +93,6 @@ fun ItemListingScreen( | |
| ) { | ||
| val state by viewModel.stateFlow.collectAsStateWithLifecycle() | ||
| val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState()) | ||
| val context = LocalContext.current | ||
| val resources = LocalResources.current | ||
| val launcher = permissionsManager.getLauncher { isGranted -> | ||
| if (isGranted) { | ||
| viewModel.trySendAction(ItemListingAction.ScanQrCodeClick) | ||
|
|
@@ -112,8 +107,8 @@ fun ItemListingScreen( | |
| is ItemListingEvent.NavigateToSearch -> onNavigateToSearch() | ||
| is ItemListingEvent.NavigateToQrCodeScanner -> onNavigateToQrCodeScanner() | ||
| is ItemListingEvent.NavigateToManualAddItem -> onNavigateToManualKeyEntry() | ||
| is ItemListingEvent.ShowToast -> { | ||
| Toast.makeText(context, event.message(resources), Toast.LENGTH_LONG).show() | ||
| is ItemListingEvent.ShowSnackbar -> { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π Good refactoring: Removed Toast imports and Android framework dependencies The removal of |
||
| snackbarHostState.showSnackbar(snackbarData = event.data) | ||
| } | ||
|
|
||
| is ItemListingEvent.NavigateToEditItem -> onNavigateToEditItemScreen(event.id) | ||
|
|
@@ -134,10 +129,6 @@ fun ItemListingScreen( | |
| ItemListingEvent.NavigateToBitwardenSettings -> { | ||
| intentManager.startBitwardenAccountSettings() | ||
| } | ||
|
|
||
| is ItemListingEvent.ShowSnackbar -> { | ||
| snackbarHostState.showSnackbar(snackbarData = event.data) | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -429,7 +420,7 @@ private fun ItemListingContent( | |
|
|
||
| when (state.sharedItems) { | ||
| is SharedCodesDisplayState.Codes -> { | ||
| state.sharedItems.sections.forEachIndexed { index, section -> | ||
| state.sharedItems.sections.forEachIndexed { _, section -> | ||
| item(key = "sharedSection_${section.id}") { | ||
| AuthenticatorExpandingHeader( | ||
| label = section.label(), | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,10 +23,13 @@ import com.bitwarden.authenticator.ui.authenticator.feature.util.toSharedCodesDi | |
| import com.bitwarden.authenticator.ui.platform.components.listitem.model.SharedCodesDisplayState | ||
| import com.bitwarden.authenticator.ui.platform.components.listitem.model.VaultDropdownMenuAction | ||
| import com.bitwarden.authenticator.ui.platform.components.listitem.model.VerificationCodeDisplayItem | ||
| import com.bitwarden.authenticator.ui.platform.model.SnackbarRelay | ||
| import com.bitwarden.authenticatorbridge.manager.AuthenticatorBridgeManager | ||
| import com.bitwarden.core.data.repository.model.DataState | ||
| import com.bitwarden.ui.platform.base.BackgroundEvent | ||
| import com.bitwarden.ui.platform.base.BaseViewModel | ||
| import com.bitwarden.ui.platform.components.snackbar.model.BitwardenSnackbarData | ||
| import com.bitwarden.ui.platform.manager.snackbar.SnackbarRelayManager | ||
| import com.bitwarden.ui.platform.resource.BitwardenString | ||
| import com.bitwarden.ui.util.Text | ||
| import com.bitwarden.ui.util.asText | ||
|
|
@@ -56,6 +59,7 @@ class ItemListingViewModel @Inject constructor( | |
| private val clipboardManager: BitwardenClipboardManager, | ||
| private val encodingManager: BitwardenEncodingManager, | ||
| private val settingsRepository: SettingsRepository, | ||
| snackbarRelayManager: SnackbarRelayManager<SnackbarRelay>, | ||
| ) : BaseViewModel<ItemListingState, ItemListingEvent, ItemListingAction>( | ||
| initialState = ItemListingState( | ||
| alertThresholdSeconds = settingsRepository.authenticatorAlertThresholdSeconds, | ||
|
|
@@ -90,6 +94,12 @@ class ItemListingViewModel @Inject constructor( | |
| .map { ItemListingAction.Internal.FirstTimeUserSyncReceive } | ||
| .onEach(::sendAction) | ||
| .launchIn(viewModelScope) | ||
|
|
||
| snackbarRelayManager | ||
| .getSnackbarDataFlow(SnackbarRelay.ITEM_SAVED, SnackbarRelay.ITEM_ADDED) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π Exemplary implementation: Correct usage of SnackbarRelayManager pattern This demonstrates proper usage of the relay pattern:
This pattern is consistent with the Password Manager app's implementation. |
||
| .map(ItemListingEvent::ShowSnackbar) | ||
| .onEach(::sendEvent) | ||
| .launchIn(viewModelScope) | ||
| } | ||
|
|
||
| override fun handleAction(action: ItemListingAction) { | ||
|
|
@@ -277,11 +287,7 @@ class ItemListingViewModel @Inject constructor( | |
| mutableStateFlow.update { | ||
| it.copy(dialog = null) | ||
| } | ||
| sendEvent( | ||
| ItemListingEvent.ShowToast( | ||
| message = BitwardenString.item_deleted.asText(), | ||
| ), | ||
| ) | ||
| sendEvent(ItemListingEvent.ShowSnackbar(BitwardenString.item_deleted.asText())) | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -305,7 +311,7 @@ class ItemListingViewModel @Inject constructor( | |
|
|
||
| CreateItemResult.Success -> { | ||
| sendEvent( | ||
| event = ItemListingEvent.ShowToast( | ||
| event = ItemListingEvent.ShowSnackbar( | ||
| message = BitwardenString.verification_code_added.asText(), | ||
| ), | ||
| ) | ||
|
|
@@ -847,19 +853,12 @@ sealed class ItemListingEvent { | |
| */ | ||
| data object NavigateToBitwardenSettings : ItemListingEvent() | ||
|
|
||
| /** | ||
| * Show a Toast with [message]. | ||
| */ | ||
| data class ShowToast( | ||
| val message: Text, | ||
| ) : ItemListingEvent() | ||
|
|
||
| /** | ||
| * Show a Snackbar with the given [data]. | ||
| */ | ||
| data class ShowSnackbar( | ||
| val data: BitwardenSnackbarData, | ||
| ) : ItemListingEvent() { | ||
| ) : ItemListingEvent(), BackgroundEvent { | ||
| constructor( | ||
| message: Text, | ||
| messageHeader: Text? = null, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π Correct pattern: Using sendSnackbarData before navigation
The pattern of sending snackbar data via relay manager before emitting NavigateBack event (lines 240-244) is correct. This ensures the destination screen can receive and display the snackbar upon arrival.