usb status, key progress timing

This commit is contained in:
Craig Raw 2020-05-21 11:01:59 +02:00
parent 2acc922b06
commit fdd8327464
13 changed files with 207 additions and 62 deletions

BIN
.DS_Store vendored

Binary file not shown.

2
drongo

@ -1 +1 @@
Subproject commit 06de1d7e1458cb00cc242025c5e0d536633083a0
Subproject commit 785040898babf4b198985531f61af7ce48178b17

View file

@ -12,13 +12,12 @@ import com.sparrowwallet.drongo.protocol.Transaction;
import com.sparrowwallet.drongo.psbt.PSBT;
import com.sparrowwallet.drongo.psbt.PSBTParseException;
import com.sparrowwallet.drongo.wallet.Keystore;
import com.sparrowwallet.drongo.wallet.KeystoreSource;
import com.sparrowwallet.drongo.wallet.MnemonicException;
import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.control.*;
import com.sparrowwallet.sparrow.event.*;
import com.sparrowwallet.sparrow.io.FileType;
import com.sparrowwallet.sparrow.io.IOUtils;
import com.sparrowwallet.sparrow.io.Storage;
import com.sparrowwallet.sparrow.io.*;
import com.sparrowwallet.sparrow.transaction.TransactionController;
import com.sparrowwallet.sparrow.wallet.WalletController;
import com.sparrowwallet.sparrow.wallet.WalletForm;
@ -30,6 +29,7 @@ import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
@ -263,7 +263,7 @@ public class AppController implements Initializable {
SecureString password = optionalPassword.get();
Storage.LoadWalletService loadWalletService = new Storage.LoadWalletService(storage, password);
loadWalletService.setOnSucceeded(workerStateEvent -> {
EventManager.get().post(new TimedWorkerEvent("Done"));
EventManager.get().post(new StorageEvent(storage.getWalletFile(), TimedEvent.Action.END, "Done"));
Storage.WalletAndKey walletAndKey = loadWalletService.getValue();
try {
restorePublicKeysFromSeed(walletAndKey.wallet, walletAndKey.key);
@ -276,7 +276,7 @@ public class AppController implements Initializable {
}
});
loadWalletService.setOnFailed(workerStateEvent -> {
EventManager.get().post(new TimedWorkerEvent("Failed"));
EventManager.get().post(new StorageEvent(storage.getWalletFile(), TimedEvent.Action.END, "Failed"));
Throwable exception = loadWalletService.getException();
if(exception instanceof InvalidPasswordException) {
showErrorDialog("Invalid Password", "The wallet password was invalid.");
@ -284,8 +284,8 @@ public class AppController implements Initializable {
showErrorDialog("Error Opening Wallet", exception.getMessage());
}
});
EventManager.get().post(new StorageEvent(storage.getWalletFile(), TimedEvent.Action.START, "Decrypting wallet..."));
loadWalletService.start();
EventManager.get().post(new TimedWorkerEvent("Decrypting wallet...", 1000));
} else {
throw new IOException("Unsupported file type");
}
@ -379,6 +379,15 @@ public class AppController implements Initializable {
WalletForm walletForm = new WalletForm(storage, wallet);
controller.setWalletForm(walletForm);
if(!storage.getWalletFile().exists() || wallet.containsSource(KeystoreSource.HW_USB)) {
Hwi.EnumerateService enumerateService = new Hwi.EnumerateService(null);
enumerateService.setOnSucceeded(workerStateEvent -> {
List<Device> devices = enumerateService.getValue();
EventManager.get().post(new UsbDeviceEvent(devices));
});
enumerateService.start();
}
tabs.getTabs().add(tab);
return tab;
} catch(IOException e) {
@ -501,26 +510,45 @@ public class AppController implements Initializable {
}
@Subscribe
public void timedWorker(TimedWorkerEvent event) {
if(statusTimeline != null && statusTimeline.getStatus() == Animation.Status.RUNNING) {
if(event.getTimeMills() == 0) {
public void timedWorker(TimedEvent event) {
if(event.getTimeMills() == 0) {
if(statusTimeline != null && statusTimeline.getStatus() == Animation.Status.RUNNING) {
statusTimeline.stop();
statusBar.setText("");
statusBar.setProgress(0);
}
return;
statusBar.setText("");
statusBar.setProgress(event.getTimeMills());
} else if(event.getTimeMills() < 0) {
statusBar.setText(event.getStatus());
statusBar.setProgress(event.getTimeMills());
} else {
statusBar.setText(event.getStatus());
statusTimeline = new Timeline(
new KeyFrame(Duration.ZERO, new KeyValue(statusBar.progressProperty(), 0)),
new KeyFrame(Duration.millis(event.getTimeMills()), e -> {
statusBar.setText("");
statusBar.setProgress(0);
}, new KeyValue(statusBar.progressProperty(), 1))
);
statusTimeline.setCycleCount(1);
statusTimeline.play();
}
}
statusBar.setText(event.getStatus());
statusTimeline = new Timeline(
new KeyFrame(Duration.ZERO, new KeyValue(statusBar.progressProperty(), 0)),
new KeyFrame(Duration.millis(event.getTimeMills()), e -> {
statusBar.setText("");
statusBar.setProgress(0);
}, new KeyValue(statusBar.progressProperty(), 1))
);
statusTimeline.setCycleCount(1);
statusTimeline.play();
@Subscribe
public void usbDevicesFound(UsbDeviceEvent event) {
if(event.getDevices().isEmpty()) {
Node usbStatus = null;
for(Node node : statusBar.getRightItems()) {
if(node instanceof UsbStatusButton) {
usbStatus = node;
}
}
if(usbStatus != null) {
statusBar.getRightItems().removeAll(usbStatus);
}
} else {
UsbStatusButton usbStatusButton = new UsbStatusButton(event.getDevices());
statusBar.getRightItems().add(usbStatusButton);
}
}
}

View file

@ -14,6 +14,9 @@ import javafx.scene.image.Image;
import javafx.stage.Stage;
import org.controlsfx.glyphfont.GlyphFontRegistry;
import java.nio.file.Path;
import java.nio.file.Paths;
public class MainApp extends Application {
@Override
@ -43,6 +46,9 @@ public class MainApp extends Application {
// KeystoreImportDialog dlg = new KeystoreImportDialog(wallet);
// dlg.showAndWait();
Path path = Paths.get("").toAbsolutePath();
System.out.println(path.toFile().getAbsolutePath());
stage.show();
}

View file

@ -300,7 +300,7 @@ public class DevicePane extends TitledDescriptionPane {
String xpub = getXpubService.getValue();
Keystore keystore = new Keystore();
keystore.setLabel(device.getModel().toDisplayString() + " " + device.getFingerprint().toUpperCase());
keystore.setLabel(device.getModel().toDisplayString());
keystore.setSource(KeystoreSource.HW_USB);
keystore.setWalletModel(device.getModel());
keystore.setKeyDerivation(new KeyDerivation(device.getFingerprint(), derivationPath));

View file

@ -3,7 +3,8 @@ package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.drongo.SecureString;
import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.event.TimedWorkerEvent;
import com.sparrowwallet.sparrow.event.StorageEvent;
import com.sparrowwallet.sparrow.event.TimedEvent;
import com.sparrowwallet.sparrow.event.WalletExportEvent;
import com.sparrowwallet.sparrow.io.Storage;
import com.sparrowwallet.sparrow.io.WalletExport;
@ -59,7 +60,7 @@ public class FileWalletExportPane extends TitledDescriptionPane {
if(password.isPresent()) {
Storage.DecryptWalletService decryptWalletService = new Storage.DecryptWalletService(copy, password.get());
decryptWalletService.setOnSucceeded(workerStateEvent -> {
EventManager.get().post(new TimedWorkerEvent("Done"));
EventManager.get().post(new StorageEvent(file, TimedEvent.Action.END, "Done"));
Wallet decryptedWallet = decryptWalletService.getValue();
try {
OutputStream outputStream = new FileOutputStream(file);
@ -76,11 +77,11 @@ public class FileWalletExportPane extends TitledDescriptionPane {
}
});
decryptWalletService.setOnFailed(workerStateEvent -> {
EventManager.get().post(new TimedWorkerEvent("Failed"));
EventManager.get().post(new StorageEvent(file, TimedEvent.Action.END, "Failed"));
setError("Export Error", decryptWalletService.getException().getMessage());
});
EventManager.get().post(new StorageEvent(file, TimedEvent.Action.START, "Decrypting wallet..."));
decryptWalletService.start();
EventManager.get().post(new TimedWorkerEvent("Decrypting wallet...", 1000));
}
}
}

View file

@ -0,0 +1,42 @@
package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5Brands;
import com.sparrowwallet.sparrow.io.Device;
import javafx.geometry.Side;
import javafx.scene.Node;
import javafx.scene.control.*;
import org.controlsfx.glyphfont.Glyph;
import java.util.List;
public class UsbStatusButton extends MenuButton {
private final List<Device> devices;
public UsbStatusButton(List<Device> devices) {
super("");
setGraphic(getIcon());
this.devices = devices;
this.setPopupSide(Side.TOP);
for(Device device : devices) {
MenuItem deviceItem = new MenuItem(device.getModel().toDisplayString());
getItems().add(deviceItem);
}
}
private Node getIcon() {
Glyph usb = new Glyph(FontAwesome5Brands.FONT_NAME, FontAwesome5Brands.Glyph.USB);
usb.setFontSize(10);
return usb;
}
private class UsbStatusContextMenu extends ContextMenu {
public UsbStatusContextMenu() {
for(Device device : devices) {
MenuItem deviceItem = new MenuItem(device.getModel().toDisplayString());
getItems().add(deviceItem);
}
}
}
}

View file

@ -0,0 +1,28 @@
package com.sparrowwallet.sparrow.event;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
public class StorageEvent extends TimedEvent {
private static boolean firstRunDone = false;
private static int keyDerivationPeriod = -1;
private static final Map<File, Long> eventTime = new HashMap<>();
public StorageEvent(File file, Action action, String status) {
super(action, status);
if(action == Action.START) {
eventTime.put(file, System.currentTimeMillis());
timeMills = keyDerivationPeriod;
} else if(action == Action.END) {
long start = eventTime.get(file);
if(firstRunDone) {
keyDerivationPeriod = (int)(System.currentTimeMillis() - start);
}
firstRunDone = true;
System.out.println(keyDerivationPeriod);
timeMills = 0;
}
}
}

View file

@ -0,0 +1,35 @@
package com.sparrowwallet.sparrow.event;
public class TimedEvent {
private final Action action;
private final String status;
protected int timeMills;
public TimedEvent(Action action, String status) {
this.action = action;
this.status = status;
this.timeMills = 0;
}
public TimedEvent(Action action, String status, int timeMills) {
this.action = action;
this.status = status;
this.timeMills = timeMills;
}
public Action getAction() {
return action;
}
public String getStatus() {
return status;
}
public int getTimeMills() {
return timeMills;
}
public enum Action {
START, END;
}
}

View file

@ -1,24 +0,0 @@
package com.sparrowwallet.sparrow.event;
public class TimedWorkerEvent {
private final String status;
private final int timeMills;
public TimedWorkerEvent(String status) {
this.status = status;
this.timeMills = 0;
}
public TimedWorkerEvent(String status, int timeMills) {
this.status = status;
this.timeMills = timeMills;
}
public String getStatus() {
return status;
}
public int getTimeMills() {
return timeMills;
}
}

View file

@ -0,0 +1,17 @@
package com.sparrowwallet.sparrow.event;
import com.sparrowwallet.sparrow.io.Device;
import java.util.List;
public class UsbDeviceEvent {
private List<Device> devices;
public UsbDeviceEvent(List<Device> devices) {
this.devices = devices;
}
public List<Device> getDevices() {
return devices;
}
}

View file

@ -15,7 +15,8 @@ import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.control.CopyableLabel;
import com.sparrowwallet.sparrow.control.WalletPasswordDialog;
import com.sparrowwallet.sparrow.event.SettingsChangedEvent;
import com.sparrowwallet.sparrow.event.TimedWorkerEvent;
import com.sparrowwallet.sparrow.event.StorageEvent;
import com.sparrowwallet.sparrow.event.TimedEvent;
import com.sparrowwallet.sparrow.event.WalletChangedEvent;
import com.sparrowwallet.sparrow.io.Storage;
import javafx.beans.property.SimpleIntegerProperty;
@ -276,7 +277,7 @@ public class SettingsController extends WalletFormController implements Initiali
} else {
Storage.KeyDerivationService keyDerivationService = new Storage.KeyDerivationService(walletForm.getStorage(), password.get());
keyDerivationService.setOnSucceeded(workerStateEvent -> {
EventManager.get().post(new TimedWorkerEvent("Done"));
EventManager.get().post(new StorageEvent(walletForm.getWalletFile(), TimedEvent.Action.END, "Done"));
ECKey encryptionFullKey = keyDerivationService.getValue();
Key key = null;
@ -308,13 +309,13 @@ public class SettingsController extends WalletFormController implements Initiali
}
});
keyDerivationService.setOnFailed(workerStateEvent -> {
EventManager.get().post(new TimedWorkerEvent("Failed"));
EventManager.get().post(new StorageEvent(walletForm.getWalletFile(), TimedEvent.Action.END, "Failed"));
AppController.showErrorDialog("Error saving wallet", keyDerivationService.getException().getMessage());
revert.setDisable(false);
apply.setDisable(false);
});
EventManager.get().post(new StorageEvent(walletForm.getWalletFile(), TimedEvent.Action.START, "Encrypting wallet..."));
keyDerivationService.start();
EventManager.get().post(new TimedWorkerEvent("Encrypting wallet...", 1000));
}
}
}

View file

@ -1,7 +1,9 @@
package com.sparrowwallet.sparrow.wallet;
import com.google.common.eventbus.Subscribe;
import com.sparrowwallet.sparrow.AppController;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.event.WalletChangedEvent;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
@ -65,13 +67,17 @@ public class WalletController extends WalletFormController implements Initializa
}
});
if(!walletForm.getWallet().isValid()) {
for(Toggle toggle : walletMenu.getToggles()) {
if(toggle.getUserData().equals(Function.SETTINGS)) {
configure(walletForm.getWallet().isValid());
}
public void configure(boolean isWalletValid) {
for(Toggle toggle : walletMenu.getToggles()) {
if(toggle.getUserData().equals(Function.SETTINGS)) {
if(!isWalletValid) {
toggle.setSelected(true);
} else {
((ToggleButton)toggle).setDisable(true);
}
} else {
((ToggleButton)toggle).setDisable(!isWalletValid);
}
}
}
@ -85,4 +91,9 @@ public class WalletController extends WalletFormController implements Initializa
}
});
}
@Subscribe
public void walletChanged(WalletChangedEvent event) {
configure(walletForm.getWallet().isValid());
}
}