From 833cb1d6d360c3c7c706a1c2964edaa760900c59 Mon Sep 17 00:00:00 2001 From: Alexander Zinchuk Date: Sun, 18 Apr 2021 23:57:52 +0300 Subject: [PATCH] Hightlight browser tab on incoming messages --- public/favicon-unread-32x32.png | Bin 0 -> 853 bytes src/components/main/Main.tsx | 65 +++++++++++++++++++++++++++----- src/modules/selectors/chats.ts | 19 ++++++++++ 3 files changed, 75 insertions(+), 9 deletions(-) create mode 100644 public/favicon-unread-32x32.png diff --git a/public/favicon-unread-32x32.png b/public/favicon-unread-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..5c93f060aa2d6d1c036d2ad97ca3c41f87078026 GIT binary patch literal 853 zcmV-b1FHOqP)?|r`^q^!epqWofx27IJG z-`!RQ9VHS+0Ga@>9l+M$^A3P-fG~xi=L3jm?JMKoc~8AVCyJ8f%MTCTT-)b}(ggrB zioi5(-eaI8gWTIMFK>CD1~CF45A)xC&AI{5c>onfq8Z~yYhzVZ~%$=rf9ta7-@EwEP={Q8h0)fAa6fPm9 zB0~td5wSqO_H$J+yVm4F0F)HE{JY?*3Gfa^j3gnCXr%r26qZ?w9%0J<3XPVa9) z{-q=U*O!yH7)03*zyk=eu+kjA#In63f$87q0xhEPP{W+=*F$)5VUT-(XNQ_u+prZA+B&0A~Und5KuLM>&L37 z?>1nRqOriRjtjIuIk@(;hn`nIQ&-0pVuGgTt&>D}n02~Z_JtqZVqPf&d(n|*86Kb@qcR}h65Bt6krL)iP&Tc~4 z$g)$oKX8C^i@&mB!eoFSTK_BBpQu-GcDgcRdNm8Z^j8)uac|kiqqeNbTKEnF^wsp! zWg44*YHw71T?vRoy!zl^=mvcX+Yx{g0c*BEtxTS_tOc(^0QBDT03t4M1;8LGa3KJC z3wSOV3BovRF)=_8Ld4^UgD@ox1Cqbaf>G_mG|XFw3a$g5YF;7ATZ;d<5+*k=zZ9o6 zqp&jhtyMy-uNRE?KH7{}NW2}V4jo)J^LE2z?ZbAQG>~LLXwzC&qU1qEKalWc{urJ$ zlJU(hz>|@>(k7$uoPH!z@5vfU*J~B!e7>QS2gRZw(uAuIl>g^pB3-eePct; +const APP_NAME = 'Telegram'; const ANIMATION_DURATION = 350; +const NOTIFICATION_INTERVAL = 1000; -let timeout: number | undefined; +let rightColumnAnimationTimeout: number | undefined; +let notificationInterval: number | undefined; let DEBUG_isLogged = false; @@ -90,18 +99,43 @@ const Main: FC = ({ document.body.classList.add('animating-right-column'); dispatchHeavyAnimationEvent(ANIMATION_DURATION + ANIMATION_END_DELAY); - if (timeout) { - clearTimeout(timeout); - timeout = undefined; + if (rightColumnAnimationTimeout) { + clearTimeout(rightColumnAnimationTimeout); + rightColumnAnimationTimeout = undefined; } - timeout = window.setTimeout(() => { + rightColumnAnimationTimeout = window.setTimeout(() => { document.body.classList.remove('animating-right-column'); - timeout = undefined; + rightColumnAnimationTimeout = undefined; }, ANIMATION_DURATION + ANIMATION_END_DELAY); } }, [animationLevel, isRightColumnShown]); + useBackgroundMode(() => { + const initialUnread = selectCountNotMutedUnread(getGlobal()); + let index = 0; + + notificationInterval = window.setInterval(() => { + if (index % 2 === 0) { + const newUnread = selectCountNotMutedUnread(getGlobal()) - initialUnread; + if (newUnread > 0) { + document.title = `${newUnread} notification${newUnread > 1 ? 's' : ''}`; + updateIcon(true); + } + } else { + document.title = APP_NAME; + updateIcon(false); + } + + index++; + }, NOTIFICATION_INTERVAL); + }, () => { + clearInterval(notificationInterval); + notificationInterval = undefined; + document.title = APP_NAME; + updateIcon(false); + }); + function stopEvent(e: React.MouseEvent) { e.preventDefault(); e.stopPropagation(); @@ -120,6 +154,19 @@ const Main: FC = ({ ); }; +function updateIcon(asUnread: boolean) { + document.querySelectorAll('link[rel="icon"]') + .forEach((link) => { + if (asUnread) { + if (!link.href.includes('favicon-unread')) { + link.href = link.href.replace('favicon', 'favicon-unread'); + } + } else { + link.href = link.href.replace('favicon-unread', 'favicon'); + } + }); +} + export default memo(withGlobal( (global): StateProps => ({ animationLevel: global.settings.byKey.animationLevel, diff --git a/src/modules/selectors/chats.ts b/src/modules/selectors/chats.ts index cf090de8f..60900bdb9 100644 --- a/src/modules/selectors/chats.ts +++ b/src/modules/selectors/chats.ts @@ -150,3 +150,22 @@ export function selectChatByUsername(global: GlobalState, username: string) { (chat) => chat.username && chat.username.toLowerCase() === usernameLowered, ); } + +export function selectCountNotMutedUnread(global: GlobalState) { + const activeChatIds = global.chats.listIds.active; + if (!activeChatIds) { + return 0; + } + + const chats = global.chats.byId; + + return activeChatIds.reduce((acc, chatId) => { + const chat = chats[chatId]; + + if (chat && chat.unreadCount && !chat.isMuted) { + return acc + chat.unreadCount; + } + + return acc; + }, 0); +}