More fixes for muted chats; PWA badge (#1133)

This commit is contained in:
Alexander Zinchuk 2021-06-03 21:22:49 +03:00
parent 9af2ce7d0b
commit ffe756414c
8 changed files with 62 additions and 9 deletions

View File

@ -100,3 +100,8 @@ interface HTMLElement {
webkitEnterFullscreen?: () => Promise<void>;
webkitRequestFullscreen?: () => Promise<void>;
}
interface Navigator {
// PWA badging extensions https://w3c.github.io/badging/
setAppBadge?(count: number): Promise<void>;
}

View File

@ -11,6 +11,7 @@ import {
ApiTypingStatus,
MAIN_THREAD_ID, ApiUser,
} from '../../api/types';
import { NotifyException, NotifySettings } from '../../types';
import {
MIN_SCREEN_WIDTH_FOR_STATIC_LEFT_COLUMN,
@ -27,6 +28,7 @@ import {
getMessageKey,
getChatTitle,
getSenderTitle,
selectIsChatMuted,
} from '../../modules/helpers';
import {
selectChat,
@ -43,6 +45,8 @@ import {
selectScheduledIds,
selectIsInSelectMode,
selectIsChatWithBot,
selectNotifySettings,
selectNotifyExceptions,
} from '../../modules/selectors';
import useEnsureMessage from '../../hooks/useEnsureMessage';
import useWindowSize from '../../hooks/useWindowSize';
@ -88,6 +92,8 @@ type StateProps = {
isChatWithSelf?: boolean;
isChatWithBot?: boolean;
lastSyncTime?: number;
notifySettings: NotifySettings;
notifyExceptions?: Record<number, NotifyException>;
};
type DispatchProps = Pick<GlobalActions, (
@ -115,6 +121,8 @@ const MiddleHeader: FC<OwnProps & StateProps & DispatchProps> = ({
isChatWithSelf,
isChatWithBot,
lastSyncTime,
notifySettings,
notifyExceptions,
openChatWithInfo,
pinMessage,
focusMessage,
@ -211,7 +219,9 @@ const MiddleHeader: FC<OwnProps & StateProps & DispatchProps> = ({
}
const count = currentChat.unreadCount || 0;
if (count && (!currentChat.isMuted || currentChat.unreadMentionsCount)) {
if (
count && (!selectIsChatMuted(currentChat, notifySettings, notifyExceptions) || currentChat.unreadMentionsCount)
) {
isActive = true;
}
@ -226,7 +236,7 @@ const MiddleHeader: FC<OwnProps & StateProps & DispatchProps> = ({
isActive,
totalCount,
};
}, [isLeftColumnHideable, chatsById]);
}, [isLeftColumnHideable, chatsById, notifySettings, notifyExceptions]);
const canToolsCollideWithChatInfo = (
windowWidth >= MIN_SCREEN_WIDTH_FOR_STATIC_LEFT_COLUMN
@ -444,6 +454,8 @@ export default memo(withGlobal<OwnProps>(
isChatWithSelf: selectIsChatWithSelf(global, chatId),
isChatWithBot: chat && selectIsChatWithBot(global, chat),
lastSyncTime,
notifySettings: selectNotifySettings(global),
notifyExceptions: selectNotifyExceptions(global),
};
const messagesById = selectChatMessages(global, chatId);

View File

@ -15,6 +15,7 @@ import {
import { initApi, callApi } from '../../../api/gramjs';
import { unsubscribe } from '../../../util/notifications';
import * as cacheApi from '../../../util/cacheApi';
import { updateAppBadge } from '../../../util/appBadge';
addReducer('initApi', (global: GlobalState, actions) => {
const sessionId = localStorage.getItem(GRAMJS_SESSION_ID_KEY) || undefined;
@ -111,6 +112,7 @@ addReducer('signOut', () => {
addReducer('reset', () => {
localStorage.removeItem(GRAMJS_SESSION_ID_KEY);
updateAppBadge(0);
cacheApi.clear(MEDIA_CACHE_NAME);
cacheApi.clear(MEDIA_CACHE_NAME_AVATARS);

View File

@ -5,6 +5,7 @@ import { ApiUpdate, MAIN_THREAD_ID } from '../../../api/types';
import { ARCHIVED_FOLDER_ID, MAX_ACTIVE_PINNED_CHATS } from '../../../config';
import { pick } from '../../../util/iteratees';
import { showNewMessageNotification } from '../../../util/notifications';
import { updateAppBadge } from '../../../util/appBadge';
import {
updateChat,
replaceChatListIds,
@ -17,12 +18,15 @@ import {
selectIsChatListed,
selectChatListType,
selectCurrentMessageList,
selectCountNotMutedUnread,
} from '../../selectors';
import { throttle } from '../../../util/schedulers';
const TYPING_STATUS_CLEAR_DELAY = 6000; // 6 seconds
// Enough to animate and mark as read in Message List
const CURRENT_CHAT_UNREAD_DELAY = 1000;
const runThrottledForUpdateAppBadge = throttle((cb) => cb(), CURRENT_CHAT_UNREAD_DELAY, true);
addReducer('apiUpdate', (global, actions, update: ApiUpdate) => {
switch (update['@type']) {
@ -32,8 +36,11 @@ addReducer('apiUpdate', (global, actions, update: ApiUpdate) => {
actions.loadTopChats();
}
setGlobal(updateChat(global, update.id, update.chat, update.newProfilePhoto));
const newGlobal = updateChat(global, update.id, update.chat, update.newProfilePhoto);
setGlobal(newGlobal);
const unreadCount = selectCountNotMutedUnread(newGlobal);
runThrottledForUpdateAppBadge(() => updateAppBadge(unreadCount));
break;
}
@ -125,6 +132,8 @@ addReducer('apiUpdate', (global, actions, update: ApiUpdate) => {
}));
}
const unreadCount = selectCountNotMutedUnread(getGlobal());
updateAppBadge(unreadCount);
showNewMessageNotification({ chat, message, isActiveChat });
break;

View File

@ -377,7 +377,7 @@ export function getFolderUnreadDialogs(
const hasActiveDialogs = listedChats.some((chat) => (
chat.unreadMentionsCount
|| (!chat.isMuted && (chat.unreadCount || chat.hasUnreadMark))
|| (!selectIsChatMuted(chat, notifySettings, notifyExceptions) && (chat.unreadCount || chat.hasUnreadMark))
));
return {

View File

@ -2,10 +2,11 @@ import { ApiChat, MAIN_THREAD_ID } from '../../api/types';
import { GlobalState } from '../../global/types';
import {
getPrivateChatUserId, isChatChannel, isChatPrivate, isHistoryClearMessage, isUserBot, isUserOnline,
getPrivateChatUserId, isChatChannel, isChatPrivate, isHistoryClearMessage, isUserBot, isUserOnline, selectIsChatMuted,
} from '../helpers';
import { selectUser } from './users';
import { ALL_FOLDER_ID, ARCHIVED_FOLDER_ID, MEMBERS_LOAD_SLICE } from '../../config';
import { selectNotifyExceptions, selectNotifySettings } from './settings';
export function selectChat(global: GlobalState, chatId: number): ApiChat | undefined {
return global.chats.byId[chatId];
@ -157,7 +158,11 @@ export function selectCountNotMutedUnread(global: GlobalState) {
return activeChatIds.reduce((acc, chatId) => {
const chat = chats[chatId];
if (chat && chat.unreadCount && !chat.isMuted) {
if (
chat
&& chat.unreadCount
&& !selectIsChatMuted(chat, selectNotifySettings(global), selectNotifyExceptions(global))
) {
return acc + chat.unreadCount;
}

14
src/util/appBadge.ts Normal file
View File

@ -0,0 +1,14 @@
import { DEBUG } from '../config';
export function updateAppBadge(unreadCount: number) {
if (typeof window.navigator.setAppBadge !== 'function') {
return;
}
window.navigator.setAppBadge(unreadCount).catch((err) => {
if (DEBUG) {
// eslint-disable-next-line no-console
console.error(err);
}
});
}

View File

@ -11,10 +11,13 @@ import {
getPrivateChatUserId,
isActionMessage,
isChatChannel,
selectIsChatMuted,
} from '../modules/helpers';
import { getTranslation } from './langProvider';
import { replaceSettings } from '../modules/reducers';
import { selectChatMessage, selectUser } from '../modules/selectors';
import {
selectChatMessage, selectNotifyExceptions, selectNotifySettings, selectUser,
} from '../modules/selectors';
import { IS_SERVICE_WORKER_SUPPORTED } from './environment';
function getDeviceToken(subscription: PushSubscription) {
@ -187,12 +190,15 @@ export async function subscribe() {
}
function checkIfShouldNotify(chat: ApiChat, isActive: boolean) {
if (chat.isMuted || chat.isNotJoined) return false;
const global = getGlobal();
if (selectIsChatMuted(chat, selectNotifySettings(global), selectNotifyExceptions(global)) || chat.isNotJoined) {
return false;
}
// Dont show notification for active chat if client has focus
if (isActive && document.hasFocus()) return false;
const global = getGlobal();
switch (chat.type) {
case 'chatTypePrivate':
case 'chatTypeSecret':