From 8dd1850905c8ff4d7d2d08213e1a4e07c72163f0 Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Tue, 18 Oct 2022 12:42:44 +0200 Subject: [PATCH] add settings dialog and other terminal improvements --- .../sparrow/terminal/MasterActionListBox.java | 2 +- .../sparrow/terminal/SparrowTerminal.java | 27 ++- .../preferences/ServerTestDialog.java | 5 +- .../terminal/wallet/AddressesDialog.java | 2 +- .../terminal/wallet/AdvancedDialog.java | 113 ++++++++++ .../sparrow/terminal/wallet/LoadWallet.java | 12 +- .../terminal/wallet/SettingsDialog.java | 208 ++++++++++++++++++ .../terminal/wallet/WalletAccountsDialog.java | 13 +- .../terminal/wallet/WalletActionsDialog.java | 27 ++- .../sparrow/terminal/wallet/WalletData.java | 12 + .../sparrow/terminal/wallet/WalletDialog.java | 2 +- 11 files changed, 387 insertions(+), 36 deletions(-) create mode 100644 src/main/java/com/sparrowwallet/sparrow/terminal/wallet/AdvancedDialog.java create mode 100644 src/main/java/com/sparrowwallet/sparrow/terminal/wallet/SettingsDialog.java diff --git a/src/main/java/com/sparrowwallet/sparrow/terminal/MasterActionListBox.java b/src/main/java/com/sparrowwallet/sparrow/terminal/MasterActionListBox.java index bed2bffe..b3cdeb0e 100644 --- a/src/main/java/com/sparrowwallet/sparrow/terminal/MasterActionListBox.java +++ b/src/main/java/com/sparrowwallet/sparrow/terminal/MasterActionListBox.java @@ -36,7 +36,7 @@ public class MasterActionListBox extends ActionListBox { .filter(entry -> entry.getValue().getWalletFile().equals(recentWalletFile)).map(Map.Entry::getKey) .map(wallet -> wallet.isMasterWallet() ? wallet : wallet.getMasterWallet()).findFirst(); if(optWallet.isPresent()) { - builder.addAction(storage.getWalletName(null) + "*", () -> LoadWallet.getOpeningDialog(optWallet.get()).showDialog(SparrowTerminal.get().getGui())); + builder.addAction(storage.getWalletName(null) + "*", () -> LoadWallet.getOpeningDialog(storage, optWallet.get()).showDialog(SparrowTerminal.get().getGui())); } else { builder.addAction(storage.getWalletName(null), new LoadWallet(storage)); } diff --git a/src/main/java/com/sparrowwallet/sparrow/terminal/SparrowTerminal.java b/src/main/java/com/sparrowwallet/sparrow/terminal/SparrowTerminal.java index b5670e39..05b404c4 100644 --- a/src/main/java/com/sparrowwallet/sparrow/terminal/SparrowTerminal.java +++ b/src/main/java/com/sparrowwallet/sparrow/terminal/SparrowTerminal.java @@ -31,10 +31,14 @@ public class SparrowTerminal extends Application { private Screen screen; private SparrowTextGui gui; - private final Map walletData = new HashMap<>(); + private final Map walletData = new HashMap<>(); @Override public void init() throws Exception { + Thread.setDefaultUncaughtExceptionHandler((t, e) -> { + log.error("Exception in thread \"" + t.getName() + "\"", e); + }); + AppServices.initialize(this, new TerminalInteractionServices()); this.terminal = new DefaultTerminalFactory().createTerminal(); @@ -59,15 +63,7 @@ public class SparrowTerminal extends Application { @Override public void stop() throws Exception { - try { - AppServices.get().stop(); - SparrowWallet.Instance instance = SparrowWallet.getSparrowInstance(); - if(instance != null) { - instance.freeLock(); - } - } catch(Exception e) { - log.error("Could not stop application", e); - } + } public Screen getScreen() { @@ -82,14 +78,21 @@ public class SparrowTerminal extends Application { return gui.getGUIThread(); } - public Map getWalletData() { + public Map getWalletData() { return walletData; } public void exit() { try { screen.stopScreen(); - Platform.runLater(Platform::exit); + Platform.runLater(() -> { + AppServices.get().stop(); + Platform.exit(); + }); + SparrowWallet.Instance instance = SparrowWallet.getSparrowInstance(); + if(instance != null) { + instance.freeLock(); + } } catch(Exception e) { log.error("Could not stop terminal screen", e); } diff --git a/src/main/java/com/sparrowwallet/sparrow/terminal/preferences/ServerTestDialog.java b/src/main/java/com/sparrowwallet/sparrow/terminal/preferences/ServerTestDialog.java index 49dfa3dd..8c7ad419 100644 --- a/src/main/java/com/sparrowwallet/sparrow/terminal/preferences/ServerTestDialog.java +++ b/src/main/java/com/sparrowwallet/sparrow/terminal/preferences/ServerTestDialog.java @@ -40,7 +40,10 @@ public class ServerTestDialog extends DialogWindow { this.testStatus = new Label(""); mainPanel.addComponent(testStatus); - this.testResults = new TextBox(new TerminalSize(60, 10)); + TerminalSize screenSize = SparrowTerminal.get().getScreen().getTerminalSize(); + int resultsWidth = Math.min(Math.max(20, screenSize.getColumns() - 20), 100); + + this.testResults = new TextBox(new TerminalSize(resultsWidth, 10)); testResults.setReadOnly(true); mainPanel.addComponent(testResults); diff --git a/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/AddressesDialog.java b/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/AddressesDialog.java index e1429b6d..a8e03784 100644 --- a/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/AddressesDialog.java +++ b/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/AddressesDialog.java @@ -60,7 +60,7 @@ public class AddressesDialog extends WalletDialog { table.setSelectAction(() -> { NodeEntry nodeEntry = (NodeEntry)getWalletForm().getNodeEntry(keyPurpose).getChildren().get(table.getSelectedRow()); close(); - WalletData walletData = SparrowTerminal.get().getWalletData().get(getWalletForm().getWallet()); + WalletData walletData = SparrowTerminal.get().getWalletData().get(getWalletForm().getWalletId()); ReceiveDialog receiveDialog = walletData.getReceiveDialog(); receiveDialog.setNodeEntry(nodeEntry); receiveDialog.showDialog(SparrowTerminal.get().getGui()); diff --git a/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/AdvancedDialog.java b/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/AdvancedDialog.java new file mode 100644 index 00000000..fd670a8d --- /dev/null +++ b/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/AdvancedDialog.java @@ -0,0 +1,113 @@ +package com.sparrowwallet.sparrow.terminal.wallet; + +import com.googlecode.lanterna.TerminalSize; +import com.googlecode.lanterna.gui2.*; +import com.sparrowwallet.drongo.wallet.Wallet; +import com.sparrowwallet.sparrow.io.Storage; +import com.sparrowwallet.sparrow.wallet.WalletForm; + +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import java.util.regex.Pattern; + +public class AdvancedDialog extends WalletDialog { + private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); + + private final TextBox birthDate; + private final TextBox gapLimit; + private final Button apply; + + private Result result = Result.CANCEL; + + public AdvancedDialog(WalletForm walletForm) { + super(walletForm.getWallet().getFullDisplayName() + " Advanced Settings", walletForm); + + setHints(List.of(Hint.CENTERED)); + + Wallet wallet = getWalletForm().getWallet(); + + Panel mainPanel = new Panel(); + mainPanel.setLayoutManager(new GridLayout(2).setHorizontalSpacing(5).setVerticalSpacing(1)); + + mainPanel.addComponent(new EmptySpace(TerminalSize.ONE)); + mainPanel.addComponent(new EmptySpace(TerminalSize.ONE)); + + mainPanel.addComponent(new Label("Birth date")); + birthDate = new TextBox().setValidationPattern(Pattern.compile("[0-9\\-/]*")); + mainPanel.addComponent(birthDate); + + mainPanel.addComponent(new Label("Gap limit")); + gapLimit = new TextBox().setValidationPattern(Pattern.compile("[0-9]*")); + mainPanel.addComponent(gapLimit); + + Panel buttonPanel = new Panel(); + buttonPanel.setLayoutManager(new GridLayout(2).setHorizontalSpacing(1)); + buttonPanel.addComponent(new Button("Cancel", this::onCancel)); + apply = new Button("Apply", this::onApply).setLayoutData(GridLayout.createLayoutData(GridLayout.Alignment.CENTER, GridLayout.Alignment.CENTER, true, false)); + apply.setEnabled(false); + buttonPanel.addComponent(apply); + + boolean noPassword = Storage.NO_PASSWORD_KEY.equals(walletForm.getStorage().getEncryptionPubKey()); + mainPanel.addComponent(new Button(noPassword ? "Add Password" : "Change Password", this::onChangePassword)); + + buttonPanel.setLayoutData(GridLayout.createLayoutData(GridLayout.Alignment.END, GridLayout.Alignment.CENTER,false,false)).addTo(mainPanel); + setComponent(mainPanel); + + if(wallet.getBirthDate() != null) { + birthDate.setText(DATE_FORMAT.format(wallet.getBirthDate())); + } + + gapLimit.setText(Integer.toString(wallet.getGapLimit())); + + birthDate.setTextChangeListener((newText, changedByUserInteraction) -> { + try { + Date newDate = DATE_FORMAT.parse(newText); + wallet.setBirthDate(newDate); + apply.setEnabled(true); + } catch(ParseException e) { + //ignore + } + }); + + gapLimit.setTextChangeListener((newText, changedByUserInteraction) -> { + try { + int newValue = Integer.parseInt(newText); + if(newValue < 0 || newValue > 1000000) { + return; + } + + wallet.setGapLimit(newValue); + apply.setEnabled(true); + } catch(NumberFormatException e) { + return; + } + }); + } + + private void onChangePassword() { + result = Result.CHANGE_PASSWORD; + close(); + } + + private void onApply() { + result = Result.APPLY; + close(); + } + + private void onCancel() { + close(); + } + + @Override + public Object showDialog(WindowBasedTextGUI textGUI) { + super.showDialog(textGUI); + return result; + } + + public enum Result { + CANCEL, APPLY, CHANGE_PASSWORD + } +} diff --git a/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/LoadWallet.java b/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/LoadWallet.java index 352f172a..38dfb0ef 100644 --- a/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/LoadWallet.java +++ b/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/LoadWallet.java @@ -120,7 +120,7 @@ public class LoadWallet implements Runnable { if(walletAndKey.getWallet().isMasterWallet()) { SparrowTerminal.get().getGuiThread().invokeLater(() -> { SparrowTerminal.get().getGui().removeWindow(loadingDialog); - getOpeningDialog(walletAndKey.getWallet()).showDialog(SparrowTerminal.get().getGui()); + getOpeningDialog(storage, walletAndKey.getWallet()).showDialog(SparrowTerminal.get().getGui()); }); } } catch(Exception e) { @@ -133,7 +133,7 @@ public class LoadWallet implements Runnable { private void addWallet(Storage storage, Wallet wallet) { if(wallet.isNested()) { - WalletData walletData = SparrowTerminal.get().getWalletData().get(wallet.getMasterWallet()); + WalletData walletData = SparrowTerminal.get().getWalletData().get(storage.getWalletId(wallet.getMasterWallet())); WalletForm walletForm = new WalletForm(storage, wallet); EventManager.get().register(walletForm); walletData.getWalletForm().getNestedWalletForms().add(walletForm); @@ -142,7 +142,7 @@ public class LoadWallet implements Runnable { WalletForm walletForm = new WalletForm(storage, wallet); EventManager.get().register(walletForm); - SparrowTerminal.get().getWalletData().put(wallet, new WalletData(walletForm)); + SparrowTerminal.get().getWalletData().put(walletForm.getWalletId(), new WalletData(walletForm)); List walletTabDataList = SparrowTerminal.get().getWalletData().values().stream() .map(data -> new WalletTabData(TabData.TabType.WALLET, data.getWalletForm())).collect(Collectors.toList()); @@ -159,11 +159,11 @@ public class LoadWallet implements Runnable { EventManager.get().post(new WalletOpenedEvent(storage, wallet)); } - public static DialogWindow getOpeningDialog(Wallet masterWallet) { + public static DialogWindow getOpeningDialog(Storage storage, Wallet masterWallet) { if(masterWallet.getChildWallets().stream().anyMatch(childWallet -> !childWallet.isNested())) { - return new WalletAccountsDialog(masterWallet); + return new WalletAccountsDialog(storage.getWalletId(masterWallet)); } else { - return new WalletActionsDialog(masterWallet); + return new WalletActionsDialog(storage.getWalletId(masterWallet)); } } diff --git a/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/SettingsDialog.java b/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/SettingsDialog.java new file mode 100644 index 00000000..26b1260c --- /dev/null +++ b/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/SettingsDialog.java @@ -0,0 +1,208 @@ +package com.sparrowwallet.sparrow.terminal.wallet; + +import com.googlecode.lanterna.TerminalSize; +import com.googlecode.lanterna.gui2.*; +import com.googlecode.lanterna.gui2.dialogs.TextInputDialogBuilder; +import com.sparrowwallet.drongo.KeyPurpose; +import com.sparrowwallet.drongo.OutputDescriptor; +import com.sparrowwallet.drongo.SecureString; +import com.sparrowwallet.drongo.crypto.ECKey; +import com.sparrowwallet.drongo.crypto.EncryptionType; +import com.sparrowwallet.drongo.crypto.Key; +import com.sparrowwallet.drongo.wallet.Wallet; +import com.sparrowwallet.sparrow.AppServices; +import com.sparrowwallet.sparrow.EventManager; +import com.sparrowwallet.sparrow.event.RequestOpenWalletsEvent; +import com.sparrowwallet.sparrow.event.StorageEvent; +import com.sparrowwallet.sparrow.event.TimedEvent; +import com.sparrowwallet.sparrow.io.Storage; +import com.sparrowwallet.sparrow.io.StorageException; +import com.sparrowwallet.sparrow.terminal.SparrowTerminal; +import com.sparrowwallet.sparrow.wallet.Function; +import com.sparrowwallet.sparrow.wallet.WalletForm; +import javafx.application.Platform; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class SettingsDialog extends WalletDialog { + private static final Logger log = LoggerFactory.getLogger(SettingsDialog.class); + + private final Label scriptType; + private final TextBox outputDescriptor; + + public SettingsDialog(WalletForm walletForm) { + super(walletForm.getWallet().getFullDisplayName() + " Settings", walletForm); + + setHints(List.of(Hint.CENTERED)); + + Panel mainPanel = new Panel(new GridLayout(2).setHorizontalSpacing(2).setVerticalSpacing(0).setTopMarginSize(1)); + + mainPanel.addComponent(new Label("Script Type")); + scriptType = new Label(getWalletForm().getWallet().getScriptType().getDescription()).addTo(mainPanel); + + mainPanel.addComponent(new EmptySpace(TerminalSize.ONE)); + mainPanel.addComponent(new EmptySpace(TerminalSize.ONE)); + + TerminalSize screenSize = SparrowTerminal.get().getScreen().getTerminalSize(); + int descriptorWidth = Math.min(Math.max(20, screenSize.getColumns() - 20), 120); + + OutputDescriptor descriptor = OutputDescriptor.getOutputDescriptor(getWalletForm().getWallet(), KeyPurpose.DEFAULT_PURPOSES, null); + String outputDescriptorString = descriptor.toString(true); + List outputDescriptorLines = splitString(outputDescriptorString, descriptorWidth); + + mainPanel.addComponent(new Label("Output Descriptor")); + outputDescriptor = new TextBox(new TerminalSize(descriptorWidth, Math.min(outputDescriptorLines.size(), 10))); + outputDescriptor.setReadOnly(true); + outputDescriptor.setText(outputDescriptorLines.stream().reduce((s1, s2) -> s1 + "\n" + s2).get()); + mainPanel.addComponent(new EmptySpace(TerminalSize.ONE)); + + mainPanel.addComponent(outputDescriptor, GridLayout.createLayoutData(GridLayout.Alignment.BEGINNING, GridLayout.Alignment.CENTER, true, true, 2, 1)); + + mainPanel.addComponent(new EmptySpace(TerminalSize.ONE)); + mainPanel.addComponent(new EmptySpace(TerminalSize.ONE)); + + Panel buttonPanel = new Panel(); + buttonPanel.setLayoutManager(new GridLayout(2).setHorizontalSpacing(1)); + buttonPanel.addComponent(new Button("Back", () -> onBack(Function.SETTINGS))); + buttonPanel.addComponent(new Button("Advanced", this::showAdvanced).setLayoutData(GridLayout.createLayoutData(GridLayout.Alignment.CENTER, GridLayout.Alignment.CENTER, true, false))); + + mainPanel.addComponent(new EmptySpace(TerminalSize.ONE)); + + buttonPanel.setLayoutData(GridLayout.createLayoutData(GridLayout.Alignment.END, GridLayout.Alignment.CENTER,false,false)).addTo(mainPanel); + setComponent(mainPanel); + } + + private void showAdvanced() { + AdvancedDialog advancedDialog = new AdvancedDialog(getWalletForm()); + AdvancedDialog.Result result = (AdvancedDialog.Result)advancedDialog.showDialog(SparrowTerminal.get().getGui()); + + if(result != AdvancedDialog.Result.CANCEL) { + saveWallet(false, result == AdvancedDialog.Result.CHANGE_PASSWORD); + } + } + + private void saveWallet(boolean changePassword, boolean suggestChangePassword) { + WalletForm walletForm = getWalletForm(); + ECKey existingPubKey = walletForm.getStorage().getEncryptionPubKey(); + + PasswordRequirement requirement; + if(existingPubKey == null) { + if(changePassword) { + requirement = PasswordRequirement.UPDATE_CHANGE; + } else { + requirement = PasswordRequirement.UPDATE_NEW; + } + } else if(Storage.NO_PASSWORD_KEY.equals(existingPubKey)) { + requirement = PasswordRequirement.UPDATE_EMPTY; + } else { + requirement = PasswordRequirement.UPDATE_SET; + } + + TextInputDialogBuilder builder = new TextInputDialogBuilder().setTitle("Wallet Password"); + builder.setDescription(requirement.description); + builder.setPasswordInput(true); + + String password = builder.build().showDialog(SparrowTerminal.get().getGui()); + if(password != null) { + Platform.runLater(() -> { + if(password.length() == 0 && requirement != PasswordRequirement.UPDATE_SET) { + try { + walletForm.getStorage().setEncryptionPubKey(Storage.NO_PASSWORD_KEY); + walletForm.saveAndRefresh(); + EventManager.get().post(new RequestOpenWalletsEvent()); + } catch (IOException | StorageException e) { + log.error("Error saving wallet", e); + AppServices.showErrorDialog("Error saving wallet", e.getMessage()); + } + } else { + Storage.KeyDerivationService keyDerivationService = new Storage.KeyDerivationService(walletForm.getStorage(), new SecureString(password)); + keyDerivationService.setOnSucceeded(workerStateEvent -> { + EventManager.get().post(new StorageEvent(walletForm.getWalletId(), TimedEvent.Action.END, "Done")); + ECKey encryptionFullKey = keyDerivationService.getValue(); + Key key = null; + + try { + ECKey encryptionPubKey = ECKey.fromPublicOnly(encryptionFullKey); + + if(existingPubKey != null && !Storage.NO_PASSWORD_KEY.equals(existingPubKey) && !existingPubKey.equals(encryptionPubKey)) { + AppServices.showErrorDialog("Incorrect Password", "The password was incorrect."); + return; + } + + key = new Key(encryptionFullKey.getPrivKeyBytes(), walletForm.getStorage().getKeyDeriver().getSalt(), EncryptionType.Deriver.ARGON2); + + Wallet masterWallet = walletForm.getWallet().isMasterWallet() ? walletForm.getWallet() : walletForm.getWallet().getMasterWallet(); + if(suggestChangePassword && requirement == PasswordRequirement.UPDATE_SET) { + walletForm.getStorage().setEncryptionPubKey(null); + masterWallet.decrypt(key); + for(Wallet childWallet : masterWallet.getChildWallets()) { + if(!childWallet.isNested()) { + childWallet.decrypt(key); + } + } + SparrowTerminal.get().getGuiThread().invokeLater(() -> saveWallet(true, false)); + return; + } + + masterWallet.encrypt(key); + for(Wallet childWallet : masterWallet.getChildWallets()) { + if(!childWallet.isNested()) { + childWallet.encrypt(key); + } + } + walletForm.getStorage().setEncryptionPubKey(encryptionPubKey); + walletForm.saveAndRefresh(); + EventManager.get().post(new RequestOpenWalletsEvent()); + } catch (Exception e) { + log.error("Error saving wallet", e); + AppServices.showErrorDialog("Error saving wallet", e.getMessage()); + } finally { + encryptionFullKey.clear(); + if(key != null) { + key.clear(); + } + } + }); + keyDerivationService.setOnFailed(workerStateEvent -> { + EventManager.get().post(new StorageEvent(walletForm.getWalletId(), TimedEvent.Action.END, "Failed")); + AppServices.showErrorDialog("Error saving wallet", keyDerivationService.getException().getMessage()); + }); + EventManager.get().post(new StorageEvent(walletForm.getWalletId(), TimedEvent.Action.START, "Encrypting wallet...")); + keyDerivationService.start(); + } + }); + } + } + + public static List splitString(String stringToSplit, int maxLength) { + String text = stringToSplit; + List lines = new ArrayList<>(); + while(text.length() > maxLength) { + int breakAt = maxLength - 1; + lines.add(text.substring(0, breakAt)); + text = text.substring(breakAt + 1); + } + + lines.add(text); + return lines; + } + + public enum PasswordRequirement { + UPDATE_NEW("Add a password to the wallet?\nLeave empty for no password:", "No Password"), + UPDATE_EMPTY("This wallet has no password.\nAdd a password to the wallet?\nLeave empty for no password:", "No Password"), + UPDATE_SET("Re-enter the wallet password:", "Verify Password"), + UPDATE_CHANGE("Enter the new wallet password.\nLeave empty for no password:", "No Password"); + + private final String description; + private final String okButtonText; + + PasswordRequirement(String description, String okButtonText) { + this.description = description; + this.okButtonText = okButtonText; + } + } +} diff --git a/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/WalletAccountsDialog.java b/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/WalletAccountsDialog.java index d30aa634..f8fee1fb 100644 --- a/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/WalletAccountsDialog.java +++ b/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/WalletAccountsDialog.java @@ -4,20 +4,23 @@ import com.googlecode.lanterna.TerminalSize; import com.googlecode.lanterna.gui2.*; import com.googlecode.lanterna.gui2.dialogs.DialogWindow; import com.sparrowwallet.drongo.wallet.Wallet; +import com.sparrowwallet.sparrow.io.Storage; import com.sparrowwallet.sparrow.terminal.SparrowTerminal; +import com.sparrowwallet.sparrow.wallet.WalletForm; import java.util.List; public class WalletAccountsDialog extends DialogWindow { - private final Wallet masterWallet; private final ActionListBox actions; - public WalletAccountsDialog(Wallet masterWallet) { - super(masterWallet.getFullDisplayName()); + public WalletAccountsDialog(String masterWalletId) { + super(SparrowTerminal.get().getWalletData().get(masterWalletId).getWalletForm().getWallet().getName()); setHints(List.of(Hint.CENTERED)); - this.masterWallet = masterWallet; + WalletForm masterWalletForm = SparrowTerminal.get().getWalletData().get(masterWalletId).getWalletForm(); + Storage storage = masterWalletForm.getStorage(); + Wallet masterWallet = masterWalletForm.getWallet(); actions = new ActionListBox(); @@ -25,7 +28,7 @@ public class WalletAccountsDialog extends DialogWindow { actions.addItem(wallet.getDisplayName(), () -> { close(); SparrowTerminal.get().getGuiThread().invokeLater(() -> { - WalletActionsDialog walletActionsDialog = new WalletActionsDialog(wallet); + WalletActionsDialog walletActionsDialog = new WalletActionsDialog(storage.getWalletId(wallet)); walletActionsDialog.showDialog(SparrowTerminal.get().getGui()); }); }); diff --git a/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/WalletActionsDialog.java b/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/WalletActionsDialog.java index d8c30bd9..615940e7 100644 --- a/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/WalletActionsDialog.java +++ b/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/WalletActionsDialog.java @@ -10,15 +10,15 @@ import com.sparrowwallet.sparrow.wallet.Function; import java.util.List; public class WalletActionsDialog extends DialogWindow { - private final Wallet wallet; + private final String walletId; private final ActionListBox actions; - public WalletActionsDialog(Wallet wallet) { - super(wallet.getFullDisplayName()); + public WalletActionsDialog(String walletId) { + super(SparrowTerminal.get().getWalletData().get(walletId).getWalletForm().getWallet().getFullDisplayName()); setHints(List.of(Hint.CENTERED)); - this.wallet = wallet; + this.walletId = walletId; actions = new ActionListBox(); actions.addItem("Transactions", () -> { @@ -43,6 +43,11 @@ public class WalletActionsDialog extends DialogWindow { UtxosDialog utxosDialog = getWalletData().getUtxosDialog(); utxosDialog.showDialog(SparrowTerminal.get().getGui()); }); + actions.addItem("Settings", () -> { + close(); + SettingsDialog settingsDialog = getWalletData().getSettingsDialog(); + settingsDialog.showDialog(SparrowTerminal.get().getGui()); + }); Panel mainPanel = new Panel(); mainPanel.setLayoutManager(new GridLayout(1).setLeftMarginSize(1).setRightMarginSize(1)); @@ -51,7 +56,7 @@ public class WalletActionsDialog extends DialogWindow { Panel buttonPanel = new Panel(); buttonPanel.setLayoutManager(new GridLayout(2).setHorizontalSpacing(1)); - Wallet masterWallet = wallet.isMasterWallet() ? wallet : wallet.getMasterWallet(); + Wallet masterWallet = getWallet().isMasterWallet() ? getWallet() : getWallet().getMasterWallet(); if(masterWallet.getChildWallets().stream().anyMatch(childWallet -> !childWallet.isNested())) { buttonPanel.addComponent(new Button("Accounts", this::onAccounts).setLayoutData(GridLayout.createLayoutData(GridLayout.Alignment.CENTER, GridLayout.Alignment.CENTER, true, false))); } @@ -80,17 +85,21 @@ public class WalletActionsDialog extends DialogWindow { private void onAccounts() { close(); - WalletAccountsDialog walletAccountsDialog = new WalletAccountsDialog(wallet.isMasterWallet() ? wallet : wallet.getMasterWallet()); - walletAccountsDialog.setWalletAccount(wallet); + WalletAccountsDialog walletAccountsDialog = new WalletAccountsDialog(getWalletData().getWalletForm().getMasterWalletId()); + walletAccountsDialog.setWalletAccount(getWallet()); walletAccountsDialog.showDialog(SparrowTerminal.get().getGui()); } private WalletData getWalletData() { - WalletData walletData = SparrowTerminal.get().getWalletData().get(wallet); + WalletData walletData = SparrowTerminal.get().getWalletData().get(walletId); if(walletData == null) { - throw new IllegalStateException("Wallet data is null for " + wallet.getFullDisplayName()); + throw new IllegalStateException("Wallet data is null for " + walletId); } return walletData; } + + private Wallet getWallet() { + return getWalletData().getWalletForm().getWallet(); + } } diff --git a/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/WalletData.java b/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/WalletData.java index 1145b857..3309fc56 100644 --- a/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/WalletData.java +++ b/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/WalletData.java @@ -1,6 +1,7 @@ package com.sparrowwallet.sparrow.terminal.wallet; import com.sparrowwallet.sparrow.EventManager; +import com.sparrowwallet.sparrow.wallet.SettingsWalletForm; import com.sparrowwallet.sparrow.wallet.WalletForm; public class WalletData { @@ -9,6 +10,7 @@ public class WalletData { private ReceiveDialog receiveDialog; private AddressesDialog addressesDialog; private UtxosDialog utxosDialog; + private SettingsDialog settingsDialog; public WalletData(WalletForm walletForm) { this.walletForm = walletForm; @@ -53,4 +55,14 @@ public class WalletData { return utxosDialog; } + + public SettingsDialog getSettingsDialog() { + if(settingsDialog == null) { + SettingsWalletForm settingsWalletForm = new SettingsWalletForm(walletForm.getStorage(), walletForm.getWallet()); + settingsDialog = new SettingsDialog(settingsWalletForm); + EventManager.get().register(settingsDialog); + } + + return settingsDialog; + } } diff --git a/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/WalletDialog.java b/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/WalletDialog.java index 8c9ecb93..906e5df7 100644 --- a/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/WalletDialog.java +++ b/src/main/java/com/sparrowwallet/sparrow/terminal/wallet/WalletDialog.java @@ -32,7 +32,7 @@ public class WalletDialog extends DialogWindow { protected void onBack(Function function) { close(); - WalletActionsDialog walletActionsDialog = new WalletActionsDialog(getWalletForm().getWallet()); + WalletActionsDialog walletActionsDialog = new WalletActionsDialog(getWalletForm().getWalletId()); walletActionsDialog.setFunction(function); walletActionsDialog.showDialog(SparrowTerminal.get().getGui()); }