Skip to content

Conversation

@aj-rosado
Copy link
Contributor

@aj-rosado aj-rosado commented Feb 6, 2026

🎟️ Tracking

https://bitwarden.atlassian.net/browse/PM-31614

📔 Objective

Initial PR to add the layout changes for the Email Verification option on Sends.
The changes are behind a feature flag and should not have any impact when it is turned off.

This does not add the changes to the server and misses validations that will be added on subsequent PRs.

📸 Screenshots

Screenshot_1770402169 Screenshot_1770402172 Screenshot_1770402191 Screenshot_1770402349

⏰ Reminders before review

  • Contributor guidelines followed
  • All formatters and local linters executed and passed
  • Written new unit and / or integration tests where applicable
  • Protected functional changes with optionality (feature flags)
  • Used internationalization (i18n) for all UI strings
  • CI builds passed
  • Communicated to DevOps any deployment requirements
  • Updated any necessary documentation (Confluence, contributing docs) or informed the documentation team

🦮 Reviewer guidelines

  • 👍 (:+1:) or similar for great changes
  • 📝 (:memo:) or ℹ️ (:information_source:) for notes or general info
  • ❓ (:question:) for questions
  • 🤔 (:thinking:) or 💭 (:thought_balloon:) for more open inquiry that's not quite a confirmed issue and could potentially benefit from discussion
  • 🎨 (:art:) for suggestions / improvements
  • ❌ (:x:) or ⚠️ (:warning:) for more significant problems or concerns needing attention
  • 🌱 (:seedling:) or ♻️ (:recycle:) for future improvements or indications of technical debt
  • ⛏ (:pick:) for minor or nitpick changes

@aj-rosado aj-rosado requested review from a team and david-livefront as code owners February 6, 2026 18:27
@github-actions github-actions bot added app:password-manager Bitwarden Password Manager app context app:authenticator Bitwarden Authenticator app context labels Feb 6, 2026
@aj-rosado aj-rosado added the ai-review Request a Claude code review label Feb 6, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Feb 6, 2026

Logo
Checkmarx One – Scan Summary & Detailsc849059b-d981-4868-9867-2b11d1c38f54

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

@codecov
Copy link

codecov bot commented Feb 6, 2026

Codecov Report

❌ Patch coverage is 93.19372% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 86.33%. Comparing base (e5875cd) to head (8917a9f).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
...tools/feature/send/addedit/AddEditSendViewModel.kt 86.00% 5 Missing and 2 partials ⚠️
...d/addedit/components/AddEditSendAuthTypeChooser.kt 95.23% 0 Missing and 3 partials ⚠️
...ls/feature/send/addedit/util/SendViewExtensions.kt 50.00% 2 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6488      +/-   ##
==========================================
+ Coverage   86.32%   86.33%   +0.01%     
==========================================
  Files         783      784       +1     
  Lines       56439    56598     +159     
  Branches     8162     8184      +22     
==========================================
+ Hits        48719    48865     +146     
- Misses       4880     4887       +7     
- Partials     2840     2846       +6     

☔ 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.

@claude
Copy link
Contributor

claude bot commented Feb 9, 2026

Claude finished @aj-rosado's task in 3m 2s —— View job


Code Review Summary

PR: PM-31614 feat: Added new UI for the Email verification on sends

Reviewed Commits: 8917a9f22 (latest) through b6b70024c (initial)


Status: Approved

All previous review comments have been addressed. The PR is ready for merge.


Summary of Changes

This PR adds a new authentication type chooser UI for Sends, allowing users to select between:

  • Anyone with the link (NONE)
  • Specific people with email verification (EMAIL)
  • Anyone with password (PASSWORD)

Key additions:

  • SendAuthType enum with Text-based display properties
  • AddEditSendAuthTypeChooser composable component
  • ViewModel actions and state management for auth type selection
  • Email list management (add/remove/edit)
  • Feature flag protection (SendEmailVerification)

Addressed Items (Latest Commits)

Reviewer Comment Status
Make supportingTextRes a Text type (david-livefront) Addressed in 8917a9f22
Pass selectedAuthType from ViewModel Addressed
Use ImmutableList for emails parameter Addressed
Use ImmutableList for authEmails in ViewModel state Addressed
Add ColumnScope. extension to SpecificPeopleEmailContent Addressed
Capitalize function name SpecificPeopleEmailContent Addressed
Simplify onClick = onAddNewEmailClick Addressed
Chain format for .takeIf { }.orNullIfBlank() Addressed
Format AuthTypeSelect on single line Addressed
Fix card style for NONE auth type (CardStyle.Full) Addressed

Code Quality Assessment

Category Assessment
Security No concerns - UI changes behind feature flag
Correctness Logic correctly handles auth type transitions
Architecture Follows MVVM + UDF pattern appropriately
Test Coverage Comprehensive tests for ViewModel, Screen, and Extensions

Non-blocking Note

The SendViewExtensionsTest.kt currently only covers the PASSWORD auth type case (via createMockSendView which has hasPassword = true). Consider adding tests for EMAIL and NONE cases in a follow-up to ensure all toViewState branches are covered.


Reviewed with Claude Code

Comment on lines 62 to 70
var selectedOption: SendAuthType by rememberSaveable {
mutableStateOf(
value = when {
hasPassword -> SendAuthType.PASSWORD
emails.isNotEmpty() -> SendAuthType.EMAIL
else -> SendAuthType.NONE
},
)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🎨 SUGGESTED: The selectedOption is managed locally with rememberSaveable and computed from hasPassword and emails props. This works correctly in most scenarios, but creates a potential state desync if the ViewModel's authType changes from an external action (e.g., if "Remove password" functionality were to reset the auth type).

Consider passing the current authType from the ViewModel as a parameter to ensure single source of truth:

fun AddEditSendAuthTypeChooser(
    selectedAuthType: SendAuthType, // Add this parameter
    onAuthTypeSelect: (SendAuthType) -> Unit,
    // ... other params
)

This is a minor suggestion - the current implementation works correctly for the current use cases since the auth type changes only occur through user interaction with this component.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I agree with Claude here, Maybe we can just pass in the SendAuthType

@andrebispo5
Copy link
Contributor

Feature label is missing.

@andrebispo5
Copy link
Contributor

⛏️ Typo in the PR description

The chagnes are behind a feature flag and should not have any impact when it is turned off.

@aj-rosado aj-rosado added the t:feature Change Type - Feature Development label Feb 10, 2026
@github-actions github-actions bot removed the t:feature Change Type - Feature Development label Feb 10, 2026
authType = SendAuthType.PASSWORD,
),
selectedType = DEFAULT_TEXT_TYPE,
),
Copy link
Contributor

Choose a reason for hiding this comment

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

🎨 SUGGESTED: Missing test coverage for authType branches

The toViewState extension function has conditional logic for determining authType based on hasPassword and emails.isNotEmpty() (lines 39-43 in SendViewExtensions.kt):

authType = when {
    hasPassword -> SendAuthType.PASSWORD
    emails.isNotEmpty() -> SendAuthType.EMAIL
    else -> SendAuthType.NONE
}

The current tests only cover the PASSWORD case (via createMockSendView which has hasPassword = true). Consider adding tests for:

  1. EMAIL case: A SendView with hasPassword = false and non-empty emails list
  2. NONE case: A SendView with hasPassword = false and empty emails list

This would ensure all branches are covered and the authType mapping logic is correctly tested.

onAddNewEmailClick: () -> Unit,
onRemoveEmailClick: (Int) -> Unit,
password: String,
emails: List<String>,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we make this an immutable list


@Composable
private fun specificPeopleEmailContent(
emails: List<String>,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Immutable list here too

.passwordInput
.takeIf {
common.authType == SendAuthType.PASSWORD
}.orNullIfBlank(),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you use chain format here:

   .passwordInput
   .takeIf { common.authType == SendAuthType.PASSWORD }
   .orNullIfBlank(),

}

@Composable
private fun specificPeopleEmailContent(
Copy link
Collaborator

Choose a reason for hiding this comment

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

This should start with a capital S

Can we also add the ColumnScope. extension. I know the IDE will say it's not needed but this composable does not make sense outside of a ColumnScope and we should enforce that it is always applied there.

label = stringResource(id = BitwardenString.add_email),
onClick = {
onAddNewEmailClick()
},
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we simplify this:

onClick = onAddNewEmailClick,

@david-livefront
Copy link
Collaborator

One of your screenshots show that part of the card has the incorrect style

val expirationDate: ZonedDateTime?,
val sendUrl: String?,
val hasPassword: Boolean,
val authEmails: List<String>,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we make this an ImmutableList

* The user selected an authentication type.
*/
data class AuthTypeSelect(val authType: SendAuthType) :
AddEditSendAction()
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we format this a bit nicer:

    data class AuthTypeSelect(val authType: SendAuthType) : AddEditSendAction()

@aj-rosado aj-rosado changed the title [PM-31614] Added new UI for the Email verification on sends [PM-31614] feat: Added new UI for the Email verification on sends Feb 11, 2026
*/
enum class SendAuthType(
val text: Text,
val supportingTextRes: Int?,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we make this a Text as well?

@github-actions github-actions bot added the t:feature Change Type - Feature Development label Feb 11, 2026
// Initialize with one empty email field if list is empty
commonContent.copy(
authEmails = commonContent.authEmails.ifEmpty { listOf("") }
.toImmutableList(),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can this be simplified:

authEmails = commonContent.authEmails.ifEmpty { persistentListOf("") },

onPasswordChange: (String) -> Unit,
onEmailValueChange: (String, Int) -> Unit,
onAddNewEmailClick: () -> Unit,
onRemoveEmailClick: (Int) -> Unit,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Instead of the index, can we [ass back the actual email to remove?

val onPasswordCopyClick: (String) -> Unit,
val onAuthTypeSelect: (SendAuthType) -> Unit,
val onAuthPasswordChange: (String) -> Unit,
val onEmailValueChange: (String, Int) -> Unit,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Using the index is unsafe and can lead to errors.

Can we wrap the emails in a data class and create ids to track them. That will make this all much safer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-review Request a Claude code review app:authenticator Bitwarden Authenticator app context app:password-manager Bitwarden Password Manager app context t:feature Change Type - Feature Development

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants