temp profile commit

improved ESG animation
This commit is contained in:
Eduard Kuzmenko 2021-04-06 19:06:42 +04:00
parent 22b3858864
commit 2a5467e074
13 changed files with 731 additions and 393 deletions

View File

@ -1,8 +1,11 @@
import { EmoticonsDropdown, EmoticonsTab } from ".."; import { EmoticonsDropdown, EmoticonsTab } from "..";
import findUpClassName from "../../../helpers/dom/findUpClassName";
import { fastRaf } from "../../../helpers/schedulers";
import appImManager from "../../../lib/appManagers/appImManager"; import appImManager from "../../../lib/appManagers/appImManager";
import appStateManager from "../../../lib/appManagers/appStateManager"; import appStateManager from "../../../lib/appManagers/appStateManager";
import Config from "../../../lib/config"; import Config from "../../../lib/config";
import { RichTextProcessor } from "../../../lib/richtextprocessor"; import { RichTextProcessor } from "../../../lib/richtextprocessor";
import rootScope from "../../../lib/rootScope";
import { putPreloader } from "../../misc"; import { putPreloader } from "../../misc";
import Scrollable from "../../scrollable"; import Scrollable from "../../scrollable";
import StickyIntersector from "../../stickyIntersector"; import StickyIntersector from "../../stickyIntersector";
@ -162,7 +165,29 @@ export default class EmojiTab implements EmoticonsTab {
} }
if(spanEmoji.firstElementChild && !RichTextProcessor.emojiSupported) { if(spanEmoji.firstElementChild && !RichTextProcessor.emojiSupported) {
(spanEmoji.firstElementChild as HTMLImageElement).setAttribute('loading', 'lazy'); const image = spanEmoji.firstElementChild as HTMLImageElement;
image.setAttribute('loading', 'lazy');
const placeholder = document.createElement('span');
placeholder.classList.add('emoji-placeholder');
if(rootScope.settings.animationsEnabled) {
image.style.opacity = '0';
placeholder.style.opacity = '1';
}
image.addEventListener('load', () => {
fastRaf(() => {
if(rootScope.settings.animationsEnabled) {
image.style.opacity = '';
placeholder.style.opacity = '';
}
spanEmoji.classList.remove('empty');
});
}, {once: true});
spanEmoji.append(placeholder);
} }
//spanEmoji = spanEmoji.firstElementChild as HTMLSpanElement; //spanEmoji = spanEmoji.firstElementChild as HTMLSpanElement;
@ -185,7 +210,7 @@ export default class EmojiTab implements EmoticonsTab {
//if(target.tagName !== 'SPAN') return; //if(target.tagName !== 'SPAN') return;
if(target.tagName === 'SPAN' && !target.classList.contains('emoji')) { if(target.tagName === 'SPAN' && !target.classList.contains('emoji')) {
target = target.firstChild as HTMLElement; target = findUpClassName(target, 'category-item').firstChild as HTMLElement;
} else if(target.tagName === 'DIV') return; } else if(target.tagName === 'DIV') return;
//console.log('contentEmoji div', target); //console.log('contentEmoji div', target);

View File

@ -8,10 +8,9 @@ import { RichTextProcessor } from "../../../lib/richtextprocessor";
import rootScope from "../../../lib/rootScope"; import rootScope from "../../../lib/rootScope";
import AppSearchSuper, { SearchSuperType } from "../../appSearchSuper."; import AppSearchSuper, { SearchSuperType } from "../../appSearchSuper.";
import AvatarElement from "../../avatar"; import AvatarElement from "../../avatar";
import Scrollable from "../../scrollable"; import SidebarSlider, { SliderSuperTab } from "../../slider";
import SidebarSlider, { SliderSuperTab, SliderTab } from "../../slider";
import CheckboxField from "../../checkboxField"; import CheckboxField from "../../checkboxField";
import { attachClickEvent } from "../../../helpers/dom"; import { attachClickEvent, replaceContent } from "../../../helpers/dom";
import appSidebarRight from ".."; import appSidebarRight from "..";
import { TransitionSlider } from "../../transition"; import { TransitionSlider } from "../../transition";
import appNotificationsManager from "../../../lib/appManagers/appNotificationsManager"; import appNotificationsManager from "../../../lib/appManagers/appNotificationsManager";
@ -20,7 +19,7 @@ import PeerTitle from "../../peerTitle";
import AppEditChannelTab from "./editChannel"; import AppEditChannelTab from "./editChannel";
import AppEditContactTab from "./editContact"; import AppEditContactTab from "./editContact";
import appChatsManager, { Channel } from "../../../lib/appManagers/appChatsManager"; import appChatsManager, { Channel } from "../../../lib/appManagers/appChatsManager";
import { Chat } from "../../../layer"; import { Chat, UserProfilePhoto } from "../../../layer";
import Button from "../../button"; import Button from "../../button";
import ButtonIcon from "../../buttonIcon"; import ButtonIcon from "../../buttonIcon";
import I18n, { i18n } from "../../../lib/langPack"; import I18n, { i18n } from "../../../lib/langPack";
@ -28,14 +27,471 @@ import { SettingSection } from "../../sidebarLeft";
import Row from "../../row"; import Row from "../../row";
import { copyTextToClipboard } from "../../../helpers/clipboard"; import { copyTextToClipboard } from "../../../helpers/clipboard";
import { toast } from "../../toast"; import { toast } from "../../toast";
import { fastRaf } from "../../../helpers/schedulers";
import { safeAssign } from "../../../helpers/object";
import { forEachReverse } from "../../../helpers/array";
import appPhotosManager from "../../../lib/appManagers/appPhotosManager";
import renderImageFromUrl from "../../../helpers/dom/renderImageFromUrl";
let setText = (text: string, row: Row) => { let setText = (text: string, row: Row) => {
window.requestAnimationFrame(() => { fastRaf(() => {
row.title.innerHTML = text; row.title.innerHTML = text;
row.container.style.display = ''; row.container.style.display = '';
}); });
}; };
type ListLoaderResult<T> = {count: number, items: any[]};
class ListLoader<T> {
public current: T;
public previous: T[] = [];
public next: T[] = [];
public tempId = 0;
public loadMore: (anchor: T, older: boolean) => Promise<ListLoaderResult<T>>;
public processItem: (item: any) => false | T;
public loadCount = 50;
public reverse = false; // reverse means next = higher msgid
public loadedAllUp = false;
public loadedAllDown = false;
public loadPromiseUp: Promise<void>;
public loadPromiseDown: Promise<void>;
constructor(options: {
loadMore: ListLoader<T>['loadMore'],
loadCount: ListLoader<T>['loadCount'],
processItem?: ListLoader<T>['processItem'],
}) {
safeAssign(this, options);
}
public go(length: number) {
let items: T[], item: T;
if(length > 0) {
items = this.next.splice(0, length);
item = items.pop();
this.previous.push(...items);
} else {
items = this.previous.splice(this.previous.length - length, length);
item = items.shift();
this.next.unshift(...items);
}
}
public load(older: boolean) {
if(older && this.loadedAllDown) return Promise.resolve();
else if(!older && this.loadedAllUp) return Promise.resolve();
if(older && this.loadPromiseDown) return this.loadPromiseDown;
else if(!older && this.loadPromiseUp) return this.loadPromiseUp;
/* const loadCount = 50;
const backLimit = older ? 0 : loadCount; */
let anchor: T;
if(older) {
anchor = this.reverse ? this.previous[0] : this.next[this.next.length - 1];
} else {
anchor = this.reverse ? this.next[this.next.length - 1] : this.previous[0];
}
const promise = this.loadMore(anchor, older).then(result => {
if(result.items.length < this.loadCount) {
if(older) this.loadedAllDown = true;
else this.loadedAllUp = true;
}
const method = older ? result.items.forEach.bind(result.items) : forEachReverse.bind(null, result.items);
method((item: any) => {
const processed = this.processItem ? this.processItem(item) : item;
if(!processed) return;
if(older) {
if(this.reverse) this.previous.unshift(processed);
else this.next.push(processed);
} else {
if(this.reverse) this.next.push(processed);
else this.previous.unshift(processed);
}
});
}, () => {}).then(() => {
if(older) this.loadPromiseDown = null;
else this.loadPromiseUp = null;
});
if(older) this.loadPromiseDown = promise;
else this.loadPromiseUp = promise;
return promise;
}
}
class PeerProfileAvatars {
public static BASE_CLASS = 'profile-avatars';
public container: HTMLElement;
public avatars: HTMLElement;
public info: HTMLElement;
public listLoader: ListLoader<string>;
public peerId: number;
constructor() {
this.container = document.createElement('div');
this.container.classList.add(PeerProfileAvatars.BASE_CLASS + '-container');
this.avatars = document.createElement('div');
this.avatars.classList.add(PeerProfileAvatars.BASE_CLASS + '-avatars');
this.info = document.createElement('div');
this.info.classList.add(PeerProfileAvatars.BASE_CLASS + '-info');
this.container.append(this.avatars, this.info);
attachClickEvent(this.container, (_e) => {
const rect = this.container.getBoundingClientRect();
const e = (_e as TouchEvent).touches ? (_e as TouchEvent).touches[0] : _e as MouseEvent;
const x = e.pageX;
const centerX = rect.right - (rect.width / 2);
const toRight = x > centerX;
const id = this.listLoader.previous.length;
const nextId = Math.max(0, id + (toRight ? 1 : -1));
this.avatars.style.transform = `translateX(-${100 * nextId}%)`;
});
}
public setPeer(peerId: number) {
this.peerId = peerId;
const photo = appPeersManager.getPeerPhoto(peerId);
if(!photo) {
return;
}
const loadCount = 50;
const listLoader: PeerProfileAvatars['listLoader'] = this.listLoader = new ListLoader<string>({
loadCount,
loadMore: (anchor, older) => {
return appPhotosManager.getUserPhotos(peerId, anchor || listLoader.current, loadCount).then(result => {
return {
count: result.count,
items: result.photos
};
});
},
processItem: this.processItem
});
listLoader.current = (photo as UserProfilePhoto.userProfilePhoto).photo_id;
this.processItem(listLoader.current);
listLoader.load(true);
}
public processItem = (photoId: string) => {
const avatar = document.createElement('div');
avatar.classList.add(PeerProfileAvatars.BASE_CLASS + '-avatar');
const photo = appPhotosManager.getPhoto(photoId);
if(photo) {
appPhotosManager.preloadPhoto(photo, appPhotosManager.choosePhotoSize(photo, 420, 420, false)).then(() => {
const img = new Image();
renderImageFromUrl(img, photo.url, () => {
avatar.append(img);
});
});
} else {
const photo = appPeersManager.getPeerPhoto(this.peerId);
appProfileManager.putAvatar(avatar, this.peerId, photo, 'photo_big');
}
this.avatars.append(avatar);
return photoId;
};
}
class PeerProfile {
public element: HTMLElement;
private avatars: PeerProfileAvatars;
private avatar: AvatarElement;
private section: SettingSection;
private name: HTMLDivElement;
private subtitle: HTMLDivElement;
private bio: Row;
private username: Row;
private phone: Row;
private notifications: Row;
private cleaned: boolean;
private setBioTimeout: number;
private setPeerStatusInterval: number;
private peerId = 0;
private threadId: number;
public init() {
this.init = null;
this.element = document.createElement('div');
this.element.classList.add('profile-content');
this.section = new SettingSection({
noDelimiter: true
});
this.avatars = new PeerProfileAvatars();
this.avatar = new AvatarElement();
this.avatar.classList.add('profile-avatar', 'avatar-120');
this.avatar.setAttribute('dialog', '1');
this.avatar.setAttribute('clickable', '');
this.name = document.createElement('div');
this.name.classList.add('profile-name');
this.subtitle = document.createElement('div');
this.subtitle.classList.add('profile-subtitle');
this.bio = new Row({
title: ' ',
subtitleLangKey: 'UserBio',
icon: 'info',
clickable: (e) => {
if((e.target as HTMLElement).tagName === 'A') {
return;
}
appProfileManager.getProfileByPeerId(this.peerId).then(full => {
copyTextToClipboard(full.about);
toast(I18n.format('BioCopied', true));
});
}
});
this.bio.title.classList.add('pre-wrap');
this.username = new Row({
title: ' ',
subtitleLangKey: 'Username',
icon: 'username',
clickable: () => {
const peer: Channel | User = appPeersManager.getPeer(this.peerId);
copyTextToClipboard('@' + peer.username);
toast(I18n.format('UsernameCopied', true));
}
});
this.phone = new Row({
title: ' ',
subtitleLangKey: 'Phone',
icon: 'phone',
clickable: () => {
const peer: User = appUsersManager.getUser(this.peerId);
copyTextToClipboard('+' + peer.phone);
toast(I18n.format('PhoneCopied', true));
}
});
this.notifications = new Row({
checkboxField: new CheckboxField({text: 'Notifications'})
});
this.section.content.append(/* this.name, this.subtitle, */
this.phone.container, this.username.container, this.bio.container, this.notifications.container);
this.element.append(this.avatars.container, this.section.container);
this.notifications.checkboxField.input.addEventListener('change', (e) => {
if(!e.isTrusted) {
return;
}
//let checked = this.notificationsCheckbox.checked;
appMessagesManager.mutePeer(this.peerId);
});
rootScope.on('dialog_notify_settings', (dialog) => {
if(this.peerId === dialog.peerId) {
const muted = appNotificationsManager.isPeerLocalMuted(this.peerId, false);
this.notifications.checkboxField.checked = !muted;
}
});
rootScope.on('peer_typings', (e) => {
const {peerId} = e;
if(this.peerId === peerId) {
this.setPeerStatus();
}
});
rootScope.on('peer_bio_edit', (peerId) => {
if(peerId === this.peerId) {
this.setBio(true);
}
});
rootScope.on('user_update', (e) => {
const userId = e;
if(this.peerId === userId) {
this.setPeerStatus();
}
});
this.setPeerStatusInterval = window.setInterval(this.setPeerStatus, 60e3);
}
public setPeerStatus = (needClear = false) => {
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 || '');
});
};
public cleanupHTML() {
this.bio.container.style.display = 'none';
this.phone.container.style.display = 'none';
this.username.container.style.display = 'none';
this.notifications.container.style.display = '';
this.notifications.checkboxField.checked = true;
if(this.setBioTimeout) {
window.clearTimeout(this.setBioTimeout);
this.setBioTimeout = 0;
}
}
public fillProfileElements() {
if(!this.cleaned) return;
this.cleaned = false;
const peerId = this.peerId;
this.cleanupHTML();
this.avatar.setAttribute('peer', '' + peerId);
this.avatars.setPeer(peerId);
this.avatars.info.append(this.name, this.subtitle);
// username
if(peerId !== rootScope.myId) {
let username = appPeersManager.getPeerUsername(peerId);
if(username) {
setText(appPeersManager.getPeerUsername(peerId), this.username);
}
const muted = appNotificationsManager.isPeerLocalMuted(peerId, false);
this.notifications.checkboxField.checked = !muted;
} else {
window.requestAnimationFrame(() => {
this.notifications.container.style.display = 'none';
});
}
//let membersLi = this.profileTabs.firstElementChild.children[0] as HTMLLIElement;
if(peerId > 0) {
//membersLi.style.display = 'none';
let user = appUsersManager.getUser(peerId);
if(user.phone && peerId !== rootScope.myId) {
setText(user.rPhone, this.phone);
}
}/* else {
//membersLi.style.display = appPeersManager.isBroadcast(peerId) ? 'none' : '';
} */
this.setBio();
replaceContent(this.name, new PeerTitle({
peerId,
dialog: true
}).element);
this.setPeerStatus(true);
}
public setBio(override?: true) {
if(this.setBioTimeout) {
window.clearTimeout(this.setBioTimeout);
this.setBioTimeout = 0;
}
const peerId = this.peerId;
const threadId = this.threadId;
if(!peerId) {
return;
}
let promise: Promise<boolean>;
if(peerId > 0) {
promise = appProfileManager.getProfile(peerId, override).then(userFull => {
if(this.peerId !== peerId || this.threadId !== threadId) {
//this.log.warn('peer changed');
return false;
}
if(userFull.rAbout && peerId !== rootScope.myId) {
setText(userFull.rAbout, this.bio);
}
//this.log('userFull', userFull);
return true;
});
} else {
promise = appProfileManager.getChatFull(-peerId, override).then((chatFull) => {
if(this.peerId !== peerId || this.threadId !== threadId) {
//this.log.warn('peer changed');
return false;
}
//this.log('chatInfo res 2:', chatFull);
if(chatFull.about) {
setText(RichTextProcessor.wrapRichText(chatFull.about), this.bio);
}
return true;
});
}
promise.then((canSetNext) => {
if(canSetNext) {
this.setBioTimeout = window.setTimeout(() => this.setBio(true), 60e3);
}
});
}
public setPeer(peerId: number, threadId = 0) {
if(this.peerId === peerId && this.threadId === peerId) return;
if(this.init) {
this.init();
}
this.peerId = peerId;
this.threadId = threadId;
this.cleaned = true;
}
}
// TODO: отредактированное сообщение не изменится // TODO: отредактированное сообщение не изменится
export default class AppSharedMediaTab extends SliderSuperTab { export default class AppSharedMediaTab extends SliderSuperTab {
public editBtn: HTMLElement; public editBtn: HTMLElement;
@ -43,17 +499,6 @@ export default class AppSharedMediaTab extends SliderSuperTab {
private peerId = 0; private peerId = 0;
private threadId = 0; private threadId = 0;
public profileContentEl: HTMLDivElement;
public profileElements: {
avatar: AvatarElement,
name: HTMLDivElement,
subtitle: HTMLDivElement,
bio: Row,
username: Row,
phone: Row,
notifications: Row
} = {} as any;
public historiesStorage: { public historiesStorage: {
[peerId: number]: Partial<{ [peerId: number]: Partial<{
[type in SearchSuperType]: {mid: number, peerId: number}[] [type in SearchSuperType]: {mid: number, peerId: number}[]
@ -61,11 +506,10 @@ export default class AppSharedMediaTab extends SliderSuperTab {
} = {}; } = {};
private log = logger('SM'/* , LogLevels.error */); private log = logger('SM'/* , LogLevels.error */);
setPeerStatusInterval: number; private cleaned: boolean;
cleaned: boolean; private searchSuper: AppSearchSuper;
searchSuper: AppSearchSuper;
private setBioTimeout: number; public profile: PeerProfile;
constructor(slider: SidebarSlider) { constructor(slider: SidebarSlider) {
super(slider, false); super(slider, false);
@ -90,7 +534,7 @@ export default class AppSharedMediaTab extends SliderSuperTab {
const transitionFirstItem = document.createElement('div'); const transitionFirstItem = document.createElement('div');
transitionFirstItem.classList.add('transition-item'); transitionFirstItem.classList.add('transition-item');
this.title.append(i18n('Telegram.PeerInfoController')); this.title.append(i18n('Profile'));
this.editBtn = ButtonIcon('edit'); this.editBtn = ButtonIcon('edit');
//const moreBtn = ButtonIcon('more'); //const moreBtn = ButtonIcon('more');
@ -109,73 +553,11 @@ export default class AppSharedMediaTab extends SliderSuperTab {
this.header.append(transitionContainer); this.header.append(transitionContainer);
// * body // * body
this.profile = new PeerProfile();
this.profile.init();
this.profileContentEl = document.createElement('div'); this.scrollable.append(this.profile.element);
this.profileContentEl.classList.add('profile-content');
const section = new SettingSection({
noDelimiter: true
});
this.profileElements.avatar = new AvatarElement();
this.profileElements.avatar.classList.add('profile-avatar', 'avatar-120');
this.profileElements.avatar.setAttribute('dialog', '1');
this.profileElements.avatar.setAttribute('clickable', '');
this.profileElements.name = document.createElement('div');
this.profileElements.name.classList.add('profile-name');
this.profileElements.subtitle = document.createElement('div');
this.profileElements.subtitle.classList.add('profile-subtitle');
this.profileElements.bio = new Row({
title: ' ',
subtitleLangKey: 'UserBio',
icon: 'info',
clickable: (e) => {
if((e.target as HTMLElement).tagName === 'A') {
return;
}
appProfileManager.getProfileByPeerId(this.peerId).then(full => {
copyTextToClipboard(full.about);
toast(I18n.format('BioCopied', true));
});
}
});
this.profileElements.bio.title.classList.add('pre-wrap');
this.profileElements.username = new Row({
title: ' ',
subtitleLangKey: 'Username',
icon: 'username',
clickable: () => {
const peer: Channel | User = appPeersManager.getPeer(this.peerId);
copyTextToClipboard('@' + peer.username);
toast(I18n.format('UsernameCopied', true));
}
});
this.profileElements.phone = new Row({
title: ' ',
subtitleLangKey: 'Phone',
icon: 'phone',
clickable: () => {
const peer: User = appUsersManager.getUser(this.peerId);
copyTextToClipboard('+' + peer.phone);
toast(I18n.format('PhoneCopied', true));
}
});
this.profileElements.notifications = new Row({
checkboxField: new CheckboxField({text: 'Notifications'})
});
section.content.append(this.profileElements.avatar, this.profileElements.name, this.profileElements.subtitle,
this.profileElements.bio.container, this.profileElements.username.container, this.profileElements.phone.container, this.profileElements.notifications.container);
this.profileContentEl.append(section.container);
this.scrollable.append(this.profileContentEl);
const HEADER_HEIGHT = 56; const HEADER_HEIGHT = 56;
this.scrollable.onAdditionalScroll = () => { this.scrollable.onAdditionalScroll = () => {
@ -229,46 +611,6 @@ export default class AppSharedMediaTab extends SliderSuperTab {
//this.container.prepend(this.closeBtn.parentElement); //this.container.prepend(this.closeBtn.parentElement);
this.profileElements.notifications.checkboxField.input.addEventListener('change', (e) => {
if(!e.isTrusted) {
return;
}
//let checked = this.profileElements.notificationsCheckbox.checked;
appMessagesManager.mutePeer(this.peerId);
});
rootScope.on('dialog_notify_settings', (dialog) => {
if(this.peerId === dialog.peerId) {
const muted = appNotificationsManager.isPeerLocalMuted(this.peerId, false);
this.profileElements.notifications.checkboxField.checked = !muted;
}
});
rootScope.on('peer_typings', (e) => {
const {peerId} = e;
if(this.peerId === peerId) {
this.setPeerStatus();
}
});
rootScope.on('peer_bio_edit', (peerId) => {
if(peerId === this.peerId) {
this.setBio(true);
}
});
rootScope.on('user_update', (e) => {
const userId = e;
if(this.peerId === userId) {
this.setPeerStatus();
}
});
this.setPeerStatusInterval = window.setInterval(this.setPeerStatus, 60e3);
this.searchSuper = new AppSearchSuper([{ this.searchSuper = new AppSearchSuper([{
inputFilter: 'inputMessagesFilterPhotoVideo', inputFilter: 'inputMessagesFilterPhotoVideo',
name: 'SharedMediaTab2', name: 'SharedMediaTab2',
@ -287,27 +629,9 @@ export default class AppSharedMediaTab extends SliderSuperTab {
type: 'music' type: 'music'
}], this.scrollable/* , undefined, undefined, false */); }], this.scrollable/* , undefined, undefined, false */);
this.profileContentEl.append(this.searchSuper.container); this.profile.element.append(this.searchSuper.container);
} }
public setPeerStatus = (needClear = false) => {
if(!this.peerId) return;
const peerId = this.peerId;
if(needClear) {
this.profileElements.subtitle.innerHTML = ''; // ! HERE U CAN FIND WHITESPACE
}
appImManager.getPeerStatus(this.peerId).then((subtitle) => {
if(peerId !== this.peerId) {
return;
}
this.profileElements.subtitle.textContent = '';
this.profileElements.subtitle.append(subtitle || '');
});
};
public renderNewMessages(peerId: number, mids: number[]) { public renderNewMessages(peerId: number, mids: number[]) {
if(this.init) return; // * not inited yet if(this.init) return; // * not inited yet
@ -369,17 +693,9 @@ export default class AppSharedMediaTab extends SliderSuperTab {
} }
public cleanupHTML() { public cleanupHTML() {
this.profileElements.bio.container.style.display = 'none'; this.profile.cleanupHTML();
this.profileElements.phone.container.style.display = 'none';
this.profileElements.username.container.style.display = 'none';
this.profileElements.notifications.container.style.display = '';
this.profileElements.notifications.checkboxField.checked = true;
this.editBtn.style.display = 'none'; this.editBtn.style.display = 'none';
if(this.setBioTimeout) {
window.clearTimeout(this.setBioTimeout);
this.setBioTimeout = 0;
}
this.searchSuper.cleanupHTML(); this.searchSuper.cleanupHTML();
this.searchSuper.selectTab(0, false); this.searchSuper.selectTab(0, false);
} }
@ -403,124 +719,30 @@ export default class AppSharedMediaTab extends SliderSuperTab {
//threadId, //threadId,
historyStorage: this.historiesStorage[peerId] ?? (this.historiesStorage[peerId] = {}) historyStorage: this.historiesStorage[peerId] ?? (this.historiesStorage[peerId] = {})
}); });
this.profile.setPeer(peerId, threadId);
this.cleaned = true; this.cleaned = true;
} }
public fillProfileElements() {
this.profile.fillProfileElements();
if(this.peerId > 0) {
if(this.peerId !== rootScope.myId && appUsersManager.isContact(this.peerId)) {
this.editBtn.style.display = '';
}
} else {
const chat: Chat = appChatsManager.getChat(-this.peerId);
if(chat._ === 'chat' || (chat as Chat.channel).admin_rights) {
this.editBtn.style.display = '';
}
}
}
public loadSidebarMedia(single: boolean) { public loadSidebarMedia(single: boolean) {
this.searchSuper.load(single); this.searchSuper.load(single);
} }
public fillProfileElements() {
if(!this.cleaned) return;
this.cleaned = false;
const peerId = this.peerId;
this.cleanupHTML();
this.profileElements.avatar.setAttribute('peer', '' + peerId);
// username
if(peerId !== rootScope.myId) {
let username = appPeersManager.getPeerUsername(peerId);
if(username) {
setText(appPeersManager.getPeerUsername(peerId), this.profileElements.username);
}
const muted = appNotificationsManager.isPeerLocalMuted(peerId, false);
this.profileElements.notifications.checkboxField.checked = !muted;
} else {
window.requestAnimationFrame(() => {
this.profileElements.notifications.container.style.display = 'none';
});
}
//let membersLi = this.profileTabs.firstElementChild.children[0] as HTMLLIElement;
if(peerId > 0) {
//membersLi.style.display = 'none';
let user = appUsersManager.getUser(peerId);
if(user.phone && peerId !== rootScope.myId) {
setText(user.rPhone, this.profileElements.phone);
}
}/* else {
//membersLi.style.display = appPeersManager.isBroadcast(peerId) ? 'none' : '';
} */
this.setBio();
this.profileElements.name.innerHTML = '';
this.profileElements.name.append(new PeerTitle({
peerId,
dialog: true
}).element);
if(peerId > 0) {
if(peerId !== rootScope.myId && appUsersManager.isContact(peerId)) {
this.editBtn.style.display = '';
}
} else {
const chat: Chat = appChatsManager.getChat(-peerId);
if(chat._ === 'chat' || (chat as Chat.channel).admin_rights) {
this.editBtn.style.display = '';
}
}
this.setPeerStatus(true);
}
public setBio(override?: true) {
if(this.setBioTimeout) {
window.clearTimeout(this.setBioTimeout);
this.setBioTimeout = 0;
}
const peerId = this.peerId;
const threadId = this.threadId;
if(!peerId) {
return;
}
let promise: Promise<boolean>;
if(peerId > 0) {
promise = appProfileManager.getProfile(peerId, override).then(userFull => {
if(this.peerId !== peerId || this.threadId !== threadId) {
this.log.warn('peer changed');
return false;
}
if(userFull.rAbout && peerId !== rootScope.myId) {
setText(userFull.rAbout, this.profileElements.bio);
}
//this.log('userFull', userFull);
return true;
});
} else {
promise = appProfileManager.getChatFull(-peerId, override).then((chatFull) => {
if(this.peerId !== peerId || this.threadId !== threadId) {
this.log.warn('peer changed');
return false;
}
//this.log('chatInfo res 2:', chatFull);
if(chatFull.about) {
setText(RichTextProcessor.wrapRichText(chatFull.about), this.profileElements.bio);
}
return true;
});
}
promise.then((canSetNext) => {
if(canSetNext) {
this.setBioTimeout = window.setTimeout(() => this.setBio(true), 60e3);
}
});
}
onOpenAfterTimeout() { onOpenAfterTimeout() {
this.scrollable.onScroll(); this.scrollable.onScroll();
} }

View File

@ -89,6 +89,7 @@ const lang = {
"TwoStepAuth.EmailCodeChangeEmail": "Change Email", "TwoStepAuth.EmailCodeChangeEmail": "Change Email",
"MarkupTooltip.LinkPlaceholder": "Enter URL...", "MarkupTooltip.LinkPlaceholder": "Enter URL...",
"MediaViewer.Context.Download": "Download", "MediaViewer.Context.Download": "Download",
"Profile": "Profile",
// * android // * android
"ActionCreateChannel": "Channel created", "ActionCreateChannel": "Channel created",
@ -484,7 +485,6 @@ const lang = {
"Telegram.GeneralSettingsViewController": "General Settings", "Telegram.GeneralSettingsViewController": "General Settings",
"Telegram.InstalledStickerPacksController": "Stickers", "Telegram.InstalledStickerPacksController": "Stickers",
"Telegram.NotificationSettingsViewController": "Notifications", "Telegram.NotificationSettingsViewController": "Notifications",
"Telegram.PeerInfoController": "Info",
"Telegram.LanguageViewController": "Language", "Telegram.LanguageViewController": "Language",
"Stickers.SearchAdd": "Add", "Stickers.SearchAdd": "Add",
"Stickers.SearchAdded": "Added", "Stickers.SearchAdded": "Added",

View File

@ -1,7 +1,7 @@
import { MOUNT_CLASS_TO } from "../../config/debug"; import { MOUNT_CLASS_TO } from "../../config/debug";
import { numberThousandSplitter } from "../../helpers/number"; import { numberThousandSplitter } from "../../helpers/number";
import { isObject, safeReplaceObject, copy, deepEqual } from "../../helpers/object"; import { isObject, safeReplaceObject, copy, deepEqual } from "../../helpers/object";
import { ChannelParticipant, Chat, ChatAdminRights, ChatBannedRights, ChatFull, ChatParticipant, ChatParticipants, InputChannel, InputChatPhoto, InputFile, InputPeer, SendMessageAction, Update, Updates } from "../../layer"; import { ChannelParticipant, Chat, ChatAdminRights, ChatBannedRights, ChatFull, ChatParticipant, ChatParticipants, ChatPhoto, InputChannel, InputChatPhoto, InputFile, InputPeer, SendMessageAction, Update, Updates } from "../../layer";
import { i18n, LangPackKey } from "../langPack"; import { i18n, LangPackKey } from "../langPack";
import apiManagerProxy from "../mtproto/mtprotoworker"; import apiManagerProxy from "../mtproto/mtprotoworker";
import apiManager from '../mtproto/mtprotoworker'; import apiManager from '../mtproto/mtprotoworker';
@ -25,7 +25,7 @@ export class AppChatsManager {
//public usernames: any = {}; //public usernames: any = {};
//public channelAccess: any = {}; //public channelAccess: any = {};
//public megagroups: {[id: number]: true} = {}; //public megagroups: {[id: number]: true} = {};
public cachedPhotoLocations: {[id: number]: any} = {}; public cachedPhotoLocations: {[id: number]: ChatPhoto} = {};
public megagroupOnlines: {[id: number]: {timestamp: number, onlines: number}} = {}; public megagroupOnlines: {[id: number]: {timestamp: number, onlines: number}} = {};
@ -371,10 +371,12 @@ export class AppChatsManager {
} }
public getChatPhoto(id: number) { public getChatPhoto(id: number) {
const chat = this.getChat(id); const chat: Chat.chat = this.getChat(id);
if(this.cachedPhotoLocations[id] === undefined) { if(this.cachedPhotoLocations[id] === undefined) {
this.cachedPhotoLocations[id] = chat && chat.photo ? chat.photo : {empty: true}; this.cachedPhotoLocations[id] = chat && chat.photo || {
_: 'chatPhotoEmpty'
};
} }
return this.cachedPhotoLocations[id]; return this.cachedPhotoLocations[id];

View File

@ -1,6 +1,6 @@
import { MOUNT_CLASS_TO } from "../../config/debug"; import { MOUNT_CLASS_TO } from "../../config/debug";
import { isObject } from "../../helpers/object"; import { isObject } from "../../helpers/object";
import { DialogPeer, InputDialogPeer, InputNotifyPeer, InputPeer, Peer, Update } from "../../layer"; import { ChatPhoto, DialogPeer, InputDialogPeer, InputNotifyPeer, InputPeer, Peer, Update, UserProfilePhoto } from "../../layer";
import { LangPackKey } from "../langPack"; import { LangPackKey } from "../langPack";
import { RichTextProcessor } from "../richtextprocessor"; import { RichTextProcessor } from "../richtextprocessor";
import rootScope from "../rootScope"; import rootScope from "../rootScope";
@ -46,10 +46,12 @@ export class AppPeersManager {
return peerId > 0 || appChatsManager.hasRights(-peerId, 'pin_messages'); return peerId > 0 || appChatsManager.hasRights(-peerId, 'pin_messages');
} }
public getPeerPhoto(peerId: number) { public getPeerPhoto(peerId: number): UserProfilePhoto.userProfilePhoto | ChatPhoto.chatPhoto {
return peerId > 0 const photo = peerId > 0
? appUsersManager.getUserPhoto(peerId) ? appUsersManager.getUserPhoto(peerId)
: appChatsManager.getChatPhoto(-peerId); : appChatsManager.getChatPhoto(-peerId);
return photo._ !== 'chatPhotoEmpty' && photo._ !== 'userProfilePhotoEmpty' ? photo : null;
} }
public getPeerMigratedTo(peerId: number) { public getPeerMigratedTo(peerId: number) {

View File

@ -129,10 +129,9 @@ export class AppPhotosManager {
max_id: maxId max_id: maxId
}).then((photosResult) => { }).then((photosResult) => {
appUsersManager.saveApiUsers(photosResult.users); appUsersManager.saveApiUsers(photosResult.users);
const photoIds: string[] = []; const photoIds: string[] = photosResult.photos.map((photo, idx) => {
photosResult.photos.forEach((photo, idx) => {
photosResult.photos[idx] = this.savePhoto(photo, {type: 'profilePhoto', peerId: userId}); photosResult.photos[idx] = this.savePhoto(photo, {type: 'profilePhoto', peerId: userId});
photoIds.push(photo.id); return photo.id;
}); });
return { return {

View File

@ -2,7 +2,7 @@ import { formatPhoneNumber } from "../../components/misc";
import { MOUNT_CLASS_TO } from "../../config/debug"; import { MOUNT_CLASS_TO } from "../../config/debug";
import { tsNow } from "../../helpers/date"; import { tsNow } from "../../helpers/date";
import { safeReplaceObject, isObject } from "../../helpers/object"; import { safeReplaceObject, isObject } from "../../helpers/object";
import { InputUser, Update, User as MTUser, UserStatus } from "../../layer"; import { InputUser, Update, User as MTUser, UserProfilePhoto, UserStatus } from "../../layer";
import I18n, { i18n, LangPackKey } from "../langPack"; import I18n, { i18n, LangPackKey } from "../langPack";
//import apiManager from '../mtproto/apiManager'; //import apiManager from '../mtproto/apiManager';
import apiManager from '../mtproto/mtprotoworker'; import apiManager from '../mtproto/mtprotoworker';
@ -24,7 +24,7 @@ export class AppUsersManager {
private users: {[userId: number]: User} = {}; private users: {[userId: number]: User} = {};
private usernames: {[username: string]: number} = {}; private usernames: {[username: string]: number} = {};
//public userAccess: {[userId: number]: string} = {}; //public userAccess: {[userId: number]: string} = {};
private cachedPhotoLocations: any = {}; private cachedPhotoLocations: {[userId: number]: UserProfilePhoto} = {};
private contactsIndex = searchIndexManager.createIndex(); private contactsIndex = searchIndexManager.createIndex();
private contactsFillPromise: Promise<Set<number>>; private contactsFillPromise: Promise<Set<number>>;
public contactsList: Set<number> = new Set(); public contactsList: Set<number> = new Set();
@ -501,10 +501,12 @@ export class AppUsersManager {
} }
public getUserPhoto(id: number) { public getUserPhoto(id: number) {
var user = this.getUser(id); const user = this.getUser(id);
if(this.cachedPhotoLocations[id] === undefined) { if(this.cachedPhotoLocations[id] === undefined) {
this.cachedPhotoLocations[id] = user && user.photo ? user.photo : {empty: true}; this.cachedPhotoLocations[id] = user && user.photo || {
_: 'userProfilePhotoEmpty'
};
} }
return this.cachedPhotoLocations[id]; return this.cachedPhotoLocations[id];

View File

@ -1041,7 +1041,7 @@ $chat-helper-size: 39px;
cursor: pointer; cursor: pointer;
//--translateY: 0; //--translateY: 0;
opacity: 1; opacity: 1;
//transition: opacity var(--layer-transition), visibility 0s 0s !important; transition: opacity var(--layer-transition), visibility 0s 0s !important;
visibility: visible; visibility: visible;
/* &.is-broadcast { /* &.is-broadcast {
@ -1164,8 +1164,8 @@ $chat-helper-size: 39px;
overflow: visible; overflow: visible;
//--translateY: calc(var(--chat-input-size) + 10px); //--translateY: calc(var(--chat-input-size) + 10px);
//--translateY: calc(100% + 10px); //--translateY: calc(100% + 10px);
//transition: opacity var(--layer-transition), visibility 0s .2s !important; transition: opacity var(--layer-transition), visibility 0s .2s !important;
transition: opacity var(--layer-transition); //transition: opacity var(--layer-transition);
transform: none !important; transform: none !important;
body.animation-level-0 & { body.animation-level-0 & {

View File

@ -41,7 +41,7 @@
} }
.drop { .drop {
background-color: #fff; background-color: var(--surface-color);
position: relative; position: relative;
//height: 100%; //height: 100%;
border-radius: $border-radius-big; border-radius: $border-radius-big;
@ -130,4 +130,4 @@ body.is-dragging {
.page-chats { .page-chats {
pointer-events: none; pointer-events: none;
} }
} }

View File

@ -19,12 +19,14 @@
box-shadow: 0px 5px 10px 5px rgba(16, 35, 47, .14); box-shadow: 0px 5px 10px 5px rgba(16, 35, 47, .14);
z-index: 3; z-index: 3;
border-radius: 10px; border-radius: 10px;
transition: transform .2s ease-out; transition: transform .2s, opacity .2s;
transition-timing-function: cubic-bezier(.4, 0, .2, 1);
transform: scale(0); transform: scale(0);
opacity: 0;
transform-origin: 0 100%; transform-origin: 0 100%;
&.active { &.active {
transition: transform .2s ease-in; opacity: 1;
transform: scale(1); transform: scale(1);
} }
@ -182,6 +184,32 @@
width: 42px; width: 42px;
height: 42px; height: 42px;
html:not(.emoji-supported) & {
position: relative;
}
.emoji-placeholder {
position: absolute;
left: 7px;
top: 7px;
width: 1.75rem;
height: 1.75rem;
border-radius: 50%;
background-color: var(--light-secondary-text-color);
@include animation-level(2) {
opacity: 0;
transition: opacity .2s ease-in-out;
}
}
@include animation-level(2) {
img {
opacity: 1;
transition: opacity .2s ease-in-out;
}
}
.emoji { .emoji {
width: 100%; width: 100%;

View File

@ -0,0 +1,155 @@
.profile {
&-avatars {
&-container {
width: 100%;
height: 26.25rem;
overflow: hidden;
position: relative;
cursor: pointer;
/* &:before, &:after {
position: absolute;
content: " ";
height: 100%;
width:
} */
}
&-avatars {
width: inherit;
height: inherit;
display: flex;
flex-wrap: nowrap;
}
&-avatar {
width: inherit;
height: inherit;
display: flex;
/* img, video {
width: 100%;
height: 100%;
object-fit: cover;
} */
}
&-info {
position: absolute;
bottom: 0;
display: flex;
flex-direction: column;
align-items: flex-start;
left: 1.5rem;
bottom: .5625rem;
.profile-name, .profile-subtitle {
color: #fff;
margin: 0;
}
.profile-name {
margin-bottom: -1px;
}
.profile-subtitle {
opacity: .7;
}
}
}
&-content {
/* flex: 1 1 auto; */
flex: 0 0 auto;
display: flex;
flex-direction: column;
/* height: 100%; */
position: relative;
width: 100%;
.checkbox-field {
margin: 0;
padding: 0;
margin-left: -54px;
}
.checkbox-caption {
padding-left: 54px;
}
&-wrapper {
flex: 1 1 auto;
display: flex;
flex-direction: column;
padding-bottom: 13px;
@include respond-to(not-handhelds) {
padding-top: 15px;
}
}
.sidebar-left-section {
//padding-top: .5625rem;
padding-bottom: 0;
}
}
&-container {
> .scrollable {
display: flex;
flex-direction: column;
//transform: none;
}
}
&-name {
text-align: center;
font-size: 20px;
line-height: 1.3125;
font-weight: 500;
text-overflow: ellipsis;
overflow: hidden;
word-break: break-word;
max-width: 340px;
margin: 0 auto;
color: var(--primary-text-color);
span.emoji {
vertical-align: inherit;
min-width: min-content;
}
}
&-subtitle {
text-align: center;
color: var(--secondary-text-color);
font-size: 14px;
margin-bottom: .875rem;
margin-top: 1px;
@include respond-to(handhelds) {
margin-top: 3px;
}
.online {
color: var(--primary-color);
}
}
&-avatar {
margin: .5rem auto 10px;
display: block;
//flex: 0 0 auto;
@include respond-to(handhelds) {
margin: 0 auto 10px;
--size: 100px;
--multiplier: .54;
}
}
&-name, &-subtitle, &-avatar {
flex: 0 0 auto;
}
}

View File

@ -93,105 +93,6 @@
} }
} }
.profile {
&-content {
/* flex: 1 1 auto; */
flex: 0 0 auto;
display: flex;
flex-direction: column;
/* height: 100%; */
position: relative;
width: 100%;
.checkbox-field {
margin: 0;
padding: 0;
margin-left: -54px;
}
.checkbox-caption {
padding-left: 54px;
}
&-wrapper {
flex: 1 1 auto;
display: flex;
flex-direction: column;
padding-bottom: 13px;
@include respond-to(not-handhelds) {
padding-top: 15px;
}
}
.sidebar-left-section {
padding-bottom: 0;
}
}
&-container {
> .scrollable {
display: flex;
flex-direction: column;
//transform: none;
}
.row-title {
word-break: break-word;
}
}
&-name {
text-align: center;
font-size: 20px;
line-height: 1.4;
font-weight: 500;
text-overflow: ellipsis;
overflow: hidden;
word-break: break-word;
max-width: 340px;
margin: 0 auto;
color: var(--primary-text-color);
span.emoji {
vertical-align: inherit;
min-width: min-content;
}
}
&-subtitle {
text-align: center;
color: var(--secondary-text-color);
font-size: 14px;
margin-bottom: .875rem;
margin-top: 1px;
@include respond-to(handhelds) {
margin-top: 3px;
}
.online {
color: var(--primary-color);
}
}
&-avatar {
margin: .5rem auto 10px;
display: block;
//flex: 0 0 auto;
@include respond-to(handhelds) {
margin: 0 auto 10px;
--size: 100px;
--multiplier: .54;
}
}
&-name, &-subtitle, &-avatar {
flex: 0 0 auto;
}
}
#shared-media-container { #shared-media-container {
/* .search-super { /* .search-super {
top: 100%; top: 100%;

View File

@ -201,6 +201,7 @@ html.night {
@import "partials/chatDrop"; @import "partials/chatDrop";
@import "partials/crop"; @import "partials/crop";
@import "partials/sidebar"; @import "partials/sidebar";
@import "partials/profile";
@import "partials/leftSidebar"; @import "partials/leftSidebar";
@import "partials/rightSidebar"; @import "partials/rightSidebar";
@import "partials/mediaViewer"; @import "partials/mediaViewer";
@ -998,9 +999,9 @@ middle-ellipsis-element {
} }
.row { .row {
min-height: 3.5rem; min-height: 3rem;
position: relative; position: relative;
padding: .9375rem 1rem; padding: .6875rem 1rem;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
@ -1027,7 +1028,7 @@ middle-ellipsis-element {
color: var(--primary-text-color); color: var(--primary-text-color);
line-height: var(--line-height); line-height: var(--line-height);
@include text-overflow(); @include text-overflow(false);
&-right { &-right {
flex: 0 0 auto !important; flex: 0 0 auto !important;
@ -1046,6 +1047,7 @@ middle-ellipsis-element {
position: absolute; position: absolute;
left: 1rem; left: 1rem;
font-size: 1.5rem; font-size: 1.5rem;
margin-top: .25rem;
color: var(--secondary-text-color); color: var(--secondary-text-color);
pointer-events: none; pointer-events: none;
} }