Skip to content

Conversation

@david-livefront
Copy link
Collaborator

@david-livefront david-livefront commented Nov 19, 2025

🎟️ Tracking

PM-28492

πŸ“” Objective

This PR replaces all the toasts in the Authenticator app with Snackbars.

πŸ“Έ Screenshots

Screen_recording_20251119_145313.mp4

@claude
Copy link
Contributor

claude bot commented Nov 19, 2025

Claude finished @david-livefront's task β€”β€” View job


Final Review Assessment

Overall Assessment: APPROVE

This PR successfully migrates the Authenticator app from Android Toast to Compose Snackbar pattern, following the established relay pattern from the Password Manager app. The implementation is clean and well-tested.

Remaining Recommendations:

  • Finding 2 (πŸ’­): SettingsViewModel subscribes to IMPORT_SUCCESS relay - verify this is intentional behavior for showing import success when returning to Settings
  • Finding 4 (πŸ“): Add KDoc to SnackbarRelay enum documenting each relay's purpose and producer/consumer screens (SnackbarRelay.kt:11)
  • Finding 5 (πŸ“): Add KDoc to provideSnackbarRelayManager function (PlatformUiManagerModule.kt:23)

Note: Finding 3 was withdrawn after author clarification - ItemSearchScreen correctly only subscribes to ITEM_SAVED since it doesn't navigate to add screens.


.onEach(::sendAction)
.launchIn(viewModelScope)
snackbarRelayManager
.getSnackbarDataFlow(SnackbarRelay.IMPORT_SUCCESS)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ’­ Finding 2: SettingsViewModel subscribes to IMPORT_SUCCESS but doesn't navigate to ImportingScreen

Details

The SettingsViewModel subscribes to SnackbarRelay.IMPORT_SUCCESS to show snackbars (lines 94-98), but the Settings screen doesn't navigate to the Importing screen where imports happen.

The ImportingViewModel sends this relay event when an import succeeds (ImportingViewModel.kt:116), then immediately navigates back. The Settings screen would show this snackbar, but only if the user happens to be on the Settings screen when returning from Import.

This pattern works but seems unusual. Consider whether:

  1. This is intentional (showing import success when returning to Settings)
  2. The snackbar should only be shown on the screen where import was initiated (ItemListing)
  3. Documentation explaining this relay pattern would be helpful

For reference, the Password Manager app has similar patterns in VaultAddEditScreen subscribing to attachment upload relays.


init {
snackbarRelayManager
.getSnackbarDataFlow(relay = SnackbarRelay.ITEM_SAVED)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ’­ Finding 3: Missing snackbar relay subscription for ITEM_ADDED

Details

The ItemSearchViewModel subscribes to SnackbarRelay.ITEM_SAVED but not to SnackbarRelay.ITEM_ADDED. Since items can be added from other screens (ManualCodeEntry, QR scan), the search screen should also display those snackbars when they navigate back.

Compare with ItemListingViewModel.kt:98-102 which subscribes to both:

snackbarRelayManager
    .getSnackbarDataFlow(SnackbarRelay.ITEM_SAVED, SnackbarRelay.ITEM_ADDED)
    .map(ItemListingEvent::ShowSnackbar)
    .onEach(::sendEvent)
    .launchIn(viewModelScope)

Consider whether search should also subscribe to ITEM_ADDED, or if this is intentional behavior.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@claude You cannot add an item from the ItemSearchScreen, so there is no benefit to subscribing to that data.

Copy link
Contributor

@claude claude bot Nov 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude finished @david-livefront's task β€”β€” View job


Response to Clarification

Thank you for the clarification! You're absolutely right - since the ItemSearchScreen doesn't have functionality to navigate to screens where items can be added (like ManualCodeEntryScreen or QR scan), there's no scenario where a user would return to the search screen after adding an item. Therefore, subscribing to SnackbarRelay.ITEM_ADDED would indeed provide no benefit.

The current implementation is correct:

  • ItemSearchViewModel only subscribes to ITEM_SAVED because users can navigate from search β†’ edit item β†’ save β†’ return to search
  • ItemListingViewModel subscribes to both ITEM_SAVED and ITEM_ADDED because users can navigate from listing β†’ add/edit screens β†’ return to listing

Finding 3 is withdrawn - the implementation is correct as-is.


* between producers and consumers of the data.
*/
@Serializable
enum class SnackbarRelay {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ“ Finding 4: Consider adding KDoc to SnackbarRelay enum

Details

Per docs/STYLE_AND_BEST_PRACTICES.md:272-273, all public classes should include KDoc documentation. The SnackbarRelay enum is public and would benefit from documentation explaining:

  1. The purpose of each relay constant
  2. Which screens produce/consume each relay
  3. Example usage pattern

Suggested documentation:

/**
 * Models a relay key to be mapped to an instance of [BitwardenSnackbarData] being sent
 * between producers and consumers of the data.
 */
@Serializable
enum class SnackbarRelay {
    /**
     * Relays success message when import completes.
     * Producer: ImportingViewModel
     * Consumer: SettingsViewModel
     */
    IMPORT_SUCCESS,
    
    /**
     * Relays success message when a new item is added.
     * Producer: ManualCodeEntryViewModel, ItemListingViewModel (QR scan)
     * Consumer: ItemListingViewModel
     */
    ITEM_ADDED,
    
    /**
     * Relays success message when an existing item is saved.
     * Producer: EditItemViewModel
     * Consumer: ItemListingViewModel, ItemSearchViewModel
     */
    ITEM_SAVED,
}

@Singleton
fun provideSnackbarRelayManager(
dispatcherManager: DispatcherManager,
): SnackbarRelayManager<SnackbarRelay> = SnackbarRelayManagerImpl(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ“ Finding 5: Missing KDoc for provideSnackbarRelayManager function

Details

Per docs/STYLE_AND_BEST_PRACTICES.md:347-380, public functions should include KDoc documentation. This provider function should document its purpose and parameters.

Suggested documentation:

/**
 * Provides a singleton [SnackbarRelayManager] for the Authenticator app to relay
 * snackbar messages between ViewModels and screens.
 */
@Provides
@Singleton
fun provideSnackbarRelayManager(
    dispatcherManager: DispatcherManager,
): SnackbarRelayManager<SnackbarRelay> = SnackbarRelayManagerImpl(
    dispatcherManager = dispatcherManager,
)

.launchIn(viewModelScope)

snackbarRelayManager
.getSnackbarDataFlow(SnackbarRelay.ITEM_SAVED, SnackbarRelay.ITEM_ADDED)
Copy link
Contributor

Choose a reason for hiding this comment

The 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:

  1. Subscribes to multiple relay keys in a single flow
  2. Maps to event with BackgroundEvent marker
  3. Uses onEach(::sendEvent) for clean event emission
  4. Properly scoped with launchIn(viewModelScope)

This pattern is consistent with the Password Manager app's implementation.


CreateItemResult.Success -> {
sendEvent(EditItemEvent.ShowToast(BitwardenString.item_saved.asText()))
snackbarRelayManager.sendSnackbarData(
Copy link
Contributor

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.

is ItemListingEvent.NavigateToManualAddItem -> onNavigateToManualKeyEntry()
is ItemListingEvent.ShowToast -> {
Toast.makeText(context, event.message(resources), Toast.LENGTH_LONG).show()
is ItemListingEvent.ShowSnackbar -> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ‘ Good refactoring: Removed Toast imports and Android framework dependencies

The removal of android.widget.Toast, LocalContext, and related Android framework dependencies from the Screen composables aligns with best practices for keeping UI layer testable and framework-agnostic. Snackbars are now properly integrated with Compose's state management.

@github-actions
Copy link
Contributor

github-actions bot commented Nov 19, 2025

Logo
Checkmarx One – Scan Summary & Details – bcb8adbf-a458-465e-9d51-77a4d3ddf885

Great job! No new security vulnerabilities introduced in this pull request

@david-livefront david-livefront force-pushed the PM-28492-authenticator-snackbars branch from 1c1f757 to 8ed4c8a Compare November 19, 2025 21:20
@codecov
Copy link

codecov bot commented Nov 19, 2025

Codecov Report

❌ Patch coverage is 58.18182% with 23 lines in your changes missing coverage. Please review.
βœ… Project coverage is 85.26%. Comparing base (839e9e8) to head (8ed4c8a).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
.../ui/platform/feature/settings/SettingsViewModel.kt 43.75% 9 Missing ⚠️
...m/feature/settings/importing/ImportingViewModel.kt 0.00% 5 Missing ⚠️
...i/platform/feature/settings/export/ExportScreen.kt 0.00% 4 Missing ⚠️
...icator/feature/itemlisting/ItemListingViewModel.kt 71.42% 2 Missing ⚠️
...latform/feature/settings/export/ExportViewModel.kt 0.00% 2 Missing ⚠️
...tor/ui/platform/feature/settings/SettingsScreen.kt 66.66% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6180      +/-   ##
==========================================
+ Coverage   85.24%   85.26%   +0.01%     
==========================================
  Files         724      724              
  Lines       52901    52907       +6     
  Branches     7687     7681       -6     
==========================================
+ Hits        45094    45109      +15     
+ Misses       5126     5120       -6     
+ Partials     2681     2678       -3     

β˜” View full report in Codecov by Sentry.
πŸ“’ Have feedback on the report? Share it here.

πŸš€ New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@david-livefront
Copy link
Collaborator Author

Thanks @SaintPatrck

@david-livefront david-livefront added this pull request to the merge queue Nov 19, 2025
Merged via the queue into main with commit 7918abd Nov 19, 2025
15 checks passed
@david-livefront david-livefront deleted the PM-28492-authenticator-snackbars branch November 19, 2025 22:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants