Skip to content

feat: implement all wired TODOs across Rust and Dart layers - #82

Merged
grunch merged 4 commits into
mainfrom
feat/implement-todos
Apr 3, 2026
Merged

feat: implement all wired TODOs across Rust and Dart layers#82
grunch merged 4 commits into
mainfrom
feat/implement-todos

Conversation

@grunch

@grunch grunch commented Apr 3, 2026

Copy link
Copy Markdown
Member

Rust:

  • orders.rs: remove stale Phase 7 doc comment; expose pub(crate)
    trade_key_for_order and publish_event for cross-module use
  • actions.rs: add rate_user() building a RateUser NIP-59 gift wrap
  • reputation.rs: wire submit_rating to dispatch RateUser via the
    daemon; replace set_privacy_mode TODO with best-effort identity check

Dart:

  • about_screen: async-load app version via getAppVersion() bridge
  • privacy_mode_provider: init from getPrivacyMode(), propagate changes
    to setPrivacyMode() on every toggle
  • rate_counterpart_screen: call submitRating() instead of delay stub
  • connect_wallet_screen: call connectWallet() and populate state from
    returned NwcWalletInfo
  • wallet_settings_screen: call disconnectWallet() before clearing state
  • relay_management_card: load relays from getRelays() on init; wire
    addRelay() and removeRelay() bridge calls
  • orders.rs: add subscribe_gift_wraps() spawned per maker order;
    decrypts Kind 1059 events with trade key, calls resolve_maker_order()
    on Action::NewOrder so daemon UUID is known before K38383 arrives
  • orders.rs: add process_gift_wrap_rumor() for dispatching inner message
  • orders.rs: call subscribe_gift_wraps() from create_order() after key derivation
  • actions.rs: add dispute() action builder using Action::Dispute
  • disputes.rs: wire open_dispute() to dispatch Action::Dispute via NIP-59
    using the stored trade key index; logs warn when no trade key found
  • relay_pool.rs: remove Phase 3 TODO, note K1059 is handled per-trade

Summary by CodeRabbit

  • New Features

    • App version now loads dynamically from backend
    • Wallet connect/disconnect integrated with backend; wallet state updated
    • Privacy mode synced with backend (async init & updates with rollback)
    • Relay management (load/add/remove) backed by network calls; failure messages added
    • Ratings and disputes published to Mostro network; background encrypted-order messaging (gift-wrap) subscriptions
  • Bug Fixes

    • Replaced placeholder implementations with real backend calls; improved error handling and optimistic-update rollback

grunch and others added 2 commits April 3, 2026 06:10
Rust:
- orders.rs: remove stale Phase 7 doc comment; expose pub(crate)
  trade_key_for_order and publish_event for cross-module use
- actions.rs: add rate_user() building a RateUser NIP-59 gift wrap
- reputation.rs: wire submit_rating to dispatch RateUser via the
  daemon; replace set_privacy_mode TODO with best-effort identity check

Dart:
- about_screen: async-load app version via getAppVersion() bridge
- privacy_mode_provider: init from getPrivacyMode(), propagate changes
  to setPrivacyMode() on every toggle
- rate_counterpart_screen: call submitRating() instead of delay stub
- connect_wallet_screen: call connectWallet() and populate state from
  returned NwcWalletInfo
- wallet_settings_screen: call disconnectWallet() before clearing state
- relay_management_card: load relays from getRelays() on init; wire
  addRelay() and removeRelay() bridge calls
- orders.rs: add subscribe_gift_wraps() spawned per maker order;
  decrypts Kind 1059 events with trade key, calls resolve_maker_order()
  on Action::NewOrder so daemon UUID is known before K38383 arrives
- orders.rs: add process_gift_wrap_rumor() for dispatching inner message
- orders.rs: call subscribe_gift_wraps() from create_order() after key derivation
- actions.rs: add dispute() action builder using Action::Dispute
- disputes.rs: wire open_dispute() to dispatch Action::Dispute via NIP-59
  using the stored trade key index; logs warn when no trade key found
- relay_pool.rs: remove Phase 3 TODO, note K1059 is handled per-trade

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Apr 3, 2026

Copy link
Copy Markdown
Contributor

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f25d1e59-ae01-428f-b54e-baac662dc453

📥 Commits

Reviewing files that changed from the base of the PR and between a5f6abd and 07f398b.

📒 Files selected for processing (18)
  • lib/features/about/screens/about_screen.dart
  • lib/features/account/providers/privacy_mode_provider.dart
  • lib/features/settings/widgets/relay_management_card.dart
  • lib/l10n/app_de.arb
  • lib/l10n/app_en.arb
  • lib/l10n/app_es.arb
  • lib/l10n/app_fr.arb
  • lib/l10n/app_it.arb
  • lib/l10n/app_localizations.dart
  • lib/l10n/app_localizations_de.dart
  • lib/l10n/app_localizations_en.dart
  • lib/l10n/app_localizations_es.dart
  • lib/l10n/app_localizations_fr.dart
  • lib/l10n/app_localizations_it.dart
  • rust/src/api/disputes.rs
  • rust/src/api/orders.rs
  • rust/src/api/reputation.rs
  • rust/src/nostr/relay_pool.rs

Walkthrough

Integrates Flutter UI with Rust bridge APIs (reputation, nwc, nostr), replaces stubbed flows with real bridge calls, adds NIP‑59 Mostro action builders and per‑trade gift‑wrap subscription/processing, and adds relay-management localization and provider wiring.

Changes

Cohort / File(s) Summary
About screen
lib/features/about/screens/about_screen.dart
Converted AboutScreenConsumerWidget; added appVersionProvider (FutureProvider) and fetch from rust_api.getAppVersion(); removed static version constant and updated build signature.
Account / Rating
lib/features/account/providers/privacy_mode_provider.dart, lib/features/rate/screens/rate_counterpart_screen.dart
Privacy provider now initializes from reputation_api.getPrivacyMode() and setPrivacyMode is async with optimistic update/rollback; rating submission now calls reputation_api.submitRating(...) instead of placeholder delay.
Wallet connect / settings
lib/features/settings/screens/connect_wallet_screen.dart, lib/features/settings/screens/wallet_settings_screen.dart
Replaced stubbed wallet connect/disconnect with nwc_api.connectWallet(...) and nwc_api.disconnectWallet(); populate NwcWalletState (name, relayUrls, balance) and handle errors via try/catch.
Relay management UI
lib/features/settings/widgets/relay_management_card.dart
Added _loadRelays() to fetch relays from nostr_api.getRelays(); add/remove relay now call nostr_api.addRelay() / nostr_api.removeRelay() with optimistic UI updates, restore on error and show localized snackbars.
Localization
lib/l10n/app_*.arb, lib/l10n/app_localizations*.dart
Added relayAddFailed and relayRemoveFailed keys and corresponding getters across en/de/es/fr/it localization files.
Rust — Mostro actions
rust/src/mostro/actions.rs
Added dispute and rate_user action builders that produce wrapped Mostro events (including rating payload) for dispatch.
Rust — Reputation
rust/src/api/reputation.rs
submit_rating reserves local rating, tries to dispatch RateUser gift-wrap when trade key exists, rolls back on dispatch failure; added remove_mine helper and a best-effort presence check in set_privacy_mode.
Rust — Disputes
rust/src/api/disputes.rs
open_dispute now requires a trade key, builds and publishes a Mostro dispute event, logs/persists result; tests adjusted to seed store and reflect new flow.
Rust — Orders & gift-wrap subscription
rust/src/api/orders.rs, rust/src/nostr/relay_pool.rs
Added trade_key_for_order and publish_event; create_order spawns subscribe_gift_wraps(...) background workers; implemented subscribe_gift_wraps and process_gift_wrap_rumor to decrypt and handle Kind 1059 gift-wrap rumors; updated relay pool subscription signature to accept (PublicKey, u32) trade keys.

Sequence Diagram(s)

mermaid
sequenceDiagram
autonumber
participant App as Flutter App
participant Rust as Rust bridge (API)
participant Relay as Nostr Relays
participant Store as Local Store/DB
App->>Rust: submitRating(tradeId, score) / connectWallet / getAppVersion
Rust-->>App: result (ok / error)
note right of Rust: For submitRating when trade index exists:
Rust->>Relay: publish_event(wrapped Mostro RateUser)
Relay-->>Rust: relay acknowledgements / rumors (Kind 1059)
Rust->>Rust: subscribe_gift_wraps -> decrypt gift-wrap -> process_gift_wrap_rumor
Rust->>Store: persist rating / dispute / order updates
Store-->>App: state read via providers (privacy mode, wallet state, relays)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐇 I tunneled through code and crossed the stream,

Rust whispers to Flutter in a brand-new dream,
Relays hum, gift-wraps flutter, ratings take wing,
Wallets connect — the rabbit cheers, "What joy you bring!" 🥕✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: implement all wired TODOs across Rust and Dart layers' directly and accurately describes the main purpose of the PR, which is to implement all wired TODOs across both the Rust and Dart codebases.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/implement-todos

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

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

- orders.rs: fetch trade keys before subscribing to prevent orphan relay
  subscription if key derivation fails
- privacy_mode_provider.dart: await setPrivacyMode and roll back state
  on failure instead of fire-and-forget ignore()
- about_screen.dart: set _appVersion = 'unknown' on getAppVersion failure
  instead of silently swallowing the error
- relay_management_card.dart: guard _loadRelays with _loading flag to
  prevent concurrent load races; make _removeRelay async with rollback +
  SnackBar on failure; rollback optimistic add + show SnackBar on failure
- l10n: add relayAddFailed / relayRemoveFailed keys in all 5 languages

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 7

Caution

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

⚠️ Outside diff range comments (2)
rust/src/nostr/relay_pool.rs (1)

143-162: ⚠️ Potential issue | 🟠 Major

Reconnect still cannot rebuild the per-trade gift-wrap workers.

This method only gets trade_pubkeys and re-applies a raw Kind 1059 filter. The actual worker in crate::api::orders::subscribe_gift_wraps() also needs the trade index to load recipient keys, so after restart/reconnect existing maker orders still have no decrypt/routing path for gift-wrap ACK/cancel events. Rehydrate (trade_pubkey, trade_index) pairs and respawn those workers here too.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@rust/src/nostr/relay_pool.rs` around lines 143 - 162,
subscribe_order_and_dm_feeds currently re-subscribes a raw Kind 1059 filter
using only trade_pubkeys, which doesn't rehydrate per-trade gift-wrap workers
because subscribe_gift_wraps (and create_order) require the trade_index to load
recipient keys; fix by querying stored maker orders (e.g. using
pending_orders_filter or DB/state that holds orders) to rebuild a Vec of
(trade_pubkey, trade_index) pairs, then for each pair call the same code path
used by crate::api::orders::subscribe_gift_wraps() (or factor out its
worker-spawn logic into a helper) to respawn the per-trade gift-wrap worker so
decrypt/routing keys are restored for KIND_GIFT_WRAP events.
rust/src/api/reputation.rs (1)

128-173: ⚠️ Potential issue | 🔴 Critical

Make rating submission atomic with the outbound send.

The RateUser event is built/published before the one-shot local insert. Two concurrent callers can therefore emit multiple rating events, and a missing trade key or transient build/publish failure still lets the later insert consume the only rating slot, blocking any retry. Reserve a pending rating under the same lock, then finalize or roll back based on the send result.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@rust/src/api/reputation.rs` around lines 128 - 173, Reserve the rating slot
before any outbound send by calling store.try_insert_mine(...) with a
provisional RatingInfo (e.g. a "pending" marker or is_mine=true but clearly
reserved) for trade_id, then perform the trade key lookup and call
crate::mostro::actions::rate_user and crate::api::orders::publish_event; if the
send succeeds leave/finalize the stored RatingInfo, but if any step fails remove
or roll back the reservation (implement and call a
store.remove_mine/delete_mine(trade_id) or an update-to-failed state) so a
transient publish/build error doesn't consume the only rating slot—use the
existing symbols RatingInfo, store.try_insert_mine,
crate::mostro::actions::rate_user, and crate::api::orders::publish_event to
locate and implement this change.
🧹 Nitpick comments (2)
lib/features/settings/screens/wallet_settings_screen.dart (1)

43-55: Consider only showing success feedback when disconnect actually succeeds.

The current implementation shows "Wallet disconnected" snackbar and clears local state even when the bridge call fails. While the Rust side's only documented failure mode is NoWalletConnected (which makes the unconditional setDisconnected() safe), showing a success message after a failure could mislead users.

♻️ Suggested approach to differentiate success/failure feedback
   Future<void> _disconnect(BuildContext context, WidgetRef ref) async {
+    bool success = false;
     try {
       await nwc_api.disconnectWallet();
+      success = true;
     } catch (e) {
       debugPrint('[WalletSettings] disconnect failed: $e');
     }
     ref.read(nwcProvider.notifier).setDisconnected();
     if (context.mounted) {
       ScaffoldMessenger.of(context).showSnackBar(
-        const SnackBar(content: Text('Wallet disconnected')),
+        SnackBar(
+          content: Text(success
+              ? 'Wallet disconnected'
+              : 'Wallet cleared locally'),
+        ),
       );
     }
   }
lib/features/about/screens/about_screen.dart (1)

14-30: Use Riverpod state management instead of StatefulWidget for the app version.

This async state is managed with StatefulWidget/setState, but the codebase uses Riverpod extensively (21+ files across lib/). Refactor to a FutureProvider and ConsumerWidget for consistency.

♻️ Refactor sketch
+import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:mostro/src/rust/api.dart' as rust_api;

+final appVersionProvider = FutureProvider<String>(
+  (ref) => rust_api.getAppVersion(),
+);
+
-class AboutScreen extends StatefulWidget {
+class AboutScreen extends ConsumerWidget {
   const AboutScreen({super.key});

   `@override`
-  State<AboutScreen> createState() => _AboutScreenState();
-}
-
-class _AboutScreenState extends State<AboutScreen> {
-  String _appVersion = '…';
-
-  `@override`
-  void initState() {
-    super.initState();
-    rust_api.getAppVersion().then((v) {
-      if (mounted) setState(() => _appVersion = v);
-    }).catchError((_) {});
-  }
+  Widget build(BuildContext context, WidgetRef ref) {
+    final version = ref.watch(appVersionProvider);
+    final appVersionText = version.when(
+      data: (v) => 'v$v',
+      loading: () => 'v…',
+      error: (_, __) => 'vunknown',
+    );
+    // existing UI...
+  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/features/about/screens/about_screen.dart` around lines 14 - 30, The
AboutScreen currently uses StatefulWidget with _AboutScreenState and a
_appVersion field populated via rust_api.getAppVersion() in initState; replace
this with a Riverpod FutureProvider (e.g., appVersionProvider) that calls
rust_api.getAppVersion(), remove the StatefulWidget and
_appVersion/_AboutScreenState, and convert AboutScreen into a ConsumerWidget
that reads ref.watch(appVersionProvider) and handles AsyncValue.when (loading,
error, data) to render the version UI; ensure you import flutter_riverpod and
update any references to use the provider instead of setState.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lib/features/about/screens/about_screen.dart`:
- Line 29: The code is silently swallowing errors in the catchError on the
version-fetch future in about_screen.dart; update the catchError handler (the
chain that ends with .catchError((_) {})) to set a sensible fallback version
string (e.g. "unknown" or "N/A") into the same state variable used to display
the version and log the error once (use your app logger or debugPrint) including
the exception details; ensure you call setState (or the appropriate state
updater) so the UI leaves the loading "…" state and shows the fallback version.

In `@lib/features/account/providers/privacy_mode_provider.dart`:
- Around line 26-28: In setPrivacyMode (privacy_mode_provider.dart) the call
reputation_api.setPrivacyMode(...) uses .ignore() but dart:async isn't imported
and the function returns Future<void>; fix by either importing dart:async so
.ignore() is available, or replace the .ignore() usage with
unawaited(reputation_api.setPrivacyMode(enabled: enabled)) and import
package:flutter/foundation.dart if needed, or alternatively make setPrivacyMode
async and await reputation_api.setPrivacyMode(...); update imports accordingly
and ensure the call matches the chosen approach.

In `@lib/features/settings/widgets/relay_management_card.dart`:
- Around line 75-81: The _removeRelay method currently removes the item from the
_relays list before calling nostr_api.removeRelay, which can desync UI if the
API fails; change the logic to perform the API call first or perform a rollback
on failure: capture the removed entry (e.g., final removed = _relays[index]),
call nostr_api.removeRelay(url: removed.url).then((_) => setState(() =>
_relays.removeAt(index))).catchError((e) { setState(() => _relays.insert(index,
removed)); debugPrint(...); }); — this uses the existing _removeRelay, _relays,
and nostr_api.removeRelay symbols to ensure the UI is only updated on success
and restored on error.
- Around line 145-147: The optimistic UI adds the relay before the backend call
and never rolls back on failure; update the logic around nostr_api.addRelay(url:
url) to mirror the removal case: either await the addRelay call before updating
the UI, or keep the optimistic insertion but in the onError callback remove the
relay from the in-memory list/state and trigger a UI refresh (and surface an
error message). Specifically, update the code path that performs the optimistic
add (the code invoking nostr_api.addRelay) so that onError undoes the prior
state change (remove the relay entry) and logs/shows the error, matching the
rollback behavior used for removeRelay.

In `@rust/src/api/disputes.rs`:
- Around line 139-176: The code currently inserts the dispute via
try_insert_if_absent_or_resolved() before attempting the Gift Wrap dispatch,
making failures non-retryable; change the flow so the dispute is not marked
fully "open" until the remote dispatch succeeds: either (A) attempt the full
dispatch sequence first (use trade_key_for_order, get_active_trade_keys,
crate::mostro::actions::dispute, and publish_event) and only call
try_insert_if_absent_or_resolved() after publish_event returns Ok, or (B)
introduce a distinct retryable state (e.g., "pending" or "dispatch_failed") in
the dispute store and call try_insert_if_absent_or_resolved_pending() initially,
then update to "open" only after publish_event succeeds; ensure error cases from
get_active_trade_keys, dispute build (crate::mostro::actions::dispute), and
publish_event bubble up or set the pending state rather than logging and
returning Ok(dispute).

In `@rust/src/api/orders.rs`:
- Around line 757-790: The match currently treats Ok(Err(_)) from rx.recv() as
terminal and breaks the per-trade listener; change it to inspect the RecvError
so that RecvError::Lagged(_) results in continue (recoverable) while only
RecvError::Closed (or other fatal cases) causes break—apply this to the match
handling rx.recv() (the arm that now reads Ok(Err(_)) => break) so the
RelayPoolNotification event loop (where gift-wrap events are deserialized and
process_gift_wrap_rumor is called) mirrors the recover-on-lagged behavior used
elsewhere (~lines 1092–1095).

---

Outside diff comments:
In `@rust/src/api/reputation.rs`:
- Around line 128-173: Reserve the rating slot before any outbound send by
calling store.try_insert_mine(...) with a provisional RatingInfo (e.g. a
"pending" marker or is_mine=true but clearly reserved) for trade_id, then
perform the trade key lookup and call crate::mostro::actions::rate_user and
crate::api::orders::publish_event; if the send succeeds leave/finalize the
stored RatingInfo, but if any step fails remove or roll back the reservation
(implement and call a store.remove_mine/delete_mine(trade_id) or an
update-to-failed state) so a transient publish/build error doesn't consume the
only rating slot—use the existing symbols RatingInfo, store.try_insert_mine,
crate::mostro::actions::rate_user, and crate::api::orders::publish_event to
locate and implement this change.

In `@rust/src/nostr/relay_pool.rs`:
- Around line 143-162: subscribe_order_and_dm_feeds currently re-subscribes a
raw Kind 1059 filter using only trade_pubkeys, which doesn't rehydrate per-trade
gift-wrap workers because subscribe_gift_wraps (and create_order) require the
trade_index to load recipient keys; fix by querying stored maker orders (e.g.
using pending_orders_filter or DB/state that holds orders) to rebuild a Vec of
(trade_pubkey, trade_index) pairs, then for each pair call the same code path
used by crate::api::orders::subscribe_gift_wraps() (or factor out its
worker-spawn logic into a helper) to respawn the per-trade gift-wrap worker so
decrypt/routing keys are restored for KIND_GIFT_WRAP events.

---

Nitpick comments:
In `@lib/features/about/screens/about_screen.dart`:
- Around line 14-30: The AboutScreen currently uses StatefulWidget with
_AboutScreenState and a _appVersion field populated via rust_api.getAppVersion()
in initState; replace this with a Riverpod FutureProvider (e.g.,
appVersionProvider) that calls rust_api.getAppVersion(), remove the
StatefulWidget and _appVersion/_AboutScreenState, and convert AboutScreen into a
ConsumerWidget that reads ref.watch(appVersionProvider) and handles
AsyncValue.when (loading, error, data) to render the version UI; ensure you
import flutter_riverpod and update any references to use the provider instead of
setState.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0b5dc636-8d6f-4634-947e-74311e965dfa

📥 Commits

Reviewing files that changed from the base of the PR and between 963df7a and a5f6abd.

📒 Files selected for processing (11)
  • lib/features/about/screens/about_screen.dart
  • lib/features/account/providers/privacy_mode_provider.dart
  • lib/features/rate/screens/rate_counterpart_screen.dart
  • lib/features/settings/screens/connect_wallet_screen.dart
  • lib/features/settings/screens/wallet_settings_screen.dart
  • lib/features/settings/widgets/relay_management_card.dart
  • rust/src/api/disputes.rs
  • rust/src/api/orders.rs
  • rust/src/api/reputation.rs
  • rust/src/mostro/actions.rs
  • rust/src/nostr/relay_pool.rs

Comment thread lib/features/about/screens/about_screen.dart Outdated
Comment on lines +14 to +23
PrivacyModeNotifier() : super(false) {
_init();
}

Future<void> _init() async {
try {
final current = await reputation_api.getPrivacyMode();
if (mounted) state = current;
} catch (_) {}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

This provider fails open while the Rust value is still loading.

super(false) is observable until _init() completes. Consumers already use this provider synchronously to choose the selected privacy option and to hide/show reputation metadata, so a stored true value briefly renders as "privacy off", and the empty catch leaves that unsafe fallback in place forever on bridge errors. Model this as loading/nullable state or default closed until the bridge value arrives. See lib/features/account/screens/account_screen.dart:245-265 and lib/features/order/screens/take_order_screen.dart:289-299.

Comment thread lib/features/account/providers/privacy_mode_provider.dart Outdated
Comment thread lib/features/settings/widgets/relay_management_card.dart Outdated
Comment thread lib/features/settings/widgets/relay_management_card.dart
Comment thread rust/src/api/disputes.rs Outdated
Comment thread rust/src/api/orders.rs
orders.rs: distinguish RecvError::Lagged (continue) from Closed (break)
in gift-wrap loop so a slow subscriber recovers instead of terminating.

disputes.rs: dispatch Action::Dispute to Mostro before persisting the
local record so failed publishes leave a retryable clean slate; update
tests to use seed_dispute() helper that bypasses dispatch.

reputation.rs: reserve the rating slot via try_insert_mine() before
attempting publish_event so concurrent submit_rating calls can't both
reach the wire; add remove_mine() rollback called on dispatch failure.

relay_pool.rs: change subscribe_order_and_dm_feeds() signature from
Vec<PublicKey> to Vec<(PublicKey, u32)> and spawn a subscribe_gift_wraps
worker per trade key so per-trade decrypt/routing is restored on reconnect.

about_screen.dart: replace StatefulWidget + initState pattern with a
FutureProvider<String> (appVersionProvider) and ConsumerWidget so version
loading is handled declaratively with AsyncValue.when(loading/data/error).
@grunch
grunch merged commit 55b2fa0 into main Apr 3, 2026
1 check was pending
@grunch
grunch deleted the feat/implement-todos branch April 3, 2026 11:38
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.

1 participant