From 97afadd7b912aa230508182fe609d81165613535 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Fri, 19 Mar 2021 17:28:58 +0100 Subject: [PATCH 01/13] fixes #1478 --- .../ui/mainwindow/VaultListController.java | 24 +++++++++++++++++++ .../src/main/resources/fxml/vault_list.fxml | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java index fc751d862..f66ef36be 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java @@ -11,7 +11,10 @@ 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.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; @@ -25,6 +28,7 @@ public class VaultListController implements FxController { private final ObservableList vaults; private final ObjectProperty selectedVault; + private final BooleanProperty selectedVaultRemovable; private final VaultListCellFactory cellFactory; private final AddVaultWizardComponent.Builder addVaultWizard; private final RemoveVaultComponent.Builder removeVault; @@ -41,6 +45,7 @@ public class VaultListController implements FxController { this.removeVault = removeVault; this.noVaultSelected = selectedVault.isNull(); this.emptyVaultList = Bindings.isEmpty(vaults); + this.selectedVaultRemovable = new SimpleBooleanProperty(false); selectedVault.addListener(this::selectedVaultDidChange); } @@ -59,12 +64,22 @@ public class VaultListController implements FxController { } private void selectedVaultDidChange(@SuppressWarnings("unused") ObservableValue observableValue, @SuppressWarnings("unused") Vault oldValue, Vault newValue) { + if(oldValue != null){ + oldValue.lockedProperty().removeListener((ChangeListener) this::updateSelectedVaultRemovable); + } if (newValue == null) { return; } VaultListManager.redetermineVaultState(newValue); + selectedVaultRemovable.setValue(newValue.isLocked()); + newValue.lockedProperty().addListener((ChangeListener) this::updateSelectedVaultRemovable); } + private void updateSelectedVaultRemovable(ObservableValue observableValue, Boolean oldVal, Boolean newVal) { + selectedVaultRemovable.setValue(newVal); + } + + @FXML public void didClickAddVault() { addVaultWizard.build().showAddVaultWizard(); @@ -97,4 +112,13 @@ public class VaultListController implements FxController { public boolean isNoVaultSelected() { return noVaultSelected.get(); } + + public BooleanProperty selectedVaultRemovableProperty() { + return selectedVaultRemovable; + } + + public boolean isSelectedVaultRemovable() { + return selectedVaultRemovable.get(); + } + } diff --git a/main/ui/src/main/resources/fxml/vault_list.fxml b/main/ui/src/main/resources/fxml/vault_list.fxml index 942074639..e7362ffbb 100644 --- a/main/ui/src/main/resources/fxml/vault_list.fxml +++ b/main/ui/src/main/resources/fxml/vault_list.fxml @@ -19,7 +19,7 @@ - + From 0e32e96c7de77f4dfe43f4899e148515e8d30458 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Mon, 22 Mar 2021 17:10:45 +0100 Subject: [PATCH 02/13] made context menu great again: * added entry to unlock / lock a vault * added entry to show vault options --- .../ui/mainwindow/VaultListController.java | 84 ++++++++++++++++--- .../src/main/resources/fxml/vault_list.fxml | 5 +- .../main/resources/i18n/strings.properties | 3 + 3 files changed, 78 insertions(+), 14 deletions(-) diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java index f66ef36be..66e42b667 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java @@ -2,9 +2,13 @@ package org.cryptomator.ui.mainwindow; 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; @@ -20,6 +24,8 @@ import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; import javafx.fxml.FXML; import javafx.scene.control.ListView; +import javafx.stage.Stage; +import java.util.Optional; @MainWindowScoped public class VaultListController implements FxController { @@ -28,24 +34,33 @@ public class VaultListController implements FxController { private final ObservableList vaults; private final ObjectProperty selectedVault; - private final BooleanProperty selectedVaultRemovable; + private final BooleanProperty selectedVaultLocked; + private final BooleanProperty selectedVaultUnlocked; private final VaultListCellFactory cellFactory; + private final Stage mainWindow; + private final FxApplication application; private final AddVaultWizardComponent.Builder addVaultWizard; private final RemoveVaultComponent.Builder removeVault; + private final VaultOptionsComponent.Builder vaultOptionsWindow; private final BooleanBinding noVaultSelected; private final BooleanBinding emptyVaultList; + public ListView vaultList; @Inject - VaultListController(ObservableList vaults, ObjectProperty selectedVault, VaultListCellFactory cellFactory, AddVaultWizardComponent.Builder addVaultWizard, RemoveVaultComponent.Builder removeVault) { + VaultListController(ObservableList vaults, ObjectProperty selectedVault, VaultListCellFactory cellFactory, @MainWindow Stage mainWindow, FxApplication application, AddVaultWizardComponent.Builder addVaultWizard, RemoveVaultComponent.Builder removeVault, VaultOptionsComponent.Builder vaultOptionsWindow) { this.vaults = vaults; this.selectedVault = selectedVault; this.cellFactory = cellFactory; + this.mainWindow = mainWindow; + this.application = application; this.addVaultWizard = addVaultWizard; this.removeVault = removeVault; this.noVaultSelected = selectedVault.isNull(); this.emptyVaultList = Bindings.isEmpty(vaults); - this.selectedVaultRemovable = new SimpleBooleanProperty(false); + this.vaultOptionsWindow = vaultOptionsWindow; + this.selectedVaultLocked = new SimpleBooleanProperty(false); + this.selectedVaultUnlocked = new SimpleBooleanProperty(false); selectedVault.addListener(this::selectedVaultDidChange); } @@ -64,19 +79,25 @@ public class VaultListController implements FxController { } private void selectedVaultDidChange(@SuppressWarnings("unused") ObservableValue observableValue, @SuppressWarnings("unused") Vault oldValue, Vault newValue) { - if(oldValue != null){ - oldValue.lockedProperty().removeListener((ChangeListener) this::updateSelectedVaultRemovable); + if (oldValue != null) { + oldValue.stateProperty().removeListener((ChangeListener) this::updateVaultStateDependencies); } if (newValue == null) { return; } VaultListManager.redetermineVaultState(newValue); - selectedVaultRemovable.setValue(newValue.isLocked()); - newValue.lockedProperty().addListener((ChangeListener) this::updateSelectedVaultRemovable); + setVaultStateDependencies(newValue.getState()); + newValue.stateProperty().addListener((ChangeListener) this::updateVaultStateDependencies); } - private void updateSelectedVaultRemovable(ObservableValue observableValue, Boolean oldVal, Boolean newVal) { - selectedVaultRemovable.setValue(newVal); + private void setVaultStateDependencies(VaultState state) { + selectedVaultLocked.setValue(state == VaultState.LOCKED); + selectedVaultUnlocked.setValue(state == VaultState.UNLOCKED); + } + + private void updateVaultStateDependencies(ObservableValue observableValue, VaultState oldVal, VaultState newVal) { + selectedVaultLocked.setValue(newVal == VaultState.LOCKED); + selectedVaultUnlocked.setValue(newVal == VaultState.UNLOCKED); } @@ -95,6 +116,36 @@ public class VaultListController implements FxController { } } + @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."); + } + } + // Getter and Setter public BooleanBinding emptyVaultListProperty() { @@ -113,12 +164,19 @@ public class VaultListController implements FxController { return noVaultSelected.get(); } - public BooleanProperty selectedVaultRemovableProperty() { - return selectedVaultRemovable; + public BooleanProperty selectedVaultLockedProperty() { + return selectedVaultLocked; } - public boolean isSelectedVaultRemovable() { - return selectedVaultRemovable.get(); + public boolean isSelectedVaultLocked() { + return selectedVaultLocked.get(); } + public BooleanProperty selectedVaultUnlockedProperty() { + return selectedVaultUnlocked; + } + + public boolean isSelectedVaultUnlocked() { + return selectedVaultUnlocked.get(); + } } diff --git a/main/ui/src/main/resources/fxml/vault_list.fxml b/main/ui/src/main/resources/fxml/vault_list.fxml index e7362ffbb..5791a8882 100644 --- a/main/ui/src/main/resources/fxml/vault_list.fxml +++ b/main/ui/src/main/resources/fxml/vault_list.fxml @@ -19,7 +19,10 @@ - + + + + diff --git a/main/ui/src/main/resources/i18n/strings.properties b/main/ui/src/main/resources/i18n/strings.properties index 20aa17a14..583468674 100644 --- a/main/ui/src/main/resources/i18n/strings.properties +++ b/main/ui/src/main/resources/i18n/strings.properties @@ -225,6 +225,9 @@ main.dropZone.unknownDragboardContent=If you want to add a vault, drag it to thi ## Vault List main.vaultlist.emptyList.onboardingInstruction=Click here to add a vault main.vaultlist.contextMenu.remove=Remove Vault… +main.vaultlist.contextMenu.lock=Lock Vault… +main.vaultlist.contextMenu.unlock=Unlock Vault… +main.vaultlist.contextMenu.vaultoptions=Show Vault Options main.vaultlist.addVaultBtn=Add Vault ## Vault Detail ### Welcome From 9dc8b2cb47f13a289c8e72851787370770e6bc6c Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Tue, 23 Mar 2021 10:50:04 +0100 Subject: [PATCH 03/13] Use Bindings instead of properties --- .../ui/mainwindow/VaultListController.java | 54 ++++++++++++------- .../src/main/resources/fxml/vault_list.fxml | 2 +- 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java index 66e42b667..cc3d55c00 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java @@ -15,10 +15,8 @@ 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.value.ChangeListener; +import javafx.beans.property.SimpleObjectProperty; import javafx.beans.value.ObservableValue; import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; @@ -27,6 +25,8 @@ import javafx.scene.control.ListView; import javafx.stage.Stage; import java.util.Optional; +import static org.cryptomator.common.vaults.VaultState.*; + @MainWindowScoped public class VaultListController implements FxController { @@ -34,8 +34,7 @@ public class VaultListController implements FxController { private final ObservableList vaults; private final ObjectProperty selectedVault; - private final BooleanProperty selectedVaultLocked; - private final BooleanProperty selectedVaultUnlocked; + private final ObjectProperty selectedVaultState; private final VaultListCellFactory cellFactory; private final Stage mainWindow; private final FxApplication application; @@ -44,6 +43,9 @@ public class VaultListController implements FxController { private final VaultOptionsComponent.Builder vaultOptionsWindow; private final BooleanBinding noVaultSelected; private final BooleanBinding emptyVaultList; + private final BooleanBinding selectedVaultRemovable; + private final BooleanBinding selectedVaultLocked; + private final BooleanBinding selectedVaultUnlocked; public ListView vaultList; @@ -59,8 +61,10 @@ public class VaultListController implements FxController { this.noVaultSelected = selectedVault.isNull(); this.emptyVaultList = Bindings.isEmpty(vaults); this.vaultOptionsWindow = vaultOptionsWindow; - this.selectedVaultLocked = new SimpleBooleanProperty(false); - this.selectedVaultUnlocked = new SimpleBooleanProperty(false); + this.selectedVaultState = new SimpleObjectProperty<>(null); + this.selectedVaultRemovable = Bindings.createBooleanBinding(() -> selectedVaultIsInState(LOCKED, MISSING, ERROR, NEEDS_MIGRATION), selectedVaultState); + this.selectedVaultLocked = Bindings.createBooleanBinding(() -> selectedVaultIsInState(LOCKED), selectedVaultState); + this.selectedVaultUnlocked = Bindings.createBooleanBinding(() -> selectedVaultIsInState(UNLOCKED), selectedVaultState); selectedVault.addListener(this::selectedVaultDidChange); } @@ -80,24 +84,26 @@ public class VaultListController implements FxController { private void selectedVaultDidChange(@SuppressWarnings("unused") ObservableValue observableValue, @SuppressWarnings("unused") Vault oldValue, Vault newValue) { if (oldValue != null) { - oldValue.stateProperty().removeListener((ChangeListener) this::updateVaultStateDependencies); + selectedVaultState.unbind(); } if (newValue == null) { return; } VaultListManager.redetermineVaultState(newValue); - setVaultStateDependencies(newValue.getState()); - newValue.stateProperty().addListener((ChangeListener) this::updateVaultStateDependencies); + selectedVaultState.bind(newValue.stateProperty()); } - private void setVaultStateDependencies(VaultState state) { - selectedVaultLocked.setValue(state == VaultState.LOCKED); - selectedVaultUnlocked.setValue(state == VaultState.UNLOCKED); - } - - private void updateVaultStateDependencies(ObservableValue observableValue, VaultState oldVal, VaultState newVal) { - selectedVaultLocked.setValue(newVal == VaultState.LOCKED); - selectedVaultUnlocked.setValue(newVal == VaultState.UNLOCKED); + private boolean selectedVaultIsInState(VaultState other, VaultState... others) { + final var state = selectedVaultState.get(); + if (state == null) { + return false; + } else { + boolean result = (state == other); + for (VaultState o : others) { + result |= (state == o); + } + return result; + } } @@ -164,7 +170,7 @@ public class VaultListController implements FxController { return noVaultSelected.get(); } - public BooleanProperty selectedVaultLockedProperty() { + public BooleanBinding selectedVaultLockedProperty() { return selectedVaultLocked; } @@ -172,11 +178,19 @@ public class VaultListController implements FxController { return selectedVaultLocked.get(); } - public BooleanProperty selectedVaultUnlockedProperty() { + public BooleanBinding selectedVaultUnlockedProperty() { return selectedVaultUnlocked; } public boolean isSelectedVaultUnlocked() { return selectedVaultUnlocked.get(); } + + public BooleanBinding selectedVaultRemovableProperty() { + return selectedVaultRemovable; + } + + public boolean isSelectedVaultRemovable() { + return selectedVaultRemovable.get(); + } } diff --git a/main/ui/src/main/resources/fxml/vault_list.fxml b/main/ui/src/main/resources/fxml/vault_list.fxml index 5791a8882..9a456ae1a 100644 --- a/main/ui/src/main/resources/fxml/vault_list.fxml +++ b/main/ui/src/main/resources/fxml/vault_list.fxml @@ -22,7 +22,7 @@ - + From 786d156b9fc8357333a2f9ea6da97fa712caef63 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Tue, 23 Mar 2021 15:08:23 +0100 Subject: [PATCH 04/13] change wording in context menu entries --- main/ui/src/main/resources/i18n/strings.properties | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/main/ui/src/main/resources/i18n/strings.properties b/main/ui/src/main/resources/i18n/strings.properties index 583468674..56461a29d 100644 --- a/main/ui/src/main/resources/i18n/strings.properties +++ b/main/ui/src/main/resources/i18n/strings.properties @@ -224,9 +224,9 @@ main.dropZone.dropVault=Add this vault main.dropZone.unknownDragboardContent=If you want to add a vault, drag it to this window ## Vault List main.vaultlist.emptyList.onboardingInstruction=Click here to add a vault -main.vaultlist.contextMenu.remove=Remove Vault… -main.vaultlist.contextMenu.lock=Lock Vault… -main.vaultlist.contextMenu.unlock=Unlock Vault… +main.vaultlist.contextMenu.remove=Remove +main.vaultlist.contextMenu.lock=Lock +main.vaultlist.contextMenu.unlock=Unlock main.vaultlist.contextMenu.vaultoptions=Show Vault Options main.vaultlist.addVaultBtn=Add Vault ## Vault Detail From f77b237e5936a8ff63b5f273d54879abf0423e18 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Mon, 29 Mar 2021 12:44:57 +0200 Subject: [PATCH 05/13] simplify private function Co-authored-by: Sebastian Stenzel --- .../ui/mainwindow/VaultListController.java | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java index cc3d55c00..aa45a2e86 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java @@ -93,17 +93,9 @@ public class VaultListController implements FxController { selectedVaultState.bind(newValue.stateProperty()); } - private boolean selectedVaultIsInState(VaultState other, VaultState... others) { - final var state = selectedVaultState.get(); - if (state == null) { - return false; - } else { - boolean result = (state == other); - for (VaultState o : others) { - result |= (state == o); - } - return result; - } + private boolean selectedVaultIsInState(VaultState... states) { + var state = selectedVaultState.get(); + return Arrays.stream(states).anyMatch(s -> state == s); } From f556301249f173092919256fca6efd9141c33012 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Mon, 29 Mar 2021 12:47:46 +0200 Subject: [PATCH 06/13] fix suggestion --- .../java/org/cryptomator/ui/mainwindow/VaultListController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java index aa45a2e86..cd6b908cd 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java @@ -23,6 +23,7 @@ import javafx.collections.ObservableList; import javafx.fxml.FXML; import javafx.scene.control.ListView; import javafx.stage.Stage; +import java.util.Arrays; import java.util.Optional; import static org.cryptomator.common.vaults.VaultState.*; From 0bdfb7c9f9a8551d4b104466721aedd9faf53395 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Mon, 29 Mar 2021 12:59:48 +0200 Subject: [PATCH 07/13] Distinct between "unlock" and "unlock now" in context menu: * inject keychainManager * bind/unbind passphraseStored property to selected vault * rename bindings to show possible action * removed unused binding * initialize properties properly --- .../ui/mainwindow/VaultListController.java | 57 +++++++++++-------- .../src/main/resources/fxml/vault_list.fxml | 7 ++- .../main/resources/i18n/strings.properties | 5 +- 3 files changed, 41 insertions(+), 28 deletions(-) diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java index cd6b908cd..dbae8b95e 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java @@ -1,5 +1,6 @@ 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; @@ -15,7 +16,9 @@ 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; @@ -36,36 +39,38 @@ public class VaultListController implements FxController { private final ObservableList vaults; private final ObjectProperty selectedVault; private final ObjectProperty 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 noVaultSelected; private final BooleanBinding emptyVaultList; private final BooleanBinding selectedVaultRemovable; - private final BooleanBinding selectedVaultLocked; - private final BooleanBinding selectedVaultUnlocked; + private final BooleanBinding selectedVaultUnlockable; + private final BooleanBinding selectedVaultLockable; public ListView vaultList; @Inject - VaultListController(ObservableList vaults, ObjectProperty selectedVault, VaultListCellFactory cellFactory, @MainWindow Stage mainWindow, FxApplication application, AddVaultWizardComponent.Builder addVaultWizard, RemoveVaultComponent.Builder removeVault, VaultOptionsComponent.Builder vaultOptionsWindow) { + VaultListController(ObservableList vaults, ObjectProperty selectedVault, VaultListCellFactory cellFactory, @MainWindow Stage mainWindow, FxApplication application, KeychainManager keychain, AddVaultWizardComponent.Builder addVaultWizard, RemoveVaultComponent.Builder removeVault, VaultOptionsComponent.Builder vaultOptionsWindow) { 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.noVaultSelected = selectedVault.isNull(); this.emptyVaultList = Bindings.isEmpty(vaults); this.vaultOptionsWindow = vaultOptionsWindow; this.selectedVaultState = new SimpleObjectProperty<>(null); + this.selectedVaultPassphraseStored = new SimpleBooleanProperty(false); this.selectedVaultRemovable = Bindings.createBooleanBinding(() -> selectedVaultIsInState(LOCKED, MISSING, ERROR, NEEDS_MIGRATION), selectedVaultState); - this.selectedVaultLocked = Bindings.createBooleanBinding(() -> selectedVaultIsInState(LOCKED), selectedVaultState); - this.selectedVaultUnlocked = Bindings.createBooleanBinding(() -> selectedVaultIsInState(UNLOCKED), selectedVaultState); + this.selectedVaultUnlockable = Bindings.createBooleanBinding(() -> selectedVaultIsInState(LOCKED), selectedVaultState); + this.selectedVaultLockable = Bindings.createBooleanBinding(() -> selectedVaultIsInState(UNLOCKED), selectedVaultState); selectedVault.addListener(this::selectedVaultDidChange); } @@ -73,6 +78,10 @@ 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 c) -> { while (c.next()) { if (c.wasAdded()) { @@ -86,12 +95,14 @@ public class VaultListController implements FxController { private void selectedVaultDidChange(@SuppressWarnings("unused") ObservableValue 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) { @@ -155,28 +166,20 @@ public class VaultListController implements FxController { return emptyVaultList.get(); } - public BooleanBinding noVaultSelectedProperty() { - return noVaultSelected; + public BooleanBinding selectedVaultUnlockableProperty() { + return selectedVaultUnlockable; } - public boolean isNoVaultSelected() { - return noVaultSelected.get(); + public boolean isSelectedVaultUnlockable() { + return selectedVaultUnlockable.get(); } - public BooleanBinding selectedVaultLockedProperty() { - return selectedVaultLocked; + public BooleanBinding selectedVaultLockableProperty() { + return selectedVaultLockable; } - public boolean isSelectedVaultLocked() { - return selectedVaultLocked.get(); - } - - public BooleanBinding selectedVaultUnlockedProperty() { - return selectedVaultUnlocked; - } - - public boolean isSelectedVaultUnlocked() { - return selectedVaultUnlocked.get(); + public boolean isSelectedVaultLockable() { + return selectedVaultLockable.get(); } public BooleanBinding selectedVaultRemovableProperty() { @@ -186,4 +189,12 @@ public class VaultListController implements FxController { public boolean isSelectedVaultRemovable() { return selectedVaultRemovable.get(); } + + public BooleanProperty selectedVaultPassphraseStoredProperty() { + return selectedVaultPassphraseStored; + } + + public boolean isSelectedVaultPassphraseStored() { + return selectedVaultPassphraseStored.get(); + } } diff --git a/main/ui/src/main/resources/fxml/vault_list.fxml b/main/ui/src/main/resources/fxml/vault_list.fxml index 9a456ae1a..7c33439fb 100644 --- a/main/ui/src/main/resources/fxml/vault_list.fxml +++ b/main/ui/src/main/resources/fxml/vault_list.fxml @@ -19,9 +19,10 @@ - - - + + + + diff --git a/main/ui/src/main/resources/i18n/strings.properties b/main/ui/src/main/resources/i18n/strings.properties index 56461a29d..49f975957 100644 --- a/main/ui/src/main/resources/i18n/strings.properties +++ b/main/ui/src/main/resources/i18n/strings.properties @@ -224,9 +224,10 @@ main.dropZone.dropVault=Add this vault main.dropZone.unknownDragboardContent=If you want to add a vault, drag it to this window ## Vault List main.vaultlist.emptyList.onboardingInstruction=Click here to add a vault -main.vaultlist.contextMenu.remove=Remove +main.vaultlist.contextMenu.remove=Remove… main.vaultlist.contextMenu.lock=Lock -main.vaultlist.contextMenu.unlock=Unlock +main.vaultlist.contextMenu.unlock=Unlock… +main.vaultlist.contextMenu.unlockNow=Unlock Now main.vaultlist.contextMenu.vaultoptions=Show Vault Options main.vaultlist.addVaultBtn=Add Vault ## Vault Detail From 96a612127c6bc147a91d4fdc95c661f717049d13 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Mon, 29 Mar 2021 16:23:24 +0200 Subject: [PATCH 08/13] add reveal entry to context menu. --- .../cryptomator/ui/mainwindow/VaultListController.java | 10 ++++++++++ main/ui/src/main/resources/fxml/vault_list.fxml | 1 + main/ui/src/main/resources/i18n/strings.properties | 1 + 3 files changed, 12 insertions(+) diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java index dbae8b95e..e52104547 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java @@ -156,6 +156,16 @@ public class VaultListController implements FxController { } } + @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() { diff --git a/main/ui/src/main/resources/fxml/vault_list.fxml b/main/ui/src/main/resources/fxml/vault_list.fxml index 7c33439fb..e616a0e08 100644 --- a/main/ui/src/main/resources/fxml/vault_list.fxml +++ b/main/ui/src/main/resources/fxml/vault_list.fxml @@ -19,6 +19,7 @@ + diff --git a/main/ui/src/main/resources/i18n/strings.properties b/main/ui/src/main/resources/i18n/strings.properties index 49f975957..22851f7cf 100644 --- a/main/ui/src/main/resources/i18n/strings.properties +++ b/main/ui/src/main/resources/i18n/strings.properties @@ -229,6 +229,7 @@ main.vaultlist.contextMenu.lock=Lock main.vaultlist.contextMenu.unlock=Unlock… main.vaultlist.contextMenu.unlockNow=Unlock Now main.vaultlist.contextMenu.vaultoptions=Show Vault Options +main.vaultlist.contextMenu.reveal=Reveal Vault main.vaultlist.addVaultBtn=Add Vault ## Vault Detail ### Welcome From 2be7a050a46f50ac948032d57c7f2fd26925c08a Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Tue, 30 Mar 2021 09:45:35 +0200 Subject: [PATCH 09/13] refine wording [ci skip] --- main/ui/src/main/resources/i18n/strings.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/ui/src/main/resources/i18n/strings.properties b/main/ui/src/main/resources/i18n/strings.properties index 22851f7cf..239e3fb74 100644 --- a/main/ui/src/main/resources/i18n/strings.properties +++ b/main/ui/src/main/resources/i18n/strings.properties @@ -229,7 +229,7 @@ main.vaultlist.contextMenu.lock=Lock main.vaultlist.contextMenu.unlock=Unlock… main.vaultlist.contextMenu.unlockNow=Unlock Now main.vaultlist.contextMenu.vaultoptions=Show Vault Options -main.vaultlist.contextMenu.reveal=Reveal Vault +main.vaultlist.contextMenu.reveal=Reveal Drive main.vaultlist.addVaultBtn=Add Vault ## Vault Detail ### Welcome From 3b4f6276b5a4cbf6552bac88a27282760d7f40c0 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Tue, 30 Mar 2021 11:25:22 +0200 Subject: [PATCH 10/13] Improve selection model of list view: * Clear selection if an empty space is clicked * only open context menu if an item is selected --- .../ui/mainwindow/VaultListController.java | 15 +++++++++++++++ main/ui/src/main/resources/fxml/vault_list.fxml | 2 +- .../src/main/resources/fxml/vault_list_cell.fxml | 1 + 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java index e52104547..274e35a6f 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java @@ -25,6 +25,8 @@ import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; 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; @@ -90,6 +92,19 @@ public class VaultListController implements FxController { } } }); + vaultList.addEventFilter(MouseEvent.MOUSE_RELEASED, this::deselect); + vaultList.addEventFilter(ContextMenuEvent.CONTEXT_MENU_REQUESTED, request -> { + if (selectedVault.get() == null) { + request.consume(); + } + }); + } + + private void deselect(MouseEvent released) { + if (released.getY() > (vaultList.getItems().size() * vaultList.fixedCellSizeProperty().get())) { + vaultList.getSelectionModel().clearSelection(); + released.consume(); + } } private void selectedVaultDidChange(@SuppressWarnings("unused") ObservableValue observableValue, @SuppressWarnings("unused") Vault oldValue, Vault newValue) { diff --git a/main/ui/src/main/resources/fxml/vault_list.fxml b/main/ui/src/main/resources/fxml/vault_list.fxml index e616a0e08..68d8b9fde 100644 --- a/main/ui/src/main/resources/fxml/vault_list.fxml +++ b/main/ui/src/main/resources/fxml/vault_list.fxml @@ -15,7 +15,7 @@ fx:controller="org.cryptomator.ui.mainwindow.VaultListController" minWidth="206"> - + diff --git a/main/ui/src/main/resources/fxml/vault_list_cell.fxml b/main/ui/src/main/resources/fxml/vault_list_cell.fxml index e86f084c1..ce8664639 100644 --- a/main/ui/src/main/resources/fxml/vault_list_cell.fxml +++ b/main/ui/src/main/resources/fxml/vault_list_cell.fxml @@ -13,6 +13,7 @@ prefWidth="200" spacing="12" alignment="CENTER_LEFT"> + From ff8423056606fa1fd4af436b507831863470e17a Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Tue, 30 Mar 2021 11:53:30 +0200 Subject: [PATCH 11/13] structure constructor --- .../org/cryptomator/ui/mainwindow/VaultListController.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java index 274e35a6f..d15a33510 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java @@ -66,13 +66,15 @@ public class VaultListController implements FxController { this.keychain = keychain; this.addVaultWizard = addVaultWizard; this.removeVault = removeVault; - this.emptyVaultList = Bindings.isEmpty(vaults); 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); } @@ -125,7 +127,6 @@ public class VaultListController implements FxController { return Arrays.stream(states).anyMatch(s -> state == s); } - @FXML public void didClickAddVault() { addVaultWizard.build().showAddVaultWizard(); From 30f0c5e697ed54893a0939921bbb8a02c0d236b5 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Tue, 30 Mar 2021 13:43:37 +0200 Subject: [PATCH 12/13] split VaultList and ContextMenu into two separate controllers --- .../ui/mainwindow/MainWindowModule.java | 5 + .../VaultListContextMenuController.java | 157 ++++++++++++++++++ .../ui/mainwindow/VaultListController.java | 135 +-------------- .../src/main/resources/fxml/vault_list.fxml | 13 +- .../fxml/vault_list_contextmenu.fxml | 16 ++ 5 files changed, 180 insertions(+), 146 deletions(-) create mode 100644 main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListContextMenuController.java create mode 100644 main/ui/src/main/resources/fxml/vault_list_contextmenu.fxml diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/MainWindowModule.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/MainWindowModule.java index f8316d289..fad1b3c85 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/MainWindowModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/MainWindowModule.java @@ -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) diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListContextMenuController.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListContextMenuController.java new file mode 100644 index 000000000..4cccdf5d8 --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListContextMenuController.java @@ -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 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 selectedVaultState; + private final BooleanBinding selectedVaultPassphraseStored; + private final BooleanBinding selectedVaultRemovable; + private final BooleanBinding selectedVaultUnlockable; + private final BooleanBinding selectedVaultLockable; + + @Inject + VaultListContextMenuController(ObjectProperty 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(); + } + } +} diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java index d15a33510..04ea9f152 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java @@ -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 vaults; private final ObjectProperty selectedVault; - private final ObjectProperty 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 vaultList; @Inject - VaultListController(ObservableList vaults, ObjectProperty selectedVault, VaultListCellFactory cellFactory, @MainWindow Stage mainWindow, FxApplication application, KeychainManager keychain, AddVaultWizardComponent.Builder addVaultWizard, RemoveVaultComponent.Builder removeVault, VaultOptionsComponent.Builder vaultOptionsWindow) { + VaultListController(ObservableList vaults, ObjectProperty 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 c) -> { while (c.next()) { if (c.wasAdded()) { @@ -110,21 +69,10 @@ public class VaultListController implements FxController { } private void selectedVaultDidChange(@SuppressWarnings("unused") ObservableValue 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(); - } } diff --git a/main/ui/src/main/resources/fxml/vault_list.fxml b/main/ui/src/main/resources/fxml/vault_list.fxml index 68d8b9fde..f01aa710c 100644 --- a/main/ui/src/main/resources/fxml/vault_list.fxml +++ b/main/ui/src/main/resources/fxml/vault_list.fxml @@ -2,10 +2,8 @@ - - @@ -17,16 +15,7 @@ - - - - - - - - - - + diff --git a/main/ui/src/main/resources/fxml/vault_list_contextmenu.fxml b/main/ui/src/main/resources/fxml/vault_list_contextmenu.fxml new file mode 100644 index 000000000..bd8f19204 --- /dev/null +++ b/main/ui/src/main/resources/fxml/vault_list_contextmenu.fxml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + From f0ebf7a638812e8083a5effe8d3b781d229333ee Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Tue, 30 Mar 2021 14:20:05 +0200 Subject: [PATCH 13/13] EasyBind rulez --- .../VaultListContextMenuController.java | 94 +++++++------------ 1 file changed, 36 insertions(+), 58 deletions(-) diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListContextMenuController.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListContextMenuController.java index 4cccdf5d8..b0866d80f 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListContextMenuController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListContextMenuController.java @@ -1,6 +1,8 @@ package org.cryptomator.ui.mainwindow; import com.tobiasdiez.easybind.EasyBind; +import com.tobiasdiez.easybind.optional.ObservableOptionalValue; +import com.tobiasdiez.easybind.optional.OptionalBinding; import org.cryptomator.common.keychain.KeychainManager; import org.cryptomator.common.vaults.Vault; import org.cryptomator.common.vaults.VaultState; @@ -9,18 +11,15 @@ 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.EnumSet; import java.util.Optional; import static org.cryptomator.common.vaults.VaultState.ERROR; @@ -32,126 +31,105 @@ 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 selectedVault; + private final ObservableOptionalValue 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 selectedVaultState; - private final BooleanBinding selectedVaultPassphraseStored; - private final BooleanBinding selectedVaultRemovable; - private final BooleanBinding selectedVaultUnlockable; - private final BooleanBinding selectedVaultLockable; + private final OptionalBinding selectedVaultState; + private final Binding selectedVaultPassphraseStored; + private final Binding selectedVaultRemovable; + private final Binding selectedVaultUnlockable; + private final Binding selectedVaultLockable; @Inject VaultListContextMenuController(ObjectProperty selectedVault, @MainWindow Stage mainWindow, FxApplication application, KeychainManager keychain, RemoveVaultComponent.Builder removeVault, VaultOptionsComponent.Builder vaultOptionsWindow) { - this.selectedVault = selectedVault; + this.selectedVault = EasyBind.wrapNullable(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); + this.selectedVaultState = this.selectedVault.mapObservable(Vault::stateProperty); + this.selectedVaultPassphraseStored = this.selectedVault.map(this::isPasswordStored).orElse(false); + this.selectedVaultRemovable = selectedVaultState.map(EnumSet.of(LOCKED, MISSING, ERROR, NEEDS_MIGRATION)::contains).orElse(false); + this.selectedVaultUnlockable = selectedVaultState.map(LOCKED::equals).orElse(false); + this.selectedVaultLockable = selectedVaultState.map(UNLOCKED::equals).orElse(false); + } - private boolean selectedVaultIsInState(VaultState... states) { - var state = selectedVaultState.getValue(); - return Arrays.stream(states).anyMatch(s -> state == s); + private boolean isPasswordStored(Vault vault) { + return keychain.getPassphraseStoredProperty(vault.getId()).get(); } @FXML public void didClickRemoveVault() { - Vault v = selectedVault.get(); - if (v != null) { + selectedVault.ifValuePresent(v -> { 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) { + selectedVault.ifValuePresent(v -> { 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) { + selectedVault.ifValuePresent(v -> { 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) { + selectedVault.ifValuePresent(v -> { 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) { + selectedVault.ifValuePresent(v -> { application.getVaultService().reveal(v); - } else { - LOG.debug("Cannot reveal vault if none is selected."); - } + }); } // Getter and Setter - public BooleanBinding selectedVaultUnlockableProperty() { + public Binding selectedVaultUnlockableProperty() { return selectedVaultUnlockable; } public boolean isSelectedVaultUnlockable() { - return selectedVaultUnlockable.get(); + return selectedVaultUnlockable.getValue(); } - public BooleanBinding selectedVaultLockableProperty() { + public Binding selectedVaultLockableProperty() { return selectedVaultLockable; } public boolean isSelectedVaultLockable() { - return selectedVaultLockable.get(); + return selectedVaultLockable.getValue(); } - public BooleanBinding selectedVaultRemovableProperty() { + public Binding selectedVaultRemovableProperty() { return selectedVaultRemovable; } public boolean isSelectedVaultRemovable() { - return selectedVaultRemovable.get(); + return selectedVaultRemovable.getValue(); } - public BooleanBinding selectedVaultPassphraseStoredProperty() { + public Binding selectedVaultPassphraseStoredProperty() { return selectedVaultPassphraseStored; } public boolean isSelectedVaultPassphraseStored() { - if (selectedVault.get() == null) { - return false; - } else { - return keychain.getPassphraseStoredProperty(selectedVault.get().getId()).get(); - } + return selectedVaultPassphraseStored.getValue(); } }