mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-24 12:46:45 +00:00
add config, usb status fixes
This commit is contained in:
parent
fdd8327464
commit
7fc0e9b530
12 changed files with 194 additions and 53 deletions
|
@ -69,7 +69,7 @@ jlink {
|
|||
jpackage {
|
||||
imageName = "Sparrow"
|
||||
installerName = "Sparrow"
|
||||
appVersion = "0.51"
|
||||
appVersion = "0.6"
|
||||
skipInstaller = true
|
||||
imageOptions = []
|
||||
installerOptions = [
|
||||
|
|
|
@ -290,6 +290,7 @@ public class AppController implements Initializable {
|
|||
throw new IOException("Unsupported file type");
|
||||
}
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
showErrorDialog("Error Opening Wallet", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
@ -380,7 +381,8 @@ public class AppController implements Initializable {
|
|||
controller.setWalletForm(walletForm);
|
||||
|
||||
if(!storage.getWalletFile().exists() || wallet.containsSource(KeystoreSource.HW_USB)) {
|
||||
Hwi.EnumerateService enumerateService = new Hwi.EnumerateService(null);
|
||||
Hwi.ScheduledEnumerateService enumerateService = new Hwi.ScheduledEnumerateService(null);
|
||||
enumerateService.setPeriod(new Duration(30 * 1000));
|
||||
enumerateService.setOnSucceeded(workerStateEvent -> {
|
||||
List<Device> devices = enumerateService.getValue();
|
||||
EventManager.get().post(new UsbDeviceEvent(devices));
|
||||
|
@ -536,19 +538,26 @@ public class AppController implements Initializable {
|
|||
|
||||
@Subscribe
|
||||
public void usbDevicesFound(UsbDeviceEvent event) {
|
||||
if(event.getDevices().isEmpty()) {
|
||||
Node usbStatus = null;
|
||||
for(Node node : statusBar.getRightItems()) {
|
||||
if(node instanceof UsbStatusButton) {
|
||||
usbStatus = node;
|
||||
}
|
||||
UsbStatusButton usbStatus = null;
|
||||
for(Node node : statusBar.getRightItems()) {
|
||||
if(node instanceof UsbStatusButton) {
|
||||
usbStatus = (UsbStatusButton)node;
|
||||
}
|
||||
}
|
||||
|
||||
if(event.getDevices().isEmpty()) {
|
||||
if(usbStatus != null) {
|
||||
statusBar.getRightItems().removeAll(usbStatus);
|
||||
}
|
||||
} else {
|
||||
UsbStatusButton usbStatusButton = new UsbStatusButton(event.getDevices());
|
||||
statusBar.getRightItems().add(usbStatusButton);
|
||||
if(usbStatus == null) {
|
||||
usbStatus = new UsbStatusButton();
|
||||
statusBar.getRightItems().add(usbStatus);
|
||||
} else {
|
||||
usbStatus.getItems().remove(0, usbStatus.getItems().size());
|
||||
}
|
||||
|
||||
usbStatus.setDevices(event.getDevices());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package com.sparrowwallet.sparrow;
|
|||
import com.sparrowwallet.drongo.policy.PolicyType;
|
||||
import com.sparrowwallet.drongo.protocol.ScriptType;
|
||||
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||
import com.sparrowwallet.sparrow.keystoreimport.KeystoreImportDialog;
|
||||
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
|
||||
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5Brands;
|
||||
import javafx.application.Application;
|
||||
|
@ -14,9 +13,6 @@ 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
|
||||
|
@ -46,9 +42,6 @@ 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();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.sparrowwallet.sparrow.control;
|
||||
|
||||
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
|
||||
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5Brands;
|
||||
import com.sparrowwallet.sparrow.io.Device;
|
||||
import javafx.geometry.Side;
|
||||
|
@ -10,33 +11,41 @@ import org.controlsfx.glyphfont.Glyph;
|
|||
import java.util.List;
|
||||
|
||||
public class UsbStatusButton extends MenuButton {
|
||||
private final List<Device> devices;
|
||||
|
||||
public UsbStatusButton(List<Device> devices) {
|
||||
public UsbStatusButton() {
|
||||
super("");
|
||||
setGraphic(getIcon());
|
||||
this.devices = devices;
|
||||
|
||||
this.setPopupSide(Side.TOP);
|
||||
getStyleClass().add("status-bar-button");
|
||||
this.setPopupSide(Side.RIGHT);
|
||||
}
|
||||
|
||||
public void setDevices(List<Device> devices) {
|
||||
for(Device device : devices) {
|
||||
MenuItem deviceItem = new MenuItem(device.getModel().toDisplayString());
|
||||
if(device.getNeedsPinSent()) {
|
||||
deviceItem.setGraphic(getLockIcon());
|
||||
} else {
|
||||
deviceItem.setGraphic(getLockOpenIcon());
|
||||
}
|
||||
getItems().add(deviceItem);
|
||||
}
|
||||
}
|
||||
|
||||
private Node getIcon() {
|
||||
Glyph usb = new Glyph(FontAwesome5Brands.FONT_NAME, FontAwesome5Brands.Glyph.USB);
|
||||
usb.setFontSize(10);
|
||||
usb.setFontSize(15);
|
||||
return usb;
|
||||
}
|
||||
|
||||
private class UsbStatusContextMenu extends ContextMenu {
|
||||
public UsbStatusContextMenu() {
|
||||
for(Device device : devices) {
|
||||
MenuItem deviceItem = new MenuItem(device.getModel().toDisplayString());
|
||||
getItems().add(deviceItem);
|
||||
}
|
||||
}
|
||||
private Node getLockIcon() {
|
||||
Glyph usb = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.LOCK);
|
||||
usb.setFontSize(12);
|
||||
return usb;
|
||||
}
|
||||
|
||||
private Node getLockOpenIcon() {
|
||||
Glyph usb = new Glyph(FontAwesome5.FONT_NAME, FontAwesome5.Glyph.LOCK_OPEN);
|
||||
usb.setFontSize(12);
|
||||
return usb;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,23 @@
|
|||
package com.sparrowwallet.sparrow.event;
|
||||
|
||||
import com.sparrowwallet.sparrow.io.Config;
|
||||
|
||||
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);
|
||||
|
||||
Integer keyDerivationPeriod = Config.get().getKeyDerivationPeriod();
|
||||
if(keyDerivationPeriod == null) {
|
||||
keyDerivationPeriod = -1;
|
||||
}
|
||||
|
||||
if(action == Action.START) {
|
||||
eventTime.put(file, System.currentTimeMillis());
|
||||
timeMills = keyDerivationPeriod;
|
||||
|
@ -19,9 +25,9 @@ public class StorageEvent extends TimedEvent {
|
|||
long start = eventTime.get(file);
|
||||
if(firstRunDone) {
|
||||
keyDerivationPeriod = (int)(System.currentTimeMillis() - start);
|
||||
Config.get().setKeyDerivationPeriod(keyDerivationPeriod);
|
||||
}
|
||||
firstRunDone = true;
|
||||
System.out.println(keyDerivationPeriod);
|
||||
timeMills = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ public class FontAwesome5 extends GlyphFont {
|
|||
EYE('\uf06e'),
|
||||
KEY('\uf084'),
|
||||
LAPTOP('\uf109'),
|
||||
LOCK('\uf023'),
|
||||
LOCK_OPEN('\uf3c1'),
|
||||
SD_CARD('\uf7c2'),
|
||||
WALLET('\uf555');
|
||||
|
||||
|
|
99
src/main/java/com/sparrowwallet/sparrow/io/Config.java
Normal file
99
src/main/java/com/sparrowwallet/sparrow/io/Config.java
Normal file
|
@ -0,0 +1,99 @@
|
|||
package com.sparrowwallet.sparrow.io;
|
||||
|
||||
import com.google.gson.*;
|
||||
import com.sparrowwallet.drongo.Utils;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
public class Config {
|
||||
public static final String CONFIG_FILENAME = ".config";
|
||||
|
||||
private Integer keyDerivationPeriod;
|
||||
private File hwi;
|
||||
|
||||
private static Config INSTANCE;
|
||||
|
||||
private static Gson getGson() {
|
||||
GsonBuilder gsonBuilder = new GsonBuilder();
|
||||
gsonBuilder.registerTypeAdapter(File.class, new FileSerializer());
|
||||
gsonBuilder.registerTypeAdapter(File.class, new FileDeserializer());
|
||||
return gsonBuilder.setPrettyPrinting().disableHtmlEscaping().create();
|
||||
}
|
||||
|
||||
private static File getConfigFile() {
|
||||
return new File(Storage.getSparrowDir(), CONFIG_FILENAME);
|
||||
}
|
||||
|
||||
private static Config load() {
|
||||
File configFile = getConfigFile();
|
||||
if(configFile.exists()) {
|
||||
try {
|
||||
Reader reader = new FileReader(configFile);
|
||||
Config config = getGson().fromJson(reader, Config.class);
|
||||
reader.close();
|
||||
|
||||
if(config != null) {
|
||||
return config;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
//Ignore and assume no config
|
||||
}
|
||||
}
|
||||
|
||||
return new Config();
|
||||
}
|
||||
|
||||
public static synchronized Config get() {
|
||||
if(INSTANCE == null) {
|
||||
INSTANCE = load();
|
||||
}
|
||||
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public Integer getKeyDerivationPeriod() {
|
||||
return keyDerivationPeriod;
|
||||
}
|
||||
|
||||
public void setKeyDerivationPeriod(Integer keyDerivationPeriod) {
|
||||
this.keyDerivationPeriod = keyDerivationPeriod;
|
||||
flush();
|
||||
}
|
||||
|
||||
public File getHwi() {
|
||||
return hwi;
|
||||
}
|
||||
|
||||
public void setHwi(File hwi) {
|
||||
this.hwi = hwi;
|
||||
flush();
|
||||
}
|
||||
|
||||
private void flush() {
|
||||
Gson gson = getGson();
|
||||
try {
|
||||
File configFile = getConfigFile();
|
||||
Writer writer = new FileWriter(configFile);
|
||||
gson.toJson(this, writer);
|
||||
writer.close();
|
||||
} catch (IOException e) {
|
||||
//Ignore
|
||||
}
|
||||
}
|
||||
|
||||
private static class FileSerializer implements JsonSerializer<File> {
|
||||
@Override
|
||||
public JsonElement serialize(File src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return new JsonPrimitive(src.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
private static class FileDeserializer implements JsonDeserializer<File> {
|
||||
@Override
|
||||
public File deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||
return new File(json.getAsJsonPrimitive().getAsString());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ import com.google.common.io.ByteStreams;
|
|||
import com.google.common.io.CharStreams;
|
||||
import com.google.gson.*;
|
||||
import com.sparrowwallet.drongo.wallet.WalletModel;
|
||||
import javafx.concurrent.ScheduledService;
|
||||
import javafx.concurrent.Service;
|
||||
import javafx.concurrent.Task;
|
||||
import org.apache.commons.compress.compressors.lz4.FramedLZ4CompressorInputStream;
|
||||
|
@ -23,8 +24,6 @@ import java.util.zip.ZipEntry;
|
|||
import java.util.zip.ZipInputStream;
|
||||
|
||||
public class Hwi {
|
||||
private static File hwiExecutable;
|
||||
|
||||
public List<Device> enumerate(String passphrase) throws ImportException {
|
||||
try {
|
||||
List<String> command;
|
||||
|
@ -86,9 +85,10 @@ public class Hwi {
|
|||
return CharStreams.toString(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
private synchronized File getHwiExecutable() throws IOException {
|
||||
try {
|
||||
if (hwiExecutable == null) {
|
||||
private synchronized File getHwiExecutable() {
|
||||
File hwiExecutable = Config.get().getHwi();
|
||||
if(hwiExecutable == null || !hwiExecutable.exists()) {
|
||||
try {
|
||||
Platform platform = Platform.getCurrent();
|
||||
Set<PosixFilePermission> ownerExecutableWritable = PosixFilePermissions.fromString("rwxr--r--");
|
||||
|
||||
|
@ -100,16 +100,15 @@ public class Hwi {
|
|||
InputStream inputStream = Hwi.class.getResourceAsStream("/external/" + platform.getPlatformId().toLowerCase() + "/hwi-1.1.0-mac-amd64-signed.zip");
|
||||
Path tempHwiDirPath = Files.createTempDirectory("hwi", PosixFilePermissions.asFileAttribute(ownerExecutableWritable));
|
||||
File tempHwiDir = tempHwiDirPath.toFile();
|
||||
tempHwiDir.deleteOnExit();
|
||||
|
||||
System.out.println(tempHwiDir.getAbsolutePath());
|
||||
//tempHwiDir.deleteOnExit();
|
||||
//System.out.println(tempHwiDir.getAbsolutePath());
|
||||
|
||||
File tempExec = null;
|
||||
ZipInputStream zis = new ZipInputStream(inputStream);
|
||||
ZipEntry zipEntry = zis.getNextEntry();
|
||||
while (zipEntry != null) {
|
||||
File newFile = newFile(tempHwiDir, zipEntry, ownerExecutableWritable);
|
||||
newFile.deleteOnExit();
|
||||
//newFile.deleteOnExit();
|
||||
FileOutputStream fos = new FileOutputStream(newFile);
|
||||
ByteStreams.copy(zis, new FileOutputStream(newFile));
|
||||
fos.flush();
|
||||
|
@ -129,7 +128,7 @@ public class Hwi {
|
|||
InputStream inputStream = Hwi.class.getResourceAsStream("/external/" + platform.getPlatformId().toLowerCase() + "/hwi");
|
||||
Path tempExecPath = Files.createTempFile("hwi", null, PosixFilePermissions.asFileAttribute(ownerExecutableWritable));
|
||||
File tempExec = tempExecPath.toFile();
|
||||
tempExec.deleteOnExit();
|
||||
//tempExec.deleteOnExit();
|
||||
OutputStream tempExecStream = new BufferedOutputStream(new FileOutputStream(tempExec));
|
||||
ByteStreams.copy(new FramedLZ4CompressorInputStream(inputStream), tempExecStream);
|
||||
inputStream.close();
|
||||
|
@ -138,9 +137,11 @@ public class Hwi {
|
|||
|
||||
hwiExecutable = tempExec;
|
||||
}
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
Config.get().setHwi(hwiExecutable);
|
||||
}
|
||||
|
||||
return hwiExecutable;
|
||||
|
@ -199,6 +200,24 @@ public class Hwi {
|
|||
}
|
||||
}
|
||||
|
||||
public static class ScheduledEnumerateService extends ScheduledService<List<Device>> {
|
||||
private final String passphrase;
|
||||
|
||||
public ScheduledEnumerateService(String passphrase) {
|
||||
this.passphrase = passphrase;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Task<List<Device>> createTask() {
|
||||
return new Task<>() {
|
||||
protected List<Device> call() throws ImportException {
|
||||
Hwi hwi = new Hwi();
|
||||
return hwi.enumerate(passphrase);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static class PromptPinService extends Service<Boolean> {
|
||||
private Device device;
|
||||
|
||||
|
|
|
@ -220,11 +220,11 @@ public class Storage {
|
|||
return walletsDir;
|
||||
}
|
||||
|
||||
private static File getSparrowDir() {
|
||||
static File getSparrowDir() {
|
||||
return new File(getHomeDir(), SPARROW_DIR);
|
||||
}
|
||||
|
||||
private static File getHomeDir() {
|
||||
static File getHomeDir() {
|
||||
return new File(System.getProperty("user.home"));
|
||||
}
|
||||
|
||||
|
|
|
@ -19,3 +19,7 @@
|
|||
.drag-over > .background-text {
|
||||
-fx-fill: #383a42;
|
||||
}
|
||||
|
||||
.status-bar .right-items {
|
||||
-fx-padding: 0 0 0 8;
|
||||
}
|
||||
|
|
|
@ -41,6 +41,6 @@
|
|||
<TabPane fx:id="tabs" />
|
||||
</StackPane>
|
||||
|
||||
<StatusBar fx:id="statusBar" text=""/>
|
||||
<StatusBar fx:id="statusBar" text="" minHeight="36"/>
|
||||
</children>
|
||||
</VBox>
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
<ToggleGroup fx:id="walletMenu" />
|
||||
</toggleGroup>
|
||||
<graphic>
|
||||
<Glyph fontFamily="FontAwesome" icon="BTC" />
|
||||
<Glyph fontFamily="FontAwesome" icon="BTC" fontSize="20" />
|
||||
</graphic>
|
||||
<userData>
|
||||
<Function fx:constant="TRANSACTIONS"/>
|
||||
|
@ -24,7 +24,7 @@
|
|||
</ToggleButton>
|
||||
<ToggleButton VBox.vgrow="ALWAYS" text="Send" contentDisplay="TOP" styleClass="list-item" maxHeight="Infinity" toggleGroup="$walletMenu">
|
||||
<graphic>
|
||||
<Glyph fontFamily="FontAwesome" icon="SEND" />
|
||||
<Glyph fontFamily="FontAwesome" icon="SEND" fontSize="20" />
|
||||
</graphic>
|
||||
<userData>
|
||||
<Function fx:constant="SEND"/>
|
||||
|
@ -32,7 +32,7 @@
|
|||
</ToggleButton>
|
||||
<ToggleButton VBox.vgrow="ALWAYS" text="Receive" contentDisplay="TOP" styleClass="list-item" maxHeight="Infinity" toggleGroup="$walletMenu">
|
||||
<graphic>
|
||||
<Glyph fontFamily="FontAwesome" icon="ARROW_DOWN" />
|
||||
<Glyph fontFamily="FontAwesome" icon="ARROW_DOWN" fontSize="20" />
|
||||
</graphic>
|
||||
<userData>
|
||||
<Function fx:constant="RECEIVE"/>
|
||||
|
@ -40,7 +40,7 @@
|
|||
</ToggleButton>
|
||||
<ToggleButton VBox.vgrow="ALWAYS" text="Addresses" contentDisplay="TOP" styleClass="list-item" maxHeight="Infinity" toggleGroup="$walletMenu">
|
||||
<graphic>
|
||||
<Glyph fontFamily="FontAwesome" icon="TH_LIST" />
|
||||
<Glyph fontFamily="FontAwesome" icon="TH_LIST" fontSize="20" />
|
||||
</graphic>
|
||||
<userData>
|
||||
<Function fx:constant="ADDRESSES"/>
|
||||
|
@ -48,7 +48,7 @@
|
|||
</ToggleButton>
|
||||
<ToggleButton VBox.vgrow="ALWAYS" text="Policies" contentDisplay="TOP" styleClass="list-item" maxHeight="Infinity" toggleGroup="$walletMenu">
|
||||
<graphic>
|
||||
<Glyph fontFamily="FontAwesome" icon="FILE_TEXT" />
|
||||
<Glyph fontFamily="FontAwesome" icon="FILE_TEXT" fontSize="20" />
|
||||
</graphic>
|
||||
<userData>
|
||||
<Function fx:constant="POLICIES"/>
|
||||
|
@ -56,7 +56,7 @@
|
|||
</ToggleButton>
|
||||
<ToggleButton VBox.vgrow="ALWAYS" text="Settings" contentDisplay="TOP" styleClass="list-item" maxHeight="Infinity" toggleGroup="$walletMenu">
|
||||
<graphic>
|
||||
<Glyph fontFamily="FontAwesome" icon="COG" />
|
||||
<Glyph fontFamily="FontAwesome" icon="COG" fontSize="20" />
|
||||
</graphic>
|
||||
<userData>
|
||||
<Function fx:constant="SETTINGS"/>
|
||||
|
|
Loading…
Reference in a new issue