terminal - show receive address as qr code

This commit is contained in:
Craig Raw 2022-11-09 11:40:34 +02:00
parent 2972f1a4d7
commit ea64fa0f85
3 changed files with 149 additions and 2 deletions

View file

@ -0,0 +1,38 @@
package com.sparrowwallet.sparrow.terminal.wallet;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.googlecode.lanterna.gui2.*;
import com.googlecode.lanterna.gui2.dialogs.DialogWindow;
import com.googlecode.lanterna.input.KeyStroke;
import java.util.List;
import java.util.Map;
public class QRCodeDialog extends DialogWindow {
public QRCodeDialog(String data) throws WriterException {
super(data);
setHints(List.of(Hint.CENTERED));
Panel mainPanel = new Panel(new GridLayout(1).setLeftMarginSize(1).setRightMarginSize(1).setTopMarginSize(1));
QRCodeWriter qrCodeWriter = new QRCodeWriter();
BitMatrix qrMatrix = qrCodeWriter.encode(data, BarcodeFormat.QR_CODE, 33, 33, Map.of(EncodeHintType.MARGIN, 0));
ImageComponent imageComponent = new ImageComponent();
imageComponent.setTextImage(new QRTextImage(qrMatrix));
mainPanel.addComponent(imageComponent);
setComponent(mainPanel);
}
@Override
public boolean handleInput(KeyStroke key) {
close();
return true;
}
}

View file

@ -0,0 +1,93 @@
package com.sparrowwallet.sparrow.terminal.wallet;
import com.google.zxing.common.BitMatrix;
import com.googlecode.lanterna.*;
import com.googlecode.lanterna.graphics.AbstractTextGraphics;
import com.googlecode.lanterna.graphics.TextGraphics;
import com.googlecode.lanterna.graphics.TextImage;
import java.util.EnumSet;
public class QRTextImage implements TextImage {
private final BitMatrix bitMatrix;
private final TerminalSize size;
private static final TextCharacter REVERSE_CHARACTER = TextCharacter.fromString(" ", TextColor.ANSI.DEFAULT, TextColor.ANSI.DEFAULT, EnumSet.of(SGR.REVERSE))[0];
public QRTextImage(BitMatrix bitMatrix) {
this.bitMatrix = bitMatrix;
this.size = new TerminalSize(bitMatrix.getWidth() * 2, bitMatrix.getHeight());
}
@Override
public TerminalSize getSize() {
return size;
}
@Override
public TextCharacter getCharacterAt(TerminalPosition position) {
return getCharacterAt(position.getColumn(), position.getRow());
}
@Override
public TextCharacter getCharacterAt(int column, int row) {
boolean filled = bitMatrix.get(column / 2, row);
return filled ? TextCharacter.DEFAULT_CHARACTER : REVERSE_CHARACTER;
}
@Override
public void setCharacterAt(TerminalPosition position, TextCharacter character) {
throw new UnsupportedOperationException("Cannot set character in QR Code");
}
@Override
public void setCharacterAt(int column, int row, TextCharacter character) {
throw new UnsupportedOperationException("Cannot set character in QR Code");
}
@Override
public void setAll(TextCharacter character) {
throw new UnsupportedOperationException("Cannot set character in QR Code");
}
@Override
public TextGraphics newTextGraphics() {
return new AbstractTextGraphics() {
@Override
public TextGraphics setCharacter(int columnIndex, int rowIndex, TextCharacter textCharacter) {
QRTextImage.this.setCharacterAt(columnIndex, rowIndex, textCharacter);
return this;
}
@Override
public TextCharacter getCharacter(int column, int row) {
return QRTextImage.this.getCharacterAt(column, row);
}
@Override
public TerminalSize getSize() {
return size;
}
};
}
@Override
public TextImage resize(TerminalSize newSize, TextCharacter filler) {
throw new UnsupportedOperationException("Cannot resize QR Code");
}
@Override
public void copyTo(TextImage destination) {
throw new UnsupportedOperationException("Cannot copy QR Code");
}
@Override
public void copyTo(TextImage destination, int startRowIndex, int rows, int startColumnIndex, int columns, int destinationRowOffset, int destinationColumnOffset) {
throw new UnsupportedOperationException("Cannot copy QR Code");
}
@Override
public void scrollLines(int firstLine, int lastLine, int distance) {
throw new UnsupportedOperationException("Cannot scroll QR Code");
}
}

View file

@ -1,7 +1,6 @@
package com.sparrowwallet.sparrow.terminal.wallet;
import com.google.common.eventbus.Subscribe;
import com.googlecode.lanterna.TerminalSize;
import com.googlecode.lanterna.gui2.*;
import com.sparrowwallet.drongo.KeyDerivation;
import com.sparrowwallet.drongo.KeyPurpose;
@ -14,6 +13,8 @@ import com.sparrowwallet.sparrow.terminal.SparrowTerminal;
import com.sparrowwallet.sparrow.wallet.Function;
import com.sparrowwallet.sparrow.wallet.NodeEntry;
import com.sparrowwallet.sparrow.wallet.WalletForm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
@ -21,6 +22,7 @@ import java.util.List;
import java.util.Set;
public class ReceiveDialog extends WalletDialog {
private static final Logger log = LoggerFactory.getLogger(ReceiveDialog.class);
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm");
private final Label address;
@ -50,7 +52,7 @@ public class ReceiveDialog extends WalletDialog {
buttonPanel.addComponent(new Button("Back", () -> onBack(Function.RECEIVE)));
buttonPanel.addComponent(new Button("Get Fresh Address", this::refreshAddress).setLayoutData(GridLayout.createLayoutData(GridLayout.Alignment.CENTER, GridLayout.Alignment.CENTER, true, false)));
mainPanel.addComponent(new EmptySpace(TerminalSize.ONE));
mainPanel.addComponent(new Button("Show QR", this::showQR));
buttonPanel.setLayoutData(GridLayout.createLayoutData(GridLayout.Alignment.END, GridLayout.Alignment.CENTER,false,false)).addTo(mainPanel);
setComponent(mainPanel);
@ -58,6 +60,20 @@ public class ReceiveDialog extends WalletDialog {
refreshAddress();
}
public void showQR() {
if(currentEntry == null) {
return;
}
try {
QRCodeDialog qrCodeDialog = new QRCodeDialog(currentEntry.getAddress().toString());
qrCodeDialog.showDialog(SparrowTerminal.get().getGui());
} catch(Exception e) {
log.error("Error creating QR", e);
AppServices.showErrorDialog("Error creating QR", e.getMessage());
}
}
public void refreshAddress() {
SparrowTerminal.get().getGuiThread().invokeLater(() -> {
NodeEntry freshEntry = getWalletForm().getFreshNodeEntry(KeyPurpose.RECEIVE, currentEntry);