Browse Source

Update icons

Unread badge
master
Eduard Kuzmenko 2 years ago
parent
commit
bad2574647
  1. 2
      src/components/sidebarLeft/index.ts
  2. 45
      src/index.hbs
  3. 3
      src/index.ts
  4. 28
      src/lib/appManagers/appDialogsManager.ts
  5. 16
      src/lib/appManagers/appMessagesManager.ts
  6. 13
      src/lib/appManagers/appNotificationsManager.ts
  7. 2
      src/lib/appManagers/createManagers.ts
  8. 15
      src/lib/appManagers/uiNotificationsManager.ts
  9. 61
      src/lib/storages/dialogs.ts
  10. 3
      webpack.common.js

2
src/components/sidebarLeft/index.ts

@ -310,7 +310,7 @@ export class AppSidebarLeft extends SidebarSlider {
rootScope.addEventListener('folder_unread', (folder) => { rootScope.addEventListener('folder_unread', (folder) => {
if(folder.id === 1) { if(folder.id === 1) {
// const count = folder.unreadMessagesCount; // const count = folder.unreadMessagesCount;
const count = folder.unreadDialogsCount; const count = folder.unreadPeerIds.size;
this.archivedCount.innerText = '' + formatNumber(count, 1); this.archivedCount.innerText = '' + formatNumber(count, 1);
this.archivedCount.classList.toggle('hide', !count); this.archivedCount.classList.toggle('hide', !count);
} }

45
src/index.hbs

@ -3,26 +3,45 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Telegram Web</title> <title>{{htmlWebpackPlugin.options.title}}</title>
<meta name="description" content="Telegram is a cloud-based mobile and desktop messaging app with a focus on security and speed."> <meta name="description" content="{{htmlWebpackPlugin.options.description}}">
<!--<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />--> <!--<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />-->
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover"> <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<meta name="mobile-web-app-capable" content="yes">
<!-- do not paste other icons here, only change these. 'icon' type must be single --> <meta name="mobile-web-app-title" content="{{htmlWebpackPlugin.options.title}}">
<link rel="apple-touch-icon" sizes="180x180" href="assets/img/apple-touch-icon.png?v=jw3mK7G9Ry"> <meta name="apple-mobile-web-app-capable" content="yes">
<link rel="icon" type="image/png" sizes="32x32" href="assets/img/favicon-32x32.png?v=jw3mK7G9Ry"> <meta name="apple-mobile-web-app-title" content="{{htmlWebpackPlugin.options.title}}">
<!--<link rel="icon" type="image/png" sizes="192x192" href="assets/img/android-chrome-192x192.png?v=jw3mK7G9Ry"> <meta name="application-name" content="{{htmlWebpackPlugin.options.title}}">
<link rel="icon" type="image/png" sizes="16x16" href="assets/img/favicon-16x16.png?v=jw3mK7G9Ry">-->
<link rel="manifest" href="site.webmanifest?v=jw3mK7G9Aq">
<link rel="mask-icon" href="assets/img/safari-pinned-tab.svg?v=jw3mK7G9Ry" color="#3390ec">
<!--<link rel="shortcut icon" href="assets/img/favicon.ico?v=jw3mK7G9Ry">-->
<meta name="apple-mobile-web-app-title" content="Telegram WebK">
<meta name="application-name" content="Telegram WebK">
<meta name="msapplication-TileColor" content="#2d89ef"> <meta name="msapplication-TileColor" content="#2d89ef">
<meta name="msapplication-TileImage" content="assets/img/mstile-144x144.png?v=jw3mK7G9Ry"> <meta name="msapplication-TileImage" content="assets/img/mstile-144x144.png?v=jw3mK7G9Ry">
<meta name="msapplication-config" content="browserconfig.xml?v=jw3mK7G9Ry"> <meta name="msapplication-config" content="browserconfig.xml?v=jw3mK7G9Ry">
<meta name="theme-color" content="#ffffff"> <meta name="theme-color" content="#ffffff">
<meta name="color-scheme" content="light"> <meta name="color-scheme" content="light">
<meta name="google" content="notranslate">
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website">
<meta property="og:url" content="{{htmlWebpackPlugin.options.url}}">
<meta property="og:title" content="{{htmlWebpackPlugin.options.title}}">
<meta property="og:description" content="{{htmlWebpackPlugin.options.description}}">
<meta property="og:image" content="assets/img/android-chrome-192x192.png?v=jw3mK7G9Ry">
<!-- Twitter -->
<meta property="twitter:card" content="summary_large_image">
<meta property="twitter:url" content="{{htmlWebpackPlugin.options.url}}">
<meta property="twitter:title" content="{{htmlWebpackPlugin.options.title}}">
<meta property="twitter:description" content="{{htmlWebpackPlugin.options.description}}">
<meta property="twitter:image" content="assets/img/android-chrome-192x192.png?v=jw3mK7G9Ry">
<link rel="apple-touch-icon" sizes="180x180" href="assets/img/apple-touch-icon.png?v=jw3mK7G9Ry">
<link rel="icon" type="image/png" sizes="16x16" href="assets/img/favicon-16x16.png?v=jw3mK7G9Ry">
<link rel="icon" type="image/png" sizes="32x32" href="assets/img/favicon-32x32.png?v=jw3mK7G9Ry">
<link rel="icon" type="image/png" sizes="192x192" href="assets/img/android-chrome-192x192.png?v=jw3mK7G9Ry">
<link rel="alternate icon" href="assets/img/favicon.ico?v=jw3mK7G9Ry" type="image/x-icon">
<link rel="mask-icon" href="assets/img/safari-pinned-tab.svg?v=jw3mK7G9Ry" color="#3390ec">
<link rel="manifest" id="manifest">
{{#each htmlWebpackPlugin.files.css}} {{#each htmlWebpackPlugin.files.css}}
<link rel="stylesheet" href="{{this}}"> <link rel="stylesheet" href="{{this}}">
{{/each}} {{/each}}

3
src/index.ts

@ -32,6 +32,9 @@ document.addEventListener('DOMContentLoaded', async() => {
rootScope.managers = getProxiedManagers(); rootScope.managers = getProxiedManagers();
const manifest = document.getElementById('manifest') as HTMLLinkElement;
manifest.href = `site${IS_APPLE && !IS_APPLE_MOBILE ? '_apple' : ''}.webmanifest?v=jw3mK7G9Aq`;
singleInstance.start(); singleInstance.start();
// We listen to the resize event (https://css-tricks.com/the-trick-to-viewport-units-on-mobile/) // We listen to the resize event (https://css-tricks.com/the-trick-to-viewport-units-on-mobile/)

28
src/lib/appManagers/appDialogsManager.ts

@ -205,7 +205,6 @@ export class AppDialogsManager {
} }
} = {}; } = {};
private showFiltersPromise: Promise<void>; private showFiltersPromise: Promise<void>;
private allUnreadCount: HTMLElement;
private sliceTimeout: number; private sliceTimeout: number;
@ -236,8 +235,6 @@ export class AppDialogsManager {
this.contextMenu = new DialogsContextMenu(managers); this.contextMenu = new DialogsContextMenu(managers);
this.allUnreadCount = this.folders.menu.querySelector('.badge');
this.folders.menuScrollContainer = this.folders.menu.parentElement; this.folders.menuScrollContainer = this.folders.menu.parentElement;
this.onListLengthChange = debounce(this._onListLengthChange, 100, false, true); this.onListLengthChange = debounce(this._onListLengthChange, 100, false, true);
@ -524,7 +521,6 @@ export class AppDialogsManager {
rootScope.addEventListener('dialog_notify_settings', (dialog) => { rootScope.addEventListener('dialog_notify_settings', (dialog) => {
this.validateDialogForFilter(dialog); this.validateDialogForFilter(dialog);
this.setUnreadMessagesN({dialog}); // возможно это не нужно, но нужно менять is-muted this.setUnreadMessagesN({dialog}); // возможно это не нужно, но нужно менять is-muted
this.setFiltersUnreadCount();
}); });
rootScope.addEventListener('dialog_draft', ({dialog, drop, peerId}) => { rootScope.addEventListener('dialog_draft', ({dialog, drop, peerId}) => {
@ -667,20 +663,6 @@ export class AppDialogsManager {
} }
} }
if(state.notifySettings) {
const promises: Promise<any>[] = [];
for(const key in state.notifySettings) {
assumeType<Exclude<NotifyPeer['_'], 'notifyPeer'>>(key);
const promise = this.managers.appNotificationsManager.savePeerSettings({
key,
settings: state.notifySettings[key]
});
promises.push(promise);
}
await Promise.all(promises);
}
this.managers.appNotificationsManager.getNotifyPeerTypeSettings(); this.managers.appNotificationsManager.getNotifyPeerTypeSettings();
await (await loadDialogsPromise).renderPromise; await (await loadDialogsPromise).renderPromise;
@ -755,13 +737,17 @@ export class AppDialogsManager {
}; };
private async setFilterUnreadCount(filterId: number) { private async setFilterUnreadCount(filterId: number) {
const unreadSpan = filterId === 0 ? this.allUnreadCount : this.filtersRendered[filterId]?.unread; if(filterId === 0) {
return;
}
const unreadSpan = this.filtersRendered[filterId]?.unread;
if(!unreadSpan) { if(!unreadSpan) {
return; return;
} }
const {foundUnmuted, unreadCount} = await this.managers.dialogsStorage.getFolderUnreadCount(filterId); const {unreadUnmutedCount, unreadCount} = await this.managers.dialogsStorage.getFolderUnreadCount(filterId);
unreadSpan.classList.toggle('badge-gray', !foundUnmuted); unreadSpan.classList.toggle('badge-gray', !unreadUnmutedCount);
unreadSpan.innerText = unreadCount ? '' + unreadCount : ''; unreadSpan.innerText = unreadCount ? '' + unreadCount : '';
} }

16
src/lib/appManagers/appMessagesManager.ts

@ -3113,18 +3113,14 @@ export class AppMessagesManager extends AppManager {
if(!this.migratedFromTo[migrateFrom] && if(!this.migratedFromTo[migrateFrom] &&
!this.migratedToFrom[migrateTo] && !this.migratedToFrom[migrateTo] &&
this.appChatsManager.hasChat(migrateTo.toChatId())) { this.appChatsManager.hasChat(migrateTo.toChatId())) {
const fromChat = this.appChatsManager.getChat(migrateFrom.toChatId()); const fromChat: Chat.chat = this.appChatsManager.getChat(migrateFrom.toChatId());
if(fromChat && if(fromChat?.migrated_to && (fromChat.migrated_to as InputChannel.inputChannel).channel_id === migrateTo.toChatId()) {
fromChat.migrated_to && this.migratedFromTo[migrateFrom] = migrateTo;
fromChat.migrated_to.channel_id === migrateTo.toChatId()) { this.migratedToFrom[migrateTo] = migrateFrom;
this.migratedFromTo[migrateFrom] = migrateTo;
this.migratedToFrom[migrateTo] = migrateFrom;
//setTimeout(() => { this.rootScope.dispatchEvent('dialog_migrate', {migrateFrom, migrateTo});
this.rootScope.dispatchEvent('dialog_migrate', {migrateFrom, migrateTo});
this.dialogsStorage.dropDialogWithEvent(migrateFrom); this.dialogsStorage.dropDialogWithEvent(migrateFrom);
//}, 100);
} }
} }
} }

13
src/lib/appManagers/appNotificationsManager.ts

@ -17,6 +17,7 @@ import convertInputKeyToKey from "../../helpers/string/convertInputKeyToKey";
import { AppManager } from "./manager"; import { AppManager } from "./manager";
import getPeerId from "./utils/peers/getPeerId"; import getPeerId from "./utils/peers/getPeerId";
import ctx from "../../environment/ctx"; import ctx from "../../environment/ctx";
import assumeType from "../../helpers/assumeType";
type ImSadAboutIt = Promise<PeerNotifySettings> | PeerNotifySettings; type ImSadAboutIt = Promise<PeerNotifySettings> | PeerNotifySettings;
export class AppNotificationsManager extends AppManager { export class AppNotificationsManager extends AppManager {
@ -50,6 +51,18 @@ export class AppNotificationsManager extends AppManager {
this.rootScope.dispatchEvent('notify_settings', update); this.rootScope.dispatchEvent('notify_settings', update);
} }
}); });
return this.appStateManager.getState().then((state) => {
if(state.notifySettings) {
for(const key in state.notifySettings) {
assumeType<Exclude<NotifyPeer['_'], 'notifyPeer'>>(key);
this.savePeerSettings({
key,
settings: state.notifySettings[key]
});
}
}
});
} }
public getNotifySettings(peer: InputNotifyPeer): ImSadAboutIt { public getNotifySettings(peer: InputNotifyPeer): ImSadAboutIt {

2
src/lib/appManagers/createManagers.ts

@ -108,7 +108,7 @@ export default function createManagers(appStoragesManager: AppStoragesManager, u
const promises: Array<Promise<(() => void) | void> | void>[] = []; const promises: Array<Promise<(() => void) | void> | void>[] = [];
let names = Object.keys(managers) as (keyof T)[]; let names = Object.keys(managers) as (keyof T)[];
names.unshift('appUsersManager', 'appChatsManager', 'appMessagesManager', 'dialogsStorage'); names.unshift('appUsersManager', 'appChatsManager', 'appNotificationsManager', 'appMessagesManager', 'dialogsStorage');
names = filterUnique(names); names = filterUnique(names);
for(const name of names) { for(const name of names) {
const manager = managers[name]; const manager = managers[name];

15
src/lib/appManagers/uiNotificationsManager.ts

@ -82,11 +82,14 @@ export class UiNotificationsManager {
private pushInited = false; private pushInited = false;
private managers: AppManagers; private managers: AppManagers;
private setAppBadge: (contents?: any) => Promise<void>;
construct(managers: AppManagers) { construct(managers: AppManagers) {
this.managers = managers; this.managers = managers;
navigator.vibrate = navigator.vibrate || (navigator as any).mozVibrate || (navigator as any).webkitVibrate; navigator.vibrate = navigator.vibrate || (navigator as any).mozVibrate || (navigator as any).webkitVibrate;
this.setAppBadge = (navigator as any).setAppBadge && (navigator as any).setAppBadge.bind(navigator);
this.setAppBadge && this.setAppBadge(0);
this.notificationsUiSupport = ('Notification' in window) || ('mozNotification' in navigator); this.notificationsUiSupport = ('Notification' in window) || ('mozNotification' in navigator);
@ -125,6 +128,14 @@ export class UiNotificationsManager {
rootScope.addEventListener('notification_cancel', (str) => { rootScope.addEventListener('notification_cancel', (str) => {
this.cancel(str); this.cancel(str);
}); });
if(this.setAppBadge) {
rootScope.addEventListener('folder_unread', (folder) => {
if(folder.id === 0) {
this.setAppBadge(folder.unreadUnmutedPeerIds.size);
}
});
}
webPushApiManager.addEventListener('push_init', (tokenData) => { webPushApiManager.addEventListener('push_init', (tokenData) => {
this.pushInited = true; this.pushInited = true;
@ -280,7 +291,7 @@ export class UiNotificationsManager {
private toggleToggler(enable = idleController.isIdle) { private toggleToggler(enable = idleController.isIdle) {
if(IS_MOBILE) return; if(IS_MOBILE) return;
const resetTitle = () => { const resetTitle = (isBlink?: boolean) => {
this.titleChanged = false; this.titleChanged = false;
document.title = this.titleBackup; document.title = this.titleBackup;
this.setFavicon(); this.setFavicon();
@ -297,7 +308,7 @@ export class UiNotificationsManager {
if(!count) { if(!count) {
this.toggleToggler(false); this.toggleToggler(false);
} else if(this.titleChanged) { } else if(this.titleChanged) {
resetTitle(); resetTitle(true);
} else { } else {
this.titleChanged = true; this.titleChanged = true;
document.title = I18n.format('Notifications.Count', true, [count]); document.title = I18n.format('Notifications.Count', true, [count]);

61
src/lib/storages/dialogs.ts

@ -45,7 +45,8 @@ export type Folder = {
dialogs: Dialog[], dialogs: Dialog[],
id: number, id: number,
unreadMessagesCount: number, unreadMessagesCount: number,
unreadDialogsCount: number, unreadPeerIds: Set<PeerId>,
unreadUnmutedPeerIds: Set<PeerId>,
dispatchUnreadTimeout?: number dispatchUnreadTimeout?: number
}; };
@ -131,6 +132,7 @@ export default class DialogsStorage extends AppManager {
this.rootScope.addEventListener('dialog_notify_settings', (dialog) => { this.rootScope.addEventListener('dialog_notify_settings', (dialog) => {
this.processDialogForFilters(dialog); this.processDialogForFilters(dialog);
this.prepareDialogUnreadCountModifying(dialog)();
}); });
this.rootScope.addEventListener('chat_update', (chatId) => { this.rootScope.addEventListener('chat_update', (chatId) => {
@ -287,7 +289,14 @@ export default class DialogsStorage extends AppManager {
public getFolder(id: number) { public getFolder(id: number) {
let folder = this.folders[id]; let folder = this.folders[id];
if(!folder) { if(!folder) {
folder = this.folders[id] = {dialogs: [], id, unreadMessagesCount: 0, unreadDialogsCount: 0}; folder = this.folders[id] = {
dialogs: [],
id,
unreadMessagesCount: 0,
unreadPeerIds: new Set(),
unreadUnmutedPeerIds: new Set()
};
defineNotNumerableProperties(folder, ['dispatchUnreadTimeout']); defineNotNumerableProperties(folder, ['dispatchUnreadTimeout']);
} }
@ -326,14 +335,14 @@ export default class DialogsStorage extends AppManager {
const filter = this.filtersStorage.getFilter(filterId); const filter = this.filtersStorage.getFilter(filterId);
return getDialogIndexKey(filter.orderIndex); return getDialogIndexKey(filter.orderIndex);
} }
public isPeerUnmuted(peerId: PeerId) {
return !this.appNotificationsManager.isPeerLocalMuted(peerId, true);
}
public getFolderUnreadCount(filterId: number) { public getFolderUnreadCount(filterId: number) {
const folder = this.getFolder(filterId); const folder = this.getFolder(filterId);
const foundUnmuted = filterId === 0 || !!folder.dialogs.find((dialog) => { return {unreadUnmutedCount: folder.unreadUnmutedPeerIds.size, unreadCount: folder.unreadPeerIds.size};
return (dialog.unread_count || dialog.pFlags.unread_mark) && !this.appNotificationsManager.isPeerLocalMuted(dialog.peerId, true);
});
return {foundUnmuted, unreadCount: folder.unreadDialogsCount};
} }
public getCachedDialogs(skipMigrated?: boolean) { public getCachedDialogs(skipMigrated?: boolean) {
@ -435,7 +444,7 @@ export default class DialogsStorage extends AppManager {
const newDialogIndex = this.setDialogIndexInFilter(dialog, indexKey, filter); const newDialogIndex = this.setDialogIndexInFilter(dialog, indexKey, filter);
if(wasDialogIndex === newDialogIndex) { if(wasDialogIndex === newDialogIndex) {
return; return false;
} }
if((!wasDialogIndex && newDialogIndex) || (wasIndex && !newDialogIndex)) { if((!wasDialogIndex && newDialogIndex) || (wasIndex && !newDialogIndex)) {
@ -449,6 +458,8 @@ export default class DialogsStorage extends AppManager {
if(newDialogIndex) { if(newDialogIndex) {
insertInDescendSortedArray(dialogs, dialog, (dialog) => this.getDialogIndex(dialog, indexKey), -1); insertInDescendSortedArray(dialogs, dialog, (dialog) => this.getDialogIndex(dialog, indexKey), -1);
} }
return true;
} }
public prepareDialogUnreadCountModifying(dialog: Dialog) { public prepareDialogUnreadCountModifying(dialog: Dialog) {
@ -469,32 +480,46 @@ export default class DialogsStorage extends AppManager {
public prepareFolderUnreadCountModifyingByDialog(folderId: number, dialog: Dialog, toggle?: boolean) { public prepareFolderUnreadCountModifyingByDialog(folderId: number, dialog: Dialog, toggle?: boolean) {
const wasUnreadCount = this.appMessagesManager.getDialogUnreadCount(dialog); const wasUnreadCount = this.appMessagesManager.getDialogUnreadCount(dialog);
const wasUnmuted = this.isPeerUnmuted(dialog.peerId);
if(toggle !== undefined) { if(toggle !== undefined) {
this.modifyFolderUnreadCount(folderId, toggle ? wasUnreadCount : -wasUnreadCount, wasUnreadCount ? (toggle ? 1 : -1) : 0); const addMessagesCount = toggle ? wasUnreadCount : -wasUnreadCount;
this.modifyFolderUnreadCount(folderId, addMessagesCount, !!wasUnreadCount, wasUnreadCount && wasUnmuted, dialog);
return; return;
} }
return () => { return () => {
const newUnreadCount = this.appMessagesManager.getDialogUnreadCount(dialog); const newUnreadCount = this.appMessagesManager.getDialogUnreadCount(dialog);
const newUnmuted = this.isPeerUnmuted(dialog.peerId);
const addMessagesCount = newUnreadCount - wasUnreadCount; const addMessagesCount = newUnreadCount - wasUnreadCount;
const addDialogsCount = (newUnreadCount && !wasUnreadCount) || (!newUnreadCount && wasUnreadCount) ? (wasUnreadCount ? -1 : 1) : 0; this.modifyFolderUnreadCount(folderId, addMessagesCount, !!newUnreadCount, newUnreadCount && newUnmuted, dialog);
this.modifyFolderUnreadCount(folderId, addMessagesCount, addDialogsCount);
}; };
} }
public modifyFolderUnreadCount(folderId: number, addMessagesCount: number, addDialogsCount: number) { public modifyFolderUnreadCount(
if(!addMessagesCount && !addDialogsCount) { folderId: number,
return; addMessagesCount: number,
} toggleDialog: boolean,
toggleUnmuted: boolean,
dialog: Dialog
) {
const folder = this.getFolder(folderId); const folder = this.getFolder(folderId);
if(addMessagesCount) { if(addMessagesCount) {
folder.unreadMessagesCount = Math.max(0, folder.unreadMessagesCount + addMessagesCount); folder.unreadMessagesCount = Math.max(0, folder.unreadMessagesCount + addMessagesCount);
} }
if(addDialogsCount) { const {peerId} = dialog;
folder.unreadDialogsCount = Math.max(0, folder.unreadDialogsCount + addDialogsCount); if(toggleDialog) {
folder.unreadPeerIds.add(peerId);
} else {
folder.unreadPeerIds.delete(peerId);
}
if(toggleUnmuted) {
folder.unreadUnmutedPeerIds.add(peerId);
} else {
folder.unreadUnmutedPeerIds.delete(peerId);
} }
if(folder.dispatchUnreadTimeout === undefined) { if(folder.dispatchUnreadTimeout === undefined) {

3
webpack.common.js

@ -241,6 +241,9 @@ module.exports = {
// }), // }),
new HtmlWebpackPlugin({ new HtmlWebpackPlugin({
title: 'Telegram Web',
description: 'Telegram is a cloud-based mobile and desktop messaging app with a focus on security and speed.',
url: 'https://web.telegram.org/k/',
filename: 'index.html', filename: 'index.html',
//template: 'public/index_template.html', //template: 'public/index_template.html',
template: 'src/index.hbs', template: 'src/index.hbs',

Loading…
Cancel
Save