diff --git a/pom.xml b/pom.xml
index ce5230f38..b7ef1a0cd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,11 +28,11 @@
2.1.1
- 2.5.3
- 1.2.0-beta3
- 1.1.2
- 1.1.2
- 1.1.0
+ 2.6.1
+ 1.2.0-beta4
+ 1.2.0-beta1
+ 1.2.0-beta1
+ 1.2.0-beta1
1.3.4
1.3.3
1.2.8
diff --git a/src/main/java/org/cryptomator/common/vaults/Vault.java b/src/main/java/org/cryptomator/common/vaults/Vault.java
index 54d37d5e3..898bf1a51 100644
--- a/src/main/java/org/cryptomator/common/vaults/Vault.java
+++ b/src/main/java/org/cryptomator/common/vaults/Vault.java
@@ -339,6 +339,23 @@ public class Vault {
return vaultSettings.path().getValue();
}
+
+ /**
+ * Gets from the cleartext path its ciphertext counterpart.
+ * The cleartext path has to start from the vault root (by starting with "/").
+ *
+ * @return Local os path to the ciphertext resource
+ * @throws IOException if an I/O error occurs
+ */
+ public Path getCiphertextPath(String cleartextPath) throws IOException {
+ if (!cleartextPath.startsWith("/")) {
+ throw new IllegalArgumentException("Input path must be absolute from vault root by starting with \"/\".");
+ }
+ var fs = cryptoFileSystem.get();
+ var cryptoPath = fs.getPath(cleartextPath);
+ return fs.getCiphertextPath(cryptoPath);
+ }
+
public boolean isHavingCustomMountFlags() {
return !Strings.isNullOrEmpty(vaultSettings.mountFlags().get());
}
diff --git a/src/main/java/org/cryptomator/ui/controls/FontAwesome5Icon.java b/src/main/java/org/cryptomator/ui/controls/FontAwesome5Icon.java
index ea6ba00d3..997bfa41f 100644
--- a/src/main/java/org/cryptomator/ui/controls/FontAwesome5Icon.java
+++ b/src/main/java/org/cryptomator/ui/controls/FontAwesome5Icon.java
@@ -25,6 +25,7 @@ public enum FontAwesome5Icon {
EYE_SLASH("\uF070"), //
FAST_FORWARD("\uF050"), //
FILE("\uF15B"), //
+ FILE_DOWNLOAD("\uF56D"), //
FILE_IMPORT("\uF56F"), //
FOLDER_OPEN("\uF07C"), //
FUNNEL("\uF0B0"), //
diff --git a/src/main/java/org/cryptomator/ui/mainwindow/MainWindowController.java b/src/main/java/org/cryptomator/ui/mainwindow/MainWindowController.java
index c81aff125..b2c912834 100644
--- a/src/main/java/org/cryptomator/ui/mainwindow/MainWindowController.java
+++ b/src/main/java/org/cryptomator/ui/mainwindow/MainWindowController.java
@@ -3,33 +3,17 @@ package org.cryptomator.ui.mainwindow;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultListManager;
-import org.cryptomator.cryptofs.CryptoFileSystemProvider;
-import org.cryptomator.cryptofs.DirStructure;
import org.cryptomator.ui.common.FxController;
-import org.cryptomator.ui.wrongfilealert.WrongFileAlertComponent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javafx.beans.Observable;
-import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
-import javafx.beans.property.SimpleBooleanProperty;
import javafx.fxml.FXML;
-import javafx.scene.input.DragEvent;
-import javafx.scene.input.TransferMode;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import static org.cryptomator.common.Constants.CRYPTOMATOR_FILENAME_EXT;
-import static org.cryptomator.common.Constants.MASTERKEY_FILENAME;
-import static org.cryptomator.common.Constants.VAULTCONFIG_FILENAME;
@MainWindowScoped
public class MainWindowController implements FxController {
@@ -37,28 +21,19 @@ public class MainWindowController implements FxController {
private static final Logger LOG = LoggerFactory.getLogger(MainWindowController.class);
private final Stage window;
- private final VaultListManager vaultListManager;
private final ReadOnlyObjectProperty selectedVault;
- private final WrongFileAlertComponent.Builder wrongFileAlert;
- private final BooleanProperty draggingOver = new SimpleBooleanProperty();
- private final BooleanProperty draggingVaultOver = new SimpleBooleanProperty();
+
public StackPane root;
@Inject
- public MainWindowController(@MainWindow Stage window, VaultListManager vaultListManager, ObjectProperty selectedVault, WrongFileAlertComponent.Builder wrongFileAlert) {
+ public MainWindowController(@MainWindow Stage window, ObjectProperty selectedVault) {
this.window = window;
- this.vaultListManager = vaultListManager;
this.selectedVault = selectedVault;
- this.wrongFileAlert = wrongFileAlert;
}
@FXML
public void initialize() {
LOG.trace("init MainWindowController");
- root.setOnDragEntered(this::handleDragEvent);
- root.setOnDragOver(this::handleDragEvent);
- root.setOnDragDropped(this::handleDragEvent);
- root.setOnDragExited(this::handleDragEvent);
if (SystemUtils.IS_OS_WINDOWS) {
root.getStyleClass().add("os-windows");
}
@@ -72,65 +47,4 @@ public class MainWindowController implements FxController {
}
}
- private void handleDragEvent(DragEvent event) {
- if (DragEvent.DRAG_ENTERED.equals(event.getEventType()) && event.getGestureSource() == null) {
- draggingOver.set(true);
- } else if (DragEvent.DRAG_OVER.equals(event.getEventType()) && event.getGestureSource() == null && event.getDragboard().hasFiles()) {
- event.acceptTransferModes(TransferMode.ANY);
- draggingVaultOver.set(event.getDragboard().getFiles().stream().map(File::toPath).anyMatch(this::containsVault));
- } else if (DragEvent.DRAG_DROPPED.equals(event.getEventType()) && event.getGestureSource() == null && event.getDragboard().hasFiles()) {
- Set vaultPaths = event.getDragboard().getFiles().stream().map(File::toPath).filter(this::containsVault).collect(Collectors.toSet());
- if (vaultPaths.isEmpty()) {
- wrongFileAlert.build().showWrongFileAlertWindow();
- } else {
- vaultPaths.forEach(this::addVault);
- }
- event.setDropCompleted(!vaultPaths.isEmpty());
- event.consume();
- } else if (DragEvent.DRAG_EXITED.equals(event.getEventType())) {
- draggingOver.set(false);
- draggingVaultOver.set(false);
- }
- }
-
- private boolean containsVault(Path path) {
- try {
- if (path.getFileName().toString().endsWith(CRYPTOMATOR_FILENAME_EXT)) {
- path = path.getParent();
- }
- return CryptoFileSystemProvider.checkDirStructureForVault(path, VAULTCONFIG_FILENAME, MASTERKEY_FILENAME) != DirStructure.UNRELATED;
- } catch (IOException e) {
- return false;
- }
- }
-
- private void addVault(Path pathToVault) {
- try {
- if (pathToVault.getFileName().toString().endsWith(CRYPTOMATOR_FILENAME_EXT)) {
- vaultListManager.add(pathToVault.getParent());
- } else {
- vaultListManager.add(pathToVault);
- }
- } catch (IOException e) {
- LOG.debug("Not a vault: {}", pathToVault);
- }
- }
-
- /* Getter/Setter */
-
- public BooleanProperty draggingOverProperty() {
- return draggingOver;
- }
-
- public boolean isDraggingOver() {
- return draggingOver.get();
- }
-
- public BooleanProperty draggingVaultOverProperty() {
- return draggingVaultOver;
- }
-
- public boolean isDraggingVaultOver() {
- return draggingVaultOver.get();
- }
}
diff --git a/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailUnlockedController.java b/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailUnlockedController.java
index 63d88a6a4..4bbfcce19 100644
--- a/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailUnlockedController.java
+++ b/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailUnlockedController.java
@@ -3,38 +3,99 @@ package org.cryptomator.ui.mainwindow;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
+import com.tobiasdiez.easybind.EasyBind;
import org.cryptomator.common.vaults.Vault;
+import org.cryptomator.integrations.revealpath.RevealFailedException;
+import org.cryptomator.integrations.revealpath.RevealPathService;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.VaultService;
import org.cryptomator.ui.fxapp.FxApplicationWindows;
import org.cryptomator.ui.stats.VaultStatisticsComponent;
+import org.cryptomator.ui.wrongfilealert.WrongFileAlertComponent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import javax.inject.Inject;
+import javafx.application.Platform;
+import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
+import javafx.beans.property.SimpleBooleanProperty;
import javafx.fxml.FXML;
+import javafx.scene.control.Button;
+import javafx.scene.input.Clipboard;
+import javafx.scene.input.DataFormat;
+import javafx.scene.input.DragEvent;
+import javafx.scene.input.TransferMode;
+import javafx.stage.FileChooser;
import javafx.stage.Stage;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.ResourceBundle;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
@MainWindowScoped
public class VaultDetailUnlockedController implements FxController {
+ private static final Logger LOG = LoggerFactory.getLogger(VaultDetailUnlockedController.class);
+ private static final String ACTIVE_CLASS = "active";
private final ReadOnlyObjectProperty vault;
private final FxApplicationWindows appWindows;
private final VaultService vaultService;
+ private final WrongFileAlertComponent.Builder wrongFileAlert;
private final Stage mainWindow;
+ private final ResourceBundle resourceBundle;
private final LoadingCache vaultStats;
private final VaultStatisticsComponent.Builder vaultStatsBuilder;
+ private final BooleanProperty draggingOver = new SimpleBooleanProperty();
+ private final BooleanProperty ciphertextPathsCopied = new SimpleBooleanProperty();
+
+ public Button dropZone;
@Inject
- public VaultDetailUnlockedController(ObjectProperty vault, FxApplicationWindows appWindows, VaultService vaultService, VaultStatisticsComponent.Builder vaultStatsBuilder, @MainWindow Stage mainWindow) {
+ public VaultDetailUnlockedController(ObjectProperty vault, FxApplicationWindows appWindows, VaultService vaultService, VaultStatisticsComponent.Builder vaultStatsBuilder, WrongFileAlertComponent.Builder wrongFileAlert, @MainWindow Stage mainWindow, ResourceBundle resourceBundle) {
this.vault = vault;
this.appWindows = appWindows;
this.vaultService = vaultService;
+ this.wrongFileAlert = wrongFileAlert;
this.mainWindow = mainWindow;
+ this.resourceBundle = resourceBundle;
this.vaultStats = CacheBuilder.newBuilder().weakValues().build(CacheLoader.from(this::buildVaultStats));
this.vaultStatsBuilder = vaultStatsBuilder;
}
+ public void initialize() {
+ dropZone.setOnDragEntered(this::handleDragEvent);
+ dropZone.setOnDragOver(this::handleDragEvent);
+ dropZone.setOnDragDropped(this::handleDragEvent);
+ dropZone.setOnDragExited(this::handleDragEvent);
+
+ EasyBind.includeWhen(dropZone.getStyleClass(), ACTIVE_CLASS, draggingOver);
+ }
+
+ private void handleDragEvent(DragEvent event) {
+ if (DragEvent.DRAG_OVER.equals(event.getEventType()) && event.getGestureSource() == null && event.getDragboard().hasFiles()) {
+ event.acceptTransferModes(TransferMode.LINK);
+ draggingOver.set(true);
+ } else if (DragEvent.DRAG_DROPPED.equals(event.getEventType()) && event.getGestureSource() == null && event.getDragboard().hasFiles()) {
+ List ciphertextPaths = event.getDragboard().getFiles().stream().map(File::toPath).map(this::getCiphertextPath).flatMap(Optional::stream).toList();
+ if (ciphertextPaths.isEmpty()) {
+ wrongFileAlert.build().showWrongFileAlertWindow();
+ } else {
+ revealOrCopyPaths(ciphertextPaths);
+ }
+ event.setDropCompleted(!ciphertextPaths.isEmpty());
+ event.consume();
+ } else if (DragEvent.DRAG_EXITED.equals(event.getEventType())) {
+ draggingOver.set(false);
+ }
+ }
+
private VaultStatisticsComponent buildVaultStats(Vault vault) {
return vaultStatsBuilder.vault(vault).build();
}
@@ -54,6 +115,76 @@ public class VaultDetailUnlockedController implements FxController {
vaultStats.getUnchecked(vault.get()).showVaultStatisticsWindow();
}
+ @FXML
+ public void chooseFileAndReveal() {
+ var fileChooser = new FileChooser();
+ fileChooser.setTitle(resourceBundle.getString("main.vaultDetail.filePickerTitle"));
+ fileChooser.setInitialDirectory(Path.of(vault.get().getAccessPoint()).toFile());
+ var cleartextFile = fileChooser.showOpenDialog(mainWindow);
+ if (cleartextFile != null) {
+ var ciphertextPaths = getCiphertextPath(cleartextFile.toPath()).stream().toList();
+ revealOrCopyPaths(ciphertextPaths);
+ }
+ }
+
+ private boolean startsWithVaultAccessPoint(Path path) {
+ return path.startsWith(vault.get().getAccessPoint());
+ }
+
+ private Optional getCiphertextPath(Path path) {
+ if (!startsWithVaultAccessPoint(path)) {
+ LOG.debug("Path does not start with access point of selected vault: {}", path);
+ return Optional.empty();
+ }
+ try {
+ var accessPoint = vault.get().getAccessPoint();
+ var cleartextPath = path.toString().substring(accessPoint.length());
+ if (!cleartextPath.startsWith("/")) {
+ cleartextPath = "/" + cleartextPath;
+ }
+ return Optional.of(vault.get().getCiphertextPath(cleartextPath));
+ } catch (IOException e) {
+ LOG.warn("Unable to get ciphertext path from path: {}", path);
+ return Optional.empty();
+ }
+ }
+
+ private void revealOrCopyPaths(List paths) {
+ if (!revealPaths(paths)) {
+ LOG.warn("No service provider to reveal files found.");
+ copyPathsToClipboard(paths);
+ }
+ }
+
+ /**
+ * Reveals the paths over the {@link RevealPathService} in the file system
+ *
+ * @param paths List of Paths to reveal
+ * @return true, if at least one service provider was present, false otherwise
+ */
+ private boolean revealPaths(List paths) {
+ return RevealPathService.get().findAny().map(s -> {
+ paths.forEach(path -> {
+ try {
+ s.reveal(path);
+ } catch (RevealFailedException e) {
+ LOG.error("Revealing ciphertext file failed.", e);
+ }
+ });
+ return true;
+ }).orElse(false);
+ }
+
+ private void copyPathsToClipboard(List paths) {
+ StringBuilder clipboardString = new StringBuilder();
+ paths.forEach(p -> clipboardString.append(p.toString()).append("\n"));
+ Clipboard.getSystemClipboard().setContent(Map.of(DataFormat.PLAIN_TEXT, clipboardString.toString()));
+ ciphertextPathsCopied.setValue(true);
+ CompletableFuture.delayedExecutor(2, TimeUnit.SECONDS, Platform::runLater).execute(() -> {
+ ciphertextPathsCopied.set(false);
+ });
+ }
+
/* Getter/Setter */
public ReadOnlyObjectProperty vaultProperty() {
@@ -64,4 +195,11 @@ public class VaultDetailUnlockedController implements FxController {
return vault.get();
}
+ public BooleanProperty ciphertextPathsCopiedProperty() {
+ return ciphertextPathsCopied;
+ }
+
+ public boolean isCiphertextPathsCopied() {
+ return ciphertextPathsCopied.get();
+ }
}
diff --git a/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java b/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java
index adb9a961b..f0aadfdfc 100644
--- a/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java
+++ b/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java
@@ -3,26 +3,43 @@ package org.cryptomator.ui.mainwindow;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultListManager;
+import org.cryptomator.cryptofs.CryptoFileSystemProvider;
+import org.cryptomator.cryptofs.DirStructure;
import org.cryptomator.ui.addvaultwizard.AddVaultWizardComponent;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.removevault.RemoveVaultComponent;
+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.value.ObservableValue;
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.DragEvent;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
+import javafx.scene.input.TransferMode;
+import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
import java.util.EnumSet;
+import java.util.Set;
+import java.util.stream.Collectors;
+import static org.cryptomator.common.Constants.CRYPTOMATOR_FILENAME_EXT;
+import static org.cryptomator.common.Constants.MASTERKEY_FILENAME;
+import static org.cryptomator.common.Constants.VAULTCONFIG_FILENAME;
import static org.cryptomator.common.vaults.VaultState.Value.ERROR;
import static org.cryptomator.common.vaults.VaultState.Value.LOCKED;
import static org.cryptomator.common.vaults.VaultState.Value.MISSING;
@@ -31,6 +48,7 @@ import static org.cryptomator.common.vaults.VaultState.Value.NEEDS_MIGRATION;
@MainWindowScoped
public class VaultListController implements FxController {
+ private static final Logger LOG = LoggerFactory.getLogger(VaultListController.class);
private final Stage mainWindow;
private final ObservableList vaults;
@@ -39,17 +57,21 @@ public class VaultListController implements FxController {
private final AddVaultWizardComponent.Builder addVaultWizard;
private final BooleanBinding emptyVaultList;
private final RemoveVaultComponent.Builder removeVaultDialogue;
+ private final VaultListManager vaultListManager;
+ private final BooleanProperty draggingVaultOver = new SimpleBooleanProperty();
public ListView vaultList;
+ public StackPane root;
@Inject
- VaultListController(@MainWindow Stage mainWindow, ObservableList vaults, ObjectProperty selectedVault, VaultListCellFactory cellFactory, AddVaultWizardComponent.Builder addVaultWizard, RemoveVaultComponent.Builder removeVaultDialogue) {
+ VaultListController(@MainWindow Stage mainWindow, ObservableList vaults, ObjectProperty selectedVault, VaultListCellFactory cellFactory, AddVaultWizardComponent.Builder addVaultWizard, RemoveVaultComponent.Builder removeVaultDialogue, VaultListManager vaultListManager) {
this.mainWindow = mainWindow;
this.vaults = vaults;
this.selectedVault = selectedVault;
this.cellFactory = cellFactory;
this.addVaultWizard = addVaultWizard;
this.removeVaultDialogue = removeVaultDialogue;
+ this.vaultListManager = vaultListManager;
this.emptyVaultList = Bindings.isEmpty(vaults);
@@ -100,6 +122,11 @@ public class VaultListController implements FxController {
keyEvent.consume();
}
});
+
+ root.setOnDragEntered(this::handleDragEvent);
+ root.setOnDragOver(this::handleDragEvent);
+ root.setOnDragDropped(this::handleDragEvent);
+ root.setOnDragExited(this::handleDragEvent);
}
private void deselect(MouseEvent released) {
@@ -128,6 +155,47 @@ public class VaultListController implements FxController {
}
}
+ private void handleDragEvent(DragEvent event) {
+ if (DragEvent.DRAG_OVER.equals(event.getEventType()) && event.getGestureSource() == null && event.getDragboard().hasFiles()) {
+ draggingVaultOver.set(event.getDragboard().getFiles().stream().map(File::toPath).anyMatch(this::containsVault));
+ if (draggingVaultOver.get()) {
+ event.acceptTransferModes(TransferMode.ANY);
+ }
+ } else if (DragEvent.DRAG_DROPPED.equals(event.getEventType()) && event.getGestureSource() == null && event.getDragboard().hasFiles()) {
+ Set vaultPaths = event.getDragboard().getFiles().stream().map(File::toPath).filter(this::containsVault).collect(Collectors.toSet());
+ if (!vaultPaths.isEmpty()) {
+ vaultPaths.forEach(this::addVault);
+ }
+ event.setDropCompleted(!vaultPaths.isEmpty());
+ event.consume();
+ } else if (DragEvent.DRAG_EXITED.equals(event.getEventType())) {
+ draggingVaultOver.set(false);
+ }
+ }
+
+ private boolean containsVault(Path path) {
+ try {
+ if (path.getFileName().toString().endsWith(CRYPTOMATOR_FILENAME_EXT)) {
+ path = path.getParent();
+ }
+ return CryptoFileSystemProvider.checkDirStructureForVault(path, VAULTCONFIG_FILENAME, MASTERKEY_FILENAME) != DirStructure.UNRELATED;
+ } catch (IOException e) {
+ return false;
+ }
+ }
+
+ private void addVault(Path pathToVault) {
+ try {
+ if (pathToVault.getFileName().toString().endsWith(CRYPTOMATOR_FILENAME_EXT)) {
+ vaultListManager.add(pathToVault.getParent());
+ } else {
+ vaultListManager.add(pathToVault);
+ }
+ } catch (IOException e) {
+ LOG.debug("Not a vault: {}", pathToVault);
+ }
+ }
+
// Getter and Setter
public BooleanBinding emptyVaultListProperty() {
@@ -138,4 +206,13 @@ public class VaultListController implements FxController {
return emptyVaultList.get();
}
+ public BooleanProperty draggingVaultOverProperty() {
+ return draggingVaultOver;
+ }
+
+ public boolean isDraggingVaultOver() {
+ return draggingVaultOver.get();
+ }
+
+
}
diff --git a/src/main/resources/css/dark_theme.css b/src/main/resources/css/dark_theme.css
index 86467bb1a..fe510d420 100644
--- a/src/main/resources/css/dark_theme.css
+++ b/src/main/resources/css/dark_theme.css
@@ -204,16 +204,6 @@
-fx-effect: dropshadow(three-pass-box, rgba(0, 0, 0, 0.8), 2, 0, 0, 0);
}
-.main-window .drag-n-drop-indicator {
- -fx-border-color: SECONDARY;
- -fx-border-width: 3px;
-}
-
-.main-window .drag-n-drop-indicator .drag-n-drop-header {
- -fx-background-color: SECONDARY;
- -fx-padding: 3px;
-}
-
/*******************************************************************************
* *
* TabPane *
@@ -884,3 +874,40 @@
-fx-fill: linear-gradient(to bottom, PRIMARY, transparent);
-fx-stroke: transparent;
}
+
+/*******************************************************************************
+ * *
+ * Drag and Drop *
+ * *
+ ******************************************************************************/
+
+.drag-n-drop-border {
+ -fx-border-color: SECONDARY;
+ -fx-border-width: 3px;
+}
+
+.button.drag-n-drop {
+ -fx-background-color: CONTROL_BG_NORMAL;
+ -fx-background-insets: 0;
+ -fx-padding: 1.4em 1em 1.4em 1em;
+ -fx-text-fill: TEXT_FILL_MUTED;
+ -fx-font-size: 0.8em;
+ -fx-border-color: CONTROL_BORDER_NORMAL;
+ -fx-border-radius: 4px;
+ -fx-border-style: dashed inside;
+ -fx-border-width: 1px;
+}
+
+.button.drag-n-drop:focused {
+ -fx-border-color: CONTROL_BORDER_FOCUSED;
+}
+
+.button.drag-n-drop:armed {
+ -fx-background-color: CONTROL_BG_ARMED;
+}
+
+.button.drag-n-drop.active {
+ -fx-border-color: SECONDARY;
+ -fx-border-style: solid inside;
+ -fx-border-width: 1px;
+}
diff --git a/src/main/resources/css/light_theme.css b/src/main/resources/css/light_theme.css
index ddc872eb2..4e47af6df 100644
--- a/src/main/resources/css/light_theme.css
+++ b/src/main/resources/css/light_theme.css
@@ -203,16 +203,6 @@
-fx-effect: dropshadow(three-pass-box, rgba(0, 0, 0, 0.8), 2, 0, 0, 0);
}
-.main-window .drag-n-drop-indicator {
- -fx-border-color: SECONDARY;
- -fx-border-width: 3px;
-}
-
-.main-window .drag-n-drop-indicator .drag-n-drop-header {
- -fx-background-color: SECONDARY;
- -fx-padding: 3px;
-}
-
/*******************************************************************************
* *
* TabPane *
@@ -883,3 +873,40 @@
-fx-fill: linear-gradient(to bottom, PRIMARY, transparent);
-fx-stroke: transparent;
}
+
+/*******************************************************************************
+ * *
+ * Drag and Drop *
+ * *
+ ******************************************************************************/
+
+.drag-n-drop-border {
+ -fx-border-color: SECONDARY;
+ -fx-border-width: 3px;
+}
+
+.button.drag-n-drop {
+ -fx-background-color: CONTROL_BG_NORMAL;
+ -fx-background-insets: 0;
+ -fx-padding: 1.4em 1em 1.4em 1em;
+ -fx-text-fill: TEXT_FILL_MUTED;
+ -fx-font-size: 0.8em;
+ -fx-border-color: CONTROL_BORDER_NORMAL;
+ -fx-border-radius: 4px;
+ -fx-border-style: dashed inside;
+ -fx-border-width: 1px;
+}
+
+.button.drag-n-drop:focused {
+ -fx-border-color: CONTROL_BORDER_FOCUSED;
+}
+
+.button.drag-n-drop:armed {
+ -fx-background-color: CONTROL_BG_ARMED;
+}
+
+.button.drag-n-drop.active {
+ -fx-border-color: SECONDARY;
+ -fx-border-style: solid inside;
+ -fx-border-width: 1px;
+}
diff --git a/src/main/resources/fxml/main_window.fxml b/src/main/resources/fxml/main_window.fxml
index 91e7512a4..2796455d3 100644
--- a/src/main/resources/fxml/main_window.fxml
+++ b/src/main/resources/fxml/main_window.fxml
@@ -1,10 +1,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
diff --git a/src/main/resources/fxml/vault_detail_unlocked.fxml b/src/main/resources/fxml/vault_detail_unlocked.fxml
index 29b11ed17..185bbefa8 100644
--- a/src/main/resources/fxml/vault_detail_unlocked.fxml
+++ b/src/main/resources/fxml/vault_detail_unlocked.fxml
@@ -35,7 +35,23 @@
-
+
+
+
+
+
+