Skip to content

Commit eba908e

Browse files
authored
Merge pull request #116 from AndreaDiazCorreia/feat/issue-86
UI Refinements for My Trades Screen
2 parents f88abd2 + d68722a commit eba908e

File tree

8 files changed

+551
-459
lines changed

8 files changed

+551
-459
lines changed

android/gradle/wrapper/gradle-wrapper.properties

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
#Sat Jun 14 02:07:21 ART 2025
12
distributionBase=GRADLE_USER_HOME
23
distributionPath=wrapper/dists
4+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
35
zipStoreBase=GRADLE_USER_HOME
46
zipStorePath=wrapper/dists
5-
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-all.zip

lib/features/order/models/order_state.dart

Lines changed: 163 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -82,78 +82,194 @@ class OrderState {
8282
}
8383

8484
OrderState updateWith(MostroMessage message) {
85-
_logger.i('Updating OrderState Action: ${message.action}');
86-
return copyWith(
87-
status: message.getPayload<Order>()?.status ?? status,
88-
action: message.action != Action.cantDo ? message.action : action,
85+
_logger.i('🔄 Updating OrderState with Action: ${message.action}');
86+
87+
// Preserve the current state entirely for cantDo messages - they are informational only
88+
if (message.action == Action.cantDo) {
89+
return this;
90+
}
91+
92+
// Determine the new status based on the action received
93+
Status newStatus = _getStatusFromAction(
94+
message.action, message.getPayload<Order>()?.status);
95+
96+
// 🔍 DEBUG: Log status mapping
97+
_logger.i('📊 Status mapping: ${message.action} → $newStatus');
98+
99+
// Preserve PaymentRequest correctly
100+
PaymentRequest? newPaymentRequest;
101+
if (message.payload is PaymentRequest) {
102+
newPaymentRequest = message.getPayload<PaymentRequest>();
103+
_logger.i('💳 New PaymentRequest found in message');
104+
} else {
105+
newPaymentRequest = paymentRequest; // Preserve existing
106+
}
107+
108+
final newState = copyWith(
109+
status: newStatus,
110+
action: message.action,
89111
order: message.payload is Order
90112
? message.getPayload<Order>()
91113
: message.payload is PaymentRequest
92114
? message.getPayload<PaymentRequest>()!.order
93115
: order,
94-
paymentRequest: message.getPayload<PaymentRequest>() ?? paymentRequest,
116+
paymentRequest: newPaymentRequest,
95117
cantDo: message.getPayload<CantDo>() ?? cantDo,
96118
dispute: message.getPayload<Dispute>() ?? dispute,
97119
peer: message.getPayload<Peer>() ?? peer,
98120
);
121+
122+
_logger.i('✅ New state: ${newState.status} - ${newState.action}');
123+
_logger
124+
.i('💳 PaymentRequest preserved: ${newState.paymentRequest != null}');
125+
126+
return newState;
127+
}
128+
129+
/// Maps actions to their corresponding statuses based on mostrod DM messages
130+
Status _getStatusFromAction(Action action, Status? payloadStatus) {
131+
switch (action) {
132+
// Actions that should set status to waiting-payment
133+
case Action.waitingSellerToPay:
134+
case Action.payInvoice:
135+
return Status.waitingPayment;
136+
137+
// Actions that should set status to waiting-buyer-invoice
138+
case Action.waitingBuyerInvoice:
139+
case Action.addInvoice:
140+
return Status.waitingBuyerInvoice;
141+
142+
// ✅ FIX: Cuando alguien toma una orden, debe cambiar el status inmediatamente
143+
case Action.takeBuy:
144+
// Cuando buyer toma sell order, seller debe esperar buyer invoice
145+
return Status.waitingBuyerInvoice;
146+
147+
case Action.takeSell:
148+
// Cuando seller toma buy order, seller debe pagar invoice
149+
return Status.waitingPayment;
150+
151+
// Actions that should set status to active
152+
case Action.buyerTookOrder:
153+
case Action.holdInvoicePaymentAccepted:
154+
case Action.holdInvoicePaymentSettled:
155+
return Status.active;
156+
157+
// Actions that should set status to fiat-sent
158+
case Action.fiatSent:
159+
case Action.fiatSentOk:
160+
return Status.fiatSent;
161+
162+
// Actions that should set status to success (completed)
163+
case Action.purchaseCompleted:
164+
case Action.released:
165+
case Action.rate:
166+
case Action.rateReceived:
167+
return Status.success;
168+
169+
// Actions that should set status to canceled
170+
case Action.canceled:
171+
case Action.adminCanceled:
172+
case Action.cooperativeCancelAccepted:
173+
return Status.canceled;
174+
175+
// For actions that include Order payload, use the payload status
176+
case Action.newOrder:
177+
return payloadStatus ?? status;
178+
179+
// For other actions, keep the current status unless payload has a different one
180+
default:
181+
return payloadStatus ?? status;
182+
}
99183
}
100184

101185
List<Action> getActions(Role role) {
102-
return actions[role]![status]![action] ?? [];
186+
return actions[role]?[status]?[action] ?? [];
103187
}
104188

105189
static final Map<Role, Map<Status, Map<Action, List<Action>>>> actions = {
106190
Role.seller: {
107191
Status.pending: {
108-
Action.takeBuy: [
109-
Action.takeBuy,
192+
Action.newOrder: [
110193
Action.cancel,
111194
],
112-
Action.waitingBuyerInvoice: [
195+
Action.takeBuy: [
113196
Action.cancel,
114197
],
198+
},
199+
Status.waitingPayment: {
115200
Action.payInvoice: [
116201
Action.payInvoice,
117202
Action.cancel,
118203
],
119-
Action.newOrder: [
204+
Action.waitingSellerToPay: [
205+
Action.payInvoice,
206+
Action.cancel,
207+
],
208+
},
209+
Status.waitingBuyerInvoice: {
210+
Action.waitingBuyerInvoice: [
211+
Action.cancel,
212+
],
213+
Action.addInvoice: [
214+
Action.cancel,
215+
],
216+
Action.takeBuy: [
120217
Action.cancel,
121218
],
122219
},
123220
Status.active: {
124221
Action.buyerTookOrder: [
125-
Action.buyerTookOrder,
126222
Action.cancel,
127223
Action.dispute,
128224
],
129-
Action.fiatSentOk: [
225+
Action.holdInvoicePaymentAccepted: [
226+
Action.cancel,
227+
Action.dispute,
228+
],
229+
Action.holdInvoicePaymentSettled: [
130230
Action.cancel,
131231
Action.dispute,
232+
],
233+
},
234+
Status.fiatSent: {
235+
Action.fiatSentOk: [
132236
Action.release,
237+
Action.cancel,
238+
Action.dispute,
133239
],
240+
},
241+
Status.success: {
134242
Action.rate: [
135243
Action.rate,
136244
],
137-
Action.purchaseCompleted: [],
138-
Action.holdInvoicePaymentSettled: [],
139-
Action.cooperativeCancelInitiatedByPeer: [
140-
Action.cancel,
245+
Action.purchaseCompleted: [
246+
Action.rate,
141247
],
142-
},
143-
Status.waitingPayment: {
144-
Action.payInvoice: [
145-
Action.payInvoice,
146-
Action.cancel,
248+
Action.released: [
249+
Action.rate,
147250
],
251+
Action.rateReceived: [],
252+
},
253+
Status.canceled: {
254+
Action.canceled: [],
255+
Action.adminCanceled: [],
256+
Action.cooperativeCancelAccepted: [],
148257
},
149258
},
150259
Role.buyer: {
151260
Status.pending: {
261+
Action.newOrder: [
262+
Action.cancel,
263+
],
152264
Action.takeSell: [
153-
Action.takeSell,
154265
Action.cancel,
155266
],
156-
Action.newOrder: [
267+
},
268+
Status.waitingPayment: {
269+
Action.waitingSellerToPay: [
270+
Action.cancel,
271+
],
272+
Action.takeSell: [
157273
Action.cancel,
158274
],
159275
},
@@ -162,30 +278,48 @@ class OrderState {
162278
Action.addInvoice,
163279
Action.cancel,
164280
],
165-
Action.waitingSellerToPay: [
281+
Action.waitingBuyerInvoice: [
166282
Action.cancel,
167283
],
168284
},
169285
Status.active: {
170286
Action.holdInvoicePaymentAccepted: [
171-
Action.holdInvoicePaymentAccepted,
172287
Action.fiatSent,
173288
Action.cancel,
174289
Action.dispute,
175290
],
291+
Action.holdInvoicePaymentSettled: [
292+
Action.fiatSent,
293+
Action.cancel,
294+
Action.dispute,
295+
],
296+
Action.buyerTookOrder: [
297+
Action.cancel,
298+
Action.dispute,
299+
],
300+
},
301+
Status.fiatSent: {
176302
Action.fiatSentOk: [
177303
Action.cancel,
178304
Action.dispute,
179305
],
306+
},
307+
Status.success: {
180308
Action.rate: [
181309
Action.rate,
182310
],
183-
Action.cooperativeCancelInitiatedByPeer: [
184-
Action.cancel,
311+
Action.purchaseCompleted: [
312+
Action.rate,
313+
],
314+
Action.released: [
315+
Action.rate,
185316
],
186317
Action.rateReceived: [],
187-
Action.purchaseCompleted: [],
188-
Action.paymentFailed: [],
318+
},
319+
Status.canceled: {
320+
Action.canceled: [],
321+
Action.adminCanceled: [],
322+
Action.cooperativeCancelAccepted: [],
189323
},
190324
},
191325
};

lib/features/order/notfiers/abstract_mostro_notifier.dart

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,14 @@ class AbstractMostroNotifier extends StateNotifier<OrderState> {
1919

2020
AbstractMostroNotifier(
2121
this.orderId,
22-
this.ref,
23-
) : super(OrderState(
24-
action: Action.newOrder, status: Status.pending, order: null)) {
22+
this.ref, {
23+
OrderState? initialState,
24+
}) : super(initialState ??
25+
OrderState(
26+
action: Action.newOrder,
27+
status: Status.pending,
28+
order: null,
29+
)) {
2530
final oldSession =
2631
ref.read(sessionNotifierProvider.notifier).getSessionByOrderId(orderId);
2732
if (oldSession != null) {

lib/features/order/notfiers/order_notifier.dart

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,41 +9,36 @@ import 'package:mostro_mobile/services/mostro_service.dart';
99

1010
class OrderNotifier extends AbstractMostroNotifier {
1111
late final MostroService mostroService;
12-
1312
OrderNotifier(super.orderId, super.ref) {
1413
mostroService = ref.read(mostroServiceProvider);
1514
sync();
1615
subscribe();
1716
}
18-
1917
Future<void> sync() async {
2018
try {
2119
final storage = ref.read(mostroStorageProvider);
2220
final messages = await storage.getAllMessagesForOrderId(orderId);
2321
if (messages.isEmpty) {
22+
logger.w('No messages found for order $orderId');
2423
return;
2524
}
26-
final msg = messages.firstWhereOrNull((m) => m.action != Action.cantDo);
27-
if (msg?.payload is Order) {
28-
state = OrderState(
29-
status: msg!.getPayload<Order>()!.status,
30-
action: msg.action,
31-
order: msg.getPayload<Order>()!,
32-
);
33-
} else {
34-
final orderMsg =
35-
await storage.getLatestMessageOfTypeById<Order>(orderId);
36-
if (orderMsg != null) {
37-
state = OrderState(
38-
status: orderMsg.getPayload<Order>()!.status,
39-
action: orderMsg.action,
40-
order: orderMsg.getPayload<Order>()!,
41-
);
25+
messages.sort((a, b) {
26+
final timestampA = a.timestamp ?? 0;
27+
final timestampB = b.timestamp ?? 0;
28+
return timestampA.compareTo(timestampB);
29+
});
30+
OrderState currentState = state;
31+
for (final message in messages) {
32+
if (message.action != Action.cantDo) {
33+
currentState = currentState.updateWith(message);
4234
}
4335
}
36+
state = currentState;
37+
logger.i(
38+
'Synced order $orderId to state: ${state.status} - ${state.action}');
4439
} catch (e, stack) {
4540
logger.e(
46-
'Error syncing order state',
41+
'Error syncing order state for $orderId',
4742
error: e,
4843
stackTrace: stack,
4944
);

lib/features/trades/providers/trades_provider.dart

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,27 @@ final _logger = Logger();
1212
final filteredTradesProvider = Provider<AsyncValue<List<NostrEvent>>>((ref) {
1313
final allOrdersAsync = ref.watch(orderEventsProvider);
1414
final sessions = ref.watch(sessionNotifierProvider);
15-
16-
_logger.d('Filtering trades: Orders state=${allOrdersAsync.toString().substring(0, math.min(100, allOrdersAsync.toString().length))}, Sessions count=${sessions.length}');
17-
15+
16+
_logger.d(
17+
'Filtering trades: Orders state=${allOrdersAsync.toString().substring(0, math.min(100, allOrdersAsync.toString().length))}, Sessions count=${sessions.length}');
18+
1819
return allOrdersAsync.when(
1920
data: (allOrders) {
2021
final orderIds = sessions.map((s) => s.orderId).toSet();
21-
_logger.d('Got ${allOrders.length} orders and ${orderIds.length} sessions');
22-
22+
_logger
23+
.d('Got ${allOrders.length} orders and ${orderIds.length} sessions');
24+
2325
// Make a copy to avoid modifying the original list
2426
final sortedOrders = List<NostrEvent>.from(allOrders);
25-
sortedOrders.sort((o1, o2) => o1.expirationDate.compareTo(o2.expirationDate));
26-
27+
sortedOrders
28+
.sort((o1, o2) => o1.expirationDate.compareTo(o2.expirationDate));
29+
2730
final filtered = sortedOrders.reversed
2831
.where((o) => orderIds.contains(o.orderId))
2932
.where((o) => o.status != Status.canceled)
3033
.where((o) => o.status != Status.canceledByAdmin)
3134
.toList();
32-
35+
3336
_logger.d('Filtered to ${filtered.length} trades');
3437
return AsyncValue.data(filtered);
3538
},

0 commit comments

Comments
 (0)