From b2f48a1b0522492842a3e76fd7da389e1f370675 Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Sun, 9 Aug 2020 14:13:10 +0200 Subject: [PATCH] improve new tx notifications --- drongo | 2 +- .../sparrowwallet/sparrow/AppController.java | 56 +++++++++++-------- .../com/sparrowwallet/sparrow/MainApp.java | 12 ++++ .../ConfirmationProgressIndicator.java | 6 +- .../event/NewWalletTransactionsEvent.java | 36 ++++++++++-- .../transaction/HeadersController.java | 2 +- .../sparrow/wallet/TransactionEntry.java | 18 ++---- .../wallet/WalletTransactionsEntry.java | 5 +- 8 files changed, 91 insertions(+), 46 deletions(-) diff --git a/drongo b/drongo index d2582c04..fff658a3 160000 --- a/drongo +++ b/drongo @@ -1 +1 @@ -Subproject commit d2582c041479704d609c20ed13195c3f92ced999 +Subproject commit fff658a3ab33a3f63f5a1cd03c2b7cc1f20bec4a diff --git a/src/main/java/com/sparrowwallet/sparrow/AppController.java b/src/main/java/com/sparrowwallet/sparrow/AppController.java index c38c5748..66e86172 100644 --- a/src/main/java/com/sparrowwallet/sparrow/AppController.java +++ b/src/main/java/com/sparrowwallet/sparrow/AppController.java @@ -44,6 +44,7 @@ import javafx.scene.input.TransferMode; import javafx.scene.layout.StackPane; import javafx.stage.FileChooser; import javafx.stage.Stage; +import javafx.stage.Window; import javafx.util.Duration; import org.controlsfx.control.Notifications; import org.controlsfx.control.StatusBar; @@ -161,9 +162,6 @@ public class AppController implements Initializable { rootStack.getStyleClass().removeAll(DRAG_OVER_CLASS); }); - Stage tabStage = (Stage)tabs.getScene().getWindow(); - tabStage.getScene().getStylesheets().add(AppController.class.getResource("notificationpopup.css").toExternalForm()); - tabs.getSelectionModel().selectedItemProperty().addListener((observable, old_val, selectedTab) -> { if(selectedTab != null) { TabData tabData = (TabData)selectedTab.getUserData(); @@ -241,15 +239,6 @@ public class AppController implements Initializable { } openTransactionIdItem.disableProperty().bind(onlineProperty.not()); - - List recentWalletFiles = Config.get().getRecentWalletFiles(); - if(recentWalletFiles != null) { - for(File walletFile : recentWalletFiles) { - if(walletFile.exists()) { - openWalletFile(walletFile); - } - } - } } private ElectrumServer.ConnectionService createConnectionService() { @@ -618,7 +607,7 @@ public class AppController implements Initializable { } } - private void openWalletFile(File file) { + public void openWalletFile(File file) { try { Storage storage = new Storage(file); FileType fileType = IOUtils.getFileType(file); @@ -959,25 +948,46 @@ public class AppController implements Initializable { @Subscribe public void newWalletTransactions(NewWalletTransactionsEvent event) { if(Config.get().isNotifyNewTransactions()) { - String text = "New " + (event.getBlockTransactions().size() > 1 ? "transactions: " : "transaction: "); + String text; + if(event.getBlockTransactions().size() == 1) { + BlockTransaction blockTransaction = event.getBlockTransactions().get(0); + if(blockTransaction.getHeight() == 0) { + text = "New mempool transaction: "; + } else { + int confirmations = blockTransaction.getConfirmations(getCurrentBlockHeight()); + if(confirmations == 1) { + text = "First transaction confirmation: "; + } else if(confirmations <= BlockTransactionHash.BLOCKS_TO_CONFIRM) { + text = "Confirming transaction: "; + } else { + text = "Confirmed transaction: "; + } + } - BitcoinUnit unit = Config.get().getBitcoinUnit(); - if(unit == null || unit.equals(BitcoinUnit.AUTO)) { - unit = (event.getTotalValue() >= BitcoinUnit.getAutoThreshold() ? BitcoinUnit.BTC : BitcoinUnit.SATOSHIS); - } - - if(unit == BitcoinUnit.BTC) { - text += CoinLabel.getBTCFormat().format((double)event.getTotalValue() / Transaction.SATOSHIS_PER_BITCOIN) + " BTC"; + text += event.getValueAsText(event.getTotalValue()); } else { - text += String.format(Locale.ENGLISH, "%,d", event.getTotalValue()) + " sats"; + if(event.getTotalBlockchainValue() > 0 && event.getTotalMempoolValue() > 0) { + text = "New transactions: " + event.getValueAsText(event.getTotalValue()) + " (" + event.getValueAsText(event.getTotalMempoolValue()) + " in mempool)"; + } else if(event.getTotalMempoolValue() > 0) { + text = "New mempool transactions: " + event.getValueAsText(event.getTotalMempoolValue()); + } else { + text = "New transactions: " + event.getValueAsText(event.getTotalValue()); + } } + Window.getWindows().forEach(window -> { + String notificationStyles = AppController.class.getResource("notificationpopup.css").toExternalForm(); + if(!window.getScene().getStylesheets().contains(notificationStyles)) { + window.getScene().getStylesheets().add(notificationStyles); + } + }); + Image image = new Image("image/sparrow-small.png", 50, 50, false, false); Notifications notificationBuilder = Notifications.create() .title("Sparrow - " + event.getWallet().getName()) .text(text) .graphic(new ImageView(image)) - .hideAfter(Duration.seconds(180)) + .hideAfter(Duration.seconds(5)) .position(Pos.TOP_RIGHT) .threshold(5, Notifications.create().title("Sparrow").text("Multiple new wallet transactions").graphic(new ImageView(image))) .onAction(e -> selectTab(event.getWallet())); diff --git a/src/main/java/com/sparrowwallet/sparrow/MainApp.java b/src/main/java/com/sparrowwallet/sparrow/MainApp.java index 8bc22deb..269bfb2c 100644 --- a/src/main/java/com/sparrowwallet/sparrow/MainApp.java +++ b/src/main/java/com/sparrowwallet/sparrow/MainApp.java @@ -7,6 +7,7 @@ import com.sparrowwallet.sparrow.io.Config; import com.sparrowwallet.sparrow.preferences.PreferenceGroup; import com.sparrowwallet.sparrow.preferences.PreferencesDialog; import javafx.application.Application; +import javafx.application.Platform; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; @@ -14,6 +15,8 @@ import javafx.scene.image.Image; import javafx.stage.Stage; import org.controlsfx.glyphfont.GlyphFontRegistry; +import java.io.File; +import java.util.List; import java.util.Optional; public class MainApp extends Application { @@ -60,6 +63,15 @@ public class MainApp extends Application { appController.initializeView(); stage.show(); + + List recentWalletFiles = Config.get().getRecentWalletFiles(); + if(recentWalletFiles != null) { + for(File walletFile : recentWalletFiles) { + if(walletFile.exists()) { + Platform.runLater(() -> appController.openWalletFile(walletFile)); + } + } + } } @Override diff --git a/src/main/java/com/sparrowwallet/sparrow/control/ConfirmationProgressIndicator.java b/src/main/java/com/sparrowwallet/sparrow/control/ConfirmationProgressIndicator.java index 416d890b..f405772a 100644 --- a/src/main/java/com/sparrowwallet/sparrow/control/ConfirmationProgressIndicator.java +++ b/src/main/java/com/sparrowwallet/sparrow/control/ConfirmationProgressIndicator.java @@ -1,6 +1,6 @@ package com.sparrowwallet.sparrow.control; -import com.sparrowwallet.sparrow.wallet.TransactionEntry; +import com.sparrowwallet.drongo.wallet.BlockTransactionHash; import javafx.animation.*; import javafx.beans.property.*; import javafx.geometry.Pos; @@ -54,7 +54,7 @@ public class ConfirmationProgressIndicator extends StackPane { arcLengthTimeline.getKeyFrames().add(arcLengthFrame); sequence.getChildren().add(arcLengthTimeline); - if(newValue.intValue() == TransactionEntry.BLOCKS_TO_CONFIRM) { + if(newValue.intValue() == BlockTransactionHash.BLOCKS_TO_CONFIRM) { Timeline arcRadiusTimeline = new Timeline(); KeyValue arcRadiusXValue = new KeyValue(arc.radiusXProperty(), 0.0); KeyValue arcRadiusYValue = new KeyValue(arc.radiusYProperty(), 0.0); @@ -98,7 +98,7 @@ public class ConfirmationProgressIndicator extends StackPane { } private static double getDegrees(int confirmations) { - int requiredConfirmations = TransactionEntry.BLOCKS_TO_CONFIRM; + int requiredConfirmations = BlockTransactionHash.BLOCKS_TO_CONFIRM; return ((double)Math.min(confirmations, requiredConfirmations)/ requiredConfirmations) * -360d; } diff --git a/src/main/java/com/sparrowwallet/sparrow/event/NewWalletTransactionsEvent.java b/src/main/java/com/sparrowwallet/sparrow/event/NewWalletTransactionsEvent.java index 61b581d4..3576e2c5 100644 --- a/src/main/java/com/sparrowwallet/sparrow/event/NewWalletTransactionsEvent.java +++ b/src/main/java/com/sparrowwallet/sparrow/event/NewWalletTransactionsEvent.java @@ -1,19 +1,26 @@ package com.sparrowwallet.sparrow.event; +import com.sparrowwallet.drongo.BitcoinUnit; +import com.sparrowwallet.drongo.protocol.Transaction; import com.sparrowwallet.drongo.wallet.BlockTransaction; import com.sparrowwallet.drongo.wallet.Wallet; +import com.sparrowwallet.sparrow.control.CoinLabel; +import com.sparrowwallet.sparrow.io.Config; import java.util.List; +import java.util.Locale; public class NewWalletTransactionsEvent { private final Wallet wallet; private final List blockTransactions; - private final long totalValue; + private final long totalBlockchainValue; + private final long totalMempoolValue; - public NewWalletTransactionsEvent(Wallet wallet, List blockTransactions, long totalValue) { + public NewWalletTransactionsEvent(Wallet wallet, List blockTransactions, long totalBlockchainValue, long totalMempoolValue) { this.wallet = wallet; this.blockTransactions = blockTransactions; - this.totalValue = totalValue; + this.totalBlockchainValue = totalBlockchainValue; + this.totalMempoolValue = totalMempoolValue; } public Wallet getWallet() { @@ -25,6 +32,27 @@ public class NewWalletTransactionsEvent { } public long getTotalValue() { - return totalValue; + return totalBlockchainValue + totalMempoolValue; + } + + public long getTotalBlockchainValue() { + return totalBlockchainValue; + } + + public long getTotalMempoolValue() { + return totalMempoolValue; + } + + public String getValueAsText(long value) { + BitcoinUnit unit = Config.get().getBitcoinUnit(); + if(unit == null || unit.equals(BitcoinUnit.AUTO)) { + unit = (value >= BitcoinUnit.getAutoThreshold() ? BitcoinUnit.BTC : BitcoinUnit.SATOSHIS); + } + + if(unit == BitcoinUnit.BTC) { + return CoinLabel.getBTCFormat().format((double) value / Transaction.SATOSHIS_PER_BITCOIN) + " BTC"; + } + + return String.format(Locale.ENGLISH, "%,d", value) + " sats"; } } diff --git a/src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.java b/src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.java index f607e9a8..6e425462 100644 --- a/src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.java +++ b/src/main/java/com/sparrowwallet/sparrow/transaction/HeadersController.java @@ -449,7 +449,7 @@ public class HeadersController extends TransactionFormController implements Init blockStatus.setText(confirmations + " Confirmations"); } - if(confirmations <= TransactionEntry.BLOCKS_TO_CONFIRM) { + if(confirmations <= BlockTransactionHash.BLOCKS_TO_CONFIRM) { ConfirmationProgressIndicator indicator; if(blockStatus.getGraphic() == null) { indicator = new ConfirmationProgressIndicator(confirmations); diff --git a/src/main/java/com/sparrowwallet/sparrow/wallet/TransactionEntry.java b/src/main/java/com/sparrowwallet/sparrow/wallet/TransactionEntry.java index bee562f2..1a01a14b 100644 --- a/src/main/java/com/sparrowwallet/sparrow/wallet/TransactionEntry.java +++ b/src/main/java/com/sparrowwallet/sparrow/wallet/TransactionEntry.java @@ -3,6 +3,7 @@ package com.sparrowwallet.sparrow.wallet; import com.google.common.eventbus.Subscribe; import com.sparrowwallet.drongo.KeyPurpose; import com.sparrowwallet.drongo.wallet.BlockTransaction; +import com.sparrowwallet.drongo.wallet.BlockTransactionHash; import com.sparrowwallet.drongo.wallet.BlockTransactionHashIndex; import com.sparrowwallet.drongo.wallet.Wallet; import com.sparrowwallet.sparrow.EventManager; @@ -17,9 +18,6 @@ import java.util.*; import java.util.stream.Collectors; public class TransactionEntry extends Entry implements Comparable { - public static final int BLOCKS_TO_CONFIRM = 6; - public static final int BLOCKS_TO_FULLY_CONFIRM = 100; - private final Wallet wallet; private final BlockTransaction blockTransaction; @@ -63,29 +61,25 @@ public class TransactionEntry extends Entry implements Comparable blockTransactions = entriesAdded.stream().map(txEntry -> ((TransactionEntry)txEntry).getBlockTransaction()).collect(Collectors.toList()); - long totalValue = entriesAdded.stream().mapToLong(Entry::getValue).sum(); - EventManager.get().post(new NewWalletTransactionsEvent(wallet, blockTransactions, totalValue)); + long totalBlockchainValue = entriesAdded.stream().filter(txEntry -> ((TransactionEntry)txEntry).getConfirmations() > 0).mapToLong(Entry::getValue).sum(); + long totalMempoolValue = entriesAdded.stream().filter(txEntry -> ((TransactionEntry)txEntry).getConfirmations() == 0).mapToLong(Entry::getValue).sum(); + EventManager.get().post(new NewWalletTransactionsEvent(wallet, blockTransactions, totalBlockchainValue, totalMempoolValue)); } }