From 85725a18a62e081a4b893d82daf03814c98c3d3f Mon Sep 17 00:00:00 2001 From: Sean Gilligan Date: Wed, 22 Sep 2021 14:02:42 -0700 Subject: [PATCH] walletfx: WalletApplication to improve encapsulation * Make all public fields private and wrap with accessors * Make `WalletAppKit` (was confusingly named `bitcoin`) field a member not a static * Rename `bitcoin` to `walletAppKit` --- .../application/WalletApplication.java | 52 +++++++++++++------ .../java/wallettemplate/MainController.java | 10 ++-- .../wallettemplate/SendMoneyController.java | 14 ++--- .../WalletPasswordController.java | 10 ++-- .../WalletSetPasswordController.java | 4 +- .../WalletSettingsController.java | 18 ++++--- 6 files changed, 68 insertions(+), 40 deletions(-) diff --git a/wallettemplate/src/main/java/org/bitcoinj/walletfx/application/WalletApplication.java b/wallettemplate/src/main/java/org/bitcoinj/walletfx/application/WalletApplication.java index a9923a838..e1d57783a 100644 --- a/wallettemplate/src/main/java/org/bitcoinj/walletfx/application/WalletApplication.java +++ b/wallettemplate/src/main/java/org/bitcoinj/walletfx/application/WalletApplication.java @@ -42,12 +42,12 @@ import static org.bitcoinj.walletfx.utils.GuiUtils.informationalAlert; * Base class for JavaFX Wallet Applications */ public abstract class WalletApplication implements AppDelegate { - public static WalletAppKit bitcoin; - public static WalletApplication instance; - public final String applicationName; - public final NetworkParameters params; - public final Script.ScriptType preferredOutputScriptType; - protected final String walletFileName; + private static WalletApplication instance; + private WalletAppKit walletAppKit; + private final String applicationName; + private final NetworkParameters params; + private final Script.ScriptType preferredOutputScriptType; + private final String walletFileName; private MainWindowController controller; public WalletApplication(String applicationName, NetworkParameters params, Script.ScriptType preferredOutputScriptType) { @@ -58,6 +58,26 @@ public abstract class WalletApplication implements AppDelegate { this.preferredOutputScriptType = preferredOutputScriptType; } + public static WalletApplication instance() { + return instance; + } + + public WalletAppKit walletAppKit() { + return walletAppKit; + } + + public String applicationName() { + return applicationName; + } + + public NetworkParameters params() { + return params; + } + + public Script.ScriptType preferredOutputScriptType() { + return preferredOutputScriptType; + } + @Override public void start(Stage mainWindow) throws Exception { try { @@ -93,7 +113,7 @@ public abstract class WalletApplication implements AppDelegate { // Create the app kit. It won't do any heavyweight initialization until after we start it. setupWalletKit(null); - if (bitcoin.isChainFileLocked()) { + if (walletAppKit.isChainFileLocked()) { informationalAlert("Already running", "This application is already running and cannot be started twice."); Platform.exit(); return; @@ -103,21 +123,21 @@ public abstract class WalletApplication implements AppDelegate { WalletSetPasswordController.estimateKeyDerivationTimeMsec(); - bitcoin.addListener(new Service.Listener() { + walletAppKit.addListener(new Service.Listener() { @Override public void failed(Service.State from, Throwable failure) { GuiUtils.crashAlert(failure); } }, Platform::runLater); - bitcoin.startAsync(); + walletAppKit.startAsync(); - controller.scene().getAccelerators().put(KeyCombination.valueOf("Shortcut+F"), () -> bitcoin.peerGroup().getDownloadPeer().close()); + controller.scene().getAccelerators().put(KeyCombination.valueOf("Shortcut+F"), () -> walletAppKit().peerGroup().getDownloadPeer().close()); } public void setupWalletKit(@Nullable DeterministicSeed seed) { // If seed is non-null it means we are restoring from backup. File appDataDirectory = AppDataDirectory.get(applicationName).toFile(); - bitcoin = new WalletAppKit(params, preferredOutputScriptType, null, appDataDirectory, walletFileName) { + walletAppKit = new WalletAppKit(params, preferredOutputScriptType, null, appDataDirectory, walletFileName) { @Override protected void onSetupCompleted() { Platform.runLater(controller::onBitcoinSetup); @@ -126,19 +146,19 @@ public abstract class WalletApplication implements AppDelegate { // Now configure and start the appkit. This will take a second or two - we could show a temporary splash screen // or progress widget to keep the user engaged whilst we initialise, but we don't. if (params == RegTestParams.get()) { - bitcoin.connectToLocalHost(); // You should run a regtest mode bitcoind locally. + walletAppKit.connectToLocalHost(); // You should run a regtest mode bitcoind locally. } - bitcoin.setDownloadListener(controller.progressBarUpdater()) + walletAppKit.setDownloadListener(controller.progressBarUpdater()) .setBlockingStartup(false) .setUserAgent(applicationName, "1.0"); if (seed != null) - bitcoin.restoreWalletFromSeed(seed); + walletAppKit.restoreWalletFromSeed(seed); } @Override public void stop() throws Exception { - bitcoin.stopAsync(); - bitcoin.awaitTerminated(); + walletAppKit.stopAsync(); + walletAppKit.awaitTerminated(); // Forcibly terminate the JVM because Orchid likes to spew non-daemon threads everywhere. Runtime.getRuntime().exit(0); } diff --git a/wallettemplate/src/main/java/wallettemplate/MainController.java b/wallettemplate/src/main/java/wallettemplate/MainController.java index b4fb10beb..713cea1bf 100644 --- a/wallettemplate/src/main/java/wallettemplate/MainController.java +++ b/wallettemplate/src/main/java/wallettemplate/MainController.java @@ -43,8 +43,6 @@ import org.bitcoinj.walletfx.utils.BitcoinUIModel; import org.bitcoinj.walletfx.utils.easing.EasingMode; import org.bitcoinj.walletfx.utils.easing.ElasticInterpolator; -import static org.bitcoinj.walletfx.application.WalletApplication.bitcoin; - /** * Gets created auto-magically by FXMLLoader via reflection. The widget fields are set to the GUI controls they're named * after. This class handles all the updates and event handling for the main UI. @@ -60,15 +58,17 @@ public class MainController extends MainWindowController { private NotificationBarPane.Item syncItem; private static final MonetaryFormat MONETARY_FORMAT = MonetaryFormat.BTC.noCode(); + private WalletApplication app; private NotificationBarPane notificationBar; // Called by FXMLLoader. public void initialize() { instance = this; + app = WalletApplication.instance(); // Special case of initOverlay that passes null as the 2nd parameter because ClickableBitcoinAddress is loaded by FXML // TODO: Extract QRCode Pane to separate reusable class that is a more standard OverlayController instance addressControl.initOverlay(this, null); - addressControl.setAppName(WalletApplication.instance.applicationName); + addressControl.setAppName(app.applicationName()); addressControl.setOpacity(0.0); } @@ -85,12 +85,12 @@ public class MainController extends MainWindowController { // Add CSS that we need. cssResourceName will be loaded from the same package as this class. scene.getStylesheets().add(getClass().getResource(cssResourceName).toString()); uiStack.getChildren().add(notificationBar); - scene.getAccelerators().put(KeyCombination.valueOf("Shortcut+F"), () -> bitcoin.peerGroup().getDownloadPeer().close()); + scene.getAccelerators().put(KeyCombination.valueOf("Shortcut+F"), () -> app.walletAppKit().peerGroup().getDownloadPeer().close()); } @Override public void onBitcoinSetup() { - model.setWallet(bitcoin.wallet()); + model.setWallet(app.walletAppKit().wallet()); addressControl.addressProperty().bind(model.addressProperty()); balance.textProperty().bind(createBalanceStringBinding(model.balanceProperty())); // Don't let the user click send money when the wallet is empty. diff --git a/wallettemplate/src/main/java/wallettemplate/SendMoneyController.java b/wallettemplate/src/main/java/wallettemplate/SendMoneyController.java index a9b029162..573b7897f 100644 --- a/wallettemplate/src/main/java/wallettemplate/SendMoneyController.java +++ b/wallettemplate/src/main/java/wallettemplate/SendMoneyController.java @@ -50,6 +50,7 @@ public class SendMoneyController implements OverlayController> overlayUI; @@ -64,13 +65,14 @@ public class SendMoneyController implements OverlayController !WTUtils.didThrow(() -> checkState(Coin.parseCoin(text).compareTo(balance) <= 0))); amountEdit.setText(balance.toPlainString()); - address.setPromptText(Address.fromKey(WalletApplication.instance.params, new ECKey(), WalletApplication.instance.preferredOutputScriptType).toString()); + address.setPromptText(Address.fromKey(app.params(), new ECKey(), app.preferredOutputScriptType()).toString()); } public void cancel(ActionEvent event) { @@ -81,9 +83,9 @@ public class SendMoneyController implements OverlayController() { @Override public void onSuccess(@Nullable Transaction result) { diff --git a/wallettemplate/src/main/java/wallettemplate/WalletPasswordController.java b/wallettemplate/src/main/java/wallettemplate/WalletPasswordController.java index 37b534b7b..3f8389c62 100644 --- a/wallettemplate/src/main/java/wallettemplate/WalletPasswordController.java +++ b/wallettemplate/src/main/java/wallettemplate/WalletPasswordController.java @@ -57,6 +57,7 @@ public class WalletPasswordController implements OverlayController> overlayUI; @@ -69,6 +70,7 @@ public class WalletPasswordController implements OverlayController> overlayUI; // These params were determined empirically on a top-range (as of 2014) MacBook Pro with native scrypt support, @@ -64,6 +65,7 @@ public class WalletSetPasswordController implements OverlayController> overlayUI; @@ -71,7 +72,8 @@ public class WalletSettingsController implements OverlayController 0) { + if (app.walletAppKit().wallet().getBalance().value > 0) { informationalAlert("Wallet is not empty", "You must empty this wallet out before attempting to restore an older one, as mixing wallets " + "together can lead to invalidated backups."); @@ -181,14 +183,14 @@ public class WalletSettingsController implements OverlayController