diff --git a/mobile/pubspec.yaml b/mobile/pubspec.yaml
index 40d0ad756..000720842 100644
--- a/mobile/pubspec.yaml
+++ b/mobile/pubspec.yaml
@@ -2,7 +2,7 @@ name: immich_mobile
description: Immich - selfhosted backup media file on mobile phone
publish_to: 'none'
-version: 3.3.1-local.2+3030200
+version: 3.3.1-local.3+3030201
environment:
sdk: '>=3.12.0 <4.0.0'
diff --git a/web/src/lib/utils/__tests__/EventNavigation.svelte b/web/src/lib/utils/__tests__/EventNavigation.svelte
new file mode 100644
index 000000000..f47d9f370
--- /dev/null
+++ b/web/src/lib/utils/__tests__/EventNavigation.svelte
@@ -0,0 +1,17 @@
+
+
+
+
+
+{#if visible}
+ {#key page}
+
+ {/key}
+{/if}
diff --git a/web/src/lib/utils/__tests__/EventSubscriber.svelte b/web/src/lib/utils/__tests__/EventSubscriber.svelte
new file mode 100644
index 000000000..6c3b35c61
--- /dev/null
+++ b/web/src/lib/utils/__tests__/EventSubscriber.svelte
@@ -0,0 +1,10 @@
+
+
+{received}
diff --git a/web/src/lib/utils/base-event-manager.spec.ts b/web/src/lib/utils/base-event-manager.spec.ts
new file mode 100644
index 000000000..812701878
--- /dev/null
+++ b/web/src/lib/utils/base-event-manager.spec.ts
@@ -0,0 +1,28 @@
+import { render, screen } from '@testing-library/svelte';
+import userEvent from '@testing-library/user-event';
+import EventNavigation from './__tests__/EventNavigation.svelte';
+
+describe('event subscriptions across navigation', () => {
+ it('keeps the new page subscribed when the previous page is destroyed', async () => {
+ const user = userEvent.setup();
+ render(EventNavigation);
+ for (let page = 0; page < 3; page++) {
+ await user.click(screen.getByRole('button', { name: 'Next page' }));
+ await user.click(screen.getByRole('button', { name: 'Update' }));
+ expect(screen.getByTestId('received')).toHaveTextContent('1');
+ }
+ });
+
+ it('updates controls when the last subscriber is removed and restored', async () => {
+ const user = userEvent.setup();
+ render(EventNavigation);
+ const update = screen.getByRole('button', { name: 'Update' });
+ expect(update).toBeEnabled();
+ await user.click(screen.getByRole('button', { name: 'Toggle subscriber' }));
+ expect(update).toBeDisabled();
+ await user.click(screen.getByRole('button', { name: 'Toggle subscriber' }));
+ expect(update).toBeEnabled();
+ await user.click(update);
+ expect(screen.getByTestId('received')).toHaveTextContent('1');
+ });
+});