From f5bd23de518455dc73c4c163cf90860d3a4efffc Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Tue, 2 Sep 2025 09:58:52 +0200 Subject: [PATCH 01/12] test impl --- pom.xml | 2 +- src/main/java/org/cryptomator/common/EventMap.java | 2 ++ .../java/org/cryptomator/common/vaults/Vault.java | 1 + .../event/FileSystemEventAggregator.java | 2 ++ .../ui/eventview/EventListCellController.java | 14 ++++++++++++++ 5 files changed, 20 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index caba8e342..7660669e2 100644 --- a/pom.xml +++ b/pom.xml @@ -33,7 +33,7 @@ org.ow2.asm,org.apache.jackrabbit,org.apache.httpcomponents - 2.9.0 + 2.10.0-SNAPSHOT 1.6.0 1.5.0 1.4.0 diff --git a/src/main/java/org/cryptomator/common/EventMap.java b/src/main/java/org/cryptomator/common/EventMap.java index 2e8dbf035..42e2f7dba 100644 --- a/src/main/java/org/cryptomator/common/EventMap.java +++ b/src/main/java/org/cryptomator/common/EventMap.java @@ -5,6 +5,7 @@ import org.cryptomator.cryptofs.event.BrokenFileNodeEvent; import org.cryptomator.cryptofs.event.ConflictResolutionFailedEvent; import org.cryptomator.cryptofs.event.ConflictResolvedEvent; import org.cryptomator.cryptofs.event.DecryptionFailedEvent; +import org.cryptomator.cryptofs.event.FileIsInUseEvent; import org.cryptomator.cryptofs.event.FilesystemEvent; import org.cryptomator.event.VaultEvent; import org.jetbrains.annotations.NotNull; @@ -154,6 +155,7 @@ public class EventMap implements ObservableMap { case ConflictResolutionFailedEvent(_, _, Path conflictingCiphertext, _) -> conflictingCiphertext; case BrokenDirFileEvent(_, Path ciphertext) -> ciphertext; case BrokenFileNodeEvent(_, _, Path ciphertext) -> ciphertext; + case FileIsInUseEvent(_,_, Path ciphertext,_) -> ciphertext; }; return new EventKey(p, e.getClass()); } diff --git a/src/main/java/org/cryptomator/common/vaults/Vault.java b/src/main/java/org/cryptomator/common/vaults/Vault.java index 2e1ae4bba..5fb4400d9 100644 --- a/src/main/java/org/cryptomator/common/vaults/Vault.java +++ b/src/main/java/org/cryptomator/common/vaults/Vault.java @@ -151,6 +151,7 @@ public class Vault { .withMaxCleartextNameLength(vaultSettings.maxCleartextFilenameLength.get()) // .withVaultConfigFilename(Constants.VAULTCONFIG_FILENAME) // .withFilesystemEventConsumer(this::consumeVaultEvent) // + .withOwner("cryptobot") .build(); return CryptoFileSystemProvider.newFileSystem(getPath(), fsProps); } diff --git a/src/main/java/org/cryptomator/event/FileSystemEventAggregator.java b/src/main/java/org/cryptomator/event/FileSystemEventAggregator.java index c871436fd..39e04ed83 100644 --- a/src/main/java/org/cryptomator/event/FileSystemEventAggregator.java +++ b/src/main/java/org/cryptomator/event/FileSystemEventAggregator.java @@ -6,6 +6,7 @@ import org.cryptomator.cryptofs.event.BrokenFileNodeEvent; import org.cryptomator.cryptofs.event.ConflictResolutionFailedEvent; import org.cryptomator.cryptofs.event.ConflictResolvedEvent; import org.cryptomator.cryptofs.event.DecryptionFailedEvent; +import org.cryptomator.cryptofs.event.FileIsInUseEvent; import org.cryptomator.cryptofs.event.FilesystemEvent; import javax.inject.Inject; @@ -101,6 +102,7 @@ public class FileSystemEventAggregator { case ConflictResolutionFailedEvent(_, _, Path conflictingCiphertext, _) -> conflictingCiphertext; case BrokenDirFileEvent(_, Path ciphertext) -> ciphertext; case BrokenFileNodeEvent(_, _, Path ciphertext) -> ciphertext; + case FileIsInUseEvent(_, _, Path ciphertext, _) -> ciphertext; }; return new FSEventBucket(v, p, event.getClass()); } diff --git a/src/main/java/org/cryptomator/ui/eventview/EventListCellController.java b/src/main/java/org/cryptomator/ui/eventview/EventListCellController.java index 3157f9f40..49b0657a4 100644 --- a/src/main/java/org/cryptomator/ui/eventview/EventListCellController.java +++ b/src/main/java/org/cryptomator/ui/eventview/EventListCellController.java @@ -1,5 +1,6 @@ package org.cryptomator.ui.eventview; +import org.cryptomator.cryptofs.event.FileIsInUseEvent; import org.cryptomator.event.FSEventBucket; import org.cryptomator.event.FSEventBucketContent; import org.cryptomator.event.FileSystemEventAggregator; @@ -124,6 +125,19 @@ public class EventListCellController implements FxController { case DecryptionFailedEvent fse -> this.adjustToDecryptionFailedEvent(fse); case BrokenDirFileEvent fse -> this.adjustToBrokenDirFileEvent(fse); case BrokenFileNodeEvent fse -> this.adjustToBrokenFileNodeEvent(fse); + case FileIsInUseEvent fse -> this.adjustToFileInUseEvent(fse); + } + } + + private void adjustToFileInUseEvent(FileIsInUseEvent fse) { + eventIcon.setValue(FontAwesome5Icon.TIMES); + //eventMessage.setValue(resourceBundle.getString("eventView.entry.brokenFileNode.message")); + eventMessage.setValue("File is in use"); + eventDescription.setValue(fse.ciphertext().getFileName().toString()); + if (revealService != null) { + addAction("Show encrypted Path", () -> reveal(revealService, fse.ciphertext())); + } else { + addAction("Copy encrypted Path", () -> copyToClipboard(fse.ciphertext().toString())); } } From f3d4494d9144972384db9274ca688bb0aeb430af Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Wed, 15 Oct 2025 17:20:56 +0200 Subject: [PATCH 02/12] [skip ci] Adjust event view to new API --- .../ui/eventview/EventListCellController.java | 45 +++++++++++-------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/cryptomator/ui/eventview/EventListCellController.java b/src/main/java/org/cryptomator/ui/eventview/EventListCellController.java index 49b0657a4..5eeda0717 100644 --- a/src/main/java/org/cryptomator/ui/eventview/EventListCellController.java +++ b/src/main/java/org/cryptomator/ui/eventview/EventListCellController.java @@ -116,7 +116,7 @@ public class EventListCellController implements FxController { eventActionsMenu.hide(); eventActionsMenu.getItems().clear(); eventTooltip.setText(item.getKey().vault().getDisplayName()); - addAction("generic.action.dismiss", () -> { + addLocalizedAction("generic.action.dismiss", () -> { fileSystemEventAggregator.remove(item.getKey()); }); switch (item.getValue().mostRecentEvent()) { @@ -131,14 +131,16 @@ public class EventListCellController implements FxController { private void adjustToFileInUseEvent(FileIsInUseEvent fse) { eventIcon.setValue(FontAwesome5Icon.TIMES); - //eventMessage.setValue(resourceBundle.getString("eventView.entry.brokenFileNode.message")); - eventMessage.setValue("File is in use"); - eventDescription.setValue(fse.ciphertext().getFileName().toString()); + eventMessage.setValue("File is in use by " + fse.owner()); + eventDescription.setValue(fse.cleartext().getFileName().toString()); if (revealService != null) { + addAction("Show decrypted file", () -> reveal(revealService, convertVaultPathToSystemPath(fse.cleartext()))); addAction("Show encrypted Path", () -> reveal(revealService, fse.ciphertext())); } else { + addAction("Copy decrypted Path", () -> copyToClipboard(convertVaultPathToSystemPath(fse.cleartext()).toString())); addAction("Copy encrypted Path", () -> copyToClipboard(fse.ciphertext().toString())); } + addAction("Discard use status for 2minutes", fse.ignoreMethod()); } @@ -147,11 +149,11 @@ public class EventListCellController implements FxController { eventMessage.setValue(resourceBundle.getString("eventView.entry.brokenFileNode.message")); eventDescription.setValue(bfe.ciphertextPath().getFileName().toString()); if (revealService != null) { - addAction("eventView.entry.brokenFileNode.showEncrypted", () -> reveal(revealService, bfe.ciphertextPath())); + addLocalizedAction("eventView.entry.brokenFileNode.showEncrypted", () -> reveal(revealService, bfe.ciphertextPath())); } else { - addAction("eventView.entry.brokenFileNode.copyEncrypted", () -> copyToClipboard(bfe.ciphertextPath().toString())); + addLocalizedAction("eventView.entry.brokenFileNode.copyEncrypted", () -> copyToClipboard(bfe.ciphertextPath().toString())); } - addAction("eventView.entry.brokenFileNode.copyDecrypted", () -> copyToClipboard(convertVaultPathToSystemPath(bfe.cleartextPath()).toString())); + addLocalizedAction("eventView.entry.brokenFileNode.copyDecrypted", () -> copyToClipboard(convertVaultPathToSystemPath(bfe.cleartextPath()).toString())); } private void adjustToConflictResolvedEvent(ConflictResolvedEvent cre) { @@ -159,9 +161,9 @@ public class EventListCellController implements FxController { eventMessage.setValue(resourceBundle.getString("eventView.entry.conflictResolved.message")); eventDescription.setValue(cre.resolvedCiphertextPath().getFileName().toString()); if (revealService != null) { - addAction("eventView.entry.conflictResolved.showDecrypted", () -> reveal(revealService, convertVaultPathToSystemPath(cre.resolvedCleartextPath()))); + addLocalizedAction("eventView.entry.conflictResolved.showDecrypted", () -> reveal(revealService, convertVaultPathToSystemPath(cre.resolvedCleartextPath()))); } else { - addAction("eventView.entry.conflictResolved.copyDecrypted", () -> copyToClipboard(convertVaultPathToSystemPath(cre.resolvedCleartextPath()).toString())); + addLocalizedAction("eventView.entry.conflictResolved.copyDecrypted", () -> copyToClipboard(convertVaultPathToSystemPath(cre.resolvedCleartextPath()).toString())); } } @@ -170,11 +172,11 @@ public class EventListCellController implements FxController { eventMessage.setValue(resourceBundle.getString("eventView.entry.conflict.message")); eventDescription.setValue(cfe.conflictingCiphertextPath().getFileName().toString()); if (revealService != null) { - addAction("eventView.entry.conflict.showDecrypted", () -> reveal(revealService, convertVaultPathToSystemPath(cfe.canonicalCleartextPath()))); - addAction("eventView.entry.conflict.showEncrypted", () -> reveal(revealService, cfe.conflictingCiphertextPath())); + addLocalizedAction("eventView.entry.conflict.showDecrypted", () -> reveal(revealService, convertVaultPathToSystemPath(cfe.canonicalCleartextPath()))); + addLocalizedAction("eventView.entry.conflict.showEncrypted", () -> reveal(revealService, cfe.conflictingCiphertextPath())); } else { - addAction("eventView.entry.conflict.copyDecrypted", () -> copyToClipboard(convertVaultPathToSystemPath(cfe.canonicalCleartextPath()).toString())); - addAction("eventView.entry.conflict.copyEncrypted", () -> copyToClipboard(cfe.conflictingCiphertextPath().toString())); + addLocalizedAction("eventView.entry.conflict.copyDecrypted", () -> copyToClipboard(convertVaultPathToSystemPath(cfe.canonicalCleartextPath()).toString())); + addLocalizedAction("eventView.entry.conflict.copyEncrypted", () -> copyToClipboard(cfe.conflictingCiphertextPath().toString())); } } @@ -183,9 +185,9 @@ public class EventListCellController implements FxController { eventMessage.setValue(resourceBundle.getString("eventView.entry.decryptionFailed.message")); eventDescription.setValue(dfe.ciphertextPath().getFileName().toString()); if (revealService != null) { - addAction("eventView.entry.decryptionFailed.showEncrypted", () -> reveal(revealService, dfe.ciphertextPath())); + addLocalizedAction("eventView.entry.decryptionFailed.showEncrypted", () -> reveal(revealService, dfe.ciphertextPath())); } else { - addAction("eventView.entry.decryptionFailed.copyEncrypted", () -> copyToClipboard(dfe.ciphertextPath().toString())); + addLocalizedAction("eventView.entry.decryptionFailed.copyEncrypted", () -> copyToClipboard(dfe.ciphertextPath().toString())); } } @@ -194,14 +196,19 @@ public class EventListCellController implements FxController { eventMessage.setValue(resourceBundle.getString("eventView.entry.brokenDirFile.message")); eventDescription.setValue(bde.ciphertextPath().getParent().getFileName().toString()); if (revealService != null) { - addAction("eventView.entry.brokenDirFile.showEncrypted", () -> reveal(revealService, bde.ciphertextPath())); + addLocalizedAction("eventView.entry.brokenDirFile.showEncrypted", () -> reveal(revealService, bde.ciphertextPath())); } else { - addAction("eventView.entry.brokenDirFile.copyEncrypted", () -> copyToClipboard(bde.ciphertextPath().toString())); + addLocalizedAction("eventView.entry.brokenDirFile.copyEncrypted", () -> copyToClipboard(bde.ciphertextPath().toString())); } } - private void addAction(String localizationKey, Runnable action) { - var entry = new MenuItem(resourceBundle.getString(localizationKey)); + private void addLocalizedAction(String localizationKey, Runnable action) { + var entryText = resourceBundle.getString(localizationKey); + addAction(entryText, action); + } + + private void addAction(String entryText, Runnable action) { + var entry = new MenuItem(entryText); entry.getStyleClass().addLast("dropdown-button-context-menu-item"); entry.setOnAction(_ -> action.run()); eventActionsMenu.getItems().addLast(entry); From e1ff552f08586b2800126fe700a82ffb8d440984 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Wed, 15 Oct 2025 17:27:12 +0200 Subject: [PATCH 03/12] [skip ci] pick a distinguishable name for fs owner --- src/main/java/org/cryptomator/common/vaults/Vault.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/cryptomator/common/vaults/Vault.java b/src/main/java/org/cryptomator/common/vaults/Vault.java index 5fb4400d9..7b1267df8 100644 --- a/src/main/java/org/cryptomator/common/vaults/Vault.java +++ b/src/main/java/org/cryptomator/common/vaults/Vault.java @@ -151,7 +151,7 @@ public class Vault { .withMaxCleartextNameLength(vaultSettings.maxCleartextFilenameLength.get()) // .withVaultConfigFilename(Constants.VAULTCONFIG_FILENAME) // .withFilesystemEventConsumer(this::consumeVaultEvent) // - .withOwner("cryptobot") + .withOwner(System.getProperty("user.name")) .build(); return CryptoFileSystemProvider.newFileSystem(getPath(), fsProps); } From 18300ee67fd8e96411c331ba3c30c4c426a8daa2 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Tue, 21 Oct 2025 15:36:30 +0200 Subject: [PATCH 04/12] [skip ci] adjust to changed API --- .../ui/eventview/EventListCellController.java | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/cryptomator/ui/eventview/EventListCellController.java b/src/main/java/org/cryptomator/ui/eventview/EventListCellController.java index 5eeda0717..70cad7093 100644 --- a/src/main/java/org/cryptomator/ui/eventview/EventListCellController.java +++ b/src/main/java/org/cryptomator/ui/eventview/EventListCellController.java @@ -132,13 +132,14 @@ public class EventListCellController implements FxController { private void adjustToFileInUseEvent(FileIsInUseEvent fse) { eventIcon.setValue(FontAwesome5Icon.TIMES); eventMessage.setValue("File is in use by " + fse.owner()); - eventDescription.setValue(fse.cleartext().getFileName().toString()); + var indexFileName = fse.cleartextPath().lastIndexOf("/"); + eventDescription.setValue(fse.cleartextPath().substring(indexFileName + 1)); if (revealService != null) { - addAction("Show decrypted file", () -> reveal(revealService, convertVaultPathToSystemPath(fse.cleartext()))); - addAction("Show encrypted Path", () -> reveal(revealService, fse.ciphertext())); + addAction("Show decrypted file", () -> reveal(revealService, convertVaultPathToSystemPath(fse.cleartextPath()))); + addAction("Show encrypted Path", () -> reveal(revealService, fse.ciphertextPath())); } else { - addAction("Copy decrypted Path", () -> copyToClipboard(convertVaultPathToSystemPath(fse.cleartext()).toString())); - addAction("Copy encrypted Path", () -> copyToClipboard(fse.ciphertext().toString())); + addAction("Copy decrypted Path", () -> copyToClipboard(convertVaultPathToSystemPath(fse.cleartextPath()).toString())); + addAction("Copy encrypted Path", () -> copyToClipboard(fse.ciphertextPath().toString())); } addAction("Discard use status for 2minutes", fse.ignoreMethod()); } @@ -255,18 +256,14 @@ public class EventListCellController implements FxController { } } - private Path convertVaultPathToSystemPath(Path p) { - if (!(p instanceof CryptoPath)) { - throw new IllegalArgumentException("Path " + p + " is not a vault path"); - } + private Path convertVaultPathToSystemPath(String vaultInternalPath) { var v = eventEntry.getValue().getKey().vault(); if (!v.isUnlocked()) { return Path.of(System.getProperty("user.home")); } var mountUri = v.getMountPoint().uri(); - var internalPath = p.toString().substring(1); - return Path.of(mountUri.getPath().concat(internalPath).substring(1)); + return Path.of(mountUri.getPath().concat(vaultInternalPath.substring(1)).substring(1)); } private void reveal(RevealPathService s, Path p) { From cee22e34db762f87caa2f8f976cc86662f181e81 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Thu, 30 Oct 2025 11:09:44 +0100 Subject: [PATCH 05/12] adjust display text --- .../org/cryptomator/ui/eventview/EventListCellController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/cryptomator/ui/eventview/EventListCellController.java b/src/main/java/org/cryptomator/ui/eventview/EventListCellController.java index 70cad7093..4c195db10 100644 --- a/src/main/java/org/cryptomator/ui/eventview/EventListCellController.java +++ b/src/main/java/org/cryptomator/ui/eventview/EventListCellController.java @@ -141,7 +141,7 @@ public class EventListCellController implements FxController { addAction("Copy decrypted Path", () -> copyToClipboard(convertVaultPathToSystemPath(fse.cleartextPath()).toString())); addAction("Copy encrypted Path", () -> copyToClipboard(fse.ciphertextPath().toString())); } - addAction("Discard use status for 2minutes", fse.ignoreMethod()); + addAction("Ignore in use status ", fse.ignoreMethod()); } From 7f4776a995872b7939f0242f7fe060658281d67a Mon Sep 17 00:00:00 2001 From: Tamara Cook Date: Sun, 23 Nov 2025 19:26:55 +0100 Subject: [PATCH 06/12] Make buttons clickable by any input device --- src/main/resources/fxml/vault_list.fxml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/resources/fxml/vault_list.fxml b/src/main/resources/fxml/vault_list.fxml index e21237a43..a7a622205 100644 --- a/src/main/resources/fxml/vault_list.fxml +++ b/src/main/resources/fxml/vault_list.fxml @@ -38,14 +38,14 @@ - - - diff --git a/src/main/resources/i18n/strings.properties b/src/main/resources/i18n/strings.properties index 66f473248..a0b287cec 100644 --- a/src/main/resources/i18n/strings.properties +++ b/src/main/resources/i18n/strings.properties @@ -400,7 +400,9 @@ main.vaultlist.contextMenu.share=Share… main.vaultlist.addVaultBtn.menuItemNew=Create New Vault… main.vaultlist.addVaultBtn.menuItemExisting=Open Existing Vault… main.vaultlist.addVaultBtn.menuItemRecover=Recover Existing Vault… -main.vaultlist.showEventsButton.tooltip=Open event view +main.vaultlist.addVaultButton.tooltip=Add Vault +main.vaultlist.showEventsButton.tooltip=Open Event View +main.vaultlist.showPreferencesButton.tooltip=Show Preferences ##Notificaition main.notification.updateAvailable=Update is available. main.notification.support=Support Cryptomator. From 7fe90492662fb1c9089c60e07e622e51d5152b18 Mon Sep 17 00:00:00 2001 From: Tobias Hagemann Date: Mon, 1 Dec 2025 22:06:57 +0100 Subject: [PATCH 08/12] Improve accessibility for icon-only controls and input labels (#4064) --- .../resources/fxml/addvault_new_expert_settings.fxml | 2 +- src/main/resources/fxml/decryptnames.fxml | 4 ++-- src/main/resources/fxml/eventview.fxml | 2 +- src/main/resources/fxml/eventview_cell.fxml | 6 +++++- src/main/resources/fxml/preferences_contribute.fxml | 6 +++++- src/main/resources/fxml/preferences_interface.fxml | 4 ++-- src/main/resources/fxml/preferences_volume.fxml | 6 +++--- .../resources/fxml/recoverykey_expert_settings.fxml | 2 +- src/main/resources/fxml/recoverykey_validate.fxml | 2 +- src/main/resources/fxml/share_vault.fxml | 2 +- src/main/resources/fxml/vault_detail_unlocked.fxml | 10 ++++++++-- src/main/resources/fxml/vault_options_general.fxml | 4 ++-- src/main/resources/fxml/vault_options_mount.fxml | 8 ++++---- src/main/resources/i18n/strings.properties | 2 ++ 14 files changed, 38 insertions(+), 22 deletions(-) diff --git a/src/main/resources/fxml/addvault_new_expert_settings.fxml b/src/main/resources/fxml/addvault_new_expert_settings.fxml index 202f7c4d7..8d3ae91aa 100644 --- a/src/main/resources/fxml/addvault_new_expert_settings.fxml +++ b/src/main/resources/fxml/addvault_new_expert_settings.fxml @@ -41,7 +41,7 @@