Merge pull request #3618 from cryptomator/feature/dialog-builder

Feature: SimpleDialogBuilder
This commit is contained in:
mindmonk
2025-01-10 15:17:24 +01:00
committed by GitHub
30 changed files with 362 additions and 629 deletions

View File

@@ -12,7 +12,6 @@ public enum FxmlFile {
CONVERTVAULT_HUBTOPASSWORD_START("/fxml/convertvault_hubtopassword_start.fxml"), //
CONVERTVAULT_HUBTOPASSWORD_CONVERT("/fxml/convertvault_hubtopassword_convert.fxml"), //
CONVERTVAULT_HUBTOPASSWORD_SUCCESS("/fxml/convertvault_hubtopassword_success.fxml"), //
DOKANY_SUPPORT_END("/fxml/dokany_support_end.fxml"), //
ERROR("/fxml/error.fxml"), //
FORGET_PASSWORD("/fxml/forget_password.fxml"), //
HEALTH_START("/fxml/health_start.fxml"), //
@@ -45,9 +44,8 @@ public enum FxmlFile {
RECOVERYKEY_RESET_PASSWORD("/fxml/recoverykey_reset_password.fxml"), //
RECOVERYKEY_RESET_PASSWORD_SUCCESS("/fxml/recoverykey_reset_password_success.fxml"), //
RECOVERYKEY_SUCCESS("/fxml/recoverykey_success.fxml"), //
REMOVE_CERT("/fxml/remove_cert.fxml"), //
REMOVE_VAULT("/fxml/remove_vault.fxml"), //
SHARE_VAULT("/fxml/share_vault.fxml"), //
SIMPLE_DIALOG("/fxml/simple_dialog.fxml"), //
UPDATE_REMINDER("/fxml/update_reminder.fxml"), //
UNLOCK_ENTER_PASSWORD("/fxml/unlock_enter_password.fxml"),
UNLOCK_REQUIRES_RESTART("/fxml/unlock_requires_restart.fxml"), //

View File

@@ -0,0 +1,75 @@
package org.cryptomator.ui.dialogs;
import org.cryptomator.common.settings.Settings;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.ui.controls.FontAwesome5Icon;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Singleton;
import javafx.collections.ObservableList;
import javafx.stage.Stage;
import java.util.ResourceBundle;
import java.util.function.Consumer;
@Singleton
public class Dialogs {
private final ResourceBundle resourceBundle;
@Inject
public Dialogs(ResourceBundle resourceBundle) {
this.resourceBundle = resourceBundle;
}
private static final Logger LOG = LoggerFactory.getLogger(Dialogs.class);
private SimpleDialog.Builder createDialogBuilder() {
return new SimpleDialog.Builder(resourceBundle);
}
public SimpleDialog.Builder prepareRemoveVaultDialog(Stage window, Vault vault, ObservableList<Vault> vaults) {
return createDialogBuilder().setOwner(window) //
.setTitleKey("removeVault.title", vault.getDisplayName()) //
.setMessageKey("removeVault.message") //
.setDescriptionKey("removeVault.description") //
.setIcon(FontAwesome5Icon.QUESTION) //
.setOkButtonKey("removeVault.confirmBtn") //
.setCancelButtonKey("generic.button.cancel") //
.setOkAction(stage -> {
LOG.debug("Removing vault {}.", vault.getDisplayName());
vaults.remove(vault);
stage.close();
});
}
public SimpleDialog.Builder prepareRemoveCertDialog(Stage window, Settings settings) {
return createDialogBuilder() //
.setOwner(window) //
.setTitleKey("removeCert.title") //
.setMessageKey("removeCert.message") //
.setDescriptionKey("removeCert.description") //
.setIcon(FontAwesome5Icon.QUESTION) //
.setOkButtonKey("removeCert.confirmBtn") //
.setCancelButtonKey("generic.button.cancel") //
.setOkAction(stage -> {
settings.licenseKey.set(null);
stage.close();
});
}
public SimpleDialog.Builder prepareDokanySupportEndDialog(Stage window, Consumer<Stage> cancelAction) {
return createDialogBuilder() //
.setOwner(window) //
.setTitleKey("dokanySupportEnd.title") //
.setMessageKey("dokanySupportEnd.message") //
.setDescriptionKey("dokanySupportEnd.description") //
.setIcon(FontAwesome5Icon.QUESTION) //
.setOkButtonKey("generic.button.close") //
.setCancelButtonKey("dokanySupportEnd.preferencesBtn") //
.setOkAction(Stage::close) //
.setCancelAction(cancelAction);
}
}

View File

@@ -0,0 +1,138 @@
package org.cryptomator.ui.dialogs;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlLoaderFactory;
import org.cryptomator.ui.controls.FontAwesome5Icon;
import javafx.scene.Scene;
import javafx.stage.Modality;
import javafx.stage.Stage;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.IllegalFormatException;
import java.util.Objects;
import java.util.ResourceBundle;
import java.util.function.Consumer;
public class SimpleDialog {
private final ResourceBundle resourceBundle;
private final Stage dialogStage;
SimpleDialog(Builder builder) throws IOException {
this.resourceBundle = builder.resourceBundle;
dialogStage = new Stage();
dialogStage.initOwner(builder.owner);
dialogStage.initModality(Modality.WINDOW_MODAL);
dialogStage.setTitle(resolveText(builder.titleKey, builder.titleArgs));
dialogStage.setResizable(false);
FxmlLoaderFactory loaderFactory = FxmlLoaderFactory.forController(
new SimpleDialogController(resolveText(builder.messageKey, null),
resolveText(builder.descriptionKey, null),
builder.icon,resolveText(builder.okButtonKey, null),
resolveText(builder.cancelButtonKey, null),
() -> builder.okAction.accept(dialogStage),
() -> builder.cancelAction.accept(dialogStage)),
Scene::new, builder.resourceBundle);
dialogStage.setScene(new Scene(loaderFactory.load(FxmlFile.SIMPLE_DIALOG.getRessourcePathString()).getRoot()));
}
public void showAndWait() {
dialogStage.showAndWait();
}
private String resolveText(String key, String[] args) {
if (key == null || key.isEmpty() || !resourceBundle.containsKey(key)) {
throw new IllegalArgumentException(String.format("Invalid key: '%s'. Key not found in ResourceBundle.", key));
}
String text = resourceBundle.getString(key);
try {
return args != null && args.length > 0 ? String.format(text, (Object[]) args) : text;
} catch (IllegalFormatException e) {
throw new IllegalArgumentException("Formatting error: Check if arguments match placeholders in the text.", e);
}
}
public static class Builder {
private Stage owner;
private final ResourceBundle resourceBundle;
private String titleKey;
private String[] titleArgs;
private String messageKey;
private String descriptionKey;
private String okButtonKey;
private String cancelButtonKey;
private FontAwesome5Icon icon;
private Consumer<Stage> okAction = Stage::close;
private Consumer<Stage> cancelAction = Stage::close;
public Builder(ResourceBundle resourceBundle) {
this.resourceBundle = resourceBundle;
}
public Builder setOwner(Stage owner) {
this.owner = owner;
return this;
}
public Builder setTitleKey(String titleKey, String... args) {
this.titleKey = titleKey;
this.titleArgs = args;
return this;
}
public Builder setMessageKey(String messageKey) {
this.messageKey = messageKey;
return this;
}
public Builder setDescriptionKey(String descriptionKey) {
this.descriptionKey = descriptionKey;
return this;
}
public Builder setIcon(FontAwesome5Icon icon) {
this.icon = icon;
return this;
}
public Builder setOkButtonKey(String okButtonKey) {
this.okButtonKey = okButtonKey;
return this;
}
public Builder setCancelButtonKey(String cancelButtonKey) {
this.cancelButtonKey = cancelButtonKey;
return this;
}
public Builder setOkAction(Consumer<Stage> okAction) {
this.okAction = okAction;
return this;
}
public Builder setCancelAction(Consumer<Stage> cancelAction) {
this.cancelAction = cancelAction;
return this;
}
public SimpleDialog build() {
Objects.requireNonNull(titleKey,"SimpleDialog titleKey must be set.");
Objects.requireNonNull(messageKey,"SimpleDialog messageKey must be set.");
Objects.requireNonNull(descriptionKey,"SimpleDialog descriptionKey must be set.");
Objects.requireNonNull(okButtonKey,"SimpleDialog okButtonKey must be set.");
Objects.requireNonNull(cancelButtonKey,"SimpleDialog cancelButtonKey must be set.");
try {
return new SimpleDialog(this);
} catch (IOException e) {
throw new UncheckedIOException("Failed to create SimpleDialog.", e);
}
}
}
}

View File

@@ -0,0 +1,61 @@
package org.cryptomator.ui.dialogs;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.controls.FontAwesome5Icon;
import javafx.fxml.FXML;
public class SimpleDialogController implements FxController {
private final String message;
private final String description;
private final FontAwesome5Icon icon;
private final String okButtonText;
private final String cancelButtonText;
private final Runnable okAction;
private final Runnable cancelAction;
public SimpleDialogController(String message, String description, FontAwesome5Icon icon, String okButtonText, String cancelButtonText, Runnable okAction, Runnable cancelAction) {
this.message = message;
this.description = description;
this.icon = icon;
this.okButtonText = okButtonText;
this.cancelButtonText = cancelButtonText;
this.okAction = okAction;
this.cancelAction = cancelAction;
}
public String getMessage() {
return message;
}
public String getDescription() {
return description;
}
public FontAwesome5Icon getIcon() {
return icon;
}
public String getOkButtonText() {
return okButtonText;
}
public String getCancelButtonText() {
return cancelButtonText;
}
@FXML
private void handleOk() {
if (okAction != null) {
okAction.run();
}
}
@FXML
private void handleCancel() {
if (cancelAction != null) {
cancelAction.run();
}
}
}

View File

@@ -1,34 +0,0 @@
package org.cryptomator.ui.dokanysupportend;
import dagger.Lazy;
import dagger.Subcomponent;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
import javafx.scene.Scene;
import javafx.stage.Stage;
@DokanySupportEndScoped
@Subcomponent(modules = {DokanySupportEndModule.class})
public interface DokanySupportEndComponent {
@DokanySupportEndWindow
Stage window();
@FxmlScene(FxmlFile.DOKANY_SUPPORT_END)
Lazy<Scene> dokanySupportEndScene();
default void showDokanySupportEndWindow() {
Stage stage = window();
stage.setScene(dokanySupportEndScene().get());
stage.sizeToScene();
stage.show();
}
@Subcomponent.Factory
interface Factory {
DokanySupportEndComponent create();
}
}

View File

@@ -1,34 +0,0 @@
package org.cryptomator.ui.dokanysupportend;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.fxapp.FxApplicationWindows;
import org.cryptomator.ui.preferences.SelectedPreferencesTab;
import javax.inject.Inject;
import javafx.fxml.FXML;
import javafx.stage.Stage;
@DokanySupportEndScoped
public class DokanySupportEndController implements FxController {
private final Stage window;
private final FxApplicationWindows applicationWindows;
@Inject
DokanySupportEndController(@DokanySupportEndWindow Stage window, FxApplicationWindows applicationWindows) {
this.window = window;
this.applicationWindows = applicationWindows;
}
@FXML
public void close() {
window.close();
}
public void openVolumePreferences() {
applicationWindows.showPreferencesWindow(SelectedPreferencesTab.VOLUME);
window.close();
}
}

View File

@@ -1,57 +0,0 @@
package org.cryptomator.ui.dokanysupportend;
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoMap;
import org.cryptomator.ui.common.DefaultSceneFactory;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.FxControllerKey;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlLoaderFactory;
import org.cryptomator.ui.common.FxmlScene;
import org.cryptomator.ui.common.StageFactory;
import javax.inject.Provider;
import javafx.scene.Scene;
import javafx.stage.Modality;
import javafx.stage.Stage;
import java.util.Map;
import java.util.ResourceBundle;
@Module
abstract class DokanySupportEndModule {
@Provides
@DokanySupportEndWindow
@DokanySupportEndScoped
static FxmlLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
return new FxmlLoaderFactory(factories, sceneFactory, resourceBundle);
}
@Provides
@DokanySupportEndWindow
@DokanySupportEndScoped
static Stage provideStage(StageFactory factory, ResourceBundle resourceBundle) {
Stage stage = factory.create();
stage.setTitle(resourceBundle.getString("dokanySupportEnd.title"));
stage.setMinWidth(500);
stage.setMinHeight(100);
stage.initModality(Modality.APPLICATION_MODAL);
return stage;
}
@Provides
@FxmlScene(FxmlFile.DOKANY_SUPPORT_END)
@DokanySupportEndScoped
static Scene provideDokanySupportEndScene(@DokanySupportEndWindow FxmlLoaderFactory fxmlLoaders) {
return fxmlLoaders.createScene(FxmlFile.DOKANY_SUPPORT_END);
}
@Binds
@IntoMap
@FxControllerKey(DokanySupportEndController.class)
abstract FxController bindDokanySupportEndController(DokanySupportEndController controller);
}

View File

@@ -1,13 +0,0 @@
package org.cryptomator.ui.dokanysupportend;
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 DokanySupportEndScoped {
}

View File

@@ -1,14 +0,0 @@
package org.cryptomator.ui.dokanysupportend;
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)
@interface DokanySupportEndWindow {
}

View File

@@ -7,14 +7,12 @@ package org.cryptomator.ui.fxapp;
import dagger.Module;
import dagger.Provides;
import org.cryptomator.ui.dokanysupportend.DokanySupportEndComponent;
import org.cryptomator.ui.error.ErrorComponent;
import org.cryptomator.ui.health.HealthCheckComponent;
import org.cryptomator.ui.lock.LockComponent;
import org.cryptomator.ui.mainwindow.MainWindowComponent;
import org.cryptomator.ui.preferences.PreferencesComponent;
import org.cryptomator.ui.quit.QuitComponent;
import org.cryptomator.ui.removecert.RemoveCertComponent;
import org.cryptomator.ui.sharevault.ShareVaultComponent;
import org.cryptomator.ui.traymenu.TrayMenuComponent;
import org.cryptomator.ui.unlock.UnlockComponent;
@@ -35,8 +33,6 @@ import java.io.InputStream;
ErrorComponent.class, //
HealthCheckComponent.class, //
UpdateReminderComponent.class, //
DokanySupportEndComponent.class, //
RemoveCertComponent.class, //
ShareVaultComponent.class})
abstract class FxApplicationModule {

View File

@@ -5,7 +5,7 @@ import dagger.Lazy;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultState;
import org.cryptomator.integrations.tray.TrayIntegrationProvider;
import org.cryptomator.ui.dokanysupportend.DokanySupportEndComponent;
import org.cryptomator.ui.dialogs.Dialogs;
import org.cryptomator.ui.error.ErrorComponent;
import org.cryptomator.ui.lock.LockComponent;
import org.cryptomator.ui.mainwindow.MainWindowComponent;
@@ -49,13 +49,13 @@ public class FxApplicationWindows {
private final QuitComponent.Builder quitWindowBuilder;
private final UnlockComponent.Factory unlockWorkflowFactory;
private final UpdateReminderComponent.Factory updateReminderWindowFactory;
private final DokanySupportEndComponent.Factory dokanySupportEndWindowBuilder;
private final LockComponent.Factory lockWorkflowFactory;
private final ErrorComponent.Factory errorWindowFactory;
private final ExecutorService executor;
private final VaultOptionsComponent.Factory vaultOptionsWindow;
private final ShareVaultComponent.Factory shareVaultWindow;
private final FilteredList<Window> visibleWindows;
private final Dialogs dialogs;
@Inject
public FxApplicationWindows(@PrimaryStage Stage primaryStage, //
@@ -65,12 +65,12 @@ public class FxApplicationWindows {
QuitComponent.Builder quitWindowBuilder, //
UnlockComponent.Factory unlockWorkflowFactory, //
UpdateReminderComponent.Factory updateReminderWindowFactory, //
DokanySupportEndComponent.Factory dokanySupportEndWindowBuilder, //
LockComponent.Factory lockWorkflowFactory, //
ErrorComponent.Factory errorWindowFactory, //
VaultOptionsComponent.Factory vaultOptionsWindow, //
ShareVaultComponent.Factory shareVaultWindow, //
ExecutorService executor) {
ExecutorService executor, //
Dialogs dialogs) {
this.primaryStage = primaryStage;
this.trayIntegration = trayIntegration;
this.mainWindow = mainWindow;
@@ -78,13 +78,13 @@ public class FxApplicationWindows {
this.quitWindowBuilder = quitWindowBuilder;
this.unlockWorkflowFactory = unlockWorkflowFactory;
this.updateReminderWindowFactory = updateReminderWindowFactory;
this.dokanySupportEndWindowBuilder = dokanySupportEndWindowBuilder;
this.lockWorkflowFactory = lockWorkflowFactory;
this.errorWindowFactory = errorWindowFactory;
this.executor = executor;
this.vaultOptionsWindow = vaultOptionsWindow;
this.shareVaultWindow = shareVaultWindow;
this.visibleWindows = Window.getWindows().filtered(Window::isShowing);
this.dialogs = dialogs;
}
public void initialize() {
@@ -147,10 +147,15 @@ public class FxApplicationWindows {
}
public void showDokanySupportEndWindow() {
CompletableFuture.runAsync(() -> dokanySupportEndWindowBuilder.create().showDokanySupportEndWindow(), Platform::runLater);
CompletableFuture.runAsync(() -> dialogs.prepareDokanySupportEndDialog(
mainWindow.get().window(),
stage -> {
showPreferencesWindow(SelectedPreferencesTab.VOLUME);
stage.close();
}
).build().showAndWait(), Platform::runLater);
}
public CompletionStage<Void> startUnlockWorkflow(Vault vault, @Nullable Stage owner) {
return CompletableFuture.supplyAsync(() -> {
Preconditions.checkState(vault.stateProperty().transition(VaultState.Value.LOCKED, VaultState.Value.PROCESSING), "Vault not locked.");

View File

@@ -16,7 +16,6 @@ import org.cryptomator.ui.common.StageInitializer;
import org.cryptomator.ui.error.ErrorComponent;
import org.cryptomator.ui.fxapp.PrimaryStage;
import org.cryptomator.ui.migration.MigrationComponent;
import org.cryptomator.ui.removevault.RemoveVaultComponent;
import org.cryptomator.ui.stats.VaultStatisticsComponent;
import org.cryptomator.ui.wrongfilealert.WrongFileAlertComponent;
@@ -30,7 +29,7 @@ import javafx.stage.Stage;
import java.util.Map;
import java.util.ResourceBundle;
@Module(subcomponents = {AddVaultWizardComponent.class, MigrationComponent.class, RemoveVaultComponent.class, VaultStatisticsComponent.class, WrongFileAlertComponent.class, ErrorComponent.class})
@Module(subcomponents = {AddVaultWizardComponent.class, MigrationComponent.class, VaultStatisticsComponent.class, WrongFileAlertComponent.class, ErrorComponent.class})
abstract class MainWindowModule {
@Provides

View File

@@ -3,10 +3,11 @@ package org.cryptomator.ui.mainwindow;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultListManager;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.removevault.RemoveVaultComponent;
import org.cryptomator.ui.dialogs.Dialogs;
import javax.inject.Inject;
import javafx.beans.property.ObjectProperty;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
@@ -19,17 +20,22 @@ import static org.cryptomator.common.Constants.CRYPTOMATOR_FILENAME_GLOB;
public class VaultDetailMissingVaultController implements FxController {
private final ObjectProperty<Vault> vault;
private final RemoveVaultComponent.Builder removeVault;
private final ObservableList<Vault> vaults;
private final ResourceBundle resourceBundle;
private final Stage window;
private final Dialogs dialogs;
@Inject
public VaultDetailMissingVaultController(ObjectProperty<Vault> vault, RemoveVaultComponent.Builder removeVault, ResourceBundle resourceBundle, @MainWindow Stage window) {
public VaultDetailMissingVaultController(ObjectProperty<Vault> vault, //
ObservableList<Vault> vaults, //
ResourceBundle resourceBundle, //
@MainWindow Stage window, //
Dialogs dialogs) {
this.vault = vault;
this.removeVault = removeVault;
this.vaults = vaults;
this.resourceBundle = resourceBundle;
this.window = window;
this.dialogs = dialogs;
}
@FXML
@@ -39,7 +45,7 @@ public class VaultDetailMissingVaultController implements FxController {
@FXML
void didClickRemoveVault() {
removeVault.vault(vault.get()).build().showRemoveVault();
dialogs.prepareRemoveVaultDialog(window, vault.get(), vaults).build().showAndWait();
}
@FXML

View File

@@ -3,12 +3,13 @@ package org.cryptomator.ui.mainwindow;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultListManager;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.dialogs.Dialogs;
import org.cryptomator.ui.fxapp.FxApplicationWindows;
import org.cryptomator.ui.removevault.RemoveVaultComponent;
import javax.inject.Inject;
import javax.inject.Named;
import javafx.beans.property.ObjectProperty;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.stage.Stage;
@@ -18,14 +19,23 @@ public class VaultDetailUnknownErrorController implements FxController {
private final ObjectProperty<Vault> vault;
private final FxApplicationWindows appWindows;
private final Stage errorWindow;
private final RemoveVaultComponent.Builder removeVault;
private final ObservableList<Vault> vaults;
private final Stage mainWindow;
private final Dialogs dialogs;
@Inject
public VaultDetailUnknownErrorController(ObjectProperty<Vault> vault, FxApplicationWindows appWindows, @Named("errorWindow") Stage errorWindow, RemoveVaultComponent.Builder removeVault) {
public VaultDetailUnknownErrorController(@MainWindow Stage mainWindow, //
ObjectProperty<Vault> vault, //
ObservableList<Vault> vaults, //
FxApplicationWindows appWindows, //
@Named("errorWindow") Stage errorWindow, //
Dialogs dialogs) {
this.mainWindow = mainWindow;
this.vault = vault;
this.vaults = vaults;
this.appWindows = appWindows;
this.errorWindow = errorWindow;
this.removeVault = removeVault;
this.dialogs = dialogs;
}
@FXML
@@ -40,6 +50,6 @@ public class VaultDetailUnknownErrorController implements FxController {
@FXML
void didClickRemoveVault() {
removeVault.vault(vault.get()).build().showRemoveVault();
dialogs.prepareRemoveVaultDialog(mainWindow, vault.get(), vaults).build().showAndWait();
}
}

View File

@@ -5,8 +5,8 @@ import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultState;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.VaultService;
import org.cryptomator.ui.dialogs.Dialogs;
import org.cryptomator.ui.fxapp.FxApplicationWindows;
import org.cryptomator.ui.removevault.RemoveVaultComponent;
import org.cryptomator.ui.vaultoptions.SelectedVaultOptionsTab;
import org.cryptomator.ui.vaultoptions.VaultOptionsComponent;
@@ -14,6 +14,7 @@ import javax.inject.Inject;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.stage.Stage;
import java.util.EnumSet;
@@ -33,23 +34,32 @@ public class VaultListContextMenuController implements FxController {
private final FxApplicationWindows appWindows;
private final VaultService vaultService;
private final KeychainManager keychain;
private final RemoveVaultComponent.Builder removeVault;
private final VaultOptionsComponent.Factory vaultOptionsWindow;
private final ObservableValue<VaultState.Value> selectedVaultState;
private final ObservableValue<Boolean> selectedVaultPassphraseStored;
private final ObservableValue<Boolean> selectedVaultRemovable;
private final ObservableValue<Boolean> selectedVaultUnlockable;
private final ObservableValue<Boolean> selectedVaultLockable;
private final ObservableList<Vault> vaults;
private final Dialogs dialogs;
@Inject
VaultListContextMenuController(ObjectProperty<Vault> selectedVault, @MainWindow Stage mainWindow, FxApplicationWindows appWindows, VaultService vaultService, KeychainManager keychain, RemoveVaultComponent.Builder removeVault, VaultOptionsComponent.Factory vaultOptionsWindow) {
VaultListContextMenuController(ObjectProperty<Vault> selectedVault, //
ObservableList<Vault> vaults, //
@MainWindow Stage mainWindow, //
FxApplicationWindows appWindows, //
VaultService vaultService, //
KeychainManager keychain, //
VaultOptionsComponent.Factory vaultOptionsWindow, //
Dialogs dialogs) {
this.selectedVault = selectedVault;
this.vaults = vaults;
this.mainWindow = mainWindow;
this.appWindows = appWindows;
this.vaultService = vaultService;
this.keychain = keychain;
this.removeVault = removeVault;
this.vaultOptionsWindow = vaultOptionsWindow;
this.dialogs = dialogs;
this.selectedVaultState = selectedVault.flatMap(Vault::stateProperty).orElse(null);
this.selectedVaultPassphraseStored = selectedVault.map(this::isPasswordStored).orElse(false);
@@ -65,7 +75,7 @@ public class VaultListContextMenuController implements FxController {
@FXML
public void didClickRemoveVault() {
var vault = Objects.requireNonNull(selectedVault.get());
removeVault.vault(vault).build().showRemoveVault();
dialogs.prepareRemoveVaultDialog(mainWindow, vault, vaults).build().showAndWait();
}
@FXML

View File

@@ -9,9 +9,9 @@ import org.cryptomator.cryptofs.DirStructure;
import org.cryptomator.ui.addvaultwizard.AddVaultWizardComponent;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.VaultService;
import org.cryptomator.ui.dialogs.Dialogs;
import org.cryptomator.ui.fxapp.FxApplicationWindows;
import org.cryptomator.ui.preferences.SelectedPreferencesTab;
import org.cryptomator.ui.removevault.RemoveVaultComponent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -66,12 +66,13 @@ public class VaultListController implements FxController {
private final VaultListCellFactory cellFactory;
private final AddVaultWizardComponent.Builder addVaultWizard;
private final BooleanBinding emptyVaultList;
private final RemoveVaultComponent.Builder removeVaultDialogue;
private final VaultListManager vaultListManager;
private final BooleanProperty draggingVaultOver = new SimpleBooleanProperty();
private final ResourceBundle resourceBundle;
private final FxApplicationWindows appWindows;
private final ObservableValue<Double> cellSize;
private final Dialogs dialogs;
public ListView<Vault> vaultList;
public StackPane root;
@FXML
@@ -86,21 +87,21 @@ public class VaultListController implements FxController {
VaultListCellFactory cellFactory, //
VaultService vaultService, //
AddVaultWizardComponent.Builder addVaultWizard, //
RemoveVaultComponent.Builder removeVaultDialogue, //
VaultListManager vaultListManager, //
ResourceBundle resourceBundle, //
FxApplicationWindows appWindows, //
Settings settings) {
Settings settings, //
Dialogs dialogs) {
this.mainWindow = mainWindow;
this.vaults = vaults;
this.selectedVault = selectedVault;
this.cellFactory = cellFactory;
this.vaultService = vaultService;
this.addVaultWizard = addVaultWizard;
this.removeVaultDialogue = removeVaultDialogue;
this.vaultListManager = vaultListManager;
this.resourceBundle = resourceBundle;
this.appWindows = appWindows;
this.dialogs = dialogs;
this.emptyVaultList = Bindings.isEmpty(vaults);
@@ -212,7 +213,7 @@ public class VaultListController implements FxController {
private void pressedShortcutToRemoveVault() {
final var vault = selectedVault.get();
if (vault != null && EnumSet.of(LOCKED, MISSING, ERROR, NEEDS_MIGRATION).contains(vault.getState())) {
removeVaultDialogue.vault(vault).build().showRemoveVault();
dialogs.prepareRemoveVaultDialog(mainWindow, vault, vaults).build().showAndWait();
}
}

View File

@@ -5,7 +5,7 @@ import org.cryptomator.common.LicenseHolder;
import org.cryptomator.common.settings.Settings;
import org.cryptomator.common.settings.UiTheme;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.removecert.RemoveCertComponent;
import org.cryptomator.ui.dialogs.Dialogs;
import javax.inject.Inject;
import javafx.application.Application;
@@ -15,6 +15,7 @@ import javafx.scene.control.TextArea;
import javafx.scene.control.TextFormatter;
import javafx.stage.Stage;
@PreferencesScoped
public class SupporterCertificateController implements FxController {
@@ -26,18 +27,22 @@ public class SupporterCertificateController implements FxController {
private final Stage window;
private final LicenseHolder licenseHolder;
private final Settings settings;
private final RemoveCertComponent.Builder removeCert;
private final Dialogs dialogs;
@FXML
private TextArea supporterCertificateField;
@Inject
SupporterCertificateController(Application application, @PreferencesWindow Stage window, LicenseHolder licenseHolder, Settings settings, RemoveCertComponent.Builder removeCert) {
SupporterCertificateController(Application application, //
@PreferencesWindow Stage window, //
LicenseHolder licenseHolder, //
Settings settings, //
Dialogs dialogs) {
this.application = application;
this.window = window;
this.licenseHolder = licenseHolder;
this.settings = settings;
this.removeCert = removeCert;
this.dialogs = dialogs;
}
@FXML
@@ -84,10 +89,11 @@ public class SupporterCertificateController implements FxController {
@FXML
void didClickRemoveCert() {
removeCert.build().showRemoveCert(window);
dialogs.prepareRemoveCertDialog(window, settings).build().showAndWait();
}
public LicenseHolder getLicenseHolder() {
return licenseHolder;
}
}

View File

@@ -1,34 +0,0 @@
package org.cryptomator.ui.removecert;
import dagger.Lazy;
import dagger.Subcomponent;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
import javafx.scene.Scene;
import javafx.stage.Stage;
@RemoveCertScoped
@Subcomponent(modules = {RemoveCertModule.class})
public interface RemoveCertComponent {
@RemoveCertWindow
Stage window();
@FxmlScene(FxmlFile.REMOVE_CERT)
Lazy<Scene> scene();
default void showRemoveCert(Stage owner) {
Stage stage = window();
stage.setScene(scene().get());
stage.sizeToScene();
stage.initOwner(owner);
stage.show();
}
@Subcomponent.Builder
interface Builder {
RemoveCertComponent build();
}
}

View File

@@ -1,32 +0,0 @@
package org.cryptomator.ui.removecert;
import org.cryptomator.common.settings.Settings;
import org.cryptomator.ui.common.FxController;
import javax.inject.Inject;
import javafx.fxml.FXML;
import javafx.stage.Stage;
@RemoveCertScoped
public class RemoveCertController implements FxController {
private final Stage window;
private final Settings settings;
@Inject
public RemoveCertController(@RemoveCertWindow Stage window, Settings settings) {
this.window = window;
this.settings = settings;
}
@FXML
public void close() {
window.close();
}
@FXML
public void remove() {
settings.licenseKey.set(null);
window.close();
}
}

View File

@@ -1,56 +0,0 @@
package org.cryptomator.ui.removecert;
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoMap;
import org.cryptomator.ui.common.DefaultSceneFactory;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.FxControllerKey;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlLoaderFactory;
import org.cryptomator.ui.common.FxmlScene;
import org.cryptomator.ui.common.StageFactory;
import javax.inject.Provider;
import javafx.scene.Scene;
import javafx.stage.Modality;
import javafx.stage.Stage;
import java.util.Map;
import java.util.ResourceBundle;
@Module
abstract class RemoveCertModule {
@Provides
@RemoveCertWindow
@RemoveCertScoped
static FxmlLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
return new FxmlLoaderFactory(factories, sceneFactory, resourceBundle);
}
@Provides
@RemoveCertWindow
@RemoveCertScoped
static Stage provideStage(StageFactory factory, ResourceBundle resourceBundle) {
Stage stage = factory.create();
stage.setTitle(resourceBundle.getString("removeCert.title"));
stage.setResizable(false);
stage.initModality(Modality.WINDOW_MODAL);
return stage;
}
@Provides
@FxmlScene(FxmlFile.REMOVE_CERT)
@RemoveCertScoped
static Scene provideRemoveCertScene(@RemoveCertWindow FxmlLoaderFactory fxmlLoaders) {
return fxmlLoaders.createScene(FxmlFile.REMOVE_CERT);
}
// ------------------
@Binds
@IntoMap
@FxControllerKey(RemoveCertController.class)
abstract FxController bindRemoveCertController(RemoveCertController controller);
}

View File

@@ -1,13 +0,0 @@
package org.cryptomator.ui.removecert;
import javax.inject.Scope;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Scope
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface RemoveCertScoped {
}

View File

@@ -1,14 +0,0 @@
package org.cryptomator.ui.removecert;
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)
@interface RemoveCertWindow {
}

View File

@@ -1,39 +0,0 @@
package org.cryptomator.ui.removevault;
import dagger.BindsInstance;
import dagger.Lazy;
import dagger.Subcomponent;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
import javafx.scene.Scene;
import javafx.stage.Stage;
@RemoveVaultScoped
@Subcomponent(modules = {RemoveVaultModule.class})
public interface RemoveVaultComponent {
@RemoveVaultWindow
Stage window();
@FxmlScene(FxmlFile.REMOVE_VAULT)
Lazy<Scene> scene();
default void showRemoveVault() {
Stage stage = window();
stage.setScene(scene().get());
stage.sizeToScene();
stage.show();
}
@Subcomponent.Builder
interface Builder {
@BindsInstance
Builder vault(@RemoveVaultWindow Vault vault);
RemoveVaultComponent build();
}
}

View File

@@ -1,40 +0,0 @@
package org.cryptomator.ui.removevault;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.ui.common.FxController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.stage.Stage;
@RemoveVaultScoped
public class RemoveVaultController implements FxController {
private static final Logger LOG = LoggerFactory.getLogger(RemoveVaultController.class);
private final Stage window;
private final Vault vault;
private final ObservableList<Vault> vaults;
@Inject
public RemoveVaultController(@RemoveVaultWindow Stage window, @RemoveVaultWindow Vault vault, ObservableList<Vault> vaults) {
this.window = window;
this.vault = vault;
this.vaults = vaults;
}
@FXML
public void close() {
window.close();
}
@FXML
public void finish() {
vaults.remove(vault);
LOG.debug("Removing vault {}.", vault.getDisplayName());
window.close();
}
}

View File

@@ -1,59 +0,0 @@
package org.cryptomator.ui.removevault;
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoMap;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.ui.common.DefaultSceneFactory;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.FxControllerKey;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlLoaderFactory;
import org.cryptomator.ui.common.FxmlScene;
import org.cryptomator.ui.common.StageFactory;
import org.cryptomator.ui.fxapp.PrimaryStage;
import javax.inject.Provider;
import javafx.scene.Scene;
import javafx.stage.Modality;
import javafx.stage.Stage;
import java.util.Map;
import java.util.ResourceBundle;
@Module
abstract class RemoveVaultModule {
@Provides
@RemoveVaultWindow
@RemoveVaultScoped
static FxmlLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
return new FxmlLoaderFactory(factories, sceneFactory, resourceBundle);
}
@Provides
@RemoveVaultWindow
@RemoveVaultScoped
static Stage provideStage(StageFactory factory, @PrimaryStage Stage primaryStage, @RemoveVaultWindow Vault vault, ResourceBundle resourceBundle) {
Stage stage = factory.create();
stage.setTitle(String.format(resourceBundle.getString("removeVault.title"), vault.getDisplayName()));
stage.setResizable(false);
stage.initModality(Modality.WINDOW_MODAL);
stage.initOwner(primaryStage);
return stage;
}
@Provides
@FxmlScene(FxmlFile.REMOVE_VAULT)
@RemoveVaultScoped
static Scene provideRemoveVaultScene(@RemoveVaultWindow FxmlLoaderFactory fxmlLoaders) {
return fxmlLoaders.createScene(FxmlFile.REMOVE_VAULT);
}
// ------------------
@Binds
@IntoMap
@FxControllerKey(RemoveVaultController.class)
abstract FxController bindRemoveVaultController(RemoveVaultController controller);
}

View File

@@ -1,13 +0,0 @@
package org.cryptomator.ui.removevault;
import javax.inject.Scope;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Scope
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface RemoveVaultScoped {
}

View File

@@ -1,14 +0,0 @@
package org.cryptomator.ui.removevault;
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)
@interface RemoveVaultWindow {
}

View File

@@ -1,53 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ButtonBar?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.Group?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Region?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.shape.Circle?>
<HBox xmlns:fx="http://javafx.com/fxml"
xmlns="http://javafx.com/javafx"
fx:controller="org.cryptomator.ui.dokanysupportend.DokanySupportEndController"
minWidth="500"
prefWidth="500"
minHeight="145"
spacing="12"
alignment="TOP_LEFT">
<padding>
<Insets topRightBottomLeft="12"/>
</padding>
<children>
<Group>
<StackPane>
<padding>
<Insets topRightBottomLeft="6"/>
</padding>
<Circle styleClass="glyph-icon-primary" radius="24"/>
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="EXCLAMATION" glyphSize="24"/>
</StackPane>
</Group>
<VBox HBox.hgrow="ALWAYS">
<Label styleClass="label-large" text="%dokanySupportEnd.message" wrapText="true">
<padding>
<Insets bottom="6" top="6"/>
</padding>
</Label>
<Label text="%dokanySupportEnd.description" wrapText="true"/>
<Region VBox.vgrow="ALWAYS" minHeight="18"/>
<ButtonBar buttonMinWidth="120" buttonOrder="+UC">
<buttons>
<Button text="%dokanySupportEnd.preferencesBtn" ButtonBar.buttonData="OTHER" cancelButton="true" onAction="#openVolumePreferences"/>
<Button text="%generic.button.close" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#close" defaultButton="true"/>
</buttons>
</ButtonBar>
</VBox>
</children>
</HBox>

View File

@@ -1,52 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ButtonBar?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.shape.Circle?>
<?import javafx.scene.Group?>
<?import javafx.scene.layout.Region?>
<HBox xmlns:fx="http://javafx.com/fxml"
xmlns="http://javafx.com/javafx"
fx:controller="org.cryptomator.ui.removevault.RemoveVaultController"
minWidth="400"
maxWidth="400"
minHeight="145"
spacing="12"
alignment="TOP_LEFT">
<padding>
<Insets topRightBottomLeft="12"/>
</padding>
<children>
<Group>
<StackPane>
<padding>
<Insets topRightBottomLeft="6"/>
</padding>
<Circle styleClass="glyph-icon-primary" radius="24"/>
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="QUESTION" glyphSize="24"/>
</StackPane>
</Group>
<VBox HBox.hgrow="ALWAYS">
<Label styleClass="label-large" text="%removeVault.message" wrapText="true" textAlignment="LEFT">
<padding>
<Insets bottom="6" top="6"/>
</padding>
</Label>
<Label text="%removeVault.description" wrapText="true" textAlignment="LEFT" />
<Region VBox.vgrow="ALWAYS" minHeight="18"/>
<ButtonBar buttonMinWidth="120" buttonOrder="+CI">
<buttons>
<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" defaultButton="true" cancelButton="true" onAction="#close"/>
<Button text="%generic.button.remove" ButtonBar.buttonData="FINISH" onAction="#finish"/>
</buttons>
</ButtonBar>
</VBox>
</children>
</HBox>

View File

@@ -1,19 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ButtonBar?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.shape.Circle?>
<?import javafx.scene.control.Button?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.Group?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.shape.Circle?>
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.layout.Region?>
<?import javafx.scene.control.ButtonBar?>
<HBox xmlns:fx="http://javafx.com/fxml"
xmlns="http://javafx.com/javafx"
fx:controller="org.cryptomator.ui.removecert.RemoveCertController"
fx:controller="org.cryptomator.ui.dialogs.SimpleDialogController"
minWidth="400"
maxWidth="400"
minHeight="145"
@@ -28,24 +28,23 @@
<Insets topRightBottomLeft="6"/>
</padding>
<Circle styleClass="glyph-icon-primary" radius="24"/>
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="QUESTION" glyphSize="24"/>
<FontAwesome5IconView glyph="${controller.icon}" styleClass="glyph-icon-white" glyphSize="24"/>
</StackPane>
</Group>
<VBox HBox.hgrow="ALWAYS">
<Label styleClass="label-large" text="%removeCert.message" wrapText="true" >
<Label text="${controller.message}" styleClass="label-large" wrapText="true">
<padding>
<Insets bottom="6" top="6"/>
</padding>
</Label>
<Label text="%removeCert.description" wrapText="true" />
<Label text="${controller.description}" wrapText="true"/>
<Region VBox.vgrow="ALWAYS" minHeight="18"/>
<ButtonBar buttonMinWidth="120" buttonOrder="+CI">
<buttons>
<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" defaultButton="true" cancelButton="true" onAction="#close"/>
<Button text="%generic.button.remove" ButtonBar.buttonData="FINISH" onAction="#remove"/>
<Button text="${controller.cancelButtonText}" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#handleCancel"/>
<Button text="${controller.okButtonText}" ButtonBar.buttonData="FINISH" defaultButton="true" onAction="#handleOk"/>
</buttons>
</ButtonBar>
</VBox>
</children>
</HBox>
</HBox>