diff --git a/src/components/left/settings/SettingsNotifications.tsx b/src/components/left/settings/SettingsNotifications.tsx index cf5b5fd5b..64c75f652 100644 --- a/src/components/left/settings/SettingsNotifications.tsx +++ b/src/components/left/settings/SettingsNotifications.tsx @@ -6,7 +6,7 @@ import { getActions, withGlobal } from '../../../global'; import useLang from '../../../hooks/useLang'; import useHistoryBack from '../../../hooks/useHistoryBack'; -import { playNotifySound } from '../../../util/notifications'; +import { playNotifySound, checkIfNotificationsSupported } from '../../../util/notifications'; import Checkbox from '../../ui/Checkbox'; import RangeSlider from '../../ui/RangeSlider'; @@ -56,6 +56,8 @@ const SettingsNotifications: FC = ({ const runDebounced = useRunDebounced(500, true); + const areNotificationsSupported = checkIfNotificationsSupported(); + const handleSettingsChange = useCallback(( e: ChangeEvent, peerType: 'contact' | 'group' | 'broadcast', @@ -147,11 +149,12 @@ const SettingsNotifications: FC = ({ // eslint-disable-next-line max-len subLabel={lang(hasWebNotifications ? 'UserInfo.NotificationsEnabled' : 'UserInfo.NotificationsDisabled')} checked={hasWebNotifications} + disabled={!areNotificationsSupported} onChange={handleWebNotificationsChange} /> = ({ label="Sound" min={0} max={10} + disabled={!areNotificationsSupported} value={notificationSoundVolume} onChange={handleVolumeChange} /> diff --git a/src/global/actions/ui/initial.ts b/src/global/actions/ui/initial.ts index cde157898..34f2b26b2 100644 --- a/src/global/actions/ui/initial.ts +++ b/src/global/actions/ui/initial.ts @@ -86,7 +86,17 @@ addActionHandler('initShared', (): ActionReturnType => { addActionHandler('initMain', (global): ActionReturnType => { const { hasWebNotifications, hasPushNotifications } = selectNotifySettings(global); if (hasWebNotifications && hasPushNotifications) { - void subscribe(); + // Most of the browsers only show the notifications permission prompt after the first user gesture + const events = ['click', 'ontouchstart', 'keypress']; + const subscribeAfterUserGesture = () => { + void subscribe(); + events.forEach((event) => { + document.removeEventListener(event, subscribeAfterUserGesture); + }); + }; + events.forEach((event) => { + document.addEventListener(event, subscribeAfterUserGesture, { once: true }); + }); } }); diff --git a/src/util/notifications.ts b/src/util/notifications.ts index 36c85fad2..c1cd5709e 100644 --- a/src/util/notifications.ts +++ b/src/util/notifications.ts @@ -73,7 +73,7 @@ function checkIfPushSupported() { return true; } -function checkIfNotificationsSupported() { +export function checkIfNotificationsSupported() { // Let's check if the browser supports notifications if (!('Notification' in window)) { if (DEBUG) { @@ -137,20 +137,27 @@ function checkIfShouldResubscribe(subscription: PushSubscription | null) { async function requestPermission() { if (!('Notification' in window)) return; - if (!['granted', 'denied'].includes(Notification.permission)) { - await Notification.requestPermission(); + let permission = Notification.permission; + if (!['granted', 'denied'].includes(permission)) { + permission = await Notification.requestPermission(); } + const isGranted = permission === 'granted'; + const { updateWebNotificationSettings } = getActions(); + updateWebNotificationSettings({ + hasWebNotifications: isGranted, + hasPushNotifications: isGranted, + }); } async function unsubscribeFromPush(subscription: PushSubscription | null) { const global = getGlobal(); - const dispatch = getActions(); + const { deleteDeviceToken } = getActions(); if (subscription) { try { const deviceToken = getDeviceToken(subscription); await callApi('unregisterDevice', deviceToken); await subscription.unsubscribe(); - dispatch.deleteDeviceToken(); + deleteDeviceToken(); return; } catch (error) { if (DEBUG) { @@ -161,7 +168,7 @@ async function unsubscribeFromPush(subscription: PushSubscription | null) { } if (global.push) { await callApi('unregisterDevice', global.push.deviceToken); - dispatch.deleteDeviceToken(); + deleteDeviceToken(); } } @@ -226,6 +233,7 @@ export async function subscribe() { let subscription = await serviceWorkerRegistration.pushManager.getSubscription(); if (!checkIfShouldResubscribe(subscription)) return; await unsubscribeFromPush(subscription); + const { setDeviceToken, updateWebNotificationSettings } = getActions(); try { subscription = await serviceWorkerRegistration.pushManager.subscribe({ userVisibleOnly: true, @@ -236,10 +244,13 @@ export async function subscribe() { console.log('[PUSH] Received push subscription: ', deviceToken); } await callApi('registerDevice', deviceToken); - getActions() - .setDeviceToken(deviceToken); + setDeviceToken(deviceToken); + updateWebNotificationSettings({ + hasWebNotifications: true, + hasPushNotifications: true, + }); } catch (error: any) { - if (Notification.permission === 'denied' as NotificationPermission) { + if (Notification.permission === 'denied') { // The user denied the notification permission which // means we failed to subscribe and the user will need // to manually change the notification permission to @@ -261,6 +272,10 @@ export async function subscribe() { await requestPermission(); } } + updateWebNotificationSettings({ + hasWebNotifications: false, + hasPushNotifications: false, + }); } }