diff --git a/.changeset/fix-built-in-push.md b/.changeset/fix-built-in-push.md new file mode 100644 index 000000000..ac48c536a --- /dev/null +++ b/.changeset/fix-built-in-push.md @@ -0,0 +1,5 @@ +--- +default: patch +--- + +Fix built-in push activation on Android and preserve custom push servers after restarting. diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 93ae20cf6..efb186ea0 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -8325,7 +8325,7 @@ dependencies = [ [[package]] name = "tauri-plugin-notifications" version = "0.5.0" -source = "git+https://github.com/SableClient/tauri-plugin-notifications.git?rev=a837cd9bb87fe85ecb2a8061e6ec7e8933823dd0#a837cd9bb87fe85ecb2a8061e6ec7e8933823dd0" +source = "git+https://github.com/SableClient/tauri-plugin-notifications.git?rev=f2f320f12a5904ece6d648ce551f9d56bb4a9175#f2f320f12a5904ece6d648ce551f9d56bb4a9175" dependencies = [ "log", "notify-rust", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 5417c3921..40d36bdaa 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -110,12 +110,12 @@ windows = { version = "0.62", features = [ tauri-plugin-single-instance = { version = "2.4.3", features = ["deep-link"] } [target.'cfg(any(windows, target_os = "linux"))'.dependencies] -tauri-plugin-notifications = { git = "https://github.com/SableClient/tauri-plugin-notifications.git", rev = "a837cd9bb87fe85ecb2a8061e6ec7e8933823dd0" } +tauri-plugin-notifications = { git = "https://github.com/SableClient/tauri-plugin-notifications.git", rev = "f2f320f12a5904ece6d648ce551f9d56bb4a9175" } # default-features = false drops notify-rust so macOS uses the native # UNUserNotificationCenter backend (needs a signed .app to deliver). [target.'cfg(target_os = "macos")'.dependencies] -tauri-plugin-notifications = { git = "https://github.com/SableClient/tauri-plugin-notifications.git", rev = "a837cd9bb87fe85ecb2a8061e6ec7e8933823dd0", default-features = false } +tauri-plugin-notifications = { git = "https://github.com/SableClient/tauri-plugin-notifications.git", rev = "f2f320f12a5904ece6d648ce551f9d56bb4a9175", default-features = false } [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] tauri-plugin-updater = { version = "2", optional = true } @@ -139,7 +139,7 @@ libloading = "0.9" zbus = "5" [target.'cfg(any(target_os = "android", target_os = "ios"))'.dependencies] -tauri-plugin-notifications = { git = "https://github.com/SableClient/tauri-plugin-notifications.git", rev = "a837cd9bb87fe85ecb2a8061e6ec7e8933823dd0", features = [ +tauri-plugin-notifications = { git = "https://github.com/SableClient/tauri-plugin-notifications.git", rev = "f2f320f12a5904ece6d648ce551f9d56bb4a9175", features = [ "push-notifications", ] } tauri-plugin-edge-to-edge = { git = "https://github.com/SableClient/tauri-plugin-edge-to-edge.git", rev = "33c6116c27be28c06df5a9d02231ecc5fdeb93c5" } diff --git a/src/app/features/settings/notifications/NotificationTransportRuntimeFeature.test.tsx b/src/app/features/settings/notifications/NotificationTransportRuntimeFeature.test.tsx new file mode 100644 index 000000000..26829c876 --- /dev/null +++ b/src/app/features/settings/notifications/NotificationTransportRuntimeFeature.test.tsx @@ -0,0 +1,65 @@ +import { render, waitFor } from '@testing-library/react'; +import { beforeEach, expect, it, vi } from 'vitest'; +import { NotificationTransportRuntimeFeature } from './NotificationTransportRuntimeFeature'; + +const mocks = vi.hoisted(() => ({ + enable: vi.fn<(...args: unknown[]) => Promise<{ endpoint: string }>>(), + config: { pushTransport: { unifiedPushEmbeddedServerUrl: 'https://push.example' } }, + overrides: {} as { unifiedPushEmbeddedServerUrl?: string }, + mx: {}, + setSetting: vi.fn<() => void>(), +})); + +vi.mock('@tauri-apps/api/core', () => ({ isTauri: () => true })); +vi.mock('@tauri-apps/plugin-os', () => ({ type: () => 'android' })); +vi.mock('$hooks/useMatrixClient', () => ({ useMatrixClient: () => mocks.mx })); +vi.mock('$hooks/useClientConfig', () => ({ useClientConfig: () => mocks.config })); +vi.mock('$state/hooks/settings', () => ({ + useSetting: (_atom: unknown, key: string) => [ + ( + { + backgroundPushEnabled: true, + backgroundPushProvider: 'unifiedpush', + pushTransportMode: 'unifiedpush', + pushTransportOverride: mocks.overrides, + } as Record + )[key], + mocks.setSetting, + ], +})); +vi.mock('./UnifiedPushNotifications', () => ({ + enableUnifiedPush: mocks.enable, + setEncryptedContentAllowed: async () => {}, + listenForUnifiedPushMessages: async () => ({ unregister: async () => {} }), +})); +vi.mock('./UnifiedPushTransport', () => ({ isUnifiedPushPermissionGranted: async () => true })); +vi.mock('./NativePushNotifications', () => ({ + enableNativePush: async () => {}, + isNativePushPermissionGranted: async () => true, +})); + +beforeEach(() => { + mocks.enable.mockReset().mockResolvedValue({ endpoint: 'https://push.example/topic' }); + mocks.overrides = {}; +}); + +it('keeps the configured built-in server during startup registration', async () => { + render(); + await waitFor(() => + expect(mocks.enable).toHaveBeenCalledWith( + mocks.mx, + expect.objectContaining({ unifiedPushEmbeddedServerUrl: 'https://push.example' }) + ) + ); +}); + +it('uses the saved built-in server override during startup registration', async () => { + mocks.overrides = { unifiedPushEmbeddedServerUrl: 'https://custom.example' }; + render(); + await waitFor(() => + expect(mocks.enable).toHaveBeenCalledWith( + mocks.mx, + expect.objectContaining({ unifiedPushEmbeddedServerUrl: 'https://custom.example' }) + ) + ); +}); diff --git a/src/app/features/settings/notifications/NotificationTransportRuntimeFeature.tsx b/src/app/features/settings/notifications/NotificationTransportRuntimeFeature.tsx index c58fb681a..26c2990ad 100644 --- a/src/app/features/settings/notifications/NotificationTransportRuntimeFeature.tsx +++ b/src/app/features/settings/notifications/NotificationTransportRuntimeFeature.tsx @@ -109,6 +109,7 @@ export function NotificationTransportRuntimeFeature() { const upConfigRef = useRef<{ unifiedPushAppID?: string; + unifiedPushEmbeddedServerUrl?: string; unifiedPushGatewayUrl?: string; vapidPublicKey?: string; webPushAppID?: string; @@ -119,10 +120,15 @@ export function NotificationTransportRuntimeFeature() { upConfigRef.current = { unifiedPushAppID: pushTransportOverride?.unifiedPushAppID ?? + clientConfig.pushTransport?.unifiedPushAppID ?? clientConfig.pushNotificationDetails?.unifiedPushAppID, unifiedPushGatewayUrl: pushTransportOverride?.unifiedPushGatewayUrl ?? + clientConfig.pushTransport?.unifiedPushGatewayUrl ?? clientConfig.pushNotificationDetails?.unifiedPushGatewayUrl, + unifiedPushEmbeddedServerUrl: + pushTransportOverride?.unifiedPushEmbeddedServerUrl ?? + clientConfig.pushTransport?.unifiedPushEmbeddedServerUrl, vapidPublicKey: clientConfig.pushNotificationDetails?.vapidPublicKey, webPushAppID: clientConfig.pushNotificationDetails?.webPushAppID, pushNotifyUrl: clientConfig.pushNotificationDetails?.pushNotifyUrl,