diff --git a/lib/main.dart b/lib/main.dart index 744a089a2..b6b7d560a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -62,6 +62,7 @@ import 'package:stackwallet/utilities/prefs.dart'; import 'package:stackwallet/utilities/stack_file_system.dart'; import 'package:stackwallet/utilities/theme/color_theme.dart'; import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/widgets/crypto_notifications.dart'; import 'package:window_size/window_size.dart'; final openedFromSWBFileStringStateProvider = @@ -202,7 +203,9 @@ class MyApp extends StatelessWidget { localeService.loadLocale(); return const KeyboardDismisser( - child: MaterialAppWithTheme(), + child: CryptoNotifications( + child: MaterialAppWithTheme(), + ), ); } } diff --git a/lib/services/coins/bitcoin/bitcoin_wallet.dart b/lib/services/coins/bitcoin/bitcoin_wallet.dart index ba49eefc0..5dee0e430 100644 --- a/lib/services/coins/bitcoin/bitcoin_wallet.dart +++ b/lib/services/coins/bitcoin/bitcoin_wallet.dart @@ -32,11 +32,9 @@ import 'package:stackwallet/services/mixins/wallet_cache.dart'; import 'package:stackwallet/services/mixins/wallet_db.dart'; import 'package:stackwallet/services/mixins/xpubable.dart'; import 'package:stackwallet/services/node_service.dart'; -import 'package:stackwallet/services/notifications_api.dart'; import 'package:stackwallet/services/transaction_notification_tracker.dart'; import 'package:stackwallet/utilities/address_utils.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; -import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/bip32_utils.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; @@ -48,6 +46,7 @@ import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/paynym_is_api.dart'; import 'package:stackwallet/utilities/prefs.dart'; +import 'package:stackwallet/widgets/crypto_notifications.dart'; import 'package:tuple/tuple.dart'; import 'package:uuid/uuid.dart'; @@ -832,32 +831,35 @@ class BitcoinWallet extends CoinServiceAPI final confirmations = tx.getConfirmations(currentChainHeight); if (tx.type == isar_models.TransactionType.incoming) { - unawaited(NotificationApi.showNotification( - title: "Incoming transaction", - body: walletName, - walletId: walletId, - iconAssetName: Assets.svg.iconFor(coin: coin), - date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), - shouldWatchForUpdates: confirmations < MINIMUM_CONFIRMATIONS, - coinName: coin.name, - txid: tx.txid, - confirmations: confirmations, - requiredConfirmations: MINIMUM_CONFIRMATIONS, - )); + CryptoNotificationsEventBus.instance.fire( + CryptoNotificationEvent( + title: "Incoming transaction", + walletId: walletId, + walletName: walletName, + date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), + shouldWatchForUpdates: confirmations < MINIMUM_CONFIRMATIONS, + coin: coin, + txid: tx.txid, + confirmations: confirmations, + requiredConfirmations: MINIMUM_CONFIRMATIONS, + ), + ); await txTracker.addNotifiedPending(tx.txid); } else if (tx.type == isar_models.TransactionType.outgoing) { - unawaited(NotificationApi.showNotification( - title: "Sending transaction", - body: walletName, - walletId: walletId, - iconAssetName: Assets.svg.iconFor(coin: coin), - date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), - shouldWatchForUpdates: confirmations < MINIMUM_CONFIRMATIONS, - coinName: coin.name, - txid: tx.txid, - confirmations: confirmations, - requiredConfirmations: MINIMUM_CONFIRMATIONS, - )); + CryptoNotificationsEventBus.instance.fire( + CryptoNotificationEvent( + title: "Sending transaction", + walletId: walletId, + date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), + shouldWatchForUpdates: confirmations < MINIMUM_CONFIRMATIONS, + txid: tx.txid, + confirmations: confirmations, + requiredConfirmations: MINIMUM_CONFIRMATIONS, + walletName: walletName, + coin: coin, + ), + ); + await txTracker.addNotifiedPending(tx.txid); } } @@ -865,26 +867,34 @@ class BitcoinWallet extends CoinServiceAPI // notify on confirmed for (final tx in unconfirmedTxnsToNotifyConfirmed) { if (tx.type == isar_models.TransactionType.incoming) { - unawaited(NotificationApi.showNotification( - title: "Incoming transaction confirmed", - body: walletName, - walletId: walletId, - iconAssetName: Assets.svg.iconFor(coin: coin), - date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), - shouldWatchForUpdates: false, - coinName: coin.name, - )); + CryptoNotificationsEventBus.instance.fire( + CryptoNotificationEvent( + title: "Incoming transaction confirmed", + walletId: walletId, + date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), + shouldWatchForUpdates: false, + txid: tx.txid, + requiredConfirmations: MINIMUM_CONFIRMATIONS, + walletName: walletName, + coin: coin, + ), + ); + await txTracker.addNotifiedConfirmed(tx.txid); } else if (tx.type == isar_models.TransactionType.outgoing) { - unawaited(NotificationApi.showNotification( - title: "Outgoing transaction confirmed", - body: walletName, - walletId: walletId, - iconAssetName: Assets.svg.iconFor(coin: coin), - date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), - shouldWatchForUpdates: false, - coinName: coin.name, - )); + CryptoNotificationsEventBus.instance.fire( + CryptoNotificationEvent( + title: "Outgoing transaction confirmed", + walletId: walletId, + date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), + shouldWatchForUpdates: false, + txid: tx.txid, + requiredConfirmations: MINIMUM_CONFIRMATIONS, + walletName: walletName, + coin: coin, + ), + ); + await txTracker.addNotifiedConfirmed(tx.txid); } } diff --git a/lib/services/coins/bitcoincash/bitcoincash_wallet.dart b/lib/services/coins/bitcoincash/bitcoincash_wallet.dart index e108352b4..b6dbca26d 100644 --- a/lib/services/coins/bitcoincash/bitcoincash_wallet.dart +++ b/lib/services/coins/bitcoincash/bitcoincash_wallet.dart @@ -31,11 +31,9 @@ import 'package:stackwallet/services/mixins/wallet_cache.dart'; import 'package:stackwallet/services/mixins/wallet_db.dart'; import 'package:stackwallet/services/mixins/xpubable.dart'; import 'package:stackwallet/services/node_service.dart'; -import 'package:stackwallet/services/notifications_api.dart'; import 'package:stackwallet/services/transaction_notification_tracker.dart'; import 'package:stackwallet/utilities/address_utils.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; -import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/bip32_utils.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; @@ -46,6 +44,7 @@ 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:stackwallet/widgets/crypto_notifications.dart'; import 'package:tuple/tuple.dart'; import 'package:uuid/uuid.dart'; @@ -756,36 +755,36 @@ class BitcoinCashWallet extends CoinServiceAPI final confirmations = tx.getConfirmations(currentChainHeight); if (tx.type == isar_models.TransactionType.incoming) { - unawaited( - NotificationApi.showNotification( + CryptoNotificationsEventBus.instance.fire( + CryptoNotificationEvent( title: "Incoming transaction", - body: walletName, walletId: walletId, - iconAssetName: Assets.svg.iconFor(coin: coin), date: DateTime.now(), shouldWatchForUpdates: confirmations < MINIMUM_CONFIRMATIONS, - coinName: coin.name, txid: tx.txid, confirmations: confirmations, requiredConfirmations: MINIMUM_CONFIRMATIONS, + walletName: walletName, + coin: coin, ), ); + await txTracker.addNotifiedPending(tx.txid); } else if (tx.type == isar_models.TransactionType.outgoing) { - unawaited( - NotificationApi.showNotification( + CryptoNotificationsEventBus.instance.fire( + CryptoNotificationEvent( title: "Sending transaction", - body: walletName, walletId: walletId, - iconAssetName: Assets.svg.iconFor(coin: coin), date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), shouldWatchForUpdates: confirmations < MINIMUM_CONFIRMATIONS, - coinName: coin.name, txid: tx.txid, confirmations: confirmations, requiredConfirmations: MINIMUM_CONFIRMATIONS, + walletName: walletName, + coin: coin, ), ); + await txTracker.addNotifiedPending(tx.txid); } } @@ -793,31 +792,34 @@ class BitcoinCashWallet extends CoinServiceAPI // notify on confirmed for (final tx in unconfirmedTxnsToNotifyConfirmed) { if (tx.type == isar_models.TransactionType.incoming) { - unawaited( - NotificationApi.showNotification( + CryptoNotificationsEventBus.instance.fire( + CryptoNotificationEvent( title: "Incoming transaction confirmed", - body: walletName, walletId: walletId, - iconAssetName: Assets.svg.iconFor(coin: coin), date: DateTime.now(), shouldWatchForUpdates: false, - coinName: coin.name, + txid: tx.txid, + requiredConfirmations: MINIMUM_CONFIRMATIONS, + walletName: walletName, + coin: coin, ), ); await txTracker.addNotifiedConfirmed(tx.txid); } else if (tx.type == isar_models.TransactionType.outgoing) { - unawaited( - NotificationApi.showNotification( + CryptoNotificationsEventBus.instance.fire( + CryptoNotificationEvent( title: "Outgoing transaction confirmed", - body: walletName, walletId: walletId, - iconAssetName: Assets.svg.iconFor(coin: coin), date: DateTime.now(), shouldWatchForUpdates: false, - coinName: coin.name, + txid: tx.txid, + requiredConfirmations: MINIMUM_CONFIRMATIONS, + walletName: walletName, + coin: coin, ), ); + await txTracker.addNotifiedConfirmed(tx.txid); } } diff --git a/lib/services/coins/dogecoin/dogecoin_wallet.dart b/lib/services/coins/dogecoin/dogecoin_wallet.dart index 8db10cc37..05170a883 100644 --- a/lib/services/coins/dogecoin/dogecoin_wallet.dart +++ b/lib/services/coins/dogecoin/dogecoin_wallet.dart @@ -30,11 +30,9 @@ import 'package:stackwallet/services/mixins/wallet_cache.dart'; import 'package:stackwallet/services/mixins/wallet_db.dart'; import 'package:stackwallet/services/mixins/xpubable.dart'; import 'package:stackwallet/services/node_service.dart'; -import 'package:stackwallet/services/notifications_api.dart'; import 'package:stackwallet/services/transaction_notification_tracker.dart'; import 'package:stackwallet/utilities/address_utils.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; -import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/bip32_utils.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; @@ -45,6 +43,7 @@ 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:stackwallet/widgets/crypto_notifications.dart'; import 'package:tuple/tuple.dart'; import 'package:uuid/uuid.dart'; @@ -721,32 +720,36 @@ class DogecoinWallet extends CoinServiceAPI final confirmations = tx.getConfirmations(currentChainHeight); if (tx.type == isar_models.TransactionType.incoming) { - unawaited(NotificationApi.showNotification( - title: "Incoming transaction", - body: walletName, - walletId: walletId, - iconAssetName: Assets.svg.iconFor(coin: coin), - date: DateTime.now(), - shouldWatchForUpdates: confirmations < MINIMUM_CONFIRMATIONS, - coinName: coin.name, - txid: tx.txid, - confirmations: confirmations, - requiredConfirmations: MINIMUM_CONFIRMATIONS, - )); + CryptoNotificationsEventBus.instance.fire( + CryptoNotificationEvent( + title: "Incoming transaction", + walletId: walletId, + date: DateTime.now(), + shouldWatchForUpdates: confirmations < MINIMUM_CONFIRMATIONS, + txid: tx.txid, + confirmations: confirmations, + requiredConfirmations: MINIMUM_CONFIRMATIONS, + walletName: walletName, + coin: coin, + ), + ); + await txTracker.addNotifiedPending(tx.txid); } else if (tx.type == isar_models.TransactionType.outgoing) { - unawaited(NotificationApi.showNotification( - title: "Sending transaction", - body: walletName, - walletId: walletId, - iconAssetName: Assets.svg.iconFor(coin: coin), - date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), - shouldWatchForUpdates: confirmations < MINIMUM_CONFIRMATIONS, - coinName: coin.name, - txid: tx.txid, - confirmations: confirmations, - requiredConfirmations: MINIMUM_CONFIRMATIONS, - )); + CryptoNotificationsEventBus.instance.fire( + CryptoNotificationEvent( + title: "Sending transaction", + walletId: walletId, + date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), + shouldWatchForUpdates: confirmations < MINIMUM_CONFIRMATIONS, + txid: tx.txid, + confirmations: confirmations, + requiredConfirmations: MINIMUM_CONFIRMATIONS, + walletName: walletName, + coin: coin, + ), + ); + await txTracker.addNotifiedPending(tx.txid); } } @@ -754,27 +757,34 @@ class DogecoinWallet extends CoinServiceAPI // notify on confirmed for (final tx in unconfirmedTxnsToNotifyConfirmed) { if (tx.type == isar_models.TransactionType.incoming) { - unawaited(NotificationApi.showNotification( - title: "Incoming transaction confirmed", - body: walletName, - walletId: walletId, - iconAssetName: Assets.svg.iconFor(coin: coin), - date: DateTime.now(), - shouldWatchForUpdates: false, - coinName: coin.name, - )); + CryptoNotificationsEventBus.instance.fire( + CryptoNotificationEvent( + title: "Incoming transaction confirmed", + walletId: walletId, + date: DateTime.now(), + shouldWatchForUpdates: false, + txid: tx.txid, + requiredConfirmations: MINIMUM_CONFIRMATIONS, + walletName: walletName, + coin: coin, + ), + ); await txTracker.addNotifiedConfirmed(tx.txid); } else if (tx.type == isar_models.TransactionType.outgoing) { - unawaited(NotificationApi.showNotification( - title: "Outgoing transaction confirmed", - body: walletName, - walletId: walletId, - iconAssetName: Assets.svg.iconFor(coin: coin), - date: DateTime.now(), - shouldWatchForUpdates: false, - coinName: coin.name, - )); + CryptoNotificationsEventBus.instance.fire( + CryptoNotificationEvent( + title: "Outgoing transaction confirmed", + walletId: walletId, + date: DateTime.now(), + shouldWatchForUpdates: false, + txid: tx.txid, + requiredConfirmations: MINIMUM_CONFIRMATIONS, + walletName: walletName, + coin: coin, + ), + ); + await txTracker.addNotifiedConfirmed(tx.txid); } } diff --git a/lib/services/coins/ethereum/ethereum_wallet.dart b/lib/services/coins/ethereum/ethereum_wallet.dart index 184b67cdb..0e933a1c0 100644 --- a/lib/services/coins/ethereum/ethereum_wallet.dart +++ b/lib/services/coins/ethereum/ethereum_wallet.dart @@ -21,10 +21,8 @@ import 'package:stackwallet/services/mixins/eth_token_cache.dart'; import 'package:stackwallet/services/mixins/wallet_cache.dart'; import 'package:stackwallet/services/mixins/wallet_db.dart'; import 'package:stackwallet/services/node_service.dart'; -import 'package:stackwallet/services/notifications_api.dart'; import 'package:stackwallet/services/transaction_notification_tracker.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; -import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; @@ -34,6 +32,7 @@ import 'package:stackwallet/utilities/extensions/extensions.dart'; import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'; import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/prefs.dart'; +import 'package:stackwallet/widgets/crypto_notifications.dart'; import 'package:tuple/tuple.dart'; import 'package:web3dart/web3dart.dart' as web3; @@ -713,32 +712,36 @@ class EthereumWallet extends CoinServiceAPI with WalletCache, WalletDB { final confirmations = tx.getConfirmations(currentChainHeight); if (tx.type == TransactionType.incoming) { - unawaited(NotificationApi.showNotification( - title: "Incoming transaction", - body: walletName, - walletId: walletId, - iconAssetName: Assets.svg.iconFor(coin: coin), - date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), - shouldWatchForUpdates: confirmations < MINIMUM_CONFIRMATIONS, - coinName: coin.name, - txid: tx.txid, - confirmations: confirmations, - requiredConfirmations: MINIMUM_CONFIRMATIONS, - )); + CryptoNotificationsEventBus.instance.fire( + CryptoNotificationEvent( + title: "Incoming transaction", + walletId: walletId, + date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), + shouldWatchForUpdates: confirmations < MINIMUM_CONFIRMATIONS, + txid: tx.txid, + confirmations: confirmations, + requiredConfirmations: MINIMUM_CONFIRMATIONS, + walletName: walletName, + coin: coin, + ), + ); + await txTracker.addNotifiedPending(tx.txid); } else if (tx.type == TransactionType.outgoing) { - unawaited(NotificationApi.showNotification( - title: "Sending transaction", - body: walletName, - walletId: walletId, - iconAssetName: Assets.svg.iconFor(coin: coin), - date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), - shouldWatchForUpdates: confirmations < MINIMUM_CONFIRMATIONS, - coinName: coin.name, - txid: tx.txid, - confirmations: confirmations, - requiredConfirmations: MINIMUM_CONFIRMATIONS, - )); + CryptoNotificationsEventBus.instance.fire( + CryptoNotificationEvent( + title: "Sending transaction", + walletId: walletId, + date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), + shouldWatchForUpdates: confirmations < MINIMUM_CONFIRMATIONS, + txid: tx.txid, + confirmations: confirmations, + requiredConfirmations: MINIMUM_CONFIRMATIONS, + walletName: walletName, + coin: coin, + ), + ); + await txTracker.addNotifiedPending(tx.txid); } } @@ -746,26 +749,34 @@ class EthereumWallet extends CoinServiceAPI with WalletCache, WalletDB { // notify on confirmed for (final tx in unconfirmedTxnsToNotifyConfirmed) { if (tx.type == TransactionType.incoming) { - unawaited(NotificationApi.showNotification( - title: "Incoming transaction confirmed", - body: walletName, - walletId: walletId, - iconAssetName: Assets.svg.iconFor(coin: coin), - date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), - shouldWatchForUpdates: false, - coinName: coin.name, - )); + CryptoNotificationsEventBus.instance.fire( + CryptoNotificationEvent( + title: "Incoming transaction confirmed", + walletId: walletId, + date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), + shouldWatchForUpdates: false, + txid: tx.txid, + requiredConfirmations: MINIMUM_CONFIRMATIONS, + walletName: walletName, + coin: coin, + ), + ); + await txTracker.addNotifiedConfirmed(tx.txid); } else if (tx.type == TransactionType.outgoing) { - unawaited(NotificationApi.showNotification( - title: "Outgoing transaction confirmed", - body: walletName, - walletId: walletId, - iconAssetName: Assets.svg.iconFor(coin: coin), - date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), - shouldWatchForUpdates: false, - coinName: coin.name, - )); + CryptoNotificationsEventBus.instance.fire( + CryptoNotificationEvent( + title: "Outgoing transaction confirmed", + walletId: walletId, + date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), + shouldWatchForUpdates: false, + txid: tx.txid, + requiredConfirmations: MINIMUM_CONFIRMATIONS, + walletName: walletName, + coin: coin, + ), + ); + await txTracker.addNotifiedConfirmed(tx.txid); } } diff --git a/lib/services/coins/firo/firo_wallet.dart b/lib/services/coins/firo/firo_wallet.dart index 14ade1d40..57e916e2e 100644 --- a/lib/services/coins/firo/firo_wallet.dart +++ b/lib/services/coins/firo/firo_wallet.dart @@ -30,11 +30,9 @@ import 'package:stackwallet/services/mixins/wallet_cache.dart'; import 'package:stackwallet/services/mixins/wallet_db.dart'; import 'package:stackwallet/services/mixins/xpubable.dart'; import 'package:stackwallet/services/node_service.dart'; -import 'package:stackwallet/services/notifications_api.dart'; import 'package:stackwallet/services/transaction_notification_tracker.dart'; import 'package:stackwallet/utilities/address_utils.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; -import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/bip32_utils.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; @@ -45,6 +43,7 @@ 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:stackwallet/widgets/crypto_notifications.dart'; import 'package:tuple/tuple.dart'; import 'package:uuid/uuid.dart'; @@ -2078,39 +2077,39 @@ class FiroWallet extends CoinServiceAPI switch (tx.type) { case isar_models.TransactionType.incoming: - unawaited( - NotificationApi.showNotification( + CryptoNotificationsEventBus.instance.fire( + CryptoNotificationEvent( title: "Incoming transaction", - body: walletName, walletId: walletId, - iconAssetName: Assets.svg.iconFor(coin: coin), date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), shouldWatchForUpdates: confirmations < MINIMUM_CONFIRMATIONS, - coinName: coin.name, txid: tx.txid, confirmations: confirmations, requiredConfirmations: MINIMUM_CONFIRMATIONS, + walletName: walletName, + coin: coin, ), ); + await txTracker.addNotifiedPending(tx.txid); break; case isar_models.TransactionType.outgoing: - unawaited( - NotificationApi.showNotification( + CryptoNotificationsEventBus.instance.fire( + CryptoNotificationEvent( title: tx.subType == isar_models.TransactionSubType.mint ? "Anonymizing" : "Outgoing transaction", - body: walletName, walletId: walletId, - iconAssetName: Assets.svg.iconFor(coin: coin), date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), shouldWatchForUpdates: confirmations < MINIMUM_CONFIRMATIONS, - coinName: coin.name, txid: tx.txid, confirmations: confirmations, requiredConfirmations: MINIMUM_CONFIRMATIONS, + walletName: walletName, + coin: coin, ), ); + await txTracker.addNotifiedPending(tx.txid); break; default: @@ -2120,32 +2119,35 @@ class FiroWallet extends CoinServiceAPI for (final tx in unconfirmedTxnsToNotifyConfirmed) { if (tx.type == isar_models.TransactionType.incoming) { - unawaited( - NotificationApi.showNotification( + CryptoNotificationsEventBus.instance.fire( + CryptoNotificationEvent( title: "Incoming transaction confirmed", - body: walletName, walletId: walletId, - iconAssetName: Assets.svg.iconFor(coin: coin), date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), shouldWatchForUpdates: false, - coinName: coin.name, + txid: tx.txid, + requiredConfirmations: MINIMUM_CONFIRMATIONS, + walletName: walletName, + coin: coin, ), ); + await txTracker.addNotifiedConfirmed(tx.txid); } else if (tx.type == isar_models.TransactionType.outgoing && tx.subType == isar_models.TransactionSubType.join) { - unawaited( - NotificationApi.showNotification( + CryptoNotificationsEventBus.instance.fire( + CryptoNotificationEvent( title: tx.subType == isar_models.TransactionSubType.mint // redundant check? ? "Anonymized" : "Outgoing transaction confirmed", - body: walletName, walletId: walletId, - iconAssetName: Assets.svg.iconFor(coin: coin), date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), shouldWatchForUpdates: false, - coinName: coin.name, + txid: tx.txid, + requiredConfirmations: MINIMUM_CONFIRMATIONS, + walletName: walletName, + coin: coin, ), ); await txTracker.addNotifiedConfirmed(tx.txid); diff --git a/lib/services/coins/litecoin/litecoin_wallet.dart b/lib/services/coins/litecoin/litecoin_wallet.dart index f3598efe6..5e1e8064c 100644 --- a/lib/services/coins/litecoin/litecoin_wallet.dart +++ b/lib/services/coins/litecoin/litecoin_wallet.dart @@ -30,10 +30,8 @@ import 'package:stackwallet/services/mixins/wallet_cache.dart'; import 'package:stackwallet/services/mixins/wallet_db.dart'; import 'package:stackwallet/services/mixins/xpubable.dart'; import 'package:stackwallet/services/node_service.dart'; -import 'package:stackwallet/services/notifications_api.dart'; import 'package:stackwallet/services/transaction_notification_tracker.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; -import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/bip32_utils.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; @@ -44,6 +42,7 @@ 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:stackwallet/widgets/crypto_notifications.dart'; import 'package:tuple/tuple.dart'; import 'package:uuid/uuid.dart'; @@ -837,32 +836,35 @@ class LitecoinWallet extends CoinServiceAPI final confirmations = tx.getConfirmations(currentChainHeight); if (tx.type == isar_models.TransactionType.incoming) { - unawaited(NotificationApi.showNotification( - title: "Incoming transaction", - body: walletName, - walletId: walletId, - iconAssetName: Assets.svg.iconFor(coin: coin), - date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), - shouldWatchForUpdates: confirmations < MINIMUM_CONFIRMATIONS, - coinName: coin.name, - txid: tx.txid, - confirmations: confirmations, - requiredConfirmations: MINIMUM_CONFIRMATIONS, - )); + CryptoNotificationsEventBus.instance.fire( + CryptoNotificationEvent( + title: "Incoming transaction", + walletId: walletId, + date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), + shouldWatchForUpdates: confirmations < MINIMUM_CONFIRMATIONS, + txid: tx.txid, + confirmations: confirmations, + requiredConfirmations: MINIMUM_CONFIRMATIONS, + walletName: walletName, + coin: coin, + ), + ); await txTracker.addNotifiedPending(tx.txid); } else if (tx.type == isar_models.TransactionType.outgoing) { - unawaited(NotificationApi.showNotification( - title: "Sending transaction", - body: walletName, - walletId: walletId, - iconAssetName: Assets.svg.iconFor(coin: coin), - date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), - shouldWatchForUpdates: confirmations < MINIMUM_CONFIRMATIONS, - coinName: coin.name, - txid: tx.txid, - confirmations: confirmations, - requiredConfirmations: MINIMUM_CONFIRMATIONS, - )); + CryptoNotificationsEventBus.instance.fire( + CryptoNotificationEvent( + title: "Sending transaction", + walletId: walletId, + date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), + shouldWatchForUpdates: confirmations < MINIMUM_CONFIRMATIONS, + txid: tx.txid, + confirmations: confirmations, + requiredConfirmations: MINIMUM_CONFIRMATIONS, + walletName: walletName, + coin: coin, + ), + ); + await txTracker.addNotifiedPending(tx.txid); } } @@ -870,26 +872,33 @@ class LitecoinWallet extends CoinServiceAPI // notify on confirmed for (final tx in unconfirmedTxnsToNotifyConfirmed) { if (tx.type == isar_models.TransactionType.incoming) { - unawaited(NotificationApi.showNotification( - title: "Incoming transaction confirmed", - body: walletName, - walletId: walletId, - iconAssetName: Assets.svg.iconFor(coin: coin), - date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), - shouldWatchForUpdates: false, - coinName: coin.name, - )); + CryptoNotificationsEventBus.instance.fire( + CryptoNotificationEvent( + title: "Incoming transaction confirmed", + walletId: walletId, + date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), + shouldWatchForUpdates: false, + txid: tx.txid, + requiredConfirmations: MINIMUM_CONFIRMATIONS, + walletName: walletName, + coin: coin, + ), + ); + await txTracker.addNotifiedConfirmed(tx.txid); } else if (tx.type == isar_models.TransactionType.outgoing) { - unawaited(NotificationApi.showNotification( - title: "Outgoing transaction confirmed", - body: walletName, - walletId: walletId, - iconAssetName: Assets.svg.iconFor(coin: coin), - date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), - shouldWatchForUpdates: false, - coinName: coin.name, - )); + CryptoNotificationsEventBus.instance.fire( + CryptoNotificationEvent( + title: "Outgoing transaction confirmed", + walletId: walletId, + date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), + shouldWatchForUpdates: false, + txid: tx.txid, + requiredConfirmations: MINIMUM_CONFIRMATIONS, + walletName: walletName, + coin: coin, + ), + ); await txTracker.addNotifiedConfirmed(tx.txid); } } diff --git a/lib/services/coins/namecoin/namecoin_wallet.dart b/lib/services/coins/namecoin/namecoin_wallet.dart index b0706abb4..19c5a823b 100644 --- a/lib/services/coins/namecoin/namecoin_wallet.dart +++ b/lib/services/coins/namecoin/namecoin_wallet.dart @@ -30,10 +30,8 @@ import 'package:stackwallet/services/mixins/wallet_cache.dart'; import 'package:stackwallet/services/mixins/wallet_db.dart'; import 'package:stackwallet/services/mixins/xpubable.dart'; import 'package:stackwallet/services/node_service.dart'; -import 'package:stackwallet/services/notifications_api.dart'; import 'package:stackwallet/services/transaction_notification_tracker.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; -import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/bip32_utils.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; @@ -44,6 +42,7 @@ 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:stackwallet/widgets/crypto_notifications.dart'; import 'package:tuple/tuple.dart'; import 'package:uuid/uuid.dart'; @@ -825,32 +824,36 @@ class NamecoinWallet extends CoinServiceAPI final confirmations = tx.getConfirmations(currentChainHeight); if (tx.type == isar_models.TransactionType.incoming) { - unawaited(NotificationApi.showNotification( - title: "Incoming transaction", - body: walletName, - walletId: walletId, - iconAssetName: Assets.svg.iconFor(coin: coin), - date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), - shouldWatchForUpdates: confirmations < MINIMUM_CONFIRMATIONS, - coinName: coin.name, - txid: tx.txid, - confirmations: confirmations, - requiredConfirmations: MINIMUM_CONFIRMATIONS, - )); + CryptoNotificationsEventBus.instance.fire( + CryptoNotificationEvent( + title: "Incoming transaction", + walletId: walletId, + date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), + shouldWatchForUpdates: confirmations < MINIMUM_CONFIRMATIONS, + txid: tx.txid, + confirmations: confirmations, + requiredConfirmations: MINIMUM_CONFIRMATIONS, + walletName: walletName, + coin: coin, + ), + ); + await txTracker.addNotifiedPending(tx.txid); } else if (tx.type == isar_models.TransactionType.outgoing) { - unawaited(NotificationApi.showNotification( - title: "Sending transaction", - body: walletName, - walletId: walletId, - iconAssetName: Assets.svg.iconFor(coin: coin), - date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), - shouldWatchForUpdates: confirmations < MINIMUM_CONFIRMATIONS, - coinName: coin.name, - txid: tx.txid, - confirmations: confirmations, - requiredConfirmations: MINIMUM_CONFIRMATIONS, - )); + CryptoNotificationsEventBus.instance.fire( + CryptoNotificationEvent( + title: "Sending transaction", + walletId: walletId, + date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), + shouldWatchForUpdates: confirmations < MINIMUM_CONFIRMATIONS, + txid: tx.txid, + confirmations: confirmations, + requiredConfirmations: MINIMUM_CONFIRMATIONS, + walletName: walletName, + coin: coin, + ), + ); + await txTracker.addNotifiedPending(tx.txid); } } @@ -858,26 +861,34 @@ class NamecoinWallet extends CoinServiceAPI // notify on confirmed for (final tx in unconfirmedTxnsToNotifyConfirmed) { if (tx.type == isar_models.TransactionType.incoming) { - unawaited(NotificationApi.showNotification( - title: "Incoming transaction confirmed", - body: walletName, - walletId: walletId, - iconAssetName: Assets.svg.iconFor(coin: coin), - date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), - shouldWatchForUpdates: false, - coinName: coin.name, - )); + CryptoNotificationsEventBus.instance.fire( + CryptoNotificationEvent( + title: "Incoming transaction confirmed", + walletId: walletId, + date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), + shouldWatchForUpdates: false, + txid: tx.txid, + requiredConfirmations: MINIMUM_CONFIRMATIONS, + walletName: walletName, + coin: coin, + ), + ); + await txTracker.addNotifiedConfirmed(tx.txid); } else if (tx.type == isar_models.TransactionType.outgoing) { - unawaited(NotificationApi.showNotification( - title: "Outgoing transaction confirmed", - body: walletName, - walletId: walletId, - iconAssetName: Assets.svg.iconFor(coin: coin), - date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), - shouldWatchForUpdates: false, - coinName: coin.name, - )); + CryptoNotificationsEventBus.instance.fire( + CryptoNotificationEvent( + title: "Outgoing transaction confirmed", + walletId: walletId, + date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), + shouldWatchForUpdates: false, + txid: tx.txid, + requiredConfirmations: MINIMUM_CONFIRMATIONS, + walletName: walletName, + coin: coin, + ), + ); + await txTracker.addNotifiedConfirmed(tx.txid); } } diff --git a/lib/services/coins/particl/particl_wallet.dart b/lib/services/coins/particl/particl_wallet.dart index 15c7b0b65..f16d8a5f2 100644 --- a/lib/services/coins/particl/particl_wallet.dart +++ b/lib/services/coins/particl/particl_wallet.dart @@ -29,10 +29,8 @@ import 'package:stackwallet/services/mixins/wallet_cache.dart'; import 'package:stackwallet/services/mixins/wallet_db.dart'; import 'package:stackwallet/services/mixins/xpubable.dart'; import 'package:stackwallet/services/node_service.dart'; -import 'package:stackwallet/services/notifications_api.dart'; import 'package:stackwallet/services/transaction_notification_tracker.dart'; import 'package:stackwallet/utilities/amount/amount.dart'; -import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/bip32_utils.dart'; import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/default_nodes.dart'; @@ -43,6 +41,7 @@ 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:stackwallet/widgets/crypto_notifications.dart'; import 'package:tuple/tuple.dart'; import 'package:uuid/uuid.dart'; @@ -755,32 +754,36 @@ class ParticlWallet extends CoinServiceAPI final confirmations = tx.getConfirmations(currentChainHeight); if (tx.type == isar_models.TransactionType.incoming) { - unawaited(NotificationApi.showNotification( - title: "Incoming transaction", - body: walletName, - walletId: walletId, - iconAssetName: Assets.svg.iconFor(coin: coin), - date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), - shouldWatchForUpdates: confirmations < MINIMUM_CONFIRMATIONS, - coinName: coin.name, - txid: tx.txid, - confirmations: confirmations, - requiredConfirmations: MINIMUM_CONFIRMATIONS, - )); + CryptoNotificationsEventBus.instance.fire( + CryptoNotificationEvent( + title: "Incoming transaction", + walletId: walletId, + date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), + shouldWatchForUpdates: confirmations < MINIMUM_CONFIRMATIONS, + txid: tx.txid, + confirmations: confirmations, + requiredConfirmations: MINIMUM_CONFIRMATIONS, + walletName: walletName, + coin: coin, + ), + ); + await txTracker.addNotifiedPending(tx.txid); } else if (tx.type == isar_models.TransactionType.outgoing) { - unawaited(NotificationApi.showNotification( - title: "Sending transaction", - body: walletName, - walletId: walletId, - iconAssetName: Assets.svg.iconFor(coin: coin), - date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), - shouldWatchForUpdates: confirmations < MINIMUM_CONFIRMATIONS, - coinName: coin.name, - txid: tx.txid, - confirmations: confirmations, - requiredConfirmations: MINIMUM_CONFIRMATIONS, - )); + CryptoNotificationsEventBus.instance.fire( + CryptoNotificationEvent( + title: "Sending transaction", + walletId: walletId, + date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), + shouldWatchForUpdates: confirmations < MINIMUM_CONFIRMATIONS, + txid: tx.txid, + confirmations: confirmations, + requiredConfirmations: MINIMUM_CONFIRMATIONS, + walletName: walletName, + coin: coin, + ), + ); + await txTracker.addNotifiedPending(tx.txid); } } @@ -788,26 +791,34 @@ class ParticlWallet extends CoinServiceAPI // notify on confirmed for (final tx in unconfirmedTxnsToNotifyConfirmed) { if (tx.type == isar_models.TransactionType.incoming) { - unawaited(NotificationApi.showNotification( - title: "Incoming transaction confirmed", - body: walletName, - walletId: walletId, - iconAssetName: Assets.svg.iconFor(coin: coin), - date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), - shouldWatchForUpdates: false, - coinName: coin.name, - )); + CryptoNotificationsEventBus.instance.fire( + CryptoNotificationEvent( + title: "Incoming transaction confirmed", + walletId: walletId, + date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), + shouldWatchForUpdates: false, + txid: tx.txid, + requiredConfirmations: MINIMUM_CONFIRMATIONS, + walletName: walletName, + coin: coin, + ), + ); + await txTracker.addNotifiedConfirmed(tx.txid); } else if (tx.type == isar_models.TransactionType.outgoing) { - unawaited(NotificationApi.showNotification( - title: "Outgoing transaction confirmed", - body: walletName, - walletId: walletId, - iconAssetName: Assets.svg.iconFor(coin: coin), - date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), - shouldWatchForUpdates: false, - coinName: coin.name, - )); + CryptoNotificationsEventBus.instance.fire( + CryptoNotificationEvent( + title: "Outgoing transaction confirmed", + walletId: walletId, + date: DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000), + shouldWatchForUpdates: false, + txid: tx.txid, + requiredConfirmations: MINIMUM_CONFIRMATIONS, + walletName: walletName, + coin: coin, + ), + ); + await txTracker.addNotifiedConfirmed(tx.txid); } } diff --git a/lib/widgets/crypto_notifications.dart b/lib/widgets/crypto_notifications.dart new file mode 100644 index 000000000..a514f63c0 --- /dev/null +++ b/lib/widgets/crypto_notifications.dart @@ -0,0 +1,98 @@ +import 'dart:async'; + +import 'package:event_bus/event_bus.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:stackwallet/services/notifications_api.dart'; +import 'package:stackwallet/themes/coin_icon_provider.dart'; +import 'package:stackwallet/utilities/enums/coin_enum.dart'; + +abstract class CryptoNotificationsEventBus { + static final instance = EventBus(); +} + +class CryptoNotificationEvent { + final String title; + final String walletId; + final String walletName; + final DateTime date; + final bool shouldWatchForUpdates; + final Coin coin; + final String? txid; + final int? confirmations; + final int? requiredConfirmations; + final String? changeNowId; + final String? payload; + + CryptoNotificationEvent({ + required this.title, + required this.walletId, + required this.walletName, + required this.date, + required this.shouldWatchForUpdates, + required this.coin, + this.txid, + this.confirmations, + this.requiredConfirmations, + this.changeNowId, + this.payload, + }); +} + +class CryptoNotifications extends ConsumerStatefulWidget { + const CryptoNotifications({ + Key? key, + required this.child, + }) : super(key: key); + + final Widget child; + + @override + ConsumerState<CryptoNotifications> createState() => + _CryptoNotificationsState(); +} + +class _CryptoNotificationsState extends ConsumerState<CryptoNotifications> { + late final StreamSubscription<dynamic>? _streamSubscription; + + Future<void> _showNotification(CryptoNotificationEvent event) async { + await NotificationApi.showNotification( + title: event.title, + body: event.walletName, + walletId: event.walletId, + iconAssetName: ref.read(coinIconProvider(event.coin)), + date: event.date, + shouldWatchForUpdates: event.shouldWatchForUpdates, + coinName: event.coin.name, + txid: event.txid, + confirmations: event.confirmations, + requiredConfirmations: event.requiredConfirmations, + changeNowId: event.changeNowId, + payload: event.payload, + ); + } + + @override + void initState() { + _streamSubscription = CryptoNotificationsEventBus.instance + .on<CryptoNotificationEvent>() + .listen( + (event) async { + unawaited(_showNotification(event)); + }, + ); + + super.initState(); + } + + @override + void dispose() { + _streamSubscription?.cancel(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return const Placeholder(); + } +}