refactor singleton services from appcontroller to appservices

This commit is contained in:
Craig Raw 2020-12-04 15:42:17 +02:00
parent 7461b47466
commit 39d1e686f4
38 changed files with 583 additions and 529 deletions

View file

@ -7,7 +7,6 @@ import com.sparrowwallet.drongo.BitcoinUnit;
import com.sparrowwallet.drongo.Network;
import com.sparrowwallet.drongo.SecureString;
import com.sparrowwallet.drongo.Utils;
import com.sparrowwallet.drongo.address.Address;
import com.sparrowwallet.drongo.crypto.ECKey;
import com.sparrowwallet.drongo.crypto.EncryptionType;
import com.sparrowwallet.drongo.crypto.InvalidPasswordException;
@ -19,15 +18,11 @@ import com.sparrowwallet.drongo.protocol.Transaction;
import com.sparrowwallet.drongo.psbt.PSBT;
import com.sparrowwallet.drongo.psbt.PSBTInput;
import com.sparrowwallet.drongo.psbt.PSBTParseException;
import com.sparrowwallet.drongo.uri.BitcoinURI;
import com.sparrowwallet.drongo.wallet.*;
import com.sparrowwallet.sparrow.control.*;
import com.sparrowwallet.sparrow.event.*;
import com.sparrowwallet.sparrow.io.*;
import com.sparrowwallet.sparrow.net.ElectrumServer;
import com.sparrowwallet.sparrow.net.ExchangeSource;
import com.sparrowwallet.sparrow.net.MempoolRateSize;
import com.sparrowwallet.sparrow.net.VersionCheckService;
import com.sparrowwallet.sparrow.preferences.PreferencesDialog;
import com.sparrowwallet.sparrow.transaction.TransactionController;
import com.sparrowwallet.sparrow.transaction.TransactionData;
@ -37,10 +32,7 @@ import com.sparrowwallet.sparrow.wallet.WalletForm;
import de.codecentric.centerdevice.MenuToolkit;
import javafx.animation.*;
import javafx.application.Platform;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.collections.ListChangeListener;
import javafx.concurrent.Worker;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
@ -55,7 +47,6 @@ import javafx.scene.image.ImageView;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Font;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
@ -70,27 +61,17 @@ import java.io.*;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;
import static com.sparrowwallet.sparrow.AppServices.*;
public class AppController implements Initializable {
private static final Logger log = LoggerFactory.getLogger(AppController.class);
private static final int SERVER_PING_PERIOD = 1 * 60 * 1000;
private static final int ENUMERATE_HW_PERIOD = 30 * 1000;
private static final int RATES_PERIOD = 5 * 60 * 1000;
private static final int VERSION_CHECK_PERIOD_HOURS = 24;
private static final ExchangeSource DEFAULT_EXCHANGE_SOURCE = ExchangeSource.COINGECKO;
private static final Currency DEFAULT_FIAT_CURRENCY = Currency.getInstance("USD");
public static final String DRAG_OVER_CLASS = "drag-over";
private MainApp application;
@FXML
private MenuItem saveTransaction;
@ -127,35 +108,8 @@ public class AppController implements Initializable {
@FXML
private UnlabeledToggleSwitch serverToggle;
//Determines if a change in serverToggle changes the offline/online mode
private boolean changeMode = true;
private static final BooleanProperty onlineProperty = new SimpleBooleanProperty(false);
private Timeline statusTimeline;
private ExchangeSource.RatesService ratesService;
private ElectrumServer.ConnectionService connectionService;
private Hwi.ScheduledEnumerateService deviceEnumerateService;
private VersionCheckService versionCheckService;
private static Integer currentBlockHeight;
private static Map<Integer, Double> targetBlockFeeRates;
private static final Map<Date, Set<MempoolRateSize>> mempoolHistogram = new TreeMap<>();
private static Double minimumRelayFeeRate;
private static CurrencyRate fiatCurrencyExchangeRate;
private static List<Device> devices;
private static final Map<Address, BitcoinURI> payjoinURIs = new HashMap<>();
@Override
public void initialize(URL location, ResourceBundle resources) {
EventManager.get().register(this);
@ -258,152 +212,12 @@ public class AppController implements Initializable {
showTxHex.setSelected(Config.get().isShowTransactionHex());
exportWallet.setDisable(true);
serverToggle.selectedProperty().addListener((observable, oldValue, newValue) -> {
if(changeMode) {
Config.get().setMode(newValue ? Mode.ONLINE : Mode.OFFLINE);
if(newValue) {
if(connectionService.getState() == Worker.State.CANCELLED) {
connectionService.reset();
}
if(!connectionService.isRunning()) {
connectionService.start();
}
if(ratesService.getState() == Worker.State.CANCELLED) {
ratesService.reset();
}
if(!ratesService.isRunning() && ratesService.getExchangeSource() != ExchangeSource.NONE) {
ratesService.start();
}
if(versionCheckService.getState() == Worker.State.CANCELLED) {
versionCheckService.reset();
}
if(!versionCheckService.isRunning() && Config.get().isCheckNewVersions()) {
versionCheckService.start();
}
} else {
connectionService.cancel();
ratesService.cancel();
versionCheckService.cancel();
}
}
});
onlineProperty.bindBidirectional(serverToggle.selectedProperty());
onlineProperty().bindBidirectional(serverToggle.selectedProperty());
onlineProperty().addListener((observable, oldValue, newValue) -> {
Platform.runLater(this::setServerToggleTooltip);
Platform.runLater(() -> setServerToggleTooltip(getCurrentBlockHeight()));
});
Config config = Config.get();
connectionService = createConnectionService();
if(config.getMode() == Mode.ONLINE && config.getElectrumServer() != null && !config.getElectrumServer().isEmpty()) {
connectionService.start();
}
ExchangeSource source = config.getExchangeSource() != null ? config.getExchangeSource() : DEFAULT_EXCHANGE_SOURCE;
Currency currency = config.getFiatCurrency() != null ? config.getFiatCurrency() : DEFAULT_FIAT_CURRENCY;
ratesService = createRatesService(source, currency);
if(config.getMode() == Mode.ONLINE && source != ExchangeSource.NONE) {
ratesService.start();
}
versionCheckService = createVersionCheckService();
if(config.getMode() == Mode.ONLINE && config.isCheckNewVersions()) {
versionCheckService.start();
}
openTransactionIdItem.disableProperty().bind(onlineProperty.not());
}
private ElectrumServer.ConnectionService createConnectionService() {
ElectrumServer.ConnectionService connectionService = new ElectrumServer.ConnectionService();
connectionService.setPeriod(new Duration(SERVER_PING_PERIOD));
connectionService.setRestartOnFailure(true);
EventManager.get().register(connectionService);
connectionService.statusProperty().addListener((observable, oldValue, newValue) -> {
if(connectionService.isRunning()) {
EventManager.get().post(new StatusEvent(newValue));
}
});
connectionService.setOnSucceeded(successEvent -> {
changeMode = false;
onlineProperty.setValue(true);
changeMode = true;
if(connectionService.getValue() != null) {
EventManager.get().post(connectionService.getValue());
}
});
connectionService.setOnFailed(failEvent -> {
//Close connection here to create a new transport next time we try
connectionService.resetConnection();
changeMode = false;
onlineProperty.setValue(false);
changeMode = true;
log.debug("Connection failed", failEvent.getSource().getException());
EventManager.get().post(new ConnectionFailedEvent(failEvent.getSource().getException()));
});
return connectionService;
}
private ExchangeSource.RatesService createRatesService(ExchangeSource exchangeSource, Currency currency) {
ExchangeSource.RatesService ratesService = new ExchangeSource.RatesService(exchangeSource, currency);
ratesService.setPeriod(new Duration(RATES_PERIOD));
ratesService.setRestartOnFailure(true);
ratesService.setOnSucceeded(successEvent -> {
EventManager.get().post(ratesService.getValue());
});
return ratesService;
}
private VersionCheckService createVersionCheckService() {
VersionCheckService versionCheckService = new VersionCheckService();
versionCheckService.setDelay(Duration.seconds(10));
versionCheckService.setPeriod(Duration.hours(VERSION_CHECK_PERIOD_HOURS));
versionCheckService.setRestartOnFailure(true);
versionCheckService.setOnSucceeded(successEvent -> {
VersionUpdatedEvent event = versionCheckService.getValue();
if(event != null) {
EventManager.get().post(event);
}
});
return versionCheckService;
}
private Hwi.ScheduledEnumerateService createDeviceEnumerateService() {
Hwi.ScheduledEnumerateService enumerateService = new Hwi.ScheduledEnumerateService(null);
enumerateService.setPeriod(new Duration(ENUMERATE_HW_PERIOD));
enumerateService.setOnSucceeded(workerStateEvent -> {
List<Device> devices = enumerateService.getValue();
//Null devices are returned if the app is currently prompting for a pin. Otherwise, the enumerate clears the pin screen
if(devices != null) {
//If another instance of HWI is currently accessing the usb interface, HWI returns empty device models. Ignore this run if that happens
List<Device> validDevices = devices.stream().filter(device -> device.getModel() != null).collect(Collectors.toList());
if(validDevices.size() == devices.size()) {
Platform.runLater(() -> EventManager.get().post(new UsbDeviceEvent(devices)));
}
}
});
return enumerateService;
}
public void setApplication(MainApp application) {
this.application = application;
openTransactionIdItem.disableProperty().bind(onlineProperty().not());
}
private void setOsxApplicationMenu() {
@ -577,7 +391,7 @@ public class AppController implements Initializable {
log.error("Error scanning QR", result.exception);
showErrorDialog("Error scanning QR", result.exception.getMessage());
} else {
AppController.showErrorDialog("Invalid QR Code", "Cannot parse QR code into a transaction or PSBT");
AppServices.showErrorDialog("Invalid QR Code", "Cannot parse QR code into a transaction or PSBT");
}
}
}
@ -626,70 +440,12 @@ public class AppController implements Initializable {
}
} catch(IOException e) {
log.error("Error saving transaction", e);
AppController.showErrorDialog("Error saving transaction", "Cannot write to " + file.getAbsolutePath());
AppServices.showErrorDialog("Error saving transaction", "Cannot write to " + file.getAbsolutePath());
}
}
}
}
public static boolean isOnline() {
return onlineProperty.get();
}
public void connect() {
serverToggle.selectedProperty().set(true);
}
public void disconnect() {
serverToggle.selectedProperty().set(false);
}
public static BooleanProperty onlineProperty() { return onlineProperty; }
public static Integer getCurrentBlockHeight() {
return currentBlockHeight;
}
public static Map<Integer, Double> getTargetBlockFeeRates() {
return targetBlockFeeRates;
}
public static Map<Date, Set<MempoolRateSize>> getMempoolHistogram() {
return mempoolHistogram;
}
private void addMempoolRateSizes(Set<MempoolRateSize> rateSizes) {
LocalDateTime dateMinute = LocalDateTime.now().truncatedTo(ChronoUnit.MINUTES);
if(mempoolHistogram.isEmpty()) {
mempoolHistogram.put(Date.from(dateMinute.minusMinutes(1).atZone(ZoneId.systemDefault()).toInstant()), rateSizes);
}
mempoolHistogram.put(Date.from(dateMinute.atZone(ZoneId.systemDefault()).toInstant()), rateSizes);
}
public static Double getMinimumRelayFeeRate() {
return minimumRelayFeeRate == null ? Transaction.DEFAULT_MIN_RELAY_FEE : minimumRelayFeeRate;
}
public static CurrencyRate getFiatCurrencyExchangeRate() {
return fiatCurrencyExchangeRate;
}
public static List<Device> getDevices() {
return devices == null ? new ArrayList<>() : devices;
}
public static BitcoinURI getPayjoinURI(Address address) {
return payjoinURIs.get(address);
}
public static void addPayjoinURI(BitcoinURI bitcoinURI) {
if(bitcoinURI.getPayjoinUrl() == null) {
throw new IllegalArgumentException("Not a payjoin URI");
}
payjoinURIs.put(bitcoinURI.getAddress(), bitcoinURI);
}
public Map<Wallet, Storage> getOpenWallets() {
Map<Wallet, Storage> openWallets = new LinkedHashMap<>();
@ -704,28 +460,6 @@ public class AppController implements Initializable {
return openWallets;
}
public static void showErrorDialog(String title, String content) {
Alert alert = new Alert(Alert.AlertType.ERROR);
setStageIcon(alert.getDialogPane().getScene().getWindow());
alert.getDialogPane().getScene().getStylesheets().add(AppController.class.getResource("general.css").toExternalForm());
alert.setTitle(title);
alert.setHeaderText(title);
alert.setContentText(content);
alert.showAndWait();
}
public static void setStageIcon(Window window) {
Stage stage = (Stage)window;
stage.getIcons().add(new Image(AppController.class.getResourceAsStream("/image/sparrow.png")));
if(stage.getScene() != null && Config.get().getTheme() == Theme.DARK) {
stage.getScene().getStylesheets().add(AppController.class.getResource("darktheme.css").toExternalForm());
}
}
public static Font getMonospaceFont() {
return Font.font("Roboto Mono", 13);
}
public void selectTab(Wallet wallet) {
for(Tab tab : tabs.getTabs()) {
@ -745,7 +479,7 @@ public class AppController implements Initializable {
public void quit(ActionEvent event) {
try {
application.stop();
AppServices.get().getApplication().stop();
} catch (Exception e) {
log.error("Error quitting application", e);
}
@ -769,8 +503,8 @@ public class AppController implements Initializable {
return FileType.JSON.equals(fileType) || FileType.BINARY.equals(fileType);
}
private void setServerToggleTooltip() {
serverToggle.setTooltip(new Tooltip(isOnline() ? "Connected to " + Config.get().getElectrumServer() + (getCurrentBlockHeight() != null ? " at height " + getCurrentBlockHeight() : "") : "Disconnected"));
private void setServerToggleTooltip(Integer currentBlockHeight) {
serverToggle.setTooltip(new Tooltip(AppServices.isOnline() ? "Connected to " + Config.get().getElectrumServer() + (currentBlockHeight != null ? " at height " + currentBlockHeight : "") : "Disconnected"));
}
public void newWallet(ActionEvent event) {
@ -1266,6 +1000,7 @@ public class AppController implements Initializable {
@Subscribe
public void tabSelected(TabSelectedEvent event) {
//TODO: Handle multiple windows
String tabName = event.getTabName();
if(tabs.getScene() != null) {
Stage tabStage = (Stage)tabs.getScene().getWindow();
@ -1304,11 +1039,13 @@ public class AppController implements Initializable {
@Subscribe
public void walletSettingsChanged(WalletSettingsChangedEvent event) {
//TODO: Handle multiple windows
exportWallet.setDisable(!event.getWallet().isValid());
}
@Subscribe
public void newWalletTransactions(NewWalletTransactionsEvent event) {
//TODO: Handle multiple windows
if(Config.get().isNotifyNewTransactions()) {
String text;
if(event.getBlockTransactions().size() == 1) {
@ -1380,7 +1117,7 @@ public class AppController implements Initializable {
public void versionUpdated(VersionUpdatedEvent event) {
Hyperlink versionUpdateLabel = new Hyperlink("Sparrow " + event.getVersion() + " available");
versionUpdateLabel.setOnAction(event1 -> {
application.getHostServices().showDocument("https://www.sparrowwallet.com/download");
AppServices.get().getApplication().getHostServices().showDocument("https://www.sparrowwallet.com/download");
});
if(statusBar.getRightItems().size() > 0 && statusBar.getRightItems().get(0) instanceof Hyperlink) {
@ -1417,8 +1154,6 @@ public class AppController implements Initializable {
@Subscribe
public void usbDevicesFound(UsbDeviceEvent event) {
devices = Collections.unmodifiableList(event.getDevices());
UsbStatusButton usbStatus = null;
for(Node node : statusBar.getRightItems()) {
if(node instanceof UsbStatusButton) {
@ -1442,46 +1177,21 @@ public class AppController implements Initializable {
}
}
@Subscribe
public void newConnection(ConnectionEvent event) {
currentBlockHeight = event.getBlockHeight();
targetBlockFeeRates = event.getTargetBlockFeeRates();
addMempoolRateSizes(event.getMempoolRateSizes());
minimumRelayFeeRate = event.getMinimumRelayFeeRate();
String banner = event.getServerBanner();
String status = "Connected to " + Config.get().getElectrumServer() + " at height " + event.getBlockHeight();
EventManager.get().post(new StatusEvent(status));
}
@Subscribe
public void connectionFailed(ConnectionFailedEvent event) {
String reason = event.getException().getCause() != null ? event.getException().getCause().getMessage() : event.getException().getMessage();
String status = "Connection error: " + reason;
EventManager.get().post(new StatusEvent(status));
}
@Subscribe
public void newBlock(NewBlockEvent event) {
currentBlockHeight = event.getHeight();
setServerToggleTooltip();
String status = "Updating to new block height " + event.getHeight();
EventManager.get().post(new StatusEvent(status));
}
@Subscribe
public void feesUpdated(FeeRatesUpdatedEvent event) {
targetBlockFeeRates = event.getTargetBlockFeeRates();
addMempoolRateSizes(event.getMempoolRateSizes());
setServerToggleTooltip(event.getHeight());
}
@Subscribe
public void viewTransaction(ViewTransactionEvent event) {
//TODO: Handle multiple windows
Tab tab = addTransactionTab(event.getBlockTransaction(), event.getInitialView(), event.getInitialIndex());
tabs.getSelectionModel().select(tab);
}
@Subscribe
public void viewPSBT(ViewPSBTEvent event) {
//TODO: Handle multiple windows
Tab tab = addTransactionTab(event.getLabel(), event.getPsbt());
tabs.getSelectionModel().select(tab);
}
@ -1492,102 +1202,27 @@ public class AppController implements Initializable {
selectedToggle.ifPresent(toggle -> bitcoinUnit.selectToggle(toggle));
}
@Subscribe
public void feeRateSourceChanged(FeeRatesSourceChangedEvent event) {
ElectrumServer.FeeRatesService feeRatesService = new ElectrumServer.FeeRatesService();
feeRatesService.setOnSucceeded(workerStateEvent -> {
EventManager.get().post(feeRatesService.getValue());
});
feeRatesService.start();
}
@Subscribe
public void fiatCurrencySelected(FiatCurrencySelectedEvent event) {
ratesService.cancel();
if (Config.get().getMode() != Mode.OFFLINE && event.getExchangeSource() != ExchangeSource.NONE) {
ratesService = createRatesService(event.getExchangeSource(), event.getCurrency());
ratesService.start();
}
}
@Subscribe
public void exchangeRatesUpdated(ExchangeRatesUpdatedEvent event) {
fiatCurrencyExchangeRate = event.getCurrencyRate();
}
@Subscribe
public void versionCheckStatus(VersionCheckStatusEvent event) {
versionCheckService.cancel();
if(Config.get().getMode() != Mode.OFFLINE && event.isEnabled()) {
versionCheckService = createVersionCheckService();
versionCheckService.start();
}
}
@Subscribe
public void openWallets(OpenWalletsEvent event) {
List<File> walletFiles = event.getWalletsMap().values().stream().map(Storage::getWalletFile).collect(Collectors.toList());
Config.get().setRecentWalletFiles(walletFiles);
boolean usbWallet = false;
for(Map.Entry<Wallet, Storage> entry : event.getWalletsMap().entrySet()) {
Wallet wallet = entry.getKey();
Storage storage = entry.getValue();
if(!storage.getWalletFile().exists() || wallet.containsSource(KeystoreSource.HW_USB)) {
usbWallet = true;
if(deviceEnumerateService == null) {
deviceEnumerateService = createDeviceEnumerateService();
}
if(deviceEnumerateService.getState() == Worker.State.CANCELLED) {
deviceEnumerateService.reset();
}
if(!deviceEnumerateService.isRunning()) {
deviceEnumerateService.start();
}
break;
}
}
if(!usbWallet && deviceEnumerateService != null && deviceEnumerateService.isRunning()) {
deviceEnumerateService.cancel();
EventManager.get().post(new UsbDeviceEvent(Collections.emptyList()));
}
}
@Subscribe
public void requestOpenWallets(RequestOpenWalletsEvent event) {
//TODO: Handle multiple windows
EventManager.get().post(new OpenWalletsEvent(getOpenWallets()));
}
@Subscribe
public void requestWalletOpen(RequestWalletOpenEvent event) {
//TODO: Handle multiple windows
openWallet(null);
}
@Subscribe
public void requestTransactionOpen(RequestTransactionOpenEvent event) {
//TODO: Handle multiple windows
openTransactionFromFile(null);
}
@Subscribe
public void requestQRScan(RequestQRScanEvent event) {
//TODO: Handle multiple windows
openTransactionFromQR(null);
}
@Subscribe
public void requestConnect(RequestConnectEvent event) {
connect();
}
@Subscribe
public void requestDisconnect(RequestDisconnectEvent event) {
disconnect();
}
}

View file

@ -0,0 +1,423 @@
package com.sparrowwallet.sparrow;
import com.google.common.eventbus.Subscribe;
import com.sparrowwallet.drongo.address.Address;
import com.sparrowwallet.drongo.protocol.Transaction;
import com.sparrowwallet.drongo.uri.BitcoinURI;
import com.sparrowwallet.drongo.wallet.KeystoreSource;
import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.event.*;
import com.sparrowwallet.sparrow.io.Config;
import com.sparrowwallet.sparrow.io.Device;
import com.sparrowwallet.sparrow.io.Hwi;
import com.sparrowwallet.sparrow.io.Storage;
import com.sparrowwallet.sparrow.net.ElectrumServer;
import com.sparrowwallet.sparrow.net.ExchangeSource;
import com.sparrowwallet.sparrow.net.MempoolRateSize;
import com.sparrowwallet.sparrow.net.VersionCheckService;
import javafx.application.Platform;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.ScheduledService;
import javafx.concurrent.Worker;
import javafx.scene.control.Alert;
import javafx.scene.image.Image;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import javafx.stage.Window;
import javafx.util.Duration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
public class AppServices {
private static final Logger log = LoggerFactory.getLogger(AppServices.class);
private static final int SERVER_PING_PERIOD = 1 * 60 * 1000;
private static final int ENUMERATE_HW_PERIOD = 30 * 1000;
private static final int RATES_PERIOD = 5 * 60 * 1000;
private static final int VERSION_CHECK_PERIOD_HOURS = 24;
private static final ExchangeSource DEFAULT_EXCHANGE_SOURCE = ExchangeSource.COINGECKO;
private static final Currency DEFAULT_FIAT_CURRENCY = Currency.getInstance("USD");
private static AppServices INSTANCE;
private final MainApp application;
private static final BooleanProperty onlineProperty = new SimpleBooleanProperty(false);
private ExchangeSource.RatesService ratesService;
private final ElectrumServer.ConnectionService connectionService;
private Hwi.ScheduledEnumerateService deviceEnumerateService;
private VersionCheckService versionCheckService;
private static Integer currentBlockHeight;
private static Map<Integer, Double> targetBlockFeeRates;
private static final Map<Date, Set<MempoolRateSize>> mempoolHistogram = new TreeMap<>();
private static Double minimumRelayFeeRate;
private static CurrencyRate fiatCurrencyExchangeRate;
private static List<Device> devices;
private static final Map<Address, BitcoinURI> payjoinURIs = new HashMap<>();
private final ChangeListener<Boolean> onlineServicesListener = new ChangeListener<>() {
@Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean online) {
Config.get().setMode(online ? Mode.ONLINE : Mode.OFFLINE);
if(online) {
restartService(connectionService);
if(ratesService.getExchangeSource() != ExchangeSource.NONE) {
restartService(ratesService);
}
if(Config.get().isCheckNewVersions()) {
restartService(versionCheckService);
}
} else {
connectionService.cancel();
ratesService.cancel();
versionCheckService.cancel();
}
}
};
private void restartService(ScheduledService<?> service) {
if(service.getState() == Worker.State.CANCELLED) {
service.reset();
}
if(!service.isRunning()) {
service.start();
}
}
public AppServices(MainApp application) {
this.application = application;
EventManager.get().register(this);
Config config = Config.get();
connectionService = createConnectionService();
if(config.getMode() == Mode.ONLINE && config.getElectrumServer() != null && !config.getElectrumServer().isEmpty()) {
connectionService.start();
}
ExchangeSource source = config.getExchangeSource() != null ? config.getExchangeSource() : DEFAULT_EXCHANGE_SOURCE;
Currency currency = config.getFiatCurrency() != null ? config.getFiatCurrency() : DEFAULT_FIAT_CURRENCY;
ratesService = createRatesService(source, currency);
if(config.getMode() == Mode.ONLINE && source != ExchangeSource.NONE) {
ratesService.start();
}
versionCheckService = createVersionCheckService();
if(config.getMode() == Mode.ONLINE && config.isCheckNewVersions()) {
versionCheckService.start();
}
onlineProperty.addListener(onlineServicesListener);
}
private ElectrumServer.ConnectionService createConnectionService() {
ElectrumServer.ConnectionService connectionService = new ElectrumServer.ConnectionService();
connectionService.setPeriod(new Duration(SERVER_PING_PERIOD));
connectionService.setRestartOnFailure(true);
EventManager.get().register(connectionService);
connectionService.statusProperty().addListener((observable, oldValue, newValue) -> {
if(connectionService.isRunning()) {
EventManager.get().post(new StatusEvent(newValue));
}
});
connectionService.setOnSucceeded(successEvent -> {
onlineProperty.removeListener(onlineServicesListener);
onlineProperty.setValue(true);
onlineProperty.addListener(onlineServicesListener);
if(connectionService.getValue() != null) {
EventManager.get().post(connectionService.getValue());
}
});
connectionService.setOnFailed(failEvent -> {
//Close connection here to create a new transport next time we try
connectionService.resetConnection();
onlineProperty.removeListener(onlineServicesListener);
onlineProperty.setValue(false);
onlineProperty.addListener(onlineServicesListener);
log.debug("Connection failed", failEvent.getSource().getException());
EventManager.get().post(new ConnectionFailedEvent(failEvent.getSource().getException()));
});
return connectionService;
}
private ExchangeSource.RatesService createRatesService(ExchangeSource exchangeSource, Currency currency) {
ExchangeSource.RatesService ratesService = new ExchangeSource.RatesService(exchangeSource, currency);
ratesService.setPeriod(new Duration(RATES_PERIOD));
ratesService.setRestartOnFailure(true);
ratesService.setOnSucceeded(successEvent -> {
EventManager.get().post(ratesService.getValue());
});
return ratesService;
}
private VersionCheckService createVersionCheckService() {
VersionCheckService versionCheckService = new VersionCheckService();
versionCheckService.setDelay(Duration.seconds(10));
versionCheckService.setPeriod(Duration.hours(VERSION_CHECK_PERIOD_HOURS));
versionCheckService.setRestartOnFailure(true);
versionCheckService.setOnSucceeded(successEvent -> {
VersionUpdatedEvent event = versionCheckService.getValue();
if(event != null) {
EventManager.get().post(event);
}
});
return versionCheckService;
}
private Hwi.ScheduledEnumerateService createDeviceEnumerateService() {
Hwi.ScheduledEnumerateService enumerateService = new Hwi.ScheduledEnumerateService(null);
enumerateService.setPeriod(new Duration(ENUMERATE_HW_PERIOD));
enumerateService.setOnSucceeded(workerStateEvent -> {
List<Device> devices = enumerateService.getValue();
//Null devices are returned if the app is currently prompting for a pin. Otherwise, the enumerate clears the pin screen
if(devices != null) {
//If another instance of HWI is currently accessing the usb interface, HWI returns empty device models. Ignore this run if that happens
List<Device> validDevices = devices.stream().filter(device -> device.getModel() != null).collect(Collectors.toList());
if(validDevices.size() == devices.size()) {
Platform.runLater(() -> EventManager.get().post(new UsbDeviceEvent(devices)));
}
}
});
return enumerateService;
}
static void initialize(MainApp application) {
INSTANCE = new AppServices(application);
}
public static AppServices get() {
return INSTANCE;
}
public MainApp getApplication() {
return application;
}
public static boolean isOnline() {
return onlineProperty.get();
}
public static BooleanProperty onlineProperty() {
return onlineProperty;
}
public static Integer getCurrentBlockHeight() {
return currentBlockHeight;
}
public static Map<Integer, Double> getTargetBlockFeeRates() {
return targetBlockFeeRates;
}
public static Map<Date, Set<MempoolRateSize>> getMempoolHistogram() {
return mempoolHistogram;
}
private void addMempoolRateSizes(Set<MempoolRateSize> rateSizes) {
LocalDateTime dateMinute = LocalDateTime.now().truncatedTo(ChronoUnit.MINUTES);
if(mempoolHistogram.isEmpty()) {
mempoolHistogram.put(Date.from(dateMinute.minusMinutes(1).atZone(ZoneId.systemDefault()).toInstant()), rateSizes);
}
mempoolHistogram.put(Date.from(dateMinute.atZone(ZoneId.systemDefault()).toInstant()), rateSizes);
}
public static Double getMinimumRelayFeeRate() {
return minimumRelayFeeRate == null ? Transaction.DEFAULT_MIN_RELAY_FEE : minimumRelayFeeRate;
}
public static CurrencyRate getFiatCurrencyExchangeRate() {
return fiatCurrencyExchangeRate;
}
public static List<Device> getDevices() {
return devices == null ? new ArrayList<>() : devices;
}
public static BitcoinURI getPayjoinURI(Address address) {
return payjoinURIs.get(address);
}
public static void addPayjoinURI(BitcoinURI bitcoinURI) {
if(bitcoinURI.getPayjoinUrl() == null) {
throw new IllegalArgumentException("Not a payjoin URI");
}
payjoinURIs.put(bitcoinURI.getAddress(), bitcoinURI);
}
public static void showErrorDialog(String title, String content) {
Alert alert = new Alert(Alert.AlertType.ERROR);
setStageIcon(alert.getDialogPane().getScene().getWindow());
alert.getDialogPane().getScene().getStylesheets().add(AppServices.class.getResource("general.css").toExternalForm());
alert.setTitle(title);
alert.setHeaderText(title);
alert.setContentText(content);
alert.showAndWait();
}
public static void setStageIcon(Window window) {
Stage stage = (Stage)window;
stage.getIcons().add(new Image(AppServices.class.getResourceAsStream("/image/sparrow.png")));
if(stage.getScene() != null && Config.get().getTheme() == Theme.DARK) {
stage.getScene().getStylesheets().add(AppServices.class.getResource("darktheme.css").toExternalForm());
}
}
public static Font getMonospaceFont() {
return Font.font("Roboto Mono", 13);
}
@Subscribe
public void newConnection(ConnectionEvent event) {
currentBlockHeight = event.getBlockHeight();
targetBlockFeeRates = event.getTargetBlockFeeRates();
addMempoolRateSizes(event.getMempoolRateSizes());
minimumRelayFeeRate = event.getMinimumRelayFeeRate();
String banner = event.getServerBanner();
String status = "Connected to " + Config.get().getElectrumServer() + " at height " + event.getBlockHeight();
EventManager.get().post(new StatusEvent(status));
}
@Subscribe
public void connectionFailed(ConnectionFailedEvent event) {
String reason = event.getException().getCause() != null ? event.getException().getCause().getMessage() : event.getException().getMessage();
String status = "Connection error: " + reason;
EventManager.get().post(new StatusEvent(status));
}
@Subscribe
public void usbDevicesFound(UsbDeviceEvent event) {
devices = Collections.unmodifiableList(event.getDevices());
}
@Subscribe
public void newBlock(NewBlockEvent event) {
currentBlockHeight = event.getHeight();
String status = "Updating to new block height " + event.getHeight();
EventManager.get().post(new StatusEvent(status));
}
@Subscribe
public void feesUpdated(FeeRatesUpdatedEvent event) {
targetBlockFeeRates = event.getTargetBlockFeeRates();
addMempoolRateSizes(event.getMempoolRateSizes());
}
@Subscribe
public void feeRateSourceChanged(FeeRatesSourceChangedEvent event) {
ElectrumServer.FeeRatesService feeRatesService = new ElectrumServer.FeeRatesService();
feeRatesService.setOnSucceeded(workerStateEvent -> {
EventManager.get().post(feeRatesService.getValue());
});
//Perform once-off fee rates retrieval to immediately change displayed rates
feeRatesService.start();
}
@Subscribe
public void fiatCurrencySelected(FiatCurrencySelectedEvent event) {
ratesService.cancel();
if(Config.get().getMode() != Mode.OFFLINE && event.getExchangeSource() != ExchangeSource.NONE) {
ratesService = createRatesService(event.getExchangeSource(), event.getCurrency());
ratesService.start();
}
}
@Subscribe
public void exchangeRatesUpdated(ExchangeRatesUpdatedEvent event) {
fiatCurrencyExchangeRate = event.getCurrencyRate();
}
@Subscribe
public void versionCheckStatus(VersionCheckStatusEvent event) {
versionCheckService.cancel();
if(Config.get().getMode() != Mode.OFFLINE && event.isEnabled()) {
versionCheckService = createVersionCheckService();
versionCheckService.start();
}
}
@Subscribe
public void openWallets(OpenWalletsEvent event) {
List<File> walletFiles = event.getWalletsMap().values().stream().map(Storage::getWalletFile).collect(Collectors.toList());
//TODO: Handle multiple windows
Config.get().setRecentWalletFiles(walletFiles);
boolean usbWallet = false;
for(Map.Entry<Wallet, Storage> entry : event.getWalletsMap().entrySet()) {
Wallet wallet = entry.getKey();
Storage storage = entry.getValue();
if(!storage.getWalletFile().exists() || wallet.containsSource(KeystoreSource.HW_USB)) {
usbWallet = true;
if(deviceEnumerateService == null) {
deviceEnumerateService = createDeviceEnumerateService();
}
if(deviceEnumerateService.getState() == Worker.State.CANCELLED) {
deviceEnumerateService.reset();
}
if(!deviceEnumerateService.isRunning()) {
deviceEnumerateService.start();
}
break;
}
}
if(!usbWallet && deviceEnumerateService != null && deviceEnumerateService.isRunning()) {
deviceEnumerateService.cancel();
EventManager.get().post(new UsbDeviceEvent(Collections.emptyList()));
}
}
@Subscribe
public void requestConnect(RequestConnectEvent event) {
onlineProperty.set(true);
}
@Subscribe
public void requestDisconnect(RequestDisconnectEvent event) {
onlineProperty.set(false);
}
}

View file

@ -49,7 +49,7 @@ public class MainApp extends Application {
GlyphFontRegistry.register(new FontAwesome5());
GlyphFontRegistry.register(new FontAwesome5Brands());
Font.loadFont(AppController.class.getResourceAsStream("/font/RobotoMono-Regular.ttf"), 13);
Font.loadFont(AppServices.class.getResourceAsStream("/font/RobotoMono-Regular.ttf"), 13);
boolean createNewWallet = false;
Mode mode = Config.get().getMode();
@ -68,10 +68,11 @@ public class MainApp extends Application {
}
}
AppServices.initialize(this);
FXMLLoader transactionLoader = new FXMLLoader(getClass().getResource("app.fxml"));
Parent root = transactionLoader.load();
AppController appController = transactionLoader.getController();
appController.setApplication(this);
Scene scene = new Scene(root);
scene.getStylesheets().add(getClass().getResource("app.css").toExternalForm());

View file

@ -1,7 +1,7 @@
package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.drongo.wallet.WalletNode;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.event.ReceiveActionEvent;
import com.sparrowwallet.sparrow.event.ReceiveToEvent;
@ -33,7 +33,7 @@ public class AddressTreeTable extends CoinTreeTable {
getColumns().add(addressCol);
if(address != null) {
addressCol.setMinWidth(TextUtils.computeTextWidth(AppController.getMonospaceFont(), address, 0.0));
addressCol.setMinWidth(TextUtils.computeTextWidth(AppServices.getMonospaceFont(), address, 0.0));
}
TreeTableColumn<Entry, String> labelCol = new TreeTableColumn<>("Label");

View file

@ -1,6 +1,6 @@
package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.event.UsbDeviceEvent;
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5Brands;
@ -33,8 +33,8 @@ public abstract class DeviceDialog<R> extends Dialog<R> {
this.operationFingerprints = operationFingerprints;
final DialogPane dialogPane = getDialogPane();
dialogPane.getStylesheets().add(AppController.class.getResource("general.css").toExternalForm());
AppController.setStageIcon(dialogPane.getScene().getWindow());
dialogPane.getStylesheets().add(AppServices.class.getResource("general.css").toExternalForm());
AppServices.setStageIcon(dialogPane.getScene().getWindow());
StackPane stackPane = new StackPane();
dialogPane.setContent(stackPane);
@ -67,7 +67,7 @@ public abstract class DeviceDialog<R> extends Dialog<R> {
stackPane.getChildren().addAll(anchorPane, scanBox);
List<Device> devices = AppController.getDevices();
List<Device> devices = AppServices.getDevices();
if(devices == null || devices.isEmpty()) {
scanBox.setVisible(true);
} else {

View file

@ -5,7 +5,7 @@ import com.sparrowwallet.drongo.address.Address;
import com.sparrowwallet.drongo.protocol.Transaction;
import com.sparrowwallet.drongo.protocol.TransactionOutput;
import com.sparrowwallet.drongo.wallet.*;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.event.*;
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
@ -202,11 +202,11 @@ class EntryCell extends TreeTableCell<Entry, Entry> {
}
private static Double getMaxFeeRate() {
if(AppController.getTargetBlockFeeRates().isEmpty()) {
if(AppServices.getTargetBlockFeeRates().isEmpty()) {
return 100.0;
}
return AppController.getTargetBlockFeeRates().values().iterator().next();
return AppServices.getTargetBlockFeeRates().values().iterator().next();
}
private static void sendSelectedUtxos(TreeTableView<Entry> treeTableView, HashIndexEntry hashIndexEntry) {

View file

@ -1,6 +1,6 @@
package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
public class IdLabel extends CopyableLabel {
public IdLabel() {
@ -9,6 +9,6 @@ public class IdLabel extends CopyableLabel {
public IdLabel(String text) {
super(text);
setFont(AppController.getMonospaceFont());
setFont(AppServices.getMonospaceFont());
}
}

View file

@ -1,7 +1,7 @@
package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
import javafx.application.Platform;
import javafx.scene.control.ButtonType;
@ -25,8 +25,8 @@ public class KeystorePassphraseDialog extends Dialog<String> {
final DialogPane dialogPane = getDialogPane();
setTitle("Keystore Passphrase" + (walletName != null ? " - " + walletName : ""));
dialogPane.setHeaderText("Please enter the passphrase for keystore: \n" + keystore.getLabel());
dialogPane.getStylesheets().add(AppController.class.getResource("general.css").toExternalForm());
AppController.setStageIcon(dialogPane.getScene().getWindow());
dialogPane.getStylesheets().add(AppServices.class.getResource("general.css").toExternalForm());
AppServices.setStageIcon(dialogPane.getScene().getWindow());
dialogPane.getButtonTypes().addAll(ButtonType.CANCEL, ButtonType.OK);
dialogPane.setPrefWidth(380);
dialogPane.setPrefHeight(200);

View file

@ -12,7 +12,7 @@ import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.drongo.wallet.KeystoreSource;
import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.drongo.wallet.WalletNode;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.event.OpenWalletsEvent;
import com.sparrowwallet.sparrow.event.RequestOpenWalletsEvent;
@ -37,8 +37,6 @@ import java.security.SignatureException;
import java.util.List;
import java.util.Optional;
import static com.sparrowwallet.sparrow.AppController.setStageIcon;
public class MessageSignDialog extends Dialog<ButtonBar.ButtonData> {
private static final Logger log = LoggerFactory.getLogger(MessageSignDialog.class);
@ -84,8 +82,8 @@ public class MessageSignDialog extends Dialog<ButtonBar.ButtonData> {
this.walletNode = walletNode;
final DialogPane dialogPane = getDialogPane();
dialogPane.getStylesheets().add(AppController.class.getResource("general.css").toExternalForm());
AppController.setStageIcon(dialogPane.getScene().getWindow());
dialogPane.getStylesheets().add(AppServices.class.getResource("general.css").toExternalForm());
AppServices.setStageIcon(dialogPane.getScene().getWindow());
dialogPane.setHeaderText(wallet == null ? "Verify Message" : "Sign/Verify Message");
Image image = new Image("image/seed.png", 50, 50, false, false);
@ -209,7 +207,7 @@ public class MessageSignDialog extends Dialog<ButtonBar.ButtonData> {
private void signMessage() {
if(walletNode == null) {
AppController.showErrorDialog("Address not in wallet", "The provided address is not present in the currently selected wallet.");
AppServices.showErrorDialog("Address not in wallet", "The provided address is not present in the currently selected wallet.");
return;
}
@ -234,7 +232,7 @@ public class MessageSignDialog extends Dialog<ButtonBar.ButtonData> {
signature.appendText(signatureText);
} catch(Exception e) {
log.error("Could not sign message", e);
AppController.showErrorDialog("Could not sign message", e.getMessage());
AppServices.showErrorDialog("Could not sign message", e.getMessage());
}
}
@ -272,19 +270,19 @@ public class MessageSignDialog extends Dialog<ButtonBar.ButtonData> {
if(verified) {
Alert alert = new Alert(Alert.AlertType.INFORMATION);
setStageIcon(alert.getDialogPane().getScene().getWindow());
AppServices.setStageIcon(alert.getDialogPane().getScene().getWindow());
alert.setTitle("Verification Succeeded");
alert.setHeaderText("Verification Succeeded");
alert.setContentText("The signature verified against the message.");
alert.showAndWait();
} else {
AppController.showErrorDialog("Verification failed", "The provided signature did not match the message for this address.");
AppServices.showErrorDialog("Verification failed", "The provided signature did not match the message for this address.");
}
} catch(IllegalArgumentException e) {
AppController.showErrorDialog("Could not verify message", e.getMessage());
AppServices.showErrorDialog("Could not verify message", e.getMessage());
} catch(Exception e) {
log.error("Could not verify message", e);
AppController.showErrorDialog("Could not verify message", e.getMessage());
AppServices.showErrorDialog("Could not verify message", e.getMessage());
}
}
@ -320,7 +318,7 @@ public class MessageSignDialog extends Dialog<ButtonBar.ButtonData> {
});
decryptWalletService.setOnFailed(workerStateEvent -> {
EventManager.get().post(new StorageEvent(storage.getWalletFile(), TimedEvent.Action.END, "Failed"));
AppController.showErrorDialog("Incorrect Password", decryptWalletService.getException().getMessage());
AppServices.showErrorDialog("Incorrect Password", decryptWalletService.getException().getMessage());
});
EventManager.get().post(new StorageEvent(storage.getWalletFile(), TimedEvent.Action.START, "Decrypting wallet..."));
decryptWalletService.start();

View file

@ -7,7 +7,7 @@ import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.sparrowwallet.hummingbird.LegacyUREncoder;
import com.sparrowwallet.hummingbird.registry.RegistryType;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
import com.sparrowwallet.sparrow.io.ImportException;
import com.sparrowwallet.hummingbird.UR;
@ -63,7 +63,7 @@ public class QRDisplayDialog extends Dialog<UR> {
final DialogPane dialogPane = new QRDisplayDialogPane();
setDialogPane(dialogPane);
AppController.setStageIcon(dialogPane.getScene().getWindow());
AppServices.setStageIcon(dialogPane.getScene().getWindow());
StackPane stackPane = new StackPane();
qrImageView = new ImageView();
@ -102,7 +102,7 @@ public class QRDisplayDialog extends Dialog<UR> {
this.encoder = null;
final DialogPane dialogPane = getDialogPane();
AppController.setStageIcon(dialogPane.getScene().getWindow());
AppServices.setStageIcon(dialogPane.getScene().getWindow());
StackPane stackPane = new StackPane();
qrImageView = new ImageView();

View file

@ -19,10 +19,10 @@ import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.hummingbird.LegacyURDecoder;
import com.sparrowwallet.hummingbird.registry.*;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.hummingbird.ResultType;
import com.sparrowwallet.hummingbird.UR;
import com.sparrowwallet.hummingbird.URDecoder;
import com.sparrowwallet.sparrow.AppServices;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
@ -66,7 +66,7 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
WebcamView webcamView = new WebcamView(webcamService);
final DialogPane dialogPane = getDialogPane();
AppController.setStageIcon(dialogPane.getScene().getWindow());
AppServices.setStageIcon(dialogPane.getScene().getWindow());
StackPane stackPane = new StackPane();
stackPane.getChildren().add(webcamView.getView());

View file

@ -1,7 +1,7 @@
package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
import javafx.application.Platform;
import javafx.scene.control.*;
import javafx.scene.layout.AnchorPane;
@ -10,8 +10,8 @@ import javafx.scene.layout.StackPane;
public class SeedDisplayDialog extends Dialog<Void> {
public SeedDisplayDialog(Keystore decryptedKeystore) {
final DialogPane dialogPane = getDialogPane();
dialogPane.getStylesheets().add(AppController.class.getResource("general.css").toExternalForm());
AppController.setStageIcon(dialogPane.getScene().getWindow());
dialogPane.getStylesheets().add(AppServices.class.getResource("general.css").toExternalForm());
AppServices.setStageIcon(dialogPane.getScene().getWindow());
int lines = decryptedKeystore.getSeed().getMnemonicCode().size() / 3;
int height = lines * 40;

View file

@ -1,6 +1,6 @@
package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
import javafx.application.Platform;
import javafx.beans.NamedArg;
import javafx.scene.control.*;
@ -29,8 +29,8 @@ public class TextAreaDialog extends Dialog<String> {
this.defaultValue = defaultValue;
dialogPane.setContent(hbox);
dialogPane.getStylesheets().add(AppController.class.getResource("general.css").toExternalForm());
AppController.setStageIcon(dialogPane.getScene().getWindow());
dialogPane.getStylesheets().add(AppServices.class.getResource("general.css").toExternalForm());
AppServices.setStageIcon(dialogPane.getScene().getWindow());
dialogPane.getStyleClass().add("text-input-dialog");
dialogPane.getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL);

View file

@ -1,6 +1,6 @@
package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
@ -21,7 +21,7 @@ public class TitledDescriptionPane extends TitledPane {
protected HBox buttonBox;
public TitledDescriptionPane(String title, String description, String content, String imageUrl) {
getStylesheets().add(AppController.class.getResource("general.css").toExternalForm());
getStylesheets().add(AppServices.class.getResource("general.css").toExternalForm());
getStyleClass().add("titled-description-pane");
setPadding(Insets.EMPTY);

View file

@ -7,7 +7,7 @@ import com.sparrowwallet.drongo.wallet.BlockTransactionHashIndex;
import com.sparrowwallet.drongo.wallet.Payment;
import com.sparrowwallet.drongo.wallet.WalletNode;
import com.sparrowwallet.drongo.wallet.WalletTransaction;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.event.ExcludeUtxoEvent;
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
@ -103,7 +103,7 @@ public class TransactionDiagram extends GridPane {
for(Payment payment : walletTx.getPayments()) {
try {
Address address = payment.getAddress();
BitcoinURI bitcoinURI = AppController.getPayjoinURI(address);
BitcoinURI bitcoinURI = AppServices.getPayjoinURI(address);
if(bitcoinURI != null) {
return bitcoinURI;
}

View file

@ -2,7 +2,7 @@ package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.drongo.Utils;
import com.sparrowwallet.drongo.protocol.Sha256Hash;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
@ -23,13 +23,13 @@ public class TransactionIdDialog extends Dialog<Sha256Hash> {
public TransactionIdDialog() {
this.txid = (CustomTextField) TextFields.createClearableTextField();
txid.setFont(AppController.getMonospaceFont());
txid.setFont(AppServices.getMonospaceFont());
final DialogPane dialogPane = getDialogPane();
AppController.setStageIcon(dialogPane.getScene().getWindow());
AppServices.setStageIcon(dialogPane.getScene().getWindow());
setTitle("Load Transaction");
dialogPane.setHeaderText("Enter the transaction ID:");
dialogPane.getStylesheets().add(AppController.class.getResource("general.css").toExternalForm());
dialogPane.getStylesheets().add(AppServices.class.getResource("general.css").toExternalForm());
dialogPane.getButtonTypes().addAll(ButtonType.CANCEL);
dialogPane.setPrefWidth(550);
dialogPane.setPrefHeight(200);

View file

@ -3,7 +3,7 @@ package com.sparrowwallet.sparrow.control;
import com.google.common.eventbus.Subscribe;
import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.event.WalletExportEvent;
import com.sparrowwallet.sparrow.io.*;
@ -23,7 +23,7 @@ public class WalletExportDialog extends Dialog<Wallet> {
});
final DialogPane dialogPane = getDialogPane();
AppController.setStageIcon(dialogPane.getScene().getWindow());
AppServices.setStageIcon(dialogPane.getScene().getWindow());
StackPane stackPane = new StackPane();
dialogPane.setContent(stackPane);

View file

@ -2,7 +2,7 @@ package com.sparrowwallet.sparrow.control;
import com.google.common.eventbus.Subscribe;
import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.event.WalletImportEvent;
import com.sparrowwallet.sparrow.io.*;
@ -22,7 +22,7 @@ public class WalletImportDialog extends Dialog<Wallet> {
});
final DialogPane dialogPane = getDialogPane();
AppController.setStageIcon(dialogPane.getScene().getWindow());
AppServices.setStageIcon(dialogPane.getScene().getWindow());
StackPane stackPane = new StackPane();
dialogPane.setContent(stackPane);

View file

@ -1,6 +1,6 @@
package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
import com.sparrowwallet.sparrow.io.Storage;
import javafx.application.Platform;
@ -22,11 +22,11 @@ public class WalletNameDialog extends Dialog<String> {
public WalletNameDialog() {
this.name = (CustomTextField)TextFields.createClearableTextField();
final DialogPane dialogPane = getDialogPane();
AppController.setStageIcon(dialogPane.getScene().getWindow());
AppServices.setStageIcon(dialogPane.getScene().getWindow());
setTitle("Wallet Name");
dialogPane.setHeaderText("Enter a name for this wallet:");
dialogPane.getStylesheets().add(AppController.class.getResource("general.css").toExternalForm());
dialogPane.getStylesheets().add(AppServices.class.getResource("general.css").toExternalForm());
dialogPane.getButtonTypes().addAll(ButtonType.CANCEL);
dialogPane.setPrefWidth(380);
dialogPane.setPrefHeight(200);

View file

@ -1,7 +1,7 @@
package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.drongo.SecureString;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
@ -37,8 +37,8 @@ public class WalletPasswordDialog extends Dialog<SecureString> {
final DialogPane dialogPane = getDialogPane();
setTitle("Wallet Password" + (walletName != null ? " - " + walletName : ""));
dialogPane.setHeaderText(walletName != null ? requirement.description.substring(0, requirement.description.length() - 1) + " for " + walletName + ":" : requirement.description);
dialogPane.getStylesheets().add(AppController.class.getResource("general.css").toExternalForm());
AppController.setStageIcon(dialogPane.getScene().getWindow());
dialogPane.getStylesheets().add(AppServices.class.getResource("general.css").toExternalForm());
AppServices.setStageIcon(dialogPane.getScene().getWindow());
dialogPane.getButtonTypes().addAll(ButtonType.CANCEL);
dialogPane.setPrefWidth(380);
dialogPane.setPrefHeight(260);

View file

@ -1,6 +1,6 @@
package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.Mode;
import javafx.application.HostServices;
import javafx.geometry.Insets;
@ -27,8 +27,8 @@ public class WelcomeDialog extends Dialog<Mode> {
setTitle("Welcome to Sparrow");
dialogPane.setHeaderText("Welcome to Sparrow!");
dialogPane.getStylesheets().add(AppController.class.getResource("general.css").toExternalForm());
AppController.setStageIcon(dialogPane.getScene().getWindow());
dialogPane.getStylesheets().add(AppServices.class.getResource("general.css").toExternalForm());
AppServices.setStageIcon(dialogPane.getScene().getWindow());
dialogPane.setPrefWidth(600);
dialogPane.setPrefHeight(480);

View file

@ -2,7 +2,7 @@ package com.sparrowwallet.sparrow.keystoreimport;
import com.sparrowwallet.drongo.wallet.KeystoreSource;
import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.io.Device;
import javafx.application.Platform;
import javafx.fxml.FXML;
@ -84,7 +84,7 @@ public class KeystoreImportController implements Initializable {
importPane.getChildren().removeAll(importPane.getChildren());
try {
FXMLLoader importLoader = new FXMLLoader(AppController.class.getResource("keystoreimport/" + fxmlName + ".fxml"));
FXMLLoader importLoader = new FXMLLoader(AppServices.class.getResource("keystoreimport/" + fxmlName + ".fxml"));
Node importTypeNode = importLoader.load();
KeystoreImportDetailController controller = importLoader.getController();
controller.setMasterController(this);

View file

@ -7,7 +7,7 @@ import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.drongo.wallet.KeystoreSource;
import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.drongo.wallet.WalletModel;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.event.KeystoreImportEvent;
import javafx.fxml.FXMLLoader;
@ -32,10 +32,10 @@ public class KeystoreImportDialog extends Dialog<Keystore> {
});
final DialogPane dialogPane = getDialogPane();
AppController.setStageIcon(dialogPane.getScene().getWindow());
AppServices.setStageIcon(dialogPane.getScene().getWindow());
try {
FXMLLoader ksiLoader = new FXMLLoader(AppController.class.getResource("keystoreimport/keystoreimport.fxml"));
FXMLLoader ksiLoader = new FXMLLoader(AppServices.class.getResource("keystoreimport/keystoreimport.fxml"));
dialogPane.setContent(Borders.wrap(ksiLoader.load()).emptyBorder().buildAll());
keystoreImportController = ksiLoader.getController();
keystoreImportController.initializeView(wallet);

View file

@ -7,7 +7,7 @@ import com.sparrowwallet.drongo.Utils;
import com.sparrowwallet.drongo.protocol.Sha256Hash;
import com.sparrowwallet.drongo.protocol.Transaction;
import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.event.WalletHistoryStatusEvent;
import org.slf4j.Logger;
@ -209,7 +209,7 @@ public class SimpleElectrumServerRpc implements ElectrumServerRpc {
VerboseTransaction verboseTransaction = new VerboseTransaction();
verboseTransaction.txid = id;
verboseTransaction.hex = rawTxHex;
verboseTransaction.confirmations = (height <= 0 ? 0 : AppController.getCurrentBlockHeight() - height + 1);
verboseTransaction.confirmations = (height <= 0 ? 0 : AppServices.getCurrentBlockHeight() - height + 1);
verboseTransaction.blockhash = Sha256Hash.ZERO_HASH.toString();
result.put(txid, verboseTransaction);
} catch(Exception ex) {

View file

@ -5,7 +5,7 @@ import com.sparrowwallet.drongo.Utils;
import com.sparrowwallet.drongo.protocol.Sha256Hash;
import com.sparrowwallet.drongo.protocol.Transaction;
import com.sparrowwallet.drongo.wallet.BlockTransaction;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
import java.util.Date;
@ -26,7 +26,7 @@ class VerboseTransaction {
return 0;
}
Integer currentHeight = AppController.getCurrentBlockHeight();
Integer currentHeight = AppServices.getCurrentBlockHeight();
if(currentHeight != null) {
return currentHeight - confirmations + 1;
}

View file

@ -1,10 +1,7 @@
package com.sparrowwallet.sparrow.preferences;
import com.sparrowwallet.drongo.wallet.KeystoreSource;
import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.io.Config;
import com.sparrowwallet.sparrow.keystoreimport.KeystoreImportDetailController;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
@ -63,7 +60,7 @@ public class PreferencesController implements Initializable {
preferencesPane.getChildren().removeAll(preferencesPane.getChildren());
try {
FXMLLoader preferencesDetailLoader = new FXMLLoader(AppController.class.getResource("preferences/" + fxmlName + ".fxml"));
FXMLLoader preferencesDetailLoader = new FXMLLoader(AppServices.class.getResource("preferences/" + fxmlName + ".fxml"));
Node preferenceGroupNode = preferencesDetailLoader.load();
PreferencesDetailController controller = preferencesDetailLoader.getController();
controller.setMasterController(this);

View file

@ -1,6 +1,6 @@
package com.sparrowwallet.sparrow.preferences;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.event.RequestConnectEvent;
import com.sparrowwallet.sparrow.io.Config;
@ -27,10 +27,10 @@ public class PreferencesDialog extends Dialog<Boolean> {
public PreferencesDialog(PreferenceGroup initialGroup, boolean initialSetup) {
final DialogPane dialogPane = getDialogPane();
AppController.setStageIcon(dialogPane.getScene().getWindow());
AppServices.setStageIcon(dialogPane.getScene().getWindow());
try {
FXMLLoader preferencesLoader = new FXMLLoader(AppController.class.getResource("preferences/preferences.fxml"));
FXMLLoader preferencesLoader = new FXMLLoader(AppServices.class.getResource("preferences/preferences.fxml"));
dialogPane.setContent(Borders.wrap(preferencesLoader.load()).emptyBorder().buildAll());
PreferencesController preferencesController = preferencesLoader.getController();
preferencesController.initializeView(Config.get());

View file

@ -11,7 +11,7 @@ import com.sparrowwallet.drongo.uri.BitcoinURI;
import com.sparrowwallet.drongo.wallet.*;
import com.sparrowwallet.hummingbird.UR;
import com.sparrowwallet.hummingbird.registry.RegistryType;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.control.*;
import com.sparrowwallet.sparrow.event.*;
@ -252,8 +252,8 @@ public class HeadersController extends TransactionFormController implements Init
locktimeFieldset.getChildren().add(locktimeBlockField);
Integer block = locktimeBlock.getValue();
if(block != null) {
locktimeCurrentHeight.setVisible(headersForm.isEditable() && AppController.getCurrentBlockHeight() != null && block < AppController.getCurrentBlockHeight());
futureBlockWarning.setVisible(AppController.getCurrentBlockHeight() != null && block > AppController.getCurrentBlockHeight());
locktimeCurrentHeight.setVisible(headersForm.isEditable() && AppServices.getCurrentBlockHeight() != null && block < AppServices.getCurrentBlockHeight());
futureBlockWarning.setVisible(AppServices.getCurrentBlockHeight() != null && block > AppServices.getCurrentBlockHeight());
tx.setLocktime(block);
if(old_toggle != null) {
EventManager.get().post(new TransactionChangedEvent(tx));
@ -303,8 +303,8 @@ public class HeadersController extends TransactionFormController implements Init
locktimeBlock.valueProperty().addListener((obs, oldValue, newValue) -> {
tx.setLocktime(newValue);
locktimeCurrentHeight.setVisible(headersForm.isEditable() && AppController.getCurrentBlockHeight() != null && newValue < AppController.getCurrentBlockHeight());
futureBlockWarning.setVisible(AppController.getCurrentBlockHeight() != null && newValue > AppController.getCurrentBlockHeight());
locktimeCurrentHeight.setVisible(headersForm.isEditable() && AppServices.getCurrentBlockHeight() != null && newValue < AppServices.getCurrentBlockHeight());
futureBlockWarning.setVisible(AppServices.getCurrentBlockHeight() != null && newValue > AppServices.getCurrentBlockHeight());
if(oldValue != null) {
EventManager.get().post(new TransactionChangedEvent(tx));
EventManager.get().post(new TransactionLocktimeChangedEvent(tx));
@ -360,7 +360,7 @@ public class HeadersController extends TransactionFormController implements Init
broadcastButton.managedProperty().bind(broadcastButton.visibleProperty());
saveFinalButton.managedProperty().bind(saveFinalButton.visibleProperty());
saveFinalButton.visibleProperty().bind(broadcastButton.visibleProperty().not());
broadcastButton.visibleProperty().bind(AppController.onlineProperty());
broadcastButton.visibleProperty().bind(AppServices.onlineProperty());
BitcoinURI payjoinURI = getPayjoinURI();
boolean isPayjoinOriginalTx = payjoinURI != null && headersForm.getPsbt() != null && headersForm.getPsbt().getPsbtInputs().stream().noneMatch(PSBTInput::isFinalized);
@ -377,7 +377,7 @@ public class HeadersController extends TransactionFormController implements Init
broadcastButtonBox.setVisible(false);
if(headersForm.getBlockTransaction() != null) {
updateBlockchainForm(headersForm.getBlockTransaction(), AppController.getCurrentBlockHeight());
updateBlockchainForm(headersForm.getBlockTransaction(), AppServices.getCurrentBlockHeight());
} else if(headersForm.getPsbt() != null) {
PSBT psbt = headersForm.getPsbt();
@ -558,7 +558,7 @@ public class HeadersController extends TransactionFormController implements Init
for(TransactionOutput txOutput : headersForm.getPsbt().getTransaction().getOutputs()) {
try {
Address address = txOutput.getScript().getToAddresses()[0];
BitcoinURI bitcoinURI = AppController.getPayjoinURI(address);
BitcoinURI bitcoinURI = AppServices.getPayjoinURI(address);
if(bitcoinURI != null) {
return bitcoinURI;
}
@ -602,8 +602,8 @@ public class HeadersController extends TransactionFormController implements Init
}
public void setLocktimeToCurrentHeight(ActionEvent event) {
if(AppController.getCurrentBlockHeight() != null && locktimeBlock.isEditable()) {
locktimeBlock.getValueFactory().setValue(AppController.getCurrentBlockHeight());
if(AppServices.getCurrentBlockHeight() != null && locktimeBlock.isEditable()) {
locktimeBlock.getValueFactory().setValue(AppServices.getCurrentBlockHeight());
Platform.runLater(() -> locktimeBlockType.requestFocus());
}
}
@ -659,7 +659,7 @@ public class HeadersController extends TransactionFormController implements Init
}
} catch(IOException e) {
log.error("Error saving PSBT", e);
AppController.showErrorDialog("Error saving PSBT", "Cannot write to " + file.getAbsolutePath());
AppServices.showErrorDialog("Error saving PSBT", "Cannot write to " + file.getAbsolutePath());
}
}
}
@ -700,7 +700,7 @@ public class HeadersController extends TransactionFormController implements Init
});
decryptWalletService.setOnFailed(workerStateEvent -> {
EventManager.get().post(new StorageEvent(file, TimedEvent.Action.END, "Failed"));
AppController.showErrorDialog("Incorrect Password", decryptWalletService.getException().getMessage());
AppServices.showErrorDialog("Incorrect Password", decryptWalletService.getException().getMessage());
});
EventManager.get().post(new StorageEvent(file, TimedEvent.Action.START, "Decrypting wallet..."));
decryptWalletService.start();
@ -716,7 +716,7 @@ public class HeadersController extends TransactionFormController implements Init
updateSignedKeystores(headersForm.getSigningWallet());
} catch(Exception e) {
log.warn("Failed to Sign", e);
AppController.showErrorDialog("Failed to Sign", e.getMessage());
AppServices.showErrorDialog("Failed to Sign", e.getMessage());
}
}
@ -726,7 +726,7 @@ public class HeadersController extends TransactionFormController implements Init
}
List<String> fingerprints = headersForm.getSigningWallet().getKeystores().stream().map(keystore -> keystore.getKeyDerivation().getMasterFingerprint()).collect(Collectors.toList());
List<Device> signingDevices = AppController.getDevices().stream().filter(device -> fingerprints.contains(device.getFingerprint())).collect(Collectors.toList());
List<Device> signingDevices = AppServices.getDevices().stream().filter(device -> fingerprints.contains(device.getFingerprint())).collect(Collectors.toList());
if(signingDevices.isEmpty() && headersForm.getSigningWallet().getKeystores().stream().noneMatch(keystore -> keystore.getSource().equals(KeystoreSource.HW_USB))) {
return;
}
@ -788,7 +788,7 @@ public class HeadersController extends TransactionFormController implements Init
broadcastTransactionService.setOnFailed(workerStateEvent -> {
broadcastProgressBar.setProgress(0);
log.error("Error broadcasting transaction", workerStateEvent.getSource().getException());
AppController.showErrorDialog("Error broadcasting transaction", "The server returned an error when broadcasting the transaction. The server response is contained in sparrow.log");
AppServices.showErrorDialog("Error broadcasting transaction", "The server returned an error when broadcasting the transaction. The server response is contained in sparrow.log");
broadcastButton.setDisable(false);
});
@ -816,7 +816,7 @@ public class HeadersController extends TransactionFormController implements Init
}
} catch(IOException e) {
log.error("Error saving transaction", e);
AppController.showErrorDialog("Error saving transaction", "Cannot write to " + file.getAbsolutePath());
AppServices.showErrorDialog("Error saving transaction", "Cannot write to " + file.getAbsolutePath());
}
}
}
@ -832,7 +832,7 @@ public class HeadersController extends TransactionFormController implements Init
PSBT proposalPsbt = payjoin.requestPayjoinPSBT(true);
EventManager.get().post(new ViewPSBTEvent(headersForm.getName() + " Payjoin", proposalPsbt));
} catch(PayjoinReceiverException e) {
AppController.showErrorDialog("Invalid Payjoin Transaction", e.getMessage());
AppServices.showErrorDialog("Invalid Payjoin Transaction", e.getMessage());
}
}
@ -844,8 +844,8 @@ public class HeadersController extends TransactionFormController implements Init
blockTransaction = headersForm.getSigningWallet().getTransactions().get(txId);
}
if(blockTransaction != null && AppController.getCurrentBlockHeight() != null) {
updateBlockchainForm(blockTransaction, AppController.getCurrentBlockHeight());
if(blockTransaction != null && AppServices.getCurrentBlockHeight() != null) {
updateBlockchainForm(blockTransaction, AppServices.getCurrentBlockHeight());
}
}
@ -867,7 +867,7 @@ public class HeadersController extends TransactionFormController implements Init
public void blockTransactionFetched(BlockTransactionFetchedEvent event) {
if(event.getTxId().equals(headersForm.getTransaction().getTxId())) {
if(event.getBlockTransaction() != null && (!Sha256Hash.ZERO_HASH.equals(event.getBlockTransaction().getBlockHash()) || headersForm.getBlockTransaction() == null)) {
updateBlockchainForm(event.getBlockTransaction(), AppController.getCurrentBlockHeight());
updateBlockchainForm(event.getBlockTransaction(), AppServices.getCurrentBlockHeight());
}
Long feeAmt = calculateFee(event.getInputTransactions());
@ -1021,7 +1021,7 @@ public class HeadersController extends TransactionFormController implements Init
BlockTransaction blockTransaction = transactionMap.get(txid);
if(blockTransaction != null) {
headersForm.setBlockTransaction(blockTransaction);
updateBlockchainForm(blockTransaction, AppController.getCurrentBlockHeight());
updateBlockchainForm(blockTransaction, AppServices.getCurrentBlockHeight());
}
});
transactionReferenceService.setOnFailed(failEvent -> {
@ -1064,7 +1064,7 @@ public class HeadersController extends TransactionFormController implements Init
updateBlockchainForm(headersForm.getBlockTransaction(), event.getHeight());
}
if(futureBlockWarning.isVisible()) {
futureBlockWarning.setVisible(AppController.getCurrentBlockHeight() != null && locktimeBlock.getValue() > event.getHeight());
futureBlockWarning.setVisible(AppServices.getCurrentBlockHeight() != null && locktimeBlock.getValue() > event.getHeight());
}
}

View file

@ -6,7 +6,7 @@ import com.sparrowwallet.drongo.psbt.PSBT;
import com.sparrowwallet.drongo.psbt.PSBTInput;
import com.sparrowwallet.drongo.psbt.PSBTOutput;
import com.sparrowwallet.drongo.wallet.BlockTransaction;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.TransactionTabData;
import com.sparrowwallet.sparrow.control.TransactionDiagram;
@ -326,7 +326,7 @@ public class TransactionController implements Initializable {
}
private void fetchThisAndInputBlockTransactions(int indexStart, int indexEnd) {
if(AppController.isOnline() && indexStart < getTransaction().getInputs().size()) {
if(AppServices.isOnline() && indexStart < getTransaction().getInputs().size()) {
Set<Sha256Hash> references = new HashSet<>();
if(getPSBT() == null) {
references.add(getTransaction().getTxId());
@ -378,7 +378,7 @@ public class TransactionController implements Initializable {
}
private void fetchOutputBlockTransactions(int indexStart, int indexEnd) {
if(AppController.isOnline() && getPSBT() == null && indexStart < getTransaction().getOutputs().size()) {
if(AppServices.isOnline() && getPSBT() == null && indexStart < getTransaction().getOutputs().size()) {
int maxIndex = Math.min(getTransaction().getOutputs().size(), indexEnd);
ElectrumServer.TransactionOutputsReferenceService transactionOutputsReferenceService = new ElectrumServer.TransactionOutputsReferenceService(getTransaction(), indexStart, maxIndex);
transactionOutputsReferenceService.setOnSucceeded(successEvent -> {

View file

@ -1,7 +1,7 @@
package com.sparrowwallet.sparrow.wallet;
import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.ButtonBar;
import javafx.scene.control.ButtonType;
@ -14,10 +14,10 @@ import java.io.IOException;
public class AdvancedDialog extends Dialog<Void> {
public AdvancedDialog(Wallet wallet) {
final DialogPane dialogPane = getDialogPane();
AppController.setStageIcon(dialogPane.getScene().getWindow());
AppServices.setStageIcon(dialogPane.getScene().getWindow());
try {
FXMLLoader advancedLoader = new FXMLLoader(AppController.class.getResource("wallet/advanced.fxml"));
FXMLLoader advancedLoader = new FXMLLoader(AppServices.class.getResource("wallet/advanced.fxml"));
dialogPane.setContent(Borders.wrap(advancedLoader.load()).emptyBorder().buildAll());
AdvancedController settingsAdvancedController = advancedLoader.getController();
settingsAdvancedController.initializeView(wallet);

View file

@ -5,7 +5,7 @@ import com.sparrowwallet.drongo.*;
import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.drongo.wallet.KeystoreSource;
import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.control.QRDisplayDialog;
import com.sparrowwallet.sparrow.control.QRScanDialog;
@ -340,7 +340,7 @@ public class KeystoreController extends WalletFormController implements Initiali
});
decryptWalletService.setOnFailed(workerStateEvent -> {
EventManager.get().post(new StorageEvent(getWalletForm().getWalletFile(), TimedEvent.Action.END, "Failed"));
AppController.showErrorDialog("Incorrect Password", decryptWalletService.getException().getMessage());
AppServices.showErrorDialog("Incorrect Password", decryptWalletService.getException().getMessage());
});
EventManager.get().post(new StorageEvent(getWalletForm().getWalletFile(), TimedEvent.Action.START, "Decrypting wallet..."));
decryptWalletService.start();
@ -364,9 +364,9 @@ public class KeystoreController extends WalletFormController implements Initiali
xpub.setText(result.extendedKey.getExtendedKey());
} else if(result.exception != null) {
log.error("Error scanning QR", result.exception);
AppController.showErrorDialog("Error scanning QR", result.exception.getMessage());
AppServices.showErrorDialog("Error scanning QR", result.exception.getMessage());
} else {
AppController.showErrorDialog("Invalid QR Code", "QR Code did not contain a valid " + Network.get().getXpubHeader().getDisplayName());
AppServices.showErrorDialog("Invalid QR Code", "QR Code did not contain a valid " + Network.get().getXpubHeader().getDisplayName());
}
}
}

View file

@ -11,7 +11,7 @@ import com.sparrowwallet.drongo.uri.BitcoinURI;
import com.sparrowwallet.drongo.wallet.MaxUtxoSelector;
import com.sparrowwallet.drongo.wallet.Payment;
import com.sparrowwallet.drongo.wallet.UtxoSelector;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.CurrencyRate;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.control.CoinTextFormatter;
@ -74,7 +74,7 @@ public class PaymentController extends WalletFormController implements Initializ
Long recipientValueSats = getRecipientValueSats();
if(recipientValueSats != null) {
setFiatAmount(AppController.getFiatCurrencyExchangeRate(), recipientValueSats);
setFiatAmount(AppServices.getFiatCurrencyExchangeRate(), recipientValueSats);
} else {
fiatAmount.setText("");
}
@ -260,7 +260,7 @@ public class PaymentController extends WalletFormController implements Initializ
label.setText(payment.getLabel());
}
setRecipientValueSats(payment.getAmount());
setFiatAmount(AppController.getFiatCurrencyExchangeRate(), payment.getAmount());
setFiatAmount(AppServices.getFiatCurrencyExchangeRate(), payment.getAmount());
}
}
@ -320,7 +320,7 @@ public class PaymentController extends WalletFormController implements Initializ
setRecipientValueSats(bitcoinURI.getAmount());
}
if(bitcoinURI.getPayjoinUrl() != null) {
AppController.addPayjoinURI(bitcoinURI);
AppServices.addPayjoinURI(bitcoinURI);
}
sendController.updateTransaction();
}

View file

@ -14,7 +14,7 @@ import com.sparrowwallet.drongo.wallet.BlockTransactionHashIndex;
import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.drongo.wallet.KeystoreSource;
import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.control.*;
import com.sparrowwallet.sparrow.event.ReceiveToEvent;
@ -116,7 +116,7 @@ public class ReceiveController extends WalletFormController implements Initializ
outputDescriptor.clear();
outputDescriptor.append(nodeEntry.getOutputDescriptor(), "descriptor-text");
updateDisplayAddress(AppController.getDevices());
updateDisplayAddress(AppServices.getDevices());
}
private void updateDerivationPath(NodeEntry nodeEntry) {
@ -138,7 +138,7 @@ public class ReceiveController extends WalletFormController implements Initializ
private void updateLastUsed() {
Set<BlockTransactionHashIndex> currentOutputs = currentEntry.getNode().getTransactionOutputs();
if(AppController.isOnline() && currentOutputs.isEmpty()) {
if(AppServices.isOnline() && currentOutputs.isEmpty()) {
lastUsed.setText("Never");
lastUsed.setGraphic(getUnusedGlyph());
} else if(!currentOutputs.isEmpty()) {

View file

@ -6,7 +6,7 @@ import com.sparrowwallet.drongo.address.InvalidAddressException;
import com.sparrowwallet.drongo.protocol.Transaction;
import com.sparrowwallet.drongo.psbt.PSBT;
import com.sparrowwallet.drongo.wallet.*;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.CurrencyRate;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.control.*;
@ -128,7 +128,7 @@ public class SendController extends WalletFormController implements Initializabl
if(newValue.isEmpty()) {
fiatFeeAmount.setText("");
} else {
setFiatFeeAmount(AppController.getFiatCurrencyExchangeRate(), getFeeValueSats());
setFiatFeeAmount(AppServices.getFiatCurrencyExchangeRate(), getFeeValueSats());
}
setTargetBlocks(getTargetBlocks());
@ -390,7 +390,7 @@ public class SendController extends WalletFormController implements Initializabl
Tab tab = new Tab(Integer.toString(highestTabNo.isPresent() ? highestTabNo.getAsInt() + 1 : 1));
try {
FXMLLoader paymentLoader = new FXMLLoader(AppController.class.getResource("wallet/payment.fxml"));
FXMLLoader paymentLoader = new FXMLLoader(AppServices.class.getResource("wallet/payment.fxml"));
tab.setContent(paymentLoader.load());
PaymentController controller = paymentLoader.getController();
controller.setSendController(this);
@ -451,7 +451,7 @@ public class SendController extends WalletFormController implements Initializabl
if(!userFeeSet.get() || (getFeeValueSats() != null && getFeeValueSats() > 0)) {
Wallet wallet = getWalletForm().getWallet();
Long userFee = userFeeSet.get() ? getFeeValueSats() : null;
Integer currentBlockHeight = AppController.getCurrentBlockHeight();
Integer currentBlockHeight = AppServices.getCurrentBlockHeight();
boolean groupByAddress = Config.get().isGroupByAddress();
boolean includeMempoolChange = Config.get().isIncludeMempoolChange();
boolean includeMempoolInputs = includeMempoolInputsProperty.get();
@ -532,7 +532,7 @@ public class SendController extends WalletFormController implements Initializabl
df.setMaximumFractionDigits(8);
fee.setText(df.format(feeAmountUnit.getValue().getValue(feeValue)));
fee.textProperty().addListener(feeListener);
setFiatFeeAmount(AppController.getFiatCurrencyExchangeRate(), feeValue);
setFiatFeeAmount(AppServices.getFiatCurrencyExchangeRate(), feeValue);
}
private Integer getTargetBlocks() {
@ -565,7 +565,7 @@ public class SendController extends WalletFormController implements Initializabl
}
private Map<Integer, Double> getTargetBlocksFeeRates() {
Map<Integer, Double> retrievedFeeRates = AppController.getTargetBlockFeeRates();
Map<Integer, Double> retrievedFeeRates = AppServices.getTargetBlockFeeRates();
if(retrievedFeeRates == null) {
retrievedFeeRates = TARGET_BLOCKS_RANGE.stream().collect(Collectors.toMap(java.util.function.Function.identity(), v -> FALLBACK_FEE_RATE,
(u, v) -> { throw new IllegalStateException("Duplicate target blocks"); },
@ -600,11 +600,11 @@ public class SendController extends WalletFormController implements Initializabl
}
private Map<Date, Set<MempoolRateSize>> getMempoolHistogram() {
return AppController.getMempoolHistogram();
return AppServices.getMempoolHistogram();
}
public boolean isInsufficientFeeRate() {
return walletTransactionProperty.get() != null && walletTransactionProperty.get().getFeeRate() < AppController.getMinimumRelayFeeRate();
return walletTransactionProperty.get() != null && walletTransactionProperty.get().getFeeRate() < AppServices.getMinimumRelayFeeRate();
}
private void setFeeRate(Double feeRateAmt) {

View file

@ -11,7 +11,7 @@ import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.drongo.wallet.KeystoreSource;
import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.drongo.wallet.WalletModel;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.control.*;
import com.sparrowwallet.sparrow.event.RequestOpenWalletsEvent;
@ -223,7 +223,7 @@ public class SettingsController extends WalletFormController implements Initiali
tab.setClosable(false);
try {
FXMLLoader keystoreLoader = new FXMLLoader(AppController.class.getResource("wallet/keystore.fxml"));
FXMLLoader keystoreLoader = new FXMLLoader(AppServices.class.getResource("wallet/keystore.fxml"));
tab.setContent(keystoreLoader.load());
KeystoreController controller = keystoreLoader.getController();
controller.setKeystore(getWalletForm(), keystore);
@ -258,7 +258,7 @@ public class SettingsController extends WalletFormController implements Initiali
} else if(result.payload != null && !result.payload.isEmpty()) {
setDescriptorText(result.payload);
} else if(result.exception != null) {
AppController.showErrorDialog("Error scanning QR", result.exception.getMessage());
AppServices.showErrorDialog("Error scanning QR", result.exception.getMessage());
}
}
}
@ -291,7 +291,7 @@ public class SettingsController extends WalletFormController implements Initiali
EventManager.get().post(new SettingsChangedEvent(editedWallet, SettingsChangedEvent.Type.POLICY));
} catch(Exception e) {
AppController.showErrorDialog("Invalid output descriptor", e.getMessage());
AppServices.showErrorDialog("Invalid output descriptor", e.getMessage());
}
}
@ -353,7 +353,7 @@ public class SettingsController extends WalletFormController implements Initiali
walletForm.saveBackup();
} catch(IOException e) {
log.error("Error saving wallet backup", e);
AppController.showErrorDialog("Error saving wallet backup", e.getMessage());
AppServices.showErrorDialog("Error saving wallet backup", e.getMessage());
revert.setDisable(false);
apply.setDisable(false);
return;
@ -369,7 +369,7 @@ public class SettingsController extends WalletFormController implements Initiali
}
} catch (IOException e) {
log.error("Error saving wallet", e);
AppController.showErrorDialog("Error saving wallet", e.getMessage());
AppServices.showErrorDialog("Error saving wallet", e.getMessage());
revert.setDisable(false);
apply.setDisable(false);
}
@ -384,7 +384,7 @@ public class SettingsController extends WalletFormController implements Initiali
ECKey encryptionPubKey = ECKey.fromPublicOnly(encryptionFullKey);
if(existingPubKey != null && !Storage.NO_PASSWORD_KEY.equals(existingPubKey) && !existingPubKey.equals(encryptionPubKey)) {
AppController.showErrorDialog("Incorrect Password", "The password was incorrect.");
AppServices.showErrorDialog("Incorrect Password", "The password was incorrect.");
revert.setDisable(false);
apply.setDisable(false);
return;
@ -406,7 +406,7 @@ public class SettingsController extends WalletFormController implements Initiali
}
} catch (Exception e) {
log.error("Error saving wallet", e);
AppController.showErrorDialog("Error saving wallet", e.getMessage());
AppServices.showErrorDialog("Error saving wallet", e.getMessage());
revert.setDisable(false);
apply.setDisable(false);
} finally {
@ -418,7 +418,7 @@ public class SettingsController extends WalletFormController implements Initiali
});
keyDerivationService.setOnFailed(workerStateEvent -> {
EventManager.get().post(new StorageEvent(walletForm.getWalletFile(), TimedEvent.Action.END, "Failed"));
AppController.showErrorDialog("Error saving wallet", keyDerivationService.getException().getMessage());
AppServices.showErrorDialog("Error saving wallet", keyDerivationService.getException().getMessage());
revert.setDisable(false);
apply.setDisable(false);
});

View file

@ -1,7 +1,7 @@
package com.sparrowwallet.sparrow.wallet;
import com.google.common.eventbus.Subscribe;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.CurrencyRate;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.control.BalanceChart;
@ -47,7 +47,7 @@ public class TransactionsController extends WalletFormController implements Init
transactionsTable.initialize(walletTransactionsEntry);
balance.valueProperty().addListener((observable, oldValue, newValue) -> {
setFiatBalance(AppController.getFiatCurrencyExchangeRate(), newValue.longValue());
setFiatBalance(AppServices.getFiatCurrencyExchangeRate(), newValue.longValue());
});
balance.setValue(walletTransactionsEntry.getBalance());
mempoolBalance.setValue(walletTransactionsEntry.getMempoolBalance());

View file

@ -1,7 +1,7 @@
package com.sparrowwallet.sparrow.wallet;
import com.google.common.eventbus.Subscribe;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.event.ReceiveActionEvent;
import com.sparrowwallet.sparrow.event.SendActionEvent;
@ -57,7 +57,7 @@ public class WalletController extends WalletFormController implements Initializa
try {
if(!existing) {
FXMLLoader functionLoader = new FXMLLoader(AppController.class.getResource("wallet/" + function.toString().toLowerCase() + ".fxml"));
FXMLLoader functionLoader = new FXMLLoader(AppServices.class.getResource("wallet/" + function.toString().toLowerCase() + ".fxml"));
Node walletFunction = functionLoader.load();
walletFunction.setUserData(function);
WalletFormController controller = functionLoader.getController();

View file

@ -4,7 +4,7 @@ import com.google.common.eventbus.Subscribe;
import com.sparrowwallet.drongo.KeyPurpose;
import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.drongo.wallet.WalletNode;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.WalletTabData;
import com.sparrowwallet.sparrow.event.*;
@ -32,7 +32,7 @@ public class WalletForm {
public WalletForm(Storage storage, Wallet currentWallet) {
this.storage = storage;
this.wallet = currentWallet;
refreshHistory(AppController.getCurrentBlockHeight());
refreshHistory(AppServices.getCurrentBlockHeight());
}
public Wallet getWallet() {
@ -62,7 +62,7 @@ public class WalletForm {
public void saveAndRefresh() throws IOException {
wallet.clearHistory();
save();
refreshHistory(AppController.getCurrentBlockHeight());
refreshHistory(AppServices.getCurrentBlockHeight());
}
public void saveBackup() throws IOException {
@ -75,7 +75,7 @@ public class WalletForm {
public void refreshHistory(Integer blockHeight, WalletNode node) {
Wallet previousWallet = wallet.copy();
if(wallet.isValid() && AppController.isOnline()) {
if(wallet.isValid() && AppServices.isOnline()) {
log.debug(node == null ? "Refreshing full wallet history" : "Requesting node wallet history for " + node.getDerivationPath());
ElectrumServer.TransactionHistoryService historyService = new ElectrumServer.TransactionHistoryService(wallet, getWalletTransactionNodes(node));
historyService.setOnSucceeded(workerStateEvent -> {
@ -226,7 +226,7 @@ public class WalletForm {
walletUtxosEntry = null;
accountEntries.clear();
EventManager.get().post(new WalletNodesChangedEvent(wallet));
refreshHistory(AppController.getCurrentBlockHeight());
refreshHistory(AppServices.getCurrentBlockHeight());
}
}
@ -249,7 +249,7 @@ public class WalletForm {
WalletNode walletNode = event.getWalletNode(wallet);
if(walletNode != null) {
log.debug(wallet.getName() + " history event for node " + walletNode);
refreshHistory(AppController.getCurrentBlockHeight(), walletNode);
refreshHistory(AppServices.getCurrentBlockHeight(), walletNode);
}
}
}