Browse Source

Context menu unpin

Refactored pinned container
Pin rights fixed again
master
morethanwords 4 years ago
parent
commit
076e648300
  1. 73
      src/components/chat/audio.ts
  2. 14
      src/components/chat/contextMenu.ts
  3. 61
      src/components/chat/pinnedContainer.ts
  4. 59
      src/components/chat/replyContainer.ts
  5. 27
      src/components/divAndCaption.ts
  6. 31
      src/components/scrollable.ts
  7. 101
      src/components/wrappers.ts
  8. 16
      src/lib/appManagers/appChatsManager.ts
  9. 82
      src/lib/appManagers/appImManager.ts
  10. 14
      src/lib/appManagers/appMessagesManager.ts
  11. 36
      src/scss/partials/_chat.scss

73
src/components/chat/audio.ts

@ -1,65 +1,43 @@
import appImManager from "../../lib/appManagers/appImManager";
import appMessagesManager from "../../lib/appManagers/appMessagesManager"; import appMessagesManager from "../../lib/appManagers/appMessagesManager";
import appPeersManager from "../../lib/appManagers/appPeersManager"; import appPeersManager from "../../lib/appManagers/appPeersManager";
import { RichTextProcessor } from "../../lib/richtextprocessor"; import { RichTextProcessor } from "../../lib/richtextprocessor";
import $rootScope from "../../lib/rootScope"; import $rootScope from "../../lib/rootScope";
import { cancelEvent } from "../../lib/utils"; import { cancelEvent } from "../../lib/utils";
import appMediaPlaybackController from "../appMediaPlaybackController"; import appMediaPlaybackController from "../appMediaPlaybackController";
import DivAndCaption from "../divAndCaption";
import { formatDate } from "../wrappers"; import { formatDate } from "../wrappers";
import PinnedContainer from "./pinnedContainer";
export class ChatAudio { export class ChatAudio extends PinnedContainer {
public container: HTMLElement; private toggleEl: HTMLElement;
private toggle: HTMLElement;
private title: HTMLElement;
private subtitle: HTMLElement;
private close: HTMLElement;
constructor() { constructor() {
this.container = document.createElement('div'); super('audio', new DivAndCaption('pinned-audio', (title: string, subtitle: string) => {
this.container.classList.add('pinned-audio', 'pinned-container'); this.divAndCaption.title.innerHTML = title;
this.container.style.display = 'none'; this.divAndCaption.subtitle.innerHTML = subtitle;
}), () => {
this.toggle = document.createElement('div'); if(this.toggleEl.classList.contains('flip-icon')) {
this.toggle.classList.add('pinned-audio-ico', 'tgico');
this.title = document.createElement('div');
this.title.classList.add('pinned-audio-title');
this.subtitle = document.createElement('div');
this.subtitle.classList.add('pinned-audio-subtitle');
this.close = document.createElement('button');
this.close.classList.add('pinned-audio-close', 'btn-icon', 'tgico-close');
this.container.append(this.toggle, this.title, this.subtitle, this.close);
this.close.addEventListener('click', (e) => {
cancelEvent(e);
const scrollTop = appImManager.scrollable.scrollTop;
this.container.style.display = 'none';
appImManager.topbar.classList.remove('is-audio-shown');
if(this.toggle.classList.contains('flip-icon')) {
appMediaPlaybackController.toggle(); appMediaPlaybackController.toggle();
} }
if(!appImManager.topbar.classList.contains('is-pinned-shown')) {
appImManager.scrollable.scrollTop = scrollTop - height;
}
}); });
this.toggle.addEventListener('click', (e) => { this.divAndCaption.border.remove();
this.toggleEl = document.createElement('div');
this.toggleEl.classList.add('pinned-audio-ico', 'tgico');
this.toggleEl.addEventListener('click', (e) => {
cancelEvent(e); cancelEvent(e);
appMediaPlaybackController.toggle(); appMediaPlaybackController.toggle();
}); });
const height = 52; this.divAndCaption.container.prepend(this.toggleEl);
$rootScope.$on('audio_play', (e) => { $rootScope.$on('audio_play', (e) => {
const {doc, mid} = e.detail; const {doc, mid} = e.detail;
let title: string, subtitle: string; let title: string, subtitle: string;
const message = appMessagesManager.getMessage(mid);
if(doc.type == 'voice' || doc.type == 'round') { if(doc.type == 'voice' || doc.type == 'round') {
const message = appMessagesManager.getMessage(mid);
title = appPeersManager.getPeerTitle(message.fromID, false, true); title = appPeersManager.getPeerTitle(message.fromID, false, true);
//subtitle = 'Voice message'; //subtitle = 'Voice message';
subtitle = formatDate(message.date, false, false); subtitle = formatDate(message.date, false, false);
@ -68,24 +46,13 @@ export class ChatAudio {
subtitle = doc.audioPerformer ? RichTextProcessor.wrapPlainText(doc.audioPerformer) : 'Unknown Artist'; subtitle = doc.audioPerformer ? RichTextProcessor.wrapPlainText(doc.audioPerformer) : 'Unknown Artist';
} }
this.title.innerHTML = title; this.fill(title, subtitle, message);
this.subtitle.innerHTML = subtitle; this.toggleEl.classList.add('flip-icon');
this.toggle.classList.add('flip-icon'); this.toggle(false);
this.container.dataset.mid = '' + mid;
if(this.container.style.display) {
const scrollTop = appImManager.scrollable.scrollTop;
this.container.style.display = '';
appImManager.topbar.classList.add('is-audio-shown');
if(!appImManager.topbar.classList.contains('is-pinned-shown')) {
appImManager.scrollable.scrollTop = scrollTop + height;
}
}
}); });
$rootScope.$on('audio_pause', () => { $rootScope.$on('audio_pause', () => {
this.toggle.classList.remove('flip-icon'); this.toggleEl.classList.remove('flip-icon');
}); });
} }
} }

14
src/components/chat/contextMenu.ts

@ -77,7 +77,15 @@ export class ChatContextMenu {
icon: 'pin', icon: 'pin',
text: 'Pin', text: 'Pin',
onClick: this.onPinClick, onClick: this.onPinClick,
verify: (peerID: number) => peerID == $rootScope.myID || (peerID < 0 && appChatsManager.hasRights(-peerID, 'pin')) verify: (peerID: number, msgID: number) => {
const message = appMessagesManager.getMessage(msgID);
return message._ != 'messageService' && appImManager.pinnedMsgID != msgID && (peerID == $rootScope.myID || (peerID < 0 && appChatsManager.hasRights(-peerID, 'pin')));
}
}, {
icon: 'unpin',
text: 'Unpin',
onClick: this.onUnpinClick,
verify: (peerID: number, msgID: number) => appImManager.pinnedMsgID == msgID && (peerID == $rootScope.myID || (peerID < 0 && appChatsManager.hasRights(-peerID, 'pin')))
}, { }, {
icon: 'revote', icon: 'revote',
text: 'Revote', text: 'Revote',
@ -154,6 +162,10 @@ export class ChatContextMenu {
appMessagesManager.updatePinnedMessage($rootScope.selectedPeerID, this.msgID); appMessagesManager.updatePinnedMessage($rootScope.selectedPeerID, this.msgID);
}; };
private onUnpinClick = () => {
appMessagesManager.updatePinnedMessage($rootScope.selectedPeerID, 0);
};
private onRetractVote = () => { private onRetractVote = () => {
appPollsManager.sendVote(this.msgID, []); appPollsManager.sendVote(this.msgID, []);
}; };

61
src/components/chat/pinnedContainer.ts

@ -0,0 +1,61 @@
import mediaSizes from "../../helpers/mediaSizes";
import appImManager from "../../lib/appManagers/appImManager";
import { cancelEvent } from "../../lib/utils";
import DivAndCaption from "../divAndCaption";
const CLASSNAME_SHOWN_MAIN = 'is-pinned-message-shown';
const CLASSNAME_BASE = 'pinned-container';
const HEIGHT = 52;
export default class PinnedContainer {
private close: HTMLElement;
constructor(protected className: string, public divAndCaption: DivAndCaption<(title: string, subtitle: string, message?: any) => void>, onClose?: () => void | Promise<boolean>) {
/* const prev = this.divAndCaption.fill;
this.divAndCaption.fill = (mid, title, subtitle) => {
this.divAndCaption.container.dataset.mid = '' + mid;
prev(mid, title, subtitle);
}; */
divAndCaption.container.classList.add(CLASSNAME_BASE, 'hide');
divAndCaption.title.classList.add(CLASSNAME_BASE + '-title');
divAndCaption.subtitle.classList.add(CLASSNAME_BASE + '-subtitle');
this.close = document.createElement('button');
this.close.classList.add(CLASSNAME_BASE + '-close', `pinned-${className}-close`, 'btn-icon', 'tgico-close');
divAndCaption.container.append(this.close);
this.close.addEventListener('click', (e) => {
cancelEvent(e);
((onClose ? onClose() : null) || Promise.resolve(true)).then(needClose => {
if(needClose) {
this.toggle(true);
}
});
});
}
public toggle(hide?: boolean) {
const isHidden = this.divAndCaption.container.classList.contains('hide');
if(hide === undefined) {
hide = !isHidden;
} else if(hide == isHidden) {
return;
}
const scrollTop = mediaSizes.isMobile ? appImManager.scrollable.scrollTop : undefined;
this.divAndCaption.container.classList.toggle('hide', hide);
appImManager.topbar.classList.toggle(`is-pinned-${this.className}-shown`, !hide);
if(scrollTop !== undefined && !appImManager.topbar.classList.contains(CLASSNAME_SHOWN_MAIN)) {
appImManager.scrollable.scrollTop = scrollTop + ((hide ? -1 : 1) * HEIGHT);
}
}
public fill(title: string, subtitle: string, message: any) {
this.divAndCaption.container.dataset.mid = '' + message.mid;
this.divAndCaption.fill(title, subtitle, message);
}
}

59
src/components/chat/replyContainer.ts

@ -0,0 +1,59 @@
import appPhotosManager from "../../lib/appManagers/appPhotosManager";
import { RichTextProcessor } from "../../lib/richtextprocessor";
import DivAndCaption from "../divAndCaption";
import { renderImageFromUrl } from "../misc";
export default class ReplyContainer extends DivAndCaption<(title: string, subtitle: string, message?: any) => void> {
private mediaEl: HTMLElement;
constructor(protected className: string) {
super(className, (title: string, subtitle: string = '', message?: any) => {
if(title.length > 150) {
title = title.substr(0, 140) + '...';
}
if(subtitle.length > 150) {
subtitle = subtitle.substr(0, 140) + '...';
}
title = title ? RichTextProcessor.wrapEmojiText(title) : '';
if(this.mediaEl) {
this.mediaEl.remove();
this.container.classList.remove('is-media');
}
const media = message && message.media;
if(media) {
subtitle = message.rReply;
//console.log('wrap reply', media);
if(media.photo || (media.document && ['video'].indexOf(media.document.type) !== -1)) {
let replyMedia = document.createElement('div');
replyMedia.classList.add(this.className + '-media');
let photo = media.photo || media.document;
let sizes = photo.sizes || photo.thumbs;
if(sizes && sizes[0].bytes) {
appPhotosManager.setAttachmentPreview(sizes[0].bytes, replyMedia, false, true);
}
appPhotosManager.preloadPhoto(photo, appPhotosManager.choosePhotoSize(photo, 32, 32))
.then(() => {
renderImageFromUrl(replyMedia, photo._ == 'photo' ? photo.url : appPhotosManager.getDocumentCachedThumb(photo.id).url);
});
this.content.prepend(this.mediaEl = replyMedia);
this.container.classList.add('is-media');
}
} else {
subtitle = subtitle ? RichTextProcessor.wrapEmojiText(subtitle) : '';
}
this.title.innerHTML = title;
this.subtitle.innerHTML = subtitle;
});
}
}

27
src/components/divAndCaption.ts

@ -0,0 +1,27 @@
export default class DivAndCaption<T> {
public container: HTMLElement;
public border: HTMLElement;
public content: HTMLElement;
public title: HTMLElement;
public subtitle: HTMLElement;
constructor(protected className: string, public fill: T) {
this.container = document.createElement('div');
this.container.className = className;
this.border = document.createElement('div');
this.border.classList.add(className + '-border');
this.content = document.createElement('div');
this.content.classList.add(className + '-content');
this.title = document.createElement('div');
this.title.classList.add(className + '-title');
this.subtitle = document.createElement('div');
this.subtitle.classList.add(className + '-subtitle');
this.content.append(this.title, this.subtitle);
this.container.append(this.border, this.content);
}
}

31
src/components/scrollable.ts

@ -104,17 +104,22 @@ export class ScrollableBase {
return; return;
} }
if(this.scrollLocked) clearTimeout(this.scrollLocked); const wasLocked = !!this.scrollLocked;
else { if(wasLocked) clearTimeout(this.scrollLocked);
this.scrollLockedPromise = deferredPromise<void>(); if(smooth) {
} if(!wasLocked) {
this.scrollLockedPromise = deferredPromise<void>();
}
this.scrollLocked = window.setTimeout(() => { this.scrollLocked = window.setTimeout(() => {
this.scrollLocked = 0; this.scrollLocked = 0;
this.scrollLockedPromise.resolve();
//this.onScroll();
this.container.dispatchEvent(new CustomEvent('scroll'));
}, scrollTime);
} else if(wasLocked) {
this.scrollLockedPromise.resolve(); this.scrollLockedPromise.resolve();
//this.onScroll(); }
this.container.dispatchEvent(new CustomEvent('scroll'));
}, scrollTime);
const options: SmoothScrollToOptions = { const options: SmoothScrollToOptions = {
behavior: smooth ? 'smooth' : 'auto', behavior: smooth ? 'smooth' : 'auto',
@ -124,6 +129,10 @@ export class ScrollableBase {
options[side] = value; options[side] = value;
this.container.scrollTo(options as any); this.container.scrollTo(options as any);
if(!smooth) {
this.container.dispatchEvent(new CustomEvent('scroll'));
}
} }
get length() { get length() {
@ -490,6 +499,10 @@ export default class Scrollable extends ScrollableBase {
return this.scrollTop; return this.scrollTop;
}; };
get isScrolledDown() {
return this.scrollHeight - Math.round(this.scrollTop + this.container.offsetHeight) <= 1;
}
set scrollTop(y: number) { set scrollTop(y: number) {
this.container.scrollTop = y; this.container.scrollTop = y;
} }

101
src/components/wrappers.ts

@ -1,26 +1,26 @@
import appPhotosManager, {MyPhoto} from '../lib/appManagers/appPhotosManager'; import { readBlobAsText } from '../helpers/blob';
import LottieLoader from '../lib/lottieLoader'; import { deferredPromise } from '../helpers/cancellablePromise';
import { months } from '../helpers/date';
import mediaSizes from '../helpers/mediaSizes';
import { isSafari } from '../helpers/userAgent';
import { PhotoSize } from '../layer';
import appDocsManager, { MyDocument } from "../lib/appManagers/appDocsManager"; import appDocsManager, { MyDocument } from "../lib/appManagers/appDocsManager";
import { DownloadBlob } from '../lib/appManagers/appDownloadManager';
import appMessagesManager from '../lib/appManagers/appMessagesManager';
import appPhotosManager, { MyPhoto } from '../lib/appManagers/appPhotosManager';
import LottieLoader from '../lib/lottieLoader';
import VideoPlayer from '../lib/mediaPlayer';
import { formatBytes, getEmojiToneIndex, isInDOM } from "../lib/utils"; import { formatBytes, getEmojiToneIndex, isInDOM } from "../lib/utils";
import ProgressivePreloader from './preloader'; import webpWorkerController from '../lib/webp/webpWorkerController';
import animationIntersector from './animationIntersector';
import appMediaPlaybackController from './appMediaPlaybackController';
import AudioElement from './audio';
import ReplyContainer from './chat/replyContainer';
import { Layouter, RectPart } from './groupedLayout';
import LazyLoadQueue from './lazyLoadQueue'; import LazyLoadQueue from './lazyLoadQueue';
import VideoPlayer from '../lib/mediaPlayer';
import { RichTextProcessor } from '../lib/richtextprocessor';
import { renderImageFromUrl } from './misc'; import { renderImageFromUrl } from './misc';
import appMessagesManager from '../lib/appManagers/appMessagesManager';
import { Layouter, RectPart } from './groupedLayout';
import PollElement from './poll'; import PollElement from './poll';
import animationIntersector from './animationIntersector'; import ProgressivePreloader from './preloader';
import AudioElement from './audio';
import { DownloadBlob } from '../lib/appManagers/appDownloadManager';
import webpWorkerController from '../lib/webp/webpWorkerController';
import { readBlobAsText } from '../helpers/blob';
import appMediaPlaybackController from './appMediaPlaybackController';
import { PhotoSize } from '../layer';
import { deferredPromise } from '../helpers/cancellablePromise';
import mediaSizes from '../helpers/mediaSizes';
import { isSafari } from '../helpers/userAgent';
import { months } from '../helpers/date';
export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTail, isOut, middleware, lazyLoadQueue, noInfo, group}: { export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTail, isOut, middleware, lazyLoadQueue, noInfo, group}: {
doc: MyDocument, doc: MyDocument,
@ -697,68 +697,11 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o
return lazyLoadQueue && (!doc.downloaded || stickerType == 2) ? (lazyLoadQueue.push({div, load, wasSeen: group == 'chat' && stickerType != 2}), Promise.resolve()) : load(); return lazyLoadQueue && (!doc.downloaded || stickerType == 2) ? (lazyLoadQueue.push({div, load, wasSeen: group == 'chat' && stickerType != 2}), Promise.resolve()) : load();
} }
export function wrapReply(title: string, subtitle: string, message?: any, isPinned?: boolean) { export function wrapReply(title: string, subtitle: string, message?: any) {
const prefix = isPinned ? 'pinned-message' : 'reply'; const replyContainer = new ReplyContainer('reply');
const div = document.createElement('div'); replyContainer.fill(title, subtitle, message);
div.classList.add(prefix);
const replyBorder = document.createElement('div');
replyBorder.classList.add(prefix + '-border');
const replyContent = document.createElement('div');
replyContent.classList.add(prefix + '-content');
const replyTitle = document.createElement('div');
replyTitle.classList.add(prefix + '-title');
const replySubtitle = document.createElement('div');
replySubtitle.classList.add(prefix + '-subtitle');
if(title.length > 150) {
title = title.substr(0, 140) + '...';
}
if(subtitle.length > 150) {
subtitle = subtitle.substr(0, 140) + '...';
}
replyTitle.innerHTML = title ? RichTextProcessor.wrapEmojiText(title) : '';
const media = message && message.media;
if(media) {
replySubtitle.innerHTML = message.rReply;
//console.log('wrap reply', media);
if(media.photo || (media.document && ['video'].indexOf(media.document.type) !== -1)) {
let replyMedia = document.createElement('div');
replyMedia.classList.add(prefix + '-media');
let photo = media.photo || media.document;
let sizes = photo.sizes || photo.thumbs;
if(sizes && sizes[0].bytes) {
appPhotosManager.setAttachmentPreview(sizes[0].bytes, replyMedia, false, true);
}
appPhotosManager.preloadPhoto(photo, appPhotosManager.choosePhotoSize(photo, 32, 32))
.then(() => {
renderImageFromUrl(replyMedia, photo._ == 'photo' ? photo.url : appPhotosManager.getDocumentCachedThumb(photo.id).url);
});
replyContent.append(replyMedia);
div.classList.add('is-media');
}
} else {
replySubtitle.innerHTML = subtitle ? RichTextProcessor.wrapEmojiText(subtitle) : '';
}
replyContent.append(replyTitle, replySubtitle);
div.append(replyBorder, replyContent);
/////////console.log('wrapReply', title, subtitle, media); /////////console.log('wrapReply', title, subtitle, media);
return replyContainer.container;
return div;
} }
export function wrapAlbum({groupID, attachmentDiv, middleware, uploading, lazyLoadQueue, isOut}: { export function wrapAlbum({groupID, attachmentDiv, middleware, uploading, lazyLoadQueue, isOut}: {

16
src/lib/appManagers/appChatsManager.ts

@ -1,4 +1,4 @@
import { ChatBannedRights, InputChannel, InputChatPhoto, InputPeer, Updates } from "../../layer"; import { ChatAdminRights, ChatBannedRights, InputChannel, InputChatPhoto, InputPeer, Updates } from "../../layer";
import apiManager from '../mtproto/mtprotoworker'; import apiManager from '../mtproto/mtprotoworker';
import { RichTextProcessor } from "../richtextprocessor"; import { RichTextProcessor } from "../richtextprocessor";
import $rootScope from "../rootScope"; import $rootScope from "../rootScope";
@ -166,17 +166,19 @@ export class AppChatsManager {
return true; return true;
} }
let myFlags = (chat.admin_rights || chat.banned_rights || chat.default_banned_rights)?.pFlags ?? {}; const rights = chat.admin_rights || chat.banned_rights || chat.default_banned_rights;
let myFlags: {[flag in keyof ChatBannedRights['pFlags'] | keyof ChatAdminRights['pFlags']]: true};
if(rights) myFlags = rights.pFlags;
switch(action) { switch(action) {
// good // good
case 'send': { case 'send': {
if(flag && myFlags[flag]) { if(flag && myFlags && myFlags[flag]) {
return false; return false;
} }
if(chat._ == 'channel') { if(chat._ == 'channel') {
if((!chat.pFlags.megagroup && !myFlags.post_messages)) { if((!chat.pFlags.megagroup && !myFlags?.post_messages)) {
return false; return false;
} }
} }
@ -187,7 +189,7 @@ export class AppChatsManager {
// good // good
case 'deleteRevoke': { case 'deleteRevoke': {
if(chat._ == 'channel') { if(chat._ == 'channel') {
return !!myFlags.delete_messages; return !!myFlags?.delete_messages;
} else if(!chat.pFlags.admin) { } else if(!chat.pFlags.admin) {
return false; return false;
} }
@ -198,9 +200,9 @@ export class AppChatsManager {
// good // good
case 'pin': { case 'pin': {
if(chat._ == 'channel') { if(chat._ == 'channel') {
return chat.admin_rights ? !!myFlags.pin_messages || !!myFlags.post_messages : !!myFlags.pin_messages; return chat.admin_rights ? !!myFlags.pin_messages || !!myFlags.post_messages : myFlags && !myFlags.pin_messages;
} else { } else {
if(myFlags.pin_messages && !chat.pFlags.admin) { if(myFlags?.pin_messages && !chat.pFlags.admin) {
return false; return false;
} }
} }

82
src/lib/appManagers/appImManager.ts

@ -6,6 +6,8 @@ import BubbleGroups from '../../components/bubbleGroups';
import { ChatAudio } from '../../components/chat/audio'; import { ChatAudio } from '../../components/chat/audio';
import { ChatContextMenu } from '../../components/chat/contextMenu'; import { ChatContextMenu } from '../../components/chat/contextMenu';
import { ChatInput } from '../../components/chat/input'; import { ChatInput } from '../../components/chat/input';
import PinnedContainer from '../../components/chat/pinnedContainer';
import ReplyContainer from '../../components/chat/replyContainer';
import { ChatSearch } from '../../components/chat/search'; import { ChatSearch } from '../../components/chat/search';
import { horizontalMenu } from '../../components/horizontalMenu'; import { horizontalMenu } from '../../components/horizontalMenu';
import LazyLoadQueue from '../../components/lazyLoadQueue'; import LazyLoadQueue from '../../components/lazyLoadQueue';
@ -94,7 +96,7 @@ export class AppImManager {
public updateStatusInterval = 0; public updateStatusInterval = 0;
public pinnedMsgID = 0; public pinnedMsgID = 0;
private pinnedMessageContainer: HTMLDivElement = null; private pinnedMessageContainer: PinnedContainer = null;
public lazyLoadQueue = new LazyLoadQueue(); public lazyLoadQueue = new LazyLoadQueue();
@ -165,7 +167,10 @@ export class AppImManager {
parseMenuButtonsTo(this.menuButtons, this.columnEl.querySelector('.chat-more-button').firstElementChild.children); parseMenuButtonsTo(this.menuButtons, this.columnEl.querySelector('.chat-more-button').firstElementChild.children);
this.chatAudio = new ChatAudio(); this.chatAudio = new ChatAudio();
this.chatInfo.nextElementSibling.prepend(this.chatAudio.container); this.chatInfo.nextElementSibling.prepend(this.chatAudio.divAndCaption.container);
this.pinnedMessageContainer = new PinnedContainer('message', new ReplyContainer('pinned-message'));
this.btnJoin.parentElement.insertBefore(this.pinnedMessageContainer.divAndCaption.container, this.btnJoin);
// will call when message is sent (only 1) // will call when message is sent (only 1)
$rootScope.$on('history_append', (e) => { $rootScope.$on('history_append', (e) => {
@ -323,17 +328,20 @@ export class AppImManager {
this.renderMessage(message, true, false, bubble, false); this.renderMessage(message, true, false, bubble, false);
}); });
$rootScope.$on('peer_pinned_message', (e) => {
const peerID = e.detail;
if(peerID == this.peerID) {
(this.messagesQueuePromise || Promise.resolve()).then(() => {
this.setPinnedMessage();
});
}
});
$rootScope.$on('messages_downloaded', (e) => { $rootScope.$on('messages_downloaded', (e) => {
const mids: number[] = e.detail; const mids: number[] = e.detail;
const pinnedMessage = appMessagesManager.getPinnedMessage(this.peerID);
mids.forEach(mid => { mids.forEach(mid => {
if(pinnedMessage.mid == mid) {
(this.messagesQueuePromise || Promise.resolve()).then(() => {
this.setPinnedMessage(pinnedMessage);
});
}
/* const promise = (this.scrollable.scrollLocked && this.scrollable.scrollLockedPromise) || Promise.resolve(); /* const promise = (this.scrollable.scrollLocked && this.scrollable.scrollLockedPromise) || Promise.resolve();
promise.then(() => { promise.then(() => {
@ -747,38 +755,18 @@ export class AppImManager {
}); });
}; };
public setPinnedMessage(message: any) { public setPinnedMessage() {
/////this.log('setting pinned message', message); /////this.log('setting pinned message', message);
//return; //return;
const height = 52; const message = appMessagesManager.getPinnedMessage(this.peerID);
const scrollTop = this.scrollable.container.scrollTop; if(message && !message.deleted) {
const newPinned = wrapReply('Pinned Message', message.message, message, true); this.pinnedMessageContainer.fill('Pinned Message', message.message, message);
newPinned.dataset.mid = '' + message.mid; this.pinnedMessageContainer.toggle(false);
newPinned.classList.add('pinned-container'); this.pinnedMsgID = message.mid;
} else if(this.pinnedMsgID) {
const close = document.createElement('button'); this.pinnedMsgID = 0;
close.classList.add('pinned-message-close', 'btn-icon', 'tgico-close'); this.pinnedMessageContainer.toggle(true);
close.addEventListener('click', (e) => {
cancelEvent(e);
const scrollTop = this.scrollable.scrollTop;
newPinned.remove();
this.topbar.classList.remove('is-pinned-shown');
this.pinnedMessageContainer = null;
this.scrollable.scrollTop = scrollTop - height;
}, {once: true});
newPinned.append(close);
this.btnJoin.parentElement.insertBefore(newPinned, this.btnJoin);
this.topbar.classList.add('is-pinned-shown');
if(this.pinnedMessageContainer) {
this.pinnedMessageContainer.remove();
} }
this.pinnedMessageContainer = newPinned;
//this.pinnedMessageContent.innerHTML = message.rReply;
this.scrollable.scrollTop = scrollTop + height;
} }
public updateStatus() { public updateStatus() {
@ -851,7 +839,7 @@ export class AppImManager {
}, 1350); }, 1350);
} }
if(this.scroll.scrollHeight - Math.round(this.scroll.scrollTop + this.scroll.offsetHeight) <= 1/* <= 5 */) { if(this.scrollable.isScrolledDown) {
this.scroll.parentElement.classList.add('scrolled-down'); this.scroll.parentElement.classList.add('scrolled-down');
this.scrolledDown = true; this.scrolledDown = true;
} else if(this.scroll.parentElement.classList.contains('scrolled-down')) { } else if(this.scroll.parentElement.classList.contains('scrolled-down')) {
@ -1289,13 +1277,7 @@ export class AppImManager {
this.menuButtons.mute.style.display = this.myID == this.peerID ? 'none' : ''; this.menuButtons.mute.style.display = this.myID == this.peerID ? 'none' : '';
const pinned = appMessagesManager.getPinnedMessage(peerID); this.setPinnedMessage();
if(pinned && !pinned.deleted) {
this.setPinnedMessage(pinned);
} else if(this.pinnedMessageContainer) {
this.pinnedMessageContainer.remove();
this.pinnedMessageContainer = null;
}
window.requestAnimationFrame(() => { window.requestAnimationFrame(() => {
let title = ''; let title = '';
@ -1370,9 +1352,13 @@ export class AppImManager {
//if(scrolledDown) this.scrollable.scrollTop = this.scrollable.scrollHeight; //if(scrolledDown) this.scrollable.scrollTop = this.scrollable.scrollHeight;
if(this.messagesQueuePromise && scrolledDown) { if(this.messagesQueuePromise && scrolledDown) {
this.scrollable.scrollTo(this.scrollable.scrollHeight - 1, 'top', false, true); if(this.scrollable.isScrolledDown && !this.scrollable.scrollLocked) {
//this.log('renderNewMessagesByIDs: messagesQueuePromise before will set prev max');
this.scrollable.scrollTo(this.scrollable.scrollHeight - 1, 'top', false, true);
}
this.messagesQueuePromise.then(() => { this.messagesQueuePromise.then(() => {
//this.log('messagesQueuePromise after:', this.chatInner.childElementCount, this.scrollable.scrollHeight); //this.log('renderNewMessagesByIDs: messagesQueuePromise after', this.scrollable.isScrolledDown);
this.scrollable.scrollTo(this.scrollable.scrollHeight, 'top', true, true); this.scrollable.scrollTo(this.scrollable.scrollHeight, 'top', true, true);
/* setTimeout(() => { /* setTimeout(() => {

14
src/lib/appManagers/appMessagesManager.ts

@ -2162,11 +2162,19 @@ export class AppMessagesManager {
public savePinnedMessage(peerID: number, mid: number) { public savePinnedMessage(peerID: number, mid: number) {
if(!mid) { if(!mid) {
delete this.pinnedMessages[peerID]; delete this.pinnedMessages[peerID];
return; } else {
this.pinnedMessages[peerID] = mid;
if(!this.messagesStorage.hasOwnProperty(mid)) {
this.wrapSingleMessage(mid).then(() => {
$rootScope.$broadcast('peer_pinned_message', peerID);
});
return;
}
} }
this.pinnedMessages[peerID] = mid; $rootScope.$broadcast('peer_pinned_message', peerID);
this.wrapSingleMessage(mid);
} }
public getPinnedMessage(peerID: number) { public getPinnedMessage(peerID: number) {

36
src/scss/partials/_chat.scss

@ -17,13 +17,13 @@
// border-bottom: 1px solid #DADCE0; // border-bottom: 1px solid #DADCE0;
@include respond-to(handhelds) { @include respond-to(handhelds) {
&.is-audio-shown, &.is-pinned-shown:not(.hide-pinned) { &.is-pinned-audio-shown, &.is-pinned-message-shown:not(.hide-pinned) {
& + #bubbles { & + #bubbles {
margin-top: 52px; margin-top: 52px;
} }
} }
&.is-pinned-shown:not(.hide-pinned):not(.is-audio-shown) { &.is-pinned-message-shown:not(.hide-pinned):not(.is-pinned-audio-shown) {
.pinned-message { .pinned-message {
display: flex; display: flex;
} }
@ -38,7 +38,7 @@
display: none; display: none;
} }
&.is-pinned-shown:not(.hide-pinned) { &.is-pinned-message-shown:not(.hide-pinned) {
.pinned-message { .pinned-message {
display: flex; display: flex;
} }
@ -102,18 +102,18 @@
} }
@include respond-to(medium-screens) { @include respond-to(medium-screens) {
&.is-pinned-shown { &.is-pinned-message-shown {
body.is-right-column-shown & { body.is-right-column-shown & {
.chat-info { .chat-info {
max-width: calc(100% - var(--right-column-width) * 1.75); max-width: calc(100% - var(--right-column-width) * 1.75);
} }
} }
}
&.is-pinned-shown.is-audio-shown { &.is-pinned-audio-shown {
body.is-right-column-shown & { body.is-right-column-shown & {
.chat-info { .chat-info {
max-width: calc(100% - var(--right-column-width) * 2.25); max-width: calc(100% - var(--right-column-width) * 2.25);
}
} }
} }
} }
@ -792,6 +792,7 @@
.pinned-container { .pinned-container {
flex: 0 0 auto; flex: 0 0 auto;
overflow: visible;
@include respond-to(handhelds) { @include respond-to(handhelds) {
box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.15); box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.15);
@ -808,21 +809,22 @@
} }
} }
.pinned-message-close, .pinned-audio-close, .pinned-audio-ico { &-close, .pinned-audio-ico {
font-size: 1.5rem; font-size: 1.5rem;
position: absolute; position: absolute;
display: flex; display: flex;
justify-content: center; justify-content: center;
right: 0; right: 0;
}
&.tgico-close { &-close {
visibility: hidden; visibility: hidden;
//left: -3rem;
@include respond-to(handhelds) { @include respond-to(handhelds) {
font-size: 1.4rem; font-size: 1.4rem;
right: 9px; right: 9px;
visibility: visible; visibility: visible;
}
} }
} }
} }

Loading…
Cancel
Save