mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-25 05:06:45 +00:00
add settings dialog and other terminal improvements
This commit is contained in:
parent
0fa6bd56e2
commit
8dd1850905
11 changed files with 387 additions and 36 deletions
|
@ -36,7 +36,7 @@ public class MasterActionListBox extends ActionListBox {
|
||||||
.filter(entry -> entry.getValue().getWalletFile().equals(recentWalletFile)).map(Map.Entry::getKey)
|
.filter(entry -> entry.getValue().getWalletFile().equals(recentWalletFile)).map(Map.Entry::getKey)
|
||||||
.map(wallet -> wallet.isMasterWallet() ? wallet : wallet.getMasterWallet()).findFirst();
|
.map(wallet -> wallet.isMasterWallet() ? wallet : wallet.getMasterWallet()).findFirst();
|
||||||
if(optWallet.isPresent()) {
|
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 {
|
} else {
|
||||||
builder.addAction(storage.getWalletName(null), new LoadWallet(storage));
|
builder.addAction(storage.getWalletName(null), new LoadWallet(storage));
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,10 +31,14 @@ public class SparrowTerminal extends Application {
|
||||||
private Screen screen;
|
private Screen screen;
|
||||||
private SparrowTextGui gui;
|
private SparrowTextGui gui;
|
||||||
|
|
||||||
private final Map<Wallet, WalletData> walletData = new HashMap<>();
|
private final Map<String, WalletData> walletData = new HashMap<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init() throws Exception {
|
public void init() throws Exception {
|
||||||
|
Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
|
||||||
|
log.error("Exception in thread \"" + t.getName() + "\"", e);
|
||||||
|
});
|
||||||
|
|
||||||
AppServices.initialize(this, new TerminalInteractionServices());
|
AppServices.initialize(this, new TerminalInteractionServices());
|
||||||
|
|
||||||
this.terminal = new DefaultTerminalFactory().createTerminal();
|
this.terminal = new DefaultTerminalFactory().createTerminal();
|
||||||
|
@ -59,15 +63,7 @@ public class SparrowTerminal extends Application {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stop() throws Exception {
|
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() {
|
public Screen getScreen() {
|
||||||
|
@ -82,14 +78,21 @@ public class SparrowTerminal extends Application {
|
||||||
return gui.getGUIThread();
|
return gui.getGUIThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<Wallet, WalletData> getWalletData() {
|
public Map<String, WalletData> getWalletData() {
|
||||||
return walletData;
|
return walletData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void exit() {
|
public void exit() {
|
||||||
try {
|
try {
|
||||||
screen.stopScreen();
|
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) {
|
} catch(Exception e) {
|
||||||
log.error("Could not stop terminal screen", e);
|
log.error("Could not stop terminal screen", e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,10 @@ public class ServerTestDialog extends DialogWindow {
|
||||||
this.testStatus = new Label("");
|
this.testStatus = new Label("");
|
||||||
mainPanel.addComponent(testStatus);
|
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);
|
testResults.setReadOnly(true);
|
||||||
mainPanel.addComponent(testResults);
|
mainPanel.addComponent(testResults);
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ public class AddressesDialog extends WalletDialog {
|
||||||
table.setSelectAction(() -> {
|
table.setSelectAction(() -> {
|
||||||
NodeEntry nodeEntry = (NodeEntry)getWalletForm().getNodeEntry(keyPurpose).getChildren().get(table.getSelectedRow());
|
NodeEntry nodeEntry = (NodeEntry)getWalletForm().getNodeEntry(keyPurpose).getChildren().get(table.getSelectedRow());
|
||||||
close();
|
close();
|
||||||
WalletData walletData = SparrowTerminal.get().getWalletData().get(getWalletForm().getWallet());
|
WalletData walletData = SparrowTerminal.get().getWalletData().get(getWalletForm().getWalletId());
|
||||||
ReceiveDialog receiveDialog = walletData.getReceiveDialog();
|
ReceiveDialog receiveDialog = walletData.getReceiveDialog();
|
||||||
receiveDialog.setNodeEntry(nodeEntry);
|
receiveDialog.setNodeEntry(nodeEntry);
|
||||||
receiveDialog.showDialog(SparrowTerminal.get().getGui());
|
receiveDialog.showDialog(SparrowTerminal.get().getGui());
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -120,7 +120,7 @@ public class LoadWallet implements Runnable {
|
||||||
if(walletAndKey.getWallet().isMasterWallet()) {
|
if(walletAndKey.getWallet().isMasterWallet()) {
|
||||||
SparrowTerminal.get().getGuiThread().invokeLater(() -> {
|
SparrowTerminal.get().getGuiThread().invokeLater(() -> {
|
||||||
SparrowTerminal.get().getGui().removeWindow(loadingDialog);
|
SparrowTerminal.get().getGui().removeWindow(loadingDialog);
|
||||||
getOpeningDialog(walletAndKey.getWallet()).showDialog(SparrowTerminal.get().getGui());
|
getOpeningDialog(storage, walletAndKey.getWallet()).showDialog(SparrowTerminal.get().getGui());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
|
@ -133,7 +133,7 @@ public class LoadWallet implements Runnable {
|
||||||
|
|
||||||
private void addWallet(Storage storage, Wallet wallet) {
|
private void addWallet(Storage storage, Wallet wallet) {
|
||||||
if(wallet.isNested()) {
|
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);
|
WalletForm walletForm = new WalletForm(storage, wallet);
|
||||||
EventManager.get().register(walletForm);
|
EventManager.get().register(walletForm);
|
||||||
walletData.getWalletForm().getNestedWalletForms().add(walletForm);
|
walletData.getWalletForm().getNestedWalletForms().add(walletForm);
|
||||||
|
@ -142,7 +142,7 @@ public class LoadWallet implements Runnable {
|
||||||
|
|
||||||
WalletForm walletForm = new WalletForm(storage, wallet);
|
WalletForm walletForm = new WalletForm(storage, wallet);
|
||||||
EventManager.get().register(walletForm);
|
EventManager.get().register(walletForm);
|
||||||
SparrowTerminal.get().getWalletData().put(wallet, new WalletData(walletForm));
|
SparrowTerminal.get().getWalletData().put(walletForm.getWalletId(), new WalletData(walletForm));
|
||||||
|
|
||||||
List<WalletTabData> walletTabDataList = SparrowTerminal.get().getWalletData().values().stream()
|
List<WalletTabData> walletTabDataList = SparrowTerminal.get().getWalletData().values().stream()
|
||||||
.map(data -> new WalletTabData(TabData.TabType.WALLET, data.getWalletForm())).collect(Collectors.toList());
|
.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));
|
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())) {
|
if(masterWallet.getChildWallets().stream().anyMatch(childWallet -> !childWallet.isNested())) {
|
||||||
return new WalletAccountsDialog(masterWallet);
|
return new WalletAccountsDialog(storage.getWalletId(masterWallet));
|
||||||
} else {
|
} else {
|
||||||
return new WalletActionsDialog(masterWallet);
|
return new WalletActionsDialog(storage.getWalletId(masterWallet));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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<String> 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<String> splitString(String stringToSplit, int maxLength) {
|
||||||
|
String text = stringToSplit;
|
||||||
|
List<String> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,20 +4,23 @@ import com.googlecode.lanterna.TerminalSize;
|
||||||
import com.googlecode.lanterna.gui2.*;
|
import com.googlecode.lanterna.gui2.*;
|
||||||
import com.googlecode.lanterna.gui2.dialogs.DialogWindow;
|
import com.googlecode.lanterna.gui2.dialogs.DialogWindow;
|
||||||
import com.sparrowwallet.drongo.wallet.Wallet;
|
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||||
|
import com.sparrowwallet.sparrow.io.Storage;
|
||||||
import com.sparrowwallet.sparrow.terminal.SparrowTerminal;
|
import com.sparrowwallet.sparrow.terminal.SparrowTerminal;
|
||||||
|
import com.sparrowwallet.sparrow.wallet.WalletForm;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class WalletAccountsDialog extends DialogWindow {
|
public class WalletAccountsDialog extends DialogWindow {
|
||||||
private final Wallet masterWallet;
|
|
||||||
private final ActionListBox actions;
|
private final ActionListBox actions;
|
||||||
|
|
||||||
public WalletAccountsDialog(Wallet masterWallet) {
|
public WalletAccountsDialog(String masterWalletId) {
|
||||||
super(masterWallet.getFullDisplayName());
|
super(SparrowTerminal.get().getWalletData().get(masterWalletId).getWalletForm().getWallet().getName());
|
||||||
|
|
||||||
setHints(List.of(Hint.CENTERED));
|
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();
|
actions = new ActionListBox();
|
||||||
|
|
||||||
|
@ -25,7 +28,7 @@ public class WalletAccountsDialog extends DialogWindow {
|
||||||
actions.addItem(wallet.getDisplayName(), () -> {
|
actions.addItem(wallet.getDisplayName(), () -> {
|
||||||
close();
|
close();
|
||||||
SparrowTerminal.get().getGuiThread().invokeLater(() -> {
|
SparrowTerminal.get().getGuiThread().invokeLater(() -> {
|
||||||
WalletActionsDialog walletActionsDialog = new WalletActionsDialog(wallet);
|
WalletActionsDialog walletActionsDialog = new WalletActionsDialog(storage.getWalletId(wallet));
|
||||||
walletActionsDialog.showDialog(SparrowTerminal.get().getGui());
|
walletActionsDialog.showDialog(SparrowTerminal.get().getGui());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,15 +10,15 @@ import com.sparrowwallet.sparrow.wallet.Function;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class WalletActionsDialog extends DialogWindow {
|
public class WalletActionsDialog extends DialogWindow {
|
||||||
private final Wallet wallet;
|
private final String walletId;
|
||||||
private final ActionListBox actions;
|
private final ActionListBox actions;
|
||||||
|
|
||||||
public WalletActionsDialog(Wallet wallet) {
|
public WalletActionsDialog(String walletId) {
|
||||||
super(wallet.getFullDisplayName());
|
super(SparrowTerminal.get().getWalletData().get(walletId).getWalletForm().getWallet().getFullDisplayName());
|
||||||
|
|
||||||
setHints(List.of(Hint.CENTERED));
|
setHints(List.of(Hint.CENTERED));
|
||||||
|
|
||||||
this.wallet = wallet;
|
this.walletId = walletId;
|
||||||
|
|
||||||
actions = new ActionListBox();
|
actions = new ActionListBox();
|
||||||
actions.addItem("Transactions", () -> {
|
actions.addItem("Transactions", () -> {
|
||||||
|
@ -43,6 +43,11 @@ public class WalletActionsDialog extends DialogWindow {
|
||||||
UtxosDialog utxosDialog = getWalletData().getUtxosDialog();
|
UtxosDialog utxosDialog = getWalletData().getUtxosDialog();
|
||||||
utxosDialog.showDialog(SparrowTerminal.get().getGui());
|
utxosDialog.showDialog(SparrowTerminal.get().getGui());
|
||||||
});
|
});
|
||||||
|
actions.addItem("Settings", () -> {
|
||||||
|
close();
|
||||||
|
SettingsDialog settingsDialog = getWalletData().getSettingsDialog();
|
||||||
|
settingsDialog.showDialog(SparrowTerminal.get().getGui());
|
||||||
|
});
|
||||||
|
|
||||||
Panel mainPanel = new Panel();
|
Panel mainPanel = new Panel();
|
||||||
mainPanel.setLayoutManager(new GridLayout(1).setLeftMarginSize(1).setRightMarginSize(1));
|
mainPanel.setLayoutManager(new GridLayout(1).setLeftMarginSize(1).setRightMarginSize(1));
|
||||||
|
@ -51,7 +56,7 @@ public class WalletActionsDialog extends DialogWindow {
|
||||||
|
|
||||||
Panel buttonPanel = new Panel();
|
Panel buttonPanel = new Panel();
|
||||||
buttonPanel.setLayoutManager(new GridLayout(2).setHorizontalSpacing(1));
|
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())) {
|
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)));
|
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() {
|
private void onAccounts() {
|
||||||
close();
|
close();
|
||||||
WalletAccountsDialog walletAccountsDialog = new WalletAccountsDialog(wallet.isMasterWallet() ? wallet : wallet.getMasterWallet());
|
WalletAccountsDialog walletAccountsDialog = new WalletAccountsDialog(getWalletData().getWalletForm().getMasterWalletId());
|
||||||
walletAccountsDialog.setWalletAccount(wallet);
|
walletAccountsDialog.setWalletAccount(getWallet());
|
||||||
walletAccountsDialog.showDialog(SparrowTerminal.get().getGui());
|
walletAccountsDialog.showDialog(SparrowTerminal.get().getGui());
|
||||||
}
|
}
|
||||||
|
|
||||||
private WalletData getWalletData() {
|
private WalletData getWalletData() {
|
||||||
WalletData walletData = SparrowTerminal.get().getWalletData().get(wallet);
|
WalletData walletData = SparrowTerminal.get().getWalletData().get(walletId);
|
||||||
if(walletData == null) {
|
if(walletData == null) {
|
||||||
throw new IllegalStateException("Wallet data is null for " + wallet.getFullDisplayName());
|
throw new IllegalStateException("Wallet data is null for " + walletId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return walletData;
|
return walletData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Wallet getWallet() {
|
||||||
|
return getWalletData().getWalletForm().getWallet();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package com.sparrowwallet.sparrow.terminal.wallet;
|
package com.sparrowwallet.sparrow.terminal.wallet;
|
||||||
|
|
||||||
import com.sparrowwallet.sparrow.EventManager;
|
import com.sparrowwallet.sparrow.EventManager;
|
||||||
|
import com.sparrowwallet.sparrow.wallet.SettingsWalletForm;
|
||||||
import com.sparrowwallet.sparrow.wallet.WalletForm;
|
import com.sparrowwallet.sparrow.wallet.WalletForm;
|
||||||
|
|
||||||
public class WalletData {
|
public class WalletData {
|
||||||
|
@ -9,6 +10,7 @@ public class WalletData {
|
||||||
private ReceiveDialog receiveDialog;
|
private ReceiveDialog receiveDialog;
|
||||||
private AddressesDialog addressesDialog;
|
private AddressesDialog addressesDialog;
|
||||||
private UtxosDialog utxosDialog;
|
private UtxosDialog utxosDialog;
|
||||||
|
private SettingsDialog settingsDialog;
|
||||||
|
|
||||||
public WalletData(WalletForm walletForm) {
|
public WalletData(WalletForm walletForm) {
|
||||||
this.walletForm = walletForm;
|
this.walletForm = walletForm;
|
||||||
|
@ -53,4 +55,14 @@ public class WalletData {
|
||||||
|
|
||||||
return utxosDialog;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ public class WalletDialog extends DialogWindow {
|
||||||
|
|
||||||
protected void onBack(Function function) {
|
protected void onBack(Function function) {
|
||||||
close();
|
close();
|
||||||
WalletActionsDialog walletActionsDialog = new WalletActionsDialog(getWalletForm().getWallet());
|
WalletActionsDialog walletActionsDialog = new WalletActionsDialog(getWalletForm().getWalletId());
|
||||||
walletActionsDialog.setFunction(function);
|
walletActionsDialog.setFunction(function);
|
||||||
walletActionsDialog.showDialog(SparrowTerminal.get().getGui());
|
walletActionsDialog.showDialog(SparrowTerminal.get().getGui());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue