From cbd9c28d3e26667ea9fa7d4db78af044f022be9e Mon Sep 17 00:00:00 2001 From: Eduard Kuzmenko Date: Mon, 21 Dec 2020 02:38:21 +0200 Subject: [PATCH] Improve smoothness of opening chat on handhelds Fix schedule send & delete Fix min schedule date --- src/components/chat/bubbles.ts | 3 +- src/components/chat/chat.ts | 2 +- src/components/chat/contextMenu.ts | 3 +- src/components/chat/search.ts | 2 +- src/components/chat/topbar.ts | 32 ++++---- src/components/misc.ts | 3 +- src/components/popups/datePicker.ts | 4 + src/components/popups/schedule.ts | 4 +- src/components/scrollable.ts | 4 +- src/components/wrappers.ts | 2 +- src/helpers/dom.ts | 8 +- src/helpers/eventListenerBase.ts | 7 +- src/lib/appManagers/apiUpdatesManager.ts | 2 +- src/lib/appManagers/appImManager.ts | 41 +++++----- src/lib/appManagers/appMessagesManager.ts | 95 +++++++++++++++-------- src/lib/appManagers/appStateManager.ts | 87 ++++++++++++++++++--- src/lib/appManagers/appUsersManager.ts | 2 +- src/lib/logger.ts | 2 +- src/lib/mediaPlayer.ts | 6 +- src/lib/storage.ts | 32 +++----- src/scss/partials/_chat.scss | 13 ++++ src/scss/partials/_leftSidebar.scss | 5 ++ src/scss/partials/_rightSidebar.scss | 6 ++ src/scss/partials/pages/_chats.scss | 6 +- src/scss/partials/popups/_datePicker.scss | 2 +- src/types.d.ts | 1 + 26 files changed, 252 insertions(+), 122 deletions(-) diff --git a/src/components/chat/bubbles.ts b/src/components/chat/bubbles.ts index e4793679..354e4187 100644 --- a/src/components/chat/bubbles.ts +++ b/src/components/chat/bubbles.ts @@ -2408,7 +2408,8 @@ export default class ChatBubbles { //console.time('appImManager call getHistory'); const pageCount = this.appPhotosManager.windowH / 38/* * 1.25 */ | 0; //const loadCount = Object.keys(this.bubbles).length > 0 ? 50 : pageCount; - const realLoadCount = Object.keys(this.bubbles).length > 0 || additionMsgId ? Math.max(40, pageCount) : pageCount;//const realLoadCount = 50; + //const realLoadCount = Object.keys(this.bubbles).length > 0 || additionMsgId ? Math.max(40, pageCount) : pageCount;//const realLoadCount = 50; + const realLoadCount = pageCount;//const realLoadCount = 50; let loadCount = realLoadCount; /* if(TEST_SCROLL) { diff --git a/src/components/chat/chat.ts b/src/components/chat/chat.ts index b8329994..f56d5aa2 100644 --- a/src/components/chat/chat.ts +++ b/src/components/chat/chat.ts @@ -191,7 +191,7 @@ export default class Chat extends EventListenerBase<{ appSidebarRight.sharedMediaTab.loadSidebarMedia(false); }); */ - return this.setPeerPromise; + return result; } public finishPeerChange(isTarget: boolean, isJump: boolean, lastMsgId: number) { diff --git a/src/components/chat/contextMenu.ts b/src/components/chat/contextMenu.ts index b552366d..e1420f40 100644 --- a/src/components/chat/contextMenu.ts +++ b/src/components/chat/contextMenu.ts @@ -113,7 +113,8 @@ export default class ChatContextMenu { const good = ['bubble', 'bubble__container', 'message', 'time', 'inner'].find(c => className.match(new RegExp(c + '($|\\s)'))); if(good) { cancelEvent(e); - onContextMenu((e as TouchEvent).changedTouches[0]); + //onContextMenu((e as TouchEvent).changedTouches[0]); + onContextMenu((e as TouchEvent).changedTouches ? (e as TouchEvent).changedTouches[0] : e as MouseEvent); } }, {listenerSetter: this.chat.bubbles.listenerSetter}); diff --git a/src/components/chat/search.ts b/src/components/chat/search.ts index afc5ba85..78541887 100644 --- a/src/components/chat/search.ts +++ b/src/components/chat/search.ts @@ -149,7 +149,7 @@ export default class ChatSearch { this.chat.bubbles.bubblesContainer.classList.remove('search-results-active'); const res = this.chat.setPeer(peerId, lastMsgId); - this.setPeerPromise = (res instanceof Promise ? res : Promise.resolve(res)).then(() => { + this.setPeerPromise = ((res instanceof Promise ? res : Promise.resolve(res)) as Promise).then(() => { this.selectedIndex = index; this.foundCountEl.innerText = `${index + 1} of ${this.foundCount}`; diff --git a/src/components/chat/topbar.ts b/src/components/chat/topbar.ts index 0a4c8c52..befeceae 100644 --- a/src/components/chat/topbar.ts +++ b/src/components/chat/topbar.ts @@ -271,22 +271,24 @@ export default class ChatTopbar { } }); - this.chat.addListener('setPeer', (mid, isTopMessage) => { - const middleware = this.chat.bubbles.getMiddleware(); - appStateManager.getState().then((state) => { - if(!middleware()) return; - - this.pinnedMessage.hidden = !!state.hiddenPinnedMessages[this.chat.peerId]; - - if(isTopMessage) { - this.pinnedMessage.unsetScrollDownListener(); - this.pinnedMessage.testMid(mid, 0); // * because slider will not let get bubble by document.elementFromPoint - } else if(!this.pinnedMessage.locked) { - this.pinnedMessage.handleFollowingPinnedMessage(); - this.pinnedMessage.testMid(mid); - } + if(this.pinnedMessage) { + this.chat.addListener('setPeer', (mid, isTopMessage) => { + const middleware = this.chat.bubbles.getMiddleware(); + appStateManager.getState().then((state) => { + if(!middleware()) return; + + this.pinnedMessage.hidden = !!state.hiddenPinnedMessages[this.chat.peerId]; + + if(isTopMessage) { + this.pinnedMessage.unsetScrollDownListener(); + this.pinnedMessage.testMid(mid, 0); // * because slider will not let get bubble by document.elementFromPoint + } else if(!this.pinnedMessage.locked) { + this.pinnedMessage.handleFollowingPinnedMessage(); + this.pinnedMessage.testMid(mid); + } + }); }); - }); + } this.setPeerStatusInterval = window.setInterval(this.setPeerStatus, 60e3); diff --git a/src/components/misc.ts b/src/components/misc.ts index 4a3dd647..329d6cb8 100644 --- a/src/components/misc.ts +++ b/src/components/misc.ts @@ -2,9 +2,8 @@ import Countries, { Country, PhoneCodesMain } from "../countries"; import { cancelEvent, CLICK_EVENT_NAME } from "../helpers/dom"; import ListenerSetter from "../helpers/listenerSetter"; import mediaSizes from "../helpers/mediaSizes"; -import { clamp } from "../helpers/number"; import { isTouchSupported } from "../helpers/touchSupport"; -import { isApple, isSafari } from "../helpers/userAgent"; +import { isApple } from "../helpers/userAgent"; export const loadedURLs: {[url: string]: boolean} = {}; const set = (elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLVideoElement, url: string) => { diff --git a/src/components/popups/datePicker.ts b/src/components/popups/datePicker.ts index e502ccc0..978ebd39 100644 --- a/src/components/popups/datePicker.ts +++ b/src/components/popups/datePicker.ts @@ -45,6 +45,10 @@ export default class PopupDatePicker extends PopupElement { this.minDate = options.minDate || new Date('2013-08-01T00:00:00'); + if(initDate < this.minDate) { + initDate.setFullYear(this.minDate.getFullYear(), this.minDate.getMonth(), this.minDate.getDate()); + } + // Controls this.controlsDiv = document.createElement('div'); this.controlsDiv.classList.add('date-picker-controls'); diff --git a/src/components/popups/schedule.ts b/src/components/popups/schedule.ts index c7671fff..491da839 100644 --- a/src/components/popups/schedule.ts +++ b/src/components/popups/schedule.ts @@ -2,8 +2,8 @@ import PopupDatePicker from "./datePicker"; const getMinDate = () => { const date = new Date(); - date.setDate(date.getDate() - 1); - //date.setHours(0, 0, 0, 0); + //date.setDate(date.getDate() - 1); + date.setHours(0, 0, 0, 0); return date; }; diff --git a/src/components/scrollable.ts b/src/components/scrollable.ts index 6d3f3a0d..8fec1d33 100644 --- a/src/components/scrollable.ts +++ b/src/components/scrollable.ts @@ -154,7 +154,9 @@ export default class Scrollable extends ScrollableBase { //return; - if(this.onScrollMeasure || ((this.scrollLocked || (!this.onScrolledTop && !this.onScrolledBottom)) && !this.splitUp && !this.onAdditionalScroll)) return; + //if(this.onScrollMeasure || ((this.scrollLocked || (!this.onScrolledTop && !this.onScrolledBottom)) && !this.splitUp && !this.onAdditionalScroll)) return; + if((this.scrollLocked || (!this.onScrolledTop && !this.onScrolledBottom)) && !this.splitUp && !this.onAdditionalScroll) return; + if(this.onScrollMeasure) window.cancelAnimationFrame(this.onScrollMeasure); this.onScrollMeasure = window.requestAnimationFrame(() => { this.onScrollMeasure = 0; diff --git a/src/components/wrappers.ts b/src/components/wrappers.ts index f176ddf0..90769b14 100644 --- a/src/components/wrappers.ts +++ b/src/components/wrappers.ts @@ -559,7 +559,7 @@ export function wrapPhoto({photo, message, container, boxWidth, boxHeight, withT if(message?.media?.preloader) { // means upload message.media.preloader.attach(container); } else if(!cacheContext.downloaded) { - preloader = new ProgressivePreloader(container, false, false, photo._ == 'document' ? 'prepend' : 'append'); + preloader = new ProgressivePreloader(null, false, false, photo._ == 'document' ? 'prepend' : 'append'); } const load = () => { diff --git a/src/helpers/dom.ts b/src/helpers/dom.ts index 198cadd0..56a224f7 100644 --- a/src/helpers/dom.ts +++ b/src/helpers/dom.ts @@ -466,13 +466,14 @@ export function blurActiveElement() { } } -export const CLICK_EVENT_NAME = isTouchSupported ? 'touchend' : 'click'; +export const CLICK_EVENT_NAME: 'mousedown' | 'touchend' | 'click' = (isTouchSupported ? 'mousedown' : 'click') as any; export type AttachClickOptions = AddEventListenerOptions & Partial<{listenerSetter: ListenerSetter, touchMouseDown: true}>; export const attachClickEvent = (elem: HTMLElement, callback: (e: TouchEvent | MouseEvent) => void, options: AttachClickOptions = {}) => { const add = options.listenerSetter ? options.listenerSetter.add.bind(options.listenerSetter, elem) : elem.addEventListener.bind(elem); const remove = options.listenerSetter ? options.listenerSetter.removeManual.bind(options.listenerSetter, elem) : elem.removeEventListener.bind(elem); - if(options.touchMouseDown && CLICK_EVENT_NAME === 'touchend') { + options.touchMouseDown = true; + /* if(options.touchMouseDown && CLICK_EVENT_NAME === 'touchend') { add('mousedown', callback, options); } else if(CLICK_EVENT_NAME === 'touchend') { const o = {...options, once: true}; @@ -498,7 +499,8 @@ export const attachClickEvent = (elem: HTMLElement, callback: (e: TouchEvent | M add('touchstart', onTouchStart); } else { add(CLICK_EVENT_NAME, callback, options); - } + } */ + add(CLICK_EVENT_NAME, callback, options); }; export const detachClickEvent = (elem: HTMLElement, callback: (e: TouchEvent | MouseEvent) => void, options?: AddEventListenerOptions) => { diff --git a/src/helpers/eventListenerBase.ts b/src/helpers/eventListenerBase.ts index 15111c7f..d1684feb 100644 --- a/src/helpers/eventListenerBase.ts +++ b/src/helpers/eventListenerBase.ts @@ -1,4 +1,4 @@ -import type { ArgumentTypes } from "../types"; +import type { ArgumentTypes, SuperReturnType } from "../types"; export default class EventListenerBase { protected listeners: Partial<{ @@ -36,14 +36,17 @@ export default class EventListenerBase> = []; if(this.listeners[name]) { this.listeners[name].forEach(listener => { - listener.callback(...args); + arr.push(listener.callback(...args)); if(listener.once) { this.removeListener(name, listener.callback); } }); } + + return arr; } } \ No newline at end of file diff --git a/src/lib/appManagers/apiUpdatesManager.ts b/src/lib/appManagers/apiUpdatesManager.ts index 372f322b..6cc4a13c 100644 --- a/src/lib/appManagers/apiUpdatesManager.ts +++ b/src/lib/appManagers/apiUpdatesManager.ts @@ -40,7 +40,7 @@ export class ApiUpdatesManager { constructor() { // * false for test purposes - /* false && */appStateManager.addListener('save', () => { + /* false && */appStateManager.addListener('save', async() => { const us = this.updatesState; appStateManager.pushToState('updates', { seq: us.seq, diff --git a/src/lib/appManagers/appImManager.ts b/src/lib/appManagers/appImManager.ts index cf22e268..ea262ffb 100644 --- a/src/lib/appManagers/appImManager.ts +++ b/src/lib/appManagers/appImManager.ts @@ -51,8 +51,8 @@ export class AppImManager { public setPeerPromise: Promise = null; - private mainColumns: HTMLElement; - public _selectTab: ReturnType; + //private mainColumns: HTMLElement; + //public _selectTab: ReturnType; public tabId = -1; //private closeBtn: HTMLButtonElement;// = this.topbar.querySelector('.sidebar-close-button') as HTMLButtonElement; public hideRightSidebar = false; @@ -74,8 +74,8 @@ export class AppImManager { this.log = logger('IM', LogLevels.log | LogLevels.warn | LogLevels.debug | LogLevels.error); - this.mainColumns = this.columnEl.parentElement; - this._selectTab = horizontalMenu(null, this.mainColumns); + //this.mainColumns = this.columnEl.parentElement; + //this._selectTab = horizontalMenu(null, this.mainColumns); this.selectTab(0); window.addEventListener('blur', () => { @@ -420,7 +420,7 @@ export class AppImManager { document.body.classList.remove(RIGHT_COLUMN_ACTIVE_CLASSNAME); } - this._selectTab(id, mediaSizes.isMobile); + //this._selectTab(id, mediaSizes.isMobile); //document.body.classList.toggle(RIGHT_COLUMN_ACTIVE_CLASSNAME, id == 2); } @@ -498,24 +498,29 @@ export class AppImManager { return this.setPeer(peerId, lastMsgId); } - if(peerId || mediaSizes.activeScreen != ScreenSize.mobile) { - chat.setPeer(peerId, lastMsgId); + if(peerId || mediaSizes.activeScreen !== ScreenSize.mobile) { + const result = chat.setPeer(peerId, lastMsgId); + + const promise = result?.cached ? result.promise : Promise.resolve(); + if(peerId) { + promise.then(() => { + //window.requestAnimationFrame(() => { + setTimeout(() => { // * setTimeout is better here + if(this.hideRightSidebar) { + appSidebarRight.toggleSidebar(true); + this.hideRightSidebar = false; + } + + this.selectTab(1); + }, 0); + }); + } } - if(peerId == 0) { + if(!peerId) { this.selectTab(0); - - document.body.classList.add(LEFT_COLUMN_ACTIVE_CLASSNAME); return false; } - - document.body.classList.remove(LEFT_COLUMN_ACTIVE_CLASSNAME); - if(this.hideRightSidebar) { - appSidebarRight.toggleSidebar(true); - this.hideRightSidebar = false; - } - - this.selectTab(1); } public setInnerPeer(peerId: number, lastMsgId?: number, type: ChatType = 'chat') { diff --git a/src/lib/appManagers/appMessagesManager.ts b/src/lib/appManagers/appMessagesManager.ts index 01633070..dfe7d667 100644 --- a/src/lib/appManagers/appMessagesManager.ts +++ b/src/lib/appManagers/appMessagesManager.ts @@ -227,51 +227,77 @@ export class AppMessagesManager { } }); */ + function timedChunk(items: any[], process: (...args: any[]) => any, context: any, callback: (...args: any[]) => void) { + const todo = items.slice(); + + const f = () => { + const start = +new Date(); + + do { + process.call(context, todo.shift()); + } while(todo.length > 0 && (+new Date() - start < 50)); + + if(todo.length > 0) { + setTimeout(f, 25); + } else { + callback(items); + } + }; + + setTimeout(f, 25); + } + appStateManager.addListener('save', () => { const messages: any[] = []; const dialogs: Dialog[] = []; - - for(const folderId in this.dialogsStorage.byFolders) { - const folder = this.dialogsStorage.getFolder(+folderId); - - for(let dialog of folder) { - const historyStorage = this.getHistoryStorage(dialog.peerId); - const history = [].concat(historyStorage.pending, historyStorage.history); - - dialog = copy(dialog); - let removeUnread = 0; - for(const mid of history) { - const message = this.getMessageByPeer(dialog.peerId, mid); - if(/* message._ != 'messageEmpty' && */!message.pFlags.is_outgoing) { - messages.push(message); + const items: any[] = []; - if(message.fromId != dialog.peerId) { - appStateManager.setPeer(message.fromId, appPeersManager.getPeer(message.fromId)); - } + const processDialog = (dialog: MTDialog.dialog) => { + const historyStorage = this.getHistoryStorage(dialog.peerId); + const history = [].concat(historyStorage.pending, historyStorage.history); + dialog = copy(dialog); + let removeUnread = 0; + for(const mid of history) { + const message = this.getMessageByPeer(dialog.peerId, mid); + if(/* message._ != 'messageEmpty' && */!message.pFlags.is_outgoing) { + messages.push(message); + + if(message.fromId != dialog.peerId) { + appStateManager.setPeer(message.fromId, appPeersManager.getPeer(message.fromId)); + } - dialog.top_message = message.mid; - this.setDialogIndexByMessage(dialog, message); + dialog.top_message = message.mid; + this.setDialogIndexByMessage(dialog, message); - break; - } else if(message.pFlags && message.pFlags.unread) { - ++removeUnread; - } + break; + } else if(message.pFlags && message.pFlags.unread) { + ++removeUnread; } + } - if(removeUnread && dialog.unread_count) dialog.unread_count -= removeUnread; + if(removeUnread && dialog.unread_count) dialog.unread_count -= removeUnread; - dialog.unread_count = Math.max(0, dialog.unread_count); - dialogs.push(dialog); + dialog.unread_count = Math.max(0, dialog.unread_count); + dialogs.push(dialog); - appStateManager.setPeer(dialog.peerId, appPeersManager.getPeer(dialog.peerId)); + appStateManager.setPeer(dialog.peerId, appPeersManager.getPeer(dialog.peerId)); + }; + + for(const folderId in this.dialogsStorage.byFolders) { + const folder = this.dialogsStorage.getFolder(+folderId); + + for(let dialog of folder) { + items.push(dialog); } } - appStateManager.pushToState('dialogs', dialogs); - appStateManager.pushToState('messages', messages); - appStateManager.pushToState('filters', this.filtersStorage.filters); - appStateManager.pushToState('allDialogsLoaded', this.dialogsStorage.allDialogsLoaded); - appStateManager.pushToState('maxSeenMsgId', this.maxSeenId); + return new Promise((resolve => timedChunk(items, processDialog, this, resolve))).then(() => { + appStateManager.pushToState('dialogs', dialogs); + appStateManager.pushToState('messages', messages); + appStateManager.pushToState('filters', this.filtersStorage.filters); + appStateManager.pushToState('allDialogsLoaded', this.dialogsStorage.allDialogsLoaded); + appStateManager.pushToState('maxSeenMsgId', this.maxSeenId); + }); }); appStateManager.getState().then(state => { @@ -3187,6 +3213,7 @@ export class AppMessagesManager { } public readMessages(peerId: number, msgIds: number[]) { + msgIds = msgIds.map(mid => this.getLocalMessageId(mid)); if(peerId < 0 && appPeersManager.isChannel(peerId)) { const channelId = -peerId; apiManager.invokeApi('channels.readMessageContents', { @@ -4113,7 +4140,7 @@ export class AppMessagesManager { public sendScheduledMessages(peerId: number, mids: number[]) { return apiManager.invokeApi('messages.sendScheduledMessages', { peer: appPeersManager.getInputPeerById(peerId), - id: mids + id: mids.map(mid => this.getLocalMessageId(mid)) }).then(updates => { apiUpdatesManager.processUpdateMessage(updates); }); @@ -4122,7 +4149,7 @@ export class AppMessagesManager { public deleteScheduledMessages(peerId: number, mids: number[]) { return apiManager.invokeApi('messages.deleteScheduledMessages', { peer: appPeersManager.getInputPeerById(peerId), - id: mids + id: mids.map(mid => this.getLocalMessageId(mid)) }).then(updates => { apiUpdatesManager.processUpdateMessage(updates); }); diff --git a/src/lib/appManagers/appStateManager.ts b/src/lib/appManagers/appStateManager.ts index 6135c2d1..cf6dca3a 100644 --- a/src/lib/appManagers/appStateManager.ts +++ b/src/lib/appManagers/appStateManager.ts @@ -16,13 +16,16 @@ const STATE_VERSION = App.version; type State = Partial<{ dialogs: Dialog[], - allDialogsLoaded: DialogsStorage['allDialogsLoaded'], - //peers: {[peerId: string]: ReturnType}, + allDialogsLoaded: DialogsStorage['allDialogsLoaded'], chats: {[peerId: string]: ReturnType}, users: {[peerId: string]: ReturnType}, messages: any[], contactsList: number[], - updates: any, + updates: Partial<{ + seq: number, + pts: number, + date: number + }>, filters: FiltersStorage['filters'], maxSeenMsgId: number, stateCreatedTime: number, @@ -35,16 +38,45 @@ type State = Partial<{ hiddenPinnedMessages: {[peerId: string]: number} }>; +/* const STATE_INIT: State = { + dialogs: [], + allDialogsLoaded: {}, + chats: {}, + users: {}, + messages: [], + contactsList: [], + updates: {}, + filters: {}, + maxSeenMsgId: 0, + stateCreatedTime: 0, + recentEmoji: [], + topPeers: [], + recentSearch: [], + stickerSets: {}, + version: '', + authState: +}; */ + +const ALL_KEYS = ['dialogs', 'allDialogsLoaded', 'chats', + 'users', 'messages', 'contactsList', + 'updates', 'filters', 'maxSeenMsgId', + 'stateCreatedTime', 'recentEmoji', 'topPeers', + 'recentSearch', 'stickerSets', 'version', + 'authState', 'hiddenPinnedMessages' +] as any as Array; + const REFRESH_KEYS = ['dialogs', 'allDialogsLoaded', 'messages', 'contactsList', 'stateCreatedTime', 'updates', 'maxSeenMsgId', 'filters', 'topPeers'] as any as Array; export class AppStateManager extends EventListenerBase<{ - save: (state: State) => void + save: (state: State) => Promise }> { public loaded: Promise; private log = logger('STATE'/* , LogLevels.error */); private state: State; + private savePromise: Promise; + private tempId = 0; constructor() { super(); @@ -55,7 +87,18 @@ export class AppStateManager extends EventListenerBase<{ if(this.loaded) return this.loaded; //console.time('load state'); return this.loaded = new Promise((resolve) => { - AppStorage.get<[State, UserAuth]>('state', 'user_auth').then(([state, auth]) => { + AppStorage.get(...ALL_KEYS, 'user_auth').then((arr) => { + let state: State = {}; + + // ! then can't store false values + ALL_KEYS.forEach((key, idx) => { + const value = arr[idx]; + if(value !== false) { + // @ts-ignore + state[key] = value; + } + }); + const time = Date.now(); if(state) { if(state.version != STATE_VERSION) { @@ -84,6 +127,7 @@ export class AppStateManager extends EventListenerBase<{ //return resolve(); + const auth: UserAuth = arr[arr.length - 1]; if(auth) { // ! Warning ! DON'T delete this this.state.authState = {_: 'authStateSignedIn'}; @@ -95,7 +139,10 @@ export class AppStateManager extends EventListenerBase<{ //console.timeEnd('load state'); resolve(this.state); }).catch(resolve).finally(() => { - setInterval(() => this.saveState(), 10000); + setInterval(() => { + this.tempId++; + this.saveState(); + }, 10000); }); }); } @@ -105,18 +152,26 @@ export class AppStateManager extends EventListenerBase<{ } public saveState() { - if(this.state === undefined) return; + if(this.state === undefined || this.savePromise) return; + const tempId = this.tempId; + this.savePromise = Promise.all(this.setListenerResult('save', this.state)).then(() => { + return AppStorage.set(this.state); + }).then(() => { + this.savePromise = null; + + if(this.tempId !== tempId) { + this.saveState(); + } + }); //let perf = performance.now(); - this.setListenerResult('save', this.state); + //this.log('saveState: event time:', performance.now() - perf); //const pinnedOrders = appMessagesManager.dialogsStorage.pinnedOrders; //perf = performance.now(); - AppStorage.set({ - state: this.state - }); + //this.log('saveState: storage set time:', performance.now() - perf); } @@ -129,6 +184,16 @@ export class AppStateManager extends EventListenerBase<{ if(container.hasOwnProperty(peerId)) return; container[peerId] = peer; } + + public resetState() { + for(let i in this.state) { + // @ts-ignore + this.state[i] = false; + } + AppStorage.set(this.state).then(() => { + location.reload(); + }); + } } //console.trace('appStateManager include'); diff --git a/src/lib/appManagers/appUsersManager.ts b/src/lib/appManagers/appUsersManager.ts index 8132ef6f..99b60c13 100644 --- a/src/lib/appManagers/appUsersManager.ts +++ b/src/lib/appManagers/appUsersManager.ts @@ -100,7 +100,7 @@ export class AppUsersManager { } }); - appStateManager.addListener('save', () => { + appStateManager.addListener('save', async() => { const contactsList = [...this.contactsList]; for(const userId of contactsList) { appStateManager.setPeer(userId, this.getUser(userId)); diff --git a/src/lib/logger.ts b/src/lib/logger.ts index 7f4cd77a..298abdae 100644 --- a/src/lib/logger.ts +++ b/src/lib/logger.ts @@ -13,7 +13,7 @@ function dT() { } export function logger(prefix: string, level = LogLevels.log | LogLevels.warn | LogLevels.error) { - if(process.env.NODE_ENV != 'development'/* || true */) { + if(process.env.NODE_ENV != 'development' || true) { level = LogLevels.error; } diff --git a/src/lib/mediaPlayer.ts b/src/lib/mediaPlayer.ts index 361cce12..5d92bc0f 100644 --- a/src/lib/mediaPlayer.ts +++ b/src/lib/mediaPlayer.ts @@ -70,9 +70,9 @@ export class ProgressLine { this.container.addEventListener('mouseup', this.onMouseUp); if(isTouchSupported) { - this.container.addEventListener('touchmove', this.onMouseMove); - this.container.addEventListener('touchstart', this.onMouseDown); - this.container.addEventListener('touchend', this.onMouseUp); + this.container.addEventListener('touchmove', this.onMouseMove, {passive: true}); + this.container.addEventListener('touchstart', this.onMouseDown, {passive: true}); + this.container.addEventListener('touchend', this.onMouseUp, {passive: true}); } } diff --git a/src/lib/storage.ts b/src/lib/storage.ts index f7ed6141..394ebc20 100644 --- a/src/lib/storage.ts +++ b/src/lib/storage.ts @@ -3,9 +3,6 @@ import { MOUNT_CLASS_TO } from './mtproto/mtproto_config'; //import { stringify } from '../helpers/json'; class AppStorage { - //private log = (...args: any[]) => console.log('[SW LS]', ...args); - private log = (...args: any[]) => {}; - private cacheStorage = new CacheStorageController('session'); //public noPrefix = false; @@ -66,24 +63,23 @@ class AppStorage { } public async set(obj: any) { - let keyValues: any = {}; - let prefix = this.storageGetPrefix(), - key, value; - + const prefix = this.storageGetPrefix(); //console.log('storageSetValue', obj, callback, arguments); - for(key in obj) { + for(let key in obj) { if(obj.hasOwnProperty(key)) { - value = obj[key]; + let value = obj[key]; key = prefix + key; this.cache[key] = value; + let perf = performance.now(); value = JSON.stringify(value); - /* let perf = performance.now(); - let value2 = JSON.stringify(value); - console.log('LocalStorage set: stringify time by JSON.stringify:', performance.now() - perf, value2); - perf = performance.now(); + let elapsedTime = performance.now() - perf; + if(elapsedTime > 10) { + console.warn('LocalStorage set: stringify time by JSON.stringify:', elapsedTime, key); + } + /* perf = performance.now(); value = stringify(value); console.log('LocalStorage set: stringify time by own stringify:', performance.now() - perf); */ @@ -97,8 +93,6 @@ class AppStorage { //this.useCS = false; console.error('[AS]: set error:', e, key/* , value */); } - } else { - keyValues[key] = value; } } } @@ -109,11 +103,9 @@ class AppStorage { keys = Array.prototype.slice.call(arguments); } - let prefix = this.storageGetPrefix(), - i, key; - - for(i = 0; i < keys.length; i++) { - key = keys[i] = prefix + keys[i]; + const prefix = this.storageGetPrefix(); + for(let i = 0; i < keys.length; i++) { + const key = keys[i] = prefix + keys[i]; delete this.cache[key]; if(this.useCS) { try { diff --git a/src/scss/partials/_chat.scss b/src/scss/partials/_chat.scss index e3257977..bb7398f1 100644 --- a/src/scss/partials/_chat.scss +++ b/src/scss/partials/_chat.scss @@ -22,6 +22,8 @@ $chat-helper-size: 39px; transition: transform var(--layer-transition); transform: translateY(var(--translateY)); + //display: none !important; + /* // * for no ESG top flex: 1 1 auto; height: calc(100% - 56px); */ @@ -407,6 +409,17 @@ $chat-helper-size: 39px; position: relative; flex: 3; + @include respond-to(handhelds) { + body.is-left-column-shown & { + transform: translate3d(100vw, 0, 0); + } + + body.is-right-column-shown & { + transform: translate3d(-25vw, 0, 0); + filter: brightness(80%); + } + } + @include respond-to(floating-left-sidebar) { position: fixed !important; left: 0; diff --git a/src/scss/partials/_leftSidebar.scss b/src/scss/partials/_leftSidebar.scss index ee0c61da..b825be78 100644 --- a/src/scss/partials/_leftSidebar.scss +++ b/src/scss/partials/_leftSidebar.scss @@ -9,6 +9,11 @@ @include respond-to(handhelds) { width: 100%; max-width: 100%; + + body:not(.is-left-column-shown) & { + transform: translate3d(-25vw, 0, 0); + filter: brightness(80%); + } } @include respond-to(floating-left-sidebar) { diff --git a/src/scss/partials/_rightSidebar.scss b/src/scss/partials/_rightSidebar.scss index 0dd6469d..500ea729 100644 --- a/src/scss/partials/_rightSidebar.scss +++ b/src/scss/partials/_rightSidebar.scss @@ -5,6 +5,12 @@ box-shadow: 0 0.25rem 0.5rem 0.1rem hsla(0, 0%, 44.7%, .25); } + @include respond-to(handhelds) { + body:not(.is-right-column-shown) & { + transform: translate3d(100vw, 0, 0); + } + } + @include respond-to(not-handhelds) { width: var(--right-column-width); transition: transform var(--layer-transition); diff --git a/src/scss/partials/pages/_chats.scss b/src/scss/partials/pages/_chats.scss index 2dd6b0a5..98298ff8 100644 --- a/src/scss/partials/pages/_chats.scss +++ b/src/scss/partials/pages/_chats.scss @@ -24,10 +24,12 @@ @include respond-to(handhelds) { .main-column { width: 100%; + display: flex !important; + z-index: 1; - &:not(.active) { + /* &:not(.active) { display: none; - } + } */ } /* #column-left { diff --git a/src/scss/partials/popups/_datePicker.scss b/src/scss/partials/popups/_datePicker.scss index 5c4293d3..6ecde0ea 100644 --- a/src/scss/partials/popups/_datePicker.scss +++ b/src/scss/partials/popups/_datePicker.scss @@ -177,7 +177,7 @@ &:disabled { visibility: visible; - opacity: 1; + //opacity: 1; } } } diff --git a/src/types.d.ts b/src/types.d.ts index 996927f1..923f7349 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -34,6 +34,7 @@ export type Modify = Omit & R; //export type Parameters = T extends (... args: infer T) => any ? T : never; export type ArgumentTypes = F extends (...args: infer A) => any ? A : never; +export type SuperReturnType = F extends (...args: any) => any ? ReturnType : never; export type AnyLiteral = Record; export type AnyClass = new (...args: any[]) => any;