all walletconfig for wallet scope configuration variables
|
@ -110,6 +110,7 @@ dependencies {
|
||||||
implementation('net.sourceforge.streamsupport:streamsupport:1.7.0')
|
implementation('net.sourceforge.streamsupport:streamsupport:1.7.0')
|
||||||
implementation('com.github.librepdf:openpdf:1.3.27')
|
implementation('com.github.librepdf:openpdf:1.3.27')
|
||||||
implementation('com.googlecode.lanterna:lanterna:3.1.1')
|
implementation('com.googlecode.lanterna:lanterna:3.1.1')
|
||||||
|
implementation('net.coobird:thumbnailator:0.4.18')
|
||||||
testImplementation('junit:junit:4.12')
|
testImplementation('junit:junit:4.12')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -579,6 +580,10 @@ extraJavaModuleInfo {
|
||||||
module('jcip-annotations-1.0.jar', 'net.jcip.annotations', '1.0') {
|
module('jcip-annotations-1.0.jar', 'net.jcip.annotations', '1.0') {
|
||||||
exports('net.jcip.annotations')
|
exports('net.jcip.annotations')
|
||||||
}
|
}
|
||||||
|
module('thumbnailator-0.4.18.jar', 'net.coobird.thumbnailator', '0.4.18') {
|
||||||
|
exports('net.coobird.thumbnailator')
|
||||||
|
requires('java.desktop')
|
||||||
|
}
|
||||||
module("netlayer-jpms-${osName}${targetName}-0.6.8.jar", 'netlayer.jpms', '0.6.8') {
|
module("netlayer-jpms-${osName}${targetName}-0.6.8.jar", 'netlayer.jpms', '0.6.8') {
|
||||||
exports('org.berndpruenster.netlayer.tor')
|
exports('org.berndpruenster.netlayer.tor')
|
||||||
requires('com.github.ravn.jsocks')
|
requires('com.github.ravn.jsocks')
|
||||||
|
|
2
drongo
|
@ -1 +1 @@
|
||||||
Subproject commit 7c34ec7c3b818634b7819f1b27a5f9c57f5554c8
|
Subproject commit fa18ec9d458bb17221fb01b6be9f4eceb354a156
|
|
@ -1463,11 +1463,10 @@ public class AppController implements Initializable {
|
||||||
wallet.setName(name);
|
wallet.setName(name);
|
||||||
}
|
}
|
||||||
Tab tab = new Tab("");
|
Tab tab = new Tab("");
|
||||||
Glyph glyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.WALLET);
|
WalletIcon walletIcon = new WalletIcon(storage, wallet);
|
||||||
glyph.setFontSize(10.0);
|
walletIcon.setOpacity(TAB_LABEL_GRAPHIC_OPACITY_ACTIVE);
|
||||||
glyph.setOpacity(TAB_LABEL_GRAPHIC_OPACITY_ACTIVE);
|
|
||||||
Label tabLabel = new Label(name);
|
Label tabLabel = new Label(name);
|
||||||
tabLabel.setGraphic(glyph);
|
tabLabel.setGraphic(walletIcon);
|
||||||
tabLabel.setGraphicTextGap(5.0);
|
tabLabel.setGraphicTextGap(5.0);
|
||||||
tab.setGraphic(tabLabel);
|
tab.setGraphic(tabLabel);
|
||||||
tab.setClosable(true);
|
tab.setClosable(true);
|
||||||
|
@ -1856,17 +1855,61 @@ public class AppController implements Initializable {
|
||||||
|
|
||||||
contextMenu.getItems().addAll(new SeparatorMenuItem(), close, closeOthers, closeAll);
|
contextMenu.getItems().addAll(new SeparatorMenuItem(), close, closeOthers, closeAll);
|
||||||
|
|
||||||
if(tab.getUserData() instanceof WalletTabData) {
|
if(tab.getUserData() instanceof WalletTabData walletTabData) {
|
||||||
|
Menu walletIcon = new Menu("Wallet Icon");
|
||||||
|
MenuItem custom = new MenuItem("Custom...");
|
||||||
|
custom.setOnAction(event -> {
|
||||||
|
setCustomIcon(walletTabData.getWallet());
|
||||||
|
});
|
||||||
|
MenuItem reset = new MenuItem("Reset");
|
||||||
|
reset.setOnAction(event -> {
|
||||||
|
resetIcon(walletTabData.getWalletForm());
|
||||||
|
});
|
||||||
|
walletIcon.getItems().addAll(custom, reset);
|
||||||
|
|
||||||
MenuItem delete = new MenuItem("Delete...");
|
MenuItem delete = new MenuItem("Delete...");
|
||||||
delete.setOnAction(event -> {
|
delete.setOnAction(event -> {
|
||||||
deleteWallet(getSelectedWalletForm());
|
deleteWallet(walletTabData.getWalletForm());
|
||||||
});
|
});
|
||||||
contextMenu.getItems().addAll(new SeparatorMenuItem(), delete);
|
contextMenu.getItems().addAll(new SeparatorMenuItem(), walletIcon, delete);
|
||||||
}
|
}
|
||||||
|
|
||||||
return contextMenu;
|
return contextMenu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setCustomIcon(Wallet wallet) {
|
||||||
|
Stage window = new Stage();
|
||||||
|
|
||||||
|
FileChooser fileChooser = new FileChooser();
|
||||||
|
fileChooser.setTitle("Open Image");
|
||||||
|
fileChooser.getExtensionFilters().addAll(
|
||||||
|
new FileChooser.ExtensionFilter("All Files", org.controlsfx.tools.Platform.getCurrent().equals(org.controlsfx.tools.Platform.UNIX) ? "*" : "*.*"),
|
||||||
|
new FileChooser.ExtensionFilter("Images", "*.png", "*.jpg", "*.jpeg", "*.gif")
|
||||||
|
);
|
||||||
|
|
||||||
|
AppServices.moveToActiveWindowScreen(window, 800, 450);
|
||||||
|
File file = fileChooser.showOpenDialog(window);
|
||||||
|
if(file != null) {
|
||||||
|
try {
|
||||||
|
byte[] iconData = ImageUtils.resize(file, WalletIcon.SAVE_WIDTH, WalletIcon.SAVE_HEIGHT);
|
||||||
|
WalletConfig walletConfig = wallet.getMasterWalletConfig();
|
||||||
|
walletConfig.setIconData(iconData, true);
|
||||||
|
EventManager.get().post(new WalletConfigChangedEvent(wallet));
|
||||||
|
} catch(Exception e) {
|
||||||
|
log.error("Error creating custom wallet icon", e);
|
||||||
|
showErrorDialog("Error creating custom wallet icon", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resetIcon(WalletForm walletForm) {
|
||||||
|
Wallet masterWallet = walletForm.getMasterWallet();
|
||||||
|
if(masterWallet.getWalletConfig() != null && masterWallet.getWalletConfig().isUserIcon()) {
|
||||||
|
masterWallet.getWalletConfig().setIconData(null, false);
|
||||||
|
EventManager.get().post(new WalletConfigChangedEvent(masterWallet));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void deleteWallet(WalletForm selectedWalletForm) {
|
private void deleteWallet(WalletForm selectedWalletForm) {
|
||||||
Optional<ButtonType> optButtonType = AppServices.showWarningDialog("Delete " + selectedWalletForm.getWallet().getMasterName() + "?", "The wallet file and any backups will be deleted. Are you sure?", ButtonType.NO, ButtonType.YES);
|
Optional<ButtonType> optButtonType = AppServices.showWarningDialog("Delete " + selectedWalletForm.getWallet().getMasterName() + "?", "The wallet file and any backups will be deleted. Are you sure?", ButtonType.NO, ButtonType.YES);
|
||||||
if(optButtonType.isPresent() && optButtonType.get() == ButtonType.YES) {
|
if(optButtonType.isPresent() && optButtonType.get() == ButtonType.YES) {
|
||||||
|
@ -2071,8 +2114,8 @@ public class AppController implements Initializable {
|
||||||
|
|
||||||
private void tabLabelAddFailure(Tab tab) {
|
private void tabLabelAddFailure(Tab tab) {
|
||||||
Label tabLabel = (Label)tab.getGraphic();
|
Label tabLabel = (Label)tab.getGraphic();
|
||||||
if(!tabLabel.getStyleClass().contains("failure")) {
|
WalletIcon walletIcon = (WalletIcon)tabLabel.getGraphic();
|
||||||
tabLabel.getGraphic().getStyleClass().add("failure");
|
if(walletIcon.addFailure()) {
|
||||||
tabLabel.setTooltip(new Tooltip("Error loading transaction history from server"));
|
tabLabel.setTooltip(new Tooltip("Error loading transaction history from server"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2105,7 +2148,8 @@ public class AppController implements Initializable {
|
||||||
|
|
||||||
private void tabLabelRemoveFailure(Tab tab) {
|
private void tabLabelRemoveFailure(Tab tab) {
|
||||||
Label tabLabel = (Label)tab.getGraphic();
|
Label tabLabel = (Label)tab.getGraphic();
|
||||||
tabLabel.getGraphic().getStyleClass().remove("failure");
|
WalletIcon walletIcon = (WalletIcon)tabLabel.getGraphic();
|
||||||
|
walletIcon.removeFailure();
|
||||||
tabLabel.setTooltip(null);
|
tabLabel.setTooltip(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2222,6 +2266,9 @@ public class AppController implements Initializable {
|
||||||
Tab masterTab = subTabs.getTabs().stream().filter(tab -> ((WalletTabData)tab.getUserData()).getWallet().isMasterWallet()).findFirst().orElse(subTabs.getTabs().get(0));
|
Tab masterTab = subTabs.getTabs().stream().filter(tab -> ((WalletTabData)tab.getUserData()).getWallet().isMasterWallet()).findFirst().orElse(subTabs.getTabs().get(0));
|
||||||
Label masterLabel = (Label)masterTab.getGraphic();
|
Label masterLabel = (Label)masterTab.getGraphic();
|
||||||
masterLabel.setText(event.getWallet().getLabel() != null ? event.getWallet().getLabel() : event.getWallet().getAutomaticName());
|
masterLabel.setText(event.getWallet().getLabel() != null ? event.getWallet().getLabel() : event.getWallet().getAutomaticName());
|
||||||
|
Label tabLabel = (Label)walletTab.getGraphic();
|
||||||
|
WalletIcon walletIcon = (WalletIcon)tabLabel.getGraphic();
|
||||||
|
walletIcon.setWallet(event.getWallet());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2749,4 +2796,17 @@ public class AppController implements Initializable {
|
||||||
lockAllWallets.setDisable(false);
|
lockAllWallets.setDisable(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void walletConfigChanged(WalletConfigChangedEvent event) {
|
||||||
|
for(Tab tab : tabs.getTabs()) {
|
||||||
|
if(tab.getUserData() instanceof WalletTabData walletTabData) {
|
||||||
|
if(walletTabData.getWallet() == event.getWallet()) {
|
||||||
|
Label tabLabel = (Label)tab.getGraphic();
|
||||||
|
WalletIcon walletIcon = (WalletIcon)tabLabel.getGraphic();
|
||||||
|
walletIcon.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package com.sparrowwallet.sparrow;
|
||||||
|
|
||||||
import com.sparrowwallet.drongo.Network;
|
import com.sparrowwallet.drongo.Network;
|
||||||
import com.sparrowwallet.drongo.wallet.Wallet;
|
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||||
|
import com.sparrowwallet.sparrow.control.WalletIcon;
|
||||||
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
|
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
|
||||||
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5Brands;
|
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5Brands;
|
||||||
import com.sparrowwallet.sparrow.io.Config;
|
import com.sparrowwallet.sparrow.io.Config;
|
||||||
|
@ -18,6 +19,7 @@ import org.controlsfx.tools.Platform;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.net.URL;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@ -43,6 +45,7 @@ public class SparrowDesktop extends Application {
|
||||||
GlyphFontRegistry.register(new FontAwesome5());
|
GlyphFontRegistry.register(new FontAwesome5());
|
||||||
GlyphFontRegistry.register(new FontAwesome5Brands());
|
GlyphFontRegistry.register(new FontAwesome5Brands());
|
||||||
Font.loadFont(AppServices.class.getResourceAsStream("/font/RobotoMono-Regular.ttf"), 13);
|
Font.loadFont(AppServices.class.getResourceAsStream("/font/RobotoMono-Regular.ttf"), 13);
|
||||||
|
URL.setURLStreamHandlerFactory(protocol -> WalletIcon.PROTOCOL.equals(protocol) ? new WalletIcon.WalletIconStreamHandler() : null);
|
||||||
|
|
||||||
AppServices.initialize(this);
|
AppServices.initialize(this);
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,8 @@ package com.sparrowwallet.sparrow.control;
|
||||||
|
|
||||||
import com.sparrowwallet.drongo.bip47.PaymentCode;
|
import com.sparrowwallet.drongo.bip47.PaymentCode;
|
||||||
import com.sparrowwallet.sparrow.AppServices;
|
import com.sparrowwallet.sparrow.AppServices;
|
||||||
|
import com.sparrowwallet.sparrow.EventManager;
|
||||||
|
import com.sparrowwallet.sparrow.event.PayNymImageLoadedEvent;
|
||||||
import com.sparrowwallet.sparrow.io.Config;
|
import com.sparrowwallet.sparrow.io.Config;
|
||||||
import com.sparrowwallet.sparrow.paynym.PayNymService;
|
import com.sparrowwallet.sparrow.paynym.PayNymService;
|
||||||
import javafx.beans.property.ObjectProperty;
|
import javafx.beans.property.ObjectProperty;
|
||||||
|
@ -47,6 +49,7 @@ public class PayNymAvatar extends StackPane {
|
||||||
});
|
});
|
||||||
payNymAvatarService.setOnSucceeded(successEvent -> {
|
payNymAvatarService.setOnSucceeded(successEvent -> {
|
||||||
setImage(payNymAvatarService.getValue());
|
setImage(payNymAvatarService.getValue());
|
||||||
|
EventManager.get().post(new PayNymImageLoadedEvent(paymentCode, payNymAvatarService.getValue()));
|
||||||
});
|
});
|
||||||
payNymAvatarService.setOnFailed(failedEvent -> {
|
payNymAvatarService.setOnFailed(failedEvent -> {
|
||||||
log.debug("Error loading PayNym avatar", failedEvent.getSource().getException());
|
log.debug("Error loading PayNym avatar", failedEvent.getSource().getException());
|
||||||
|
|
167
src/main/java/com/sparrowwallet/sparrow/control/WalletIcon.java
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
package com.sparrowwallet.sparrow.control;
|
||||||
|
|
||||||
|
import com.sparrowwallet.drongo.wallet.*;
|
||||||
|
import com.sparrowwallet.sparrow.AppServices;
|
||||||
|
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
|
||||||
|
import com.sparrowwallet.sparrow.io.ImageUtils;
|
||||||
|
import com.sparrowwallet.sparrow.io.Storage;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.beans.property.ObjectProperty;
|
||||||
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
|
import javafx.geometry.Pos;
|
||||||
|
import javafx.scene.image.Image;
|
||||||
|
import javafx.scene.image.ImageView;
|
||||||
|
import javafx.scene.layout.StackPane;
|
||||||
|
import javafx.scene.paint.ImagePattern;
|
||||||
|
import javafx.scene.shape.Circle;
|
||||||
|
import org.controlsfx.glyphfont.Glyph;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
|
import java.net.URLStreamHandler;
|
||||||
|
|
||||||
|
public class WalletIcon extends StackPane {
|
||||||
|
public static final String PROTOCOL = "walleticon";
|
||||||
|
private static final String QUERY = "icon";
|
||||||
|
public static final int WIDTH = 15;
|
||||||
|
public static final int HEIGHT = 15;
|
||||||
|
public static final int SAVE_WIDTH = WIDTH * 2;
|
||||||
|
public static final int SAVE_HEIGHT = HEIGHT * 2;
|
||||||
|
|
||||||
|
private final Storage storage;
|
||||||
|
private final ObjectProperty<Wallet> walletProperty = new SimpleObjectProperty<>();
|
||||||
|
|
||||||
|
public WalletIcon(Storage storage, Wallet wallet) {
|
||||||
|
super();
|
||||||
|
this.storage = storage;
|
||||||
|
setPrefSize(WIDTH, HEIGHT);
|
||||||
|
walletProperty.addListener((observable, oldValue, newValue) -> {
|
||||||
|
refresh();
|
||||||
|
});
|
||||||
|
walletProperty.set(wallet);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void refresh() {
|
||||||
|
Wallet wallet = getWallet();
|
||||||
|
|
||||||
|
getChildren().clear();
|
||||||
|
if(wallet.getWalletConfig() != null && wallet.getWalletConfig().getIconData() != null) {
|
||||||
|
String walletId = storage.getWalletId(wallet);
|
||||||
|
if(AppServices.get().getWallet(walletId) != null) {
|
||||||
|
addWalletIcon(walletId);
|
||||||
|
} else {
|
||||||
|
Platform.runLater(() -> addWalletIcon(walletId));
|
||||||
|
}
|
||||||
|
} else if(wallet.getKeystores().size() == 1) {
|
||||||
|
Keystore keystore = wallet.getKeystores().get(0);
|
||||||
|
if(keystore.getSource() == KeystoreSource.HW_USB || keystore.getSource() == KeystoreSource.HW_AIRGAPPED) {
|
||||||
|
WalletModel walletModel = keystore.getWalletModel();
|
||||||
|
|
||||||
|
Image image = null;
|
||||||
|
try {
|
||||||
|
image = new Image("image/" + walletModel.getType() + "-icon.png", 15, 15, true, true);
|
||||||
|
} catch(Exception e) {
|
||||||
|
//ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
if(image == null) {
|
||||||
|
try {
|
||||||
|
image = new Image("image/" + walletModel.getType() + ".png", 15, 15, true, true);
|
||||||
|
} catch(Exception e) {
|
||||||
|
//ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(image != null && !image.isError()) {
|
||||||
|
ImageView imageView = new ImageView(image);
|
||||||
|
getChildren().add(imageView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(getChildren().isEmpty()) {
|
||||||
|
Glyph glyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.WALLET);
|
||||||
|
glyph.setFontSize(10.0);
|
||||||
|
getChildren().add(glyph);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addWalletIcon(String walletId) {
|
||||||
|
Image image = new Image(PROTOCOL + ":" + walletId + "?" + QUERY, WIDTH, HEIGHT, true, false);
|
||||||
|
getChildren().clear();
|
||||||
|
Circle circle = new Circle(getPrefWidth() / 2,getPrefHeight() / 2,getPrefWidth() / 2);
|
||||||
|
circle.setFill(new ImagePattern(image));
|
||||||
|
getChildren().add(circle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean addFailure() {
|
||||||
|
if(getChildren().stream().noneMatch(node -> node.getStyleClass().contains("failure"))) {
|
||||||
|
Glyph failGlyph = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.EXCLAMATION_CIRCLE);
|
||||||
|
failGlyph.setFontSize(10);
|
||||||
|
failGlyph.getStyleClass().add("failure");
|
||||||
|
getChildren().add(failGlyph);
|
||||||
|
StackPane.setAlignment(failGlyph, Pos.TOP_RIGHT);
|
||||||
|
failGlyph.setTranslateX(5);
|
||||||
|
failGlyph.setTranslateY(-4);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeFailure() {
|
||||||
|
getChildren().removeIf(node -> node.getStyleClass().contains("failure"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Wallet getWallet() {
|
||||||
|
return walletProperty.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObjectProperty<Wallet> walletProperty() {
|
||||||
|
return walletProperty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWallet(Wallet wallet) {
|
||||||
|
this.walletProperty.set(wallet);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class WalletIconStreamHandler extends URLStreamHandler {
|
||||||
|
@Override
|
||||||
|
protected URLConnection openConnection(URL url) throws IOException {
|
||||||
|
return new URLConnection(url) {
|
||||||
|
@Override
|
||||||
|
public void connect() throws IOException {
|
||||||
|
//Nothing required
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream getInputStream() throws IOException {
|
||||||
|
String walletId = url.getPath();
|
||||||
|
String query = url.getQuery();
|
||||||
|
|
||||||
|
Wallet wallet = AppServices.get().getWallet(walletId);
|
||||||
|
if(wallet == null) {
|
||||||
|
throw new IOException("Cannot find wallet for wallet id " + walletId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(query.startsWith(QUERY)) {
|
||||||
|
if(wallet.getWalletConfig() == null || wallet.getWalletConfig().getIconData() == null) {
|
||||||
|
throw new IOException("No icon data for " + walletId);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteArrayInputStream bais = new ByteArrayInputStream(wallet.getWalletConfig().getIconData());
|
||||||
|
if(query.endsWith("@2x")) {
|
||||||
|
return bais;
|
||||||
|
} else {
|
||||||
|
return ImageUtils.resize(bais, WalletIcon.WIDTH, WalletIcon.HEIGHT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new MalformedURLException("Cannot load url " + url);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.sparrowwallet.sparrow.event;
|
||||||
|
|
||||||
|
import com.sparrowwallet.drongo.bip47.PaymentCode;
|
||||||
|
import javafx.scene.image.Image;
|
||||||
|
|
||||||
|
public class PayNymImageLoadedEvent {
|
||||||
|
private final PaymentCode paymentCode;
|
||||||
|
private final Image image;
|
||||||
|
|
||||||
|
public PayNymImageLoadedEvent(PaymentCode paymentCode, Image image) {
|
||||||
|
this.paymentCode = paymentCode;
|
||||||
|
this.image = image;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PaymentCode getPaymentCode() {
|
||||||
|
return paymentCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Image getImage() {
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.sparrowwallet.sparrow.event;
|
||||||
|
|
||||||
|
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||||
|
|
||||||
|
public class WalletConfigChangedEvent extends WalletChangedEvent {
|
||||||
|
public WalletConfigChangedEvent(Wallet wallet) {
|
||||||
|
super(wallet);
|
||||||
|
}
|
||||||
|
}
|
56
src/main/java/com/sparrowwallet/sparrow/io/ImageUtils.java
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
package com.sparrowwallet.sparrow.io;
|
||||||
|
|
||||||
|
import javafx.embed.swing.SwingFXUtils;
|
||||||
|
import javafx.scene.image.Image;
|
||||||
|
import net.coobird.thumbnailator.Thumbnails;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
|
public class ImageUtils {
|
||||||
|
public static byte[] resize(Image image, int width, int height) {
|
||||||
|
return resize(SwingFXUtils.fromFXImage(image, null), width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] resize(BufferedImage image, int width, int height) {
|
||||||
|
try {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
resize(image, baos, width, height);
|
||||||
|
return baos.toByteArray();
|
||||||
|
} catch(IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void resize(BufferedImage image, OutputStream outputStream, int width, int height) throws IOException {
|
||||||
|
resize(Thumbnails.of(image), outputStream, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] resize(File file, int width, int height) throws IOException {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
resize(file, baos, width, height);
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void resize(File file, OutputStream outputStream, int width, int height) throws IOException {
|
||||||
|
resize(Thumbnails.of(file), outputStream, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InputStream resize(InputStream inputStream, int width, int height) {
|
||||||
|
try {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
resize(inputStream, baos, width, height);
|
||||||
|
return new ByteArrayInputStream(baos.toByteArray());
|
||||||
|
} catch(IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void resize(InputStream inputStream, OutputStream outputStream, int width, int height) throws IOException {
|
||||||
|
resize(Thumbnails.of(inputStream), outputStream, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void resize(Thumbnails.Builder<?> builder, OutputStream outputStream, int width, int height) throws IOException {
|
||||||
|
builder.size(width, height).outputFormat("png").outputQuality(1).toOutputStream(outputStream);
|
||||||
|
}
|
||||||
|
}
|
|
@ -315,6 +315,11 @@ public class DbPersistence implements Persistence {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(dirtyPersistables.walletConfig) {
|
||||||
|
WalletConfigDao walletConfigDao = handle.attach(WalletConfigDao.class);
|
||||||
|
walletConfigDao.addOrUpdate(wallet, wallet.getWalletConfig());
|
||||||
|
}
|
||||||
|
|
||||||
if(dirtyPersistables.mixConfig) {
|
if(dirtyPersistables.mixConfig) {
|
||||||
MixConfigDao mixConfigDao = handle.attach(MixConfigDao.class);
|
MixConfigDao mixConfigDao = handle.attach(MixConfigDao.class);
|
||||||
mixConfigDao.addOrUpdate(wallet, wallet.getMixConfig());
|
mixConfigDao.addOrUpdate(wallet, wallet.getMixConfig());
|
||||||
|
@ -745,6 +750,13 @@ public class DbPersistence implements Persistence {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void walletConfigChanged(WalletConfigChangedEvent event) {
|
||||||
|
if(persistsFor(event.getWallet()) && event.getWallet().getWalletConfig() != null) {
|
||||||
|
updateExecutor.execute(() -> dirtyPersistablesMap.computeIfAbsent(event.getWallet(), key -> new DirtyPersistables()).walletConfig = true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void walletMixConfigChanged(WalletMixConfigChangedEvent event) {
|
public void walletMixConfigChanged(WalletMixConfigChangedEvent event) {
|
||||||
if(persistsFor(event.getWallet()) && event.getWallet().getMixConfig() != null) {
|
if(persistsFor(event.getWallet()) && event.getWallet().getMixConfig() != null) {
|
||||||
|
@ -793,6 +805,7 @@ public class DbPersistence implements Persistence {
|
||||||
public Integer watchLast = null;
|
public Integer watchLast = null;
|
||||||
public final List<Entry> labelEntries = new ArrayList<>();
|
public final List<Entry> labelEntries = new ArrayList<>();
|
||||||
public final List<BlockTransactionHashIndex> utxoStatuses = new ArrayList<>();
|
public final List<BlockTransactionHashIndex> utxoStatuses = new ArrayList<>();
|
||||||
|
public boolean walletConfig;
|
||||||
public boolean mixConfig;
|
public boolean mixConfig;
|
||||||
public final Map<Sha256Hash, UtxoMixData> changedUtxoMixes = new HashMap<>();
|
public final Map<Sha256Hash, UtxoMixData> changedUtxoMixes = new HashMap<>();
|
||||||
public final Map<Sha256Hash, UtxoMixData> removedUtxoMixes = new HashMap<>();
|
public final Map<Sha256Hash, UtxoMixData> removedUtxoMixes = new HashMap<>();
|
||||||
|
@ -812,6 +825,7 @@ public class DbPersistence implements Persistence {
|
||||||
"\nAddress labels:" + labelEntries.stream().filter(entry -> entry instanceof NodeEntry).map(entry -> ((NodeEntry)entry).getNode().toString() + " " + entry.getLabel()).collect(Collectors.toList()) +
|
"\nAddress labels:" + labelEntries.stream().filter(entry -> entry instanceof NodeEntry).map(entry -> ((NodeEntry)entry).getNode().toString() + " " + entry.getLabel()).collect(Collectors.toList()) +
|
||||||
"\nUTXO labels:" + labelEntries.stream().filter(entry -> entry instanceof HashIndexEntry).map(entry -> ((HashIndexEntry)entry).getHashIndex().toString()).collect(Collectors.toList()) +
|
"\nUTXO labels:" + labelEntries.stream().filter(entry -> entry instanceof HashIndexEntry).map(entry -> ((HashIndexEntry)entry).getHashIndex().toString()).collect(Collectors.toList()) +
|
||||||
"\nUTXO statuses:" + utxoStatuses +
|
"\nUTXO statuses:" + utxoStatuses +
|
||||||
|
"\nWallet config:" + walletConfig +
|
||||||
"\nMix config:" + mixConfig +
|
"\nMix config:" + mixConfig +
|
||||||
"\nUTXO mixes changed:" + changedUtxoMixes +
|
"\nUTXO mixes changed:" + changedUtxoMixes +
|
||||||
"\nUTXO mixes removed:" + removedUtxoMixes +
|
"\nUTXO mixes removed:" + removedUtxoMixes +
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
package com.sparrowwallet.sparrow.io.db;
|
||||||
|
|
||||||
|
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||||
|
import com.sparrowwallet.drongo.wallet.WalletConfig;
|
||||||
|
import org.jdbi.v3.sqlobject.config.RegisterRowMapper;
|
||||||
|
import org.jdbi.v3.sqlobject.statement.GetGeneratedKeys;
|
||||||
|
import org.jdbi.v3.sqlobject.statement.SqlQuery;
|
||||||
|
import org.jdbi.v3.sqlobject.statement.SqlUpdate;
|
||||||
|
|
||||||
|
public interface WalletConfigDao {
|
||||||
|
@SqlQuery("select id, iconData, userIcon, usePayNym from walletConfig where wallet = ?")
|
||||||
|
@RegisterRowMapper(WalletConfigMapper.class)
|
||||||
|
WalletConfig getForWalletId(Long id);
|
||||||
|
|
||||||
|
@SqlUpdate("insert into walletConfig (iconData, userIcon, usePayNym, wallet) values (?, ?, ?, ?)")
|
||||||
|
@GetGeneratedKeys("id")
|
||||||
|
long insertWalletConfig(byte[] iconData, boolean userIcon, boolean usePayNym, long wallet);
|
||||||
|
|
||||||
|
@SqlUpdate("update walletConfig set iconData = ?, userIcon = ?, usePayNym = ?, wallet = ? where id = ?")
|
||||||
|
void updateWalletConfig(byte[] iconData, boolean userIcon, boolean usePayNym, long wallet, long id);
|
||||||
|
|
||||||
|
default void addWalletConfig(Wallet wallet) {
|
||||||
|
if(wallet.getWalletConfig() != null) {
|
||||||
|
addOrUpdate(wallet, wallet.getWalletConfig());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default void addOrUpdate(Wallet wallet, WalletConfig walletConfig) {
|
||||||
|
if(walletConfig.getId() == null) {
|
||||||
|
long id = insertWalletConfig(walletConfig.getIconData(), walletConfig.isUserIcon(), walletConfig.isUsePayNym(), wallet.getId());
|
||||||
|
walletConfig.setId(id);
|
||||||
|
} else {
|
||||||
|
updateWalletConfig(walletConfig.getIconData(), walletConfig.isUserIcon(), walletConfig.isUsePayNym(), wallet.getId(), walletConfig.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package com.sparrowwallet.sparrow.io.db;
|
||||||
|
|
||||||
|
import com.sparrowwallet.drongo.wallet.WalletConfig;
|
||||||
|
import org.jdbi.v3.core.mapper.RowMapper;
|
||||||
|
import org.jdbi.v3.core.statement.StatementContext;
|
||||||
|
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
public class WalletConfigMapper implements RowMapper<WalletConfig> {
|
||||||
|
@Override
|
||||||
|
public WalletConfig map(ResultSet rs, StatementContext ctx) throws SQLException {
|
||||||
|
byte[] iconData = rs.getBytes("iconData");
|
||||||
|
boolean userIcon = rs.getBoolean("userIcon");
|
||||||
|
boolean usePayNym = rs.getBoolean("usePayNym");
|
||||||
|
|
||||||
|
WalletConfig walletConfig = new WalletConfig(iconData, userIcon, usePayNym);
|
||||||
|
walletConfig.setId(rs.getLong("id"));
|
||||||
|
return walletConfig;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,7 @@
|
||||||
package com.sparrowwallet.sparrow.io.db;
|
package com.sparrowwallet.sparrow.io.db;
|
||||||
|
|
||||||
import com.sparrowwallet.drongo.protocol.Sha256Hash;
|
import com.sparrowwallet.drongo.protocol.Sha256Hash;
|
||||||
import com.sparrowwallet.drongo.wallet.BlockTransaction;
|
import com.sparrowwallet.drongo.wallet.*;
|
||||||
import com.sparrowwallet.drongo.wallet.UtxoMixData;
|
|
||||||
import com.sparrowwallet.drongo.wallet.Wallet;
|
|
||||||
import com.sparrowwallet.drongo.wallet.WalletNode;
|
|
||||||
import org.jdbi.v3.sqlobject.CreateSqlObject;
|
import org.jdbi.v3.sqlobject.CreateSqlObject;
|
||||||
import org.jdbi.v3.sqlobject.config.RegisterRowMapper;
|
import org.jdbi.v3.sqlobject.config.RegisterRowMapper;
|
||||||
import org.jdbi.v3.sqlobject.customizer.Bind;
|
import org.jdbi.v3.sqlobject.customizer.Bind;
|
||||||
|
@ -33,6 +30,9 @@ public interface WalletDao {
|
||||||
@CreateSqlObject
|
@CreateSqlObject
|
||||||
DetachedLabelDao createDetachedLabelDao();
|
DetachedLabelDao createDetachedLabelDao();
|
||||||
|
|
||||||
|
@CreateSqlObject
|
||||||
|
WalletConfigDao createWalletConfigDao();
|
||||||
|
|
||||||
@CreateSqlObject
|
@CreateSqlObject
|
||||||
MixConfigDao createMixConfigDao();
|
MixConfigDao createMixConfigDao();
|
||||||
|
|
||||||
|
@ -118,6 +118,7 @@ public interface WalletDao {
|
||||||
Map<String, String> detachedLabels = createDetachedLabelDao().getAll();
|
Map<String, String> detachedLabels = createDetachedLabelDao().getAll();
|
||||||
wallet.getDetachedLabels().putAll(detachedLabels);
|
wallet.getDetachedLabels().putAll(detachedLabels);
|
||||||
|
|
||||||
|
wallet.setWalletConfig(createWalletConfigDao().getForWalletId(wallet.getId()));
|
||||||
wallet.setMixConfig(createMixConfigDao().getForWalletId(wallet.getId()));
|
wallet.setMixConfig(createMixConfigDao().getForWalletId(wallet.getId()));
|
||||||
|
|
||||||
Map<Sha256Hash, UtxoMixData> utxoMixes = createUtxoMixDataDao().getForWalletId(wallet.getId());
|
Map<Sha256Hash, UtxoMixData> utxoMixes = createUtxoMixDataDao().getForWalletId(wallet.getId());
|
||||||
|
@ -136,6 +137,7 @@ public interface WalletDao {
|
||||||
createWalletNodeDao().addWalletNodes(wallet);
|
createWalletNodeDao().addWalletNodes(wallet);
|
||||||
createBlockTransactionDao().addBlockTransactions(wallet);
|
createBlockTransactionDao().addBlockTransactions(wallet);
|
||||||
createDetachedLabelDao().clearAndAddAll(wallet);
|
createDetachedLabelDao().clearAndAddAll(wallet);
|
||||||
|
createWalletConfigDao().addWalletConfig(wallet);
|
||||||
createMixConfigDao().addMixConfig(wallet);
|
createMixConfigDao().addMixConfig(wallet);
|
||||||
createUtxoMixDataDao().addUtxoMixData(wallet);
|
createUtxoMixDataDao().addUtxoMixData(wallet);
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
@ -165,7 +165,7 @@ public class PayNymController {
|
||||||
followersList.setSelectionModel(new NoSelectionModel<>());
|
followersList.setSelectionModel(new NoSelectionModel<>());
|
||||||
followersList.setFocusTraversable(false);
|
followersList.setFocusTraversable(false);
|
||||||
|
|
||||||
if(Config.get().isUsePayNym() && AppServices.isConnected() && masterWallet.hasPaymentCode()) {
|
if(isUsePayNym(masterWallet) && AppServices.isConnected() && masterWallet.hasPaymentCode()) {
|
||||||
refresh();
|
refresh();
|
||||||
} else {
|
} else {
|
||||||
payNymName.setVisible(false);
|
payNymName.setVisible(false);
|
||||||
|
@ -260,9 +260,9 @@ public class PayNymController {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void retrievePayNym(ActionEvent event) {
|
public void retrievePayNym(ActionEvent event) {
|
||||||
Config.get().setUsePayNym(true);
|
|
||||||
PayNymService payNymService = AppServices.getPayNymService();
|
PayNymService payNymService = AppServices.getPayNymService();
|
||||||
Wallet masterWallet = getMasterWallet();
|
Wallet masterWallet = getMasterWallet();
|
||||||
|
setUsePayNym(masterWallet, true);
|
||||||
payNymService.createPayNym(masterWallet).subscribe(createMap -> {
|
payNymService.createPayNym(masterWallet).subscribe(createMap -> {
|
||||||
payNymName.setText((String)createMap.get("nymName"));
|
payNymName.setText((String)createMap.get("nymName"));
|
||||||
payNymAvatar.setPaymentCode(masterWallet.getPaymentCode());
|
payNymAvatar.setPaymentCode(masterWallet.getPaymentCode());
|
||||||
|
@ -630,6 +630,31 @@ public class PayNymController {
|
||||||
return wallet.isMasterWallet() ? wallet : wallet.getMasterWallet();
|
return wallet.isMasterWallet() ? wallet : wallet.getMasterWallet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean isUsePayNym(Wallet wallet) {
|
||||||
|
//TODO: Remove config setting
|
||||||
|
boolean usePayNym = Config.get().isUsePayNym();
|
||||||
|
if(usePayNym && wallet != null) {
|
||||||
|
setUsePayNym(wallet, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return usePayNym;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setUsePayNym(Wallet wallet, boolean usePayNym) {
|
||||||
|
//TODO: Remove config setting
|
||||||
|
if(Config.get().isUsePayNym() != usePayNym) {
|
||||||
|
Config.get().setUsePayNym(usePayNym);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(wallet != null) {
|
||||||
|
WalletConfig walletConfig = wallet.getMasterWalletConfig();
|
||||||
|
if(walletConfig.isUsePayNym() != usePayNym) {
|
||||||
|
walletConfig.setUsePayNym(usePayNym);
|
||||||
|
EventManager.get().post(new WalletConfigChangedEvent(wallet.isMasterWallet() ? wallet : wallet.getMasterWallet()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isSelectLinkedOnly() {
|
public boolean isSelectLinkedOnly() {
|
||||||
return selectLinkedOnly;
|
return selectLinkedOnly;
|
||||||
}
|
}
|
||||||
|
|
|
@ -174,7 +174,7 @@ public class CounterpartyController extends SorobanController {
|
||||||
payNymAvatar.visibleProperty().bind(payNym.visibleProperty());
|
payNymAvatar.visibleProperty().bind(payNym.visibleProperty());
|
||||||
payNymButton.managedProperty().bind(payNymButton.visibleProperty());
|
payNymButton.managedProperty().bind(payNymButton.visibleProperty());
|
||||||
payNymButton.visibleProperty().bind(payNym.visibleProperty().not());
|
payNymButton.visibleProperty().bind(payNym.visibleProperty().not());
|
||||||
if(Config.get().isUsePayNym()) {
|
if(isUsePayNym(wallet)) {
|
||||||
retrievePayNym(null);
|
retrievePayNym(null);
|
||||||
} else {
|
} else {
|
||||||
payNym.setVisible(false);
|
payNym.setVisible(false);
|
||||||
|
@ -270,7 +270,7 @@ public class CounterpartyController extends SorobanController {
|
||||||
private void updateMixPartner(PaymentCode paymentCodeInitiator, CahootsType cahootsType) {
|
private void updateMixPartner(PaymentCode paymentCodeInitiator, CahootsType cahootsType) {
|
||||||
String code = paymentCodeInitiator.toString();
|
String code = paymentCodeInitiator.toString();
|
||||||
mixingPartner.setText(code.substring(0, 12) + "..." + code.substring(code.length() - 5));
|
mixingPartner.setText(code.substring(0, 12) + "..." + code.substring(code.length() - 5));
|
||||||
if(Config.get().isUsePayNym()) {
|
if(isUsePayNym(wallet)) {
|
||||||
mixPartnerAvatar.setPaymentCode(paymentCodeInitiator);
|
mixPartnerAvatar.setPaymentCode(paymentCodeInitiator);
|
||||||
AppServices.getPayNymService().getPayNym(paymentCodeInitiator.toString()).subscribe(payNym -> {
|
AppServices.getPayNymService().getPayNym(paymentCodeInitiator.toString()).subscribe(payNym -> {
|
||||||
mixingPartner.setText(payNym.nymName());
|
mixingPartner.setText(payNym.nymName());
|
||||||
|
@ -351,7 +351,7 @@ public class CounterpartyController extends SorobanController {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void followPaymentCode(PaymentCode paymentCodeInitiator) {
|
private void followPaymentCode(PaymentCode paymentCodeInitiator) {
|
||||||
if(Config.get().isUsePayNym()) {
|
if(isUsePayNym(wallet)) {
|
||||||
PayNymService payNymService = AppServices.getPayNymService();
|
PayNymService payNymService = AppServices.getPayNymService();
|
||||||
payNymService.getAuthToken(wallet, new HashMap<>()).subscribe(authToken -> {
|
payNymService.getAuthToken(wallet, new HashMap<>()).subscribe(authToken -> {
|
||||||
String signature = payNymService.getSignature(wallet, authToken);
|
String signature = payNymService.getSignature(wallet, authToken);
|
||||||
|
@ -393,7 +393,7 @@ public class CounterpartyController extends SorobanController {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void retrievePayNym(ActionEvent event) {
|
public void retrievePayNym(ActionEvent event) {
|
||||||
Config.get().setUsePayNym(true);
|
setUsePayNym(wallet, true);
|
||||||
|
|
||||||
PayNymService payNymService = AppServices.getPayNymService();
|
PayNymService payNymService = AppServices.getPayNymService();
|
||||||
payNymService.createPayNym(wallet).subscribe(createMap -> {
|
payNymService.createPayNym(wallet).subscribe(createMap -> {
|
||||||
|
|
|
@ -158,7 +158,7 @@ public class InitiatorController extends SorobanController {
|
||||||
if(newValue != null) {
|
if(newValue != null) {
|
||||||
if(newValue.startsWith("P") && newValue.contains("...") && newValue.length() == 20 && counterpartyPaymentCode.get() != null) {
|
if(newValue.startsWith("P") && newValue.contains("...") && newValue.length() == 20 && counterpartyPaymentCode.get() != null) {
|
||||||
//Assumed valid payment code
|
//Assumed valid payment code
|
||||||
} else if(Config.get().isUsePayNym() && PAYNYM_REGEX.matcher(newValue).matches()) {
|
} else if(isUsePayNym(wallet) && PAYNYM_REGEX.matcher(newValue).matches()) {
|
||||||
if(!newValue.equals(counterpartyPayNymName.get())) {
|
if(!newValue.equals(counterpartyPayNymName.get())) {
|
||||||
searchPayNyms(newValue);
|
searchPayNyms(newValue);
|
||||||
}
|
}
|
||||||
|
@ -233,7 +233,7 @@ public class InitiatorController extends SorobanController {
|
||||||
payNymFollowers.prefWidthProperty().bind(counterparty.widthProperty());
|
payNymFollowers.prefWidthProperty().bind(counterparty.widthProperty());
|
||||||
payNymFollowers.valueProperty().addListener((observable, oldValue, payNym) -> {
|
payNymFollowers.valueProperty().addListener((observable, oldValue, payNym) -> {
|
||||||
if(payNym == FIND_FOLLOWERS) {
|
if(payNym == FIND_FOLLOWERS) {
|
||||||
Config.get().setUsePayNym(true);
|
setUsePayNym(wallet, true);
|
||||||
setPayNymFollowers();
|
setPayNymFollowers();
|
||||||
} else if(payNym != null) {
|
} else if(payNym != null) {
|
||||||
counterpartyPayNymName.set(payNym.nymName());
|
counterpartyPayNymName.set(payNym.nymName());
|
||||||
|
@ -349,7 +349,7 @@ public class InitiatorController extends SorobanController {
|
||||||
payNymFollowers.setItems(FXCollections.observableList(followerPayNyms));
|
payNymFollowers.setItems(FXCollections.observableList(followerPayNyms));
|
||||||
}, error -> {
|
}, error -> {
|
||||||
if(error.getMessage().endsWith("404")) {
|
if(error.getMessage().endsWith("404")) {
|
||||||
Config.get().setUsePayNym(false);
|
setUsePayNym(masterWallet, false);
|
||||||
AppServices.showErrorDialog("Could not retrieve PayNym", "This wallet does not have an associated PayNym or any followers yet. You can retrieve the PayNym using the Find PayNym button.");
|
AppServices.showErrorDialog("Could not retrieve PayNym", "This wallet does not have an associated PayNym or any followers yet. You can retrieve the PayNym using the Find PayNym button.");
|
||||||
} else {
|
} else {
|
||||||
log.warn("Could not retrieve followers: ", error);
|
log.warn("Could not retrieve followers: ", error);
|
||||||
|
|
|
@ -10,7 +10,10 @@ import com.sparrowwallet.drongo.protocol.TransactionOutput;
|
||||||
import com.sparrowwallet.drongo.psbt.PSBT;
|
import com.sparrowwallet.drongo.psbt.PSBT;
|
||||||
import com.sparrowwallet.drongo.psbt.PSBTParseException;
|
import com.sparrowwallet.drongo.psbt.PSBTParseException;
|
||||||
import com.sparrowwallet.drongo.wallet.*;
|
import com.sparrowwallet.drongo.wallet.*;
|
||||||
|
import com.sparrowwallet.sparrow.EventManager;
|
||||||
import com.sparrowwallet.sparrow.control.TransactionDiagram;
|
import com.sparrowwallet.sparrow.control.TransactionDiagram;
|
||||||
|
import com.sparrowwallet.sparrow.event.WalletConfigChangedEvent;
|
||||||
|
import com.sparrowwallet.sparrow.io.Config;
|
||||||
import com.sparrowwallet.sparrow.net.ElectrumServer;
|
import com.sparrowwallet.sparrow.net.ElectrumServer;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -126,4 +129,29 @@ public class SorobanController {
|
||||||
Taskbar.getTaskbar().requestUserAttention(true, false);
|
Taskbar.getTaskbar().requestUserAttention(true, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean isUsePayNym(Wallet wallet) {
|
||||||
|
//TODO: Remove config setting
|
||||||
|
boolean usePayNym = Config.get().isUsePayNym();
|
||||||
|
if(usePayNym && wallet != null) {
|
||||||
|
setUsePayNym(wallet, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return usePayNym;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setUsePayNym(Wallet wallet, boolean usePayNym) {
|
||||||
|
//TODO: Remove config setting
|
||||||
|
if(Config.get().isUsePayNym() != usePayNym) {
|
||||||
|
Config.get().setUsePayNym(usePayNym);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(wallet != null) {
|
||||||
|
WalletConfig walletConfig = wallet.getMasterWalletConfig();
|
||||||
|
if(walletConfig.isUsePayNym() != usePayNym) {
|
||||||
|
walletConfig.setUsePayNym(usePayNym);
|
||||||
|
EventManager.get().post(new WalletConfigChangedEvent(wallet.isMasterWallet() ? wallet : wallet.getMasterWallet()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import com.sparrowwallet.sparrow.control.*;
|
||||||
import com.sparrowwallet.sparrow.event.*;
|
import com.sparrowwallet.sparrow.event.*;
|
||||||
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
|
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
|
||||||
import com.sparrowwallet.sparrow.io.Config;
|
import com.sparrowwallet.sparrow.io.Config;
|
||||||
|
import com.sparrowwallet.sparrow.io.Storage;
|
||||||
import com.sparrowwallet.sparrow.net.ExchangeSource;
|
import com.sparrowwallet.sparrow.net.ExchangeSource;
|
||||||
import com.sparrowwallet.sparrow.paynym.PayNym;
|
import com.sparrowwallet.sparrow.paynym.PayNym;
|
||||||
import com.sparrowwallet.sparrow.paynym.PayNymAddress;
|
import com.sparrowwallet.sparrow.paynym.PayNymAddress;
|
||||||
|
@ -39,6 +40,7 @@ import javafx.collections.ListChangeListener;
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.*;
|
import javafx.scene.control.*;
|
||||||
import org.controlsfx.glyphfont.Glyph;
|
import org.controlsfx.glyphfont.Glyph;
|
||||||
import org.controlsfx.validation.ValidationResult;
|
import org.controlsfx.validation.ValidationResult;
|
||||||
|
@ -176,7 +178,7 @@ public class PaymentController extends WalletFormController implements Initializ
|
||||||
setGraphic(null);
|
setGraphic(null);
|
||||||
} else {
|
} else {
|
||||||
setText(wallet.getFullDisplayName() + (wallet == sendController.getWalletForm().getWallet() ? " (Consolidation)" : ""));
|
setText(wallet.getFullDisplayName() + (wallet == sendController.getWalletForm().getWallet() ? " (Consolidation)" : ""));
|
||||||
setGraphic(wallet == payNymWallet ? getPayNymGlyph() : null);
|
setGraphic(getOpenWalletIcon(wallet));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -325,6 +327,20 @@ public class PaymentController extends WalletFormController implements Initializ
|
||||||
openWallets.setItems(FXCollections.observableList(openWalletList));
|
openWallets.setItems(FXCollections.observableList(openWalletList));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Node getOpenWalletIcon(Wallet wallet) {
|
||||||
|
if(wallet == payNymWallet) {
|
||||||
|
return getPayNymGlyph();
|
||||||
|
}
|
||||||
|
|
||||||
|
Wallet masterWallet = wallet.isMasterWallet() ? wallet : wallet.getMasterWallet();
|
||||||
|
Storage storage = AppServices.get().getOpenWallets().get(masterWallet);
|
||||||
|
if(storage != null) {
|
||||||
|
return new WalletIcon(storage, masterWallet);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private void addValidation(ValidationSupport validationSupport) {
|
private void addValidation(ValidationSupport validationSupport) {
|
||||||
this.validationSupport = validationSupport;
|
this.validationSupport = validationSupport;
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,9 @@ import com.sparrowwallet.drongo.wallet.*;
|
||||||
import com.sparrowwallet.sparrow.AppServices;
|
import com.sparrowwallet.sparrow.AppServices;
|
||||||
import com.sparrowwallet.sparrow.EventManager;
|
import com.sparrowwallet.sparrow.EventManager;
|
||||||
import com.sparrowwallet.sparrow.WalletTabData;
|
import com.sparrowwallet.sparrow.WalletTabData;
|
||||||
|
import com.sparrowwallet.sparrow.control.WalletIcon;
|
||||||
import com.sparrowwallet.sparrow.event.*;
|
import com.sparrowwallet.sparrow.event.*;
|
||||||
|
import com.sparrowwallet.sparrow.io.ImageUtils;
|
||||||
import com.sparrowwallet.sparrow.io.StorageException;
|
import com.sparrowwallet.sparrow.io.StorageException;
|
||||||
import com.sparrowwallet.sparrow.net.AllHistoryChangedException;
|
import com.sparrowwallet.sparrow.net.AllHistoryChangedException;
|
||||||
import com.sparrowwallet.sparrow.net.ElectrumServer;
|
import com.sparrowwallet.sparrow.net.ElectrumServer;
|
||||||
|
@ -561,6 +563,13 @@ public class WalletForm {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void walletConfigChanged(WalletConfigChangedEvent event) {
|
||||||
|
if(event.getWallet() == wallet) {
|
||||||
|
Platform.runLater(() -> EventManager.get().post(new WalletDataChangedEvent(wallet)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void walletMixConfigChanged(WalletMixConfigChangedEvent event) {
|
public void walletMixConfigChanged(WalletMixConfigChangedEvent event) {
|
||||||
if(event.getWallet() == wallet) {
|
if(event.getWallet() == wallet) {
|
||||||
|
@ -660,4 +669,18 @@ public class WalletForm {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void payNymImageLoaded(PayNymImageLoadedEvent event) {
|
||||||
|
if(wallet.isMasterWallet() && wallet.hasPaymentCode() && event.getPaymentCode().equals(wallet.getPaymentCode())) {
|
||||||
|
WalletConfig walletConfig = wallet.getMasterWalletConfig();
|
||||||
|
if(!walletConfig.isUserIcon()) {
|
||||||
|
byte[] iconData = ImageUtils.resize(event.getImage(), WalletIcon.SAVE_WIDTH, WalletIcon.SAVE_HEIGHT);
|
||||||
|
if(walletConfig.getIconData() == null || !Arrays.equals(walletConfig.getIconData(), iconData)) {
|
||||||
|
walletConfig.setIconData(iconData, false);
|
||||||
|
EventManager.get().post(new WalletConfigChangedEvent(wallet));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,4 +46,5 @@ open module com.sparrowwallet.sparrow {
|
||||||
requires co.nstant.in.cbor;
|
requires co.nstant.in.cbor;
|
||||||
requires com.github.librepdf.openpdf;
|
requires com.github.librepdf.openpdf;
|
||||||
requires com.googlecode.lanterna;
|
requires com.googlecode.lanterna;
|
||||||
|
requires net.coobird.thumbnailator;
|
||||||
}
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
create table walletConfig (id identity not null, iconData varbinary(4096), userIcon boolean, usePayNym boolean, wallet bigint not null);
|
BIN
src/main/resources/image/bitbox02-icon.png
Normal file
After Width: | Height: | Size: 550 B |
BIN
src/main/resources/image/bitbox02-icon@2x.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
src/main/resources/image/coldcard-icon.png
Normal file
After Width: | Height: | Size: 287 B |
BIN
src/main/resources/image/coldcard-icon@2x.png
Normal file
After Width: | Height: | Size: 741 B |
BIN
src/main/resources/image/ledger-icon.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
src/main/resources/image/ledger-icon@2x.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
src/main/resources/image/passport-icon.png
Normal file
After Width: | Height: | Size: 558 B |
BIN
src/main/resources/image/passport-icon@2x.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
src/main/resources/image/seedsigner-icon.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
src/main/resources/image/seedsigner-icon@2x.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
src/main/resources/image/trezor-icon.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
src/main/resources/image/trezor-icon@2x.png
Normal file
After Width: | Height: | Size: 1.9 KiB |