Skip to content

Conversation

@Quwaysim
Copy link
Contributor

@Quwaysim Quwaysim commented May 15, 2025

  • Added new chat UIs
  • Added customisable utility class to show BottomSheets
  • Added reusable and customisable TextField widget

Summary by CodeRabbit

  • New Features

    • Introduced new bottom sheet interfaces for starting new chats and searching contacts/chats, offering improved and interactive UI experiences.
    • Added a customizable bottom sheet utility for consistent modal interactions.
    • Added a reusable, styled text field widget for consistent input fields.
    • Added a new model for managing contact data with name, email, public key, and image.
  • Enhancements

    • Updated contact list and related UI components to use the new contact model and improved interaction handling.
    • Centralized asset path management for easier maintenance.
  • Bug Fixes

    • Corrected image asset imports on the welcome page to prevent loading errors.
  • Removals

    • Removed the previous full-screen search modal in favor of new bottom sheet components.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented May 15, 2025

Walkthrough

This 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 ContactModel. Asset path management is centralized, and search/add chat interactions in the chat list app bar are updated to use the new bottom sheets. Supporting widgets and utilities are added or updated accordingly.

Changes

File(s) Change Summary
lib/core/utils/assets_paths.dart Added three new asset path constants (two SVG, one PNG) as static String to AssetsPaths.
lib/features/contact_list/data/dummy_data.dart Changed dummyContacts from List<ChatModel> to List<ContactModel>, updated entries and imports accordingly.
lib/features/contact_list/models/contact_model.dart Added new ContactModel class with required fields: name, email, publicKey, imagePath.
lib/features/contact_list/presentation/new_chat_bottom_sheet.dart Added NewChatBottomSheet widget for starting new chats with search/filter functionality.
lib/features/contact_list/presentation/search_chat_bottom_sheet.dart Added SearchChatBottomSheet widget for searching contacts/chats with dynamic filtering.
lib/features/contact_list/presentation/search_screen.dart Removed SearchBottomSheet widget and its associated code.
lib/features/contact_list/presentation/start_chat_bottom_sheet.dart Added StartSecureChatBottomSheet widget for initiating secure chats via a bottom sheet.
lib/features/contact_list/presentation/widgets/chat_list_appbar.dart Updated imports and tap handlers to use new bottom sheets for search and new chat actions.
lib/features/contact_list/presentation/widgets/contact_list_tile.dart Updated to use ContactModel instead of ChatModel, added optional onTap callback, wrapped in GestureDetector.
lib/main.dart Removed unused import for chat_list_screen.dart.
lib/screens/auth_flow/welcome_page.dart Fixed login page import, centralized splash image path using asset paths utility.
lib/shared/custom_bottom_sheet.dart Added CustomBottomSheet utility class for configurable, animated bottom sheets.
lib/shared/custom_textfield.dart Added CustomTextField widget for consistent, styled text input fields.

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
Loading

Poem

In the warren of widgets, a bottom sheet hops,
For searching and chatting, it never quite stops.
Contacts now shimmer with models anew,
While asset paths guide what the bunnies view.
Custom sheets slide up, so lively and neat—
Fluttering changes, a code rabbit treat!
🐇✨

Note

⚡️ AI Code Reviews for VS Code, Cursor, Windsurf

CodeRabbit 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.
Learn more here.


Note

⚡️ Faster reviews with caching

CodeRabbit 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 Review - Disable Cache at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the Data Retention setting under your Organization Settings.
Enjoy the performance boost—your workflow just got faster.


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

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need 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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🧹 Nitpick comments (16)
lib/shared/custom_textfield.dart (2)

6-21: Reconsider the default autofocus behavior

Setting autofocus = true as 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 options

The current implementation provides basic functionality but could be enhanced with additional customization options to make it more versatile:

  1. Text styling for input text (not just hint text)
  2. Keyboard type configuration
  3. Text input action configuration
  4. Focus node parameter
  5. Error state handling and error text display
  6. Different border colors for different states (normal/focused/error)
  7. 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 method

The 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 container

Bottom 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 parameters

While 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, and heightFactor.

lib/features/contact_list/models/contact_model.dart (3)

1-13: Consider adding equality and toString methods

The ContactModel class is well-structured but would benefit from implementing equality comparison (using == operator and hashCode) and a toString method 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 updates

Since this is an immutable model, adding a copyWith method 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 display

Consider 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 ContactModel

The dummy contacts list has been successfully refactored to use the new ContactModel instead of ChatModel, 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:

  1. Using a more descriptive message
  2. Adding a duration
  3. 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 required keyword 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

📥 Commits

Reviewing files that changed from the base of the PR and between a925672 and 02c4a8d.

⛔ Files ignored due to path filters (3)
  • assets/pngs/login_splash.png is excluded by !**/*.png
  • assets/svgs/ic_chevron_right.svg is excluded by !**/*.svg
  • assets/svgs/ic_group_chat.svg is 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 field

The 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 CustomBottomSheet

The 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 management

Using the centralized AssetsPaths class 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 loginSplash constant is properly defined in the AssetsPaths class 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
The loginSplash constant is present in lib/core/utils/assets_paths.dart as expected, so no further changes are needed.

lib/features/contact_list/models/contact_model.dart (1)

1-13: Good structured model implementation

The ContactModel class 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 components

The 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 sheet

The search functionality has been updated to use the new SearchChatBottomSheet component instead of the previous implementation. This is a good improvement for UI consistency.


30-33: Added tap functionality to the add icon

The add icon has been properly wrapped in a GestureDetector to handle tap events, invoking the new NewChatBottomSheet component. 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 ContactModel

The import for the new ContactModel has 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 ContactModel

The import for ContactModel has been properly added to replace the previous ChatModel.


10-14: Updated widget to use ContactModel and added onTap callback

The widget has been properly updated to use ContactModel instead of ChatModel and an optional onTap callback 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 initState and properly cleans up in dispose, following best practices for managing resources in stateful widgets.


104-113: Consider pagination for large chat lists.

The chat list is wrapped in an Expanded widget 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.builder with 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)),
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

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';
Copy link
Contributor

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.

Suggested change
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.

Comment on lines +11 to +12
static String icChevronRight = '$_svgsDir/ic_chevron_right.svg';
static String icGroupChat = '$_svgsDir/ic_group_chat.svg';
Copy link
Contributor

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.

Suggested change
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.

Comment on lines +18 to 65
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),
),
],
),
),
),
],
],
),
),
);
Copy link
Contributor

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.

Suggested change
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.

Comment on lines +87 to +96
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);
},
),
Copy link
Contributor

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.

Comment on lines +68 to +88
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,
),
],
),
),
Copy link
Contributor

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.

Suggested change
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.

Comment on lines +72 to +82
Padding(
padding: EdgeInsets.symmetric(horizontal: 16.w),
child: Text(
publicKey,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14.sp,
color: AppColors.color727772,
),
),
),
Copy link
Contributor

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.

@erskingardner erskingardner merged commit fb53c1b into master May 16, 2025
1 check passed
@erskingardner erskingardner deleted the feature/new-chat-pages branch May 16, 2025 07:43
@coderabbitai coderabbitai bot mentioned this pull request May 27, 2025
@untreu2 untreu2 mentioned this pull request Aug 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants