mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-17 10:11:27 +00:00
Added proper Quit dialog (not yet fully implemented), fixes #838
This commit is contained in:
@@ -8,6 +8,7 @@ public enum FxmlFile {
|
||||
ADDVAULT_NEW_LOCATION("/fxml/addvault_new_location.fxml"), //
|
||||
ADDVAULT_NEW_PASSWORD("/fxml/addvault_new_password.fxml"), //
|
||||
PREFERENCES("/fxml/preferences.fxml"), //
|
||||
QUIT("/fxml/quit.fxml"),
|
||||
UNLOCK("/fxml/unlock2.fxml"), // TODO rename
|
||||
UNLOCK_SUCCESS("/fxml/unlock_success.fxml"),
|
||||
VAULT_OPTIONS("/fxml/vault_options.fxml");
|
||||
|
||||
@@ -12,13 +12,13 @@ import org.cryptomator.jni.MacApplicationUiAppearance;
|
||||
import org.cryptomator.jni.MacFunctions;
|
||||
import org.cryptomator.ui.mainwindow.MainWindowComponent;
|
||||
import org.cryptomator.ui.preferences.PreferencesComponent;
|
||||
import org.cryptomator.ui.quit.QuitComponent;
|
||||
import org.cryptomator.ui.unlock.UnlockComponent;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.awt.Desktop;
|
||||
import java.awt.desktop.PreferencesEvent;
|
||||
import java.awt.desktop.QuitResponse;
|
||||
import java.util.Optional;
|
||||
|
||||
@FxApplicationScoped
|
||||
@@ -30,14 +30,16 @@ public class FxApplication extends Application {
|
||||
private final Lazy<MainWindowComponent> mainWindow;
|
||||
private final Lazy<PreferencesComponent> preferencesWindow;
|
||||
private final UnlockComponent.Builder unlockWindowBuilder;
|
||||
private final QuitComponent.Builder quitWindowBuilder;
|
||||
private final Optional<MacFunctions> macFunctions;
|
||||
|
||||
@Inject
|
||||
FxApplication(Settings settings, Lazy<MainWindowComponent> mainWindow, Lazy<PreferencesComponent> preferencesWindow, UnlockComponent.Builder unlockWindowBuilder, Optional<MacFunctions> macFunctions) {
|
||||
FxApplication(Settings settings, Lazy<MainWindowComponent> mainWindow, Lazy<PreferencesComponent> preferencesWindow, UnlockComponent.Builder unlockWindowBuilder, QuitComponent.Builder quitWindowBuilder, Optional<MacFunctions> macFunctions) {
|
||||
this.settings = settings;
|
||||
this.mainWindow = mainWindow;
|
||||
this.preferencesWindow = preferencesWindow;
|
||||
this.unlockWindowBuilder = unlockWindowBuilder;
|
||||
this.quitWindowBuilder = quitWindowBuilder;
|
||||
this.macFunctions = macFunctions;
|
||||
}
|
||||
|
||||
@@ -75,6 +77,13 @@ public class FxApplication extends Application {
|
||||
});
|
||||
}
|
||||
|
||||
public void showQuitWindow(QuitResponse response) {
|
||||
Platform.runLater(() -> {
|
||||
quitWindowBuilder.quitResponse(response).build().showQuitWindow();
|
||||
LOG.debug("Showing QuitWindow");
|
||||
});
|
||||
}
|
||||
|
||||
private void themeChanged(@SuppressWarnings("unused") ObservableValue<? extends UiTheme> observable, @SuppressWarnings("unused") UiTheme oldValue, UiTheme newValue) {
|
||||
loadSelectedStyleSheet(newValue);
|
||||
}
|
||||
|
||||
@@ -15,11 +15,12 @@ import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.keychain.KeychainModule;
|
||||
import org.cryptomator.ui.mainwindow.MainWindowComponent;
|
||||
import org.cryptomator.ui.preferences.PreferencesComponent;
|
||||
import org.cryptomator.ui.quit.QuitComponent;
|
||||
import org.cryptomator.ui.unlock.UnlockComponent;
|
||||
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
@Module(includes = {KeychainModule.class, UpdateCheckerModule.class}, subcomponents = {MainWindowComponent.class, PreferencesComponent.class, UnlockComponent.class})
|
||||
@Module(includes = {KeychainModule.class, UpdateCheckerModule.class}, subcomponents = {MainWindowComponent.class, PreferencesComponent.class, UnlockComponent.class, QuitComponent.class})
|
||||
abstract class FxApplicationModule {
|
||||
|
||||
@Binds
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Skymatic UG (haftungsbeschränkt).
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the accompanying LICENSE file.
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.ui.quit;
|
||||
|
||||
import dagger.BindsInstance;
|
||||
import dagger.Lazy;
|
||||
import dagger.Subcomponent;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
|
||||
import java.awt.desktop.QuitResponse;
|
||||
|
||||
@QuitScoped
|
||||
@Subcomponent(modules = {QuitModule.class})
|
||||
public interface QuitComponent {
|
||||
|
||||
@QuitWindow
|
||||
Stage window();
|
||||
|
||||
@FxmlScene(FxmlFile.QUIT)
|
||||
Lazy<Scene> scene();
|
||||
|
||||
default void showQuitWindow() {
|
||||
Stage stage = window();
|
||||
stage.setScene(scene().get());
|
||||
stage.show();
|
||||
stage.requestFocus();
|
||||
}
|
||||
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
|
||||
@BindsInstance
|
||||
Builder quitResponse(QuitResponse response);
|
||||
|
||||
QuitComponent build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package org.cryptomator.ui.quit;
|
||||
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.ContentDisplay;
|
||||
import javafx.stage.Stage;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.awt.desktop.QuitResponse;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
@QuitScoped
|
||||
public class QuitController implements FxController {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(QuitController.class);
|
||||
|
||||
private final Stage window;
|
||||
private final QuitResponse response;
|
||||
private final ExecutorService executor;
|
||||
private final ObjectProperty<ContentDisplay> quitButtonState;
|
||||
|
||||
@Inject
|
||||
QuitController(@QuitWindow Stage window, QuitResponse response, ExecutorService executor) {
|
||||
this.window = window;
|
||||
this.response = response;
|
||||
this.executor = executor;
|
||||
this.quitButtonState = new SimpleObjectProperty<>(ContentDisplay.TEXT_ONLY);
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void cancel() {
|
||||
LOG.info("Quitting application canceled by user.");
|
||||
window.close();
|
||||
response.cancelQuit();
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void quit() {
|
||||
LOG.warn("Quit not yet implemented.");
|
||||
window.close();
|
||||
response.cancelQuit();
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void forceQuit() {
|
||||
LOG.warn("Force Quit not yet implemented.");
|
||||
window.close();
|
||||
response.cancelQuit();
|
||||
}
|
||||
|
||||
/* Observable Properties */
|
||||
|
||||
public ObjectProperty<ContentDisplay> quitButtonStateProperty() {
|
||||
return quitButtonState;
|
||||
}
|
||||
|
||||
public ContentDisplay getQuitButtonState() {
|
||||
return quitButtonState.get();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package org.cryptomator.ui.quit;
|
||||
|
||||
import dagger.Binds;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import dagger.multibindings.IntoMap;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import org.cryptomator.ui.common.FXMLLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxControllerKey;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
import org.cryptomator.ui.unlock.UnlockController;
|
||||
|
||||
import javax.inject.Provider;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
@Module
|
||||
abstract class QuitModule {
|
||||
|
||||
@Provides
|
||||
@QuitWindow
|
||||
@QuitScoped
|
||||
static FXMLLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, ResourceBundle resourceBundle) {
|
||||
return new FXMLLoaderFactory(factories, resourceBundle);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@QuitWindow
|
||||
@QuitScoped
|
||||
static Stage provideStage() {
|
||||
Stage stage = new Stage();
|
||||
stage.setMinWidth(300);
|
||||
stage.setMinHeight(200);
|
||||
stage.initModality(Modality.APPLICATION_MODAL);
|
||||
return stage;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.QUIT)
|
||||
@QuitScoped
|
||||
static Scene provideUnlockScene(@QuitWindow FXMLLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene("/fxml/quit.fxml");
|
||||
}
|
||||
|
||||
// ------------------
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FxControllerKey(QuitController.class)
|
||||
abstract FxController bindQuitController(QuitController controller);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.cryptomator.ui.quit;
|
||||
|
||||
import javax.inject.Scope;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Scope
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface QuitScoped {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package org.cryptomator.ui.quit;
|
||||
|
||||
import javax.inject.Qualifier;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
@Qualifier
|
||||
@Documented
|
||||
@Retention(RUNTIME)
|
||||
public @interface QuitWindow {
|
||||
|
||||
}
|
||||
@@ -1,10 +1,13 @@
|
||||
package org.cryptomator.ui.traymenu;
|
||||
|
||||
import javafx.beans.Observable;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.binding.BooleanBinding;
|
||||
import javafx.collections.ObservableList;
|
||||
import org.cryptomator.common.settings.Settings;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.fxapp.FxApplication;
|
||||
import org.fxmisc.easybind.EasyBind;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
@@ -12,6 +15,8 @@ import java.awt.Desktop;
|
||||
import java.awt.Menu;
|
||||
import java.awt.MenuItem;
|
||||
import java.awt.PopupMenu;
|
||||
import java.awt.desktop.QuitEvent;
|
||||
import java.awt.desktop.QuitResponse;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.EventObject;
|
||||
@@ -26,6 +31,7 @@ class TrayMenuController {
|
||||
private final Settings settings;
|
||||
private final ObservableList<Vault> vaults;
|
||||
private final PopupMenu menu;
|
||||
private final BooleanBinding allLocked;
|
||||
|
||||
@Inject
|
||||
TrayMenuController(FxApplicationStarter fxApplicationStarter, @Named("shutdownLatch") CountDownLatch shutdownLatch, Settings settings, ObservableList<Vault> vaults) {
|
||||
@@ -34,6 +40,7 @@ class TrayMenuController {
|
||||
this.settings = settings;
|
||||
this.vaults = vaults;
|
||||
this.menu = new PopupMenu();
|
||||
this.allLocked = Bindings.isEmpty(vaults.filtered(Vault::isUnlocked)); // TODO better use Vault::isNotLocked ;)
|
||||
}
|
||||
|
||||
public PopupMenu getMenu() {
|
||||
@@ -50,6 +57,11 @@ class TrayMenuController {
|
||||
Desktop.getDesktop().setPreferencesHandler(this::showPreferencesWindow);
|
||||
}
|
||||
|
||||
// register preferences shortcut
|
||||
if (Desktop.getDesktop().isSupported(Desktop.Action.APP_QUIT_HANDLER)) {
|
||||
Desktop.getDesktop().setQuitHandler(this::handleQuitRequest);
|
||||
}
|
||||
|
||||
// show window on start?
|
||||
if (!settings.startHidden().get()) {
|
||||
showMainWindow(null);
|
||||
@@ -111,14 +123,32 @@ class TrayMenuController {
|
||||
}
|
||||
|
||||
void showMainWindow(@SuppressWarnings("unused") ActionEvent actionEvent) {
|
||||
fxApplicationStarter.get(true).thenAccept(FxApplication::showMainWindow);
|
||||
fxApplicationStarter.get(true).thenAccept(app -> app.showMainWindow());
|
||||
}
|
||||
|
||||
void showPreferencesWindow(@SuppressWarnings("unused") EventObject actionEvent) {
|
||||
private void showPreferencesWindow(@SuppressWarnings("unused") EventObject actionEvent) {
|
||||
fxApplicationStarter.get(true).thenAccept(FxApplication::showPreferencesWindow);
|
||||
}
|
||||
|
||||
void quitApplication(@SuppressWarnings("unused") ActionEvent actionEvent) {
|
||||
shutdownLatch.countDown();
|
||||
private void handleQuitRequest(EventObject e, QuitResponse response) {
|
||||
if (allLocked.get()) {
|
||||
response.performQuit(); // really?
|
||||
} else {
|
||||
fxApplicationStarter.get(true).thenAccept(app -> app.showQuitWindow(response));
|
||||
}
|
||||
}
|
||||
|
||||
private void quitApplication(EventObject actionEvent) {
|
||||
handleQuitRequest(actionEvent, new QuitResponse() {
|
||||
@Override
|
||||
public void performQuit() {
|
||||
shutdownLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelQuit() {
|
||||
// no-op
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
34
main/ui/src/main/resources/fxml/quit.fxml
Normal file
34
main/ui/src/main/resources/fxml/quit.fxml
Normal file
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.ProgressIndicator?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.text.Text?>
|
||||
<?import javafx.scene.text.TextFlow?>
|
||||
<VBox xmlns="http://javafx.com/javafx"
|
||||
xmlns:fx="http://javafx.com/fxml"
|
||||
fx:controller="org.cryptomator.ui.quit.QuitController"
|
||||
minWidth="300"
|
||||
spacing="6">
|
||||
<padding>
|
||||
<Insets bottom="6.0" left="6.0" right="6.0" top="6.0"/>
|
||||
</padding>
|
||||
<children>
|
||||
<TextFlow styleClass="text-flow">
|
||||
<Text text="TODO Quit application? There are unlocked vaults "/>
|
||||
</TextFlow>
|
||||
<HBox>
|
||||
<Button text="TODO cancel" cancelButton="true" onAction="#cancel"/>
|
||||
<Region HBox.hgrow="ALWAYS"/>
|
||||
<Button text="TODO force quit" cancelButton="true" onAction="#forceQuit"/>
|
||||
<Button text="TODO lock and quit" defaultButton="true" onAction="#quit" contentDisplay="${controller.quitButtonState}">
|
||||
<graphic>
|
||||
<ProgressIndicator progress="-1" prefWidth="12" prefHeight="12"/>
|
||||
</graphic>
|
||||
</Button>
|
||||
</HBox>
|
||||
</children>
|
||||
</VBox>
|
||||
Reference in New Issue
Block a user