Typing statuses
Handle AUTH_KEY_DUPLICATED
This commit is contained in:
parent
882977a459
commit
73b47ad5c7
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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];
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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) => {
|
||||
|
@ -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() {
|
||||
|
@ -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[],
|
||||
|
@ -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};
|
||||
|
27
src/lang.ts
27
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",
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user