mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-06-28 20:39:51 +00:00
CW-959: Swap Status on Transaction Screen (#2247)
* feat(swap-status-monitor): add real-time swap status monitoring and UI updates - Introduce SwapManager for automatic tracking of active-wallet swaps. - Automatically queues new or updated trades from the Hive box. - Periodically fetch and persist swap statuses via the corresponding trade provider. - Implement start(wallet, providers), stop(), and dispose() for lifecycle control. - Apply user's ExchangeApiMode(disabled, tor-only, enabled) when fetching updates. - Remove swaps from the watchlist on any final state (completed, expired, failed). - Dispose SwapManager in AppState.dispose() to cancel polling and the Hive subscription. * refactor(swap-status): replace SwapManager with TradeMonitor for improved trade monitoring. This change improves the flow by simplifying the trade monitoring logic. - Removes SwapManager class and replace with TradeMonitor implementation - Update di and Appstate to register and dispose TradeMonitor - Modify DashboardViewModel to use TradeMonitor instead of SwapManager * fix: Modify trade monitoring logic to ensure trade timers are properly disposed when wallet switching occurs * fix(swap-status): Fix receive amount for exchanges showing as .00 because of null values
This commit is contained in:
parent
78bb170533
commit
eede8fa6c7
6 changed files with 322 additions and 55 deletions
211
lib/core/trade_monitor.dart
Normal file
211
lib/core/trade_monitor.dart
Normal file
|
@ -0,0 +1,211 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'package:cake_wallet/exchange/provider/simpleswap_exchange_provider.dart';
|
||||||
|
import 'package:cake_wallet/exchange/trade.dart';
|
||||||
|
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||||
|
import 'package:cake_wallet/store/dashboard/trades_store.dart';
|
||||||
|
import 'package:cake_wallet/store/settings_store.dart';
|
||||||
|
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
||||||
|
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||||
|
import 'package:cake_wallet/exchange/provider/chainflip_exchange_provider.dart';
|
||||||
|
import 'package:cake_wallet/exchange/provider/changenow_exchange_provider.dart';
|
||||||
|
import 'package:cake_wallet/exchange/provider/exchange_provider.dart';
|
||||||
|
import 'package:cake_wallet/exchange/provider/exolix_exchange_provider.dart';
|
||||||
|
import 'package:cake_wallet/exchange/provider/letsexchange_exchange_provider.dart';
|
||||||
|
import 'package:cake_wallet/exchange/provider/swaptrade_exchange_provider.dart';
|
||||||
|
import 'package:cake_wallet/exchange/provider/sideshift_exchange_provider.dart';
|
||||||
|
import 'package:cake_wallet/exchange/provider/stealth_ex_exchange_provider.dart';
|
||||||
|
import 'package:cake_wallet/exchange/provider/thorchain_exchange.provider.dart';
|
||||||
|
import 'package:cake_wallet/exchange/provider/trocador_exchange_provider.dart';
|
||||||
|
import 'package:cake_wallet/exchange/provider/xoswap_exchange_provider.dart';
|
||||||
|
import 'package:cw_core/utils/print_verbose.dart';
|
||||||
|
import 'package:hive/hive.dart';
|
||||||
|
|
||||||
|
class TradeMonitor {
|
||||||
|
static const int _tradeCheckIntervalMinutes = 1;
|
||||||
|
static const int _maxTradeAgeHours = 24;
|
||||||
|
|
||||||
|
TradeMonitor({
|
||||||
|
required this.tradesStore,
|
||||||
|
required this.settingsStore,
|
||||||
|
required this.trades,
|
||||||
|
});
|
||||||
|
|
||||||
|
final TradesStore tradesStore;
|
||||||
|
final Box<Trade> trades;
|
||||||
|
final SettingsStore settingsStore;
|
||||||
|
final Map<String, Timer> _tradeTimers = {};
|
||||||
|
|
||||||
|
ExchangeProvider? _getProviderByDescription(ExchangeProviderDescription description) {
|
||||||
|
switch (description) {
|
||||||
|
case ExchangeProviderDescription.changeNow:
|
||||||
|
return ChangeNowExchangeProvider(settingsStore: settingsStore);
|
||||||
|
case ExchangeProviderDescription.sideShift:
|
||||||
|
return SideShiftExchangeProvider();
|
||||||
|
case ExchangeProviderDescription.simpleSwap:
|
||||||
|
return SimpleSwapExchangeProvider();
|
||||||
|
case ExchangeProviderDescription.trocador:
|
||||||
|
return TrocadorExchangeProvider();
|
||||||
|
case ExchangeProviderDescription.exolix:
|
||||||
|
return ExolixExchangeProvider();
|
||||||
|
case ExchangeProviderDescription.thorChain:
|
||||||
|
return ThorChainExchangeProvider(tradesStore: trades);
|
||||||
|
case ExchangeProviderDescription.swapTrade:
|
||||||
|
return SwapTradeExchangeProvider();
|
||||||
|
case ExchangeProviderDescription.letsExchange:
|
||||||
|
return LetsExchangeExchangeProvider();
|
||||||
|
case ExchangeProviderDescription.stealthEx:
|
||||||
|
return StealthExExchangeProvider();
|
||||||
|
case ExchangeProviderDescription.chainflip:
|
||||||
|
return ChainflipExchangeProvider(tradesStore: trades);
|
||||||
|
case ExchangeProviderDescription.xoSwap:
|
||||||
|
return XOSwapExchangeProvider();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void monitorActiveTrades(String walletId) {
|
||||||
|
final now = DateTime.now();
|
||||||
|
final trades = tradesStore.trades;
|
||||||
|
final tradesToCancel = <String>[];
|
||||||
|
|
||||||
|
for (final item in trades) {
|
||||||
|
final trade = item.trade;
|
||||||
|
|
||||||
|
if (_shouldCancelTradeTimer(trade, walletId, now)) {
|
||||||
|
if (_tradeTimers.containsKey(trade.id)) {
|
||||||
|
tradesToCancel.add(trade.id);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_tradeTimers.containsKey(trade.id)) {
|
||||||
|
printV('Starting trade monitoring for ${trade.id}');
|
||||||
|
_startTradeMonitoring(trade);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_cancelTradeTimers(tradesToCancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _shouldCancelTradeTimer(Trade trade, String walletId, DateTime now) {
|
||||||
|
if (trade.walletId != walletId) return true;
|
||||||
|
|
||||||
|
final createdAt = trade.createdAt;
|
||||||
|
if (createdAt == null) return true;
|
||||||
|
|
||||||
|
if (now.difference(createdAt).inHours > _maxTradeAgeHours) return true;
|
||||||
|
|
||||||
|
return _isFinalState(trade.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _startTradeMonitoring(Trade trade) {
|
||||||
|
if (_tradeTimers.containsKey(trade.id)) return;
|
||||||
|
|
||||||
|
_checkTradeStatus(trade);
|
||||||
|
|
||||||
|
final timer = Timer.periodic(
|
||||||
|
Duration(minutes: _tradeCheckIntervalMinutes),
|
||||||
|
(_) => _checkTradeStatus(trade)
|
||||||
|
);
|
||||||
|
|
||||||
|
_tradeTimers[trade.id] = timer;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _checkTradeStatus(Trade trade) async {
|
||||||
|
printV('Checking trade status for ${trade.id}');
|
||||||
|
|
||||||
|
if (_isTradeOld(trade)) {
|
||||||
|
printV('The trade ${trade.id} is older than $_maxTradeAgeHours hours, we will cancel the timer');
|
||||||
|
_cancelTradeTimer(trade.id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final provider = _getProviderByDescription(trade.provider);
|
||||||
|
if (provider == null) {
|
||||||
|
printV('No provider found for trade ${trade.id}');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_isExchangeModeEnabled(provider)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await _updateTradeStatus(trade, provider);
|
||||||
|
} catch (e) {
|
||||||
|
printV('Error fetching status for ${trade.id}: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _isTradeOld(Trade trade) {
|
||||||
|
final now = DateTime.now();
|
||||||
|
final createdAt = trade.createdAt;
|
||||||
|
return createdAt != null && now.difference(createdAt).inHours > _maxTradeAgeHours;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _isExchangeModeEnabled(ExchangeProvider provider) {
|
||||||
|
final exchangeApiMode = settingsStore.exchangeStatus;
|
||||||
|
|
||||||
|
if (exchangeApiMode == ExchangeApiMode.disabled) {
|
||||||
|
printV('Exchange API mode is disabled');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exchangeApiMode == ExchangeApiMode.torOnly && !provider.supportsOnionAddress) {
|
||||||
|
printV('Skipping ${provider.description}, no TOR support');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _updateTradeStatus(Trade trade, ExchangeProvider provider) async {
|
||||||
|
final updated = await provider.findTradeById(id: trade.id);
|
||||||
|
trade
|
||||||
|
..stateRaw = updated.state.raw
|
||||||
|
..receiveAmount = updated.receiveAmount ?? trade.receiveAmount
|
||||||
|
..outputTransaction = updated.outputTransaction ?? trade.outputTransaction;
|
||||||
|
printV('Trade ${trade.id} updated: ${trade.state}');
|
||||||
|
await trade.save();
|
||||||
|
|
||||||
|
if (_isFinalState(updated.state)) {
|
||||||
|
printV('Trade ${trade.id} is in final state');
|
||||||
|
_cancelTradeTimer(trade.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _cancelTradeTimer(String tradeId) {
|
||||||
|
_tradeTimers[tradeId]?.cancel();
|
||||||
|
_tradeTimers.remove(tradeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _cancelTradeTimers(List<String> tradeIds) {
|
||||||
|
for (final tradeId in tradeIds) {
|
||||||
|
_cancelTradeTimer(tradeId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cancelAllTradeTimers() {
|
||||||
|
for (final timer in _tradeTimers.values) {
|
||||||
|
timer.cancel();
|
||||||
|
}
|
||||||
|
_tradeTimers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _isFinalState(TradeState state) {
|
||||||
|
return {
|
||||||
|
TradeState.completed.raw,
|
||||||
|
TradeState.success.raw,
|
||||||
|
TradeState.confirmed.raw,
|
||||||
|
TradeState.settled.raw,
|
||||||
|
TradeState.finished.raw,
|
||||||
|
TradeState.expired.raw,
|
||||||
|
TradeState.failed.raw,
|
||||||
|
TradeState.notFound.raw,
|
||||||
|
}.contains(state.raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dispose() {
|
||||||
|
cancelAllTradeTimers();
|
||||||
|
}
|
||||||
|
}
|
36
lib/di.dart
36
lib/di.dart
|
@ -275,6 +275,7 @@ import 'src/screens/buy/buy_sell_page.dart';
|
||||||
import 'cake_pay/cake_pay_payment_credantials.dart';
|
import 'cake_pay/cake_pay_payment_credantials.dart';
|
||||||
import 'package:cake_wallet/view_model/dev/background_sync_logs_view_model.dart';
|
import 'package:cake_wallet/view_model/dev/background_sync_logs_view_model.dart';
|
||||||
import 'package:cake_wallet/src/screens/dev/background_sync_logs_page.dart';
|
import 'package:cake_wallet/src/screens/dev/background_sync_logs_page.dart';
|
||||||
|
import 'package:cake_wallet/core/trade_monitor.dart';
|
||||||
|
|
||||||
final getIt = GetIt.instance;
|
final getIt = GetIt.instance;
|
||||||
|
|
||||||
|
@ -507,7 +508,29 @@ Future<void> setup({
|
||||||
settingsStore: getIt.get<SettingsStore>(),
|
settingsStore: getIt.get<SettingsStore>(),
|
||||||
fiatConvertationStore: getIt.get<FiatConversionStore>()));
|
fiatConvertationStore: getIt.get<FiatConversionStore>()));
|
||||||
|
|
||||||
|
getIt.registerFactory(
|
||||||
|
() => ExchangeViewModel(
|
||||||
|
getIt.get<AppStore>(),
|
||||||
|
_tradesSource,
|
||||||
|
getIt.get<ExchangeTemplateStore>(),
|
||||||
|
getIt.get<TradesStore>(),
|
||||||
|
getIt.get<AppStore>().settingsStore,
|
||||||
|
getIt.get<SharedPreferences>(),
|
||||||
|
getIt.get<ContactListViewModel>(),
|
||||||
|
getIt.get<FeesViewModel>(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
getIt.registerSingleton(
|
||||||
|
TradeMonitor(
|
||||||
|
tradesStore: getIt.get<TradesStore>(),
|
||||||
|
settingsStore: getIt.get<SettingsStore>(),
|
||||||
|
trades: _tradesSource
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
getIt.registerFactory(() => DashboardViewModel(
|
getIt.registerFactory(() => DashboardViewModel(
|
||||||
|
tradeMonitor: getIt.get<TradeMonitor>(),
|
||||||
balanceViewModel: getIt.get<BalanceViewModel>(),
|
balanceViewModel: getIt.get<BalanceViewModel>(),
|
||||||
appStore: getIt.get<AppStore>(),
|
appStore: getIt.get<AppStore>(),
|
||||||
tradesStore: getIt.get<TradesStore>(),
|
tradesStore: getIt.get<TradesStore>(),
|
||||||
|
@ -1051,19 +1074,6 @@ Future<void> setup({
|
||||||
|
|
||||||
getIt.registerFactoryParam<WebViewPage, String, Uri>((title, uri) => WebViewPage(title, uri));
|
getIt.registerFactoryParam<WebViewPage, String, Uri>((title, uri) => WebViewPage(title, uri));
|
||||||
|
|
||||||
getIt.registerFactory(
|
|
||||||
() => ExchangeViewModel(
|
|
||||||
getIt.get<AppStore>(),
|
|
||||||
_tradesSource,
|
|
||||||
getIt.get<ExchangeTemplateStore>(),
|
|
||||||
getIt.get<TradesStore>(),
|
|
||||||
getIt.get<SettingsStore>(),
|
|
||||||
getIt.get<SharedPreferences>(),
|
|
||||||
getIt.get<ContactListViewModel>(),
|
|
||||||
getIt.get<FeesViewModel>(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
getIt.registerFactory<FeesViewModel>(
|
getIt.registerFactory<FeesViewModel>(
|
||||||
() => FeesViewModel(
|
() => FeesViewModel(
|
||||||
getIt.get<AppStore>(),
|
getIt.get<AppStore>(),
|
||||||
|
|
|
@ -51,6 +51,7 @@ import 'package:cw_core/root_dir.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:cw_core/window_size.dart';
|
import 'package:cw_core/window_size.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
|
import 'package:cake_wallet/core/trade_monitor.dart';
|
||||||
|
|
||||||
final navigatorKey = GlobalKey<NavigatorState>();
|
final navigatorKey = GlobalKey<NavigatorState>();
|
||||||
final rootKey = GlobalKey<RootState>();
|
final rootKey = GlobalKey<RootState>();
|
||||||
|
|
|
@ -169,6 +169,7 @@ class TransactionsPage extends StatelessWidget {
|
||||||
key: item.key,
|
key: item.key,
|
||||||
onTap: () => Navigator.of(context)
|
onTap: () => Navigator.of(context)
|
||||||
.pushNamed(Routes.tradeDetails, arguments: trade),
|
.pushNamed(Routes.tradeDetails, arguments: trade),
|
||||||
|
swapState: trade.state,
|
||||||
provider: trade.provider,
|
provider: trade.provider,
|
||||||
from: trade.from,
|
from: trade.from,
|
||||||
to: trade.to,
|
to: trade.to,
|
||||||
|
@ -176,7 +177,8 @@ class TransactionsPage extends StatelessWidget {
|
||||||
? DateFormat('HH:mm').format(trade.createdAt!)
|
? DateFormat('HH:mm').format(trade.createdAt!)
|
||||||
: null,
|
: null,
|
||||||
formattedAmount: item.tradeFormattedAmount,
|
formattedAmount: item.tradeFormattedAmount,
|
||||||
formattedReceiveAmount: item.tradeFormattedReceiveAmount),
|
formattedReceiveAmount: item.tradeFormattedReceiveAmount
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (item is OrderListItem) {
|
if (item is OrderListItem) {
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
|
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||||
|
import 'package:cake_wallet/palette.dart';
|
||||||
import 'package:cake_wallet/utils/image_utill.dart';
|
import 'package:cake_wallet/utils/image_utill.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
|
||||||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||||
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
|
|
||||||
class TradeRow extends StatelessWidget {
|
class TradeRow extends StatelessWidget {
|
||||||
TradeRow({
|
TradeRow({
|
||||||
|
@ -12,6 +14,7 @@ class TradeRow extends StatelessWidget {
|
||||||
this.onTap,
|
this.onTap,
|
||||||
this.formattedAmount,
|
this.formattedAmount,
|
||||||
this.formattedReceiveAmount,
|
this.formattedReceiveAmount,
|
||||||
|
required this.swapState,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -22,6 +25,7 @@ class TradeRow extends StatelessWidget {
|
||||||
final String? createdAtFormattedDate;
|
final String? createdAtFormattedDate;
|
||||||
final String? formattedAmount;
|
final String? formattedAmount;
|
||||||
final String? formattedReceiveAmount;
|
final String? formattedReceiveAmount;
|
||||||
|
final TradeState swapState;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -36,15 +40,29 @@ class TradeRow extends StatelessWidget {
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.max,
|
mainAxisSize: MainAxisSize.max,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Stack(
|
||||||
|
clipBehavior: Clip.none,
|
||||||
children: [
|
children: [
|
||||||
ClipRRect(
|
ClipRRect(
|
||||||
borderRadius: BorderRadius.circular(50),
|
borderRadius: BorderRadius.circular(50),
|
||||||
child: ImageUtil.getImageFromPath(
|
child: ImageUtil.getImageFromPath(
|
||||||
imagePath: provider.image,
|
imagePath: provider.image, height: 36, width: 36),),
|
||||||
height: 36,
|
Positioned(
|
||||||
width: 36,
|
right: 0,
|
||||||
|
bottom: 2,
|
||||||
|
child: Container(
|
||||||
|
height: 8,
|
||||||
|
width: 8,
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 2),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: _statusColor(context, swapState),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
SizedBox(width: 12),
|
SizedBox(width: 12),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
|
@ -104,4 +122,21 @@ class TradeRow extends StatelessWidget {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Color _statusColor(BuildContext context, TradeState status) {
|
||||||
|
switch (status) {
|
||||||
|
case TradeState.complete:
|
||||||
|
case TradeState.completed:
|
||||||
|
case TradeState.finished:
|
||||||
|
case TradeState.success:
|
||||||
|
case TradeState.settled:
|
||||||
|
return PaletteDark.brightGreen;
|
||||||
|
case TradeState.failed:
|
||||||
|
case TradeState.expired:
|
||||||
|
case TradeState.notFound:
|
||||||
|
return Palette.darkRed;
|
||||||
|
default:
|
||||||
|
return const Color(0xffff6600);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,6 @@ import 'package:cake_wallet/store/dashboard/trades_store.dart';
|
||||||
import 'package:cake_wallet/store/dashboard/transaction_filter_store.dart';
|
import 'package:cake_wallet/store/dashboard/transaction_filter_store.dart';
|
||||||
import 'package:cake_wallet/store/settings_store.dart';
|
import 'package:cake_wallet/store/settings_store.dart';
|
||||||
import 'package:cake_wallet/store/yat/yat_store.dart';
|
import 'package:cake_wallet/store/yat/yat_store.dart';
|
||||||
import 'package:cake_wallet/themes/core/material_base_theme.dart';
|
|
||||||
import 'package:cake_wallet/view_model/dashboard/action_list_item.dart';
|
import 'package:cake_wallet/view_model/dashboard/action_list_item.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/anonpay_transaction_list_item.dart';
|
import 'package:cake_wallet/view_model/dashboard/anonpay_transaction_list_item.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
|
import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
|
||||||
|
@ -56,6 +55,8 @@ import 'package:mobx/mobx.dart';
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
import 'package:cake_wallet/core/trade_monitor.dart';
|
||||||
|
|
||||||
part 'dashboard_view_model.g.dart';
|
part 'dashboard_view_model.g.dart';
|
||||||
|
|
||||||
class DashboardViewModel = DashboardViewModelBase with _$DashboardViewModel;
|
class DashboardViewModel = DashboardViewModelBase with _$DashboardViewModel;
|
||||||
|
@ -63,6 +64,7 @@ class DashboardViewModel = DashboardViewModelBase with _$DashboardViewModel;
|
||||||
abstract class DashboardViewModelBase with Store {
|
abstract class DashboardViewModelBase with Store {
|
||||||
DashboardViewModelBase(
|
DashboardViewModelBase(
|
||||||
{required this.balanceViewModel,
|
{required this.balanceViewModel,
|
||||||
|
required this.tradeMonitor,
|
||||||
required this.appStore,
|
required this.appStore,
|
||||||
required this.tradesStore,
|
required this.tradesStore,
|
||||||
required this.tradeFilterStore,
|
required this.tradeFilterStore,
|
||||||
|
@ -298,6 +300,10 @@ abstract class DashboardViewModelBase with Store {
|
||||||
|
|
||||||
_checkMweb();
|
_checkMweb();
|
||||||
reaction((_) => settingsStore.mwebAlwaysScan, (bool value) => _checkMweb());
|
reaction((_) => settingsStore.mwebAlwaysScan, (bool value) => _checkMweb());
|
||||||
|
|
||||||
|
reaction((_) => tradesStore.trades, (_) => tradeMonitor.monitorActiveTrades(wallet.id));
|
||||||
|
|
||||||
|
tradeMonitor.monitorActiveTrades(wallet.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _isTransactionDisposerCallbackRunning = false;
|
bool _isTransactionDisposerCallbackRunning = false;
|
||||||
|
@ -773,6 +779,8 @@ abstract class DashboardViewModelBase with Store {
|
||||||
|
|
||||||
BalanceViewModel balanceViewModel;
|
BalanceViewModel balanceViewModel;
|
||||||
|
|
||||||
|
TradeMonitor tradeMonitor;
|
||||||
|
|
||||||
AppStore appStore;
|
AppStore appStore;
|
||||||
|
|
||||||
SettingsStore settingsStore;
|
SettingsStore settingsStore;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue