mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2026-08-10 16:43:14 +00:00
configure a block explorer url, and open a txid in the configured block explorer
This commit is contained in:
@@ -811,6 +811,20 @@ public class AppServices {
|
||||
}
|
||||
}
|
||||
|
||||
public static void openBlockExplorer(String txid) {
|
||||
Server blockExplorer = Config.get().getBlockExplorer() == null ? BlockExplorer.MEMPOOL_SPACE.getServer() : Config.get().getBlockExplorer();
|
||||
String url = blockExplorer.getUrl();
|
||||
if(url.contains("{0}")) {
|
||||
url = url.replace("{0}", txid);
|
||||
} else {
|
||||
if(Network.get() != Network.MAINNET) {
|
||||
url += "/" + Network.get().getName();
|
||||
}
|
||||
url += "/tx/" + txid;
|
||||
}
|
||||
AppServices.get().getApplication().getHostServices().showDocument(url);
|
||||
}
|
||||
|
||||
static void parseFileUriArguments(List<String> fileUriArguments) {
|
||||
for(String fileUri : fileUriArguments) {
|
||||
try {
|
||||
|
||||
@@ -537,6 +537,13 @@ public class EntryCell extends TreeTableCell<Entry, Entry> implements Confirmati
|
||||
getItems().add(createCpfp);
|
||||
}
|
||||
|
||||
MenuItem openBlockExplorer = new MenuItem("Open in Block Explorer");
|
||||
openBlockExplorer.setOnAction(AE -> {
|
||||
hide();
|
||||
AppServices.openBlockExplorer(blockTransaction.getHashAsString());
|
||||
});
|
||||
getItems().add(openBlockExplorer);
|
||||
|
||||
MenuItem copyTxid = new MenuItem("Copy Transaction ID");
|
||||
copyTxid.setOnAction(AE -> {
|
||||
hide();
|
||||
@@ -558,6 +565,12 @@ public class EntryCell extends TreeTableCell<Entry, Entry> implements Confirmati
|
||||
EventManager.get().post(new ViewTransactionEvent(this.getOwnerWindow(), blockTransaction));
|
||||
});
|
||||
|
||||
MenuItem openBlockExplorer = new MenuItem("Open in Block Explorer");
|
||||
openBlockExplorer.setOnAction(AE -> {
|
||||
hide();
|
||||
AppServices.openBlockExplorer(blockTransaction.getHashAsString());
|
||||
});
|
||||
|
||||
MenuItem copyDate = new MenuItem("Copy Date");
|
||||
copyDate.setOnAction(AE -> {
|
||||
hide();
|
||||
@@ -582,7 +595,7 @@ public class EntryCell extends TreeTableCell<Entry, Entry> implements Confirmati
|
||||
Clipboard.getSystemClipboard().setContent(content);
|
||||
});
|
||||
|
||||
getItems().addAll(viewTransaction, copyDate, copyTxid, copyHeight);
|
||||
getItems().addAll(viewTransaction, openBlockExplorer, copyDate, copyTxid, copyHeight);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ public class FontAwesome5 extends GlyphFont {
|
||||
TOGGLE_OFF('\uf204'),
|
||||
TOGGLE_ON('\uf205'),
|
||||
TOOLS('\uf7d9'),
|
||||
UP_RIGHT_FROM_SQUARE('\uf35d'),
|
||||
UNDO('\uf0e2'),
|
||||
USER('\uf007'),
|
||||
USER_FRIENDS('\uf500'),
|
||||
|
||||
@@ -30,6 +30,7 @@ public class Config {
|
||||
private Mode mode;
|
||||
private BitcoinUnit bitcoinUnit;
|
||||
private UnitFormat unitFormat;
|
||||
private Server blockExplorer;
|
||||
private FeeRatesSource feeRatesSource;
|
||||
private FeeRatesSelection feeRatesSelection;
|
||||
private OptimizationStrategy sendOptimizationStrategy;
|
||||
@@ -150,6 +151,15 @@ public class Config {
|
||||
flush();
|
||||
}
|
||||
|
||||
public Server getBlockExplorer() {
|
||||
return blockExplorer;
|
||||
}
|
||||
|
||||
public void setBlockExplorer(Server blockExplorer) {
|
||||
this.blockExplorer = blockExplorer;
|
||||
flush();
|
||||
}
|
||||
|
||||
public FeeRatesSource getFeeRatesSource() {
|
||||
return feeRatesSource;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.sparrowwallet.sparrow.net;
|
||||
|
||||
import com.sparrowwallet.sparrow.io.Server;
|
||||
|
||||
public enum BlockExplorer {
|
||||
MEMPOOL_SPACE("https://mempool.space"),
|
||||
BLOCKSTREAM_INFO("https://blockstream.info");
|
||||
|
||||
private final Server server;
|
||||
|
||||
BlockExplorer(String url) {
|
||||
this.server = new Server(url);
|
||||
}
|
||||
|
||||
public Server getServer() {
|
||||
return server;
|
||||
}
|
||||
}
|
||||
+88
-14
@@ -1,32 +1,44 @@
|
||||
package com.sparrowwallet.sparrow.preferences;
|
||||
|
||||
import com.sparrowwallet.drongo.BitcoinUnit;
|
||||
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||
import com.sparrowwallet.sparrow.AppServices;
|
||||
import com.sparrowwallet.sparrow.EventManager;
|
||||
import com.sparrowwallet.sparrow.control.UnlabeledToggleSwitch;
|
||||
import com.sparrowwallet.sparrow.event.*;
|
||||
import com.sparrowwallet.sparrow.io.Config;
|
||||
import com.sparrowwallet.sparrow.io.Server;
|
||||
import com.sparrowwallet.sparrow.net.BlockExplorer;
|
||||
import com.sparrowwallet.sparrow.net.ExchangeSource;
|
||||
import com.sparrowwallet.sparrow.net.FeeRatesSource;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.control.TextInputDialog;
|
||||
import javafx.util.StringConverter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Currency;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class GeneralPreferencesController extends PreferencesDetailController {
|
||||
private static final Logger log = LoggerFactory.getLogger(GeneralPreferencesController.class);
|
||||
|
||||
@FXML
|
||||
private ComboBox<BitcoinUnit> bitcoinUnit;
|
||||
private static final Server CUSTOM_BLOCK_EXPLORER = new Server("http://custom.block.explorer");
|
||||
|
||||
@FXML
|
||||
private ComboBox<FeeRatesSource> feeRatesSource;
|
||||
|
||||
@FXML
|
||||
private ComboBox<Server> blockExplorers;
|
||||
|
||||
@FXML
|
||||
private ComboBox<Currency> fiatCurrency;
|
||||
|
||||
@@ -63,17 +75,6 @@ public class GeneralPreferencesController extends PreferencesDetailController {
|
||||
|
||||
@Override
|
||||
public void initializeView(Config config) {
|
||||
if(config.getBitcoinUnit() != null) {
|
||||
bitcoinUnit.setValue(config.getBitcoinUnit());
|
||||
} else {
|
||||
bitcoinUnit.setValue(BitcoinUnit.AUTO);
|
||||
}
|
||||
|
||||
bitcoinUnit.valueProperty().addListener((observable, oldValue, newValue) -> {
|
||||
config.setBitcoinUnit(newValue);
|
||||
EventManager.get().post(new BitcoinUnitChangedEvent(newValue));
|
||||
});
|
||||
|
||||
if(config.getFeeRatesSource() != null) {
|
||||
feeRatesSource.setValue(config.getFeeRatesSource());
|
||||
} else {
|
||||
@@ -86,6 +87,62 @@ public class GeneralPreferencesController extends PreferencesDetailController {
|
||||
EventManager.get().post(new FeeRatesSourceChangedEvent(newValue));
|
||||
});
|
||||
|
||||
blockExplorers.setItems(getBlockExplorerList());
|
||||
blockExplorers.setConverter(new StringConverter<>() {
|
||||
@Override
|
||||
public String toString(Server server) {
|
||||
if(server == null) {
|
||||
return "None Available";
|
||||
}
|
||||
|
||||
if(server == CUSTOM_BLOCK_EXPLORER) {
|
||||
return "Custom...";
|
||||
}
|
||||
|
||||
return server.getHost();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Server fromString(String string) {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
blockExplorers.valueProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if(newValue != null) {
|
||||
if(newValue == CUSTOM_BLOCK_EXPLORER) {
|
||||
TextInputDialog textInputDialog = new TextInputDialog();
|
||||
textInputDialog.setTitle("Enter Block Explorer URL");
|
||||
textInputDialog.setHeaderText("Enter the URL of the block explorer.\n\nIf present, the characters {0} will be replaced with the txid.\nFor example, https://localhost or https://localhost/tx/{0}\n");
|
||||
textInputDialog.getEditor().setPromptText("https://localhost");
|
||||
Optional<String> optUrl = textInputDialog.showAndWait();
|
||||
if(optUrl.isPresent() && !optUrl.get().isEmpty()) {
|
||||
try {
|
||||
Server server = getBlockExplorer(optUrl.get());
|
||||
config.setBlockExplorer(server);
|
||||
Platform.runLater(() -> {
|
||||
blockExplorers.getSelectionModel().select(-1);
|
||||
blockExplorers.setItems(getBlockExplorerList());
|
||||
blockExplorers.setValue(Config.get().getBlockExplorer());
|
||||
});
|
||||
} catch(Exception e) {
|
||||
AppServices.showErrorDialog("Invalid URL", "The URL " + optUrl.get() + " is not valid.");
|
||||
blockExplorers.setValue(oldValue);
|
||||
}
|
||||
} else {
|
||||
blockExplorers.setValue(oldValue);
|
||||
}
|
||||
} else {
|
||||
Config.get().setBlockExplorer(newValue);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if(config.getBlockExplorer() != null) {
|
||||
blockExplorers.setValue(config.getBlockExplorer());
|
||||
} else {
|
||||
blockExplorers.getSelectionModel().select(0);
|
||||
}
|
||||
|
||||
if(config.getExchangeSource() != null) {
|
||||
exchangeSource.setValue(config.getExchangeSource());
|
||||
} else {
|
||||
@@ -134,6 +191,23 @@ public class GeneralPreferencesController extends PreferencesDetailController {
|
||||
});
|
||||
}
|
||||
|
||||
private static Server getBlockExplorer(String serverUrl) {
|
||||
String url = serverUrl.trim();
|
||||
if(url.endsWith("/")) {
|
||||
url = url.substring(0, url.length() - 1);
|
||||
}
|
||||
return new Server(url);
|
||||
}
|
||||
|
||||
private ObservableList<Server> getBlockExplorerList() {
|
||||
List<Server> servers = Arrays.stream(BlockExplorer.values()).map(BlockExplorer::getServer).collect(Collectors.toList());
|
||||
if(Config.get().getBlockExplorer() != null && !servers.contains(Config.get().getBlockExplorer())) {
|
||||
servers.add(Config.get().getBlockExplorer());
|
||||
}
|
||||
servers.add(CUSTOM_BLOCK_EXPLORER);
|
||||
return FXCollections.observableList(servers);
|
||||
}
|
||||
|
||||
private void updateCurrencies(ExchangeSource exchangeSource) {
|
||||
ExchangeSource.CurrenciesService currenciesService = new ExchangeSource.CurrenciesService(exchangeSource);
|
||||
currenciesService.setOnSucceeded(event -> {
|
||||
|
||||
@@ -78,6 +78,12 @@ public class HeadersController extends TransactionFormController implements Init
|
||||
@FXML
|
||||
private IdLabel id;
|
||||
|
||||
@FXML
|
||||
private ToggleButton copyTxid;
|
||||
|
||||
@FXML
|
||||
private ToggleButton openBlockExplorer;
|
||||
|
||||
@FXML
|
||||
private TransactionDiagram transactionDiagram;
|
||||
|
||||
@@ -806,11 +812,13 @@ public class HeadersController extends TransactionFormController implements Init
|
||||
addStyleClass(size, UNFINALIZED_TXID_CLASS);
|
||||
addStyleClass(virtualSize, UNFINALIZED_TXID_CLASS);
|
||||
addStyleClass(feeRate, UNFINALIZED_TXID_CLASS);
|
||||
openBlockExplorer.setDisable(true);
|
||||
} else {
|
||||
id.getStyleClass().remove(UNFINALIZED_TXID_CLASS);
|
||||
size.getStyleClass().remove(UNFINALIZED_TXID_CLASS);
|
||||
virtualSize.getStyleClass().remove(UNFINALIZED_TXID_CLASS);
|
||||
feeRate.getStyleClass().remove(UNFINALIZED_TXID_CLASS);
|
||||
openBlockExplorer.setDisable(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -821,11 +829,18 @@ public class HeadersController extends TransactionFormController implements Init
|
||||
}
|
||||
|
||||
public void copyId(ActionEvent event) {
|
||||
copyTxid.setSelected(false);
|
||||
ClipboardContent content = new ClipboardContent();
|
||||
content.putString(headersForm.getTransaction().calculateTxId(false).toString());
|
||||
Clipboard.getSystemClipboard().setContent(content);
|
||||
}
|
||||
|
||||
public void openInBlockExplorer(ActionEvent event) {
|
||||
openBlockExplorer.setSelected(false);
|
||||
String txid = headersForm.getTransaction().calculateTxId(false).toString();
|
||||
AppServices.openBlockExplorer(txid);
|
||||
}
|
||||
|
||||
public void setLocktimeToCurrentHeight(ActionEvent event) {
|
||||
if(AppServices.getCurrentBlockHeight() != null && locktimeBlock.isEditable()) {
|
||||
locktimeBlock.getValueFactory().setValue(AppServices.getCurrentBlockHeight());
|
||||
|
||||
Reference in New Issue
Block a user