Notifications: Add web settings, sound and avatar, some fixes (#1317)
This commit is contained in:
parent
dd58fc08df
commit
d59390364c
BIN
public/notification.mp3
Normal file
BIN
public/notification.mp3
Normal file
Binary file not shown.
@ -136,6 +136,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
&-slider {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
&-description {
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-text-secondary);
|
||||
|
||||
@ -12,6 +12,7 @@ import useLang from '../../../hooks/useLang';
|
||||
import useHistoryBack from '../../../hooks/useHistoryBack';
|
||||
|
||||
import Checkbox from '../../ui/Checkbox';
|
||||
import RangeSlider from '../../ui/RangeSlider';
|
||||
|
||||
type OwnProps = {
|
||||
isActive?: boolean;
|
||||
@ -27,10 +28,14 @@ type StateProps = {
|
||||
hasBroadcastNotifications: boolean;
|
||||
hasBroadcastMessagePreview: boolean;
|
||||
hasContactJoinedNotifications: boolean;
|
||||
hasWebNotifications: boolean;
|
||||
hasPushNotifications: boolean;
|
||||
notificationSoundVolume: number;
|
||||
};
|
||||
|
||||
type DispatchProps = Pick<GlobalActions, (
|
||||
'loadNotificationSettings' | 'updateContactSignUpNotification' | 'updateNotificationSettings'
|
||||
'loadNotificationSettings' | 'updateContactSignUpNotification' |
|
||||
'updateNotificationSettings' | 'updateWebNotificationSettings'
|
||||
)>;
|
||||
|
||||
const SettingsNotifications: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
@ -44,9 +49,13 @@ const SettingsNotifications: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
hasBroadcastNotifications,
|
||||
hasBroadcastMessagePreview,
|
||||
hasContactJoinedNotifications,
|
||||
hasPushNotifications,
|
||||
hasWebNotifications,
|
||||
notificationSoundVolume,
|
||||
loadNotificationSettings,
|
||||
updateContactSignUpNotification,
|
||||
updateNotificationSettings,
|
||||
updateWebNotificationSettings,
|
||||
}) => {
|
||||
useEffect(() => {
|
||||
loadNotificationSettings();
|
||||
@ -88,6 +97,44 @@ const SettingsNotifications: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
|
||||
return (
|
||||
<div className="settings-content custom-scroll">
|
||||
<div className="settings-item">
|
||||
<h4 className="settings-item-header" dir={lang.isRtl ? 'rtl' : undefined}>
|
||||
Web notifications
|
||||
</h4>
|
||||
<Checkbox
|
||||
label="Web notifications"
|
||||
// eslint-disable-next-line max-len
|
||||
subLabel={lang(hasWebNotifications ? 'UserInfo.NotificationsEnabled' : 'UserInfo.NotificationsDisabled')}
|
||||
checked={hasWebNotifications}
|
||||
onChange={(e) => {
|
||||
updateWebNotificationSettings({ hasWebNotifications: e.target.checked });
|
||||
}}
|
||||
/>
|
||||
<Checkbox
|
||||
label="Offline notifications"
|
||||
disabled={!hasWebNotifications}
|
||||
// eslint-disable-next-line max-len
|
||||
subLabel={lang(hasPushNotifications ? 'UserInfo.NotificationsEnabled' : 'UserInfo.NotificationsDisabled')}
|
||||
checked={hasPushNotifications}
|
||||
onChange={(e) => {
|
||||
updateWebNotificationSettings({ hasPushNotifications: e.target.checked });
|
||||
}}
|
||||
/>
|
||||
<div className="settings-item-slider">
|
||||
<RangeSlider
|
||||
label="Sound"
|
||||
disabled={!hasWebNotifications}
|
||||
range={{
|
||||
min: 0,
|
||||
max: 10,
|
||||
}}
|
||||
value={notificationSoundVolume}
|
||||
onChange={(volume) => {
|
||||
updateWebNotificationSettings({ notificationSoundVolume: volume });
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="settings-item">
|
||||
<h4 className="settings-item-header" dir={lang.isRtl ? 'rtl' : undefined}>
|
||||
{lang('AutodownloadPrivateChats')}
|
||||
@ -102,6 +149,7 @@ const SettingsNotifications: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
/>
|
||||
<Checkbox
|
||||
label={lang('MessagePreview')}
|
||||
disabled={!hasPrivateChatsNotifications}
|
||||
// eslint-disable-next-line max-len
|
||||
subLabel={lang(hasPrivateChatsMessagePreview ? 'UserInfo.NotificationsEnabled' : 'UserInfo.NotificationsDisabled')}
|
||||
checked={hasPrivateChatsMessagePreview}
|
||||
@ -120,6 +168,7 @@ const SettingsNotifications: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
/>
|
||||
<Checkbox
|
||||
label={lang('MessagePreview')}
|
||||
disabled={!hasGroupNotifications}
|
||||
subLabel={lang(hasGroupMessagePreview ? 'UserInfo.NotificationsEnabled' : 'UserInfo.NotificationsDisabled')}
|
||||
checked={hasGroupMessagePreview}
|
||||
onChange={(e) => { handleSettingsChange(e, 'group', 'showPreviews'); }}
|
||||
@ -138,6 +187,7 @@ const SettingsNotifications: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
/>
|
||||
<Checkbox
|
||||
label={lang('MessagePreview')}
|
||||
disabled={!hasBroadcastNotifications}
|
||||
// eslint-disable-next-line max-len
|
||||
subLabel={lang(hasBroadcastMessagePreview ? 'UserInfo.NotificationsEnabled' : 'UserInfo.NotificationsDisabled')}
|
||||
checked={hasBroadcastMessagePreview}
|
||||
@ -167,10 +217,14 @@ export default memo(withGlobal<OwnProps>((global): StateProps => {
|
||||
hasBroadcastNotifications: Boolean(global.settings.byKey.hasBroadcastNotifications),
|
||||
hasBroadcastMessagePreview: Boolean(global.settings.byKey.hasBroadcastMessagePreview),
|
||||
hasContactJoinedNotifications: Boolean(global.settings.byKey.hasContactJoinedNotifications),
|
||||
hasWebNotifications: global.settings.byKey.hasWebNotifications,
|
||||
hasPushNotifications: global.settings.byKey.hasPushNotifications,
|
||||
notificationSoundVolume: global.settings.byKey.notificationSoundVolume,
|
||||
};
|
||||
},
|
||||
(setGlobal, actions): DispatchProps => pick(actions, [
|
||||
'loadNotificationSettings',
|
||||
'updateContactSignUpNotification',
|
||||
'updateNotificationSettings',
|
||||
'updateWebNotificationSettings',
|
||||
]))(SettingsNotifications));
|
||||
|
||||
@ -133,6 +133,9 @@ export const INITIAL_STATE: GlobalState = {
|
||||
shouldAutoDownloadMediaInPrivateChats: true,
|
||||
shouldAutoDownloadMediaInGroups: true,
|
||||
shouldAutoDownloadMediaInChannels: true,
|
||||
hasWebNotifications: true,
|
||||
hasPushNotifications: true,
|
||||
notificationSoundVolume: 5,
|
||||
shouldAutoPlayGifs: true,
|
||||
shouldAutoPlayVideos: true,
|
||||
shouldSuggestStickers: true,
|
||||
|
||||
@ -483,9 +483,9 @@ export type ActionTypes = (
|
||||
'loadBlockedContacts' | 'blockContact' | 'unblockContact' |
|
||||
'loadAuthorizations' | 'terminateAuthorization' | 'terminateAllAuthorizations' |
|
||||
'loadNotificationSettings' | 'updateContactSignUpNotification' | 'updateNotificationSettings' |
|
||||
'loadLanguages' | 'loadPrivacySettings' | 'setPrivacyVisibility' | 'setPrivacySettings' |
|
||||
'loadNotificationExceptions' | 'setThemeSettings' | 'updateIsOnline' | 'loadContentSettings' |
|
||||
'updateContentSettings' |
|
||||
'updateWebNotificationSettings' | 'loadLanguages' | 'loadPrivacySettings' | 'setPrivacyVisibility' |
|
||||
'setPrivacySettings' | 'loadNotificationExceptions' | 'setThemeSettings' | 'updateIsOnline' |
|
||||
'loadContentSettings' | 'updateContentSettings' |
|
||||
// Stickers & GIFs
|
||||
'loadStickerSets' | 'loadAddedStickers' | 'loadRecentStickers' | 'loadFavoriteStickers' | 'loadFeaturedStickers' |
|
||||
'loadStickers' | 'setStickerSearchQuery' | 'loadSavedGifs' | 'setGifSearchQuery' | 'searchMoreGifs' |
|
||||
|
||||
@ -8,6 +8,7 @@ import {
|
||||
|
||||
import { callApi } from '../../../api/gramjs';
|
||||
import { buildCollectionByKey } from '../../../util/iteratees';
|
||||
import { subscribe, unsubscribe } from '../../../util/notifications';
|
||||
import { selectUser } from '../../selectors';
|
||||
import {
|
||||
addUsers, addBlockedContact, updateChats, updateUser, removeBlockedContact, replaceSettings, updateNotifySettings,
|
||||
@ -346,6 +347,19 @@ addReducer('updateNotificationSettings', (global, actions, payload) => {
|
||||
})();
|
||||
});
|
||||
|
||||
addReducer('updateWebNotificationSettings', (global, actions, payload) => {
|
||||
(async () => {
|
||||
setGlobal(replaceSettings(getGlobal(), payload));
|
||||
const newGlobal = getGlobal();
|
||||
const { hasPushNotifications, hasWebNotifications } = newGlobal.settings.byKey;
|
||||
if (hasWebNotifications && hasPushNotifications) {
|
||||
await subscribe();
|
||||
} else {
|
||||
await unsubscribe();
|
||||
}
|
||||
})();
|
||||
});
|
||||
|
||||
addReducer('updateContactSignUpNotification', (global, actions, payload) => {
|
||||
const { isSilent } = payload!;
|
||||
|
||||
|
||||
@ -19,7 +19,7 @@ import {
|
||||
selectIsChatListed,
|
||||
selectChatListType,
|
||||
selectCurrentMessageList,
|
||||
selectCountNotMutedUnread,
|
||||
selectCountNotMutedUnread, selectNotifySettings,
|
||||
} from '../../selectors';
|
||||
import { throttle } from '../../../util/schedulers';
|
||||
|
||||
@ -135,7 +135,15 @@ addReducer('apiUpdate', (global, actions, update: ApiUpdate) => {
|
||||
|
||||
const unreadCount = selectCountNotMutedUnread(getGlobal());
|
||||
updateAppBadge(unreadCount);
|
||||
showNewMessageNotification({ chat, message, isActiveChat });
|
||||
|
||||
const { hasWebNotifications } = selectNotifySettings(global);
|
||||
if (hasWebNotifications) {
|
||||
showNewMessageNotification({
|
||||
chat,
|
||||
message,
|
||||
isActiveChat,
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -16,6 +16,7 @@ import { DEBUG, SESSION_USER_KEY } from '../../../config';
|
||||
import { subscribe } from '../../../util/notifications';
|
||||
import { updateUser } from '../../reducers';
|
||||
import { setLanguage } from '../../../util/langProvider';
|
||||
import { selectNotifySettings } from '../../selectors';
|
||||
|
||||
addReducer('apiUpdate', (global, actions, update: ApiUpdate) => {
|
||||
if (DEBUG) {
|
||||
@ -68,7 +69,8 @@ addReducer('apiUpdate', (global, actions, update: ApiUpdate) => {
|
||||
});
|
||||
|
||||
function onUpdateApiReady(global: GlobalState) {
|
||||
subscribe();
|
||||
const { hasWebNotifications, hasPushNotifications } = selectNotifySettings(global);
|
||||
if (hasWebNotifications && hasPushNotifications) subscribe();
|
||||
setLanguage(global.settings.byKey.language);
|
||||
}
|
||||
|
||||
|
||||
@ -225,9 +225,14 @@ export function isChatArchived(chat: ApiChat) {
|
||||
}
|
||||
|
||||
export function selectIsChatMuted(
|
||||
chat: ApiChat, notifySettings: NotifySettings, notifyExceptions?: Record<number, NotifyException>,
|
||||
chat: ApiChat, notifySettings: NotifySettings, notifyExceptions: Record<number, NotifyException> = [],
|
||||
) {
|
||||
return !(notifyExceptions && notifyExceptions[chat.id] && !notifyExceptions[chat.id].isMuted) && (
|
||||
// If this chat is in exceptions they take precedence
|
||||
if (notifyExceptions[chat.id] && notifyExceptions[chat.id].isMuted !== undefined) {
|
||||
return notifyExceptions[chat.id].isMuted;
|
||||
}
|
||||
|
||||
return (
|
||||
chat.isMuted
|
||||
|| (isChatPrivate(chat.id) && !notifySettings.hasPrivateChatsNotifications)
|
||||
|| (isChatChannel(chat) && !notifySettings.hasBroadcastNotifications)
|
||||
@ -235,6 +240,24 @@ export function selectIsChatMuted(
|
||||
);
|
||||
}
|
||||
|
||||
export function selectShouldShowMessagePreview(
|
||||
chat: ApiChat, notifySettings: NotifySettings, notifyExceptions: Record<number, NotifyException> = [],
|
||||
) {
|
||||
const {
|
||||
hasPrivateChatsMessagePreview = true,
|
||||
hasBroadcastMessagePreview = true,
|
||||
hasGroupMessagePreview = true,
|
||||
} = notifySettings;
|
||||
// If this chat is in exceptions they take precedence
|
||||
if (notifyExceptions[chat.id] && notifyExceptions[chat.id].shouldShowPreviews !== undefined) {
|
||||
return notifyExceptions[chat.id].shouldShowPreviews;
|
||||
}
|
||||
|
||||
return (isChatPrivate(chat.id) && hasPrivateChatsMessagePreview)
|
||||
|| (isChatChannel(chat) && hasBroadcastMessagePreview)
|
||||
|| (isChatGroup(chat) && hasGroupMessagePreview);
|
||||
}
|
||||
|
||||
export function getCanDeleteChat(chat: ApiChat) {
|
||||
return isChatBasicGroup(chat) || ((isChatSuperGroup(chat) || isChatChannel(chat)) && chat.isCreator);
|
||||
}
|
||||
|
||||
@ -28,6 +28,7 @@ type NotificationData = {
|
||||
chatId?: number;
|
||||
title: string;
|
||||
body: string;
|
||||
icon?: string;
|
||||
};
|
||||
|
||||
let lastSyncAt = new Date().valueOf();
|
||||
@ -75,22 +76,36 @@ function getNotificationData(data: PushData): NotificationData {
|
||||
};
|
||||
}
|
||||
|
||||
function showNotification({
|
||||
async function playNotificationSound(id: number) {
|
||||
const clients = await self.clients.matchAll({ type: 'window' }) as WindowClient[];
|
||||
const clientsInScope = clients.filter((client) => client.url === self.registration.scope);
|
||||
const client = clientsInScope[0];
|
||||
if (!client) return;
|
||||
if (clientsInScope.length === 0) return;
|
||||
client.postMessage({
|
||||
type: 'playNotificationSound',
|
||||
payload: { id },
|
||||
});
|
||||
}
|
||||
|
||||
async function showNotification({
|
||||
chatId,
|
||||
messageId,
|
||||
body,
|
||||
title,
|
||||
icon,
|
||||
}: NotificationData) {
|
||||
return self.registration.showNotification(title, {
|
||||
await self.registration.showNotification(title, {
|
||||
body,
|
||||
data: {
|
||||
chatId,
|
||||
messageId,
|
||||
},
|
||||
icon: 'icon-192x192.png',
|
||||
badge: 'icon-192x192.png',
|
||||
icon: icon || 'icon-192x192.png',
|
||||
badge: icon || 'icon-192x192.png',
|
||||
vibrate: [200, 100, 200],
|
||||
});
|
||||
await playNotificationSound(messageId || chatId || 0);
|
||||
}
|
||||
|
||||
export function handlePush(e: PushEvent) {
|
||||
|
||||
@ -38,6 +38,9 @@ export type NotifySettings = {
|
||||
hasBroadcastNotifications?: boolean;
|
||||
hasBroadcastMessagePreview?: boolean;
|
||||
hasContactJoinedNotifications?: boolean;
|
||||
hasWebNotifications: boolean;
|
||||
hasPushNotifications: boolean;
|
||||
notificationSoundVolume: number;
|
||||
};
|
||||
|
||||
export type LangCode = (
|
||||
|
||||
@ -1,9 +1,12 @@
|
||||
import { callApi } from '../api/gramjs';
|
||||
import { ApiChat, ApiMessage, ApiUser } from '../api/types';
|
||||
import {
|
||||
ApiChat, ApiMediaFormat, ApiMessage, ApiUser,
|
||||
} from '../api/types';
|
||||
import { renderActionMessageText } from '../components/common/helpers/renderActionMessageText';
|
||||
import { DEBUG } from '../config';
|
||||
import { getDispatch, getGlobal, setGlobal } from '../lib/teact/teactn';
|
||||
import {
|
||||
getChatAvatarHash,
|
||||
getChatTitle,
|
||||
getMessageAction,
|
||||
getMessageSenderName,
|
||||
@ -11,7 +14,7 @@ import {
|
||||
getPrivateChatUserId,
|
||||
isActionMessage,
|
||||
isChatChannel,
|
||||
selectIsChatMuted,
|
||||
selectIsChatMuted, selectShouldShowMessagePreview,
|
||||
} from '../modules/helpers';
|
||||
import { getTranslation } from './langProvider';
|
||||
import { addNotifyExceptions, replaceSettings } from '../modules/reducers';
|
||||
@ -19,6 +22,8 @@ import {
|
||||
selectChatMessage, selectNotifyExceptions, selectNotifySettings, selectUser,
|
||||
} from '../modules/selectors';
|
||||
import { IS_SERVICE_WORKER_SUPPORTED } from './environment';
|
||||
import * as mediaLoader from './mediaLoader';
|
||||
import { debounce } from './schedulers';
|
||||
|
||||
function getDeviceToken(subscription: PushSubscription) {
|
||||
const data = subscription.toJSON();
|
||||
@ -81,6 +86,38 @@ function checkIfNotificationsSupported() {
|
||||
}
|
||||
|
||||
const expirationTime = 12 * 60 * 60 * 1000; // 12 hours
|
||||
// Notification id is removed from soundPlayed cache after 3 seconds
|
||||
const soundPlayedDelay = 3 * 1000;
|
||||
const soundPlayed = new Set<number>();
|
||||
|
||||
async function playSound(id: number) {
|
||||
if (soundPlayed.has(id)) return;
|
||||
const { notificationSoundVolume } = selectNotifySettings(getGlobal());
|
||||
const volume = notificationSoundVolume / 10;
|
||||
if (volume === 0) return;
|
||||
|
||||
const audio = new Audio('/notification.mp3');
|
||||
audio.volume = volume;
|
||||
audio.setAttribute('mozaudiochannel', 'notification');
|
||||
audio.addEventListener('ended', () => {
|
||||
soundPlayed.add(id);
|
||||
}, { once: true });
|
||||
|
||||
setTimeout(() => {
|
||||
soundPlayed.delete(id);
|
||||
}, soundPlayedDelay);
|
||||
|
||||
try {
|
||||
await audio.play();
|
||||
} catch (error) {
|
||||
if (DEBUG) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('[PUSH] Unable to play notification sound');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const playNotificationSound = debounce(playSound, 1000, true, false);
|
||||
|
||||
function checkIfShouldResubscribe(subscription: PushSubscription | null) {
|
||||
const global = getGlobal();
|
||||
@ -202,8 +239,8 @@ export async function subscribe() {
|
||||
function checkIfShouldNotify(chat: ApiChat, isActive: boolean) {
|
||||
if (!areSettingsLoaded) return false;
|
||||
const global = getGlobal();
|
||||
if (selectIsChatMuted(chat, selectNotifySettings(global), selectNotifyExceptions(global)) || chat.isNotJoined
|
||||
|| !chat.isListed) {
|
||||
const isMuted = selectIsChatMuted(chat, selectNotifySettings(global), selectNotifyExceptions(global));
|
||||
if (isMuted || chat.isNotJoined || !chat.isListed) {
|
||||
return false;
|
||||
}
|
||||
// Dont show notification for active chat if client has focus
|
||||
@ -216,6 +253,7 @@ function getNotificationContent(chat: ApiChat, message: ApiMessage) {
|
||||
senderId,
|
||||
replyToMessageId,
|
||||
} = message;
|
||||
|
||||
const messageSender = senderId ? selectUser(global, senderId) : undefined;
|
||||
const messageAction = getMessageAction(message as ApiMessage);
|
||||
const actionTargetMessage = messageAction && replyToMessageId
|
||||
@ -227,29 +265,35 @@ function getNotificationContent(chat: ApiChat, message: ApiMessage) {
|
||||
} = messageAction || {};
|
||||
|
||||
const actionTargetUsers = actionTargetUserIds
|
||||
? actionTargetUserIds.map((userId) => selectUser(global, userId)).filter<ApiUser>(Boolean as any)
|
||||
? actionTargetUserIds.map((userId) => selectUser(global, userId))
|
||||
.filter<ApiUser>(Boolean as any)
|
||||
: undefined;
|
||||
const privateChatUserId = getPrivateChatUserId(chat);
|
||||
const privateChatUser = privateChatUserId ? selectUser(global, privateChatUserId) : undefined;
|
||||
let body: string;
|
||||
if (isActionMessage(message)) {
|
||||
const actionOrigin = chat && (isChatChannel(chat) || message.senderId === message.chatId)
|
||||
? chat
|
||||
: messageSender;
|
||||
body = renderActionMessageText(
|
||||
getTranslation,
|
||||
message,
|
||||
actionOrigin,
|
||||
actionTargetUsers,
|
||||
actionTargetMessage,
|
||||
actionTargetChatId,
|
||||
{ asPlain: true },
|
||||
) as string;
|
||||
} else {
|
||||
const senderName = getMessageSenderName(getTranslation, chat.id, messageSender);
|
||||
const summary = getMessageSummaryText(getTranslation, message);
|
||||
|
||||
body = senderName ? `${senderName}: ${summary}` : summary;
|
||||
let body: string;
|
||||
if (selectShouldShowMessagePreview(chat, selectNotifySettings(global), selectNotifyExceptions(global))) {
|
||||
if (isActionMessage(message)) {
|
||||
const actionOrigin = chat && (isChatChannel(chat) || message.senderId === message.chatId)
|
||||
? chat
|
||||
: messageSender;
|
||||
body = renderActionMessageText(
|
||||
getTranslation,
|
||||
message,
|
||||
actionOrigin,
|
||||
actionTargetUsers,
|
||||
actionTargetMessage,
|
||||
actionTargetChatId,
|
||||
{ asPlain: true },
|
||||
) as string;
|
||||
} else {
|
||||
const senderName = getMessageSenderName(getTranslation, chat.id, messageSender);
|
||||
const summary = getMessageSummaryText(getTranslation, message);
|
||||
|
||||
body = senderName ? `${senderName}: ${summary}` : summary;
|
||||
}
|
||||
} else {
|
||||
body = 'New message';
|
||||
}
|
||||
|
||||
return {
|
||||
@ -258,11 +302,22 @@ function getNotificationContent(chat: ApiChat, message: ApiMessage) {
|
||||
};
|
||||
}
|
||||
|
||||
async function getAvatar(chat: ApiChat) {
|
||||
const imageHash = getChatAvatarHash(chat);
|
||||
if (!imageHash) return undefined;
|
||||
let mediaData = mediaLoader.getFromMemory<ApiMediaFormat.BlobUrl>(imageHash);
|
||||
if (!mediaData) {
|
||||
await mediaLoader.fetch(imageHash, ApiMediaFormat.BlobUrl);
|
||||
mediaData = mediaLoader.getFromMemory<ApiMediaFormat.BlobUrl>(imageHash);
|
||||
}
|
||||
return mediaData;
|
||||
}
|
||||
|
||||
export async function showNewMessageNotification({
|
||||
chat,
|
||||
message,
|
||||
isActiveChat,
|
||||
}: { chat: ApiChat; message: Partial<ApiMessage>; isActiveChat: boolean}) {
|
||||
}: { chat: ApiChat; message: Partial<ApiMessage>; isActiveChat: boolean }) {
|
||||
if (!checkIfNotificationsSupported()) return;
|
||||
if (!message.id) return;
|
||||
|
||||
@ -274,6 +329,8 @@ export async function showNewMessageNotification({
|
||||
body,
|
||||
} = getNotificationContent(chat, message as ApiMessage);
|
||||
|
||||
const icon = await getAvatar(chat);
|
||||
|
||||
if (checkIfPushSupported()) {
|
||||
if (navigator.serviceWorker.controller) {
|
||||
// notify service worker about new message notification
|
||||
@ -282,6 +339,7 @@ export async function showNewMessageNotification({
|
||||
payload: {
|
||||
title,
|
||||
body,
|
||||
icon,
|
||||
chatId: chat.id,
|
||||
messageId: message.id,
|
||||
},
|
||||
@ -291,8 +349,8 @@ export async function showNewMessageNotification({
|
||||
const dispatch = getDispatch();
|
||||
const options: NotificationOptions = {
|
||||
body,
|
||||
icon: 'icon-192x192.png',
|
||||
badge: 'icon-192x192.png',
|
||||
icon,
|
||||
badge: icon,
|
||||
tag: message.id.toString(),
|
||||
};
|
||||
|
||||
@ -312,6 +370,11 @@ export async function showNewMessageNotification({
|
||||
window.focus();
|
||||
}
|
||||
};
|
||||
|
||||
// Play sound when notification is displayed
|
||||
notification.onshow = () => {
|
||||
playNotificationSound(message.id || chat.id);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ import { scriptUrl } from 'service-worker-loader!../serviceWorker';
|
||||
import { DEBUG } from '../config';
|
||||
import { getDispatch } from '../lib/teact/teactn';
|
||||
import { IS_ANDROID, IS_IOS, IS_SERVICE_WORKER_SUPPORTED } from './environment';
|
||||
import { notifyClientReady } from './notifications';
|
||||
import { notifyClientReady, playNotificationSound } from './notifications';
|
||||
|
||||
type WorkerAction = {
|
||||
type: string;
|
||||
@ -16,7 +16,12 @@ function handleWorkerMessage(e: MessageEvent) {
|
||||
const dispatch = getDispatch();
|
||||
switch (action.type) {
|
||||
case 'focusMessage':
|
||||
dispatch.focusMessage(action.payload);
|
||||
if (dispatch.focusMessage) {
|
||||
dispatch.focusMessage(action.payload);
|
||||
}
|
||||
break;
|
||||
case 'playNotificationSound':
|
||||
playNotificationSound(action.payload.id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user