diff --git a/pom.xml b/pom.xml
index cea4bc575..e6f1e96e4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -33,7 +33,7 @@
org.ow2.asm,org.apache.jackrabbit,org.apache.httpcomponents
- 2.8.0
+ 2.9.0-SNAPSHOT
1.5.0
1.3.0
1.2.4
diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java
index 4dd4242b3..f43e6599d 100644
--- a/src/main/java/module-info.java
+++ b/src/main/java/module-info.java
@@ -59,6 +59,7 @@ open module org.cryptomator.desktop {
uses org.cryptomator.common.locationpresets.LocationPresetsProvider;
uses SSLContextProvider;
+ uses org.cryptomator.notify.NotificationHandler;
provides TrayMenuController with AwtTrayMenuController;
provides Configurator with LogbackConfiguratorFactory;
diff --git a/src/main/java/org/cryptomator/common/CommonsModule.java b/src/main/java/org/cryptomator/common/CommonsModule.java
index a1e3c0950..a3f8f29a6 100644
--- a/src/main/java/org/cryptomator/common/CommonsModule.java
+++ b/src/main/java/org/cryptomator/common/CommonsModule.java
@@ -15,11 +15,14 @@ import org.cryptomator.common.vaults.VaultComponent;
import org.cryptomator.common.vaults.VaultListModule;
import org.cryptomator.cryptolib.common.MasterkeyFileAccess;
import org.cryptomator.integrations.revealpath.RevealPathService;
+import org.cryptomator.notify.Event;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Named;
import javax.inject.Singleton;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Comparator;
@@ -128,6 +131,12 @@ public abstract class CommonsModule {
return executorService;
}
+ @Provides
+ @Singleton
+ static ObservableList provideAppEventQueue() {
+ return FXCollections.observableArrayList();
+ }
+
private static void handleUncaughtExceptionInBackgroundThread(Thread thread, Throwable throwable) {
LOG.error("Uncaught exception in " + thread.getName(), throwable);
}
diff --git a/src/main/java/org/cryptomator/common/vaults/Vault.java b/src/main/java/org/cryptomator/common/vaults/Vault.java
index f857d6ba1..6d47c95f5 100644
--- a/src/main/java/org/cryptomator/common/vaults/Vault.java
+++ b/src/main/java/org/cryptomator/common/vaults/Vault.java
@@ -18,6 +18,7 @@ import org.cryptomator.cryptofs.CryptoFileSystemProperties;
import org.cryptomator.cryptofs.CryptoFileSystemProperties.FileSystemFlags;
import org.cryptomator.cryptofs.CryptoFileSystemProvider;
import org.cryptomator.cryptofs.common.FileSystemCapabilityChecker;
+import org.cryptomator.cryptofs.event.FilesystemEvent;
import org.cryptomator.cryptolib.api.CryptoException;
import org.cryptomator.cryptolib.api.MasterkeyLoader;
import org.cryptomator.cryptolib.api.MasterkeyLoadingFailedException;
@@ -26,6 +27,8 @@ import org.cryptomator.integrations.mount.Mountpoint;
import org.cryptomator.integrations.mount.UnmountFailedException;
import org.cryptomator.integrations.quickaccess.QuickAccessService;
import org.cryptomator.integrations.quickaccess.QuickAccessServiceException;
+import org.cryptomator.notify.Event;
+import org.cryptomator.notify.VaultEvent;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -41,6 +44,7 @@ import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyStringProperty;
import javafx.beans.property.SimpleBooleanProperty;
+import javafx.collections.ObservableList;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -74,6 +78,7 @@ public class Vault {
private final ObjectBinding mountPoint;
private final Mounter mounter;
private final Settings settings;
+ private final ObservableList eventQueue;
private final BooleanProperty showingStats;
private final AtomicReference mountHandle = new AtomicReference<>(null);
@@ -85,7 +90,9 @@ public class Vault {
VaultState state, //
@Named("lastKnownException") ObjectProperty lastKnownException, //
VaultStats stats, //
- Mounter mounter, Settings settings) {
+ Mounter mounter, Settings settings, //
+ ObservableList eventQueue
+ ) {
this.vaultSettings = vaultSettings;
this.configCache = configCache;
this.cryptoFileSystem = cryptoFileSystem;
@@ -102,6 +109,7 @@ public class Vault {
this.mountPoint = Bindings.createObjectBinding(this::getMountPoint, state);
this.mounter = mounter;
this.settings = settings;
+ this.eventQueue = eventQueue;
this.showingStats = new SimpleBooleanProperty(false);
this.quickAccessEntry = new AtomicReference<>(null);
}
@@ -143,6 +151,7 @@ public class Vault {
.withFlags(flags) //
.withMaxCleartextNameLength(vaultSettings.maxCleartextFilenameLength.get()) //
.withVaultConfigFilename(Constants.VAULTCONFIG_FILENAME) //
+ .withFilesystemEventConsumer(this::consumeVaultEvent)
.build();
return CryptoFileSystemProvider.newFileSystem(getPath(), fsProps);
}
@@ -251,6 +260,10 @@ public class Vault {
}
}
+ private void consumeVaultEvent(FilesystemEvent e) {
+ eventQueue.addLast(new VaultEvent(vaultSettings.id, vaultSettings.path.get().toString(), e));
+ }
+
// ******************************************************************************
// Observable Properties
// *******************************************************************************
diff --git a/src/main/java/org/cryptomator/notify/Answer.java b/src/main/java/org/cryptomator/notify/Answer.java
new file mode 100644
index 000000000..8c99b82de
--- /dev/null
+++ b/src/main/java/org/cryptomator/notify/Answer.java
@@ -0,0 +1,14 @@
+package org.cryptomator.notify;
+
+public sealed interface Answer permits Answer.DoNothing, Answer.DoSomething {
+
+
+ record DoNothing() implements Answer {}
+
+ record DoSomething(Runnable action) implements Answer {
+
+ void run() {
+ action.run();
+ }
+ }
+}
diff --git a/src/main/java/org/cryptomator/notify/AppEvent.java b/src/main/java/org/cryptomator/notify/AppEvent.java
new file mode 100644
index 000000000..afeb829e4
--- /dev/null
+++ b/src/main/java/org/cryptomator/notify/AppEvent.java
@@ -0,0 +1,3 @@
+package org.cryptomator.notify;
+
+public record AppEvent() implements Event {}
diff --git a/src/main/java/org/cryptomator/notify/Event.java b/src/main/java/org/cryptomator/notify/Event.java
new file mode 100644
index 000000000..a2dda9559
--- /dev/null
+++ b/src/main/java/org/cryptomator/notify/Event.java
@@ -0,0 +1,5 @@
+package org.cryptomator.notify;
+
+public sealed interface Event permits AppEvent, VaultEvent {
+
+}
diff --git a/src/main/java/org/cryptomator/notify/NotificationHandler.java b/src/main/java/org/cryptomator/notify/NotificationHandler.java
new file mode 100644
index 000000000..48936e30b
--- /dev/null
+++ b/src/main/java/org/cryptomator/notify/NotificationHandler.java
@@ -0,0 +1,15 @@
+package org.cryptomator.notify;
+
+import org.cryptomator.integrations.common.IntegrationsLoader;
+
+import java.util.ServiceLoader;
+import java.util.stream.Stream;
+
+public interface NotificationHandler {
+
+ Answer handle(Event e);
+
+ static Stream loadAll() {
+ return IntegrationsLoader.loadAll(ServiceLoader.load(NotificationHandler.class), NotificationHandler.class);
+ }
+}
diff --git a/src/main/java/org/cryptomator/notify/VaultEvent.java b/src/main/java/org/cryptomator/notify/VaultEvent.java
new file mode 100644
index 000000000..6c2690494
--- /dev/null
+++ b/src/main/java/org/cryptomator/notify/VaultEvent.java
@@ -0,0 +1,7 @@
+package org.cryptomator.notify;
+
+import org.cryptomator.cryptofs.event.FilesystemEvent;
+
+public record VaultEvent(String vaultId, String path, FilesystemEvent actualEvent) implements Event {
+
+}
diff --git a/src/main/java/org/cryptomator/ui/eventviewer/EventViewerComponent.java b/src/main/java/org/cryptomator/ui/eventviewer/EventViewerComponent.java
new file mode 100644
index 000000000..8ac56320b
--- /dev/null
+++ b/src/main/java/org/cryptomator/ui/eventviewer/EventViewerComponent.java
@@ -0,0 +1,3 @@
+package org.cryptomator.ui.eventviewer;
+
+public interface EventViewerComponent {}