diff --git a/src/components/appSelectPeers.ts b/src/components/appSelectPeers.ts index 9ae992c8..9fa3534f 100644 --- a/src/components/appSelectPeers.ts +++ b/src/components/appSelectPeers.ts @@ -7,7 +7,6 @@ import appChatsManager, { ChatRights } from "../lib/appManagers/appChatsManager"; import appDialogsManager from "../lib/appManagers/appDialogsManager"; import appMessagesManager, { Dialog } from "../lib/appManagers/appMessagesManager"; -import appPeersManager from "../lib/appManagers/appPeersManager"; import appPhotosManager from "../lib/appManagers/appPhotosManager"; import appUsersManager from "../lib/appManagers/appUsersManager"; import rootScope from "../lib/rootScope"; @@ -167,7 +166,7 @@ export default class AppSelectPeers { return; } - target.classList.toggle('active'); + //target.classList.toggle('active'); if(this.selected.has(key)) { this.remove(key); } else { @@ -436,7 +435,7 @@ export default class AppSelectPeers { const checkboxField = new CheckboxField(); if(selected) { - dom.listEl.classList.add('active'); + //dom.listEl.classList.add('active'); checkboxField.input.checked = true; } diff --git a/src/components/chat/bubbles.ts b/src/components/chat/bubbles.ts index 7b18420f..6bea986f 100644 --- a/src/components/chat/bubbles.ts +++ b/src/components/chat/bubbles.ts @@ -394,6 +394,14 @@ export default class ChatBubbles { }); } + this.listenerSetter.add(this.bubblesContainer, 'dblclick', (e) => { + const bubble = (e.target as HTMLElement).classList.contains('bubble') ? e.target as HTMLElement : null; + if(bubble) { + const mid = +bubble.dataset.mid + this.chat.input.initMessageReply(mid); + } + }); + /* if(false) */this.stickyIntersector = new StickyIntersector(this.scrollable.container, (stuck, target) => { for(const timestamp in this.dateMessages) { const dateMessage = this.dateMessages[timestamp]; diff --git a/src/components/chat/contextMenu.ts b/src/components/chat/contextMenu.ts index 9bdc91d7..4e524002 100644 --- a/src/components/chat/contextMenu.ts +++ b/src/components/chat/contextMenu.ts @@ -36,7 +36,7 @@ export default class ChatContextMenu { public message: any; constructor(private attachTo: HTMLElement, private chat: Chat, private appMessagesManager: AppMessagesManager, private appChatsManager: AppChatsManager, private appPeersManager: AppPeersManager, private appPollsManager: AppPollsManager) { - const onContextMenu = (e: MouseEvent | Touch) => { + const onContextMenu = (e: MouseEvent | Touch | TouchEvent) => { if(this.init) { this.init(); this.init = null; @@ -52,11 +52,11 @@ export default class ChatContextMenu { // ! context menu click by date bubble (there is no pointer-events) if(!bubble) return; - if(e instanceof MouseEvent) e.preventDefault(); + if(e instanceof MouseEvent || e.hasOwnProperty('preventDefault')) (e as any).preventDefault(); if(this.element.classList.contains('active')) { return false; } - if(e instanceof MouseEvent) e.cancelBubble = true; + if(e instanceof MouseEvent || e.hasOwnProperty('cancelBubble')) (e as any).cancelBubble = true; let mid = +bubble.dataset.mid; if(!mid) return; @@ -107,14 +107,14 @@ export default class ChatContextMenu { const side: 'left' | 'right' = bubble.classList.contains('is-in') ? 'left' : 'right'; //bubble.parentElement.append(this.element); //appImManager.log('contextmenu', e, bubble, side); - positionMenu(e, this.element, side); + positionMenu((e as TouchEvent).touches ? (e as TouchEvent).touches[0] : e as MouseEvent, this.element, side); openBtnMenu(this.element, () => { this.peerId = this.mid = 0; this.target = null; }); }; - if(isTouchSupported) { + if(isTouchSupported/* && false */) { attachClickEvent(attachTo, (e) => { if(chat.selection.isSelecting) { return; diff --git a/src/components/chat/topbar.ts b/src/components/chat/topbar.ts index 23704b99..70b712b2 100644 --- a/src/components/chat/topbar.ts +++ b/src/components/chat/topbar.ts @@ -10,7 +10,7 @@ import type { AppMessagesManager } from "../../lib/appManagers/appMessagesManage import type { AppPeersManager } from "../../lib/appManagers/appPeersManager"; import type { AppSidebarRight } from "../sidebarRight"; import type Chat from "./chat"; -import { cancelEvent, attachClickEvent, blurActiveElement } from "../../helpers/dom"; +import { cancelEvent, attachClickEvent, blurActiveElement, replaceContent } from "../../helpers/dom"; import mediaSizes, { ScreenSize } from "../../helpers/mediaSizes"; import { isSafari } from "../../helpers/userAgent"; import rootScope from "../../lib/rootScope"; @@ -562,17 +562,6 @@ export default class ChatTopbar { if(!this.subtitle) return; const peerId = this.peerId; - if(needClear) { - this.subtitle.innerHTML = ''; - } - - this.chat.appImManager.getPeerStatus(this.peerId).then((subtitle) => { - if(peerId !== this.peerId) { - return; - } - - this.subtitle.textContent = ''; - this.subtitle.append(subtitle); - }); + this.chat.appImManager.setPeerStatus(this.peerId, this.subtitle, needClear, false, () => peerId === this.peerId); }; } diff --git a/src/components/misc.ts b/src/components/misc.ts index e55af6a3..a46bd3cd 100644 --- a/src/components/misc.ts +++ b/src/components/misc.ts @@ -10,7 +10,7 @@ import { cancelEvent, CLICK_EVENT_NAME } from "../helpers/dom"; import ListenerSetter from "../helpers/listenerSetter"; import mediaSizes from "../helpers/mediaSizes"; import { isTouchSupported } from "../helpers/touchSupport"; -import { isApple, isMobileSafari } from "../helpers/userAgent"; +import { isApple, isMobileSafari, isSafari } from "../helpers/userAgent"; import appNavigationController from "./appNavigationController"; export function putPreloader(elem: Element, returnDiv = false): HTMLElement { @@ -341,6 +341,12 @@ export function attachContextMenuListener(element: HTMLElement, callback: (e: To } }, .4e3); }); + + /* if(!isSafari) { + add('contextmenu', (e: any) => { + cancelEvent(e); + }, {passive: false, capture: true}); + } */ } else { add('contextmenu', isTouchSupported ? (e: any) => { callback(e); diff --git a/src/components/sidebarLeft/tabs/includedChats.ts b/src/components/sidebarLeft/tabs/includedChats.ts index fe28184d..0ea83058 100644 --- a/src/components/sidebarLeft/tabs/includedChats.ts +++ b/src/components/sidebarLeft/tabs/includedChats.ts @@ -138,7 +138,7 @@ export default class AppIncludedChatsTab extends SliderSuperTab { const selected = this.selector.selected.has(peerId); dom.containerEl.append(this.checkbox(selected)); - if(selected) dom.listEl.classList.add('active'); + //if(selected) dom.listEl.classList.add('active'); const foundInFilters: HTMLElement[] = []; this.dialogsByFilters.forEach((dialogs, filter) => { diff --git a/src/components/sidebarRight/tabs/sharedMedia.ts b/src/components/sidebarRight/tabs/sharedMedia.ts index 4a317412..a8c4e26c 100644 --- a/src/components/sidebarRight/tabs/sharedMedia.ts +++ b/src/components/sidebarRight/tabs/sharedMedia.ts @@ -579,18 +579,7 @@ class PeerProfile { if(!this.peerId) return; const peerId = this.peerId; - if(needClear) { - this.subtitle.innerHTML = '‎'; // ! HERE U CAN FIND WHITESPACE - } - - appImManager.getPeerStatus(this.peerId).then((subtitle) => { - if(peerId !== this.peerId) { - return; - } - - this.subtitle.textContent = ''; - this.subtitle.append(subtitle || ''); - }); + appImManager.setPeerStatus(this.peerId, this.subtitle, needClear, true, () => peerId === this.peerId); }; public cleanupHTML() { diff --git a/src/config/app.ts b/src/config/app.ts index 75a1b40a..a5137496 100644 --- a/src/config/app.ts +++ b/src/config/app.ts @@ -12,8 +12,8 @@ const App = { id: 1025907, hash: '452b0359b988148995f22ff0f4229750', - version: '0.4.2', - langPackVersion: '0.1.4', + version: '0.4.3', + langPackVersion: '0.1.5', langPack: 'macos', langPackCode: 'en', domains: [] as string[], diff --git a/src/index.ts b/src/index.ts index 317af995..aec06518 100644 --- a/src/index.ts +++ b/src/index.ts @@ -139,10 +139,10 @@ console.timeEnd('get storage1'); */ }); if(userAgent.isApple) { - if(userAgent.isSafari && userAgent.isMobile) { + if(userAgent.isSafari) { document.documentElement.classList.add('is-safari'); - if(touchSupport.isTouchSupported) { + if(userAgent.isMobile && touchSupport.isTouchSupported) { let key: 'clientY' | 'pageY' = 'clientY'; let startY = 0; const o = {capture: true, passive: false}; diff --git a/src/lang.ts b/src/lang.ts index a4db9b3b..373fa0dd 100644 --- a/src/lang.ts +++ b/src/lang.ts @@ -524,13 +524,28 @@ const lang = { "Stickers.SuggestStickers": "Suggest Stickers by Emoji", "ShareModal.Search.ForwardPlaceholder": "Forward to...", "InstalledStickers.LoopAnimated": "Loop Animated Stickers", - // "Peer.Activity.User.PlayingGame": "playing a game", + "Peer.Activity.User.PlayingGame": "playing a game", "Peer.Activity.User.TypingText": "typing", - // "Peer.Activity.User.SendingPhoto": "sending a photo", - // "Peer.Activity.User.RecordingVideo": "recording video", - // "Peer.Activity.User.SendingVideo": "sending a video", - // "Peer.Activity.User.RecordingAudio": "recording voice", - // "Peer.Activity.User.SendingFile": "sending file", + "Peer.Activity.User.SendingPhoto": "sending a photo", + "Peer.Activity.User.RecordingVideo": "recording video", + "Peer.Activity.User.SendingVideo": "sending a video", + "Peer.Activity.User.RecordingAudio": "recording voice", + "Peer.Activity.User.SendingFile": "sending file", + "Peer.Activity.Chat.PlayingGame": "%@ is playing a game", + "Peer.Activity.Chat.TypingText": "%@ is typing", + "Peer.Activity.Chat.SendingPhoto": "%@ is sending a photo", + "Peer.Activity.Chat.RecordingVideo": "%@ is recording video", + "Peer.Activity.Chat.SendingVideo": "%@ is sending a video", + "Peer.Activity.Chat.RecordingAudio": "%@ is recording voice", + "Peer.Activity.Chat.SendingFile": "%@ is sending a file", + "Peer.Activity.Chat.Multi.PlayingGame1": "%@ and %d others are playing a game", + "Peer.Activity.Chat.Multi.TypingText1": "%@ and %d others are typing", + "Peer.Activity.Chat.Multi.SendingPhoto1": "%@ and %d others are sending photos", + "Peer.Activity.Chat.Multi.RecordingVideo1": "%@ and %d others are recording video", + "Peer.Activity.Chat.Multi.SendingVideo1": "%@ and %d others are sending videos", + "Peer.Activity.Chat.Multi.RecordingAudio1": "%@ and %d others are recording voice", + //"Peer.Activity.Chat.Multi.SendingAudio1": "%@ and %d others are sending audio", + "Peer.Activity.Chat.Multi.SendingFile1": "%@ and %d others are sending files", "Peer.ServiceNotifications": "service notifications", "Peer.RepliesNotifications": "Reply Notifications", "Peer.Status.online": "online", diff --git a/src/lib/appManagers/appChatsManager.ts b/src/lib/appManagers/appChatsManager.ts index 03d556b6..e4221caf 100644 --- a/src/lib/appManagers/appChatsManager.ts +++ b/src/lib/appManagers/appChatsManager.ts @@ -71,53 +71,74 @@ export class AppChatsManager { } case 'updateUserTyping': - case 'updateChatUserTyping': { + case 'updateChatUserTyping': + case 'updateChannelUserTyping': { const fromId = (update as Update.updateUserTyping).user_id || appPeersManager.getPeerId((update as Update.updateChatUserTyping).from_id); if(rootScope.myId === fromId) { - return; + break; } - const peerId = update._ === 'updateUserTyping' ? fromId : -update.chat_id; + const peerId = update._ === 'updateUserTyping' ? + fromId : + -((update as Update.updateChatUserTyping).chat_id || (update as Update.updateChannelUserTyping).channel_id); const typings = this.typingsInPeer[peerId] ?? (this.typingsInPeer[peerId] = []); let typing = typings.find(t => t.userId === fromId); - if(!typing) { - typing = { - userId: fromId - }; - typings.push(typing); - } - - //console.log('updateChatUserTyping', update, typings); - - typing.action = update.action; - - if(!appUsersManager.hasUser(fromId)) { - if(update._ === 'updateChatUserTyping') { - if(update.chat_id && appChatsManager.hasChat(update.chat_id) && !appChatsManager.isChannel(update.chat_id)) { - appProfileManager.getChatFull(update.chat_id); - } - } - - //return; - } - - appUsersManager.forceUserOnline(fromId); - - if(typing.timeout !== undefined) clearTimeout(typing.timeout); - - typing.timeout = window.setTimeout(() => { + const cancelAction = () => { delete typing.timeout; - typings.findAndSplice(t => t.userId === fromId); + //typings.findAndSplice(t => t === typing); + const idx = typings.indexOf(typing); + if(idx !== -1) { + typings.splice(idx, 1); + } rootScope.broadcast('peer_typings', {peerId, typings}); if(!typings.length) { delete this.typingsInPeer[peerId]; } - }, 6000); + }; + + if(typing && typing.timeout !== undefined) { + clearTimeout(typing.timeout); + } + + if(update.action._ === 'sendMessageCancelAction') { + if(!typing) { + break; + } + + cancelAction(); + break; + } else { + if(!typing) { + typing = { + userId: fromId + }; + + typings.push(typing); + } + + //console.log('updateChatUserTyping', update, typings); + + typing.action = update.action; + + if(!appUsersManager.hasUser(fromId)) { + if(update._ === 'updateChatUserTyping') { + if(update.chat_id && appChatsManager.hasChat(update.chat_id) && !appChatsManager.isChannel(update.chat_id)) { + appProfileManager.getChatFull(update.chat_id); + } + } + + //return; + } + + appUsersManager.forceUserOnline(fromId); + + typing.timeout = window.setTimeout(cancelAction, 6000); + rootScope.broadcast('peer_typings', {peerId, typings}); + } - rootScope.broadcast('peer_typings', {peerId, typings}); break; } } diff --git a/src/lib/appManagers/appDialogsManager.ts b/src/lib/appManagers/appDialogsManager.ts index 432125f6..a207fbf5 100644 --- a/src/lib/appManagers/appDialogsManager.ts +++ b/src/lib/appManagers/appDialogsManager.ts @@ -16,7 +16,7 @@ import { isSafari } from "../../helpers/userAgent"; import { logger, LogLevels } from "../logger"; import { RichTextProcessor } from "../richtextprocessor"; import rootScope from "../rootScope"; -import { positionElementByIndex } from "../../helpers/dom"; +import { positionElementByIndex, replaceContent } from "../../helpers/dom"; import appImManager from "./appImManager"; import appMessagesManager, { Dialog } from "./appMessagesManager"; import {MyDialogFilter as DialogFilter} from "../storages/filters"; @@ -36,6 +36,7 @@ import { InputNotifyPeer } from "../../layer"; import PeerTitle from "../../components/peerTitle"; import { i18n } from "../langPack"; import findUpTag from "../../helpers/dom/findUpTag"; +import appChatsManager from "./appChatsManager"; export type DialogDom = { avatarEl: AvatarElement, @@ -465,7 +466,7 @@ export class AppDialogsManager { if(!dialog) return; if(typings.length) { - this.setTyping(dialog, appUsersManager.getUser(typings[0])); + this.setTyping(dialog); } else { this.unsetTyping(dialog); } @@ -1379,26 +1380,20 @@ export class AppDialogsManager { return {dom, dialog}; } - public setTyping(dialog: Dialog, user: User) { + public setTyping(dialog: Dialog) { const dom = this.getDialogDom(dialog.peerId); if(!dom) { return; } - let str = ''; - if(dialog.peerId < 0) { - let s = user.rFirstName || user.username; - if(!s) return; - str = s + ' '; - } - - const senderBold = document.createElement('i'); - str += 'typing...'; - senderBold.innerHTML = str; - - dom.lastMessageSpan.innerHTML = ''; - dom.lastMessageSpan.append(senderBold); - dom.lastMessageSpan.classList.add('user-typing'); + let typingElement = dom.lastMessageSpan.querySelector('.peer-typing-container') as HTMLElement; + if(typingElement) { + appImManager.getPeerTyping(dialog.peerId, typingElement); + } else { + typingElement = appImManager.getPeerTyping(dialog.peerId); + replaceContent(dom.lastMessageSpan, typingElement); + dom.lastMessageSpan.classList.add('user-typing'); + } } public unsetTyping(dialog: Dialog) { diff --git a/src/lib/appManagers/appImManager.ts b/src/lib/appManagers/appImManager.ts index ff9a7175..fa78c63f 100644 --- a/src/lib/appManagers/appImManager.ts +++ b/src/lib/appManagers/appImManager.ts @@ -24,7 +24,7 @@ import appPhotosManager from './appPhotosManager'; import appProfileManager from './appProfileManager'; import appStickersManager from './appStickersManager'; import appWebPagesManager from './appWebPagesManager'; -import { blurActiveElement, cancelEvent, disableTransition, placeCaretAtEnd, whichChild } from '../../helpers/dom'; +import { blurActiveElement, cancelEvent, disableTransition, placeCaretAtEnd, replaceContent, whichChild } from '../../helpers/dom'; import PopupNewMedia from '../../components/popups/newMedia'; import MarkupTooltip from '../../components/chat/markupTooltip'; import { isTouchSupported } from '../../helpers/touchSupport'; @@ -43,11 +43,12 @@ import { MOUNT_CLASS_TO } from '../../config/debug'; import appNavigationController from '../../components/appNavigationController'; import appNotificationsManager from './appNotificationsManager'; import AppPrivateSearchTab from '../../components/sidebarRight/tabs/search'; -import { i18n } from '../langPack'; +import { i18n, LangPackKey } from '../langPack'; import { SendMessageAction } from '../../layer'; import { hslaStringToRgbString } from '../../helpers/color'; import { copy, getObjectKeysAndSort } from '../../helpers/object'; import { getFilesFromEvent } from '../../helpers/files'; +import PeerTitle from '../../components/peerTitle'; //console.log('appImManager included33!'); @@ -295,7 +296,8 @@ export class AppImManager { } const key = chat.peerId + (chat.threadId ? '_' + chat.threadId : ''); - return sessionStorage.getFromCache('chatPositions')[key]; + const cache = sessionStorage.getFromCache('chatPositions'); + return cache && cache[key]; } public applyHighlightningColor() { @@ -840,9 +842,10 @@ export class AppImManager { private getTypingElement(action: SendMessageAction) { const el = document.createElement('span'); el.classList.add('peer-typing'); + el.dataset.action = action._; switch(action._) { - //case 'sendMessageTypingAction': { - default: { + case 'sendMessageTypingAction': { + //default: { const c = 'peer-typing-text'; el.classList.add(c); for(let i = 0; i < 3; ++i) { @@ -852,16 +855,146 @@ export class AppImManager { } break; } + + case 'sendMessageUploadAudioAction': + case 'sendMessageUploadDocumentAction': + case 'sendMessageUploadRoundAction': + case 'sendMessageUploadVideoAction': + case 'sendMessageUploadPhotoAction': { + const c = 'peer-typing-upload'; + el.classList.add(c); + /* const trail = document.createElement('span'); + trail.className = c + '-trail'; + el.append(trail); */ + break; + } + + case 'sendMessageRecordAudioAction': + case 'sendMessageRecordRoundAction': + case 'sendMessageRecordVideoAction': { + const c = 'peer-typing-record'; + el.classList.add(c); + break; + } } return el; } + public getPeerTyping(peerId: number, container?: HTMLElement) { + if(!appUsersManager.isBot(peerId)) { + const typings = appChatsManager.typingsInPeer[peerId]; + if(!typings || !typings.length) { + return; + } + + const typing = typings[0]; + + const langPackKeys: { + [peerType in 'private' | 'chat' | 'multi']?: Partial<{[action in SendMessageAction['_']]: LangPackKey}> + } = { + private: { + 'sendMessageTypingAction': 'Peer.Activity.User.TypingText', + 'sendMessageUploadAudioAction': 'Peer.Activity.User.SendingFile', + 'sendMessageUploadDocumentAction': 'Peer.Activity.User.SendingFile', + 'sendMessageUploadPhotoAction': 'Peer.Activity.User.SendingPhoto', + 'sendMessageUploadVideoAction': 'Peer.Activity.User.SendingVideo', + 'sendMessageUploadRoundAction': 'Peer.Activity.User.SendingVideo', + 'sendMessageRecordVideoAction': 'Peer.Activity.User.RecordingVideo', + 'sendMessageRecordAudioAction': 'Peer.Activity.User.RecordingAudio', + 'sendMessageRecordRoundAction': 'Peer.Activity.User.RecordingVideo', + 'sendMessageGamePlayAction': 'Peer.Activity.User.PlayingGame' + }, + chat: { + 'sendMessageTypingAction': 'Peer.Activity.Chat.TypingText', + 'sendMessageUploadAudioAction': 'Peer.Activity.Chat.SendingFile', + 'sendMessageUploadDocumentAction': 'Peer.Activity.Chat.SendingFile', + 'sendMessageUploadPhotoAction': 'Peer.Activity.Chat.SendingPhoto', + 'sendMessageUploadVideoAction': 'Peer.Activity.Chat.SendingVideo', + 'sendMessageUploadRoundAction': 'Peer.Activity.Chat.SendingVideo', + 'sendMessageRecordVideoAction': 'Peer.Activity.Chat.RecordingVideo', + 'sendMessageRecordAudioAction': 'Peer.Activity.Chat.RecordingAudio', + 'sendMessageRecordRoundAction': 'Peer.Activity.Chat.RecordingVideo', + 'sendMessageGamePlayAction': 'Peer.Activity.Chat.PlayingGame' + }, + multi: { + 'sendMessageTypingAction': 'Peer.Activity.Chat.Multi.TypingText1', + 'sendMessageUploadAudioAction': 'Peer.Activity.Chat.Multi.SendingFile1', + 'sendMessageUploadDocumentAction': 'Peer.Activity.Chat.Multi.SendingFile1', + 'sendMessageUploadPhotoAction': 'Peer.Activity.Chat.Multi.SendingPhoto1', + 'sendMessageUploadVideoAction': 'Peer.Activity.Chat.Multi.SendingVideo1', + 'sendMessageUploadRoundAction': 'Peer.Activity.Chat.Multi.SendingVideo1', + 'sendMessageRecordVideoAction': 'Peer.Activity.Chat.Multi.RecordingVideo1', + 'sendMessageRecordAudioAction': 'Peer.Activity.Chat.Multi.RecordingAudio1', + 'sendMessageRecordRoundAction': 'Peer.Activity.Chat.Multi.RecordingVideo1', + 'sendMessageGamePlayAction': 'Peer.Activity.Chat.Multi.PlayingGame1' + } + }; + + const mapa = peerId > 0 ? langPackKeys.private : (typings.length > 1 ? langPackKeys.multi : langPackKeys.chat); + let action = typing.action; + + if(typings.length > 1) { + const s: any = {}; + typings.forEach(typing => { + const type = typing.action._; + if(s[type] === undefined) s[type] = 0; + ++s[type]; + }); + + if(Object.keys(s).length > 1) { + action = { + _: 'sendMessageTypingAction' + }; + } + } + + const langPackKey = mapa[action._]; + if(!langPackKey) { + return; + } + + if(!container) { + container = document.createElement('span'); + container.classList.add('online', 'peer-typing-container'); + } + + let typingElement = container.firstElementChild as HTMLElement; + if(!typingElement) { + typingElement = this.getTypingElement(action); + container.prepend(typingElement); + } else { + if(typingElement.dataset.action !== action._) { + typingElement.replaceWith(this.getTypingElement(action)); + } + } + + let args: any[]; + if(peerId < 0) { + args = [ + new PeerTitle({peerId: typing.userId, onlyFirstName: true}).element, + typings.length - 1 + ]; + } + const descriptionElement = i18n(langPackKey, args); + descriptionElement.classList.add('peer-typing-description'); + + if(container.childElementCount > 1) container.lastElementChild.replaceWith(descriptionElement); + else container.append(descriptionElement); + return container; + } + } + public async getPeerStatus(peerId: number) { let subtitle: HTMLElement; if(!peerId) return ''; if(peerId < 0) { // not human + let span = this.getPeerTyping(peerId); + if(span) { + return span; + } + const chatInfo = await appProfileManager.getChatFull(-peerId) as any; this.chat.log('chatInfo res:', chatInfo); @@ -886,16 +1019,14 @@ export class AppImManager { subtitle = appUsersManager.getUserStatusString(user.id); if(!appUsersManager.isBot(peerId)) { - const typings = appChatsManager.typingsInPeer[peerId]; - if(typings && typings.length) { - const span = document.createElement('span'); - span.classList.add('online'); - span.append(this.getTypingElement(typings[0].action), i18n('Peer.Activity.User.TypingText')); - return span; - } else if(user.status?._ === 'userStatusOnline') { - const span = document.createElement('span'); + let span = this.getPeerTyping(peerId); + if(!span && user.status?._ === 'userStatusOnline') { + span = document.createElement('span'); span.classList.add('online'); span.append(subtitle); + } + + if(span) { return span; } } @@ -904,6 +1035,26 @@ export class AppImManager { } } } + + public setPeerStatus(peerId: number, element: HTMLElement, needClear: boolean, useWhitespace: boolean, middleware: () => boolean) { + if(needClear) { + element.innerHTML = useWhitespace ? '‎' : ''; // ! HERE U CAN FIND WHITESPACE + } + + // * good good good + const typingContainer = element.querySelector('.peer-typing-container') as HTMLElement; + if(typingContainer && this.getPeerTyping(peerId, typingContainer)) { + return; + } + + this.getPeerStatus(peerId).then((subtitle) => { + if(!middleware()) { + return; + } + + replaceContent(element, subtitle || (useWhitespace ? '‎' : '')); + }); + } } const appImManager = new AppImManager(); diff --git a/src/lib/mtproto/apiManager.ts b/src/lib/mtproto/apiManager.ts index 9ccc4d95..0f8de549 100644 --- a/src/lib/mtproto/apiManager.ts +++ b/src/lib/mtproto/apiManager.ts @@ -301,7 +301,8 @@ export class ApiManager { deferred.reject(error); - if(error.code === 401 && error.type === 'SESSION_REVOKED') { + if((error.code === 401 && error.type === 'SESSION_REVOKED') || + (error.code === 406 && error.type === 'AUTH_KEY_DUPLICATED')) { this.logOut(); } diff --git a/src/scss/partials/_chat.scss b/src/scss/partials/_chat.scss index f3917a06..23baf165 100644 --- a/src/scss/partials/_chat.scss +++ b/src/scss/partials/_chat.scss @@ -70,7 +70,7 @@ $chat-helper-size: 39px; } .chat-input-container { - --padding-horizontal: #{$chat-padding-handhelds}; + --padding-horizontal: var(--chat-input-padding); display: flex; align-items: flex-end; justify-content: space-between; @@ -82,10 +82,6 @@ $chat-helper-size: 39px; position: relative; padding-bottom: var(--bottom); - @include respond-to(not-handhelds) { - --padding-horizontal: #{$chat-padding}; - } - .btn-circle { width: var(--chat-input-size); height: var(--chat-input-size); @@ -611,7 +607,7 @@ $chat-helper-size: 39px; .chat-input-wrapper { --padding-vertical: .3125rem; - --padding-horizontal: .5rem; + --padding-horizontal: var(--chat-input-inner-padding); --padding: var(--padding-vertical) var(--padding-horizontal); display: flex; align-items: center; @@ -781,7 +777,6 @@ $chat-helper-size: 39px; @include respond-to(handhelds) { --padding-vertical: 1px; - --padding-horizontal: #{$chat-padding-handhelds}; } @media only screen and (max-width: 420px) { @@ -790,7 +785,6 @@ $chat-helper-size: 39px; @include respond-to(esg-bottom) { --padding-vertical: 1px; - --padding-horizontal: #{$chat-padding-handhelds}; } .bubble-tail { diff --git a/src/scss/partials/_chatlist.scss b/src/scss/partials/_chatlist.scss index 1ae4d331..71ecd68b 100644 --- a/src/scss/partials/_chatlist.scss +++ b/src/scss/partials/_chatlist.scss @@ -156,15 +156,6 @@ ul.chatlist { } } - span { - //display: inline-block; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - //margin: .1rem 0; - line-height: 27px; - } - p { margin: 0; display: flex; @@ -204,11 +195,14 @@ ul.chatlist { .tgico-chatspinned:before, //.user-title:after, .user-title, - b, .message-status { color: #fff; } + b { + color: #fff !important; + } + .user-title:after { color: rgba(255, 255, 255, .7); } @@ -230,10 +224,34 @@ ul.chatlist { background-color: #fff !important; color: var(--primary-color); } + + .peer-typing-container { + --color: #fff; + } } } } + /* .user-title, + .dialog-title-details, + .user-last-message */li span { + //display: inline-block; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + //margin: .1rem 0; + line-height: 27px; + } + + .peer-typing-container { + --color: var(--secondary-text-color); + + .peer-typing-text { + display: inline-flex; + transform: translateY(-2px); + } + } + .dialog { &-title { &-details { diff --git a/src/scss/partials/_peerTyping.scss b/src/scss/partials/_peerTyping.scss index 465a2a0d..59d92a04 100644 --- a/src/scss/partials/_peerTyping.scss +++ b/src/scss/partials/_peerTyping.scss @@ -5,16 +5,34 @@ */ .peer-typing { - display: inline-block; + //display: flex; margin-right: 4px; + + &-container { + --color: var(--primary-color); + color: var(--color); + //display: inline-block; + //display: flex; + //align-items: center; + } + + /* &-description { + @include text-overflow(); + } */ + + &:not(.peer-typing-text) { + display: inline-block; + vertical-align: middle; + transform: translateY(-1px); + } &-text { &-dot { width: 6px; height: 6px; border-radius: 50%; - background-color: var(--primary-color); - margin: 0 1px; + background-color: var(--color); + margin: 0 .5px; display: inline-block; vertical-align: middle; animation-duration: .6s; @@ -31,6 +49,49 @@ animation-name: dotLast; } } + + &-upload { + width: 13px; + height: 5px; + overflow: hidden; + position: relative; + border-radius: 2px; + margin-right: .375rem; + + &:before, &:after { + display: block; + content: " "; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + background-color: var(--color); + border-radius: inherit; + } + + &:before { + opacity: .3; + } + + &:after { + animation: upload 1s ease-in-out infinite; + } + } + + &-record { + margin-right: .375rem; + + &:before { + content: " "; + display: block; + width: 6px; + height: 6px; + border-radius: 50%; + background-color: var(--color); + animation: recordBlink 1.25s infinite; + } + } } $scale-max: 1; @@ -111,3 +172,13 @@ $opacity-min: $opacity-max - ($opacity-step * 2); opacity: $opacity-max; } } + +@keyframes upload { + 0% { + transform: translateX(-13px); + } + + 100% { + transform: translate(13px); + } +} diff --git a/src/scss/partials/_profile.scss b/src/scss/partials/_profile.scss index 3b298602..efd73732 100644 --- a/src/scss/partials/_profile.scss +++ b/src/scss/partials/_profile.scss @@ -82,8 +82,8 @@ margin: 0; } - .peer-typing-text-dot { - background-color: #fff; + .peer-typing-container { + --color: #fff; } .profile-name { @@ -162,6 +162,12 @@ padding-bottom: .5rem; //margin-bottom: .75rem; //box-shadow: 0px 1px 5px -1px rgba(0, 0, 0, .16); + + .profile-subtitle { + .peer-typing-container { + justify-content: center; + } + } } /* .search-super { diff --git a/src/scss/style.scss b/src/scss/style.scss index 8902c3e4..126f512f 100644 --- a/src/scss/style.scss +++ b/src/scss/style.scss @@ -24,12 +24,21 @@ $messages-container-width: 728px; $chat-input-size: 3.375rem; $chat-input-handhelds-size: 2.875rem; $chat-padding: .8125rem; -$chat-padding-handhelds: .25rem; +$chat-padding-handhelds: .5rem; +$chat-input-inner-padding: .5rem; +$chat-input-inner-padding-handhelds: .25rem; @function hover-color($color) { @return rgba($color, $hover-alpha); } +/* @mixin safari-overflow() { + html.is-safari & { + -webkit-mask-image: -webkit-radial-gradient(circle, white 100%, black 100%); + @content; + } +} */ + @import "mixins/hover"; @import "mixins/respondTo"; @import "mixins/textOverflow"; @@ -90,6 +99,7 @@ $chat-padding-handhelds: .25rem; --chat-input-size: #{$chat-input-handhelds-size}; --chat-input-padding: #{$chat-padding-handhelds}; + --chat-input-inner-padding: #{$chat-input-inner-padding-handhelds}; } @include respond-to(not-handhelds) { @@ -97,10 +107,12 @@ $chat-padding-handhelds: .25rem; --chat-input-size: #{$chat-input-size}; --chat-input-padding: #{$chat-padding}; + --chat-input-inner-padding: #{$chat-input-inner-padding}; } @include respond-to(esg-bottom) { --chat-input-size: #{$chat-input-handhelds-size}; + --chat-input-inner-padding: #{$chat-input-inner-padding-handhelds}; } @include respond-to(only-medium-screens) {