diff --git a/assets/svg/fruit-sorbet-theme.svg b/assets/svg/fruit-sorbet-theme.svg index d8680aec9..9ae18fa40 100644 --- a/assets/svg/fruit-sorbet-theme.svg +++ b/assets/svg/fruit-sorbet-theme.svg @@ -1,28 +1,66 @@ - - - + + + + + + + + + + + + + + - + - + - + - + - + - + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - diff --git a/lib/main.dart b/lib/main.dart index 146d090ec..b83a89354 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -17,6 +17,7 @@ import 'package:hive_flutter/hive_flutter.dart'; import 'package:isar/isar.dart'; import 'package:keyboard_dismisser/keyboard_dismisser.dart'; import 'package:path_provider/path_provider.dart'; +import 'package:stackwallet/db/main_db.dart'; import 'package:stackwallet/hive/db.dart'; import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart'; import 'package:stackwallet/models/exchange/change_now/exchange_transaction_status.dart'; @@ -65,8 +66,6 @@ import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/utilities/util.dart'; import 'package:window_size/window_size.dart'; -import 'db/main_db.dart'; - final openedFromSWBFileStringStateProvider = StateProvider((ref) => null); @@ -290,10 +289,6 @@ class _MaterialAppWithThemeState extends ConsumerState // TODO: this should probably run unawaited. Keep commented out for now as proper community nodes ui hasn't been implemented yet // unawaited(_nodeService.updateCommunityNodes()); - print("================================================"); - print("${ref.read(prefsChangeNotifierProvider).externalCalls}"); - print("${await ref.read(prefsChangeNotifierProvider).isExternalCallsSet()}"); - print("================================================"); // run without awaiting if (ref.read(prefsChangeNotifierProvider).externalCalls && await ref.read(prefsChangeNotifierProvider).isExternalCallsSet()) { diff --git a/lib/models/exchange/aggregate_currency.dart b/lib/models/exchange/aggregate_currency.dart new file mode 100644 index 000000000..6cd1ef6cf --- /dev/null +++ b/lib/models/exchange/aggregate_currency.dart @@ -0,0 +1,40 @@ +import 'package:stackwallet/models/isar/exchange_cache/currency.dart'; +import 'package:stackwallet/models/isar/exchange_cache/pair.dart'; +import 'package:tuple/tuple.dart'; + +class AggregateCurrency { + final Map _map = {}; + + AggregateCurrency( + {required List> exchangeCurrencyPairs}) { + assert(exchangeCurrencyPairs.isNotEmpty); + + for (final item in exchangeCurrencyPairs) { + _map[item.item1] = item.item2; + } + } + + Currency? forExchange(String exchangeName) { + return _map[exchangeName]; + } + + String get ticker => _map.values.first!.ticker; + + String get name => _map.values.first!.name; + + String get image => _map.values.first!.image; + + SupportedRateType get rateType => _map.values.first!.rateType; + + bool get isStackCoin => _map.values.first!.isStackCoin; + + @override + String toString() { + String str = "AggregateCurrency: {"; + for (final key in _map.keys) { + str += " $key: ${_map[key]},"; + } + str += " }"; + return str; + } +} diff --git a/lib/models/exchange/exchange_form_state.dart b/lib/models/exchange/exchange_form_state.dart index 94bcd09de..c96f7df34 100644 --- a/lib/models/exchange/exchange_form_state.dart +++ b/lib/models/exchange/exchange_form_state.dart @@ -1,14 +1,11 @@ import 'package:decimal/decimal.dart'; import 'package:flutter/foundation.dart'; -import 'package:isar/isar.dart'; +import 'package:stackwallet/models/exchange/aggregate_currency.dart'; import 'package:stackwallet/models/exchange/response_objects/estimate.dart'; -import 'package:stackwallet/models/isar/exchange_cache/currency.dart'; -import 'package:stackwallet/models/isar/exchange_cache/pair.dart'; -import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart'; import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart'; import 'package:stackwallet/services/exchange/exchange.dart'; -import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart'; import 'package:stackwallet/services/exchange/majestic_bank/majestic_bank_exchange.dart'; +import 'package:stackwallet/utilities/enums/exchange_rate_type_enum.dart'; import 'package:stackwallet/utilities/logger.dart'; class ExchangeFormState extends ChangeNotifier { @@ -53,15 +50,15 @@ class ExchangeFormState extends ChangeNotifier { // } - Currency? _sendCurrency; - Currency? get sendCurrency => _sendCurrency; + AggregateCurrency? _sendCurrency; + AggregateCurrency? get sendCurrency => _sendCurrency; // set sendCurrency(Currency? sendCurrency) { // _sendCurrency = sendCurrency; // // // } - Currency? _receiveCurrency; - Currency? get receiveCurrency => _receiveCurrency; + AggregateCurrency? _receiveCurrency; + AggregateCurrency? get receiveCurrency => _receiveCurrency; // set receiveCurrency(Currency? receiveCurrency) { // _receiveCurrency = receiveCurrency; // // @@ -113,8 +110,8 @@ class ExchangeFormState extends ChangeNotifier { receiveAmount != null && rate != null && rate! >= Decimal.zero && - exchange.name == sendCurrency!.exchangeName && - exchange.name == receiveCurrency!.exchangeName && + sendCurrency!.forExchange(exchange.name) != null && + receiveCurrency!.forExchange(exchange.name) != null && warning.isEmpty; } @@ -156,73 +153,6 @@ class ExchangeFormState extends ChangeNotifier { }) async { _exchange = exchange; if (shouldUpdateData) { - if (_sendCurrency != null) { - _sendCurrency = await ExchangeDataLoadingService - .instance.isar.currencies - .where() - .exchangeNameEqualTo(exchange.name) - .filter() - .tickerEqualTo(_sendCurrency!.ticker) - .and() - .group((q) => exchangeRateType == ExchangeRateType.fixed - ? q - .rateTypeEqualTo(SupportedRateType.both) - .or() - .rateTypeEqualTo(SupportedRateType.fixed) - : q - .rateTypeEqualTo(SupportedRateType.both) - .or() - .rateTypeEqualTo(SupportedRateType.estimated)) - .findFirst(); - } - if (_sendCurrency == null) { - switch (exchange.name) { - case ChangeNowExchange.exchangeName: - _sendCurrency = _cachedSendCN; - break; - case MajesticBankExchange.exchangeName: - _sendCurrency = _cachedSendMB; - break; - } - } - - if (_receiveCurrency != null) { - _receiveCurrency = await ExchangeDataLoadingService - .instance.isar.currencies - .where() - .exchangeNameEqualTo(exchange.name) - .filter() - .tickerEqualTo(_receiveCurrency!.ticker) - .and() - .group((q) => exchangeRateType == ExchangeRateType.fixed - ? q - .rateTypeEqualTo(SupportedRateType.both) - .or() - .rateTypeEqualTo(SupportedRateType.fixed) - : q - .rateTypeEqualTo(SupportedRateType.both) - .or() - .rateTypeEqualTo(SupportedRateType.estimated)) - .findFirst(); - } - - if (_receiveCurrency == null) { - switch (exchange.name) { - case ChangeNowExchange.exchangeName: - _receiveCurrency = _cachedReceivingCN; - break; - case MajesticBankExchange.exchangeName: - _receiveCurrency = _cachedReceivingMB; - break; - } - } - - _updateCachedCurrencies( - exchangeName: exchange.name, - send: _sendCurrency, - receiving: _receiveCurrency, - ); - await _updateRangesAndEstimate( shouldNotifyListeners: false, ); @@ -233,14 +163,9 @@ class ExchangeFormState extends ChangeNotifier { } } - void setCurrencies(Currency from, Currency to) { + void setCurrencies(AggregateCurrency from, AggregateCurrency to) { _sendCurrency = from; _receiveCurrency = to; - _updateCachedCurrencies( - exchangeName: exchange.name, - send: _sendCurrency, - receiving: _receiveCurrency, - ); } void reset({ @@ -316,7 +241,7 @@ class ExchangeFormState extends ChangeNotifier { } Future updateSendCurrency( - Currency sendCurrency, + AggregateCurrency sendCurrency, bool shouldNotifyListeners, ) async { try { @@ -324,12 +249,6 @@ class ExchangeFormState extends ChangeNotifier { _minSendAmount = null; _maxSendAmount = null; - _updateCachedCurrencies( - exchangeName: exchange.name, - send: _sendCurrency, - receiving: _receiveCurrency, - ); - if (_receiveCurrency == null) { _rate = null; } else { @@ -346,7 +265,7 @@ class ExchangeFormState extends ChangeNotifier { } Future updateReceivingCurrency( - Currency receiveCurrency, + AggregateCurrency receiveCurrency, bool shouldNotifyListeners, ) async { try { @@ -354,12 +273,6 @@ class ExchangeFormState extends ChangeNotifier { _minReceiveAmount = null; _maxReceiveAmount = null; - _updateCachedCurrencies( - exchangeName: exchange.name, - send: _sendCurrency, - receiving: _receiveCurrency, - ); - if (_sendCurrency == null) { _rate = null; } else { @@ -387,16 +300,10 @@ class ExchangeFormState extends ChangeNotifier { _minReceiveAmount = null; _maxReceiveAmount = null; - final Currency? tmp = sendCurrency; + final AggregateCurrency? tmp = sendCurrency; _sendCurrency = receiveCurrency; _receiveCurrency = tmp; - _updateCachedCurrencies( - exchangeName: exchange.name, - send: _sendCurrency, - receiving: _receiveCurrency, - ); - await _updateRangesAndEstimate( shouldNotifyListeners: false, ); @@ -418,6 +325,29 @@ class ExchangeFormState extends ChangeNotifier { required bool shouldNotifyListeners, }) async { try { + switch (exchange.name) { + case ChangeNowExchange.exchangeName: + if (!_exchangeSupported( + exchangeName: exchange.name, + sendCurrency: sendCurrency, + receiveCurrency: receiveCurrency, + exchangeRateType: exchangeRateType, + )) { + _exchange = MajesticBankExchange.instance; + } + break; + case MajesticBankExchange.exchangeName: + if (!_exchangeSupported( + exchangeName: exchange.name, + sendCurrency: sendCurrency, + receiveCurrency: receiveCurrency, + exchangeRateType: exchangeRateType, + )) { + _exchange = ChangeNowExchange.instance; + } + break; + } + await _updateRanges(shouldNotifyListeners: false); await _updateEstimate(shouldNotifyListeners: false); if (shouldNotifyListeners) { @@ -542,33 +472,30 @@ class ExchangeFormState extends ChangeNotifier { //============================================================================ - Currency? _cachedReceivingMB; - Currency? _cachedSendMB; - Currency? _cachedReceivingCN; - Currency? _cachedSendCN; - - void _updateCachedCurrencies({ - required String exchangeName, - required Currency? send, - required Currency? receiving, - }) { - switch (exchangeName) { - case ChangeNowExchange.exchangeName: - _cachedSendCN = send ?? _cachedSendCN; - _cachedReceivingCN = receiving ?? _cachedReceivingCN; - break; - case MajesticBankExchange.exchangeName: - _cachedSendMB = send ?? _cachedSendMB; - _cachedReceivingMB = receiving ?? _cachedReceivingMB; - break; - } - } - void _notify() { debugPrint("ExFState NOTIFY: ${toString()}"); notifyListeners(); } + bool _exchangeSupported({ + required String exchangeName, + required AggregateCurrency? sendCurrency, + required AggregateCurrency? receiveCurrency, + required ExchangeRateType exchangeRateType, + }) { + final send = sendCurrency?.forExchange(exchangeName); + if (send == null) return false; + + final rcv = receiveCurrency?.forExchange(exchangeName); + if (rcv == null) return false; + + if (exchangeRateType == ExchangeRateType.fixed) { + return send.supportsFixedRate && rcv.supportsFixedRate; + } else { + return send.supportsEstimatedRate && rcv.supportsEstimatedRate; + } + } + @override String toString() { return "{" diff --git a/lib/models/exchange/incomplete_exchange.dart b/lib/models/exchange/incomplete_exchange.dart index 46e7ffd68..864a25490 100644 --- a/lib/models/exchange/incomplete_exchange.dart +++ b/lib/models/exchange/incomplete_exchange.dart @@ -1,7 +1,7 @@ import 'package:decimal/decimal.dart'; import 'package:flutter/foundation.dart'; import 'package:stackwallet/models/exchange/response_objects/trade.dart'; -import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart'; +import 'package:stackwallet/utilities/enums/exchange_rate_type_enum.dart'; class IncompleteExchangeModel extends ChangeNotifier { final String sendTicker; @@ -15,6 +15,7 @@ class IncompleteExchangeModel extends ChangeNotifier { final ExchangeRateType rateType; final bool reversed; + final bool walletInitiated; String? _recipientAddress; @@ -68,6 +69,7 @@ class IncompleteExchangeModel extends ChangeNotifier { required this.receiveAmount, required this.rateType, required this.reversed, + required this.walletInitiated, String? rateId, }) : _rateId = rateId; } diff --git a/lib/models/isar/exchange_cache/currency.dart b/lib/models/isar/exchange_cache/currency.dart index ced37557c..81471a3d1 100644 --- a/lib/models/isar/exchange_cache/currency.dart +++ b/lib/models/isar/exchange_cache/currency.dart @@ -44,6 +44,12 @@ class Currency { @Index() final bool isStackCoin; + @ignore + bool get supportsFixedRate => rateType == SupportedRateType.fixed || rateType == SupportedRateType.both; + + @ignore + bool get supportsEstimatedRate => rateType == SupportedRateType.estimated || rateType == SupportedRateType.both; + Currency({ required this.exchangeName, required this.ticker, diff --git a/lib/models/isar/models/blockchain_data/address.dart b/lib/models/isar/models/blockchain_data/address.dart index cbdc6b2a1..0d29f28a7 100644 --- a/lib/models/isar/models/blockchain_data/address.dart +++ b/lib/models/isar/models/blockchain_data/address.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:isar/isar.dart'; import 'package:stackwallet/exceptions/address/address_exception.dart'; import 'package:stackwallet/models/isar/models/blockchain_data/crypto_currency_address.dart'; @@ -71,6 +73,45 @@ class Address extends CryptoCurrencyAddress { "derivationPath: $derivationPath, " "otherData: $otherData, " "}"; + + String toJsonString() { + final Map result = { + "walletId": walletId, + "value": value, + "publicKey": publicKey, + "derivationIndex": derivationIndex, + "type": type.name, + "subType": subType.name, + "derivationPath": derivationPath?.value, + "otherData": otherData, + }; + return jsonEncode(result); + } + + static Address fromJsonString( + String jsonString, { + String? overrideWalletId, + }) { + final json = jsonDecode(jsonString); + final derivationPathString = json["derivationPath"] as String?; + + final DerivationPath? derivationPath = + derivationPathString == null ? null : DerivationPath(); + if (derivationPath != null) { + derivationPath.value = derivationPathString!; + } + + return Address( + walletId: overrideWalletId ?? json["walletId"] as String, + value: json["value"] as String, + publicKey: List.from(json["publicKey"] as List), + derivationIndex: json["derivationIndex"] as int, + derivationPath: derivationPath, + type: AddressType.values.byName(json["type"] as String), + subType: AddressSubType.values.byName(json["subType"] as String), + otherData: json["otherData"] as String?, + ); + } } // do not modify diff --git a/lib/models/isar/models/blockchain_data/input.dart b/lib/models/isar/models/blockchain_data/input.dart index b530da61a..c97cff73d 100644 --- a/lib/models/isar/models/blockchain_data/input.dart +++ b/lib/models/isar/models/blockchain_data/input.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:isar/isar.dart'; part 'input.g.dart'; @@ -30,4 +32,32 @@ class Input { late final int? sequence; late final String? innerRedeemScriptAsm; + + String toJsonString() { + final Map result = { + "txid": txid, + "vout": vout, + "scriptSig": scriptSig, + "scriptSigAsm": scriptSigAsm, + "witness": witness, + "isCoinbase": isCoinbase, + "sequence": sequence, + "innerRedeemScriptAsm": innerRedeemScriptAsm, + }; + return jsonEncode(result); + } + + static Input fromJsonString(String jsonString) { + final json = jsonDecode(jsonString); + return Input( + txid: json["txid"] as String, + vout: json["vout"] as int, + scriptSig: json["scriptSig"] as String?, + scriptSigAsm: json["scriptSigAsm"] as String?, + witness: json["witness"] as String?, + isCoinbase: json["isCoinbase"] as bool?, + sequence: json["sequence"] as int?, + innerRedeemScriptAsm: json["innerRedeemScriptAsm"] as String?, + ); + } } diff --git a/lib/models/isar/models/blockchain_data/output.dart b/lib/models/isar/models/blockchain_data/output.dart index 375905ad8..959fc37a2 100644 --- a/lib/models/isar/models/blockchain_data/output.dart +++ b/lib/models/isar/models/blockchain_data/output.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:isar/isar.dart'; part 'output.g.dart'; @@ -21,4 +23,26 @@ class Output { late final String scriptPubKeyAddress; late final int value; + + String toJsonString() { + final Map result = { + "scriptPubKey": scriptPubKey, + "scriptPubKeyAsm": scriptPubKeyAsm, + "scriptPubKeyType": scriptPubKeyType, + "scriptPubKeyAddress": scriptPubKeyAddress, + "value": value, + }; + return jsonEncode(result); + } + + static Output fromJsonString(String jsonString) { + final json = jsonDecode(jsonString); + return Output( + scriptPubKey: json["scriptPubKey"] as String?, + scriptPubKeyAsm: json["scriptPubKeyAsm"] as String?, + scriptPubKeyType: json["scriptPubKeyType"] as String?, + scriptPubKeyAddress: json["scriptPubKeyAddress"] as String, + value: json["value"] as int, + ); + } } diff --git a/lib/models/isar/models/blockchain_data/transaction.dart b/lib/models/isar/models/blockchain_data/transaction.dart index a3496d715..191f62b46 100644 --- a/lib/models/isar/models/blockchain_data/transaction.dart +++ b/lib/models/isar/models/blockchain_data/transaction.dart @@ -1,3 +1,4 @@ +import 'dart:convert'; import 'dart:math'; import 'package:isar/isar.dart'; @@ -133,6 +134,60 @@ class Transaction { "inputsLength: ${inputs.length}, " "outputsLength: ${outputs.length}, " "}"; + + String toJsonString() { + final Map result = { + "walletId": walletId, + "txid": txid, + "timestamp": timestamp, + "type": type.name, + "subType": subType.name, + "amount": amount, + "fee": fee, + "height": height, + "isCancelled": isCancelled, + "isLelantus": isLelantus, + "slateId": slateId, + "otherData": otherData, + "address": address.value?.toJsonString(), + "inputs": inputs.map((e) => e.toJsonString()).toList(), + "outputs": outputs.map((e) => e.toJsonString()).toList(), + }; + return jsonEncode(result); + } + + static Tuple2 fromJsonString( + String jsonString, { + String? overrideWalletId, + }) { + final json = jsonDecode(jsonString); + final transaction = Transaction( + walletId: overrideWalletId ?? json["walletId"] as String, + txid: json["txid"] as String, + timestamp: json["timestamp"] as int, + type: TransactionType.values.byName(json["type"] as String), + subType: TransactionSubType.values.byName(json["subType"] as String), + amount: json["amount"] as int, + fee: json["fee"] as int, + height: json["height"] as int?, + isCancelled: json["isCancelled"] as bool, + isLelantus: json["isLelantus"] as bool?, + slateId: json["slateId"] as String?, + otherData: json["otherData"] as String?, + inputs: List.from(json["inputs"] as List) + .map((e) => Input.fromJsonString(e)) + .toList(), + outputs: List.from(json["outputs"] as List) + .map((e) => Output.fromJsonString(e)) + .toList(), + ); + if (json["address"] == null) { + return Tuple2(transaction, null); + } else { + final address = Address.fromJsonString(json["address"] as String); + return Tuple2(transaction, address); + } + } } // Used in Isar db and stored there as int indexes so adding/removing values diff --git a/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/restore_options_view.dart b/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/restore_options_view.dart index 6b03d06fb..213bee484 100644 --- a/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/restore_options_view.dart +++ b/lib/pages/add_wallet_views/restore_wallet_view/restore_options_view/restore_options_view.dart @@ -20,10 +20,13 @@ import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/widgets/conditional_parent.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart'; import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart'; +import 'package:stackwallet/widgets/expandable.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; +import 'package:stackwallet/widgets/stack_text_field.dart'; import 'package:tuple/tuple.dart'; class RestoreOptionsView extends ConsumerStatefulWidget { @@ -49,10 +52,17 @@ class _RestoreOptionsViewState extends ConsumerState { late TextEditingController _dateController; late FocusNode textFieldFocusNode; + late final FocusNode passwordFocusNode; + late final TextEditingController passwordController; final bool _nextEnabled = true; DateTime _restoreFromDate = DateTime.fromMillisecondsSinceEpoch(0); late final Color baseColor; + bool hidePassword = true; + bool _expandedAdavnced = false; + + bool get supportsMnemonicPassphrase => + !(coin == Coin.monero || coin == Coin.wownero || coin == Coin.epicCash); @override void initState() { @@ -63,6 +73,8 @@ class _RestoreOptionsViewState extends ConsumerState { _dateController = TextEditingController(); textFieldFocusNode = FocusNode(); + passwordController = TextEditingController(); + passwordFocusNode = FocusNode(); super.initState(); } @@ -71,6 +83,8 @@ class _RestoreOptionsViewState extends ConsumerState { void dispose() { _dateController.dispose(); textFieldFocusNode.dispose(); + passwordController.dispose(); + passwordFocusNode.dispose(); super.dispose(); } @@ -132,11 +146,12 @@ class _RestoreOptionsViewState extends ConsumerState { if (mounted) { await Navigator.of(context).pushNamed( RestoreWalletView.routeName, - arguments: Tuple4( + arguments: Tuple5( walletName, coin, ref.read(mnemonicWordCountStateProvider.state).state, _restoreFromDate, + passwordController.text, ), ); } @@ -186,8 +201,6 @@ class _RestoreOptionsViewState extends ConsumerState { await Future.delayed(const Duration(milliseconds: 125)); } - final now = DateTime.now(); - final date = await showRoundedDatePicker( context: context, initialDate: DateTime.now(), @@ -441,6 +454,120 @@ class _RestoreOptionsViewState extends ConsumerState { MobileMnemonicLengthSelector( chooseMnemonicLength: chooseMnemonicLength, ), + if (supportsMnemonicPassphrase) + SizedBox( + height: isDesktop ? 24 : 16, + ), + if (supportsMnemonicPassphrase) + Expandable( + onExpandChanged: (state) { + setState(() { + _expandedAdavnced = state == ExpandableState.expanded; + }); + }, + header: Container( + color: Colors.transparent, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 8.0, + horizontal: 16, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "Advanced", + style: isDesktop + ? STextStyles.desktopTextExtraExtraSmall( + context) + .copyWith( + color: Theme.of(context) + .extension()! + .textDark3, + ) + : STextStyles.smallMed12(context), + textAlign: TextAlign.left, + ), + SvgPicture.asset( + _expandedAdavnced + ? Assets.svg.chevronUp + : Assets.svg.chevronDown, + width: 12, + height: 6, + color: Theme.of(context) + .extension()! + .textFieldActiveSearchIconRight, + ), + ], + ), + ), + ), + body: Container( + color: Colors.transparent, + child: ClipRRect( + borderRadius: BorderRadius.circular( + Constants.size.circularBorderRadius, + ), + child: TextField( + key: const Key("mnemonicPassphraseFieldKey1"), + focusNode: passwordFocusNode, + controller: passwordController, + style: isDesktop + ? STextStyles.desktopTextMedium(context).copyWith( + height: 2, + ) + : STextStyles.field(context), + obscureText: hidePassword, + enableSuggestions: false, + autocorrect: false, + decoration: standardInputDecoration( + "Recovery phrase password", + passwordFocusNode, + context, + ).copyWith( + suffixIcon: UnconstrainedBox( + child: ConditionalParent( + condition: isDesktop, + builder: (child) => SizedBox( + height: 70, + child: child, + ), + child: Row( + children: [ + SizedBox( + width: isDesktop ? 24 : 16, + ), + GestureDetector( + key: const Key( + "mnemonicPassphraseFieldShowPasswordButtonKey"), + onTap: () async { + setState(() { + hidePassword = !hidePassword; + }); + }, + child: SvgPicture.asset( + hidePassword + ? Assets.svg.eye + : Assets.svg.eyeSlash, + color: Theme.of(context) + .extension()! + .textDark3, + width: isDesktop ? 24 : 16, + height: isDesktop ? 24 : 16, + ), + ), + const SizedBox( + width: 12, + ), + ], + ), + ), + ), + ), + ), + ), + ), + ), if (!isDesktop) const Spacer( flex: 3, diff --git a/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart b/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart index 883af77e6..45df3e2fc 100644 --- a/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart +++ b/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart @@ -54,6 +54,7 @@ class RestoreWalletView extends ConsumerStatefulWidget { required this.walletName, required this.coin, required this.seedWordsLength, + required this.mnemonicPassphrase, required this.restoreFromDate, this.barcodeScanner = const BarcodeScannerWrapper(), this.clipboard = const ClipboardWrapper(), @@ -63,6 +64,7 @@ class RestoreWalletView extends ConsumerStatefulWidget { final String walletName; final Coin coin; + final String mnemonicPassphrase; final int seedWordsLength; final DateTime restoreFromDate; @@ -290,7 +292,7 @@ class _RestoreWalletViewState extends ConsumerState { // without using them await manager.recoverFromMnemonic( mnemonic: mnemonic, - mnemonicPassphrase: "", // TODO add ui for certain coins + mnemonicPassphrase: widget.mnemonicPassphrase, maxUnusedAddressGap: widget.coin == Coin.firo ? 50 : 20, maxNumberOfIndexesToCheck: 1000, height: height, diff --git a/lib/pages/exchange_view/exchange_coin_selection/exchange_currency_selection_view.dart b/lib/pages/exchange_view/exchange_coin_selection/exchange_currency_selection_view.dart index c6ba3de2d..6d1956256 100644 --- a/lib/pages/exchange_view/exchange_coin_selection/exchange_currency_selection_view.dart +++ b/lib/pages/exchange_view/exchange_coin_selection/exchange_currency_selection_view.dart @@ -26,16 +26,14 @@ import 'package:stackwallet/widgets/textfield_icon_button.dart'; class ExchangeCurrencySelectionView extends StatefulWidget { const ExchangeCurrencySelectionView({ Key? key, - required this.exchangeName, - required this.willChange, - required this.paired, + required this.willChangeTicker, + required this.pairedTicker, required this.isFixedRate, required this.willChangeIsSend, }) : super(key: key); - final String exchangeName; - final Currency? willChange; - final Currency? paired; + final String? willChangeTicker; + final String? pairedTicker; final bool isFixedRate; final bool willChangeIsSend; @@ -89,7 +87,7 @@ class _ExchangeCurrencySelectionViewState } Future> _loadCurrencies() async { - if (widget.paired == null) { + if (widget.pairedTicker == null) { return await _getCurrencies(); } @@ -109,7 +107,6 @@ class _ExchangeCurrencySelectionViewState Future _getCurrency(String ticker) { return ExchangeDataLoadingService.instance.isar.currencies .where() - .exchangeNameEqualTo(widget.exchangeName) .filter() .tickerEqualTo(ticker, caseSensitive: false) .group((q) => widget.isFixedRate @@ -127,7 +124,6 @@ class _ExchangeCurrencySelectionViewState Future> _loadAvailablePairs() { final query = ExchangeDataLoadingService.instance.isar.pairs .where() - .exchangeNameEqualTo(widget.exchangeName) .filter() .group((q) => widget.isFixedRate ? q @@ -140,8 +136,8 @@ class _ExchangeCurrencySelectionViewState .rateTypeEqualTo(SupportedRateType.estimated)) .and() .group((q) => widget.willChangeIsSend - ? q.toEqualTo(widget.paired!.ticker, caseSensitive: false) - : q.fromEqualTo(widget.paired!.ticker, caseSensitive: false)); + ? q.toEqualTo(widget.pairedTicker!, caseSensitive: false) + : q.fromEqualTo(widget.pairedTicker!, caseSensitive: false)); if (widget.willChangeIsSend) { return query.sortByFrom().findAll(); @@ -153,7 +149,6 @@ class _ExchangeCurrencySelectionViewState Future> _getCurrencies() async { return ExchangeDataLoadingService.instance.isar.currencies .where() - .exchangeNameEqualTo(widget.exchangeName) .filter() .group((q) => widget.isFixedRate ? q @@ -166,6 +161,7 @@ class _ExchangeCurrencySelectionViewState .rateTypeEqualTo(SupportedRateType.estimated)) .sortByIsStackCoin() .thenByName() + .distinctByTicker(caseSensitive: false) .findAll(); } @@ -174,7 +170,7 @@ class _ExchangeCurrencySelectionViewState return _currencies; } - if (widget.paired == null) { + if (widget.pairedTicker == null) { return _currencies .where((e) => e.name.toLowerCase().contains(text.toLowerCase()) || @@ -183,7 +179,7 @@ class _ExchangeCurrencySelectionViewState } else { return _currencies .where((e) => - e.ticker.toLowerCase() != widget.paired!.ticker.toLowerCase() && + e.ticker.toLowerCase() != widget.pairedTicker!.toLowerCase() && (e.name.toLowerCase().contains(text.toLowerCase()) || e.ticker.toLowerCase().contains(text.toLowerCase()))) .toList(growable: false); @@ -322,8 +318,7 @@ class _ExchangeCurrencySelectionViewState Flexible( child: Builder(builder: (context) { final coins = Coin.values.where((e) => - e.ticker.toLowerCase() != - widget.paired?.ticker.toLowerCase()); + e.ticker.toLowerCase() != widget.pairedTicker?.toLowerCase()); final items = filter(_searchString) .where((e) => coins diff --git a/lib/pages/exchange_view/exchange_form.dart b/lib/pages/exchange_view/exchange_form.dart index d73dd2eb5..ba40f4d0f 100644 --- a/lib/pages/exchange_view/exchange_form.dart +++ b/lib/pages/exchange_view/exchange_form.dart @@ -6,6 +6,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/svg.dart'; import 'package:isar/isar.dart'; +import 'package:stackwallet/models/exchange/aggregate_currency.dart'; import 'package:stackwallet/models/exchange/incomplete_exchange.dart'; import 'package:stackwallet/models/isar/exchange_cache/currency.dart'; import 'package:stackwallet/models/isar/exchange_cache/pair.dart'; @@ -13,7 +14,6 @@ import 'package:stackwallet/pages/exchange_view/exchange_coin_selection/exchange import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_1_view.dart'; import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_2_view.dart'; import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_provider_options.dart'; -import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart'; import 'package:stackwallet/pages/exchange_view/sub_widgets/rate_type_toggle.dart'; import 'package:stackwallet/pages_desktop_specific/desktop_exchange/exchange_steps/step_scaffold.dart'; import 'package:stackwallet/providers/providers.dart'; @@ -22,6 +22,7 @@ import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/enums/exchange_rate_type_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/utilities/util.dart'; @@ -128,8 +129,37 @@ class _ExchangeFormState extends ConsumerState { }); } + Future _getAggregateCurrency(Currency currency) async { + final rateType = ref.read(exchangeFormStateProvider).exchangeRateType; + final currencies = await ExchangeDataLoadingService.instance.isar.currencies + .filter() + .group((q) => rateType == ExchangeRateType.fixed + ? q + .rateTypeEqualTo(SupportedRateType.both) + .or() + .rateTypeEqualTo(SupportedRateType.fixed) + : q + .rateTypeEqualTo(SupportedRateType.both) + .or() + .rateTypeEqualTo(SupportedRateType.estimated)) + .and() + .tickerEqualTo( + currency.ticker, + caseSensitive: false, + ) + .findAll(); + + final items = [Tuple2(currency.exchangeName, currency)]; + + for (final currency in currencies) { + items.add(Tuple2(currency.exchangeName, currency)); + } + + return AggregateCurrency(exchangeCurrencyPairs: items); + } + void selectSendCurrency() async { - final type = (ref.read(prefsChangeNotifierProvider).exchangeRateType); + final type = (ref.read(exchangeFormStateProvider).exchangeRateType); final fromTicker = ref.read(exchangeFormStateProvider).fromTicker ?? ""; if (walletInitiated && @@ -139,17 +169,18 @@ class _ExchangeFormState extends ConsumerState { } final selectedCurrency = await _showCurrencySelectionSheet( - willChange: ref.read(exchangeFormStateProvider).sendCurrency, + willChange: ref.read(exchangeFormStateProvider).sendCurrency?.ticker, willChangeIsSend: true, - paired: ref.read(exchangeFormStateProvider).receiveCurrency, + paired: ref.read(exchangeFormStateProvider).receiveCurrency?.ticker, isFixedRate: type == ExchangeRateType.fixed, ); if (selectedCurrency != null) { await showUpdatingExchangeRate( - whileFuture: ref - .read(exchangeFormStateProvider) - .updateSendCurrency(selectedCurrency, true), + whileFuture: _getAggregateCurrency(selectedCurrency).then( + (aggregateSelected) => ref + .read(exchangeFormStateProvider) + .updateSendCurrency(aggregateSelected, true)), ); } } @@ -163,18 +194,19 @@ class _ExchangeFormState extends ConsumerState { } final selectedCurrency = await _showCurrencySelectionSheet( - willChange: ref.read(exchangeFormStateProvider).receiveCurrency, + willChange: ref.read(exchangeFormStateProvider).receiveCurrency?.ticker, willChangeIsSend: false, - paired: ref.read(exchangeFormStateProvider).sendCurrency, - isFixedRate: ref.read(prefsChangeNotifierProvider).exchangeRateType == + paired: ref.read(exchangeFormStateProvider).sendCurrency?.ticker, + isFixedRate: ref.read(exchangeFormStateProvider).exchangeRateType == ExchangeRateType.fixed, ); if (selectedCurrency != null) { await showUpdatingExchangeRate( - whileFuture: ref - .read(exchangeFormStateProvider) - .updateReceivingCurrency(selectedCurrency, true), + whileFuture: _getAggregateCurrency(selectedCurrency).then( + (aggregateSelected) => ref + .read(exchangeFormStateProvider) + .updateReceivingCurrency(aggregateSelected, true)), ); } } @@ -193,8 +225,8 @@ class _ExchangeFormState extends ConsumerState { } Future _showCurrencySelectionSheet({ - required Currency? willChange, - required Currency? paired, + required String? willChange, + required String? paired, required bool isFixedRate, required bool willChangeIsSend, }) async { @@ -241,12 +273,8 @@ class _ExchangeFormState extends ConsumerState { .extension()! .background, child: ExchangeCurrencySelectionView( - exchangeName: ref - .read(currentExchangeNameStateProvider - .state) - .state, - willChange: willChange, - paired: paired, + willChangeTicker: willChange, + pairedTicker: paired, isFixedRate: isFixedRate, willChangeIsSend: willChangeIsSend, ), @@ -263,10 +291,8 @@ class _ExchangeFormState extends ConsumerState { : await Navigator.of(context).push( MaterialPageRoute( builder: (_) => ExchangeCurrencySelectionView( - exchangeName: - ref.read(currentExchangeNameStateProvider.state).state, - willChange: willChange, - paired: paired, + willChangeTicker: willChange, + pairedTicker: paired, isFixedRate: isFixedRate, willChangeIsSend: willChangeIsSend, ), @@ -298,68 +324,69 @@ class _ExchangeFormState extends ConsumerState { ref.read(exchangeFormStateProvider).reversed = false; if (!(toTicker == "-" || fromTicker == "-")) { - final available = await ExchangeDataLoadingService.instance.isar.pairs - .where() - .exchangeNameEqualTo( - ref.read(currentExchangeNameStateProvider.state).state) - .filter() - .fromEqualTo(fromTicker) - .and() - .toEqualTo(toTicker) - .findAll(); + // final available = await ExchangeDataLoadingService.instance.isar.pairs + // .where() + // .exchangeNameEqualTo( + // ref.read(currentExchangeNameStateProvider.state).state) + // .filter() + // .fromEqualTo(fromTicker) + // .and() + // .toEqualTo(toTicker) + // .findAll(); + await ref.read(exchangeFormStateProvider).refresh(); - if (available.isNotEmpty) { - final availableCurrencies = await ExchangeDataLoadingService - .instance.isar.currencies - .where() - .exchangeNameEqualTo( - ref.read(currentExchangeNameStateProvider.state).state) - .filter() - .tickerEqualTo(fromTicker) - .or() - .tickerEqualTo(toTicker) - .findAll(); - - if (availableCurrencies.length > 1) { - final from = - availableCurrencies.firstWhere((e) => e.ticker == fromTicker); - final to = - availableCurrencies.firstWhere((e) => e.ticker == toTicker); - - final newFromAmount = Decimal.tryParse(_sendController.text); - ref.read(exchangeFormStateProvider).receiveAmount = newFromAmount; - if (newFromAmount == null) { - _receiveController.text = ""; - } - - await ref - .read(exchangeFormStateProvider) - .updateReceivingCurrency(to, false); - await ref - .read(exchangeFormStateProvider) - .updateSendCurrency(from, true); - - _receiveController.text = - ref.read(exchangeFormStateProvider).toAmountString.isEmpty - ? "-" - : ref.read(exchangeFormStateProvider).toAmountString; - if (mounted) { - Navigator.of(context, rootNavigator: isDesktop).pop(); - } - return; - } - } + // if (available.isNotEmpty) { + // final availableCurrencies = await ExchangeDataLoadingService + // .instance.isar.currencies + // .where() + // .exchangeNameEqualTo( + // ref.read(currentExchangeNameStateProvider.state).state) + // .filter() + // .tickerEqualTo(fromTicker) + // .or() + // .tickerEqualTo(toTicker) + // .findAll(); + // + // if (availableCurrencies.length > 1) { + // final from = + // availableCurrencies.firstWhere((e) => e.ticker == fromTicker); + // final to = + // availableCurrencies.firstWhere((e) => e.ticker == toTicker); + // + // final newFromAmount = Decimal.tryParse(_sendController.text); + // ref.read(exchangeFormStateProvider).receiveAmount = newFromAmount; + // if (newFromAmount == null) { + // _receiveController.text = ""; + // } + // + // await ref + // .read(exchangeFormStateProvider) + // .updateReceivingCurrency(to, false); + // await ref + // .read(exchangeFormStateProvider) + // .updateSendCurrency(from, true); + // + // _receiveController.text = + // ref.read(exchangeFormStateProvider).toAmountString.isEmpty + // ? "-" + // : ref.read(exchangeFormStateProvider).toAmountString; + // if (mounted) { + // Navigator.of(context, rootNavigator: isDesktop).pop(); + // } + // return; + // } + // } } } void onExchangePressed() async { - final rateType = ref.read(prefsChangeNotifierProvider).exchangeRateType; + final rateType = ref.read(exchangeFormStateProvider).exchangeRateType; final fromTicker = ref.read(exchangeFormStateProvider).fromTicker ?? ""; final toTicker = ref.read(exchangeFormStateProvider).toTicker ?? ""; final sendAmount = ref.read(exchangeFormStateProvider).sendAmount!; final estimate = ref.read(exchangeFormStateProvider).estimate!; - final exchangeName = ref.read(currentExchangeNameStateProvider.state).state; + final exchangeName = ref.read(exchangeFormStateProvider).exchange.name; String rate; @@ -531,6 +558,7 @@ class _ExchangeFormState extends ConsumerState { rateType: rateType, rateId: estimate.rateId, reversed: estimate.reversed, + walletInitiated: walletInitiated, ); if (mounted) { @@ -644,7 +672,7 @@ class _ExchangeFormState extends ConsumerState { debugPrint("BUILD: $runtimeType"); final rateType = ref.watch( - prefsChangeNotifierProvider.select((value) => value.exchangeRateType)); + exchangeFormStateProvider.select((value) => value.exchangeRateType)); final isEstimated = rateType == ExchangeRateType.estimated; @@ -708,10 +736,8 @@ class _ExchangeFormState extends ConsumerState { onChanged: sendFieldOnChanged, onButtonTap: selectSendCurrency, isWalletCoin: isWalletCoin(coin, true), - image: ref.watch(exchangeFormStateProvider - .select((value) => value.sendCurrency?.image)), - ticker: ref.watch( - exchangeFormStateProvider.select((value) => value.fromTicker)), + currency: ref.watch( + exchangeFormStateProvider.select((value) => value.sendCurrency)), ), SizedBox( height: isDesktop ? 10 : 4, @@ -791,7 +817,7 @@ class _ExchangeFormState extends ConsumerState { background: Theme.of(context).extension()!.textFieldDefaultBG, onTap: () { - if (!(ref.read(prefsChangeNotifierProvider).exchangeRateType == + if (!(ref.read(exchangeFormStateProvider).exchangeRateType == ExchangeRateType.estimated) && _receiveController.text == "-") { _receiveController.text = ""; @@ -800,13 +826,11 @@ class _ExchangeFormState extends ConsumerState { onChanged: receiveFieldOnChanged, onButtonTap: selectReceiveCurrency, isWalletCoin: isWalletCoin(coin, true), - image: ref.watch(exchangeFormStateProvider - .select((value) => value.receiveCurrency?.image)) ?? - "", - ticker: ref.watch( - exchangeFormStateProvider.select((value) => value.toTicker)), + currency: ref.watch(exchangeFormStateProvider + .select((value) => value.receiveCurrency)), readOnly: (rateType) == ExchangeRateType.estimated && - ref.watch(exchangeProvider).name == + ref.watch(exchangeFormStateProvider + .select((value) => value.exchange.name)) == ChangeNowExchange.exchangeName, ), if (ref @@ -840,10 +864,6 @@ class _ExchangeFormState extends ConsumerState { if (ref.watch(exchangeFormStateProvider).sendAmount != null && ref.watch(exchangeFormStateProvider).sendAmount != Decimal.zero) ExchangeProviderOptions( - from: ref.watch(exchangeFormStateProvider).fromTicker, - to: ref.watch(exchangeFormStateProvider).toTicker, - fromAmount: ref.watch(exchangeFormStateProvider).sendAmount, - toAmount: ref.watch(exchangeFormStateProvider).receiveAmount, fixedRate: rateType == ExchangeRateType.fixed, reversed: ref.watch( exchangeFormStateProvider.select((value) => value.reversed)), diff --git a/lib/pages/exchange_view/exchange_step_views/step_1_view.dart b/lib/pages/exchange_view/exchange_step_views/step_1_view.dart index 8733be77c..c57e0acad 100644 --- a/lib/pages/exchange_view/exchange_step_views/step_1_view.dart +++ b/lib/pages/exchange_view/exchange_step_views/step_1_view.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; import 'package:stackwallet/models/exchange/incomplete_exchange.dart'; import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_2_view.dart'; -import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart'; import 'package:stackwallet/pages/exchange_view/sub_widgets/step_row.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; +import 'package:stackwallet/utilities/enums/exchange_rate_type_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/background.dart'; diff --git a/lib/pages/exchange_view/exchange_step_views/step_2_view.dart b/lib/pages/exchange_view/exchange_step_views/step_2_view.dart index af2567d9a..18950b851 100644 --- a/lib/pages/exchange_view/exchange_step_views/step_2_view.dart +++ b/lib/pages/exchange_view/exchange_step_views/step_2_view.dart @@ -124,9 +124,9 @@ class _Step2ViewState extends ConsumerState { @override Widget build(BuildContext context) { - final supportsRefund = - ref.watch(currentExchangeNameStateProvider.state).state != - MajesticBankExchange.exchangeName; + final supportsRefund = ref.watch( + exchangeFormStateProvider.select((value) => value.exchange.name)) != + MajesticBankExchange.exchangeName; return Background( child: Scaffold( diff --git a/lib/pages/exchange_view/exchange_step_views/step_3_view.dart b/lib/pages/exchange_view/exchange_step_views/step_3_view.dart index 8b08f7961..0c5eaa8c9 100644 --- a/lib/pages/exchange_view/exchange_step_views/step_3_view.dart +++ b/lib/pages/exchange_view/exchange_step_views/step_3_view.dart @@ -5,16 +5,15 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/models/exchange/incomplete_exchange.dart'; import 'package:stackwallet/models/exchange/response_objects/trade.dart'; import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_4_view.dart'; -import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart'; import 'package:stackwallet/pages/exchange_view/sub_widgets/step_row.dart'; -import 'package:stackwallet/providers/exchange/current_exchange_name_state_provider.dart'; -import 'package:stackwallet/providers/exchange/exchange_provider.dart'; import 'package:stackwallet/providers/global/trades_service_provider.dart'; +import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/services/exchange/exchange_response.dart'; import 'package:stackwallet/services/exchange/majestic_bank/majestic_bank_exchange.dart'; import 'package:stackwallet/services/notifications_api.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; +import 'package:stackwallet/utilities/enums/exchange_rate_type_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/background.dart'; @@ -53,9 +52,9 @@ class _Step3ViewState extends ConsumerState { @override Widget build(BuildContext context) { - final supportsRefund = - ref.watch(currentExchangeNameStateProvider.state).state != - MajesticBankExchange.exchangeName; + final supportsRefund = ref.watch( + exchangeFormStateProvider.select((value) => value.exchange.name)) != + MajesticBankExchange.exchangeName; return Background( child: Scaffold( @@ -255,7 +254,8 @@ class _Step3ViewState extends ConsumerState { final ExchangeResponse response = await ref - .read(exchangeProvider) + .read(exchangeFormStateProvider) + .exchange .createTrade( from: model.sendTicker, to: model.receiveTicker, diff --git a/lib/pages/exchange_view/exchange_step_views/step_4_view.dart b/lib/pages/exchange_view/exchange_step_views/step_4_view.dart index d5f1339d0..2507ac2d4 100644 --- a/lib/pages/exchange_view/exchange_step_views/step_4_view.dart +++ b/lib/pages/exchange_view/exchange_step_views/step_4_view.dart @@ -12,6 +12,7 @@ import 'package:stackwallet/pages/exchange_view/send_from_view.dart'; import 'package:stackwallet/pages/exchange_view/sub_widgets/step_row.dart'; import 'package:stackwallet/pages/home_view/home_view.dart'; import 'package:stackwallet/pages/send_view/sub_widgets/building_transaction_dialog.dart'; +import 'package:stackwallet/pages/wallet_view/wallet_view.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/route_generator.dart'; import 'package:stackwallet/utilities/assets.dart'; @@ -65,8 +66,10 @@ class _Step4ViewState extends ConsumerState { } Future _updateStatus() async { - final statusResponse = - await ref.read(exchangeProvider).updateTrade(model.trade!); + final statusResponse = await ref + .read(exchangeFormStateProvider) + .exchange + .updateTrade(model.trade!); String status = "Waiting"; if (statusResponse.value != null) { status = statusResponse.value!.status; @@ -103,551 +106,593 @@ class _Step4ViewState extends ConsumerState { super.dispose(); } + Future _close() async { + if (FocusScope.of(context).hasFocus) { + FocusScope.of(context).unfocus(); + await Future.delayed(const Duration(milliseconds: 75)); + } + if (mounted) { + Navigator.of(context).popUntil( + ModalRoute.withName( + model.walletInitiated ? WalletView.routeName : HomeView.routeName, + ), + ); + } + } + @override Widget build(BuildContext context) { final bool isWalletCoin = _isWalletCoinAndHasWallet(model.trade!.payInCurrency, ref); - return Background( - child: Scaffold( - backgroundColor: Theme.of(context).extension()!.background, - appBar: AppBar( - leading: AppBarBackButton( - onPressed: () async { - if (FocusScope.of(context).hasFocus) { - FocusScope.of(context).unfocus(); - await Future.delayed(const Duration(milliseconds: 75)); - } - if (mounted) { - Navigator.of(context).pop(); - } - }, + return WillPopScope( + onWillPop: () async { + await _close(); + return false; + }, + child: Background( + child: Scaffold( + backgroundColor: + Theme.of(context).extension()!.background, + appBar: AppBar( + leading: Padding( + padding: const EdgeInsets.all(10), + child: AppBarIconButton( + size: 32, + color: Theme.of(context).extension()!.background, + shadows: const [], + icon: SvgPicture.asset( + Assets.svg.x, + width: 24, + height: 24, + color: Theme.of(context) + .extension()! + .topNavIconPrimary, + ), + onPressed: _close, + ), + ), + title: Text( + "Exchange", + style: STextStyles.navBarTitle(context), + ), ), - title: Text( - "Exchange", - style: STextStyles.navBarTitle(context), - ), - ), - body: LayoutBuilder( - builder: (context, constraints) { - final width = MediaQuery.of(context).size.width - 32; - return Padding( - padding: const EdgeInsets.all(12), - child: SingleChildScrollView( - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: constraints.maxHeight - 24, - ), - child: IntrinsicHeight( - child: Padding( - padding: const EdgeInsets.all(4), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - StepRow( - count: 4, - current: 3, - width: width, - ), - const SizedBox( - height: 14, - ), - Text( - "Send ${model.sendTicker.toUpperCase()} to the address below", - style: STextStyles.pageTitleH1(context), - ), - const SizedBox( - height: 8, - ), - Text( - "Send ${model.sendTicker.toUpperCase()} to the address below. Once it is received, ${model.trade!.exchangeName} will send the ${model.receiveTicker.toUpperCase()} to the recipient address you provided. You can find this trade details and check its status in the list of trades.", - style: STextStyles.itemSubtitle(context), - ), - const SizedBox( - height: 12, - ), - RoundedContainer( - color: Theme.of(context) - .extension()! - .warningBackground, - child: RichText( - text: TextSpan( - text: - "You must send at least ${model.sendAmount.toString()} ${model.sendTicker}. ", - style: STextStyles.label700(context).copyWith( - color: Theme.of(context) - .extension()! - .warningForeground, + body: LayoutBuilder( + builder: (context, constraints) { + final width = MediaQuery.of(context).size.width - 32; + return Padding( + padding: const EdgeInsets.all(12), + child: SingleChildScrollView( + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: constraints.maxHeight - 24, + ), + child: IntrinsicHeight( + child: Padding( + padding: const EdgeInsets.all(4), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + StepRow( + count: 4, + current: 3, + width: width, + ), + const SizedBox( + height: 14, + ), + Text( + "Send ${model.sendTicker.toUpperCase()} to the address below", + style: STextStyles.pageTitleH1(context), + ), + const SizedBox( + height: 8, + ), + Text( + "Send ${model.sendTicker.toUpperCase()} to the address below. Once it is received, ${model.trade!.exchangeName} will send the ${model.receiveTicker.toUpperCase()} to the recipient address you provided. You can find this trade details and check its status in the list of trades.", + style: STextStyles.itemSubtitle(context), + ), + const SizedBox( + height: 12, + ), + RoundedContainer( + color: Theme.of(context) + .extension()! + .warningBackground, + child: RichText( + text: TextSpan( + text: + "You must send at least ${model.sendAmount.toString()} ${model.sendTicker}. ", + style: STextStyles.label700(context).copyWith( + color: Theme.of(context) + .extension()! + .warningForeground, + ), + children: [ + TextSpan( + text: + "If you send less than ${model.sendAmount.toString()} ${model.sendTicker}, your transaction may not be converted and it may not be refunded.", + style: + STextStyles.label(context).copyWith( + color: Theme.of(context) + .extension()! + .warningForeground, + ), + ), + ], ), + ), + ), + const SizedBox( + height: 8, + ), + RoundedWhiteContainer( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - TextSpan( - text: - "If you send less than ${model.sendAmount.toString()} ${model.sendTicker}, your transaction may not be converted and it may not be refunded.", - style: STextStyles.label(context).copyWith( + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text( + "Amount", + style: + STextStyles.itemSubtitle(context), + ), + GestureDetector( + onTap: () async { + final data = ClipboardData( + text: + model.sendAmount.toString()); + await clipboard.setData(data); + unawaited(showFloatingFlushBar( + type: FlushBarType.info, + message: "Copied to clipboard", + context: context, + )); + }, + child: Row( + children: [ + SvgPicture.asset( + Assets.svg.copy, + color: Theme.of(context) + .extension()! + .infoItemIcons, + width: 10, + ), + const SizedBox( + width: 4, + ), + Text( + "Copy", + style: STextStyles.link2(context), + ), + ], + ), + ), + ], + ), + const SizedBox( + height: 4, + ), + Text( + "${model.sendAmount.toString()} ${model.sendTicker.toUpperCase()}", + style: STextStyles.itemSubtitle12(context), + ), + ], + ), + ), + const SizedBox( + height: 8, + ), + RoundedWhiteContainer( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text( + "Send ${model.sendTicker.toUpperCase()} to this address", + style: + STextStyles.itemSubtitle(context), + ), + GestureDetector( + onTap: () async { + final data = ClipboardData( + text: model.trade!.payInAddress); + await clipboard.setData(data); + unawaited(showFloatingFlushBar( + type: FlushBarType.info, + message: "Copied to clipboard", + context: context, + )); + }, + child: Row( + children: [ + SvgPicture.asset( + Assets.svg.copy, + color: Theme.of(context) + .extension()! + .infoItemIcons, + width: 10, + ), + const SizedBox( + width: 4, + ), + Text( + "Copy", + style: STextStyles.link2(context), + ), + ], + ), + ), + ], + ), + const SizedBox( + height: 4, + ), + Text( + model.trade!.payInAddress, + style: STextStyles.itemSubtitle12(context), + ), + ], + ), + ), + const SizedBox( + height: 6, + ), + RoundedWhiteContainer( + child: Row( + children: [ + Text( + "Trade ID", + style: STextStyles.itemSubtitle(context), + ), + const Spacer(), + Row( + children: [ + Text( + model.trade!.tradeId, + style: + STextStyles.itemSubtitle12(context), + ), + const SizedBox( + width: 10, + ), + GestureDetector( + onTap: () async { + final data = ClipboardData( + text: model.trade!.tradeId); + await clipboard.setData(data); + unawaited(showFloatingFlushBar( + type: FlushBarType.info, + message: "Copied to clipboard", + context: context, + )); + }, + child: SvgPicture.asset( + Assets.svg.copy, + color: Theme.of(context) + .extension()! + .infoItemIcons, + width: 12, + ), + ) + ], + ) + ], + ), + ), + const SizedBox( + height: 6, + ), + RoundedWhiteContainer( + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text( + "Status", + style: STextStyles.itemSubtitle(context), + ), + Text( + _statusString, + style: STextStyles.itemSubtitle(context) + .copyWith( color: Theme.of(context) .extension()! - .warningForeground, + .colorForStatus(_statusString), ), ), ], ), ), - ), - const SizedBox( - height: 8, - ), - RoundedWhiteContainer( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Text( - "Amount", - style: STextStyles.itemSubtitle(context), - ), - GestureDetector( - onTap: () async { - final data = ClipboardData( - text: model.sendAmount.toString()); - await clipboard.setData(data); - unawaited(showFloatingFlushBar( - type: FlushBarType.info, - message: "Copied to clipboard", - context: context, - )); - }, - child: Row( - children: [ - SvgPicture.asset( - Assets.svg.copy, - color: Theme.of(context) - .extension()! - .infoItemIcons, - width: 10, - ), - const SizedBox( - width: 4, - ), - Text( - "Copy", - style: STextStyles.link2(context), - ), - ], - ), - ), - ], - ), - const SizedBox( - height: 4, - ), - Text( - "${model.sendAmount.toString()} ${model.sendTicker.toUpperCase()}", - style: STextStyles.itemSubtitle12(context), - ), - ], - ), - ), - const SizedBox( - height: 8, - ), - RoundedWhiteContainer( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Text( - "Send ${model.sendTicker.toUpperCase()} to this address", - style: STextStyles.itemSubtitle(context), - ), - GestureDetector( - onTap: () async { - final data = ClipboardData( - text: model.trade!.payInAddress); - await clipboard.setData(data); - unawaited(showFloatingFlushBar( - type: FlushBarType.info, - message: "Copied to clipboard", - context: context, - )); - }, - child: Row( - children: [ - SvgPicture.asset( - Assets.svg.copy, - color: Theme.of(context) - .extension()! - .infoItemIcons, - width: 10, - ), - const SizedBox( - width: 4, - ), - Text( - "Copy", - style: STextStyles.link2(context), - ), - ], - ), - ), - ], - ), - const SizedBox( - height: 4, - ), - Text( - model.trade!.payInAddress, - style: STextStyles.itemSubtitle12(context), - ), - ], - ), - ), - const SizedBox( - height: 6, - ), - RoundedWhiteContainer( - child: Row( - children: [ - Text( - "Trade ID", - style: STextStyles.itemSubtitle(context), - ), - const Spacer(), - Row( - children: [ - Text( - model.trade!.tradeId, - style: - STextStyles.itemSubtitle12(context), - ), - const SizedBox( - width: 10, - ), - GestureDetector( - onTap: () async { - final data = ClipboardData( - text: model.trade!.tradeId); - await clipboard.setData(data); - unawaited(showFloatingFlushBar( - type: FlushBarType.info, - message: "Copied to clipboard", - context: context, - )); - }, - child: SvgPicture.asset( - Assets.svg.copy, - color: Theme.of(context) - .extension()! - .infoItemIcons, - width: 12, - ), - ) - ], - ) - ], - ), - ), - const SizedBox( - height: 6, - ), - RoundedWhiteContainer( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - "Status", - style: STextStyles.itemSubtitle(context), - ), - Text( - _statusString, - style: STextStyles.itemSubtitle(context) - .copyWith( - color: Theme.of(context) - .extension()! - .colorForStatus(_statusString), - ), - ), - ], - ), - ), - const Spacer(), - const SizedBox( - height: 12, - ), - TextButton( - onPressed: () { - showDialog( - context: context, - barrierDismissible: true, - builder: (_) { - return StackDialogBase( - child: Column( - children: [ - const SizedBox( - height: 8, - ), - Center( - child: Text( - "Send ${model.sendTicker} to this address", - style: STextStyles.pageTitleH2( - context), - ), - ), - const SizedBox( - height: 24, - ), - Center( - child: QrImage( - // TODO: grab coin uri scheme from somewhere - // data: "${coin.uriScheme}:$receivingAddress", - data: model.trade!.payInAddress, - size: MediaQuery.of(context) - .size - .width / - 2, - foregroundColor: Theme.of(context) - .extension()! - .accentColorDark, - ), - ), - const SizedBox( - height: 24, - ), - Row( - children: [ - const Spacer(), - Expanded( - child: TextButton( - onPressed: () => - Navigator.of(context).pop(), - style: Theme.of(context) - .extension()! - .getSecondaryEnabledButtonStyle( - context), - child: Text( - "Cancel", - style: STextStyles.button( - context) - .copyWith( - color: Theme.of(context) - .extension< - StackColors>()! - .buttonTextSecondary, - ), - ), - ), - ), - ], - ) - ], - ), - ); - }, - ); - }, - style: Theme.of(context) - .extension()! - .getPrimaryEnabledButtonStyle(context), - child: Text( - "Show QR Code", - style: STextStyles.button(context), - ), - ), - if (isWalletCoin) + const Spacer(), const SizedBox( height: 12, ), - if (isWalletCoin) - Builder( - builder: (context) { - String buttonTitle = "Send from Stack Wallet"; - - final tuple = ref - .read(exchangeSendFromWalletIdStateProvider - .state) - .state; - if (tuple != null && - model.sendTicker.toLowerCase() == - tuple.item2.ticker.toLowerCase()) { - final walletName = ref - .read(walletsChangeNotifierProvider) - .getManager(tuple.item1) - .walletName; - buttonTitle = "Send from $walletName"; - } - - return TextButton( - onPressed: tuple != null && - model.sendTicker.toLowerCase() == - tuple.item2.ticker.toLowerCase() - ? () async { - final manager = ref - .read( - walletsChangeNotifierProvider) - .getManager(tuple.item1); - - final amount = - Format.decimalAmountToSatoshis( - model.sendAmount, - manager.coin); - final address = - model.trade!.payInAddress; - - try { - bool wasCancelled = false; - - unawaited(showDialog( - context: context, - useSafeArea: false, - barrierDismissible: false, - builder: (context) { - return BuildingTransactionDialog( - onCancel: () { - wasCancelled = true; - - Navigator.of(context).pop(); - }, - ); - }, - )); - - final txData = - await manager.prepareSend( - address: address, - satoshiAmount: amount, - args: { - "feeRate": FeeRateType.average, - // ref.read(feeRateTypeStateProvider) - }, - ); - - if (!wasCancelled) { - // pop building dialog - - if (mounted) { - Navigator.of(context).pop(); - } - - txData["note"] = - "${model.trade!.payInCurrency.toUpperCase()}/${model.trade!.payOutCurrency.toUpperCase()} exchange"; - txData["address"] = address; - - if (mounted) { - unawaited( - Navigator.of(context).push( - RouteGenerator.getRoute( - shouldUseMaterialRoute: - RouteGenerator - .useMaterialPageRoute, - builder: (_) => - ConfirmChangeNowSendView( - transactionInfo: txData, - walletId: tuple.item1, - routeOnSuccessName: - HomeView.routeName, - trade: model.trade!, - ), - settings: - const RouteSettings( - name: - ConfirmChangeNowSendView - .routeName, + TextButton( + onPressed: () { + showDialog( + context: context, + barrierDismissible: true, + builder: (_) { + return StackDialogBase( + child: Column( + children: [ + const SizedBox( + height: 8, + ), + Center( + child: Text( + "Send ${model.sendTicker} to this address", + style: STextStyles.pageTitleH2( + context), + ), + ), + const SizedBox( + height: 24, + ), + Center( + child: QrImage( + // TODO: grab coin uri scheme from somewhere + // data: "${coin.uriScheme}:$receivingAddress", + data: model.trade!.payInAddress, + size: MediaQuery.of(context) + .size + .width / + 2, + foregroundColor: Theme.of(context) + .extension()! + .accentColorDark, + ), + ), + const SizedBox( + height: 24, + ), + Row( + children: [ + const Spacer(), + Expanded( + child: TextButton( + onPressed: () => + Navigator.of(context) + .pop(), + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonStyle( + context), + child: Text( + "Cancel", + style: STextStyles.button( + context) + .copyWith( + color: Theme.of(context) + .extension< + StackColors>()! + .buttonTextSecondary, ), ), - )); - } - } - } catch (e) { - // if (mounted) { - // pop building dialog - Navigator.of(context).pop(); + ), + ), + ], + ) + ], + ), + ); + }, + ); + }, + style: Theme.of(context) + .extension()! + .getPrimaryEnabledButtonStyle(context), + child: Text( + "Show QR Code", + style: STextStyles.button(context), + ), + ), + if (isWalletCoin) + const SizedBox( + height: 12, + ), + if (isWalletCoin) + Builder( + builder: (context) { + String buttonTitle = "Send from Stack Wallet"; + + final tuple = ref + .read( + exchangeSendFromWalletIdStateProvider + .state) + .state; + if (tuple != null && + model.sendTicker.toLowerCase() == + tuple.item2.ticker.toLowerCase()) { + final walletName = ref + .read(walletsChangeNotifierProvider) + .getManager(tuple.item1) + .walletName; + buttonTitle = "Send from $walletName"; + } + + return TextButton( + onPressed: tuple != null && + model.sendTicker.toLowerCase() == + tuple.item2.ticker.toLowerCase() + ? () async { + final manager = ref + .read( + walletsChangeNotifierProvider) + .getManager(tuple.item1); + + final amount = + Format.decimalAmountToSatoshis( + model.sendAmount, + manager.coin); + final address = + model.trade!.payInAddress; + + try { + bool wasCancelled = false; + + unawaited(showDialog( + context: context, + useSafeArea: false, + barrierDismissible: false, + builder: (context) { + return BuildingTransactionDialog( + onCancel: () { + wasCancelled = true; - unawaited(showDialog( - context: context, - useSafeArea: false, - barrierDismissible: true, - builder: (context) { - return StackDialog( - title: "Transaction failed", - message: e.toString(), - rightButton: TextButton( - style: Theme.of(context) - .extension< - StackColors>()! - .getSecondaryEnabledButtonStyle( - context), - child: Text( - "Ok", - style: STextStyles.button( - context) - .copyWith( - color: Theme.of(context) - .extension< - StackColors>()! - .buttonTextSecondary, - ), - ), - onPressed: () { Navigator.of(context) .pop(); }, - ), - ); - }, - )); - // } + ); + }, + )); + + final txData = + await manager.prepareSend( + address: address, + satoshiAmount: amount, + args: { + "feeRate": + FeeRateType.average, + // ref.read(feeRateTypeStateProvider) + }, + ); + + if (!wasCancelled) { + // pop building dialog + + if (mounted) { + Navigator.of(context).pop(); + } + + txData["note"] = + "${model.trade!.payInCurrency.toUpperCase()}/${model.trade!.payOutCurrency.toUpperCase()} exchange"; + txData["address"] = address; + + if (mounted) { + unawaited( + Navigator.of(context) + .push( + RouteGenerator.getRoute( + shouldUseMaterialRoute: + RouteGenerator + .useMaterialPageRoute, + builder: (_) => + ConfirmChangeNowSendView( + transactionInfo: txData, + walletId: tuple.item1, + routeOnSuccessName: + HomeView.routeName, + trade: model.trade!, + ), + settings: + const RouteSettings( + name: + ConfirmChangeNowSendView + .routeName, + ), + ), + )); + } + } + } catch (e) { + // if (mounted) { + // pop building dialog + Navigator.of(context).pop(); + + unawaited(showDialog( + context: context, + useSafeArea: false, + barrierDismissible: true, + builder: (context) { + return StackDialog( + title: "Transaction failed", + message: e.toString(), + rightButton: TextButton( + style: Theme.of(context) + .extension< + StackColors>()! + .getSecondaryEnabledButtonStyle( + context), + child: Text( + "Ok", + style: + STextStyles.button( + context) + .copyWith( + color: Theme.of( + context) + .extension< + StackColors>()! + .buttonTextSecondary, + ), + ), + onPressed: () { + Navigator.of(context) + .pop(); + }, + ), + ); + }, + )); + // } + } } - } - : () { - Navigator.of(context).push( - RouteGenerator.getRoute( - shouldUseMaterialRoute: - RouteGenerator - .useMaterialPageRoute, - builder: (BuildContext context) { - return SendFromView( - coin: - coinFromTickerCaseInsensitive( - model.trade! - .payInCurrency), - amount: model.sendAmount, - address: - model.trade!.payInAddress, - trade: model.trade!, - ); - }, - settings: const RouteSettings( - name: SendFromView.routeName, + : () { + Navigator.of(context).push( + RouteGenerator.getRoute( + shouldUseMaterialRoute: + RouteGenerator + .useMaterialPageRoute, + builder: + (BuildContext context) { + return SendFromView( + coin: + coinFromTickerCaseInsensitive( + model.trade! + .payInCurrency), + amount: model.sendAmount, + address: model + .trade!.payInAddress, + trade: model.trade!, + ); + }, + settings: const RouteSettings( + name: SendFromView.routeName, + ), ), - ), - ); - }, - style: Theme.of(context) - .extension()! - .getSecondaryEnabledButtonStyle(context), - child: Text( - buttonTitle, - style: STextStyles.button(context).copyWith( - color: Theme.of(context) - .extension()! - .buttonTextSecondary, + ); + }, + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonStyle( + context), + child: Text( + buttonTitle, + style: + STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension()! + .buttonTextSecondary, + ), ), - ), - ); - }, - ), - ], + ); + }, + ), + ], + ), ), ), ), ), - ), - ); - }, + ); + }, + ), ), ), ); diff --git a/lib/pages/exchange_view/exchange_view.dart b/lib/pages/exchange_view/exchange_view.dart index f429b2c7b..054ced189 100644 --- a/lib/pages/exchange_view/exchange_view.dart +++ b/lib/pages/exchange_view/exchange_view.dart @@ -8,9 +8,12 @@ import 'package:stackwallet/pages/exchange_view/exchange_form.dart'; import 'package:stackwallet/pages/exchange_view/trade_details_view.dart'; import 'package:stackwallet/providers/global/trades_service_provider.dart'; import 'package:stackwallet/providers/providers.dart'; +import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; +import 'package:stackwallet/widgets/conditional_parent.dart'; +import 'package:stackwallet/widgets/custom_loading_overlay.dart'; import 'package:stackwallet/widgets/trade_card.dart'; import 'package:tuple/tuple.dart'; @@ -24,8 +27,38 @@ class ExchangeView extends ConsumerStatefulWidget { } class _ExchangeViewState extends ConsumerState { + bool _initialCachePopulationUnderway = false; + @override void initState() { + if (!ref.read(prefsChangeNotifierProvider).externalCalls) { + if (ExchangeDataLoadingService.currentCacheVersion < + ExchangeDataLoadingService.cacheVersion) { + _initialCachePopulationUnderway = true; + ExchangeDataLoadingService.instance.onLoadingComplete = () { + WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + setState(() { + _initialCachePopulationUnderway = false; + }); + }); + }; + } + ExchangeDataLoadingService.instance + .init() + .then((_) => ExchangeDataLoadingService.instance.loadAll()); + } else if (ExchangeDataLoadingService.instance.isLoading && + ExchangeDataLoadingService.currentCacheVersion < + ExchangeDataLoadingService.cacheVersion) { + _initialCachePopulationUnderway = true; + ExchangeDataLoadingService.instance.onLoadingComplete = () { + WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + setState(() { + _initialCachePopulationUnderway = false; + }); + }); + }; + } + super.initState(); } @@ -38,154 +71,176 @@ class _ExchangeViewState extends ConsumerState { Widget build(BuildContext context) { debugPrint("BUILD: $runtimeType"); - return SafeArea( - child: NestedScrollView( - floatHeaderSlivers: true, - headerSliverBuilder: (context, innerBoxIsScrolled) { - return [ - SliverOverlapAbsorber( - handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), - sliver: const SliverToBoxAdapter( - child: Padding( - padding: EdgeInsets.only( - left: 16, - right: 16, - top: 16, - ), - child: ExchangeForm(), - ), + return ConditionalParent( + condition: _initialCachePopulationUnderway, + builder: (child) { + return Stack( + children: [ + child, + Material( + color: Theme.of(context) + .extension()! + .overlay + .withOpacity(0.6), + child: const CustomLoadingOverlay( + message: "Updating exchange data", + subMessage: "This could take a few minutes", + eventBus: null, ), ) - ]; - }, - body: Builder( - builder: (buildContext) { - final trades = ref - .watch(tradesServiceProvider.select((value) => value.trades)); - final tradeCount = trades.length; - final hasHistory = tradeCount > 0; - - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 12), - child: CustomScrollView( - slivers: [ - SliverOverlapInjector( - handle: NestedScrollView.sliverOverlapAbsorberHandleFor( - buildContext, + ], + ); + }, + child: SafeArea( + child: NestedScrollView( + floatHeaderSlivers: true, + headerSliverBuilder: (context, innerBoxIsScrolled) { + return [ + SliverOverlapAbsorber( + handle: + NestedScrollView.sliverOverlapAbsorberHandleFor(context), + sliver: const SliverToBoxAdapter( + child: Padding( + padding: EdgeInsets.only( + left: 16, + right: 16, + top: 16, ), + child: ExchangeForm(), ), - SliverToBoxAdapter( - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 4), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - const SizedBox( - height: 12, - ), - Text( - "Trades", - style: STextStyles.itemSubtitle(context).copyWith( - color: Theme.of(context) - .extension()! - .textDark3, - ), - ), - const SizedBox( - height: 12, - ), - ], + ), + ) + ]; + }, + body: Builder( + builder: (buildContext) { + final trades = ref + .watch(tradesServiceProvider.select((value) => value.trades)); + final tradeCount = trades.length; + final hasHistory = tradeCount > 0; + + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: CustomScrollView( + slivers: [ + SliverOverlapInjector( + handle: NestedScrollView.sliverOverlapAbsorberHandleFor( + buildContext, ), ), - ), - if (hasHistory) - SliverList( - delegate: SliverChildBuilderDelegate((context, index) { - return Padding( - padding: const EdgeInsets.all(4), - child: TradeCard( - key: Key("tradeCard_${trades[index].uuid}"), - trade: trades[index], - onTap: () async { - final String tradeId = trades[index].tradeId; - - final lookup = ref - .read(tradeSentFromStackLookupProvider) - .all; - - //todo: check if print needed - // debugPrint("ALL: $lookup"); - - final String? txid = ref - .read(tradeSentFromStackLookupProvider) - .getTxidForTradeId(tradeId); - final List? walletIds = ref - .read(tradeSentFromStackLookupProvider) - .getWalletIdsForTradeId(tradeId); - - if (txid != null && - walletIds != null && - walletIds.isNotEmpty) { - final manager = ref - .read(walletsChangeNotifierProvider) - .getManager(walletIds.first); - - //todo: check if print needed - // debugPrint("name: ${manager.walletName}"); - - final tx = await MainDB.instance - .getTransactions(walletIds.first) - .filter() - .txidEqualTo(txid) - .findFirst(); - - if (mounted) { - unawaited(Navigator.of(context).pushNamed( - TradeDetailsView.routeName, - arguments: Tuple4(tradeId, tx, - walletIds.first, manager.walletName), - )); - } - } else { - unawaited(Navigator.of(context).pushNamed( - TradeDetailsView.routeName, - arguments: Tuple4( - tradeId, null, walletIds?.first, null), - )); - } - }, - ), - ); - }, childCount: tradeCount), - ), - if (!hasHistory) SliverToBoxAdapter( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 4), - child: Container( - decoration: BoxDecoration( - color: Theme.of(context) - .extension()! - .popupBG, - borderRadius: BorderRadius.circular( - Constants.size.circularBorderRadius, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const SizedBox( + height: 12, ), - ), - child: Padding( - padding: const EdgeInsets.all(12), - child: Text( - "Trades will appear here", - textAlign: TextAlign.center, - style: STextStyles.itemSubtitle(context), + Text( + "Trades", + style: STextStyles.itemSubtitle(context).copyWith( + color: Theme.of(context) + .extension()! + .textDark3, + ), + ), + const SizedBox( + height: 12, + ), + ], + ), + ), + ), + if (hasHistory) + SliverList( + delegate: SliverChildBuilderDelegate((context, index) { + return Padding( + padding: const EdgeInsets.all(4), + child: TradeCard( + key: Key("tradeCard_${trades[index].uuid}"), + trade: trades[index], + onTap: () async { + final String tradeId = trades[index].tradeId; + + final lookup = ref + .read(tradeSentFromStackLookupProvider) + .all; + + //todo: check if print needed + // debugPrint("ALL: $lookup"); + + final String? txid = ref + .read(tradeSentFromStackLookupProvider) + .getTxidForTradeId(tradeId); + final List? walletIds = ref + .read(tradeSentFromStackLookupProvider) + .getWalletIdsForTradeId(tradeId); + + if (txid != null && + walletIds != null && + walletIds.isNotEmpty) { + final manager = ref + .read(walletsChangeNotifierProvider) + .getManager(walletIds.first); + + //todo: check if print needed + // debugPrint("name: ${manager.walletName}"); + + final tx = await MainDB.instance + .getTransactions(walletIds.first) + .filter() + .txidEqualTo(txid) + .findFirst(); + + if (mounted) { + unawaited(Navigator.of(context).pushNamed( + TradeDetailsView.routeName, + arguments: Tuple4(tradeId, tx, + walletIds.first, manager.walletName), + )); + } + } else { + unawaited(Navigator.of(context).pushNamed( + TradeDetailsView.routeName, + arguments: Tuple4( + tradeId, null, walletIds?.first, null), + )); + } + }, + ), + ); + }, childCount: tradeCount), + ), + if (!hasHistory) + SliverToBoxAdapter( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 4), + child: Container( + decoration: BoxDecoration( + color: Theme.of(context) + .extension()! + .popupBG, + borderRadius: BorderRadius.circular( + Constants.size.circularBorderRadius, + ), + ), + child: Padding( + padding: const EdgeInsets.all(12), + child: Text( + "Trades will appear here", + textAlign: TextAlign.center, + style: STextStyles.itemSubtitle(context), + ), ), ), ), ), - ), - ], - ), - ); - }, + ], + ), + ); + }, + ), ), ), ); diff --git a/lib/pages/exchange_view/sub_widgets/exchange_provider_options.dart b/lib/pages/exchange_view/sub_widgets/exchange_provider_options.dart index 9db3b9cb3..c0f4312d0 100644 --- a/lib/pages/exchange_view/sub_widgets/exchange_provider_options.dart +++ b/lib/pages/exchange_view/sub_widgets/exchange_provider_options.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/exceptions/exchange/pair_unavailable_exception.dart'; +import 'package:stackwallet/models/exchange/aggregate_currency.dart'; import 'package:stackwallet/models/exchange/response_objects/estimate.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart'; @@ -20,27 +21,62 @@ import 'package:stackwallet/widgets/animated_text.dart'; import 'package:stackwallet/widgets/conditional_parent.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; -class ExchangeProviderOptions extends ConsumerWidget { +class ExchangeProviderOptions extends ConsumerStatefulWidget { const ExchangeProviderOptions({ Key? key, - required this.from, - required this.to, - required this.fromAmount, - required this.toAmount, required this.fixedRate, required this.reversed, }) : super(key: key); - final String? from; - final String? to; - final Decimal? fromAmount; - final Decimal? toAmount; final bool fixedRate; final bool reversed; @override - Widget build(BuildContext context, WidgetRef ref) { - final isDesktop = Util.isDesktop; + ConsumerState createState() => + _ExchangeProviderOptionsState(); +} + +class _ExchangeProviderOptionsState + extends ConsumerState { + final isDesktop = Util.isDesktop; + + bool exchangeSupported({ + required String exchangeName, + required AggregateCurrency? sendCurrency, + required AggregateCurrency? receiveCurrency, + }) { + final send = sendCurrency?.forExchange(exchangeName); + if (send == null) return false; + + final rcv = receiveCurrency?.forExchange(exchangeName); + if (rcv == null) return false; + + if (widget.fixedRate) { + return send.supportsFixedRate && rcv.supportsFixedRate; + } else { + return send.supportsEstimatedRate && rcv.supportsEstimatedRate; + } + } + + @override + Widget build(BuildContext context) { + final sendCurrency = ref.watch(exchangeFormStateProvider).sendCurrency; + final receivingCurrency = + ref.watch(exchangeFormStateProvider).receiveCurrency; + final fromAmount = ref.watch(exchangeFormStateProvider).sendAmount; + final toAmount = ref.watch(exchangeFormStateProvider).receiveAmount; + + final showChangeNow = exchangeSupported( + exchangeName: ChangeNowExchange.exchangeName, + sendCurrency: sendCurrency, + receiveCurrency: receivingCurrency, + ); + final showMajesticBank = exchangeSupported( + exchangeName: MajesticBankExchange.exchangeName, + sendCurrency: sendCurrency, + receiveCurrency: receivingCurrency, + ); + return RoundedWhiteContainer( padding: isDesktop ? const EdgeInsets.all(0) : const EdgeInsets.all(12), borderColor: isDesktop @@ -48,181 +84,196 @@ class ExchangeProviderOptions extends ConsumerWidget { : null, child: Column( children: [ - ConditionalParent( - condition: isDesktop, - builder: (child) => MouseRegion( - cursor: SystemMouseCursors.click, - child: child, - ), - child: GestureDetector( - onTap: () { - if (ref.read(currentExchangeNameStateProvider.state).state != - ChangeNowExchange.exchangeName) { - ref.read(currentExchangeNameStateProvider.state).state = - ChangeNowExchange.exchangeName; - ref.read(exchangeFormStateProvider).updateExchange( - exchange: ref.read(exchangeProvider), - shouldUpdateData: true, - shouldNotifyListeners: true, - ); - } - }, - child: Container( - color: Colors.transparent, - child: Padding( - padding: isDesktop - ? const EdgeInsets.all(16) - : const EdgeInsets.all(0), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - width: 20, - height: 20, - child: Padding( - padding: - EdgeInsets.only(top: isDesktop ? 20.0 : 15.0), - child: Radio( - activeColor: Theme.of(context) - .extension()! - .radioButtonIconEnabled, - value: ChangeNowExchange.exchangeName, - groupValue: ref - .watch(currentExchangeNameStateProvider.state) - .state, - onChanged: (_) { - // if (value is String) { - // ref - // .read( - // currentExchangeNameStateProvider.state) - // .state = value; - // ref - // .read(exchangeFormStateProvider(ref - // .read(prefsChangeNotifierProvider) - // .exchangeRateType)) - // .exchange = - // Exchange.fromName(ref - // .read(currentExchangeNameStateProvider - // .state) - // .state); - // } - }, + if (showChangeNow) + ConditionalParent( + condition: isDesktop, + builder: (child) => MouseRegion( + cursor: SystemMouseCursors.click, + child: child, + ), + child: GestureDetector( + onTap: () { + if (ref.read(exchangeFormStateProvider).exchange.name != + ChangeNowExchange.exchangeName) { + ref.read(exchangeFormStateProvider).updateExchange( + exchange: ChangeNowExchange.instance, + shouldUpdateData: true, + shouldNotifyListeners: true, + ); + } + }, + child: Container( + color: Colors.transparent, + child: Padding( + padding: isDesktop + ? const EdgeInsets.all(16) + : const EdgeInsets.all(0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 20, + height: 20, + child: Padding( + padding: + EdgeInsets.only(top: isDesktop ? 20.0 : 15.0), + child: Radio( + activeColor: Theme.of(context) + .extension()! + .radioButtonIconEnabled, + value: ChangeNowExchange.exchangeName, + groupValue: ref.watch(exchangeFormStateProvider + .select((value) => value.exchange.name)), + onChanged: (_) { + if (ref + .read(exchangeFormStateProvider) + .exchange + .name != + ChangeNowExchange.exchangeName) { + ref + .read(exchangeFormStateProvider) + .updateExchange( + exchange: ChangeNowExchange.instance, + shouldUpdateData: true, + shouldNotifyListeners: true, + ); + } + }, + ), ), ), - ), - const SizedBox( - width: 14, - ), - Padding( - padding: const EdgeInsets.only(top: 5.0), - child: SizedBox( - width: isDesktop ? 32 : 24, - height: isDesktop ? 32 : 24, - child: SvgPicture.asset( - Assets.exchange.changeNow, + const SizedBox( + width: 14, + ), + Padding( + padding: const EdgeInsets.only(top: 5.0), + child: SizedBox( width: isDesktop ? 32 : 24, height: isDesktop ? 32 : 24, + child: SvgPicture.asset( + Assets.exchange.changeNow, + width: isDesktop ? 32 : 24, + height: isDesktop ? 32 : 24, + ), ), ), - ), - const SizedBox( - width: 10, - ), - Expanded( - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - ChangeNowExchange.exchangeName, - style: STextStyles.titleBold12(context).copyWith( - color: Theme.of(context) - .extension()! - .textDark2, - ), - ), - if (from != null && - to != null && - toAmount != null && - toAmount! > Decimal.zero && - fromAmount != null && - fromAmount! > Decimal.zero) - FutureBuilder( - future: ChangeNowExchange.instance.getEstimate( - from!, - to!, - reversed ? toAmount! : fromAmount!, - fixedRate, - reversed, + const SizedBox( + width: 10, + ), + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + ChangeNowExchange.exchangeName, + style: + STextStyles.titleBold12(context).copyWith( + color: Theme.of(context) + .extension()! + .textDark2, ), - builder: (context, - AsyncSnapshot> - snapshot) { - if (snapshot.connectionState == - ConnectionState.done && - snapshot.hasData) { - final estimate = snapshot.data?.value; - if (estimate != null) { - Decimal rate; - if (estimate.reversed) { - rate = (toAmount! / - estimate.estimatedAmount) - .toDecimal( - scaleOnInfinitePrecision: 12); - } else { - rate = (estimate.estimatedAmount / - fromAmount!) - .toDecimal( - scaleOnInfinitePrecision: 12); - } - Coin coin; - try { - coin = - coinFromTickerCaseInsensitive(to!); - } catch (_) { - coin = Coin.bitcoin; - } + ), + if (sendCurrency != null && + receivingCurrency != null && + toAmount != null && + toAmount > Decimal.zero && + fromAmount != null && + fromAmount > Decimal.zero) + FutureBuilder( + future: + ChangeNowExchange.instance.getEstimate( + sendCurrency.ticker, + receivingCurrency.ticker, + widget.reversed ? toAmount : fromAmount, + widget.fixedRate, + widget.reversed, + ), + builder: (context, + AsyncSnapshot> + snapshot) { + if (snapshot.connectionState == + ConnectionState.done && + snapshot.hasData) { + final estimate = snapshot.data?.value; + if (estimate != null) { + Decimal rate; + if (estimate.reversed) { + rate = (toAmount / + estimate.estimatedAmount) + .toDecimal( + scaleOnInfinitePrecision: 12); + } else { + rate = (estimate.estimatedAmount / + fromAmount) + .toDecimal( + scaleOnInfinitePrecision: 12); + } + Coin coin; + try { + coin = coinFromTickerCaseInsensitive( + receivingCurrency.ticker); + } catch (_) { + coin = Coin.bitcoin; + } - return Text( - "1 ${from!.toUpperCase()} ~ ${Format.localizedStringAsFixed( - value: rate, - locale: ref.watch( - localeServiceChangeNotifierProvider - .select( - (value) => value.locale), + return Text( + "1 ${sendCurrency.ticker.toUpperCase()} ~ ${Format.localizedStringAsFixed( + value: rate, + locale: ref.watch( + localeServiceChangeNotifierProvider + .select( + (value) => value.locale), + ), + decimalPlaces: + Constants.decimalPlacesForCoin( + coin), + )} ${receivingCurrency.ticker.toUpperCase()}", + style: STextStyles.itemSubtitle12( + context) + .copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, ), - decimalPlaces: - Constants.decimalPlacesForCoin( - coin), - )} ${to!.toUpperCase()}", - style: - STextStyles.itemSubtitle12(context) - .copyWith( - color: Theme.of(context) - .extension()! - .textSubtitle1, - ), - ); - } else if (snapshot.data?.exception - is PairUnavailableException) { - return Text( - "Unsupported pair", - style: - STextStyles.itemSubtitle12(context) - .copyWith( - color: Theme.of(context) - .extension()! - .textSubtitle1, - ), - ); + ); + } else if (snapshot.data?.exception + is PairUnavailableException) { + return Text( + "Unsupported pair", + style: STextStyles.itemSubtitle12( + context) + .copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, + ), + ); + } else { + Logging.instance.log( + "$runtimeType failed to fetch rate for ChangeNOW: ${snapshot.data}", + level: LogLevel.Warning, + ); + return Text( + "Failed to fetch rate", + style: STextStyles.itemSubtitle12( + context) + .copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, + ), + ); + } } else { - Logging.instance.log( - "$runtimeType failed to fetch rate for ChangeNOW: ${snapshot.data}", - level: LogLevel.Warning, - ); - return Text( - "Failed to fetch rate", + return AnimatedText( + stringsToLoopThrough: const [ + "Loading", + "Loading.", + "Loading..", + "Loading...", + ], style: STextStyles.itemSubtitle12(context) .copyWith( @@ -232,233 +283,234 @@ class ExchangeProviderOptions extends ConsumerWidget { ), ); } - } else { - return AnimatedText( - stringsToLoopThrough: const [ - "Loading", - "Loading.", - "Loading..", - "Loading...", - ], - style: STextStyles.itemSubtitle12(context) - .copyWith( - color: Theme.of(context) - .extension()! - .textSubtitle1, - ), - ); - } - }, - ), - if (!(from != null && - to != null && - toAmount != null && - toAmount! > Decimal.zero && - fromAmount != null && - fromAmount! > Decimal.zero)) - Text( - "n/a", - style: STextStyles.itemSubtitle12(context) - .copyWith( - color: Theme.of(context) - .extension()! - .textSubtitle1, + }, ), - ), - ], + if (!(sendCurrency != null && + receivingCurrency != null && + toAmount != null && + toAmount > Decimal.zero && + fromAmount != null && + fromAmount > Decimal.zero)) + Text( + "n/a", + style: STextStyles.itemSubtitle12(context) + .copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, + ), + ), + ], + ), ), - ), - ], + ], + ), ), ), ), ), - ), - if (isDesktop) - Container( - height: 1, - color: Theme.of(context).extension()!.background, - ), - if (!isDesktop) - const SizedBox( - height: 16, - ), - ConditionalParent( - condition: isDesktop, - builder: (child) => MouseRegion( - cursor: SystemMouseCursors.click, - child: child, - ), - child: GestureDetector( - onTap: () { - if (ref.read(currentExchangeNameStateProvider.state).state != - MajesticBankExchange.exchangeName) { - ref.read(currentExchangeNameStateProvider.state).state = - MajesticBankExchange.exchangeName; - ref.read(exchangeFormStateProvider).updateExchange( - exchange: ref.read(exchangeProvider), - shouldUpdateData: true, - shouldNotifyListeners: true, - ); - } - }, - child: Container( - color: Colors.transparent, - child: Padding( - padding: isDesktop - ? const EdgeInsets.all(16) - : const EdgeInsets.all(0), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - width: 20, - height: 20, - child: Padding( - padding: - EdgeInsets.only(top: isDesktop ? 20.0 : 15.0), - child: Radio( - activeColor: Theme.of(context) - .extension()! - .radioButtonIconEnabled, - value: MajesticBankExchange.exchangeName, - groupValue: ref - .watch(currentExchangeNameStateProvider.state) - .state, - onChanged: (_) { - // if (value is String) { - // ref - // .read( - // currentExchangeNameStateProvider.state) - // .state = value; - // ref - // .read(exchangeFormStateProvider(ref - // .read(prefsChangeNotifierProvider) - // .exchangeRateType)) - // .exchange = - // Exchange.fromName(ref - // .read(currentExchangeNameStateProvider - // .state) - // .state); - // } - }, + + if (showChangeNow && showMajesticBank) + isDesktop + ? Container( + height: 1, + color: + Theme.of(context).extension()!.background, + ) + : const SizedBox( + height: 16, + ), + + if (showMajesticBank) + ConditionalParent( + condition: isDesktop, + builder: (child) => MouseRegion( + cursor: SystemMouseCursors.click, + child: child, + ), + child: GestureDetector( + onTap: () { + if (ref.read(exchangeFormStateProvider).exchange.name != + MajesticBankExchange.exchangeName) { + ref.read(exchangeFormStateProvider).updateExchange( + exchange: MajesticBankExchange.instance, + shouldUpdateData: true, + shouldNotifyListeners: true, + ); + } + }, + child: Container( + color: Colors.transparent, + child: Padding( + padding: isDesktop + ? const EdgeInsets.all(16) + : const EdgeInsets.all(0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 20, + height: 20, + child: Padding( + padding: + EdgeInsets.only(top: isDesktop ? 20.0 : 15.0), + child: Radio( + activeColor: Theme.of(context) + .extension()! + .radioButtonIconEnabled, + value: MajesticBankExchange.exchangeName, + groupValue: ref.watch(exchangeFormStateProvider + .select((value) => value.exchange.name)), + onChanged: (_) { + if (ref + .read(exchangeFormStateProvider) + .exchange + .name != + MajesticBankExchange.exchangeName) { + ref + .read(exchangeFormStateProvider) + .updateExchange( + exchange: MajesticBankExchange.instance, + shouldUpdateData: true, + shouldNotifyListeners: true, + ); + } + }, + ), ), ), - ), - const SizedBox( - width: 14, - ), - Padding( - padding: const EdgeInsets.only(top: 5.0), - child: SizedBox( - width: isDesktop ? 32 : 24, - height: isDesktop ? 32 : 24, - child: SvgPicture.asset( - Assets.exchange.majesticBankBlue, + const SizedBox( + width: 14, + ), + Padding( + padding: const EdgeInsets.only(top: 5.0), + child: SizedBox( width: isDesktop ? 32 : 24, height: isDesktop ? 32 : 24, + child: SvgPicture.asset( + Assets.exchange.majesticBankBlue, + width: isDesktop ? 32 : 24, + height: isDesktop ? 32 : 24, + ), ), ), - ), - const SizedBox( - width: 10, - ), - Expanded( - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - MajesticBankExchange.exchangeName, - style: STextStyles.titleBold12(context).copyWith( - color: Theme.of(context) - .extension()! - .textDark2, - ), - ), - if (from != null && - to != null && - toAmount != null && - toAmount! > Decimal.zero && - fromAmount != null && - fromAmount! > Decimal.zero) - FutureBuilder( - future: - MajesticBankExchange.instance.getEstimate( - from!, - to!, - reversed ? toAmount! : fromAmount!, - fixedRate, - reversed, + const SizedBox( + width: 10, + ), + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + MajesticBankExchange.exchangeName, + style: + STextStyles.titleBold12(context).copyWith( + color: Theme.of(context) + .extension()! + .textDark2, ), - builder: (context, - AsyncSnapshot> - snapshot) { - if (snapshot.connectionState == - ConnectionState.done && - snapshot.hasData) { - final estimate = snapshot.data?.value; - if (estimate != null) { - Decimal rate; - if (estimate.reversed) { - rate = (toAmount! / - estimate.estimatedAmount) - .toDecimal( - scaleOnInfinitePrecision: 12); - } else { - rate = (estimate.estimatedAmount / - fromAmount!) - .toDecimal( - scaleOnInfinitePrecision: 12); - } - Coin coin; - try { - coin = - coinFromTickerCaseInsensitive(to!); - } catch (_) { - coin = Coin.bitcoin; - } + ), + if (sendCurrency != null && + receivingCurrency != null && + toAmount != null && + toAmount > Decimal.zero && + fromAmount != null && + fromAmount > Decimal.zero) + FutureBuilder( + future: + MajesticBankExchange.instance.getEstimate( + sendCurrency.ticker, + receivingCurrency.ticker, + widget.reversed ? toAmount : fromAmount, + widget.fixedRate, + widget.reversed, + ), + builder: (context, + AsyncSnapshot> + snapshot) { + if (snapshot.connectionState == + ConnectionState.done && + snapshot.hasData) { + final estimate = snapshot.data?.value; + if (estimate != null) { + Decimal rate; + if (estimate.reversed) { + rate = (toAmount / + estimate.estimatedAmount) + .toDecimal( + scaleOnInfinitePrecision: 12); + } else { + rate = (estimate.estimatedAmount / + fromAmount) + .toDecimal( + scaleOnInfinitePrecision: 12); + } + Coin coin; + try { + coin = coinFromTickerCaseInsensitive( + receivingCurrency.ticker); + } catch (_) { + coin = Coin.bitcoin; + } - return Text( - "1 ${from!.toUpperCase()} ~ ${Format.localizedStringAsFixed( - value: rate, - locale: ref.watch( - localeServiceChangeNotifierProvider - .select( - (value) => value.locale), + return Text( + "1 ${sendCurrency.ticker.toUpperCase()} ~ ${Format.localizedStringAsFixed( + value: rate, + locale: ref.watch( + localeServiceChangeNotifierProvider + .select( + (value) => value.locale), + ), + decimalPlaces: + Constants.decimalPlacesForCoin( + coin), + )} ${receivingCurrency.ticker.toUpperCase()}", + style: STextStyles.itemSubtitle12( + context) + .copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, ), - decimalPlaces: - Constants.decimalPlacesForCoin( - coin), - )} ${to!.toUpperCase()}", - style: - STextStyles.itemSubtitle12(context) - .copyWith( - color: Theme.of(context) - .extension()! - .textSubtitle1, - ), - ); - } else if (snapshot.data?.exception - is PairUnavailableException) { - return Text( - "Unsupported pair", - style: - STextStyles.itemSubtitle12(context) - .copyWith( - color: Theme.of(context) - .extension()! - .textSubtitle1, - ), - ); + ); + } else if (snapshot.data?.exception + is PairUnavailableException) { + return Text( + "Unsupported pair", + style: STextStyles.itemSubtitle12( + context) + .copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, + ), + ); + } else { + Logging.instance.log( + "$runtimeType failed to fetch rate for ChangeNOW: ${snapshot.data}", + level: LogLevel.Warning, + ); + return Text( + "Failed to fetch rate", + style: STextStyles.itemSubtitle12( + context) + .copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, + ), + ); + } } else { - Logging.instance.log( - "$runtimeType failed to fetch rate for ChangeNOW: ${snapshot.data}", - level: LogLevel.Warning, - ); - return Text( - "Failed to fetch rate", + return AnimatedText( + stringsToLoopThrough: const [ + "Loading", + "Loading.", + "Loading..", + "Loading...", + ], style: STextStyles.itemSubtitle12(context) .copyWith( @@ -468,53 +520,37 @@ class ExchangeProviderOptions extends ConsumerWidget { ), ); } - } else { - return AnimatedText( - stringsToLoopThrough: const [ - "Loading", - "Loading.", - "Loading..", - "Loading...", - ], - style: STextStyles.itemSubtitle12(context) - .copyWith( - color: Theme.of(context) - .extension()! - .textSubtitle1, - ), - ); - } - }, - ), - if (!(from != null && - to != null && - toAmount != null && - toAmount! > Decimal.zero && - fromAmount != null && - fromAmount! > Decimal.zero)) - Text( - "n/a", - style: STextStyles.itemSubtitle12(context) - .copyWith( - color: Theme.of(context) - .extension()! - .textSubtitle1, + }, ), - ), - ], + if (!(sendCurrency != null && + receivingCurrency != null && + toAmount != null && + toAmount > Decimal.zero && + fromAmount != null && + fromAmount > Decimal.zero)) + Text( + "n/a", + style: STextStyles.itemSubtitle12(context) + .copyWith( + color: Theme.of(context) + .extension()! + .textSubtitle1, + ), + ), + ], + ), ), - ), - ], + ], + ), ), ), ), ), - ), - if (isDesktop) - Container( - height: 1, - color: Theme.of(context).extension()!.background, - ), + // if (isDesktop) + // Container( + // height: 1, + // color: Theme.of(context).extension()!.background, + // ), // if (!isDesktop) // const SizedBox( // height: 16, diff --git a/lib/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart b/lib/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart deleted file mode 100644 index b56d2fbff..000000000 --- a/lib/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart +++ /dev/null @@ -1,210 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:stackwallet/providers/providers.dart'; -import 'package:stackwallet/utilities/constants.dart'; -import 'package:stackwallet/utilities/text_styles.dart'; -import 'package:stackwallet/utilities/theme/stack_colors.dart'; - -enum ExchangeRateType { estimated, fixed } - -class ExchangeRateSheet extends ConsumerWidget { - const ExchangeRateSheet({ - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context, WidgetRef ref) { - return Container( - decoration: BoxDecoration( - color: Theme.of(context).extension()!.popupBG, - borderRadius: const BorderRadius.vertical( - top: Radius.circular(20), - ), - ), - child: Padding( - padding: const EdgeInsets.only( - left: 24, - right: 24, - top: 10, - bottom: 0, - ), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Center( - child: Container( - decoration: BoxDecoration( - color: - Theme.of(context).extension()!.textSubtitle4, - borderRadius: BorderRadius.circular( - Constants.size.circularBorderRadius, - ), - ), - width: 60, - height: 4, - ), - ), - const SizedBox( - height: 36, - ), - Text( - "Exchange rate", - style: STextStyles.pageTitleH2(context), - textAlign: TextAlign.left, - ), - const SizedBox( - height: 16, - ), - GestureDetector( - onTap: () { - final state = - ref.read(prefsChangeNotifierProvider).exchangeRateType; - if (state != ExchangeRateType.estimated) { - ref.read(prefsChangeNotifierProvider).exchangeRateType = - ExchangeRateType.estimated; - } - Navigator.of(context).pop(ExchangeRateType.estimated); - }, - child: Container( - color: Colors.transparent, - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Column( - children: [ - SizedBox( - width: 20, - height: 20, - child: Radio( - activeColor: Theme.of(context) - .extension()! - .radioButtonIconEnabled, - value: ExchangeRateType.estimated, - groupValue: ref.watch(prefsChangeNotifierProvider - .select((value) => value.exchangeRateType)), - onChanged: (x) { - //todo: check if print needed - // debugPrint(x.toString()); - ref - .read(prefsChangeNotifierProvider) - .exchangeRateType = - ExchangeRateType.estimated; - Navigator.of(context) - .pop(ExchangeRateType.estimated); - }, - ), - ) - ], - ), - const SizedBox( - width: 12, - ), - Flexible( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Estimated rate", - style: STextStyles.titleBold12(context), - textAlign: TextAlign.left, - ), - const SizedBox( - height: 2, - ), - Text( - "ChangeNOW will pick the best rate for you during the moment of the exchange.", - style: STextStyles.itemSubtitle(context).copyWith( - color: Theme.of(context) - .extension()! - .textSubtitle1, - ), - textAlign: TextAlign.left, - ), - ], - ), - ) - ], - ), - ), - ), - const SizedBox( - height: 16, - ), - GestureDetector( - onTap: () { - final state = - ref.read(prefsChangeNotifierProvider).exchangeRateType; - if (state != ExchangeRateType.fixed) { - ref.read(prefsChangeNotifierProvider).exchangeRateType = - ExchangeRateType.fixed; - } - Navigator.of(context).pop(ExchangeRateType.fixed); - }, - child: Container( - color: Colors.transparent, - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Column( - children: [ - SizedBox( - width: 20, - height: 20, - child: Radio( - activeColor: Theme.of(context) - .extension()! - .radioButtonIconEnabled, - value: ExchangeRateType.fixed, - groupValue: ref.watch(prefsChangeNotifierProvider - .select((value) => value.exchangeRateType)), - onChanged: (x) { - ref - .read(prefsChangeNotifierProvider) - .exchangeRateType = ExchangeRateType.fixed; - Navigator.of(context).pop(ExchangeRateType.fixed); - }, - ), - ), - ], - ), - const SizedBox( - width: 12, - ), - Flexible( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Fixed rate", - style: STextStyles.titleBold12(context), - textAlign: TextAlign.left, - ), - const SizedBox( - height: 2, - ), - Text( - "You will get the exact exchange amount displayed - ChangeNOW takes all the rate risks.", - style: STextStyles.itemSubtitle(context).copyWith( - color: Theme.of(context) - .extension()! - .textSubtitle1, - ), - textAlign: TextAlign.left, - ) - ], - ), - ), - ], - ), - ), - ), - const SizedBox( - height: 24, - ), - ], - ), - ), - ); - } -} diff --git a/lib/pages/exchange_view/sub_widgets/rate_type_toggle.dart b/lib/pages/exchange_view/sub_widgets/rate_type_toggle.dart index 68dadf3c9..f85c0cfcd 100644 --- a/lib/pages/exchange_view/sub_widgets/rate_type_toggle.dart +++ b/lib/pages/exchange_view/sub_widgets/rate_type_toggle.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; +import 'package:stackwallet/utilities/enums/exchange_rate_type_enum.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/widgets/toggle.dart'; @@ -24,16 +24,12 @@ class RateTypeToggle extends ConsumerWidget { return Toggle( onValueChanged: (value) { if (value) { - ref.read(prefsChangeNotifierProvider).exchangeRateType = - ExchangeRateType.fixed; onChanged?.call(ExchangeRateType.fixed); } else { - ref.read(prefsChangeNotifierProvider).exchangeRateType = - ExchangeRateType.estimated; onChanged?.call(ExchangeRateType.estimated); } }, - isOn: ref.watch(prefsChangeNotifierProvider + isOn: ref.watch(exchangeFormStateProvider .select((value) => value.exchangeRateType)) == ExchangeRateType.fixed, onColor: isDesktop diff --git a/lib/pages/exchange_view/trade_details_view.dart b/lib/pages/exchange_view/trade_details_view.dart index 4e42ff888..99fc64bf2 100644 --- a/lib/pages/exchange_view/trade_details_view.dart +++ b/lib/pages/exchange_view/trade_details_view.dart @@ -18,6 +18,7 @@ import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/route_generator.dart'; import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart'; import 'package:stackwallet/services/exchange/exchange.dart'; +import 'package:stackwallet/services/exchange/majestic_bank/majestic_bank_exchange.dart'; import 'package:stackwallet/services/exchange/simpleswap/simpleswap_exchange.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart'; @@ -1128,6 +1129,10 @@ class _TradeDetailsViewState extends ConsumerState { url = "https://simpleswap.io/exchange?id=${trade.tradeId}"; break; + case MajesticBankExchange.exchangeName: + url = + "https://majesticbank.sc/track?trx=${trade.tradeId}"; + break; } return ConditionalParent( condition: isDesktop, diff --git a/lib/pages/exchange_view/wallet_initiated_exchange_view.dart b/lib/pages/exchange_view/wallet_initiated_exchange_view.dart index 915fb33ba..e6ee7d3a3 100644 --- a/lib/pages/exchange_view/wallet_initiated_exchange_view.dart +++ b/lib/pages/exchange_view/wallet_initiated_exchange_view.dart @@ -4,11 +4,15 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/pages/exchange_view/exchange_form.dart'; import 'package:stackwallet/pages/exchange_view/sub_widgets/step_row.dart'; +import 'package:stackwallet/providers/global/prefs_provider.dart'; +import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/background.dart'; +import 'package:stackwallet/widgets/conditional_parent.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; +import 'package:stackwallet/widgets/custom_loading_overlay.dart'; class WalletInitiatedExchangeView extends ConsumerStatefulWidget { const WalletInitiatedExchangeView({ @@ -32,10 +36,41 @@ class _WalletInitiatedExchangeViewState late final String walletId; late final Coin coin; + bool _initialCachePopulationUnderway = false; + @override void initState() { walletId = widget.walletId; coin = widget.coin; + + if (!ref.read(prefsChangeNotifierProvider).externalCalls) { + if (ExchangeDataLoadingService.currentCacheVersion < + ExchangeDataLoadingService.cacheVersion) { + _initialCachePopulationUnderway = true; + ExchangeDataLoadingService.instance.onLoadingComplete = () { + WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + setState(() { + _initialCachePopulationUnderway = false; + }); + }); + }; + } + ExchangeDataLoadingService.instance + .init() + .then((_) => ExchangeDataLoadingService.instance.loadAll()); + } else if (ExchangeDataLoadingService.instance.isLoading && + ExchangeDataLoadingService.currentCacheVersion < + ExchangeDataLoadingService.cacheVersion) { + _initialCachePopulationUnderway = true; + ExchangeDataLoadingService.instance.onLoadingComplete = () { + WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + setState(() { + _initialCachePopulationUnderway = false; + }); + }); + }; + } + super.initState(); } @@ -48,76 +83,98 @@ class _WalletInitiatedExchangeViewState Widget build(BuildContext context) { debugPrint("BUILD: $runtimeType"); - return Background( - child: Scaffold( - backgroundColor: Theme.of(context).extension()!.background, - appBar: AppBar( - leading: AppBarBackButton( - onPressed: () async { - if (FocusScope.of(context).hasFocus) { - FocusScope.of(context).unfocus(); - await Future.delayed(const Duration(milliseconds: 75)); - } - if (mounted) { - Navigator.of(context).pop(); - } - }, + return ConditionalParent( + condition: _initialCachePopulationUnderway, + builder: (child) { + return Stack( + children: [ + child, + Material( + color: Theme.of(context) + .extension()! + .overlay + .withOpacity(0.6), + child: const CustomLoadingOverlay( + message: "Updating exchange data", + subMessage: "This could take a few minutes", + eventBus: null, + ), + ) + ], + ); + }, + child: Background( + child: Scaffold( + backgroundColor: + Theme.of(context).extension()!.background, + appBar: AppBar( + leading: AppBarBackButton( + onPressed: () async { + if (FocusScope.of(context).hasFocus) { + FocusScope.of(context).unfocus(); + await Future.delayed(const Duration(milliseconds: 75)); + } + if (mounted) { + Navigator.of(context).pop(); + } + }, + ), + title: Text( + "Exchange", + style: STextStyles.navBarTitle(context), + ), ), - title: Text( - "Exchange", - style: STextStyles.navBarTitle(context), - ), - ), - body: LayoutBuilder( - builder: (context, constraints) { - final width = MediaQuery.of(context).size.width - 32; - return Padding( - padding: const EdgeInsets.all(12), - child: SingleChildScrollView( - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: constraints.maxHeight - 24, - ), - child: IntrinsicHeight( - child: Padding( - padding: const EdgeInsets.all(4), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - StepRow( - count: 4, - current: 0, - width: width, - ), - const SizedBox( - height: 14, - ), - Text( - "Exchange amount", - style: STextStyles.pageTitleH1(context), - ), - const SizedBox( - height: 8, - ), - Text( - "Network fees and other exchange charges are included in the rate.", - style: STextStyles.itemSubtitle(context), - ), - const SizedBox( - height: 24, - ), - ExchangeForm( - walletId: walletId, - coin: coin, - ), - ], + body: LayoutBuilder( + builder: (context, constraints) { + final width = MediaQuery.of(context).size.width - 32; + return Padding( + padding: const EdgeInsets.all(12), + child: SingleChildScrollView( + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: constraints.maxHeight - 24, + ), + child: IntrinsicHeight( + child: Padding( + padding: const EdgeInsets.all(4), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + StepRow( + count: 4, + current: 0, + width: width, + ), + const SizedBox( + height: 14, + ), + Text( + "Exchange amount", + style: STextStyles.pageTitleH1(context), + ), + const SizedBox( + height: 8, + ), + Text( + "Network fees and other exchange charges are included in the rate.", + style: STextStyles.itemSubtitle(context), + ), + const SizedBox( + height: 24, + ), + ExchangeForm( + walletId: walletId, + coin: coin, + ), + ], + ), ), ), ), ), - ), - ); - }, + ); + }, + ), ), ), ); diff --git a/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart b/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart index c517e5851..280077819 100644 --- a/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart +++ b/lib/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart @@ -13,7 +13,6 @@ import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/models/stack_restoring_ui_state.dart'; import 'package:stackwallet/models/trade_wallet_lookup.dart'; import 'package:stackwallet/models/wallet_restore_state.dart'; -import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart'; import 'package:stackwallet/services/address_book_service.dart'; import 'package:stackwallet/services/coins/coin_service.dart'; import 'package:stackwallet/services/coins/manager.dart'; @@ -246,7 +245,6 @@ abstract class SWB { final _prefs = Prefs.instance; await _prefs.init(); prefs['currency'] = _prefs.currency; - prefs['exchangeRateType'] = _prefs.exchangeRateType.name; prefs['useBiometrics'] = _prefs.useBiometrics; prefs['hasPin'] = _prefs.hasPin; prefs['language'] = _prefs.language; @@ -992,9 +990,6 @@ abstract class SWB { final _prefs = Prefs.instance; await _prefs.init(); _prefs.currency = prefs['currency'] as String; - _prefs.exchangeRateType = prefs['exchangeRateType'] == "estimated" - ? ExchangeRateType.estimated - : ExchangeRateType.fixed; // _prefs.useBiometrics = prefs['useBiometrics'] as bool; // _prefs.hasPin = prefs['hasPin'] as bool; _prefs.language = prefs['language'] as String; diff --git a/lib/pages/wallet_view/wallet_view.dart b/lib/pages/wallet_view/wallet_view.dart index 02e3be244..c5768c659 100644 --- a/lib/pages/wallet_view/wallet_view.dart +++ b/lib/pages/wallet_view/wallet_view.dart @@ -29,7 +29,6 @@ import 'package:stackwallet/services/coins/manager.dart'; import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart'; import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart'; import 'package:stackwallet/services/event_bus/global_event_bus.dart'; -import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/backup_frequency_type.dart'; @@ -38,6 +37,7 @@ import 'package:stackwallet/utilities/enums/wallet_balance_toggle_state.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/background.dart'; +import 'package:stackwallet/widgets/conditional_parent.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart'; import 'package:stackwallet/widgets/custom_loading_overlay.dart'; @@ -77,6 +77,8 @@ class _WalletViewState extends ConsumerState { late StreamSubscription _syncStatusSubscription; late StreamSubscription _nodeStatusSubscription; + bool _rescanningOnOpen = false; + @override void initState() { walletId = widget.walletId; @@ -91,7 +93,18 @@ class _WalletViewState extends ConsumerState { _shouldDisableAutoSyncOnLogOut = false; } - ref.read(managerProvider).refresh(); + if (ref.read(managerProvider).rescanOnOpenVersion == Constants.rescanV1) { + _rescanningOnOpen = true; + ref.read(managerProvider).fullRescan(20, 1000).then( + (_) => ref.read(managerProvider).resetRescanOnOpen().then( + (_) => WidgetsBinding.instance.addPostFrameCallback( + (_) => setState(() => _rescanningOnOpen = false), + ), + ), + ); + } else { + ref.read(managerProvider).refresh(); + } if (ref.read(managerProvider).isRefreshing) { _currentSyncStatus = WalletSyncStatus.syncing; @@ -278,10 +291,9 @@ class _WalletViewState extends ConsumerState { unawaited( Navigator.of(context).pushNamed( WalletInitiatedExchangeView.routeName, - arguments: Tuple3( + arguments: Tuple2( walletId, coin, - _loadCNData, ), ), ); @@ -355,435 +367,454 @@ class _WalletViewState extends ConsumerState { } } - void _loadCNData() { - // unawaited future - // if (ref.read(prefsChangeNotifierProvider).externalCalls) { - ExchangeDataLoadingService.instance.loadAll(); - // .loadAll(ref, coin: ref.read(managerProvider).coin); - // } else { - // Logging.instance.log("User does not want to use external calls", - // level: LogLevel.Info); - // } - } - @override Widget build(BuildContext context) { debugPrint("BUILD: $runtimeType"); final coin = ref.watch(managerProvider.select((value) => value.coin)); - return WillPopScope( - onWillPop: _onWillPop, - child: Background( - child: Scaffold( - backgroundColor: - Theme.of(context).extension()!.background, - appBar: AppBar( - leading: AppBarBackButton( - onPressed: () { - _logout(); - Navigator.of(context).pop(); - }, - ), - titleSpacing: 0, - title: Row( - children: [ - SvgPicture.asset( - Assets.svg.iconFor(coin: coin), - // color: Theme.of(context).extension()!.accentColorDark - width: 24, - height: 24, + return ConditionalParent( + condition: _rescanningOnOpen, + builder: (child) { + return WillPopScope( + onWillPop: () async => !_rescanningOnOpen, + child: Stack( + children: [ + child, + Background( + child: CustomLoadingOverlay( + message: + "Migration in progress\nThis could take a while\nPlease don't leave this screen", + subMessage: "This only needs to run once per wallet", + eventBus: null, + textColor: + Theme.of(context).extension()!.textDark, ), - const SizedBox( - width: 16, - ), - Expanded( - child: Text( - ref.watch( - managerProvider.select((value) => value.walletName)), - style: STextStyles.navBarTitle(context), - overflow: TextOverflow.ellipsis, - ), - ) - ], - ), - actions: [ - Padding( - padding: const EdgeInsets.only( - top: 10, - bottom: 10, - right: 10, - ), - child: AspectRatio( - aspectRatio: 1, - child: AppBarIconButton( - key: const Key("walletViewRadioButton"), - size: 36, - shadows: const [], - color: - Theme.of(context).extension()!.background, - icon: _buildNetworkIcon(_currentSyncStatus), - onPressed: () { - Navigator.of(context).pushNamed( - WalletNetworkSettingsView.routeName, - arguments: Tuple3( - walletId, - _currentSyncStatus, - _currentNodeStatus, - ), - ); - }, - ), - ), - ), - Padding( - padding: const EdgeInsets.only( - top: 10, - bottom: 10, - right: 10, - ), - child: AspectRatio( - aspectRatio: 1, - child: AppBarIconButton( - key: const Key("walletViewAlertsButton"), - size: 36, - shadows: const [], - color: - Theme.of(context).extension()!.background, - icon: SvgPicture.asset( - ref.watch(notificationsProvider.select((value) => - value.hasUnreadNotificationsFor(walletId))) - ? Assets.svg.bellNew(context) - : Assets.svg.bell, - width: 20, - height: 20, - color: ref.watch(notificationsProvider.select((value) => - value.hasUnreadNotificationsFor(walletId))) - ? null - : Theme.of(context) - .extension()! - .topNavIconPrimary, - ), - onPressed: () { - // reset unread state - ref.refresh(unreadNotificationsStateProvider); - - Navigator.of(context) - .pushNamed( - NotificationsView.routeName, - arguments: walletId, - ) - .then((_) { - final Set unreadNotificationIds = ref - .read(unreadNotificationsStateProvider.state) - .state; - if (unreadNotificationIds.isEmpty) return; - - List> futures = []; - for (int i = 0; - i < unreadNotificationIds.length - 1; - i++) { - futures.add(ref - .read(notificationsProvider) - .markAsRead( - unreadNotificationIds.elementAt(i), false)); - } - - // wait for multiple to update if any - Future.wait(futures).then((_) { - // only notify listeners once - ref - .read(notificationsProvider) - .markAsRead(unreadNotificationIds.last, true); - }); - }); - }, - ), - ), - ), - Padding( - padding: const EdgeInsets.only( - top: 10, - bottom: 10, - right: 10, - ), - child: AspectRatio( - aspectRatio: 1, - child: AppBarIconButton( - key: const Key("walletViewSettingsButton"), - size: 36, - shadows: const [], - color: - Theme.of(context).extension()!.background, - icon: SvgPicture.asset( - Assets.svg.bars, - color: Theme.of(context) - .extension()! - .accentColorDark, - width: 20, - height: 20, - ), - onPressed: () { - //todo: check if print needed - // debugPrint("wallet view settings tapped"); - Navigator.of(context).pushNamed( - WalletSettingsView.routeName, - arguments: Tuple4( - walletId, - ref.read(managerProvider).coin, - _currentSyncStatus, - _currentNodeStatus, - ), - ); - }, - ), - ), - ), + ) ], ), - body: SafeArea( - child: Container( - color: Theme.of(context).extension()!.background, - child: Column( + ); + }, + child: WillPopScope( + onWillPop: _onWillPop, + child: Background( + child: Scaffold( + backgroundColor: + Theme.of(context).extension()!.background, + appBar: AppBar( + leading: AppBarBackButton( + onPressed: () { + _logout(); + Navigator.of(context).pop(); + }, + ), + titleSpacing: 0, + title: Row( children: [ - const SizedBox( - height: 10, + SvgPicture.asset( + Assets.svg.iconFor(coin: coin), + // color: Theme.of(context).extension()!.accentColorDark + width: 24, + height: 24, ), - Center( - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: WalletSummary( - walletId: walletId, - managerProvider: managerProvider, - initialSyncStatus: ref.watch(managerProvider - .select((value) => value.isRefreshing)) - ? WalletSyncStatus.syncing - : WalletSyncStatus.synced, - ), + const SizedBox( + width: 16, + ), + Expanded( + child: Text( + ref.watch( + managerProvider.select((value) => value.walletName)), + style: STextStyles.navBarTitle(context), + overflow: TextOverflow.ellipsis, + ), + ) + ], + ), + actions: [ + Padding( + padding: const EdgeInsets.only( + top: 10, + bottom: 10, + right: 10, + ), + child: AspectRatio( + aspectRatio: 1, + child: AppBarIconButton( + key: const Key("walletViewRadioButton"), + size: 36, + shadows: const [], + color: Theme.of(context) + .extension()! + .background, + icon: _buildNetworkIcon(_currentSyncStatus), + onPressed: () { + Navigator.of(context).pushNamed( + WalletNetworkSettingsView.routeName, + arguments: Tuple3( + walletId, + _currentSyncStatus, + _currentNodeStatus, + ), + ); + }, ), ), - if (coin == Coin.firo) + ), + Padding( + padding: const EdgeInsets.only( + top: 10, + bottom: 10, + right: 10, + ), + child: AspectRatio( + aspectRatio: 1, + child: AppBarIconButton( + key: const Key("walletViewAlertsButton"), + size: 36, + shadows: const [], + color: Theme.of(context) + .extension()! + .background, + icon: SvgPicture.asset( + ref.watch(notificationsProvider.select((value) => + value.hasUnreadNotificationsFor(walletId))) + ? Assets.svg.bellNew(context) + : Assets.svg.bell, + width: 20, + height: 20, + color: ref.watch(notificationsProvider.select((value) => + value.hasUnreadNotificationsFor(walletId))) + ? null + : Theme.of(context) + .extension()! + .topNavIconPrimary, + ), + onPressed: () { + // reset unread state + ref.refresh(unreadNotificationsStateProvider); + + Navigator.of(context) + .pushNamed( + NotificationsView.routeName, + arguments: walletId, + ) + .then((_) { + final Set unreadNotificationIds = ref + .read(unreadNotificationsStateProvider.state) + .state; + if (unreadNotificationIds.isEmpty) return; + + List> futures = []; + for (int i = 0; + i < unreadNotificationIds.length - 1; + i++) { + futures.add(ref + .read(notificationsProvider) + .markAsRead( + unreadNotificationIds.elementAt(i), false)); + } + + // wait for multiple to update if any + Future.wait(futures).then((_) { + // only notify listeners once + ref + .read(notificationsProvider) + .markAsRead(unreadNotificationIds.last, true); + }); + }); + }, + ), + ), + ), + Padding( + padding: const EdgeInsets.only( + top: 10, + bottom: 10, + right: 10, + ), + child: AspectRatio( + aspectRatio: 1, + child: AppBarIconButton( + key: const Key("walletViewSettingsButton"), + size: 36, + shadows: const [], + color: Theme.of(context) + .extension()! + .background, + icon: SvgPicture.asset( + Assets.svg.bars, + color: Theme.of(context) + .extension()! + .accentColorDark, + width: 20, + height: 20, + ), + onPressed: () { + //todo: check if print needed + // debugPrint("wallet view settings tapped"); + Navigator.of(context).pushNamed( + WalletSettingsView.routeName, + arguments: Tuple4( + walletId, + ref.read(managerProvider).coin, + _currentSyncStatus, + _currentNodeStatus, + ), + ); + }, + ), + ), + ), + ], + ), + body: SafeArea( + child: Container( + color: Theme.of(context).extension()!.background, + child: Column( + children: [ const SizedBox( height: 10, ), - if (coin == Coin.firo) - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: Row( - children: [ - Expanded( - child: TextButton( - style: Theme.of(context) - .extension()! - .getSecondaryEnabledButtonStyle(context), - onPressed: () async { - await showDialog( - context: context, - builder: (context) => StackDialog( - title: "Attention!", - message: - "You're about to anonymize all of your public funds.", - leftButton: TextButton( - onPressed: () { - Navigator.of(context).pop(); - }, - child: Text( - "Cancel", - style: STextStyles.button(context) - .copyWith( - color: Theme.of(context) - .extension()! - .accentColorDark, + Center( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: WalletSummary( + walletId: walletId, + managerProvider: managerProvider, + initialSyncStatus: ref.watch(managerProvider + .select((value) => value.isRefreshing)) + ? WalletSyncStatus.syncing + : WalletSyncStatus.synced, + ), + ), + ), + if (coin == Coin.firo) + const SizedBox( + height: 10, + ), + if (coin == Coin.firo) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Row( + children: [ + Expanded( + child: TextButton( + style: Theme.of(context) + .extension()! + .getSecondaryEnabledButtonStyle(context), + onPressed: () async { + await showDialog( + context: context, + builder: (context) => StackDialog( + title: "Attention!", + message: + "You're about to anonymize all of your public funds.", + leftButton: TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: Text( + "Cancel", + style: STextStyles.button(context) + .copyWith( + color: Theme.of(context) + .extension()! + .accentColorDark, + ), + ), + ), + rightButton: TextButton( + onPressed: () async { + Navigator.of(context).pop(); + + unawaited(attemptAnonymize()); + }, + style: Theme.of(context) + .extension()! + .getPrimaryEnabledButtonStyle( + context), + child: Text( + "Continue", + style: STextStyles.button(context), ), ), ), - rightButton: TextButton( - onPressed: () async { - Navigator.of(context).pop(); - - unawaited(attemptAnonymize()); - }, - style: Theme.of(context) - .extension()! - .getPrimaryEnabledButtonStyle( - context), - child: Text( - "Continue", - style: STextStyles.button(context), - ), - ), + ); + }, + child: Text( + "Anonymize funds", + style: STextStyles.button(context).copyWith( + color: Theme.of(context) + .extension()! + .buttonTextSecondary, ), - ); - }, - child: Text( - "Anonymize funds", - style: STextStyles.button(context).copyWith( - color: Theme.of(context) - .extension()! - .buttonTextSecondary, ), ), ), + ], + ), + ), + const SizedBox( + height: 20, + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "Transactions", + style: STextStyles.itemSubtitle(context).copyWith( + color: Theme.of(context) + .extension()! + .textDark3, + ), + ), + CustomTextButton( + text: "See all", + onTap: () { + Navigator.of(context).pushNamed( + AllTransactionsView.routeName, + arguments: walletId, + ); + }, ), ], ), ), - const SizedBox( - height: 20, - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - "Transactions", - style: STextStyles.itemSubtitle(context).copyWith( - color: Theme.of(context) - .extension()! - .textDark3, - ), - ), - CustomTextButton( - text: "See all", - onTap: () { - Navigator.of(context).pushNamed( - AllTransactionsView.routeName, - arguments: walletId, - ); - }, - ), - ], + const SizedBox( + height: 12, ), - ), - const SizedBox( - height: 12, - ), - Expanded( - child: Stack( - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: Padding( - padding: const EdgeInsets.only(bottom: 14), - child: ClipRRect( - borderRadius: BorderRadius.vertical( - top: Radius.circular( - Constants.size.circularBorderRadius, - ), - bottom: Radius.circular( - // WalletView.navBarHeight / 2.0, - Constants.size.circularBorderRadius, - ), - ), - child: Container( - decoration: BoxDecoration( - color: Colors.transparent, - borderRadius: BorderRadius.circular( + Expanded( + child: Stack( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Padding( + padding: const EdgeInsets.only(bottom: 14), + child: ClipRRect( + borderRadius: BorderRadius.vertical( + top: Radius.circular( + Constants.size.circularBorderRadius, + ), + bottom: Radius.circular( + // WalletView.navBarHeight / 2.0, Constants.size.circularBorderRadius, ), ), - child: Column( - crossAxisAlignment: - CrossAxisAlignment.stretch, - children: [ - Expanded( - child: TransactionsList( - managerProvider: managerProvider, - walletId: walletId, - ), + child: Container( + decoration: BoxDecoration( + color: Colors.transparent, + borderRadius: BorderRadius.circular( + Constants.size.circularBorderRadius, ), - ], + ), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.stretch, + children: [ + Expanded( + child: TransactionsList( + managerProvider: managerProvider, + walletId: walletId, + ), + ), + ], + ), ), ), ), ), - ), - Column( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding( - padding: const EdgeInsets.only( - bottom: 14, - left: 16, - right: 16, - ), - child: WalletNavigationBar( - walletId: widget.walletId, - coin: ref.watch(managerProvider - .select((value) => value.coin)), - enableExchange: Constants.enableExchange && - ref.watch(managerProvider.select( - (value) => value.coin)) != - Coin.epicCash, - height: WalletView.navBarHeight, - onExchangePressed: () => - _onExchangePressed(context), - onReceivePressed: () async { - final coin = - ref.read(managerProvider).coin; - if (mounted) { - unawaited( - Navigator.of(context).pushNamed( - ReceiveView.routeName, + Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.only( + bottom: 14, + left: 16, + right: 16, + ), + child: WalletNavigationBar( + walletId: widget.walletId, + coin: ref.watch(managerProvider + .select((value) => value.coin)), + enableExchange: + Constants.enableExchange && + ref.watch(managerProvider.select( + (value) => value.coin)) != + Coin.epicCash, + height: WalletView.navBarHeight, + onExchangePressed: () => + _onExchangePressed(context), + onReceivePressed: () async { + final coin = + ref.read(managerProvider).coin; + if (mounted) { + unawaited( + Navigator.of(context).pushNamed( + ReceiveView.routeName, + arguments: Tuple2( + walletId, + coin, + ), + )); + } + }, + onSendPressed: () { + final walletId = + ref.read(managerProvider).walletId; + final coin = + ref.read(managerProvider).coin; + switch (ref + .read( + walletBalanceToggleStateProvider + .state) + .state) { + case WalletBalanceToggleState.full: + ref + .read( + publicPrivateBalanceStateProvider + .state) + .state = "Public"; + break; + case WalletBalanceToggleState + .available: + ref + .read( + publicPrivateBalanceStateProvider + .state) + .state = "Private"; + break; + } + Navigator.of(context).pushNamed( + SendView.routeName, arguments: Tuple2( walletId, coin, ), + ); + }, + onBuyPressed: () { + unawaited( + Navigator.of(context).pushNamed( + BuyInWalletView.routeName, + arguments: coin, )); - } - }, - onSendPressed: () { - final walletId = - ref.read(managerProvider).walletId; - final coin = - ref.read(managerProvider).coin; - switch (ref - .read(walletBalanceToggleStateProvider - .state) - .state) { - case WalletBalanceToggleState.full: - ref - .read( - publicPrivateBalanceStateProvider - .state) - .state = "Public"; - break; - case WalletBalanceToggleState.available: - ref - .read( - publicPrivateBalanceStateProvider - .state) - .state = "Private"; - break; - } - Navigator.of(context).pushNamed( - SendView.routeName, - arguments: Tuple2( - walletId, - coin, - ), - ); - }, - onBuyPressed: () { - unawaited(Navigator.of(context).pushNamed( - BuyInWalletView.routeName, - arguments: coin, - )); - }, + }, + ), ), - ), - ], - ), - ], - ) - ], + ], + ), + ], + ) + ], + ), ), - ), - ], + ], + ), ), ), ), diff --git a/lib/pages_desktop_specific/desktop_exchange/desktop_exchange_view.dart b/lib/pages_desktop_specific/desktop_exchange/desktop_exchange_view.dart index 105c485f0..19484e376 100644 --- a/lib/pages_desktop_specific/desktop_exchange/desktop_exchange_view.dart +++ b/lib/pages_desktop_specific/desktop_exchange/desktop_exchange_view.dart @@ -1,79 +1,142 @@ import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/pages/exchange_view/exchange_form.dart'; import 'package:stackwallet/pages_desktop_specific/desktop_exchange/subwidgets/desktop_trade_history.dart'; +import 'package:stackwallet/providers/global/prefs_provider.dart'; +import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart'; import 'package:stackwallet/utilities/text_styles.dart'; +import 'package:stackwallet/utilities/theme/stack_colors.dart'; +import 'package:stackwallet/widgets/conditional_parent.dart'; +import 'package:stackwallet/widgets/custom_loading_overlay.dart'; import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart'; import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; -class DesktopExchangeView extends StatefulWidget { +class DesktopExchangeView extends ConsumerStatefulWidget { const DesktopExchangeView({Key? key}) : super(key: key); static const String routeName = "/desktopExchange"; @override - State createState() => _DesktopExchangeViewState(); + ConsumerState createState() => + _DesktopExchangeViewState(); } -class _DesktopExchangeViewState extends State { +class _DesktopExchangeViewState extends ConsumerState { + bool _initialCachePopulationUnderway = false; + + @override + void initState() { + if (!ref.read(prefsChangeNotifierProvider).externalCalls) { + if (ExchangeDataLoadingService.currentCacheVersion < + ExchangeDataLoadingService.cacheVersion) { + _initialCachePopulationUnderway = true; + ExchangeDataLoadingService.instance.onLoadingComplete = () { + WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + setState(() { + _initialCachePopulationUnderway = false; + }); + }); + }; + } + ExchangeDataLoadingService.instance + .init() + .then((_) => ExchangeDataLoadingService.instance.loadAll()); + } else if (ExchangeDataLoadingService.instance.isLoading && + ExchangeDataLoadingService.currentCacheVersion < + ExchangeDataLoadingService.cacheVersion) { + _initialCachePopulationUnderway = true; + ExchangeDataLoadingService.instance.onLoadingComplete = () { + WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + setState(() { + _initialCachePopulationUnderway = false; + }); + }); + }; + } + + super.initState(); + } + @override Widget build(BuildContext context) { - return DesktopScaffold( - appBar: DesktopAppBar( - isCompactHeight: true, - leading: Padding( + return ConditionalParent( + condition: _initialCachePopulationUnderway, + builder: (child) { + return Stack( + children: [ + child, + Material( + color: Theme.of(context) + .extension()! + .overlay + .withOpacity(0.6), + child: const CustomLoadingOverlay( + message: "Updating exchange data", + subMessage: "This could take a few minutes", + eventBus: null, + ), + ) + ], + ); + }, + child: DesktopScaffold( + appBar: DesktopAppBar( + isCompactHeight: true, + leading: Padding( + padding: const EdgeInsets.only( + left: 24, + ), + child: Text( + "Exchange", + style: STextStyles.desktopH3(context), + ), + ), + ), + body: Padding( padding: const EdgeInsets.only( left: 24, + right: 24, + bottom: 24, ), - child: Text( - "Exchange", - style: STextStyles.desktopH3(context), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Exchange details", + style: STextStyles.desktopTextExtraExtraSmall(context), + ), + const SizedBox( + height: 16, + ), + const RoundedWhiteContainer( + padding: EdgeInsets.all(24), + child: ExchangeForm(), + ), + ], + ), + ), + const SizedBox( + width: 16, + ), + Expanded( + child: Row( + children: const [ + Expanded( + child: DesktopTradeHistory(), + ), + ], + ), + ), + ], ), ), ), - body: Padding( - padding: const EdgeInsets.only( - left: 24, - right: 24, - bottom: 24, - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Exchange details", - style: STextStyles.desktopTextExtraExtraSmall(context), - ), - const SizedBox( - height: 16, - ), - const RoundedWhiteContainer( - padding: EdgeInsets.all(24), - child: ExchangeForm(), - ), - ], - ), - ), - const SizedBox( - width: 16, - ), - Expanded( - child: Row( - children: const [ - Expanded( - child: DesktopTradeHistory(), - ), - ], - ), - ), - ], - ), - ), ); } } diff --git a/lib/pages_desktop_specific/desktop_exchange/exchange_steps/step_scaffold.dart b/lib/pages_desktop_specific/desktop_exchange/exchange_steps/step_scaffold.dart index 88a8c34ff..1c4ef0143 100644 --- a/lib/pages_desktop_specific/desktop_exchange/exchange_steps/step_scaffold.dart +++ b/lib/pages_desktop_specific/desktop_exchange/exchange_steps/step_scaffold.dart @@ -7,19 +7,19 @@ import 'package:qr_flutter/qr_flutter.dart'; import 'package:stackwallet/models/exchange/incomplete_exchange.dart'; import 'package:stackwallet/models/exchange/response_objects/trade.dart'; import 'package:stackwallet/pages/exchange_view/send_from_view.dart'; -import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart'; import 'package:stackwallet/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_1.dart'; import 'package:stackwallet/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_2.dart'; import 'package:stackwallet/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_3.dart'; import 'package:stackwallet/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_4.dart'; import 'package:stackwallet/pages_desktop_specific/desktop_exchange/subwidgets/desktop_exchange_steps_indicator.dart'; -import 'package:stackwallet/providers/exchange/exchange_provider.dart'; +import 'package:stackwallet/providers/exchange/exchange_form_state_provider.dart'; import 'package:stackwallet/providers/global/trades_service_provider.dart'; import 'package:stackwallet/route_generator.dart'; import 'package:stackwallet/services/exchange/exchange_response.dart'; import 'package:stackwallet/services/notifications_api.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/enums/exchange_rate_type_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; @@ -83,7 +83,8 @@ class _StepScaffoldState extends ConsumerState { ); final ExchangeResponse response = await ref - .read(exchangeProvider) + .read(exchangeFormStateProvider) + .exchange .createTrade( from: ref.read(desktopExchangeModelProvider)!.sendTicker, to: ref.read(desktopExchangeModelProvider)!.receiveTicker, diff --git a/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_1.dart b/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_1.dart index 4ec96f95d..b57fb1899 100644 --- a/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_1.dart +++ b/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_1.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart'; import 'package:stackwallet/pages_desktop_specific/desktop_exchange/exchange_steps/step_scaffold.dart'; import 'package:stackwallet/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_item.dart'; import 'package:stackwallet/providers/providers.dart'; +import 'package:stackwallet/utilities/enums/exchange_rate_type_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; @@ -38,7 +38,8 @@ class DesktopStep1 extends ConsumerWidget { children: [ DesktopStepItem( label: "Exchange", - value: ref.watch(currentExchangeNameStateProvider.state).state, + value: ref.watch(exchangeFormStateProvider + .select((value) => value.exchange.name)), ), Container( height: 1, diff --git a/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_3.dart b/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_3.dart index 714cee971..aeb8ece54 100644 --- a/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_3.dart +++ b/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_3.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart'; import 'package:stackwallet/pages_desktop_specific/desktop_exchange/exchange_steps/step_scaffold.dart'; import 'package:stackwallet/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_item.dart'; -import 'package:stackwallet/providers/exchange/current_exchange_name_state_provider.dart'; +import 'package:stackwallet/providers/providers.dart'; +import 'package:stackwallet/utilities/enums/exchange_rate_type_enum.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; @@ -36,7 +36,8 @@ class _DesktopStep3State extends ConsumerState { children: [ DesktopStepItem( label: "Exchange", - value: ref.watch(currentExchangeNameStateProvider.state).state, + value: ref.watch(exchangeFormStateProvider + .select((value) => value.exchange.name)), ), Container( height: 1, diff --git a/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_4.dart b/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_4.dart index 4943ed442..2654c2cea 100644 --- a/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_4.dart +++ b/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_4.dart @@ -45,7 +45,8 @@ class _DesktopStep4State extends ConsumerState { return; } - final statusResponse = await ref.read(exchangeProvider).updateTrade(trade); + final statusResponse = + await ref.read(exchangeFormStateProvider).exchange.updateTrade(trade); String status = "Waiting"; if (statusResponse.value != null) { status = statusResponse.value!.status; diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/desktop_wallet_view.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/desktop_wallet_view.dart index 8b8a65b58..2e5087c4a 100644 --- a/lib/pages_desktop_specific/my_stack_view/wallet_view/desktop_wallet_view.dart +++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/desktop_wallet_view.dart @@ -24,12 +24,15 @@ import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_ import 'package:stackwallet/services/event_bus/global_event_bus.dart'; import 'package:stackwallet/services/mixins/paynym_wallet_interface.dart'; import 'package:stackwallet/utilities/assets.dart'; +import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/backup_frequency_type.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart'; +import 'package:stackwallet/widgets/background.dart'; +import 'package:stackwallet/widgets/conditional_parent.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/custom_loading_overlay.dart'; import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart'; @@ -63,6 +66,7 @@ class _DesktopWalletViewState extends ConsumerState { late final EventBus eventBus; late final bool _shouldDisableAutoSyncOnLogOut; + bool _rescanningOnOpen = false; Future onBackPressed() async { await _logout(); @@ -265,7 +269,18 @@ class _DesktopWalletViewState extends ConsumerState { _shouldDisableAutoSyncOnLogOut = false; } - ref.read(managerProvider).refresh(); + if (ref.read(managerProvider).rescanOnOpenVersion == Constants.rescanV1) { + _rescanningOnOpen = true; + ref.read(managerProvider).fullRescan(20, 1000).then( + (_) => ref.read(managerProvider).resetRescanOnOpen().then( + (_) => WidgetsBinding.instance.addPostFrameCallback( + (_) => setState(() => _rescanningOnOpen = false), + ), + ), + ); + } else { + ref.read(managerProvider).refresh(); + } super.initState(); } @@ -284,241 +299,263 @@ class _DesktopWalletViewState extends ConsumerState { final managerProvider = ref.watch(walletsChangeNotifierProvider .select((value) => value.getManagerProvider(widget.walletId))); - return DesktopScaffold( - appBar: DesktopAppBar( - background: Theme.of(context).extension()!.popupBG, - leading: Expanded( - child: Row( - children: [ - const SizedBox( - width: 32, + return ConditionalParent( + condition: _rescanningOnOpen, + builder: (child) { + return Stack( + children: [ + child, + Background( + child: CustomLoadingOverlay( + message: + "Migration in progress\nThis could take a while\nPlease don't leave this screen", + subMessage: "This only needs to run once per wallet", + eventBus: null, + textColor: Theme.of(context).extension()!.textDark, ), - AppBarIconButton( - size: 32, - color: Theme.of(context) - .extension()! - .textFieldDefaultBG, - shadows: const [], - icon: SvgPicture.asset( - Assets.svg.arrowLeft, - width: 18, - height: 18, + ) + ], + ); + }, + child: DesktopScaffold( + appBar: DesktopAppBar( + background: Theme.of(context).extension()!.popupBG, + leading: Expanded( + child: Row( + children: [ + const SizedBox( + width: 32, + ), + AppBarIconButton( + size: 32, color: Theme.of(context) .extension()! - .topNavIconPrimary, + .textFieldDefaultBG, + shadows: const [], + icon: SvgPicture.asset( + Assets.svg.arrowLeft, + width: 18, + height: 18, + color: Theme.of(context) + .extension()! + .topNavIconPrimary, + ), + onPressed: onBackPressed, + ), + const SizedBox( + width: 15, + ), + SvgPicture.asset( + Assets.svg.iconFor(coin: coin), + width: 32, + height: 32, + ), + const SizedBox( + width: 12, + ), + ConstrainedBox( + constraints: const BoxConstraints( + minWidth: 48, + ), + child: IntrinsicWidth( + child: DesktopWalletNameField( + walletId: widget.walletId, + ), + ), + ), + const Spacer(), + Row( + children: [ + NetworkInfoButton( + walletId: widget.walletId, + eventBus: eventBus, + ), + const SizedBox( + width: 2, + ), + WalletKeysButton( + walletId: widget.walletId, + ), + const SizedBox( + width: 2, + ), + DeleteWalletButton( + walletId: widget.walletId, + ), + const SizedBox( + width: 12, + ), + ], + ), + ], + ), + ), + useSpacers: false, + isCompactHeight: true, + ), + body: Padding( + padding: const EdgeInsets.all(24), + child: Column( + children: [ + RoundedWhiteContainer( + padding: const EdgeInsets.all(20), + child: Row( + children: [ + SvgPicture.asset( + Assets.svg.iconFor(coin: coin), + width: 40, + height: 40, + ), + const SizedBox( + width: 10, + ), + DesktopWalletSummary( + walletId: widget.walletId, + managerProvider: managerProvider, + initialSyncStatus: ref.watch(managerProvider + .select((value) => value.isRefreshing)) + ? WalletSyncStatus.syncing + : WalletSyncStatus.synced, + ), + const Spacer(), + if (coin == Coin.firo) const SizedBox(width: 10), + if (coin == Coin.firo) + SecondaryButton( + width: 180, + buttonHeight: ButtonHeight.l, + label: "Anonymize funds", + onPressed: () async { + await showDialog( + context: context, + barrierDismissible: false, + builder: (context) => DesktopDialog( + maxWidth: 500, + maxHeight: 210, + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 32, vertical: 20), + child: Column( + children: [ + Text( + "Attention!", + style: STextStyles.desktopH2(context), + ), + const SizedBox(height: 16), + Text( + "You're about to anonymize all of your public funds.", + style: + STextStyles.desktopTextSmall(context), + ), + const SizedBox(height: 32), + Row( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + SecondaryButton( + width: 200, + buttonHeight: ButtonHeight.l, + label: "Cancel", + onPressed: () { + Navigator.of(context).pop(); + }, + ), + const SizedBox(width: 20), + PrimaryButton( + width: 200, + buttonHeight: ButtonHeight.l, + label: "Continue", + onPressed: () { + Navigator.of(context).pop(); + + unawaited(attemptAnonymize()); + }, + ) + ], + ), + ], + ), + ), + ), + ); + }, + ), + if (ref.watch(walletsChangeNotifierProvider.select( + (value) => value + .getManager(widget.walletId) + .hasPaynymSupport))) + SecondaryButton( + label: "PayNym", + width: 160, + buttonHeight: ButtonHeight.l, + icon: SvgPicture.asset( + Assets.svg.user, + height: 20, + width: 20, + color: Theme.of(context) + .extension()! + .buttonTextSecondary, + ), + onPressed: onPaynymButtonPressed, + ), + // if (coin == Coin.firo) const SizedBox(width: 16), + // SecondaryButton( + // width: 180, + // buttonHeight: ButtonHeight.l, + // onPressed: () { + // _onExchangePressed(context); + // }, + // label: "Exchange", + // icon: Container( + // width: 24, + // height: 24, + // decoration: BoxDecoration( + // borderRadius: BorderRadius.circular(24), + // color: Theme.of(context) + // .extension()! + // .buttonBackPrimary + // .withOpacity(0.2), + // ), + // child: Center( + // child: SvgPicture.asset( + // Assets.svg.arrowRotate2, + // width: 14, + // height: 14, + // color: Theme.of(context) + // .extension()! + // .buttonTextSecondary, + // ), + // ), + // ), + // ), + ], ), - onPressed: onBackPressed, ), const SizedBox( - width: 15, + height: 24, ), - SvgPicture.asset( - Assets.svg.iconFor(coin: coin), - width: 32, - height: 32, - ), - const SizedBox( - width: 12, - ), - ConstrainedBox( - constraints: const BoxConstraints( - minWidth: 48, + Expanded( + child: Row( + children: [ + SizedBox( + width: 450, + child: MyWallet( + walletId: widget.walletId, + ), + ), + const SizedBox( + width: 16, + ), + Expanded( + child: RecentDesktopTransactions( + walletId: widget.walletId, + ), + ), + ], ), - child: IntrinsicWidth( - child: DesktopWalletNameField( - walletId: widget.walletId, - ), - ), - ), - const Spacer(), - Row( - children: [ - NetworkInfoButton( - walletId: widget.walletId, - eventBus: eventBus, - ), - const SizedBox( - width: 2, - ), - WalletKeysButton( - walletId: widget.walletId, - ), - const SizedBox( - width: 2, - ), - DeleteWalletButton( - walletId: widget.walletId, - ), - const SizedBox( - width: 12, - ), - ], ), ], ), ), - useSpacers: false, - isCompactHeight: true, - ), - body: Padding( - padding: const EdgeInsets.all(24), - child: Column( - children: [ - RoundedWhiteContainer( - padding: const EdgeInsets.all(20), - child: Row( - children: [ - SvgPicture.asset( - Assets.svg.iconFor(coin: coin), - width: 40, - height: 40, - ), - const SizedBox( - width: 10, - ), - DesktopWalletSummary( - walletId: widget.walletId, - managerProvider: managerProvider, - initialSyncStatus: ref.watch(managerProvider - .select((value) => value.isRefreshing)) - ? WalletSyncStatus.syncing - : WalletSyncStatus.synced, - ), - const Spacer(), - if (coin == Coin.firo) const SizedBox(width: 10), - if (coin == Coin.firo) - SecondaryButton( - width: 180, - buttonHeight: ButtonHeight.l, - label: "Anonymize funds", - onPressed: () async { - await showDialog( - context: context, - barrierDismissible: false, - builder: (context) => DesktopDialog( - maxWidth: 500, - maxHeight: 210, - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 32, vertical: 20), - child: Column( - children: [ - Text( - "Attention!", - style: STextStyles.desktopH2(context), - ), - const SizedBox(height: 16), - Text( - "You're about to anonymize all of your public funds.", - style: - STextStyles.desktopTextSmall(context), - ), - const SizedBox(height: 32), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SecondaryButton( - width: 200, - buttonHeight: ButtonHeight.l, - label: "Cancel", - onPressed: () { - Navigator.of(context).pop(); - }, - ), - const SizedBox(width: 20), - PrimaryButton( - width: 200, - buttonHeight: ButtonHeight.l, - label: "Continue", - onPressed: () { - Navigator.of(context).pop(); - - unawaited(attemptAnonymize()); - }, - ) - ], - ), - ], - ), - ), - ), - ); - }, - ), - if (ref.watch(walletsChangeNotifierProvider.select((value) => - value.getManager(widget.walletId).hasPaynymSupport))) - SecondaryButton( - label: "PayNym", - width: 160, - buttonHeight: ButtonHeight.l, - icon: SvgPicture.asset( - Assets.svg.user, - height: 20, - width: 20, - color: Theme.of(context) - .extension()! - .buttonTextSecondary, - ), - onPressed: onPaynymButtonPressed, - ), - // if (coin == Coin.firo) const SizedBox(width: 16), - // SecondaryButton( - // width: 180, - // buttonHeight: ButtonHeight.l, - // onPressed: () { - // _onExchangePressed(context); - // }, - // label: "Exchange", - // icon: Container( - // width: 24, - // height: 24, - // decoration: BoxDecoration( - // borderRadius: BorderRadius.circular(24), - // color: Theme.of(context) - // .extension()! - // .buttonBackPrimary - // .withOpacity(0.2), - // ), - // child: Center( - // child: SvgPicture.asset( - // Assets.svg.arrowRotate2, - // width: 14, - // height: 14, - // color: Theme.of(context) - // .extension()! - // .buttonTextSecondary, - // ), - // ), - // ), - // ), - ], - ), - ), - const SizedBox( - height: 24, - ), - Expanded( - child: Row( - children: [ - SizedBox( - width: 450, - child: MyWallet( - walletId: widget.walletId, - ), - ), - const SizedBox( - width: 16, - ), - Expanded( - child: RecentDesktopTransactions( - walletId: widget.walletId, - ), - ), - ], - ), - ), - ], - ), ), ); } diff --git a/lib/providers/exchange/current_exchange_name_state_provider.dart b/lib/providers/exchange/current_exchange_name_state_provider.dart deleted file mode 100644 index 3dc481c8f..000000000 --- a/lib/providers/exchange/current_exchange_name_state_provider.dart +++ /dev/null @@ -1,6 +0,0 @@ -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:stackwallet/services/exchange/exchange.dart'; - -final currentExchangeNameStateProvider = StateProvider( - (ref) => Exchange.defaultExchange.name, -); diff --git a/lib/providers/exchange/exchange_provider.dart b/lib/providers/exchange/exchange_provider.dart deleted file mode 100644 index e65847a18..000000000 --- a/lib/providers/exchange/exchange_provider.dart +++ /dev/null @@ -1,9 +0,0 @@ -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:stackwallet/providers/exchange/current_exchange_name_state_provider.dart'; -import 'package:stackwallet/services/exchange/exchange.dart'; - -final exchangeProvider = Provider( - (ref) => Exchange.fromName( - ref.watch(currentExchangeNameStateProvider.state).state, - ), -); diff --git a/lib/providers/providers.dart b/lib/providers/providers.dart index 73234c464..2c027b169 100644 --- a/lib/providers/providers.dart +++ b/lib/providers/providers.dart @@ -2,10 +2,8 @@ export './buy/buy_form_state_provider.dart'; export './buy/simplex_initial_load_status.dart'; export './buy/simplex_provider.dart'; export './exchange/changenow_initial_load_status.dart'; -export './exchange/current_exchange_name_state_provider.dart'; export './exchange/exchange_flow_is_active_state_provider.dart'; export './exchange/exchange_form_state_provider.dart'; -export './exchange/exchange_provider.dart'; export './exchange/exchange_send_from_wallet_id_provider.dart'; export './exchange/trade_note_service_provider.dart'; export './exchange/trade_sent_from_stack_lookup_provider.dart'; diff --git a/lib/route_generator.dart b/lib/route_generator.dart index ec592fdf1..a9ce742ec 100644 --- a/lib/route_generator.dart +++ b/lib/route_generator.dart @@ -711,15 +711,15 @@ class RouteGenerator { return _routeError("${settings.name} invalid args: ${args.toString()}"); case RestoreWalletView.routeName: - if (args is Tuple4) { + if (args is Tuple5) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => RestoreWalletView( - walletName: args.item1, - coin: args.item2, - seedWordsLength: args.item3, - restoreFromDate: args.item4, - ), + walletName: args.item1, + coin: args.item2, + seedWordsLength: args.item3, + restoreFromDate: args.item4, + mnemonicPassphrase: args.item5), settings: RouteSettings( name: settings.name, ), diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index b6986508d..4bd4f4b31 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -871,7 +871,7 @@ class EpicCashWallet extends CoinServiceAPI publicKey: [], // ?? ); - await db.putAddress(address); + await db.updateOrPutAddresses([address]); } return address; @@ -2094,12 +2094,14 @@ class EpicCashWallet extends CoinServiceAPI height = null; } + final isIncoming = (tx["tx_type"] == "TxReceived" || + tx["tx_type"] == "TxReceivedCancelled"); + final txn = isar_models.Transaction( walletId: walletId, txid: commitId ?? tx["id"].toString(), timestamp: (dt.millisecondsSinceEpoch ~/ 1000), - type: (tx["tx_type"] == "TxReceived" || - tx["tx_type"] == "TxReceivedCancelled") + type: isIncoming ? isar_models.TransactionType.incoming : isar_models.TransactionType.outgoing, subType: isar_models.TransactionSubType.none, @@ -2122,6 +2124,38 @@ class EpicCashWallet extends CoinServiceAPI .filter() .valueEqualTo(address) .findFirst(); + + if (transactionAddress == null) { + if (isIncoming) { + transactionAddress = isar_models.Address( + walletId: walletId, + value: address, + publicKey: [], + derivationIndex: 0, + derivationPath: null, + type: isar_models.AddressType.mimbleWimble, + subType: isar_models.AddressSubType.receiving, + ); + } else { + final myRcvAddr = await currentReceivingAddress; + final isSentToSelf = myRcvAddr == address; + + transactionAddress = isar_models.Address( + walletId: walletId, + value: address, + publicKey: [], + derivationIndex: isSentToSelf ? 0 : -1, + derivationPath: null, + type: isSentToSelf + ? isar_models.AddressType.mimbleWimble + : isar_models.AddressType.nonWallet, + subType: isSentToSelf + ? isar_models.AddressSubType.receiving + : isar_models.AddressSubType.nonWallet, + ); + } + } + // // midSortedTx["inputSize"] = tx["num_inputs"]; // midSortedTx["outputSize"] = tx["num_outputs"]; diff --git a/lib/services/coins/manager.dart b/lib/services/coins/manager.dart index 1ddf4499d..a15d227c6 100644 --- a/lib/services/coins/manager.dart +++ b/lib/services/coins/manager.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:event_bus/event_bus.dart'; import 'package:flutter/material.dart'; +import 'package:stackwallet/hive/db.dart'; import 'package:stackwallet/models/balance.dart'; import 'package:stackwallet/models/isar/models/isar_models.dart' as isar_models; import 'package:stackwallet/models/models.dart'; @@ -227,4 +228,18 @@ class Manager with ChangeNotifier { int get currentHeight => _currentWallet.storedChainHeight; bool get hasPaynymSupport => _currentWallet is PaynymWalletInterface; + + int get rescanOnOpenVersion => + DB.instance.get( + boxName: DB.boxNameDBInfo, + key: "rescan_on_open_$walletId", + ) as int? ?? + 0; + + Future resetRescanOnOpen() async { + await DB.instance.delete( + key: "rescan_on_open_$walletId", + boxName: DB.boxNameDBInfo, + ); + } } diff --git a/lib/services/exchange/change_now/change_now_api.dart b/lib/services/exchange/change_now/change_now_api.dart index 4c8b1d55c..99171a62f 100644 --- a/lib/services/exchange/change_now/change_now_api.dart +++ b/lib/services/exchange/change_now/change_now_api.dart @@ -434,8 +434,27 @@ class ChangeNowAPI { final json = await _makeGetRequest(uri); try { - final value = EstimatedExchangeAmount.fromJson( - Map.from(json as Map)); + final map = Map.from(json as Map); + + if (map["error"] != null) { + if (map["error"] == "not_valid_fixed_rate_pair") { + return ExchangeResponse( + exception: PairUnavailableException( + map["message"] as String? ?? "Unsupported fixed rate pair", + ExchangeExceptionType.generic, + ), + ); + } else { + return ExchangeResponse( + exception: ExchangeException( + map["message"] as String? ?? map["error"].toString(), + ExchangeExceptionType.generic, + ), + ); + } + } + + final value = EstimatedExchangeAmount.fromJson(map); return ExchangeResponse( value: Estimate( estimatedAmount: value.estimatedAmount, diff --git a/lib/services/exchange/exchange_data_loading_service.dart b/lib/services/exchange/exchange_data_loading_service.dart index 8298aed96..3d29e038d 100644 --- a/lib/services/exchange/exchange_data_loading_service.dart +++ b/lib/services/exchange/exchange_data_loading_service.dart @@ -1,5 +1,6 @@ import 'package:flutter/foundation.dart'; import 'package:isar/isar.dart'; +import 'package:stackwallet/hive/db.dart'; import 'package:stackwallet/models/isar/exchange_cache/currency.dart'; import 'package:stackwallet/models/isar/exchange_cache/pair.dart'; import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart'; @@ -16,6 +17,25 @@ class ExchangeDataLoadingService { Isar? _isar; Isar get isar => _isar!; + VoidCallback? onLoadingError; + VoidCallback? onLoadingComplete; + + static const int cacheVersion = 1; + + static int get currentCacheVersion => + DB.instance.get( + boxName: DB.boxNameDBInfo, + key: "exchange_data_cache_version") as int? ?? + 0; + + Future _updateCurrentCacheVersion(int version) async { + await DB.instance.put( + boxName: DB.boxNameDBInfo, + key: "exchange_data_cache_version", + value: version, + ); + } + Future init() async { if (_isar != null && isar.isOpen) return; _isar = await Isar.open( @@ -25,18 +45,23 @@ class ExchangeDataLoadingService { ], directory: (await StackFileSystem.applicationIsarDirectory()).path, inspector: kDebugMode, + // inspector: false, name: "exchange_cache", ); } + bool get isLoading => _locked; + bool _locked = false; Future loadAll() async { - print("LOADINGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG: LOCKED=$_locked"); if (!_locked) { _locked = true; - print("LOADINGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG"); - final time = DateTime.now(); + Logging.instance.log( + "ExchangeDataLoadingService.loadAll starting...", + level: LogLevel.Info, + ); + final start = DateTime.now(); try { await Future.wait([ _loadChangeNowCurrencies(), @@ -46,13 +71,18 @@ class ExchangeDataLoadingService { // loadSimpleswapFloatingRateCurrencies(ref), loadMajesticBankCurrencies(), ]); - - print( - "LOADINGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG done in ${DateTime.now().difference(time).inSeconds} seconds"); + Logging.instance.log( + "ExchangeDataLoadingService.loadAll finished in ${DateTime.now().difference(start).inSeconds} seconds", + level: LogLevel.Info, + ); + onLoadingComplete?.call(); + await _updateCurrentCacheVersion(cacheVersion); } catch (e, s) { Logging.instance.log( - "ExchangeDataLoadingService.loadAll failed: $e\n$s", - level: LogLevel.Error); + "ExchangeDataLoadingService.loadAll failed after ${DateTime.now().difference(start).inSeconds} seconds: $e\n$s", + level: LogLevel.Error, + ); + onLoadingError?.call(); } _locked = false; } @@ -82,7 +112,7 @@ class ExchangeDataLoadingService { Future _loadChangeNowFixedRatePairs() async { final exchange = ChangeNowExchange.instance; - final responsePairs = await exchange.getAllPairs(true); + final responsePairs = await compute(exchange.getAllPairs, true); if (responsePairs.value != null) { await isar.writeTxn(() async { @@ -107,7 +137,7 @@ class ExchangeDataLoadingService { Future _loadChangeNowEstimatedRatePairs() async { final exchange = ChangeNowExchange.instance; - final responsePairs = await exchange.getAllPairs(false); + final responsePairs = await compute(exchange.getAllPairs, false); if (responsePairs.value != null) { await isar.writeTxn(() async { diff --git a/lib/utilities/constants.dart b/lib/utilities/constants.dart index ba128ab35..2d600b69f 100644 --- a/lib/utilities/constants.dart +++ b/lib/utilities/constants.dart @@ -21,7 +21,8 @@ abstract class Constants { } static bool enableExchange = Util.isDesktop || !Platform.isIOS; - static bool enableBuy = true; // true for development, TODO change to "Util.isDesktop || !Platform.isIOS;" as above or even just = enableExchange + static bool enableBuy = + true; // true for development, TODO change to "Util.isDesktop || !Platform.isIOS;" as above or even just = enableExchange //TODO: correct for monero? static const int _satsPerCoinMonero = 1000000000000; @@ -41,6 +42,8 @@ abstract class Constants { static const int currentHiveDbVersion = 5; + static const int rescanV1 = 1; + static int satsPerCoin(Coin coin) { switch (coin) { case Coin.bitcoin: diff --git a/lib/utilities/db_version_migration.dart b/lib/utilities/db_version_migration.dart index 45c15ab82..67e76ef29 100644 --- a/lib/utilities/db_version_migration.dart +++ b/lib/utilities/db_version_migration.dart @@ -1,5 +1,3 @@ -import 'dart:convert'; - import 'package:hive/hive.dart'; import 'package:stackwallet/db/main_db.dart'; import 'package:stackwallet/electrumx_rpc/electrumx.dart'; @@ -12,10 +10,10 @@ import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/services/mixins/wallet_db.dart'; import 'package:stackwallet/services/node_service.dart'; import 'package:stackwallet/services/wallets_service.dart'; +import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'; -import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/prefs.dart'; import 'package:tuple/tuple.dart'; @@ -200,6 +198,7 @@ class DbVersionMigrator with WalletDB { final prefs = Prefs.instance; final walletInfoList = await walletsService.walletNames; await prefs.init(); + await MainDB.instance.initMainDB(); for (final walletId in walletInfoList.keys) { final info = walletInfoList[walletId]!; @@ -207,206 +206,67 @@ class DbVersionMigrator with WalletDB { final walletBox = await Hive.openBox(info.walletId); - final receiveDerivePrefix = "${walletId}_receiveDerivations"; - final changeDerivePrefix = "${walletId}_changeDerivations"; - const receiveAddressesPrefix = "receivingAddresses"; const changeAddressesPrefix = "changeAddresses"; - final p2pkhRcvDerivations = - (await secureStore.read(key: receiveDerivePrefix)) ?? - (await secureStore.read(key: "${receiveDerivePrefix}P2PKH")); - final p2shRcvDerivations = - await secureStore.read(key: "${receiveDerivePrefix}P2SH"); - final p2wpkhRcvDerivations = - await secureStore.read(key: "${receiveDerivePrefix}P2WPKH"); + // we need to manually migrate epic cash transactions as they are not + // stored on the epic cash blockchain + if (info.coin == Coin.epicCash) { + final txnData = walletBox.get("latest_tx_model") as TransactionData?; - final p2pkhCngDerivations = - (await secureStore.read(key: changeDerivePrefix)) ?? - (await secureStore.read(key: "${changeDerivePrefix}P2PKH")); - final p2shCngDerivations = - await secureStore.read(key: "${changeDerivePrefix}P2SH"); - final p2wpkhCngDerivations = - await secureStore.read(key: "${changeDerivePrefix}P2WPKH"); + // we ever only used index 0 in the past + const rcvIndex = 0; - // useless? - // const receiveIndexPrefix = "receivingIndex"; - // const changeIndexPrefix = "changeIndex"; - // final p2pkhRcvIndex = walletBox.get(receiveIndexPrefix) as int? ?? - // walletBox.get("${receiveIndexPrefix}P2PKH") as int?; - // final p2shRcvIndex = - // walletBox.get("${receiveIndexPrefix}P2SH") as int?; - // final p2wpkhRcvIndex = - // walletBox.get("${receiveIndexPrefix}P2WPKH") as int?; - // - // final p2pkhCngIndex = walletBox.get(changeIndexPrefix) as int? ?? - // walletBox.get("${changeIndexPrefix}P2PKH") as int?; - // final p2shCngIndex = - // walletBox.get("${changeIndexPrefix}P2SH") as int?; - // final p2wpkhCngIndex = - // walletBox.get("${changeIndexPrefix}P2WPKH") as int?; + final List> + transactionsData = []; + if (txnData != null) { + final txns = txnData.getAllTransactions(); - final List newAddresses = []; + for (final tx in txns.values) { + bool isIncoming = tx.txType == "Received"; - if (p2pkhRcvDerivations != null) { - newAddresses.addAll( - _v4GetAddressesFromDerivationString( - p2pkhRcvDerivations, - isar_models.AddressType.p2pkh, - isar_models.AddressSubType.receiving, - walletId, - ), - ); - } + final iTx = isar_models.Transaction( + walletId: walletId, + txid: tx.txid, + timestamp: tx.timestamp, + type: isIncoming + ? isar_models.TransactionType.incoming + : isar_models.TransactionType.outgoing, + subType: isar_models.TransactionSubType.none, + amount: tx.amount, + fee: tx.fees, + height: tx.height, + isCancelled: tx.isCancelled, + isLelantus: false, + slateId: tx.slateId, + otherData: tx.otherData, + inputs: [], + outputs: [], + ); - if (p2shRcvDerivations != null) { - newAddresses.addAll( - _v4GetAddressesFromDerivationString( - p2shRcvDerivations, - isar_models.AddressType.p2sh, - isar_models.AddressSubType.receiving, - walletId, - ), - ); - } - - if (p2wpkhRcvDerivations != null) { - newAddresses.addAll( - _v4GetAddressesFromDerivationString( - p2wpkhRcvDerivations, - isar_models.AddressType.p2wpkh, - isar_models.AddressSubType.receiving, - walletId, - ), - ); - } - - if (p2pkhCngDerivations != null) { - newAddresses.addAll( - _v4GetAddressesFromDerivationString( - p2pkhCngDerivations, - isar_models.AddressType.p2pkh, - isar_models.AddressSubType.change, - walletId, - ), - ); - } - - if (p2shCngDerivations != null) { - newAddresses.addAll( - _v4GetAddressesFromDerivationString( - p2shCngDerivations, - isar_models.AddressType.p2sh, - isar_models.AddressSubType.change, - walletId, - ), - ); - } - - if (p2wpkhCngDerivations != null) { - newAddresses.addAll( - _v4GetAddressesFromDerivationString( - p2wpkhCngDerivations, - isar_models.AddressType.p2wpkh, - isar_models.AddressSubType.change, - walletId, - ), - ); - } - - final currentNewSet = newAddresses.map((e) => e.value).toSet(); - - final p2pkhRcvAddresses = _v4GetAddressesFromList( - _getList(walletBox.get(receiveAddressesPrefix) ?? - walletBox.get("${receiveAddressesPrefix}P2PKH")), - isar_models.AddressType.p2pkh, - isar_models.AddressSubType.receiving, - walletId); - for (final address in p2pkhRcvAddresses) { - if (!currentNewSet.contains(address.value)) { - newAddresses.add(address); + if (tx.address.isEmpty) { + transactionsData.add(Tuple2(iTx, null)); + } else { + final address = isar_models.Address( + walletId: walletId, + value: tx.address, + publicKey: [], + derivationIndex: isIncoming ? rcvIndex : -1, + derivationPath: null, + type: isIncoming + ? isar_models.AddressType.mimbleWimble + : isar_models.AddressType.unknown, + subType: isIncoming + ? isar_models.AddressSubType.receiving + : isar_models.AddressSubType.unknown, + ); + transactionsData.add(Tuple2(iTx, address)); + } + } } + await MainDB.instance.addNewTransactionData(transactionsData, walletId); } - final p2shRcvAddresses = _v4GetAddressesFromList( - _getList(walletBox.get("${receiveAddressesPrefix}P2SH")), - isar_models.AddressType.p2sh, - isar_models.AddressSubType.receiving, - walletId); - for (final address in p2shRcvAddresses) { - if (!currentNewSet.contains(address.value)) { - newAddresses.add(address); - } - } - - final p2wpkhRcvAddresses = _v4GetAddressesFromList( - _getList(walletBox.get("${receiveAddressesPrefix}P2WPKH")), - isar_models.AddressType.p2wpkh, - isar_models.AddressSubType.receiving, - walletId); - for (final address in p2wpkhRcvAddresses) { - if (!currentNewSet.contains(address.value)) { - newAddresses.add(address); - } - } - - final p2pkhCngAddresses = _v4GetAddressesFromList( - _getList(walletBox.get(changeAddressesPrefix) ?? - walletBox.get("${changeAddressesPrefix}P2PKH")), - isar_models.AddressType.p2wpkh, - isar_models.AddressSubType.change, - walletId); - for (final address in p2pkhCngAddresses) { - if (!currentNewSet.contains(address.value)) { - newAddresses.add(address); - } - } - - final p2shCngAddresses = _v4GetAddressesFromList( - _getList(walletBox.get("${changeAddressesPrefix}P2SH")), - isar_models.AddressType.p2wpkh, - isar_models.AddressSubType.change, - walletId); - for (final address in p2shCngAddresses) { - if (!currentNewSet.contains(address.value)) { - newAddresses.add(address); - } - } - - final p2wpkhCngAddresses = _v4GetAddressesFromList( - _getList(walletBox.get("${changeAddressesPrefix}P2WPKH")), - isar_models.AddressType.p2wpkh, - isar_models.AddressSubType.change, - walletId); - for (final address in p2wpkhCngAddresses) { - if (!currentNewSet.contains(address.value)) { - newAddresses.add(address); - } - } - - // transactions - final txnData = walletBox.get("latest_tx_model") as TransactionData?; - final txns = txnData?.getAllTransactions().values ?? []; - final txnDataLelantus = - walletBox.get("latest_lelantus_tx_model") as TransactionData?; - final txnsLelantus = txnDataLelantus?.getAllTransactions().values ?? []; - - final List> - newTransactions = []; - - newTransactions - .addAll(_parseTransactions(txns, walletId, false, newAddresses)); - newTransactions.addAll( - _parseTransactions(txnsLelantus, walletId, true, newAddresses)); - - // store newly parsed data in isar - await MainDB.instance.initMainDB(); - initWalletDB(); - await db.isar.writeTxn(() async { - await db.isar.addresses.putAll(newAddresses); - }); - await db.addNewTransactionData(newTransactions, walletId); - // delete data from hive await walletBox.delete(receiveAddressesPrefix); await walletBox.delete("${receiveAddressesPrefix}P2PKH"); @@ -418,154 +278,24 @@ class DbVersionMigrator with WalletDB { await walletBox.delete("${changeAddressesPrefix}P2WPKH"); await walletBox.delete("latest_tx_model"); await walletBox.delete("latest_lelantus_tx_model"); - } - } - List> - _parseTransactions( - Iterable txns, - String walletId, - bool isLelantus, - List parsedAddresses, - ) { - List> transactions = - []; - for (final tx in txns) { - final type = tx.txType.toLowerCase() == "received" - ? isar_models.TransactionType.incoming - : isar_models.TransactionType.outgoing; - final subType = tx.subType.toLowerCase() == "mint" - ? isar_models.TransactionSubType.mint - : tx.subType.toLowerCase() == "join" - ? isar_models.TransactionSubType.join - : isar_models.TransactionSubType.none; + // set empty mnemonic passphrase as we used that by default before + if ((await secureStore.read(key: '${walletId}_mnemonicPassphrase')) == + null) { + await secureStore.write( + key: '${walletId}_mnemonicPassphrase', value: ""); + } - final List inputs = []; - final List outputs = []; - - for (final inp in tx.inputs) { - final input = isar_models.Input( - txid: inp.txid, - vout: inp.vout, - scriptSig: inp.scriptsig, - scriptSigAsm: inp.scriptsigAsm, - isCoinbase: inp.isCoinbase, - sequence: inp.sequence, - innerRedeemScriptAsm: inp.innerRedeemscriptAsm, + // doing this for epic cash will delete transaction history as it is not + // stored on the epic cash blockchain + if (info.coin != Coin.epicCash) { + // set flag to initiate full rescan on opening wallet + await DB.instance.put( + boxName: DB.boxNameDBInfo, + key: "rescan_on_open_$walletId", + value: Constants.rescanV1, ); - inputs.add(input); } - for (final out in tx.outputs) { - final output = isar_models.Output( - scriptPubKey: out.scriptpubkey, - scriptPubKeyAsm: out.scriptpubkeyAsm, - scriptPubKeyType: out.scriptpubkeyType, - scriptPubKeyAddress: out.scriptpubkeyAddress, - value: out.value, - ); - outputs.add(output); - } - - final transaction = isar_models.Transaction( - walletId: walletId, - txid: tx.txid, - timestamp: tx.timestamp, - type: type, - subType: subType, - amount: tx.amount, - fee: tx.fees, - height: tx.height, - isCancelled: tx.isCancelled, - isLelantus: false, - slateId: tx.slateId, - otherData: tx.otherData, - inputs: inputs, - outputs: outputs, - ); - - isar_models.Address? address; - if (tx.address.isNotEmpty) { - final addresses = parsedAddresses.where((e) => e.value == tx.address); - if (addresses.isNotEmpty) { - address = addresses.first; - } else { - address = isar_models.Address( - walletId: walletId, - value: tx.address, - publicKey: [], - derivationIndex: -1, - derivationPath: null, - type: isar_models.AddressType.unknown, - subType: type == isar_models.TransactionType.incoming - ? isar_models.AddressSubType.receiving - : isar_models.AddressSubType.unknown, - ); - } - } - - transactions.add(Tuple2(transaction, address)); } - return transactions; - } - - List _v4GetAddressesFromDerivationString( - String derivationsString, - isar_models.AddressType type, - isar_models.AddressSubType subType, - String walletId, - ) { - final List addresses = []; - - final derivations = - Map.from(jsonDecode(derivationsString) as Map); - - for (final entry in derivations.entries) { - final addr = entry.value["address"] as String? ?? entry.key; - final pubKey = entry.value["pubKey"] as String? ?? - entry.value["publicKey"] as String; - final index = int.tryParse(entry.key) ?? -1; - - final address = isar_models.Address( - walletId: walletId, - value: addr, - publicKey: Format.stringToUint8List(pubKey), - derivationIndex: index, - derivationPath: null, // we have no idea what the full path is - type: type, - subType: subType, - ); - addresses.add(address); - } - - return addresses; - } - - List _v4GetAddressesFromList( - List addressStrings, - isar_models.AddressType type, - isar_models.AddressSubType subType, - String walletId, - ) { - final List addresses = []; - - for (final addr in addressStrings) { - final address = isar_models.Address( - walletId: walletId, - value: addr, - publicKey: [], - derivationIndex: -1, - derivationPath: null, // index unknown - type: type, - subType: subType, - ); - addresses.add(address); - } - - return addresses; - } - - List _getList(dynamic list) { - if (list == null) return []; - return List.from(list as List); } } diff --git a/lib/utilities/enums/exchange_rate_type_enum.dart b/lib/utilities/enums/exchange_rate_type_enum.dart new file mode 100644 index 000000000..2b6267805 --- /dev/null +++ b/lib/utilities/enums/exchange_rate_type_enum.dart @@ -0,0 +1 @@ +enum ExchangeRateType { estimated, fixed } diff --git a/lib/utilities/prefs.dart b/lib/utilities/prefs.dart index 14f95d039..f803ff9b2 100644 --- a/lib/utilities/prefs.dart +++ b/lib/utilities/prefs.dart @@ -1,6 +1,5 @@ import 'package:flutter/cupertino.dart'; import 'package:stackwallet/hive/db.dart'; -import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/backup_frequency_type.dart'; import 'package:stackwallet/utilities/enums/languages_enum.dart'; @@ -18,7 +17,7 @@ class Prefs extends ChangeNotifier { Future init() async { if (!_initialized) { _currency = await _getPreferredCurrency(); - _exchangeRateType = await _getExchangeRateType(); + // _exchangeRateType = await _getExchangeRateType(); _useBiometrics = await _getUseBiometrics(); _hasPin = await _getHasPin(); _language = await _getPreferredLanguage(); @@ -251,44 +250,44 @@ class Prefs extends ChangeNotifier { // exchange rate type - ExchangeRateType _exchangeRateType = ExchangeRateType.estimated; - - ExchangeRateType get exchangeRateType => _exchangeRateType; - - set exchangeRateType(ExchangeRateType exchangeRateType) { - if (_exchangeRateType != exchangeRateType) { - switch (exchangeRateType) { - case ExchangeRateType.estimated: - DB.instance.put( - boxName: DB.boxNamePrefs, - key: "exchangeRateType", - value: "estimated"); - break; - case ExchangeRateType.fixed: - DB.instance.put( - boxName: DB.boxNamePrefs, - key: "exchangeRateType", - value: "fixed"); - break; - } - _exchangeRateType = exchangeRateType; - notifyListeners(); - } - } - - Future _getExchangeRateType() async { - String? rate = await DB.instance.get( - boxName: DB.boxNamePrefs, key: "exchangeRateType") as String?; - rate ??= "estimated"; - switch (rate) { - case "estimated": - return ExchangeRateType.estimated; - case "fixed": - return ExchangeRateType.fixed; - default: - throw Exception("Invalid exchange rate type found in prefs!"); - } - } + // ExchangeRateType _exchangeRateType = ExchangeRateType.estimated; + // + // ExchangeRateType get exchangeRateType => _exchangeRateType; + // + // set exchangeRateType(ExchangeRateType exchangeRateType) { + // if (_exchangeRateType != exchangeRateType) { + // switch (exchangeRateType) { + // case ExchangeRateType.estimated: + // DB.instance.put( + // boxName: DB.boxNamePrefs, + // key: "exchangeRateType", + // value: "estimated"); + // break; + // case ExchangeRateType.fixed: + // DB.instance.put( + // boxName: DB.boxNamePrefs, + // key: "exchangeRateType", + // value: "fixed"); + // break; + // } + // _exchangeRateType = exchangeRateType; + // notifyListeners(); + // } + // } + // + // Future _getExchangeRateType() async { + // String? rate = await DB.instance.get( + // boxName: DB.boxNamePrefs, key: "exchangeRateType") as String?; + // rate ??= "estimated"; + // switch (rate) { + // case "estimated": + // return ExchangeRateType.estimated; + // case "fixed": + // return ExchangeRateType.fixed; + // default: + // throw Exception("Invalid exchange rate type found in prefs!"); + // } + // } // use biometrics diff --git a/lib/widgets/custom_loading_overlay.dart b/lib/widgets/custom_loading_overlay.dart index c92d7705d..e05158bc4 100644 --- a/lib/widgets/custom_loading_overlay.dart +++ b/lib/widgets/custom_loading_overlay.dart @@ -11,11 +11,15 @@ class CustomLoadingOverlay extends ConsumerStatefulWidget { const CustomLoadingOverlay({ Key? key, required this.message, + this.subMessage, required this.eventBus, + this.textColor, }) : super(key: key); final String message; + final String? subMessage; final EventBus? eventBus; + final Color? textColor; @override ConsumerState createState() => @@ -56,10 +60,12 @@ class _CustomLoadingOverlayState extends ConsumerState { children: [ Text( widget.message, + textAlign: TextAlign.center, style: STextStyles.pageTitleH2(context).copyWith( - color: Theme.of(context) - .extension()! - .loadingOverlayTextColor, + color: widget.textColor ?? + Theme.of(context) + .extension()! + .loadingOverlayTextColor, ), ), if (widget.eventBus != null) @@ -70,11 +76,28 @@ class _CustomLoadingOverlayState extends ConsumerState { Text( "${(_percent * 100).toStringAsFixed(2)}%", style: STextStyles.pageTitleH2(context).copyWith( - color: Theme.of(context) - .extension()! - .loadingOverlayTextColor, + color: widget.textColor ?? + Theme.of(context) + .extension()! + .loadingOverlayTextColor, ), ), + if (widget.subMessage != null) + const SizedBox( + height: 10, + ), + if (widget.subMessage != null) + Text( + widget.subMessage!, + textAlign: TextAlign.center, + style: STextStyles.pageTitleH2(context).copyWith( + fontSize: 14, + color: widget.textColor ?? + Theme.of(context) + .extension()! + .loadingOverlayTextColor, + ), + ) ], ), ), diff --git a/lib/widgets/textfields/exchange_textfield.dart b/lib/widgets/textfields/exchange_textfield.dart index 9003046ec..33fc6d738 100644 --- a/lib/widgets/textfields/exchange_textfield.dart +++ b/lib/widgets/textfields/exchange_textfield.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:stackwallet/models/exchange/aggregate_currency.dart'; import 'package:stackwallet/pages/buy_view/sub_widgets/crypto_selection_view.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/text_styles.dart'; @@ -23,8 +24,7 @@ class ExchangeTextField extends StatefulWidget { this.onSubmitted, this.onTap, required this.isWalletCoin, - this.image, - this.ticker, + this.currency, this.readOnly = false, }) : super(key: key); @@ -42,8 +42,7 @@ class ExchangeTextField extends StatefulWidget { final bool isWalletCoin; final bool readOnly; - final String? image; - final String? ticker; + final AggregateCurrency? currency; @override State createState() => _ExchangeTextFieldState(); @@ -115,7 +114,7 @@ class _ExchangeTextFieldState extends State { top: 12, left: 12, ), - hintText: "0", + hintText: widget.currency == null ? "select currency" : "0", hintStyle: STextStyles.fieldLabel(context).copyWith( fontSize: 14, ), @@ -157,18 +156,18 @@ class _ExchangeTextFieldState extends State { ), child: Builder( builder: (context) { - if (isStackCoin(widget.ticker)) { + if (isStackCoin(widget.currency?.ticker)) { return Center( child: getIconForTicker( - widget.ticker!, + widget.currency!.ticker, size: 18, ), ); - } else if (widget.image != null && - widget.image!.isNotEmpty) { + } else if (widget.currency != null && + widget.currency!.image.isNotEmpty) { return Center( child: SvgPicture.network( - widget.image!, + widget.currency!.image, height: 18, placeholderBuilder: (_) => Container( width: 18, @@ -215,7 +214,7 @@ class _ExchangeTextFieldState extends State { width: 6, ), Text( - widget.ticker?.toUpperCase() ?? "-", + widget.currency?.ticker.toUpperCase() ?? "n/a", style: STextStyles.smallMed14(context).copyWith( color: Theme.of(context) .extension()! diff --git a/test/cached_electrumx_test.mocks.dart b/test/cached_electrumx_test.mocks.dart index 191f34b67..e447b3384 100644 --- a/test/cached_electrumx_test.mocks.dart +++ b/test/cached_electrumx_test.mocks.dart @@ -4,14 +4,12 @@ // ignore_for_file: no_leading_underscores_for_library_prefixes import 'dart:async' as _i4; -import 'dart:ui' as _i9; +import 'dart:ui' as _i8; import 'package:decimal/decimal.dart' as _i2; import 'package:mockito/mockito.dart' as _i1; import 'package:stackwallet/electrumx_rpc/electrumx.dart' as _i3; -import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart' - as _i7; -import 'package:stackwallet/utilities/enums/backup_frequency_type.dart' as _i8; +import 'package:stackwallet/utilities/enums/backup_frequency_type.dart' as _i7; import 'package:stackwallet/utilities/enums/sync_type_enum.dart' as _i6; import 'package:stackwallet/utilities/prefs.dart' as _i5; @@ -511,20 +509,6 @@ class MockPrefs extends _i1.Mock implements _i5.Prefs { returnValueForMissingStub: null, ); @override - _i7.ExchangeRateType get exchangeRateType => (super.noSuchMethod( - Invocation.getter(#exchangeRateType), - returnValue: _i7.ExchangeRateType.estimated, - ) as _i7.ExchangeRateType); - @override - set exchangeRateType(_i7.ExchangeRateType? exchangeRateType) => - super.noSuchMethod( - Invocation.setter( - #exchangeRateType, - exchangeRateType, - ), - returnValueForMissingStub: null, - ); - @override bool get useBiometrics => (super.noSuchMethod( Invocation.getter(#useBiometrics), returnValue: false, @@ -598,12 +582,12 @@ class MockPrefs extends _i1.Mock implements _i5.Prefs { returnValueForMissingStub: null, ); @override - _i8.BackupFrequencyType get backupFrequencyType => (super.noSuchMethod( + _i7.BackupFrequencyType get backupFrequencyType => (super.noSuchMethod( Invocation.getter(#backupFrequencyType), - returnValue: _i8.BackupFrequencyType.everyTenMinutes, - ) as _i8.BackupFrequencyType); + returnValue: _i7.BackupFrequencyType.everyTenMinutes, + ) as _i7.BackupFrequencyType); @override - set backupFrequencyType(_i8.BackupFrequencyType? backupFrequencyType) => + set backupFrequencyType(_i7.BackupFrequencyType? backupFrequencyType) => super.noSuchMethod( Invocation.setter( #backupFrequencyType, @@ -717,7 +701,7 @@ class MockPrefs extends _i1.Mock implements _i5.Prefs { returnValueForMissingStub: _i4.Future.value(), ) as _i4.Future); @override - void addListener(_i9.VoidCallback? listener) => super.noSuchMethod( + void addListener(_i8.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, [listener], @@ -725,7 +709,7 @@ class MockPrefs extends _i1.Mock implements _i5.Prefs { returnValueForMissingStub: null, ); @override - void removeListener(_i9.VoidCallback? listener) => super.noSuchMethod( + void removeListener(_i8.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #removeListener, [listener], diff --git a/test/electrumx_test.mocks.dart b/test/electrumx_test.mocks.dart index 5515acfb7..299386599 100644 --- a/test/electrumx_test.mocks.dart +++ b/test/electrumx_test.mocks.dart @@ -4,13 +4,11 @@ // ignore_for_file: no_leading_underscores_for_library_prefixes import 'dart:async' as _i3; -import 'dart:ui' as _i8; +import 'dart:ui' as _i7; import 'package:mockito/mockito.dart' as _i1; import 'package:stackwallet/electrumx_rpc/rpc.dart' as _i2; -import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart' - as _i6; -import 'package:stackwallet/utilities/enums/backup_frequency_type.dart' as _i7; +import 'package:stackwallet/utilities/enums/backup_frequency_type.dart' as _i6; import 'package:stackwallet/utilities/enums/sync_type_enum.dart' as _i5; import 'package:stackwallet/utilities/prefs.dart' as _i4; @@ -232,20 +230,6 @@ class MockPrefs extends _i1.Mock implements _i4.Prefs { returnValueForMissingStub: null, ); @override - _i6.ExchangeRateType get exchangeRateType => (super.noSuchMethod( - Invocation.getter(#exchangeRateType), - returnValue: _i6.ExchangeRateType.estimated, - ) as _i6.ExchangeRateType); - @override - set exchangeRateType(_i6.ExchangeRateType? exchangeRateType) => - super.noSuchMethod( - Invocation.setter( - #exchangeRateType, - exchangeRateType, - ), - returnValueForMissingStub: null, - ); - @override bool get useBiometrics => (super.noSuchMethod( Invocation.getter(#useBiometrics), returnValue: false, @@ -319,12 +303,12 @@ class MockPrefs extends _i1.Mock implements _i4.Prefs { returnValueForMissingStub: null, ); @override - _i7.BackupFrequencyType get backupFrequencyType => (super.noSuchMethod( + _i6.BackupFrequencyType get backupFrequencyType => (super.noSuchMethod( Invocation.getter(#backupFrequencyType), - returnValue: _i7.BackupFrequencyType.everyTenMinutes, - ) as _i7.BackupFrequencyType); + returnValue: _i6.BackupFrequencyType.everyTenMinutes, + ) as _i6.BackupFrequencyType); @override - set backupFrequencyType(_i7.BackupFrequencyType? backupFrequencyType) => + set backupFrequencyType(_i6.BackupFrequencyType? backupFrequencyType) => super.noSuchMethod( Invocation.setter( #backupFrequencyType, @@ -438,7 +422,7 @@ class MockPrefs extends _i1.Mock implements _i4.Prefs { returnValueForMissingStub: _i3.Future.value(), ) as _i3.Future); @override - void addListener(_i8.VoidCallback? listener) => super.noSuchMethod( + void addListener(_i7.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, [listener], @@ -446,7 +430,7 @@ class MockPrefs extends _i1.Mock implements _i4.Prefs { returnValueForMissingStub: null, ); @override - void removeListener(_i8.VoidCallback? listener) => super.noSuchMethod( + void removeListener(_i7.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #removeListener, [listener], diff --git a/test/pages/send_view/send_view_test.mocks.dart b/test/pages/send_view/send_view_test.mocks.dart index 032983189..47721c0b0 100644 --- a/test/pages/send_view/send_view_test.mocks.dart +++ b/test/pages/send_view/send_view_test.mocks.dart @@ -19,8 +19,6 @@ import 'package:stackwallet/models/balance.dart' as _i12; import 'package:stackwallet/models/isar/models/isar_models.dart' as _i16; import 'package:stackwallet/models/node_model.dart' as _i24; import 'package:stackwallet/models/paymint/fee_object_model.dart' as _i9; -import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart' - as _i30; import 'package:stackwallet/services/coins/bitcoin/bitcoin_wallet.dart' as _i25; import 'package:stackwallet/services/coins/coin_service.dart' as _i18; import 'package:stackwallet/services/coins/manager.dart' as _i6; @@ -30,7 +28,7 @@ import 'package:stackwallet/services/transaction_notification_tracker.dart' as _i8; import 'package:stackwallet/services/wallets.dart' as _i19; import 'package:stackwallet/services/wallets_service.dart' as _i2; -import 'package:stackwallet/utilities/enums/backup_frequency_type.dart' as _i31; +import 'package:stackwallet/utilities/enums/backup_frequency_type.dart' as _i30; import 'package:stackwallet/utilities/enums/coin_enum.dart' as _i20; import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart' as _i26; import 'package:stackwallet/utilities/enums/sync_type_enum.dart' as _i29; @@ -2307,20 +2305,6 @@ class MockPrefs extends _i1.Mock implements _i22.Prefs { returnValueForMissingStub: null, ); @override - _i30.ExchangeRateType get exchangeRateType => (super.noSuchMethod( - Invocation.getter(#exchangeRateType), - returnValue: _i30.ExchangeRateType.estimated, - ) as _i30.ExchangeRateType); - @override - set exchangeRateType(_i30.ExchangeRateType? exchangeRateType) => - super.noSuchMethod( - Invocation.setter( - #exchangeRateType, - exchangeRateType, - ), - returnValueForMissingStub: null, - ); - @override bool get useBiometrics => (super.noSuchMethod( Invocation.getter(#useBiometrics), returnValue: false, @@ -2394,12 +2378,12 @@ class MockPrefs extends _i1.Mock implements _i22.Prefs { returnValueForMissingStub: null, ); @override - _i31.BackupFrequencyType get backupFrequencyType => (super.noSuchMethod( + _i30.BackupFrequencyType get backupFrequencyType => (super.noSuchMethod( Invocation.getter(#backupFrequencyType), - returnValue: _i31.BackupFrequencyType.everyTenMinutes, - ) as _i31.BackupFrequencyType); + returnValue: _i30.BackupFrequencyType.everyTenMinutes, + ) as _i30.BackupFrequencyType); @override - set backupFrequencyType(_i31.BackupFrequencyType? backupFrequencyType) => + set backupFrequencyType(_i30.BackupFrequencyType? backupFrequencyType) => super.noSuchMethod( Invocation.setter( #backupFrequencyType, @@ -2693,6 +2677,11 @@ class MockManager extends _i1.Mock implements _i6.Manager { returnValue: false, ) as bool); @override + int get rescanOnOpenVersion => (super.noSuchMethod( + Invocation.getter(#rescanOnOpenVersion), + returnValue: 0, + ) as int); + @override bool get hasListeners => (super.noSuchMethod( Invocation.getter(#hasListeners), returnValue: false, @@ -2858,6 +2847,15 @@ class MockManager extends _i1.Mock implements _i6.Manager { returnValue: _i21.Future.value(false), ) as _i21.Future); @override + _i21.Future resetRescanOnOpen() => (super.noSuchMethod( + Invocation.method( + #resetRescanOnOpen, + [], + ), + returnValue: _i21.Future.value(), + returnValueForMissingStub: _i21.Future.value(), + ) as _i21.Future); + @override void addListener(_i23.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, diff --git a/test/screen_tests/address_book_view/subviews/add_address_book_view_screen_test.mocks.dart b/test/screen_tests/address_book_view/subviews/add_address_book_view_screen_test.mocks.dart index 313bff98a..38d959835 100644 --- a/test/screen_tests/address_book_view/subviews/add_address_book_view_screen_test.mocks.dart +++ b/test/screen_tests/address_book_view/subviews/add_address_book_view_screen_test.mocks.dart @@ -373,6 +373,11 @@ class MockManager extends _i1.Mock implements _i11.Manager { returnValue: false, ) as bool); @override + int get rescanOnOpenVersion => (super.noSuchMethod( + Invocation.getter(#rescanOnOpenVersion), + returnValue: 0, + ) as int); + @override bool get hasListeners => (super.noSuchMethod( Invocation.getter(#hasListeners), returnValue: false, @@ -538,6 +543,15 @@ class MockManager extends _i1.Mock implements _i11.Manager { returnValue: _i8.Future.value(false), ) as _i8.Future); @override + _i8.Future resetRescanOnOpen() => (super.noSuchMethod( + Invocation.method( + #resetRescanOnOpen, + [], + ), + returnValue: _i8.Future.value(), + returnValueForMissingStub: _i8.Future.value(), + ) as _i8.Future); + @override void addListener(_i10.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, diff --git a/test/screen_tests/address_book_view/subviews/address_book_entry_details_view_screen_test.mocks.dart b/test/screen_tests/address_book_view/subviews/address_book_entry_details_view_screen_test.mocks.dart index b5178f2a0..0d3123461 100644 --- a/test/screen_tests/address_book_view/subviews/address_book_entry_details_view_screen_test.mocks.dart +++ b/test/screen_tests/address_book_view/subviews/address_book_entry_details_view_screen_test.mocks.dart @@ -334,6 +334,11 @@ class MockManager extends _i1.Mock implements _i9.Manager { returnValue: false, ) as bool); @override + int get rescanOnOpenVersion => (super.noSuchMethod( + Invocation.getter(#rescanOnOpenVersion), + returnValue: 0, + ) as int); + @override bool get hasListeners => (super.noSuchMethod( Invocation.getter(#hasListeners), returnValue: false, @@ -499,6 +504,15 @@ class MockManager extends _i1.Mock implements _i9.Manager { returnValue: _i7.Future.value(false), ) as _i7.Future); @override + _i7.Future resetRescanOnOpen() => (super.noSuchMethod( + Invocation.method( + #resetRescanOnOpen, + [], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + @override void addListener(_i8.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, diff --git a/test/screen_tests/address_book_view/subviews/edit_address_book_entry_view_screen_test.mocks.dart b/test/screen_tests/address_book_view/subviews/edit_address_book_entry_view_screen_test.mocks.dart index cc6e3fe1e..fa15063f7 100644 --- a/test/screen_tests/address_book_view/subviews/edit_address_book_entry_view_screen_test.mocks.dart +++ b/test/screen_tests/address_book_view/subviews/edit_address_book_entry_view_screen_test.mocks.dart @@ -332,6 +332,11 @@ class MockManager extends _i1.Mock implements _i9.Manager { returnValue: false, ) as bool); @override + int get rescanOnOpenVersion => (super.noSuchMethod( + Invocation.getter(#rescanOnOpenVersion), + returnValue: 0, + ) as int); + @override bool get hasListeners => (super.noSuchMethod( Invocation.getter(#hasListeners), returnValue: false, @@ -497,6 +502,15 @@ class MockManager extends _i1.Mock implements _i9.Manager { returnValue: _i7.Future.value(false), ) as _i7.Future); @override + _i7.Future resetRescanOnOpen() => (super.noSuchMethod( + Invocation.method( + #resetRescanOnOpen, + [], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + @override void addListener(_i8.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, diff --git a/test/screen_tests/exchange/exchange_view_test.mocks.dart b/test/screen_tests/exchange/exchange_view_test.mocks.dart index 752d1ef0f..767b18bb6 100644 --- a/test/screen_tests/exchange/exchange_view_test.mocks.dart +++ b/test/screen_tests/exchange/exchange_view_test.mocks.dart @@ -3,36 +3,33 @@ // Do not manually edit this file. // ignore_for_file: no_leading_underscores_for_library_prefixes -import 'dart:async' as _i7; -import 'dart:ui' as _i8; +import 'dart:async' as _i6; +import 'dart:ui' as _i7; -import 'package:decimal/decimal.dart' as _i15; -import 'package:http/http.dart' as _i13; +import 'package:decimal/decimal.dart' as _i14; +import 'package:http/http.dart' as _i12; import 'package:mockito/mockito.dart' as _i1; import 'package:stackwallet/models/exchange/change_now/cn_exchange_estimate.dart' - as _i18; -import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart' - as _i20; -import 'package:stackwallet/models/exchange/change_now/exchange_transaction_status.dart' - as _i21; -import 'package:stackwallet/models/exchange/response_objects/estimate.dart' as _i17; -import 'package:stackwallet/models/exchange/response_objects/fixed_rate_market.dart' +import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart' as _i19; -import 'package:stackwallet/models/exchange/response_objects/range.dart' +import 'package:stackwallet/models/exchange/change_now/exchange_transaction_status.dart' + as _i20; +import 'package:stackwallet/models/exchange/response_objects/estimate.dart' as _i16; -import 'package:stackwallet/models/exchange/response_objects/trade.dart' - as _i10; -import 'package:stackwallet/models/isar/exchange_cache/currency.dart' as _i14; -import 'package:stackwallet/models/isar/exchange_cache/pair.dart' as _i22; -import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart' - as _i5; +import 'package:stackwallet/models/exchange/response_objects/fixed_rate_market.dart' + as _i18; +import 'package:stackwallet/models/exchange/response_objects/range.dart' + as _i15; +import 'package:stackwallet/models/exchange/response_objects/trade.dart' as _i9; +import 'package:stackwallet/models/isar/exchange_cache/currency.dart' as _i13; +import 'package:stackwallet/models/isar/exchange_cache/pair.dart' as _i21; import 'package:stackwallet/services/exchange/change_now/change_now_api.dart' - as _i12; + as _i11; import 'package:stackwallet/services/exchange/exchange_response.dart' as _i2; -import 'package:stackwallet/services/trade_notes_service.dart' as _i11; -import 'package:stackwallet/services/trade_service.dart' as _i9; -import 'package:stackwallet/utilities/enums/backup_frequency_type.dart' as _i6; +import 'package:stackwallet/services/trade_notes_service.dart' as _i10; +import 'package:stackwallet/services/trade_service.dart' as _i8; +import 'package:stackwallet/utilities/enums/backup_frequency_type.dart' as _i5; import 'package:stackwallet/utilities/enums/sync_type_enum.dart' as _i4; import 'package:stackwallet/utilities/prefs.dart' as _i3; @@ -182,20 +179,6 @@ class MockPrefs extends _i1.Mock implements _i3.Prefs { returnValueForMissingStub: null, ); @override - _i5.ExchangeRateType get exchangeRateType => (super.noSuchMethod( - Invocation.getter(#exchangeRateType), - returnValue: _i5.ExchangeRateType.estimated, - ) as _i5.ExchangeRateType); - @override - set exchangeRateType(_i5.ExchangeRateType? exchangeRateType) => - super.noSuchMethod( - Invocation.setter( - #exchangeRateType, - exchangeRateType, - ), - returnValueForMissingStub: null, - ); - @override bool get useBiometrics => (super.noSuchMethod( Invocation.getter(#useBiometrics), returnValue: false, @@ -269,12 +252,12 @@ class MockPrefs extends _i1.Mock implements _i3.Prefs { returnValueForMissingStub: null, ); @override - _i6.BackupFrequencyType get backupFrequencyType => (super.noSuchMethod( + _i5.BackupFrequencyType get backupFrequencyType => (super.noSuchMethod( Invocation.getter(#backupFrequencyType), - returnValue: _i6.BackupFrequencyType.everyTenMinutes, - ) as _i6.BackupFrequencyType); + returnValue: _i5.BackupFrequencyType.everyTenMinutes, + ) as _i5.BackupFrequencyType); @override - set backupFrequencyType(_i6.BackupFrequencyType? backupFrequencyType) => + set backupFrequencyType(_i5.BackupFrequencyType? backupFrequencyType) => super.noSuchMethod( Invocation.setter( #backupFrequencyType, @@ -344,51 +327,51 @@ class MockPrefs extends _i1.Mock implements _i3.Prefs { returnValue: false, ) as bool); @override - _i7.Future init() => (super.noSuchMethod( + _i6.Future init() => (super.noSuchMethod( Invocation.method( #init, [], ), - returnValue: _i7.Future.value(), - returnValueForMissingStub: _i7.Future.value(), - ) as _i7.Future); + returnValue: _i6.Future.value(), + returnValueForMissingStub: _i6.Future.value(), + ) as _i6.Future); @override - _i7.Future incrementCurrentNotificationIndex() => (super.noSuchMethod( + _i6.Future incrementCurrentNotificationIndex() => (super.noSuchMethod( Invocation.method( #incrementCurrentNotificationIndex, [], ), - returnValue: _i7.Future.value(), - returnValueForMissingStub: _i7.Future.value(), - ) as _i7.Future); + returnValue: _i6.Future.value(), + returnValueForMissingStub: _i6.Future.value(), + ) as _i6.Future); @override - _i7.Future isExternalCallsSet() => (super.noSuchMethod( + _i6.Future isExternalCallsSet() => (super.noSuchMethod( Invocation.method( #isExternalCallsSet, [], ), - returnValue: _i7.Future.value(false), - ) as _i7.Future); + returnValue: _i6.Future.value(false), + ) as _i6.Future); @override - _i7.Future saveUserID(String? userId) => (super.noSuchMethod( + _i6.Future saveUserID(String? userId) => (super.noSuchMethod( Invocation.method( #saveUserID, [userId], ), - returnValue: _i7.Future.value(), - returnValueForMissingStub: _i7.Future.value(), - ) as _i7.Future); + returnValue: _i6.Future.value(), + returnValueForMissingStub: _i6.Future.value(), + ) as _i6.Future); @override - _i7.Future saveSignupEpoch(int? signupEpoch) => (super.noSuchMethod( + _i6.Future saveSignupEpoch(int? signupEpoch) => (super.noSuchMethod( Invocation.method( #saveSignupEpoch, [signupEpoch], ), - returnValue: _i7.Future.value(), - returnValueForMissingStub: _i7.Future.value(), - ) as _i7.Future); + returnValue: _i6.Future.value(), + returnValueForMissingStub: _i6.Future.value(), + ) as _i6.Future); @override - void addListener(_i8.VoidCallback? listener) => super.noSuchMethod( + void addListener(_i7.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, [listener], @@ -396,7 +379,7 @@ class MockPrefs extends _i1.Mock implements _i3.Prefs { returnValueForMissingStub: null, ); @override - void removeListener(_i8.VoidCallback? listener) => super.noSuchMethod( + void removeListener(_i7.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #removeListener, [listener], @@ -424,29 +407,29 @@ class MockPrefs extends _i1.Mock implements _i3.Prefs { /// A class which mocks [TradesService]. /// /// See the documentation for Mockito's code generation for more information. -class MockTradesService extends _i1.Mock implements _i9.TradesService { +class MockTradesService extends _i1.Mock implements _i8.TradesService { MockTradesService() { _i1.throwOnMissingStub(this); } @override - List<_i10.Trade> get trades => (super.noSuchMethod( + List<_i9.Trade> get trades => (super.noSuchMethod( Invocation.getter(#trades), - returnValue: <_i10.Trade>[], - ) as List<_i10.Trade>); + returnValue: <_i9.Trade>[], + ) as List<_i9.Trade>); @override bool get hasListeners => (super.noSuchMethod( Invocation.getter(#hasListeners), returnValue: false, ) as bool); @override - _i10.Trade? get(String? tradeId) => (super.noSuchMethod(Invocation.method( + _i9.Trade? get(String? tradeId) => (super.noSuchMethod(Invocation.method( #get, [tradeId], - )) as _i10.Trade?); + )) as _i9.Trade?); @override - _i7.Future add({ - required _i10.Trade? trade, + _i6.Future add({ + required _i9.Trade? trade, required bool? shouldNotifyListeners, }) => (super.noSuchMethod( @@ -458,12 +441,12 @@ class MockTradesService extends _i1.Mock implements _i9.TradesService { #shouldNotifyListeners: shouldNotifyListeners, }, ), - returnValue: _i7.Future.value(), - returnValueForMissingStub: _i7.Future.value(), - ) as _i7.Future); + returnValue: _i6.Future.value(), + returnValueForMissingStub: _i6.Future.value(), + ) as _i6.Future); @override - _i7.Future edit({ - required _i10.Trade? trade, + _i6.Future edit({ + required _i9.Trade? trade, required bool? shouldNotifyListeners, }) => (super.noSuchMethod( @@ -475,12 +458,12 @@ class MockTradesService extends _i1.Mock implements _i9.TradesService { #shouldNotifyListeners: shouldNotifyListeners, }, ), - returnValue: _i7.Future.value(), - returnValueForMissingStub: _i7.Future.value(), - ) as _i7.Future); + returnValue: _i6.Future.value(), + returnValueForMissingStub: _i6.Future.value(), + ) as _i6.Future); @override - _i7.Future delete({ - required _i10.Trade? trade, + _i6.Future delete({ + required _i9.Trade? trade, required bool? shouldNotifyListeners, }) => (super.noSuchMethod( @@ -492,11 +475,11 @@ class MockTradesService extends _i1.Mock implements _i9.TradesService { #shouldNotifyListeners: shouldNotifyListeners, }, ), - returnValue: _i7.Future.value(), - returnValueForMissingStub: _i7.Future.value(), - ) as _i7.Future); + returnValue: _i6.Future.value(), + returnValueForMissingStub: _i6.Future.value(), + ) as _i6.Future); @override - _i7.Future deleteByUuid({ + _i6.Future deleteByUuid({ required String? uuid, required bool? shouldNotifyListeners, }) => @@ -509,11 +492,11 @@ class MockTradesService extends _i1.Mock implements _i9.TradesService { #shouldNotifyListeners: shouldNotifyListeners, }, ), - returnValue: _i7.Future.value(), - returnValueForMissingStub: _i7.Future.value(), - ) as _i7.Future); + returnValue: _i6.Future.value(), + returnValueForMissingStub: _i6.Future.value(), + ) as _i6.Future); @override - void addListener(_i8.VoidCallback? listener) => super.noSuchMethod( + void addListener(_i7.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, [listener], @@ -521,7 +504,7 @@ class MockTradesService extends _i1.Mock implements _i9.TradesService { returnValueForMissingStub: null, ); @override - void removeListener(_i8.VoidCallback? listener) => super.noSuchMethod( + void removeListener(_i7.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #removeListener, [listener], @@ -549,7 +532,7 @@ class MockTradesService extends _i1.Mock implements _i9.TradesService { /// A class which mocks [TradeNotesService]. /// /// See the documentation for Mockito's code generation for more information. -class MockTradeNotesService extends _i1.Mock implements _i11.TradeNotesService { +class MockTradeNotesService extends _i1.Mock implements _i10.TradeNotesService { MockTradeNotesService() { _i1.throwOnMissingStub(this); } @@ -574,7 +557,7 @@ class MockTradeNotesService extends _i1.Mock implements _i11.TradeNotesService { returnValue: '', ) as String); @override - _i7.Future set({ + _i6.Future set({ required String? tradeId, required String? note, }) => @@ -587,21 +570,21 @@ class MockTradeNotesService extends _i1.Mock implements _i11.TradeNotesService { #note: note, }, ), - returnValue: _i7.Future.value(), - returnValueForMissingStub: _i7.Future.value(), - ) as _i7.Future); + returnValue: _i6.Future.value(), + returnValueForMissingStub: _i6.Future.value(), + ) as _i6.Future); @override - _i7.Future delete({required String? tradeId}) => (super.noSuchMethod( + _i6.Future delete({required String? tradeId}) => (super.noSuchMethod( Invocation.method( #delete, [], {#tradeId: tradeId}, ), - returnValue: _i7.Future.value(), - returnValueForMissingStub: _i7.Future.value(), - ) as _i7.Future); + returnValue: _i6.Future.value(), + returnValueForMissingStub: _i6.Future.value(), + ) as _i6.Future); @override - void addListener(_i8.VoidCallback? listener) => super.noSuchMethod( + void addListener(_i7.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, [listener], @@ -609,7 +592,7 @@ class MockTradeNotesService extends _i1.Mock implements _i11.TradeNotesService { returnValueForMissingStub: null, ); @override - void removeListener(_i8.VoidCallback? listener) => super.noSuchMethod( + void removeListener(_i7.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #removeListener, [listener], @@ -637,13 +620,13 @@ class MockTradeNotesService extends _i1.Mock implements _i11.TradeNotesService { /// A class which mocks [ChangeNowAPI]. /// /// See the documentation for Mockito's code generation for more information. -class MockChangeNowAPI extends _i1.Mock implements _i12.ChangeNowAPI { +class MockChangeNowAPI extends _i1.Mock implements _i11.ChangeNowAPI { MockChangeNowAPI() { _i1.throwOnMissingStub(this); } @override - set client(_i13.Client? _client) => super.noSuchMethod( + set client(_i12.Client? _client) => super.noSuchMethod( Invocation.setter( #client, _client, @@ -651,7 +634,7 @@ class MockChangeNowAPI extends _i1.Mock implements _i12.ChangeNowAPI { returnValueForMissingStub: null, ); @override - _i7.Future<_i2.ExchangeResponse>> getAvailableCurrencies({ + _i6.Future<_i2.ExchangeResponse>> getAvailableCurrencies({ bool? fixedRate, bool? active, }) => @@ -665,8 +648,8 @@ class MockChangeNowAPI extends _i1.Mock implements _i12.ChangeNowAPI { }, ), returnValue: - _i7.Future<_i2.ExchangeResponse>>.value( - _FakeExchangeResponse_0>( + _i6.Future<_i2.ExchangeResponse>>.value( + _FakeExchangeResponse_0>( this, Invocation.method( #getAvailableCurrencies, @@ -677,9 +660,9 @@ class MockChangeNowAPI extends _i1.Mock implements _i12.ChangeNowAPI { }, ), )), - ) as _i7.Future<_i2.ExchangeResponse>>); + ) as _i6.Future<_i2.ExchangeResponse>>); @override - _i7.Future<_i2.ExchangeResponse>> getPairedCurrencies({ + _i6.Future<_i2.ExchangeResponse>> getPairedCurrencies({ required String? ticker, bool? fixedRate, }) => @@ -693,8 +676,8 @@ class MockChangeNowAPI extends _i1.Mock implements _i12.ChangeNowAPI { }, ), returnValue: - _i7.Future<_i2.ExchangeResponse>>.value( - _FakeExchangeResponse_0>( + _i6.Future<_i2.ExchangeResponse>>.value( + _FakeExchangeResponse_0>( this, Invocation.method( #getPairedCurrencies, @@ -705,9 +688,9 @@ class MockChangeNowAPI extends _i1.Mock implements _i12.ChangeNowAPI { }, ), )), - ) as _i7.Future<_i2.ExchangeResponse>>); + ) as _i6.Future<_i2.ExchangeResponse>>); @override - _i7.Future<_i2.ExchangeResponse<_i15.Decimal>> getMinimalExchangeAmount({ + _i6.Future<_i2.ExchangeResponse<_i14.Decimal>> getMinimalExchangeAmount({ required String? fromTicker, required String? toTicker, String? apiKey, @@ -722,8 +705,8 @@ class MockChangeNowAPI extends _i1.Mock implements _i12.ChangeNowAPI { #apiKey: apiKey, }, ), - returnValue: _i7.Future<_i2.ExchangeResponse<_i15.Decimal>>.value( - _FakeExchangeResponse_0<_i15.Decimal>( + returnValue: _i6.Future<_i2.ExchangeResponse<_i14.Decimal>>.value( + _FakeExchangeResponse_0<_i14.Decimal>( this, Invocation.method( #getMinimalExchangeAmount, @@ -735,9 +718,9 @@ class MockChangeNowAPI extends _i1.Mock implements _i12.ChangeNowAPI { }, ), )), - ) as _i7.Future<_i2.ExchangeResponse<_i15.Decimal>>); + ) as _i6.Future<_i2.ExchangeResponse<_i14.Decimal>>); @override - _i7.Future<_i2.ExchangeResponse<_i16.Range>> getRange({ + _i6.Future<_i2.ExchangeResponse<_i15.Range>> getRange({ required String? fromTicker, required String? toTicker, required bool? isFixedRate, @@ -754,8 +737,8 @@ class MockChangeNowAPI extends _i1.Mock implements _i12.ChangeNowAPI { #apiKey: apiKey, }, ), - returnValue: _i7.Future<_i2.ExchangeResponse<_i16.Range>>.value( - _FakeExchangeResponse_0<_i16.Range>( + returnValue: _i6.Future<_i2.ExchangeResponse<_i15.Range>>.value( + _FakeExchangeResponse_0<_i15.Range>( this, Invocation.method( #getRange, @@ -768,12 +751,12 @@ class MockChangeNowAPI extends _i1.Mock implements _i12.ChangeNowAPI { }, ), )), - ) as _i7.Future<_i2.ExchangeResponse<_i16.Range>>); + ) as _i6.Future<_i2.ExchangeResponse<_i15.Range>>); @override - _i7.Future<_i2.ExchangeResponse<_i17.Estimate>> getEstimatedExchangeAmount({ + _i6.Future<_i2.ExchangeResponse<_i16.Estimate>> getEstimatedExchangeAmount({ required String? fromTicker, required String? toTicker, - required _i15.Decimal? fromAmount, + required _i14.Decimal? fromAmount, String? apiKey, }) => (super.noSuchMethod( @@ -787,8 +770,8 @@ class MockChangeNowAPI extends _i1.Mock implements _i12.ChangeNowAPI { #apiKey: apiKey, }, ), - returnValue: _i7.Future<_i2.ExchangeResponse<_i17.Estimate>>.value( - _FakeExchangeResponse_0<_i17.Estimate>( + returnValue: _i6.Future<_i2.ExchangeResponse<_i16.Estimate>>.value( + _FakeExchangeResponse_0<_i16.Estimate>( this, Invocation.method( #getEstimatedExchangeAmount, @@ -801,13 +784,13 @@ class MockChangeNowAPI extends _i1.Mock implements _i12.ChangeNowAPI { }, ), )), - ) as _i7.Future<_i2.ExchangeResponse<_i17.Estimate>>); + ) as _i6.Future<_i2.ExchangeResponse<_i16.Estimate>>); @override - _i7.Future<_i2.ExchangeResponse<_i17.Estimate>> + _i6.Future<_i2.ExchangeResponse<_i16.Estimate>> getEstimatedExchangeAmountFixedRate({ required String? fromTicker, required String? toTicker, - required _i15.Decimal? fromAmount, + required _i14.Decimal? fromAmount, required bool? reversed, bool? useRateId = true, String? apiKey, @@ -825,8 +808,8 @@ class MockChangeNowAPI extends _i1.Mock implements _i12.ChangeNowAPI { #apiKey: apiKey, }, ), - returnValue: _i7.Future<_i2.ExchangeResponse<_i17.Estimate>>.value( - _FakeExchangeResponse_0<_i17.Estimate>( + returnValue: _i6.Future<_i2.ExchangeResponse<_i16.Estimate>>.value( + _FakeExchangeResponse_0<_i16.Estimate>( this, Invocation.method( #getEstimatedExchangeAmountFixedRate, @@ -841,17 +824,17 @@ class MockChangeNowAPI extends _i1.Mock implements _i12.ChangeNowAPI { }, ), )), - ) as _i7.Future<_i2.ExchangeResponse<_i17.Estimate>>); + ) as _i6.Future<_i2.ExchangeResponse<_i16.Estimate>>); @override - _i7.Future<_i2.ExchangeResponse<_i18.CNExchangeEstimate>> + _i6.Future<_i2.ExchangeResponse<_i17.CNExchangeEstimate>> getEstimatedExchangeAmountV2({ required String? fromTicker, required String? toTicker, - required _i18.CNEstimateType? fromOrTo, - required _i15.Decimal? amount, + required _i17.CNEstimateType? fromOrTo, + required _i14.Decimal? amount, String? fromNetwork, String? toNetwork, - _i18.CNFlowType? flow = _i18.CNFlowType.standard, + _i17.CNFlowType? flow = _i17.CNFlowType.standard, String? apiKey, }) => (super.noSuchMethod( @@ -870,8 +853,8 @@ class MockChangeNowAPI extends _i1.Mock implements _i12.ChangeNowAPI { }, ), returnValue: - _i7.Future<_i2.ExchangeResponse<_i18.CNExchangeEstimate>>.value( - _FakeExchangeResponse_0<_i18.CNExchangeEstimate>( + _i6.Future<_i2.ExchangeResponse<_i17.CNExchangeEstimate>>.value( + _FakeExchangeResponse_0<_i17.CNExchangeEstimate>( this, Invocation.method( #getEstimatedExchangeAmountV2, @@ -888,18 +871,18 @@ class MockChangeNowAPI extends _i1.Mock implements _i12.ChangeNowAPI { }, ), )), - ) as _i7.Future<_i2.ExchangeResponse<_i18.CNExchangeEstimate>>); + ) as _i6.Future<_i2.ExchangeResponse<_i17.CNExchangeEstimate>>); @override - _i7.Future<_i2.ExchangeResponse>> + _i6.Future<_i2.ExchangeResponse>> getAvailableFixedRateMarkets({String? apiKey}) => (super.noSuchMethod( Invocation.method( #getAvailableFixedRateMarkets, [], {#apiKey: apiKey}, ), - returnValue: _i7.Future< - _i2.ExchangeResponse>>.value( - _FakeExchangeResponse_0>( + returnValue: _i6.Future< + _i2.ExchangeResponse>>.value( + _FakeExchangeResponse_0>( this, Invocation.method( #getAvailableFixedRateMarkets, @@ -907,14 +890,14 @@ class MockChangeNowAPI extends _i1.Mock implements _i12.ChangeNowAPI { {#apiKey: apiKey}, ), )), - ) as _i7.Future<_i2.ExchangeResponse>>); + ) as _i6.Future<_i2.ExchangeResponse>>); @override - _i7.Future<_i2.ExchangeResponse<_i20.ExchangeTransaction>> + _i6.Future<_i2.ExchangeResponse<_i19.ExchangeTransaction>> createStandardExchangeTransaction({ required String? fromTicker, required String? toTicker, required String? receivingAddress, - required _i15.Decimal? amount, + required _i14.Decimal? amount, String? extraId = r'', String? userId = r'', String? contactEmail = r'', @@ -939,9 +922,9 @@ class MockChangeNowAPI extends _i1.Mock implements _i12.ChangeNowAPI { #apiKey: apiKey, }, ), - returnValue: _i7.Future< - _i2.ExchangeResponse<_i20.ExchangeTransaction>>.value( - _FakeExchangeResponse_0<_i20.ExchangeTransaction>( + returnValue: _i6.Future< + _i2.ExchangeResponse<_i19.ExchangeTransaction>>.value( + _FakeExchangeResponse_0<_i19.ExchangeTransaction>( this, Invocation.method( #createStandardExchangeTransaction, @@ -960,14 +943,14 @@ class MockChangeNowAPI extends _i1.Mock implements _i12.ChangeNowAPI { }, ), )), - ) as _i7.Future<_i2.ExchangeResponse<_i20.ExchangeTransaction>>); + ) as _i6.Future<_i2.ExchangeResponse<_i19.ExchangeTransaction>>); @override - _i7.Future<_i2.ExchangeResponse<_i20.ExchangeTransaction>> + _i6.Future<_i2.ExchangeResponse<_i19.ExchangeTransaction>> createFixedRateExchangeTransaction({ required String? fromTicker, required String? toTicker, required String? receivingAddress, - required _i15.Decimal? amount, + required _i14.Decimal? amount, required String? rateId, required bool? reversed, String? extraId = r'', @@ -996,9 +979,9 @@ class MockChangeNowAPI extends _i1.Mock implements _i12.ChangeNowAPI { #apiKey: apiKey, }, ), - returnValue: _i7.Future< - _i2.ExchangeResponse<_i20.ExchangeTransaction>>.value( - _FakeExchangeResponse_0<_i20.ExchangeTransaction>( + returnValue: _i6.Future< + _i2.ExchangeResponse<_i19.ExchangeTransaction>>.value( + _FakeExchangeResponse_0<_i19.ExchangeTransaction>( this, Invocation.method( #createFixedRateExchangeTransaction, @@ -1019,9 +1002,9 @@ class MockChangeNowAPI extends _i1.Mock implements _i12.ChangeNowAPI { }, ), )), - ) as _i7.Future<_i2.ExchangeResponse<_i20.ExchangeTransaction>>); + ) as _i6.Future<_i2.ExchangeResponse<_i19.ExchangeTransaction>>); @override - _i7.Future<_i2.ExchangeResponse<_i21.ExchangeTransactionStatus>> + _i6.Future<_i2.ExchangeResponse<_i20.ExchangeTransactionStatus>> getTransactionStatus({ required String? id, String? apiKey, @@ -1035,9 +1018,9 @@ class MockChangeNowAPI extends _i1.Mock implements _i12.ChangeNowAPI { #apiKey: apiKey, }, ), - returnValue: _i7.Future< - _i2.ExchangeResponse<_i21.ExchangeTransactionStatus>>.value( - _FakeExchangeResponse_0<_i21.ExchangeTransactionStatus>( + returnValue: _i6.Future< + _i2.ExchangeResponse<_i20.ExchangeTransactionStatus>>.value( + _FakeExchangeResponse_0<_i20.ExchangeTransactionStatus>( this, Invocation.method( #getTransactionStatus, @@ -1048,10 +1031,10 @@ class MockChangeNowAPI extends _i1.Mock implements _i12.ChangeNowAPI { }, ), )), - ) as _i7 - .Future<_i2.ExchangeResponse<_i21.ExchangeTransactionStatus>>); + ) as _i6 + .Future<_i2.ExchangeResponse<_i20.ExchangeTransactionStatus>>); @override - _i7.Future<_i2.ExchangeResponse>> + _i6.Future<_i2.ExchangeResponse>> getAvailableFloatingRatePairs({bool? includePartners = false}) => (super.noSuchMethod( Invocation.method( @@ -1060,8 +1043,8 @@ class MockChangeNowAPI extends _i1.Mock implements _i12.ChangeNowAPI { {#includePartners: includePartners}, ), returnValue: - _i7.Future<_i2.ExchangeResponse>>.value( - _FakeExchangeResponse_0>( + _i6.Future<_i2.ExchangeResponse>>.value( + _FakeExchangeResponse_0>( this, Invocation.method( #getAvailableFloatingRatePairs, @@ -1069,5 +1052,5 @@ class MockChangeNowAPI extends _i1.Mock implements _i12.ChangeNowAPI { {#includePartners: includePartners}, ), )), - ) as _i7.Future<_i2.ExchangeResponse>>); + ) as _i6.Future<_i2.ExchangeResponse>>); } diff --git a/test/screen_tests/lockscreen_view_screen_test.mocks.dart b/test/screen_tests/lockscreen_view_screen_test.mocks.dart index a7f124337..a527edbe2 100644 --- a/test/screen_tests/lockscreen_view_screen_test.mocks.dart +++ b/test/screen_tests/lockscreen_view_screen_test.mocks.dart @@ -641,6 +641,11 @@ class MockManager extends _i1.Mock implements _i12.Manager { returnValue: false, ) as bool); @override + int get rescanOnOpenVersion => (super.noSuchMethod( + Invocation.getter(#rescanOnOpenVersion), + returnValue: 0, + ) as int); + @override bool get hasListeners => (super.noSuchMethod( Invocation.getter(#hasListeners), returnValue: false, @@ -806,6 +811,15 @@ class MockManager extends _i1.Mock implements _i12.Manager { returnValue: _i7.Future.value(false), ) as _i7.Future); @override + _i7.Future resetRescanOnOpen() => (super.noSuchMethod( + Invocation.method( + #resetRescanOnOpen, + [], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + @override void addListener(_i9.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, diff --git a/test/screen_tests/main_view_tests/main_view_screen_testA_test.mocks.dart b/test/screen_tests/main_view_tests/main_view_screen_testA_test.mocks.dart index e7c4658a6..d3409d31a 100644 --- a/test/screen_tests/main_view_tests/main_view_screen_testA_test.mocks.dart +++ b/test/screen_tests/main_view_tests/main_view_screen_testA_test.mocks.dart @@ -428,6 +428,11 @@ class MockManager extends _i1.Mock implements _i9.Manager { returnValue: false, ) as bool); @override + int get rescanOnOpenVersion => (super.noSuchMethod( + Invocation.getter(#rescanOnOpenVersion), + returnValue: 0, + ) as int); + @override bool get hasListeners => (super.noSuchMethod( Invocation.getter(#hasListeners), returnValue: false, @@ -593,6 +598,15 @@ class MockManager extends _i1.Mock implements _i9.Manager { returnValue: _i6.Future.value(false), ) as _i6.Future); @override + _i6.Future resetRescanOnOpen() => (super.noSuchMethod( + Invocation.method( + #resetRescanOnOpen, + [], + ), + returnValue: _i6.Future.value(), + returnValueForMissingStub: _i6.Future.value(), + ) as _i6.Future); + @override void addListener(_i8.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, diff --git a/test/screen_tests/main_view_tests/main_view_screen_testB_test.mocks.dart b/test/screen_tests/main_view_tests/main_view_screen_testB_test.mocks.dart index 920ebc0f7..8d391409d 100644 --- a/test/screen_tests/main_view_tests/main_view_screen_testB_test.mocks.dart +++ b/test/screen_tests/main_view_tests/main_view_screen_testB_test.mocks.dart @@ -428,6 +428,11 @@ class MockManager extends _i1.Mock implements _i9.Manager { returnValue: false, ) as bool); @override + int get rescanOnOpenVersion => (super.noSuchMethod( + Invocation.getter(#rescanOnOpenVersion), + returnValue: 0, + ) as int); + @override bool get hasListeners => (super.noSuchMethod( Invocation.getter(#hasListeners), returnValue: false, @@ -593,6 +598,15 @@ class MockManager extends _i1.Mock implements _i9.Manager { returnValue: _i6.Future.value(false), ) as _i6.Future); @override + _i6.Future resetRescanOnOpen() => (super.noSuchMethod( + Invocation.method( + #resetRescanOnOpen, + [], + ), + returnValue: _i6.Future.value(), + returnValueForMissingStub: _i6.Future.value(), + ) as _i6.Future); + @override void addListener(_i8.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, diff --git a/test/screen_tests/main_view_tests/main_view_screen_testC_test.mocks.dart b/test/screen_tests/main_view_tests/main_view_screen_testC_test.mocks.dart index 4b4f63225..f1f5581d6 100644 --- a/test/screen_tests/main_view_tests/main_view_screen_testC_test.mocks.dart +++ b/test/screen_tests/main_view_tests/main_view_screen_testC_test.mocks.dart @@ -428,6 +428,11 @@ class MockManager extends _i1.Mock implements _i9.Manager { returnValue: false, ) as bool); @override + int get rescanOnOpenVersion => (super.noSuchMethod( + Invocation.getter(#rescanOnOpenVersion), + returnValue: 0, + ) as int); + @override bool get hasListeners => (super.noSuchMethod( Invocation.getter(#hasListeners), returnValue: false, @@ -593,6 +598,15 @@ class MockManager extends _i1.Mock implements _i9.Manager { returnValue: _i6.Future.value(false), ) as _i6.Future); @override + _i6.Future resetRescanOnOpen() => (super.noSuchMethod( + Invocation.method( + #resetRescanOnOpen, + [], + ), + returnValue: _i6.Future.value(), + returnValueForMissingStub: _i6.Future.value(), + ) as _i6.Future); + @override void addListener(_i8.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, diff --git a/test/screen_tests/onboarding/backup_key_view_screen_test.mocks.dart b/test/screen_tests/onboarding/backup_key_view_screen_test.mocks.dart index ceb07514a..88b477129 100644 --- a/test/screen_tests/onboarding/backup_key_view_screen_test.mocks.dart +++ b/test/screen_tests/onboarding/backup_key_view_screen_test.mocks.dart @@ -203,6 +203,11 @@ class MockManager extends _i1.Mock implements _i5.Manager { returnValue: false, ) as bool); @override + int get rescanOnOpenVersion => (super.noSuchMethod( + Invocation.getter(#rescanOnOpenVersion), + returnValue: 0, + ) as int); + @override bool get hasListeners => (super.noSuchMethod( Invocation.getter(#hasListeners), returnValue: false, @@ -368,6 +373,15 @@ class MockManager extends _i1.Mock implements _i5.Manager { returnValue: _i7.Future.value(false), ) as _i7.Future); @override + _i7.Future resetRescanOnOpen() => (super.noSuchMethod( + Invocation.method( + #resetRescanOnOpen, + [], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + @override void addListener(_i9.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, diff --git a/test/screen_tests/onboarding/backup_key_warning_view_screen_test.mocks.dart b/test/screen_tests/onboarding/backup_key_warning_view_screen_test.mocks.dart index 9c75c178d..b3d727de7 100644 --- a/test/screen_tests/onboarding/backup_key_warning_view_screen_test.mocks.dart +++ b/test/screen_tests/onboarding/backup_key_warning_view_screen_test.mocks.dart @@ -426,6 +426,11 @@ class MockManager extends _i1.Mock implements _i9.Manager { returnValue: false, ) as bool); @override + int get rescanOnOpenVersion => (super.noSuchMethod( + Invocation.getter(#rescanOnOpenVersion), + returnValue: 0, + ) as int); + @override bool get hasListeners => (super.noSuchMethod( Invocation.getter(#hasListeners), returnValue: false, @@ -591,6 +596,15 @@ class MockManager extends _i1.Mock implements _i9.Manager { returnValue: _i6.Future.value(false), ) as _i6.Future); @override + _i6.Future resetRescanOnOpen() => (super.noSuchMethod( + Invocation.method( + #resetRescanOnOpen, + [], + ), + returnValue: _i6.Future.value(), + returnValueForMissingStub: _i6.Future.value(), + ) as _i6.Future); + @override void addListener(_i8.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, diff --git a/test/screen_tests/onboarding/create_pin_view_screen_test.mocks.dart b/test/screen_tests/onboarding/create_pin_view_screen_test.mocks.dart index fed2fe069..a70f86c6f 100644 --- a/test/screen_tests/onboarding/create_pin_view_screen_test.mocks.dart +++ b/test/screen_tests/onboarding/create_pin_view_screen_test.mocks.dart @@ -641,6 +641,11 @@ class MockManager extends _i1.Mock implements _i12.Manager { returnValue: false, ) as bool); @override + int get rescanOnOpenVersion => (super.noSuchMethod( + Invocation.getter(#rescanOnOpenVersion), + returnValue: 0, + ) as int); + @override bool get hasListeners => (super.noSuchMethod( Invocation.getter(#hasListeners), returnValue: false, @@ -806,6 +811,15 @@ class MockManager extends _i1.Mock implements _i12.Manager { returnValue: _i7.Future.value(false), ) as _i7.Future); @override + _i7.Future resetRescanOnOpen() => (super.noSuchMethod( + Invocation.method( + #resetRescanOnOpen, + [], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + @override void addListener(_i9.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, diff --git a/test/screen_tests/onboarding/restore_wallet_view_screen_test.mocks.dart b/test/screen_tests/onboarding/restore_wallet_view_screen_test.mocks.dart index 9b169bad2..dfa8052fd 100644 --- a/test/screen_tests/onboarding/restore_wallet_view_screen_test.mocks.dart +++ b/test/screen_tests/onboarding/restore_wallet_view_screen_test.mocks.dart @@ -482,6 +482,11 @@ class MockManager extends _i1.Mock implements _i12.Manager { returnValue: false, ) as bool); @override + int get rescanOnOpenVersion => (super.noSuchMethod( + Invocation.getter(#rescanOnOpenVersion), + returnValue: 0, + ) as int); + @override bool get hasListeners => (super.noSuchMethod( Invocation.getter(#hasListeners), returnValue: false, @@ -647,6 +652,15 @@ class MockManager extends _i1.Mock implements _i12.Manager { returnValue: _i8.Future.value(false), ) as _i8.Future); @override + _i8.Future resetRescanOnOpen() => (super.noSuchMethod( + Invocation.method( + #resetRescanOnOpen, + [], + ), + returnValue: _i8.Future.value(), + returnValueForMissingStub: _i8.Future.value(), + ) as _i8.Future); + @override void addListener(_i11.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, diff --git a/test/screen_tests/onboarding/verify_backup_key_view_screen_test.mocks.dart b/test/screen_tests/onboarding/verify_backup_key_view_screen_test.mocks.dart index 924a72df8..e11f58e31 100644 --- a/test/screen_tests/onboarding/verify_backup_key_view_screen_test.mocks.dart +++ b/test/screen_tests/onboarding/verify_backup_key_view_screen_test.mocks.dart @@ -203,6 +203,11 @@ class MockManager extends _i1.Mock implements _i5.Manager { returnValue: false, ) as bool); @override + int get rescanOnOpenVersion => (super.noSuchMethod( + Invocation.getter(#rescanOnOpenVersion), + returnValue: 0, + ) as int); + @override bool get hasListeners => (super.noSuchMethod( Invocation.getter(#hasListeners), returnValue: false, @@ -368,6 +373,15 @@ class MockManager extends _i1.Mock implements _i5.Manager { returnValue: _i7.Future.value(false), ) as _i7.Future); @override + _i7.Future resetRescanOnOpen() => (super.noSuchMethod( + Invocation.method( + #resetRescanOnOpen, + [], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + @override void addListener(_i9.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, diff --git a/test/screen_tests/settings_view/settings_subviews/currency_view_screen_test.mocks.dart b/test/screen_tests/settings_view/settings_subviews/currency_view_screen_test.mocks.dart index db22ecacc..eef71451f 100644 --- a/test/screen_tests/settings_view/settings_subviews/currency_view_screen_test.mocks.dart +++ b/test/screen_tests/settings_view/settings_subviews/currency_view_screen_test.mocks.dart @@ -203,6 +203,11 @@ class MockManager extends _i1.Mock implements _i5.Manager { returnValue: false, ) as bool); @override + int get rescanOnOpenVersion => (super.noSuchMethod( + Invocation.getter(#rescanOnOpenVersion), + returnValue: 0, + ) as int); + @override bool get hasListeners => (super.noSuchMethod( Invocation.getter(#hasListeners), returnValue: false, @@ -368,6 +373,15 @@ class MockManager extends _i1.Mock implements _i5.Manager { returnValue: _i7.Future.value(false), ) as _i7.Future); @override + _i7.Future resetRescanOnOpen() => (super.noSuchMethod( + Invocation.method( + #resetRescanOnOpen, + [], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + @override void addListener(_i9.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, diff --git a/test/screen_tests/settings_view/settings_subviews/network_settings_subviews/add_custom_node_view_screen_test.mocks.dart b/test/screen_tests/settings_view/settings_subviews/network_settings_subviews/add_custom_node_view_screen_test.mocks.dart index 8a9fd0935..7d6ac052f 100644 --- a/test/screen_tests/settings_view/settings_subviews/network_settings_subviews/add_custom_node_view_screen_test.mocks.dart +++ b/test/screen_tests/settings_view/settings_subviews/network_settings_subviews/add_custom_node_view_screen_test.mocks.dart @@ -418,6 +418,11 @@ class MockManager extends _i1.Mock implements _i11.Manager { returnValue: false, ) as bool); @override + int get rescanOnOpenVersion => (super.noSuchMethod( + Invocation.getter(#rescanOnOpenVersion), + returnValue: 0, + ) as int); + @override bool get hasListeners => (super.noSuchMethod( Invocation.getter(#hasListeners), returnValue: false, @@ -583,6 +588,15 @@ class MockManager extends _i1.Mock implements _i11.Manager { returnValue: _i8.Future.value(false), ) as _i8.Future); @override + _i8.Future resetRescanOnOpen() => (super.noSuchMethod( + Invocation.method( + #resetRescanOnOpen, + [], + ), + returnValue: _i8.Future.value(), + returnValueForMissingStub: _i8.Future.value(), + ) as _i8.Future); + @override void addListener(_i10.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, diff --git a/test/screen_tests/settings_view/settings_subviews/network_settings_subviews/node_details_view_screen_test.mocks.dart b/test/screen_tests/settings_view/settings_subviews/network_settings_subviews/node_details_view_screen_test.mocks.dart index db88f6067..7c7319cd8 100644 --- a/test/screen_tests/settings_view/settings_subviews/network_settings_subviews/node_details_view_screen_test.mocks.dart +++ b/test/screen_tests/settings_view/settings_subviews/network_settings_subviews/node_details_view_screen_test.mocks.dart @@ -418,6 +418,11 @@ class MockManager extends _i1.Mock implements _i11.Manager { returnValue: false, ) as bool); @override + int get rescanOnOpenVersion => (super.noSuchMethod( + Invocation.getter(#rescanOnOpenVersion), + returnValue: 0, + ) as int); + @override bool get hasListeners => (super.noSuchMethod( Invocation.getter(#hasListeners), returnValue: false, @@ -583,6 +588,15 @@ class MockManager extends _i1.Mock implements _i11.Manager { returnValue: _i8.Future.value(false), ) as _i8.Future); @override + _i8.Future resetRescanOnOpen() => (super.noSuchMethod( + Invocation.method( + #resetRescanOnOpen, + [], + ), + returnValue: _i8.Future.value(), + returnValueForMissingStub: _i8.Future.value(), + ) as _i8.Future); + @override void addListener(_i10.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, diff --git a/test/screen_tests/settings_view/settings_subviews/wallet_backup_view_screen_test.mocks.dart b/test/screen_tests/settings_view/settings_subviews/wallet_backup_view_screen_test.mocks.dart index 3d6b30b2d..78fafef16 100644 --- a/test/screen_tests/settings_view/settings_subviews/wallet_backup_view_screen_test.mocks.dart +++ b/test/screen_tests/settings_view/settings_subviews/wallet_backup_view_screen_test.mocks.dart @@ -203,6 +203,11 @@ class MockManager extends _i1.Mock implements _i5.Manager { returnValue: false, ) as bool); @override + int get rescanOnOpenVersion => (super.noSuchMethod( + Invocation.getter(#rescanOnOpenVersion), + returnValue: 0, + ) as int); + @override bool get hasListeners => (super.noSuchMethod( Invocation.getter(#hasListeners), returnValue: false, @@ -368,6 +373,15 @@ class MockManager extends _i1.Mock implements _i5.Manager { returnValue: _i7.Future.value(false), ) as _i7.Future); @override + _i7.Future resetRescanOnOpen() => (super.noSuchMethod( + Invocation.method( + #resetRescanOnOpen, + [], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + @override void addListener(_i9.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, diff --git a/test/screen_tests/settings_view/settings_subviews/wallet_settings_subviews/rescan_warning_view_screen_test.mocks.dart b/test/screen_tests/settings_view/settings_subviews/wallet_settings_subviews/rescan_warning_view_screen_test.mocks.dart index ce44e5fd8..099e486be 100644 --- a/test/screen_tests/settings_view/settings_subviews/wallet_settings_subviews/rescan_warning_view_screen_test.mocks.dart +++ b/test/screen_tests/settings_view/settings_subviews/wallet_settings_subviews/rescan_warning_view_screen_test.mocks.dart @@ -203,6 +203,11 @@ class MockManager extends _i1.Mock implements _i5.Manager { returnValue: false, ) as bool); @override + int get rescanOnOpenVersion => (super.noSuchMethod( + Invocation.getter(#rescanOnOpenVersion), + returnValue: 0, + ) as int); + @override bool get hasListeners => (super.noSuchMethod( Invocation.getter(#hasListeners), returnValue: false, @@ -368,6 +373,15 @@ class MockManager extends _i1.Mock implements _i5.Manager { returnValue: _i7.Future.value(false), ) as _i7.Future); @override + _i7.Future resetRescanOnOpen() => (super.noSuchMethod( + Invocation.method( + #resetRescanOnOpen, + [], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + @override void addListener(_i9.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, diff --git a/test/screen_tests/settings_view/settings_subviews/wallet_settings_subviews/wallet_delete_mnemonic_view_screen_test.mocks.dart b/test/screen_tests/settings_view/settings_subviews/wallet_settings_subviews/wallet_delete_mnemonic_view_screen_test.mocks.dart index 94633d738..69f7b2af4 100644 --- a/test/screen_tests/settings_view/settings_subviews/wallet_settings_subviews/wallet_delete_mnemonic_view_screen_test.mocks.dart +++ b/test/screen_tests/settings_view/settings_subviews/wallet_settings_subviews/wallet_delete_mnemonic_view_screen_test.mocks.dart @@ -426,6 +426,11 @@ class MockManager extends _i1.Mock implements _i9.Manager { returnValue: false, ) as bool); @override + int get rescanOnOpenVersion => (super.noSuchMethod( + Invocation.getter(#rescanOnOpenVersion), + returnValue: 0, + ) as int); + @override bool get hasListeners => (super.noSuchMethod( Invocation.getter(#hasListeners), returnValue: false, @@ -591,6 +596,15 @@ class MockManager extends _i1.Mock implements _i9.Manager { returnValue: _i6.Future.value(false), ) as _i6.Future); @override + _i6.Future resetRescanOnOpen() => (super.noSuchMethod( + Invocation.method( + #resetRescanOnOpen, + [], + ), + returnValue: _i6.Future.value(), + returnValueForMissingStub: _i6.Future.value(), + ) as _i6.Future); + @override void addListener(_i8.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, diff --git a/test/screen_tests/settings_view/settings_subviews/wallet_settings_view_screen_test.mocks.dart b/test/screen_tests/settings_view/settings_subviews/wallet_settings_view_screen_test.mocks.dart index 824ffe3af..9e553a09d 100644 --- a/test/screen_tests/settings_view/settings_subviews/wallet_settings_view_screen_test.mocks.dart +++ b/test/screen_tests/settings_view/settings_subviews/wallet_settings_view_screen_test.mocks.dart @@ -683,6 +683,11 @@ class MockManager extends _i1.Mock implements _i15.Manager { returnValue: false, ) as bool); @override + int get rescanOnOpenVersion => (super.noSuchMethod( + Invocation.getter(#rescanOnOpenVersion), + returnValue: 0, + ) as int); + @override bool get hasListeners => (super.noSuchMethod( Invocation.getter(#hasListeners), returnValue: false, @@ -848,6 +853,15 @@ class MockManager extends _i1.Mock implements _i15.Manager { returnValue: _i8.Future.value(false), ) as _i8.Future); @override + _i8.Future resetRescanOnOpen() => (super.noSuchMethod( + Invocation.method( + #resetRescanOnOpen, + [], + ), + returnValue: _i8.Future.value(), + returnValueForMissingStub: _i8.Future.value(), + ) as _i8.Future); + @override void addListener(_i14.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, diff --git a/test/screen_tests/settings_view/settings_view_screen_test.mocks.dart b/test/screen_tests/settings_view/settings_view_screen_test.mocks.dart index c4ffca6b5..2eec54013 100644 --- a/test/screen_tests/settings_view/settings_view_screen_test.mocks.dart +++ b/test/screen_tests/settings_view/settings_view_screen_test.mocks.dart @@ -426,6 +426,11 @@ class MockManager extends _i1.Mock implements _i9.Manager { returnValue: false, ) as bool); @override + int get rescanOnOpenVersion => (super.noSuchMethod( + Invocation.getter(#rescanOnOpenVersion), + returnValue: 0, + ) as int); + @override bool get hasListeners => (super.noSuchMethod( Invocation.getter(#hasListeners), returnValue: false, @@ -591,6 +596,15 @@ class MockManager extends _i1.Mock implements _i9.Manager { returnValue: _i6.Future.value(false), ) as _i6.Future); @override + _i6.Future resetRescanOnOpen() => (super.noSuchMethod( + Invocation.method( + #resetRescanOnOpen, + [], + ), + returnValue: _i6.Future.value(), + returnValueForMissingStub: _i6.Future.value(), + ) as _i6.Future); + @override void addListener(_i8.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, diff --git a/test/screen_tests/transaction_subviews/transaction_search_results_view_screen_test.mocks.dart b/test/screen_tests/transaction_subviews/transaction_search_results_view_screen_test.mocks.dart index 5c7a23188..541ebe771 100644 --- a/test/screen_tests/transaction_subviews/transaction_search_results_view_screen_test.mocks.dart +++ b/test/screen_tests/transaction_subviews/transaction_search_results_view_screen_test.mocks.dart @@ -205,6 +205,11 @@ class MockManager extends _i1.Mock implements _i5.Manager { returnValue: false, ) as bool); @override + int get rescanOnOpenVersion => (super.noSuchMethod( + Invocation.getter(#rescanOnOpenVersion), + returnValue: 0, + ) as int); + @override bool get hasListeners => (super.noSuchMethod( Invocation.getter(#hasListeners), returnValue: false, @@ -370,6 +375,15 @@ class MockManager extends _i1.Mock implements _i5.Manager { returnValue: _i7.Future.value(false), ) as _i7.Future); @override + _i7.Future resetRescanOnOpen() => (super.noSuchMethod( + Invocation.method( + #resetRescanOnOpen, + [], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + @override void addListener(_i9.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, diff --git a/test/screen_tests/wallet_view/confirm_send_view_screen_test.mocks.dart b/test/screen_tests/wallet_view/confirm_send_view_screen_test.mocks.dart index 9a9c1aabf..0fd8166a6 100644 --- a/test/screen_tests/wallet_view/confirm_send_view_screen_test.mocks.dart +++ b/test/screen_tests/wallet_view/confirm_send_view_screen_test.mocks.dart @@ -204,6 +204,11 @@ class MockManager extends _i1.Mock implements _i5.Manager { returnValue: false, ) as bool); @override + int get rescanOnOpenVersion => (super.noSuchMethod( + Invocation.getter(#rescanOnOpenVersion), + returnValue: 0, + ) as int); + @override bool get hasListeners => (super.noSuchMethod( Invocation.getter(#hasListeners), returnValue: false, @@ -369,6 +374,15 @@ class MockManager extends _i1.Mock implements _i5.Manager { returnValue: _i7.Future.value(false), ) as _i7.Future); @override + _i7.Future resetRescanOnOpen() => (super.noSuchMethod( + Invocation.method( + #resetRescanOnOpen, + [], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + @override void addListener(_i9.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, diff --git a/test/screen_tests/wallet_view/receive_view_screen_test.mocks.dart b/test/screen_tests/wallet_view/receive_view_screen_test.mocks.dart index dd59e74bf..66bf7ae61 100644 --- a/test/screen_tests/wallet_view/receive_view_screen_test.mocks.dart +++ b/test/screen_tests/wallet_view/receive_view_screen_test.mocks.dart @@ -203,6 +203,11 @@ class MockManager extends _i1.Mock implements _i5.Manager { returnValue: false, ) as bool); @override + int get rescanOnOpenVersion => (super.noSuchMethod( + Invocation.getter(#rescanOnOpenVersion), + returnValue: 0, + ) as int); + @override bool get hasListeners => (super.noSuchMethod( Invocation.getter(#hasListeners), returnValue: false, @@ -368,6 +373,15 @@ class MockManager extends _i1.Mock implements _i5.Manager { returnValue: _i7.Future.value(false), ) as _i7.Future); @override + _i7.Future resetRescanOnOpen() => (super.noSuchMethod( + Invocation.method( + #resetRescanOnOpen, + [], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + @override void addListener(_i9.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, diff --git a/test/screen_tests/wallet_view/send_view_screen_test.mocks.dart b/test/screen_tests/wallet_view/send_view_screen_test.mocks.dart index cbd3c0795..18318af3e 100644 --- a/test/screen_tests/wallet_view/send_view_screen_test.mocks.dart +++ b/test/screen_tests/wallet_view/send_view_screen_test.mocks.dart @@ -245,6 +245,11 @@ class MockManager extends _i1.Mock implements _i8.Manager { returnValue: false, ) as bool); @override + int get rescanOnOpenVersion => (super.noSuchMethod( + Invocation.getter(#rescanOnOpenVersion), + returnValue: 0, + ) as int); + @override bool get hasListeners => (super.noSuchMethod( Invocation.getter(#hasListeners), returnValue: false, @@ -410,6 +415,15 @@ class MockManager extends _i1.Mock implements _i8.Manager { returnValue: _i7.Future.value(false), ) as _i7.Future); @override + _i7.Future resetRescanOnOpen() => (super.noSuchMethod( + Invocation.method( + #resetRescanOnOpen, + [], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + @override void addListener(_i11.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, diff --git a/test/screen_tests/wallet_view/wallet_view_screen_test.mocks.dart b/test/screen_tests/wallet_view/wallet_view_screen_test.mocks.dart index 892ec66ec..a20a9a381 100644 --- a/test/screen_tests/wallet_view/wallet_view_screen_test.mocks.dart +++ b/test/screen_tests/wallet_view/wallet_view_screen_test.mocks.dart @@ -205,6 +205,11 @@ class MockManager extends _i1.Mock implements _i5.Manager { returnValue: false, ) as bool); @override + int get rescanOnOpenVersion => (super.noSuchMethod( + Invocation.getter(#rescanOnOpenVersion), + returnValue: 0, + ) as int); + @override bool get hasListeners => (super.noSuchMethod( Invocation.getter(#hasListeners), returnValue: false, @@ -370,6 +375,15 @@ class MockManager extends _i1.Mock implements _i5.Manager { returnValue: _i7.Future.value(false), ) as _i7.Future); @override + _i7.Future resetRescanOnOpen() => (super.noSuchMethod( + Invocation.method( + #resetRescanOnOpen, + [], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + @override void addListener(_i9.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, diff --git a/test/widget_tests/managed_favorite_test.mocks.dart b/test/widget_tests/managed_favorite_test.mocks.dart index 89d6ae344..eb1112bad 100644 --- a/test/widget_tests/managed_favorite_test.mocks.dart +++ b/test/widget_tests/managed_favorite_test.mocks.dart @@ -2320,6 +2320,11 @@ class MockManager extends _i1.Mock implements _i6.Manager { returnValue: false, ) as bool); @override + int get rescanOnOpenVersion => (super.noSuchMethod( + Invocation.getter(#rescanOnOpenVersion), + returnValue: 0, + ) as int); + @override bool get hasListeners => (super.noSuchMethod( Invocation.getter(#hasListeners), returnValue: false, @@ -2485,6 +2490,15 @@ class MockManager extends _i1.Mock implements _i6.Manager { returnValue: _i21.Future.value(false), ) as _i21.Future); @override + _i21.Future resetRescanOnOpen() => (super.noSuchMethod( + Invocation.method( + #resetRescanOnOpen, + [], + ), + returnValue: _i21.Future.value(), + returnValueForMissingStub: _i21.Future.value(), + ) as _i21.Future); + @override void addListener(_i23.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, diff --git a/test/widget_tests/node_options_sheet_test.mocks.dart b/test/widget_tests/node_options_sheet_test.mocks.dart index d18c5165e..b4a020078 100644 --- a/test/widget_tests/node_options_sheet_test.mocks.dart +++ b/test/widget_tests/node_options_sheet_test.mocks.dart @@ -9,14 +9,12 @@ import 'dart:ui' as _i12; import 'package:flutter/foundation.dart' as _i4; import 'package:flutter_riverpod/flutter_riverpod.dart' as _i5; import 'package:mockito/mockito.dart' as _i1; -import 'package:stackwallet/models/node_model.dart' as _i16; -import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart' - as _i14; +import 'package:stackwallet/models/node_model.dart' as _i15; import 'package:stackwallet/services/coins/manager.dart' as _i6; import 'package:stackwallet/services/node_service.dart' as _i3; import 'package:stackwallet/services/wallets.dart' as _i8; import 'package:stackwallet/services/wallets_service.dart' as _i2; -import 'package:stackwallet/utilities/enums/backup_frequency_type.dart' as _i15; +import 'package:stackwallet/utilities/enums/backup_frequency_type.dart' as _i14; import 'package:stackwallet/utilities/enums/coin_enum.dart' as _i9; import 'package:stackwallet/utilities/enums/sync_type_enum.dart' as _i13; import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart' @@ -416,20 +414,6 @@ class MockPrefs extends _i1.Mock implements _i11.Prefs { returnValueForMissingStub: null, ); @override - _i14.ExchangeRateType get exchangeRateType => (super.noSuchMethod( - Invocation.getter(#exchangeRateType), - returnValue: _i14.ExchangeRateType.estimated, - ) as _i14.ExchangeRateType); - @override - set exchangeRateType(_i14.ExchangeRateType? exchangeRateType) => - super.noSuchMethod( - Invocation.setter( - #exchangeRateType, - exchangeRateType, - ), - returnValueForMissingStub: null, - ); - @override bool get useBiometrics => (super.noSuchMethod( Invocation.getter(#useBiometrics), returnValue: false, @@ -503,12 +487,12 @@ class MockPrefs extends _i1.Mock implements _i11.Prefs { returnValueForMissingStub: null, ); @override - _i15.BackupFrequencyType get backupFrequencyType => (super.noSuchMethod( + _i14.BackupFrequencyType get backupFrequencyType => (super.noSuchMethod( Invocation.getter(#backupFrequencyType), - returnValue: _i15.BackupFrequencyType.everyTenMinutes, - ) as _i15.BackupFrequencyType); + returnValue: _i14.BackupFrequencyType.everyTenMinutes, + ) as _i14.BackupFrequencyType); @override - set backupFrequencyType(_i15.BackupFrequencyType? backupFrequencyType) => + set backupFrequencyType(_i14.BackupFrequencyType? backupFrequencyType) => super.noSuchMethod( Invocation.setter( #backupFrequencyType, @@ -672,15 +656,15 @@ class MockNodeService extends _i1.Mock implements _i3.NodeService { ), ) as _i7.SecureStorageInterface); @override - List<_i16.NodeModel> get primaryNodes => (super.noSuchMethod( + List<_i15.NodeModel> get primaryNodes => (super.noSuchMethod( Invocation.getter(#primaryNodes), - returnValue: <_i16.NodeModel>[], - ) as List<_i16.NodeModel>); + returnValue: <_i15.NodeModel>[], + ) as List<_i15.NodeModel>); @override - List<_i16.NodeModel> get nodes => (super.noSuchMethod( + List<_i15.NodeModel> get nodes => (super.noSuchMethod( Invocation.getter(#nodes), - returnValue: <_i16.NodeModel>[], - ) as List<_i16.NodeModel>); + returnValue: <_i15.NodeModel>[], + ) as List<_i15.NodeModel>); @override bool get hasListeners => (super.noSuchMethod( Invocation.getter(#hasListeners), @@ -698,7 +682,7 @@ class MockNodeService extends _i1.Mock implements _i3.NodeService { @override _i10.Future setPrimaryNodeFor({ required _i9.Coin? coin, - required _i16.NodeModel? node, + required _i15.NodeModel? node, bool? shouldNotifyListeners = false, }) => (super.noSuchMethod( @@ -715,40 +699,40 @@ class MockNodeService extends _i1.Mock implements _i3.NodeService { returnValueForMissingStub: _i10.Future.value(), ) as _i10.Future); @override - _i16.NodeModel? getPrimaryNodeFor({required _i9.Coin? coin}) => + _i15.NodeModel? getPrimaryNodeFor({required _i9.Coin? coin}) => (super.noSuchMethod(Invocation.method( #getPrimaryNodeFor, [], {#coin: coin}, - )) as _i16.NodeModel?); + )) as _i15.NodeModel?); @override - List<_i16.NodeModel> getNodesFor(_i9.Coin? coin) => (super.noSuchMethod( + List<_i15.NodeModel> getNodesFor(_i9.Coin? coin) => (super.noSuchMethod( Invocation.method( #getNodesFor, [coin], ), - returnValue: <_i16.NodeModel>[], - ) as List<_i16.NodeModel>); + returnValue: <_i15.NodeModel>[], + ) as List<_i15.NodeModel>); @override - _i16.NodeModel? getNodeById({required String? id}) => + _i15.NodeModel? getNodeById({required String? id}) => (super.noSuchMethod(Invocation.method( #getNodeById, [], {#id: id}, - )) as _i16.NodeModel?); + )) as _i15.NodeModel?); @override - List<_i16.NodeModel> failoverNodesFor({required _i9.Coin? coin}) => + List<_i15.NodeModel> failoverNodesFor({required _i9.Coin? coin}) => (super.noSuchMethod( Invocation.method( #failoverNodesFor, [], {#coin: coin}, ), - returnValue: <_i16.NodeModel>[], - ) as List<_i16.NodeModel>); + returnValue: <_i15.NodeModel>[], + ) as List<_i15.NodeModel>); @override _i10.Future add( - _i16.NodeModel? node, + _i15.NodeModel? node, String? password, bool? shouldNotifyListeners, ) => @@ -800,7 +784,7 @@ class MockNodeService extends _i1.Mock implements _i3.NodeService { ) as _i10.Future); @override _i10.Future edit( - _i16.NodeModel? editedNode, + _i15.NodeModel? editedNode, String? password, bool? shouldNotifyListeners, ) => diff --git a/test/widget_tests/table_view/table_view_row_test.mocks.dart b/test/widget_tests/table_view/table_view_row_test.mocks.dart index 829d3a81b..0f89fb269 100644 --- a/test/widget_tests/table_view/table_view_row_test.mocks.dart +++ b/test/widget_tests/table_view/table_view_row_test.mocks.dart @@ -2045,6 +2045,11 @@ class MockManager extends _i1.Mock implements _i6.Manager { returnValue: false, ) as bool); @override + int get rescanOnOpenVersion => (super.noSuchMethod( + Invocation.getter(#rescanOnOpenVersion), + returnValue: 0, + ) as int); + @override bool get hasListeners => (super.noSuchMethod( Invocation.getter(#hasListeners), returnValue: false, @@ -2210,6 +2215,15 @@ class MockManager extends _i1.Mock implements _i6.Manager { returnValue: _i20.Future.value(false), ) as _i20.Future); @override + _i20.Future resetRescanOnOpen() => (super.noSuchMethod( + Invocation.method( + #resetRescanOnOpen, + [], + ), + returnValue: _i20.Future.value(), + returnValueForMissingStub: _i20.Future.value(), + ) as _i20.Future); + @override void addListener(_i22.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, diff --git a/test/widget_tests/transaction_card_test.mocks.dart b/test/widget_tests/transaction_card_test.mocks.dart index a650dee57..5f33e0a53 100644 --- a/test/widget_tests/transaction_card_test.mocks.dart +++ b/test/widget_tests/transaction_card_test.mocks.dart @@ -16,20 +16,18 @@ import 'package:stackwallet/electrumx_rpc/electrumx.dart' as _i11; import 'package:stackwallet/models/balance.dart' as _i9; import 'package:stackwallet/models/isar/models/isar_models.dart' as _i21; import 'package:stackwallet/models/models.dart' as _i8; -import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart' - as _i25; import 'package:stackwallet/services/coins/coin_service.dart' as _i7; import 'package:stackwallet/services/coins/firo/firo_wallet.dart' as _i22; import 'package:stackwallet/services/coins/manager.dart' as _i6; import 'package:stackwallet/services/locale_service.dart' as _i23; import 'package:stackwallet/services/node_service.dart' as _i3; -import 'package:stackwallet/services/notes_service.dart' as _i28; -import 'package:stackwallet/services/price_service.dart' as _i27; +import 'package:stackwallet/services/notes_service.dart' as _i27; +import 'package:stackwallet/services/price_service.dart' as _i26; import 'package:stackwallet/services/transaction_notification_tracker.dart' as _i10; import 'package:stackwallet/services/wallets.dart' as _i16; import 'package:stackwallet/services/wallets_service.dart' as _i2; -import 'package:stackwallet/utilities/enums/backup_frequency_type.dart' as _i26; +import 'package:stackwallet/utilities/enums/backup_frequency_type.dart' as _i25; import 'package:stackwallet/utilities/enums/coin_enum.dart' as _i17; import 'package:stackwallet/utilities/enums/sync_type_enum.dart' as _i24; import 'package:stackwallet/utilities/prefs.dart' as _i19; @@ -548,6 +546,11 @@ class MockManager extends _i1.Mock implements _i6.Manager { returnValue: false, ) as bool); @override + int get rescanOnOpenVersion => (super.noSuchMethod( + Invocation.getter(#rescanOnOpenVersion), + returnValue: 0, + ) as int); + @override bool get hasListeners => (super.noSuchMethod( Invocation.getter(#hasListeners), returnValue: false, @@ -713,6 +716,15 @@ class MockManager extends _i1.Mock implements _i6.Manager { returnValue: _i18.Future.value(false), ) as _i18.Future); @override + _i18.Future resetRescanOnOpen() => (super.noSuchMethod( + Invocation.method( + #resetRescanOnOpen, + [], + ), + returnValue: _i18.Future.value(), + returnValueForMissingStub: _i18.Future.value(), + ) as _i18.Future); + @override void addListener(_i20.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, @@ -2164,20 +2176,6 @@ class MockPrefs extends _i1.Mock implements _i19.Prefs { returnValueForMissingStub: null, ); @override - _i25.ExchangeRateType get exchangeRateType => (super.noSuchMethod( - Invocation.getter(#exchangeRateType), - returnValue: _i25.ExchangeRateType.estimated, - ) as _i25.ExchangeRateType); - @override - set exchangeRateType(_i25.ExchangeRateType? exchangeRateType) => - super.noSuchMethod( - Invocation.setter( - #exchangeRateType, - exchangeRateType, - ), - returnValueForMissingStub: null, - ); - @override bool get useBiometrics => (super.noSuchMethod( Invocation.getter(#useBiometrics), returnValue: false, @@ -2251,12 +2249,12 @@ class MockPrefs extends _i1.Mock implements _i19.Prefs { returnValueForMissingStub: null, ); @override - _i26.BackupFrequencyType get backupFrequencyType => (super.noSuchMethod( + _i25.BackupFrequencyType get backupFrequencyType => (super.noSuchMethod( Invocation.getter(#backupFrequencyType), - returnValue: _i26.BackupFrequencyType.everyTenMinutes, - ) as _i26.BackupFrequencyType); + returnValue: _i25.BackupFrequencyType.everyTenMinutes, + ) as _i25.BackupFrequencyType); @override - set backupFrequencyType(_i26.BackupFrequencyType? backupFrequencyType) => + set backupFrequencyType(_i25.BackupFrequencyType? backupFrequencyType) => super.noSuchMethod( Invocation.setter( #backupFrequencyType, @@ -2406,7 +2404,7 @@ class MockPrefs extends _i1.Mock implements _i19.Prefs { /// A class which mocks [PriceService]. /// /// See the documentation for Mockito's code generation for more information. -class MockPriceService extends _i1.Mock implements _i27.PriceService { +class MockPriceService extends _i1.Mock implements _i26.PriceService { MockPriceService() { _i1.throwOnMissingStub(this); } @@ -2514,7 +2512,7 @@ class MockPriceService extends _i1.Mock implements _i27.PriceService { /// A class which mocks [NotesService]. /// /// See the documentation for Mockito's code generation for more information. -class MockNotesService extends _i1.Mock implements _i28.NotesService { +class MockNotesService extends _i1.Mock implements _i27.NotesService { MockNotesService() { _i1.throwOnMissingStub(this); } diff --git a/test/widget_tests/wallet_info_row/sub_widgets/wallet_info_row_balance_future_test.mocks.dart b/test/widget_tests/wallet_info_row/sub_widgets/wallet_info_row_balance_future_test.mocks.dart index aaa0a2baf..7d84b5547 100644 --- a/test/widget_tests/wallet_info_row/sub_widgets/wallet_info_row_balance_future_test.mocks.dart +++ b/test/widget_tests/wallet_info_row/sub_widgets/wallet_info_row_balance_future_test.mocks.dart @@ -2257,6 +2257,11 @@ class MockManager extends _i1.Mock implements _i6.Manager { returnValue: false, ) as bool); @override + int get rescanOnOpenVersion => (super.noSuchMethod( + Invocation.getter(#rescanOnOpenVersion), + returnValue: 0, + ) as int); + @override bool get hasListeners => (super.noSuchMethod( Invocation.getter(#hasListeners), returnValue: false, @@ -2422,6 +2427,15 @@ class MockManager extends _i1.Mock implements _i6.Manager { returnValue: _i21.Future.value(false), ) as _i21.Future); @override + _i21.Future resetRescanOnOpen() => (super.noSuchMethod( + Invocation.method( + #resetRescanOnOpen, + [], + ), + returnValue: _i21.Future.value(), + returnValueForMissingStub: _i21.Future.value(), + ) as _i21.Future); + @override void addListener(_i23.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, diff --git a/test/widget_tests/wallet_info_row/wallet_info_row_test.mocks.dart b/test/widget_tests/wallet_info_row/wallet_info_row_test.mocks.dart index 2f252b0a8..86ffa6c63 100644 --- a/test/widget_tests/wallet_info_row/wallet_info_row_test.mocks.dart +++ b/test/widget_tests/wallet_info_row/wallet_info_row_test.mocks.dart @@ -2257,6 +2257,11 @@ class MockManager extends _i1.Mock implements _i6.Manager { returnValue: false, ) as bool); @override + int get rescanOnOpenVersion => (super.noSuchMethod( + Invocation.getter(#rescanOnOpenVersion), + returnValue: 0, + ) as int); + @override bool get hasListeners => (super.noSuchMethod( Invocation.getter(#hasListeners), returnValue: false, @@ -2422,6 +2427,15 @@ class MockManager extends _i1.Mock implements _i6.Manager { returnValue: _i21.Future.value(false), ) as _i21.Future); @override + _i21.Future resetRescanOnOpen() => (super.noSuchMethod( + Invocation.method( + #resetRescanOnOpen, + [], + ), + returnValue: _i21.Future.value(), + returnValueForMissingStub: _i21.Future.value(), + ) as _i21.Future); + @override void addListener(_i23.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener,