Push notifications: Fixes for not joined chats (#1099)
This commit is contained in:
parent
f964517a25
commit
c94163803e
@ -74,11 +74,17 @@ function getNotificationData(data: PushData): NotificationData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function showNotification({
|
function showNotification({
|
||||||
chatId, messageId, body, title,
|
chatId,
|
||||||
|
messageId,
|
||||||
|
body,
|
||||||
|
title,
|
||||||
}: NotificationData) {
|
}: NotificationData) {
|
||||||
return self.registration.showNotification(title, {
|
return self.registration.showNotification(title, {
|
||||||
body,
|
body,
|
||||||
data: { chatId, messageId },
|
data: {
|
||||||
|
chatId,
|
||||||
|
messageId,
|
||||||
|
},
|
||||||
icon: 'icon-192x192.png',
|
icon: 'icon-192x192.png',
|
||||||
badge: 'icon-192x192.png',
|
badge: 'icon-192x192.png',
|
||||||
vibrate: [200, 100, 200],
|
vibrate: [200, 100, 200],
|
||||||
@ -110,8 +116,11 @@ export function handlePush(e: PushEvent) {
|
|||||||
e.waitUntil(showNotification(notification));
|
e.waitUntil(showNotification(notification));
|
||||||
}
|
}
|
||||||
|
|
||||||
function focusChatMessage(client: WindowClient, data: { chatId?: number; messageId?: number }) {
|
async function focusChatMessage(client: WindowClient, data: { chatId?: number; messageId?: number }) {
|
||||||
const { chatId, messageId } = data;
|
const {
|
||||||
|
chatId,
|
||||||
|
messageId,
|
||||||
|
} = data;
|
||||||
if (!chatId) return;
|
if (!chatId) return;
|
||||||
client.postMessage({
|
client.postMessage({
|
||||||
type: 'focusMessage',
|
type: 'focusMessage',
|
||||||
@ -120,6 +129,15 @@ function focusChatMessage(client: WindowClient, data: { chatId?: number; message
|
|||||||
messageId,
|
messageId,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
// Catch "focus not allowed" DOM Exceptions
|
||||||
|
try {
|
||||||
|
await client.focus();
|
||||||
|
} catch (error) {
|
||||||
|
if (DEBUG) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.warn('[SW] ', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function handleNotificationClick(e: NotificationEvent) {
|
export function handleNotificationClick(e: NotificationEvent) {
|
||||||
@ -129,10 +147,10 @@ export function handleNotificationClick(e: NotificationEvent) {
|
|||||||
const notifyClients = async () => {
|
const notifyClients = async () => {
|
||||||
const clients = await self.clients.matchAll({ type: 'window' }) as WindowClient[];
|
const clients = await self.clients.matchAll({ type: 'window' }) as WindowClient[];
|
||||||
const clientsInScope = clients.filter((client) => client.url === self.registration.scope);
|
const clientsInScope = clients.filter((client) => client.url === self.registration.scope);
|
||||||
await Promise.all(clientsInScope.map(async (client) => {
|
e.waitUntil(Promise.all(clientsInScope.map((client) => {
|
||||||
await client.focus();
|
|
||||||
clickBuffer[client.id] = data;
|
clickBuffer[client.id] = data;
|
||||||
}));
|
return focusChatMessage(client, data);
|
||||||
|
})));
|
||||||
if (!self.clients.openWindow || clientsInScope.length > 0) return undefined;
|
if (!self.clients.openWindow || clientsInScope.length > 0) return undefined;
|
||||||
|
|
||||||
// If there is no opened client we need to open one and wait until it is fully loaded
|
// If there is no opened client we need to open one and wait until it is fully loaded
|
||||||
@ -147,12 +165,16 @@ export function handleNotificationClick(e: NotificationEvent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function handleClientMessage(e: ExtendableMessageEvent) {
|
export function handleClientMessage(e: ExtendableMessageEvent) {
|
||||||
|
if (DEBUG) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log('[SW] New message from client', e);
|
||||||
|
}
|
||||||
if (!e.data) return;
|
if (!e.data) return;
|
||||||
const source = e.source as WindowClient;
|
const source = e.source as WindowClient;
|
||||||
if (e.data.type === 'clientReady') {
|
if (e.data.type === 'clientReady') {
|
||||||
// focus on chat message when client is fully ready
|
// focus on chat message when client is fully ready
|
||||||
if (clickBuffer[source.id]) {
|
if (clickBuffer[source.id]) {
|
||||||
focusChatMessage(source, clickBuffer[source.id]);
|
e.waitUntil(focusChatMessage(source, clickBuffer[source.id]));
|
||||||
delete clickBuffer[source.id];
|
delete clickBuffer[source.id];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { callApi } from '../api/gramjs';
|
|||||||
import { ApiChat, ApiMessage } from '../api/types';
|
import { ApiChat, ApiMessage } from '../api/types';
|
||||||
import { renderActionMessageText } from '../components/common/helpers/renderActionMessageText';
|
import { renderActionMessageText } from '../components/common/helpers/renderActionMessageText';
|
||||||
import { DEBUG } from '../config';
|
import { DEBUG } from '../config';
|
||||||
import { getDispatch, getGlobal } from '../lib/teact/teactn';
|
import { getDispatch, getGlobal, setGlobal } from '../lib/teact/teactn';
|
||||||
import {
|
import {
|
||||||
getChatTitle,
|
getChatTitle,
|
||||||
getMessageAction,
|
getMessageAction,
|
||||||
@ -12,6 +12,7 @@ import {
|
|||||||
isActionMessage,
|
isActionMessage,
|
||||||
isChatChannel,
|
isChatChannel,
|
||||||
} from '../modules/helpers';
|
} from '../modules/helpers';
|
||||||
|
import { replaceSettings } from '../modules/reducers';
|
||||||
import { selectChatMessage, selectUser } from '../modules/selectors';
|
import { selectChatMessage, selectUser } from '../modules/selectors';
|
||||||
import { IS_SERVICE_WORKER_SUPPORTED } from './environment';
|
import { IS_SERVICE_WORKER_SUPPORTED } from './environment';
|
||||||
|
|
||||||
@ -122,9 +123,22 @@ export async function unsubscribe() {
|
|||||||
await unsubscribeFromPush(subscription);
|
await unsubscribeFromPush(subscription);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load notification settings from the api
|
||||||
|
async function loadNotificationsSettings() {
|
||||||
|
const result = await callApi('loadNotificationsSettings');
|
||||||
|
if (!result) return;
|
||||||
|
setGlobal(replaceSettings(getGlobal(), result));
|
||||||
|
}
|
||||||
|
|
||||||
export async function subscribe() {
|
export async function subscribe() {
|
||||||
await requestPermission();
|
loadNotificationsSettings();
|
||||||
if (!checkIfPushSupported()) return;
|
|
||||||
|
if (!checkIfPushSupported()) {
|
||||||
|
// Ask for notification permissions only if service worker notifications are not supported
|
||||||
|
// As pushManager.subscribe automatically triggers permission popup
|
||||||
|
await requestPermission();
|
||||||
|
return;
|
||||||
|
}
|
||||||
const serviceWorkerRegistration = await navigator.serviceWorker.ready;
|
const serviceWorkerRegistration = await navigator.serviceWorker.ready;
|
||||||
let subscription = await serviceWorkerRegistration.pushManager.getSubscription();
|
let subscription = await serviceWorkerRegistration.pushManager.getSubscription();
|
||||||
if (!checkIfShouldResubscribe(subscription)) return;
|
if (!checkIfShouldResubscribe(subscription)) return;
|
||||||
@ -157,17 +171,22 @@ export async function subscribe() {
|
|||||||
// and / or gcm_user_visible_only
|
// and / or gcm_user_visible_only
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log('[PUSH] Unable to subscribe to push.', error);
|
console.log('[PUSH] Unable to subscribe to push.', error);
|
||||||
|
|
||||||
|
// Request permissions and fall back to local notifications
|
||||||
|
// if pushManager.subscribe was aborted due to invalid VAPID key.
|
||||||
|
if (error.code === DOMException.ABORT_ERR) {
|
||||||
|
await requestPermission();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function checkIfShouldNotify(chat: ApiChat, isActive: boolean) {
|
function checkIfShouldNotify(chat: ApiChat, isActive: boolean) {
|
||||||
if (chat.isMuted) return false;
|
if (chat.isMuted || chat.isNotJoined) return false;
|
||||||
|
|
||||||
// Dont show notification for active chat if client has focus
|
// Dont show notification for active chat if client has focus
|
||||||
if (isActive && document.hasFocus()) return false;
|
if (isActive && document.hasFocus()) return false;
|
||||||
|
|
||||||
await getDispatch().loadNotificationsSettings();
|
|
||||||
const global = getGlobal();
|
const global = getGlobal();
|
||||||
switch (chat.type) {
|
switch (chat.type) {
|
||||||
case 'chatTypePrivate':
|
case 'chatTypePrivate':
|
||||||
@ -226,7 +245,7 @@ function getNotificationContent(chat: ApiChat, message: ApiMessage) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function showNewMessageNotification({
|
export function showNewMessageNotification({
|
||||||
chat,
|
chat,
|
||||||
message,
|
message,
|
||||||
isActiveChat,
|
isActiveChat,
|
||||||
@ -234,8 +253,7 @@ export async function showNewMessageNotification({
|
|||||||
if (!checkIfNotificationsSupported()) return;
|
if (!checkIfNotificationsSupported()) return;
|
||||||
if (!message.id) return;
|
if (!message.id) return;
|
||||||
|
|
||||||
const shouldNotify = await checkIfShouldNotify(chat, isActiveChat);
|
if (!checkIfShouldNotify(chat, isActiveChat)) return;
|
||||||
if (!shouldNotify) return;
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
title,
|
title,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user