split VaultList and ContextMenu into two separate controllers

This commit is contained in:
Sebastian Stenzel
2021-03-30 13:43:37 +02:00
parent ff84230566
commit 30f0c5e697
5 changed files with 180 additions and 146 deletions

View File

@@ -86,6 +86,11 @@ abstract class MainWindowModule {
@FxControllerKey(VaultListController.class)
abstract FxController bindVaultListController(VaultListController controller);
@Binds
@IntoMap
@FxControllerKey(VaultListContextMenuController.class)
abstract FxController bindVaultListContextMenuController(VaultListContextMenuController controller);
@Binds
@IntoMap
@FxControllerKey(VaultDetailController.class)

View File

@@ -0,0 +1,157 @@
package org.cryptomator.ui.mainwindow;
import com.tobiasdiez.easybind.EasyBind;
import org.cryptomator.common.keychain.KeychainManager;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultState;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.fxapp.FxApplication;
import org.cryptomator.ui.removevault.RemoveVaultComponent;
import org.cryptomator.ui.vaultoptions.SelectedVaultOptionsTab;
import org.cryptomator.ui.vaultoptions.VaultOptionsComponent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javafx.beans.binding.Binding;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.fxml.FXML;
import javafx.stage.Stage;
import java.util.Arrays;
import java.util.Optional;
import static org.cryptomator.common.vaults.VaultState.ERROR;
import static org.cryptomator.common.vaults.VaultState.LOCKED;
import static org.cryptomator.common.vaults.VaultState.MISSING;
import static org.cryptomator.common.vaults.VaultState.NEEDS_MIGRATION;
import static org.cryptomator.common.vaults.VaultState.UNLOCKED;
@MainWindowScoped
public class VaultListContextMenuController implements FxController {
private static final Logger LOG = LoggerFactory.getLogger(VaultListContextMenuController.class);
private final ReadOnlyObjectProperty<Vault> selectedVault;
private final Stage mainWindow;
private final FxApplication application;
private final KeychainManager keychain;
private final RemoveVaultComponent.Builder removeVault;
private final VaultOptionsComponent.Builder vaultOptionsWindow;
private final Binding<VaultState> selectedVaultState;
private final BooleanBinding selectedVaultPassphraseStored;
private final BooleanBinding selectedVaultRemovable;
private final BooleanBinding selectedVaultUnlockable;
private final BooleanBinding selectedVaultLockable;
@Inject
VaultListContextMenuController(ObjectProperty<Vault> selectedVault, @MainWindow Stage mainWindow, FxApplication application, KeychainManager keychain, RemoveVaultComponent.Builder removeVault, VaultOptionsComponent.Builder vaultOptionsWindow) {
this.selectedVault = selectedVault;
this.mainWindow = mainWindow;
this.application = application;
this.keychain = keychain;
this.removeVault = removeVault;
this.vaultOptionsWindow = vaultOptionsWindow;
this.selectedVaultState = EasyBind.wrapNullable(selectedVault).mapObservable(Vault::stateProperty).orElse((VaultState) null);
this.selectedVaultPassphraseStored = Bindings.createBooleanBinding(this::isSelectedVaultPassphraseStored, selectedVault);
this.selectedVaultRemovable = Bindings.createBooleanBinding(() -> selectedVaultIsInState(LOCKED, MISSING, ERROR, NEEDS_MIGRATION), selectedVaultState);
this.selectedVaultUnlockable = Bindings.createBooleanBinding(() -> selectedVaultIsInState(LOCKED), selectedVaultState);
this.selectedVaultLockable = Bindings.createBooleanBinding(() -> selectedVaultIsInState(UNLOCKED), selectedVaultState);
}
private boolean selectedVaultIsInState(VaultState... states) {
var state = selectedVaultState.getValue();
return Arrays.stream(states).anyMatch(s -> state == s);
}
@FXML
public void didClickRemoveVault() {
Vault v = selectedVault.get();
if (v != null) {
removeVault.vault(v).build().showRemoveVault();
} else {
LOG.debug("Cannot remove a vault if none is selected.");
}
}
@FXML
public void didClickShowVaultOptions() {
Vault v = selectedVault.get();
if (v != null) {
vaultOptionsWindow.vault(v).build().showVaultOptionsWindow(SelectedVaultOptionsTab.ANY);
} else {
LOG.debug("Cannot open vault options if none is selected.");
}
}
@FXML
public void didClickUnlockVault() {
Vault v = selectedVault.get();
if (v != null) {
application.startUnlockWorkflow(v, Optional.of(mainWindow));
} else {
LOG.debug("Cannot unlock vault if none is selected.");
}
}
@FXML
public void didClickLockVault() {
Vault v = selectedVault.get();
if (v != null) {
application.startLockWorkflow(v, Optional.of(mainWindow));
} else {
LOG.debug("Cannot lock vault if none is selected.");
}
}
@FXML
public void didClickRevealVault() {
Vault v = selectedVault.get();
if (v != null) {
application.getVaultService().reveal(v);
} else {
LOG.debug("Cannot reveal vault if none is selected.");
}
}
// Getter and Setter
public BooleanBinding selectedVaultUnlockableProperty() {
return selectedVaultUnlockable;
}
public boolean isSelectedVaultUnlockable() {
return selectedVaultUnlockable.get();
}
public BooleanBinding selectedVaultLockableProperty() {
return selectedVaultLockable;
}
public boolean isSelectedVaultLockable() {
return selectedVaultLockable.get();
}
public BooleanBinding selectedVaultRemovableProperty() {
return selectedVaultRemovable;
}
public boolean isSelectedVaultRemovable() {
return selectedVaultRemovable.get();
}
public BooleanBinding selectedVaultPassphraseStoredProperty() {
return selectedVaultPassphraseStored;
}
public boolean isSelectedVaultPassphraseStored() {
if (selectedVault.get() == null) {
return false;
} else {
return keychain.getPassphraseStoredProperty(selectedVault.get().getId()).get();
}
}
}

View File

@@ -1,25 +1,14 @@
package org.cryptomator.ui.mainwindow;
import org.cryptomator.common.keychain.KeychainManager;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultListManager;
import org.cryptomator.common.vaults.VaultState;
import org.cryptomator.ui.addvaultwizard.AddVaultWizardComponent;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.fxapp.FxApplication;
import org.cryptomator.ui.removevault.RemoveVaultComponent;
import org.cryptomator.ui.vaultoptions.SelectedVaultOptionsTab;
import org.cryptomator.ui.vaultoptions.VaultOptionsComponent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
@@ -27,53 +16,27 @@ import javafx.fxml.FXML;
import javafx.scene.control.ListView;
import javafx.scene.input.ContextMenuEvent;
import javafx.scene.input.MouseEvent;
import javafx.stage.Stage;
import java.util.Arrays;
import java.util.Optional;
import static org.cryptomator.common.vaults.VaultState.*;
@MainWindowScoped
public class VaultListController implements FxController {
private static final Logger LOG = LoggerFactory.getLogger(VaultListController.class);
private final ObservableList<Vault> vaults;
private final ObjectProperty<Vault> selectedVault;
private final ObjectProperty<VaultState> selectedVaultState;
private final BooleanProperty selectedVaultPassphraseStored;
private final VaultListCellFactory cellFactory;
private final Stage mainWindow;
private final FxApplication application;
private final KeychainManager keychain;
private final AddVaultWizardComponent.Builder addVaultWizard;
private final RemoveVaultComponent.Builder removeVault;
private final VaultOptionsComponent.Builder vaultOptionsWindow;
private final BooleanBinding emptyVaultList;
private final BooleanBinding selectedVaultRemovable;
private final BooleanBinding selectedVaultUnlockable;
private final BooleanBinding selectedVaultLockable;
public ListView<Vault> vaultList;
@Inject
VaultListController(ObservableList<Vault> vaults, ObjectProperty<Vault> selectedVault, VaultListCellFactory cellFactory, @MainWindow Stage mainWindow, FxApplication application, KeychainManager keychain, AddVaultWizardComponent.Builder addVaultWizard, RemoveVaultComponent.Builder removeVault, VaultOptionsComponent.Builder vaultOptionsWindow) {
VaultListController(ObservableList<Vault> vaults, ObjectProperty<Vault> selectedVault, VaultListCellFactory cellFactory, AddVaultWizardComponent.Builder addVaultWizard) {
this.vaults = vaults;
this.selectedVault = selectedVault;
this.cellFactory = cellFactory;
this.mainWindow = mainWindow;
this.application = application;
this.keychain = keychain;
this.addVaultWizard = addVaultWizard;
this.removeVault = removeVault;
this.vaultOptionsWindow = vaultOptionsWindow;
this.emptyVaultList = Bindings.isEmpty(vaults);
this.selectedVaultState = new SimpleObjectProperty<>(null);
this.selectedVaultPassphraseStored = new SimpleBooleanProperty(false);
this.selectedVaultRemovable = Bindings.createBooleanBinding(() -> selectedVaultIsInState(LOCKED, MISSING, ERROR, NEEDS_MIGRATION), selectedVaultState);
this.selectedVaultUnlockable = Bindings.createBooleanBinding(() -> selectedVaultIsInState(LOCKED), selectedVaultState);
this.selectedVaultLockable = Bindings.createBooleanBinding(() -> selectedVaultIsInState(UNLOCKED), selectedVaultState);
selectedVault.addListener(this::selectedVaultDidChange);
}
@@ -82,10 +45,6 @@ public class VaultListController implements FxController {
vaultList.setItems(vaults);
vaultList.setCellFactory(cellFactory);
selectedVault.bind(vaultList.getSelectionModel().selectedItemProperty());
if (selectedVault.get() != null) {
selectedVaultState.set(selectedVault.get().getState());
selectedVaultPassphraseStored.bind(keychain.getPassphraseStoredProperty(selectedVault.get().getId()));
}
vaults.addListener((ListChangeListener.Change<? extends Vault> c) -> {
while (c.next()) {
if (c.wasAdded()) {
@@ -110,21 +69,10 @@ public class VaultListController implements FxController {
}
private void selectedVaultDidChange(@SuppressWarnings("unused") ObservableValue<? extends Vault> observableValue, @SuppressWarnings("unused") Vault oldValue, Vault newValue) {
if (oldValue != null) {
selectedVaultState.unbind();
selectedVaultPassphraseStored.unbind();
}
if (newValue == null) {
return;
}
VaultListManager.redetermineVaultState(newValue);
selectedVaultState.bind(newValue.stateProperty());
selectedVaultPassphraseStored.bind(keychain.getPassphraseStoredProperty(newValue.getId()));
}
private boolean selectedVaultIsInState(VaultState... states) {
var state = selectedVaultState.get();
return Arrays.stream(states).anyMatch(s -> state == s);
}
@FXML
@@ -132,56 +80,6 @@ public class VaultListController implements FxController {
addVaultWizard.build().showAddVaultWizard();
}
@FXML
public void didClickRemoveVault() {
Vault v = selectedVault.get();
if (v != null) {
removeVault.vault(v).build().showRemoveVault();
} else {
LOG.debug("Cannot remove a vault if none is selected.");
}
}
@FXML
public void didClickShowVaultOptions() {
Vault v = selectedVault.get();
if (v != null) {
vaultOptionsWindow.vault(v).build().showVaultOptionsWindow(SelectedVaultOptionsTab.ANY);
} else {
LOG.debug("Cannot open vault options if none is selected.");
}
}
@FXML
public void didClickUnlockVault() {
Vault v = selectedVault.get();
if (v != null) {
application.startUnlockWorkflow(v, Optional.of(mainWindow));
} else {
LOG.debug("Cannot unlock vault if none is selected.");
}
}
@FXML
public void didClickLockVault() {
Vault v = selectedVault.get();
if (v != null) {
application.startLockWorkflow(v, Optional.of(mainWindow));
} else {
LOG.debug("Cannot lock vault if none is selected.");
}
}
@FXML
public void didClickRevealVault() {
Vault v = selectedVault.get();
if (v != null) {
application.getVaultService().reveal(v);
} else {
LOG.debug("Cannot reveal vault if none is selected.");
}
}
// Getter and Setter
public BooleanBinding emptyVaultListProperty() {
@@ -192,35 +90,4 @@ public class VaultListController implements FxController {
return emptyVaultList.get();
}
public BooleanBinding selectedVaultUnlockableProperty() {
return selectedVaultUnlockable;
}
public boolean isSelectedVaultUnlockable() {
return selectedVaultUnlockable.get();
}
public BooleanBinding selectedVaultLockableProperty() {
return selectedVaultLockable;
}
public boolean isSelectedVaultLockable() {
return selectedVaultLockable.get();
}
public BooleanBinding selectedVaultRemovableProperty() {
return selectedVaultRemovable;
}
public boolean isSelectedVaultRemovable() {
return selectedVaultRemovable.get();
}
public BooleanProperty selectedVaultPassphraseStoredProperty() {
return selectedVaultPassphraseStored;
}
public boolean isSelectedVaultPassphraseStored() {
return selectedVaultPassphraseStored.get();
}
}

View File

@@ -2,10 +2,8 @@
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ContextMenu?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.layout.Region?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
@@ -17,16 +15,7 @@
<StackPane VBox.vgrow="ALWAYS">
<ListView fx:id="vaultList" editable="true" fixedCellSize="60">
<contextMenu>
<ContextMenu>
<items>
<MenuItem fx:id="revealEntry" text="%main.vaultlist.contextMenu.reveal" onAction="#didClickRevealVault" visible="${controller.selectedVaultLockable}"/>
<MenuItem fx:id="lockEntry" text="%main.vaultlist.contextMenu.lock" onAction="#didClickLockVault" visible="${controller.selectedVaultLockable}"/>
<MenuItem fx:id="unlockEntry" text="%main.vaultlist.contextMenu.unlock" onAction="#didClickUnlockVault" visible="${controller.selectedVaultUnlockable &amp;&amp; !controller.selectedVaultPassphraseStored}"/>
<MenuItem fx:id="unlockNowEntry" text="%main.vaultlist.contextMenu.unlockNow" onAction="#didClickUnlockVault" visible="${controller.selectedVaultUnlockable &amp;&amp; controller.selectedVaultPassphraseStored}"/>
<MenuItem fx:id="optionsEntry" text="%main.vaultlist.contextMenu.vaultoptions" onAction="#didClickShowVaultOptions" disable="${!controller.selectedVaultUnlockable}"/>
<MenuItem fx:id="removeEntry" text="%main.vaultlist.contextMenu.remove" onAction="#didClickRemoveVault" disable="${!controller.selectedVaultRemovable}"/>
</items>
</ContextMenu>
<fx:include source="vault_list_contextmenu.fxml"/>
</contextMenu>
</ListView>
<VBox visible="${controller.emptyVaultList}" spacing="6" alignment="CENTER">

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.ContextMenu?>
<?import javafx.scene.control.MenuItem?>
<ContextMenu xmlns:fx="http://javafx.com/fxml"
xmlns="http://javafx.com/javafx"
fx:controller="org.cryptomator.ui.mainwindow.VaultListContextMenuController">
<items>
<MenuItem fx:id="revealEntry" text="%main.vaultlist.contextMenu.reveal" onAction="#didClickRevealVault" visible="${controller.selectedVaultLockable}"/>
<MenuItem fx:id="lockEntry" text="%main.vaultlist.contextMenu.lock" onAction="#didClickLockVault" visible="${controller.selectedVaultLockable}"/>
<MenuItem fx:id="unlockEntry" text="%main.vaultlist.contextMenu.unlock" onAction="#didClickUnlockVault" visible="${controller.selectedVaultUnlockable &amp;&amp; !controller.selectedVaultPassphraseStored}"/>
<MenuItem fx:id="unlockNowEntry" text="%main.vaultlist.contextMenu.unlockNow" onAction="#didClickUnlockVault" visible="${controller.selectedVaultUnlockable &amp;&amp; controller.selectedVaultPassphraseStored}"/>
<MenuItem fx:id="optionsEntry" text="%main.vaultlist.contextMenu.vaultoptions" onAction="#didClickShowVaultOptions" disable="${!controller.selectedVaultUnlockable}"/>
<MenuItem fx:id="removeEntry" text="%main.vaultlist.contextMenu.remove" onAction="#didClickRemoveVault" disable="${!controller.selectedVaultRemovable}"/>
</items>
</ContextMenu>