import 'dart:async'; import 'package:hash_wallet/exchange/exchange_provider_description.dart'; import 'package:hash_wallet/exchange/provider/exchange_provider.dart'; import 'package:hash_wallet/exchange/provider/near_Intents_exchange_provider.dart'; import 'package:hash_wallet/exchange/provider/trocador_exchange_provider.dart'; import 'package:hash_wallet/exchange/trade.dart'; import 'package:hash_wallet/generated/i18n.dart'; import 'package:hash_wallet/src/screens/trade_details/track_trade_list_item.dart'; import 'package:hash_wallet/src/screens/trade_details/trade_details_list_card.dart'; import 'package:hash_wallet/src/screens/trade_details/trade_details_status_item.dart'; import 'package:hash_wallet/src/screens/trade_details/trade_provider_unsupported_item.dart'; import 'package:hash_wallet/src/screens/transaction_details/standart_list_item.dart'; import 'package:hash_wallet/store/app_store.dart'; import 'package:hash_wallet/utils/date_formatter.dart'; import 'package:hash_wallet/utils/show_bar.dart'; import 'package:cw_core/utils/print_verbose.dart'; import 'package:flutter/services.dart'; import 'package:mobx/mobx.dart'; import 'package:url_launcher/url_launcher.dart'; part 'trade_details_view_model.g.dart'; class TradeDetailsViewModel = TradeDetailsViewModelBase with _$TradeDetailsViewModel; abstract class TradeDetailsViewModelBase with Store { TradeDetailsViewModelBase({ required Trade tradeForDetails, required this.appStore, }) : items = ObservableList(), trade = tradeForDetails { // Trades from providers whose implementations were removed keep a null // _provider and show the "provider unsupported" item with stored data. switch (trade.provider) { case ExchangeProviderDescription.trocador: _provider = TrocadorExchangeProvider(); break; case ExchangeProviderDescription.nearIntents: _provider = NearIntentsExchangeProvider(); break; } _updateItems(); if (_provider != null) { _updateTrade(); timer = Timer.periodic(Duration(seconds: 20), (_) async => _updateTrade()); } } static String? getTrackUrl(ExchangeProviderDescription provider, Trade trade) { switch (provider) { case ExchangeProviderDescription.changeNow: return 'https://changenow.io/exchange/txs/${trade.id}'; case ExchangeProviderDescription.sideShift: return 'https://sideshift.ai/orders/${trade.id}'; case ExchangeProviderDescription.simpleSwap: return 'https://simpleswap.io/exchange?id=${trade.id}'; case ExchangeProviderDescription.trocador: return 'https://trocador.app/en/checkout/${trade.id}'; case ExchangeProviderDescription.exolix: return 'https://exolix.com/transaction/${trade.id}'; case ExchangeProviderDescription.thorChain: return 'https://track.ninerealms.com/${trade.id}'; case ExchangeProviderDescription.swapTrade: return 'https://swaptrade.io/send/${trade.id}'; case ExchangeProviderDescription.letsExchange: return 'https://letsexchange.io/?transactionId=${trade.id}'; case ExchangeProviderDescription.stealthEx: return 'https://stealthex.io/exchange/?id=${trade.id}'; case ExchangeProviderDescription.chainflip: return 'https://scan.chainflip.io/channels/${trade.id}'; case ExchangeProviderDescription.xoSwap: return 'https://orders.xoswap.com/${trade.id}'; case ExchangeProviderDescription.swapsXyz: return 'https://scan.swaps.xyz/transactions/${trade.id}'; case ExchangeProviderDescription.nearIntents: return 'https://explorer.near-intents.org/transactions/${trade.id}'; } return null; } @observable Trade trade; @observable ObservableList items; ExchangeProvider? _provider; Timer? timer; final AppStore appStore; @action Future _updateTrade() async { try { final updatedTrade = await _provider!.findTradeById(id: trade.id); trade.mergeFindTradeByIdResult(updatedTrade); await trade.save(); _updateItems(); } catch (e) { printV(e.toString()); } } void _updateItems() { final dateFormat = DateFormatter.withCurrentLocal(reverse: true); items.clear(); if (_provider == null) items.add(TradeProviderUnsupportedItem( error: S.current.exchange_provider_unsupported(trade.provider.title))); items.add( DetailsListStatusItem(title: S.current.trade_details_state, value: trade.state.toString())); final tradeFrom = trade.from; final tradeTo = trade.to; if (tradeFrom != null && tradeTo != null) { items.add(TradeDetailsListCardItem.tradeDetails( id: trade.id, extraId: trade.extraId, createdAt: trade.createdAt != null ? dateFormat.format(trade.createdAt!) : '', from: tradeFrom, to: tradeTo, onTap: (context) { Clipboard.setData(ClipboardData(text: trade.id)); showBar(context, S.of(context).copied_to_clipboard); }, )); } items.add(StandartListItem( title: S.current.trade_details_provider, value: trade.provider.toString())); final trackUrl = TradeDetailsViewModelBase.getTrackUrl(trade.provider, trade); if (trackUrl != null) { items.add(TrackTradeListItem( title: S.current.track, value: trackUrl, onTap: () => _launchUrl(trackUrl))); } if (trade.isRefund == true) { items.add(StandartListItem( title: 'Refund', value: trade.refundAddress ?? '')); } if (trade.provider == ExchangeProviderDescription.trocador) { items.add(StandartListItem( title: '${trade.providerName} ${S.current.id.toUpperCase()}', value: trade.providerId ?? '')); if (trade.password != null && trade.password!.isNotEmpty) { items.add(StandartListItem( title: '${trade.providerName} ${S.current.password}', value: trade.password ?? '')); } } if (trade.provider == ExchangeProviderDescription.swapsXyz && trade.txId != null && trade.txId!.isNotEmpty) { items.add(StandartListItem( title: 'Transaction ID', value: trade.txId!)); } } void _launchUrl(String url) { final uri = Uri.parse(url); try { launchUrl(uri, mode: LaunchMode.externalApplication); } catch (e) {} } }