[iOS] Add Passkey Creation Bottom Sheet class structure [chromium/src : main]

0 views
Skip to first unread message

Alexis Hétu (Gerrit)

unread,
Jan 14, 2026, 3:53:52 PM (4 days ago) Jan 14
to Noémie St-Onge, Tommy Martino, chromium...@chromium.org, feature-me...@chromium.org, gcasto+w...@chromium.org, ios-revie...@chromium.org, ios-r...@chromium.org, marq+...@chromium.org, tmartino+tran...@chromium.org, vasilii+watchlis...@chromium.org
Attention needed from Noémie St-Onge and Tommy Martino

Alexis Hétu voted Commit-Queue+1

Commit-Queue+1
Open in Gerrit

Related details

Attention is currently required from:
  • Noémie St-Onge
  • Tommy Martino
Submit Requirements:
  • requirement satisfiedCode-Coverage
  • requirement satisfiedCode-Owners
  • requirement is not satisfiedCode-Review
  • requirement is not satisfiedReview-Enforcement
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: chromium/src
Gerrit-Branch: main
Gerrit-Change-Id: Ibc9360f1b11d40a48800a45434ee4ddf1c0f1fe3
Gerrit-Change-Number: 7472659
Gerrit-PatchSet: 2
Gerrit-Owner: Alexis Hétu <su...@chromium.org>
Gerrit-Reviewer: Alexis Hétu <su...@chromium.org>
Gerrit-Reviewer: Noémie St-Onge <noe...@google.com>
Gerrit-Reviewer: Tommy Martino <tmar...@chromium.org>
Gerrit-Attention: Noémie St-Onge <noe...@google.com>
Gerrit-Attention: Tommy Martino <tmar...@chromium.org>
Gerrit-Comment-Date: Wed, 14 Jan 2026 20:53:45 +0000
Gerrit-HasComments: No
Gerrit-Has-Labels: Yes
satisfied_requirement
unsatisfied_requirement
open
diffy

Noémie St-Onge (Gerrit)

unread,
Jan 15, 2026, 10:03:17 AM (3 days ago) Jan 15
to Alexis Hétu, Chromium LUCI CQ, Tommy Martino, chromium...@chromium.org, feature-me...@chromium.org, gcasto+w...@chromium.org, ios-revie...@chromium.org, ios-r...@chromium.org, marq+...@chromium.org, tmartino+tran...@chromium.org, vasilii+watchlis...@chromium.org
Attention needed from Alexis Hétu and Tommy Martino

Noémie St-Onge added 26 comments

Patchset-level comments
File-level comment, Patchset 2 (Latest):
Noémie St-Onge . unresolved

I think we should take advantage of the fact that we're adding brand new files to follow the new folder structure guidance https://g3doc.corp.google.com/company/teams/chrome/ios/docs/engineering/internal_workflow/folder_structure.md#ioschromebrowser-structure

File ios/chrome/browser/passwords/ui_bundled/bottom_sheet/passkey_creation_bottom_sheet_coordinator.h
Line 21, Patchset 2 (Latest):// `requestId` comes from the PasskeyTabHelper and identifies the passkey
File ios/chrome/browser/passwords/ui_bundled/bottom_sheet/passkey_creation_bottom_sheet_coordinator.mm
Line 23, Patchset 2 (Latest):@property(nonatomic, strong)
PasskeyCreationBottomSheetViewController* viewController;
@property(nonatomic, strong) PasskeyCreationBottomSheetMediator* mediator;
Noémie St-Onge . unresolved

we should prefer using ivars when possible + these should come with a comment

Line 33, Patchset 2 (Latest): requestId:(const std::string&)requestId {
Noémie St-Onge . unresolved

`requestID`

Line 36, Patchset 2 (Latest): ProfileIOS* profile = browser->GetProfile()->GetOriginalProfile();
Noémie St-Onge . unresolved

Why do we need the original profile here? We should explain it with a comment

Line 36, Patchset 2 (Latest): ProfileIOS* profile = browser->GetProfile()->GetOriginalProfile();
Noémie St-Onge . unresolved

nit: we can use `self.profile` directly

Line 43, Patchset 2 (Latest): self.mediator = [[PasskeyCreationBottomSheetMediator alloc]
initWithWebStateList:webStateList
requestId:requestId
accountForSaving:accountForSaving
presenter:self];

const GURL& URL = webStateList->GetActiveWebState()->GetLastCommittedURL();
self.viewController =
[[PasskeyCreationBottomSheetViewController alloc] initWithHandler:self
URL:URL];
self.viewController.actionHandler = self;
self.viewController.delegate = self.mediator;
Noémie St-Onge . unresolved

The mediator and vc (along with their dependencies) are typically initialized in the `-start` method rather than in the `-init` method. From what I understand from the [Coordinator fascicle](https://docs.google.com/document/d/1nyPbvbciPWXlj-oTC6CP0Z-jkERggd_9ZZjKQrLoBBU/edit?tab=t.0#heading=h.cgua8kfbjxyn), `-init` should be used for dependency injection, whereas `-start` should be used to activate the feature. I don't think we should be creating the mediator and VC in advance

File ios/chrome/browser/passwords/ui_bundled/bottom_sheet/passkey_creation_bottom_sheet_handler.h
Line 16, Patchset 2 (Latest):- (void)viewDidDisappear;
Noémie St-Onge . unresolved

I would name this differently so that it doesn't get confused with Apple's `viewDidDisappear` function. We could also be more precise about the view that is implied, could be something like `passkeyCreationBottomSheetViewDidDisappear`

File ios/chrome/browser/passwords/ui_bundled/bottom_sheet/passkey_creation_bottom_sheet_mediator.h
Line 35, Patchset 2 (Latest):- (void)deferToRenderer;
Noémie St-Onge . unresolved

Suggestion as I feel like `deferToRenderer` could be harder to understand outside of the core passkey land ```suggestion

  • (void)deferPasskeyCreationToRenderer;
  • ```
Line 23, Patchset 2 (Latest): requestId:(const std::string&)requestId
Noémie St-Onge . unresolved

`requestID`, same with argument name

File ios/chrome/browser/passwords/ui_bundled/bottom_sheet/passkey_creation_bottom_sheet_mediator.mm
Line 23, Patchset 2 (Latest):// Email associated with account the passkey will get saved in.ß
Noémie St-Onge . unresolved

```suggestion
// Email associated with the account the passkey will get saved in.ß
```

Line 23, Patchset 2 (Latest):// Email associated with account the passkey will get saved in.ß
Noémie St-Onge . unresolved

😅

Line 24, Patchset 2 (Latest):@property(nonatomic, strong, readonly) NSString* accountForSaving;
Noémie St-Onge . unresolved

Should be an ivar if possible

Line 45, Patchset 2 (Latest): std::string _requestId;
Noémie St-Onge . unresolved

`_requestID`

Line 49, Patchset 2 (Latest): requestId:(const std::string&)requestId
Noémie St-Onge . unresolved

`requestID`

Line 82, Patchset 2 (Latest): if (_requestId.empty()) {
Noémie St-Onge . unresolved

Are we going to silently fail here? Should we CHECK instead? (Same question for `passkeyTabHelper`)

Line 137, Patchset 2 (Latest): DCHECK_EQ(_webStateList, webStateList);
Noémie St-Onge . unresolved

Should this be `CHECK_EQ` to follow the new guidance?

Line 144, Patchset 2 (Latest): DCHECK_EQ(webStateList, _webStateList);
Noémie St-Onge . unresolved

Same, should this be `CHECK_EQ` to follow the new guidance?

Line 160, Patchset 2 (Latest):- (void)onWebStateChange {
Noémie St-Onge . unresolved

Missing a comment + suggestion ```suggestion

  • (void)onWebStateChanged {
  • ```
Line 172, Patchset 2 (Latest):- (webauthn::PasskeyTabHelper*)tabHelper {
Noémie St-Onge . unresolved

Suggestion for clarity as we have multiple tab helpers ```suggestion

  • (webauthn::PasskeyTabHelper*)passkeyTabHelper {
  • ```
File ios/chrome/browser/passwords/ui_bundled/bottom_sheet/passkey_creation_bottom_sheet_view_controller.h
Line 18, Patchset 2 (Latest):// Initialize with the handler for user actions and the URL of the current page.
Noémie St-Onge . unresolved

```suggestion
// Initializes the view controller with the `handler` for user actions and the `URL` of the current page.
```

File ios/chrome/browser/passwords/ui_bundled/bottom_sheet/passkey_creation_bottom_sheet_view_controller.mm
Line 24, Patchset 2 (Latest):@property(nonatomic, weak) id<PasskeyCreationBottomSheetHandler> handler;
Noémie St-Onge . unresolved

Switch to ivar if possible

Line 49, Patchset 2 (Latest): // Set the properties read by the super when constructing the
Noémie St-Onge . unresolved

`base class`?

Line 57, Patchset 2 (Latest): self.titleString =
l10n_util::GetNSString(IDS_IOS_PASSKEY_CREATION_BOTTOM_SHEET_TITLE);
self.titleTextStyle = UIFontTextStyleTitle2;

NSString* host = base::SysUTF8ToNSString(_URL.host());
NSString* username = [self.delegate username];
self.secondaryTitleString =
[NSString stringWithFormat:@"%@\n%@", username ?: @"", host];

NSString* subtitle =
l10n_util::GetNSString(IDS_IOS_PASSKEY_CREATION_BOTTOM_SHEET_SUBTITLE);
NSString* accountInfo =
l10n_util::GetNSString(IDS_IOS_PASSKEY_CREATION_BOTTOM_SHEET_ACCOUNT);
NSString* email = [self.delegate email];
self.subtitleString =
[NSString stringWithFormat:@"%@\n%@\n%@", subtitle, accountInfo, email];
self.subtitleTextStyle = UIFontTextStyleFootnote;
Noémie St-Onge . unresolved

optional: we could create helper functions for these setups to lighten the `viewDidLoad` method, which tends to get quite long. Not a strong opinion though since it is not that big right now

Line 78, Patchset 2 (Latest):- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[self.handler viewDidDisappear];
}
Noémie St-Onge . unresolved

Forwarding a comment made by Gauthier on Angela's Test Project CL https://chromium-review.googlesource.com/c/chromium/src/+/7107319/comment/fbf500d5_04f46e06/

Line 85, Patchset 2 (Latest):// Configures the title view of this ViewController.
- (UIView*)setUpTitleView {
NSString* title =
l10n_util::GetNSString(IDS_IOS_CREDENTIAL_BOTTOM_SHEET_TITLE);
UIView* titleView = password_manager::CreatePasswordManagerTitleView(title);
return titleView;
}
Noémie St-Onge . unresolved

I think this could be moved to the anonymous namespace since we're not accessing any members of `self`

Open in Gerrit

Related details

Attention is currently required from:
  • Alexis Hétu
  • Tommy Martino
Submit Requirements:
    • requirement satisfiedCode-Coverage
    • requirement satisfiedCode-Owners
    • requirement is not satisfiedCode-Review
    • requirement is not satisfiedNo-Unresolved-Comments
    • requirement is not satisfiedReview-Enforcement
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: Ibc9360f1b11d40a48800a45434ee4ddf1c0f1fe3
    Gerrit-Change-Number: 7472659
    Gerrit-PatchSet: 2
    Gerrit-Owner: Alexis Hétu <su...@chromium.org>
    Gerrit-Reviewer: Alexis Hétu <su...@chromium.org>
    Gerrit-Reviewer: Noémie St-Onge <noe...@google.com>
    Gerrit-Reviewer: Tommy Martino <tmar...@chromium.org>
    Gerrit-Attention: Alexis Hétu <su...@chromium.org>
    Gerrit-Attention: Tommy Martino <tmar...@chromium.org>
    Gerrit-Comment-Date: Thu, 15 Jan 2026 15:03:04 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    satisfied_requirement
    unsatisfied_requirement
    open
    diffy

    Alexis Hétu (Gerrit)

    unread,
    Jan 15, 2026, 10:55:59 AM (3 days ago) Jan 15
    to Chromium LUCI CQ, Noémie St-Onge, Tommy Martino, chromium...@chromium.org, feature-me...@chromium.org, gcasto+w...@chromium.org, ios-revie...@chromium.org, ios-r...@chromium.org, marq+...@chromium.org, tmartino+tran...@chromium.org, vasilii+watchlis...@chromium.org
    Attention needed from Noémie St-Onge and Tommy Martino

    Alexis Hétu added 4 comments

    Patchset-level comments
    Noémie St-Onge . unresolved

    I think we should take advantage of the fact that we're adding brand new files to follow the new folder structure guidance https://g3doc.corp.google.com/company/teams/chrome/ios/docs/engineering/internal_workflow/folder_structure.md#ioschromebrowser-structure

    Alexis Hétu

    Already working on this 😊

    File ios/chrome/browser/passwords/ui_bundled/bottom_sheet/passkey_creation_bottom_sheet_coordinator.mm
    Line 36, Patchset 2 (Latest): ProfileIOS* profile = browser->GetProfile()->GetOriginalProfile();
    Noémie St-Onge . unresolved

    Why do we need the original profile here? We should explain it with a comment

    Alexis Hétu

    My understanding is that if we don't, it won't work in incognito.

    File ios/chrome/browser/passwords/ui_bundled/bottom_sheet/passkey_creation_bottom_sheet_mediator.mm
    Line 82, Patchset 2 (Latest): if (_requestId.empty()) {
    Noémie St-Onge . unresolved

    Are we going to silently fail here? Should we CHECK instead? (Same question for `passkeyTabHelper`)

    Alexis Hétu

    I could add a check in the init method and remove this if statement, PasskeyTabHelper should have already validated that request ID was valid.

    File ios/chrome/browser/passwords/ui_bundled/bottom_sheet/passkey_creation_bottom_sheet_view_controller.mm
    Line 78, Patchset 2 (Latest):- (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];
    [self.handler viewDidDisappear];
    }
    Noémie St-Onge . unresolved

    Forwarding a comment made by Gauthier on Angela's Test Project CL https://chromium-review.googlesource.com/c/chromium/src/+/7107319/comment/fbf500d5_04f46e06/

    Alexis Hétu

    I *think* this is ok since the view is modal, but I'll change it anyway. We'll probably want to update the other bottom sheets as well, once we've validated that the new way of doing this works for this bottom sheet.

    Open in Gerrit

    Related details

    Attention is currently required from:
    • Noémie St-Onge
    • Tommy Martino
    Submit Requirements:
    • requirement satisfiedCode-Coverage
    • requirement satisfiedCode-Owners
    • requirement is not satisfiedCode-Review
    • requirement is not satisfiedNo-Unresolved-Comments
    • requirement is not satisfiedReview-Enforcement
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: Ibc9360f1b11d40a48800a45434ee4ddf1c0f1fe3
    Gerrit-Change-Number: 7472659
    Gerrit-PatchSet: 2
    Gerrit-Owner: Alexis Hétu <su...@chromium.org>
    Gerrit-Reviewer: Alexis Hétu <su...@chromium.org>
    Gerrit-Reviewer: Noémie St-Onge <noe...@google.com>
    Gerrit-Reviewer: Tommy Martino <tmar...@chromium.org>
    Gerrit-Attention: Noémie St-Onge <noe...@google.com>
    Gerrit-Attention: Tommy Martino <tmar...@chromium.org>
    Gerrit-Comment-Date: Thu, 15 Jan 2026 15:55:54 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    Comment-In-Reply-To: Noémie St-Onge <noe...@google.com>
    satisfied_requirement
    unsatisfied_requirement
    open
    diffy

    Alexis Hétu (Gerrit)

    unread,
    Jan 15, 2026, 2:38:21 PM (3 days ago) Jan 15
    to Chromium LUCI CQ, Noémie St-Onge, Tommy Martino, chromium...@chromium.org, feature-me...@chromium.org, gcasto+w...@chromium.org, ios-revie...@chromium.org, ios-r...@chromium.org, marq+...@chromium.org, tmartino+tran...@chromium.org, vasilii+watchlis...@chromium.org
    Attention needed from Noémie St-Onge and Tommy Martino

    Alexis Hétu voted and added 26 comments

    Votes added by Alexis Hétu

    Commit-Queue+1

    26 comments

    Patchset-level comments
    File-level comment, Patchset 2:
    Noémie St-Onge . resolved

    I think we should take advantage of the fact that we're adding brand new files to follow the new folder structure guidance https://g3doc.corp.google.com/company/teams/chrome/ios/docs/engineering/internal_workflow/folder_structure.md#ioschromebrowser-structure

    Alexis Hétu

    Already working on this 😊

    Alexis Hétu

    Done

    File ios/chrome/browser/passwords/ui_bundled/bottom_sheet/passkey_creation_bottom_sheet_coordinator.h
    Line 21, Patchset 2:// `requestId` comes from the PasskeyTabHelper and identifies the passkey
    Noémie St-Onge . resolved
    Alexis Hétu

    Done

    File ios/chrome/browser/passwords/ui_bundled/bottom_sheet/passkey_creation_bottom_sheet_coordinator.mm
    Line 23, Patchset 2:@property(nonatomic, strong)

    PasskeyCreationBottomSheetViewController* viewController;
    @property(nonatomic, strong) PasskeyCreationBottomSheetMediator* mediator;
    Noémie St-Onge . resolved

    we should prefer using ivars when possible + these should come with a comment

    Alexis Hétu

    Done

    Line 33, Patchset 2: requestId:(const std::string&)requestId {
    Noémie St-Onge . resolved

    `requestID`

    Alexis Hétu

    Done

    Line 36, Patchset 2: ProfileIOS* profile = browser->GetProfile()->GetOriginalProfile();
    Noémie St-Onge . resolved

    nit: we can use `self.profile` directly

    Alexis Hétu

    Done

    Line 36, Patchset 2: ProfileIOS* profile = browser->GetProfile()->GetOriginalProfile();
    Noémie St-Onge . resolved

    Why do we need the original profile here? We should explain it with a comment

    Alexis Hétu

    My understanding is that if we don't, it won't work in incognito.

    Alexis Hétu

    Done

    Line 43, Patchset 2: self.mediator = [[PasskeyCreationBottomSheetMediator alloc]

    initWithWebStateList:webStateList
    requestId:requestId
    accountForSaving:accountForSaving
    presenter:self];

    const GURL& URL = webStateList->GetActiveWebState()->GetLastCommittedURL();
    self.viewController =
    [[PasskeyCreationBottomSheetViewController alloc] initWithHandler:self
    URL:URL];
    self.viewController.actionHandler = self;
    self.viewController.delegate = self.mediator;
    Noémie St-Onge . resolved

    The mediator and vc (along with their dependencies) are typically initialized in the `-start` method rather than in the `-init` method. From what I understand from the [Coordinator fascicle](https://docs.google.com/document/d/1nyPbvbciPWXlj-oTC6CP0Z-jkERggd_9ZZjKQrLoBBU/edit?tab=t.0#heading=h.cgua8kfbjxyn), `-init` should be used for dependency injection, whereas `-start` should be used to activate the feature. I don't think we should be creating the mediator and VC in advance

    Alexis Hétu

    Done

    File ios/chrome/browser/passwords/ui_bundled/bottom_sheet/passkey_creation_bottom_sheet_handler.h
    Line 16, Patchset 2:- (void)viewDidDisappear;
    Noémie St-Onge . resolved

    I would name this differently so that it doesn't get confused with Apple's `viewDidDisappear` function. We could also be more precise about the view that is implied, could be something like `passkeyCreationBottomSheetViewDidDisappear`

    Alexis Hétu

    Done

    File ios/chrome/browser/passwords/ui_bundled/bottom_sheet/passkey_creation_bottom_sheet_mediator.h
    Line 35, Patchset 2:- (void)deferToRenderer;
    Noémie St-Onge . resolved

    Suggestion as I feel like `deferToRenderer` could be harder to understand outside of the core passkey land ```suggestion

    • (void)deferPasskeyCreationToRenderer;
    • ```
    Alexis Hétu

    Done

    Line 23, Patchset 2: requestId:(const std::string&)requestId
    Noémie St-Onge . resolved

    `requestID`, same with argument name

    Alexis Hétu

    Done

    File ios/chrome/browser/passwords/ui_bundled/bottom_sheet/passkey_creation_bottom_sheet_mediator.mm
    Line 23, Patchset 2:// Email associated with account the passkey will get saved in.ß
    Noémie St-Onge . resolved

    😅

    Alexis Hétu

    Done

    Line 23, Patchset 2:// Email associated with account the passkey will get saved in.ß
    Noémie St-Onge . resolved

    ```suggestion
    // Email associated with the account the passkey will get saved in.ß
    ```

    Alexis Hétu

    Done

    Line 24, Patchset 2:@property(nonatomic, strong, readonly) NSString* accountForSaving;
    Noémie St-Onge . resolved

    Should be an ivar if possible

    Alexis Hétu

    Done

    Line 45, Patchset 2: std::string _requestId;
    Noémie St-Onge . resolved

    `_requestID`

    Alexis Hétu

    Done

    Line 49, Patchset 2: requestId:(const std::string&)requestId
    Noémie St-Onge . resolved

    `requestID`

    Alexis Hétu

    Done

    Line 82, Patchset 2: if (_requestId.empty()) {
    Noémie St-Onge . resolved

    Are we going to silently fail here? Should we CHECK instead? (Same question for `passkeyTabHelper`)

    Alexis Hétu

    I could add a check in the init method and remove this if statement, PasskeyTabHelper should have already validated that request ID was valid.

    Alexis Hétu

    For PasskeyTabHelper, if might be gone if we navigated to another page, so it might be nil, but we'd want to do nothing in that case, so I think that's ok to leave as is.

    Line 137, Patchset 2: DCHECK_EQ(_webStateList, webStateList);
    Noémie St-Onge . resolved

    Should this be `CHECK_EQ` to follow the new guidance?

    Alexis Hétu

    Done

    Line 144, Patchset 2: DCHECK_EQ(webStateList, _webStateList);
    Noémie St-Onge . resolved

    Same, should this be `CHECK_EQ` to follow the new guidance?

    Alexis Hétu

    Done

    Line 160, Patchset 2:- (void)onWebStateChange {
    Noémie St-Onge . resolved

    Missing a comment + suggestion ```suggestion

    • (void)onWebStateChanged {
    • ```
    Alexis Hétu

    Done

    Line 172, Patchset 2:- (webauthn::PasskeyTabHelper*)tabHelper {
    Noémie St-Onge . resolved

    Suggestion for clarity as we have multiple tab helpers ```suggestion

    • (webauthn::PasskeyTabHelper*)passkeyTabHelper {
    • ```
    Alexis Hétu

    Done

    File ios/chrome/browser/passwords/ui_bundled/bottom_sheet/passkey_creation_bottom_sheet_view_controller.h
    Line 18, Patchset 2:// Initialize with the handler for user actions and the URL of the current page.
    Noémie St-Onge . resolved

    ```suggestion
    // Initializes the view controller with the `handler` for user actions and the `URL` of the current page.
    ```

    Alexis Hétu

    Done

    File ios/chrome/browser/passwords/ui_bundled/bottom_sheet/passkey_creation_bottom_sheet_view_controller.mm
    Line 24, Patchset 2:@property(nonatomic, weak) id<PasskeyCreationBottomSheetHandler> handler;
    Noémie St-Onge . resolved

    Switch to ivar if possible

    Alexis Hétu

    Done

    Line 49, Patchset 2: // Set the properties read by the super when constructing the
    Noémie St-Onge . resolved

    `base class`?

    Alexis Hétu

    Done

    Line 57, Patchset 2: self.titleString =

    l10n_util::GetNSString(IDS_IOS_PASSKEY_CREATION_BOTTOM_SHEET_TITLE);
    self.titleTextStyle = UIFontTextStyleTitle2;

    NSString* host = base::SysUTF8ToNSString(_URL.host());
    NSString* username = [self.delegate username];
    self.secondaryTitleString =
    [NSString stringWithFormat:@"%@\n%@", username ?: @"", host];

    NSString* subtitle =
    l10n_util::GetNSString(IDS_IOS_PASSKEY_CREATION_BOTTOM_SHEET_SUBTITLE);
    NSString* accountInfo =
    l10n_util::GetNSString(IDS_IOS_PASSKEY_CREATION_BOTTOM_SHEET_ACCOUNT);
    NSString* email = [self.delegate email];
    self.subtitleString =
    [NSString stringWithFormat:@"%@\n%@\n%@", subtitle, accountInfo, email];
    self.subtitleTextStyle = UIFontTextStyleFootnote;
    Noémie St-Onge . resolved

    optional: we could create helper functions for these setups to lighten the `viewDidLoad` method, which tends to get quite long. Not a strong opinion though since it is not that big right now

    Alexis Hétu

    Done

    Line 78, Patchset 2:- (void)viewDidDisappear:(BOOL)animated {

    [super viewDidDisappear:animated];
    [self.handler viewDidDisappear];
    }
    Noémie St-Onge . resolved

    Forwarding a comment made by Gauthier on Angela's Test Project CL https://chromium-review.googlesource.com/c/chromium/src/+/7107319/comment/fbf500d5_04f46e06/

    Alexis Hétu

    I *think* this is ok since the view is modal, but I'll change it anyway. We'll probably want to update the other bottom sheets as well, once we've validated that the new way of doing this works for this bottom sheet.

    Alexis Hétu

    Replaced with `didMoveToParentViewController`.

    Line 85, Patchset 2:// Configures the title view of this ViewController.

    - (UIView*)setUpTitleView {
    NSString* title =
    l10n_util::GetNSString(IDS_IOS_CREDENTIAL_BOTTOM_SHEET_TITLE);
    UIView* titleView = password_manager::CreatePasswordManagerTitleView(title);
    return titleView;
    }
    Noémie St-Onge . resolved

    I think this could be moved to the anonymous namespace since we're not accessing any members of `self`

    Alexis Hétu

    Done

    Open in Gerrit

    Related details

    Attention is currently required from:
    • Noémie St-Onge
    • Tommy Martino
    Submit Requirements:
    • requirement satisfiedCode-Coverage
    • requirement is not satisfiedCode-Owners
    • requirement is not satisfiedCode-Review
    • requirement is not satisfiedReview-Enforcement
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: Ibc9360f1b11d40a48800a45434ee4ddf1c0f1fe3
    Gerrit-Change-Number: 7472659
    Gerrit-PatchSet: 3
    Gerrit-Owner: Alexis Hétu <su...@chromium.org>
    Gerrit-Reviewer: Alexis Hétu <su...@chromium.org>
    Gerrit-Reviewer: Noémie St-Onge <noe...@google.com>
    Gerrit-Reviewer: Tommy Martino <tmar...@chromium.org>
    Gerrit-Attention: Noémie St-Onge <noe...@google.com>
    Gerrit-Attention: Tommy Martino <tmar...@chromium.org>
    Gerrit-Comment-Date: Thu, 15 Jan 2026 19:38:15 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: Yes
    Comment-In-Reply-To: Alexis Hétu <su...@chromium.org>
    Comment-In-Reply-To: Noémie St-Onge <noe...@google.com>
    satisfied_requirement
    unsatisfied_requirement
    open
    diffy

    Noémie St-Onge (Gerrit)

    unread,
    Jan 16, 2026, 12:18:46 PM (2 days ago) Jan 16
    to Alexis Hétu, Chromium LUCI CQ, Tommy Martino, chromium...@chromium.org, feature-me...@chromium.org, gcasto+w...@chromium.org, ios-revie...@chromium.org, ios-r...@chromium.org, marq+...@chromium.org, tmartino+tran...@chromium.org, vasilii+watchlis...@chromium.org
    Attention needed from Alexis Hétu and Tommy Martino

    Noémie St-Onge voted and added 8 comments

    Votes added by Noémie St-Onge

    Code-Review+1

    8 comments

    Patchset-level comments
    File-level comment, Patchset 3 (Latest):
    Noémie St-Onge . resolved

    LGTM with nits! Request for next time: please consider breaking such CLs into smaller pieces. This CL is quite large, which makes it harder to reason about all at once

    File ios/chrome/browser/passwords/bottom_sheet/coordinator/passkey_creation_bottom_sheet_coordinator.h
    Line 19, Patchset 3 (Latest):// `viewController` is the VC used to present the bottom sheet.
    Noémie St-Onge . unresolved

    ```suggestion
    // `viewController` is the view controller used to present the bottom sheet.
    ```

    File ios/chrome/browser/passwords/bottom_sheet/coordinator/passkey_creation_bottom_sheet_coordinator.mm
    Line 22, Patchset 3 (Latest): PasskeyCreationBottomSheetViewController* _viewController;
    PasskeyCreationBottomSheetMediator* _mediator;
    std::string _requestID;
    Noémie St-Onge . unresolved

    Missing comments

    Line 96, Patchset 3 (Latest): // Use GetOriginalProfile so that it uses the signed in profile even when
    // incognito mode.
    Noémie St-Onge . unresolved
    ```suggestion
    // Use GetOriginalProfile so that it uses the signed in profile even when in
    // incognito mode.
    ```
    File ios/chrome/browser/passwords/bottom_sheet/coordinator/passkey_creation_bottom_sheet_mediator.mm
    Line 20, Patchset 3 (Latest):// Presenter that controls the presentation of the bottom sheet.
    @property(nonatomic, weak) id<PasskeyCreationBottomSheetPresenter> presenter;
    Noémie St-Onge . unresolved

    Could this be an ivar?

    Line 149, Patchset 3 (Latest):- (void)onWebStateChanged {
    Noémie St-Onge . unresolved

    Missing comment

    File ios/chrome/browser/passwords/bottom_sheet/ui/passkey_creation_bottom_sheet_view_controller.mm
    Line 20, Patchset 3 (Latest):UIView* setUpTitleView() {
    Noémie St-Onge . unresolved

    Should start with a capital `S`
    ```suggestion
    UIView* SetUpTitleView() {
    ```

    Line 23, Patchset 3 (Latest): UIView* titleView = password_manager::CreatePasswordManagerTitleView(title);
    Noémie St-Onge . unresolved

    `title_view`

    Open in Gerrit

    Related details

    Attention is currently required from:
    • Alexis Hétu
    • Tommy Martino
    Submit Requirements:
      • requirement satisfiedCode-Coverage
      • requirement is not satisfiedCode-Owners
      • requirement satisfiedCode-Review
      • requirement is not satisfiedNo-Unresolved-Comments
      • requirement satisfiedReview-Enforcement
      Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
      Gerrit-MessageType: comment
      Gerrit-Project: chromium/src
      Gerrit-Branch: main
      Gerrit-Change-Id: Ibc9360f1b11d40a48800a45434ee4ddf1c0f1fe3
      Gerrit-Change-Number: 7472659
      Gerrit-PatchSet: 3
      Gerrit-Owner: Alexis Hétu <su...@chromium.org>
      Gerrit-Reviewer: Alexis Hétu <su...@chromium.org>
      Gerrit-Reviewer: Noémie St-Onge <noe...@google.com>
      Gerrit-Reviewer: Tommy Martino <tmar...@chromium.org>
      Gerrit-Attention: Alexis Hétu <su...@chromium.org>
      Gerrit-Attention: Tommy Martino <tmar...@chromium.org>
      Gerrit-Comment-Date: Fri, 16 Jan 2026 17:18:38 +0000
      Gerrit-HasComments: Yes
      Gerrit-Has-Labels: Yes
      satisfied_requirement
      unsatisfied_requirement
      open
      diffy

      Alexis Hétu (Gerrit)

      unread,
      Jan 16, 2026, 1:24:12 PM (2 days ago) Jan 16
      to Noémie St-Onge, Chromium LUCI CQ, Tommy Martino, chromium...@chromium.org, feature-me...@chromium.org, gcasto+w...@chromium.org, ios-revie...@chromium.org, ios-r...@chromium.org, marq+...@chromium.org, tmartino+tran...@chromium.org, vasilii+watchlis...@chromium.org
      Attention needed from Tommy Martino

      Alexis Hétu voted and added 8 comments

      Votes added by Alexis Hétu

      Commit-Queue+1

      8 comments

      Patchset-level comments
      Noémie St-Onge . resolved

      LGTM with nits! Request for next time: please consider breaking such CLs into smaller pieces. This CL is quite large, which makes it harder to reason about all at once

      Alexis Hétu

      Ah yes, sorry about that, I should've split it once I split the ui and coordinator portions, but I didn't think about it.

      File ios/chrome/browser/passwords/bottom_sheet/coordinator/passkey_creation_bottom_sheet_coordinator.h
      Line 19, Patchset 3:// `viewController` is the VC used to present the bottom sheet.
      Noémie St-Onge . resolved

      ```suggestion
      // `viewController` is the view controller used to present the bottom sheet.
      ```

      Alexis Hétu

      Done

      File ios/chrome/browser/passwords/bottom_sheet/coordinator/passkey_creation_bottom_sheet_coordinator.mm
      Line 22, Patchset 3: PasskeyCreationBottomSheetViewController* _viewController;

      PasskeyCreationBottomSheetMediator* _mediator;
      std::string _requestID;
      Noémie St-Onge . resolved

      Missing comments

      Alexis Hétu

      Done

      Line 96, Patchset 3: // Use GetOriginalProfile so that it uses the signed in profile even when
      // incognito mode.
      Noémie St-Onge . resolved
      ```suggestion
      // Use GetOriginalProfile so that it uses the signed in profile even when in
      // incognito mode.
      ```
      Alexis Hétu

      Done

      File ios/chrome/browser/passwords/bottom_sheet/coordinator/passkey_creation_bottom_sheet_mediator.mm
      Line 20, Patchset 3:// Presenter that controls the presentation of the bottom sheet.

      @property(nonatomic, weak) id<PasskeyCreationBottomSheetPresenter> presenter;
      Noémie St-Onge . resolved

      Could this be an ivar?

      Alexis Hétu

      Done

      Line 149, Patchset 3:- (void)onWebStateChanged {
      Noémie St-Onge . resolved

      Missing comment

      Alexis Hétu

      Done

      File ios/chrome/browser/passwords/bottom_sheet/ui/passkey_creation_bottom_sheet_view_controller.mm
      Line 20, Patchset 3:UIView* setUpTitleView() {
      Noémie St-Onge . resolved

      Should start with a capital `S`
      ```suggestion
      UIView* SetUpTitleView() {
      ```

      Alexis Hétu

      Done

      Line 23, Patchset 3: UIView* titleView = password_manager::CreatePasswordManagerTitleView(title);
      Noémie St-Onge . resolved

      `title_view`

      Alexis Hétu

      Done

      Open in Gerrit

      Related details

      Attention is currently required from:
      • Tommy Martino
      Submit Requirements:
        • requirement satisfiedCode-Coverage
        • requirement is not satisfiedCode-Owners
        • requirement satisfiedCode-Review
        • requirement satisfiedReview-Enforcement
        Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
        Gerrit-MessageType: comment
        Gerrit-Project: chromium/src
        Gerrit-Branch: main
        Gerrit-Change-Id: Ibc9360f1b11d40a48800a45434ee4ddf1c0f1fe3
        Gerrit-Change-Number: 7472659
        Gerrit-PatchSet: 4
        Gerrit-Owner: Alexis Hétu <su...@chromium.org>
        Gerrit-Reviewer: Alexis Hétu <su...@chromium.org>
        Gerrit-Reviewer: Noémie St-Onge <noe...@google.com>
        Gerrit-Reviewer: Tommy Martino <tmar...@chromium.org>
        Gerrit-Attention: Tommy Martino <tmar...@chromium.org>
        Gerrit-Comment-Date: Fri, 16 Jan 2026 18:24:02 +0000
        Gerrit-HasComments: Yes
        Gerrit-Has-Labels: Yes
        Comment-In-Reply-To: Noémie St-Onge <noe...@google.com>
        satisfied_requirement
        unsatisfied_requirement
        open
        diffy

        Tommy Martino (Gerrit)

        unread,
        Jan 16, 2026, 1:46:02 PM (2 days ago) Jan 16
        to Alexis Hétu, Noémie St-Onge, Chromium LUCI CQ, chromium...@chromium.org, feature-me...@chromium.org, gcasto+w...@chromium.org, ios-revie...@chromium.org, ios-r...@chromium.org, marq+...@chromium.org, tmartino+tran...@chromium.org, vasilii+watchlis...@chromium.org
        Attention needed from Alexis Hétu

        Tommy Martino added 13 comments

        File ios/chrome/browser/passwords/bottom_sheet/coordinator/passkey_creation_bottom_sheet_coordinator.h
        Line 24, Patchset 3: requestID:(const std::string&)requestID;
        Tommy Martino . unresolved

        There's no real point in taking this by constref if the first thing we're going to do is copy it into a member variable anyway. Let's change this parameter to pass-by-value (and then `std::move` in the initializer).

        That way (a) the lifetime is unambiguous (the caller knows they don't have to persist `requestID` throughout the lifetime of this object) and (b) if the caller doesn't need `requestID` anymore, they can `std::move` into it and save a copy.

        Line 17, Patchset 3: : ChromeCoordinator <PasskeyCreationBottomSheetPresenter>
        Tommy Martino . unresolved

        Nit: the fact that this is a `PasskeyCreationBottomSheetPresenter` (MediatorDelegate) does not need to be part of the public interface, as it relates only to the instantiation of the mediator (which happens in the impl). This can be declared in the .mm file instead.

        File ios/chrome/browser/passwords/bottom_sheet/coordinator/passkey_creation_bottom_sheet_coordinator.mm
        Line 24, Patchset 3: std::string _requestID;
        Tommy Martino . unresolved

        There isn't really a reason for the coordinator to know about the request ID (which is really model-layer information), except so that it can pass it on to the mediator. Let's make this an `std::optional<std::string> _pendingRequestID`, and move + reset when we create the mediator.

        Line 97, Patchset 3: // incognito mode.
        Tommy Martino . unresolved

        Whenever we do this, I like for the comment to document *why* it's OK to use the original profile (so, in this case, the user is later asked to make an explicit choice about saving this data to their account).

        File ios/chrome/browser/passwords/bottom_sheet/coordinator/passkey_creation_bottom_sheet_mediator.mm
        Line 32, Patchset 4 (Latest): std::unique_ptr<ActiveWebStateObservationForwarder> _forwarder;
        Tommy Martino . unresolved

        I don't think we actually need to forward from the ActiveWebState; it should be sufficient to observe the WebState that's active at initialization.

        This sheet is presented over a single WebState/tab that shouldn't change (as it's modal). If the active tab *does* somehow change, then we'll be notified via `didChangeWebStateList` and will close anyway.

        Line 28, Patchset 4 (Latest): // Bridge and forwarder for observing WebState events. The forwarder is a
        // scoped observation, so the bridge will automatically be removed from the
        // relevant observer list.
        std::unique_ptr<web::WebStateObserverBridge> _webStateObserver;
        std::unique_ptr<ActiveWebStateObservationForwarder> _forwarder;

        // Bridge for observing WebStateList events.
        std::unique_ptr<WebStateListObserverBridge> _webStateListObserver;
        std::unique_ptr<
        base::ScopedObservation<WebStateList, WebStateListObserverBridge>>
        _webStateListObservation;
        Tommy Martino . unresolved

        For objects that don't ever get moved, avoid using unique_ptr. Ideally we would just make the object an ivar of this class directly, but since I think none of these are/can be default-constructed, we can use std::optional to handle the uninitialized state.

        Ref: https://abseil.io/tips/187

        File ios/chrome/browser/passwords/bottom_sheet/coordinator/passkey_creation_bottom_sheet_presenter.h
        Line 11, Patchset 3:@protocol PasskeyCreationBottomSheetPresenter <NSObject>
        Tommy Martino . unresolved

        I believe the preferred term for the protocol that a mediator uses to talk to a coordinator is now `FooMediatorDelegate` rather than `FooPresenter`.

        File ios/chrome/browser/passwords/bottom_sheet/ui/passkey_creation_bottom_sheet_delegate.h
        Line 18, Patchset 3:
        Tommy Martino . unresolved

        Could we also pass URL via the same mechanism as username/email?

        Line 11, Patchset 3:@protocol PasskeyCreationBottomSheetDelegate
        Tommy Martino . unresolved

        Generally, the protocol whereby a VC talks to a Mediator would be called a Mutator.

        However, in this case, I think the model is somewhat backwards – typically in the CMVC architecture, we push data to a receiver (ref. the diagram in https://docs.google.com/document/d/1YjLSWwUgBy4OPJZtKUlypu2VseLufrodCxL-wU1kdEM/edit?tab=t.0#heading=h.qc4f3ngdx65b) rather than pulling it from a delegate.

        IOW, we would want a *consumer* protocol that lets the mediator provide the username/email to the VC, and then any mutator protocol (if necessary) would be used to trigger model updates (e.g., "the user said OK, so please create this passkey").

        File ios/chrome/browser/passwords/bottom_sheet/ui/passkey_creation_bottom_sheet_view_controller.h
        Line 24, Patchset 3:@property(nonatomic, strong) id<PasskeyCreationBottomSheetDelegate> delegate;
        Tommy Martino . unresolved

        Does this need to be `strong`?

        Line 21, Patchset 3: URL:(const GURL&)URL;
        Tommy Martino . unresolved

        Same deal as with the string in the coordinator/mediator -- let's take this by (possibly-moved) value since we're ultimately copying it anyway.

        File ios/chrome/browser/passwords/bottom_sheet/ui/passkey_creation_bottom_sheet_view_controller.mm
        Line 23, Patchset 4 (Latest): UIView* title_view = password_manager::CreatePasswordManagerTitleView(title);
        Tommy Martino . unresolved

        Nit, not for this CL: probably `create_password_manager_title_view` should be moved into icb/passwords/ui, since we now use it in a lot of places beyond settings.

        File ios/chrome/browser/passwords/ui_bundled/bottom_sheet/BUILD.gn
        File-level comment, Patchset 2:
        Tommy Martino . unresolved

        Please do not add new stuff to `ui_bundled` directories. Instead, let's create an `icb/passwords/passkey_creation/` directory (with its own `coordinator`, `model`, `ui`, etc subfolders as needed).

        Open in Gerrit

        Related details

        Attention is currently required from:
        • Alexis Hétu
        Submit Requirements:
          • requirement satisfiedCode-Coverage
          • requirement is not satisfiedCode-Owners
          • requirement satisfiedCode-Review
          • requirement is not satisfiedNo-Unresolved-Comments
          • requirement satisfiedReview-Enforcement
          Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
          Gerrit-MessageType: comment
          Gerrit-Project: chromium/src
          Gerrit-Branch: main
          Gerrit-Change-Id: Ibc9360f1b11d40a48800a45434ee4ddf1c0f1fe3
          Gerrit-Change-Number: 7472659
          Gerrit-PatchSet: 4
          Gerrit-Owner: Alexis Hétu <su...@chromium.org>
          Gerrit-Reviewer: Alexis Hétu <su...@chromium.org>
          Gerrit-Reviewer: Noémie St-Onge <noe...@google.com>
          Gerrit-Reviewer: Tommy Martino <tmar...@chromium.org>
          Gerrit-Attention: Alexis Hétu <su...@chromium.org>
          Gerrit-Comment-Date: Fri, 16 Jan 2026 18:45:55 +0000
          Gerrit-HasComments: Yes
          Gerrit-Has-Labels: No
          satisfied_requirement
          unsatisfied_requirement
          open
          diffy

          Noémie St-Onge (Gerrit)

          unread,
          Jan 16, 2026, 2:36:15 PM (2 days ago) Jan 16
          to Alexis Hétu, Chromium LUCI CQ, Tommy Martino, chromium...@chromium.org, feature-me...@chromium.org, gcasto+w...@chromium.org, ios-revie...@chromium.org, ios-r...@chromium.org, marq+...@chromium.org, tmartino+tran...@chromium.org, vasilii+watchlis...@chromium.org
          Attention needed from Alexis Hétu

          Noémie St-Onge voted and added 1 comment

          Votes added by Noémie St-Onge

          Code-Review+1

          1 comment

          File ios/chrome/browser/passwords/bottom_sheet/coordinator/passkey_creation_bottom_sheet_coordinator.mm
          Line 79, Patchset 4 (Latest): // upon calling -viewDidDisappear.
          Noémie St-Onge . unresolved

          forgot to add this comment earlier: I think this is obsolete now

          Gerrit-Comment-Date: Fri, 16 Jan 2026 19:36:06 +0000
          Gerrit-HasComments: Yes
          Gerrit-Has-Labels: Yes
          satisfied_requirement
          unsatisfied_requirement
          open
          diffy

          Alexis Hétu (Gerrit)

          unread,
          Jan 16, 2026, 4:47:31 PM (2 days ago) Jan 16
          to Noémie St-Onge, Chromium LUCI CQ, Tommy Martino, chromium...@chromium.org, feature-me...@chromium.org, gcasto+w...@chromium.org, ios-revie...@chromium.org, ios-r...@chromium.org, marq+...@chromium.org, tmartino+tran...@chromium.org, vasilii+watchlis...@chromium.org
          Attention needed from Noémie St-Onge and Tommy Martino

          Alexis Hétu voted and added 13 comments

          Votes added by Alexis Hétu

          Commit-Queue+1

          13 comments

          File ios/chrome/browser/passwords/bottom_sheet/coordinator/passkey_creation_bottom_sheet_coordinator.h
          Line 24, Patchset 3: requestID:(const std::string&)requestID;
          Tommy Martino . resolved

          There's no real point in taking this by constref if the first thing we're going to do is copy it into a member variable anyway. Let's change this parameter to pass-by-value (and then `std::move` in the initializer).

          That way (a) the lifetime is unambiguous (the caller knows they don't have to persist `requestID` throughout the lifetime of this object) and (b) if the caller doesn't need `requestID` anymore, they can `std::move` into it and save a copy.

          Alexis Hétu

          Done

          Line 17, Patchset 3: : ChromeCoordinator <PasskeyCreationBottomSheetPresenter>
          Tommy Martino . resolved

          Nit: the fact that this is a `PasskeyCreationBottomSheetPresenter` (MediatorDelegate) does not need to be part of the public interface, as it relates only to the instantiation of the mediator (which happens in the impl). This can be declared in the .mm file instead.

          Alexis Hétu

          Done

          File ios/chrome/browser/passwords/bottom_sheet/coordinator/passkey_creation_bottom_sheet_coordinator.mm
          Line 24, Patchset 3: std::string _requestID;
          Tommy Martino . resolved

          There isn't really a reason for the coordinator to know about the request ID (which is really model-layer information), except so that it can pass it on to the mediator. Let's make this an `std::optional<std::string> _pendingRequestID`, and move + reset when we create the mediator.

          Alexis Hétu

          Done

          Line 79, Patchset 4: // upon calling -viewDidDisappear.
          Noémie St-Onge . resolved

          forgot to add this comment earlier: I think this is obsolete now

          Alexis Hétu

          Done

          Line 97, Patchset 3: // incognito mode.
          Tommy Martino . resolved

          Whenever we do this, I like for the comment to document *why* it's OK to use the original profile (so, in this case, the user is later asked to make an explicit choice about saving this data to their account).

          Alexis Hétu

          Done

          File ios/chrome/browser/passwords/bottom_sheet/coordinator/passkey_creation_bottom_sheet_mediator.mm
          Line 32, Patchset 4: std::unique_ptr<ActiveWebStateObservationForwarder> _forwarder;
          Tommy Martino . resolved

          I don't think we actually need to forward from the ActiveWebState; it should be sufficient to observe the WebState that's active at initialization.

          This sheet is presented over a single WebState/tab that shouldn't change (as it's modal). If the active tab *does* somehow change, then we'll be notified via `didChangeWebStateList` and will close anyway.

          Alexis Hétu

          Done

          Line 28, Patchset 4: // Bridge and forwarder for observing WebState events. The forwarder is a

          // scoped observation, so the bridge will automatically be removed from the
          // relevant observer list.
          std::unique_ptr<web::WebStateObserverBridge> _webStateObserver;
          std::unique_ptr<ActiveWebStateObservationForwarder> _forwarder;

          // Bridge for observing WebStateList events.
          std::unique_ptr<WebStateListObserverBridge> _webStateListObserver;
          std::unique_ptr<
          base::ScopedObservation<WebStateList, WebStateListObserverBridge>>
          _webStateListObservation;
          Tommy Martino . resolved

          For objects that don't ever get moved, avoid using unique_ptr. Ideally we would just make the object an ivar of this class directly, but since I think none of these are/can be default-constructed, we can use std::optional to handle the uninitialized state.

          Ref: https://abseil.io/tips/187

          Alexis Hétu

          Done

          File ios/chrome/browser/passwords/bottom_sheet/coordinator/passkey_creation_bottom_sheet_presenter.h
          Line 11, Patchset 3:@protocol PasskeyCreationBottomSheetPresenter <NSObject>
          Tommy Martino . resolved

          I believe the preferred term for the protocol that a mediator uses to talk to a coordinator is now `FooMediatorDelegate` rather than `FooPresenter`.

          Alexis Hétu

          Done

          File ios/chrome/browser/passwords/bottom_sheet/ui/passkey_creation_bottom_sheet_delegate.h
          Line 18, Patchset 3:
          Tommy Martino . resolved

          Could we also pass URL via the same mechanism as username/email?

          Alexis Hétu

          Done

          Line 11, Patchset 3:@protocol PasskeyCreationBottomSheetDelegate
          Tommy Martino . resolved

          Generally, the protocol whereby a VC talks to a Mediator would be called a Mutator.

          However, in this case, I think the model is somewhat backwards – typically in the CMVC architecture, we push data to a receiver (ref. the diagram in https://docs.google.com/document/d/1YjLSWwUgBy4OPJZtKUlypu2VseLufrodCxL-wU1kdEM/edit?tab=t.0#heading=h.qc4f3ngdx65b) rather than pulling it from a delegate.

          IOW, we would want a *consumer* protocol that lets the mediator provide the username/email to the VC, and then any mutator protocol (if necessary) would be used to trigger model updates (e.g., "the user said OK, so please create this passkey").

          Alexis Hétu

          Done

          File ios/chrome/browser/passwords/bottom_sheet/ui/passkey_creation_bottom_sheet_view_controller.h
          Line 24, Patchset 3:@property(nonatomic, strong) id<PasskeyCreationBottomSheetDelegate> delegate;
          Tommy Martino . resolved

          Does this need to be `strong`?

          Alexis Hétu

          Removed.

          Line 21, Patchset 3: URL:(const GURL&)URL;
          Tommy Martino . resolved

          Same deal as with the string in the coordinator/mediator -- let's take this by (possibly-moved) value since we're ultimately copying it anyway.

          Alexis Hétu

          Done

          File ios/chrome/browser/passwords/bottom_sheet/ui/passkey_creation_bottom_sheet_view_controller.mm
          Line 23, Patchset 4: UIView* title_view = password_manager::CreatePasswordManagerTitleView(title);
          Tommy Martino . resolved

          Nit, not for this CL: probably `create_password_manager_title_view` should be moved into icb/passwords/ui, since we now use it in a lot of places beyond settings.

          Alexis Hétu

          Acknowledged

          Open in Gerrit

          Related details

          Attention is currently required from:
          • Noémie St-Onge
          • Tommy Martino
          Submit Requirements:
            • requirement satisfiedCode-Coverage
            • requirement is not satisfiedCode-Owners
            • requirement is not satisfiedCode-Review
            • requirement is not satisfiedNo-Unresolved-Comments
            • requirement is not satisfiedReview-Enforcement
            Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
            Gerrit-MessageType: comment
            Gerrit-Project: chromium/src
            Gerrit-Branch: main
            Gerrit-Change-Id: Ibc9360f1b11d40a48800a45434ee4ddf1c0f1fe3
            Gerrit-Change-Number: 7472659
            Gerrit-PatchSet: 5
            Gerrit-Owner: Alexis Hétu <su...@chromium.org>
            Gerrit-Reviewer: Alexis Hétu <su...@chromium.org>
            Gerrit-Reviewer: Noémie St-Onge <noe...@google.com>
            Gerrit-Reviewer: Tommy Martino <tmar...@chromium.org>
            Gerrit-Attention: Noémie St-Onge <noe...@google.com>
            Gerrit-Attention: Tommy Martino <tmar...@chromium.org>
            Gerrit-Comment-Date: Fri, 16 Jan 2026 21:47:26 +0000
            Gerrit-HasComments: Yes
            Gerrit-Has-Labels: Yes
            Comment-In-Reply-To: Noémie St-Onge <noe...@google.com>
            Comment-In-Reply-To: Tommy Martino <tmar...@chromium.org>
            satisfied_requirement
            unsatisfied_requirement
            open
            diffy

            Alexis Hétu (Gerrit)

            unread,
            Jan 16, 2026, 5:01:14 PM (2 days ago) Jan 16
            to Noémie St-Onge, Chromium LUCI CQ, Tommy Martino, chromium...@chromium.org, feature-me...@chromium.org, gcasto+w...@chromium.org, ios-revie...@chromium.org, ios-r...@chromium.org, marq+...@chromium.org, tmartino+tran...@chromium.org, vasilii+watchlis...@chromium.org
            Attention needed from Noémie St-Onge and Tommy Martino

            Alexis Hétu added 1 comment

            File ios/chrome/browser/passwords/ui_bundled/bottom_sheet/BUILD.gn
            File-level comment, Patchset 2:
            Tommy Martino . resolved

            Please do not add new stuff to `ui_bundled` directories. Instead, let's create an `icb/passwords/passkey_creation/` directory (with its own `coordinator`, `model`, `ui`, etc subfolders as needed).

            Alexis Hétu

            Done

            Open in Gerrit

            Related details

            Attention is currently required from:
            • Noémie St-Onge
            • Tommy Martino
            Submit Requirements:
              • requirement satisfiedCode-Coverage
              • requirement is not satisfiedCode-Owners
              • requirement is not satisfiedCode-Review
              • requirement is not satisfiedReview-Enforcement
              Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
              Gerrit-MessageType: comment
              Gerrit-Project: chromium/src
              Gerrit-Branch: main
              Gerrit-Change-Id: Ibc9360f1b11d40a48800a45434ee4ddf1c0f1fe3
              Gerrit-Change-Number: 7472659
              Gerrit-PatchSet: 5
              Gerrit-Owner: Alexis Hétu <su...@chromium.org>
              Gerrit-Reviewer: Alexis Hétu <su...@chromium.org>
              Gerrit-Reviewer: Noémie St-Onge <noe...@google.com>
              Gerrit-Reviewer: Tommy Martino <tmar...@chromium.org>
              Gerrit-Attention: Noémie St-Onge <noe...@google.com>
              Gerrit-Attention: Tommy Martino <tmar...@chromium.org>
              Gerrit-Comment-Date: Fri, 16 Jan 2026 22:01:09 +0000
              Gerrit-HasComments: Yes
              Gerrit-Has-Labels: No
              Comment-In-Reply-To: Tommy Martino <tmar...@chromium.org>
              satisfied_requirement
              unsatisfied_requirement
              open
              diffy

              Tommy Martino (Gerrit)

              unread,
              Jan 16, 2026, 5:06:34 PM (2 days ago) Jan 16
              to Alexis Hétu, Noémie St-Onge, Chromium LUCI CQ, chromium...@chromium.org, feature-me...@chromium.org, gcasto+w...@chromium.org, ios-revie...@chromium.org, ios-r...@chromium.org, marq+...@chromium.org, tmartino+tran...@chromium.org, vasilii+watchlis...@chromium.org
              Attention needed from Alexis Hétu and Noémie St-Onge

              Tommy Martino voted and added 7 comments

              Votes added by Tommy Martino

              Code-Review+1

              7 comments

              Patchset-level comments
              File-level comment, Patchset 5 (Latest):
              Tommy Martino . resolved

              lgtm % nits, thanks!

              File ios/chrome/browser/passwords/bottom_sheet/coordinator/passkey_creation_bottom_sheet_coordinator.mm
              Line 50, Patchset 5 (Latest): const GURL& URL = webStateList->GetActiveWebState()->GetLastCommittedURL();
              Tommy Martino . unresolved

              Nit: the mediator receives webStateList, so no need to get and pass this URL separately

              File ios/chrome/browser/passwords/bottom_sheet/coordinator/passkey_creation_bottom_sheet_mediator.mm
              Line 40, Patchset 5 (Latest): GURL _url;
              Tommy Martino . unresolved

              nit: `_URL`

              Line 62, Patchset 5 (Latest): _url = URL;
              Tommy Martino . unresolved

              nit: std::move

              File ios/chrome/browser/passwords/bottom_sheet/ui/passkey_creation_bottom_sheet_consumer.h
              Line 16, Patchset 5 (Latest):- (void)setUsername:(NSString*)username email:(NSString*)email url:(GURL)url;
              Tommy Martino . unresolved

              URL

              File ios/chrome/browser/passwords/bottom_sheet/ui/passkey_creation_bottom_sheet_view_controller.mm
              Line 101, Patchset 5 (Latest):}
              Tommy Martino . unresolved

              Should this trigger a refresh of the UI elements, so that the new values are reflected in `secondaryTitle` and `subtitle` if set after `viewDidLoad`?

              File ios/chrome/browser/passwords/ui_bundled/bottom_sheet/BUILD.gn
              Tommy Martino . resolved

              Please do not add new stuff to `ui_bundled` directories. Instead, let's create an `icb/passwords/passkey_creation/` directory (with its own `coordinator`, `model`, `ui`, etc subfolders as needed).

              Tommy Martino

              Acknowledged

              Open in Gerrit

              Related details

              Attention is currently required from:
              • Alexis Hétu
              • Noémie St-Onge
              Submit Requirements:
              • requirement satisfiedCode-Coverage
              • requirement satisfiedCode-Owners
              • requirement satisfiedCode-Review
              • requirement is not satisfiedNo-Unresolved-Comments
              • requirement satisfiedReview-Enforcement
              Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
              Gerrit-MessageType: comment
              Gerrit-Project: chromium/src
              Gerrit-Branch: main
              Gerrit-Change-Id: Ibc9360f1b11d40a48800a45434ee4ddf1c0f1fe3
              Gerrit-Change-Number: 7472659
              Gerrit-PatchSet: 5
              Gerrit-Owner: Alexis Hétu <su...@chromium.org>
              Gerrit-Reviewer: Alexis Hétu <su...@chromium.org>
              Gerrit-Reviewer: Noémie St-Onge <noe...@google.com>
              Gerrit-Reviewer: Tommy Martino <tmar...@chromium.org>
              Gerrit-Attention: Alexis Hétu <su...@chromium.org>
              Gerrit-Attention: Noémie St-Onge <noe...@google.com>
              Gerrit-Comment-Date: Fri, 16 Jan 2026 22:06:28 +0000
              Gerrit-HasComments: Yes
              Gerrit-Has-Labels: Yes
              Comment-In-Reply-To: Tommy Martino <tmar...@chromium.org>
              satisfied_requirement
              unsatisfied_requirement
              open
              diffy
              Reply all
              Reply to author
              Forward
              0 new messages