change qr code density for ur encoding via qr dialog button

This commit is contained in:
Craig Raw 2022-11-17 10:19:04 +02:00
parent e39a2cb944
commit c9288ab25b
5 changed files with 106 additions and 14 deletions

View file

@ -0,0 +1,22 @@
package com.sparrowwallet.sparrow.control;
public enum QRDensity {
NORMAL("Normal", 250),
LOW("Low", 80);
private final String name;
private final int maxFragmentLength;
QRDensity(String name, int maxFragmentLength) {
this.name = name;
this.maxFragmentLength = maxFragmentLength;
}
public String getName() {
return name;
}
public int getMaxFragmentLength() {
return maxFragmentLength;
}
}

View file

@ -9,6 +9,7 @@ import com.sparrowwallet.hummingbird.LegacyUREncoder;
import com.sparrowwallet.hummingbird.registry.RegistryType; import com.sparrowwallet.hummingbird.registry.RegistryType;
import com.sparrowwallet.sparrow.AppServices; import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5; import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
import com.sparrowwallet.sparrow.io.Config;
import com.sparrowwallet.sparrow.io.ImportException; import com.sparrowwallet.sparrow.io.ImportException;
import com.sparrowwallet.hummingbird.UR; import com.sparrowwallet.hummingbird.UR;
import com.sparrowwallet.hummingbird.UREncoder; import com.sparrowwallet.hummingbird.UREncoder;
@ -28,13 +29,13 @@ import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.util.Locale; import java.util.Locale;
import java.util.Optional;
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public class QRDisplayDialog extends Dialog<UR> { public class QRDisplayDialog extends Dialog<UR> {
private static final Logger log = LoggerFactory.getLogger(QRDisplayDialog.class); private static final Logger log = LoggerFactory.getLogger(QRDisplayDialog.class);
private static final int MIN_FRAGMENT_LENGTH = 10; private static final int MIN_FRAGMENT_LENGTH = 10;
private static final int MAX_FRAGMENT_LENGTH = 250;
private static final int ANIMATION_PERIOD_MILLIS = 200; private static final int ANIMATION_PERIOD_MILLIS = 200;
@ -42,17 +43,20 @@ public class QRDisplayDialog extends Dialog<UR> {
private static final int QR_HEIGHT = 480; private static final int QR_HEIGHT = 480;
private final UR ur; private final UR ur;
private final UREncoder encoder; private UREncoder encoder;
private final ImageView qrImageView; private final ImageView qrImageView;
private AnimateQRService animateQRService; private AnimateQRService animateQRService;
private String currentPart; private String currentPart;
private boolean addLegacyEncodingOption;
private boolean useLegacyEncoding; private boolean useLegacyEncoding;
private String[] legacyParts; private String[] legacyParts;
private int legacyPartIndex; private int legacyPartIndex;
private static boolean initialDensityChange;
public QRDisplayDialog(String type, byte[] data, boolean addLegacyEncodingOption) throws UR.URException { public QRDisplayDialog(String type, byte[] data, boolean addLegacyEncodingOption) throws UR.URException {
this(UR.fromBytes(type, data), addLegacyEncodingOption); this(UR.fromBytes(type, data), addLegacyEncodingOption);
} }
@ -63,7 +67,8 @@ public class QRDisplayDialog extends Dialog<UR> {
public QRDisplayDialog(UR ur, boolean addLegacyEncodingOption) { public QRDisplayDialog(UR ur, boolean addLegacyEncodingOption) {
this.ur = ur; this.ur = ur;
this.encoder = new UREncoder(ur, MAX_FRAGMENT_LENGTH, MIN_FRAGMENT_LENGTH, 0); this.addLegacyEncodingOption = addLegacyEncodingOption;
this.encoder = new UREncoder(ur, Config.get().getQrDensity().getMaxFragmentLength(), MIN_FRAGMENT_LENGTH, 0);
final DialogPane dialogPane = new QRDisplayDialogPane(); final DialogPane dialogPane = new QRDisplayDialogPane();
setDialogPane(dialogPane); setDialogPane(dialogPane);
@ -88,6 +93,9 @@ public class QRDisplayDialog extends Dialog<UR> {
if(addLegacyEncodingOption) { if(addLegacyEncodingOption) {
final ButtonType legacyEncodingButtonType = new javafx.scene.control.ButtonType("Use Legacy Encoding (Cobo Vault)", ButtonBar.ButtonData.LEFT); final ButtonType legacyEncodingButtonType = new javafx.scene.control.ButtonType("Use Legacy Encoding (Cobo Vault)", ButtonBar.ButtonData.LEFT);
dialogPane.getButtonTypes().add(legacyEncodingButtonType); dialogPane.getButtonTypes().add(legacyEncodingButtonType);
} else {
final ButtonType densityButtonType = new javafx.scene.control.ButtonType("Change Density", ButtonBar.ButtonData.LEFT);
dialogPane.getButtonTypes().add(densityButtonType);
} }
dialogPane.setPrefWidth(40 + QR_WIDTH + 40); dialogPane.setPrefWidth(40 + QR_WIDTH + 40);
@ -201,6 +209,20 @@ public class QRDisplayDialog extends Dialog<UR> {
} }
} }
private void changeQRDensity() {
if(animateQRService != null) {
animateQRService.cancel();
}
this.encoder = new UREncoder(ur, Config.get().getQrDensity().getMaxFragmentLength(), MIN_FRAGMENT_LENGTH, 0);
nextPart();
if(encoder.isSinglePart()) {
qrImageView.setImage(getQrCode(currentPart));
} else {
createAnimateQRService();
}
}
private class AnimateQRService extends ScheduledService<Boolean> { private class AnimateQRService extends ScheduledService<Boolean> {
@Override @Override
protected Task<Boolean> createTask() { protected Task<Boolean> createTask() {
@ -220,18 +242,44 @@ public class QRDisplayDialog extends Dialog<UR> {
@Override @Override
protected Node createButton(ButtonType buttonType) { protected Node createButton(ButtonType buttonType) {
if(buttonType.getButtonData() == ButtonBar.ButtonData.LEFT) { if(buttonType.getButtonData() == ButtonBar.ButtonData.LEFT) {
ToggleButton legacy = new ToggleButton(buttonType.getText()); if(addLegacyEncodingOption) {
legacy.setGraphicTextGap(5); ToggleButton legacy = new ToggleButton(buttonType.getText());
setLegacyGraphic(legacy, false); legacy.setGraphicTextGap(5);
setLegacyGraphic(legacy, false);
final ButtonBar.ButtonData buttonData = buttonType.getButtonData(); final ButtonBar.ButtonData buttonData = buttonType.getButtonData();
ButtonBar.setButtonData(legacy, buttonData); ButtonBar.setButtonData(legacy, buttonData);
legacy.selectedProperty().addListener((observable, oldValue, newValue) -> { legacy.selectedProperty().addListener((observable, oldValue, newValue) -> {
setUseLegacyEncoding(newValue); setUseLegacyEncoding(newValue);
setLegacyGraphic(legacy, newValue); setLegacyGraphic(legacy, newValue);
}); });
return legacy; return legacy;
} else {
Button density = new Button(buttonType.getText());
density.setPrefWidth(160);
density.setGraphicTextGap(5);
updateDensityButton(density);
final ButtonBar.ButtonData buttonData = buttonType.getButtonData();
ButtonBar.setButtonData(density, buttonData);
density.setOnAction(event -> {
if(!initialDensityChange && !encoder.isSinglePart()) {
Optional<ButtonType> optButtonType = AppServices.showWarningDialog("Discard progress?", "Changing the QR code density means any progress on the receiving device must be discarded. Proceed?", ButtonType.NO, ButtonType.YES);
if(optButtonType.isPresent() && optButtonType.get() == ButtonType.YES) {
initialDensityChange = true;
} else {
return;
}
}
Config.get().setQrDensity(Config.get().getQrDensity() == QRDensity.NORMAL ? QRDensity.LOW : QRDensity.NORMAL);
updateDensityButton(density);
changeQRDensity();
});
return density;
}
} }
return super.createButton(buttonType); return super.createButton(buttonType);
@ -244,6 +292,15 @@ public class QRDisplayDialog extends Dialog<UR> {
legacy.setGraphic(getGlyph(FontAwesome5.Glyph.BAN)); legacy.setGraphic(getGlyph(FontAwesome5.Glyph.BAN));
} }
} }
private void updateDensityButton(Button density) {
density.setText(Config.get().getQrDensity() == QRDensity.NORMAL ? "Decrease Density" : "Increase Density");
if(Config.get().getQrDensity() == QRDensity.NORMAL) {
density.setGraphic(getGlyph(FontAwesome5.Glyph.MAGNIFYING_GLASS_PLUS));
} else {
density.setGraphic(getGlyph(FontAwesome5.Glyph.MAGNIFYING_GLASS_MINUS));
}
}
} }
protected static Glyph getGlyph(FontAwesome5.Glyph glyphName) { protected static Glyph getGlyph(FontAwesome5.Glyph glyphName) {

View file

@ -49,6 +49,8 @@ public class FontAwesome5 extends GlyphFont {
LINK('\uf0c1'), LINK('\uf0c1'),
LOCK('\uf023'), LOCK('\uf023'),
LOCK_OPEN('\uf3c1'), LOCK_OPEN('\uf3c1'),
MAGNIFYING_GLASS_PLUS('\uf00e'),
MAGNIFYING_GLASS_MINUS('\uf010'),
MINUS_CIRCLE('\uf056'), MINUS_CIRCLE('\uf056'),
PEN_FANCY('\uf5ac'), PEN_FANCY('\uf5ac'),
PLUS('\uf067'), PLUS('\uf067'),

View file

@ -5,6 +5,7 @@ import com.sparrowwallet.drongo.BitcoinUnit;
import com.sparrowwallet.sparrow.UnitFormat; import com.sparrowwallet.sparrow.UnitFormat;
import com.sparrowwallet.sparrow.Mode; import com.sparrowwallet.sparrow.Mode;
import com.sparrowwallet.sparrow.Theme; import com.sparrowwallet.sparrow.Theme;
import com.sparrowwallet.sparrow.control.QRDensity;
import com.sparrowwallet.sparrow.net.*; import com.sparrowwallet.sparrow.net.*;
import com.sparrowwallet.sparrow.wallet.FeeRatesSelection; import com.sparrowwallet.sparrow.wallet.FeeRatesSelection;
import com.sparrowwallet.sparrow.wallet.OptimizationStrategy; import com.sparrowwallet.sparrow.wallet.OptimizationStrategy;
@ -53,6 +54,7 @@ public class Config {
private long dustAttackThreshold = DUST_ATTACK_THRESHOLD_SATS; private long dustAttackThreshold = DUST_ATTACK_THRESHOLD_SATS;
private File hwi; private File hwi;
private int enumerateHwPeriod = ENUMERATE_HW_PERIOD_SECS; private int enumerateHwPeriod = ENUMERATE_HW_PERIOD_SECS;
private QRDensity qrDensity;
private Boolean hdCapture; private Boolean hdCapture;
private String webcamDevice; private String webcamDevice;
private ServerType serverType; private ServerType serverType;
@ -354,6 +356,15 @@ public class Config {
return enumerateHwPeriod; return enumerateHwPeriod;
} }
public QRDensity getQrDensity() {
return qrDensity == null ? QRDensity.NORMAL : qrDensity;
}
public void setQrDensity(QRDensity qrDensity) {
this.qrDensity = qrDensity;
flush();
}
public Boolean getHdCapture() { public Boolean getHdCapture() {
return hdCapture; return hdCapture;
} }

View file

@ -841,7 +841,7 @@ public class HeadersController extends TransactionFormController implements Init
toggleButton.setSelected(false); toggleButton.setSelected(false);
//TODO: Remove once Cobo Vault has upgraded to UR2.0 //TODO: Remove once Cobo Vault has upgraded to UR2.0
boolean addLegacyEncodingOption = headersForm.getSigningWallet().getKeystores().stream().anyMatch(keystore -> keystore.getWalletModel().equals(WalletModel.COBO_VAULT) || keystore.getWalletModel().equals(WalletModel.SPARROW)); boolean addLegacyEncodingOption = headersForm.getSigningWallet().getKeystores().stream().anyMatch(keystore -> keystore.getWalletModel().equals(WalletModel.COBO_VAULT));
CryptoPSBT cryptoPSBT = new CryptoPSBT(headersForm.getPsbt().serialize()); CryptoPSBT cryptoPSBT = new CryptoPSBT(headersForm.getPsbt().serialize());
QRDisplayDialog qrDisplayDialog = new QRDisplayDialog(cryptoPSBT.toUR(), addLegacyEncodingOption); QRDisplayDialog qrDisplayDialog = new QRDisplayDialog(cryptoPSBT.toUR(), addLegacyEncodingOption);