mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-23 20:36:44 +00:00
add minimize to system tray functionality
This commit is contained in:
parent
cb884d97cb
commit
8fc971c07c
7 changed files with 123 additions and 1 deletions
|
@ -92,6 +92,9 @@ public class AppController implements Initializable {
|
|||
@FXML
|
||||
private Menu fileMenu;
|
||||
|
||||
@FXML
|
||||
private Menu viewMenu;
|
||||
|
||||
@FXML
|
||||
private Menu toolsMenu;
|
||||
|
||||
|
@ -116,6 +119,9 @@ public class AppController implements Initializable {
|
|||
@FXML
|
||||
private CheckMenuItem showTxHex;
|
||||
|
||||
@FXML
|
||||
private MenuItem minimizeToTray;
|
||||
|
||||
@FXML
|
||||
private MenuItem refreshWallet;
|
||||
|
||||
|
@ -285,6 +291,10 @@ public class AppController implements Initializable {
|
|||
} else if(platform == org.controlsfx.tools.Platform.WINDOWS) {
|
||||
toolsMenu.getItems().removeIf(item -> item.getStyleClass().contains("windowsHide"));
|
||||
}
|
||||
|
||||
if(platform == org.controlsfx.tools.Platform.UNIX || !TrayManager.isSupported()) {
|
||||
viewMenu.getItems().remove(minimizeToTray);
|
||||
}
|
||||
}
|
||||
|
||||
public void showIntroduction(ActionEvent event) {
|
||||
|
@ -953,6 +963,10 @@ public class AppController implements Initializable {
|
|||
messageSignDialog.showAndWait();
|
||||
}
|
||||
|
||||
public void minimizeToTray(ActionEvent event) {
|
||||
AppServices.get().minimizeStage((Stage)tabs.getScene().getWindow());
|
||||
}
|
||||
|
||||
public void refreshWallet(ActionEvent event) {
|
||||
Tab selectedTab = tabs.getSelectionModel().getSelectedItem();
|
||||
TabData tabData = (TabData)selectedTab.getUserData();
|
||||
|
|
|
@ -9,6 +9,7 @@ import com.sparrowwallet.drongo.psbt.PSBT;
|
|||
import com.sparrowwallet.drongo.uri.BitcoinURI;
|
||||
import com.sparrowwallet.drongo.wallet.KeystoreSource;
|
||||
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||
import com.sparrowwallet.sparrow.control.TrayManager;
|
||||
import com.sparrowwallet.sparrow.event.*;
|
||||
import com.sparrowwallet.sparrow.io.Config;
|
||||
import com.sparrowwallet.sparrow.io.Device;
|
||||
|
@ -64,6 +65,8 @@ public class AppServices {
|
|||
|
||||
private final Map<Window, List<WalletTabData>> walletWindows = new LinkedHashMap<>();
|
||||
|
||||
private TrayManager trayManager;
|
||||
|
||||
private static final BooleanProperty onlineProperty = new SimpleBooleanProperty(false);
|
||||
|
||||
private ExchangeSource.RatesService ratesService;
|
||||
|
@ -401,6 +404,15 @@ public class AppServices {
|
|||
return application;
|
||||
}
|
||||
|
||||
public void minimizeStage(Stage stage) {
|
||||
if(trayManager == null) {
|
||||
trayManager = new TrayManager();
|
||||
}
|
||||
|
||||
trayManager.addStage(stage);
|
||||
stage.hide();
|
||||
}
|
||||
|
||||
public Map<Wallet, Storage> getOpenWallets() {
|
||||
Map<Wallet, Storage> openWallets = new LinkedHashMap<>();
|
||||
for(List<WalletTabData> walletTabDataList : walletWindows.values()) {
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
package com.sparrowwallet.sparrow.control;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.stage.Stage;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BaseMultiResolutionImage;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class TrayManager {
|
||||
private static final Logger log = LoggerFactory.getLogger(TrayManager.class);
|
||||
|
||||
private final SystemTray tray;
|
||||
private final TrayIcon trayIcon;
|
||||
private final PopupMenu popupMenu = new PopupMenu();
|
||||
|
||||
public TrayManager() {
|
||||
if(!SystemTray.isSupported()) {
|
||||
throw new UnsupportedOperationException("SystemTray icons are not supported by the current desktop environment.");
|
||||
}
|
||||
|
||||
tray = SystemTray.getSystemTray();
|
||||
|
||||
try {
|
||||
List<Image> imgList = new ArrayList<>();
|
||||
imgList.add(ImageIO.read(getClass().getResource("/image/sparrow-white-small.png")));
|
||||
imgList.add(ImageIO.read(getClass().getResource("/image/sparrow-white-small@2x.png")));
|
||||
imgList.add(ImageIO.read(getClass().getResource("/image/sparrow-white-small@3x.png")));
|
||||
BaseMultiResolutionImage mrImage = new BaseMultiResolutionImage(imgList.toArray(new Image[0]));
|
||||
|
||||
this.trayIcon = new TrayIcon(mrImage, "Sparrow", popupMenu);
|
||||
|
||||
MenuItem miExit = new MenuItem("Quit Sparrow");
|
||||
miExit.addActionListener(e -> {
|
||||
SwingUtilities.invokeLater(() -> { tray.remove(this.trayIcon); });
|
||||
Platform.exit();
|
||||
});
|
||||
this.popupMenu.add(miExit);
|
||||
} catch(IOException e) {
|
||||
log.error("Could not load system tray image", e);
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void addStage(Stage stage) {
|
||||
EventQueue.invokeLater(() -> {
|
||||
MenuItem miStage = new MenuItem(stage.getTitle());
|
||||
miStage.setFont(Font.decode(null).deriveFont(Font.BOLD));
|
||||
miStage.addActionListener(e -> Platform.runLater(() -> {
|
||||
stage.show();
|
||||
EventQueue.invokeLater(() -> {
|
||||
popupMenu.remove(miStage);
|
||||
|
||||
if(popupMenu.getItemCount() == 1) {
|
||||
Platform.setImplicitExit(true);
|
||||
SwingUtilities.invokeLater(() -> tray.remove(trayIcon));
|
||||
}
|
||||
});
|
||||
}));
|
||||
//Make sure it's always at the top
|
||||
this.popupMenu.insert(miStage,popupMenu.getItemCount() - 1);
|
||||
|
||||
if(!isShowing()) {
|
||||
// Keeps the JVM running even if there are no
|
||||
// visible JavaFX Stages, otherwise JVM would
|
||||
// exit and we lose the TrayIcon
|
||||
Platform.setImplicitExit(false);
|
||||
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
try {
|
||||
tray.add(this.trayIcon);
|
||||
} catch(AWTException e) {
|
||||
log.error("Unable to add system tray icon", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean isShowing() {
|
||||
return Arrays.stream(tray.getTrayIcons()).collect(Collectors.toList()).contains(trayIcon);
|
||||
}
|
||||
|
||||
public static boolean isSupported() {
|
||||
return Desktop.isDesktopSupported() && SystemTray.isSupported();
|
||||
}
|
||||
}
|
|
@ -47,7 +47,7 @@
|
|||
<fx:define>
|
||||
<ToggleGroup fx:id="theme"/>
|
||||
</fx:define>
|
||||
<Menu mnemonicParsing="false" text="View">
|
||||
<Menu fx:id="viewMenu" mnemonicParsing="false" text="View">
|
||||
<items>
|
||||
<Menu mnemonicParsing="false" text="Bitcoin Unit">
|
||||
<items>
|
||||
|
@ -87,6 +87,7 @@
|
|||
<CheckMenuItem fx:id="hideEmptyUsedAddresses" mnemonicParsing="false" text="Hide Empty Used Addresses" onAction="#hideEmptyUsedAddresses"/>
|
||||
<CheckMenuItem fx:id="showTxHex" mnemonicParsing="false" text="Show Transaction Hex" onAction="#showTxHex"/>
|
||||
<SeparatorMenuItem />
|
||||
<MenuItem fx:id="minimizeToTray" mnemonicParsing="false" text="Minimize to System Tray" accelerator="Shortcut+Y" onAction="#minimizeToTray"/>
|
||||
<MenuItem fx:id="refreshWallet" mnemonicParsing="false" text="Refresh Wallet" accelerator="Shortcut+R" onAction="#refreshWallet"/>
|
||||
</items>
|
||||
</Menu>
|
||||
|
|
BIN
src/main/resources/image/sparrow-white-small.png
Normal file
BIN
src/main/resources/image/sparrow-white-small.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 544 B |
BIN
src/main/resources/image/sparrow-white-small@2x.png
Normal file
BIN
src/main/resources/image/sparrow-white-small@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 913 B |
BIN
src/main/resources/image/sparrow-white-small@3x.png
Normal file
BIN
src/main/resources/image/sparrow-white-small@3x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
Loading…
Reference in a new issue