fix: add Tauri opener plugin for external URL handling and improve notification focus behavior
This commit is contained in:
@@ -90,13 +90,15 @@ function InviteNotifications() {
|
||||
const notify = useCallback(
|
||||
(count: number) => {
|
||||
const body = `You have ${count} new invitation request.`;
|
||||
const invitesPath = getInboxInvitesPath();
|
||||
|
||||
if (isTauri()) {
|
||||
sendNotification({
|
||||
title: 'Invitation',
|
||||
body,
|
||||
path: invitesPath,
|
||||
onClick: () => {
|
||||
if (!window.closed) navigate(getInboxInvitesPath());
|
||||
if (!window.closed) navigate(invitesPath);
|
||||
},
|
||||
});
|
||||
} else {
|
||||
@@ -108,7 +110,8 @@ function InviteNotifications() {
|
||||
});
|
||||
|
||||
noti.onclick = () => {
|
||||
if (!window.closed) navigate(getInboxInvitesPath());
|
||||
window.focus();
|
||||
if (!window.closed) navigate(invitesPath);
|
||||
noti.close();
|
||||
};
|
||||
}
|
||||
@@ -207,6 +210,7 @@ function MessageNotifications() {
|
||||
});
|
||||
|
||||
noti.onclick = () => {
|
||||
window.focus();
|
||||
if (!window.closed) navigate(roomPath);
|
||||
noti.close();
|
||||
notifRef.current = undefined;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Open an external URL using Tauri shell on desktop/mobile, or window.open in browser
|
||||
* Open an external URL using Tauri opener plugin on desktop/mobile, or window.open in browser
|
||||
* @param url The URL to open
|
||||
*/
|
||||
export const openExternalUrl = async (url: string): Promise<void> => {
|
||||
@@ -9,11 +9,11 @@ export const openExternalUrl = async (url: string): Promise<void> => {
|
||||
// Use new Function to avoid static analysis by Vite/Rollup
|
||||
await new Function(
|
||||
'url',
|
||||
"return import('@tauri-apps/plugin-shell').then(m => m.open(url));"
|
||||
"return import('@tauri-apps/plugin-opener').then(m => m.openUrl(url));"
|
||||
)(url);
|
||||
return;
|
||||
} catch (err) {
|
||||
console.warn('Tauri shell.open failed, falling back to window.open:', err);
|
||||
console.warn('Tauri opener.openUrl failed, falling back to window.open:', err);
|
||||
}
|
||||
}
|
||||
window.open(url, '_blank');
|
||||
@@ -26,7 +26,23 @@ export const openExternalUrl = async (url: string): Promise<void> => {
|
||||
let notificationTapCallback: ((path: string) => void) | null = null;
|
||||
|
||||
/**
|
||||
* Set up listener for notification tap actions on mobile
|
||||
* Bring the Tauri window to the front and focus it
|
||||
*/
|
||||
export const focusWindow = async (): Promise<void> => {
|
||||
if (!isTauri()) return;
|
||||
|
||||
try {
|
||||
const { getCurrentWindow } = await import('@tauri-apps/api/window');
|
||||
const window = getCurrentWindow();
|
||||
await window.unminimize();
|
||||
await window.setFocus();
|
||||
} catch (err) {
|
||||
console.warn('Failed to focus window:', err);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Set up listener for notification tap/click actions
|
||||
* Call this once at app startup with a navigation callback
|
||||
*/
|
||||
export const setupNotificationTapListener = async (onTap: (path: string) => void): Promise<void> => {
|
||||
@@ -37,7 +53,10 @@ export const setupNotificationTapListener = async (onTap: (path: string) => void
|
||||
try {
|
||||
const { onAction } = await import('@tauri-apps/plugin-notification');
|
||||
|
||||
await onAction((notification) => {
|
||||
await onAction(async (notification) => {
|
||||
// Bring window to front first
|
||||
await focusWindow();
|
||||
|
||||
// Get the path from extra data and navigate
|
||||
const path = notification.notification?.extra?.path;
|
||||
if (path && typeof path === 'string' && notificationTapCallback) {
|
||||
@@ -115,7 +134,11 @@ const sendBrowserNotification = (options: {
|
||||
});
|
||||
|
||||
if (onClick) {
|
||||
notification.onclick = () => {
|
||||
notification.onclick = async () => {
|
||||
// Bring Tauri window to front if in Tauri
|
||||
await focusWindow();
|
||||
// Also use standard window.focus for browser
|
||||
window.focus();
|
||||
if (!window.closed) onClick();
|
||||
notification.close();
|
||||
};
|
||||
@@ -124,6 +147,34 @@ const sendBrowserNotification = (options: {
|
||||
return notification;
|
||||
};
|
||||
|
||||
/** Flag to track if notification channel has been created on Android */
|
||||
let notificationChannelCreated = false;
|
||||
|
||||
/**
|
||||
* Create notification channel for Android
|
||||
* Required for Android 8.0+ to show notifications
|
||||
*/
|
||||
const ensureNotificationChannel = async (): Promise<void> => {
|
||||
if (notificationChannelCreated || !isAndroid()) return;
|
||||
|
||||
try {
|
||||
const { createChannel, Importance } = await import('@tauri-apps/plugin-notification');
|
||||
|
||||
await createChannel({
|
||||
id: 'messages',
|
||||
name: 'Messages',
|
||||
description: 'Message notifications from Matrix',
|
||||
importance: Importance.High,
|
||||
vibration: true,
|
||||
sound: 'default',
|
||||
});
|
||||
|
||||
notificationChannelCreated = true;
|
||||
} catch (err) {
|
||||
console.warn('Failed to create notification channel:', err);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Send a notification using Tauri's notification plugin
|
||||
* Falls back to browser Notification API if not in Tauri
|
||||
@@ -152,9 +203,14 @@ export const sendNotification = async (options: {
|
||||
}
|
||||
|
||||
if (permissionGranted) {
|
||||
// Ensure notification channel exists on Android
|
||||
await ensureNotificationChannel();
|
||||
|
||||
await tauriSendNotification({
|
||||
title,
|
||||
body,
|
||||
// Use the channel on Android
|
||||
channelId: isAndroid() ? 'messages' : undefined,
|
||||
// Store path in extra data for notification tap handling
|
||||
extra: path ? { path } : undefined,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user