Skip to content

Conversation

@Quwaysim
Copy link
Contributor

@Quwaysim Quwaysim commented Sep 16, 2025

Description

Added #477. This adds the paste button beside the npub/user search in the profile search/start new chat bottom sheet. Also made some minor UI changes to match the design.

Edit: fixes #613 too to format pasted npubs with whitespaces.

Type of Change

  • ✨ New feature (non-breaking change which adds functionality)
  • 🛠️ Bug fix (non-breaking change which fixes an issue)
  • ❌ Breaking change (fix or feature that would cause existing functionality to change)
  • 🧹 Code refactor
  • ✅ Build configuration change
  • 📝 Documentation
  • 🗑️ Chore
  • 🧪 Tests

Checklist

  • Run just precommit to ensure that formatting and linting are correct
  • Run just check-flutter-coverage to ensure that flutter coverage rules are passing
  • Updated the CHANGELOG.md file with your changes (if they affect the user experience)

Summary by CodeRabbit

  • New Features

    • Centralized paste-from-clipboard support with user-facing toasts (available in search rows and login key field).
  • Style

    • Title changed to “Start New Chat”; compacted search area; tightened spacing; reduced icon and typography sizes for chat tiles.
  • Bug Fixes

    • Search input trims whitespace for key-like entries (e.g., npub...) to improve lookup accuracy.
  • Tests

    • Clipboard paste behavior covered by new tests validating toasts and edge cases.

@Quwaysim Quwaysim linked an issue Sep 16, 2025 that may be closed by this pull request
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 16, 2025

Walkthrough

Adds a paste-from-clipboard helper and tests; wires paste CTAs into New Chat bottom sheet, New Group Chat sheet, and Login screen; auto-strips whitespace for inputs starting with npub; updates New Chat UI spacing/typography and title; removes isScrollControlled param from WnBottomSheet.show; documents the feature in CHANGELOG.

Changes

Cohort / File(s) Summary
Changelog
CHANGELOG.md
Adds Unreleased entry documenting "Paste from clipboard functionality (cta) in new chat bottom sheet."
Clipboard utility & tests
lib/utils/clipboard_utils.dart, test/utils/clipboard_utils_test.dart
Adds ClipboardUtils.pasteWithToast(...) to read clipboard, invoke an onPaste(String) callback, show success/info/error toasts, and log PlatformExceptions; tests cover text, empty/null, and error scenarios with mocked clipboard responses.
New Chat bottom sheet (UI + logic)
lib/ui/contact_list/new_chat_bottom_sheet.dart
Adds paste button wired to ClipboardUtils.pasteWithToast, inserts pasted text into _searchController, trims whitespace when input starts with npub, replaces input with WnTextFormField + paste WnIconButton, tightens spacing, reduces icon/text sizes, and changes title to "Start New Chat."
New Group Chat search sanitization
lib/ui/contact_list/new_group_chat_sheet.dart
Replaces text field with WnTextFormField + paste WnIconButton; uses ClipboardUtils.pasteWithToast; sanitizes whitespace only for inputs beginning with npub, updates controller and caret when modified, and sets _searchQuery to the processed value.
Login screen paste wiring
lib/ui/auth_flow/login_screen.dart
Replaces local clipboard handling with ClipboardUtils.pasteWithToast(ref: ..., onPaste: ...); onPaste sets _keyController.text; removes direct Clipboard.getData usage and local toast logic.
Bottom sheet API
lib/ui/core/ui/wn_bottom_sheet.dart
Removes isScrollControlled parameter from WnBottomSheet.show(...) signature.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant UI as "NewChat / NewGroupChat / LoginScreen"
  participant Clipboard as "System Clipboard"
  participant Toast as "ToastService"

  User->>UI: Tap paste CTA
  UI->>Clipboard: Clipboard.getData(Clipboard.kTextPlain)
  alt clipboard has text
    Clipboard-->>UI: text
    UI->>UI: if text.startswith("npub") then remove whitespace\nupdate controller.text & move caret to end
    UI->>Toast: show success toast
    UI-->>User: pasted text visible in input
  else empty/null
    Clipboard-->>UI: empty/null
    UI->>Toast: show info toast
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • josefinalliende
  • untreu2

Poem

I nibble the clipboard, whiskers bright,
I paste a hop of daylight.
Whitespace gone from every npub line,
Small button pressed — the threads align.
Hoppity paste, new chats take flight 🥕🐇

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning Most edits are on-topic (paste CTA, clipboard utils, whitespace sanitization, UI tweaks), but the removal of the public parameter isScrollControlled from WnBottomSheet.show is an API signature change not described in the PR objectives and could be breaking for callers; this change appears out of scope for the linked issue and the stated non-breaking intent. Other minor UI spacing/text tweaks are acceptable under "minor UI changes" but the public API removal should be isolated or documented. Please revert or move the WnBottomSheet.show signature change into a separate, explicitly scoped PR (or provide a compatibility shim and a clear changelog/migration note), update any callers, and run integration/build checks before merging.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "Added paste npub cta in profile search sheet" succinctly and accurately describes the primary change — adding a paste CTA for npub in the profile/search bottom sheet — and aligns with the PR objectives and changed files. It is concise, specific, and relevant to the main change in the diff.
Linked Issues Check ✅ Passed The changes implement the linked issue #613: a paste button is added and whitespace-normalization logic was introduced so that inputs starting with "npub" have all whitespace removed (the code updates the TextEditingValue and caret), and the paste action uses ClipboardUtils.pasteWithToast to insert clipboard text into the search field, which enables the sanitization to run. Based on the file summaries, this directly satisfies the objective to auto-remove whitespaces from pasted npubs.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 477-past-npub-icon-button-in-profile-search

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 36d25b8 and c089355.

📒 Files selected for processing (1)
  • lib/utils/clipboard_utils.dart (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/utils/clipboard_utils.dart
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Flutter CI

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Quwaysim Quwaysim changed the title Paste npub cta in profile search sheet Added paste npub cta in profile search sheet Sep 16, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (3)
CHANGELOG.md (1)

15-15: Tighten wording and casing for consistency with sheet title.

Prefer: “Start New Chat: add Paste from clipboard CTA in the search field.”

Apply this diff:

-- Paste from clipboard functionality (cta) in new chat bottom sheet.
+- Start New Chat: add Paste from clipboard CTA in the search field.
lib/ui/contact_list/new_chat_bottom_sheet.dart (2)

36-36: Localize the new title.

Use AppLocalizations instead of a hardcoded string.

Apply this diff (adjust to your l10n API):

-      title: 'Start New Chat',
+      title: AppLocalizations.of(context)!.startNewChat,

352-391: Add tooltip/semantics and meet 48×48 tap target for the paste CTA; localize hint.

  • Wrap the icon button in Tooltip and bump size to 48 for a11y.
  • Localize the hintText.

Apply this diff:

-            Expanded(
+            Expanded(
               child: WnTextFormField(
                 controller: _searchController,
                 focusNode: _searchFocusNode,
                 size: FieldSize.small,
-                hintText: 'Search contact or public key...',
+                hintText: AppLocalizations.of(context)!.searchContactOrPubkeyHint,
                 decoration: InputDecoration(
@@
-            WnIconButton(
-              iconPath: AssetsPaths.icPaste,
-              onTap: _pasteFromClipboard,
-              padding: 14.w,
-              size: 44.h,
-            ),
+            Tooltip(
+              message: AppLocalizations.of(context)!.pasteFromClipboard,
+              child: WnIconButton(
+                iconPath: AssetsPaths.icPaste,
+                onTap: _pasteFromClipboard,
+                padding: 14.w,
+                size: 48.w,
+              ),
+            ),
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f1cce74 and 12a612a.

📒 Files selected for processing (2)
  • CHANGELOG.md (1 hunks)
  • lib/ui/contact_list/new_chat_bottom_sheet.dart (7 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.md

📄 CodeRabbit inference engine (.cursor/rules/whitenoise.mdc)

**/*.md: NIPs (Nostr Implementation Possibilities) are numbered like NIP-XX where XX are two capitalized hexadecimal digits, e.g., NIP-01 and NIP-C7.
To read a specific NIP, construct the NIP URL following this template: https://raw.githubusercontent.com/nostr-protocol/nips/refs/heads/master/{nip}.md (replace {nip} in the URL template with the relevant NIP name, e.g., 07 for NIP-07, or C7 for NIP-C7).
To read the definition of a specific kind, construct a URL following this template: https://nostrbook.dev/kinds/{kind}.md (replace {kind} in the template with the kind number, e.g., https://nostrbook.dev/kinds/0.md for kind 0).

Files:

  • CHANGELOG.md
**/*.dart

📄 CodeRabbit inference engine (.cursor/rules/flutter.mdc)

**/*.dart: Always declare the type of each variable and function (parameters and return value). Avoid using 'any'. Create necessary types.
Don't leave blank lines within a function.
One export per file.
Use PascalCase for classes.
Use camelCase for variables, functions, and methods.
Use underscores_case for file and directory names.
Use UPPERCASE for environment variables. Avoid magic numbers and define constants.
Start each function with a verb.
Use verbs for boolean variables. Example: isLoading, hasError, canDelete, etc.
Use complete words instead of abbreviations and correct spelling, except for standard and well-known abbreviations (API, URL, i, j, err, ctx, req, res, next).
Write short functions with a single purpose. Less than 20 instructions.
Name functions with a verb and something else. If it returns a boolean, use isX or hasX, canX, etc. If it doesn't return anything, use executeX or saveX, etc.
Avoid nesting blocks by early checks and returns, or extraction to utility functions.
Use higher-order functions (map, filter, reduce, etc.) to avoid function nesting. Use arrow functions for simple functions (less than 3 instructions). Use named functions for non-simple functions.
Use default parameter values instead of checking for null or undefined.
Reduce function parameters using RO-RO: use an object to pass multiple parameters and to return results. Declare necessary types for input arguments and output.
Use a single level of abstraction in functions.
Don't abuse primitive types and encapsulate data in composite types.
Avoid data validations in functions and use classes with internal validation.
Prefer immutability for data. Use readonly for data that doesn't change. Use 'as const' for literals that don't change.
Declare interfaces to define contracts.
Write small classes with a single purpose. Less than 200 instructions, less than 10 public methods, less than 10 properties.
Use exceptions to handle errors you don't expect. If you catch an exception, it sh...

Files:

  • lib/ui/contact_list/new_chat_bottom_sheet.dart
🧠 Learnings (4)
📚 Learning: 2025-08-08T13:39:00.500Z
Learnt from: CR
PR: parres-hq/whitenoise_flutter#0
File: .cursor/rules/flutter.mdc:0-0
Timestamp: 2025-08-08T13:39:00.500Z
Learning: Applies to **/*.dart : Use Riverpod to manage state. Use StreamProviders to watch for state changes that come from the rust api. See keepAlive if you need to keep the state alive.

Applied to files:

  • lib/ui/contact_list/new_chat_bottom_sheet.dart
📚 Learning: 2025-08-23T11:02:28.308Z
Learnt from: Quwaysim
PR: parres-hq/whitenoise_flutter#527
File: lib/ui/core/ui/wn_avatar.dart:1-6
Timestamp: 2025-08-23T11:02:28.308Z
Learning: In the whitenoise_flutter codebase, flutter_screenutil is re-exported through lib/ui/core/themes/src/app_theme.dart, so files that import app_theme.dart do not need to directly import flutter_screenutil to use .w, .h, .sp extensions.

Applied to files:

  • lib/ui/contact_list/new_chat_bottom_sheet.dart
📚 Learning: 2025-09-01T14:56:50.988Z
Learnt from: josefinalliende
PR: parres-hq/whitenoise_flutter#568
File: lib/ui/core/ui/wn_image.dart:1-2
Timestamp: 2025-09-01T14:56:50.988Z
Learning: The whitenoise_flutter project does not target web platforms and any future web version would be in a separate repository, so dart:io imports and file system operations are acceptable in this codebase.

Applied to files:

  • lib/ui/contact_list/new_chat_bottom_sheet.dart
📚 Learning: 2025-09-16T06:28:24.611Z
Learnt from: Quwaysim
PR: parres-hq/whitenoise_flutter#640
File: lib/ui/chat/services/chat_dialog_service.dart:21-25
Timestamp: 2025-09-16T06:28:24.611Z
Learning: In lib/ui/core/ui/wn_bottom_sheet.dart, the WnBottomSheet.show method has barrierDismissible parameter that defaults to false, not true.

Applied to files:

  • lib/ui/contact_list/new_chat_bottom_sheet.dart
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Flutter CI
🔇 Additional comments (3)
lib/ui/contact_list/new_chat_bottom_sheet.dart (3)

2-2: Clipboard and button imports LGTM.

Both are needed for the new paste CTA.

Also applies to: 22-22


392-392: No action.

Spacing tweak is fine.


406-406: No action.

Spacing tweak is fine.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 12a612a and d71d744.

📒 Files selected for processing (2)
  • lib/ui/contact_list/new_chat_bottom_sheet.dart (8 hunks)
  • lib/ui/contact_list/new_group_chat_sheet.dart (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/ui/contact_list/new_chat_bottom_sheet.dart
🧰 Additional context used
📓 Path-based instructions (1)
**/*.dart

📄 CodeRabbit inference engine (.cursor/rules/flutter.mdc)

**/*.dart: Always declare the type of each variable and function (parameters and return value). Avoid using 'any'. Create necessary types.
Don't leave blank lines within a function.
One export per file.
Use PascalCase for classes.
Use camelCase for variables, functions, and methods.
Use underscores_case for file and directory names.
Use UPPERCASE for environment variables. Avoid magic numbers and define constants.
Start each function with a verb.
Use verbs for boolean variables. Example: isLoading, hasError, canDelete, etc.
Use complete words instead of abbreviations and correct spelling, except for standard and well-known abbreviations (API, URL, i, j, err, ctx, req, res, next).
Write short functions with a single purpose. Less than 20 instructions.
Name functions with a verb and something else. If it returns a boolean, use isX or hasX, canX, etc. If it doesn't return anything, use executeX or saveX, etc.
Avoid nesting blocks by early checks and returns, or extraction to utility functions.
Use higher-order functions (map, filter, reduce, etc.) to avoid function nesting. Use arrow functions for simple functions (less than 3 instructions). Use named functions for non-simple functions.
Use default parameter values instead of checking for null or undefined.
Reduce function parameters using RO-RO: use an object to pass multiple parameters and to return results. Declare necessary types for input arguments and output.
Use a single level of abstraction in functions.
Don't abuse primitive types and encapsulate data in composite types.
Avoid data validations in functions and use classes with internal validation.
Prefer immutability for data. Use readonly for data that doesn't change. Use 'as const' for literals that don't change.
Declare interfaces to define contracts.
Write small classes with a single purpose. Less than 200 instructions, less than 10 public methods, less than 10 properties.
Use exceptions to handle errors you don't expect. If you catch an exception, it sh...

Files:

  • lib/ui/contact_list/new_group_chat_sheet.dart
🪛 GitHub Actions: CI
lib/ui/contact_list/new_group_chat_sheet.dart

[error] 1-1: Dart format changed this file due to formatting by 'dart format --set-exit-if-changed lib/ integration_test/'. Please run 'dart format' and commit the changes.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Flutter CI
🔇 Additional comments (1)
lib/ui/contact_list/new_group_chat_sheet.dart (1)

1-212: Fix CI: run dart format and commit.

CI failed with “dart format changed this file…”. Please run: dart format --set-exit-if-changed lib/ integration_test/ and commit the result.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
lib/ui/contact_list/new_chat_bottom_sheet.dart (1)

581-582: Compile error: const EdgeInsets.all(13).w.

Remove const and scale the numeric literal.

-        padding: const EdgeInsets.all(13).w,
+        padding: EdgeInsets.all(13.w),
🧹 Nitpick comments (7)
lib/utils/clipboard_utils.dart (3)

98-106: Type the callback and hoist logger (avoid per-call allocation).

  • Prefer void Function(String) over Function(String).
  • Use a static class logger; remove the local Logger(...).
-  static Future<void> pasteWithToast({
-    required WidgetRef ref,
-    required Function(String) onPaste,
+  static Future<void> pasteWithToast({
+    required WidgetRef ref,
+    required void Function(String) onPaste,
@@
-  }) async {
-    final logger = Logger('ClipboardUtils');
+  }) async {

Add this near other statics in the class (outside the function):

static final Logger _logger = Logger('ClipboardUtils');

122-129: Use class logger; broaden error handling.

  • Swap to _logger.
  • Optionally add a generic catch to cover non-Platform exceptions.
-    } on PlatformException catch (e) {
-      logger.warning('Clipboard read failed: $e');
+    } on PlatformException catch (e) {
+      _logger.warning('Clipboard read failed: $e');
       ref.showErrorToast(
         errorMessage ?? 'Clipboard unavailable',
         autoDismiss: true,
       );
-    }
+    } catch (e) {
+      _logger.warning('Clipboard read failed (non-platform): $e');
+      ref.showErrorToast(
+        errorMessage ?? 'Clipboard unavailable',
+        autoDismiss: true,
+      );
+    }

98-129: Localize toast strings.

Route messages through AppLocalizations instead of hard-coded English.

lib/ui/auth_flow/login_screen.dart (1)

200-206: Set caret to end after paste; simplify handler.

Ensure a good UX and avoid redundant await in arrow body.

-                              onTap:
-                                  () async => await ClipboardUtils.pasteWithToast(
+                              onTap: () async {
+                                await ClipboardUtils.pasteWithToast(
                                   ref: ref,
                                   onPaste: (text) {
-                                      _keyController.text = text;
+                                    _keyController.value = TextEditingValue(
+                                      text: text,
+                                      selection: TextSelection.collapsed(offset: text.length),
+                                    );
                                   },
-                                  ),
+                                );
+                              },
lib/ui/contact_list/new_chat_bottom_sheet.dart (3)

36-36: Localize bottom sheet title.

Use AppLocalizations instead of a hard-coded string.

-      title: 'Start New Chat',
+      title: AppLocalizations.of(context)!.startNewChat,

76-91: Comment/code mismatch; make npub check case-insensitive.

Comment mentions “npub or hex-like,” but code only checks npub1 and case-sensitively.

-    if (originalText.startsWith('npub1')) {
+    if (originalText.toLowerCase().startsWith('npub1')) {
       processedText = originalText.replaceAll(RegExp(r'\s+'), '');

If hex handling is out of scope, adjust the comment accordingly.


354-399: Paste handler UX: set caret; prefer block body.

Mirror the login screen behavior for consistency.

-            WnIconButton(
+            WnIconButton(
               iconPath: AssetsPaths.icPaste,
-              onTap:
-                  () async => await ClipboardUtils.pasteWithToast(
-                    ref: ref,
-                    onPaste: (text) {
-                      _searchController.text = text;
-                    },
-                  ),
+              onTap: () async {
+                await ClipboardUtils.pasteWithToast(
+                  ref: ref,
+                  onPaste: (text) {
+                    _searchController.value = TextEditingValue(
+                      text: text,
+                      selection: TextSelection.collapsed(offset: text.length),
+                    );
+                  },
+                );
+              },
               padding: 14.w,
               size: 44.h,
             ),
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d71d744 and 502074e.

📒 Files selected for processing (4)
  • lib/ui/auth_flow/login_screen.dart (2 hunks)
  • lib/ui/contact_list/new_chat_bottom_sheet.dart (6 hunks)
  • lib/ui/contact_list/new_group_chat_sheet.dart (1 hunks)
  • lib/utils/clipboard_utils.dart (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/ui/contact_list/new_group_chat_sheet.dart
🧰 Additional context used
📓 Path-based instructions (1)
**/*.dart

📄 CodeRabbit inference engine (.cursor/rules/flutter.mdc)

**/*.dart: Always declare the type of each variable and function (parameters and return value). Avoid using 'any'. Create necessary types.
Don't leave blank lines within a function.
One export per file.
Use PascalCase for classes.
Use camelCase for variables, functions, and methods.
Use underscores_case for file and directory names.
Use UPPERCASE for environment variables. Avoid magic numbers and define constants.
Start each function with a verb.
Use verbs for boolean variables. Example: isLoading, hasError, canDelete, etc.
Use complete words instead of abbreviations and correct spelling, except for standard and well-known abbreviations (API, URL, i, j, err, ctx, req, res, next).
Write short functions with a single purpose. Less than 20 instructions.
Name functions with a verb and something else. If it returns a boolean, use isX or hasX, canX, etc. If it doesn't return anything, use executeX or saveX, etc.
Avoid nesting blocks by early checks and returns, or extraction to utility functions.
Use higher-order functions (map, filter, reduce, etc.) to avoid function nesting. Use arrow functions for simple functions (less than 3 instructions). Use named functions for non-simple functions.
Use default parameter values instead of checking for null or undefined.
Reduce function parameters using RO-RO: use an object to pass multiple parameters and to return results. Declare necessary types for input arguments and output.
Use a single level of abstraction in functions.
Don't abuse primitive types and encapsulate data in composite types.
Avoid data validations in functions and use classes with internal validation.
Prefer immutability for data. Use readonly for data that doesn't change. Use 'as const' for literals that don't change.
Declare interfaces to define contracts.
Write small classes with a single purpose. Less than 200 instructions, less than 10 public methods, less than 10 properties.
Use exceptions to handle errors you don't expect. If you catch an exception, it sh...

Files:

  • lib/ui/auth_flow/login_screen.dart
  • lib/utils/clipboard_utils.dart
  • lib/ui/contact_list/new_chat_bottom_sheet.dart
🧠 Learnings (8)
📓 Common learnings
Learnt from: Quwaysim
PR: parres-hq/whitenoise_flutter#642
File: lib/ui/contact_list/new_chat_bottom_sheet.dart:324-336
Timestamp: 2025-09-16T07:24:07.453Z
Learning: In the whitenoise_flutter project, the user Quwaysim prefers to handle security improvements incrementally across different PRs rather than bundling them all together. Input trimming for search functionality was handled in PR #613, and private key security measures are planned for PR #505.
📚 Learning: 2025-09-07T02:15:31.931Z
Learnt from: josefinalliende
PR: parres-hq/whitenoise_flutter#594
File: lib/src/rust/api/utils.dart:12-16
Timestamp: 2025-09-07T02:15:31.931Z
Learning: The lingering PublicKey references in lib/config/providers/auth_provider.dart, lib/config/providers/group_provider.dart, and rust_builder/cargokit/build_tool/lib/src/options.dart identified during the utils.dart API cleanup were fixed in PR #597 in the whitenoise_flutter codebase.

Applied to files:

  • lib/ui/auth_flow/login_screen.dart
  • lib/ui/contact_list/new_chat_bottom_sheet.dart
📚 Learning: 2025-08-23T11:02:28.308Z
Learnt from: Quwaysim
PR: parres-hq/whitenoise_flutter#527
File: lib/ui/core/ui/wn_avatar.dart:1-6
Timestamp: 2025-08-23T11:02:28.308Z
Learning: In the whitenoise_flutter codebase, flutter_screenutil is re-exported through lib/ui/core/themes/src/app_theme.dart, so files that import app_theme.dart do not need to directly import flutter_screenutil to use .w, .h, .sp extensions.

Applied to files:

  • lib/ui/auth_flow/login_screen.dart
  • lib/ui/contact_list/new_chat_bottom_sheet.dart
📚 Learning: 2025-08-08T13:39:00.500Z
Learnt from: CR
PR: parres-hq/whitenoise_flutter#0
File: .cursor/rules/flutter.mdc:0-0
Timestamp: 2025-08-08T13:39:00.500Z
Learning: Applies to **/*.dart : Use Riverpod to manage state. Use StreamProviders to watch for state changes that come from the rust api. See keepAlive if you need to keep the state alive.

Applied to files:

  • lib/ui/auth_flow/login_screen.dart
📚 Learning: 2025-09-07T02:08:09.199Z
Learnt from: josefinalliende
PR: parres-hq/whitenoise_flutter#594
File: lib/domain/models/contact_model.dart:36-41
Timestamp: 2025-09-07T02:08:09.199Z
Learning: The issue of ContactModel.publicKey potentially being set to an empty string when pubkey.toNpub() conversion fails (causing collision/lookup issues) is being addressed in PR #597 in the whitenoise_flutter codebase.

Applied to files:

  • lib/ui/contact_list/new_chat_bottom_sheet.dart
📚 Learning: 2025-09-16T07:24:07.453Z
Learnt from: Quwaysim
PR: parres-hq/whitenoise_flutter#642
File: lib/ui/contact_list/new_chat_bottom_sheet.dart:324-336
Timestamp: 2025-09-16T07:24:07.453Z
Learning: In the whitenoise_flutter project, the user Quwaysim prefers to handle security improvements incrementally across different PRs rather than bundling them all together. Input trimming for search functionality was handled in PR #613, and private key security measures are planned for PR #505.

Applied to files:

  • lib/ui/contact_list/new_chat_bottom_sheet.dart
📚 Learning: 2025-09-05T00:08:34.509Z
Learnt from: josefinalliende
PR: parres-hq/whitenoise_flutter#594
File: lib/config/providers/active_account_provider.dart:140-146
Timestamp: 2025-09-05T00:08:34.509Z
Learning: josefinalliende prefers centralizing validation logic (like trimming whitespace) in providers rather than handling it defensively at every consumer site. This approach was applied to activePubkeyProvider in the whitenoise_flutter codebase.

Applied to files:

  • lib/ui/contact_list/new_chat_bottom_sheet.dart
📚 Learning: 2025-09-16T06:28:24.611Z
Learnt from: Quwaysim
PR: parres-hq/whitenoise_flutter#640
File: lib/ui/chat/services/chat_dialog_service.dart:21-25
Timestamp: 2025-09-16T06:28:24.611Z
Learning: In lib/ui/core/ui/wn_bottom_sheet.dart, the WnBottomSheet.show method has barrierDismissible parameter that defaults to false, not true.

Applied to files:

  • lib/ui/contact_list/new_chat_bottom_sheet.dart
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Flutter CI
🔇 Additional comments (2)
lib/ui/auth_flow/login_screen.dart (1)

16-16: LGTM: Centralized paste via ClipboardUtils.

lib/ui/contact_list/new_chat_bottom_sheet.dart (1)

21-24: LGTM: Imports for paste CTA.

@Quwaysim Quwaysim requested a review from codeswot September 16, 2025 13:08
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
lib/ui/contact_list/new_group_chat_sheet.dart (1)

58-76: Don’t mutate the controller; sanitize only for key matching.

Updating _searchController.value mid-typing is jarring and can break IME/selection. Keep raw trimmed text for name/NIP‑05, use a sanitized variant only when matching keys. Also remove intra‑function blank lines per guidelines. Comment about “hex-like” isn’t implemented.

Apply this diff:

   void _onSearchChanged() {
-    final originalText = _searchController.text;
-    String processedText = originalText;
-
-    // Only remove whitespace if it looks like a public key (starts with npub or is hex-like)
-    if (originalText.startsWith('npub1')) {
-      processedText = originalText.replaceAll(RegExp(r'\s+'), '');
-
-      // Update the controller if we removed whitespace
-      if (originalText != processedText) {
-        _searchController.value = _searchController.value.copyWith(
-          text: processedText,
-          selection: TextSelection.collapsed(offset: processedText.length),
-        );
-      }
-    }
-
-    setState(() {
-      _searchQuery = processedText;
-    });
+    final String text = _searchController.text;
+    setState(() {
+      _searchQuery = text.trim();
+    });
   }
🧹 Nitpick comments (2)
lib/ui/contact_list/new_group_chat_sheet.dart (2)

133-147: Use sanitized “no‑whitespace” variant only for publicKey matching.

Precompute q and keyQ. This preserves display‑name/NIP‑05 searches with spaces while still handling pasted npub1… with inserted whitespace.

-    return contactsWithoutCreator
-        .where(
-          (contact) =>
-              contact.displayName.toLowerCase().contains(
-                _searchQuery.toLowerCase(),
-              ) ||
-              (contact.nip05?.toLowerCase().contains(
-                    _searchQuery.toLowerCase(),
-                  ) ??
-                  false) ||
-              contact.publicKey.toLowerCase().contains(
-                _searchQuery.toLowerCase(),
-              ),
-        )
-        .toList();
+    final String q = _searchQuery.toLowerCase();
+    final String keyQ = _searchQuery.replaceAll(RegExp(r'\s+'), '').toLowerCase();
+    return contactsWithoutCreator
+        .where(
+          (contact) =>
+              contact.displayName.toLowerCase().contains(q) ||
+              (contact.nip05?.toLowerCase().contains(q) ?? false) ||
+              contact.publicKey.toLowerCase().contains(keyQ),
+        )
+        .toList();

164-197: Add an accessibility label for the paste button.

Improve a11y/UX for screen readers.

-              WnIconButton(
-                iconPath: AssetsPaths.icPaste,
-                onTap:
-                    () async => await ClipboardUtils.pasteWithToast(
-                      ref: ref,
-                      onPaste: (text) {
-                        _searchController.text = text;
-                      },
-                    ),
-                padding: 14.w,
-                size: 44.h,
-              ),
+              Semantics(
+                button: true,
+                label: 'Paste',
+                child: WnIconButton(
+                  iconPath: AssetsPaths.icPaste,
+                  onTap: () async => await ClipboardUtils.pasteWithToast(
+                    ref: ref,
+                    onPaste: (text) {
+                      _searchController.text = text;
+                    },
+                  ),
+                  padding: 14.w,
+                  size: 44.h,
+                ),
+              ),
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bb41afe and b1df11e.

📒 Files selected for processing (1)
  • lib/ui/contact_list/new_group_chat_sheet.dart (3 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.dart

📄 CodeRabbit inference engine (.cursor/rules/flutter.mdc)

**/*.dart: Always declare the type of each variable and function (parameters and return value). Avoid using 'any'. Create necessary types.
Don't leave blank lines within a function.
One export per file.
Use PascalCase for classes.
Use camelCase for variables, functions, and methods.
Use underscores_case for file and directory names.
Use UPPERCASE for environment variables. Avoid magic numbers and define constants.
Start each function with a verb.
Use verbs for boolean variables. Example: isLoading, hasError, canDelete, etc.
Use complete words instead of abbreviations and correct spelling, except for standard and well-known abbreviations (API, URL, i, j, err, ctx, req, res, next).
Write short functions with a single purpose. Less than 20 instructions.
Name functions with a verb and something else. If it returns a boolean, use isX or hasX, canX, etc. If it doesn't return anything, use executeX or saveX, etc.
Avoid nesting blocks by early checks and returns, or extraction to utility functions.
Use higher-order functions (map, filter, reduce, etc.) to avoid function nesting. Use arrow functions for simple functions (less than 3 instructions). Use named functions for non-simple functions.
Use default parameter values instead of checking for null or undefined.
Reduce function parameters using RO-RO: use an object to pass multiple parameters and to return results. Declare necessary types for input arguments and output.
Use a single level of abstraction in functions.
Don't abuse primitive types and encapsulate data in composite types.
Avoid data validations in functions and use classes with internal validation.
Prefer immutability for data. Use readonly for data that doesn't change. Use 'as const' for literals that don't change.
Declare interfaces to define contracts.
Write small classes with a single purpose. Less than 200 instructions, less than 10 public methods, less than 10 properties.
Use exceptions to handle errors you don't expect. If you catch an exception, it sh...

Files:

  • lib/ui/contact_list/new_group_chat_sheet.dart
🧠 Learnings (4)
📓 Common learnings
Learnt from: Quwaysim
PR: parres-hq/whitenoise_flutter#642
File: lib/ui/contact_list/new_chat_bottom_sheet.dart:324-336
Timestamp: 2025-09-16T07:24:07.453Z
Learning: In the whitenoise_flutter project, the user Quwaysim prefers to handle security improvements incrementally across different PRs rather than bundling them all together. Input trimming for search functionality was handled in PR #613, and private key security measures are planned for PR #505.
📚 Learning: 2025-09-16T07:24:07.453Z
Learnt from: Quwaysim
PR: parres-hq/whitenoise_flutter#642
File: lib/ui/contact_list/new_chat_bottom_sheet.dart:324-336
Timestamp: 2025-09-16T07:24:07.453Z
Learning: In the whitenoise_flutter project, the user Quwaysim prefers to handle security improvements incrementally across different PRs rather than bundling them all together. Input trimming for search functionality was handled in PR #613, and private key security measures are planned for PR #505.

Applied to files:

  • lib/ui/contact_list/new_group_chat_sheet.dart
📚 Learning: 2025-09-14T21:22:00.952Z
Learnt from: Quwaysim
PR: parres-hq/whitenoise_flutter#634
File: lib/config/providers/group_provider.dart:1130-1132
Timestamp: 2025-09-14T21:22:00.952Z
Learning: In the whitenoise_flutter codebase, the _updateGroupInfo method in GroupsNotifier performs optimistic updates that directly modify Group objects in the provider state (groups list and groupsMap). For non-DM groups, the display name comes from group.name, so updating the Group object directly is sufficient to reflect name changes in the UI without needing to refresh the separate display name cache.

Applied to files:

  • lib/ui/contact_list/new_group_chat_sheet.dart
📚 Learning: 2025-09-07T13:10:16.542Z
Learnt from: josefinalliende
PR: parres-hq/whitenoise_flutter#597
File: lib/config/providers/group_provider.dart:311-314
Timestamp: 2025-09-07T13:10:16.542Z
Learning: In the whitenoise_flutter codebase, the User class used in group_provider.dart (and similar contexts) is presentational only, not the actual user class from the Rust API. There are plans to remove this User class and replace it with UserProfileData, similar to the planned consolidation with ContactModel.

Applied to files:

  • lib/ui/contact_list/new_group_chat_sheet.dart
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Flutter CI
🔇 Additional comments (2)
lib/ui/contact_list/new_group_chat_sheet.dart (2)

11-11: LGTM: assets import is appropriate.

Aligns with new search/paste UI.


15-18: LGTM: centralized paste helper and UI widgets.

Good reuse of ClipboardUtils and WN UI components.

Copy link
Contributor

@josefinalliende josefinalliende left a comment

Choose a reason for hiding this comment

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

A tiny suggestion, but worked perfect for npubs splitted in groups of 5. 👍🏻 Approved! ✅

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
lib/ui/contact_list/new_chat_bottom_sheet.dart (1)

581-606: Fix compile error: invalid EdgeInsets scaling extension usage.

const EdgeInsets.all(13).w won’t compile. Apply scaling to the numeric and drop const.

-        padding: const EdgeInsets.all(13).w,
+        padding: EdgeInsets.all(13.w),
🧹 Nitpick comments (5)
test/utils/clipboard_utils_test.dart (2)

298-353: Add a whitespace-only clipboard case.

Edge case: clipboard text containing only whitespace (e.g., " \n\t ") should likely be treated as empty/info toast. Add a test to lock this in (or clarify expected behavior).


355-387: Parity nit: also assert autoDismiss for null clipboard.

For consistency with the “empty clipboard” group, assert autoDismiss == true here as well.

lib/ui/contact_list/new_chat_bottom_sheet.dart (3)

36-36: Localize the new sheet title.

Replace the hardcoded 'Start New Chat' with AppLocalizations (or the context.l10n extension) to comply with the project’s i18n guideline.


76-91: Make npub detection case‑insensitive and fix the misleading comment.

Current logic misses uppercase inputs like 'NPUB…'. Also, the comment mentions “hex‑like” but code doesn’t handle it. Either handle hex here or update the comment. Suggested minimal fix (case‑insensitive) + add explicit types per guidelines:

-    final originalText = _searchController.text;
-    String processedText = originalText;
-
-    // Only remove whitespace if it looks like a public key (starts with npub or is hex-like)
-    if (originalText.startsWith('npub')) {
+    final String originalText = _searchController.text;
+    String processedText = originalText;
+    // Remove whitespace for npub-like inputs (case-insensitive).
+    final String lower = originalText.toLowerCase();
+    if (lower.startsWith('npub')) {
       processedText = originalText.replaceAll(RegExp(r'\s+'), '');

354-399: Remove redundant async/await in paste onTap.

No need to mark onTap async just to immediately await. This also shortens the callback.

-            WnIconButton(
+            WnIconButton(
               iconPath: AssetsPaths.icPaste,
-              onTap:
-                  () async => await ClipboardUtils.pasteWithToast(
-                    ref: ref,
-                    onPaste: (text) {
-                      _searchController.text = text;
-                    },
-                  ),
+              onTap: () => ClipboardUtils.pasteWithToast(
+                ref: ref,
+                onPaste: (text) => _searchController.text = text,
+              ),
               padding: 14.w,
               size: 44.h,
             ),
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b1df11e and 512d077.

📒 Files selected for processing (3)
  • lib/ui/contact_list/new_chat_bottom_sheet.dart (6 hunks)
  • lib/ui/contact_list/new_group_chat_sheet.dart (3 hunks)
  • test/utils/clipboard_utils_test.dart (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/ui/contact_list/new_group_chat_sheet.dart
🧰 Additional context used
📓 Path-based instructions (2)
**/*.dart

📄 CodeRabbit inference engine (.cursor/rules/flutter.mdc)

**/*.dart: Always declare the type of each variable and function (parameters and return value). Avoid using 'any'. Create necessary types.
Don't leave blank lines within a function.
One export per file.
Use PascalCase for classes.
Use camelCase for variables, functions, and methods.
Use underscores_case for file and directory names.
Use UPPERCASE for environment variables. Avoid magic numbers and define constants.
Start each function with a verb.
Use verbs for boolean variables. Example: isLoading, hasError, canDelete, etc.
Use complete words instead of abbreviations and correct spelling, except for standard and well-known abbreviations (API, URL, i, j, err, ctx, req, res, next).
Write short functions with a single purpose. Less than 20 instructions.
Name functions with a verb and something else. If it returns a boolean, use isX or hasX, canX, etc. If it doesn't return anything, use executeX or saveX, etc.
Avoid nesting blocks by early checks and returns, or extraction to utility functions.
Use higher-order functions (map, filter, reduce, etc.) to avoid function nesting. Use arrow functions for simple functions (less than 3 instructions). Use named functions for non-simple functions.
Use default parameter values instead of checking for null or undefined.
Reduce function parameters using RO-RO: use an object to pass multiple parameters and to return results. Declare necessary types for input arguments and output.
Use a single level of abstraction in functions.
Don't abuse primitive types and encapsulate data in composite types.
Avoid data validations in functions and use classes with internal validation.
Prefer immutability for data. Use readonly for data that doesn't change. Use 'as const' for literals that don't change.
Declare interfaces to define contracts.
Write small classes with a single purpose. Less than 200 instructions, less than 10 public methods, less than 10 properties.
Use exceptions to handle errors you don't expect. If you catch an exception, it sh...

Files:

  • test/utils/clipboard_utils_test.dart
  • lib/ui/contact_list/new_chat_bottom_sheet.dart
**/*_test.dart

📄 CodeRabbit inference engine (.cursor/rules/flutter.mdc)

**/*_test.dart: Follow the Arrange-Act-Assert convention for tests.
Name test variables clearly. Follow the convention: inputX, mockX, actualX, expectedX, etc.
Write unit tests for each public function. Use test doubles to simulate dependencies, except for third-party dependencies that are not expensive to execute.
Write acceptance tests for each module. Follow the Given-When-Then convention.
Use the standard widget testing for Flutter.

Files:

  • test/utils/clipboard_utils_test.dart
🧠 Learnings (7)
📓 Common learnings
Learnt from: Quwaysim
PR: parres-hq/whitenoise_flutter#642
File: lib/ui/contact_list/new_chat_bottom_sheet.dart:324-336
Timestamp: 2025-09-16T07:24:07.453Z
Learning: In the whitenoise_flutter project, the user Quwaysim prefers to handle security improvements incrementally across different PRs rather than bundling them all together. Input trimming for search functionality was handled in PR #613, and private key security measures are planned for PR #505.
📚 Learning: 2025-09-16T07:24:07.453Z
Learnt from: Quwaysim
PR: parres-hq/whitenoise_flutter#642
File: lib/ui/contact_list/new_chat_bottom_sheet.dart:324-336
Timestamp: 2025-09-16T07:24:07.453Z
Learning: In the whitenoise_flutter project, the user Quwaysim prefers to handle security improvements incrementally across different PRs rather than bundling them all together. Input trimming for search functionality was handled in PR #613, and private key security measures are planned for PR #505.

Applied to files:

  • lib/ui/contact_list/new_chat_bottom_sheet.dart
📚 Learning: 2025-09-07T02:08:09.199Z
Learnt from: josefinalliende
PR: parres-hq/whitenoise_flutter#594
File: lib/domain/models/contact_model.dart:36-41
Timestamp: 2025-09-07T02:08:09.199Z
Learning: The issue of ContactModel.publicKey potentially being set to an empty string when pubkey.toNpub() conversion fails (causing collision/lookup issues) is being addressed in PR #597 in the whitenoise_flutter codebase.

Applied to files:

  • lib/ui/contact_list/new_chat_bottom_sheet.dart
📚 Learning: 2025-09-05T00:08:34.509Z
Learnt from: josefinalliende
PR: parres-hq/whitenoise_flutter#594
File: lib/config/providers/active_account_provider.dart:140-146
Timestamp: 2025-09-05T00:08:34.509Z
Learning: josefinalliende prefers centralizing validation logic (like trimming whitespace) in providers rather than handling it defensively at every consumer site. This approach was applied to activePubkeyProvider in the whitenoise_flutter codebase.

Applied to files:

  • lib/ui/contact_list/new_chat_bottom_sheet.dart
📚 Learning: 2025-09-07T02:15:31.931Z
Learnt from: josefinalliende
PR: parres-hq/whitenoise_flutter#594
File: lib/src/rust/api/utils.dart:12-16
Timestamp: 2025-09-07T02:15:31.931Z
Learning: The lingering PublicKey references in lib/config/providers/auth_provider.dart, lib/config/providers/group_provider.dart, and rust_builder/cargokit/build_tool/lib/src/options.dart identified during the utils.dart API cleanup were fixed in PR #597 in the whitenoise_flutter codebase.

Applied to files:

  • lib/ui/contact_list/new_chat_bottom_sheet.dart
📚 Learning: 2025-08-23T11:02:28.308Z
Learnt from: Quwaysim
PR: parres-hq/whitenoise_flutter#527
File: lib/ui/core/ui/wn_avatar.dart:1-6
Timestamp: 2025-08-23T11:02:28.308Z
Learning: In the whitenoise_flutter codebase, flutter_screenutil is re-exported through lib/ui/core/themes/src/app_theme.dart, so files that import app_theme.dart do not need to directly import flutter_screenutil to use .w, .h, .sp extensions.

Applied to files:

  • lib/ui/contact_list/new_chat_bottom_sheet.dart
📚 Learning: 2025-09-16T06:28:24.611Z
Learnt from: Quwaysim
PR: parres-hq/whitenoise_flutter#640
File: lib/ui/chat/services/chat_dialog_service.dart:21-25
Timestamp: 2025-09-16T06:28:24.611Z
Learning: In lib/ui/core/ui/wn_bottom_sheet.dart, the WnBottomSheet.show method has barrierDismissible parameter that defaults to false, not true.

Applied to files:

  • lib/ui/contact_list/new_chat_bottom_sheet.dart
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Flutter CI
🔇 Additional comments (5)
test/utils/clipboard_utils_test.dart (4)

216-233: Good test helper for mocking Clipboard.getData.

Scoped handler is clear and contained to this group. Nice.


235-246: Solid setup/teardown hygiene.

Resetting the platform handler in tearDown prevents cross-test leakage.


247-263: Happy path covered: callback invoked and success toast asserted.

This validates both behavior and user feedback.


389-450: Error path coverage looks complete.

Verifies no callback, error type, auto-dismiss, and default/custom messages.

lib/ui/contact_list/new_chat_bottom_sheet.dart (1)

21-25: Right abstraction: use ClipboardUtils and WnIconButton.

Importing and reusing shared utilities/components keeps behavior consistent across screens.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (2)
lib/ui/contact_list/new_group_chat_sheet.dart (2)

70-90: Don’t mutate the controller on change; use raw trimmed text for query.

Mutating _searchController.value mid-typing is jarring and was flagged previously. Sanitize only for key matching (and on paste), not while the user types. Also remove intra-function blank lines per guidelines.

Apply this diff:

   void _onSearchChanged() {
-    final originalText = _searchController.text;
-    String processedText = originalText;
-
-    // Only remove whitespace if it looks like a public key (starts with npub or is hex-like)
-    if (originalText.startsWith('npub')) {
-      processedText = originalText.replaceAll(RegExp(r'\s+'), '');
-
-      // Update the controller if we removed whitespace
-      if (originalText != processedText) {
-        _searchController.value = _searchController.value.copyWith(
-          text: processedText,
-          selection: TextSelection.collapsed(offset: processedText.length),
-        );
-      }
-    }
-
     setState(() {
-      _searchQuery = processedText;
+      final String text = _searchController.text;
+      _searchQuery = text.trim();
     });
   }

146-159: Use sanitized variant only for key matching; keep name/NIP‑05 matching unchanged.

This fixes npub-with-spaces search without rewriting the input and aligns with issue #613.

Apply this diff:

-    return contactsWithoutCreator
-        .where(
-          (contact) =>
-              contact.displayName.toLowerCase().contains(
-                _searchQuery.toLowerCase(),
-              ) ||
-              (contact.nip05?.toLowerCase().contains(
-                    _searchQuery.toLowerCase(),
-                  ) ??
-                  false) ||
-              contact.publicKey.toLowerCase().contains(
-                _searchQuery.toLowerCase(),
-              ),
-        )
-        .toList();
+    final String q = _searchQuery.toLowerCase();
+    final String keyQ = _searchQuery.replaceAll(RegExp(r'\s+'), '').toLowerCase();
+    return contactsWithoutCreator
+        .where((contact) =>
+            contact.displayName.toLowerCase().contains(q) ||
+            (contact.nip05?.toLowerCase().contains(q) ?? false) ||
+            contact.publicKey.toLowerCase().contains(keyQ))
+        .toList();
🧹 Nitpick comments (2)
lib/ui/contact_list/new_group_chat_sheet.dart (2)

177-209: Sanitize only on paste; avoid redundant async/await.

Normalize pasted npubs by stripping whitespace, but don’t sanitize during typing. Also drop async => await.

Apply this diff:

-              WnIconButton(
+              WnIconButton(
                 iconPath: AssetsPaths.icPaste,
-                onTap:
-                    () async => await ClipboardUtils.pasteWithToast(
+                onTap: () => ClipboardUtils.pasteWithToast(
                       ref: ref,
-                      onPaste: (text) {
-                        _searchController.text = text;
-                      },
+                      onPaste: (String text) {
+                        final String v = text.trimLeft();
+                        final String normalized =
+                            v.startsWith('npub') ? v.replaceAll(RegExp(r'\s+'), '') : v;
+                        _searchController.text = normalized;
+                      },
                     ),
                 padding: 14.w,
                 size: 44.h,
               ),

197-209: Add accessibility label to paste button.

Ensure screen readers can discover the control.

If WnIconButton supports a11y labels/tooltips, set one (e.g., “Paste”). Otherwise, wrap with Semantics(label: 'Paste', button: true, child: ...).

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 512d077 and 36d25b8.

📒 Files selected for processing (1)
  • lib/ui/contact_list/new_group_chat_sheet.dart (3 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.dart

📄 CodeRabbit inference engine (.cursor/rules/flutter.mdc)

**/*.dart: Always declare the type of each variable and function (parameters and return value). Avoid using 'any'. Create necessary types.
Don't leave blank lines within a function.
One export per file.
Use PascalCase for classes.
Use camelCase for variables, functions, and methods.
Use underscores_case for file and directory names.
Use UPPERCASE for environment variables. Avoid magic numbers and define constants.
Start each function with a verb.
Use verbs for boolean variables. Example: isLoading, hasError, canDelete, etc.
Use complete words instead of abbreviations and correct spelling, except for standard and well-known abbreviations (API, URL, i, j, err, ctx, req, res, next).
Write short functions with a single purpose. Less than 20 instructions.
Name functions with a verb and something else. If it returns a boolean, use isX or hasX, canX, etc. If it doesn't return anything, use executeX or saveX, etc.
Avoid nesting blocks by early checks and returns, or extraction to utility functions.
Use higher-order functions (map, filter, reduce, etc.) to avoid function nesting. Use arrow functions for simple functions (less than 3 instructions). Use named functions for non-simple functions.
Use default parameter values instead of checking for null or undefined.
Reduce function parameters using RO-RO: use an object to pass multiple parameters and to return results. Declare necessary types for input arguments and output.
Use a single level of abstraction in functions.
Don't abuse primitive types and encapsulate data in composite types.
Avoid data validations in functions and use classes with internal validation.
Prefer immutability for data. Use readonly for data that doesn't change. Use 'as const' for literals that don't change.
Declare interfaces to define contracts.
Write small classes with a single purpose. Less than 200 instructions, less than 10 public methods, less than 10 properties.
Use exceptions to handle errors you don't expect. If you catch an exception, it sh...

Files:

  • lib/ui/contact_list/new_group_chat_sheet.dart
🧠 Learnings (4)
📓 Common learnings
Learnt from: Quwaysim
PR: parres-hq/whitenoise_flutter#642
File: lib/ui/contact_list/new_chat_bottom_sheet.dart:324-336
Timestamp: 2025-09-16T07:24:07.489Z
Learning: In the whitenoise_flutter project, the user Quwaysim prefers to handle security improvements incrementally across different PRs rather than bundling them all together. Input trimming for search functionality was handled in PR #613, and private key security measures are planned for PR #505.
📚 Learning: 2025-09-16T07:24:07.489Z
Learnt from: Quwaysim
PR: parres-hq/whitenoise_flutter#642
File: lib/ui/contact_list/new_chat_bottom_sheet.dart:324-336
Timestamp: 2025-09-16T07:24:07.489Z
Learning: In the whitenoise_flutter project, the user Quwaysim prefers to handle security improvements incrementally across different PRs rather than bundling them all together. Input trimming for search functionality was handled in PR #613, and private key security measures are planned for PR #505.

Applied to files:

  • lib/ui/contact_list/new_group_chat_sheet.dart
📚 Learning: 2025-09-14T21:22:00.962Z
Learnt from: Quwaysim
PR: parres-hq/whitenoise_flutter#634
File: lib/config/providers/group_provider.dart:1130-1132
Timestamp: 2025-09-14T21:22:00.962Z
Learning: In the whitenoise_flutter codebase, the _updateGroupInfo method in GroupsNotifier performs optimistic updates that directly modify Group objects in the provider state (groups list and groupsMap). For non-DM groups, the display name comes from group.name, so updating the Group object directly is sufficient to reflect name changes in the UI without needing to refresh the separate display name cache.

Applied to files:

  • lib/ui/contact_list/new_group_chat_sheet.dart
📚 Learning: 2025-09-07T13:10:16.542Z
Learnt from: josefinalliende
PR: parres-hq/whitenoise_flutter#597
File: lib/config/providers/group_provider.dart:311-314
Timestamp: 2025-09-07T13:10:16.542Z
Learning: In the whitenoise_flutter codebase, the User class used in group_provider.dart (and similar contexts) is presentational only, not the actual user class from the Rust API. There are plans to remove this User class and replace it with UserProfileData, similar to the planned consolidation with ContactModel.

Applied to files:

  • lib/ui/contact_list/new_group_chat_sheet.dart
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Flutter CI
🔇 Additional comments (2)
lib/ui/contact_list/new_group_chat_sheet.dart (2)

11-18: LGTM on imports.

New UI and clipboard utilities are used below and keep concerns well-scoped.


182-183: Localize hardcoded hint text

Search returned no matches for the literal 'Search contact or public key...'; confirm lib/ui/contact_list/new_group_chat_sheet.dart (lines 182–183) contains this hardcoded hint and replace it with AppLocalizations.of(context)!.searchContactOrKeyHint.

  • Also localize the sheet title, empty/error strings, and buttons.

Copy link
Contributor

@josefinalliende josefinalliende left a comment

Choose a reason for hiding this comment

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

✅ Tried it locally with both npub formats (grouped in 4 chars and in 5) and works perfect for me

@Quwaysim Quwaysim merged commit d0e9414 into master Sep 17, 2025
2 checks passed
@Quwaysim Quwaysim deleted the 477-past-npub-icon-button-in-profile-search branch September 17, 2025 14:17
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.

Auto-remove whitespaces in pasted npubs Past Npub Icon Button in profile search

4 participants