diff --git a/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailUnlockedController.java b/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailUnlockedController.java index 6a44cb74a..af8bf2aec 100644 --- a/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailUnlockedController.java +++ b/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailUnlockedController.java @@ -6,14 +6,13 @@ import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.tobiasdiez.easybind.EasyBind; import org.apache.commons.lang3.SystemUtils; +import org.cryptomator.common.Nullable; import org.cryptomator.common.vaults.Vault; import org.cryptomator.integrations.mount.Mountpoint; import org.cryptomator.integrations.revealpath.RevealFailedException; import org.cryptomator.integrations.revealpath.RevealPathService; import org.cryptomator.ui.common.FxController; -import org.cryptomator.ui.common.StageFactory; import org.cryptomator.ui.common.VaultService; -import org.cryptomator.ui.dialogs.SimpleDialog; import org.cryptomator.ui.fxapp.FxApplicationWindows; import org.cryptomator.ui.stats.VaultStatisticsComponent; import org.cryptomator.ui.wrongfilealert.WrongFileAlertComponent; @@ -37,17 +36,19 @@ import javafx.scene.input.DataFormat; import javafx.scene.input.DragEvent; import javafx.scene.input.TransferMode; import javafx.stage.FileChooser; -import javafx.stage.Popup; 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.Objects; import java.util.Optional; import java.util.ResourceBundle; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; +import java.util.function.Function; @MainWindowScoped public class VaultDetailUnlockedController implements FxController { @@ -67,11 +68,14 @@ public class VaultDetailUnlockedController implements FxController { private final ObservableValue accessibleViaPath; private final ObservableValue accessibleViaUri; private final ObservableValue mountPoint; - private final BooleanProperty draggingOver = new SimpleBooleanProperty(); + private final BooleanProperty draggingOverLocateEncrypted = new SimpleBooleanProperty(); + private final BooleanProperty draggingOverDecryptName = new SimpleBooleanProperty(); private final BooleanProperty ciphertextPathsCopied = new SimpleBooleanProperty(); - //FXML - public Button dropZone; + @FXML + public Button revealEncryptedDropZone; + @FXML + public Button decryptNameDropZone; @Inject public VaultDetailUnlockedController(ObjectProperty vault, FxApplicationWindows appWindows, VaultService vaultService, VaultStatisticsComponent.Builder vaultStatsBuilder, WrongFileAlertComponent.Builder wrongFileAlert, @MainWindow Stage mainWindow, Optional revealPathService, ResourceBundle resourceBundle) { @@ -97,93 +101,92 @@ public class VaultDetailUnlockedController implements FxController { } public void initialize() { - dropZone.setOnDragEntered(this::handleDragEvent); - dropZone.setOnDragOver(this::handleDragEvent); - dropZone.setOnDragDropped(this::handleDragEvent); - dropZone.setOnDragExited(this::handleDragEvent); + revealEncryptedDropZone.setOnDragOver(e -> handleDragOver(e, draggingOverLocateEncrypted)); + revealEncryptedDropZone.setOnDragDropped(e -> handleDragDropped(e, this::getCiphertextPath, this::revealOrCopyPaths)); + revealEncryptedDropZone.setOnDragExited(_ -> draggingOverLocateEncrypted.setValue(false)); - EasyBind.includeWhen(dropZone.getStyleClass(), ACTIVE_CLASS, draggingOver); + decryptNameDropZone.setOnDragOver(e -> handleDragOver(e, draggingOverDecryptName)); + decryptNameDropZone.setOnDragDropped(e -> handleDragDropped(e, this::getCleartextName, this::doSomethingWithFileNames)); + decryptNameDropZone.setOnDragExited(_ -> draggingOverDecryptName.setValue(false)); + + EasyBind.includeWhen(revealEncryptedDropZone.getStyleClass(), ACTIVE_CLASS, draggingOverLocateEncrypted); + EasyBind.includeWhen(decryptNameDropZone.getStyleClass(), ACTIVE_CLASS, draggingOverDecryptName); } - private void handleDragEvent(DragEvent event) { - if (DragEvent.DRAG_OVER.equals(event.getEventType()) && event.getGestureSource() == null && event.getDragboard().hasFiles()) { - if(SystemUtils.IS_OS_WINDOWS || SystemUtils.IS_OS_MAC) { + private void handleDragOver(DragEvent event, BooleanProperty prop) { + if (event.getGestureSource() == null && event.getDragboard().hasFiles()) { + if (SystemUtils.IS_OS_WINDOWS || SystemUtils.IS_OS_MAC) { event.acceptTransferModes(TransferMode.LINK); } else { event.acceptTransferModes(TransferMode.ANY); } - 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(); - //TODO: differ between encrypted and decrypted files - 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); + prop.set(true); } } - private VaultStatisticsComponent buildVaultStats(Vault vault) { - return vaultStatsBuilder.vault(vault).build(); + //TODO: split in two dedicated Methods + private void handleDragDropped(DragEvent event, Function computation, Consumer> positiveAction) { + if (event.getGestureSource() == null && event.getDragboard().hasFiles()) { + List objects = event.getDragboard().getFiles().stream().map(File::toPath).map(computation).filter(Objects::nonNull).toList(); + if (objects.isEmpty()) { + wrongFileAlert.build().showWrongFileAlertWindow(); + } else { + positiveAction.accept(objects); + } + event.setDropCompleted(!objects.isEmpty()); + event.consume(); + } } @FXML - public void revealAccessLocation() { - vaultService.reveal(vault.get()); - } - - @FXML - public void copyMountUri() { - ClipboardContent clipboardContent = new ClipboardContent(); - clipboardContent.putString(mountPoint.getValue()); - Clipboard.getSystemClipboard().setContent(clipboardContent); - } - - @FXML - public void lock() { - appWindows.startLockWorkflow(vault.get(), mainWindow); - } - - @FXML - public void showVaultStatistics() { - vaultStats.getUnchecked(vault.get()).showVaultStatisticsWindow(); - } - - @FXML - public void chooseFileAndReveal() { + public void chooseDecryptedFileAndReveal() { Preconditions.checkState(accessibleViaPath.getValue()); var fileChooser = new FileChooser(); - fileChooser.setTitle(resourceBundle.getString("main.vaultDetail.decryptedFilePickerTitle")); + fileChooser.setTitle(resourceBundle.getString("main.vaultDetail.locateEncrypted.filePickerTitle")); fileChooser.setInitialDirectory(Path.of(mountPoint.getValue()).toFile()); var cleartextFile = fileChooser.showOpenDialog(mainWindow); if (cleartextFile != null) { - var ciphertextPaths = getCiphertextPath(cleartextFile.toPath()).stream().toList(); - revealOrCopyPaths(ciphertextPaths); + var ciphertextPath = getCiphertextPath(cleartextFile.toPath()); + if (ciphertextPath != null) { + revealOrCopyPaths(List.of(ciphertextPath)); + } } } @FXML public void chooseEncryptedFileAndGetName() { var fileChooser = new FileChooser(); - fileChooser.setTitle(resourceBundle.getString("main.vaultDetail.encryptedFilePickerTitle")); + fileChooser.setTitle(resourceBundle.getString("main.vaultDetail.decryptName.filePickerTitle")); fileChooser.setInitialDirectory(vault.getValue().getPath().toFile()); var ciphertextNode = fileChooser.showOpenDialog(mainWindow); + if (ciphertextNode != null) { + var nodeName = getCleartextName(ciphertextNode.toPath()); + Alert dialog; + if (nodeName != null) { + dialog = new Alert(Alert.AlertType.INFORMATION, "The answer is: %s".formatted(nodeName), ButtonType.OK); + } else { + dialog = new Alert(Alert.AlertType.ERROR, "Unable to get Name", ButtonType.OK); + } + dialog.showAndWait(); + } + } + + private void doSomethingWithFileNames(List names) { + Clipboard.getSystemClipboard().setContent(Map.of(DataFormat.PLAIN_TEXT, String.join(", ", names))); + ciphertextPathsCopied.setValue(true); + CompletableFuture.delayedExecutor(2, TimeUnit.SECONDS, Platform::runLater).execute(() -> { + ciphertextPathsCopied.set(false); + }); + } + + @Nullable + private String getCleartextName(Path ciphertextNode) { try { - var nodeName = vault.get().getCleartextName(ciphertextNode.toPath()); - var alert = new Alert(Alert.AlertType.INFORMATION, "The answer is: %s".formatted(nodeName), ButtonType.OK); - alert.showAndWait(); - //.filter(response -> response == ButtonType.OK) - //.ifPresent(response -> formatSystem()); - } catch (Exception e) { + return vault.get().getCleartextName(ciphertextNode); + } catch (IOException e) { LOG.warn("Failed to decrypt filename for {}", ciphertextNode, e); - var alert = new Alert(Alert.AlertType.ERROR, "The exception is: %s".formatted(e.getClass()), ButtonType.OK); - alert.showAndWait(); + return null; } } @@ -191,16 +194,17 @@ public class VaultDetailUnlockedController implements FxController { return path.startsWith(Path.of(mountPoint.getValue())); } - private Optional getCiphertextPath(Path path) { + @Nullable + private Path getCiphertextPath(Path path) { if (!startsWithVaultAccessPoint(path)) { - LOG.debug("Path does not start with access point of selected vault: {}", path); - return Optional.empty(); + LOG.debug("Path does not start with mount point of selected vault: {}", path); + return null; } try { - return Optional.of(vault.get().getCiphertextPath(path)); + return vault.get().getCiphertextPath(path); } catch (IOException e) { LOG.warn("Unable to get ciphertext path from path: {}", path, e); - return Optional.empty(); + return null; } } @@ -232,6 +236,32 @@ public class VaultDetailUnlockedController implements FxController { }); } + private VaultStatisticsComponent buildVaultStats(Vault vault) { + return vaultStatsBuilder.vault(vault).build(); + } + + @FXML + public void revealAccessLocation() { + vaultService.reveal(vault.get()); + } + + @FXML + public void copyMountUri() { + ClipboardContent clipboardContent = new ClipboardContent(); + clipboardContent.putString(mountPoint.getValue()); + Clipboard.getSystemClipboard().setContent(clipboardContent); + } + + @FXML + public void lock() { + appWindows.startLockWorkflow(vault.get(), mainWindow); + } + + @FXML + public void showVaultStatistics() { + vaultStats.getUnchecked(vault.get()).showVaultStatisticsWindow(); + } + /* Getter/Setter */ public ReadOnlyObjectProperty vaultProperty() { diff --git a/src/main/resources/css/courierprime_regular.ttf b/src/main/resources/css/courierprime_regular.ttf deleted file mode 100644 index 4af1ff54c..000000000 Binary files a/src/main/resources/css/courierprime_regular.ttf and /dev/null differ diff --git a/src/main/resources/css/firacode_regular.ttf b/src/main/resources/css/firacode_regular.ttf new file mode 100644 index 000000000..b8a44d2db Binary files /dev/null and b/src/main/resources/css/firacode_regular.ttf differ diff --git a/src/main/resources/css/light_theme.css b/src/main/resources/css/light_theme.css index fd682ad26..ea82411f4 100644 --- a/src/main/resources/css/light_theme.css +++ b/src/main/resources/css/light_theme.css @@ -17,7 +17,8 @@ } @font-face { - src: url('courierprime_regular.ttf'); + src: url('firacode_regular.ttf'); +} } /******************************************************************************* @@ -128,6 +129,13 @@ -fx-fill: TEXT_FILL; } +.cryptic-text { + -fx-background-color: MAIN_BG; + -fx-text-fill: TEXT_FILL; + -fx-font-family: 'Fira Code'; + -fx-font-size: 1.1em; +} + /******************************************************************************* * * * Glyph Icons * @@ -929,13 +937,6 @@ -fx-border-width: 1px; } -.cryptic-text { - -fx-background-color: MAIN_BG; - -fx-text-fill: TEXT_FILL; - -fx-font-family: 'Courier Prime'; - -fx-font-size: 1.1em; -} - .button.drag-n-drop:focused { -fx-border-color: CONTROL_BORDER_FOCUSED; } diff --git a/src/main/resources/fxml/vault_detail_unlocked.fxml b/src/main/resources/fxml/vault_detail_unlocked.fxml index f0cba7cf3..fabac406c 100644 --- a/src/main/resources/fxml/vault_detail_unlocked.fxml +++ b/src/main/resources/fxml/vault_detail_unlocked.fxml @@ -50,19 +50,15 @@ - - -