Skip to content

Conversation

@josefinalliende
Copy link
Contributor

@josefinalliende josefinalliende commented Oct 3, 2025

Description

We want to stop using the contact word, as we don't really have contacts but users we follow (follows) and user we don't follow (just users). We had already removed the contact word from multiple places, in particular by replacing the contact provider by follows provider. But ContactModel was still present and the contact word was used in lots of parts as a synonym for user.

This PR:

  • 🧹 Renames contact word everywhere
    • Renames the ContactModel class to UserProfile
    • Renames /contacts route for /users
    • Renames userProfileDataProvider to useProfileProvider to be consistent with the new naming
    • Renames the contact_list directory and widgets to user_profile_list. Thar dir still has lots of widgets that are not really related to contact/user/follows list but I didn't move them to other folders cause we sill have this discussion pending.. Docs: add architecture documentation with clean feature-first structure #694
    • Updates locales files to replace contact word in each language
    • 🛠️ Fixes inconsistency in welcome text button, that said to tap a text that wasn't there. Now the text matches the text of the button
  • 🗑️ Deletes a .md file in local_research/ folder that had mentions to contacts and seems to be outdated, looks like a file that someone made when wanting to implement a feature with AI and then uploaded it by mistake 😅
  • 🛠️ Fixes coderabbit comment 🐰 related to trasnform to hex before checking if a user is in a group or not in the add to group screen
Before After

Why UserProfile ?
There is already a User type that comes from rust side an a User model in flutter side (which is confusing), I couldn't rename the ContactModel to User, so I decided to rename it to UserProfile. We had talked in the issue about UserProfileData but I think that the Data does not provide really any useful info about wha the model is about.

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

    • Follow/unfollow toggle added to member actions.
    • New user-profile fetching/provider powering profile screens.
  • Refactor

    • App-wide rename from “Contacts” to “Users” (routes, headers, screens, tiles, APIs).
  • UI

    • Search, user list and detail screens updated; removed swipe-to-delete/remove-contact action.
    • Chat bubble colors standardized.
  • Localization

    • Updated translations and keys to use user-centric terminology.
  • Chores

    • Removed outdated local research doc and a deprecated fallback message.

@josefinalliende josefinalliende linked an issue Oct 3, 2025 that may be closed by this pull request
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 3, 2025

Walkthrough

Renames ContactModel to UserProfile across models, providers, UI, routing, tests, and locales; removes user_profile_data_provider and adds user_profile_provider with a Notifier API; updates routes (contacts → users), theme keys (contact* → other*), group creation flows, and related tests; deletes a local doc and one error helper.

Changes

Cohort / File(s) Summary
Model rename: ContactModel → UserProfile
lib/domain/models/user_profile.dart, lib/domain/services/dm_chat_service.dart
Public class renamed; factories/equality updated; usages switched to UserProfile.
Provider replacement: remove old, add new
lib/config/providers/user_profile_data_provider.dart, lib/config/providers/user_profile_provider.dart
Deletes UserProfileDataNotifier/provider; adds UserProfileNotifier, getUserProfile(pubkey), and userProfileProvider.
Group messages / mapping updates
lib/config/providers/group_messages_provider.dart, lib/config/providers/group_provider.dart
Mappings and helpers renamed from contacts → userProfiles; minor comment tweak.
Create-group provider & state retyped
lib/config/providers/create_group_provider.dart, lib/config/states/create_group_state.dart, lib/config/states/create_group_state.freezed.dart
Filters, methods, and state fields converted to List<UserProfile>; API names updated.
Routing and route constants renamed
lib/routing/router_provider.dart, lib/routing/routes.dart
Routes/helpers and params renamed: contacts → users; QR and add-to-group paths renamed; AddToGroupScreen param now userNpub.
Add-to-group / create dialogs adjusted
lib/ui/chat/chat_management/add_to_group_screen.dart, lib/ui/chat/chat_management/widgets/create_group_dialog.dart
Constructor/fields and preselected lists use userNpub / UserProfile; provider usage updated.
Chat header/info renames
lib/ui/chat/chat_screen.dart, lib/ui/chat/widgets/chat_header_widget.dart, lib/ui/chat/widgets/user_profile_info.dart
ContactInfoUserProfileInfo; ChatContactHeaderChatUserHeader; call sites updated.
Invite screen & provider changes
lib/ui/chat/invite/chat_invite_screen.dart
Uses userProfileProvider and UserProfileInfo; bindings renamed (e.g., welcomerUser).
Member actions: follow toggle
lib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dart, lib/ui/chat/chat_info/widgets/member_action_buttons.dart
Replaces AddToContactButton with FollowToggleButton; widget/state renamed.
Theme key renames & message bubble colors
lib/ui/core/themes/src/colors.dart, .../colors_light.dart, .../colors_dark.dart, .../light/extensions.dart, lib/ui/chat/widgets/message_widget.dart
Theme fields contactChatBubble*otherChatBubble*; message bubble color refs updated.
Settings/profile flows updated
lib/ui/settings/general_settings_screen.dart, lib/ui/settings/profile/*.dart, lib/ui/settings/widgets/active_account_tile.dart
Switches to UserProfile model/provider across account switching, QR scan, and profile lists/tiles.
User-profile list module migration
lib/ui/user_profile_list/* (many files)
Replaces contact_list imports/usages with user_profile_list equivalents; tiles/cards renamed and retyped to UserProfile.
New chat & group selection sheets
lib/ui/user_profile_list/new_chat_bottom_sheet.dart, lib/ui/user_profile_list/new_group_chat_sheet.dart, lib/ui/user_profile_list/group_chat_details_sheet.dart
Flows retyped to UserProfile; selection, filtering, and final sheet usage updated.
Start/share invite bottom sheets
lib/ui/user_profile_list/start_chat_bottom_sheet.dart, lib/ui/user_profile_list/share_invite_bottom_sheet.dart, lib/ui/user_profile_list/widgets/share_invite_callout.dart
Public APIs and constructors now accept UserProfile; UI bindings updated.
UserProfile tiles/cards & widgets
lib/ui/user_profile_list/widgets/user_profile_tile.dart, lib/ui/user_profile_list/widgets/user_profile_card.dart
ContactListTileUserProfileTile; UserProfile widget → UserProfileCard; fields and keys updated; dismissible removed.
Tests updated to new types/providers
test/config/providers/*, test/ui/contact_list/*test/ui/user_profile_list/*
Tests switched from ContactModel/userProfileDataProvider to UserProfile/userProfileProvider; mocks and fixtures updated.
Utilities & docs removed
lib/utils/error_handling.dart, local-research/go_router_implementation_plan.md
Removes getContactLoadFallbackMessage() and deletes the local-research doc.
Localization updates (contacts → users)
lib/locales/*.json (en, de, es, fr, it, pt, ru, tr)
Locale keys/strings renamed to user-centric terms (e.g., searchContactPlaceholdersearchUserPlaceholder, {contactName}{userName}); some keys removed/added.

Sequence Diagram(s)

sequenceDiagram
  participant UI as UI Widget
  participant RP as userProfileProvider (Notifier)
  participant API as wn_users_api
  participant M as UserProfile.fromMetadata

  UI->>RP: getUserProfile(pubkey)
  RP->>API: getUser(pubkey)
  API-->>RP: User { metadata }
  RP->>M: fromMetadata(pubkey, metadata)
  M-->>RP: UserProfile
  RP-->>UI: UserProfile
  Note over RP,API: Replaces earlier user_profile_data_provider flow
Loading
sequenceDiagram
  participant Sheet as StartChatBottomSheet
  participant GK as keyPackageService
  participant G as createGroupProvider
  participant F as followProvider

  Sheet->>GK: userHasKeyPackage(userProfile.publicKey)
  alt Has key package
    Sheet->>G: createGroup([userProfile.publicKey])
    G-->>Sheet: Group created
  else No key package
    Sheet->>F: follow(userProfile.publicKey)
    Sheet-->>Sheet: Show invite/share options
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • erskingardner
  • untreu2
  • Quwaysim

Poem

In burrows of code I wiggle and weave,
Contacts shed their coats — new profiles achieve.
Routes hop to /users, colors shift anew,
Follow toggles twitch, locales sing too.
A rabbit thumps once — tests green for the crew! 🐇✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title succinctly describes the primary change of replacing “contact” terminology with user profile terminology as a refactor across the codebase and directly aligns with the PR’s objectives to rename ContactModel to UserProfile and update related routes and locale keys. It is clear and concise without extraneous detail or vague language. Therefore, it accurately summarizes the main intent of the changeset.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/remove-contact-word

📜 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 e1214cd and c1e33ed.

⛔ Files ignored due to path filters (1)
  • ios/Podfile.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • CHANGELOG.md (1 hunks)
  • lib/ui/chat/chat_screen.dart (3 hunks)
  • lib/ui/user_profile_list/chat_list_screen.dart (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/ui/user_profile_list/chat_list_screen.dart
🧰 Additional context used
📓 Path-based instructions (3)
**/*.dart

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

**/*.dart: Always declare the type of each variable and function (parameters and return value)
Avoid using dynamic and Object without justification
Create necessary types instead of overusing primitives or dynamic
One export per file
Use PascalCase for classes
Use camelCase for variables, functions, and methods
Avoid magic numbers and define constants
Start each function name with a verb
Use verbs for boolean variables (e.g., isLoading, hasError, canDelete)
Write short functions with a single purpose (under ~20 instructions)
Name functions with a verb plus context; for booleans use isX/hasX/canX; for void use executeX/saveX
Avoid deep nesting via early returns and extraction to utility functions
Use higher-order functions (map, where/filter, reduce) to avoid nesting
Use arrow functions for simple functions (under ~3 statements); use named functions otherwise
Use default parameter values instead of null checks
Reduce function parameters using RO-RO: pass/return parameter objects with declared types
Maintain a single level of abstraction within functions
Encapsulate data in composite types; avoid overusing primitives
Prefer validating data within classes rather than in functions
Prefer immutability; use final for runtime constants and const for compile-time constants
Use const constructors and const literals where possible
Follow SOLID principles
Prefer composition over inheritance
Declare interfaces (abstract classes) to define contracts
Write small classes with a single purpose (under ~200 instructions, <10 public methods, <10 properties)
Use exceptions for unexpected errors
Only catch exceptions to fix expected problems or add context; otherwise use a global handler

Files:

  • lib/ui/chat/chat_screen.dart
lib/**/*.dart

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

lib/**/*.dart: Use flutter_rust_bridge to access core app functionality
Use Riverpod for state management; prefer StreamProviders for Rust API streams; use keepAlive if needed
Use freezed to model/manage UI states
Controllers should expose methods as inputs and update UI state that drives the UI
Use AutoRoute for navigation and use extras to pass data between pages
Use Dart extensions to manage reusable code
Use ThemeData to manage themes
Use AppLocalizations for translations
Use constants to manage constant values
Avoid deeply nested widget trees; aim for a flatter widget structure for performance and readability
Break down large widgets into smaller, focused, reusable components
Keep the widget tree shallow to simplify state management and data flow
Utilize const constructors and const widgets wherever possible to reduce rebuilds

Files:

  • lib/ui/chat/chat_screen.dart
**/*.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
⏰ 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 (4)
lib/ui/chat/chat_screen.dart (4)

24-24: LGTM! Import updated consistently with the refactoring.

The import statement correctly references the renamed widget file.


374-374: LGTM! Proper const usage for loading state.

The const constructor optimizes widget rebuilds during the loading state.


377-388: LGTM! Proper null handling and conditional logic.

The widget correctly handles different group types with appropriate null-safe operators and fallback values.


400-400: LGTM! Widget rename completed correctly.

The ChatUserHeader widget usage is consistent with the broader refactoring effort.


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.

@josefinalliende josefinalliende force-pushed the refactor/remove-contact-word branch from 6ee52d5 to f791d93 Compare October 3, 2025 16:54
@josefinalliende josefinalliende marked this pull request as ready for review October 3, 2025 16:55
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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
lib/ui/user_profile_list/start_chat_bottom_sheet.dart (1)

86-95: Fix indefinite loading when no active account

Early return leaves _isLoadingKeyPackage true. Reset flags before returning.

   final activeAccountState = await ref.read(activeAccountProvider.future);
   final activeAccount = activeAccountState.account;
   if (activeAccount == null) {
-    ref.showErrorToast('No active account found');
-    return;
+    if (mounted) {
+      setState(() {
+        _isLoadingKeyPackage = false;
+        _isLoadingKeyPackageError = true;
+      });
+    }
+    ref.showErrorToast('No active account found');
+    return;
   }
lib/ui/settings/profile/switch_profile_bottom_sheet.dart (1)

134-141: Normalize active pubkey to hex before comparisons.
_getActivePubkeyHex keeps the pubkey exactly as stored, but the active account can be persisted as npub while _isActiveAccount and the sort path compare against hex-formatted keys. When the active key is npub and the cached list is hex, the active profile never highlights or bubbles to the top. Convert the active key to hex (falling back to the original if conversion fails) before storing it.
Based on learnings

   Future<void> _getActivePubkeyHex() async {
-    final activeAccountPubkey = ref.read(activePubkeyProvider) ?? '';
-    if (activeAccountPubkey.isNotEmpty) {
-      setState(() {
-        _activeAccountHex = activeAccountPubkey;
-      });
-    }
+    final String? activeAccountPubkey = ref.read(activePubkeyProvider);
+    if (activeAccountPubkey == null || activeAccountPubkey.isEmpty) return;
+
+    final String? activeAccountHex =
+        PubkeyFormatter(pubkey: activeAccountPubkey).toHex();
+
+    setState(() {
+      _activeAccountHex = activeAccountHex ?? activeAccountPubkey;
+    });
   }
🧹 Nitpick comments (6)
lib/ui/chat/invite/chat_invite_screen.dart (3)

8-12: Type the FutureBuilder and handle errors

Avoid dynamic. Add generic type and minimal error handling; import the model.

@@
-import 'package:whitenoise/config/providers/user_profile_provider.dart';
+import 'package:whitenoise/config/providers/user_profile_provider.dart';
+import 'package:whitenoise/domain/models/user_profile.dart';
@@
-    return FutureBuilder(
-      future: userProfileNotifier.getUserProfile(welcome.welcomer),
+    return FutureBuilder<UserProfile>(
+      future: userProfileNotifier.getUserProfile(welcome.welcomer),
       builder: (context, snapshot) {
-        final welcomerUser = snapshot.data;
+        if (snapshot.hasError) {
+          // Fallback UI; keep minimal to avoid flicker
+        }
+        final UserProfile? welcomerUser = snapshot.data;
         final welcomerName = welcomerUser?.displayName ?? 'Unknown User';
         final welcomerImageUrl = welcomerUser?.imagePath ?? '';
@@
-              Text(
-                welcomerUser?.nip05 ?? '',
+              Text(
+                welcomerUser?.nip05 ?? '',

Also applies to: 244-252, 275-276


329-350: Also type the AppBar FutureBuilder

Same rationale as above; add generic and explicit type.

-    return FutureBuilder(
-      future: userProfileNotifier.getUserProfile(welcome.welcomer),
+    return FutureBuilder<UserProfile>(
+      future: userProfileNotifier.getUserProfile(welcome.welcomer),
       builder: (context, snapshot) {
         final isLoading = snapshot.connectionState == ConnectionState.waiting;
@@
-        final welcomerUser = snapshot.data;
-        final welcomerName = welcomerUser?.displayName ?? 'Unknown User';
-        final welcomerImageUrl = welcomerUser?.imagePath ?? '';
+        final UserProfile? welcomerUser = snapshot.data;
+        final String welcomerName = welcomerUser?.displayName ?? 'Unknown User';
+        final String welcomerImageUrl = welcomerUser?.imagePath ?? '';

250-251: Localize user-facing strings

'Unknown User' and the loading widget should use AppLocalizations per guidelines.

Also applies to: 275-276, 336-338, 345-347

lib/ui/user_profile_list/start_chat_bottom_sheet.dart (1)

95-98: Normalize key before userHasKeyPackage call

API likely expects hex. Normalize for consistency with group creation.

-      final userHasKeyPackage = await usersApi.userHasKeyPackage(
-        pubkey: widget.userProfile.publicKey,
-      );
+      final String pubkeyHex =
+          PubkeyFormatter(pubkey: widget.userProfile.publicKey).toHex() ?? widget.userProfile.publicKey;
+      final bool userHasKeyPackage = await usersApi.userHasKeyPackage(pubkey: pubkeyHex);
lib/ui/chat/chat_management/add_to_group_screen.dart (2)

144-173: Ensure userProfileToAdd is non-null and typed

It’s always assigned in try/catch, but make it explicit to satisfy analyzers and readability.

-          UserProfile? userProfileToAdd;
+          UserProfile userProfileToAdd;
@@
-              userProfileToAdd = await userProfileNotifier.getUserProfile(widget.userNpub);
+              userProfileToAdd = await userProfileNotifier.getUserProfile(widget.userNpub);
@@
-            userProfileToAdd = UserProfile(
+            userProfileToAdd = UserProfile(
               displayName: 'Unknown User',
               publicKey: widget.userNpub,
             );
@@
-            preSelectedUserProfiles: [userProfileToAdd],
+            preSelectedUserProfiles: [userProfileToAdd],

37-37: Use Set for selected group IDs

Avoid duplicates and improve contains/remove complexity.

-  final List<String> _groupsToAddUserTo = [];
+  final Set<String> _groupsToAddUserTo = <String>{};
@@
-                      value: _groupsToAddUserTo.contains(group.mlsGroupId) || isUserInGroup,
+                      value: _groupsToAddUserTo.contains(group.mlsGroupId) || isUserInGroup,
@@
-                          if (value == true) {
-                            _groupsToAddUserTo.add(group.mlsGroupId);
-                          } else {
-                            _groupsToAddUserTo.remove(group.mlsGroupId);
-                          }
+                          if (value == true) {
+                            _groupsToAddUserTo.add(group.mlsGroupId);
+                          } else {
+                            _groupsToAddUserTo.remove(group.mlsGroupId);
+                          }

Also applies to: 269-276

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8c399c4 and f791d93.

📒 Files selected for processing (50)
  • CHANGELOG.md (1 hunks)
  • lib/config/providers/group_messages_provider.dart (2 hunks)
  • lib/config/providers/group_provider.dart (1 hunks)
  • lib/config/providers/user_profile_data_provider.dart (0 hunks)
  • lib/config/providers/user_profile_provider.dart (1 hunks)
  • lib/domain/models/user_profile.dart (5 hunks)
  • lib/domain/services/dm_chat_service.dart (2 hunks)
  • lib/routing/router_provider.dart (4 hunks)
  • lib/routing/routes.dart (2 hunks)
  • lib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dart (2 hunks)
  • lib/ui/chat/chat_info/widgets/member_action_buttons.dart (1 hunks)
  • lib/ui/chat/chat_management/add_to_group_screen.dart (5 hunks)
  • lib/ui/chat/chat_management/widgets/create_group_dialog.dart (3 hunks)
  • lib/ui/chat/chat_screen.dart (3 hunks)
  • lib/ui/chat/invite/chat_invite_screen.dart (5 hunks)
  • lib/ui/chat/widgets/chat_header_widget.dart (1 hunks)
  • lib/ui/chat/widgets/message_widget.dart (8 hunks)
  • lib/ui/chat/widgets/user_profile_info.dart (1 hunks)
  • lib/ui/core/themes/src/colors.dart (7 hunks)
  • lib/ui/core/themes/src/colors_dark.dart (1 hunks)
  • lib/ui/core/themes/src/colors_light.dart (1 hunks)
  • lib/ui/core/themes/src/light/extensions.dart (1 hunks)
  • lib/ui/settings/general_settings_screen.dart (2 hunks)
  • lib/ui/settings/network/network_screen.dart (1 hunks)
  • lib/ui/settings/profile/share_profile_qr_scan_screen.dart (2 hunks)
  • lib/ui/settings/profile/switch_profile_bottom_sheet.dart (6 hunks)
  • lib/ui/settings/widgets/active_account_tile.dart (2 hunks)
  • lib/ui/user_profile_list/chat_list_screen.dart (1 hunks)
  • lib/ui/user_profile_list/group_chat_details_sheet.dart (6 hunks)
  • lib/ui/user_profile_list/new_chat_bottom_sheet.dart (17 hunks)
  • lib/ui/user_profile_list/new_group_chat_sheet.dart (8 hunks)
  • lib/ui/user_profile_list/services/welcome_notification_service.dart (1 hunks)
  • lib/ui/user_profile_list/share_invite_bottom_sheet.dart (4 hunks)
  • lib/ui/user_profile_list/start_chat_bottom_sheet.dart (10 hunks)
  • lib/ui/user_profile_list/widgets/chat_list_active_account_avatar.dart (3 hunks)
  • lib/ui/user_profile_list/widgets/chat_list_item_tile.dart (1 hunks)
  • lib/ui/user_profile_list/widgets/profile_ready_card.dart (1 hunks)
  • lib/ui/user_profile_list/widgets/share_invite_callout.dart (1 hunks)
  • lib/ui/user_profile_list/widgets/user_profile_card.dart (1 hunks)
  • lib/ui/user_profile_list/widgets/user_profile_tile.dart (7 hunks)
  • lib/ui/user_profile_list/widgets/welcome_tile.dart (2 hunks)
  • lib/utils/error_handling.dart (0 hunks)
  • local-research/go_router_implementation_plan.md (0 hunks)
  • test/config/providers/group_messages_provider_test.dart (7 hunks)
  • test/config/providers/user_profile_provider_test.dart (8 hunks)
  • test/ui/contact_list/services/welcome_notification_service_simple_test.dart (1 hunks)
  • test/ui/contact_list/share_invite_bottom_sheet_test.dart (6 hunks)
  • test/ui/contact_list/start_chat_bottom_sheet_test.dart (11 hunks)
  • test/ui/contact_list/widgets/share_invite_callout_test.dart (3 hunks)
  • test/ui/contact_list/widgets/user_profile_test.dart (6 hunks)
💤 Files with no reviewable changes (3)
  • lib/utils/error_handling.dart
  • lib/config/providers/user_profile_data_provider.dart
  • local-research/go_router_implementation_plan.md
🧰 Additional context used
📓 Path-based instructions (3)
**/*.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/user_profile_list/services/welcome_notification_service.dart
  • lib/ui/chat/widgets/user_profile_info.dart
  • lib/config/providers/user_profile_provider.dart
  • lib/routing/router_provider.dart
  • test/ui/contact_list/share_invite_bottom_sheet_test.dart
  • lib/ui/user_profile_list/widgets/user_profile_card.dart
  • lib/ui/settings/network/network_screen.dart
  • lib/ui/chat/chat_screen.dart
  • lib/ui/user_profile_list/widgets/share_invite_callout.dart
  • lib/ui/core/themes/src/colors.dart
  • lib/domain/services/dm_chat_service.dart
  • lib/ui/core/themes/src/light/extensions.dart
  • test/ui/contact_list/services/welcome_notification_service_simple_test.dart
  • lib/ui/chat/chat_info/widgets/member_action_buttons.dart
  • lib/config/providers/group_messages_provider.dart
  • lib/ui/core/themes/src/colors_dark.dart
  • lib/ui/user_profile_list/widgets/welcome_tile.dart
  • lib/ui/settings/widgets/active_account_tile.dart
  • lib/ui/user_profile_list/start_chat_bottom_sheet.dart
  • lib/config/providers/group_provider.dart
  • lib/ui/user_profile_list/widgets/profile_ready_card.dart
  • lib/ui/chat/widgets/message_widget.dart
  • lib/ui/core/themes/src/colors_light.dart
  • lib/domain/models/user_profile.dart
  • lib/ui/chat/chat_management/widgets/create_group_dialog.dart
  • lib/ui/settings/profile/switch_profile_bottom_sheet.dart
  • lib/ui/user_profile_list/new_chat_bottom_sheet.dart
  • lib/ui/user_profile_list/group_chat_details_sheet.dart
  • lib/ui/user_profile_list/chat_list_screen.dart
  • lib/ui/chat/widgets/chat_header_widget.dart
  • test/config/providers/user_profile_provider_test.dart
  • lib/ui/settings/profile/share_profile_qr_scan_screen.dart
  • lib/ui/chat/invite/chat_invite_screen.dart
  • lib/ui/user_profile_list/widgets/chat_list_item_tile.dart
  • lib/routing/routes.dart
  • lib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dart
  • lib/ui/user_profile_list/share_invite_bottom_sheet.dart
  • test/ui/contact_list/widgets/user_profile_test.dart
  • lib/ui/user_profile_list/new_group_chat_sheet.dart
  • lib/ui/settings/general_settings_screen.dart
  • lib/ui/user_profile_list/widgets/chat_list_active_account_avatar.dart
  • test/ui/contact_list/start_chat_bottom_sheet_test.dart
  • lib/ui/user_profile_list/widgets/user_profile_tile.dart
  • test/ui/contact_list/widgets/share_invite_callout_test.dart
  • test/config/providers/group_messages_provider_test.dart
  • lib/ui/chat/chat_management/add_to_group_screen.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/ui/contact_list/share_invite_bottom_sheet_test.dart
  • test/ui/contact_list/services/welcome_notification_service_simple_test.dart
  • test/config/providers/user_profile_provider_test.dart
  • test/ui/contact_list/widgets/user_profile_test.dart
  • test/ui/contact_list/start_chat_bottom_sheet_test.dart
  • test/ui/contact_list/widgets/share_invite_callout_test.dart
  • test/config/providers/group_messages_provider_test.dart
🧠 Learnings (5)
📚 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/config/providers/user_profile_provider.dart
  • lib/ui/user_profile_list/widgets/share_invite_callout.dart
  • lib/domain/services/dm_chat_service.dart
  • lib/config/providers/group_messages_provider.dart
  • lib/ui/user_profile_list/widgets/welcome_tile.dart
  • lib/ui/settings/widgets/active_account_tile.dart
  • lib/ui/user_profile_list/start_chat_bottom_sheet.dart
  • lib/ui/user_profile_list/widgets/profile_ready_card.dart
  • lib/domain/models/user_profile.dart
  • lib/ui/chat/chat_management/widgets/create_group_dialog.dart
  • lib/ui/settings/profile/switch_profile_bottom_sheet.dart
  • lib/ui/user_profile_list/new_chat_bottom_sheet.dart
  • lib/ui/user_profile_list/group_chat_details_sheet.dart
  • lib/ui/chat/widgets/chat_header_widget.dart
  • test/config/providers/user_profile_provider_test.dart
  • lib/ui/chat/invite/chat_invite_screen.dart
  • test/ui/contact_list/widgets/user_profile_test.dart
  • lib/ui/user_profile_list/new_group_chat_sheet.dart
  • lib/ui/settings/general_settings_screen.dart
  • lib/ui/user_profile_list/widgets/chat_list_active_account_avatar.dart
  • test/ui/contact_list/start_chat_bottom_sheet_test.dart
  • lib/ui/user_profile_list/widgets/user_profile_tile.dart
  • test/config/providers/group_messages_provider_test.dart
  • lib/ui/chat/chat_management/add_to_group_screen.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/config/providers/group_messages_provider.dart
  • test/config/providers/group_messages_provider_test.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/user_profile_list/start_chat_bottom_sheet.dart
📚 Learning: 2025-08-12T11:21:53.640Z
Learnt from: josefinalliende
PR: parres-hq/whitenoise_flutter#455
File: lib/ui/settings/profile/switch_profile_bottom_sheet.dart:0-0
Timestamp: 2025-08-12T11:21:53.640Z
Learning: In the whitenoise_flutter codebase, ContactModel.publicKey can be stored in either npub format (from metadata cache) or hex format (from account storage). The activeAccountProvider may return either format depending on how the account was originally stored, so normalization to hex format is required when comparing with other hex-normalized keys in sorting logic.

Applied to files:

  • lib/domain/models/user_profile.dart
  • lib/ui/settings/profile/switch_profile_bottom_sheet.dart
  • lib/ui/user_profile_list/widgets/user_profile_tile.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/chat/chat_management/widgets/create_group_dialog.dart
  • lib/ui/user_profile_list/widgets/user_profile_tile.dart
🔇 Additional comments (37)
lib/ui/user_profile_list/widgets/chat_list_item_tile.dart (1)

18-19: LGTM! Import paths correctly updated.

The import paths have been properly updated from ui/contact_list/widgets/ to ui/user_profile_list/widgets/, aligning with the refactoring objective. Both imported widgets (MessageReadStatus and WelcomeTile) are used within the file.

lib/config/providers/group_provider.dart (1)

366-366: LGTM!

The comment update is accurate and consistent with the broader refactor replacing ContactModel with UserProfile. No logic changes.

CHANGELOG.md (1)

12-12: LGTM!

The changelog entry accurately documents the rename from "contact" to "user profile" throughout the codebase.

lib/ui/user_profile_list/services/welcome_notification_service.dart (1)

8-8: LGTM!

The import path update correctly reflects the refactor moving UI components from contact_list to user_profile_list.

lib/ui/user_profile_list/widgets/profile_ready_card.dart (1)

13-13: LGTM!

The import path update correctly reflects the refactor moving UI components to user_profile_list.

test/ui/contact_list/services/welcome_notification_service_simple_test.dart (1)

5-5: LGTM!

The import path update correctly reflects the service relocation to user_profile_list.

lib/ui/core/themes/src/light/extensions.dart (1)

32-34: LGTM!

The theme color field renames from contactChatBubble/contactChatBubbleText to otherChatBubble/otherChatBubbleText are consistent with the terminology shift from Contact to UserProfile.

lib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dart (1)

259-259: LGTM!

The replacement of AddToContactButton with AddToFollowsButton aligns with the terminology shift from contact to user profile/follows throughout the codebase.

Also applies to: 306-306

lib/ui/core/themes/src/colors_light.dart (1)

72-75: LGTM!

The color constant renames from contactChatBubble/contactChatBubbleText to otherChatBubble/otherChatBubbleText are consistent with the refactor to UserProfile terminology. Color values are preserved.

lib/ui/user_profile_list/widgets/user_profile_card.dart (1)

12-26: LGTM! Clean class rename.

The rename from UserProfile to UserProfileCard improves clarity and avoids confusion with the domain model UserProfile. The constructor update is correct and consistent.

lib/ui/user_profile_list/chat_list_screen.dart (1)

27-31: LGTM! Import paths correctly updated.

The import paths have been updated from contact_list to user_profile_list, aligning with the refactor objective. No logic changes are introduced.

lib/ui/chat/widgets/message_widget.dart (1)

47-47: LGTM! Theme color properties renamed consistently.

All references to contactChatBubble and contactChatBubbleText have been systematically replaced with otherChatBubble and otherChatBubbleText. The changes are consistent across the message bubble, reactions, and text styling.

Also applies to: 60-60, 133-133, 324-324, 337-337, 354-354, 368-368, 386-386

lib/domain/services/dm_chat_service.dart (1)

4-4: LGTM! Model migration correctly applied.

The service has been updated to use UserProfile.fromMetadata instead of ContactModel.fromMetadata. Field access patterns are consistent with the new domain model.

Also applies to: 21-28

lib/ui/chat/widgets/chat_header_widget.dart (1)

15-18: LGTM! Class rename is clean and consistent.

The rename from ChatContactHeader to ChatUserHeader aligns with the terminology shift from contact to user. No behavioral changes introduced.

lib/ui/settings/widgets/active_account_tile.dart (1)

6-6: LGTM! Widget and model types updated consistently.

All references have been updated from ContactModel/ContactListTile to UserProfile/UserProfileTile. The changes are systematic and maintain the same behavior.

Also applies to: 11-11, 16-21, 30-31

lib/ui/chat/widgets/user_profile_info.dart (1)

6-6: LGTM! Class and constructor renames are consistent.

The rename from ContactInfo to UserProfileInfo (including both the regular and .loading() constructors) aligns with the terminology shift. No behavioral changes introduced.

Also applies to: 12-12, 19-19

lib/ui/settings/general_settings_screen.dart (1)

10-10: LGTM! Type migration applied correctly.

The import and callback parameter type have been updated from ContactModel to UserProfile. Field access pattern (selectedProfile.publicKey) remains consistent with the new domain model.

Also applies to: 85-86

lib/config/providers/group_messages_provider.dart (1)

127-163: User profile mapping keeps domain users consistent.
Thanks for keeping the “You” resolution and metadata normalization intact while swapping in UserProfile; the downstream message conversion still receives the same shape it expects.

lib/ui/user_profile_list/share_invite_bottom_sheet.dart (1)

1-99: LGTM! Clean refactoring from Contact to UserProfile.

The file consistently updates all references from ContactModel/contacts to UserProfile/userProfiles. Import paths, parameter names, and UI references are all correctly aligned with the new domain model.

test/ui/contact_list/widgets/user_profile_test.dart (1)

1-112: LGTM! Test wrapper correctly updated.

The test file properly renames UserProfileTestWrapper to UserProfileCardTestWrapper and updates the widget under test from UserProfile to UserProfileCard. All test cases are consistently updated.

test/ui/contact_list/widgets/share_invite_callout_test.dart (1)

1-70: LGTM! Test consistently migrated to UserProfile.

The test file properly updates all references from ContactModel/contact to UserProfile/userProfile. Import paths, function parameters, and test data construction are all correctly aligned with the new domain model.

lib/ui/settings/profile/share_profile_qr_scan_screen.dart (1)

11-11: LGTM! QR scan screen correctly wired to new provider.

The screen properly updates to use userProfileProvider instead of userProfileDataProvider, calls getUserProfile instead of getUserProfileData, and passes userProfile to StartChatBottomSheet. All changes are consistent with the refactoring.

Also applies to: 19-19, 208-213

lib/config/providers/user_profile_provider.dart (2)

7-29: LGTM! Well-structured provider with dependency injection.

The UserProfileNotifier properly implements dependency injection for testability, with clear method names and explicit type declarations. The getUserProfile method correctly chains API calls to build a UserProfile from metadata.


31-33: LGTM! Provider correctly configured.

The provider is properly set up with a factory function that creates a new UserProfileNotifier instance.

lib/routing/routes.dart (1)

17-19: LGTM! Route constants and helpers consistently updated.

All route constants and navigation helpers are properly renamed from contact-centric to user-centric terminology. The changes maintain consistency across path values and method parameters.

Also applies to: 33-33, 36-36, 42-44

test/ui/contact_list/start_chat_bottom_sheet_test.dart (1)

1-309: LGTM! Comprehensive test migration to UserProfile.

The test file thoroughly updates all references from ContactModel/contact to UserProfile/userProfile. Import paths, test data construction, widget instantiation, and mock data references are all correctly aligned with the new domain model.

lib/ui/user_profile_list/new_chat_bottom_sheet.dart (5)

13-14: LGTM! Imports correctly updated to new provider and paths.

All import paths are properly updated from user_profile_data_provider to user_profile_provider and from contact_list to user_profile_list components.

Also applies to: 23-25


53-54: LGTM! State variables correctly renamed.

The state variables _tempContact_tempUserProfile and _isLoadingContact_isLoadingUserProfile are consistently updated throughout the widget, following camelCase convention.

Also applies to: 102-102, 107-107


146-175: LGTM! User profile fetching method correctly implemented.

The _getUserProfileForPublicKey method properly uses the new userProfileProvider and getUserProfile API. Error handling creates a fallback UserProfile with "Unknown User" display name, which maintains the existing behavior.


177-204: LGTM! Tap handler correctly updated.

The _handleUserProfileTap method is properly renamed from _handleContactTap and consistently uses UserProfile type throughout. The logic flow remains functionally equivalent.


283-491: LGTM! Comprehensive UI updates throughout the widget.

All widget building methods are thoroughly updated with consistent UserProfile terminology:

  • _buildUserProfilesList and related variables
  • List item building logic
  • Filter and search operations
  • Loading states and empty states

The changes maintain functional equivalence while improving domain model accuracy.

test/config/providers/user_profile_provider_test.dart (2)

74-85: Provider override and wiring look correct

Good use of overrideWith and injection of getUser and mockUserProfileFromMetadata. Test setup is clear and aligns with the rename.


103-139: Tests cover npub/hex and error/fallback paths

Coverage for both key formats, missing displayName fallback, and API error looks solid. No issues found.

Also applies to: 157-176, 189-193

lib/ui/user_profile_list/start_chat_bottom_sheet.dart (1)

174-186: Key format for followProvider

Ensure followProvider expects the provided key format (npub vs hex). Normalize if needed for consistent state.

Would you confirm followProvider’s expected key format? If hex is required, normalize with PubkeyFormatter(pubkey).toHex().

lib/ui/user_profile_list/widgets/user_profile_tile.dart (1)

56-67: LGTM on the rename and bindings

Bindings, keys, and Dismissible wiring look good after the migration.

Also applies to: 133-182

lib/ui/chat/chat_management/add_to_group_screen.dart (2)

101-109: Correct to use npubs in addToGroup

membersNpubs aligns with userNpub. Good change.


240-242: Membership check by key format

members.any compares member.publicKey to userNpub. Confirm member.publicKey is npub; otherwise normalize formats to avoid false negatives.

If needed:

final npub = PubkeyFormatter(pubkey: member.publicKey).toNpub() ?? member.publicKey;
final isUserInGroup = members.any((m) => (PubkeyFormatter(pubkey: m.publicKey).toNpub() ?? m.publicKey) == widget.userNpub);

Also applies to: 267-269

@josefinalliende josefinalliende marked this pull request as draft October 3, 2025 17:43
@josefinalliende josefinalliende marked this pull request as ready for review October 6, 2025 18:30
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

🧹 Nitpick comments (4)
lib/ui/user_profile_list/start_chat_bottom_sheet.dart (4)

41-41: Remove blank line within function body.

Line 41 contains a blank line within the function body, which violates the coding guideline "Don't leave blank lines within a function."

As per coding guidelines.

Apply this diff:

   Future<bool> userHasKeyPackage({required String pubkey}) {
     final hexPubkey = PubkeyFormatter(pubkey: pubkey).toHex();
     if (hexPubkey == null) return Future.value(false);
-
     return wn_users_api.userHasKeyPackage(pubkey: hexPubkey);
   }

90-124: Consider extracting key package validation logic.

The _loadKeyPackage method exceeds the guideline of <20 instructions and handles multiple concerns (fetching, state updates, error handling). Extracting the key package fetch and error transformation into separate methods would improve testability and readability.

As per coding guidelines.


126-176: Consider extracting group creation logic.

The _createOrOpenDirectMessageGroup method exceeds the guideline of <20 instructions. Consider extracting the group creation API call, success handling, and error handling into separate focused methods.

As per coding guidelines.


230-296: Flatten widget tree to improve readability.

The nested AnimatedSize → AnimatedSwitcher → conditional Column structure is deeply nested. The guideline recommends breaking down large widgets into smaller, focused widgets and avoiding deep nesting for improved efficiency and maintainability.

As per coding guidelines.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f791d93 and b28e648.

📒 Files selected for processing (2)
  • lib/ui/user_profile_list/group_chat_details_sheet.dart (6 hunks)
  • lib/ui/user_profile_list/start_chat_bottom_sheet.dart (10 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/user_profile_list/start_chat_bottom_sheet.dart
  • lib/ui/user_profile_list/group_chat_details_sheet.dart
🧠 Learnings (7)
📚 Learning: 2025-08-12T11:21:53.640Z
Learnt from: josefinalliende
PR: parres-hq/whitenoise_flutter#455
File: lib/ui/settings/profile/switch_profile_bottom_sheet.dart:0-0
Timestamp: 2025-08-12T11:21:53.640Z
Learning: In the whitenoise_flutter codebase, ContactModel.publicKey can be stored in either npub format (from metadata cache) or hex format (from account storage). The activeAccountProvider may return either format depending on how the account was originally stored, so normalization to hex format is required when comparing with other hex-normalized keys in sorting logic.

Applied to files:

  • lib/ui/user_profile_list/start_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/user_profile_list/start_chat_bottom_sheet.dart
📚 Learning: 2025-09-04T17:54:09.162Z
Learnt from: josefinalliende
PR: parres-hq/whitenoise_flutter#594
File: lib/ui/chat/chat_info/dm_chat_info.dart:0-0
Timestamp: 2025-09-04T17:54:09.162Z
Learning: In the whitenoise_flutter codebase, pubkey conversion from hex to npub format is handled using a .toNpub() extension method on String, which eliminates the need for manual format checking or calling npubFromHexPubkey() function directly.

Applied to files:

  • lib/ui/user_profile_list/start_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/user_profile_list/start_chat_bottom_sheet.dart
📚 Learning: 2025-09-03T20:57:53.202Z
Learnt from: josefinalliende
PR: parres-hq/whitenoise_flutter#594
File: lib/config/providers/user_profile_data_provider.dart:0-0
Timestamp: 2025-09-03T20:57:53.202Z
Learning: In the whitenoise_flutter codebase, pubkey normalization (npub/hex format handling) is implemented in a pubkey validations extension rather than being imported directly into individual providers like user_profile_data_provider.dart.

Applied to files:

  • lib/ui/user_profile_list/start_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/user_profile_list/start_chat_bottom_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/user_profile_list/start_chat_bottom_sheet.dart
  • lib/ui/user_profile_list/group_chat_details_sheet.dart
🔇 Additional comments (5)
lib/ui/user_profile_list/start_chat_bottom_sheet.dart (1)

1-301: LGTM! Refactor correctly replaces ContactModel with UserProfile.

The refactoring is thorough and consistent:

  • All imports updated to user_profile_list namespace
  • Widget interface and internal references properly migrated from contact to userProfile
  • PubkeyFormatter usage correctly handles npub/hex conversion at lines 39-42 and 132
  • Follow state, group creation, and UI rendering all use userProfile fields appropriately

The past issue with npub/hex format mismatches has been resolved.

Based on learnings.

lib/ui/user_profile_list/group_chat_details_sheet.dart (4)

1-21: LGTM!

Import statements correctly updated to reflect the ContactModel → UserProfile refactoring, including the new pubkey_formatter utility.


23-49: LGTM!

Class constructor, fields, and static method parameters consistently renamed to use selectedUserProfiles instead of selectedContacts.


176-203: LGTM!

Method correctly uses PubkeyFormatter before calling the Rust API method userHasKeyPackage, with appropriate null checking. The error handling strategy (assuming no key package on exceptions) is reasonable for this flow.


205-286: LGTM!

Build method correctly updated to use selectedUserProfiles and render with UserProfileTile instead of the old contact-based widget.

@josefinalliende josefinalliende force-pushed the refactor/remove-contact-word branch 2 times, most recently from 43b8773 to a2dda1a Compare October 6, 2025 19:29
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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
lib/ui/chat/chat_info/widgets/member_action_buttons.dart (1)

106-126: Remove blank lines within the function.

The function contains blank lines (after line 109 and after line 117), which violates the coding guideline that states: "Don't leave blank lines within a function."

As per coding guidelines, apply this diff to remove blank lines:

   Future<void> _toggleFollow() async {
     final followNotifier = ref.read(followProvider(widget.user.publicKey).notifier);
     var currentFollowState = ref.read(followProvider(widget.user.publicKey));
     late String successMessage;
-
     if (currentFollowState.isFollowing) {
       successMessage = 'Unfollowed ${widget.user.displayName}';
       await followNotifier.removeFollow(widget.user.publicKey);
     } else {
       successMessage = 'Followed ${widget.user.displayName}';
       await followNotifier.addFollow(widget.user.publicKey);
     }
-
     currentFollowState = ref.read(followProvider(widget.user.publicKey));
     final errorMessage = currentFollowState.error ?? '';
     if (errorMessage.isNotEmpty) {
       ref.showErrorToast(errorMessage);
     } else {
       ref.showSuccessToast(successMessage);
     }
   }
lib/ui/settings/profile/switch_profile_bottom_sheet.dart (1)

134-148: Normalize _activeAccountHex before sorting/highlighting.

Line 134 now assigns the raw value from activePubkeyProvider straight into _activeAccountHex. That provider may yield either npub or hex (see retrieved learnings), so when it returns an npub you never match/sort against the hex-normalized profiles. As a result the active profile no longer bubbles to the top nor receives the highlight. Convert once with PubkeyFormatter.toHex() and fall back to the original if conversion fails.

   Future<void> _getActivePubkeyHex() async {
-    final activeAccountPubkey = ref.read(activePubkeyProvider) ?? '';
-    if (activeAccountPubkey.isNotEmpty) {
-      setState(() {
-        _activeAccountHex = activeAccountPubkey;
-      });
-    }
+    final String? activeAccountPubkey = ref.read(activePubkeyProvider);
+    if (activeAccountPubkey == null || activeAccountPubkey.isEmpty) {
+      return;
+    }
+    final String? activeAccountHex =
+        PubkeyFormatter(pubkey: activeAccountPubkey).toHex();
+    setState(() {
+      _activeAccountHex = activeAccountHex ?? activeAccountPubkey;
+    });
   }

Based on learnings

♻️ Duplicate comments (1)
lib/ui/user_profile_list/group_chat_details_sheet.dart (1)

113-118: Convert publicKey to hex format before passing to createNewGroup.

The memberPublicKeyHexs parameter expects hex-encoded pubkeys, but line 116 passes raw publicKey values without conversion. Your filtering method (lines 185-186) correctly uses PubkeyFormatter(pubkey: userProfile.publicKey).toHex(), which should be applied here as well.

Apply this diff to convert pubkeys to hex format:

       final createdGroup = await notifier.createNewGroup(
         groupName: groupName,
         groupDescription: '',
-        memberPublicKeyHexs: userProfilesWithKeyPackage.map((c) => c.publicKey).toList(),
+        memberPublicKeyHexs: userProfilesWithKeyPackage
+            .map((c) => PubkeyFormatter(pubkey: c.publicKey).toHex())
+            .where((hex) => hex != null && hex.isNotEmpty)
+            .cast<String>()
+            .toList(),
         adminPublicKeyHexs: [],
       );
🧹 Nitpick comments (2)
lib/ui/chat/chat_info/widgets/member_action_buttons.dart (1)

97-103: Consider renaming to reflect toggle behavior.

The class is renamed successfully, aligning with the PR's goal to replace "contact" terminology. However, AddToFollowsButton suggests a one-directional action, while the implementation (line 137) shows the button toggles between "Follow" and "Unfollow". Consider renaming to FollowToggleButton or simply FollowButton to better reflect its behavior.

test/ui/contact_list/widgets/user_profile_test.dart (1)

1-1: Consider aligning test file path with the module structure.

The test file is located at test/ui/contact_list/widgets/user_profile_test.dart but tests a widget from lib/ui/user_profile_list/widgets/user_profile_card.dart. For consistency, consider moving the test to test/ui/user_profile_list/widgets/user_profile_card_test.dart.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b28e648 and 43b8773.

📒 Files selected for processing (50)
  • CHANGELOG.md (1 hunks)
  • lib/config/providers/group_messages_provider.dart (2 hunks)
  • lib/config/providers/group_provider.dart (1 hunks)
  • lib/config/providers/user_profile_data_provider.dart (0 hunks)
  • lib/config/providers/user_profile_provider.dart (1 hunks)
  • lib/domain/models/user_profile.dart (5 hunks)
  • lib/domain/services/dm_chat_service.dart (2 hunks)
  • lib/routing/router_provider.dart (4 hunks)
  • lib/routing/routes.dart (2 hunks)
  • lib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dart (2 hunks)
  • lib/ui/chat/chat_info/widgets/member_action_buttons.dart (1 hunks)
  • lib/ui/chat/chat_management/add_to_group_screen.dart (5 hunks)
  • lib/ui/chat/chat_management/widgets/create_group_dialog.dart (3 hunks)
  • lib/ui/chat/chat_screen.dart (3 hunks)
  • lib/ui/chat/invite/chat_invite_screen.dart (5 hunks)
  • lib/ui/chat/widgets/chat_header_widget.dart (1 hunks)
  • lib/ui/chat/widgets/message_widget.dart (8 hunks)
  • lib/ui/chat/widgets/user_profile_info.dart (1 hunks)
  • lib/ui/core/themes/src/colors.dart (7 hunks)
  • lib/ui/core/themes/src/colors_dark.dart (1 hunks)
  • lib/ui/core/themes/src/colors_light.dart (1 hunks)
  • lib/ui/core/themes/src/light/extensions.dart (1 hunks)
  • lib/ui/settings/general_settings_screen.dart (2 hunks)
  • lib/ui/settings/network/network_screen.dart (1 hunks)
  • lib/ui/settings/profile/share_profile_qr_scan_screen.dart (2 hunks)
  • lib/ui/settings/profile/switch_profile_bottom_sheet.dart (6 hunks)
  • lib/ui/settings/widgets/active_account_tile.dart (2 hunks)
  • lib/ui/user_profile_list/chat_list_screen.dart (1 hunks)
  • lib/ui/user_profile_list/group_chat_details_sheet.dart (6 hunks)
  • lib/ui/user_profile_list/new_chat_bottom_sheet.dart (17 hunks)
  • lib/ui/user_profile_list/new_group_chat_sheet.dart (8 hunks)
  • lib/ui/user_profile_list/services/welcome_notification_service.dart (1 hunks)
  • lib/ui/user_profile_list/share_invite_bottom_sheet.dart (4 hunks)
  • lib/ui/user_profile_list/start_chat_bottom_sheet.dart (10 hunks)
  • lib/ui/user_profile_list/widgets/chat_list_active_account_avatar.dart (3 hunks)
  • lib/ui/user_profile_list/widgets/chat_list_item_tile.dart (1 hunks)
  • lib/ui/user_profile_list/widgets/profile_ready_card.dart (1 hunks)
  • lib/ui/user_profile_list/widgets/share_invite_callout.dart (1 hunks)
  • lib/ui/user_profile_list/widgets/user_profile_card.dart (1 hunks)
  • lib/ui/user_profile_list/widgets/user_profile_tile.dart (7 hunks)
  • lib/ui/user_profile_list/widgets/welcome_tile.dart (2 hunks)
  • lib/utils/error_handling.dart (0 hunks)
  • local-research/go_router_implementation_plan.md (0 hunks)
  • test/config/providers/group_messages_provider_test.dart (7 hunks)
  • test/config/providers/user_profile_provider_test.dart (8 hunks)
  • test/ui/contact_list/services/welcome_notification_service_simple_test.dart (1 hunks)
  • test/ui/contact_list/share_invite_bottom_sheet_test.dart (6 hunks)
  • test/ui/contact_list/start_chat_bottom_sheet_test.dart (11 hunks)
  • test/ui/contact_list/widgets/share_invite_callout_test.dart (3 hunks)
  • test/ui/contact_list/widgets/user_profile_test.dart (6 hunks)
💤 Files with no reviewable changes (3)
  • local-research/go_router_implementation_plan.md
  • lib/utils/error_handling.dart
  • lib/config/providers/user_profile_data_provider.dart
🚧 Files skipped from review as they are similar to previous changes (19)
  • lib/ui/user_profile_list/widgets/profile_ready_card.dart
  • lib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dart
  • lib/ui/user_profile_list/widgets/chat_list_item_tile.dart
  • test/ui/contact_list/widgets/share_invite_callout_test.dart
  • lib/domain/services/dm_chat_service.dart
  • lib/ui/chat/widgets/chat_header_widget.dart
  • lib/ui/chat/chat_management/widgets/create_group_dialog.dart
  • lib/ui/settings/profile/share_profile_qr_scan_screen.dart
  • lib/ui/user_profile_list/start_chat_bottom_sheet.dart
  • lib/ui/core/themes/src/colors_dark.dart
  • lib/config/providers/user_profile_provider.dart
  • test/ui/contact_list/share_invite_bottom_sheet_test.dart
  • test/ui/contact_list/services/welcome_notification_service_simple_test.dart
  • lib/ui/user_profile_list/widgets/share_invite_callout.dart
  • lib/config/providers/group_messages_provider.dart
  • lib/domain/models/user_profile.dart
  • lib/ui/core/themes/src/light/extensions.dart
  • test/config/providers/user_profile_provider_test.dart
  • lib/ui/chat/chat_screen.dart
🧰 Additional context used
📓 Path-based instructions (3)
**/*.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/core/themes/src/colors_light.dart
  • lib/ui/settings/widgets/active_account_tile.dart
  • test/ui/contact_list/widgets/user_profile_test.dart
  • lib/ui/settings/general_settings_screen.dart
  • lib/ui/user_profile_list/widgets/welcome_tile.dart
  • lib/routing/router_provider.dart
  • lib/ui/chat/widgets/user_profile_info.dart
  • lib/ui/user_profile_list/new_chat_bottom_sheet.dart
  • lib/ui/chat/chat_management/add_to_group_screen.dart
  • lib/ui/user_profile_list/share_invite_bottom_sheet.dart
  • lib/ui/chat/widgets/message_widget.dart
  • lib/ui/chat/chat_info/widgets/member_action_buttons.dart
  • lib/ui/user_profile_list/group_chat_details_sheet.dart
  • lib/routing/routes.dart
  • lib/ui/settings/network/network_screen.dart
  • lib/ui/user_profile_list/services/welcome_notification_service.dart
  • lib/ui/core/themes/src/colors.dart
  • lib/config/providers/group_provider.dart
  • test/ui/contact_list/start_chat_bottom_sheet_test.dart
  • lib/ui/user_profile_list/new_group_chat_sheet.dart
  • test/config/providers/group_messages_provider_test.dart
  • lib/ui/settings/profile/switch_profile_bottom_sheet.dart
  • lib/ui/user_profile_list/chat_list_screen.dart
  • lib/ui/user_profile_list/widgets/user_profile_card.dart
  • lib/ui/user_profile_list/widgets/user_profile_tile.dart
  • lib/ui/user_profile_list/widgets/chat_list_active_account_avatar.dart
  • lib/ui/chat/invite/chat_invite_screen.dart
**/*.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
**/*_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/ui/contact_list/widgets/user_profile_test.dart
  • test/ui/contact_list/start_chat_bottom_sheet_test.dart
  • test/config/providers/group_messages_provider_test.dart
🧠 Learnings (5)
📚 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/settings/widgets/active_account_tile.dart
  • test/ui/contact_list/widgets/user_profile_test.dart
  • lib/ui/settings/general_settings_screen.dart
  • lib/ui/user_profile_list/new_chat_bottom_sheet.dart
  • lib/ui/chat/chat_management/add_to_group_screen.dart
  • lib/ui/user_profile_list/group_chat_details_sheet.dart
  • test/ui/contact_list/start_chat_bottom_sheet_test.dart
  • lib/ui/user_profile_list/new_group_chat_sheet.dart
  • test/config/providers/group_messages_provider_test.dart
  • lib/ui/settings/profile/switch_profile_bottom_sheet.dart
  • lib/ui/user_profile_list/widgets/user_profile_tile.dart
  • lib/ui/user_profile_list/widgets/chat_list_active_account_avatar.dart
  • lib/ui/chat/invite/chat_invite_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/user_profile_list/group_chat_details_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:

  • test/config/providers/group_messages_provider_test.dart
📚 Learning: 2025-08-12T11:21:53.640Z
Learnt from: josefinalliende
PR: parres-hq/whitenoise_flutter#455
File: lib/ui/settings/profile/switch_profile_bottom_sheet.dart:0-0
Timestamp: 2025-08-12T11:21:53.640Z
Learning: In the whitenoise_flutter codebase, ContactModel.publicKey can be stored in either npub format (from metadata cache) or hex format (from account storage). The activeAccountProvider may return either format depending on how the account was originally stored, so normalization to hex format is required when comparing with other hex-normalized keys in sorting logic.

Applied to files:

  • lib/ui/settings/profile/switch_profile_bottom_sheet.dart
  • lib/ui/user_profile_list/widgets/user_profile_tile.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/user_profile_list/widgets/user_profile_tile.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 (41)
lib/ui/user_profile_list/services/welcome_notification_service.dart (1)

8-8: LGTM!

The import path correctly reflects the directory restructure from contact_list to user_profile_list. This change aligns with the PR's refactoring objectives.

lib/ui/settings/network/network_screen.dart (1)

189-189: LGTM!

The tooltip text change successfully removes "contact" terminology while maintaining clarity about the purpose of Inbox Relays. The shortened message remains informative and aligns with the PR's objective to shift from contact-centric to user-centric terminology.

lib/ui/settings/widgets/active_account_tile.dart (3)

6-6: LGTM! Import statements correctly updated.

The imports have been systematically renamed from contact-related paths to user_profile-related paths, aligning with the PR objectives.

Also applies to: 11-11


16-21: LGTM! Method refactored consistently.

The method return type and factory method call have been correctly updated from ContactModel to UserProfile. The method remains concise and follows coding guidelines (explicit types, no blank lines, single purpose).


30-31: LGTM! Widget usage updated correctly.

The widget has been changed from ContactListTile to UserProfileTile with the parameter renamed from contact to userProfile. This is consistent with the systematic refactoring across the codebase.

lib/config/providers/group_provider.dart (1)

366-366: LGTM! Documentation update aligns with PR objectives.

The comment simplification from "cached follows lookup" to "follows lookup" appropriately reflects the PR's goal of refining terminology. The implementation detail (cache lookup via findFollowByPubkey) remains clear from the code itself.

lib/ui/chat/chat_info/widgets/member_action_buttons.dart (1)

128-144: LGTM!

The build method correctly watches the follow state and renders the appropriate UI based on whether the user is following or not. The implementation is clean and follows the coding guidelines.

CHANGELOG.md (1)

12-12: LGTM!

The changelog entry accurately reflects the scope of this refactoring PR.

lib/ui/user_profile_list/chat_list_screen.dart (1)

27-31: LGTM!

The import path updates correctly reflect the module restructuring from contact_list to user_profile_list. All five imports are consistently updated.

lib/ui/chat/widgets/message_widget.dart (1)

47-47: LGTM!

The theme color constant renames from contactChatBubble/contactChatBubbleText to otherChatBubble/otherChatBubbleText improve clarity. The term "other" is more intuitive for representing non-sender messages in a chat context.

Also applies to: 60-60, 133-133, 324-324, 337-337, 354-354, 368-368, 386-386

lib/ui/core/themes/src/colors_light.dart (1)

72-72: LGTM!

Theme constant renames are consistent with the terminology update. The color values remain unchanged, ensuring no visual regression.

Also applies to: 75-75

lib/ui/user_profile_list/widgets/user_profile_card.dart (1)

12-12: LGTM!

Renaming the widget from UserProfile to UserProfileCard prevents naming collision with the domain model and clarifies that this is a UI component. The "Card" suffix follows Flutter widget naming conventions.

Also applies to: 19-19

test/ui/contact_list/widgets/user_profile_test.dart (1)

5-5: LGTM!

Test updates correctly reflect the widget rename from UserProfile to UserProfileCard. The test wrapper class and all test cases are consistently updated.

Also applies to: 10-10, 16-16, 26-34

lib/ui/chat/widgets/user_profile_info.dart (1)

6-6: LGTM!

The widget class rename from ContactInfo to UserProfileInfo aligns with the domain model terminology and removes the deprecated "contact" naming throughout the codebase.

Also applies to: 12-12, 19-19

lib/ui/user_profile_list/widgets/welcome_tile.dart (1)

4-4: LGTM!

Provider and method updates are consistent with the refactoring:

  • Import updated to the consolidated user_profile_provider
  • Method simplified from getUserProfileData to getUserProfile
  • Variable naming updated from welcomerContact to welcomerUserProfile

All changes maintain existing functionality while improving naming consistency.

Also applies to: 29-29, 32-32, 34-36

lib/routing/router_provider.dart (1)

25-25: LGTM! Routing refactor is consistent and complete.

All route constants, paths, parameters, and import references have been properly updated from contact-centric to user-centric terminology. The protected routes list, route handlers, and parameter bindings are all correctly aligned with the new naming scheme.

Also applies to: 88-88, 125-133, 216-216, 220-224

lib/ui/settings/general_settings_screen.dart (1)

10-10: LGTM! Account switcher callback properly updated.

The import and callback parameter type have been correctly updated from ContactModel to UserProfile. The switch-by-publicKey logic remains functionally equivalent.

Also applies to: 85-87

lib/ui/user_profile_list/share_invite_bottom_sheet.dart (2)

5-11: LGTM! Share invite flow properly migrated to UserProfile.

All data model references, imports, parameters, and UI components have been consistently updated from ContactModel to UserProfile. The builder instantiation and public API surface are correctly aligned with the new domain model.

Also applies to: 14-21, 33-35


46-93: LGTM! UI rendering correctly handles UserProfile data.

The conditional rendering logic and list building have been properly updated to work with UserProfile collections. Variable names (isSingleUserProfile, singleUserProfile, userProfiles) and widget data bindings (imagePath, displayName, nip05, publicKey) are all correctly aligned with the new model.

test/ui/contact_list/start_chat_bottom_sheet_test.dart (1)

5-10: LGTM! Test suite properly updated for UserProfile model.

All test imports, data fixtures, widget instantiations, and assertions have been correctly migrated from ContactModel to UserProfile. The test coverage and behavior remain functionally equivalent while using the new domain model.

Also applies to: 71-76, 86-119, 184-198, 230-238

lib/ui/user_profile_list/widgets/chat_list_active_account_avatar.dart (1)

6-7: LGTM! Avatar widget correctly migrated to new provider.

The imports, field type, and provider method call have been properly updated from the legacy userProfileDataProvider.getUserProfileData to userProfileProvider.getUserProfile. The runtime checks and data flow logic remain intact.

Also applies to: 25-25, 54-62

lib/routing/routes.dart (1)

17-19: LGTM! Route constants and helpers consistently updated.

All public route declarations have been correctly renamed from contact-centric to user-centric terminology. The navigation helper method signature and implementation properly reflect the parameter rename from contactId to userId.

Also applies to: 33-33, 36-36, 42-44

lib/ui/chat/invite/chat_invite_screen.dart (1)

8-11: LGTM! Invite screen properly migrated to UserProfile provider.

All provider references, method calls, and UI component usages have been correctly updated from the legacy userProfileDataProvider/ContactInfo to userProfileProvider/UserProfileInfo. The welcomer data flow and rendering logic remain functionally equivalent with the new domain model.

Also applies to: 57-60, 244-252, 329-346

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

13-14: LGTM! New chat sheet comprehensively refactored to UserProfile.

All data model references, provider calls, and internal state management have been correctly updated from contact-based to user-profile-based patterns. Variable names (_tempUserProfile, _isLoadingUserProfile), function names (_getUserProfileForPublicKey), and provider usage (userProfileProvider.getUserProfile) are all consistently aligned with the new domain model.

Also applies to: 23-25, 53-54, 102-108, 146-175


177-204: LGTM! User interaction handlers properly updated.

The tap handlers, navigation targets, and support contact flow have been correctly migrated to use UserProfile data and the renamed methods (_handleUserProfileTap). Route navigation properly updated to Routes.userProfileQrScan.

Also applies to: 207-209, 260-277


283-409: LGTM! List rendering logic consistently updated.

The list building, filtering, and rendering logic has been properly migrated to work with UserProfile collections. Function signatures (_buildUserProfilesList), variable names (filteredUserProfiles, showTempUserProfile), widget usages (UserProfileTile, UserProfileTileLoading), and the loading state component (_LoadingUserProfileList) are all correctly aligned with the new model.

Also applies to: 419-432, 487-491, 545-559

lib/ui/user_profile_list/group_chat_details_sheet.dart (7)

8-8: LGTM!

The import updates correctly reflect the refactoring from ContactModel to UserProfile and the contact_list directory to user_profile_list.

Also applies to: 18-21


26-26: LGTM!

The constructor and static show method parameter rename from selectedContacts to selectedUserProfiles is consistent with the refactoring objective.

Also applies to: 30-30, 35-35, 45-45


86-94: LGTM!

The filter call and variable assignments are correctly updated to use the renamed _filterUserProfilesByKeyPackage method and userProfilesWithKeyPackage/userProfilesWithoutKeyPackage variables.


96-108: LGTM!

The conditional logic correctly handles the case when no user profiles have keypackages, showing only the invite sheet without attempting group creation.


124-135: LGTM!

The invite sheet logic correctly handles user profiles without keypackages after successful group creation.


177-203: LGTM!

The filter method correctly uses PubkeyFormatter to convert pubkeys to hex format before checking keypackage availability. Error handling appropriately assumes no keypackage on conversion failure.


271-275: LGTM!

The ListView correctly renders the updated selectedUserProfiles list using the UserProfileTile widget.

lib/ui/user_profile_list/new_group_chat_sheet.dart (8)

22-22: LGTM!

The field and parameter rename from preSelectedContacts to preSelectedUserProfiles is consistent throughout the constructor and static show method.

Also applies to: 24-24, 32-32, 42-42


51-51: LGTM!

The state field rename to _selectedUserProfiles and initialization logic correctly handle pre-selected user profiles.

Also applies to: 57-60


92-100: LGTM!

The toggle method correctly uses Set operations to add/remove user profiles from the selection.


102-127: LGTM!

The list builder correctly uses UserProfileTile with the updated user profile data and selection state.


129-161: LGTM!

The filter method correctly excludes the current user and applies search filtering on displayName, nip05, and publicKey fields of UserProfile.


168-171: LGTM!

The mapping from follows to UserProfile objects using UserProfile.fromMetadata is correct.


182-182: LGTM!

The UI text updates from "contact" to "user" terminology align with the refactoring objectives.

Also applies to: 221-221


247-256: LGTM!

The group creation flow correctly passes selectedUserProfiles to GroupChatDetailsSheet.show as a List.

@josefinalliende josefinalliende force-pushed the refactor/remove-contact-word branch 2 times, most recently from 683e3fc to 2cf156f Compare October 6, 2025 19:39
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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
lib/domain/models/user_profile.dart (1)

106-125: Fix equals/hashCode contract (normalized key vs raw key mismatch)

operator == normalizes keys to hex, but hashCode hashes the raw publicKey, causing equal objects to produce different hashes. This breaks Set/Map behavior.

Apply this diff to hash on the same normalized representation and fields used in ==:

   @override
   int get hashCode {
-    return Object.hash(publicKey, imagePath, displayName, about, website, nip05, lud16);
+    final String? normalizedHex = PubkeyFormatter(pubkey: publicKey).toHex();
+    return Object.hash(
+      normalizedHex ?? publicKey,
+      imagePath,
+      displayName,
+      about,
+      website,
+      nip05,
+      lud16,
+    );
   }

Based on learnings

lib/ui/settings/profile/share_profile_qr_scan_screen.dart (1)

175-189: Fix switch fallthrough in didChangeAppLifecycleState (scanner stops immediately)

resumed falls through to inactive and stops the camera. Add breaks and stop on background states.

   void didChangeAppLifecycleState(AppLifecycleState state) {
     switch (state) {
-      case AppLifecycleState.detached:
-      case AppLifecycleState.hidden:
-      case AppLifecycleState.paused:
-        return;
-      case AppLifecycleState.resumed:
-        _subscription = _controller.barcodes.listen(_handleBarcode);
-        unawaited(_controller.start());
-      case AppLifecycleState.inactive:
-        unawaited(_subscription?.cancel());
-        _subscription = null;
-        unawaited(_controller.stop());
+      case AppLifecycleState.resumed:
+        _subscription = _controller.barcodes.listen(_handleBarcode);
+        unawaited(_controller.start());
+        break;
+      case AppLifecycleState.inactive:
+      case AppLifecycleState.paused:
+      case AppLifecycleState.hidden:
+      case AppLifecycleState.detached:
+        unawaited(_subscription?.cancel());
+        _subscription = null;
+        unawaited(_controller.stop());
+        break;
     }
   }
♻️ Duplicate comments (1)
lib/ui/user_profile_list/group_chat_details_sheet.dart (1)

116-122: Correct: convert pubkeys to hex for createNewGroup

Using PubkeyFormatter(...).toHex() and filtering null/empty ensures correct API input.

Thanks for addressing the earlier pubkey formatting concern. Based on learnings

🧹 Nitpick comments (28)
lib/ui/settings/widgets/active_account_tile.dart (1)

16-21: Avoid empty-string fallback for pubkey here

This branch guards on state.account != null; you can safely use the non-null pubkey and avoid passing an empty string.

Apply this diff:

-  return UserProfile.fromMetadata(
-    pubkey: state.account?.pubkey ?? '',
-    metadata: state.metadata,
-  );
+  return UserProfile.fromMetadata(
+    pubkey: state.account!.pubkey,
+    metadata: state.metadata,
+  );
test/ui/contact_list/share_invite_bottom_sheet_test.dart (1)

11-16: Add explicit type annotation for clarity

Explicitly type test fixtures per project guidelines.

As per coding guidelines

-    final testUserProfile = UserProfile(
+    final UserProfile testUserProfile = UserProfile(
       displayName: 'Satoshi Nakamoto',
       publicKey: 'abc123def456789012345678901234567890123456789012345678901234567890',
       nip05: 'satoshi@nakamoto.com',
       imagePath: 'https://example.com/satoshi.png',
     );
lib/domain/models/user_profile.dart (1)

72-81: Consider canonical internal key format (or document npub usage)

You store publicKey as npub. Given Rust APIs typically expect hex and comparisons normalize to hex, consider storing hex internally and deriving npub/format only for display, or at minimum document that publicKey holds npub.

Based on learnings

test/ui/contact_list/start_chat_bottom_sheet_test.dart (2)

71-76: Add explicit type annotation for the fixture

Keep tests explicit per guidelines.

As per coding guidelines

-    final userProfile = UserProfile(
+    final UserProfile userProfile = UserProfile(
       displayName: 'Satoshi Nakamoto',
       publicKey: 'abc123def456789012345678901234567890123456789012345678901234567890',
       nip05: 'satoshi@nakamoto.com',
       imagePath: 'https://example.com/satoshi.png',
     );

129-133: Tighten the copy-button selector

Match the intended icon to avoid false positives when multiple WnImage widgets exist.

-      final copyButton = find.byType(WnImage);
+      final copyButton = find.byWidgetPredicate(
+        (w) => w is WnImage && w.src.contains('assets/svgs/ic_copy.svg'),
+      );
lib/ui/user_profile_list/share_invite_bottom_sheet.dart (2)

46-48: Empty data: consider closing the sheet instead of rendering nothing

Returning SizedBox.shrink() yields an empty sheet body under the title. Prefer early guard before showing, or pop the sheet here.

Is the caller already ensuring userProfiles is non-empty? If not, shall we auto-close?


73-77: Localize hardcoded copy

Move strings into AppLocalizations to meet i18n guidelines.

As per coding guidelines

test/ui/contact_list/widgets/share_invite_callout_test.dart (1)

2-3: Move test under user_profile_list path

The file still lives under test/ui/contact_list/… Consider relocating to test/ui/user_profile_list/… for consistency with the rename.

lib/routing/routes.dart (1)

33-37: Consider temporary redirects from legacy paths

If deep links/bookmarks still point to /contacts or /contact/:id, add route-level redirects in the router to avoid breakage.

Can you confirm whether go_router configuration includes redirects for legacy contact routes?

lib/ui/user_profile_list/widgets/chat_list_active_account_avatar.dart (1)

49-57: Prefer a provider to fetch profile instead of manual Future + listen

Define a FutureProvider.family<UserProfile, String> and ref.watch it to avoid manual subscriptions, reduce state, and prevent duplicate fetches.

As per coding guidelines

lib/ui/chat/invite/chat_invite_screen.dart (2)

244-248: Avoid duplicate fetches for welcomer profile

Both DMInviteHeader and DMAppBarTitle fetch the same profile. Extract a FutureProvider.family and watch it in both places to share the result and handle loading/error uniformly.

As per coding guidelines


250-251: Localize fallback strings

Replace 'Unknown User' and similar literals with AppLocalizations.

As per coding guidelines

Also applies to: 275-275

test/config/providers/user_profile_provider_test.dart (1)

8-10: Add explicit types to align with repo Dart style

Declare types for constants and locals (pubkeys, metadata, user) for consistency with guidelines.

As per coding guidelines

-final testNpubPubkey = 'npub1zygjyg3nxdzyg424ven8waug3zvejqqq424thw7venwammhwlllsj2q4yf';
-final testHexPubkey = '1111222233334444555566667777888899990000aaaabbbbccccddddeeeeffff';
+final String testNpubPubkey = 'npub1zygjyg3nxdzyg424ven8waug3zvejqqq424thw7venwammhwlllsj2q4yf';
+final String testHexPubkey = '1111222233334444555566667777888899990000aaaabbbbccccddddeeeeffff';
@@
-    final testMetadata = const FlutterMetadata(
+    const FlutterMetadata testMetadata = FlutterMetadata(
@@
-    final testUser = User(
+    final User testUser = User(

Also applies to: 57-72

lib/ui/settings/profile/share_profile_qr_scan_screen.dart (2)

199-206: Minor: name the variable pubkey, avoid double trim, and add local types

Small clarity/readability tweaks; keep one trim and type annotations.

-        final npub = rawValue.trim();
-        if (!npub.isValidPublicKey) {
+        final String pubkey = rawValue.trim();
+        if (!pubkey.isValidPublicKey) {
           ref.showWarningToast('Invalid public key format');
           return;
         }
         _controller.stop();
-        final userProfileNotifier = ref.read(userProfileProvider.notifier);
-        final userProfile = await userProfileNotifier.getUserProfile(npub.trim());
+        final UserProfileNotifier userProfileNotifier = ref.read(userProfileProvider.notifier);
+        final userProfile = await userProfileNotifier.getUserProfile(pubkey);

As per coding guidelines

Also applies to: 208-214


84-91: Localize user-visible strings

Move hard-coded strings to AppLocalizations: title, helper text, button label, validation, and error.

As per coding guidelines

Also applies to: 133-140, 146-154, 204-206, 234-239

lib/ui/user_profile_list/start_chat_bottom_sheet.dart (2)

116-121: Avoid side-effects inside setState

Call showErrorToast outside setState.

-      if (mounted) {
-        setState(() {
-          _isLoadingKeyPackage = false;
-          _isLoadingKeyPackageError = true;
-          ref.showErrorToast('Error loading user key package: $e');
-        });
-      }
+      if (mounted) {
+        setState(() {
+          _isLoadingKeyPackage = false;
+          _isLoadingKeyPackageError = true;
+        });
+        ref.showErrorToast('Error loading user key package: $e');
+      }

65-70: Localize user-visible strings

Use AppLocalizations for: sheet title, error toasts, success toasts, and button labels.

As per coding guidelines

Also applies to: 120-121, 158-159, 266-276, 279-293

lib/ui/user_profile_list/widgets/user_profile_tile.dart (2)

145-159: Dialog copy and localization

Use AppLocalizations for title/content/actions. Consider using a question mark and aligning action text (e.g., 'Unfollow').

As per coding guidelines

-                  title: const Text('Unfollow'),
+                  title: Text(context.l10n.unfollowTitle),
                   content: Text(
-                    'Are you sure you want to stop following ${userProfile.displayName}',
+                    context.l10n.unfollowConfirm(userProfile.displayName),
                   ),
@@
-                      child: const Text('Cancel'),
+                      child: Text(context.l10n.cancel),
@@
-                      child: const Text('Remove'),
+                      child: Text(context.l10n.unfollow),

53-67: Optional: add explicit local types for clarity

Add types for locals (image path, formattedKey, userProfileTile) per repo style.

As per coding guidelines

-    final userProfileImagePath = userProfile.imagePath ?? '';
-    final formattedKey = _getFormattedPublicKey();
-    final userProfileTile = GestureDetector(
+    final String userProfileImagePath = userProfile.imagePath ?? '';
+    final String formattedKey = _getFormattedPublicKey();
+    final Widget userProfileTile = GestureDetector(

Also applies to: 76-85, 90-96

lib/ui/settings/profile/switch_profile_bottom_sheet.dart (2)

119-124: Ensure list is sorted within state update

Sort inside setState (or follow-up setState) so the rebuild reflects the final order deterministically.

-      setState(() {
-        _accountsProfileData = accountsProfileData;
-        _isLoadingAccounts = false;
-      });
-      _sortAccountsProfileData();
+      setState(() {
+        _accountsProfileData = accountsProfileData;
+        _isLoadingAccounts = false;
+        _sortAccountsProfileData();
+      });

39-47: Localize user-visible strings

Localize sheet title, sign-out message, and 'Connect Another Profile' button.

As per coding guidelines

Also applies to: 97-99, 239-243

lib/ui/chat/chat_management/add_to_group_screen.dart (2)

240-242: Normalize pubkey formats when checking membership

member.publicKey may be hex while widget.userNpub is npub; direct string compare can fail.

-                    final isUserInGroup = members.any(
-                      (member) => member.publicKey == widget.userNpub,
-                    );
+                    final isUserInGroup = members.any((member) {
+                      final memberHex = PubkeyFormatter(pubkey: member.publicKey).toHex();
+                      final userHex = PubkeyFormatter(pubkey: widget.userNpub).toHex();
+                      return memberHex != null &&
+                          userHex != null &&
+                          memberHex.toLowerCase() == userHex.toLowerCase();
+                    });

Add import:

import 'package:whitenoise/utils/pubkey_formatter.dart';

Please confirm the stored group member key format (hex vs npub) to ensure correct normalization. Based on learnings


269-276: Prevent duplicate group IDs in selection

Repeated toggles can add the same groupId multiple times.

-                          if (value == true) {
-                            _groupsToAddUserTo.add(group.mlsGroupId);
-                          } else {
+                          if (value == true) {
+                            if (!_groupsToAddUserTo.contains(group.mlsGroupId)) {
+                              _groupsToAddUserTo.add(group.mlsGroupId);
+                            }
+                          } else {
                             _groupsToAddUserTo.remove(group.mlsGroupId);
                           }
test/config/providers/group_messages_provider_test.dart (1)

83-102: Add explicit type for test data map

Keep explicit types per guidelines and improve readability.

-    final testUserProfiles = {
+    final Map<String, UserProfile> testUserProfiles = {

As per coding guidelines

lib/ui/user_profile_list/new_chat_bottom_sheet.dart (2)

53-55: Declare logger type explicitly

Use explicit types for variables.

-  final _logger = Logger('NewChatBottomSheet');
+  final Logger _logger = Logger('NewChatBottomSheet');

As per coding guidelines


146-175: Guard against stale async results in search

Debounced requests can return out of order; ensure setState applies to current query only.

-  Future<void> _getUserProfileForPublicKey(String publicKey) async {
+  Future<void> _getUserProfileForPublicKey(String publicKey) async {
     if (_isLoadingUserProfile) return;
 
     setState(() {
       _isLoadingUserProfile = true;
     });
 
     try {
-      final userProfileNotifier = ref.read(userProfileProvider.notifier);
-      final userProfile = await userProfileNotifier.getUserProfile(publicKey.trim());
+      final String request = publicKey.trim();
+      final userProfileNotifier = ref.read(userProfileProvider.notifier);
+      final userProfile = await userProfileNotifier.getUserProfile(request);
+      if (!mounted || _searchQuery.trim() != request) {
+        setState(() => _isLoadingUserProfile = false);
+        return;
+      }
 
       if (mounted) {
         setState(() {
           _tempUserProfile = userProfile;
           _isLoadingUserProfile = false;
         });
       }
lib/ui/user_profile_list/group_chat_details_sheet.dart (2)

95-98: Update comment to reflect current logic

Comment says “less than 2” but code checks only for empty.

-      // If less than 2 userProfiles have keypackages, only show invite sheet (no group creation)
+      // If no selected user has a keypackage, only show invite sheet (no group creation)

181-208: Prefer a typed result over Map with string keys

Returning a Map with 'withKeyPackage'/'withoutKeyPackage' is brittle. Consider a small value class.

Example:

class KeyPackageSplit {
  final List<UserProfile> withKeyPackage;
  final List<UserProfile> withoutKeyPackage;
  const KeyPackageSplit({required this.withKeyPackage, required this.withoutKeyPackage});
}

Then return KeyPackageSplit instead of Map<String, List>.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 683e3fc and d60a19b.

📒 Files selected for processing (50)
  • CHANGELOG.md (1 hunks)
  • lib/config/providers/group_messages_provider.dart (2 hunks)
  • lib/config/providers/group_provider.dart (1 hunks)
  • lib/config/providers/user_profile_data_provider.dart (0 hunks)
  • lib/config/providers/user_profile_provider.dart (1 hunks)
  • lib/domain/models/user_profile.dart (5 hunks)
  • lib/domain/services/dm_chat_service.dart (2 hunks)
  • lib/routing/router_provider.dart (4 hunks)
  • lib/routing/routes.dart (2 hunks)
  • lib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dart (2 hunks)
  • lib/ui/chat/chat_info/widgets/member_action_buttons.dart (1 hunks)
  • lib/ui/chat/chat_management/add_to_group_screen.dart (5 hunks)
  • lib/ui/chat/chat_management/widgets/create_group_dialog.dart (3 hunks)
  • lib/ui/chat/chat_screen.dart (3 hunks)
  • lib/ui/chat/invite/chat_invite_screen.dart (5 hunks)
  • lib/ui/chat/widgets/chat_header_widget.dart (1 hunks)
  • lib/ui/chat/widgets/message_widget.dart (8 hunks)
  • lib/ui/chat/widgets/user_profile_info.dart (1 hunks)
  • lib/ui/core/themes/src/colors.dart (7 hunks)
  • lib/ui/core/themes/src/colors_dark.dart (1 hunks)
  • lib/ui/core/themes/src/colors_light.dart (1 hunks)
  • lib/ui/core/themes/src/light/extensions.dart (1 hunks)
  • lib/ui/settings/general_settings_screen.dart (2 hunks)
  • lib/ui/settings/network/network_screen.dart (1 hunks)
  • lib/ui/settings/profile/share_profile_qr_scan_screen.dart (2 hunks)
  • lib/ui/settings/profile/switch_profile_bottom_sheet.dart (6 hunks)
  • lib/ui/settings/widgets/active_account_tile.dart (2 hunks)
  • lib/ui/user_profile_list/chat_list_screen.dart (1 hunks)
  • lib/ui/user_profile_list/group_chat_details_sheet.dart (6 hunks)
  • lib/ui/user_profile_list/new_chat_bottom_sheet.dart (17 hunks)
  • lib/ui/user_profile_list/new_group_chat_sheet.dart (8 hunks)
  • lib/ui/user_profile_list/services/welcome_notification_service.dart (1 hunks)
  • lib/ui/user_profile_list/share_invite_bottom_sheet.dart (4 hunks)
  • lib/ui/user_profile_list/start_chat_bottom_sheet.dart (10 hunks)
  • lib/ui/user_profile_list/widgets/chat_list_active_account_avatar.dart (3 hunks)
  • lib/ui/user_profile_list/widgets/chat_list_item_tile.dart (1 hunks)
  • lib/ui/user_profile_list/widgets/profile_ready_card.dart (1 hunks)
  • lib/ui/user_profile_list/widgets/share_invite_callout.dart (1 hunks)
  • lib/ui/user_profile_list/widgets/user_profile_card.dart (1 hunks)
  • lib/ui/user_profile_list/widgets/user_profile_tile.dart (7 hunks)
  • lib/ui/user_profile_list/widgets/welcome_tile.dart (2 hunks)
  • lib/utils/error_handling.dart (0 hunks)
  • local-research/go_router_implementation_plan.md (0 hunks)
  • test/config/providers/group_messages_provider_test.dart (7 hunks)
  • test/config/providers/user_profile_provider_test.dart (8 hunks)
  • test/ui/contact_list/services/welcome_notification_service_simple_test.dart (1 hunks)
  • test/ui/contact_list/share_invite_bottom_sheet_test.dart (6 hunks)
  • test/ui/contact_list/start_chat_bottom_sheet_test.dart (11 hunks)
  • test/ui/contact_list/widgets/share_invite_callout_test.dart (3 hunks)
  • test/ui/contact_list/widgets/user_profile_card_test.dart (6 hunks)
💤 Files with no reviewable changes (3)
  • lib/utils/error_handling.dart
  • local-research/go_router_implementation_plan.md
  • lib/config/providers/user_profile_data_provider.dart
✅ Files skipped from review due to trivial changes (1)
  • test/ui/contact_list/services/welcome_notification_service_simple_test.dart
🚧 Files skipped from review as they are similar to previous changes (15)
  • lib/ui/core/themes/src/colors_light.dart
  • lib/domain/services/dm_chat_service.dart
  • lib/routing/router_provider.dart
  • lib/ui/chat/chat_screen.dart
  • lib/ui/settings/network/network_screen.dart
  • lib/ui/user_profile_list/widgets/welcome_tile.dart
  • lib/ui/chat/chat_management/widgets/create_group_dialog.dart
  • lib/ui/user_profile_list/widgets/share_invite_callout.dart
  • lib/ui/user_profile_list/chat_list_screen.dart
  • lib/config/providers/group_messages_provider.dart
  • lib/config/providers/user_profile_provider.dart
  • lib/ui/chat/chat_info/widgets/member_action_buttons.dart
  • lib/ui/core/themes/src/colors_dark.dart
  • lib/ui/settings/general_settings_screen.dart
  • lib/ui/user_profile_list/widgets/profile_ready_card.dart
🧰 Additional context used
📓 Path-based instructions (3)
**/*.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/config/providers/group_provider.dart
  • lib/ui/user_profile_list/widgets/user_profile_card.dart
  • lib/ui/chat/widgets/message_widget.dart
  • lib/ui/user_profile_list/services/welcome_notification_service.dart
  • lib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dart
  • lib/ui/chat/widgets/user_profile_info.dart
  • lib/ui/core/themes/src/light/extensions.dart
  • test/config/providers/user_profile_provider_test.dart
  • test/ui/contact_list/share_invite_bottom_sheet_test.dart
  • test/config/providers/group_messages_provider_test.dart
  • lib/ui/user_profile_list/share_invite_bottom_sheet.dart
  • lib/ui/settings/profile/share_profile_qr_scan_screen.dart
  • test/ui/contact_list/widgets/user_profile_card_test.dart
  • lib/ui/user_profile_list/start_chat_bottom_sheet.dart
  • test/ui/contact_list/start_chat_bottom_sheet_test.dart
  • lib/ui/user_profile_list/widgets/chat_list_item_tile.dart
  • lib/routing/routes.dart
  • lib/ui/core/themes/src/colors.dart
  • lib/ui/user_profile_list/new_group_chat_sheet.dart
  • lib/domain/models/user_profile.dart
  • lib/ui/settings/profile/switch_profile_bottom_sheet.dart
  • lib/ui/chat/invite/chat_invite_screen.dart
  • lib/ui/chat/chat_management/add_to_group_screen.dart
  • test/ui/contact_list/widgets/share_invite_callout_test.dart
  • lib/ui/user_profile_list/widgets/chat_list_active_account_avatar.dart
  • lib/ui/user_profile_list/group_chat_details_sheet.dart
  • lib/ui/settings/widgets/active_account_tile.dart
  • lib/ui/user_profile_list/widgets/user_profile_tile.dart
  • lib/ui/chat/widgets/chat_header_widget.dart
  • lib/ui/user_profile_list/new_chat_bottom_sheet.dart
**/*.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
**/*_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/config/providers/user_profile_provider_test.dart
  • test/ui/contact_list/share_invite_bottom_sheet_test.dart
  • test/config/providers/group_messages_provider_test.dart
  • test/ui/contact_list/widgets/user_profile_card_test.dart
  • test/ui/contact_list/start_chat_bottom_sheet_test.dart
  • test/ui/contact_list/widgets/share_invite_callout_test.dart
🧠 Learnings (9)
📚 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:

  • test/config/providers/user_profile_provider_test.dart
  • test/config/providers/group_messages_provider_test.dart
  • test/ui/contact_list/widgets/user_profile_card_test.dart
  • lib/ui/user_profile_list/start_chat_bottom_sheet.dart
  • test/ui/contact_list/start_chat_bottom_sheet_test.dart
  • lib/ui/user_profile_list/new_group_chat_sheet.dart
  • lib/domain/models/user_profile.dart
  • lib/ui/settings/profile/switch_profile_bottom_sheet.dart
  • lib/ui/chat/invite/chat_invite_screen.dart
  • lib/ui/chat/chat_management/add_to_group_screen.dart
  • lib/ui/user_profile_list/widgets/chat_list_active_account_avatar.dart
  • lib/ui/user_profile_list/group_chat_details_sheet.dart
  • lib/ui/settings/widgets/active_account_tile.dart
  • lib/ui/user_profile_list/widgets/user_profile_tile.dart
  • lib/ui/chat/widgets/chat_header_widget.dart
  • lib/ui/user_profile_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:

  • test/config/providers/group_messages_provider_test.dart
  • lib/ui/user_profile_list/start_chat_bottom_sheet.dart
  • lib/ui/user_profile_list/group_chat_details_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 **/*_test.dart : Use the standard widget testing for Flutter.

Applied to files:

  • test/ui/contact_list/widgets/user_profile_card_test.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/user_profile_list/start_chat_bottom_sheet.dart
  • lib/ui/user_profile_list/group_chat_details_sheet.dart
📚 Learning: 2025-08-12T11:21:53.640Z
Learnt from: josefinalliende
PR: parres-hq/whitenoise_flutter#455
File: lib/ui/settings/profile/switch_profile_bottom_sheet.dart:0-0
Timestamp: 2025-08-12T11:21:53.640Z
Learning: In the whitenoise_flutter codebase, ContactModel.publicKey can be stored in either npub format (from metadata cache) or hex format (from account storage). The activeAccountProvider may return either format depending on how the account was originally stored, so normalization to hex format is required when comparing with other hex-normalized keys in sorting logic.

Applied to files:

  • lib/ui/user_profile_list/start_chat_bottom_sheet.dart
  • lib/domain/models/user_profile.dart
  • lib/ui/settings/profile/switch_profile_bottom_sheet.dart
  • lib/ui/user_profile_list/widgets/user_profile_tile.dart
📚 Learning: 2025-09-03T20:57:53.202Z
Learnt from: josefinalliende
PR: parres-hq/whitenoise_flutter#594
File: lib/config/providers/user_profile_data_provider.dart:0-0
Timestamp: 2025-09-03T20:57:53.202Z
Learning: In the whitenoise_flutter codebase, pubkey normalization (npub/hex format handling) is implemented in a pubkey validations extension rather than being imported directly into individual providers like user_profile_data_provider.dart.

Applied to files:

  • lib/ui/user_profile_list/start_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/user_profile_list/start_chat_bottom_sheet.dart
📚 Learning: 2025-09-04T17:54:09.162Z
Learnt from: josefinalliende
PR: parres-hq/whitenoise_flutter#594
File: lib/ui/chat/chat_info/dm_chat_info.dart:0-0
Timestamp: 2025-09-04T17:54:09.162Z
Learning: In the whitenoise_flutter codebase, pubkey conversion from hex to npub format is handled using a .toNpub() extension method on String, which eliminates the need for manual format checking or calling npubFromHexPubkey() function directly.

Applied to files:

  • lib/ui/user_profile_list/group_chat_details_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/user_profile_list/widgets/user_profile_tile.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 (26)
lib/ui/user_profile_list/services/welcome_notification_service.dart (1)

8-8: No issues found.

Import path now aligns with the renamed user_profile_list module.

lib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dart (2)

259-260: Follow toggle button swap looks good.

Nice drop-in replacement—the layout stays intact and the new wording matches the refactor intent.


305-307: Consistent follow action for non-admins.

Appreciate the mirrored change here so both branches share the same follow/unfollow affordance.

lib/ui/user_profile_list/widgets/user_profile_card.dart (1)

12-26: LGTM! Clean rename from UserProfile to UserProfileCard.

The class and constructor rename aligns with the PR's terminology refactor. The implementation remains unchanged and correct.

CHANGELOG.md (1)

12-12: LGTM! Change properly documented.

The CHANGELOG entry accurately describes the scope of the refactor.

test/ui/contact_list/widgets/user_profile_card_test.dart (1)

5-34: LGTM! Test updates match widget rename.

The test wrapper class and widget instantiations have been updated consistently to reflect the UserProfileCard rename. Test structure and assertions remain valid.

lib/ui/core/themes/src/colors.dart (1)

36-38: LGTM! Color field renames applied consistently across the theme API.

The contactChatBubble/contactChatBubbleTextotherChatBubble/otherChatBubbleText renames are correctly propagated through constructor parameters, field declarations, light/dark initializers, copyWith, and lerp methods.

lib/config/providers/group_provider.dart (1)

366-366: LGTM! Comment clarification aligns with terminology refactor.

The updated comment accurately reflects that data is retrieved from follows (cached user profiles) without the outdated "contacts" terminology.

lib/ui/core/themes/src/light/extensions.dart (1)

32-34: LGTM! All references to contactChatBubble/contactChatBubbleText have been removed from the codebase.

lib/ui/chat/widgets/chat_header_widget.dart (1)

15-18: Approve ChatUserHeader rename; no remaining references detected.

Ran a recursive search across all .dart files—no instances of ChatContactHeader remain.

lib/ui/chat/widgets/user_profile_info.dart (1)

6-23: Ready to merge – no remaining ContactInfo references
Rename and constructors are consistently updated across all Dart files.

lib/ui/settings/widgets/active_account_tile.dart (1)

30-38: LGTM: correct migration to UserProfileTile

Props renamed and wiring look consistent with the new model.

lib/ui/chat/widgets/message_widget.dart (1)

47-48: LGTM: color renames are consistent

Renamed theme tokens (otherChatBubble/otherChatBubbleText) applied correctly across bubble, text, and reactions.

Also applies to: 60-61, 133-134, 323-325, 336-338, 353-355, 366-369, 384-387

test/ui/contact_list/start_chat_bottom_sheet_test.dart (1)

188-196: Clarify pubkey normalization in tests
Production code: DefaultWnUsersApi normalizes userProfile.publicKey to hex via PubkeyFormatter before invoking the Rust API. In tests, MockWnUsersApiWithPackage bypasses that layer—ensure your mock’s expected pubkey is PubkeyFormatter(pubkey).toHex() of userProfile.publicKey when stubbing or verifying userHasKeyPackage.

lib/ui/user_profile_list/share_invite_bottom_sheet.dart (1)

33-36: API rename looks good

Builder and parameter rename to userProfiles are consistent and clear.

test/ui/contact_list/widgets/share_invite_callout_test.dart (1)

8-12: Test update aligns with new API

Setup now uses UserProfile and ShareInviteCallout(userProfile: …). Looks correct.

lib/routing/routes.dart (2)

17-20: Contacts → Users route rename looks correct

Constants and paths are consistent.


42-44: Helper method addition LGTM

goToUser(context, userId) matches the new path.

lib/ui/user_profile_list/widgets/chat_list_active_account_avatar.dart (1)

25-25: Type migration to UserProfile is correct

Field and usage align with the new model and provider.

Based on learnings

lib/ui/chat/invite/chat_invite_screen.dart (2)

57-61: UserProfileInfo for group title is a good consolidation

Keeps UI consistent with the new user-profile model.


247-248: getUserProfile normalizes both hex and npub inputs
user_profile_provider tests verify conversion of hex→npub and support npub directly, so passing welcome.welcomer requires no additional formatting.

test/config/providers/user_profile_provider_test.dart (1)

74-85: Good provider override and wiring

Override uses UserProfileNotifier with mock dependencies; test container setup/teardown is correct.

lib/ui/user_profile_list/start_chat_bottom_sheet.dart (2)

39-43: Nice: converting pubkey to hex before API call

Correctly normalizes input for userHasKeyPackage.

Based on learnings


178-191: Key format consistency for followProvider

Confirm followProvider expects npub or hex; normalize if needed to avoid cache/key mismatches.

Based on learnings

test/config/providers/group_messages_provider_test.dart (1)

19-33: Mocks align with UserProfile provider refactor

Extending UserProfileNotifier and overriding getUserProfile is appropriate for these tests. Looks good.

If UserProfileNotifier’s constructor parameters are non-nullable in main code, ensure passing nulls here won’t execute base logic paths during tests.

lib/ui/user_profile_list/new_group_chat_sheet.dart (1)

57-61: Preselected user profiles initialization is correct

Adding preSelectedUserProfiles into the selection in initState is correct and side‑effect free.

@josefinalliende
Copy link
Contributor Author

This PR has loots of conflicts. I'm turning it back to draft while I fix them

@josefinalliende josefinalliende marked this pull request as draft October 12, 2025 22:43
@josefinalliende josefinalliende force-pushed the refactor/remove-contact-word branch 2 times, most recently from 45c9dbc to 3c6ca9d Compare October 13, 2025 00:24
@josefinalliende josefinalliende marked this pull request as ready for review October 13, 2025 00:28
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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/ui/settings/profile/switch_profile_bottom_sheet.dart (1)

135-141: Normalize active pubkey before comparisons

activePubkeyProvider can return either npub or hex (see prior note on key normalization). Because _activeAccountHex now stores the raw value, the later hex comparisons never match for npub accounts—active profile highlighting breaks and selecting the current profile triggers a redundant switch.

Based on learnings

   Future<void> _getActivePubkeyHex() async {
     final activeAccountPubkey = ref.read(activePubkeyProvider) ?? '';
     if (activeAccountPubkey.isNotEmpty) {
-      setState(() {
-        _activeAccountHex = activeAccountPubkey;
-      });
+      String? normalizedHex;
+      try {
+        normalizedHex = PubkeyFormatter(pubkey: activeAccountPubkey).toHex();
+      } catch (_) {
+        normalizedHex = null;
+      }
+      setState(() {
+        _activeAccountHex = normalizedHex ?? activeAccountPubkey;
+      });
     }
   }
🧹 Nitpick comments (1)
lib/locales/ru.json (1)

247-247: Normalize “ещё” spelling for consistency

Other strings in this locale (e.g., Line 169) already use “ещё” with diacritic. Please align this one as well so the RU copy stays consistent.

-        "usersNotReadyForSecureMessaging": "Эти пользователи еще не готовы к безопасному обмену сообщениями. Поделитесь с ними приложением White Noise, чтобы начать!",
+        "usersNotReadyForSecureMessaging": "Эти пользователи ещё не готовы к безопасному обмену сообщениями. Поделитесь с ними приложением White Noise, чтобы начать!",
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9fea4a2 and 3c6ca9d.

📒 Files selected for processing (61)
  • CHANGELOG.md (1 hunks)
  • lib/config/providers/create_group_provider.dart (8 hunks)
  • lib/config/providers/group_messages_provider.dart (2 hunks)
  • lib/config/providers/group_provider.dart (1 hunks)
  • lib/config/providers/user_profile_data_provider.dart (0 hunks)
  • lib/config/providers/user_profile_provider.dart (1 hunks)
  • lib/config/states/create_group_state.dart (3 hunks)
  • lib/config/states/create_group_state.freezed.dart (14 hunks)
  • lib/config/states/localization_state.freezed.dart (3 hunks)
  • lib/domain/models/user_profile.dart (5 hunks)
  • lib/domain/services/dm_chat_service.dart (2 hunks)
  • lib/locales/de.json (4 hunks)
  • lib/locales/en.json (4 hunks)
  • lib/locales/es.json (5 hunks)
  • lib/locales/fr.json (4 hunks)
  • lib/locales/it.json (4 hunks)
  • lib/locales/pt.json (4 hunks)
  • lib/locales/ru.json (4 hunks)
  • lib/locales/tr.json (4 hunks)
  • lib/routing/router_provider.dart (4 hunks)
  • lib/routing/routes.dart (2 hunks)
  • lib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dart (2 hunks)
  • lib/ui/chat/chat_info/widgets/member_action_buttons.dart (1 hunks)
  • lib/ui/chat/chat_management/add_to_group_screen.dart (5 hunks)
  • lib/ui/chat/chat_management/widgets/create_group_dialog.dart (3 hunks)
  • lib/ui/chat/chat_screen.dart (3 hunks)
  • lib/ui/chat/invite/chat_invite_screen.dart (5 hunks)
  • lib/ui/chat/widgets/chat_header_widget.dart (1 hunks)
  • lib/ui/chat/widgets/message_widget.dart (8 hunks)
  • lib/ui/chat/widgets/user_profile_info.dart (1 hunks)
  • lib/ui/core/themes/src/colors.dart (7 hunks)
  • lib/ui/core/themes/src/colors_dark.dart (1 hunks)
  • lib/ui/core/themes/src/colors_light.dart (1 hunks)
  • lib/ui/core/themes/src/light/extensions.dart (1 hunks)
  • lib/ui/settings/general_settings_screen.dart (2 hunks)
  • lib/ui/settings/profile/share_profile_qr_scan_screen.dart (2 hunks)
  • lib/ui/settings/profile/switch_profile_bottom_sheet.dart (6 hunks)
  • lib/ui/settings/widgets/active_account_tile.dart (2 hunks)
  • lib/ui/user_profile_list/chat_list_screen.dart (1 hunks)
  • lib/ui/user_profile_list/group_chat_details_sheet.dart (7 hunks)
  • lib/ui/user_profile_list/new_chat_bottom_sheet.dart (17 hunks)
  • lib/ui/user_profile_list/new_group_chat_sheet.dart (8 hunks)
  • lib/ui/user_profile_list/services/welcome_notification_service.dart (1 hunks)
  • lib/ui/user_profile_list/share_invite_bottom_sheet.dart (3 hunks)
  • lib/ui/user_profile_list/start_chat_bottom_sheet.dart (10 hunks)
  • lib/ui/user_profile_list/widgets/chat_list_active_account_avatar.dart (3 hunks)
  • lib/ui/user_profile_list/widgets/chat_list_item_tile.dart (1 hunks)
  • lib/ui/user_profile_list/widgets/profile_ready_card.dart (1 hunks)
  • lib/ui/user_profile_list/widgets/share_invite_callout.dart (1 hunks)
  • lib/ui/user_profile_list/widgets/user_profile_card.dart (1 hunks)
  • lib/ui/user_profile_list/widgets/user_profile_tile.dart (4 hunks)
  • lib/ui/user_profile_list/widgets/welcome_tile.dart (2 hunks)
  • lib/utils/error_handling.dart (0 hunks)
  • local-research/go_router_implementation_plan.md (0 hunks)
  • test/config/providers/group_messages_provider_test.dart (7 hunks)
  • test/config/providers/user_profile_provider_test.dart (8 hunks)
  • test/ui/contact_list/services/welcome_notification_service_simple_test.dart (1 hunks)
  • test/ui/contact_list/share_invite_bottom_sheet_test.dart (6 hunks)
  • test/ui/contact_list/start_chat_bottom_sheet_test.dart (11 hunks)
  • test/ui/contact_list/widgets/share_invite_callout_test.dart (1 hunks)
  • test/ui/contact_list/widgets/user_profile_card_test.dart (6 hunks)
💤 Files with no reviewable changes (3)
  • lib/config/providers/user_profile_data_provider.dart
  • lib/utils/error_handling.dart
  • local-research/go_router_implementation_plan.md
✅ Files skipped from review due to trivial changes (1)
  • lib/config/states/localization_state.freezed.dart
🚧 Files skipped from review as they are similar to previous changes (16)
  • lib/ui/chat/widgets/user_profile_info.dart
  • test/ui/contact_list/share_invite_bottom_sheet_test.dart
  • lib/ui/user_profile_list/widgets/user_profile_card.dart
  • lib/config/providers/group_messages_provider.dart
  • lib/ui/settings/general_settings_screen.dart
  • lib/ui/user_profile_list/widgets/profile_ready_card.dart
  • lib/domain/services/dm_chat_service.dart
  • lib/ui/chat/widgets/message_widget.dart
  • CHANGELOG.md
  • lib/ui/user_profile_list/chat_list_screen.dart
  • lib/ui/user_profile_list/widgets/welcome_tile.dart
  • lib/ui/core/themes/src/colors.dart
  • lib/config/providers/user_profile_provider.dart
  • lib/ui/user_profile_list/widgets/share_invite_callout.dart
  • lib/ui/user_profile_list/group_chat_details_sheet.dart
  • lib/ui/chat/widgets/chat_header_widget.dart
🧰 Additional context used
📓 Path-based instructions (3)
**/*.dart

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

**/*.dart: Always declare the type of each variable and function (parameters and return value)
Avoid using dynamic and Object without justification
Create necessary types instead of overusing primitives or dynamic
One export per file
Use PascalCase for classes
Use camelCase for variables, functions, and methods
Avoid magic numbers and define constants
Start each function name with a verb
Use verbs for boolean variables (e.g., isLoading, hasError, canDelete)
Write short functions with a single purpose (under ~20 instructions)
Name functions with a verb plus context; for booleans use isX/hasX/canX; for void use executeX/saveX
Avoid deep nesting via early returns and extraction to utility functions
Use higher-order functions (map, where/filter, reduce) to avoid nesting
Use arrow functions for simple functions (under ~3 statements); use named functions otherwise
Use default parameter values instead of null checks
Reduce function parameters using RO-RO: pass/return parameter objects with declared types
Maintain a single level of abstraction within functions
Encapsulate data in composite types; avoid overusing primitives
Prefer validating data within classes rather than in functions
Prefer immutability; use final for runtime constants and const for compile-time constants
Use const constructors and const literals where possible
Follow SOLID principles
Prefer composition over inheritance
Declare interfaces (abstract classes) to define contracts
Write small classes with a single purpose (under ~200 instructions, <10 public methods, <10 properties)
Use exceptions for unexpected errors
Only catch exceptions to fix expected problems or add context; otherwise use a global handler

Files:

  • lib/ui/chat/chat_info/widgets/member_action_buttons.dart
  • lib/ui/user_profile_list/widgets/chat_list_item_tile.dart
  • lib/config/providers/group_provider.dart
  • lib/config/states/create_group_state.freezed.dart
  • test/ui/contact_list/services/welcome_notification_service_simple_test.dart
  • lib/domain/models/user_profile.dart
  • test/ui/contact_list/start_chat_bottom_sheet_test.dart
  • lib/ui/settings/profile/share_profile_qr_scan_screen.dart
  • test/config/providers/user_profile_provider_test.dart
  • lib/ui/user_profile_list/start_chat_bottom_sheet.dart
  • lib/ui/core/themes/src/light/extensions.dart
  • lib/ui/settings/widgets/active_account_tile.dart
  • lib/ui/user_profile_list/share_invite_bottom_sheet.dart
  • lib/ui/chat/chat_management/widgets/create_group_dialog.dart
  • test/ui/contact_list/widgets/user_profile_card_test.dart
  • lib/ui/chat/chat_screen.dart
  • lib/config/providers/create_group_provider.dart
  • test/ui/contact_list/widgets/share_invite_callout_test.dart
  • lib/ui/chat/chat_management/add_to_group_screen.dart
  • lib/routing/routes.dart
  • lib/ui/core/themes/src/colors_dark.dart
  • lib/ui/settings/profile/switch_profile_bottom_sheet.dart
  • lib/config/states/create_group_state.dart
  • lib/ui/user_profile_list/widgets/chat_list_active_account_avatar.dart
  • lib/ui/core/themes/src/colors_light.dart
  • test/config/providers/group_messages_provider_test.dart
  • lib/routing/router_provider.dart
  • lib/ui/user_profile_list/widgets/user_profile_tile.dart
  • lib/ui/user_profile_list/services/welcome_notification_service.dart
  • lib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dart
  • lib/ui/chat/invite/chat_invite_screen.dart
  • lib/ui/user_profile_list/new_chat_bottom_sheet.dart
  • lib/ui/user_profile_list/new_group_chat_sheet.dart
lib/**/*.dart

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

lib/**/*.dart: Use flutter_rust_bridge to access core app functionality
Use Riverpod for state management; prefer StreamProviders for Rust API streams; use keepAlive if needed
Use freezed to model/manage UI states
Controllers should expose methods as inputs and update UI state that drives the UI
Use AutoRoute for navigation and use extras to pass data between pages
Use Dart extensions to manage reusable code
Use ThemeData to manage themes
Use AppLocalizations for translations
Use constants to manage constant values
Avoid deeply nested widget trees; aim for a flatter widget structure for performance and readability
Break down large widgets into smaller, focused, reusable components
Keep the widget tree shallow to simplify state management and data flow
Utilize const constructors and const widgets wherever possible to reduce rebuilds

Files:

  • lib/ui/chat/chat_info/widgets/member_action_buttons.dart
  • lib/ui/user_profile_list/widgets/chat_list_item_tile.dart
  • lib/config/providers/group_provider.dart
  • lib/config/states/create_group_state.freezed.dart
  • lib/domain/models/user_profile.dart
  • lib/ui/settings/profile/share_profile_qr_scan_screen.dart
  • lib/ui/user_profile_list/start_chat_bottom_sheet.dart
  • lib/ui/core/themes/src/light/extensions.dart
  • lib/ui/settings/widgets/active_account_tile.dart
  • lib/ui/user_profile_list/share_invite_bottom_sheet.dart
  • lib/ui/chat/chat_management/widgets/create_group_dialog.dart
  • lib/ui/chat/chat_screen.dart
  • lib/config/providers/create_group_provider.dart
  • lib/ui/chat/chat_management/add_to_group_screen.dart
  • lib/routing/routes.dart
  • lib/ui/core/themes/src/colors_dark.dart
  • lib/ui/settings/profile/switch_profile_bottom_sheet.dart
  • lib/config/states/create_group_state.dart
  • lib/ui/user_profile_list/widgets/chat_list_active_account_avatar.dart
  • lib/ui/core/themes/src/colors_light.dart
  • lib/routing/router_provider.dart
  • lib/ui/user_profile_list/widgets/user_profile_tile.dart
  • lib/ui/user_profile_list/services/welcome_notification_service.dart
  • lib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dart
  • lib/ui/chat/invite/chat_invite_screen.dart
  • lib/ui/user_profile_list/new_chat_bottom_sheet.dart
  • lib/ui/user_profile_list/new_group_chat_sheet.dart
test/**/*.dart

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

test/**/*.dart: Follow Arrange-Act-Assert in tests
Name test variables clearly using inputX, mockX, actualX, expectedX
Write unit tests for each public function; use test doubles for dependencies (except cheap third-party)
Use standard Flutter widget testing

Files:

  • test/ui/contact_list/services/welcome_notification_service_simple_test.dart
  • test/ui/contact_list/start_chat_bottom_sheet_test.dart
  • test/config/providers/user_profile_provider_test.dart
  • test/ui/contact_list/widgets/user_profile_card_test.dart
  • test/ui/contact_list/widgets/share_invite_callout_test.dart
  • test/config/providers/group_messages_provider_test.dart
🧠 Learnings (9)
📚 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/domain/models/user_profile.dart
  • test/ui/contact_list/start_chat_bottom_sheet_test.dart
  • test/config/providers/user_profile_provider_test.dart
  • lib/ui/user_profile_list/start_chat_bottom_sheet.dart
  • lib/ui/settings/widgets/active_account_tile.dart
  • lib/ui/chat/chat_management/widgets/create_group_dialog.dart
  • test/ui/contact_list/widgets/user_profile_card_test.dart
  • lib/config/providers/create_group_provider.dart
  • lib/ui/chat/chat_management/add_to_group_screen.dart
  • lib/ui/settings/profile/switch_profile_bottom_sheet.dart
  • lib/config/states/create_group_state.dart
  • lib/ui/user_profile_list/widgets/chat_list_active_account_avatar.dart
  • test/config/providers/group_messages_provider_test.dart
  • lib/ui/chat/invite/chat_invite_screen.dart
  • lib/ui/user_profile_list/new_chat_bottom_sheet.dart
  • lib/ui/user_profile_list/new_group_chat_sheet.dart
📚 Learning: 2025-08-12T11:21:53.640Z
Learnt from: josefinalliende
PR: parres-hq/whitenoise_flutter#455
File: lib/ui/settings/profile/switch_profile_bottom_sheet.dart:0-0
Timestamp: 2025-08-12T11:21:53.640Z
Learning: In the whitenoise_flutter codebase, ContactModel.publicKey can be stored in either npub format (from metadata cache) or hex format (from account storage). The activeAccountProvider may return either format depending on how the account was originally stored, so normalization to hex format is required when comparing with other hex-normalized keys in sorting logic.

Applied to files:

  • lib/domain/models/user_profile.dart
  • lib/ui/user_profile_list/start_chat_bottom_sheet.dart
  • lib/ui/settings/profile/switch_profile_bottom_sheet.dart
  • lib/ui/user_profile_list/widgets/user_profile_tile.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/user_profile_list/start_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/user_profile_list/start_chat_bottom_sheet.dart
  • lib/config/providers/create_group_provider.dart
  • test/config/providers/group_messages_provider_test.dart
📚 Learning: 2025-09-03T20:57:53.202Z
Learnt from: josefinalliende
PR: parres-hq/whitenoise_flutter#594
File: lib/config/providers/user_profile_data_provider.dart:0-0
Timestamp: 2025-09-03T20:57:53.202Z
Learning: In the whitenoise_flutter codebase, pubkey normalization (npub/hex format handling) is implemented in a pubkey validations extension rather than being imported directly into individual providers like user_profile_data_provider.dart.

Applied to files:

  • lib/ui/user_profile_list/start_chat_bottom_sheet.dart
📚 Learning: 2025-10-12T22:44:49.592Z
Learnt from: CR
PR: parres-hq/whitenoise_flutter#0
File: .cursor/rules/flutter.mdc:0-0
Timestamp: 2025-10-12T22:44:49.592Z
Learning: Applies to lib/**/*.dart : Use Riverpod for state management; prefer StreamProviders for Rust API streams; use keepAlive if needed

Applied to files:

  • lib/ui/user_profile_list/start_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/chat/chat_management/widgets/create_group_dialog.dart
📚 Learning: 2025-10-12T22:44:49.592Z
Learnt from: CR
PR: parres-hq/whitenoise_flutter#0
File: .cursor/rules/flutter.mdc:0-0
Timestamp: 2025-10-12T22:44:49.592Z
Learning: Applies to test/**/*.dart : Use standard Flutter widget testing

Applied to files:

  • test/ui/contact_list/widgets/user_profile_card_test.dart
📚 Learning: 2025-10-12T22:44:49.592Z
Learnt from: CR
PR: parres-hq/whitenoise_flutter#0
File: .cursor/rules/flutter.mdc:0-0
Timestamp: 2025-10-12T22:44:49.592Z
Learning: Applies to lib/**/*.dart : Use freezed to model/manage UI states

Applied to files:

  • lib/config/states/create_group_state.dart
🔇 Additional comments (54)
lib/ui/user_profile_list/widgets/chat_list_item_tile.dart (1)

18-19: LGTM! Import paths correctly updated.

The import paths have been updated to reflect the new directory structure as part of the refactor from "contact" to "user_profile" terminology. Both imported widgets (MessageReadStatus and WelcomeTile) are actively used in this file.

test/ui/contact_list/services/welcome_notification_service_simple_test.dart (1)

5-5: LGTM!

The import path has been correctly updated to reflect the new directory structure (user_profile_list instead of contact_list).

lib/ui/user_profile_list/services/welcome_notification_service.dart (1)

8-8: LGTM!

The import path has been correctly updated to reflect the new directory structure.

lib/config/providers/group_provider.dart (1)

366-366: LGTM!

The comment has been appropriately updated to reflect the generic terminology "from follows" instead of "cached contacts," aligning with the broader refactor.

lib/ui/settings/widgets/active_account_tile.dart (3)

7-7: LGTM!

The imports have been correctly updated to reference the new UserProfile model and UserProfileTile widget.

Also applies to: 12-12


18-23: LGTM!

The method signature and return type have been correctly updated from ContactModel to UserProfile, maintaining consistency with the broader refactor.


32-33: LGTM!

The widget has been correctly updated from ContactListTile to UserProfileTile, with the parameter renamed from contact to userProfile.

test/ui/contact_list/widgets/user_profile_card_test.dart (2)

5-5: LGTM!

The test wrapper class has been correctly renamed from UserProfileTestWrapper to UserProfileCardTestWrapper, with the import and widget instantiation updated accordingly.

Also applies to: 10-10, 16-16, 26-26


37-37: LGTM!

The test group name has been correctly updated to "UserProfileCard Widget Tests", and all test instantiations have been updated to use UserProfileCardTestWrapper.

Also applies to: 44-44, 61-61, 80-80, 96-96

lib/ui/chat/chat_management/widgets/create_group_dialog.dart (1)

4-4: LGTM!

The import, field, and method parameters have been consistently updated from ContactModel/contactToAdd to UserProfile/userProfileToAdd, maintaining type safety and naming conventions.

Also applies to: 15-15, 21-21, 100-100, 108-108

lib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dart (1)

249-249: LGTM!

The widget has been correctly updated from AddToContactButton to FollowToggleButton in both the admin and non-admin branches, aligning with the terminology shift from contacts to follows.

Also applies to: 296-296

lib/ui/core/themes/src/colors_light.dart (1)

72-72: All old constants have been fully renamed. No remaining references to contactChatBubble or contactChatBubbleText found.

lib/ui/core/themes/src/light/extensions.dart (1)

32-34: LGTM! Color property rename aligns with terminology update.

The rename from contactChatBubble/contactChatBubbleText to otherChatBubble/otherChatBubbleText is consistent with the broader refactor to move away from contact-centric terminology. The values are preserved correctly.

lib/ui/core/themes/src/colors_dark.dart (1)

76-79: LGTM! Dark theme color properties renamed consistently.

The changes mirror the light theme updates, maintaining consistency across themes. The color values remain unchanged, ensuring visual consistency.

lib/config/states/create_group_state.dart (2)

2-2: Import updated correctly.

The import change from contact_model to user_profile aligns with the domain model rename.


16-17: LGTM! State field types and names updated consistently.

The changes properly update:

  • Field types from List<ContactModel> to List<UserProfile>
  • Field names to reflect user-centric terminology (userProfilesWithoutKeyPackage, userProfilesWithKeyPackage)
  • Getter reference in canCreateGroup

The type safety is preserved, and naming follows Dart conventions. Based on coding guidelines

Also applies to: 27-27

lib/locales/es.json (1)

100-100: LGTM! Locale strings updated to reflect user-centric terminology.

All Spanish locale strings have been consistently updated:

  • Key renames align with the broader refactor (e.g., searchContactPlaceholdersearchUserPlaceholder)
  • User-facing text correctly uses "usuarios" instead of "contactos"
  • Parameter placeholders updated appropriately ({contactName}{userName})
  • Maintains consistency with other locale files in the PR

Also applies to: 135-137, 152-152, 158-159, 161-162, 169-169, 185-186, 246-246

lib/ui/chat/chat_info/widgets/member_action_buttons.dart (1)

98-104: LGTM! Widget renamed to better reflect its purpose.

The rename from AddToContactButton to FollowToggleButton is more accurate as the widget handles both follow and unfollow actions (toggle behavior). This aligns well with the PR's objective to move away from contact-centric terminology.

lib/config/states/create_group_state.freezed.dart (1)

27-28: LGTM! Generated code updated consistently.

This freezed-generated file has been properly regenerated to reflect the type changes from List<ContactModel> to List<UserProfile> and the field name updates. All boilerplate (getters, copyWith, equality, hashCode, toString) is consistent with the source state class.

Also applies to: 52-53, 80-81, 121-130, 158-160, 185-187, 226-235, 257-261, 283-301, 330-335, 351-352, 377-379, 398-400

lib/domain/models/user_profile.dart (1)

6-6: LGTM! Core domain model renamed appropriately.

The rename from ContactModel to UserProfile is well-executed:

  • Constructor, factory method, and equality operator updated consistently
  • All internal logic and field names preserved
  • The new name better reflects domain concepts and resolves naming conflicts with the Rust API's User type

Based on learnings: This addresses the planned consolidation to replace ContactModel with a user-profile concept that doesn't conflict with the existing User class.

Also applies to: 16-25, 42-82, 107-120

lib/locales/pt.json (1)

100-100: LGTM! Portuguese locale strings aligned with terminology update.

All Portuguese translations have been consistently updated:

  • Keys renamed to reflect user-centric model
  • User-facing text correctly uses "utilizadores" instead of "contatos"
  • Parameter placeholders updated ({contactName}{userName})
  • Maintains consistency with other locale files (es.json, etc.)

Also applies to: 135-138, 158-159, 161-162, 169-169, 242-242, 248-248

lib/ui/user_profile_list/share_invite_bottom_sheet.dart (1)

42-62: Nice guard on empty and single-user handling

The early return plus the split between single-user cards and multi-user tiles keeps the bottom sheet resilient after the rename. Good job keeping the UX logic intact during the refactor.

lib/ui/user_profile_list/widgets/chat_list_active_account_avatar.dart (3)

6-7: LGTM: Imports updated correctly.

The imports have been cleanly updated to use the new user_profile_provider and UserProfile model.


25-25: LGTM: Field type updated correctly.

The field type has been updated from ContactModel? to UserProfile?, consistent with the refactor.


54-56: LGTM: Provider and method call updated correctly.

The provider reference and method call have been updated to use the new userProfileProvider and getUserProfile method.

lib/ui/chat/invite/chat_invite_screen.dart (7)

8-8: LGTM: Imports updated correctly.

The imports have been cleanly updated to use the new user_profile_provider and UserProfileInfo widget.

Also applies to: 11-11


58-61: LGTM: Widget updated to UserProfileInfo.

The widget has been correctly updated from ContactInfo to UserProfileInfo.


245-245: LGTM: Provider and method call updated correctly.

The provider reference and method call have been updated to use the new userProfileProvider and getUserProfile method.

Also applies to: 248-248


250-252: LGTM: Variable renamed consistently.

The variable has been renamed from welcomerContact to welcomerUser and all field accesses have been updated accordingly.

Also applies to: 276-276


333-333: LGTM: Provider and method call updated correctly.

Consistent with previous changes in the file.

Also applies to: 336-336


341-342: LGTM: Loading state widget used correctly.

The UserProfileInfo.loading() constructor is used appropriately to show a loading state.


344-350: LGTM: Variable and widget usage updated correctly.

All references to welcomerUser and UserProfileInfo are consistent and correct.

lib/ui/settings/profile/share_profile_qr_scan_screen.dart (3)

11-11: LGTM: Imports updated correctly.

The imports have been updated to use the new user_profile_provider and the relocated start_chat_bottom_sheet from the user_profile_list directory.

Also applies to: 19-19


208-209: LGTM: Provider and method call updated correctly.

The provider reference and method call have been updated consistently with the refactor.


213-213: LGTM: Parameter name updated correctly.

The parameter name has been updated from contact to userProfile, consistent with the updated StartChatBottomSheet.show API.

lib/locales/fr.json (5)

100-100: LGTM: Locale value updated correctly.

The French translation has been updated to use "nouveaux utilisateurs" (new users) instead of "nouveaux contacts" (new contacts), consistent with the terminology refactor.


135-137: LGTM: Locale keys renamed correctly.

The locale keys have been renamed to use user-centric terminology:

  • searchContactPlaceholdersearchUserPlaceholder
  • contactsLoadingErrorfollowsLoadingError
  • noContactsFoundnoUsersFound

The French translations are correct.


158-158: LGTM: Locale values updated correctly.

The locale values have been updated to reflect the new user-centric terminology. The French translations are appropriate.

Also applies to: 161-161


169-169: LGTM: Placeholder updated correctly.

The placeholder has been updated from {contactName} to {userName}, consistent with the terminology refactor.


247-247: LGTM: Locale key renamed correctly.

The locale key has been renamed from contactsNotReadyForSecureMessaging to usersNotReadyForSecureMessaging, and the French translation is correct.

lib/locales/en.json (1)

100-100: LGTM: English locale updates are correct.

All locale keys and values have been updated consistently to reflect user-centric terminology:

  • searchContactPlaceholdersearchUserPlaceholder
  • contactsLoadingErrorfollowsLoadingError
  • noContactsFoundnoUsersFound
  • noContactsMatchSearchnoUsersMatchSearch
  • contactsNotReadyForSecureMessagingusersNotReadyForSecureMessaging
  • Placeholder updated from {contactName} to {userName}

The English translations are clear and appropriate.

Also applies to: 135-137, 158-158, 161-161, 169-169, 247-247

lib/locales/it.json (1)

100-100: LGTM: Italian locale updates are mostly correct.

The locale keys and values have been updated consistently to reflect user-centric terminology, and the Italian translations are appropriate.

Also applies to: 135-137, 158-158, 161-161, 169-169

lib/ui/user_profile_list/start_chat_bottom_sheet.dart (6)

14-14: LGTM: Type changes and imports updated correctly.

The widget has been refactored to use UserProfile instead of ContactModel:

  • Import updated from contact_model.dart to user_profile.dart
  • Field type changed from ContactModel to UserProfile
  • Constructor parameter updated accordingly
  • PubkeyFormatter import added for proper pubkey handling

The changes are consistent throughout the file.

Also applies to: 23-27, 48-48, 54-54


40-43: LGTM: Pubkey formatting added correctly.

The addition of PubkeyFormatter to convert the pubkey to hex format before passing it to the API is appropriate. The null check ensures that invalid pubkeys don't cause runtime errors.


59-72: LGTM: Public API updated correctly.

The show method signature has been updated to accept a UserProfile parameter instead of ContactModel, and the builder uses it correctly.


100-102: LGTM: Field access updated correctly.

The method now correctly accesses widget.userProfile.publicKey instead of the old contact field.


133-133: LGTM: Group creation updated correctly.

The pubkey is properly converted to hex format using PubkeyFormatter before being passed to createNewGroup. The displayName is accessed from the UserProfile field correctly.

Based on past review comments, the empty string fallback after .toHex() ?? '' was discussed, and the developer confirmed that users should only reach this point with valid pubkeys.

Also applies to: 140-141, 159-159


180-198: LGTM: All UserProfile field accesses updated correctly.

Throughout the rest of the file, all references have been consistently updated to use widget.userProfile and its fields:

  • Follow/unfollow logic uses userProfile.publicKey and userProfile.displayName
  • Add to group functionality checks userProfile.publicKey
  • UI components access userProfile.imagePath, userProfile.displayName, userProfile.nip05, etc.
  • Child widgets receive the userProfile object

All changes are consistent and correct.

Also applies to: 201-205, 210-226, 258-258

lib/ui/user_profile_list/widgets/user_profile_tile.dart (3)

4-4: LGTM: Class and field renamed correctly.

The widget has been renamed from ContactListTile to UserProfileTile, and the field has been renamed from contact to userProfile. The import and constructor have been updated accordingly.

Also applies to: 13-14, 23-24


41-41: LGTM: Public key access updated correctly.

The method now correctly accesses userProfile.publicKey instead of the old contact field.

Also applies to: 45-45


51-75: LGTM: Widget implementation updated correctly.

All field accesses throughout the widget have been updated to use userProfile:

  • Avatar displays userProfile.imagePath and userProfile.displayName
  • Display name text shows userProfile.displayName
  • Variable renamed from contactTile to userProfileTile

The loading widget has also been renamed from ContactListTileLoading to UserProfileTileLoading.

All changes are consistent and correct.

Also applies to: 131-131, 135-136

lib/ui/user_profile_list/new_group_chat_sheet.dart (1)

7-7: LGTM! Comprehensive and consistent refactor.

The refactor from ContactModel to UserProfile is thorough and consistent across:

  • Import statements updated to reference user profile models and components
  • Constructor parameters (preSelectedContactspreSelectedUserProfiles)
  • State fields (_selectedContacts_selectedUserProfiles)
  • Method signatures and implementations (_toggleUserProfileSelection, _buildUserProfilesList, _getFilteredUserProfiles)
  • UI component usage (ContactListTileUserProfileTile)
  • Data mapping (ContactModel.fromMetadataUserProfile.fromMetadata)
  • User-facing text (search hints, error messages)

All type declarations are explicit, naming conventions follow camelCase for variables and PascalCase for classes, and the code maintains single responsibility per function as per coding guidelines.

Also applies to: 16-17, 23-23, 25-25, 33-33, 43-43, 52-52, 58-61, 93-101, 103-128, 130-162, 169-172, 183-183, 222-222, 244-244, 248-253

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

13-14: LGTM! Thorough and consistent refactor.

The refactor from ContactModel to UserProfile is complete and consistent across:

  • Import statements (updated to user_profile_provider, user_profile.dart, UserProfileTile)
  • State fields (_tempContact_tempUserProfile, _isLoadingUserProfileData_isLoadingUserProfile)
  • Method signatures (_getUserProfileDataForPublicKey_getUserProfileForPublicKey, _handleContactTap_handleUserProfileTap)
  • Provider usage (userProfileDataProvideruserProfileProvider, getUserProfileDatagetUserProfile)
  • Route references (Routes.contactQrScanRoutes.userProfileQrScan)
  • UI components (ContactListTileUserProfileTile, _LoadingContactList_LoadingUserProfileList)
  • Data mapping (ContactModel.fromMetadataUserProfile.fromMetadata)
  • Variable naming throughout list building and filtering logic
  • Log messages and user-facing text

All type declarations are explicit, naming conventions are consistent with coding guidelines, and the code maintains proper separation of concerns.

Also applies to: 23-25, 54-55, 103-103, 108-108, 128-128, 147-176, 178-205, 209-209, 261-276, 284-410, 420-432, 443-443, 488-491, 546-560

lib/locales/tr.json (1)

100-100: LGTM! Localization updates are consistent and grammatically correct.

The Turkish translations have been properly updated to reflect the terminology shift from "contacts" (kişiler) to "users" (kullanıcılar). Key updates include:

  • Line 100: Updated to reference "aktarıcılar" (relays) and "yeni kullanıcılarla güvenli sohbetler" (secure chats with new users)
  • Lines 135-137: Search placeholder and error messages updated to user-centric terminology
  • Line 158: Profile ready description updated with contextually appropriate phrasing
  • Line 161: Search match message updated to reference users
  • Line 169: Placeholder variable renamed from {contactName} to {userName}
  • Line 247: Ready-for-messaging text updated to reference users

All translations are grammatically correct and semantically appropriate for the Turkish language context.

Also applies to: 135-137, 158-158, 161-161, 169-169, 247-247

@josefinalliende josefinalliende force-pushed the refactor/remove-contact-word branch from 3c6ca9d to 80bbb91 Compare October 13, 2025 00:48
@josefinalliende josefinalliende force-pushed the refactor/remove-contact-word branch from 80bbb91 to e1214cd Compare October 13, 2025 00:51
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

🧹 Nitpick comments (1)
lib/ui/chat/widgets/message_widget.dart (1)

316-375: LGTM! Consider reducing duplication (optional).

The color property changes are correct and consistent. However, the color selection logic is duplicated four times within the Platform.isIOS conditional blocks.

To reduce duplication, consider extracting the color selection into a local variable at the start of the build method:

final reactionTextColor = message.isMe 
    ? context.colors.meChatBubbleText 
    : context.colors.otherChatBubbleText;

Then reference reactionTextColor in all four text style declarations.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3c6ca9d and e1214cd.

⛔ Files ignored due to path filters (1)
  • ios/Podfile.lock is excluded by !**/*.lock
📒 Files selected for processing (61)
  • CHANGELOG.md (1 hunks)
  • lib/config/providers/create_group_provider.dart (8 hunks)
  • lib/config/providers/group_messages_provider.dart (2 hunks)
  • lib/config/providers/group_provider.dart (1 hunks)
  • lib/config/providers/user_profile_data_provider.dart (0 hunks)
  • lib/config/providers/user_profile_provider.dart (1 hunks)
  • lib/config/states/create_group_state.dart (3 hunks)
  • lib/config/states/create_group_state.freezed.dart (14 hunks)
  • lib/config/states/localization_state.freezed.dart (3 hunks)
  • lib/domain/models/user_profile.dart (5 hunks)
  • lib/domain/services/dm_chat_service.dart (2 hunks)
  • lib/locales/de.json (4 hunks)
  • lib/locales/en.json (4 hunks)
  • lib/locales/es.json (5 hunks)
  • lib/locales/fr.json (4 hunks)
  • lib/locales/it.json (4 hunks)
  • lib/locales/pt.json (4 hunks)
  • lib/locales/ru.json (4 hunks)
  • lib/locales/tr.json (4 hunks)
  • lib/routing/router_provider.dart (4 hunks)
  • lib/routing/routes.dart (2 hunks)
  • lib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dart (2 hunks)
  • lib/ui/chat/chat_info/widgets/member_action_buttons.dart (1 hunks)
  • lib/ui/chat/chat_management/add_to_group_screen.dart (5 hunks)
  • lib/ui/chat/chat_management/widgets/create_group_dialog.dart (3 hunks)
  • lib/ui/chat/chat_screen.dart (3 hunks)
  • lib/ui/chat/invite/chat_invite_screen.dart (5 hunks)
  • lib/ui/chat/widgets/chat_header_widget.dart (1 hunks)
  • lib/ui/chat/widgets/message_widget.dart (8 hunks)
  • lib/ui/chat/widgets/user_profile_info.dart (1 hunks)
  • lib/ui/core/themes/src/colors.dart (7 hunks)
  • lib/ui/core/themes/src/colors_dark.dart (1 hunks)
  • lib/ui/core/themes/src/colors_light.dart (1 hunks)
  • lib/ui/core/themes/src/light/extensions.dart (1 hunks)
  • lib/ui/settings/general_settings_screen.dart (2 hunks)
  • lib/ui/settings/profile/share_profile_qr_scan_screen.dart (2 hunks)
  • lib/ui/settings/profile/switch_profile_bottom_sheet.dart (6 hunks)
  • lib/ui/settings/widgets/active_account_tile.dart (2 hunks)
  • lib/ui/user_profile_list/chat_list_screen.dart (1 hunks)
  • lib/ui/user_profile_list/group_chat_details_sheet.dart (7 hunks)
  • lib/ui/user_profile_list/new_chat_bottom_sheet.dart (17 hunks)
  • lib/ui/user_profile_list/new_group_chat_sheet.dart (8 hunks)
  • lib/ui/user_profile_list/services/welcome_notification_service.dart (1 hunks)
  • lib/ui/user_profile_list/share_invite_bottom_sheet.dart (3 hunks)
  • lib/ui/user_profile_list/start_chat_bottom_sheet.dart (10 hunks)
  • lib/ui/user_profile_list/widgets/chat_list_active_account_avatar.dart (3 hunks)
  • lib/ui/user_profile_list/widgets/chat_list_item_tile.dart (1 hunks)
  • lib/ui/user_profile_list/widgets/profile_ready_card.dart (1 hunks)
  • lib/ui/user_profile_list/widgets/share_invite_callout.dart (1 hunks)
  • lib/ui/user_profile_list/widgets/user_profile_card.dart (1 hunks)
  • lib/ui/user_profile_list/widgets/user_profile_tile.dart (4 hunks)
  • lib/ui/user_profile_list/widgets/welcome_tile.dart (2 hunks)
  • lib/utils/error_handling.dart (0 hunks)
  • local-research/go_router_implementation_plan.md (0 hunks)
  • test/config/providers/group_messages_provider_test.dart (7 hunks)
  • test/config/providers/user_profile_provider_test.dart (8 hunks)
  • test/ui/contact_list/services/welcome_notification_service_simple_test.dart (1 hunks)
  • test/ui/contact_list/share_invite_bottom_sheet_test.dart (6 hunks)
  • test/ui/contact_list/start_chat_bottom_sheet_test.dart (11 hunks)
  • test/ui/contact_list/widgets/share_invite_callout_test.dart (1 hunks)
  • test/ui/contact_list/widgets/user_profile_card_test.dart (6 hunks)
💤 Files with no reviewable changes (3)
  • lib/config/providers/user_profile_data_provider.dart
  • local-research/go_router_implementation_plan.md
  • lib/utils/error_handling.dart
✅ Files skipped from review due to trivial changes (1)
  • lib/config/providers/group_provider.dart
🚧 Files skipped from review as they are similar to previous changes (22)
  • lib/ui/chat/widgets/chat_header_widget.dart
  • lib/ui/core/themes/src/colors_light.dart
  • lib/ui/user_profile_list/widgets/profile_ready_card.dart
  • lib/config/providers/group_messages_provider.dart
  • lib/domain/services/dm_chat_service.dart
  • lib/config/states/localization_state.freezed.dart
  • lib/ui/core/themes/src/colors_dark.dart
  • lib/domain/models/user_profile.dart
  • lib/ui/core/themes/src/colors.dart
  • lib/ui/chat/widgets/user_profile_info.dart
  • lib/ui/settings/profile/share_profile_qr_scan_screen.dart
  • lib/ui/chat/chat_management/widgets/create_group_dialog.dart
  • lib/locales/de.json
  • CHANGELOG.md
  • lib/config/states/create_group_state.dart
  • lib/ui/chat/invite/chat_invite_screen.dart
  • lib/routing/router_provider.dart
  • lib/ui/chat/chat_screen.dart
  • lib/ui/user_profile_list/services/welcome_notification_service.dart
  • lib/ui/user_profile_list/widgets/share_invite_callout.dart
  • lib/config/providers/user_profile_provider.dart
  • lib/ui/user_profile_list/widgets/welcome_tile.dart
🧰 Additional context used
📓 Path-based instructions (3)
**/*.dart

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

**/*.dart: Always declare the type of each variable and function (parameters and return value)
Avoid using dynamic and Object without justification
Create necessary types instead of overusing primitives or dynamic
One export per file
Use PascalCase for classes
Use camelCase for variables, functions, and methods
Avoid magic numbers and define constants
Start each function name with a verb
Use verbs for boolean variables (e.g., isLoading, hasError, canDelete)
Write short functions with a single purpose (under ~20 instructions)
Name functions with a verb plus context; for booleans use isX/hasX/canX; for void use executeX/saveX
Avoid deep nesting via early returns and extraction to utility functions
Use higher-order functions (map, where/filter, reduce) to avoid nesting
Use arrow functions for simple functions (under ~3 statements); use named functions otherwise
Use default parameter values instead of null checks
Reduce function parameters using RO-RO: pass/return parameter objects with declared types
Maintain a single level of abstraction within functions
Encapsulate data in composite types; avoid overusing primitives
Prefer validating data within classes rather than in functions
Prefer immutability; use final for runtime constants and const for compile-time constants
Use const constructors and const literals where possible
Follow SOLID principles
Prefer composition over inheritance
Declare interfaces (abstract classes) to define contracts
Write small classes with a single purpose (under ~200 instructions, <10 public methods, <10 properties)
Use exceptions for unexpected errors
Only catch exceptions to fix expected problems or add context; otherwise use a global handler

Files:

  • lib/ui/user_profile_list/widgets/user_profile_card.dart
  • lib/ui/chat/chat_info/widgets/member_action_buttons.dart
  • test/ui/contact_list/widgets/share_invite_callout_test.dart
  • lib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dart
  • lib/ui/settings/general_settings_screen.dart
  • test/ui/contact_list/widgets/user_profile_card_test.dart
  • lib/ui/chat/chat_management/add_to_group_screen.dart
  • lib/ui/user_profile_list/chat_list_screen.dart
  • lib/ui/user_profile_list/share_invite_bottom_sheet.dart
  • lib/ui/settings/widgets/active_account_tile.dart
  • lib/routing/routes.dart
  • lib/ui/user_profile_list/start_chat_bottom_sheet.dart
  • test/ui/contact_list/share_invite_bottom_sheet_test.dart
  • lib/config/providers/create_group_provider.dart
  • lib/ui/user_profile_list/widgets/chat_list_item_tile.dart
  • lib/config/states/create_group_state.freezed.dart
  • lib/ui/user_profile_list/widgets/user_profile_tile.dart
  • lib/ui/user_profile_list/new_chat_bottom_sheet.dart
  • lib/ui/settings/profile/switch_profile_bottom_sheet.dart
  • test/ui/contact_list/start_chat_bottom_sheet_test.dart
  • lib/ui/user_profile_list/new_group_chat_sheet.dart
  • lib/ui/user_profile_list/widgets/chat_list_active_account_avatar.dart
  • test/config/providers/group_messages_provider_test.dart
  • lib/ui/chat/widgets/message_widget.dart
  • test/ui/contact_list/services/welcome_notification_service_simple_test.dart
  • test/config/providers/user_profile_provider_test.dart
  • lib/ui/user_profile_list/group_chat_details_sheet.dart
  • lib/ui/core/themes/src/light/extensions.dart
lib/**/*.dart

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

lib/**/*.dart: Use flutter_rust_bridge to access core app functionality
Use Riverpod for state management; prefer StreamProviders for Rust API streams; use keepAlive if needed
Use freezed to model/manage UI states
Controllers should expose methods as inputs and update UI state that drives the UI
Use AutoRoute for navigation and use extras to pass data between pages
Use Dart extensions to manage reusable code
Use ThemeData to manage themes
Use AppLocalizations for translations
Use constants to manage constant values
Avoid deeply nested widget trees; aim for a flatter widget structure for performance and readability
Break down large widgets into smaller, focused, reusable components
Keep the widget tree shallow to simplify state management and data flow
Utilize const constructors and const widgets wherever possible to reduce rebuilds

Files:

  • lib/ui/user_profile_list/widgets/user_profile_card.dart
  • lib/ui/chat/chat_info/widgets/member_action_buttons.dart
  • lib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dart
  • lib/ui/settings/general_settings_screen.dart
  • lib/ui/chat/chat_management/add_to_group_screen.dart
  • lib/ui/user_profile_list/chat_list_screen.dart
  • lib/ui/user_profile_list/share_invite_bottom_sheet.dart
  • lib/ui/settings/widgets/active_account_tile.dart
  • lib/routing/routes.dart
  • lib/ui/user_profile_list/start_chat_bottom_sheet.dart
  • lib/config/providers/create_group_provider.dart
  • lib/ui/user_profile_list/widgets/chat_list_item_tile.dart
  • lib/config/states/create_group_state.freezed.dart
  • lib/ui/user_profile_list/widgets/user_profile_tile.dart
  • lib/ui/user_profile_list/new_chat_bottom_sheet.dart
  • lib/ui/settings/profile/switch_profile_bottom_sheet.dart
  • lib/ui/user_profile_list/new_group_chat_sheet.dart
  • lib/ui/user_profile_list/widgets/chat_list_active_account_avatar.dart
  • lib/ui/chat/widgets/message_widget.dart
  • lib/ui/user_profile_list/group_chat_details_sheet.dart
  • lib/ui/core/themes/src/light/extensions.dart
test/**/*.dart

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

test/**/*.dart: Follow Arrange-Act-Assert in tests
Name test variables clearly using inputX, mockX, actualX, expectedX
Write unit tests for each public function; use test doubles for dependencies (except cheap third-party)
Use standard Flutter widget testing

Files:

  • test/ui/contact_list/widgets/share_invite_callout_test.dart
  • test/ui/contact_list/widgets/user_profile_card_test.dart
  • test/ui/contact_list/share_invite_bottom_sheet_test.dart
  • test/ui/contact_list/start_chat_bottom_sheet_test.dart
  • test/config/providers/group_messages_provider_test.dart
  • test/ui/contact_list/services/welcome_notification_service_simple_test.dart
  • test/config/providers/user_profile_provider_test.dart
🧠 Learnings (8)
📚 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/settings/general_settings_screen.dart
  • test/ui/contact_list/widgets/user_profile_card_test.dart
  • lib/ui/chat/chat_management/add_to_group_screen.dart
  • lib/ui/settings/widgets/active_account_tile.dart
  • lib/ui/user_profile_list/start_chat_bottom_sheet.dart
  • lib/config/providers/create_group_provider.dart
  • lib/ui/user_profile_list/new_chat_bottom_sheet.dart
  • lib/ui/settings/profile/switch_profile_bottom_sheet.dart
  • test/ui/contact_list/start_chat_bottom_sheet_test.dart
  • lib/ui/user_profile_list/new_group_chat_sheet.dart
  • lib/ui/user_profile_list/widgets/chat_list_active_account_avatar.dart
  • test/config/providers/group_messages_provider_test.dart
  • test/config/providers/user_profile_provider_test.dart
  • lib/ui/user_profile_list/group_chat_details_sheet.dart
📚 Learning: 2025-10-12T22:44:49.592Z
Learnt from: CR
PR: parres-hq/whitenoise_flutter#0
File: .cursor/rules/flutter.mdc:0-0
Timestamp: 2025-10-12T22:44:49.592Z
Learning: Applies to test/**/*.dart : Use standard Flutter widget testing

Applied to files:

  • test/ui/contact_list/widgets/user_profile_card_test.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/user_profile_list/start_chat_bottom_sheet.dart
  • lib/ui/user_profile_list/group_chat_details_sheet.dart
📚 Learning: 2025-08-12T11:21:53.640Z
Learnt from: josefinalliende
PR: parres-hq/whitenoise_flutter#455
File: lib/ui/settings/profile/switch_profile_bottom_sheet.dart:0-0
Timestamp: 2025-08-12T11:21:53.640Z
Learning: In the whitenoise_flutter codebase, ContactModel.publicKey can be stored in either npub format (from metadata cache) or hex format (from account storage). The activeAccountProvider may return either format depending on how the account was originally stored, so normalization to hex format is required when comparing with other hex-normalized keys in sorting logic.

Applied to files:

  • lib/ui/user_profile_list/start_chat_bottom_sheet.dart
  • lib/ui/user_profile_list/widgets/user_profile_tile.dart
  • lib/ui/settings/profile/switch_profile_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/user_profile_list/start_chat_bottom_sheet.dart
  • lib/config/providers/create_group_provider.dart
  • test/config/providers/group_messages_provider_test.dart
  • lib/ui/user_profile_list/group_chat_details_sheet.dart
📚 Learning: 2025-09-03T20:57:53.202Z
Learnt from: josefinalliende
PR: parres-hq/whitenoise_flutter#594
File: lib/config/providers/user_profile_data_provider.dart:0-0
Timestamp: 2025-09-03T20:57:53.202Z
Learning: In the whitenoise_flutter codebase, pubkey normalization (npub/hex format handling) is implemented in a pubkey validations extension rather than being imported directly into individual providers like user_profile_data_provider.dart.

Applied to files:

  • lib/ui/user_profile_list/start_chat_bottom_sheet.dart
📚 Learning: 2025-10-12T22:44:49.592Z
Learnt from: CR
PR: parres-hq/whitenoise_flutter#0
File: .cursor/rules/flutter.mdc:0-0
Timestamp: 2025-10-12T22:44:49.592Z
Learning: Applies to lib/**/*.dart : Use Riverpod for state management; prefer StreamProviders for Rust API streams; use keepAlive if needed

Applied to files:

  • lib/ui/user_profile_list/start_chat_bottom_sheet.dart
📚 Learning: 2025-09-04T17:54:09.162Z
Learnt from: josefinalliende
PR: parres-hq/whitenoise_flutter#594
File: lib/ui/chat/chat_info/dm_chat_info.dart:0-0
Timestamp: 2025-09-04T17:54:09.162Z
Learning: In the whitenoise_flutter codebase, pubkey conversion from hex to npub format is handled using a .toNpub() extension method on String, which eliminates the need for manual format checking or calling npubFromHexPubkey() function directly.

Applied to files:

  • lib/ui/user_profile_list/group_chat_details_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 (32)
test/ui/contact_list/services/welcome_notification_service_simple_test.dart (1)

5-5: LGTM! Import path updated correctly.

The import path change from contact_list to user_profile_list aligns with the PR's refactoring goal.

Note: The test file itself remains under test/ui/contact_list/ directory. Based on the PR description mentioning that some widgets remain in place pending discussion #694, this appears intentional. Consider moving this test file to test/ui/user_profile_list/ in a follow-up if the service has fully migrated.

lib/ui/core/themes/src/light/extensions.dart (1)

32-34: All color field renames are consistent.

No remaining references to contactChatBubble/contactChatBubbleText; AppColorsThemeExt, LightAppColors, DarkAppColors, and widget usages have been updated accordingly.

lib/ui/chat/widgets/message_widget.dart (1)

50-50: LGTM — color key rename verified
The rename of contactChatBubble/contactChatBubbleText to otherChatBubble/otherChatBubbleText is consistent, all new keys are defined, and no contactChatBubble references remain.

lib/ui/settings/widgets/active_account_tile.dart (1)

7-7: LGTM! Clean refactor to UserProfile terminology.

The changes consistently update from ContactModel to UserProfile, replacing ContactListTile with UserProfileTile. The logic remains unchanged—profile data is still constructed from metadata and rendered in the tile.

Also applies to: 12-12, 18-23, 32-33

lib/ui/chat/chat_info/widgets/member_action_buttons.dart (1)

98-104: LGTM! Widget renamed to reflect user-centric terminology.

The rename from AddToContactButton to FollowToggleButton better reflects the domain model shift while preserving all follow/unfollow functionality.

lib/ui/user_profile_list/widgets/chat_list_active_account_avatar.dart (1)

6-7: LGTM! Provider and model updated consistently.

The changes update to the new userProfileProvider and UserProfile model. The data loading and rendering logic remains unchanged.

Also applies to: 25-25, 54-56

lib/ui/user_profile_list/widgets/user_profile_tile.dart (1)

4-4: LGTM! Tile widget comprehensively updated.

The widget and its loading state have been consistently renamed from ContactListTile to UserProfileTile, with all field accesses updated from contact to userProfile. The rendering logic remains unchanged.

Also applies to: 13-33, 41-45, 51-75, 135-136

lib/ui/user_profile_list/chat_list_screen.dart (1)

27-31: LGTM! Import paths updated for directory refactor.

The imports have been updated from contact_list to user_profile_list to reflect the directory restructure. No logic changes.

lib/ui/user_profile_list/widgets/chat_list_item_tile.dart (1)

18-19: LGTM! Import paths updated for widget relocation.

The imports have been updated to reference the widgets in their new user_profile_list location. No logic changes.

lib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dart (1)

249-249: LGTM! Widget references updated to FollowToggleButton.

The references to AddToContactButton have been updated to use the renamed FollowToggleButton in both the admin and non-admin branches. Functionality is preserved.

Also applies to: 296-296

lib/ui/user_profile_list/widgets/user_profile_card.dart (1)

13-27: LGTM! Widget renamed to avoid domain model conflict.

The class has been renamed from UserProfile to UserProfileCard to avoid naming conflict with the new UserProfile domain model (lib/domain/models/user_profile.dart). The "Card" suffix appropriately distinguishes this UI widget from the domain entity.

test/config/providers/user_profile_provider_test.dart (1)

1-198: LGTM!

The test file has been successfully updated to reflect the ContactModel → UserProfile refactoring. All test cases, mock data, and provider references are consistent with the new naming convention. The test coverage remains comprehensive and properly validates the UserProfileNotifier functionality.

lib/ui/settings/general_settings_screen.dart (2)

10-10: LGTM!

Import path correctly updated to reflect the UserProfile model.


86-89: LGTM!

The callback parameter type has been correctly updated from ContactModel to UserProfile, maintaining compatibility with the publicKey field access in line 87.

test/ui/contact_list/share_invite_bottom_sheet_test.dart (1)

1-99: LGTM!

The test file has been successfully updated to use UserProfile instead of ContactModel. All test cases properly exercise the ShareInviteBottomSheet widget with the updated API:

  • Test data migrated to UserProfile
  • Widget constructor calls use userProfiles parameter
  • All assertions remain valid and comprehensive
test/ui/contact_list/widgets/user_profile_card_test.dart (1)

1-112: LGTM!

The test file correctly distinguishes between the UserProfile data model and the UserProfileCard UI component. All test wrapper references, group names, and widget instantiations have been consistently updated. The test coverage remains comprehensive.

test/ui/contact_list/start_chat_bottom_sheet_test.dart (1)

1-309: LGTM!

The test file has been thoroughly updated to use UserProfile instead of ContactModel. All test scenarios are properly migrated:

  • Test data construction uses UserProfile
  • Widget instantiations use userProfile parameter
  • Mock provider data correctly references userProfile.publicKey
  • Group names and test descriptions updated to reflect the new terminology
  • Test coverage remains comprehensive
test/ui/contact_list/widgets/share_invite_callout_test.dart (1)

1-55: LGTM!

The test file has been consistently updated to use UserProfile terminology:

  • Imports point to the correct paths
  • Setup function signature accepts UserProfile
  • Widget instantiations use userProfile parameter
  • Test groups and data construction reflect the new model
  • All test cases remain valid
lib/routing/routes.dart (1)

17-44: LGTM!

The routing constants and helper methods have been consistently updated to reflect the user-centric terminology:

  • Route paths changed from /contacts to /users
  • Helper method goToContact renamed to goToUser with parameter name updated to userId
  • QR scan route appropriately uses user_profiles prefix to differentiate the feature namespace from the user entity routes
lib/ui/user_profile_list/share_invite_bottom_sheet.dart (1)

1-94: LGTM!

The file has been thoroughly refactored to use UserProfile terminology:

  • All imports updated to user_profile_list paths
  • Public API (userProfiles parameter) consistently updated in constructor and static show() method
  • Internal variables renamed from contacts to userProfiles
  • UI components switched to UserProfile variants (UserProfileCard, UserProfileTile, ShareInviteCallout)
  • Localization keys updated to reflect user-centric messaging
  • The unused onInviteSent callback mentioned in past reviews has been properly addressed (removed)
lib/config/providers/create_group_provider.dart (1)

55-75: Convert userProfile keys to hex before calling Rust APIs

userHasKeyPackage and createNewGroup both expect hex keys. Passing UserProfile.publicKey directly reintroduces the npub/hex mismatch we just eliminated elsewhere: profiles stored in npub format will always be treated as lacking a key package, and group creation will fail because the member list contains invalid hex strings. Please normalize every key with PubkeyFormatter before calling the Rust layer.

@@
-import 'package:whitenoise/domain/models/user_profile.dart';
+import 'package:whitenoise/domain/models/user_profile.dart';
+import 'package:whitenoise/utils/pubkey_formatter.dart';
@@
-      final filteredUserProfiles = await _filterUserProfilesByKeyPackage(selectedUserProfiles);
+      final filteredUserProfiles = await _filterUserProfilesByKeyPackage(selectedUserProfiles);
@@
-Future<Group?> _createGroupWithUserProfiles(List<UserProfile> userProfilesWithKeyPackage) async {
+Future<Group?> _createGroupWithUserProfiles(List<UserProfile> userProfilesWithKeyPackage) async {
@@
-    return await notifier.createNewGroup(
+    final memberHexPubkeys = userProfilesWithKeyPackage
+        .map((profile) => PubkeyFormatter(pubkey: profile.publicKey).toHex())
+        .whereType<String>()
+        .where((hex) => hex.isNotEmpty)
+        .toList();
+
+    if (memberHexPubkeys.isEmpty) {
+      _logger.warning('No valid public keys found for group creation');
+      return null;
+    }
+
+    return await notifier.createNewGroup(
@@
-      memberPublicKeyHexs: userProfilesWithKeyPackage.map((c) => c.publicKey).toList(),
+      memberPublicKeyHexs: memberHexPubkeys,
@@
-        final hasKeyPackage = await userHasKeyPackage(pubkey: userProfile.publicKey);
+        final String? userHex = PubkeyFormatter(pubkey: userProfile.publicKey).toHex();
+        if (userHex == null || userHex.isEmpty) {
+          userProfilesWithoutKeyPackage.add(userProfile);
+          continue;
+        }
+
+        final hasKeyPackage = await userHasKeyPackage(pubkey: userHex);

Also applies to: 139-214

⛔ Skipped due to learnings
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.
Learnt from: josefinalliende
PR: parres-hq/whitenoise_flutter#594
File: lib/config/providers/user_profile_data_provider.dart:0-0
Timestamp: 2025-09-03T20:57:53.202Z
Learning: In the whitenoise_flutter codebase, pubkey normalization (npub/hex format handling) is implemented in a pubkey validations extension rather than being imported directly into individual providers like user_profile_data_provider.dart.
test/config/providers/group_messages_provider_test.dart (2)

1-33: LGTM! Test infrastructure updated correctly.

The test mock and imports have been properly updated to reflect the ContactModel → UserProfile refactor. The mock class now extends UserProfileNotifier and correctly handles Map<String, UserProfile> data.


83-279: LGTM! Test data and setup aligned with UserProfile model.

All test fixtures, container configurations, and test setup have been correctly updated to use UserProfile instead of ContactModel. The tests maintain their original coverage while adapting to the new domain model.

lib/ui/user_profile_list/new_group_chat_sheet.dart (3)

21-46: LGTM! Public API updated consistently.

The constructor and static show method have been properly updated to accept List<UserProfile> instead of contacts. The parameter naming is clear and aligns with the domain model refactor.


49-162: LGTM! Internal state and logic properly updated.

The internal state management, selection handling, and filtering logic have been correctly updated to work with UserProfile. The filter method maintains the same filtering behavior (by displayName, nip05, and publicKey) while operating on the new model.


164-263: LGTM! UI rendering and data flow updated correctly.

The UI rendering has been properly updated to use UserProfileTile components and the data flow from follows to UserProfile is correctly implemented using UserProfile.fromMetadata. User-facing text has been appropriately updated to reflect user profile terminology.

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

48-176: LGTM! State management and data fetching updated correctly.

The state variables and data fetching logic have been properly updated to handle UserProfile instead of contacts. The _getUserProfileForPublicKey method correctly uses the userProfileProvider to fetch user profile data.


178-282: LGTM! User interaction handlers updated consistently.

The tap handlers and navigation have been correctly updated to work with UserProfile. The route to Routes.userProfileQrScan aligns with the domain model changes. The support user profile handling maintains the same fallback behavior while using the new model.


284-560: LGTM! UI rendering comprehensively updated.

The list building and rendering logic has been thoroughly updated to handle UserProfile data. The _buildUserProfilesList method correctly renders UserProfileTile components, and the loading state widget has been appropriately renamed to _LoadingUserProfileList.

lib/ui/user_profile_list/group_chat_details_sheet.dart (3)

22-68: LGTM! Public API and initialization updated correctly.

The constructor and static show method have been properly updated to accept List<UserProfile>. The initialization correctly delegates the filtering of user profiles with key packages to the provider notifier.


82-123: LGTM! Group creation flow updated correctly.

The group creation and invite flow have been properly updated to work with user profiles. The method correctly delegates to createGroupProvider.notifier.createGroup() and handles the invite sheet with userProfilesWithoutKeyPackage. Based on the resolved past review comment, pubkey hex conversion is now correctly handled at the provider level.


135-302: LGTM! UI rendering updated to use UserProfile model.

The UI rendering has been properly updated to display user profiles. The invite sheet trigger condition correctly checks userProfilesWithoutKeyPackage, and the member display section properly renders user profile data (avatar, display name) from the userProfilesWithKeyPackage list.

Quwaysim
Quwaysim previously approved these changes Oct 14, 2025
Copy link
Contributor

@Quwaysim Quwaysim left a comment

Choose a reason for hiding this comment

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

Phew! I need to go treat myself to a cup of coffee 😂

Great work @josefinalliende. LGTM 🚀

Copy link
Contributor

@untreu2 untreu2 left a comment

Choose a reason for hiding this comment

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

LGTM ✅

@josefinalliende josefinalliende merged commit a500098 into master Oct 14, 2025
2 checks passed
@josefinalliende josefinalliende deleted the refactor/remove-contact-word branch October 14, 2025 15:19
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.

Remove or rename Contacts everywhere

5 participants