fix notification crash on ios (#2192)
authorAjay Bura <32841439+ajbura@users.noreply.github.com>
Mon, 10 Feb 2025 10:02:33 +0000 (21:02 +1100)
committerGitHub <noreply@github.com>
Mon, 10 Feb 2025 10:02:33 +0000 (21:02 +1100)
* fix notification crash for ios

* access notification from window variable

* fix Notification check

* catch notification variable error

* fix missing check for Notification

src/app/features/settings/notifications/Notifications.tsx
src/app/hooks/usePermission.ts
src/app/pages/client/ClientNonUIFeatures.tsx
src/app/utils/dom.ts

index 230d60a3298ae567ef4d8613c7e689b7822e035c..88e16d296e15ed157a4ced575dd8212c8513d274 100644 (file)
@@ -6,17 +6,14 @@ import { SequenceCardStyle } from '../styles.css';
 import { SettingTile } from '../../../components/setting-tile';
 import { useSetting } from '../../../state/hooks/settings';
 import { settingsAtom } from '../../../state/settings';
-import { usePermissionState } from '../../../hooks/usePermission';
+import { getNotificationState, usePermissionState } from '../../../hooks/usePermission';
 import { AllMessagesNotifications } from './AllMessages';
 import { SpecialMessagesNotifications } from './SpecialMessages';
 import { KeywordMessagesNotifications } from './KeywordMessages';
 import { IgnoredUserList } from './IgnoredUserList';
 
 function SystemNotification() {
-  const notifPermission = usePermissionState(
-    'notifications',
-    window.Notification.permission === 'default' ? 'prompt' : window.Notification.permission
-  );
+  const notifPermission = usePermissionState('notifications', getNotificationState());
   const [showNotifications, setShowNotifications] = useSetting(settingsAtom, 'showNotifications');
   const [isNotificationSounds, setIsNotificationSounds] = useSetting(
     settingsAtom,
@@ -41,8 +38,9 @@ function SystemNotification() {
           description={
             notifPermission === 'denied' ? (
               <Text as="span" style={{ color: color.Critical.Main }} size="T200">
-                Notification permission is blocked. Please allow notification permission from
-                browser address bar.
+                {'Notification' in window
+                  ? 'Notification permission is blocked. Please allow notification permission from browser address bar.'
+                  : 'Notifications are not supported by the system.'}
               </Text>
             ) : (
               <span>Show desktop notifications when message arrive.</span>
index 5a3ec9f6bb3474fd644769eec0414fa4f71f65c4..71a601be285212d141fa2746bab623822f42d2ad 100644 (file)
@@ -1,4 +1,16 @@
-import { useEffect, useState } from "react";
+import { useEffect, useState } from 'react';
+
+export const getNotificationState = (): PermissionState => {
+  if ('Notification' in window) {
+    if (window.Notification.permission === 'default') {
+      return 'prompt';
+    }
+
+    return window.Notification.permission;
+  }
+
+  return 'denied';
+};
 
 export function usePermissionState(name: PermissionName, initialValue: PermissionState = 'prompt') {
   const [permissionState, setPermissionState] = useState<PermissionState>(initialValue);
@@ -15,16 +27,16 @@ export function usePermissionState(name: PermissionName, initialValue: Permissio
       .then((permStatus: PermissionStatus) => {
         permissionStatus = permStatus;
         handlePermissionChange.apply(permStatus);
-        permStatus.addEventListener("change", handlePermissionChange);
+        permStatus.addEventListener('change', handlePermissionChange);
       })
       .catch(() => {
         // Silence error since FF doesn't support microphone permission
       });
 
     return () => {
-      permissionStatus?.removeEventListener("change", handlePermissionChange);
+      permissionStatus?.removeEventListener('change', handlePermissionChange);
     };
   }, [name]);
 
   return permissionState;
-}
\ No newline at end of file
+}
index 8678e61946faa1b0094cfdd097d85ae244c28b4b..ce952bfc675ab06efe799108b7f017f83416b918 100644 (file)
@@ -8,7 +8,7 @@ import LogoUnreadSVG from '../../../../public/res/svg/cinny-unread.svg';
 import LogoHighlightSVG from '../../../../public/res/svg/cinny-highlight.svg';
 import NotificationSound from '../../../../public/sound/notification.ogg';
 import InviteSound from '../../../../public/sound/invite.ogg';
-import { setFavicon } from '../../utils/dom';
+import { notificationPermission, setFavicon } from '../../utils/dom';
 import { useSetting } from '../../state/hooks/settings';
 import { settingsAtom } from '../../state/settings';
 import { allInvitesAtom } from '../../state/room-list/inviteList';
@@ -110,7 +110,7 @@ function InviteNotifications() {
 
   useEffect(() => {
     if (invites.length > perviousInviteLen && mx.getSyncState() === 'SYNCING') {
-      if (showNotifications && Notification.permission === 'granted') {
+      if (showNotifications && notificationPermission('granted')) {
         notify(invites.length - perviousInviteLen);
       }
 
@@ -212,7 +212,7 @@ function MessageNotifications() {
         return;
       }
 
-      if (showNotifications && Notification.permission === 'granted') {
+      if (showNotifications && notificationPermission('granted')) {
         const avatarMxc =
           room.getAvatarFallbackMember()?.getMxcAvatarUrl() ?? room.getMxcAvatarUrl();
         notify({
index f931ac45369c503cc606ae4b61a5746b1c22e774..f4c3f719be9c3171b83ff915591b67c6a788ea90 100644 (file)
@@ -217,3 +217,10 @@ export const syntaxErrorPosition = (error: SyntaxError): number | undefined => {
   if (Number.isNaN(position)) return undefined;
   return position;
 };
+
+export const notificationPermission = (permission: NotificationPermission) => {
+  if ('Notification' in window) {
+    return window.Notification.permission === permission;
+  }
+  return false;
+};