Browse Source

temp profile commit

improved ESG animation
master
Eduard Kuzmenko 3 years ago
parent
commit
2a5467e074
  1. 29
      src/components/emoticonsDropdown/tabs/emoji.ts
  2. 724
      src/components/sidebarRight/tabs/sharedMedia.ts
  3. 2
      src/lang.ts
  4. 10
      src/lib/appManagers/appChatsManager.ts
  5. 8
      src/lib/appManagers/appPeersManager.ts
  6. 5
      src/lib/appManagers/appPhotosManager.ts
  7. 10
      src/lib/appManagers/appUsersManager.ts
  8. 6
      src/scss/partials/_chat.scss
  9. 4
      src/scss/partials/_chatDrop.scss
  10. 32
      src/scss/partials/_emojiDropdown.scss
  11. 155
      src/scss/partials/_profile.scss
  12. 99
      src/scss/partials/_rightSidebar.scss
  13. 8
      src/scss/style.scss

29
src/components/emoticonsDropdown/tabs/emoji.ts

@ -1,8 +1,11 @@ @@ -1,8 +1,11 @@
import { EmoticonsDropdown, EmoticonsTab } from "..";
import findUpClassName from "../../../helpers/dom/findUpClassName";
import { fastRaf } from "../../../helpers/schedulers";
import appImManager from "../../../lib/appManagers/appImManager";
import appStateManager from "../../../lib/appManagers/appStateManager";
import Config from "../../../lib/config";
import { RichTextProcessor } from "../../../lib/richtextprocessor";
import rootScope from "../../../lib/rootScope";
import { putPreloader } from "../../misc";
import Scrollable from "../../scrollable";
import StickyIntersector from "../../stickyIntersector";
@ -162,7 +165,29 @@ export default class EmojiTab implements EmoticonsTab { @@ -162,7 +165,29 @@ export default class EmojiTab implements EmoticonsTab {
}
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;
@ -185,7 +210,7 @@ export default class EmojiTab implements EmoticonsTab { @@ -185,7 +210,7 @@ export default class EmojiTab implements EmoticonsTab {
//if(target.tagName !== 'SPAN') return;
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;
//console.log('contentEmoji div', target);

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

@ -8,10 +8,9 @@ import { RichTextProcessor } from "../../../lib/richtextprocessor"; @@ -8,10 +8,9 @@ import { RichTextProcessor } from "../../../lib/richtextprocessor";
import rootScope from "../../../lib/rootScope";
import AppSearchSuper, { SearchSuperType } from "../../appSearchSuper.";
import AvatarElement from "../../avatar";
import Scrollable from "../../scrollable";
import SidebarSlider, { SliderSuperTab, SliderTab } from "../../slider";
import SidebarSlider, { SliderSuperTab } from "../../slider";
import CheckboxField from "../../checkboxField";
import { attachClickEvent } from "../../../helpers/dom";
import { attachClickEvent, replaceContent } from "../../../helpers/dom";
import appSidebarRight from "..";
import { TransitionSlider } from "../../transition";
import appNotificationsManager from "../../../lib/appManagers/appNotificationsManager";
@ -20,7 +19,7 @@ import PeerTitle from "../../peerTitle"; @@ -20,7 +19,7 @@ import PeerTitle from "../../peerTitle";
import AppEditChannelTab from "./editChannel";
import AppEditContactTab from "./editContact";
import appChatsManager, { Channel } from "../../../lib/appManagers/appChatsManager";
import { Chat } from "../../../layer";
import { Chat, UserProfilePhoto } from "../../../layer";
import Button from "../../button";
import ButtonIcon from "../../buttonIcon";
import I18n, { i18n } from "../../../lib/langPack";
@ -28,107 +27,237 @@ import { SettingSection } from "../../sidebarLeft"; @@ -28,107 +27,237 @@ import { SettingSection } from "../../sidebarLeft";
import Row from "../../row";
import { copyTextToClipboard } from "../../../helpers/clipboard";
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) => {
window.requestAnimationFrame(() => {
fastRaf(() => {
row.title.innerHTML = text;
row.container.style.display = '';
});
};
// TODO: отредактированное сообщение не изменится
export default class AppSharedMediaTab extends SliderSuperTab {
public editBtn: HTMLElement;
type ListLoaderResult<T> = {count: number, items: any[]};
class ListLoader<T> {
public current: T;
public previous: T[] = [];
public next: T[] = [];
private peerId = 0;
private threadId = 0;
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 profileContentEl: HTMLDivElement;
public profileElements: {
avatar: AvatarElement,
name: HTMLDivElement,
subtitle: HTMLDivElement,
bio: Row,
username: Row,
phone: Row,
notifications: Row
} = {} as any;
public loadedAllUp = false;
public loadedAllDown = false;
public loadPromiseUp: Promise<void>;
public loadPromiseDown: Promise<void>;
public historiesStorage: {
[peerId: number]: Partial<{
[type in SearchSuperType]: {mid: number, peerId: number}[]
}>
} = {};
constructor(options: {
loadMore: ListLoader<T>['loadMore'],
loadCount: ListLoader<T>['loadCount'],
processItem?: ListLoader<T>['processItem'],
}) {
safeAssign(this, options);
private log = logger('SM'/* , LogLevels.error */);
setPeerStatusInterval: number;
cleaned: boolean;
searchSuper: AppSearchSuper;
private setBioTimeout: number;
}
constructor(slider: SidebarSlider) {
super(slider, false);
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);
}
}
protected init() {
this.container.id = 'shared-media-container';
this.container.classList.add('profile-container');
public load(older: boolean) {
if(older && this.loadedAllDown) return Promise.resolve();
else if(!older && this.loadedAllUp) return Promise.resolve();
// * header
const newCloseBtn = Button('btn-icon sidebar-close-button', {noRipple: true});
this.closeBtn.replaceWith(newCloseBtn);
this.closeBtn = newCloseBtn;
if(older && this.loadPromiseDown) return this.loadPromiseDown;
else if(!older && this.loadPromiseUp) return this.loadPromiseUp;
const animatedCloseIcon = document.createElement('div');
animatedCloseIcon.classList.add('animated-close-icon');
newCloseBtn.append(animatedCloseIcon);
/* 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 transitionContainer = document.createElement('div');
transitionContainer.className = 'transition slide-fade';
const transitionFirstItem = document.createElement('div');
transitionFirstItem.classList.add('transition-item');
const promise = this.loadMore(anchor, older).then(result => {
if(result.items.length < this.loadCount) {
if(older) this.loadedAllDown = true;
else this.loadedAllUp = true;
}
this.title.append(i18n('Telegram.PeerInfoController'));
this.editBtn = ButtonIcon('edit');
//const moreBtn = ButtonIcon('more');
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;
transitionFirstItem.append(this.title, this.editBtn/* , moreBtn */);
if(!processed) return;
const transitionLastItem = document.createElement('div');
transitionLastItem.classList.add('transition-item');
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;
});
const secondTitle: HTMLElement = this.title.cloneNode() as any;
secondTitle.append(i18n('PeerInfo.SharedMedia'));
if(older) this.loadPromiseDown = promise;
else this.loadPromiseUp = promise;
transitionLastItem.append(secondTitle);
return promise;
}
}
transitionContainer.append(transitionFirstItem, transitionLastItem);
class PeerProfileAvatars {
public static BASE_CLASS = 'profile-avatars';
public container: HTMLElement;
public avatars: HTMLElement;
public info: HTMLElement;
public listLoader: ListLoader<string>;
public peerId: number;
this.header.append(transitionContainer);
constructor() {
this.container = document.createElement('div');
this.container.classList.add(PeerProfileAvatars.BASE_CLASS + '-container');
// * body
this.profileContentEl = document.createElement('div');
this.profileContentEl.classList.add('profile-content');
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 section = new SettingSection({
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.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.avatars = new PeerProfileAvatars();
this.profileElements.name = document.createElement('div');
this.profileElements.name.classList.add('profile-name');
this.avatar = new AvatarElement();
this.avatar.classList.add('profile-avatar', 'avatar-120');
this.avatar.setAttribute('dialog', '1');
this.avatar.setAttribute('clickable', '');
this.profileElements.subtitle = document.createElement('div');
this.profileElements.subtitle.classList.add('profile-subtitle');
this.name = document.createElement('div');
this.name.classList.add('profile-name');
this.profileElements.bio = new Row({
this.subtitle = document.createElement('div');
this.subtitle.classList.add('profile-subtitle');
this.bio = new Row({
title: ' ',
subtitleLangKey: 'UserBio',
icon: 'info',
@ -144,9 +273,9 @@ export default class AppSharedMediaTab extends SliderSuperTab { @@ -144,9 +273,9 @@ export default class AppSharedMediaTab extends SliderSuperTab {
}
});
this.profileElements.bio.title.classList.add('pre-wrap');
this.bio.title.classList.add('pre-wrap');
this.profileElements.username = new Row({
this.username = new Row({
title: ' ',
subtitleLangKey: 'Username',
icon: 'username',
@ -157,7 +286,7 @@ export default class AppSharedMediaTab extends SliderSuperTab { @@ -157,7 +286,7 @@ export default class AppSharedMediaTab extends SliderSuperTab {
}
});
this.profileElements.phone = new Row({
this.phone = new Row({
title: ' ',
subtitleLangKey: 'Phone',
icon: 'phone',
@ -168,14 +297,267 @@ export default class AppSharedMediaTab extends SliderSuperTab { @@ -168,14 +297,267 @@ export default class AppSharedMediaTab extends SliderSuperTab {
}
});
this.profileElements.notifications = new Row({
this.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);
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: отредактированное сообщение не изменится
export default class AppSharedMediaTab extends SliderSuperTab {
public editBtn: HTMLElement;
private peerId = 0;
private threadId = 0;
public historiesStorage: {
[peerId: number]: Partial<{
[type in SearchSuperType]: {mid: number, peerId: number}[]
}>
} = {};
private log = logger('SM'/* , LogLevels.error */);
private cleaned: boolean;
private searchSuper: AppSearchSuper;
public profile: PeerProfile;
constructor(slider: SidebarSlider) {
super(slider, false);
}
protected init() {
this.container.id = 'shared-media-container';
this.container.classList.add('profile-container');
// * header
const newCloseBtn = Button('btn-icon sidebar-close-button', {noRipple: true});
this.closeBtn.replaceWith(newCloseBtn);
this.closeBtn = newCloseBtn;
const animatedCloseIcon = document.createElement('div');
animatedCloseIcon.classList.add('animated-close-icon');
newCloseBtn.append(animatedCloseIcon);
const transitionContainer = document.createElement('div');
transitionContainer.className = 'transition slide-fade';
const transitionFirstItem = document.createElement('div');
transitionFirstItem.classList.add('transition-item');
this.title.append(i18n('Profile'));
this.editBtn = ButtonIcon('edit');
//const moreBtn = ButtonIcon('more');
transitionFirstItem.append(this.title, this.editBtn/* , moreBtn */);
const transitionLastItem = document.createElement('div');
transitionLastItem.classList.add('transition-item');
const secondTitle: HTMLElement = this.title.cloneNode() as any;
secondTitle.append(i18n('PeerInfo.SharedMedia'));
transitionLastItem.append(secondTitle);
transitionContainer.append(transitionFirstItem, transitionLastItem);
this.header.append(transitionContainer);
// * body
this.profile = new PeerProfile();
this.profile.init();
this.scrollable.append(this.profile.element);
const HEADER_HEIGHT = 56;
this.scrollable.onAdditionalScroll = () => {
@ -229,46 +611,6 @@ export default class AppSharedMediaTab extends SliderSuperTab { @@ -229,46 +611,6 @@ export default class AppSharedMediaTab extends SliderSuperTab {
//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([{
inputFilter: 'inputMessagesFilterPhotoVideo',
name: 'SharedMediaTab2',
@ -287,27 +629,9 @@ export default class AppSharedMediaTab extends SliderSuperTab { @@ -287,27 +629,9 @@ export default class AppSharedMediaTab extends SliderSuperTab {
type: 'music'
}], 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[]) {
if(this.init) return; // * not inited yet
@ -369,17 +693,9 @@ export default class AppSharedMediaTab extends SliderSuperTab { @@ -369,17 +693,9 @@ export default class AppSharedMediaTab extends SliderSuperTab {
}
public cleanupHTML() {
this.profileElements.bio.container.style.display = 'none';
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.profile.cleanupHTML();
this.editBtn.style.display = 'none';
if(this.setBioTimeout) {
window.clearTimeout(this.setBioTimeout);
this.setBioTimeout = 0;
}
this.searchSuper.cleanupHTML();
this.searchSuper.selectTab(0, false);
}
@ -403,122 +719,28 @@ export default class AppSharedMediaTab extends SliderSuperTab { @@ -403,122 +719,28 @@ export default class AppSharedMediaTab extends SliderSuperTab {
//threadId,
historyStorage: this.historiesStorage[peerId] ?? (this.historiesStorage[peerId] = {})
});
this.cleaned = true;
}
public loadSidebarMedia(single: boolean) {
this.searchSuper.load(single);
this.profile.setPeer(peerId, threadId);
this.cleaned = true;
}
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.profile.fillProfileElements();
this.profileElements.name.innerHTML = '';
this.profileElements.name.append(new PeerTitle({
peerId,
dialog: true
}).element);
if(peerId > 0) {
if(peerId !== rootScope.myId && appUsersManager.isContact(peerId)) {
if(this.peerId > 0) {
if(this.peerId !== rootScope.myId && appUsersManager.isContact(this.peerId)) {
this.editBtn.style.display = '';
}
} else {
const chat: Chat = appChatsManager.getChat(-peerId);
const chat: Chat = appChatsManager.getChat(-this.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);
}
});
public loadSidebarMedia(single: boolean) {
this.searchSuper.load(single);
}
onOpenAfterTimeout() {

2
src/lang.ts

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

10
src/lib/appManagers/appChatsManager.ts

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
import { MOUNT_CLASS_TO } from "../../config/debug";
import { numberThousandSplitter } from "../../helpers/number";
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 apiManagerProxy from "../mtproto/mtprotoworker";
import apiManager from '../mtproto/mtprotoworker';
@ -25,7 +25,7 @@ export class AppChatsManager { @@ -25,7 +25,7 @@ export class AppChatsManager {
//public usernames: any = {};
//public channelAccess: any = {};
//public megagroups: {[id: number]: true} = {};
public cachedPhotoLocations: {[id: number]: any} = {};
public cachedPhotoLocations: {[id: number]: ChatPhoto} = {};
public megagroupOnlines: {[id: number]: {timestamp: number, onlines: number}} = {};
@ -371,10 +371,12 @@ export class AppChatsManager { @@ -371,10 +371,12 @@ export class AppChatsManager {
}
public getChatPhoto(id: number) {
const chat = this.getChat(id);
const chat: Chat.chat = this.getChat(id);
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];

8
src/lib/appManagers/appPeersManager.ts

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
import { MOUNT_CLASS_TO } from "../../config/debug";
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 { RichTextProcessor } from "../richtextprocessor";
import rootScope from "../rootScope";
@ -46,10 +46,12 @@ export class AppPeersManager { @@ -46,10 +46,12 @@ export class AppPeersManager {
return peerId > 0 || appChatsManager.hasRights(-peerId, 'pin_messages');
}
public getPeerPhoto(peerId: number) {
return peerId > 0
public getPeerPhoto(peerId: number): UserProfilePhoto.userProfilePhoto | ChatPhoto.chatPhoto {
const photo = peerId > 0
? appUsersManager.getUserPhoto(peerId)
: appChatsManager.getChatPhoto(-peerId);
return photo._ !== 'chatPhotoEmpty' && photo._ !== 'userProfilePhotoEmpty' ? photo : null;
}
public getPeerMigratedTo(peerId: number) {

5
src/lib/appManagers/appPhotosManager.ts

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

10
src/lib/appManagers/appUsersManager.ts

@ -2,7 +2,7 @@ import { formatPhoneNumber } from "../../components/misc"; @@ -2,7 +2,7 @@ import { formatPhoneNumber } from "../../components/misc";
import { MOUNT_CLASS_TO } from "../../config/debug";
import { tsNow } from "../../helpers/date";
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 apiManager from '../mtproto/apiManager';
import apiManager from '../mtproto/mtprotoworker';
@ -24,7 +24,7 @@ export class AppUsersManager { @@ -24,7 +24,7 @@ export class AppUsersManager {
private users: {[userId: number]: User} = {};
private usernames: {[username: string]: number} = {};
//public userAccess: {[userId: number]: string} = {};
private cachedPhotoLocations: any = {};
private cachedPhotoLocations: {[userId: number]: UserProfilePhoto} = {};
private contactsIndex = searchIndexManager.createIndex();
private contactsFillPromise: Promise<Set<number>>;
public contactsList: Set<number> = new Set();
@ -501,10 +501,12 @@ export class AppUsersManager { @@ -501,10 +501,12 @@ export class AppUsersManager {
}
public getUserPhoto(id: number) {
var user = this.getUser(id);
const user = this.getUser(id);
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];

6
src/scss/partials/_chat.scss

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

4
src/scss/partials/_chatDrop.scss

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

32
src/scss/partials/_emojiDropdown.scss

@ -19,12 +19,14 @@ @@ -19,12 +19,14 @@
box-shadow: 0px 5px 10px 5px rgba(16, 35, 47, .14);
z-index: 3;
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);
opacity: 0;
transform-origin: 0 100%;
&.active {
transition: transform .2s ease-in;
opacity: 1;
transform: scale(1);
}
@ -182,6 +184,32 @@ @@ -182,6 +184,32 @@
width: 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 {
width: 100%;

155
src/scss/partials/_profile.scss

@ -0,0 +1,155 @@ @@ -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;
}
}

99
src/scss/partials/_rightSidebar.scss

@ -93,105 +93,6 @@ @@ -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 {
/* .search-super {
top: 100%;

8
src/scss/style.scss

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

Loading…
Cancel
Save