Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions lib/features/key_manager/key_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ class KeyManager {
}

Future<bool> hasMasterKey() async {
if (masterKeyPair != null) {
return true;
}
_masterKeyHex = await _storage.readMasterKey();
return _masterKeyHex != null;
}
Expand Down
92 changes: 68 additions & 24 deletions lib/features/order/screens/take_order_screen.dart
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
import 'package:circular_countdown/circular_countdown.dart';
import 'package:dart_nostr/nostr/model/event/event.dart';
import 'package:flutter/material.dart';

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:intl/intl.dart';
import 'package:mostro_mobile/core/app_theme.dart';
import 'package:mostro_mobile/data/models/enums/action.dart' as actions;
import 'package:mostro_mobile/data/models/enums/order_type.dart';
import 'package:mostro_mobile/data/models/nostr_event.dart';
import 'package:mostro_mobile/features/order/providers/order_notifier_provider.dart';
import 'package:mostro_mobile/features/order/widgets/order_app_bar.dart';
import 'package:mostro_mobile/shared/providers.dart';
import 'package:mostro_mobile/shared/widgets/order_cards.dart';
import 'package:mostro_mobile/shared/providers/order_repository_provider.dart';
import 'package:mostro_mobile/shared/providers/exchange_service_provider.dart';
import 'package:mostro_mobile/shared/utils/currency_utils.dart';
import 'package:mostro_mobile/shared/widgets/custom_card.dart';
import 'package:mostro_mobile/features/mostro/mostro_instance.dart';
import 'package:mostro_mobile/shared/providers/time_provider.dart';
import 'package:mostro_mobile/generated/l10n.dart';

class TakeOrderScreen extends ConsumerWidget {
class TakeOrderScreen extends ConsumerStatefulWidget {
final String orderId;
final OrderType orderType;
final TextEditingController _fiatAmountController = TextEditingController();
Expand All @@ -28,13 +29,39 @@ class TakeOrderScreen extends ConsumerWidget {
TakeOrderScreen({super.key, required this.orderId, required this.orderType});

@override
Widget build(BuildContext context, WidgetRef ref) {
final order = ref.watch(eventProvider(orderId));
ConsumerState<TakeOrderScreen> createState() => _TakeOrderScreenState();
}

class _TakeOrderScreenState extends ConsumerState<TakeOrderScreen> {
bool _isSubmitting = false;
dynamic _lastSeenAction;

@override
Widget build(BuildContext context) {
final order = ref.watch(eventProvider(widget.orderId));

// Listen for messages to reset loading state on CantDo
ref.listen(
mostroMessageStreamProvider(widget.orderId),
(_, next) {
next.whenData((msg) {
if (msg == null || msg.action == _lastSeenAction) return;
_lastSeenAction = msg.action;

// Reset loading state only on CantDo message
if (msg.action == actions.Action.cantDo && _isSubmitting) {
setState(() {
_isSubmitting = false;
});
}
});
},
);

return Scaffold(
backgroundColor: AppTheme.backgroundDark,
appBar: OrderAppBar(
title: orderType == OrderType.buy
title: widget.orderType == OrderType.buy
? S.of(context)!.buyOrderDetailsTitle
: S.of(context)!.sellOrderDetailsTitle),
body: SingleChildScrollView(
Expand Down Expand Up @@ -94,7 +121,7 @@ class TakeOrderScreen extends ConsumerWidget {
}
}

final hasFixedSatsAmount = order.amount != null && order.amount != '0';
final hasFixedSatsAmount = order.amount != '0';

return CustomCard(
padding: const EdgeInsets.all(16),
Expand All @@ -103,10 +130,10 @@ class TakeOrderScreen extends ConsumerWidget {
children: [
Text(
hasFixedSatsAmount
? (orderType == OrderType.sell
? (widget.orderType == OrderType.sell
? "${S.of(context)!.someoneIsSellingTitle.replaceAll(' Sats', '')} ${order.amount} Sats"
: "${S.of(context)!.someoneIsBuyingTitle.replaceAll(' Sats', '')} ${order.amount} Sats")
: (orderType == OrderType.sell
: (widget.orderType == OrderType.sell
? S.of(context)!.someoneIsSellingTitle
: S.of(context)!.someoneIsBuyingTitle),
style: const TextStyle(
Expand Down Expand Up @@ -153,7 +180,7 @@ class TakeOrderScreen extends ConsumerWidget {

Widget _buildOrderId(BuildContext context) {
return OrderIdCard(
orderId: orderId,
orderId: widget.orderId,
);
}

Expand Down Expand Up @@ -194,25 +221,28 @@ class TakeOrderScreen extends ConsumerWidget {
Widget _buildActionButtons(
BuildContext context, WidgetRef ref, NostrEvent order) {
final orderDetailsNotifier =
ref.read(orderNotifierProvider(orderId).notifier);
ref.read(orderNotifierProvider(widget.orderId).notifier);

final buttonText =
orderType == OrderType.buy ? S.of(context)!.sell : S.of(context)!.buy;
widget.orderType == OrderType.buy ? S.of(context)!.sell : S.of(context)!.buy;

return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: OutlinedButton(
onPressed: () => Navigator.of(context).pop(),
onPressed: () => context.pop(),
style: AppTheme.theme.outlinedButtonTheme.style,
child: Text(S.of(context)!.close),
),
),
const SizedBox(width: 16),
Expanded(
child: ElevatedButton(
onPressed: () async {
onPressed: _isSubmitting ? null : () async {
setState(() {
_isSubmitting = true;
});
// Check if this is a range order
if (order.fiatAmount.maximum != null &&
order.fiatAmount.minimum != order.fiatAmount.maximum) {
Expand All @@ -226,7 +256,7 @@ class TakeOrderScreen extends ConsumerWidget {
return AlertDialog(
title: Text(S.of(context)!.enterAmount),
content: TextField(
controller: _fiatAmountController,
controller: widget._fiatAmountController,
keyboardType: TextInputType.number,
decoration: InputDecoration(
hintText: S.of(context)!.enterAmountBetween(
Expand All @@ -237,14 +267,14 @@ class TakeOrderScreen extends ConsumerWidget {
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(null),
onPressed: () => context.pop(),
child: Text(S.of(context)!.cancel),
),
ElevatedButton(
key: const Key('submitAmountButton'),
onPressed: () {
final inputAmount = int.tryParse(
_fiatAmountController.text.trim());
widget._fiatAmountController.text.trim());
if (inputAmount == null) {
setState(() {
errorText =
Expand All @@ -264,7 +294,7 @@ class TakeOrderScreen extends ConsumerWidget {
.toString());
});
} else {
Navigator.of(context).pop(inputAmount);
context.pop(inputAmount);
}
},
child: Text(S.of(context)!.submit),
Expand All @@ -277,27 +307,32 @@ class TakeOrderScreen extends ConsumerWidget {
);

if (enteredAmount != null) {
if (orderType == OrderType.buy) {
if (widget.orderType == OrderType.buy) {
await orderDetailsNotifier.takeBuyOrder(
order.orderId!, enteredAmount);
} else {
final lndAddress = _lndAddressController.text.trim();
final lndAddress = widget._lndAddressController.text.trim();
await orderDetailsNotifier.takeSellOrder(
order.orderId!,
enteredAmount,
lndAddress.isEmpty ? null : lndAddress,
);
}
} else {
// Dialog was dismissed without entering amount, reset loading state
setState(() {
_isSubmitting = false;
});
}
} else {
// Not a range order – use the existing logic.
final fiatAmount =
int.tryParse(_fiatAmountController.text.trim());
if (orderType == OrderType.buy) {
int.tryParse(widget._fiatAmountController.text.trim());
if (widget.orderType == OrderType.buy) {
await orderDetailsNotifier.takeBuyOrder(
order.orderId!, fiatAmount);
} else {
final lndAddress = _lndAddressController.text.trim();
final lndAddress = widget._lndAddressController.text.trim();
await orderDetailsNotifier.takeSellOrder(
order.orderId!,
fiatAmount,
Expand All @@ -309,7 +344,16 @@ class TakeOrderScreen extends ConsumerWidget {
style: ElevatedButton.styleFrom(
backgroundColor: AppTheme.mostroGreen,
),
child: Text(buttonText),
child: _isSubmitting
? const SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
),
)
: Text(buttonText),
),
),
],
Expand Down
3 changes: 3 additions & 0 deletions lib/shared/notifiers/session_notifier.dart
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ class SessionNotifier extends StateNotifier<List<Session>> {

Future<Session> newSession(
{String? orderId, int? requestId, Role? role}) async {
if (state.any((s) => s.orderId == orderId)) {
return state.firstWhere((s) => s.orderId == orderId);
}
final masterKey = ref.read(keyManagerProvider).masterKeyPair!;
final keyIndex = await ref.read(keyManagerProvider).getCurrentKeyIndex();
final tradeKey = await ref.read(keyManagerProvider).deriveTradeKey();
Expand Down
48 changes: 24 additions & 24 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,26 @@ packages:
dependency: transitive
description:
name: _fe_analyzer_shared
sha256: e55636ed79578b9abca5fecf9437947798f5ef7456308b5cb85720b793eac92f
sha256: da0d9209ca76bde579f2da330aeb9df62b6319c834fa7baae052021b0462401f
url: "https://pub.dev"
source: hosted
version: "82.0.0"
version: "85.0.0"
analyzer:
dependency: transitive
description:
name: analyzer
sha256: "904ae5bb474d32c38fb9482e2d925d5454cda04ddd0e55d2e6826bc72f6ba8c0"
sha256: f4ad0fea5f102201015c9aae9d93bc02f75dd9491529a8c21f88d17a8523d44c
url: "https://pub.dev"
source: hosted
version: "7.4.5"
version: "7.6.0"
analyzer_plugin:
dependency: transitive
description:
name: analyzer_plugin
sha256: ee188b6df6c85f1441497c7171c84f1392affadc0384f71089cb10a3bc508cef
sha256: a5ab7590c27b779f3d4de67f31c4109dbe13dd7339f86461a6f2a8ab2594d8ce
url: "https://pub.dev"
source: hosted
version: "0.13.1"
version: "0.13.4"
app_links:
dependency: "direct main"
description:
Expand Down Expand Up @@ -213,10 +213,10 @@ packages:
dependency: transitive
description:
name: built_value
sha256: "082001b5c3dc495d4a42f1d5789990505df20d8547d42507c29050af6933ee27"
sha256: "0b1b12a0a549605e5f04476031cd0bc91ead1d7c8e830773a18ee54179b3cb62"
url: "https://pub.dev"
source: hosted
version: "8.10.1"
version: "8.11.0"
characters:
dependency: transitive
description:
Expand Down Expand Up @@ -293,10 +293,10 @@ packages:
dependency: transitive
description:
name: coverage
sha256: aa07dbe5f2294c827b7edb9a87bba44a9c15a3cc81bc8da2ca19b37322d30080
sha256: "5da775aa218eaf2151c721b16c01c7676fbfdd99cebba2bf64e8b807a28ff94d"
url: "https://pub.dev"
source: hosted
version: "1.14.1"
version: "1.15.0"
cross_file:
dependency: transitive
description:
Expand Down Expand Up @@ -341,10 +341,10 @@ packages:
dependency: transitive
description:
name: custom_lint_visitor
sha256: cba5b6d7a6217312472bf4468cdf68c949488aed7ffb0eab792cd0b6c435054d
sha256: "4a86a0d8415a91fbb8298d6ef03e9034dc8e323a599ddc4120a0e36c433983a2"
url: "https://pub.dev"
source: hosted
version: "1.0.0+7.4.5"
version: "1.0.0+7.7.0"
dart_nostr:
dependency: "direct main"
description:
Expand All @@ -357,10 +357,10 @@ packages:
dependency: transitive
description:
name: dart_style
sha256: "5b236382b47ee411741447c1f1e111459c941ea1b3f2b540dde54c210a3662af"
sha256: "8a0e5fba27e8ee025d2ffb4ee820b4e6e2cf5e4246a6b1a477eb66866947e0bb"
url: "https://pub.dev"
source: hosted
version: "3.1.0"
version: "3.1.1"
dbus:
dependency: transitive
description:
Expand Down Expand Up @@ -442,10 +442,10 @@ packages:
dependency: transitive
description:
name: flutter_background_service_android
sha256: b73d903056240e23a5c56d9e52d3a5d02ae41cb18b2988a97304ae37b2bae4bf
sha256: ca0793d4cd19f1e194a130918401a3d0b1076c81236f7273458ae96987944a87
url: "https://pub.dev"
source: hosted
version: "6.3.0"
version: "6.3.1"
flutter_background_service_ios:
dependency: transitive
description:
Expand Down Expand Up @@ -551,10 +551,10 @@ packages:
dependency: "direct main"
description:
name: flutter_local_notifications
sha256: edae0c34573233ab03f5ba1f07465e55c384743893042cb19e010b4ee8541c12
sha256: "20ca0a9c82ce0c855ac62a2e580ab867f3fbea82680a90647f7953832d0850ae"
url: "https://pub.dev"
source: hosted
version: "19.3.0"
version: "19.4.0"
flutter_local_notifications_linux:
dependency: transitive
description:
Expand All @@ -575,10 +575,10 @@ packages:
dependency: transitive
description:
name: flutter_local_notifications_windows
sha256: f8fc0652a601f83419d623c85723a3e82ad81f92b33eaa9bcc21ea1b94773e6e
sha256: ed46d7ae4ec9d19e4c8fa2badac5fe27ba87a3fe387343ce726f927af074ec98
url: "https://pub.dev"
source: hosted
version: "1.0.0"
version: "1.0.2"
flutter_localizations:
dependency: "direct main"
description: flutter
Expand Down Expand Up @@ -880,10 +880,10 @@ packages:
dependency: transitive
description:
name: local_auth_android
sha256: "63ad7ca6396290626dc0cb34725a939e4cfe965d80d36112f08d49cf13a8136e"
sha256: "82b2bdeee2199a510d3b7716121e96a6609da86693bb0863edd8566355406b79"
url: "https://pub.dev"
source: hosted
version: "1.0.49"
version: "1.0.50"
local_auth_darwin:
dependency: transitive
description:
Expand Down Expand Up @@ -912,10 +912,10 @@ packages:
dependency: "direct main"
description:
name: logger
sha256: "2621da01aabaf223f8f961e751f2c943dbb374dc3559b982f200ccedadaa6999"
sha256: "55d6c23a6c15db14920e037fe7e0dc32e7cdaf3b64b4b25df2d541b5b6b81c0c"
url: "https://pub.dev"
source: hosted
version: "2.6.0"
version: "2.6.1"
logging:
dependency: transitive
description:
Expand Down