-
Notifications
You must be signed in to change notification settings - Fork 13
refactor: replace contact word for user profile #710
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughRenames 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
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
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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (1)
🧰 Additional context used📓 Path-based instructions (3)**/*.dart📄 CodeRabbit inference engine (.cursor/rules/flutter.mdc)
Files:
lib/**/*.dart📄 CodeRabbit inference engine (.cursor/rules/flutter.mdc)
Files:
**/*.md📄 CodeRabbit inference engine (.cursor/rules/whitenoise.mdc)
Files:
⏰ 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)
🔇 Additional comments (4)
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. Comment |
6ee52d5 to
f791d93
Compare
There was a problem hiding this 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 accountEarly 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.
_getActivePubkeyHexkeeps the pubkey exactly as stored, but the active account can be persisted as npub while_isActiveAccountand 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 learningsFuture<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 errorsAvoid 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 FutureBuilderSame 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 callAPI 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 typedIt’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 IDsAvoid 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
📒 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 likeNIP-XXwhereXXare two capitalized hexadecimal digits, e.g.,NIP-01andNIP-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.,07for NIP-07, orC7for 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.mdfor 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.dartlib/ui/chat/widgets/user_profile_info.dartlib/config/providers/user_profile_provider.dartlib/routing/router_provider.darttest/ui/contact_list/share_invite_bottom_sheet_test.dartlib/ui/user_profile_list/widgets/user_profile_card.dartlib/ui/settings/network/network_screen.dartlib/ui/chat/chat_screen.dartlib/ui/user_profile_list/widgets/share_invite_callout.dartlib/ui/core/themes/src/colors.dartlib/domain/services/dm_chat_service.dartlib/ui/core/themes/src/light/extensions.darttest/ui/contact_list/services/welcome_notification_service_simple_test.dartlib/ui/chat/chat_info/widgets/member_action_buttons.dartlib/config/providers/group_messages_provider.dartlib/ui/core/themes/src/colors_dark.dartlib/ui/user_profile_list/widgets/welcome_tile.dartlib/ui/settings/widgets/active_account_tile.dartlib/ui/user_profile_list/start_chat_bottom_sheet.dartlib/config/providers/group_provider.dartlib/ui/user_profile_list/widgets/profile_ready_card.dartlib/ui/chat/widgets/message_widget.dartlib/ui/core/themes/src/colors_light.dartlib/domain/models/user_profile.dartlib/ui/chat/chat_management/widgets/create_group_dialog.dartlib/ui/settings/profile/switch_profile_bottom_sheet.dartlib/ui/user_profile_list/new_chat_bottom_sheet.dartlib/ui/user_profile_list/group_chat_details_sheet.dartlib/ui/user_profile_list/chat_list_screen.dartlib/ui/chat/widgets/chat_header_widget.darttest/config/providers/user_profile_provider_test.dartlib/ui/settings/profile/share_profile_qr_scan_screen.dartlib/ui/chat/invite/chat_invite_screen.dartlib/ui/user_profile_list/widgets/chat_list_item_tile.dartlib/routing/routes.dartlib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dartlib/ui/user_profile_list/share_invite_bottom_sheet.darttest/ui/contact_list/widgets/user_profile_test.dartlib/ui/user_profile_list/new_group_chat_sheet.dartlib/ui/settings/general_settings_screen.dartlib/ui/user_profile_list/widgets/chat_list_active_account_avatar.darttest/ui/contact_list/start_chat_bottom_sheet_test.dartlib/ui/user_profile_list/widgets/user_profile_tile.darttest/ui/contact_list/widgets/share_invite_callout_test.darttest/config/providers/group_messages_provider_test.dartlib/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.darttest/ui/contact_list/services/welcome_notification_service_simple_test.darttest/config/providers/user_profile_provider_test.darttest/ui/contact_list/widgets/user_profile_test.darttest/ui/contact_list/start_chat_bottom_sheet_test.darttest/ui/contact_list/widgets/share_invite_callout_test.darttest/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.dartlib/ui/user_profile_list/widgets/share_invite_callout.dartlib/domain/services/dm_chat_service.dartlib/config/providers/group_messages_provider.dartlib/ui/user_profile_list/widgets/welcome_tile.dartlib/ui/settings/widgets/active_account_tile.dartlib/ui/user_profile_list/start_chat_bottom_sheet.dartlib/ui/user_profile_list/widgets/profile_ready_card.dartlib/domain/models/user_profile.dartlib/ui/chat/chat_management/widgets/create_group_dialog.dartlib/ui/settings/profile/switch_profile_bottom_sheet.dartlib/ui/user_profile_list/new_chat_bottom_sheet.dartlib/ui/user_profile_list/group_chat_details_sheet.dartlib/ui/chat/widgets/chat_header_widget.darttest/config/providers/user_profile_provider_test.dartlib/ui/chat/invite/chat_invite_screen.darttest/ui/contact_list/widgets/user_profile_test.dartlib/ui/user_profile_list/new_group_chat_sheet.dartlib/ui/settings/general_settings_screen.dartlib/ui/user_profile_list/widgets/chat_list_active_account_avatar.darttest/ui/contact_list/start_chat_bottom_sheet_test.dartlib/ui/user_profile_list/widgets/user_profile_tile.darttest/config/providers/group_messages_provider_test.dartlib/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.darttest/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.dartlib/ui/settings/profile/switch_profile_bottom_sheet.dartlib/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.dartlib/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/toui/user_profile_list/widgets/, aligning with the refactoring objective. Both imported widgets (MessageReadStatusandWelcomeTile) 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_listtouser_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/contactChatBubbleTexttootherChatBubble/otherChatBubbleTextare 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
AddToContactButtonwithAddToFollowsButtonaligns 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/contactChatBubbleTexttootherChatBubble/otherChatBubbleTextare 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
UserProfiletoUserProfileCardimproves clarity and avoids confusion with the domain modelUserProfile. 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_listtouser_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
contactChatBubbleandcontactChatBubbleTexthave been systematically replaced withotherChatBubbleandotherChatBubbleText. 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.fromMetadatainstead ofContactModel.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
ChatContactHeadertoChatUserHeaderaligns 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/ContactListTiletoUserProfile/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
ContactInfotoUserProfileInfo(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
ContactModeltoUserProfile. 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 inUserProfile; 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/contactstoUserProfile/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
UserProfileTestWrappertoUserProfileCardTestWrapperand updates the widget under test fromUserProfiletoUserProfileCard. 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/contacttoUserProfile/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
userProfileProviderinstead ofuserProfileDataProvider, callsgetUserProfileinstead ofgetUserProfileData, and passesuserProfiletoStartChatBottomSheet. 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
UserProfileNotifierproperly implements dependency injection for testability, with clear method names and explicit type declarations. ThegetUserProfilemethod correctly chains API calls to build aUserProfilefrom metadata.
31-33: LGTM! Provider correctly configured.The provider is properly set up with a factory function that creates a new
UserProfileNotifierinstance.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/contacttoUserProfile/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_providertouser_profile_providerand fromcontact_listtouser_profile_listcomponents.Also applies to: 23-25
53-54: LGTM! State variables correctly renamed.The state variables
_tempContact→_tempUserProfileand_isLoadingContact→_isLoadingUserProfileare 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
_getUserProfileForPublicKeymethod properly uses the newuserProfileProviderandgetUserProfileAPI. Error handling creates a fallbackUserProfilewith "Unknown User" display name, which maintains the existing behavior.
177-204: LGTM! Tap handler correctly updated.The
_handleUserProfileTapmethod is properly renamed from_handleContactTapand consistently usesUserProfiletype 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
UserProfileterminology:
_buildUserProfilesListand 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 correctGood 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 pathsCoverage 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 followProviderEnsure 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 bindingsBindings, 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 addToGroupmembersNpubs aligns with userNpub. Good change.
240-242: Membership check by key formatmembers.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
There was a problem hiding this 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
_loadKeyPackagemethod 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
_createOrOpenDirectMessageGroupmethod 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
📒 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.dartlib/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.dartlib/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
selectedUserProfilesinstead ofselectedContacts.
176-203: LGTM!Method correctly uses
PubkeyFormatterbefore calling the Rust API methoduserHasKeyPackage, 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
selectedUserProfilesand render withUserProfileTileinstead of the old contact-based widget.
43b8773 to
a2dda1a
Compare
There was a problem hiding this 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_activeAccountHexbefore sorting/highlighting.Line 134 now assigns the raw value from
activePubkeyProviderstraight 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 withPubkeyFormatter.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
memberPublicKeyHexsparameter expects hex-encoded pubkeys, but line 116 passes rawpublicKeyvalues without conversion. Your filtering method (lines 185-186) correctly usesPubkeyFormatter(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,
AddToFollowsButtonsuggests a one-directional action, while the implementation (line 137) shows the button toggles between "Follow" and "Unfollow". Consider renaming toFollowToggleButtonor simplyFollowButtonto 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.dartbut tests a widget fromlib/ui/user_profile_list/widgets/user_profile_card.dart. For consistency, consider moving the test totest/ui/user_profile_list/widgets/user_profile_card_test.dart.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 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.dartlib/ui/settings/widgets/active_account_tile.darttest/ui/contact_list/widgets/user_profile_test.dartlib/ui/settings/general_settings_screen.dartlib/ui/user_profile_list/widgets/welcome_tile.dartlib/routing/router_provider.dartlib/ui/chat/widgets/user_profile_info.dartlib/ui/user_profile_list/new_chat_bottom_sheet.dartlib/ui/chat/chat_management/add_to_group_screen.dartlib/ui/user_profile_list/share_invite_bottom_sheet.dartlib/ui/chat/widgets/message_widget.dartlib/ui/chat/chat_info/widgets/member_action_buttons.dartlib/ui/user_profile_list/group_chat_details_sheet.dartlib/routing/routes.dartlib/ui/settings/network/network_screen.dartlib/ui/user_profile_list/services/welcome_notification_service.dartlib/ui/core/themes/src/colors.dartlib/config/providers/group_provider.darttest/ui/contact_list/start_chat_bottom_sheet_test.dartlib/ui/user_profile_list/new_group_chat_sheet.darttest/config/providers/group_messages_provider_test.dartlib/ui/settings/profile/switch_profile_bottom_sheet.dartlib/ui/user_profile_list/chat_list_screen.dartlib/ui/user_profile_list/widgets/user_profile_card.dartlib/ui/user_profile_list/widgets/user_profile_tile.dartlib/ui/user_profile_list/widgets/chat_list_active_account_avatar.dartlib/ui/chat/invite/chat_invite_screen.dart
**/*.md
📄 CodeRabbit inference engine (.cursor/rules/whitenoise.mdc)
**/*.md: NIPs (Nostr Implementation Possibilities) are numbered likeNIP-XXwhereXXare two capitalized hexadecimal digits, e.g.,NIP-01andNIP-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.,07for NIP-07, orC7for 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.mdfor 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.darttest/ui/contact_list/start_chat_bottom_sheet_test.darttest/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.darttest/ui/contact_list/widgets/user_profile_test.dartlib/ui/settings/general_settings_screen.dartlib/ui/user_profile_list/new_chat_bottom_sheet.dartlib/ui/chat/chat_management/add_to_group_screen.dartlib/ui/user_profile_list/group_chat_details_sheet.darttest/ui/contact_list/start_chat_bottom_sheet_test.dartlib/ui/user_profile_list/new_group_chat_sheet.darttest/config/providers/group_messages_provider_test.dartlib/ui/settings/profile/switch_profile_bottom_sheet.dartlib/ui/user_profile_list/widgets/user_profile_tile.dartlib/ui/user_profile_list/widgets/chat_list_active_account_avatar.dartlib/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.dartlib/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_listtouser_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
ContactModeltoUserProfile. 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
ContactListTiletoUserProfileTilewith the parameter renamed fromcontacttouserProfile. 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_listtouser_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/contactChatBubbleTexttootherChatBubble/otherChatBubbleTextimprove 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
UserProfiletoUserProfileCardprevents 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
UserProfiletoUserProfileCard. 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
ContactInfotoUserProfileInfoaligns 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
getUserProfileDatatogetUserProfile- Variable naming updated from
welcomerContacttowelcomerUserProfileAll 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
ContactModeltoUserProfile. 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
ContactModeltoUserProfile. 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
UserProfilecollections. 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
ContactModeltoUserProfile. 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.getUserProfileDatatouserProfileProvider.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
contactIdtouserId.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/ContactInfotouserProfileProvider/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
UserProfiledata and the renamed methods (_handleUserProfileTap). Route navigation properly updated toRoutes.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
UserProfilecollections. 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
selectedContactstoselectedUserProfilesis 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
_filterUserProfilesByKeyPackagemethod anduserProfilesWithKeyPackage/userProfilesWithoutKeyPackagevariables.
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
PubkeyFormatterto 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
selectedUserProfileslist using theUserProfileTilewidget.lib/ui/user_profile_list/new_group_chat_sheet.dart (8)
22-22: LGTM!The field and parameter rename from
preSelectedContactstopreSelectedUserProfilesis 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
_selectedUserProfilesand 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
UserProfileTilewith 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, andpublicKeyfields of UserProfile.
168-171: LGTM!The mapping from follows to UserProfile objects using
UserProfile.fromMetadatais 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
selectedUserProfilestoGroupChatDetailsSheet.showas a List.
683e3fc to
2cf156f
Compare
There was a problem hiding this 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 createNewGroupUsing 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 hereThis 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 clarityExplicitly 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 fixtureKeep 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 selectorMatch 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 nothingReturning 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 copyMove 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 pathThe 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 pathsIf 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 + listenDefine 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 profileBoth 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 stringsReplace '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 styleDeclare 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 typesSmall 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 stringsMove 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 setStateCall 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 stringsUse 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 localizationUse 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 clarityAdd 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 updateSort 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 stringsLocalize 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 membershipmember.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 selectionRepeated 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 mapKeep 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 explicitlyUse 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 searchDebounced 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 logicComment 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 keysReturning 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
📒 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.dartlib/ui/user_profile_list/widgets/user_profile_card.dartlib/ui/chat/widgets/message_widget.dartlib/ui/user_profile_list/services/welcome_notification_service.dartlib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dartlib/ui/chat/widgets/user_profile_info.dartlib/ui/core/themes/src/light/extensions.darttest/config/providers/user_profile_provider_test.darttest/ui/contact_list/share_invite_bottom_sheet_test.darttest/config/providers/group_messages_provider_test.dartlib/ui/user_profile_list/share_invite_bottom_sheet.dartlib/ui/settings/profile/share_profile_qr_scan_screen.darttest/ui/contact_list/widgets/user_profile_card_test.dartlib/ui/user_profile_list/start_chat_bottom_sheet.darttest/ui/contact_list/start_chat_bottom_sheet_test.dartlib/ui/user_profile_list/widgets/chat_list_item_tile.dartlib/routing/routes.dartlib/ui/core/themes/src/colors.dartlib/ui/user_profile_list/new_group_chat_sheet.dartlib/domain/models/user_profile.dartlib/ui/settings/profile/switch_profile_bottom_sheet.dartlib/ui/chat/invite/chat_invite_screen.dartlib/ui/chat/chat_management/add_to_group_screen.darttest/ui/contact_list/widgets/share_invite_callout_test.dartlib/ui/user_profile_list/widgets/chat_list_active_account_avatar.dartlib/ui/user_profile_list/group_chat_details_sheet.dartlib/ui/settings/widgets/active_account_tile.dartlib/ui/user_profile_list/widgets/user_profile_tile.dartlib/ui/chat/widgets/chat_header_widget.dartlib/ui/user_profile_list/new_chat_bottom_sheet.dart
**/*.md
📄 CodeRabbit inference engine (.cursor/rules/whitenoise.mdc)
**/*.md: NIPs (Nostr Implementation Possibilities) are numbered likeNIP-XXwhereXXare two capitalized hexadecimal digits, e.g.,NIP-01andNIP-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.,07for NIP-07, orC7for 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.mdfor 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.darttest/ui/contact_list/share_invite_bottom_sheet_test.darttest/config/providers/group_messages_provider_test.darttest/ui/contact_list/widgets/user_profile_card_test.darttest/ui/contact_list/start_chat_bottom_sheet_test.darttest/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.darttest/config/providers/group_messages_provider_test.darttest/ui/contact_list/widgets/user_profile_card_test.dartlib/ui/user_profile_list/start_chat_bottom_sheet.darttest/ui/contact_list/start_chat_bottom_sheet_test.dartlib/ui/user_profile_list/new_group_chat_sheet.dartlib/domain/models/user_profile.dartlib/ui/settings/profile/switch_profile_bottom_sheet.dartlib/ui/chat/invite/chat_invite_screen.dartlib/ui/chat/chat_management/add_to_group_screen.dartlib/ui/user_profile_list/widgets/chat_list_active_account_avatar.dartlib/ui/user_profile_list/group_chat_details_sheet.dartlib/ui/settings/widgets/active_account_tile.dartlib/ui/user_profile_list/widgets/user_profile_tile.dartlib/ui/chat/widgets/chat_header_widget.dartlib/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.dartlib/ui/user_profile_list/start_chat_bottom_sheet.dartlib/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.dartlib/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.dartlib/domain/models/user_profile.dartlib/ui/settings/profile/switch_profile_bottom_sheet.dartlib/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_listmodule.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
UserProfileCardrename. 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/contactChatBubbleText→otherChatBubble/otherChatBubbleTextrenames are correctly propagated through constructor parameters, field declarations, light/dark initializers,copyWith, andlerpmethods.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 tocontactChatBubble/contactChatBubbleTexthave 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
.dartfiles—no instances ofChatContactHeaderremain.lib/ui/chat/widgets/user_profile_info.dart (1)
6-23: Ready to merge – no remainingContactInforeferences
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 UserProfileTileProps renamed and wiring look consistent with the new model.
lib/ui/chat/widgets/message_widget.dart (1)
47-48: LGTM: color renames are consistentRenamed 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 isPubkeyFormatter(pubkey).toHex()ofuserProfile.publicKeywhen stubbing or verifyinguserHasKeyPackage.lib/ui/user_profile_list/share_invite_bottom_sheet.dart (1)
33-36: API rename looks goodBuilder 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 APISetup now uses UserProfile and ShareInviteCallout(userProfile: …). Looks correct.
lib/routing/routes.dart (2)
17-20: Contacts → Users route rename looks correctConstants and paths are consistent.
42-44: Helper method addition LGTMgoToUser(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 correctField 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 consolidationKeeps 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 passingwelcome.welcomerrequires no additional formatting.test/config/providers/user_profile_provider_test.dart (1)
74-85: Good provider override and wiringOverride 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 callCorrectly normalizes input for userHasKeyPackage.
Based on learnings
178-191: Key format consistency for followProviderConfirm 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 refactorExtending 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 correctAdding preSelectedUserProfiles into the selection in initState is correct and side‑effect free.
|
This PR has loots of conflicts. I'm turning it back to draft while I fix them |
45c9dbc to
3c6ca9d
Compare
There was a problem hiding this 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
activePubkeyProvidercan return either npub or hex (see prior note on key normalization). Because_activeAccountHexnow 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 consistencyOther 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
📒 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.dartlib/ui/user_profile_list/widgets/chat_list_item_tile.dartlib/config/providers/group_provider.dartlib/config/states/create_group_state.freezed.darttest/ui/contact_list/services/welcome_notification_service_simple_test.dartlib/domain/models/user_profile.darttest/ui/contact_list/start_chat_bottom_sheet_test.dartlib/ui/settings/profile/share_profile_qr_scan_screen.darttest/config/providers/user_profile_provider_test.dartlib/ui/user_profile_list/start_chat_bottom_sheet.dartlib/ui/core/themes/src/light/extensions.dartlib/ui/settings/widgets/active_account_tile.dartlib/ui/user_profile_list/share_invite_bottom_sheet.dartlib/ui/chat/chat_management/widgets/create_group_dialog.darttest/ui/contact_list/widgets/user_profile_card_test.dartlib/ui/chat/chat_screen.dartlib/config/providers/create_group_provider.darttest/ui/contact_list/widgets/share_invite_callout_test.dartlib/ui/chat/chat_management/add_to_group_screen.dartlib/routing/routes.dartlib/ui/core/themes/src/colors_dark.dartlib/ui/settings/profile/switch_profile_bottom_sheet.dartlib/config/states/create_group_state.dartlib/ui/user_profile_list/widgets/chat_list_active_account_avatar.dartlib/ui/core/themes/src/colors_light.darttest/config/providers/group_messages_provider_test.dartlib/routing/router_provider.dartlib/ui/user_profile_list/widgets/user_profile_tile.dartlib/ui/user_profile_list/services/welcome_notification_service.dartlib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dartlib/ui/chat/invite/chat_invite_screen.dartlib/ui/user_profile_list/new_chat_bottom_sheet.dartlib/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.dartlib/ui/user_profile_list/widgets/chat_list_item_tile.dartlib/config/providers/group_provider.dartlib/config/states/create_group_state.freezed.dartlib/domain/models/user_profile.dartlib/ui/settings/profile/share_profile_qr_scan_screen.dartlib/ui/user_profile_list/start_chat_bottom_sheet.dartlib/ui/core/themes/src/light/extensions.dartlib/ui/settings/widgets/active_account_tile.dartlib/ui/user_profile_list/share_invite_bottom_sheet.dartlib/ui/chat/chat_management/widgets/create_group_dialog.dartlib/ui/chat/chat_screen.dartlib/config/providers/create_group_provider.dartlib/ui/chat/chat_management/add_to_group_screen.dartlib/routing/routes.dartlib/ui/core/themes/src/colors_dark.dartlib/ui/settings/profile/switch_profile_bottom_sheet.dartlib/config/states/create_group_state.dartlib/ui/user_profile_list/widgets/chat_list_active_account_avatar.dartlib/ui/core/themes/src/colors_light.dartlib/routing/router_provider.dartlib/ui/user_profile_list/widgets/user_profile_tile.dartlib/ui/user_profile_list/services/welcome_notification_service.dartlib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dartlib/ui/chat/invite/chat_invite_screen.dartlib/ui/user_profile_list/new_chat_bottom_sheet.dartlib/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.darttest/ui/contact_list/start_chat_bottom_sheet_test.darttest/config/providers/user_profile_provider_test.darttest/ui/contact_list/widgets/user_profile_card_test.darttest/ui/contact_list/widgets/share_invite_callout_test.darttest/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.darttest/ui/contact_list/start_chat_bottom_sheet_test.darttest/config/providers/user_profile_provider_test.dartlib/ui/user_profile_list/start_chat_bottom_sheet.dartlib/ui/settings/widgets/active_account_tile.dartlib/ui/chat/chat_management/widgets/create_group_dialog.darttest/ui/contact_list/widgets/user_profile_card_test.dartlib/config/providers/create_group_provider.dartlib/ui/chat/chat_management/add_to_group_screen.dartlib/ui/settings/profile/switch_profile_bottom_sheet.dartlib/config/states/create_group_state.dartlib/ui/user_profile_list/widgets/chat_list_active_account_avatar.darttest/config/providers/group_messages_provider_test.dartlib/ui/chat/invite/chat_invite_screen.dartlib/ui/user_profile_list/new_chat_bottom_sheet.dartlib/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.dartlib/ui/user_profile_list/start_chat_bottom_sheet.dartlib/ui/settings/profile/switch_profile_bottom_sheet.dartlib/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.dartlib/config/providers/create_group_provider.darttest/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 (
MessageReadStatusandWelcomeTile) 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_listinstead ofcontact_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
UserProfilemodel andUserProfileTilewidget.Also applies to: 12-12
18-23: LGTM!The method signature and return type have been correctly updated from
ContactModeltoUserProfile, maintaining consistency with the broader refactor.
32-33: LGTM!The widget has been correctly updated from
ContactListTiletoUserProfileTile, with the parameter renamed fromcontacttouserProfile.test/ui/contact_list/widgets/user_profile_card_test.dart (2)
5-5: LGTM!The test wrapper class has been correctly renamed from
UserProfileTestWrappertoUserProfileCardTestWrapper, 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/contactToAddtoUserProfile/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
AddToContactButtontoFollowToggleButtonin 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 tocontactChatBubbleorcontactChatBubbleTextfound.lib/ui/core/themes/src/light/extensions.dart (1)
32-34: LGTM! Color property rename aligns with terminology update.The rename from
contactChatBubble/contactChatBubbleTexttootherChatBubble/otherChatBubbleTextis 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_modeltouser_profilealigns with the domain model rename.
16-17: LGTM! State field types and names updated consistently.The changes properly update:
- Field types from
List<ContactModel>toList<UserProfile>- Field names to reflect user-centric terminology (
userProfilesWithoutKeyPackage,userProfilesWithKeyPackage)- Getter reference in
canCreateGroupThe 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.,
searchContactPlaceholder→searchUserPlaceholder)- 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
AddToContactButtontoFollowToggleButtonis 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>toList<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
ContactModeltoUserProfileis 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 handlingThe 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_providerandUserProfilemodel.
25-25: LGTM: Field type updated correctly.The field type has been updated from
ContactModel?toUserProfile?, 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
userProfileProviderandgetUserProfilemethod.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_providerandUserProfileInfowidget.Also applies to: 11-11
58-61: LGTM: Widget updated to UserProfileInfo.The widget has been correctly updated from
ContactInfotoUserProfileInfo.
245-245: LGTM: Provider and method call updated correctly.The provider reference and method call have been updated to use the new
userProfileProviderandgetUserProfilemethod.Also applies to: 248-248
250-252: LGTM: Variable renamed consistently.The variable has been renamed from
welcomerContacttowelcomerUserand 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
welcomerUserandUserProfileInfoare 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_providerand the relocatedstart_chat_bottom_sheetfrom theuser_profile_listdirectory.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
contacttouserProfile, consistent with the updatedStartChatBottomSheet.showAPI.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:
searchContactPlaceholder→searchUserPlaceholdercontactsLoadingError→followsLoadingErrornoContactsFound→noUsersFoundThe 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
contactsNotReadyForSecureMessagingtousersNotReadyForSecureMessaging, 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:
searchContactPlaceholder→searchUserPlaceholdercontactsLoadingError→followsLoadingErrornoContactsFound→noUsersFoundnoContactsMatchSearch→noUsersMatchSearchcontactsNotReadyForSecureMessaging→usersNotReadyForSecureMessaging- 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
UserProfileinstead ofContactModel:
- Import updated from
contact_model.darttouser_profile.dart- Field type changed from
ContactModeltoUserProfile- Constructor parameter updated accordingly
PubkeyFormatterimport added for proper pubkey handlingThe 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
PubkeyFormatterto 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
showmethod signature has been updated to accept aUserProfileparameter instead ofContactModel, and the builder uses it correctly.
100-102: LGTM: Field access updated correctly.The method now correctly accesses
widget.userProfile.publicKeyinstead of the old contact field.
133-133: LGTM: Group creation updated correctly.The pubkey is properly converted to hex format using
PubkeyFormatterbefore being passed tocreateNewGroup. The displayName is accessed from theUserProfilefield 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.userProfileand its fields:
- Follow/unfollow logic uses
userProfile.publicKeyanduserProfile.displayName- Add to group functionality checks
userProfile.publicKey- UI components access
userProfile.imagePath,userProfile.displayName,userProfile.nip05, etc.- Child widgets receive the
userProfileobjectAll 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
ContactListTiletoUserProfileTile, and the field has been renamed fromcontacttouserProfile. 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.publicKeyinstead 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.imagePathanduserProfile.displayName- Display name text shows
userProfile.displayName- Variable renamed from
contactTiletouserProfileTileThe loading widget has also been renamed from
ContactListTileLoadingtoUserProfileTileLoading.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
ContactModeltoUserProfileis thorough and consistent across:
- Import statements updated to reference user profile models and components
- Constructor parameters (
preSelectedContacts→preSelectedUserProfiles)- State fields (
_selectedContacts→_selectedUserProfiles)- Method signatures and implementations (
_toggleUserProfileSelection,_buildUserProfilesList,_getFilteredUserProfiles)- UI component usage (
ContactListTile→UserProfileTile)- Data mapping (
ContactModel.fromMetadata→UserProfile.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
ContactModeltoUserProfileis 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 (
userProfileDataProvider→userProfileProvider,getUserProfileData→getUserProfile)- Route references (
Routes.contactQrScan→Routes.userProfileQrScan)- UI components (
ContactListTile→UserProfileTile,_LoadingContactList→_LoadingUserProfileList)- Data mapping (
ContactModel.fromMetadata→UserProfile.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
3c6ca9d to
80bbb91
Compare
80bbb91 to
e1214cd
Compare
There was a problem hiding this 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
reactionTextColorin all four text style declarations.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
ios/Podfile.lockis 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.dartlib/ui/chat/chat_info/widgets/member_action_buttons.darttest/ui/contact_list/widgets/share_invite_callout_test.dartlib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dartlib/ui/settings/general_settings_screen.darttest/ui/contact_list/widgets/user_profile_card_test.dartlib/ui/chat/chat_management/add_to_group_screen.dartlib/ui/user_profile_list/chat_list_screen.dartlib/ui/user_profile_list/share_invite_bottom_sheet.dartlib/ui/settings/widgets/active_account_tile.dartlib/routing/routes.dartlib/ui/user_profile_list/start_chat_bottom_sheet.darttest/ui/contact_list/share_invite_bottom_sheet_test.dartlib/config/providers/create_group_provider.dartlib/ui/user_profile_list/widgets/chat_list_item_tile.dartlib/config/states/create_group_state.freezed.dartlib/ui/user_profile_list/widgets/user_profile_tile.dartlib/ui/user_profile_list/new_chat_bottom_sheet.dartlib/ui/settings/profile/switch_profile_bottom_sheet.darttest/ui/contact_list/start_chat_bottom_sheet_test.dartlib/ui/user_profile_list/new_group_chat_sheet.dartlib/ui/user_profile_list/widgets/chat_list_active_account_avatar.darttest/config/providers/group_messages_provider_test.dartlib/ui/chat/widgets/message_widget.darttest/ui/contact_list/services/welcome_notification_service_simple_test.darttest/config/providers/user_profile_provider_test.dartlib/ui/user_profile_list/group_chat_details_sheet.dartlib/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.dartlib/ui/chat/chat_info/widgets/member_action_buttons.dartlib/ui/chat/chat_info/widgets/group_member_bottom_sheet.dartlib/ui/settings/general_settings_screen.dartlib/ui/chat/chat_management/add_to_group_screen.dartlib/ui/user_profile_list/chat_list_screen.dartlib/ui/user_profile_list/share_invite_bottom_sheet.dartlib/ui/settings/widgets/active_account_tile.dartlib/routing/routes.dartlib/ui/user_profile_list/start_chat_bottom_sheet.dartlib/config/providers/create_group_provider.dartlib/ui/user_profile_list/widgets/chat_list_item_tile.dartlib/config/states/create_group_state.freezed.dartlib/ui/user_profile_list/widgets/user_profile_tile.dartlib/ui/user_profile_list/new_chat_bottom_sheet.dartlib/ui/settings/profile/switch_profile_bottom_sheet.dartlib/ui/user_profile_list/new_group_chat_sheet.dartlib/ui/user_profile_list/widgets/chat_list_active_account_avatar.dartlib/ui/chat/widgets/message_widget.dartlib/ui/user_profile_list/group_chat_details_sheet.dartlib/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.darttest/ui/contact_list/widgets/user_profile_card_test.darttest/ui/contact_list/share_invite_bottom_sheet_test.darttest/ui/contact_list/start_chat_bottom_sheet_test.darttest/config/providers/group_messages_provider_test.darttest/ui/contact_list/services/welcome_notification_service_simple_test.darttest/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.darttest/ui/contact_list/widgets/user_profile_card_test.dartlib/ui/chat/chat_management/add_to_group_screen.dartlib/ui/settings/widgets/active_account_tile.dartlib/ui/user_profile_list/start_chat_bottom_sheet.dartlib/config/providers/create_group_provider.dartlib/ui/user_profile_list/new_chat_bottom_sheet.dartlib/ui/settings/profile/switch_profile_bottom_sheet.darttest/ui/contact_list/start_chat_bottom_sheet_test.dartlib/ui/user_profile_list/new_group_chat_sheet.dartlib/ui/user_profile_list/widgets/chat_list_active_account_avatar.darttest/config/providers/group_messages_provider_test.darttest/config/providers/user_profile_provider_test.dartlib/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.dartlib/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.dartlib/ui/user_profile_list/widgets/user_profile_tile.dartlib/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.dartlib/config/providers/create_group_provider.darttest/config/providers/group_messages_provider_test.dartlib/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_listtouser_profile_listaligns 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 totest/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 ofcontactChatBubble/contactChatBubbleTexttootherChatBubble/otherChatBubbleTextis consistent, all new keys are defined, and nocontactChatBubblereferences 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
contacttouserProfile. 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_listtouser_profile_listto 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_listlocation. 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
UserProfiletoUserProfileCardto 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
ContactModeltoUserProfile, maintaining compatibility with thepublicKeyfield 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
UserProfileinstead ofContactModel. All test cases properly exercise theShareInviteBottomSheetwidget with the updated API:
- Test data migrated to
UserProfile- Widget constructor calls use
userProfilesparameter- 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
UserProfiledata model and theUserProfileCardUI 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
UserProfileinstead ofContactModel. All test scenarios are properly migrated:
- Test data construction uses
UserProfile- Widget instantiations use
userProfileparameter- 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
UserProfileterminology:
- Imports point to the correct paths
- Setup function signature accepts
UserProfile- Widget instantiations use
userProfileparameter- 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
/contactsto/users- Helper method
goToContactrenamed togoToUserwith parameter name updated touserId- QR scan route appropriately uses
user_profilesprefix to differentiate the feature namespace from the user entity routeslib/ui/user_profile_list/share_invite_bottom_sheet.dart (1)
1-94: LGTM!The file has been thoroughly refactored to use
UserProfileterminology:
- All imports updated to
user_profile_listpaths- Public API (
userProfilesparameter) consistently updated in constructor and staticshow()method- Internal variables renamed from
contactstouserProfiles- UI components switched to
UserProfilevariants (UserProfileCard,UserProfileTile,ShareInviteCallout)- Localization keys updated to reflect user-centric messaging
- The unused
onInviteSentcallback 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
userHasKeyPackageandcreateNewGroupboth expect hex keys. PassingUserProfile.publicKeydirectly 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 withPubkeyFormatterbefore 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
UserProfileNotifierand correctly handlesMap<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
UserProfileinstead ofContactModel. 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
showmethod have been properly updated to acceptList<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
UserProfileTilecomponents and the data flow from follows toUserProfileis correctly implemented usingUserProfile.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
UserProfileinstead of contacts. The_getUserProfileForPublicKeymethod correctly uses theuserProfileProviderto 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 toRoutes.userProfileQrScanaligns 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
UserProfiledata. The_buildUserProfilesListmethod correctly rendersUserProfileTilecomponents, 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
showmethod have been properly updated to acceptList<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 withuserProfilesWithoutKeyPackage. 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 theuserProfilesWithKeyPackagelist.
Quwaysim
left a comment
There was a problem hiding this 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 🚀
untreu2
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM ✅
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
ContactModelwas still present and the contact word was used in lots of parts as a synonym for user.This PR:
ContactModelclass toUserProfileuserProfileDataProvidertouseProfileProviderto be consistent with the new namingWhy
UserProfile?There is already a
Usertype that comes from rust side an a User model in flutter side (which is confusing), I couldn't rename theContactModeltoUser, so I decided to rename it toUserProfile. We had talked in the issue aboutUserProfileDatabut I think that theDatadoes not provide really any useful info about wha the model is about.Type of Change
Checklist
just precommitto ensure that formatting and linting are correctjust check-flutter-coverageto ensure that flutter coverage rules are passingCHANGELOG.mdfile with your changes (if they affect the user experience)Summary by CodeRabbit
New Features
Refactor
UI
Localization
Chores