@ -1 +1 @@ |
|||
Subproject commit 7c34ec7c3b818634b7819f1b27a5f9c57f5554c8 |
|||
Subproject commit fa18ec9d458bb17221fb01b6be9f4eceb354a156 |
@ -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); |
|||
} |
|||
} |
@ -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); |
|||
} |
|||
} |
@ -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; |
|||
} |
|||
} |
@ -0,0 +1 @@ |
|||
create table walletConfig (id identity not null, iconData varbinary(4096), userIcon boolean, usePayNym boolean, wallet bigint not null); |
After Width: | Height: | Size: 550 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 287 B |
After Width: | Height: | Size: 741 B |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 558 B |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.9 KiB |