Refactored FXML loading

This commit is contained in:
Sebastian Stenzel
2017-04-19 00:06:46 +02:00
parent be8949157f
commit 42be5330fe
27 changed files with 288 additions and 241 deletions

View File

@@ -3,7 +3,7 @@ package org.cryptomator.launcher;
import javax.inject.Singleton;
import org.cryptomator.logging.DebugMode;
import org.cryptomator.ui.controllers.MainController;
import org.cryptomator.ui.controllers.ViewControllerLoader;
import dagger.Component;
@@ -11,7 +11,7 @@ import dagger.Component;
@Component(modules = LauncherModule.class)
interface LauncherComponent {
MainController mainController();
ViewControllerLoader fxmlLoader();
DebugMode debugMode();

View File

@@ -27,7 +27,7 @@ public class MainApplication extends Application {
launcherComponent.debugMode().initialize();
MainController mainCtrl = launcherComponent.mainController();
MainController mainCtrl = launcherComponent.fxmlLoader().load("/fxml/main.fxml");
mainCtrl.initStage(primaryStage);
primaryStage.show();

View File

@@ -22,6 +22,7 @@ import org.cryptomator.common.settings.SettingsProvider;
import org.cryptomator.frontend.webdav.WebDavServer;
import org.cryptomator.jni.JniModule;
import org.cryptomator.keychain.KeychainModule;
import org.cryptomator.ui.controllers.ViewControllerModule;
import org.cryptomator.ui.model.VaultComponent;
import org.cryptomator.ui.util.DeferredCloser;
import org.fxmisc.easybind.EasyBind;
@@ -32,7 +33,7 @@ import dagger.Module;
import dagger.Provides;
import javafx.beans.binding.Binding;
@Module(includes = {CommonsModule.class, KeychainModule.class, JniModule.class}, subcomponents = {VaultComponent.class})
@Module(includes = {ViewControllerModule.class, CommonsModule.class, KeychainModule.class, JniModule.class}, subcomponents = {VaultComponent.class})
public class UiModule {
private static final Logger LOG = LoggerFactory.getLogger(UiModule.class);

View File

@@ -1,101 +0,0 @@
/*******************************************************************************
* Copyright (c) 2016 Sebastian Stenzel and others.
* This file is licensed under the terms of the MIT license.
* See the LICENSE.txt file for more info.
*
* Contributors:
* Sebastian Stenzel - initial API and implementation
*******************************************************************************/
package org.cryptomator.ui.controllers;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.concurrent.atomic.AtomicReference;
import org.cryptomator.common.LazyInitializer;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
/**
* Controller presenting a single view.
*/
abstract class AbstractFXMLViewController implements Initializable {
private final AtomicReference<Parent> fxmlRoot = new AtomicReference<>();
/**
* Gets the URL to the FXML file describing the view presented by this controller.<br/>
*
* A default implementation would look like this:<br/>
* <code>
* return getClass().getResource("/myView.fxml");
* </code>
*
* @return FXML resource URL
*/
protected abstract URL getFxmlResourceUrl();
/**
* @return Localization bundle for the FXML labels or <code>null</code>.
*/
protected abstract ResourceBundle getFxmlResourceBundle();
@Override
public final void initialize(URL location, ResourceBundle resources) {
this.initialize();
}
protected void initialize() {
}
/**
* Creates a FXML loader used in {@link #loadFxml()}. This method can be overwritten for further loader customization.
*
* @return Configured loader ready to load.
*/
protected FXMLLoader createFxmlLoader() {
final URL fxmlUrl = getFxmlResourceUrl();
final ResourceBundle rb = getFxmlResourceBundle();
final FXMLLoader loader = new FXMLLoader(fxmlUrl, rb);
loader.setController(this);
return loader;
}
/**
* Loads the view presented by this controller from the FXML file return by {@link #getFxmlResourceUrl()}. This method can only be invoked once.
*
* @return Parent view element.
*/
protected final Parent loadFxml() {
final FXMLLoader loader = createFxmlLoader();
try {
return LazyInitializer.initializeLazily(fxmlRoot, loader::load, IOException.class);
} catch (IOException e) {
throw new IllegalStateException("Could not load FXML file from location: " + loader.getLocation(), e);
}
}
/**
* Creates a new scene with the root node from the FXML file and applies it to the given stage.
*/
public void initStage(Stage stage) {
final Parent root = loadFxml();
stage.setScene(new Scene(root));
stage.sizeToScene();
}
/**
* @return Creates a new stage and calls {@link #initStage(Stage)}.
*/
public Stage createStage() {
final Stage stage = new Stage();
initStage(stage);
return stage;
}
}

View File

@@ -11,7 +11,6 @@ package org.cryptomator.ui.controllers;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.URL;
import java.util.Objects;
import java.util.Optional;
@@ -35,28 +34,31 @@ import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Parent;
import javafx.scene.control.Button;
import javafx.scene.control.Hyperlink;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Region;
import javafx.scene.text.Text;
@Singleton
public class ChangePasswordController extends LocalizedFXMLViewController {
public class ChangePasswordController implements ViewController {
private static final Logger LOG = LoggerFactory.getLogger(ChangePasswordController.class);
private final Application app;
private final PasswordStrengthUtil strengthRater;
private final Localization localization;
private final IntegerProperty passwordStrength = new SimpleIntegerProperty(); // 0-4
private Optional<ChangePasswordListener> listener = Optional.empty();
private Vault vault;
@Inject
public ChangePasswordController(Application app, PasswordStrengthUtil strengthRater, Localization localization) {
super(localization);
this.app = app;
this.strengthRater = strengthRater;
this.localization = localization;
}
@FXML
@@ -95,6 +97,9 @@ public class ChangePasswordController extends LocalizedFXMLViewController {
@FXML
private Region passwordStrengthLevel4;
@FXML
private GridPane root;
@Override
public void initialize() {
BooleanBinding oldPasswordIsEmpty = oldPasswordField.textProperty().isEmpty();
@@ -112,8 +117,8 @@ public class ChangePasswordController extends LocalizedFXMLViewController {
}
@Override
protected URL getFxmlResourceUrl() {
return getClass().getResource("/fxml/change_password.fxml");
public Parent getRoot() {
return root;
}
void setVault(Vault vault) {

View File

@@ -10,7 +10,6 @@
package org.cryptomator.ui.controllers;
import java.io.IOException;
import java.net.URL;
import java.nio.file.DirectoryNotEmptyException;
import java.nio.file.FileAlreadyExistsException;
import java.util.Objects;
@@ -33,15 +32,18 @@ import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Parent;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Region;
@Singleton
public class InitializeController extends LocalizedFXMLViewController {
public class InitializeController implements ViewController {
private static final Logger LOG = LoggerFactory.getLogger(InitializeController.class);
private final Localization localization;
private final PasswordStrengthUtil strengthRater;
private final IntegerProperty passwordStrength = new SimpleIntegerProperty(); // 0-4
private Optional<InitializationListener> listener = Optional.empty();
@@ -49,7 +51,7 @@ public class InitializeController extends LocalizedFXMLViewController {
@Inject
public InitializeController(Localization localization, PasswordStrengthUtil strengthRater) {
super(localization);
this.localization = localization;
this.strengthRater = strengthRater;
}
@@ -83,6 +85,9 @@ public class InitializeController extends LocalizedFXMLViewController {
@FXML
private Region passwordStrengthLevel4;
@FXML
private GridPane root;
@Override
public void initialize() {
BooleanBinding passwordIsEmpty = passwordField.textProperty().isEmpty();
@@ -99,8 +104,8 @@ public class InitializeController extends LocalizedFXMLViewController {
}
@Override
protected URL getFxmlResourceUrl() {
return getClass().getResource("/fxml/initialize.fxml");
public Parent getRoot() {
return root;
}
void setVault(Vault vault) {

View File

@@ -1,23 +0,0 @@
/*******************************************************************************
* 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.controllers;
import org.cryptomator.ui.settings.Localization;
abstract class LocalizedFXMLViewController extends AbstractFXMLViewController {
protected final Localization localization;
public LocalizedFXMLViewController(Localization localization) {
this.localization = localization;
}
@Override
protected Localization getFxmlResourceBundle() {
return localization;
}
}

View File

@@ -12,7 +12,6 @@ package org.cryptomator.ui.controllers;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
@@ -24,7 +23,6 @@ import java.util.concurrent.ExecutorService;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.apache.commons.lang3.SystemUtils;
@@ -45,7 +43,6 @@ import org.fxmisc.easybind.monadic.MonadicBinding;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import dagger.Lazy;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.binding.Binding;
@@ -58,6 +55,7 @@ import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.geometry.Side;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
@@ -74,7 +72,7 @@ import javafx.stage.FileChooser;
import javafx.stage.Stage;
@Singleton
public class MainController extends LocalizedFXMLViewController {
public class MainController implements ViewController {
private static final Logger LOG = LoggerFactory.getLogger(MainController.class);
private static final String ACTIVE_WINDOW_STYLE_CLASS = "active-window";
@@ -82,23 +80,17 @@ public class MainController extends LocalizedFXMLViewController {
private final Stage mainWindow;
private final ExitUtil exitUtil;
private final Localization localization;
private final ExecutorService executorService;
private final BlockingQueue<Path> fileOpenRequests;
private final Settings settings;
private final VaultFactory vaultFactoy;
private final Lazy<WelcomeController> welcomeController;
private final Lazy<InitializeController> initializeController;
private final Lazy<NotFoundController> notFoundController;
private final Lazy<UpgradeController> upgradeController;
private final Lazy<UnlockController> unlockController;
private final Provider<UnlockedController> unlockedControllerProvider;
private final Lazy<ChangePasswordController> changePasswordController;
private final Lazy<SettingsController> settingsController;
private final ObjectProperty<AbstractFXMLViewController> activeController = new SimpleObjectProperty<>();
private final ViewControllerLoader fxmlLoader;
private final ObjectProperty<ViewController> activeController = new SimpleObjectProperty<>();
private final VaultList vaults;
private final ObjectProperty<Vault> selectedVault = new SimpleObjectProperty<>();
private final BooleanExpression isSelectedVaultUnlocked = BooleanBinding.booleanExpression(EasyBind.select(selectedVault).selectObject(Vault::unlockedProperty).orElse(false));
private final BooleanExpression isSelectedVaultValid = BooleanBinding.booleanExpression(EasyBind.monadic(selectedVault).map(Vault::isValidVaultDirectory).orElse(false));
private final BooleanExpression isSelectedVaultUnlocked = BooleanExpression.booleanExpression(EasyBind.select(selectedVault).selectObject(Vault::unlockedProperty).orElse(false));
private final BooleanExpression isSelectedVaultValid = BooleanExpression.booleanExpression(EasyBind.monadic(selectedVault).map(Vault::isValidVaultDirectory).orElse(false));
private final BooleanExpression canEditSelectedVault = selectedVault.isNotNull().and(isSelectedVaultUnlocked.not());
private final MonadicBinding<UpgradeStrategy> upgradeStrategyForSelectedVault;
private final BooleanBinding isShowingSettings;
@@ -108,28 +100,19 @@ public class MainController extends LocalizedFXMLViewController {
@Inject
public MainController(@Named("mainWindow") Stage mainWindow, ExecutorService executorService, @Named("fileOpenRequests") BlockingQueue<Path> fileOpenRequests, ExitUtil exitUtil, Localization localization,
Settings settings, VaultFactory vaultFactoy, Lazy<WelcomeController> welcomeController, Lazy<InitializeController> initializeController, Lazy<NotFoundController> notFoundController,
Lazy<UpgradeController> upgradeController, Lazy<UnlockController> unlockController, Provider<UnlockedController> unlockedControllerProvider, Lazy<ChangePasswordController> changePasswordController,
Lazy<SettingsController> settingsController, UpgradeStrategies upgradeStrategies, VaultList vaults) {
super(localization);
Settings settings, VaultFactory vaultFactoy, ViewControllerLoader fxmlLoader, UpgradeStrategies upgradeStrategies, VaultList vaults) {
this.mainWindow = mainWindow;
this.executorService = executorService;
this.fileOpenRequests = fileOpenRequests;
this.exitUtil = exitUtil;
this.localization = localization;
this.settings = settings;
this.vaultFactoy = vaultFactoy;
this.welcomeController = welcomeController;
this.initializeController = initializeController;
this.notFoundController = notFoundController;
this.upgradeController = upgradeController;
this.unlockController = unlockController;
this.unlockedControllerProvider = unlockedControllerProvider;
this.changePasswordController = changePasswordController;
this.settingsController = settingsController;
this.fxmlLoader = fxmlLoader;
this.vaults = vaults;
// derived bindings:
this.isShowingSettings = activeController.isEqualTo(settingsController.get());
this.isShowingSettings = Bindings.equal(SettingsController.class, EasyBind.monadic(activeController).map(ViewController::getClass));
this.upgradeStrategyForSelectedVault = EasyBind.monadic(selectedVault).map(upgradeStrategies::getUpgradeStrategy);
}
@@ -143,7 +126,7 @@ public class MainController extends LocalizedFXMLViewController {
private ContextMenu addVaultContextMenu;
@FXML
private HBox rootPane;
private HBox root;
@FXML
private ListView<Vault> vaultList;
@@ -167,7 +150,7 @@ public class MainController extends LocalizedFXMLViewController {
public void initialize() {
vaultList.setItems(vaults);
vaultList.setCellFactory(this::createDirecoryListCell);
activeController.set(welcomeController.get());
activeController.set(fxmlLoader.load("/fxml/welcome.fxml"));
selectedVault.bind(vaultList.getSelectionModel().selectedItemProperty());
removeVaultButton.disableProperty().bind(canEditSelectedVault.not());
emptyListInstructions.visibleProperty().bind(Bindings.isEmpty(vaults));
@@ -180,8 +163,13 @@ public class MainController extends LocalizedFXMLViewController {
}
@Override
public Parent getRoot() {
return root;
}
public void initStage(Stage stage) {
super.initStage(stage);
stage.setScene(new Scene(getRoot()));
stage.sizeToScene();
stage.titleProperty().bind(windowTitle());
stage.setResizable(false);
loadFont("/css/ionicons.ttf");
@@ -227,11 +215,6 @@ public class MainController extends LocalizedFXMLViewController {
});
}
@Override
protected URL getFxmlResourceUrl() {
return getClass().getResource("/fxml/main.fxml");
}
private ListCell<Vault> createDirecoryListCell(ListView<Vault> param) {
final DirectoryListCell cell = new DirectoryListCell();
cell.setVaultContextMenu(vaultListCellContextMenu);
@@ -323,7 +306,7 @@ public class MainController extends LocalizedFXMLViewController {
if (ButtonType.OK.equals(choice.get())) {
vaults.remove(selectedVault.get());
if (vaults.isEmpty()) {
activeController.set(welcomeController.get());
activeController.set(fxmlLoader.load("/fxml/welcome.fxml"));
}
}
}
@@ -335,10 +318,10 @@ public class MainController extends LocalizedFXMLViewController {
@FXML
private void didClickShowSettings(ActionEvent e) {
if (settingsController.get().equals(activeController.get())) {
activeController.set(welcomeController.get());
if (isShowingSettings.get()) {
activeController.set(fxmlLoader.load("/fxml/welcome.fxml"));
} else {
activeController.set(settingsController.get());
activeController.set(fxmlLoader.load("/fxml/settings.fxml"));
}
vaultList.getSelectionModel().clearSelection();
}
@@ -347,8 +330,8 @@ public class MainController extends LocalizedFXMLViewController {
// Binding Listeners
// ****************************************
private void activeControllerDidChange(AbstractFXMLViewController newValue) {
final Parent root = newValue.loadFxml();
private void activeControllerDidChange(ViewController newValue) {
final Parent root = newValue.getRoot();
contentPane.getChildren().clear();
contentPane.getChildren().add(root);
}
@@ -383,13 +366,11 @@ public class MainController extends LocalizedFXMLViewController {
// ****************************************
private void showNotFoundView() {
final NotFoundController ctrl = notFoundController.get();
activeController.set(ctrl);
activeController.set(fxmlLoader.load("/fxml/notfound.fxml"));
}
private void showInitializeView() {
final InitializeController ctrl = initializeController.get();
ctrl.loadFxml();
final InitializeController ctrl = fxmlLoader.load("/fxml/initialize.fxml");
ctrl.setVault(selectedVault.get());
ctrl.setListener(this::didInitialize);
activeController.set(ctrl);
@@ -400,8 +381,7 @@ public class MainController extends LocalizedFXMLViewController {
}
private void showUpgradeView() {
final UpgradeController ctrl = upgradeController.get();
ctrl.loadFxml();
final UpgradeController ctrl = fxmlLoader.load("/fxml/upgrade.fxml");
ctrl.setVault(selectedVault.get());
ctrl.setListener(this::didUpgrade);
activeController.set(ctrl);
@@ -412,8 +392,7 @@ public class MainController extends LocalizedFXMLViewController {
}
private void showUnlockView() {
final UnlockController ctrl = unlockController.get();
ctrl.loadFxml();
final UnlockController ctrl = fxmlLoader.load("/fxml/unlock.fxml");
ctrl.setVault(selectedVault.get());
ctrl.setListener(this::didUnlock);
activeController.set(ctrl);
@@ -428,9 +407,8 @@ public class MainController extends LocalizedFXMLViewController {
private void showUnlockedView(Vault vault) {
final UnlockedController ctrl = unlockedVaults.computeIfAbsent(vault, k -> {
return unlockedControllerProvider.get();
return fxmlLoader.load("/fxml/unlocked.fxml");
});
ctrl.loadFxml();
ctrl.setVault(vault);
ctrl.setListener(this::didLock);
activeController.set(ctrl);
@@ -445,8 +423,7 @@ public class MainController extends LocalizedFXMLViewController {
}
private void showChangePasswordView() {
final ChangePasswordController ctrl = changePasswordController.get();
ctrl.loadFxml();
final ChangePasswordController ctrl = fxmlLoader.load("/fxml/change_password.fxml");
ctrl.setVault(selectedVault.get());
ctrl.setListener(this::didChangePassword);
activeController.set(ctrl);

View File

@@ -5,24 +5,27 @@
*******************************************************************************/
package org.cryptomator.ui.controllers;
import java.net.URL;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.cryptomator.ui.settings.Localization;
import javafx.fxml.FXML;
import javafx.scene.Parent;
import javafx.scene.layout.VBox;
@Singleton
public class NotFoundController extends LocalizedFXMLViewController {
public class NotFoundController implements ViewController {
@Inject
public NotFoundController(Localization localization) {
super(localization);
public NotFoundController() {
// no-op
}
@FXML
VBox root;
@Override
protected URL getFxmlResourceUrl() {
return getClass().getResource("/fxml/notfound.fxml");
public Parent getRoot() {
return root;
}
}

View File

@@ -8,10 +8,10 @@
******************************************************************************/
package org.cryptomator.ui.controllers;
import java.net.URL;
import java.util.Optional;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.apache.commons.lang3.CharUtils;
@@ -22,22 +22,27 @@ import org.cryptomator.ui.settings.Localization;
import javafx.beans.binding.Bindings;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Parent;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.VBox;
@Singleton
public class SettingsController extends LocalizedFXMLViewController {
public class SettingsController implements ViewController {
private final Localization localization;
private final Settings settings;
private final Optional<String> applicationVersion;
@Inject
public SettingsController(Localization localization, Settings settings) {
super(localization);
public SettingsController(Localization localization, Settings settings, @Named("applicationVersion") Optional<String> applicationVersion) {
this.localization = localization;
this.settings = settings;
this.applicationVersion = applicationVersion;
}
@FXML
@@ -67,6 +72,9 @@ public class SettingsController extends LocalizedFXMLViewController {
@FXML
private CheckBox debugModeCheckbox;
@FXML
private VBox root;
@Override
public void initialize() {
checkForUpdatesCheckbox.setDisable(areUpdatesManagedExternally());
@@ -78,7 +86,7 @@ public class SettingsController extends LocalizedFXMLViewController {
useIpv6Label.setVisible(SystemUtils.IS_OS_WINDOWS);
useIpv6Checkbox.setVisible(SystemUtils.IS_OS_WINDOWS);
useIpv6Checkbox.setSelected(SystemUtils.IS_OS_WINDOWS && settings.useIpv6().get());
versionLabel.setText(String.format(localization.getString("settings.version.label"), applicationVersion().orElse("SNAPSHOT")));
versionLabel.setText(String.format(localization.getString("settings.version.label"), applicationVersion.orElse("SNAPSHOT")));
prefGvfsSchemeLabel.setVisible(SystemUtils.IS_OS_LINUX);
prefGvfsScheme.setVisible(SystemUtils.IS_OS_LINUX);
prefGvfsScheme.getItems().add("dav");
@@ -93,12 +101,8 @@ public class SettingsController extends LocalizedFXMLViewController {
}
@Override
protected URL getFxmlResourceUrl() {
return getClass().getResource("/fxml/settings.fxml");
}
private Optional<String> applicationVersion() {
return Optional.ofNullable(getClass().getPackage().getImplementationVersion());
public Parent getRoot() {
return root;
}
@FXML

View File

@@ -8,7 +8,6 @@
******************************************************************************/
package org.cryptomator.ui.controllers;
import java.net.URL;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Objects;
@@ -38,6 +37,7 @@ import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Parent;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
@@ -52,11 +52,12 @@ import javafx.scene.layout.GridPane;
import javafx.scene.text.Text;
import javafx.util.StringConverter;
public class UnlockController extends LocalizedFXMLViewController {
public class UnlockController implements ViewController {
private static final Logger LOG = LoggerFactory.getLogger(UnlockController.class);
private final Application app;
private final Localization localization;
private final AsyncTaskService asyncTaskService;
private final WindowsDriveLetters driveLetters;
private final ChangeListener<Character> driveLetterChangeListener = this::winDriveLetterDidChange;
@@ -66,8 +67,8 @@ public class UnlockController extends LocalizedFXMLViewController {
@Inject
public UnlockController(Application app, Localization localization, AsyncTaskService asyncTaskService, WindowsDriveLetters driveLetters, Optional<KeychainAccess> keychainAccess) {
super(localization);
this.app = app;
this.localization = localization;
this.asyncTaskService = asyncTaskService;
this.driveLetters = driveLetters;
this.keychainAccess = keychainAccess;
@@ -112,6 +113,9 @@ public class UnlockController extends LocalizedFXMLViewController {
@FXML
private GridPane advancedOptions;
@FXML
private GridPane root;
@Override
public void initialize() {
advancedOptions.managedProperty().bind(advancedOptions.visibleProperty());
@@ -132,8 +136,8 @@ public class UnlockController extends LocalizedFXMLViewController {
}
@Override
protected URL getFxmlResourceUrl() {
return getClass().getResource("/fxml/unlock.fxml");
public Parent getRoot() {
return root;
}
void setVault(Vault vault) {

View File

@@ -8,7 +8,6 @@
******************************************************************************/
package org.cryptomator.ui.controllers;
import java.net.URL;
import java.util.Optional;
import javax.inject.Inject;
@@ -27,6 +26,7 @@ import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.geometry.Side;
import javafx.scene.Parent;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart.Data;
@@ -37,14 +37,16 @@ import javafx.scene.control.MenuItem;
import javafx.scene.control.ToggleButton;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import javafx.scene.layout.VBox;
import javafx.stage.PopupWindow.AnchorLocation;
import javafx.util.Duration;
public class UnlockedController extends LocalizedFXMLViewController {
public class UnlockedController implements ViewController {
private static final int IO_SAMPLING_STEPS = 100;
private static final double IO_SAMPLING_INTERVAL = 0.25;
private final Localization localization;
private final AsyncTaskService asyncTaskService;
private final ObjectProperty<Vault> vault = new SimpleObjectProperty<>();
private Optional<LockListener> listener = Optional.empty();
@@ -68,9 +70,12 @@ public class UnlockedController extends LocalizedFXMLViewController {
@FXML
private MenuItem revealVaultMenuItem;
@FXML
private VBox root;
@Inject
public UnlockedController(Localization localization, AsyncTaskService asyncTaskService) {
super(localization);
this.localization = localization;
this.asyncTaskService = asyncTaskService;
}
@@ -83,8 +88,8 @@ public class UnlockedController extends LocalizedFXMLViewController {
}
@Override
protected URL getFxmlResourceUrl() {
return getClass().getResource("/fxml/unlocked.fxml");
public Parent getRoot() {
return root;
}
private void vaultChanged(Vault newVault) {

View File

@@ -5,7 +5,6 @@
*******************************************************************************/
package org.cryptomator.ui.controllers;
import java.net.URL;
import java.util.Objects;
import java.util.Optional;
@@ -25,12 +24,14 @@ import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Parent;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.GridPane;
public class UpgradeController extends LocalizedFXMLViewController {
public class UpgradeController implements ViewController {
private final ObjectProperty<UpgradeStrategy> strategy = new SimpleObjectProperty<>();
private final UpgradeStrategies strategies;
@@ -40,7 +41,6 @@ public class UpgradeController extends LocalizedFXMLViewController {
@Inject
public UpgradeController(Localization localization, UpgradeStrategies strategies, AsyncTaskService asyncTaskService) {
super(localization);
this.strategies = strategies;
this.asyncTaskService = asyncTaskService;
}
@@ -66,8 +66,11 @@ public class UpgradeController extends LocalizedFXMLViewController {
@FXML
private Label errorLabel;
@FXML
private GridPane root;
@Override
protected void initialize() {
public void initialize() {
upgradeTitleLabel.textProperty().bind(EasyBind.monadic(strategy).map(this::upgradeTitle).orElse(""));
upgradeMsgLabel.textProperty().bind(EasyBind.monadic(strategy).map(this::upgradeMessage).orElse(""));
@@ -77,8 +80,8 @@ public class UpgradeController extends LocalizedFXMLViewController {
}
@Override
protected URL getFxmlResourceUrl() {
return getClass().getResource("/fxml/upgrade.fxml");
public Parent getRoot() {
return root;
}
void setVault(Vault vault) {

View File

@@ -0,0 +1,22 @@
package org.cryptomator.ui.controllers;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
public interface ViewController extends Initializable {
Parent getRoot();
@Override
default void initialize(URL location, ResourceBundle resources) {
initialize();
}
default void initialize() {
// no-op
}
}

View File

@@ -0,0 +1,18 @@
package org.cryptomator.ui.controllers;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import dagger.MapKey;
@Documented
@Target(METHOD)
@Retention(RUNTIME)
@MapKey
public @interface ViewControllerKey {
Class<? extends ViewController> value();
}

View File

@@ -0,0 +1,44 @@
package org.cryptomator.ui.controllers;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.cryptomator.ui.settings.Localization;
import javafx.fxml.FXMLLoader;
@Singleton
public class ViewControllerLoader {
private final Map<Class<? extends ViewController>, Provider<ViewController>> controllerProviders;
private final Localization localization;
@Inject
public ViewControllerLoader(Map<Class<? extends ViewController>, Provider<ViewController>> controllerProviders, Localization localization) {
this.controllerProviders = controllerProviders;
this.localization = localization;
}
public <T extends ViewController> T load(String resourceName) {
FXMLLoader loader = new FXMLLoader();
loader.setControllerFactory(this::constructController);
loader.setResources(localization);
try (InputStream in = getClass().getResourceAsStream(resourceName)) {
loader.load(in);
} catch (IOException e) {
throw new UncheckedIOException("Error loading FXML: " + resourceName, e);
}
return loader.getController();
}
private ViewController constructController(Class<?> clazz) {
return controllerProviders.get(clazz).get();
}
}

View File

@@ -0,0 +1,73 @@
package org.cryptomator.ui.controllers;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoMap;
@Module
public class ViewControllerModule {
@Provides
@IntoMap
@ViewControllerKey(ChangePasswordController.class)
ViewController provideChangePasswordController(ChangePasswordController controller) {
return controller;
}
@Provides
@IntoMap
@ViewControllerKey(InitializeController.class)
ViewController provideInitializeController(InitializeController controller) {
return controller;
}
@Provides
@IntoMap
@ViewControllerKey(MainController.class)
ViewController provideMainController(MainController controller) {
return controller;
}
@Provides
@IntoMap
@ViewControllerKey(NotFoundController.class)
ViewController provideNotFoundController(NotFoundController controller) {
return controller;
}
@Provides
@IntoMap
@ViewControllerKey(SettingsController.class)
ViewController provideSettingsController(SettingsController controller) {
return controller;
}
@Provides
@IntoMap
@ViewControllerKey(UnlockController.class)
ViewController provideUnlockController(UnlockController controller) {
return controller;
}
@Provides
@IntoMap
@ViewControllerKey(UnlockedController.class)
ViewController provideUnlockedController(UnlockedController controller) {
return controller;
}
@Provides
@IntoMap
@ViewControllerKey(UpgradeController.class)
ViewController provideUpgradeController(UpgradeController controller) {
return controller;
}
@Provides
@IntoMap
@ViewControllerKey(WelcomeController.class)
ViewController provideWelcomeController(WelcomeController controller) {
return controller;
}
}

View File

@@ -16,6 +16,7 @@ import java.nio.charset.StandardCharsets;
import java.util.Comparator;
import java.util.Map;
import java.util.Optional;
import java.util.ResourceBundle;
import javax.inject.Inject;
import javax.inject.Named;
@@ -43,17 +44,20 @@ import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.control.Hyperlink;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.VBox;
@Singleton
public class WelcomeController extends LocalizedFXMLViewController {
public class WelcomeController implements ViewController {
private static final Logger LOG = LoggerFactory.getLogger(WelcomeController.class);
private final Application app;
private final Optional<String> applicationVersion;
private final Localization localization;
private final Settings settings;
private final Comparator<String> semVerComparator;
private final AsyncTaskService asyncTaskService;
@@ -61,9 +65,9 @@ public class WelcomeController extends LocalizedFXMLViewController {
@Inject
public WelcomeController(Application app, @Named("applicationVersion") Optional<String> applicationVersion, Localization localization, Settings settings, @Named("SemVer") Comparator<String> semVerComparator,
AsyncTaskService asyncTaskService) {
super(localization);
this.app = app;
this.applicationVersion = applicationVersion;
this.localization = localization;
this.settings = settings;
this.semVerComparator = semVerComparator;
this.asyncTaskService = asyncTaskService;
@@ -81,8 +85,11 @@ public class WelcomeController extends LocalizedFXMLViewController {
@FXML
private Hyperlink updateLink;
@FXML
private VBox root;
@Override
public void initialize() {
public void initialize(URL location, ResourceBundle resources) {
if (areUpdatesManagedExternally()) {
checkForUpdatesContainer.setVisible(false);
} else if (settings.checkForUpdates().get()) {
@@ -91,8 +98,8 @@ public class WelcomeController extends LocalizedFXMLViewController {
}
@Override
protected URL getFxmlResourceUrl() {
return getClass().getResource("/fxml/welcome.fxml");
public Parent getRoot() {
return root;
}
// ****************************************

View File

@@ -25,7 +25,7 @@
<?import javafx.scene.layout.Region?>
<?import javafx.scene.layout.VBox?>
<GridPane vgap="12.0" hgap="12.0" prefWidth="400.0" xmlns:fx="http://javafx.com/fxml" cacheShape="true" cache="true">
<GridPane fx:controller="org.cryptomator.ui.controllers.ChangePasswordController" fx:id="root" vgap="12.0" hgap="12.0" prefWidth="400.0" xmlns:fx="http://javafx.com/fxml" cacheShape="true" cache="true">
<padding>
<Insets top="24.0" right="12.0" bottom="24.0" left="12.0" />
</padding>

View File

@@ -23,7 +23,7 @@
<?import javafx.scene.layout.Region?>
<?import javafx.scene.layout.VBox?>
<GridPane vgap="12.0" hgap="12.0" prefWidth="400.0" xmlns:fx="http://javafx.com/fxml" cacheShape="true" cache="true">
<GridPane fx:controller="org.cryptomator.ui.controllers.InitializeController" fx:id="root" vgap="12.0" hgap="12.0" prefWidth="400.0" xmlns:fx="http://javafx.com/fxml" cacheShape="true" cache="true">
<padding>
<Insets top="24.0" right="12.0" bottom="24.0" left="12.0" />
</padding>

View File

@@ -24,7 +24,7 @@
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.shape.Arc?>
<HBox fx:id="rootPane" prefHeight="440.0" prefWidth="652.0" spacing="12.0" xmlns:fx="http://javafx.com/fxml" cacheShape="true" cache="true">
<HBox fx:controller="org.cryptomator.ui.controllers.MainController" fx:id="root" prefHeight="440.0" prefWidth="652.0" spacing="12.0" xmlns:fx="http://javafx.com/fxml" cacheShape="true" cache="true">
<padding><Insets top="20" right="20" bottom="20" left="20.0"/></padding>

View File

@@ -11,7 +11,7 @@
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>
<VBox prefWidth="400.0" prefHeight="400.0" spacing="24.0" alignment="CENTER" xmlns:fx="http://javafx.com/fxml" cacheShape="true" cache="true">
<VBox fx:controller="org.cryptomator.ui.controllers.NotFoundController" fx:id="root" prefWidth="400.0" prefHeight="400.0" spacing="24.0" alignment="CENTER" xmlns:fx="http://javafx.com/fxml" cacheShape="true" cache="true">
<Label text="%notfound.label" textAlignment="CENTER" wrapText="true" cacheShape="true" cache="true"/>

View File

@@ -19,7 +19,7 @@
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.control.Button?>
<VBox prefWidth="400.0" alignment="TOP_CENTER" spacing="12.0" xmlns:fx="http://javafx.com/fxml" cacheShape="true" cache="true">
<VBox fx:controller="org.cryptomator.ui.controllers.SettingsController" fx:id="root" prefWidth="400.0" alignment="TOP_CENTER" spacing="12.0" xmlns:fx="http://javafx.com/fxml" cacheShape="true" cache="true">
<Label VBox.vgrow="NEVER" fx:id="versionLabel" alignment="CENTER" cacheShape="true" cache="true" />
<GridPane VBox.vgrow="ALWAYS" vgap="12.0" hgap="12.0" cacheShape="true" cache="true">
<padding>

View File

@@ -25,7 +25,7 @@
<?import javafx.scene.control.Separator?>
<?import javafx.scene.control.ChoiceBox?>
<GridPane vgap="12.0" hgap="12.0" prefWidth="400.0" xmlns:fx="http://javafx.com/fxml" cacheShape="true" cache="true">
<GridPane fx:controller="org.cryptomator.ui.controllers.UnlockController" fx:id="root" vgap="12.0" hgap="12.0" prefWidth="400.0" xmlns:fx="http://javafx.com/fxml" cacheShape="true" cache="true">
<padding>
<Insets top="24.0" right="12.0" bottom="24.0" left="12.0" />
</padding>

View File

@@ -23,7 +23,7 @@
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.layout.Pane?>
<VBox prefWidth="400.0" prefHeight="400.0" spacing="6.0" xmlns:fx="http://javafx.com/fxml" cacheShape="true" cache="true">
<VBox fx:controller="org.cryptomator.ui.controllers.UnlockedController" fx:id="root" prefWidth="400.0" prefHeight="400.0" spacing="6.0" xmlns:fx="http://javafx.com/fxml" cacheShape="true" cache="true">
<fx:define>
<ContextMenu fx:id="moreOptionsMenu">

View File

@@ -20,7 +20,7 @@
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.CheckBox?>
<GridPane vgap="12.0" hgap="12.0" prefWidth="400.0" xmlns:fx="http://javafx.com/fxml" cacheShape="true" cache="true">
<GridPane fx:controller="org.cryptomator.ui.controllers.UpgradeController" fx:id="root" vgap="12.0" hgap="12.0" prefWidth="400.0" xmlns:fx="http://javafx.com/fxml" cacheShape="true" cache="true">
<padding>
<Insets top="24.0" right="12.0" bottom="24.0" left="12.0" />
</padding>

View File

@@ -18,7 +18,7 @@
<?import javafx.scene.control.ProgressIndicator?>
<?import javafx.scene.control.Button?>
<VBox prefWidth="400.0" prefHeight="400.0" spacing="24.0" alignment="CENTER" xmlns:fx="http://javafx.com/fxml" cacheShape="true" cache="true">
<VBox fx:controller="org.cryptomator.ui.controllers.WelcomeController" fx:id="root" prefWidth="400.0" prefHeight="400.0" spacing="24.0" alignment="CENTER" xmlns:fx="http://javafx.com/fxml" cacheShape="true" cache="true">
<VBox fx:id="checkForUpdatesContainer" spacing="6.0" alignment="CENTER" cacheShape="true" cache="true" prefHeight="64.0">
<HBox alignment="CENTER" spacing="5.0" cacheShape="true" cache="true">