21 changed files with 386 additions and 58 deletions
@ -1 +1 @@ |
|||
Subproject commit 766a986abb72ea84317a405b93055abc3d1eaf22 |
|||
Subproject commit f6414a447550eb87a871c54c7e376713cae8eb9c |
@ -0,0 +1,16 @@ |
|||
package com.sparrowwallet.sparrow; |
|||
|
|||
import com.sparrowwallet.drongo.protocol.Transaction; |
|||
|
|||
public class TransactionTabData extends TabData { |
|||
private Transaction transaction; |
|||
|
|||
public TransactionTabData(TabType type, Transaction transaction) { |
|||
super(type); |
|||
this.transaction = transaction; |
|||
} |
|||
|
|||
public Transaction getTransaction() { |
|||
return transaction; |
|||
} |
|||
} |
@ -0,0 +1,35 @@ |
|||
package com.sparrowwallet.sparrow; |
|||
|
|||
import com.google.common.eventbus.Subscribe; |
|||
import com.sparrowwallet.drongo.wallet.Wallet; |
|||
import com.sparrowwallet.sparrow.event.WalletChangedEvent; |
|||
|
|||
import java.io.File; |
|||
|
|||
public class WalletTabData extends TabData { |
|||
private Wallet wallet; |
|||
private final File walletFile; |
|||
|
|||
public WalletTabData(TabType type, Wallet wallet, File walletFile) { |
|||
super(type); |
|||
this.wallet = wallet; |
|||
this.walletFile = walletFile; |
|||
|
|||
EventManager.get().register(this); |
|||
} |
|||
|
|||
public Wallet getWallet() { |
|||
return wallet; |
|||
} |
|||
|
|||
public File getWalletFile() { |
|||
return walletFile; |
|||
} |
|||
|
|||
@Subscribe |
|||
public void walletChanged(WalletChangedEvent event) { |
|||
if(event.getWalletFile().equals(walletFile)) { |
|||
wallet = event.getWallet(); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,88 @@ |
|||
package com.sparrowwallet.sparrow.control; |
|||
|
|||
import com.sparrowwallet.drongo.wallet.Keystore; |
|||
import com.sparrowwallet.drongo.wallet.Wallet; |
|||
import com.sparrowwallet.sparrow.EventManager; |
|||
import com.sparrowwallet.sparrow.event.WalletExportEvent; |
|||
import com.sparrowwallet.sparrow.io.WalletExport; |
|||
import javafx.geometry.Pos; |
|||
import javafx.scene.control.Button; |
|||
import javafx.scene.control.Control; |
|||
import javafx.stage.FileChooser; |
|||
import javafx.stage.Stage; |
|||
|
|||
import java.io.File; |
|||
import java.io.FileOutputStream; |
|||
import java.io.OutputStream; |
|||
import java.util.Optional; |
|||
|
|||
public class FileWalletExportPane extends TitledDescriptionPane { |
|||
private final Wallet wallet; |
|||
private final WalletExport exporter; |
|||
|
|||
public FileWalletExportPane(Wallet wallet, WalletExport exporter) { |
|||
super(exporter.getName(), "Wallet file export", exporter.getWalletExportDescription(), "image/" + exporter.getWalletModel().getType() + ".png"); |
|||
this.wallet = wallet; |
|||
this.exporter = exporter; |
|||
} |
|||
|
|||
@Override |
|||
protected Control createButton() { |
|||
Button exportButton = new Button("Export Wallet..."); |
|||
exportButton.setAlignment(Pos.CENTER_RIGHT); |
|||
exportButton.setOnAction(event -> { |
|||
exportWallet(); |
|||
}); |
|||
return exportButton; |
|||
} |
|||
|
|||
private void exportWallet() { |
|||
Stage window = new Stage(); |
|||
|
|||
FileChooser fileChooser = new FileChooser(); |
|||
fileChooser.setTitle("Export " + exporter.getWalletModel().toDisplayString() + " File"); |
|||
|
|||
File file = fileChooser.showSaveDialog(window); |
|||
if(file != null) { |
|||
exportWallet(file); |
|||
} |
|||
} |
|||
|
|||
private void exportWallet(File file) { |
|||
Wallet copy = wallet.copy(); |
|||
|
|||
if(copy.isEncrypted()) { |
|||
WalletPasswordDialog dlg = new WalletPasswordDialog(WalletPasswordDialog.PasswordRequirement.LOAD); |
|||
Optional<String> password = dlg.showAndWait(); |
|||
if(password.isPresent()) { |
|||
copy.decrypt(password.get(), ""); |
|||
|
|||
for(Keystore keystore : copy.getKeystores()) { |
|||
if(keystore.hasSeed() && keystore.getSeed().needPassphrase()) { |
|||
KeystorePassphraseDialog passphraseDialog = new KeystorePassphraseDialog(keystore); |
|||
Optional<String> passphrase = passphraseDialog.showAndWait(); |
|||
if(passphrase.isPresent()) { |
|||
keystore.setPassphrase(passphrase.get()); |
|||
} else { |
|||
return; |
|||
} |
|||
} |
|||
} |
|||
} else { |
|||
return; |
|||
} |
|||
} |
|||
|
|||
try { |
|||
OutputStream outputStream = new FileOutputStream(file); |
|||
exporter.exportWallet(copy, outputStream); |
|||
EventManager.get().post(new WalletExportEvent(copy)); |
|||
} catch(Exception e) { |
|||
String errorMessage = e.getMessage(); |
|||
if(e.getCause() != null && e.getCause().getMessage() != null && !e.getCause().getMessage().isEmpty()) { |
|||
errorMessage = e.getCause().getMessage(); |
|||
} |
|||
setError("Export Error", errorMessage); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,41 @@ |
|||
package com.sparrowwallet.sparrow.control; |
|||
|
|||
import com.sparrowwallet.drongo.wallet.Keystore; |
|||
import com.sparrowwallet.sparrow.AppController; |
|||
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5; |
|||
import javafx.scene.control.ButtonType; |
|||
import javafx.scene.control.Dialog; |
|||
import javafx.scene.control.DialogPane; |
|||
import javafx.scene.layout.VBox; |
|||
import org.controlsfx.control.textfield.CustomPasswordField; |
|||
import org.controlsfx.control.textfield.TextFields; |
|||
import org.controlsfx.glyphfont.Glyph; |
|||
|
|||
public class KeystorePassphraseDialog extends Dialog<String> { |
|||
private final CustomPasswordField passphrase; |
|||
|
|||
public KeystorePassphraseDialog(Keystore keystore) { |
|||
this.passphrase = (CustomPasswordField) TextFields.createClearablePasswordField(); |
|||
|
|||
final DialogPane dialogPane = getDialogPane(); |
|||
setTitle("Keystore Passphrase"); |
|||
dialogPane.setHeaderText("Please enter the passphrase for keystore: " + keystore.getLabel()); |
|||
dialogPane.getStylesheets().add(AppController.class.getResource("general.css").toExternalForm()); |
|||
dialogPane.getButtonTypes().addAll(ButtonType.CANCEL, ButtonType.OK); |
|||
dialogPane.setPrefWidth(380); |
|||
dialogPane.setPrefHeight(200); |
|||
|
|||
Glyph lock = new Glyph("FontAwesome5", FontAwesome5.Glyph.KEY); |
|||
lock.setFontSize(50); |
|||
dialogPane.setGraphic(lock); |
|||
|
|||
final VBox content = new VBox(10); |
|||
content.setPrefHeight(50); |
|||
content.getChildren().add(passphrase); |
|||
|
|||
dialogPane.setContent(content); |
|||
passphrase.requestFocus(); |
|||
|
|||
setResultConverter(dialogButton -> dialogButton == ButtonType.OK ? passphrase.getText() : null); |
|||
} |
|||
} |
@ -0,0 +1,71 @@ |
|||
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.EventManager; |
|||
import com.sparrowwallet.sparrow.event.WalletExportEvent; |
|||
import com.sparrowwallet.sparrow.event.WalletImportEvent; |
|||
import com.sparrowwallet.sparrow.io.ColdcardMultisig; |
|||
import com.sparrowwallet.sparrow.io.Electrum; |
|||
import com.sparrowwallet.sparrow.io.WalletExport; |
|||
import com.sparrowwallet.sparrow.io.WalletImport; |
|||
import javafx.scene.control.*; |
|||
import javafx.scene.layout.AnchorPane; |
|||
import javafx.scene.layout.StackPane; |
|||
|
|||
import java.util.List; |
|||
|
|||
public class WalletExportDialog extends Dialog<Wallet> { |
|||
private Wallet wallet; |
|||
|
|||
public WalletExportDialog(Wallet wallet) { |
|||
EventManager.get().register(this); |
|||
|
|||
final DialogPane dialogPane = getDialogPane(); |
|||
|
|||
StackPane stackPane = new StackPane(); |
|||
dialogPane.setContent(stackPane); |
|||
|
|||
AnchorPane anchorPane = new AnchorPane(); |
|||
stackPane.getChildren().add(anchorPane); |
|||
|
|||
ScrollPane scrollPane = new ScrollPane(); |
|||
scrollPane.setPrefHeight(280); |
|||
scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); |
|||
anchorPane.getChildren().add(scrollPane); |
|||
scrollPane.setFitToWidth(true); |
|||
AnchorPane.setLeftAnchor(scrollPane, 0.0); |
|||
AnchorPane.setRightAnchor(scrollPane, 0.0); |
|||
|
|||
List<WalletExport> exporters; |
|||
if(wallet.getPolicyType() == PolicyType.SINGLE) { |
|||
exporters = List.of(new Electrum()); |
|||
} else if(wallet.getPolicyType() == PolicyType.MULTI) { |
|||
exporters = List.of(new ColdcardMultisig(), new Electrum()); |
|||
} else { |
|||
throw new UnsupportedOperationException("Cannot export wallet with policy type " + wallet.getPolicyType()); |
|||
} |
|||
|
|||
Accordion exportAccordion = new Accordion(); |
|||
for (WalletExport exporter : exporters) { |
|||
FileWalletExportPane exportPane = new FileWalletExportPane(wallet, exporter); |
|||
exportAccordion.getPanes().add(exportPane); |
|||
} |
|||
scrollPane.setContent(exportAccordion); |
|||
|
|||
final ButtonType cancelButtonType = new javafx.scene.control.ButtonType("Cancel", ButtonBar.ButtonData.CANCEL_CLOSE); |
|||
dialogPane.getButtonTypes().addAll(cancelButtonType); |
|||
dialogPane.setPrefWidth(500); |
|||
dialogPane.setPrefHeight(360); |
|||
|
|||
setResultConverter(dialogButton -> dialogButton != cancelButtonType ? wallet : null); |
|||
} |
|||
|
|||
@Subscribe |
|||
public void walletExported(WalletExportEvent event) { |
|||
wallet = event.getWallet(); |
|||
setResult(wallet); |
|||
this.close(); |
|||
} |
|||
} |
@ -0,0 +1,9 @@ |
|||
package com.sparrowwallet.sparrow.event; |
|||
|
|||
import javafx.scene.control.Tab; |
|||
|
|||
public class TabSelectedEvent extends TabEvent { |
|||
public TabSelectedEvent(Tab tab) { |
|||
super(tab); |
|||
} |
|||
} |
@ -0,0 +1,15 @@ |
|||
package com.sparrowwallet.sparrow.event; |
|||
|
|||
import com.sparrowwallet.drongo.wallet.Wallet; |
|||
|
|||
public class WalletExportEvent { |
|||
private Wallet wallet; |
|||
|
|||
public WalletExportEvent(Wallet wallet) { |
|||
this.wallet = wallet; |
|||
} |
|||
|
|||
public Wallet getWallet() { |
|||
return wallet; |
|||
} |
|||
} |
@ -0,0 +1,9 @@ |
|||
package com.sparrowwallet.sparrow.event; |
|||
|
|||
import javafx.scene.control.Tab; |
|||
|
|||
public class WalletTabSelectedEvent extends TabSelectedEvent { |
|||
public WalletTabSelectedEvent(Tab tab) { |
|||
super(tab); |
|||
} |
|||
} |
@ -1,5 +1,8 @@ |
|||
package com.sparrowwallet.sparrow.io; |
|||
|
|||
import com.sparrowwallet.drongo.wallet.WalletModel; |
|||
|
|||
public interface Export { |
|||
String getName(); |
|||
WalletModel getWalletModel(); |
|||
} |
|||
|
Loading…
Reference in new issue