mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-11-02 20:36:44 +00:00
ensure file and uri opening on original app instance
This commit is contained in:
parent
74c83fc5e1
commit
574209c837
9 changed files with 229 additions and 48 deletions
|
@ -71,6 +71,9 @@ dependencies {
|
|||
}
|
||||
implementation('dev.bwt:bwt-jni:0.1.7')
|
||||
implementation('net.sourceforge.javacsv:javacsv:2.0')
|
||||
implementation('tk.pratanumandal:unique4j:1.3') {
|
||||
exclude group: 'com.google.code.gson'
|
||||
}
|
||||
implementation('org.slf4j:jul-to-slf4j:1.7.30') {
|
||||
exclude group: 'org.slf4j'
|
||||
}
|
||||
|
@ -151,7 +154,8 @@ jlink {
|
|||
"--add-opens=javafx.graphics/com.sun.glass.ui=com.sparrowwallet.sparrow",
|
||||
"--add-opens=javafx.graphics/com.sun.javafx.application=com.sparrowwallet.sparrow",
|
||||
"--add-opens=java.base/java.net=com.sparrowwallet.sparrow",
|
||||
"--add-reads=com.sparrowwallet.merged.module=java.desktop"]
|
||||
"--add-reads=com.sparrowwallet.merged.module=java.desktop",
|
||||
"--add-reads=com.sparrowwallet.merged.module=java.sql"]
|
||||
|
||||
if(os.macOsX) {
|
||||
jvmArgs += "--add-opens=javafx.graphics/com.sun.glass.ui.mac=com.sparrowwallet.merged.module"
|
||||
|
|
|
@ -54,5 +54,69 @@
|
|||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>UTImportedTypeDeclarations</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>UTTypeIdentifier</key>
|
||||
<string>org.bitcoin.psbt</string>
|
||||
<key>UTTypeTagSpecification</key>
|
||||
<dict>
|
||||
<key>public.filename-extension</key>
|
||||
<array>
|
||||
<string>psbt</string>
|
||||
</array>
|
||||
</dict>
|
||||
<key>UTTypeDescription</key>
|
||||
<string>Partially Signed Bitcoin Transaction</string>
|
||||
<key>UTTypeIconFile</key>
|
||||
<string>sparrow.icns</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>UTTypeIdentifier</key>
|
||||
<string>org.bitcoin.txn</string>
|
||||
<key>UTTypeTagSpecification</key>
|
||||
<dict>
|
||||
<key>public.filename-extension</key>
|
||||
<array>
|
||||
<string>txn</string>
|
||||
</array>
|
||||
</dict>
|
||||
<key>UTTypeDescription</key>
|
||||
<string>Bitcoin Transaction</string>
|
||||
<key>UTTypeIconFile</key>
|
||||
<string>sparrow.icns</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleDocumentTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>sparrow.icns</string>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>psbt</string>
|
||||
</array>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>Partially Signed Bitcoin Transaction</string>
|
||||
<key>LSHandlerRank</key>
|
||||
<string>Default</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>sparrow.icns</string>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>txn</string>
|
||||
</array>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>Bitcoin Transaction</string>
|
||||
<key>LSHandlerRank</key>
|
||||
<string>Default</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
3
src/main/deploy/txn.properties
Normal file
3
src/main/deploy/txn.properties
Normal file
|
@ -0,0 +1,3 @@
|
|||
mime-type=application/bitcoin-transaction
|
||||
extension=txn
|
||||
description=Bitcoin Transaction
|
|
@ -691,11 +691,6 @@ public class AppController implements Initializable {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean isWalletFile(File file) {
|
||||
FileType fileType = IOUtils.getFileType(file);
|
||||
return FileType.JSON.equals(fileType) || FileType.BINARY.equals(fileType);
|
||||
}
|
||||
|
||||
private void setServerToggleTooltip(Integer currentBlockHeight) {
|
||||
Tooltip tooltip = new Tooltip(getServerToggleTooltipText(currentBlockHeight));
|
||||
tooltip.setShowDuration(Duration.seconds(15));
|
||||
|
@ -1808,16 +1803,24 @@ public class AppController implements Initializable {
|
|||
@Subscribe
|
||||
public void requestWalletOpen(RequestWalletOpenEvent event) {
|
||||
if(tabs.getScene().getWindow().equals(event.getWindow())) {
|
||||
if(event.getFile() != null) {
|
||||
openWalletFile(event.getFile(), true);
|
||||
} else {
|
||||
openWallet(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void requestTransactionOpen(RequestTransactionOpenEvent event) {
|
||||
if(tabs.getScene().getWindow().equals(event.getWindow())) {
|
||||
if(event.getFile() != null) {
|
||||
openTransactionFile(event.getFile());
|
||||
} else {
|
||||
openTransactionFromFile(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void requestQRScan(RequestQRScanEvent event) {
|
||||
|
|
|
@ -13,10 +13,7 @@ import com.sparrowwallet.drongo.wallet.Wallet;
|
|||
import com.sparrowwallet.sparrow.control.TextUtils;
|
||||
import com.sparrowwallet.sparrow.control.TrayManager;
|
||||
import com.sparrowwallet.sparrow.event.*;
|
||||
import com.sparrowwallet.sparrow.io.Config;
|
||||
import com.sparrowwallet.sparrow.io.Device;
|
||||
import com.sparrowwallet.sparrow.io.Hwi;
|
||||
import com.sparrowwallet.sparrow.io.Storage;
|
||||
import com.sparrowwallet.sparrow.io.*;
|
||||
import com.sparrowwallet.sparrow.net.*;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
|
@ -45,13 +42,14 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.desktop.OpenURIEvent;
|
||||
import java.awt.desktop.OpenFilesHandler;
|
||||
import java.awt.desktop.OpenURIHandler;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Proxy;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
@ -104,6 +102,10 @@ public class AppServices {
|
|||
|
||||
private static List<Device> devices;
|
||||
|
||||
private static final List<File> argFiles = new ArrayList<>();
|
||||
|
||||
private static final List<URI> argUris = new ArrayList<>();
|
||||
|
||||
private static final Map<Address, BitcoinURI> payjoinURIs = new HashMap<>();
|
||||
|
||||
private final ChangeListener<Boolean> onlineServicesListener = new ChangeListener<>() {
|
||||
|
@ -124,12 +126,11 @@ public class AppServices {
|
|||
};
|
||||
|
||||
private static final OpenURIHandler openURIHandler = event -> {
|
||||
URI uri = event.getURI();
|
||||
if("bitcoin".equals(uri.getScheme())) {
|
||||
Platform.runLater(() -> openBitcoinUri(uri));
|
||||
} else if("aopp".equals(uri.getScheme())) {
|
||||
Platform.runLater(() -> openAddressOwnershipProof(uri));
|
||||
}
|
||||
openURI(event.getURI());
|
||||
};
|
||||
|
||||
private static final OpenFilesHandler openFilesHandler = event -> {
|
||||
openFiles(event.getFiles(), null);
|
||||
};
|
||||
|
||||
public AppServices(MainApp application) {
|
||||
|
@ -521,6 +522,11 @@ public class AppServices {
|
|||
ElectrumServer.clearRetrievedScriptHashes(wallet);
|
||||
}
|
||||
|
||||
public static boolean isWalletFile(File file) {
|
||||
FileType fileType = IOUtils.getFileType(file);
|
||||
return FileType.JSON.equals(fileType) || FileType.BINARY.equals(fileType);
|
||||
}
|
||||
|
||||
public static Optional<ButtonType> showWarningDialog(String title, String content, ButtonType... buttons) {
|
||||
return showAlertDialog(title, content, Alert.AlertType.WARNING, buttons);
|
||||
}
|
||||
|
@ -611,15 +617,72 @@ public class AppServices {
|
|||
}
|
||||
}
|
||||
|
||||
public static void handleURI(URI uri) {
|
||||
openURIHandler.openURI(new OpenURIEvent(uri));
|
||||
static void parseFileUriArguments(List<String> fileUriArguments) {
|
||||
for(String fileUri : fileUriArguments) {
|
||||
try {
|
||||
File file = new File(fileUri.replace("~", System.getProperty("user.home")));
|
||||
if(file.exists()) {
|
||||
argFiles.add(file);
|
||||
continue;
|
||||
}
|
||||
URI uri = new URI(fileUri);
|
||||
argUris.add(uri);
|
||||
} catch(URISyntaxException e) {
|
||||
log.warn("Could not parse " + fileUri + " as a valid file or URI");
|
||||
} catch(Exception e) {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void openFileUriArguments(Window window) {
|
||||
openFiles(argFiles, window);
|
||||
argFiles.clear();
|
||||
|
||||
for(URI argUri : argUris) {
|
||||
openURI(argUri);
|
||||
}
|
||||
argUris.clear();
|
||||
}
|
||||
|
||||
private static void openFiles(List<File> files, Window window) {
|
||||
final List<File> openFiles = new ArrayList<>(files);
|
||||
Platform.runLater(() -> {
|
||||
Window openWindow = window;
|
||||
if(openWindow == null) {
|
||||
openWindow = getActiveWindow();
|
||||
}
|
||||
|
||||
for(File file : openFiles) {
|
||||
if(isWalletFile(file)) {
|
||||
EventManager.get().post(new RequestWalletOpenEvent(openWindow, file));
|
||||
} else {
|
||||
EventManager.get().post(new RequestTransactionOpenEvent(openWindow, file));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void openURI(URI uri) {
|
||||
Platform.runLater(() -> {
|
||||
if("bitcoin".equals(uri.getScheme())) {
|
||||
openBitcoinUri(uri);
|
||||
} else if("aopp".equals(uri.getScheme())) {
|
||||
openAddressOwnershipProof(uri);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void addURIHandlers() {
|
||||
try {
|
||||
if(Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.APP_OPEN_URI)) {
|
||||
if(Desktop.isDesktopSupported()) {
|
||||
if(Desktop.getDesktop().isSupported(Desktop.Action.APP_OPEN_FILE)) {
|
||||
Desktop.getDesktop().setOpenFileHandler(openFilesHandler);
|
||||
}
|
||||
if(Desktop.getDesktop().isSupported(Desktop.Action.APP_OPEN_URI)) {
|
||||
Desktop.getDesktop().setOpenURIHandler(openURIHandler);
|
||||
}
|
||||
}
|
||||
} catch(Exception e) {
|
||||
log.error("Could not add URI handler", e);
|
||||
}
|
||||
|
|
|
@ -23,14 +23,15 @@ import org.controlsfx.tools.Platform;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.slf4j.bridge.SLF4JBridgeHandler;
|
||||
import tk.pratanumandal.unique4j.Unique4jList;
|
||||
import tk.pratanumandal.unique4j.exception.Unique4jException;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class MainApp extends Application {
|
||||
public static final String APP_ID = "com.sparrowwallet.sparrow";
|
||||
public static final String APP_NAME = "Sparrow";
|
||||
public static final String APP_VERSION = "1.4.0";
|
||||
public static final String APP_HOME_PROPERTY = "sparrow.home";
|
||||
|
@ -38,8 +39,7 @@ public class MainApp extends Application {
|
|||
|
||||
private Stage mainStage;
|
||||
|
||||
private static final List<File> argFiles = new ArrayList<>();
|
||||
private static final List<URI> argUris = new ArrayList<>();
|
||||
private static SparrowUnique sparrowUnique;
|
||||
|
||||
@Override
|
||||
public void init() throws Exception {
|
||||
|
@ -113,13 +113,7 @@ public class MainApp extends Application {
|
|||
}
|
||||
}
|
||||
|
||||
for(File argFile : argFiles) {
|
||||
appController.openFile(argFile);
|
||||
}
|
||||
|
||||
for(URI argUri : argUris) {
|
||||
AppServices.handleURI(argUri);
|
||||
}
|
||||
AppServices.openFileUriArguments(stage);
|
||||
|
||||
AppServices.get().start();
|
||||
}
|
||||
|
@ -128,6 +122,9 @@ public class MainApp extends Application {
|
|||
public void stop() throws Exception {
|
||||
AppServices.get().stop();
|
||||
mainStage.close();
|
||||
if(sparrowUnique != null) {
|
||||
sparrowUnique.freeLock();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] argv) {
|
||||
|
@ -175,22 +172,18 @@ public class MainApp extends Application {
|
|||
getLogger().info("Using " + Network.get() + " configuration");
|
||||
}
|
||||
|
||||
if(!jCommander.getUnknownOptions().isEmpty()) {
|
||||
for(String fileUri : jCommander.getUnknownOptions()) {
|
||||
List<String> fileUriArguments = jCommander.getUnknownOptions();
|
||||
if(!fileUriArguments.isEmpty()) {
|
||||
if(args.network == null && args.dir == null) {
|
||||
try {
|
||||
File file = new File(fileUri);
|
||||
if(file.exists()) {
|
||||
argFiles.add(file);
|
||||
continue;
|
||||
}
|
||||
URI uri = new URI(fileUri);
|
||||
argUris.add(uri);
|
||||
} catch(URISyntaxException e) {
|
||||
getLogger().warn("Could not parse " + fileUri + " as a valid file or URI");
|
||||
} catch(Exception e) {
|
||||
//ignore
|
||||
sparrowUnique = new SparrowUnique(APP_ID, fileUriArguments);
|
||||
sparrowUnique.acquireLock(); //Will exit app after sending fileUriArguments if lock cannot be acquired
|
||||
} catch(Unique4jException e) {
|
||||
getLogger().error("Could not obtain unique lock", e);
|
||||
}
|
||||
}
|
||||
|
||||
AppServices.parseFileUriArguments(fileUriArguments);
|
||||
}
|
||||
|
||||
SLF4JBridgeHandler.removeHandlersForRootLogger();
|
||||
|
@ -201,4 +194,29 @@ public class MainApp extends Application {
|
|||
private static Logger getLogger() {
|
||||
return LoggerFactory.getLogger(MainApp.class);
|
||||
}
|
||||
|
||||
private static class SparrowUnique extends Unique4jList {
|
||||
private final List<String> fileUriArguments;
|
||||
|
||||
public SparrowUnique(String APP_ID, List<String> fileUriArguments) {
|
||||
super(APP_ID + "." + Network.get());
|
||||
this.fileUriArguments = fileUriArguments;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void receiveMessageList(List<String> messageList) {
|
||||
AppServices.parseFileUriArguments(messageList);
|
||||
AppServices.openFileUriArguments(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> sendMessageList() {
|
||||
return fileUriArguments;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void beforeExit() {
|
||||
getLogger().info("Opening files/URIs in already running instance, exiting...");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,17 +2,30 @@ package com.sparrowwallet.sparrow.event;
|
|||
|
||||
import javafx.stage.Window;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Event class used to request the transaction open file dialog
|
||||
*/
|
||||
public class RequestTransactionOpenEvent {
|
||||
private final Window window;
|
||||
private final File file;
|
||||
|
||||
public RequestTransactionOpenEvent(Window window) {
|
||||
this.window = window;
|
||||
this.file = null;
|
||||
}
|
||||
|
||||
public RequestTransactionOpenEvent(Window window, File file) {
|
||||
this.window = window;
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public Window getWindow() {
|
||||
return window;
|
||||
}
|
||||
|
||||
public File getFile() {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,17 +2,30 @@ package com.sparrowwallet.sparrow.event;
|
|||
|
||||
import javafx.stage.Window;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Event class used to request the wallet open dialog
|
||||
*/
|
||||
public class RequestWalletOpenEvent {
|
||||
private final Window window;
|
||||
private final File file;
|
||||
|
||||
public RequestWalletOpenEvent(Window window) {
|
||||
this.window = window;
|
||||
this.file = null;
|
||||
}
|
||||
|
||||
public RequestWalletOpenEvent(Window window, File file) {
|
||||
this.window = window;
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public Window getWindow() {
|
||||
return window;
|
||||
}
|
||||
|
||||
public File getFile() {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ open module com.sparrowwallet.sparrow {
|
|||
requires com.sparrowwallet.drongo;
|
||||
requires com.google.common;
|
||||
requires flowless;
|
||||
requires com.google.gson;
|
||||
requires com.google.zxing;
|
||||
requires com.google.zxing.javase;
|
||||
requires simple.json.rpc.client;
|
||||
|
@ -28,6 +27,7 @@ open module com.sparrowwallet.sparrow {
|
|||
requires bwt.jni;
|
||||
requires jtorctl;
|
||||
requires javacsv;
|
||||
requires unique4j;
|
||||
requires jul.to.slf4j;
|
||||
requires bridj;
|
||||
}
|
Loading…
Reference in a new issue