Skip to content

Conversation

@AndreaDiazCorreia
Copy link
Member

@AndreaDiazCorreia AndreaDiazCorreia commented Aug 29, 2025

This PR introduces the complete UI implementation for the Disputes feature, addressing issues #171, #172, and #173.

The implementation includes a fully functional dispute chat interface that replicates the existing chat UI patterns, with message bubbles, admin communications, and proper state management across different dispute statuses (initiated, in-progress, resolved). The UI features proper internationalization support across English, Spanish, and Italian languages, with status-dependent behavior where initiated disputes show a waiting screen without chat input, in-progress disputes display active communication with admins, and resolved disputes show historical messages with resolution notifications.

All hardcoded data has been centralized into a mock data system that can be easily toggled or removed when real dispute integration is implemented. The interface maintains consistency with the existing application design patterns while providing a smooth user experience for dispute resolution workflows.

image image image image

Summary by CodeRabbit

  • New Features

    • Disputes: list, details screen with chat, compose/send UI, message bubbles, status badges, info cards, mock data and chat state for UI.
  • Enhancements

    • Chat: tab-based Messages/Disputes with provider-driven state and swipe navigation.
    • Order amounts: display includes currency formatting.
  • Localization

    • Added comprehensive dispute-related translations and new forAmountWithCurrency keys for EN/ES/IT.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 29, 2025

Walkthrough

Adds a disputes feature: new dispute domain and UI models, mock repository/service, Riverpod providers/notifier, many dispute UI widgets and screen, chat tab provider integration, router entry /dispute_details/:disputeId, and extensive localization additions including forAmount → forAmountWithCurrency.

Changes

Cohort / File(s) Summary
Routing
lib/core/app_routes.dart
Adds route /dispute_details/:disputeId that builds DisputeChatScreen using path parameters and wraps it with the existing default transition inside the ShellRoute.
Domain & UI models
lib/data/models/dispute.dart, lib/data/models/dispute_chat.dart, lib/data/models/dispute_event.dart
Expands Dispute (many optional fields, fromNostrEvent, extended fromJson, copyWith, equality), adds DisputeData view-model and enums (DisputeDescriptionKey, UserRole), and introduces DisputeChat and DisputeEvent stub models with (de)serialization.
Repository & Service (mock)
lib/data/repositories/dispute_repository.dart, lib/services/dispute_service.dart
New singleton mock DisputeRepository and DisputeService with mocked get/list/send/initiate methods and artificial delays.
Providers & Notifiers
lib/features/disputes/providers/dispute_providers.dart, lib/features/disputes/notifiers/dispute_chat_notifier.dart
Adds Riverpod providers: disputeDetailsProvider, userDisputesProvider, disputeChatProvider, and a DisputeChatNotifier StateNotifier family for per-dispute chat state.
Mock data
lib/features/disputes/data/dispute_mock_data.dart
Adds DisputeMockData supplying sample DisputeData, mock messages, lookup/create helpers and isMockEnabled getter (debug-only mock data).
Screens
lib/features/disputes/screens/dispute_chat_screen.dart
New DisputeChatScreen that loads mock dispute data and renders communication section and conditional message input; shows "Dispute not found" fallback.
Dispute UI widgets
lib/features/disputes/widgets/*
Adds many UI widgets: DisputesList, DisputeListItem, DisputeContent, DisputeHeader, DisputeIcon, DisputeDescription, DisputeOrderId, DisputeInfoCard, DisputeStatusBadge, DisputeStatusContent, DisputeMessagesList, DisputeMessageBubble, DisputeMessageInput, DisputeInputSection, DisputeCommunicationSection.
Chat integration & tab state
lib/features/chat/screens/chat_rooms_list.dart, lib/features/chat/widgets/chat_tabs.dart, lib/features/chat/providers/chat_tab_provider.dart
Replaces TabController state with a Riverpod-backed chatTabProvider and ChatTabType enum; converts ChatRoomsScreen/ChatTabs to provider-driven flows and renders DisputesList in the disputes tab with swipe handling.
I18n call-site updates
lib/features/chat/widgets/trade_information_tab.dart, lib/features/order/screens/take_order_screen.dart, lib/shared/widgets/order_cards.dart
Replaces forAmount(...) calls with forAmountWithCurrency(...) at call sites.
Localization
lib/l10n/intl_en.arb, lib/l10n/intl_es.arb, lib/l10n/intl_it.arb
Adds comprehensive dispute- and admin-chat localization keys & metadata, renames/introduces forAmountWithCurrency, and updates locale files accordingly.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant Chat as ChatRoomsScreen
  participant Tabs as ChatTabs
  participant Disputes as DisputesList
  participant Router as GoRouter
  participant Screen as DisputeChatScreen
  participant Mock as DisputeMockData

  User->>Chat: open Chats screen
  Chat->>Tabs: render tabs (provider-driven)
  Tabs->>Disputes: render disputes tab when active
  User->>Disputes: tap dispute item
  Disputes->>Router: context.push("/dispute_details/{id}")
  Router->>Screen: instantiate DisputeChatScreen(disputeId)
  Screen->>Mock: DisputeMockData.getDisputeById(disputeId)
  Mock-->>Screen: DisputeData or null
  alt dispute found
    Screen->>Screen: render messages + conditional input
  else not found
    Screen->>User: show "Dispute not found"
  end
Loading
sequenceDiagram
  autonumber
  actor User
  participant Screen as DisputeChatScreen
  participant Messages as DisputeMessagesList
  participant Notifier as DisputeChatNotifier
  participant Mock as DisputeMockData

  Screen->>Messages: build with disputeId/status/disputeData
  Messages->>Mock: getMockMessages(disputeId, status)
  Mock-->>Messages: List<DisputeChat>
  User->>Messages: long-press or view message
  User->>Screen: send message
  Screen->>Notifier: sendMessage(text)
  Notifier-->>Messages: state updated -> UI rebuilds with new bubble
  Note right of Mock: mock-only data/service behavior (debug)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • Catrya
  • grunch
  • chebizarro

Poem

A rabbit hops through code so bright,
I stitch up chats and route the night.
Disputes in bubbles, mock data near,
Admins and badges, menus clear.
Tap a thread — carrot-powered cheer! 🥕✨

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/dispute-ui-only

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.
    • 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.
  • 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 the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit 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

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • 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: 26

Caution

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

⚠️ Outside diff range comments (6)
lib/features/order/screens/take_order_screen.dart (2)

379-383: Guard setState after async gap

setState is called after awaiting showDialog; if the widget was disposed, this will throw.

-                  // Dialog was dismissed without entering amount, reset loading state
-                  setState(() {
-                    _isSubmitting = false;
-                  });
+                  // Dialog was dismissed without entering amount, reset loading state
+                  if (!mounted) return;
+                  setState(() {
+                    _isSubmitting = false;
+                  });

108-110: Avoid duplicated currency in forAmountWithCurrency
Remove the currency code from amountString so the ARB templates (for {amount} {currency}, por {amount} {currency}, per {amount} {currency}) append it exactly once. For example in lib/features/order/screens/take_order_screen.dart:

- final amountString = '${order.fiatAmount} ${order.currency} $currencyFlag';
+ final amountString = '${order.fiatAmount} $currencyFlag';
lib/features/chat/widgets/trade_information_tab.dart (1)

26-37: Don’t fabricate dates; show “Unknown date” when missing.

Current fallback subtracts one hour from now, which misleads users. Return null and let the formatter show the localized “Unknown date”.

Apply this diff:

-  /// Get a valid creation date for the order
-  /// Uses order.createdAt if valid, otherwise falls back to current time
-  DateTime _getOrderCreationDate() {
+  /// Get a valid creation date for the order
+  /// Uses order.createdAt if valid, otherwise returns null
+  DateTime? _getOrderCreationDate() {
     if (order?.createdAt != null && order!.createdAt! > 0) {
       // Convert Unix timestamp to DateTime
       return DateTime.fromMillisecondsSinceEpoch(order!.createdAt! * 1000);
     }
-    
-    // Fallback: use current time minus a reasonable amount
-    // This is better than showing "Unknown date"
-    return DateTime.now().subtract(const Duration(hours: 1));
+    return null;
   }

And adjust formatter signature:

-  String _formatOrderDate(DateTime? date, BuildContext context) {
+  String _formatOrderDate(DateTime? date, BuildContext context) {
     if (date == null) {
       return S.of(context)!.unknownDate;
     }
-    return DateFormat('MMMM d, yyyy').format(date);
+    // Locale-aware format
+    final locale = Localizations.localeOf(context).toString();
+    return DateFormat.yMMMd(locale).format(date);
   }
lib/features/chat/screens/chat_rooms_list.dart (2)

66-66: Localize without hardcoded fallbacks; avoid nullable access on S.of(context)

Per guidelines, prefer fully localized strings. The generated S.of(context) is non-null; drop the fallback and the optional chaining.

-                    S.of(context)?.chat ?? 'Chat',
+                    S.of(context).chat,

137-138: Localize empty state message (no hardcoded fallback)

Keep UX consistent with i18n.

-      return EmptyStateView(
-        message: S.of(context)?.noMessagesAvailable ?? 'No messages available',
-      );
+      return EmptyStateView(
+        message: S.of(context).noMessagesAvailable,
+      );
lib/l10n/intl_it.arb (1)

760-771: Duplicate ARB keys will break i18n generation or shadow values. Remove duplicates.

  • Key duplicated: forAmount (also defined at Line 619).
  • Key duplicated: retry (already at Line 215).
  • Key duplicated: orderIdLabel (already at Line 641).

Apply this minimal cleanup:

-  "forAmount": "per {amount}",
-  "forAmountWithCurrency": "per {amount} {currency}",
+  "forAmountWithCurrency": "per {amount} {currency}",
@@
-  "retry": "Riprova",
@@
-  "orderIdLabel": "ID Ordine",

Then ensure call sites reuse the existing retry and orderIdLabel, and forAmount (Line 619) or the new forAmountWithCurrency where needed.

Also applies to: 965-966, 976-976

🧹 Nitpick comments (45)
lib/data/models/dispute_event.dart (1)

6-7: Prefer a typed status over raw String

An enum (e.g., DisputeStatus) avoids typos and enables exhaustiveness in UI.

Example:

enum DisputeStatus { initiated, inProgress, resolved, unknown }
lib/l10n/intl_es.arb (2)

903-917: Minor wording nit: prefer “Clave pública del administrador”.

"adminPubkey" value is "Pubkey del administrador". For consistency with other strings (e.g., “Clave Pública”), consider:

  • adminPubkey: "Clave pública del administrador"

731-741: Remove deprecated “forAmount” keys and metadata from all ARB locales
No Dart references remain; legacy entries still exist in:

  • lib/l10n/intl_en.arb (line 243)
  • lib/l10n/intl_es.arb (line 586)
  • lib/l10n/intl_it.arb (lines 619, 760)
    Remove each "forAmount" translation and its corresponding @forAmount metadata to prevent accidental use.
lib/l10n/intl_en.arb (1)

703-713: Remove deprecated “forAmount” entries from all locales
• lib/l10n/intl_en.arb:243
• lib/l10n/intl_es.arb:586
• lib/l10n/intl_it.arb:619, 760

lib/features/chat/widgets/trade_information_tab.dart (1)

19-24: Use locale-aware date format.

Hardcoded 'MMMM d, yyyy' won’t match non-English locales. Switch to DateFormat.yMMMd(locale).

lib/features/disputes/widgets/dispute_icon.dart (1)

9-16: Make these widgets const; consider semantics for accessibility

  • Minor perf/readability win: the Padding/Icon subtree can be const.
  • If the icon is decorative, exclude it from semantics; if meaningful, add a localized semanticLabel.
-    return Padding(
-      padding: const EdgeInsets.only(top: 8.0),
-      child: Icon(
-        Icons.warning_amber,
-        color: Colors.amber,
-        size: 32,
-      ),
-    );
+    return const Padding(
+      padding: EdgeInsets.only(top: 8.0),
+      child: Icon(
+        Icons.warning_amber,
+        color: Colors.amber,
+        size: 32,
+      ),
+    );

Optionally, one of:

-      child: Icon(
+      child: ExcludeSemantics(
+        child: Icon(
           Icons.warning_amber,
           color: Colors.amber,
           size: 32,
-      ),
+        ),
+      ),

or (if meaningful and localized):

-      child: Icon(
+      child: Icon(
         Icons.warning_amber,
-        color: Colors.amber,
+        semanticLabel: S.of(context).disputeWarningIconLabel,
+        color: Colors.amber,
         size: 32,
       ),
lib/features/disputes/widgets/dispute_order_id.dart (1)

11-16: Avoid overflow for long IDs

Add single-line ellipsis to keep list rows tidy with long order IDs.

-    return Text(
-      orderId,
-      style: Theme.of(context).textTheme.bodyMedium?.copyWith(
-            fontWeight: FontWeight.w500,
-          ),
-    );
+    return Text(
+      orderId,
+      maxLines: 1,
+      overflow: TextOverflow.ellipsis,
+      style: Theme.of(context).textTheme.bodyMedium?.copyWith(
+            fontWeight: FontWeight.w500,
+          ),
+    );
lib/features/disputes/widgets/dispute_description.dart (1)

12-20: LGTM: concise, single-line description

Ellipsis and size fit list density. Consider using textTheme.bodySmall?.copyWith(color: AppTheme.textSecondary) if you want to inherit dynamic typography; optional.

lib/features/disputes/widgets/disputes_list.dart (2)

25-28: Normalize status values.

This file uses 'in-progress' while other widgets switch on description/status enums/keys. Prefer a typed DisputeStatus enum or a single canonical string set to avoid mismatches.


87-88: Avoid hardcoded route strings.

Use a shared route builder/constant (e.g., AppRoutes.disputeDetails(disputeId)) to prevent drift with router definitions.

lib/features/disputes/widgets/dispute_header.dart (1)

14-27: Prevent overflow in narrow layouts.

Wrap the title in Expanded and ellipsize to avoid layout overflow beside the badge.

-    return Row(
+    return Row(
       mainAxisAlignment: MainAxisAlignment.spaceBetween,
       children: [
-        Text(
+        Expanded(
+          child: Text(
             S.of(context)!.disputeForOrder,
-          style: const TextStyle(
+            overflow: TextOverflow.ellipsis,
+            style: const TextStyle(
               color: Colors.white,
               fontWeight: FontWeight.bold,
               fontSize: 16,
-          ),
-        ),
+            ),
+          ),
+        ),
         DisputeStatusBadge(status: dispute.status),
       ],
     );
lib/features/disputes/widgets/dispute_info_card.dart (1)

70-97: Fixed-width label can truncate in longer locales.

Consider making label width responsive (e.g., using IntrinsicWidth or flex) to accommodate translations.

lib/features/disputes/widgets/dispute_status_content.dart (1)

16-17: Prefer a typed status over free-form strings.

String compares for 'resolved'/'closed' are brittle. Use a DisputeStatus enum or normalized status mapping.

lib/data/repositories/dispute_repository.dart (1)

3-8: Keep UI-only repo behind a feature flag and inject a clock.

  • Gate this mock via a feature flag/env to avoid shipping in production.
  • Inject a clock (e.g., via constructor) for test determinism instead of DateTime.now().

Also applies to: 9-30, 45-48

lib/features/disputes/widgets/dispute_list_item.dart (1)

18-21: Prefer InkWell (with Material) over GestureDetector for tap semantics and ripple

Improves accessibility (focus/semantics), hover/click feedback, and consistency with app patterns.

-    return GestureDetector(
-      onTap: onTap,
-      child: Container(
+    return Material(
+      color: Colors.transparent,
+      child: InkWell(
+        onTap: onTap,
+        child: Container(
           decoration: BoxDecoration(
             border: Border(
               bottom: BorderSide(
                 color: Colors.white.withValues(alpha: 0.05),
                 width: 1.0,
               ),
             ),
           ),
           child: Padding(
             padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 16),
             child: Row(
               crossAxisAlignment: CrossAxisAlignment.start,
               children: [
-              DisputeIcon(),
+              const DisputeIcon(),
               const SizedBox(width: 16),
               Expanded(
                 child: DisputeContent(dispute: dispute),
               ),
               ],
             ),
           ),
-        ),
-      ),
-    );
+        ),
+      ),
+    );

Also applies to: 29-43

lib/features/disputes/widgets/dispute_communication_section.dart (1)

7-15: Avoid stringly-typed status; use an enum

Prevents typos (“in-progress” vs “in_progress”) and eases refactors.

Example:

enum DisputeStatus { initiated, inProgress, resolved }
final DisputeStatus status;
const DisputeCommunicationSection({ required this.status, ... });
lib/services/dispute_service.dart (2)

12-22: Drop redundant awaits to reduce stack depth

Methods simply forward repository futures; return them directly.

-  Future<List<Dispute>> getUserDisputes() async {
-    return await _disputeRepository.getUserDisputes();
-  }
+  Future<List<Dispute>> getUserDisputes() {
+    return _disputeRepository.getUserDisputes();
+  }

-  Future<Dispute?> getDispute(String disputeId) async {
-    return await _disputeRepository.getDispute(disputeId);
-  }
+  Future<Dispute?> getDispute(String disputeId) {
+    return _disputeRepository.getDispute(disputeId);
+  }

-  Future<void> sendDisputeMessage(String disputeId, String message) async {
-    await _disputeRepository.sendDisputeMessage(disputeId, message);
-  }
+  Future<void> sendDisputeMessage(String disputeId, String message) {
+    return _disputeRepository.sendDisputeMessage(disputeId, message);
+  }

24-27: Consider injection for testability

Allow passing a repository in ctor to mock/stub in tests.

-class DisputeService {
-  static final DisputeService _instance = DisputeService._internal();
-  factory DisputeService() => _instance;
-  DisputeService._internal();
-
-  final DisputeRepository _disputeRepository = DisputeRepository();
+class DisputeService {
+  static final DisputeService _instance = DisputeService._internal();
+  factory DisputeService({DisputeRepository? repository}) =>
+      (_instance.._instance._disputeRepository = repository ?? _instance._disputeRepository);
+  DisputeService._internal();
+
+  DisputeRepository _disputeRepository = DisputeRepository();
lib/features/disputes/screens/dispute_chat_screen.dart (3)

41-51: Localize the app bar title and prefer theme text styles

Follow l10n and app typography instead of hardcoded TextStyle.

-        title: Text(
-          'Dispute Chat',
-          style: const TextStyle(
-            color: Colors.white,
-            fontSize: 18,
-            fontWeight: FontWeight.w600,
-          ),
-        ),
+        title: Text(
+          S.of(context).disputeChatTitle,
+          style: Theme.of(context).textTheme.titleMedium?.copyWith(color: Colors.white),
+        ),

Also applies to: 45-51


60-65: Wrap the communication section with Expanded (after removing it from the widget itself)

Ensures proper flex layout ownership at the parent.

-          DisputeCommunicationSection(
-            disputeId: disputeId,
-            disputeData: mockDispute,
-            status: mockDispute.status,
-          ),
+          Expanded(
+            child: DisputeCommunicationSection(
+              disputeId: disputeId,
+              disputeData: mockDispute,
+              status: mockDispute.status,
+            ),
+          ),

66-69: Stringly-typed status checks are brittle

Prefer an enum (e.g., DisputeStatus.resolved) to avoid typos and enable exhaustive switches.

lib/features/disputes/widgets/dispute_input_section.dart (2)

83-90: Prefer IconButton/ElevatedButton and theme colors

Improves accessibility (semantics/disabled state/focus), and uses app color scheme.

-            GestureDetector(
-              onTap: _isLoading ? null : _sendMessage,
-              child: Container(
-                width: 40,
-                height: 40,
-                decoration: BoxDecoration(
-                  color: _canSend() ? Colors.blue : Colors.grey[600],
-                  shape: BoxShape.circle,
-                ),
-                child: _isLoading
+            IconButton.filled(
+              onPressed: _canSend() ? _sendMessage : null,
+              style: ButtonStyle(
+                backgroundColor: WidgetStateProperty.resolveWith((states) {
+                  final scheme = Theme.of(context).colorScheme;
+                  return states.contains(WidgetState.disabled)
+                      ? scheme.surfaceVariant
+                      : scheme.primary;
+                }),
+                fixedSize: const WidgetStatePropertyAll(Size(40, 40)),
+                shape: const WidgetStatePropertyAll(CircleBorder()),
+              ),
+              icon: _isLoading
                     ? Padding(
                         padding: const EdgeInsets.all(8.0),
                         child: CircularProgressIndicator(
                           color: Colors.white,
                           strokeWidth: 2,
                         ),
                       )
-                    : const Icon(
-                        Icons.send,
-                        color: Colors.white,
-                        size: 20,
-                      ),
-              ),
-            ),
+                    : const Icon(Icons.send, color: Colors.white, size: 20),
+            ),

Also applies to: 98-103


115-123: Minor UX: dismiss keyboard after sending; keep mounted checks

Optional polish.

   final message = _messageController.text.trim();
   _messageController.clear();
+  FocusScope.of(context).unfocus();

Also applies to: 146-152

lib/features/disputes/widgets/dispute_status_badge.dart (3)

74-88: Standardize localization access (avoid null/force unwrap).

Use S.of(context).key consistently; remove !. This aligns with our localization guideline and avoids unnecessary null assertions.

-        return S.of(context)!.disputeStatusInitiated;
+        return S.of(context).disputeStatusInitiated;
...
-        return S.of(context)!.disputeStatusInProgress;
+        return S.of(context).disputeStatusInProgress;
...
-        return S.of(context)!.disputeStatusResolved;
+        return S.of(context).disputeStatusResolved;
...
-        return S.of(context)!.disputeStatusClosed;
+        return S.of(context).disputeStatusClosed;
...
-        return S.of(context)!.disputeStatusInitiated;
+        return S.of(context).disputeStatusInitiated;

40-55: Avoid hardcoded Colors; route through AppTheme.

Replace Colors.blue with theme tokens (e.g., add statusInfoBackground/statusInfoText in AppTheme and use them here) to keep visual consistency and enable theming.

Also applies to: 57-72


7-10: Strongly type status (enum/sealed) instead of String.

Using a DisputeStatus enum or sealed class will remove normalization needs and prevent invalid states at compile time.

Also applies to: 33-38, 40-55, 57-72

lib/features/disputes/notifiers/dispute_chat_notifier.dart (2)

19-36: Expose immutable state to consumers.

Wrap assigned lists with List.unmodifiable(...) to prevent accidental mutation by downstream code reading provider state.

-  void loadMessages(String disputeId) {
+  void loadMessages(String disputeId) {
     // Stub implementation - load mock messages
-    state = [
+    state = List.unmodifiable([
       DisputeChat(
         id: '1',
         message: 'Hello, I have an issue with this order',
         timestamp: DateTime.now().subtract(const Duration(minutes: 5)),
         isFromUser: true,
       ),
       DisputeChat(
         id: '2',
         message: 'I understand. Let me review the details.',
         timestamp: DateTime.now().subtract(const Duration(minutes: 3)),
         isFromUser: false,
         adminPubkey: 'admin_pubkey_123',
       ),
-    ];
+    ]);
   }

39-46: Avoid duplicating providers; re-export the existing family.

disputeChatProvider duplicates disputeChatNotifierProvider. Prefer a direct alias to prevent confusion and rebuild indirection.

-final disputeChatNotifierProvider =
+final disputeChatNotifierProvider =
     StateNotifierProvider.family<DisputeChatNotifier, List<DisputeChat>, String>(
   (ref, disputeId) {
     final notifier = DisputeChatNotifier();
     notifier.loadMessages(disputeId);
     return notifier;
   },
 );

Then in providers/dispute_providers.dart, alias it:

-final disputeChatProvider = StateNotifierProvider.family<DisputeChatNotifier, List<DisputeChat>, String>(
-  (ref, disputeId) {
-    return ref.watch(disputeChatNotifierProvider(disputeId).notifier);
-  },
-);
+final disputeChatProvider = disputeChatNotifierProvider;
lib/features/disputes/widgets/dispute_messages_list.dart (7)

37-39: Check mounted before scheduling scroll.

Prevents acting on a disposed State during rapid navigations.

-    WidgetsBinding.instance.addPostFrameCallback((_) {
-      _scrollToBottom(animate: false);
-    });
+    WidgetsBinding.instance.addPostFrameCallback((_) {
+      if (!mounted) return;
+      _scrollToBottom(animate: false);
+    });

108-110: Normalize status comparisons (trim/lowercase).

Avoids subtle mismatches from casing/whitespace.

-          if (widget.status == 'resolved')
+          if (widget.status.trim().toLowerCase() == 'resolved')
             _buildResolutionNotification(context),
-    if (widget.status == 'initiated') {
+    if (widget.status.trim().toLowerCase() == 'initiated') {
       return const SizedBox.shrink();
     }

Also applies to: 148-150


122-140: Remove hardcoded fallbacks; require localized strings.

Per guidelines, avoid English literals in UI. Use S.of(context).key directly (ensure ARB keys exist).

-              S.of(context)?.waitingAdminAssignment ?? 'Waiting for admin assignment',
+              S.of(context).waitingAdminAssignment,
-              S.of(context)?.waitingAdminDescription ?? 'Your dispute has been submitted. An admin will be assigned to help resolve this issue.',
+              S.of(context).waitingAdminDescription,
-              S.of(context)?.adminAssigned ?? 'Admin has been assigned to this dispute',
+              S.of(context).adminAssigned,
-              S.of(context)?.disputeResolvedMessage ?? 'This dispute has been resolved. Check your wallet for any refunds or payments.',
+              S.of(context).disputeResolvedMessage,

Also applies to: 168-176, 199-206


153-176: Avoid hardcoded Colors; move banner palette to AppTheme.

Replace Colors.blue[...]/Colors.green[...] with theme tokens (e.g., AppTheme.infoBackground/Text, AppTheme.successBackground/Text) for consistency and dark-mode flexibility.

Also applies to: 183-205


76-76: Fix typo in comment (“scrollable”).

-          // Messages list with info card at top (scrolleable)
+          // Messages list with info card at top (scrollable)

95-103: Consider adding stable keys to message items.

If DisputeMessageBubble supports key, pass ValueKey(message.id) to improve list diffing and avoid rebuild artifacts.


213-221: Prefer sourcing messages via providers, not mock directly.

To align with our architecture (Riverpod Notifiers + repositories), consume disputeChatProvider(disputeId) instead of calling DisputeMockData.getMockMessages(...) from the widget.

lib/features/disputes/providers/dispute_providers.dart (2)

17-20: Dead code: getDisputeById never returns null.

DisputeMockData.getDisputeById falls back to a default dispute; this null check is unreachable. Either make getDisputeById non-nullable and remove this check, or allow nulls consistently.

-  final disputeData = DisputeMockData.getDisputeById(disputeId);
-  if (disputeData == null) return null;
+  final disputeData = DisputeMockData.getDisputeById(disputeId);

45-50: Alias the existing notifier provider instead of wrapping it.

Reduces indirection and unnecessary rebuild coupling.

-final disputeChatProvider = StateNotifierProvider.family<DisputeChatNotifier, List<DisputeChat>, String>(
-  (ref, disputeId) {
-    return ref.watch(disputeChatNotifierProvider(disputeId).notifier);
-  },
-);
+final disputeChatProvider = disputeChatNotifierProvider;
lib/features/disputes/data/dispute_mock_data.dart (3)

42-51: Make getDisputeById non-nullable to reflect actual behavior.

It always returns a dispute (default fallback). Update signature and call sites to simplify logic.

-  static DisputeData? getDisputeById(String disputeId) {
+  static DisputeData getDisputeById(String disputeId) {
     try {
       return mockDisputes.firstWhere(
         (dispute) => dispute.disputeId == disputeId,
       );
     } catch (e) {
       return _getDefaultMockDispute(disputeId);
     }
   }

130-142: Type safety for initiatorRole.

Use UserRole instead of String to avoid invalid inputs.

-  static String createMockDispute({
+  static String createMockDispute({
     required String orderId,
-    required String reason,
-    required String initiatorRole,
+    required String reason,
+    required UserRole initiatorRole,
     required Map<String, dynamic> orderDetails,
   }) {

53-114: Normalize status input once.

Consider normalizing status (trim().toLowerCase()) before comparisons to accept flexible inputs.

lib/data/models/dispute.dart (3)

449-465: Avoid hardcoded UI strings in model; deprecate description and localize in UI via descriptionKey.

Models should not emit user-facing text. Use descriptionKey in widgets with S.of(context) and deprecate this getter.

-  /// Backward compatibility getter for description
-  String get description {
+  /// Backward compatibility getter for description
+  @Deprecated('Use descriptionKey + UI localization (S.of(context)) instead. '
+      'This getter will be removed.')
+  String get description {

409-413: Also normalize legacy event timestamps.

createdAt unconditionally multiplies by 1000 if int; handle ms vs s like above.

-      createdAt: DateTime.fromMillisecondsSinceEpoch(
-        disputeEvent.createdAt is int 
-          ? disputeEvent.createdAt * 1000 
-          : DateTime.now().millisecondsSinceEpoch
-      ),
+      createdAt: DateTime.fromMillisecondsSinceEpoch(
+        disputeEvent.createdAt is int
+          ? ((disputeEvent.createdAt as int) < 10000000000
+              ? (disputeEvent.createdAt as int) * 1000
+              : (disputeEvent.createdAt as int))
+          : DateTime.now().millisecondsSinceEpoch
+      ),

471-475: Prefer semantic nulls over sentinel strings for fallbacks.

Returning 'unknownOrderId'/'unknownCounterparty' pushes string handling into model. Consider returning null and letting UI localize with S.of(context).unknown.

lib/l10n/intl_it.arb (2)

936-951: Minor Italian polish.

“Citare” suona innaturale qui; “riportare” o “ripetere” il token è più idiomatico.

-  "askAdminQuoteToken": "Chiedi all'amministratore di citare questo token:",
+  "askAdminQuoteToken": "Chiedi all'amministratore di riportare questo token:",

111-116: One typo: double period.

...il token per la tua disputa.. → single period.

-  "adminTookDisputeUsers": "L'amministratore {admin_npub} gestirà la tua disputa. Devi contattare l'amministratore direttamente, ma se qualcuno ti contatta prima, assicurati di chiedergli di fornirti il token per la tua disputa..",
+  "adminTookDisputeUsers": "L'amministratore {admin_npub} gestirà la tua disputa. Devi contattare l'amministratore direttamente, ma se qualcuno ti contatta prima, assicurati di chiedergli di fornirti il token per la tua disputa.",
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between aa9dd2e and 601104d.

⛔ Files ignored due to path filters (1)
  • pubspec.lock is excluded by !**/*.lock
📒 Files selected for processing (32)
  • lib/core/app_routes.dart (2 hunks)
  • lib/data/models/dispute.dart (2 hunks)
  • lib/data/models/dispute_chat.dart (1 hunks)
  • lib/data/models/dispute_event.dart (1 hunks)
  • lib/data/repositories/dispute_repository.dart (1 hunks)
  • lib/features/chat/screens/chat_rooms_list.dart (5 hunks)
  • lib/features/chat/widgets/trade_information_tab.dart (1 hunks)
  • lib/features/disputes/data/dispute_mock_data.dart (1 hunks)
  • lib/features/disputes/notifiers/dispute_chat_notifier.dart (1 hunks)
  • lib/features/disputes/providers/dispute_providers.dart (1 hunks)
  • lib/features/disputes/screens/dispute_chat_screen.dart (1 hunks)
  • lib/features/disputes/widgets/dispute_communication_section.dart (1 hunks)
  • lib/features/disputes/widgets/dispute_content.dart (1 hunks)
  • lib/features/disputes/widgets/dispute_description.dart (1 hunks)
  • lib/features/disputes/widgets/dispute_header.dart (1 hunks)
  • lib/features/disputes/widgets/dispute_icon.dart (1 hunks)
  • lib/features/disputes/widgets/dispute_info_card.dart (1 hunks)
  • lib/features/disputes/widgets/dispute_input_section.dart (1 hunks)
  • lib/features/disputes/widgets/dispute_list_item.dart (1 hunks)
  • lib/features/disputes/widgets/dispute_message_bubble.dart (1 hunks)
  • lib/features/disputes/widgets/dispute_message_input.dart (1 hunks)
  • lib/features/disputes/widgets/dispute_messages_list.dart (1 hunks)
  • lib/features/disputes/widgets/dispute_order_id.dart (1 hunks)
  • lib/features/disputes/widgets/dispute_status_badge.dart (1 hunks)
  • lib/features/disputes/widgets/dispute_status_content.dart (1 hunks)
  • lib/features/disputes/widgets/disputes_list.dart (1 hunks)
  • lib/features/order/screens/take_order_screen.dart (1 hunks)
  • lib/l10n/intl_en.arb (3 hunks)
  • lib/l10n/intl_es.arb (4 hunks)
  • lib/l10n/intl_it.arb (4 hunks)
  • lib/services/dispute_service.dart (1 hunks)
  • lib/shared/widgets/order_cards.dart (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
{lib/*.dart,lib/!(generated)/**/*.dart}

📄 CodeRabbit inference engine (CLAUDE.md)

{lib/*.dart,lib/!(generated)/**/*.dart}: Use localized strings; replace hardcoded user-facing text with S.of(context).keyName
Prefer const constructors and const where possible
Use latest Flutter/Dart APIs (e.g., withValues() instead of deprecated withOpacity())

Files:

  • lib/shared/widgets/order_cards.dart
  • lib/features/order/screens/take_order_screen.dart
  • lib/data/repositories/dispute_repository.dart
  • lib/features/chat/widgets/trade_information_tab.dart
  • lib/features/disputes/screens/dispute_chat_screen.dart
  • lib/features/disputes/widgets/dispute_order_id.dart
  • lib/data/models/dispute_event.dart
  • lib/features/disputes/widgets/dispute_description.dart
  • lib/features/disputes/widgets/dispute_status_badge.dart
  • lib/services/dispute_service.dart
  • lib/features/disputes/widgets/dispute_message_bubble.dart
  • lib/features/disputes/widgets/dispute_header.dart
  • lib/features/disputes/widgets/dispute_list_item.dart
  • lib/features/disputes/widgets/dispute_status_content.dart
  • lib/features/disputes/notifiers/dispute_chat_notifier.dart
  • lib/core/app_routes.dart
  • lib/features/disputes/widgets/dispute_info_card.dart
  • lib/features/disputes/widgets/dispute_message_input.dart
  • lib/features/disputes/widgets/dispute_icon.dart
  • lib/data/models/dispute_chat.dart
  • lib/features/disputes/widgets/disputes_list.dart
  • lib/features/disputes/widgets/dispute_messages_list.dart
  • lib/features/disputes/widgets/dispute_input_section.dart
  • lib/features/disputes/widgets/dispute_content.dart
  • lib/features/disputes/providers/dispute_providers.dart
  • lib/features/disputes/widgets/dispute_communication_section.dart
  • lib/features/disputes/data/dispute_mock_data.dart
  • lib/features/chat/screens/chat_rooms_list.dart
  • lib/data/models/dispute.dart
{lib/*.dart,lib/!(generated)/**/*.dart,test/**/*.dart}

📄 CodeRabbit inference engine (CLAUDE.md)

{lib/*.dart,lib/!(generated)/**/*.dart,test/**/*.dart}: Check mounted before using BuildContext after await (async gaps)
Remove unused imports and dependencies

Files:

  • lib/shared/widgets/order_cards.dart
  • lib/features/order/screens/take_order_screen.dart
  • lib/data/repositories/dispute_repository.dart
  • lib/features/chat/widgets/trade_information_tab.dart
  • lib/features/disputes/screens/dispute_chat_screen.dart
  • lib/features/disputes/widgets/dispute_order_id.dart
  • lib/data/models/dispute_event.dart
  • lib/features/disputes/widgets/dispute_description.dart
  • lib/features/disputes/widgets/dispute_status_badge.dart
  • lib/services/dispute_service.dart
  • lib/features/disputes/widgets/dispute_message_bubble.dart
  • lib/features/disputes/widgets/dispute_header.dart
  • lib/features/disputes/widgets/dispute_list_item.dart
  • lib/features/disputes/widgets/dispute_status_content.dart
  • lib/features/disputes/notifiers/dispute_chat_notifier.dart
  • lib/core/app_routes.dart
  • lib/features/disputes/widgets/dispute_info_card.dart
  • lib/features/disputes/widgets/dispute_message_input.dart
  • lib/features/disputes/widgets/dispute_icon.dart
  • lib/data/models/dispute_chat.dart
  • lib/features/disputes/widgets/disputes_list.dart
  • lib/features/disputes/widgets/dispute_messages_list.dart
  • lib/features/disputes/widgets/dispute_input_section.dart
  • lib/features/disputes/widgets/dispute_content.dart
  • lib/features/disputes/providers/dispute_providers.dart
  • lib/features/disputes/widgets/dispute_communication_section.dart
  • lib/features/disputes/data/dispute_mock_data.dart
  • lib/features/chat/screens/chat_rooms_list.dart
  • lib/data/models/dispute.dart
**/*.dart

📄 CodeRabbit inference engine (CLAUDE.md)

All code comments, variable names, and function names must be in English

Files:

  • lib/shared/widgets/order_cards.dart
  • lib/features/order/screens/take_order_screen.dart
  • lib/data/repositories/dispute_repository.dart
  • lib/features/chat/widgets/trade_information_tab.dart
  • lib/features/disputes/screens/dispute_chat_screen.dart
  • lib/features/disputes/widgets/dispute_order_id.dart
  • lib/data/models/dispute_event.dart
  • lib/features/disputes/widgets/dispute_description.dart
  • lib/features/disputes/widgets/dispute_status_badge.dart
  • lib/services/dispute_service.dart
  • lib/features/disputes/widgets/dispute_message_bubble.dart
  • lib/features/disputes/widgets/dispute_header.dart
  • lib/features/disputes/widgets/dispute_list_item.dart
  • lib/features/disputes/widgets/dispute_status_content.dart
  • lib/features/disputes/notifiers/dispute_chat_notifier.dart
  • lib/core/app_routes.dart
  • lib/features/disputes/widgets/dispute_info_card.dart
  • lib/features/disputes/widgets/dispute_message_input.dart
  • lib/features/disputes/widgets/dispute_icon.dart
  • lib/data/models/dispute_chat.dart
  • lib/features/disputes/widgets/disputes_list.dart
  • lib/features/disputes/widgets/dispute_messages_list.dart
  • lib/features/disputes/widgets/dispute_input_section.dart
  • lib/features/disputes/widgets/dispute_content.dart
  • lib/features/disputes/providers/dispute_providers.dart
  • lib/features/disputes/widgets/dispute_communication_section.dart
  • lib/features/disputes/data/dispute_mock_data.dart
  • lib/features/chat/screens/chat_rooms_list.dart
  • lib/data/models/dispute.dart
lib/l10n/intl_{en,es,it}.arb

📄 CodeRabbit inference engine (CLAUDE.md)

Add new localization keys to all three ARB files (en, es, it)

Files:

  • lib/l10n/intl_it.arb
  • lib/l10n/intl_en.arb
  • lib/l10n/intl_es.arb
🧠 Learnings (5)
📚 Learning: 2025-08-28T20:32:34.592Z
Learnt from: CR
PR: MostroP2P/mobile#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-28T20:32:34.592Z
Learning: Applies to {lib/*.dart,lib/!(generated)/**/*.dart} : Use localized strings; replace hardcoded user-facing text with `S.of(context).keyName`

Applied to files:

  • lib/features/chat/widgets/trade_information_tab.dart
📚 Learning: 2025-08-28T20:32:34.592Z
Learnt from: CR
PR: MostroP2P/mobile#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-28T20:32:34.592Z
Learning: Use Riverpod for state management with Notifiers encapsulating business logic; access data only through repositories

Applied to files:

  • lib/features/disputes/notifiers/dispute_chat_notifier.dart
📚 Learning: 2025-08-28T20:32:34.592Z
Learnt from: CR
PR: MostroP2P/mobile#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-28T20:32:34.592Z
Learning: Applies to lib/l10n/intl_{en,es,it}.arb : Add new localization keys to all three ARB files (en, es, it)

Applied to files:

  • lib/l10n/intl_it.arb
  • lib/l10n/intl_en.arb
📚 Learning: 2025-08-28T20:32:34.592Z
Learnt from: CR
PR: MostroP2P/mobile#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-28T20:32:34.592Z
Learning: Applies to test/mocks.mocks.dart : Do not manually modify `test/mocks.mocks.dart` (auto-generated by Mockito)

Applied to files:

  • lib/features/disputes/data/dispute_mock_data.dart
📚 Learning: 2025-08-28T20:32:34.592Z
Learnt from: CR
PR: MostroP2P/mobile#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-28T20:32:34.592Z
Learning: Applies to **/*.mocks.dart : Never manually edit Mockito-generated `*.mocks.dart` files

Applied to files:

  • lib/features/disputes/data/dispute_mock_data.dart
🪛 RuboCop (1.76.1)
lib/l10n/intl_it.arb

[warning] 760-760: Duplicated key in hash literal.

(Lint/DuplicateHashKey)


[warning] 965-965: Duplicated key in hash literal.

(Lint/DuplicateHashKey)


[warning] 976-976: Duplicated key in hash literal.

(Lint/DuplicateHashKey)

lib/l10n/intl_en.arb

[warning] 862-862: Duplicated key in hash literal.

(Lint/DuplicateHashKey)


[warning] 873-873: Duplicated key in hash literal.

(Lint/DuplicateHashKey)

lib/l10n/intl_es.arb

[warning] 931-931: Duplicated key in hash literal.

(Lint/DuplicateHashKey)


[warning] 942-942: Duplicated key in hash literal.

(Lint/DuplicateHashKey)

⏰ 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: build
🔇 Additional comments (11)
lib/features/chat/widgets/trade_information_tab.dart (1)

134-140: Null-safety check for currency code.

If order!.fiatCode can be null/empty, forAmountWithCurrency will throw or produce odd UI. Consider a safe fallback (e.g., use order!.fiatCode ?? '' or hide the currency text until loaded).

Apply this diff if appropriate:

-                Text(
-                  S.of(context)!.forAmountWithCurrency(order!.fiatAmount.toString(), order!.fiatCode),
+                Text(
+                  S.of(context)!.forAmountWithCurrency(
+                    order!.fiatAmount.toString(),
+                    order!.fiatCode ?? '',
+                  ),
lib/core/app_routes.dart (1)

147-157: Route addition LGTM.

New /dispute_details/:disputeId integrates cleanly with existing transition wrapper and ShellRoute.

lib/features/chat/screens/chat_rooms_list.dart (3)

60-63: Good use of Color.withValues for alpha

Using withValues over deprecated withOpacity aligns with newer Flutter APIs. LGTM.

Also applies to: 88-91


111-111: Nice: real Disputes tab wired in

Replacing the placeholder with const DisputesList() completes the UX flow.


157-167: Use non-nullable localized strings for tab descriptions
Replace the ?.… ?? '…' pattern with S.of(context).conversationsDescription and S.of(context).disputesDescription; both keys exist in every intl_*.arb file.

lib/features/disputes/widgets/dispute_content.dart (1)

15-23: LGTM: clean composition and spacing

Good use of small, focused widgets and const SizedBox spacers. No i18n concerns here.

lib/features/disputes/widgets/dispute_list_item.dart (1)

24-26: Good: uses withValues instead of deprecated withOpacity

Alignment with latest Flutter API is correct.

lib/features/disputes/screens/dispute_chat_screen.dart (1)

1-13: Ignore duplicate input widget suggestion
Only DisputeMessageInput is implemented; DisputeInputSection does not exist. No action required.

Likely an incorrect or invalid review comment.

lib/features/disputes/widgets/dispute_input_section.dart (1)

65-76: Good: withValues usage and SafeArea

API usage and layout considerations are solid.

lib/features/disputes/providers/dispute_providers.dart (1)

31-43: Verify action mapping against product copy.

Ensure these action keys match localization and UX expectations for buyer/seller roles; otherwise add a dedicated enum or constants to avoid typos.

lib/l10n/intl_it.arb (1)

712-740: No missing dispute keys in EN/ES ARBs. Verified that all keys added in intl_it.arb appear in intl_en.arb and intl_es.arb.

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: 6

♻️ Duplicate comments (4)
lib/l10n/intl_en.arb (2)

862-862: Remove duplicate key: "retry" (already defined at Line 215).

-  "retry": "Retry",

873-873: Remove duplicate key: "orderIdLabel" (already defined at Line 259).

-  "orderIdLabel": "Order ID",
lib/l10n/intl_es.arb (2)

1023-1023: Remove duplicate key: "retry" (already defined at Line 206).

-  "retry": "Reintentar",

1034-1034: Remove duplicate key: "orderIdLabel" (already defined at Line 600).

-  "orderIdLabel": "ID de Orden",
🧹 Nitpick comments (5)
lib/l10n/intl_it.arb (1)

1029-1043: Small terminology consistency (optional): use “Disputa” instead of “Controversia”.

Multiple entries in this block use “Controversia” while the rest of the file uses “Disputa”. Align for consistency.

lib/features/disputes/data/dispute_mock_data.dart (3)

13-39: Stabilize timestamps to make UI/tests deterministic.

DateTime.now() is evaluated on each access to mockDisputes, causing drifting times. Cache a single “now”.

 class DisputeMockData {
-  
+  static final DateTime _now = DateTime.now();
@@
-      createdAt: DateTime.now().subtract(const Duration(minutes: 30)),
+      createdAt: _now.subtract(const Duration(minutes: 30)),
@@
-      createdAt: DateTime.now().subtract(const Duration(hours: 6)),
+      createdAt: _now.subtract(const Duration(hours: 6)),
@@
-      createdAt: DateTime.now().subtract(const Duration(days: 2)),
+      createdAt: _now.subtract(const Duration(days: 2)),

60-61: Treat “closed” like “resolved” for mock chats.

UI mentions “closed”; include it here to keep behavior consistent.

-    if (status == 'resolved') {
+    if (status == 'resolved' || status == 'closed') {

54-58: Consider using a typed status (enum/union) for mocks.

Free-form strings make it easy to mistype and drift from UI logic. Optional.

lib/data/models/dispute.dart (1)

124-144: Optional: accept string/double for createdAt in Nostr events.

Robustness improvement; mirror handling you added in fromJson.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 601104d and af03335.

📒 Files selected for processing (9)
  • lib/core/app_routes.dart (2 hunks)
  • lib/data/models/dispute.dart (2 hunks)
  • lib/data/models/dispute_chat.dart (1 hunks)
  • lib/data/models/dispute_event.dart (1 hunks)
  • lib/features/disputes/data/dispute_mock_data.dart (1 hunks)
  • lib/features/disputes/widgets/disputes_list.dart (1 hunks)
  • lib/l10n/intl_en.arb (3 hunks)
  • lib/l10n/intl_es.arb (3 hunks)
  • lib/l10n/intl_it.arb (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • lib/core/app_routes.dart
  • lib/features/disputes/widgets/disputes_list.dart
  • lib/data/models/dispute_chat.dart
  • lib/data/models/dispute_event.dart
🧰 Additional context used
📓 Path-based instructions (4)
{lib/*.dart,lib/!(generated)/**/*.dart}

📄 CodeRabbit inference engine (CLAUDE.md)

{lib/*.dart,lib/!(generated)/**/*.dart}: Use localized strings; replace hardcoded user-facing text with S.of(context).keyName
Prefer const constructors and const where possible
Use latest Flutter/Dart APIs (e.g., withValues() instead of deprecated withOpacity())

Files:

  • lib/data/models/dispute.dart
  • lib/features/disputes/data/dispute_mock_data.dart
{lib/*.dart,lib/!(generated)/**/*.dart,test/**/*.dart}

📄 CodeRabbit inference engine (CLAUDE.md)

{lib/*.dart,lib/!(generated)/**/*.dart,test/**/*.dart}: Check mounted before using BuildContext after await (async gaps)
Remove unused imports and dependencies

Files:

  • lib/data/models/dispute.dart
  • lib/features/disputes/data/dispute_mock_data.dart
**/*.dart

📄 CodeRabbit inference engine (CLAUDE.md)

All code comments, variable names, and function names must be in English

Files:

  • lib/data/models/dispute.dart
  • lib/features/disputes/data/dispute_mock_data.dart
lib/l10n/intl_{en,es,it}.arb

📄 CodeRabbit inference engine (CLAUDE.md)

Add new localization keys to all three ARB files (en, es, it)

Files:

  • lib/l10n/intl_it.arb
  • lib/l10n/intl_es.arb
  • lib/l10n/intl_en.arb
🧠 Learnings (3)
📚 Learning: 2025-08-28T20:32:34.625Z
Learnt from: CR
PR: MostroP2P/mobile#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-28T20:32:34.625Z
Learning: Applies to lib/l10n/intl_{en,es,it}.arb : Add new localization keys to all three ARB files (en, es, it)

Applied to files:

  • lib/l10n/intl_it.arb
📚 Learning: 2025-08-28T20:32:34.625Z
Learnt from: CR
PR: MostroP2P/mobile#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-28T20:32:34.625Z
Learning: Applies to test/mocks.mocks.dart : Do not manually modify `test/mocks.mocks.dart` (auto-generated by Mockito)

Applied to files:

  • lib/features/disputes/data/dispute_mock_data.dart
📚 Learning: 2025-08-28T20:32:34.625Z
Learnt from: CR
PR: MostroP2P/mobile#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-28T20:32:34.625Z
Learning: Applies to **/*.mocks.dart : Never manually edit Mockito-generated `*.mocks.dart` files

Applied to files:

  • lib/features/disputes/data/dispute_mock_data.dart
🪛 RuboCop (1.76.1)
lib/l10n/intl_it.arb

[warning] 760-760: Duplicated key in hash literal.

(Lint/DuplicateHashKey)


[warning] 1057-1057: Duplicated key in hash literal.

(Lint/DuplicateHashKey)


[warning] 1068-1068: Duplicated key in hash literal.

(Lint/DuplicateHashKey)

lib/l10n/intl_es.arb

[warning] 1023-1023: Duplicated key in hash literal.

(Lint/DuplicateHashKey)


[warning] 1034-1034: Duplicated key in hash literal.

(Lint/DuplicateHashKey)

lib/l10n/intl_en.arb

[warning] 862-862: Duplicated key in hash literal.

(Lint/DuplicateHashKey)


[warning] 873-873: Duplicated key in hash literal.

(Lint/DuplicateHashKey)

🔇 Additional comments (2)
lib/l10n/intl_en.arb (1)

703-713: LGTM on the new forAmountWithCurrency placeholders.

Placeholders look correct and consistent across locales.

lib/l10n/intl_it.arb (1)

762-772: LGTM on forAmountWithCurrency addition.

Placeholders align with EN; good parity.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

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

⚠️ Outside diff range comments (1)
lib/l10n/intl_it.arb (1)

620-628: Unify placeholder types for forAmount.amount across locales: add "type": "Object" (or "String" if you’re passing formatted strings) to the amount placeholder under @forAmount in intl_en.arb and intl_es.arb so they match intl_it.arb and avoid gen-l10n signature mismatches.

♻️ Duplicate comments (3)
lib/l10n/intl_it.arb (3)

714-721: Add missing dispute status strings to match EN (if present)

If EN defines these keys, add their IT counterparts to avoid fallback-to-English.

Proposed additions (only if they exist in EN/ES):

   "disputeResolvedTitle": "Disputa risolta",
   "disputeResolvedMessage": "Questa disputa è stata risolta. Il risolutore ha preso una decisione sulla base delle prove presentate. Controlla il tuo wallet per eventuali rimborsi o pagamenti.",
+  "disputeInProgress": "Questa disputa è attualmente in corso. Un risolutore sta esaminando il tuo caso.",
+  "disputeSellerRefunded": "Questa disputa è stata risolta con rimborso al venditore.",
+  "disputeUnknownStatus": "Lo stato di questa disputa è sconosciuto.",

1053-1056: Duplicate key “retry” (already defined at Line 215) — remove

Duplicated JSON key breaks ARB/gen-l10n. Keep the earlier definition.

   "disputesWillAppear": "Le dispute appariranno qui quando le apri dai tuoi scambi",
   "failedLoadDisputes": "Impossibile caricare le dispute",
-  "retry": "Riprova",

1066-1066: Duplicate key “orderIdLabel” (already defined at Line 641) — remove

Avoid ARB duplication errors.

-  "orderIdLabel": "ID Ordine",
🧹 Nitpick comments (2)
lib/l10n/intl_it.arb (2)

1030-1031: Terminology consistency: use “disputa” instead of “controversia”

Earlier strings use “disputa”; align new ones for a consistent UX.

-  "waitingAdminDescription": "La tua controversia è stata inviata. Un amministratore verrà assegnato per aiutare a risolvere questo problema.",
+  "waitingAdminDescription": "La tua disputa è stata inviata. Un amministratore verrà assegnato per aiutare a risolvere questo problema.",
-  "adminAssignmentDescription": "Un amministratore verrà assegnato alla tua controversia a breve. Una volta assegnato, potrai comunicare direttamente con lui qui.",
+  "adminAssignmentDescription": "Un amministratore verrà assegnato alla tua disputa a breve. Una volta assegnato, potrai comunicare direttamente con lui qui.",
-  "disputesWillAppear": "Le controversie appariranno qui quando le apri dai tuoi scambi",
+  "disputesWillAppear": "Le dispute appariranno qui quando le apri dai tuoi scambi",
-  "failedLoadDisputes": "Impossibile caricare le controversie",
+  "failedLoadDisputes": "Impossibile caricare le dispute",
-  "disputeWith": "Controversia con {role}: {counterparty}",
+  "disputeWith": "Disputa con {role}: {counterparty}",
-  "disputeIdLabel": "ID Controversia",
+  "disputeIdLabel": "ID Disputa",
-  "disputeNotFound": "Controversia non trovata",
+  "disputeNotFound": "Disputa non trovata",
-  "errorLoadingDispute": "Errore nel caricamento della controversia: {error}",
+  "errorLoadingDispute": "Errore nel caricamento della disputa: {error}",

Also applies to: 1053-1054, 1059-1069, 1072-1074


1037-1037: Prefer “Chiave pubblica” over “Pubkey” in Italian

Matches earlier usage (e.g., “Chiave Pubblica Mostro”).

-  "adminPubkey": "Pubkey dell'amministratore",
+  "adminPubkey": "Chiave pubblica dell'amministratore",
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between af03335 and e1d8b1c.

⛔ Files ignored due to path filters (1)
  • pubspec.lock is excluded by !**/*.lock
📒 Files selected for processing (1)
  • lib/l10n/intl_it.arb (4 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
lib/l10n/intl_{en,es,it}.arb

📄 CodeRabbit inference engine (CLAUDE.md)

Add new localization keys to all three ARB files (en, es, it)

Files:

  • lib/l10n/intl_it.arb
🪛 RuboCop (1.76.1)
lib/l10n/intl_it.arb

[warning] 1055-1055: Duplicated key in hash literal.

(Lint/DuplicateHashKey)


[warning] 1066-1066: Duplicated key in hash literal.

(Lint/DuplicateHashKey)

⏰ 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: build
🔇 Additional comments (3)
lib/l10n/intl_it.arb (3)

711-740: Dispute lifecycle strings and metadata — LGTM

Good coverage of statuses, instructions, and placeholders.


760-770: New key forAmountWithCurrency — LGTM

Clear separation from forAmount; placeholders look good.


711-740: Verified EN/ES parity for all new dispute keys and forAmountWithCurrency—no missing keys.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

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

⚠️ Outside diff range comments (1)
lib/l10n/intl_it.arb (1)

620-628: Align placeholder metadata for forAmount.amount across locales
In lib/l10n/intl_it.arb the @forAmount.placeholders.amount.type is set to Object, while both intl_en.arb and intl_es.arb omit the type property. Add or remove the "type" entry so all three ARB files declare the same placeholder metadata to prevent gen-l10n inconsistencies.

♻️ Duplicate comments (2)
lib/l10n/intl_es.arb (2)

1037-1041: Fix duplicate key: "orderIdLabel" defined twice.

Earlier at Line 600; remove this one.

Apply:

-  "orderIdLabel": "ID de Orden",
   "disputeIdLabel": "ID de Disputa",
   "seller": "Vendedor",
   "buyer": "Comprador",

1023-1027: Fix duplicate key: "retry" defined twice (breaks ARB/JSON).

Remove this second occurrence.

Apply:

-  "disputesWillAppear": "Las disputas aparecerán aquí cuando las abras desde tus intercambios",
-  "failedLoadDisputes": "Error al cargar disputas",
-  "retry": "Reintentar",
+  "disputesWillAppear": "Las disputas aparecerán aquí cuando las abras desde tus intercambios",
+  "failedLoadDisputes": "Error al cargar disputas",
🧹 Nitpick comments (2)
lib/l10n/intl_it.arb (1)

711-743: Unify Italian terminology: prefer “disputa” over “controversia”.

Minor copy consistency across new dispute strings.

Apply:

-  "@_comment_dispute_communication": "Testo Comunicazione Controversie",
+  "@_comment_dispute_communication": "Testo Comunicazione Dispute",
-  "waitingAdminDescription": "La tua controversia è stata inviata. Un amministratore verrà assegnato per aiutare a risolvere questo problema.",
+  "waitingAdminDescription": "La tua disputa è stata inviata. Un amministratore verrà assegnato per aiutare a risolvere questo problema.",
-  "adminAssignmentDescription": "Un amministratore verrà assegnato alla tua controversia a breve. Una volta assegnato, potrai comunicare direttamente con lui qui.",
+  "adminAssignmentDescription": "Un amministratore verrà assegnato alla tua disputa a breve. Una volta assegnato, potrai comunicare direttamente con lui qui.",
-  "disputesWillAppear": "Le controversie appariranno qui quando le apri dai tuoi scambi",
+  "disputesWillAppear": "Le dispute appariranno qui quando le apri dai tuoi scambi",
-  "disputeWith": "Controversia con {role}: {counterparty}",
+  "disputeWith": "Disputa con {role}: {counterparty}",
-  "disputeIdLabel": "ID Controversia",
+  "disputeIdLabel": "ID Disputa",
-  "@_comment_dispute_screen": "Testo Schermata Controversie",
+  "@_comment_dispute_screen": "Testo Schermata Dispute",
-  "disputeNotFound": "Controversia non trovata",
+  "disputaNotFound": "Disputa non trovata",
-  "errorLoadingDispute": "Errore nel caricamento della controversia: {error}",
+  "errorLoadingDispute": "Errore nel caricamento della disputa: {error}",

Note: Keep the key name "disputeNotFound"; only change its value.

Also applies to: 1056-1079

lib/l10n/intl_es.arb (1)

688-693: Standardize role term: use “administrador” (matches other keys).

Replace “mediador” to keep consistency with “admin/administrador”.

Apply:

-  "disputeResolvedMessage": "Esta disputa ha sido resuelta. El mediador tomó una decisión basada en la evidencia presentada. Revisa tu billetera para ver reembolsos o pagos.",
+  "disputeResolvedMessage": "Esta disputa ha sido resuelta. El administrador tomó una decisión basada en la evidencia presentada. Revisa tu billetera para ver reembolsos o pagos.",
-  "disputeInProgress": "Esta disputa está actualmente en progreso. Un mediador está revisando tu caso.",
+  "disputeInProgress": "Esta disputa está actualmente en progreso. Un administrador está revisando tu caso.",
-  "disputeSellerRefunded": "Esta disputa ha sido resuelta con el vendedor siendo reembolsado.",
+  "disputeSellerRefunded": "Esta disputa se resolvió con reembolso al vendedor.",
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between e1d8b1c and 6d6970f.

📒 Files selected for processing (3)
  • lib/data/models/dispute.dart (2 hunks)
  • lib/l10n/intl_es.arb (3 hunks)
  • lib/l10n/intl_it.arb (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/data/models/dispute.dart
🧰 Additional context used
📓 Path-based instructions (1)
lib/l10n/intl_{en,es,it}.arb

📄 CodeRabbit inference engine (CLAUDE.md)

Add new localization keys to all three ARB files (en, es, it)

Files:

  • lib/l10n/intl_es.arb
  • lib/l10n/intl_it.arb
🧠 Learnings (1)
📚 Learning: 2025-08-28T20:32:34.625Z
Learnt from: CR
PR: MostroP2P/mobile#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-28T20:32:34.625Z
Learning: Applies to lib/l10n/intl_{en,es,it}.arb : Add new localization keys to all three ARB files (en, es, it)

Applied to files:

  • lib/l10n/intl_it.arb
🪛 RuboCop (1.76.1)
lib/l10n/intl_es.arb

[warning] 1026-1026: Duplicated key in hash literal.

(Lint/DuplicateHashKey)


[warning] 1037-1037: Duplicated key in hash literal.

(Lint/DuplicateHashKey)

⏰ 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: build
🔇 Additional comments (5)
lib/l10n/intl_it.arb (3)

763-773: LGTM: Added forAmountWithCurrency.

Key and placeholders look consistent with usage.


1030-1054: LGTM: Dispute communication cluster.

Clear labels and statuses; placeholders are correct.


1056-1058: LGTM: Dispute list texts.

No duplicate “retry” here; good.

lib/l10n/intl_es.arb (2)

733-743: LGTM: Added forAmountWithCurrency.

Key and placeholders are correct.


681-713: Localization parity verified All dispute-related keys, including disputesDescription through disputeInstruction4 and forAmountWithCurrency, are present in intl_en.arb, intl_es.arb, and intl_it.arb.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (6)
lib/features/chat/widgets/chat_tabs.dart (4)

7-13: Avoid prop drilling: read current tab from the provider inside ChatTabs

Since this is already a ConsumerWidget, watch the provider internally and drop the currentTab prop.

Apply this diff:

-class ChatTabs extends ConsumerWidget {
-  final ChatTabType currentTab;
+class ChatTabs extends ConsumerWidget {
 
   const ChatTabs({
     super.key,
-    required this.currentTab,
   });
 
   @override
-  Widget build(BuildContext context, WidgetRef ref) {
+  Widget build(BuildContext context, WidgetRef ref) {
+    final currentTab = ref.watch(chatTabProvider);

And update the call site (see chat_rooms_list.dart suggestion).


29-31: Avoid null-bang on localized strings

Prefer safe access with fallbacks to prevent crashes if localization isn’t initialized.

Apply this diff:

-          _buildTabButton(context, ref, ChatTabType.messages, S.of(context)!.messages, currentTab == ChatTabType.messages),
-          _buildTabButton(context, ref, ChatTabType.disputes, S.of(context)!.disputes, currentTab == ChatTabType.disputes),
+          _buildTabButton(
+            context,
+            ref,
+            ChatTabType.messages,
+            S.of(context)?.messages ?? 'Messages',
+            currentTab == ChatTabType.messages,
+          ),
+          _buildTabButton(
+            context,
+            ref,
+            ChatTabType.disputes,
+            S.of(context)?.disputes ?? 'Disputes',
+            currentTab == ChatTabType.disputes,
+          ),

36-66: Ink ripple won’t render without a Material ancestor

Wrap InkWell in a transparent Material so ripple/focus highlights display correctly.

Apply this diff:

-    return Expanded(
-      child: InkWell(
+    return Expanded(
+      child: Material(
+        color: Colors.transparent,
+        child: InkWell(
           onTap: () {
             ref.read(chatTabProvider.notifier).state = tabType;
           },
           child: Container(
             padding: const EdgeInsets.symmetric(vertical: 16),
             decoration: BoxDecoration(
               border: Border(
                 bottom: BorderSide(
                   color: isActive ? AppTheme.mostroGreen : Colors.transparent,
                   width: 3.0,
                 ),
               ),
             ),
             child: Text(
               text,
               textAlign: TextAlign.center,
               style: TextStyle(
                 color: isActive ? AppTheme.mostroGreen : AppTheme.textInactive,
                 fontWeight: FontWeight.w600,
                 fontSize: 15,
                 letterSpacing: 0.5,
               ),
             ),
           ),
-        ),
+        ),
+      ),
     );

41-41: Minor: use update for clarity

Using update conveys intent and keeps old/new state transitions uniform.

Apply this diff:

-          ref.read(chatTabProvider.notifier).state = tabType;
+          ref.read(chatTabProvider.notifier).update((_) => tabType);
lib/features/chat/screens/chat_rooms_list.dart (2)

80-91: Reduce accidental tab switches on subtle swipes

Use a velocity threshold so short drags don’t flip tabs unintentionally.

Apply this diff:

-                    onHorizontalDragEnd: (details) {
-                      if (details.primaryVelocity != null &&
-                          details.primaryVelocity! < 0) {
+                    onHorizontalDragEnd: (details) {
+                      const kThreshold = 300; // px/s
+                      final v = details.primaryVelocity ?? 0;
+                      if (v < -kThreshold) {
                         // Swipe left - go to disputes
-                        ref.read(chatTabProvider.notifier).state = ChatTabType.disputes;
-                      } else if (details.primaryVelocity != null &&
-                          details.primaryVelocity! > 0) {
+                        ref.read(chatTabProvider.notifier).state = ChatTabType.disputes;
+                      } else if (v > kThreshold) {
                         // Swipe right - go to messages
                         ref.read(chatTabProvider.notifier).state = ChatTabType.messages;
                       }
                     },

101-103: Bottom padding: avoid hardcoding 80

Tie the spacer to the BottomNavBar’s actual height or reuse a shared constant to prevent layout drift if the bar changes.

Example:

-                SizedBox(
-                    height: 80 + MediaQuery.of(context).viewPadding.bottom),
+                SizedBox(
+                  height: BottomNavBar.height +
+                      MediaQuery.of(context).viewPadding.bottom,
+                ),

If BottomNavBar.height isn’t exposed, consider adding a static const there or using SafeArea around scroll content instead of manual padding.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 6d6970f and f718272.

📒 Files selected for processing (5)
  • lib/features/chat/providers/chat_tab_provider.dart (1 hunks)
  • lib/features/chat/screens/chat_rooms_list.dart (5 hunks)
  • lib/features/chat/widgets/chat_tabs.dart (2 hunks)
  • lib/features/disputes/data/dispute_mock_data.dart (1 hunks)
  • lib/features/disputes/widgets/disputes_list.dart (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • lib/features/disputes/widgets/disputes_list.dart
  • lib/features/disputes/data/dispute_mock_data.dart
🧰 Additional context used
📓 Path-based instructions (3)
{lib/*.dart,lib/!(generated)/**/*.dart}

📄 CodeRabbit inference engine (CLAUDE.md)

{lib/*.dart,lib/!(generated)/**/*.dart}: Use localized strings; replace hardcoded user-facing text with S.of(context).keyName
Prefer const constructors and const where possible
Use latest Flutter/Dart APIs (e.g., withValues() instead of deprecated withOpacity())

Files:

  • lib/features/chat/providers/chat_tab_provider.dart
  • lib/features/chat/widgets/chat_tabs.dart
  • lib/features/chat/screens/chat_rooms_list.dart
{lib/*.dart,lib/!(generated)/**/*.dart,test/**/*.dart}

📄 CodeRabbit inference engine (CLAUDE.md)

{lib/*.dart,lib/!(generated)/**/*.dart,test/**/*.dart}: Check mounted before using BuildContext after await (async gaps)
Remove unused imports and dependencies

Files:

  • lib/features/chat/providers/chat_tab_provider.dart
  • lib/features/chat/widgets/chat_tabs.dart
  • lib/features/chat/screens/chat_rooms_list.dart
**/*.dart

📄 CodeRabbit inference engine (CLAUDE.md)

All code comments, variable names, and function names must be in English

Files:

  • lib/features/chat/providers/chat_tab_provider.dart
  • lib/features/chat/widgets/chat_tabs.dart
  • lib/features/chat/screens/chat_rooms_list.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: build
🔇 Additional comments (3)
lib/features/chat/providers/chat_tab_provider.dart (1)

3-3: Enum addition looks good

Clear, descriptive tab types.

lib/features/chat/screens/chat_rooms_list.dart (2)

42-45: Borders with withValues API — nice modernization

Good use of withValues over deprecated withOpacity and consistent divider styling.

Also applies to: 65-68


23-26: Strong typing currentTab (will be inferred once provider is typed)

After typing chatTabProvider as StateProvider, currentTab will infer correctly. No action here once that change lands.

Please confirm after applying the provider typing that this line infers ChatTabType without casts:

final currentTab = ref.watch(chatTabProvider);

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
lib/features/chat/screens/chat_rooms_list.dart (1)

116-116: Empty-state source-of-truth fix applied—thank you.
Now both the check and the list use sortedChatRoomsProvider.

🧹 Nitpick comments (3)
lib/features/chat/screens/chat_rooms_list.dart (3)

76-95: Prevent accidental tab switches; add a velocity threshold.
Small horizontal drags may flip tabs. Gate on a minimum velocity.

Apply:

-                    onHorizontalDragEnd: (details) {
-                      if (details.primaryVelocity != null &&
-                          details.primaryVelocity! < 0) {
+                    onHorizontalDragEnd: (details) {
+                      final v = details.primaryVelocity ?? 0;
+                      const minV = 400; // px/s
+                      if (v < -minV) {
                         // Swipe left - go to disputes
                         ref.read(chatTabProvider.notifier).state = ChatTabType.disputes;
-                      } else if (details.primaryVelocity != null &&
-                          details.primaryVelocity! > 0) {
+                      } else if (v > minV) {
                         // Swipe right - go to messages
                         ref.read(chatTabProvider.notifier).state = ChatTabType.messages;
                       }
                     },

121-125: Avoid hardcoded fallback text; rely on i18n keys.
Per guidelines, prefer localized strings only (ensure keys exist).

-      return EmptyStateView(
-        message: S.of(context)?.noMessagesAvailable ?? 'No messages available',
-      );
+      return EmptyStateView(
+        message: S.of(context).noMessagesAvailable,
+      );

139-149: Remove fallback prose; use strict i18n.
Keep user-facing text in ARB files only.

-  String _getTabDescription(BuildContext context, ChatTabType currentTab) {
-    if (currentTab == ChatTabType.messages) {
-      // Messages tab
-      return S.of(context)?.conversationsDescription ??
-          'Here you\'ll find your conversations with other users during trades.';
-    } else {
-      // Disputes tab
-      return S.of(context)?.disputesDescription ??
-          'These are your open disputes and the chats with the admin helping resolve them.';
-    }
-  }
+  String _getTabDescription(BuildContext context, ChatTabType currentTab) {
+    return currentTab == ChatTabType.messages
+        ? S.of(context).conversationsDescription
+        : S.of(context).disputesDescription;
+  }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f718272 and 6fe1a94.

📒 Files selected for processing (2)
  • lib/features/chat/providers/chat_tab_provider.dart (1 hunks)
  • lib/features/chat/screens/chat_rooms_list.dart (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/features/chat/providers/chat_tab_provider.dart
🧰 Additional context used
📓 Path-based instructions (3)
{lib/*.dart,lib/!(generated)/**/*.dart}

📄 CodeRabbit inference engine (CLAUDE.md)

{lib/*.dart,lib/!(generated)/**/*.dart}: Use localized strings; replace hardcoded user-facing text with S.of(context).keyName
Prefer const constructors and const where possible
Use latest Flutter/Dart APIs (e.g., withValues() instead of deprecated withOpacity())

Files:

  • lib/features/chat/screens/chat_rooms_list.dart
{lib/*.dart,lib/!(generated)/**/*.dart,test/**/*.dart}

📄 CodeRabbit inference engine (CLAUDE.md)

{lib/*.dart,lib/!(generated)/**/*.dart,test/**/*.dart}: Check mounted before using BuildContext after await (async gaps)
Remove unused imports and dependencies

Files:

  • lib/features/chat/screens/chat_rooms_list.dart
**/*.dart

📄 CodeRabbit inference engine (CLAUDE.md)

All code comments, variable names, and function names must be in English

Files:

  • lib/features/chat/screens/chat_rooms_list.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: build
🔇 Additional comments (7)
lib/features/chat/screens/chat_rooms_list.dart (7)

10-11: Imports look correct for the new Disputes tab and tab state provider.
No unused-imports; aligns with the new UI.


18-18: Good refactor to ConsumerWidget.
Simplifies lifecycle; no TabController cleanup needed.


40-42: Nice: uses withValues() instead of deprecated withOpacity().
Consistent with guidelines.


55-55: Ensure tab taps update state, not just swipes.
Confirm ChatTabs writes to chatTabProvider on tap; otherwise only the swipe handler will switch tabs.


63-65: Border styling LGTM.
Consistent divider styling with withValues().


69-69: Dynamic description hook looks good.
Wires tab state to description text cleanly.


22-24: chatTabProvider confirmed as StateProvider; .state = … assignment is valid.

Copy link
Member

@grunch grunch left a comment

Choose a reason for hiding this comment

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

tACK

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

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

⚠️ Outside diff range comments (2)
lib/l10n/intl_es.arb (1)

714-717: Duplicate key: createdOn — remove this entry.

"createdOn" already exists earlier (Line 252). Keep the existing key or reuse createdOnLabel; delete this new one with the colon to avoid JSON/ARB conflicts.

Apply:

-  "createdOn": "Creado el:",
lib/l10n/intl_en.arb (1)

684-687: Duplicate key: createdOn — remove this new entry.

"createdOn" already exists above (Line 298). Prefer using the existing createdOnLabel if a label form is needed.

Apply:

-  "createdOn": "Created on:",
♻️ Duplicate comments (4)
lib/l10n/intl_es.arb (2)

1039-1043: Duplicate key: orderIdLabel — remove this instance.

"orderIdLabel" exists earlier (Line 600). Keep the earlier definition.

Apply:

-  "orderIdLabel": "ID de Orden",

1023-1029: Duplicate key: retry — remove the second definition here.

"retry" is already defined earlier (Line 206). Duplicates break ARB codegen.

Apply:

-  "retry": "Reintentar",
lib/l10n/intl_en.arb (2)

875-878: Duplicate key: orderIdLabel — remove this instance.

Already defined earlier (Line 259). Duplicates can cause flakey localization generation.

Apply:

-  "orderIdLabel": "Order ID",

859-865: Duplicate key: retry — remove this duplicate.

"retry" already defined earlier (Line 215). Keep only one.

Apply:

-  "retry": "Retry",
🧹 Nitpick comments (3)
lib/l10n/intl_it.arb (1)

624-624: Align placeholder type for amount (Object → String) for consistency.

Only IT defines @forAmount.amount.type as Object while EN/ES omit or use String in similar contexts. Recommend switching to String to avoid tooling surprises.

Apply:

-        "type": "Object",
+        "type": "String",
lib/l10n/intl_en.arb (2)

232-246: Nit: missing space before {sats} in titles.

"You are selling{sats}" and "You are buying{sats}" are missing a space before the placeholder.

Apply:

-  "youAreSellingTitle": "You are selling{sats} sats",
+  "youAreSellingTitle": "You are selling {sats} sats",
-  "youAreBuyingTitle": "You are buying{sats} sats",
+  "youAreBuyingTitle": "You are buying {sats} sats",

821-833: Housekeeping: leftover blank line.

There’s a stray blank line after relay dialog header; safe to keep, but consider removing for consistency.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 6fe1a94 and 1a30762.

📒 Files selected for processing (4)
  • lib/features/disputes/widgets/disputes_list.dart (1 hunks)
  • lib/l10n/intl_en.arb (3 hunks)
  • lib/l10n/intl_es.arb (3 hunks)
  • lib/l10n/intl_it.arb (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/features/disputes/widgets/disputes_list.dart
🧰 Additional context used
📓 Path-based instructions (1)
lib/l10n/intl_{en,es,it}.arb

📄 CodeRabbit inference engine (CLAUDE.md)

Add new localization keys to all three ARB files (en, es, it)

Files:

  • lib/l10n/intl_it.arb
  • lib/l10n/intl_en.arb
  • lib/l10n/intl_es.arb
🧠 Learnings (1)
📚 Learning: 2025-08-28T20:32:34.625Z
Learnt from: CR
PR: MostroP2P/mobile#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-28T20:32:34.625Z
Learning: Applies to lib/l10n/intl_{en,es,it}.arb : Add new localization keys to all three ARB files (en, es, it)

Applied to files:

  • lib/l10n/intl_it.arb
  • lib/l10n/intl_es.arb
🪛 RuboCop (1.76.1)
lib/l10n/intl_en.arb

[warning] 864-864: Duplicated key in hash literal.

(Lint/DuplicateHashKey)


[warning] 875-875: Duplicated key in hash literal.

(Lint/DuplicateHashKey)

lib/l10n/intl_es.arb

[warning] 1028-1028: Duplicated key in hash literal.

(Lint/DuplicateHashKey)


[warning] 1039-1039: Duplicated key in hash literal.

(Lint/DuplicateHashKey)

⏰ 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: build
🔇 Additional comments (13)
lib/l10n/intl_it.arb (7)

711-743: Disputes UI strings: parity and placeholders look good.

The added dispute keys and metadata match EN/ES, placeholders are correct.


762-773: New forAmountWithCurrency key looks correct.

Placeholders and wording align with EN/ES.


1031-1044: Dispute communication block: looks solid.

Labels and flow messages are consistent and idiomatic.


1046-1054: Dispute input block: OK.

Placeholder for error is correctly declared.


1056-1060: List/info/screen scaffolding: OK.

Good coverage for empty/error states.


1062-1073: Dispute info labels: OK.

Roles and placeholders are correct.


1075-1081: Dispute screen error block: OK.

Error placeholder wired correctly.

lib/l10n/intl_es.arb (2)

681-713: Disputes UI strings added correctly.

Parity with EN/IT looks good; placeholders validated.


733-743: forAmountWithCurrency added correctly.

Looks consistent with other locales.

lib/l10n/intl_en.arb (4)

651-683: Disputes UI strings: LGTM.

Keys and phrasing align with the new UI states; placeholders are correct.


703-713: forAmountWithCurrency: correct addition.

Placeholder names/types match other locales.


834-848: Dispute communication block: OK.

Wording and flow align with product language.


849-858: Dispute input block: OK.

Error placeholder wired correctly.

@grunch grunch merged commit 2645c22 into main Sep 2, 2025
2 checks passed
@grunch grunch deleted the feature/dispute-ui-only branch September 2, 2025 15:35
@coderabbitai coderabbitai bot mentioned this pull request Oct 10, 2025
3 tasks
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