Browse Source

Typing statuses

Handle AUTH_KEY_DUPLICATED
master
morethanwords 3 years ago
parent
commit
73b47ad5c7
  1. 5
      src/components/appSelectPeers.ts
  2. 8
      src/components/chat/bubbles.ts
  3. 10
      src/components/chat/contextMenu.ts
  4. 15
      src/components/chat/topbar.ts
  5. 8
      src/components/misc.ts
  6. 2
      src/components/sidebarLeft/tabs/includedChats.ts
  7. 13
      src/components/sidebarRight/tabs/sharedMedia.ts
  8. 4
      src/config/app.ts
  9. 4
      src/index.ts
  10. 27
      src/lang.ts
  11. 85
      src/lib/appManagers/appChatsManager.ts
  12. 29
      src/lib/appManagers/appDialogsManager.ts
  13. 177
      src/lib/appManagers/appImManager.ts
  14. 3
      src/lib/mtproto/apiManager.ts
  15. 10
      src/scss/partials/_chat.scss
  16. 38
      src/scss/partials/_chatlist.scss
  17. 77
      src/scss/partials/_peerTyping.scss
  18. 10
      src/scss/partials/_profile.scss
  19. 14
      src/scss/style.scss

5
src/components/appSelectPeers.ts

@ -7,7 +7,6 @@
import appChatsManager, { ChatRights } from "../lib/appManagers/appChatsManager"; import appChatsManager, { ChatRights } from "../lib/appManagers/appChatsManager";
import appDialogsManager from "../lib/appManagers/appDialogsManager"; import appDialogsManager from "../lib/appManagers/appDialogsManager";
import appMessagesManager, { Dialog } from "../lib/appManagers/appMessagesManager"; import appMessagesManager, { Dialog } from "../lib/appManagers/appMessagesManager";
import appPeersManager from "../lib/appManagers/appPeersManager";
import appPhotosManager from "../lib/appManagers/appPhotosManager"; import appPhotosManager from "../lib/appManagers/appPhotosManager";
import appUsersManager from "../lib/appManagers/appUsersManager"; import appUsersManager from "../lib/appManagers/appUsersManager";
import rootScope from "../lib/rootScope"; import rootScope from "../lib/rootScope";
@ -167,7 +166,7 @@ export default class AppSelectPeers {
return; return;
} }
target.classList.toggle('active'); //target.classList.toggle('active');
if(this.selected.has(key)) { if(this.selected.has(key)) {
this.remove(key); this.remove(key);
} else { } else {
@ -436,7 +435,7 @@ export default class AppSelectPeers {
const checkboxField = new CheckboxField(); const checkboxField = new CheckboxField();
if(selected) { if(selected) {
dom.listEl.classList.add('active'); //dom.listEl.classList.add('active');
checkboxField.input.checked = true; checkboxField.input.checked = true;
} }

8
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) => { /* if(false) */this.stickyIntersector = new StickyIntersector(this.scrollable.container, (stuck, target) => {
for(const timestamp in this.dateMessages) { for(const timestamp in this.dateMessages) {
const dateMessage = this.dateMessages[timestamp]; const dateMessage = this.dateMessages[timestamp];

10
src/components/chat/contextMenu.ts

@ -36,7 +36,7 @@ export default class ChatContextMenu {
public message: any; public message: any;
constructor(private attachTo: HTMLElement, private chat: Chat, private appMessagesManager: AppMessagesManager, private appChatsManager: AppChatsManager, private appPeersManager: AppPeersManager, private appPollsManager: AppPollsManager) { 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) { if(this.init) {
this.init(); this.init();
this.init = null; this.init = null;
@ -52,11 +52,11 @@ export default class ChatContextMenu {
// ! context menu click by date bubble (there is no pointer-events) // ! context menu click by date bubble (there is no pointer-events)
if(!bubble) return; 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')) { if(this.element.classList.contains('active')) {
return false; 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; let mid = +bubble.dataset.mid;
if(!mid) return; if(!mid) return;
@ -107,14 +107,14 @@ export default class ChatContextMenu {
const side: 'left' | 'right' = bubble.classList.contains('is-in') ? 'left' : 'right'; const side: 'left' | 'right' = bubble.classList.contains('is-in') ? 'left' : 'right';
//bubble.parentElement.append(this.element); //bubble.parentElement.append(this.element);
//appImManager.log('contextmenu', e, bubble, side); //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, () => { openBtnMenu(this.element, () => {
this.peerId = this.mid = 0; this.peerId = this.mid = 0;
this.target = null; this.target = null;
}); });
}; };
if(isTouchSupported) { if(isTouchSupported/* && false */) {
attachClickEvent(attachTo, (e) => { attachClickEvent(attachTo, (e) => {
if(chat.selection.isSelecting) { if(chat.selection.isSelecting) {
return; return;

15
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 { AppPeersManager } from "../../lib/appManagers/appPeersManager";
import type { AppSidebarRight } from "../sidebarRight"; import type { AppSidebarRight } from "../sidebarRight";
import type Chat from "./chat"; 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 mediaSizes, { ScreenSize } from "../../helpers/mediaSizes";
import { isSafari } from "../../helpers/userAgent"; import { isSafari } from "../../helpers/userAgent";
import rootScope from "../../lib/rootScope"; import rootScope from "../../lib/rootScope";
@ -562,17 +562,6 @@ export default class ChatTopbar {
if(!this.subtitle) return; if(!this.subtitle) return;
const peerId = this.peerId; const peerId = this.peerId;
if(needClear) { this.chat.appImManager.setPeerStatus(this.peerId, this.subtitle, needClear, false, () => peerId === this.peerId);
this.subtitle.innerHTML = '';
}
this.chat.appImManager.getPeerStatus(this.peerId).then((subtitle) => {
if(peerId !== this.peerId) {
return;
}
this.subtitle.textContent = '';
this.subtitle.append(subtitle);
});
}; };
} }

8
src/components/misc.ts

@ -10,7 +10,7 @@ import { cancelEvent, CLICK_EVENT_NAME } from "../helpers/dom";
import ListenerSetter from "../helpers/listenerSetter"; import ListenerSetter from "../helpers/listenerSetter";
import mediaSizes from "../helpers/mediaSizes"; import mediaSizes from "../helpers/mediaSizes";
import { isTouchSupported } from "../helpers/touchSupport"; import { isTouchSupported } from "../helpers/touchSupport";
import { isApple, isMobileSafari } from "../helpers/userAgent"; import { isApple, isMobileSafari, isSafari } from "../helpers/userAgent";
import appNavigationController from "./appNavigationController"; import appNavigationController from "./appNavigationController";
export function putPreloader(elem: Element, returnDiv = false): HTMLElement { export function putPreloader(elem: Element, returnDiv = false): HTMLElement {
@ -341,6 +341,12 @@ export function attachContextMenuListener(element: HTMLElement, callback: (e: To
} }
}, .4e3); }, .4e3);
}); });
/* if(!isSafari) {
add('contextmenu', (e: any) => {
cancelEvent(e);
}, {passive: false, capture: true});
} */
} else { } else {
add('contextmenu', isTouchSupported ? (e: any) => { add('contextmenu', isTouchSupported ? (e: any) => {
callback(e); callback(e);

2
src/components/sidebarLeft/tabs/includedChats.ts

@ -138,7 +138,7 @@ export default class AppIncludedChatsTab extends SliderSuperTab {
const selected = this.selector.selected.has(peerId); const selected = this.selector.selected.has(peerId);
dom.containerEl.append(this.checkbox(selected)); dom.containerEl.append(this.checkbox(selected));
if(selected) dom.listEl.classList.add('active'); //if(selected) dom.listEl.classList.add('active');
const foundInFilters: HTMLElement[] = []; const foundInFilters: HTMLElement[] = [];
this.dialogsByFilters.forEach((dialogs, filter) => { this.dialogsByFilters.forEach((dialogs, filter) => {

13
src/components/sidebarRight/tabs/sharedMedia.ts

@ -579,18 +579,7 @@ class PeerProfile {
if(!this.peerId) return; if(!this.peerId) return;
const peerId = this.peerId; const peerId = this.peerId;
if(needClear) { appImManager.setPeerStatus(this.peerId, this.subtitle, needClear, true, () => peerId === this.peerId);
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 || '');
});
}; };
public cleanupHTML() { public cleanupHTML() {

4
src/config/app.ts

@ -12,8 +12,8 @@
const App = { const App = {
id: 1025907, id: 1025907,
hash: '452b0359b988148995f22ff0f4229750', hash: '452b0359b988148995f22ff0f4229750',
version: '0.4.2', version: '0.4.3',
langPackVersion: '0.1.4', langPackVersion: '0.1.5',
langPack: 'macos', langPack: 'macos',
langPackCode: 'en', langPackCode: 'en',
domains: [] as string[], domains: [] as string[],

4
src/index.ts

@ -139,10 +139,10 @@ console.timeEnd('get storage1'); */
}); });
if(userAgent.isApple) { if(userAgent.isApple) {
if(userAgent.isSafari && userAgent.isMobile) { if(userAgent.isSafari) {
document.documentElement.classList.add('is-safari'); document.documentElement.classList.add('is-safari');
if(touchSupport.isTouchSupported) { if(userAgent.isMobile && touchSupport.isTouchSupported) {
let key: 'clientY' | 'pageY' = 'clientY'; let key: 'clientY' | 'pageY' = 'clientY';
let startY = 0; let startY = 0;
const o = {capture: true, passive: false}; const o = {capture: true, passive: false};

27
src/lang.ts

@ -524,13 +524,28 @@ const lang = {
"Stickers.SuggestStickers": "Suggest Stickers by Emoji", "Stickers.SuggestStickers": "Suggest Stickers by Emoji",
"ShareModal.Search.ForwardPlaceholder": "Forward to...", "ShareModal.Search.ForwardPlaceholder": "Forward to...",
"InstalledStickers.LoopAnimated": "Loop Animated Stickers", "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.TypingText": "typing",
// "Peer.Activity.User.SendingPhoto": "sending a photo", "Peer.Activity.User.SendingPhoto": "sending a photo",
// "Peer.Activity.User.RecordingVideo": "recording video", "Peer.Activity.User.RecordingVideo": "recording video",
// "Peer.Activity.User.SendingVideo": "sending a video", "Peer.Activity.User.SendingVideo": "sending a video",
// "Peer.Activity.User.RecordingAudio": "recording voice", "Peer.Activity.User.RecordingAudio": "recording voice",
// "Peer.Activity.User.SendingFile": "sending file", "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.ServiceNotifications": "service notifications",
"Peer.RepliesNotifications": "Reply Notifications", "Peer.RepliesNotifications": "Reply Notifications",
"Peer.Status.online": "online", "Peer.Status.online": "online",

85
src/lib/appManagers/appChatsManager.ts

@ -71,53 +71,74 @@ export class AppChatsManager {
} }
case 'updateUserTyping': case 'updateUserTyping':
case 'updateChatUserTyping': { case 'updateChatUserTyping':
case 'updateChannelUserTyping': {
const fromId = (update as Update.updateUserTyping).user_id || appPeersManager.getPeerId((update as Update.updateChatUserTyping).from_id); const fromId = (update as Update.updateUserTyping).user_id || appPeersManager.getPeerId((update as Update.updateChatUserTyping).from_id);
if(rootScope.myId === fromId) { 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] = []); const typings = this.typingsInPeer[peerId] ?? (this.typingsInPeer[peerId] = []);
let typing = typings.find(t => t.userId === fromId); let typing = typings.find(t => t.userId === fromId);
if(!typing) {
typing = {
userId: fromId
};
typings.push(typing); const cancelAction = () => {
}
//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(() => {
delete typing.timeout; 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}); rootScope.broadcast('peer_typings', {peerId, typings});
if(!typings.length) { if(!typings.length) {
delete this.typingsInPeer[peerId]; 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; break;
} }
} }

29
src/lib/appManagers/appDialogsManager.ts

@ -16,7 +16,7 @@ import { isSafari } from "../../helpers/userAgent";
import { logger, LogLevels } from "../logger"; import { logger, LogLevels } from "../logger";
import { RichTextProcessor } from "../richtextprocessor"; import { RichTextProcessor } from "../richtextprocessor";
import rootScope from "../rootScope"; import rootScope from "../rootScope";
import { positionElementByIndex } from "../../helpers/dom"; import { positionElementByIndex, replaceContent } from "../../helpers/dom";
import appImManager from "./appImManager"; import appImManager from "./appImManager";
import appMessagesManager, { Dialog } from "./appMessagesManager"; import appMessagesManager, { Dialog } from "./appMessagesManager";
import {MyDialogFilter as DialogFilter} from "../storages/filters"; import {MyDialogFilter as DialogFilter} from "../storages/filters";
@ -36,6 +36,7 @@ import { InputNotifyPeer } from "../../layer";
import PeerTitle from "../../components/peerTitle"; import PeerTitle from "../../components/peerTitle";
import { i18n } from "../langPack"; import { i18n } from "../langPack";
import findUpTag from "../../helpers/dom/findUpTag"; import findUpTag from "../../helpers/dom/findUpTag";
import appChatsManager from "./appChatsManager";
export type DialogDom = { export type DialogDom = {
avatarEl: AvatarElement, avatarEl: AvatarElement,
@ -465,7 +466,7 @@ export class AppDialogsManager {
if(!dialog) return; if(!dialog) return;
if(typings.length) { if(typings.length) {
this.setTyping(dialog, appUsersManager.getUser(typings[0])); this.setTyping(dialog);
} else { } else {
this.unsetTyping(dialog); this.unsetTyping(dialog);
} }
@ -1379,26 +1380,20 @@ export class AppDialogsManager {
return {dom, dialog}; return {dom, dialog};
} }
public setTyping(dialog: Dialog, user: User) { public setTyping(dialog: Dialog) {
const dom = this.getDialogDom(dialog.peerId); const dom = this.getDialogDom(dialog.peerId);
if(!dom) { if(!dom) {
return; return;
} }
let str = ''; let typingElement = dom.lastMessageSpan.querySelector('.peer-typing-container') as HTMLElement;
if(dialog.peerId < 0) { if(typingElement) {
let s = user.rFirstName || user.username; appImManager.getPeerTyping(dialog.peerId, typingElement);
if(!s) return; } else {
str = s + ' '; typingElement = appImManager.getPeerTyping(dialog.peerId);
} replaceContent(dom.lastMessageSpan, typingElement);
dom.lastMessageSpan.classList.add('user-typing');
const senderBold = document.createElement('i'); }
str += 'typing...';
senderBold.innerHTML = str;
dom.lastMessageSpan.innerHTML = '';
dom.lastMessageSpan.append(senderBold);
dom.lastMessageSpan.classList.add('user-typing');
} }
public unsetTyping(dialog: Dialog) { public unsetTyping(dialog: Dialog) {

177
src/lib/appManagers/appImManager.ts

@ -24,7 +24,7 @@ import appPhotosManager from './appPhotosManager';
import appProfileManager from './appProfileManager'; import appProfileManager from './appProfileManager';
import appStickersManager from './appStickersManager'; import appStickersManager from './appStickersManager';
import appWebPagesManager from './appWebPagesManager'; 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 PopupNewMedia from '../../components/popups/newMedia';
import MarkupTooltip from '../../components/chat/markupTooltip'; import MarkupTooltip from '../../components/chat/markupTooltip';
import { isTouchSupported } from '../../helpers/touchSupport'; import { isTouchSupported } from '../../helpers/touchSupport';
@ -43,11 +43,12 @@ import { MOUNT_CLASS_TO } from '../../config/debug';
import appNavigationController from '../../components/appNavigationController'; import appNavigationController from '../../components/appNavigationController';
import appNotificationsManager from './appNotificationsManager'; import appNotificationsManager from './appNotificationsManager';
import AppPrivateSearchTab from '../../components/sidebarRight/tabs/search'; import AppPrivateSearchTab from '../../components/sidebarRight/tabs/search';
import { i18n } from '../langPack'; import { i18n, LangPackKey } from '../langPack';
import { SendMessageAction } from '../../layer'; import { SendMessageAction } from '../../layer';
import { hslaStringToRgbString } from '../../helpers/color'; import { hslaStringToRgbString } from '../../helpers/color';
import { copy, getObjectKeysAndSort } from '../../helpers/object'; import { copy, getObjectKeysAndSort } from '../../helpers/object';
import { getFilesFromEvent } from '../../helpers/files'; import { getFilesFromEvent } from '../../helpers/files';
import PeerTitle from '../../components/peerTitle';
//console.log('appImManager included33!'); //console.log('appImManager included33!');
@ -295,7 +296,8 @@ export class AppImManager {
} }
const key = chat.peerId + (chat.threadId ? '_' + chat.threadId : ''); const key = chat.peerId + (chat.threadId ? '_' + chat.threadId : '');
return sessionStorage.getFromCache('chatPositions')[key]; const cache = sessionStorage.getFromCache('chatPositions');
return cache && cache[key];
} }
public applyHighlightningColor() { public applyHighlightningColor() {
@ -840,9 +842,10 @@ export class AppImManager {
private getTypingElement(action: SendMessageAction) { private getTypingElement(action: SendMessageAction) {
const el = document.createElement('span'); const el = document.createElement('span');
el.classList.add('peer-typing'); el.classList.add('peer-typing');
el.dataset.action = action._;
switch(action._) { switch(action._) {
//case 'sendMessageTypingAction': { case 'sendMessageTypingAction': {
default: { //default: {
const c = 'peer-typing-text'; const c = 'peer-typing-text';
el.classList.add(c); el.classList.add(c);
for(let i = 0; i < 3; ++i) { for(let i = 0; i < 3; ++i) {
@ -852,16 +855,146 @@ export class AppImManager {
} }
break; 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; 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) { public async getPeerStatus(peerId: number) {
let subtitle: HTMLElement; let subtitle: HTMLElement;
if(!peerId) return ''; if(!peerId) return '';
if(peerId < 0) { // not human if(peerId < 0) { // not human
let span = this.getPeerTyping(peerId);
if(span) {
return span;
}
const chatInfo = await appProfileManager.getChatFull(-peerId) as any; const chatInfo = await appProfileManager.getChatFull(-peerId) as any;
this.chat.log('chatInfo res:', chatInfo); this.chat.log('chatInfo res:', chatInfo);
@ -886,16 +1019,14 @@ export class AppImManager {
subtitle = appUsersManager.getUserStatusString(user.id); subtitle = appUsersManager.getUserStatusString(user.id);
if(!appUsersManager.isBot(peerId)) { if(!appUsersManager.isBot(peerId)) {
const typings = appChatsManager.typingsInPeer[peerId]; let span = this.getPeerTyping(peerId);
if(typings && typings.length) { if(!span && user.status?._ === 'userStatusOnline') {
const span = document.createElement('span'); 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');
span.classList.add('online'); span.classList.add('online');
span.append(subtitle); span.append(subtitle);
}
if(span) {
return 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(); const appImManager = new AppImManager();

3
src/lib/mtproto/apiManager.ts

@ -301,7 +301,8 @@ export class ApiManager {
deferred.reject(error); 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(); this.logOut();
} }

10
src/scss/partials/_chat.scss

@ -70,7 +70,7 @@ $chat-helper-size: 39px;
} }
.chat-input-container { .chat-input-container {
--padding-horizontal: #{$chat-padding-handhelds}; --padding-horizontal: var(--chat-input-padding);
display: flex; display: flex;
align-items: flex-end; align-items: flex-end;
justify-content: space-between; justify-content: space-between;
@ -82,10 +82,6 @@ $chat-helper-size: 39px;
position: relative; position: relative;
padding-bottom: var(--bottom); padding-bottom: var(--bottom);
@include respond-to(not-handhelds) {
--padding-horizontal: #{$chat-padding};
}
.btn-circle { .btn-circle {
width: var(--chat-input-size); width: var(--chat-input-size);
height: var(--chat-input-size); height: var(--chat-input-size);
@ -611,7 +607,7 @@ $chat-helper-size: 39px;
.chat-input-wrapper { .chat-input-wrapper {
--padding-vertical: .3125rem; --padding-vertical: .3125rem;
--padding-horizontal: .5rem; --padding-horizontal: var(--chat-input-inner-padding);
--padding: var(--padding-vertical) var(--padding-horizontal); --padding: var(--padding-vertical) var(--padding-horizontal);
display: flex; display: flex;
align-items: center; align-items: center;
@ -781,7 +777,6 @@ $chat-helper-size: 39px;
@include respond-to(handhelds) { @include respond-to(handhelds) {
--padding-vertical: 1px; --padding-vertical: 1px;
--padding-horizontal: #{$chat-padding-handhelds};
} }
@media only screen and (max-width: 420px) { @media only screen and (max-width: 420px) {
@ -790,7 +785,6 @@ $chat-helper-size: 39px;
@include respond-to(esg-bottom) { @include respond-to(esg-bottom) {
--padding-vertical: 1px; --padding-vertical: 1px;
--padding-horizontal: #{$chat-padding-handhelds};
} }
.bubble-tail { .bubble-tail {

38
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 { p {
margin: 0; margin: 0;
display: flex; display: flex;
@ -204,11 +195,14 @@ ul.chatlist {
.tgico-chatspinned:before, .tgico-chatspinned:before,
//.user-title:after, //.user-title:after,
.user-title, .user-title,
b,
.message-status { .message-status {
color: #fff; color: #fff;
} }
b {
color: #fff !important;
}
.user-title:after { .user-title:after {
color: rgba(255, 255, 255, .7); color: rgba(255, 255, 255, .7);
} }
@ -230,10 +224,34 @@ ul.chatlist {
background-color: #fff !important; background-color: #fff !important;
color: var(--primary-color); 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 { .dialog {
&-title { &-title {
&-details { &-details {

77
src/scss/partials/_peerTyping.scss

@ -5,16 +5,34 @@
*/ */
.peer-typing { .peer-typing {
display: inline-block; //display: flex;
margin-right: 4px; 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 { &-text {
&-dot { &-dot {
width: 6px; width: 6px;
height: 6px; height: 6px;
border-radius: 50%; border-radius: 50%;
background-color: var(--primary-color); background-color: var(--color);
margin: 0 1px; margin: 0 .5px;
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
animation-duration: .6s; animation-duration: .6s;
@ -31,6 +49,49 @@
animation-name: dotLast; 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; $scale-max: 1;
@ -111,3 +172,13 @@ $opacity-min: $opacity-max - ($opacity-step * 2);
opacity: $opacity-max; opacity: $opacity-max;
} }
} }
@keyframes upload {
0% {
transform: translateX(-13px);
}
100% {
transform: translate(13px);
}
}

10
src/scss/partials/_profile.scss

@ -82,8 +82,8 @@
margin: 0; margin: 0;
} }
.peer-typing-text-dot { .peer-typing-container {
background-color: #fff; --color: #fff;
} }
.profile-name { .profile-name {
@ -162,6 +162,12 @@
padding-bottom: .5rem; padding-bottom: .5rem;
//margin-bottom: .75rem; //margin-bottom: .75rem;
//box-shadow: 0px 1px 5px -1px rgba(0, 0, 0, .16); //box-shadow: 0px 1px 5px -1px rgba(0, 0, 0, .16);
.profile-subtitle {
.peer-typing-container {
justify-content: center;
}
}
} }
/* .search-super { /* .search-super {

14
src/scss/style.scss

@ -24,12 +24,21 @@ $messages-container-width: 728px;
$chat-input-size: 3.375rem; $chat-input-size: 3.375rem;
$chat-input-handhelds-size: 2.875rem; $chat-input-handhelds-size: 2.875rem;
$chat-padding: .8125rem; $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) { @function hover-color($color) {
@return rgba($color, $hover-alpha); @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/hover";
@import "mixins/respondTo"; @import "mixins/respondTo";
@import "mixins/textOverflow"; @import "mixins/textOverflow";
@ -90,6 +99,7 @@ $chat-padding-handhelds: .25rem;
--chat-input-size: #{$chat-input-handhelds-size}; --chat-input-size: #{$chat-input-handhelds-size};
--chat-input-padding: #{$chat-padding-handhelds}; --chat-input-padding: #{$chat-padding-handhelds};
--chat-input-inner-padding: #{$chat-input-inner-padding-handhelds};
} }
@include respond-to(not-handhelds) { @include respond-to(not-handhelds) {
@ -97,10 +107,12 @@ $chat-padding-handhelds: .25rem;
--chat-input-size: #{$chat-input-size}; --chat-input-size: #{$chat-input-size};
--chat-input-padding: #{$chat-padding}; --chat-input-padding: #{$chat-padding};
--chat-input-inner-padding: #{$chat-input-inner-padding};
} }
@include respond-to(esg-bottom) { @include respond-to(esg-bottom) {
--chat-input-size: #{$chat-input-handhelds-size}; --chat-input-size: #{$chat-input-handhelds-size};
--chat-input-inner-padding: #{$chat-input-inner-padding-handhelds};
} }
@include respond-to(only-medium-screens) { @include respond-to(only-medium-screens) {

Loading…
Cancel
Save