-
Notifications
You must be signed in to change notification settings - Fork 14
Added New Chat Pages #5
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
WalkthroughThis update introduces new bottom sheet components for starting and searching chats, adds a reusable custom bottom sheet utility, and refactors contact data and UI to use a new Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant ChatListAppBar
participant NewChatBottomSheet
participant SearchChatBottomSheet
participant StartSecureChatBottomSheet
participant CustomBottomSheet
User->>ChatListAppBar: Tap search icon
ChatListAppBar->>SearchChatBottomSheet: show(context)
SearchChatBottomSheet->>CustomBottomSheet: show(...)
CustomBottomSheet-->>User: Display search bottom sheet
User->>ChatListAppBar: Tap add chat icon
ChatListAppBar->>NewChatBottomSheet: show(context)
NewChatBottomSheet->>CustomBottomSheet: show(...)
CustomBottomSheet-->>User: Display new chat bottom sheet
User->>NewChatBottomSheet: Tap contact
NewChatBottomSheet->>StartSecureChatBottomSheet: show(context, contact details)
StartSecureChatBottomSheet->>CustomBottomSheet: show(...)
CustomBottomSheet-->>User: Display start chat bottom sheet
User->>StartSecureChatBottomSheet: Tap "Start & Send Invite"
StartSecureChatBottomSheet-->>User: Show confirmation/snackbar
Poem
Note ⚡️ AI Code Reviews for VS Code, Cursor, WindsurfCodeRabbit now has a plugin for VS Code, Cursor and Windsurf. This brings AI code reviews directly in the code editor. Each commit is reviewed immediately, finding bugs before the PR is raised. Seamless context handoff to your AI code agent ensures that you can easily incorporate review feedback. Note ⚡️ Faster reviews with cachingCodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure 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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
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: 7
🧹 Nitpick comments (16)
lib/shared/custom_textfield.dart (2)
6-21: Reconsider the default autofocus behaviorSetting
autofocus = trueas the default might not be appropriate for all use cases. This could cause unexpected behavior when the widget is used in various contexts where autofocus isn't desired.const CustomTextField({ super.key, required this.textController, this.padding, this.contentPadding, - this.autofocus = true, + this.autofocus = false, this.hintText, });
22-39: Consider enhancing widget with additional customization optionsThe current implementation provides basic functionality but could be enhanced with additional customization options to make it more versatile:
- Text styling for input text (not just hint text)
- Keyboard type configuration
- Text input action configuration
- Focus node parameter
- Error state handling and error text display
- Different border colors for different states (normal/focused/error)
- Suffix/prefix icon support
This would make the widget more reusable across different contexts in the application.
lib/shared/custom_bottom_sheet.dart (3)
87-107: Consider extracting header widget to a separate methodThe header section with title and close button has complex conditional logic that could be extracted to a separate method for better readability.
- if (title != null || showCloseButton) - Padding( - padding: EdgeInsets.fromLTRB(24.w, 16.h, 16.w, 24.h), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - if (title != null) - Text( - title, - style: TextStyle(color: Colors.black, fontSize: 24.sp), - ) - else - const Spacer(), - if (showCloseButton) - GestureDetector( - onTap: () => Navigator.pop(context), - child: Icon(Icons.close, color: Colors.black, size: 24.w), - ), - ], - ), - ), + if (title != null || showCloseButton) + _buildHeader(context, title, showCloseButton),Add the following method:
static Widget _buildHeader(BuildContext context, String? title, bool showCloseButton) { return Padding( padding: EdgeInsets.fromLTRB(24.w, 16.h, 16.w, 24.h), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ if (title != null) Text( title, style: TextStyle(color: Colors.black, fontSize: 24.sp), ) else const Spacer(), if (showCloseButton) GestureDetector( onTap: () => Navigator.pop(context), child: Icon(Icons.close, color: Colors.black, size: 24.w), ), ], ), ); }
80-85: Consider adding radius to bottom sheet containerBottom sheets typically have rounded corners at the top to provide a better visual cue that they can be dismissed by swiping down. Consider adding a border radius to the top corners.
decoration: BoxDecoration( color: backgroundColor, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(16.r), + topRight: Radius.circular(16.r), + ), ),
5-21: Add more documentation for complex parametersWhile there's a class-level doc comment, some parameters would benefit from additional documentation to explain their usage and implications, especially those like
blurBackground,blurSigma, andheightFactor.lib/features/contact_list/models/contact_model.dart (3)
1-13: Consider adding equality and toString methodsThe
ContactModelclass is well-structured but would benefit from implementing equality comparison (using==operator andhashCode) and atoStringmethod for debugging purposes.class ContactModel { final String name; final String email; final String publicKey; final String imagePath; ContactModel({ required this.name, required this.email, required this.publicKey, required this.imagePath, }); + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + return other is ContactModel && + other.name == name && + other.email == email && + other.publicKey == publicKey && + other.imagePath == imagePath; + } + + @override + int get hashCode => Object.hash(name, email, publicKey, imagePath); + + @override + String toString() { + return 'ContactModel(name: $name, email: $email, publicKey: ${publicKey.substring(0, 8)}..., imagePath: $imagePath)'; + } }
1-13: Consider adding a copyWith method for immutable updatesSince this is an immutable model, adding a
copyWithmethod would allow for easy creation of modified copies of the model.class ContactModel { final String name; final String email; final String publicKey; final String imagePath; ContactModel({ required this.name, required this.email, required this.publicKey, required this.imagePath, }); + + ContactModel copyWith({ + String? name, + String? email, + String? publicKey, + String? imagePath, + }) { + return ContactModel( + name: name ?? this.name, + email: email ?? this.email, + publicKey: publicKey ?? this.publicKey, + imagePath: imagePath ?? this.imagePath, + ); + } }
3-5: Add validation for email and consider shortening public key displayConsider adding validation for the email field and potentially include a method to get a shortened version of the public key for display purposes.
final String name; final String email; final String publicKey; final String imagePath; + + // Returns a shortened version of the public key for display + String get shortPublicKey => publicKey.length > 16 + ? '${publicKey.substring(0, 8)}...${publicKey.substring(publicKey.length - 8)}' + : publicKey;lib/features/contact_list/data/dummy_data.dart (1)
6-19: Refactored dummy contacts to use ContactModelThe dummy contacts list has been successfully refactored to use the new
ContactModelinstead ofChatModel, with appropriate fields for contact data. However, there's a duplicate email address for both contacts.Consider diversifying the email addresses for the dummy contacts to better represent real-world data and avoid potential confusion during testing.
ContactModel( name: 'Hillebrand', - email: 'max@towardsliberty.com', + email: 'hillebrand@towardsliberty.com', publicKey: 'npub1 klkk3 vrzme 455yh 9rl2j shq7r c8dpe gj3nd f82c3 ks2sk 7qulx 40dxt 3vt', imagePath: AssetsPaths.icImage, ),lib/features/contact_list/presentation/search_chat_bottom_sheet.dart (2)
50-57: Consider adding debounce for search.The search is currently triggered on every character change, which could cause performance issues with larger datasets. Consider implementing a debounce mechanism to limit how frequently the search is performed.
+ import 'dart:async'; class _SearchChatBottomSheetState extends State<SearchChatBottomSheet> { final TextEditingController _searchController = TextEditingController(); String _searchQuery = ''; bool _hasSearchResults = false; List<ContactModel> _filteredContacts = []; List<ChatModel> _filteredChats = []; + Timer? _debounce; @override void dispose() { _searchController.removeListener(_onSearchChanged); _searchController.dispose(); + _debounce?.cancel(); super.dispose(); } void _onSearchChanged() { + if (_debounce?.isActive ?? false) _debounce!.cancel(); + _debounce = Timer(const Duration(milliseconds: 300), () { setState(() { _searchQuery = _searchController.text; _hasSearchResults = _searchQuery.isNotEmpty; _filteredContacts = _getFilteredContacts(); _filteredChats = _getFilteredChats(); }); + }); }
79-79: Auto-focus on text field when sheet opens.To improve user experience, consider auto-focusing the search field when the bottom sheet opens, so users can start typing immediately.
- CustomTextField(textController: _searchController, hintText: 'Search contacts or chats...'), + CustomTextField( + textController: _searchController, + hintText: 'Search contacts or chats...', + autofocus: true, + ),lib/features/contact_list/presentation/new_chat_bottom_sheet.dart (2)
102-108: Improve SnackBar usage and consider more informative feedback.The current SnackBar shows a basic message after starting a chat. Consider improving this by:
- Using a more descriptive message
- Adding a duration
- Including an action for quick follow-up
ScaffoldMessenger.of( context, -).showSnackBar(SnackBar(content: Text('Started secure chat with ${contact.name}'))); +).showSnackBar( + SnackBar( + content: Text('Secure chat started with ${contact.name}'), + duration: const Duration(seconds: 4), + action: SnackBarAction( + label: 'Open', + onPressed: () { + // Navigate to the chat screen with this contact + }, + ), + ), +);
56-59: Improve search filtering capabilities.The current search only filters by name. Consider expanding the search capabilities to include filtering by email address as well, since that's an important identifying field for contacts.
List<ContactModel> _getFilteredContacts() { if (_searchQuery.isEmpty) return dummyContacts; - return dummyContacts.where((contact) => contact.name.toLowerCase().contains(_searchQuery.toLowerCase())).toList(); + return dummyContacts.where((contact) => + contact.name.toLowerCase().contains(_searchQuery.toLowerCase()) || + contact.email.toLowerCase().contains(_searchQuery.toLowerCase()) + ).toList(); }lib/features/contact_list/presentation/start_chat_bottom_sheet.dart (3)
50-53: Use dynamic avatar image.Currently, the avatar image is hardcoded. Consider making it dynamic based on the contact's information or allowing an avatar parameter to be passed to the widget.
- CircleAvatar( - radius: 40.r, - backgroundImage: AssetImage(AssetsPaths.icImage), - ), + CircleAvatar( + radius: 40.r, + backgroundImage: AssetImage(AssetsPaths.icImage), + child: Text( + name.isNotEmpty ? name[0].toUpperCase() : '?', + style: TextStyle( + fontSize: 32.sp, + fontWeight: FontWeight.bold, + color: AppColors.white, + ), + ), + ),
22-41: Consider adding validation for required parameters.While Flutter's
requiredkeyword ensures parameters are passed, it doesn't validate their contents. Consider adding validation to ensure the parameters contain meaningful values.static Future<void> show({ required BuildContext context, required String name, required String email, required String publicKey, VoidCallback? onStartChat, }) { + // Validate inputs + assert(name.isNotEmpty, 'Name cannot be empty'); + assert(email.isNotEmpty, 'Email cannot be empty'); + assert(publicKey.isNotEmpty, 'Public key cannot be empty'); return CustomBottomSheet.show( context: context, title: 'Start secure chat', heightFactor: 0.55, backgroundColor: Colors.white, builder: (context) => StartSecureChatBottomSheet( name: name, email: email, publicKey: publicKey, onStartChat: onStartChat, ), ); }
87-92: Implement loading state for start chat button.The current implementation doesn't handle potential network delays when starting a chat. Consider adding a loading state to the button to prevent multiple taps and provide user feedback.
+ final ValueNotifier<bool> _isLoading = ValueNotifier<bool>(false); // In the StatelessWidget constructor, add dispose for the ValueNotifier onPressed: () { + _isLoading.value = true; Navigator.pop(context); if (onStartChat != null) { onStartChat!(); } + _isLoading.value = false; },Alternative approach for a stateful implementation:
// Change to StatefulWidget and add: bool _isLoading = false; // In the button: onPressed: () async { setState(() => _isLoading = true); try { Navigator.pop(context); if (onStartChat != null) { onStartChat!(); } } finally { if (mounted) setState(() => _isLoading = false); } }, child: _isLoading ? const CircularProgressIndicator(color: Colors.white) : Text('Start & Send Invite', ...),
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting
⛔ Files ignored due to path filters (3)
assets/pngs/login_splash.pngis excluded by!**/*.pngassets/svgs/ic_chevron_right.svgis excluded by!**/*.svgassets/svgs/ic_group_chat.svgis excluded by!**/*.svg
📒 Files selected for processing (13)
lib/core/utils/assets_paths.dart(1 hunks)lib/features/contact_list/data/dummy_data.dart(1 hunks)lib/features/contact_list/models/contact_model.dart(1 hunks)lib/features/contact_list/presentation/new_chat_bottom_sheet.dart(1 hunks)lib/features/contact_list/presentation/search_chat_bottom_sheet.dart(1 hunks)lib/features/contact_list/presentation/search_screen.dart(0 hunks)lib/features/contact_list/presentation/start_chat_bottom_sheet.dart(1 hunks)lib/features/contact_list/presentation/widgets/chat_list_appbar.dart(2 hunks)lib/features/contact_list/presentation/widgets/contact_list_tile.dart(1 hunks)lib/main.dart(0 hunks)lib/screens/auth_flow/welcome_page.dart(2 hunks)lib/shared/custom_bottom_sheet.dart(1 hunks)lib/shared/custom_textfield.dart(1 hunks)
💤 Files with no reviewable changes (2)
- lib/main.dart
- lib/features/contact_list/presentation/search_screen.dart
🔇 Additional comments (13)
lib/shared/custom_textfield.dart (1)
1-40: Good implementation of the custom text fieldThe widget follows Flutter best practices for creating a reusable component. It encapsulates the TextField with consistent styling, uses responsive dimensions with ScreenUtil, and provides a clean API with required and optional parameters.
lib/shared/custom_bottom_sheet.dart (1)
6-64: Well-structured implementation of CustomBottomSheetThe implementation provides a flexible and reusable bottom sheet utility with many customization options. The code is well-documented with a clear API.
lib/screens/auth_flow/welcome_page.dart (2)
2-4: Good use of centralized asset path managementUsing the centralized
AssetsPathsclass instead of hardcoded strings is a good practice. This change improves maintainability by centralizing asset path management.Also applies to: 31-31
2-2:✅ Verification successful
Verify that AssetsPaths.loginSplash exists
Ensure that the
loginSplashconstant is properly defined in theAssetsPathsclass to avoid runtime errors.
🏁 Script executed:
#!/bin/bash # Check if the AssetsPaths.loginSplash constant is properly defined cat lib/core/utils/assets_paths.dart | grep -A 2 "loginSplash"Length of output: 124
AssetsPaths.loginSplash is defined
TheloginSplashconstant is present inlib/core/utils/assets_paths.dartas expected, so no further changes are needed.lib/features/contact_list/models/contact_model.dart (1)
1-13: Good structured model implementationThe
ContactModelclass is well-designed with clear, immutable properties and a straightforward constructor that requires all fields. This approach supports type safety and makes usage of the model intuitive.lib/features/contact_list/presentation/widgets/chat_list_appbar.dart (3)
8-9: Added imports for new bottom sheet componentsThe imports for the new bottom sheet components have been properly added, which will be used for the search and new chat functionality.
26-26: Updated search icon tap handler to use bottom sheetThe search functionality has been updated to use the new
SearchChatBottomSheetcomponent instead of the previous implementation. This is a good improvement for UI consistency.
30-33: Added tap functionality to the add iconThe add icon has been properly wrapped in a
GestureDetectorto handle tap events, invoking the newNewChatBottomSheetcomponent. This enhances the user experience by providing a consistent interaction pattern.lib/features/contact_list/data/dummy_data.dart (1)
3-3: Added import for new ContactModelThe import for the new
ContactModelhas been correctly added to support the updated data structure.lib/features/contact_list/presentation/widgets/contact_list_tile.dart (2)
7-7: Updated import for ContactModelThe import for
ContactModelhas been properly added to replace the previousChatModel.
10-14: Updated widget to use ContactModel and added onTap callbackThe widget has been properly updated to use
ContactModelinstead ofChatModeland an optionalonTapcallback has been added to support interactivity.lib/features/contact_list/presentation/search_chat_bottom_sheet.dart (2)
37-48: Good lifecycle management.The component correctly adds listeners in
initStateand properly cleans up indispose, following best practices for managing resources in stateful widgets.
104-113: Consider pagination for large chat lists.The chat list is wrapped in an
Expandedwidget which allows for scrolling, but there's no pagination mechanism for large datasets. If the number of chats grows significantly, this could impact performance.Are there plans to implement pagination for handling large datasets? If so, consider using a
ListView.builderwith a scroll controller that loads more items when reaching the end of the list.
| return Stack( | ||
| fit: StackFit.expand, | ||
| children: [ | ||
| Container(color: Colors.black.withValues(alpha: 0.1)), |
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.
Consider using Color.fromRGBO for clarity
The withValues(alpha: 0.1) extension method isn't a standard Flutter method. Consider using the standard Color.fromRGBO or withOpacity method for better code clarity and maintainability.
- Container(color: Colors.black.withValues(alpha: 0.1)),
+ Container(color: Colors.black.withOpacity(0.1)),🤖 Prompt for AI Agents
In lib/shared/custom_bottom_sheet.dart at line 76, replace the non-standard
method call `Colors.black.withValues(alpha: 0.1)` with the standard Flutter
method `Colors.black.withOpacity(0.1)` or use `Color.fromRGBO` to set the black
color with 10% opacity. This change will improve code clarity and
maintainability by using recognized Flutter APIs.
| //PNGS | ||
| static const String icImage = '$_pngsDir/ic_image.png'; | ||
| } | ||
| static String loginSplash = '$_pngsDir/login_splash.png'; |
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.
🛠️ Refactor suggestion
Missing const modifier for loginSplash asset path
The loginSplash constant is missing the const modifier, unlike other asset path constants in this class. Using const for compile-time constants improves performance and prevents accidental modification.
- static String loginSplash = '$_pngsDir/login_splash.png';
+ static const String loginSplash = '$_pngsDir/login_splash.png';📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| static String loginSplash = '$_pngsDir/login_splash.png'; | |
| static const String loginSplash = '$_pngsDir/login_splash.png'; |
🤖 Prompt for AI Agents
In lib/core/utils/assets_paths.dart at line 16, the loginSplash asset path is
missing the const modifier. Add the const keyword before the declaration of
loginSplash to make it a compile-time constant, aligning it with other asset
path constants and improving performance and immutability.
| static String icChevronRight = '$_svgsDir/ic_chevron_right.svg'; | ||
| static String icGroupChat = '$_svgsDir/ic_group_chat.svg'; |
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.
🛠️ Refactor suggestion
Inconsistent use of const modifier for asset path constants
The new SVG paths icChevronRight and icGroupChat are declared as static String without the const modifier, unlike all other asset paths in this class that use static const String. This inconsistency could cause maintenance issues and doesn't follow the established pattern in this file.
- static String icChevronRight = '$_svgsDir/ic_chevron_right.svg';
- static String icGroupChat = '$_svgsDir/ic_group_chat.svg';
+ static const String icChevronRight = '$_svgsDir/ic_chevron_right.svg';
+ static const String icGroupChat = '$_svgsDir/ic_group_chat.svg';📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| static String icChevronRight = '$_svgsDir/ic_chevron_right.svg'; | |
| static String icGroupChat = '$_svgsDir/ic_group_chat.svg'; | |
| static const String icChevronRight = '$_svgsDir/ic_chevron_right.svg'; | |
| static const String icGroupChat = '$_svgsDir/ic_group_chat.svg'; |
🤖 Prompt for AI Agents
In lib/core/utils/assets_paths.dart around lines 11 to 12, the asset path
constants icChevronRight and icGroupChat are declared as static String without
the const modifier, unlike other asset paths that use static const String. To
fix this, change their declarations to static const String to maintain
consistency and follow the established pattern in the file.
| return GestureDetector( | ||
| onTap: onTap, | ||
| child: Padding( | ||
| padding: EdgeInsets.symmetric(vertical: 8.h), | ||
| child: Row( | ||
| children: [ | ||
| ClipRRect( | ||
| borderRadius: BorderRadius.circular(30.r), | ||
| child: | ||
| contact.imagePath.isNotEmpty | ||
| ? Image.asset(contact.imagePath, width: 56.w, height: 56.w) | ||
| : Container( | ||
| width: 56.w, | ||
| height: 56.w, | ||
| color: Colors.orange, | ||
| alignment: Alignment.center, | ||
| child: Text( | ||
| contact.name.substring(0, 1).toUpperCase(), | ||
| style: TextStyle(color: AppColors.white, fontSize: 20.sp, fontWeight: FontWeight.bold), | ||
| ), | ||
| ), | ||
| ), | ||
| Gap(12.w), | ||
| Expanded( | ||
| child: Column( | ||
| crossAxisAlignment: CrossAxisAlignment.start, | ||
| children: [ | ||
| Row( | ||
| children: [ | ||
| Text( | ||
| contact.name, | ||
| style: TextStyle(color: AppColors.color2D312D, fontSize: 18.sp, fontWeight: FontWeight.w500), | ||
| ), | ||
| ), | ||
| ), | ||
| Gap(12.w), | ||
| Expanded( | ||
| child: Column( | ||
| crossAxisAlignment: CrossAxisAlignment.start, | ||
| children: [ | ||
| Row( | ||
| children: [ | ||
| Text(contact.name, style: TextStyle(color: AppColors.color2D312D, fontSize: 18.sp, fontWeight: FontWeight.w500)), | ||
| Gap(6.w), | ||
| SvgPicture.asset(AssetsPaths.icVerifiedUser, height: 12.w, width: 12.w), | ||
| ], | ||
| ), | ||
| Text( | ||
| 'npubt klkk3 vrzme 455yh 9rl2j shq7r c8dpe gj3hd f82c3 ks2sk 7qulx 40dxt 3vt', | ||
| style: TextStyle(color: AppColors.color727772, fontSize: 14.sp), | ||
| ), | ||
| ], | ||
| Gap(6.w), | ||
| SvgPicture.asset(AssetsPaths.icVerifiedUser, height: 12.w, width: 12.w), | ||
| ], | ||
| ), | ||
| Text( | ||
| 'npubt klkk3 vrzme 455yh 9rl2j shq7r c8dpe gj3hd f82c3 ks2sk 7qulx 40dxt 3vt', | ||
| style: TextStyle(color: AppColors.color727772, fontSize: 14.sp), | ||
| ), | ||
| ], | ||
| ), | ||
| ), | ||
| ), | ||
| ], | ||
| ], | ||
| ), | ||
| ), | ||
| ); |
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.
🛠️ Refactor suggestion
Refactored widget to handle tap events and display contact information
The widget has been successfully refactored to use a GestureDetector for tap handling and to display contact information. However, there's a potential issue with the displayed public key.
The public key display doesn't use the actual publicKey field from the ContactModel. Instead, it's using a hardcoded string that might not match the actual public key.
Text(
- 'npubt klkk3 vrzme 455yh 9rl2j shq7r c8dpe gj3hd f82c3 ks2sk 7qulx 40dxt 3vt',
+ contact.publicKey,
style: TextStyle(color: AppColors.color727772, fontSize: 14.sp),
),Additionally, you might want to consider adding an email display or truncating the public key for better readability.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| return GestureDetector( | |
| onTap: onTap, | |
| child: Padding( | |
| padding: EdgeInsets.symmetric(vertical: 8.h), | |
| child: Row( | |
| children: [ | |
| ClipRRect( | |
| borderRadius: BorderRadius.circular(30.r), | |
| child: | |
| contact.imagePath.isNotEmpty | |
| ? Image.asset(contact.imagePath, width: 56.w, height: 56.w) | |
| : Container( | |
| width: 56.w, | |
| height: 56.w, | |
| color: Colors.orange, | |
| alignment: Alignment.center, | |
| child: Text( | |
| contact.name.substring(0, 1).toUpperCase(), | |
| style: TextStyle(color: AppColors.white, fontSize: 20.sp, fontWeight: FontWeight.bold), | |
| ), | |
| ), | |
| ), | |
| Gap(12.w), | |
| Expanded( | |
| child: Column( | |
| crossAxisAlignment: CrossAxisAlignment.start, | |
| children: [ | |
| Row( | |
| children: [ | |
| Text( | |
| contact.name, | |
| style: TextStyle(color: AppColors.color2D312D, fontSize: 18.sp, fontWeight: FontWeight.w500), | |
| ), | |
| ), | |
| ), | |
| Gap(12.w), | |
| Expanded( | |
| child: Column( | |
| crossAxisAlignment: CrossAxisAlignment.start, | |
| children: [ | |
| Row( | |
| children: [ | |
| Text(contact.name, style: TextStyle(color: AppColors.color2D312D, fontSize: 18.sp, fontWeight: FontWeight.w500)), | |
| Gap(6.w), | |
| SvgPicture.asset(AssetsPaths.icVerifiedUser, height: 12.w, width: 12.w), | |
| ], | |
| ), | |
| Text( | |
| 'npubt klkk3 vrzme 455yh 9rl2j shq7r c8dpe gj3hd f82c3 ks2sk 7qulx 40dxt 3vt', | |
| style: TextStyle(color: AppColors.color727772, fontSize: 14.sp), | |
| ), | |
| ], | |
| Gap(6.w), | |
| SvgPicture.asset(AssetsPaths.icVerifiedUser, height: 12.w, width: 12.w), | |
| ], | |
| ), | |
| Text( | |
| 'npubt klkk3 vrzme 455yh 9rl2j shq7r c8dpe gj3hd f82c3 ks2sk 7qulx 40dxt 3vt', | |
| style: TextStyle(color: AppColors.color727772, fontSize: 14.sp), | |
| ), | |
| ], | |
| ), | |
| ), | |
| ), | |
| ], | |
| ], | |
| ), | |
| ), | |
| ); | |
| return GestureDetector( | |
| onTap: onTap, | |
| child: Padding( | |
| padding: EdgeInsets.symmetric(vertical: 8.h), | |
| child: Row( | |
| children: [ | |
| ClipRRect( | |
| borderRadius: BorderRadius.circular(30.r), | |
| child: contact.imagePath.isNotEmpty | |
| ? Image.asset(contact.imagePath, width: 56.w, height: 56.w) | |
| : Container( | |
| width: 56.w, | |
| height: 56.w, | |
| color: Colors.orange, | |
| alignment: Alignment.center, | |
| child: Text( | |
| contact.name.substring(0, 1).toUpperCase(), | |
| style: TextStyle(color: AppColors.white, fontSize: 20.sp, fontWeight: FontWeight.bold), | |
| ), | |
| ), | |
| ), | |
| Gap(12.w), | |
| Expanded( | |
| child: Column( | |
| crossAxisAlignment: CrossAxisAlignment.start, | |
| children: [ | |
| Row( | |
| children: [ | |
| Text( | |
| contact.name, | |
| style: TextStyle(color: AppColors.color2D312D, fontSize: 18.sp, fontWeight: FontWeight.w500), | |
| ), | |
| Gap(6.w), | |
| SvgPicture.asset(AssetsPaths.icVerifiedUser, height: 12.w, width: 12.w), | |
| ], | |
| ), | |
| Text( | |
| - 'npubt klkk3 vrzme 455yh 9rl2j shq7r c8dpe gj3hd f82c3 ks2sk 7qulx 40dxt 3vt', | |
| + contact.publicKey, | |
| style: TextStyle(color: AppColors.color727772, fontSize: 14.sp), | |
| ), | |
| ], | |
| ), | |
| ), | |
| ], | |
| ), | |
| ), | |
| ); |
🤖 Prompt for AI Agents
In lib/features/contact_list/presentation/widgets/contact_list_tile.dart between
lines 18 and 65, replace the hardcoded public key string with the actual
publicKey field from the ContactModel to ensure accurate display. Additionally,
consider truncating the public key for readability or adding an email display if
available. Update the Text widget accordingly to reflect these changes.
| ListView.builder( | ||
| padding: EdgeInsets.symmetric(horizontal: 16.w), | ||
| itemCount: _filteredContacts.length, | ||
| shrinkWrap: true, | ||
| physics: const NeverScrollableScrollPhysics(), | ||
| itemBuilder: (context, index) { | ||
| final contact = _filteredContacts[index]; | ||
| return ContactListTile(contact: contact); | ||
| }, | ||
| ), |
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.
🛠️ Refactor suggestion
Add tap handling for contact items.
Unlike in NewChatBottomSheet, the contacts in this list don't have any tap behavior. Consider adding an onTap callback to the ContactListTile for consistency and to allow navigation to the contact's chat.
return ContactListTile(
contact: contact,
+ onTap: () {
+ Navigator.pop(context);
+ // Navigate to chat with this contact or open StartSecureChatBottomSheet
+ },
);🤖 Prompt for AI Agents
In lib/features/contact_list/presentation/search_chat_bottom_sheet.dart around
lines 87 to 96, the ContactListTile items lack tap handling unlike in
NewChatBottomSheet. Add an onTap callback to each ContactListTile that triggers
navigation to the contact's chat screen or performs the appropriate action. Pass
this onTap callback as a parameter to ContactListTile and implement the
navigation logic inside it to ensure consistent behavior.
| Padding( | ||
| padding: EdgeInsets.symmetric(horizontal: 24.w, vertical: 12.h), | ||
| child: Row( | ||
| children: [ | ||
| SvgPicture.asset( | ||
| AssetsPaths.icGroupChat, | ||
| colorFilter: ColorFilter.mode(AppColors.color727772, BlendMode.srcIn), | ||
| width: 20.w, | ||
| height: 20.w, | ||
| ), | ||
| Gap(10.w), | ||
| Expanded(child: Text('New Group Chat', style: TextStyle(color: AppColors.color727772, fontSize: 18.sp))), | ||
| SvgPicture.asset( | ||
| AssetsPaths.icChevronRight, | ||
| colorFilter: ColorFilter.mode(AppColors.color727772, BlendMode.srcIn), | ||
| width: 8.55.w, | ||
| height: 15.w, | ||
| ), | ||
| ], | ||
| ), | ||
| ), |
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.
🛠️ Refactor suggestion
Add functionality to the "New Group Chat" row.
The "New Group Chat" row is currently non-interactive. Consider adding a tap gesture to navigate to a group chat creation screen.
- Padding(
- padding: EdgeInsets.symmetric(horizontal: 24.w, vertical: 12.h),
- child: Row(
+ GestureDetector(
+ onTap: () {
+ // Navigate to group chat creation screen or show group creation bottom sheet
+ },
+ child: Padding(
+ padding: EdgeInsets.symmetric(horizontal: 24.w, vertical: 12.h),
+ child: Row(
children: [
SvgPicture.asset(
AssetsPaths.icGroupChat,
colorFilter: ColorFilter.mode(AppColors.color727772, BlendMode.srcIn),
width: 20.w,
height: 20.w,
),
Gap(10.w),
Expanded(child: Text('New Group Chat', style: TextStyle(color: AppColors.color727772, fontSize: 18.sp))),
SvgPicture.asset(
AssetsPaths.icChevronRight,
colorFilter: ColorFilter.mode(AppColors.color727772, BlendMode.srcIn),
width: 8.55.w,
height: 15.w,
),
],
- ),
- ),
+ ),
+ ),
+ ),📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| Padding( | |
| padding: EdgeInsets.symmetric(horizontal: 24.w, vertical: 12.h), | |
| child: Row( | |
| children: [ | |
| SvgPicture.asset( | |
| AssetsPaths.icGroupChat, | |
| colorFilter: ColorFilter.mode(AppColors.color727772, BlendMode.srcIn), | |
| width: 20.w, | |
| height: 20.w, | |
| ), | |
| Gap(10.w), | |
| Expanded(child: Text('New Group Chat', style: TextStyle(color: AppColors.color727772, fontSize: 18.sp))), | |
| SvgPicture.asset( | |
| AssetsPaths.icChevronRight, | |
| colorFilter: ColorFilter.mode(AppColors.color727772, BlendMode.srcIn), | |
| width: 8.55.w, | |
| height: 15.w, | |
| ), | |
| ], | |
| ), | |
| ), | |
| GestureDetector( | |
| onTap: () { | |
| // Navigate to group chat creation screen or show group creation bottom sheet | |
| }, | |
| child: Padding( | |
| padding: EdgeInsets.symmetric(horizontal: 24.w, vertical: 12.h), | |
| child: Row( | |
| children: [ | |
| SvgPicture.asset( | |
| AssetsPaths.icGroupChat, | |
| colorFilter: ColorFilter.mode(AppColors.color727772, BlendMode.srcIn), | |
| width: 20.w, | |
| height: 20.w, | |
| ), | |
| Gap(10.w), | |
| Expanded( | |
| child: Text( | |
| 'New Group Chat', | |
| style: TextStyle( | |
| color: AppColors.color727772, | |
| fontSize: 18.sp, | |
| ), | |
| ), | |
| ), | |
| SvgPicture.asset( | |
| AssetsPaths.icChevronRight, | |
| colorFilter: ColorFilter.mode(AppColors.color727772, BlendMode.srcIn), | |
| width: 8.55.w, | |
| height: 15.w, | |
| ), | |
| ], | |
| ), | |
| ), | |
| ), |
🤖 Prompt for AI Agents
In lib/features/contact_list/presentation/new_chat_bottom_sheet.dart between
lines 68 and 88, the "New Group Chat" row is currently static and lacks
interactivity. Wrap the Padding widget with a GestureDetector or InkWell and
implement the onTap callback to navigate to the group chat creation screen.
Ensure the navigation logic uses the appropriate context and routing method
consistent with the app's navigation architecture.
| Padding( | ||
| padding: EdgeInsets.symmetric(horizontal: 16.w), | ||
| child: Text( | ||
| publicKey, | ||
| textAlign: TextAlign.center, | ||
| style: TextStyle( | ||
| fontSize: 14.sp, | ||
| color: AppColors.color727772, | ||
| ), | ||
| ), | ||
| ), |
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.
🛠️ Refactor suggestion
Add copy functionality for the public key.
Public keys are typically long strings that users might want to copy. Add a copy button to improve user experience.
+ import 'package:flutter/services.dart';
// In the build method:
Padding(
padding: EdgeInsets.symmetric(horizontal: 16.w),
- child: Text(
- publicKey,
- textAlign: TextAlign.center,
- style: TextStyle(
- fontSize: 14.sp,
- color: AppColors.color727772,
- ),
- ),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Expanded(
+ child: Text(
+ publicKey,
+ textAlign: TextAlign.center,
+ style: TextStyle(
+ fontSize: 14.sp,
+ color: AppColors.color727772,
+ ),
+ ),
+ ),
+ IconButton(
+ icon: Icon(Icons.copy, size: 20.w, color: AppColors.color727772),
+ onPressed: () {
+ Clipboard.setData(ClipboardData(text: publicKey));
+ ScaffoldMessenger.of(context).showSnackBar(
+ SnackBar(content: Text('Public key copied to clipboard'), duration: const Duration(seconds: 2)),
+ );
+ },
+ ),
+ ],
+ ),🤖 Prompt for AI Agents
In lib/features/contact_list/presentation/start_chat_bottom_sheet.dart around
lines 72 to 82, the public key text is displayed but lacks a copy-to-clipboard
feature. Add a copy button or icon next to the public key text that, when
tapped, copies the public key string to the clipboard. Use Flutter's Clipboard
API to implement the copy functionality and provide user feedback such as a
toast or snackbar confirming the copy action.
Summary by CodeRabbit
New Features
Enhancements
Bug Fixes
Removals