Browse Source

Multiselect: almost finished

Select by mousemove
New forward
New chat input helper animation
master
morethanwords 4 years ago
parent
commit
f135565529
  1. 14
      src/components/appMediaViewer.ts
  2. 90
      src/components/appSelectPeers.ts
  3. 11
      src/components/button.ts
  4. 7
      src/components/buttonIcon.ts
  5. 21
      src/components/chat/contextMenu.ts
  6. 112
      src/components/chat/input.ts
  7. 242
      src/components/chat/selection.ts
  8. 32
      src/components/popupForward.ts
  9. 2
      src/components/sidebarLeft/tabs/addMembers.ts
  10. 2
      src/components/sidebarLeft/tabs/includedChats.ts
  11. 18
      src/components/sidebarRight/index.ts
  12. 6
      src/components/sidebarRight/tabs/forward.ts
  13. 7
      src/index.hbs
  14. 4
      src/lib/appManagers/appDialogsManager.ts
  15. 11
      src/lib/appManagers/appImManager.ts
  16. 1199
      src/lib/appManagers/appMediaViewer_old.ts
  17. 4
      src/lib/appManagers/appMessagesManager.ts
  18. 4
      src/lib/appManagers/appPollsManager.ts
  19. 14
      src/lib/utils.ts
  20. 10
      src/scss/components/_global.scss
  21. 517
      src/scss/partials/_chat.scss
  22. 8
      src/scss/partials/_chatBubble.scss
  23. 275
      src/scss/partials/_fonts.scss
  24. 146
      src/scss/partials/_ico.scss
  25. 8
      src/scss/partials/_rightSidebar.scss
  26. 8
      src/scss/partials/_selector.scss
  27. 44
      src/scss/partials/popups/_forward.scss
  28. 36
      src/scss/style.scss

14
src/components/appMediaViewer.ts

@ -19,6 +19,7 @@ import { ButtonMenuItemOptions } from "./buttonMenu";
import ButtonMenuToggle from "./buttonMenuToggle"; import ButtonMenuToggle from "./buttonMenuToggle";
import { LazyLoadQueueBase } from "./lazyLoadQueue"; import { LazyLoadQueueBase } from "./lazyLoadQueue";
import { renderImageFromUrl } from "./misc"; import { renderImageFromUrl } from "./misc";
import PopupForward from "./popupForward";
import ProgressivePreloader from "./preloader"; import ProgressivePreloader from "./preloader";
import appSidebarRight, { AppSidebarRight } from "./sidebarRight"; import appSidebarRight, { AppSidebarRight } from "./sidebarRight";
import SwipeHandler from "./swipeHandler"; import SwipeHandler from "./swipeHandler";
@ -231,11 +232,11 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
this.loadMediaPromiseUp = this.loadMediaPromiseDown = null; this.loadMediaPromiseUp = this.loadMediaPromiseDown = null;
this.setMoverPromise = null; this.setMoverPromise = null;
if(appSidebarRight.historyTabIDs.slice(-1)[0] == AppSidebarRight.SLIDERITEMSIDS.forward) { /* if(appSidebarRight.historyTabIDs.slice(-1)[0] == AppSidebarRight.SLIDERITEMSIDS.forward) {
promise.then(() => { promise.then(() => {
appSidebarRight.forwardTab.closeBtn.click(); appSidebarRight.forwardTab.closeBtn.click();
}); });
} } */
window.removeEventListener('keydown', this.onKeyDown); window.removeEventListener('keydown', this.onKeyDown);
@ -794,10 +795,10 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
this.isFirstOpen = false; this.isFirstOpen = false;
//this.loadMore = loadMore; //this.loadMore = loadMore;
if(appSidebarRight.historyTabIDs.slice(-1)[0] == AppSidebarRight.SLIDERITEMSIDS.forward) { /* if(appSidebarRight.historyTabIDs.slice(-1)[0] == AppSidebarRight.SLIDERITEMSIDS.forward) {
appSidebarRight.forwardTab.closeBtn.click(); appSidebarRight.forwardTab.closeBtn.click();
await new Promise((resolve) => setTimeout(resolve, 200)); await new Promise((resolve) => setTimeout(resolve, 200));
} } */
} }
/* if(this.nextTargets.length < 10 && this.loadMore) { /* if(this.nextTargets.length < 10 && this.loadMore) {
@ -1132,7 +1133,10 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet
onForwardClick = (e: MouseEvent) => { onForwardClick = (e: MouseEvent) => {
if(this.currentMessageID) { if(this.currentMessageID) {
appSidebarRight.forwardTab.open([this.currentMessageID]); //appSidebarRight.forwardTab.open([this.currentMessageID]);
new PopupForward([this.currentMessageID], () => {
return this.close();
});
} }
}; };

90
src/components/appSelectPeers.ts

@ -13,15 +13,15 @@ type PeerType = 'contacts' | 'dialogs';
// TODO: правильная сортировка для addMembers, т.е. для peerType: 'contacts', потому что там идут сначала контакты - потом неконтакты, а должно всё сортироваться по имени // TODO: правильная сортировка для addMembers, т.е. для peerType: 'contacts', потому что там идут сначала контакты - потом неконтакты, а должно всё сортироваться по имени
let loadedAllDialogs = false, loadAllDialogsPromise: Promise<any>; let loadedAllDialogs = false, loadAllDialogsPromise: Promise<any>;
export class AppSelectPeers { export default class AppSelectPeers {
public container = document.createElement('div'); public container = document.createElement('div');
public list = document.createElement('ul'); public list = document.createElement('ul');
public chatsContainer = document.createElement('div'); public chatsContainer = document.createElement('div');
public scrollable: Scrollable; public scrollable: Scrollable;
public selectedScrollable: Scrollable; public selectedScrollable: Scrollable;
public selectedContainer = document.createElement('div'); public selectedContainer: HTMLElement;
public input = document.createElement('input'); public input: HTMLInputElement;
//public selected: {[peerID: number]: HTMLElement} = {}; //public selected: {[peerID: number]: HTMLElement} = {};
public selected = new Set<any>(); public selected = new Set<any>();
@ -37,24 +37,49 @@ export class AppSelectPeers {
private loadedWhat: Partial<{[k in 'dialogs' | 'archived' | 'contacts']: true}> = {}; private loadedWhat: Partial<{[k in 'dialogs' | 'archived' | 'contacts']: true}> = {};
constructor(private appendTo: HTMLElement, private onChange?: (length: number) => void, private peerType: PeerType[] = ['dialogs'], onFirstRender?: () => void, private renderResultsFunc?: (peerIDs: number[]) => void, private chatRightsAction?: ChatRights) { constructor(private appendTo: HTMLElement, private onChange?: (length: number) => void, private peerType: PeerType[] = ['dialogs'], onFirstRender?: () => void, private renderResultsFunc?: (peerIDs: number[]) => void, private chatRightsAction?: ChatRights, private multiSelect = true) {
this.container.classList.add('selector'); this.container.classList.add('selector');
if(!this.renderResultsFunc) { if(!this.renderResultsFunc) {
this.renderResultsFunc = this.renderResults; this.renderResultsFunc = this.renderResults;
} }
let topContainer = document.createElement('div'); this.input = document.createElement('input');
topContainer.classList.add('selector-search-container'); this.input.classList.add('selector-search-input');
this.selectedContainer.classList.add('selector-search');
this.input.placeholder = !peerType.includes('dialogs') ? 'Add People...' : 'Select chat'; this.input.placeholder = !peerType.includes('dialogs') ? 'Add People...' : 'Select chat';
this.input.type = 'text'; this.input.type = 'text';
this.selectedContainer.append(this.input);
topContainer.append(this.selectedContainer);
this.selectedScrollable = new Scrollable(topContainer);
let delimiter = document.createElement('hr'); if(multiSelect) {
let topContainer = document.createElement('div');
topContainer.classList.add('selector-search-container');
this.selectedContainer = document.createElement('div');
this.selectedContainer.classList.add('selector-search');
this.selectedContainer.append(this.input);
topContainer.append(this.selectedContainer);
this.selectedScrollable = new Scrollable(topContainer);
let delimiter = document.createElement('hr');
this.selectedContainer.addEventListener('click', (e) => {
if(this.freezed) return;
let target = e.target as HTMLElement;
target = findUpClassName(target, 'selector-user');
if(!target) return;
const peerID = target.dataset.key;
const li = this.chatsContainer.querySelector('[data-peerid="' + peerID + '"]') as HTMLElement;
if(!li) {
this.remove(+peerID || peerID);
} else {
li.click();
}
});
this.container.append(topContainer, delimiter);
}
this.chatsContainer.classList.add('chats-container'); this.chatsContainer.classList.add('chats-container');
this.chatsContainer.append(this.list); this.chatsContainer.append(this.list);
@ -70,6 +95,12 @@ export class AppSelectPeers {
let key: any = target.getAttribute('data-peerID'); let key: any = target.getAttribute('data-peerID');
key = +key || key; key = +key || key;
if(!this.multiSelect) {
this.add(key);
return;
}
target.classList.toggle('active'); target.classList.toggle('active');
if(this.selected.has(key)) { if(this.selected.has(key)) {
this.remove(key); this.remove(key);
@ -81,22 +112,6 @@ export class AppSelectPeers {
checkbox.checked = !checkbox.checked; checkbox.checked = !checkbox.checked;
}); });
this.selectedContainer.addEventListener('click', (e) => {
if(this.freezed) return;
let target = e.target as HTMLElement;
target = findUpClassName(target, 'selector-user');
if(!target) return;
const peerID = target.dataset.key;
const li = this.chatsContainer.querySelector('[data-peerid="' + peerID + '"]') as HTMLElement;
if(!li) {
this.remove(+peerID || peerID);
} else {
li.click();
}
});
this.input.addEventListener('input', () => { this.input.addEventListener('input', () => {
const value = this.input.value; const value = this.input.value;
if(this.query != value) { if(this.query != value) {
@ -125,7 +140,7 @@ export class AppSelectPeers {
this.getMoreResults(); this.getMoreResults();
}; };
this.container.append(topContainer, delimiter, this.chatsContainer); this.container.append(this.chatsContainer);
appendTo.append(this.container); appendTo.append(this.container);
// WARNING TIMEOUT // WARNING TIMEOUT
@ -292,9 +307,11 @@ export class AppSelectPeers {
peerIDs.forEach(peerID => { peerIDs.forEach(peerID => {
const {dom} = appDialogsManager.addDialog(peerID, this.scrollable, false, false); const {dom} = appDialogsManager.addDialog(peerID, this.scrollable, false, false);
const selected = this.selected.has(peerID); if(this.multiSelect) {
dom.containerEl.insertAdjacentHTML('afterbegin', `<div class="checkbox"><label><input type="checkbox" ${selected ? 'checked' : ''}><span></span></label></div>`); const selected = this.selected.has(peerID);
if(selected) dom.listEl.classList.add('active'); dom.containerEl.insertAdjacentHTML('afterbegin', `<div class="checkbox"><label><input type="checkbox" ${selected ? 'checked' : ''}><span></span></label></div>`);
if(selected) dom.listEl.classList.add('active');
}
let subtitle = ''; let subtitle = '';
if(peerID < 0) { if(peerID < 0) {
@ -314,6 +331,13 @@ export class AppSelectPeers {
public add(peerID: any, title?: string) { public add(peerID: any, title?: string) {
//console.trace('add'); //console.trace('add');
this.selected.add(peerID);
if(!this.multiSelect) {
this.onChange(this.selected.size);
return;
}
const div = document.createElement('div'); const div = document.createElement('div');
div.classList.add('selector-user', 'scale-in'); div.classList.add('selector-user', 'scale-in');
@ -322,7 +346,6 @@ export class AppSelectPeers {
avatarEl.setAttribute('dialog', '1'); avatarEl.setAttribute('dialog', '1');
div.dataset.key = '' + peerID; div.dataset.key = '' + peerID;
this.selected.add(peerID);
if(typeof(peerID) === 'number') { if(typeof(peerID) === 'number') {
if(title === undefined) { if(title === undefined) {
title = peerID == $rootScope.myID ? 'Saved' : appPeersManager.getPeerTitle(peerID, false, true); title = peerID == $rootScope.myID ? 'Saved' : appPeersManager.getPeerTitle(peerID, false, true);
@ -346,6 +369,7 @@ export class AppSelectPeers {
} }
public remove(key: any) { public remove(key: any) {
if(!this.multiSelect) return;
//const div = this.selected[peerID]; //const div = this.selected[peerID];
const div = this.selectedContainer.querySelector(`[data-key="${key}"]`) as HTMLElement; const div = this.selectedContainer.querySelector(`[data-key="${key}"]`) as HTMLElement;
div.classList.remove('scale-in'); div.classList.remove('scale-in');

11
src/components/button.ts

@ -0,0 +1,11 @@
import { ripple } from "./ripple";
const Button = (className: string, options: Partial<{noRipple: true, onlyMobile: true, icon: string}> = {}) => {
const button = document.createElement('button');
button.className = className + (options.icon ? ' tgico-' + options.icon : '');
if(!options.noRipple) ripple(button);
if(options.onlyMobile) button.classList.add('only-handhelds');
return button;
};
export default Button;

7
src/components/buttonIcon.ts

@ -1,10 +1,7 @@
import { ripple } from "./ripple"; import Button from "./button";
const ButtonIcon = (className: string, options: Partial<{noRipple: true, onlyMobile: true}> = {}) => { const ButtonIcon = (className: string, options: Partial<{noRipple: true, onlyMobile: true}> = {}) => {
const button = document.createElement('button'); const button = Button('btn-icon', {icon: className, ...options});
button.className = `btn-icon tgico-${className}`;
if(!options.noRipple) ripple(button);
if(options.onlyMobile) button.classList.add('only-handhelds');
return button; return button;
}; };

21
src/components/chat/contextMenu.ts

@ -8,6 +8,7 @@ import { findUpClassName } from "../../lib/utils";
import ButtonMenu, { ButtonMenuItemOptions } from "../buttonMenu"; import ButtonMenu, { ButtonMenuItemOptions } from "../buttonMenu";
import { attachContextMenuListener, openBtnMenu, positionMenu } from "../misc"; import { attachContextMenuListener, openBtnMenu, positionMenu } from "../misc";
import { PopupButton } from "../popup"; import { PopupButton } from "../popup";
import PopupForward from "../popupForward";
import PopupPeer from "../popupPeer"; import PopupPeer from "../popupPeer";
import appSidebarRight from "../sidebarRight"; import appSidebarRight from "../sidebarRight";
@ -124,7 +125,7 @@ export default class ChatContextMenu {
onClick: this.onForwardClick, onClick: this.onForwardClick,
verify: () => this.msgID > 0 verify: () => this.msgID > 0
}, { }, {
icon: 'revote', icon: 'select',
text: 'Select', text: 'Select',
onClick: this.onSelectClick, onClick: this.onSelectClick,
verify: () => { verify: () => {
@ -133,7 +134,7 @@ export default class ChatContextMenu {
}, },
notDirect: () => true notDirect: () => true
}, { }, {
icon: 'revote', icon: 'select',
text: 'Clear selection', text: 'Clear selection',
onClick: this.onClearSelectionClick, onClick: this.onClearSelectionClick,
verify: () => { verify: () => {
@ -155,17 +156,15 @@ export default class ChatContextMenu {
private onReplyClick = () => { private onReplyClick = () => {
const message = appMessagesManager.getMessage(this.msgID); const message = appMessagesManager.getMessage(this.msgID);
const chatInputC = appImManager.chatInputC; const chatInputC = appImManager.chatInputC;
chatInputC.setTopInfo(appPeersManager.getPeerTitle(message.fromID, true), message.message, undefined, message); const f = () => {
chatInputC.replyToMsgID = this.msgID; chatInputC.setTopInfo('reply', f, appPeersManager.getPeerTitle(message.fromID, true), message.message, undefined, message);
chatInputC.editMsgID = 0; chatInputC.replyToMsgID = this.msgID;
};
f();
}; };
private onEditClick = () => { private onEditClick = () => {
const message = appMessagesManager.getMessage(this.msgID); appImManager.chatInputC.initMessageEditing(this.msgID);
const chatInputC = appImManager.chatInputC;
chatInputC.setTopInfo('Editing', message.message, message.message, message);
chatInputC.replyToMsgID = 0;
chatInputC.editMsgID = this.msgID;
}; };
private onCopyClick = () => { private onCopyClick = () => {
@ -206,7 +205,7 @@ export default class ChatContextMenu {
}; };
private onForwardClick = () => { private onForwardClick = () => {
appSidebarRight.forwardTab.open([this.msgID]); new PopupForward([this.msgID]);
}; };
private onSelectClick = () => { private onSelectClick = () => {

112
src/components/chat/input.ts

@ -4,6 +4,7 @@ import appChatsManager from '../../lib/appManagers/appChatsManager';
import appDocsManager from "../../lib/appManagers/appDocsManager"; import appDocsManager from "../../lib/appManagers/appDocsManager";
import appImManager from "../../lib/appManagers/appImManager"; 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 appWebPagesManager from "../../lib/appManagers/appWebPagesManager"; import appWebPagesManager from "../../lib/appManagers/appWebPagesManager";
import apiManager from "../../lib/mtproto/mtprotoworker"; import apiManager from "../../lib/mtproto/mtprotoworker";
//import Recorder from '../opus-recorder/dist/recorder.min'; //import Recorder from '../opus-recorder/dist/recorder.min';
@ -23,6 +24,8 @@ import { wrapReply } from "../wrappers";
const RECORD_MIN_TIME = 500; const RECORD_MIN_TIME = 500;
const POSTING_MEDIA_NOT_ALLOWED = 'Posting media content isn\'t allowed in this group.'; const POSTING_MEDIA_NOT_ALLOWED = 'Posting media content isn\'t allowed in this group.';
type ChatInputHelperType = 'edit' | 'webpage' | 'forward' | 'reply';
export class ChatInput { export class ChatInput {
public pageEl = document.getElementById('page-chats') as HTMLDivElement; public pageEl = document.getElementById('page-chats') as HTMLDivElement;
public messageInput = document.getElementById('input-message') as HTMLDivElement/* HTMLInputElement */; public messageInput = document.getElementById('input-message') as HTMLDivElement/* HTMLInputElement */;
@ -48,6 +51,7 @@ export class ChatInput {
} = {}; } = {};
public willSendWebPage: any = null; public willSendWebPage: any = null;
public forwardingMids: number[] = [];
public replyToMsgID = 0; public replyToMsgID = 0;
public editMsgID = 0; public editMsgID = 0;
public noWebPage: true; public noWebPage: true;
@ -63,6 +67,9 @@ export class ChatInput {
private scrollOffsetTop = 0; private scrollOffsetTop = 0;
private scrollDiff = 0; private scrollDiff = 0;
private helperType: Exclude<ChatInputHelperType, 'webpage'>;
private helperFunc: () => void;
constructor() { constructor() {
this.attachMenu = document.getElementById('attach-file') as HTMLButtonElement; this.attachMenu = document.getElementById('attach-file') as HTMLButtonElement;
@ -198,9 +205,8 @@ export class ChatInput {
if(this.lastUrl != url) return; if(this.lastUrl != url) return;
//console.log('got webpage: ', webpage); //console.log('got webpage: ', webpage);
this.setTopInfo(webpage.site_name || webpage.title, webpage.description || webpage.url); this.setTopInfo('webpage', () => {}, webpage.site_name || webpage.title, webpage.description || webpage.url);
this.replyToMsgID = 0;
delete this.noWebPage; delete this.noWebPage;
this.willSendWebPage = webpage; this.willSendWebPage = webpage;
} }
@ -313,7 +319,7 @@ export class ChatInput {
const onBtnSendClick = (e: Event) => { const onBtnSendClick = (e: Event) => {
cancelEvent(e); cancelEvent(e);
if(!this.recorder || this.recording || !this.isInputEmpty()) { if(!this.recorder || this.recording || !this.isInputEmpty() || this.forwardingMids.length) {
if(this.recording) { if(this.recording) {
if((Date.now() - this.recordStartTime) < RECORD_MIN_TIME) { if((Date.now() - this.recordStartTime) < RECORD_MIN_TIME) {
this.btnCancelRecord.click(); this.btnCancelRecord.click();
@ -487,23 +493,21 @@ export class ChatInput {
} }
this.replyElements.cancelBtn.addEventListener('click', () => { this.replyElements.cancelBtn.addEventListener('click', () => {
this.replyElements.container.classList.remove('active'); if(this.willSendWebPage) {
this.replyToMsgID = 0; this.noWebPage = true;
this.willSendWebPage = null;
if(this.editMsgID) { if(this.helperType) {
if(this.willSendWebPage) { //if(this.helperFunc) {
let message = appMessagesManager.getMessage(this.editMsgID); this.helperFunc();
this.setTopInfo('Editing', message.message); //}
} else {
this.editMsgID = 0;
this.messageInput.innerHTML = '';
this.updateSendBtn(); return;
} }
} }
this.noWebPage = true; this.clearHelper();
this.willSendWebPage = null; this.updateSendBtn();
}); });
} }
@ -516,7 +520,7 @@ export class ChatInput {
public updateSendBtn() { public updateSendBtn() {
let icon: 'send' | 'record'; let icon: 'send' | 'record';
if(!this.recorder || this.recording || !this.isInputEmpty()) icon = 'send'; if(!this.recorder || this.recording || !this.isInputEmpty() || this.forwardingMids.length) icon = 'send';
else icon = 'record'; else icon = 'record';
this.btnSend.classList.toggle('send', icon == 'send'); this.btnSend.classList.toggle('send', icon == 'send');
@ -543,18 +547,16 @@ export class ChatInput {
if(clearInput) { if(clearInput) {
this.lastUrl = ''; this.lastUrl = '';
this.editMsgID = 0;
delete this.noWebPage; delete this.noWebPage;
this.willSendWebPage = null; this.willSendWebPage = null;
this.messageInput.innerText = ''; this.messageInput.innerText = '';
this.updateSendBtn();
} }
if(clearReply || clearInput) { if(clearReply || clearInput) {
this.replyToMsgID = 0; this.clearHelper();
this.replyElements.container.classList.remove('active');
} }
this.updateSendBtn();
} }
public sendMessage() { public sendMessage() {
@ -577,6 +579,10 @@ export class ChatInput {
}); });
} }
if(this.forwardingMids.length) {
appMessagesManager.forwardMessages(appImManager.peerID, this.forwardingMids);
}
this.onMessageSent(); this.onMessageSent();
} }
@ -596,24 +602,72 @@ export class ChatInput {
return false; return false;
} }
public setTopInfo(title: string, subtitle: string, input?: string, message?: any) { public initMessageEditing(mid: number) {
//appImManager.scrollPosition.prepareFor('down'); const message = appMessagesManager.getMessage(mid);
let input = message.message;
const f = () => {
this.setTopInfo('edit', f, 'Editing', message.message, input, message);
this.editMsgID = mid;
input = undefined;
};
f();
}
public initMessagesForward(mids: number[]) {
const f = () => {
//const peerTitles: string[]
const fromIDs = new Set(mids.map(mid => appMessagesManager.getMessage(mid).fromID));
const onlyFirstName = fromIDs.size > 1;
const peerTitles = [...fromIDs].map(peerID => appPeersManager.getPeerTitle(peerID, true, onlyFirstName));
const title = peerTitles.length < 3 ? peerTitles.join(' and ') : peerTitles[0] + ' and ' + (peerTitles.length - 1) + ' others';
if(mids.length == 1) {
const message = appMessagesManager.getMessage(mids[0]);
this.setTopInfo('forward', f, title, message.message, undefined, message);
} else {
this.setTopInfo('forward', f, title, mids.length + ' forwarded messages');
}
this.forwardingMids = mids;
};
f();
}
public clearHelper(type?: ChatInputHelperType) {
if(this.helperType == 'edit' && type != 'edit') {
this.messageInput.innerText = '';
}
this.replyToMsgID = 0;
this.forwardingMids.length = 0;
this.editMsgID = 0;
this.helperType = this.helperFunc = undefined;
this.chatInput.parentElement.classList.remove('is-helper-active');
}
public setTopInfo(type: ChatInputHelperType, callerFunc: () => void, title: string, subtitle: string, input?: string, message?: any) {
if(type != 'webpage') {
this.clearHelper(type);
this.helperType = type;
this.helperFunc = callerFunc;
}
if(this.replyElements.container.lastElementChild.tagName == 'DIV') { if(this.replyElements.container.lastElementChild.tagName == 'DIV') {
this.replyElements.container.lastElementChild.remove(); this.replyElements.container.lastElementChild.remove();
this.replyElements.container.append(wrapReply(title, subtitle, message)); this.replyElements.container.append(wrapReply(title, subtitle, message));
} }
//this.replyElements.titleEl.innerHTML = title ? RichTextProcessor.wrapEmojiText(title) : '';
//this.replyElements.subtitleEl.innerHTML = subtitle ? RichTextProcessor.wrapEmojiText(subtitle) : ''; this.chatInput.parentElement.classList.add('is-helper-active');
this.replyElements.container.classList.add('active');
if(input !== undefined) { if(input !== undefined) {
this.messageInput.innerHTML = input ? RichTextProcessor.wrapRichText(input) : ''; this.messageInput.innerHTML = input ? RichTextProcessor.wrapRichText(input) : '';
this.updateSendBtn();
} }
//appImManager.scrollPosition.restore(); setTimeout(() => {
this.updateSendBtn();
}, 0);
} }
public saveScroll() { public saveScroll() {

242
src/components/chat/selection.ts

@ -1,13 +1,143 @@
import { isTouchSupported } from "../../helpers/touchSupport";
import type { AppImManager } from "../../lib/appManagers/appImManager"; import type { AppImManager } from "../../lib/appManagers/appImManager";
import type { AppMessagesManager } from "../../lib/appManagers/appMessagesManager"; import type { AppMessagesManager } from "../../lib/appManagers/appMessagesManager";
import { cancelEvent, cancelSelection, findUpClassName } from "../../lib/utils";
import Button from "../button";
import ButtonIcon from "../buttonIcon";
import CheckboxField from "../checkbox"; import CheckboxField from "../checkbox";
import PopupForward from "../popupForward";
import { toast } from "../toast";
const SetTransition = (element: HTMLElement, className: string, forwards: boolean, duration: number, onTransitionEnd?: () => void) => {
const timeout = element.dataset.timeout;
if(timeout !== undefined) {
clearTimeout(+timeout);
}
if(forwards) {
element.classList.add(className);
}
element.classList.add('animating');
element.classList.toggle('backwards', !forwards);
element.dataset.timeout = '' + setTimeout(() => {
delete element.dataset.timeout;
if(!forwards) {
element.classList.remove('backwards', className);
}
element.classList.remove('animating');
onTransitionEnd && onTransitionEnd();
}, duration);
};
const MAX_SELECTION_LENGTH = 100;
const MIN_CLICK_MOVE = 32; // minimum bubble height
export default class ChatSelection { export default class ChatSelection {
public selectedMids: Set<number> = new Set(); public selectedMids: Set<number> = new Set();
public isSelecting = false; public isSelecting = false;
private selectionContainer: HTMLElement;
private selectionCountEl: HTMLElement;
constructor(private appImManager: AppImManager, private appMessagesManager: AppMessagesManager) { constructor(private appImManager: AppImManager, private appMessagesManager: AppMessagesManager) {
if(isTouchSupported) return;
const bubblesContainer = appImManager.bubblesContainer;
bubblesContainer.addEventListener('mousedown', (e) => {
//console.log('selection mousedown', e);
if(e.button != 0) { // LEFT BUTTON
return;
}
const seen: Set<number> = new Set();
let selecting: boolean;
/* let good = false;
const {x, y} = e; */
/* const bubbles = appImManager.bubbles;
for(const mid in bubbles) {
const bubble = bubbles[mid];
bubble.addEventListener('mouseover', () => {
console.log('mouseover');
}, {once: true});
} */
//const foundTargets: Map<HTMLElement, true> = new Map();
const onMouseMove = (e: MouseEvent) => {
/* if(!good) {
if(Math.abs(e.x - x) > MIN_CLICK_MOVE || Math.abs(e.y - y) > MIN_CLICK_MOVE) {
good = true;
} else {
return;
}
} */
/* if(foundTargets.has(e.target as HTMLElement)) return;
foundTargets.set(e.target as HTMLElement, true); */
const bubble = findUpClassName(e.target, 'bubble');
if(!bubble) {
console.error('found no bubble', e);
return;
}
const mid = +bubble.dataset.mid;
if(!mid) return;
if(e.target != bubble && selecting === undefined) {
bubblesContainer.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseUp);
return;
}
if(!seen.has(mid)) {
const isBubbleSelected = this.selectedMids.has(mid);
if(selecting === undefined) {
appImManager.scrollable.container.classList.add('no-select');
selecting = !isBubbleSelected;
}
seen.add(mid);
if((selecting && !isBubbleSelected) || (!selecting && isBubbleSelected)) {
if(!this.selectedMids.size) {
if(seen.size == 2) {
[...seen].forEach(mid => {
const mounted = this.appImManager.getMountedBubble(mid);
if(mounted) {
this.toggleByBubble(mounted.bubble);
}
})
}
} else {
this.toggleByBubble(bubble);
}
}
}
//console.log('onMouseMove', target);
};
const onMouseUp = (e: MouseEvent) => {
if(seen.size) {
window.addEventListener('click', (e) => {
cancelEvent(e);
}, {capture: true, once: true, passive: false});
}
bubblesContainer.removeEventListener('mousemove', onMouseMove);
appImManager.scrollable.container.classList.remove('no-select');
// ! CANCEL USER SELECTION !
cancelSelection();
};
bubblesContainer.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp, {once: true});
});
} }
public toggleBubbleCheckbox(bubble: HTMLElement, show: boolean) { public toggleBubbleCheckbox(bubble: HTMLElement, show: boolean) {
@ -25,31 +155,79 @@ export default class ChatSelection {
bubble.classList.add('is-selected'); bubble.classList.add('is-selected');
} }
bubble.append(checkboxField.label); bubble.prepend(checkboxField.label);
} else if(hasCheckbox) { } else if(hasCheckbox) {
bubble.lastElementChild.remove(); bubble.firstElementChild.remove();
} }
} }
public getCheckboxInputFromBubble(bubble: HTMLElement) { public getCheckboxInputFromBubble(bubble: HTMLElement) {
return bubble.lastElementChild.tagName == 'LABEL' && bubble.lastElementChild.firstElementChild as HTMLInputElement; return bubble.firstElementChild.tagName == 'LABEL' && bubble.firstElementChild.firstElementChild as HTMLInputElement;
} }
public toggleSelection() { public updateForwardContainer() {
if(!this.selectedMids.size) return;
this.selectionCountEl.innerText = this.selectedMids.size + ' Message' + (this.selectedMids.size == 1 ? '' : 's');
}
public toggleSelection(toggleCheckboxes = true) {
const wasSelecting = this.isSelecting; const wasSelecting = this.isSelecting;
this.isSelecting = this.selectedMids.size > 0; this.isSelecting = this.selectedMids.size > 0;
if(wasSelecting == this.isSelecting) return; if(wasSelecting == this.isSelecting) return;
this.appImManager.bubblesContainer.classList.toggle('is-selecting', !!this.selectedMids.size); const bubblesContainer = this.appImManager.bubblesContainer;
//bubblesContainer.classList.toggle('is-selecting', !!this.selectedMids.size);
for(const mid in this.appImManager.bubbles) { SetTransition(bubblesContainer, 'is-selecting', !!this.selectedMids.size, 200, () => {
const bubble = this.appImManager.bubbles[mid]; if(!this.isSelecting) {
this.toggleBubbleCheckbox(bubble, this.isSelecting); this.selectionContainer.remove();
this.selectionContainer = null;
}
});
//const chatInput = this.appImManager.chatInput;
if(this.isSelecting) {
if(!this.selectionContainer) {
const inputMessageDiv = document.querySelector('.input-message');
this.selectionContainer = document.createElement('div');
this.selectionContainer.classList.add('selection-container');
const btnCancel = ButtonIcon('close', {noRipple: true});
btnCancel.addEventListener('click', this.cancelSelection, {once: true});
this.selectionCountEl = document.createElement('div');
this.selectionCountEl.classList.add('selection-container-count');
const btnForward = Button('btn-primary btn-transparent', {icon: 'forward'});
btnForward.append('Forward');
btnForward.addEventListener('click', () => {
new PopupForward([...this.selectedMids], () => {
this.cancelSelection();
});
});
const btnDelete = Button('btn-primary btn-transparent danger', {icon: 'delete'});
btnDelete.append('Delete');
this.selectionContainer.append(btnCancel, this.selectionCountEl, btnForward, btnDelete);
inputMessageDiv.append(this.selectionContainer);
}
}
if(toggleCheckboxes) {
for(const mid in this.appImManager.bubbles) {
const bubble = this.appImManager.bubbles[mid];
this.toggleBubbleCheckbox(bubble, this.isSelecting);
}
} }
} }
public cancelSelection() { public cancelSelection = () => {
for(const mid of this.selectedMids) { for(const mid of this.selectedMids) {
const bubble = this.appImManager.bubbles[mid]; const bubble = this.appImManager.bubbles[mid];
if(bubble) { if(bubble) {
@ -59,12 +237,12 @@ export default class ChatSelection {
this.selectedMids.clear(); this.selectedMids.clear();
this.toggleSelection(); this.toggleSelection();
} cancelSelection();
};
public cleanup() { public cleanup() {
this.isSelecting = false;
this.selectedMids.clear(); this.selectedMids.clear();
this.appImManager.bubblesContainer.classList.remove('is-selecting'); this.toggleSelection(false);
} }
public toggleByBubble(bubble: HTMLElement) { public toggleByBubble(bubble: HTMLElement) {
@ -75,6 +253,25 @@ export default class ChatSelection {
if(found) { if(found) {
mids.forEach(mid => this.selectedMids.delete(mid)); mids.forEach(mid => this.selectedMids.delete(mid));
} else { } else {
let diff = MAX_SELECTION_LENGTH - this.selectedMids.size - mids.length;
if(diff < 0) {
toast('Max selection count reached.');
return;
/* const it = this.selectedMids.values();
do {
const mid = it.next().value;
const mounted = this.appImManager.getMountedBubble(mid);
if(mounted) {
this.toggleByBubble(mounted.bubble);
} else {
const mids = this.appMessagesManager.getMidsByMid(mid);
for(const mid of mids) {
this.selectedMids.delete(mid);
}
}
} while(this.selectedMids.size > MAX_SELECTION_LENGTH); */
}
mids.forEach(mid => this.selectedMids.add(mid)); mids.forEach(mid => this.selectedMids.add(mid));
} }
@ -83,24 +280,7 @@ export default class ChatSelection {
input.checked = !found; input.checked = !found;
this.toggleSelection(); this.toggleSelection();
if(found) { this.updateForwardContainer();
bubble.classList.add('backwards'); SetTransition(bubble, 'is-selected', !found, 200);
bubble.dataset.timeout = '' + setTimeout(() => {
delete bubble.dataset.timeout;
bubble.classList.remove('backwards', 'is-selected');
}, 200);
} else {
bubble.classList.remove('backwards');
const timeout = bubble.dataset.timeout;
if(timeout !== undefined) {
clearTimeout(+timeout);
}
bubble.classList.add('is-selected');
}
}
public selectMessage(mid: number) {
} }
} }

32
src/components/popupForward.ts

@ -0,0 +1,32 @@
import appImManager from "../lib/appManagers/appImManager";
import AppSelectPeers from "./appSelectPeers";
import { PopupElement } from "./popup";
export default class PopupForward extends PopupElement {
private selector: AppSelectPeers;
//private scrollable: Scrollable;
constructor(mids: number[], onSelect?: () => Promise<void> | void) {
super('popup-forward', null, {closable: true, body: true});
this.selector = new AppSelectPeers(this.body, async() => {
const peerID = this.selector.getSelected()[0];
this.closeBtn.click();
this.selector = null;
await (onSelect ? onSelect() || Promise.resolve() : Promise.resolve());
appImManager.setPeer(peerID);
appImManager.chatInputC.initMessagesForward(mids.slice());
}, ['dialogs', 'contacts'], () => {
this.show();
}, null, 'send', false);
//this.scrollable = new Scrollable(this.body);
this.selector.input.placeholder = 'Forward to...';
this.title.append(this.selector.input);
}
}

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

@ -1,5 +1,5 @@
import { SliderTab } from "../../slider"; import { SliderTab } from "../../slider";
import { AppSelectPeers } from "../../appSelectPeers"; import AppSelectPeers from "../../appSelectPeers";
import { putPreloader } from "../../misc"; import { putPreloader } from "../../misc";
import appChatsManager from "../../../lib/appManagers/appChatsManager"; import appChatsManager from "../../../lib/appManagers/appChatsManager";
import appSidebarLeft, { AppSidebarLeft } from ".."; import appSidebarLeft, { AppSidebarLeft } from "..";

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

@ -1,5 +1,5 @@
import { SliderTab } from "../../slider"; import { SliderTab } from "../../slider";
import { AppSelectPeers } from "../../appSelectPeers"; import AppSelectPeers from "../../appSelectPeers";
import appSidebarLeft, { AppSidebarLeft } from ".."; import appSidebarLeft, { AppSidebarLeft } from "..";
import appDialogsManager from "../../../lib/appManagers/appDialogsManager"; import appDialogsManager from "../../../lib/appManagers/appDialogsManager";
import appPeersManager from "../../../lib/appManagers/appPeersManager"; import appPeersManager from "../../../lib/appManagers/appPeersManager";

18
src/components/sidebarRight/index.ts

@ -6,14 +6,14 @@ import AppGifsTab from "./tabs/gifs";
import mediaSizes, { ScreenSize } from "../../helpers/mediaSizes"; import mediaSizes, { ScreenSize } from "../../helpers/mediaSizes";
import AppPrivateSearchTab from "./tabs/search"; import AppPrivateSearchTab from "./tabs/search";
import AppSharedMediaTab from "./tabs/sharedMedia"; import AppSharedMediaTab from "./tabs/sharedMedia";
import AppForwardTab from "./tabs/forward"; //import AppForwardTab from "./tabs/forward";
import { MOUNT_CLASS_TO } from "../../lib/mtproto/mtproto_config"; import { MOUNT_CLASS_TO } from "../../lib/mtproto/mtproto_config";
export const RIGHT_COLUMN_ACTIVE_CLASSNAME = 'is-right-column-shown'; export const RIGHT_COLUMN_ACTIVE_CLASSNAME = 'is-right-column-shown';
const sharedMediaTab = new AppSharedMediaTab(); const sharedMediaTab = new AppSharedMediaTab();
const searchTab = new AppPrivateSearchTab(); const searchTab = new AppPrivateSearchTab();
const forwardTab = new AppForwardTab(); //const forwardTab = new AppForwardTab();
const stickersTab = new AppStickersTab(); const stickersTab = new AppStickersTab();
const pollResultsTab = new AppPollResultsTab(); const pollResultsTab = new AppPollResultsTab();
const gifsTab = new AppGifsTab(); const gifsTab = new AppGifsTab();
@ -22,15 +22,15 @@ export class AppSidebarRight extends SidebarSlider {
public static SLIDERITEMSIDS = { public static SLIDERITEMSIDS = {
sharedMedia: 0, sharedMedia: 0,
search: 1, search: 1,
forward: 2, //forward: 2,
stickers: 3, stickers: 2,
pollResults: 4, pollResults: 3,
gifs: 5, gifs: 4,
}; };
public sharedMediaTab: AppSharedMediaTab; public sharedMediaTab: AppSharedMediaTab;
public searchTab: AppPrivateSearchTab; public searchTab: AppPrivateSearchTab;
public forwardTab: AppForwardTab; //public forwardTab: AppForwardTab;
public stickersTab: AppStickersTab; public stickersTab: AppStickersTab;
public pollResultsTab: AppPollResultsTab; public pollResultsTab: AppPollResultsTab;
public gifsTab: AppGifsTab; public gifsTab: AppGifsTab;
@ -39,7 +39,7 @@ export class AppSidebarRight extends SidebarSlider {
super(document.getElementById('column-right') as HTMLElement, { super(document.getElementById('column-right') as HTMLElement, {
[AppSidebarRight.SLIDERITEMSIDS.sharedMedia]: sharedMediaTab, [AppSidebarRight.SLIDERITEMSIDS.sharedMedia]: sharedMediaTab,
[AppSidebarRight.SLIDERITEMSIDS.search]: searchTab, [AppSidebarRight.SLIDERITEMSIDS.search]: searchTab,
[AppSidebarRight.SLIDERITEMSIDS.forward]: forwardTab, //[AppSidebarRight.SLIDERITEMSIDS.forward]: forwardTab,
[AppSidebarRight.SLIDERITEMSIDS.stickers]: stickersTab, [AppSidebarRight.SLIDERITEMSIDS.stickers]: stickersTab,
[AppSidebarRight.SLIDERITEMSIDS.pollResults]: pollResultsTab, [AppSidebarRight.SLIDERITEMSIDS.pollResults]: pollResultsTab,
[AppSidebarRight.SLIDERITEMSIDS.gifs]: gifsTab [AppSidebarRight.SLIDERITEMSIDS.gifs]: gifsTab
@ -49,7 +49,7 @@ export class AppSidebarRight extends SidebarSlider {
this.sharedMediaTab = sharedMediaTab; this.sharedMediaTab = sharedMediaTab;
this.searchTab = searchTab; this.searchTab = searchTab;
this.forwardTab = forwardTab; //this.forwardTab = forwardTab;
this.stickersTab = stickersTab; this.stickersTab = stickersTab;
this.pollResultsTab = pollResultsTab; this.pollResultsTab = pollResultsTab;
this.gifsTab = gifsTab; this.gifsTab = gifsTab;

6
src/components/sidebarRight/tabs/forward.ts

@ -1,6 +1,6 @@
import appSidebarRight, { AppSidebarRight } from ".."; import appSidebarRight, { AppSidebarRight } from "..";
import appMessagesManager from "../../../lib/appManagers/appMessagesManager"; import appMessagesManager from "../../../lib/appManagers/appMessagesManager";
import { AppSelectPeers } from "../../appSelectPeers"; import AppSelectPeers from "../../appSelectPeers";
import { putPreloader } from "../../misc"; import { putPreloader } from "../../misc";
import { SliderTab } from "../../slider"; import { SliderTab } from "../../slider";
@ -75,7 +75,9 @@ export default class AppForwardTab implements SliderTab {
this.sendBtn.classList.toggle('is-visible', !!length); this.sendBtn.classList.toggle('is-visible', !!length);
}, ['dialogs', 'contacts'], () => { }, ['dialogs', 'contacts'], () => {
//console.log('forward rendered:', this.container.querySelector('.selector ul').childElementCount); //console.log('forward rendered:', this.container.querySelector('.selector ul').childElementCount);
appSidebarRight.selectTab(AppSidebarRight.SLIDERITEMSIDS.forward);
// !!!!!!!!!! UNCOMMENT BELOW IF NEED TO USE THIS CLASS
////////////////////////////////////////appSidebarRight.selectTab(AppSidebarRight.SLIDERITEMSIDS.forward);
appSidebarRight.toggleSidebar(true).then(() => { appSidebarRight.toggleSidebar(true).then(() => {
if(this.selector) { if(this.selector) {
this.selector.checkForTriggers(); this.selector.checkForTriggers();

7
src/index.hbs

@ -587,13 +587,6 @@
</div> </div>
<div class="chats-container"></div> <div class="chats-container"></div>
</div> </div>
<div class="sidebar-slider-item" id="forward-container">
<div class="sidebar-header">
<button class="btn-icon tgico-close sidebar-close-button"></button>
<div class="sidebar-header__title">Forward</div>
</div>
<button class="btn-primary btn-circle btn-icon rp btn-corner tgico-send"></button>
</div>
<div class="sidebar-slider-item chats-container" id="stickers-container"> <div class="sidebar-slider-item chats-container" id="stickers-container">
<div class="sidebar-header"> <div class="sidebar-header">
<button class="btn-icon tgico-close sidebar-close-button"></button> <button class="btn-icon tgico-close sidebar-close-button"></button>

4
src/lib/appManagers/appDialogsManager.ts

@ -686,7 +686,7 @@ export class AppDialogsManager {
} }
if(found) { if(found) {
entities.sort((a: any, b: any) => a.offset - b.offset); entities.sort((a, b) => a.offset - b.offset);
} }
let messageWrapped = RichTextProcessor.wrapRichText(messageText, { let messageWrapped = RichTextProcessor.wrapRichText(messageText, {
@ -717,7 +717,7 @@ export class AppDialogsManager {
} }
//senderBold.innerText = str + ': '; //senderBold.innerText = str + ': ';
senderBold.innerHTML = RichTextProcessor.wrapRichText(str, {noLinebreaks: true}) + ': '; senderBold.innerHTML = RichTextProcessor.wrapRichText(str, {noLinebreaks: true, noLinks: true}) + ': ';
//console.log(sender, senderBold.innerText); //console.log(sender, senderBold.innerText);
dom.lastMessageSpan.prepend(senderBold); dom.lastMessageSpan.prepend(senderBold);
} //////// else console.log('no sender', lastMessage, peerID); } //////// else console.log('no sender', lastMessage, peerID);

11
src/lib/appManagers/appImManager.ts

@ -17,6 +17,7 @@ import { horizontalMenu } from '../../components/horizontalMenu';
import LazyLoadQueue from '../../components/lazyLoadQueue'; import LazyLoadQueue from '../../components/lazyLoadQueue';
import { formatPhoneNumber, parseMenuButtonsTo } from '../../components/misc'; import { formatPhoneNumber, parseMenuButtonsTo } from '../../components/misc';
import PopupDatePicker from '../../components/popupDatepicker'; import PopupDatePicker from '../../components/popupDatepicker';
import PopupForward from '../../components/popupForward';
import PopupStickers from '../../components/popupStickers'; import PopupStickers from '../../components/popupStickers';
import ProgressivePreloader from '../../components/preloader'; import ProgressivePreloader from '../../components/preloader';
import { ripple } from '../../components/ripple'; import { ripple } from '../../components/ripple';
@ -542,7 +543,8 @@ export class AppImManager {
return; return;
} else if(target.classList.contains('forward')) { } else if(target.classList.contains('forward')) {
const mid = +bubble.dataset.mid; const mid = +bubble.dataset.mid;
appSidebarRight.forwardTab.open([mid]); new PopupForward([mid]);
//appSidebarRight.forwardTab.open([mid]);
return; return;
} else if(target.classList.contains('name')) { } else if(target.classList.contains('name')) {
let peerID = +target.dataset.peerID; let peerID = +target.dataset.peerID;
@ -642,8 +644,10 @@ export class AppImManager {
if(e.key == 'Escape') { if(e.key == 'Escape') {
/* if(AppMediaViewer.wholeDiv.classList.contains('active')) { /* if(AppMediaViewer.wholeDiv.classList.contains('active')) {
AppMediaViewer.buttons.close.click(); AppMediaViewer.buttons.close.click();
} else */ if(appSidebarRight.historyTabIDs.slice(-1)[0] == AppSidebarRight.SLIDERITEMSIDS.forward) { } else */ /* if(appSidebarRight.historyTabIDs.slice(-1)[0] == AppSidebarRight.SLIDERITEMSIDS.forward) {
appSidebarRight.forwardTab.closeBtn.click(); appSidebarRight.forwardTab.closeBtn.click();
} else */ if(this.chatSelection.isSelecting) {
this.chatSelection.cancelSelection();
} else if(this.chatInputC.replyElements.container.classList.contains('active')) { } else if(this.chatInputC.replyElements.container.classList.contains('active')) {
this.chatInputC.replyElements.cancelBtn.click(); this.chatInputC.replyElements.cancelBtn.click();
} else if(this.peerID != 0) { // hide current dialog } else if(this.peerID != 0) { // hide current dialog
@ -1139,6 +1143,7 @@ export class AppImManager {
this.chatInner.classList.add('disable-hover', 'is-scrolling'); this.chatInner.classList.add('disable-hover', 'is-scrolling');
if(!samePeer) { if(!samePeer) {
this.chatSelection.cleanup();
this.lazyLoadQueue.clear(); this.lazyLoadQueue.clear();
} }
@ -1274,8 +1279,6 @@ export class AppImManager {
let peerID = this.peerID; let peerID = this.peerID;
this.peerChanged = true; this.peerChanged = true;
this.chatSelection.cleanup();
this.avatarEl.setAttribute('peer', '' + this.peerID); this.avatarEl.setAttribute('peer', '' + this.peerID);
this.avatarEl.update(); this.avatarEl.update();

1199
src/lib/appManagers/appMediaViewer_old.ts

File diff suppressed because it is too large Load Diff

4
src/lib/appManagers/appMessagesManager.ts

@ -2268,7 +2268,9 @@ export class AppMessagesManager {
message.savedFrom = savedFromPeerID + '_' + savedFromMid; message.savedFrom = savedFromPeerID + '_' + savedFromMid;
} }
message.fromID = appPeersManager.getPeerID(deepEqual(message.from_id, fwdHeader.from_id) ? fwdHeader.from_id : message.from_id); if(peerID < 0 || peerID == myID) {
message.fromID = appPeersManager.getPeerID(!message.from_id || deepEqual(message.from_id, fwdHeader.from_id) ? fwdHeader.from_id : message.from_id);
}
/* } else { /* } else {
apiMessage.fwdPostID = fwdHeader.channel_post; apiMessage.fwdPostID = fwdHeader.channel_post;
} */ } */

4
src/lib/appManagers/appPollsManager.ts

@ -1,5 +1,5 @@
import { InputMedia } from "../../layer"; import { InputMedia } from "../../layer";
import { logger } from "../logger"; import { logger, LogLevels } from "../logger";
import apiManager from "../mtproto/mtprotoworker"; import apiManager from "../mtproto/mtprotoworker";
import { MOUNT_CLASS_TO } from "../mtproto/mtproto_config"; import { MOUNT_CLASS_TO } from "../mtproto/mtproto_config";
import { RichTextProcessor } from "../richtextprocessor"; import { RichTextProcessor } from "../richtextprocessor";
@ -74,7 +74,7 @@ class AppPollsManager {
public polls: {[id: string]: Poll} = {}; public polls: {[id: string]: Poll} = {};
public results: {[id: string]: PollResults} = {}; public results: {[id: string]: PollResults} = {};
private log = logger('POLLS'/* , LogLevels.error */); private log = logger('POLLS', LogLevels.error);
constructor() { constructor() {
$rootScope.$on('apiUpdate', (e) => { $rootScope.$on('apiUpdate', (e) => {

14
src/lib/utils.ts

@ -593,4 +593,18 @@ export function defineNotNumerableProperties(obj: {[key: string]: any}, names: s
//console.log('defineNotNumerableProperties time:', performance.now() - perf); //console.log('defineNotNumerableProperties time:', performance.now() - perf);
} }
export function cancelSelection() {
if(window.getSelection) {
if(window.getSelection().empty) { // Chrome
window.getSelection().empty();
} else if(window.getSelection().removeAllRanges) { // Firefox
window.getSelection().removeAllRanges();
}
// @ts-ignore
} else if(document.selection) { // IE?
// @ts-ignore
document.selection.empty();
}
}
//(window as any).splitStringByLength = splitStringByLength; //(window as any).splitStringByLength = splitStringByLength;

10
src/scss/components/_global.scss

@ -109,4 +109,12 @@ Utility Classes
left: 50%; left: 50%;
top: 50%; top: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
} }
/* .flex-grow {
flex-grow: 1;
}
.flex-shrink {
flex-shrink: 1;
} */

517
src/scss/partials/_chat.scss

@ -1,6 +1,9 @@
$btn-send-margin: .5625rem; $btn-send-margin: .5625rem;
$chat-input-size: 3rem; $chat-input-size: 3.375rem;
$chat-input-handhelds-size: 2.875rem; $chat-input-handhelds-size: 2.875rem;
$chat-padding: 1rem;
$chat-padding-handhelds: .5rem;
$chat-helper-size: 39px;
#bubble-contextmenu > div { #bubble-contextmenu > div {
padding: 0 5.25 0 1rem; padding: 0 5.25 0 1rem;
@ -250,26 +253,26 @@ $chat-input-handhelds-size: 2.875rem;
max-width: var(--messages-container-width); max-width: var(--messages-container-width);
margin: 0 auto; margin: 0 auto;
width: 100%; width: 100%;
padding: 0 .5rem; padding: 0 $chat-padding-handhelds;
flex: 0 0 auto; flex: 0 0 auto;
position: relative; position: relative;
@include respond-to(not-handhelds) { @include respond-to(not-handhelds) {
padding-left: 1rem; padding-left: $chat-padding;
padding-right: 1rem; padding-right: $chat-padding;
padding-bottom: 21px; padding-bottom: 21px;
} }
@include respond-to(handhelds) { @include respond-to(handhelds) {
padding-bottom: .5rem; padding-bottom: $chat-padding-handhelds;
} }
@include respond-to(esg-bottom) { @include respond-to(esg-bottom) {
padding-bottom: .5rem; padding-bottom: $chat-padding-handhelds;
.btn-circle { .btn-circle {
height: 46px; height: $chat-input-handhelds-size;
width: 46px; width: $chat-input-handhelds-size;
} }
} }
} }
@ -428,7 +431,7 @@ $chat-input-handhelds-size: 2.875rem;
} }
.input-message { .input-message {
width: calc(100% - #{$chat-input-size * 2 + $btn-send-margin * 3 + $btn-send-margin / 2}); width: calc(100% - #{$chat-input-size * 2 + $btn-send-margin * 2});
@include respond-to(handhelds) { @include respond-to(handhelds) {
width: calc(100% - #{$chat-input-handhelds-size * 2 + $btn-send-margin * 2}); width: calc(100% - #{$chat-input-handhelds-size * 2 + $btn-send-margin * 2});
@ -455,6 +458,101 @@ $chat-input-handhelds-size: 2.875rem;
width: 0px; width: 0px;
} }
} }
#bubbles.is-selecting ~ & {
.new-message-wrapper {
transition: .1s opacity;
}
.selection-container {
opacity: 0;
}
#btn-send {
transition: .2s transform;
}
.input-message {
html:not(.is-safari) & {
transition: width .2s, border-bottom-right-radius .1s, transform .2s;
}
html.is-safari & {
transition: none;
}
//will-change: transform;
&:after {
transition: transform .1s;
}
}
}
#bubbles.is-selecting:not(.backwards) ~ & {
.new-message-wrapper {
opacity: 0;
}
.selection-container {
animation: fade-in-opacity .1s .1s forwards;
}
.input-message {
max-height: $chat-input-size;
border-bottom-right-radius: 12px;
transform-origin: left;
width: 28.75rem;
transform: translate3d(25%, 0, 0);
//transform: translate3d(#{calc(28.75rem / 4)}, 0, 0);
/* html.is-safari & {
max-width: 28.75rem;
} */
/* transform: translateX(-50%);
left: 50%;
position: absolute; */
// left sidebar (420px) + 728px chat max width
@media only screen and (min-width: $floating-left-sidebar + 1) and (max-width: $large-screen / 4 + $messages-container-width) {
//transform: translateX(calc((100vw - 420px - 100%) / 2 - #{$chat-padding}));
transform: translate3d(calc((100vw - min(100vw / 2.5, #{$large-screen / 4}) - 100%) / 2 - #{$chat-padding}), 0, 0);
}
@media only screen and (max-width: 728px) {
//transform: translateX(calc((100vw - 420px - 100%) / 2 - #{$chat-padding}));
transform: translate3d(calc((100vw - 100%) / 2 - #{$chat-padding}), 0, 0);
}
@include respond-to(handhelds) {
transform: translate3d(calc((100vw - 100%) / 2 - #{$chat-padding-handhelds}), 0, 0);
}
&:after {
transform: scaleX(-1) translateX(#{.5625rem * 2});
}
}
.reply-wrapper {
transform: none !important;
border-radius: inherit;
}
#btn-send {
transform: scale(0);
}
}
#bubbles.is-selecting.backwards ~ & {
.new-message-wrapper {
transition-delay: .1s;
}
.selection-container {
animation: fade-in-backwards-opacity .1s forwards;
}
}
} }
@keyframes recordBlink { @keyframes recordBlink {
@ -557,138 +655,6 @@ $chat-input-handhelds-size: 2.875rem;
} }
} }
} }
#chat-background-canvas {
display: none;
}
.input-message {
display: flex;
align-items: center;
flex-direction: column;
width: calc(100% - #{$chat-input-size + $btn-send-margin + $btn-send-margin / 2});
justify-content: center;
background-color: #fff;
border-radius: 12px;
border-bottom-right-radius: 0;
box-shadow: 0 1px 2px 0 rgba(16, 35, 47, .07);
padding: 4.5px .5rem;
/* padding: 3px .5rem 6px .5rem; */
min-height: $chat-input-size;
max-height: 30rem;
caret-color: $button-primary-background;
flex: 0 0 auto;
position: relative;
z-index: 3;
transition: width .1s;
@include respond-to(handhelds) {
width: calc(100% - #{$chat-input-handhelds-size + $btn-send-margin});
min-height: $chat-input-handhelds-size;
padding: .5px .5rem;
}
@include respond-to(esg-bottom) {
min-height: $chat-input-handhelds-size;
padding: .5px .5rem;
}
&:after {
content: '';
position: absolute;
bottom: -.1875rem;
right: -8.4px;
width: .5625rem;
height: 1.25rem;
background-repeat: no-repeat no-repeat;
background-position: 0 100%;
background-image: url('assets/img/msg-tail-left-blur.svg');
transform: scaleX(-1);
}
#attach-file {
&.menu-open {
color: $color-blue;
background-color: transparent;
}
.btn-menu {
padding: 8px 0;
right: -8px;
bottom: calc(100% + 16px);
> div {
padding: 0 38px 0 16px;
}
}
}
> div {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
//min-height: inherit;
}
.reply-wrapper {
justify-content: flex-start;
overflow: hidden;
transition: .2s all;
height: 0px;
&.active {
height: 39px;
}
.reply {
width: 100%;
margin-left: .5rem;
min-height: 35px;
}
}
.new-message-wrapper {
//padding: 4.5px 0;
//padding-bottom: 4.5px;
align-items: flex-end;
.btn-icon:before {
vertical-align: bottom;
}
}
.input-message-container {
width: 1%;
max-height: inherit;
flex: 1 1 auto;
position: relative;
overflow: hidden;
> .scrollable {
position: relative;
}
}
.btn-icon {
display: block;
flex: 0 0 auto;
font-size: 24px;
line-height: 24px;
color: #8d969c;
margin-bottom: 1px;
&.active {
color: $color-blue;
}
}
.emoji {
font-size: 24px;
height: 24px;
width: 24px;
}
}
@include respond-to(handhelds) { @include respond-to(handhelds) {
.pinned-message { .pinned-message {
@ -910,76 +876,207 @@ $chat-input-handhelds-size: 2.875rem;
max-width: 240px; max-width: 240px;
} }
} }
}
/* #chat-closed {
.input-message {
--padding: .3125rem .5rem;
display: flex;
align-items: center;
flex-direction: column;
width: calc(100% - #{$chat-input-size + $btn-send-margin});
max-width: 100%;
justify-content: center;
background-color: #fff;
border-radius: 12px;
border-bottom-right-radius: 0;
box-shadow: 0 1px 2px 0 rgba(16, 35, 47, .07);
min-height: $chat-input-size;
max-height: 30rem;
caret-color: $button-primary-background;
flex: 0 0 auto;
position: relative;
z-index: 3;
transition: width .1s;
// ! Need due to reply transform under the container
&:before {
position: absolute; position: absolute;
z-index: 2;
left: 0; left: 0;
top: 0; top: 0;
width: 100%; bottom: 0;
height: 100%; right: 0;
background-color: inherit; background: inherit;
z-index: 3; content: " ";
display: block;
border-radius: inherit;
}
/* #chat-input.is-helper-active & {
border-top-left-radius: 0;
border-top-right-radius: 0;
} */
@include respond-to(handhelds) {
--padding: .5px .5rem;
width: calc(100% - #{$chat-input-handhelds-size + $btn-send-margin});
min-height: $chat-input-handhelds-size;
}
@include respond-to(esg-bottom) {
--padding: .5px .5rem;
min-height: $chat-input-handhelds-size;
}
&:after {
content: '';
position: absolute;
bottom: -.1875rem;
right: -8.4px;
width: .5625rem;
height: 1.25rem;
background-repeat: no-repeat no-repeat;
background-position: 0 100%;
background-image: url('assets/img/msg-tail-left-blur.svg');
transform: scaleX(-1);
}
#attach-file {
&.menu-open {
color: $color-blue;
background-color: transparent;
}
.btn-menu {
padding: 8px 0;
right: -8px;
bottom: calc(100% + 16px);
> div {
padding: 0 38px 0 16px;
}
}
}
> div {
display: flex; display: flex;
justify-content: space-between;
align-items: center; align-items: center;
justify-content: center; width: 100%;
flex-direction: column; position: relative;
z-index: 2;
background-color: inherit;
border-radius: 12px;
padding: var(--padding);
}
.reply-wrapper {
justify-content: flex-start;
overflow: hidden;
transition: transform var(--layer-transition), border-radius var(--layer-transition);
position: absolute;
left: 0;
top: 0;
//height: calc(#{$chat-helper-size} + .3125rem);
height: 100%;
align-items: flex-start;
z-index: 1;
user-select: none;
.chat-container.is-helper-active & {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
transform: translateY(#{-$chat-helper-size});
}
/* &.active {
height: 39px;
} */
.tgico-chatsplaceholder { .reply {
font-size: 10rem; width: 100%;
color: #ABB0B3; margin-left: .5rem;
min-height: 35px;
} }
}
.new-message-wrapper {
//padding: 4.5px 0;
//padding-bottom: 4.5px;
align-items: flex-end;
h3 { .btn-icon:before {
font-size: 2rem; vertical-align: bottom;
color: #707579;
text-align: center;
} }
}
.input-message-container {
width: 1%;
max-height: inherit;
flex: 1 1 auto;
position: relative;
overflow: hidden;
> .scrollable {
position: relative;
}
}
.selection-container {
position: absolute;
left: 0;
top: 0;
height: 100%;
//background-color: #ccc;
border-radius: inherit;
padding: inherit;
user-select: none;
&-count {
color: #000;
font-weight: 500;
flex-grow: 1;
padding-left: .5rem;
}
.btn-primary {
height: 2.5rem;
width: 7.5rem;
}
.btn-primary + .btn-primary {
margin-left: .75rem;
}
}
.btn-icon {
display: block;
flex: 0 0 auto;
font-size: 24px;
line-height: 24px;
color: #8d969c;
//margin-bottom: 1px;
// ! EXPERIMENTAL
margin: 0 3px 4px;
padding: 0.25rem;
width: 34px;
height: 34px;
.buttons { &.active {
display: flex; color: $color-blue;
justify-content: center;
align-items: center;
margin-top: 1rem;
button {
margin: 0 2.5rem;
width: 4rem;
height: 4rem;
background: #fff;
border: none;
position: relative;
font-size: 2rem;
color: #707579;
cursor: pointer;
box-shadow: 0 1px 2px 0 rgba(16, 35, 47, 0.07);
&:hover {
background: #4EA4F6;
color: #fff;
span {
color: #4EA4F6;
}
}
span {
position: absolute;
top: 100%;
left: 50%;
width: 100%;
padding-top: 1rem;
transform: translateX(-50%);
font-size: .9rem;
font-family: "Roboto";
}
}
} }
} */ }
.emoji {
font-size: 24px;
height: 24px;
width: 24px;
}
} }
#bubbles { #bubbles {
--translateY: 0;
/* overflow-y: scroll; /* overflow-y: scroll;
scrollbar-width: none; scrollbar-width: none;
-ms-overflow-style: none; */ -ms-overflow-style: none; */
@ -989,17 +1086,25 @@ $chat-input-handhelds-size: 2.875rem;
flex: 1 1 auto; /* Lets middle column shrink/grow to available width */ flex: 1 1 auto; /* Lets middle column shrink/grow to available width */
//overflow: hidden; //overflow: hidden;
position: relative; position: relative;
transform: translateY(var(--translateY));
transition: transform var(--layer-transition);
/* html.is-safari & > .scrollable { /* html.is-safari & > .scrollable {
-webkit-mask-image: -webkit-radial-gradient(circle, white 100%, black 100%); // fix safari overflow -webkit-mask-image: -webkit-radial-gradient(circle, white 100%, black 100%); // fix safari overflow
} */ } */
.chat-container.is-helper-active & {
&:not(.is-selecting), &.is-selecting.backwards {
--translateY: -#{$chat-helper-size};
}
}
// ! WARNING, НЕЛЬЗЯ СТАВИТЬ ТРАНСФОРМ КРОМЕ TRANSLATEZ(0) НА БЛОК С OVERFLOW, ОН БУДЕТ ПРЫГАТЬ ВВЕРХ ПРИ ВКЛЮЧЕННОМ ПРАВИЛЕ И ЭТО НЕ ИСПРАВИТЬ JS'ОМ! // ! WARNING, НЕЛЬЗЯ СТАВИТЬ ТРАНСФОРМ КРОМЕ TRANSLATEZ(0) НА БЛОК С OVERFLOW, ОН БУДЕТ ПРЫГАТЬ ВВЕРХ ПРИ ВКЛЮЧЕННОМ ПРАВИЛЕ И ЭТО НЕ ИСПРАВИТЬ JS'ОМ!
@include respond-to(medium-screens) { @include respond-to(medium-screens) {
transition: transform var(--layer-transition); //transition: transform var(--layer-transition);
body.is-right-column-shown & { body.is-right-column-shown & {
transform: translate3d(calc(var(--right-column-width) / -2), 0, 0); transform: translate3d(calc(var(--right-column-width) / -2), var(--translateY), 0);
} }
body.animation-level-0 & { body.animation-level-0 & {
@ -1011,14 +1116,22 @@ $chat-input-handhelds-size: 2.875rem;
cursor: default !important; cursor: default !important;
user-select: none; user-select: none;
.is-in .bubble__container { &:not(.backwards) .is-in .bubble__container {
transform: translateX(2.5rem); transform: translateX(2.5rem);
} }
// ! this animation will slow down chat input's animation due to count of elements
/* &.animating:not(.backwards) {
.checkbox-field-round {
opacity: 0;
animation: fade-in-opacity .1s .1s forwards;
}
} */
} }
&.is-selecting > .scrollable::-webkit-scrollbar { /* &.is-selecting > .scrollable::-webkit-scrollbar {
display: none; display: none;
} } */
> .scrollable { > .scrollable {
height: auto; height: auto;

8
src/scss/partials/_chatBubble.scss

@ -159,17 +159,17 @@ $bubble-margin: .25rem;
&-select-checkbox { &-select-checkbox {
z-index: 2; z-index: 2;
position: absolute; position: absolute;
left: 0; /* left: 0;
//bottom: .25rem; // * by avatar bottom: .75rem; // * by avatar */
left: 0; left: 0;
top: 50%; top: 50%;
transform: translateY(-50%); transform: translateY(-50%);
display: flex; display: flex;
[type="checkbox"] { [type="checkbox"] {
&:not(:checked) + .checkbox-caption:after { /* &:not(:checked) + .checkbox-caption:after {
} } */
&:checked + .checkbox-caption { &:checked + .checkbox-caption {
&:after { &:after {

275
src/scss/partials/_fonts.scss

@ -1,3 +1,5 @@
// ! https://icomoon.io/app/#/select
@font-face { @font-face {
font-family: "#{$tgico-font-family}"; font-family: "#{$tgico-font-family}";
src: url("#{$tgico-font-path}/#{$tgico-font-family}.eot?owpifk"); src: url("#{$tgico-font-path}/#{$tgico-font-family}.eot?owpifk");
@ -32,339 +34,348 @@
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
.tgico-check:before { .tgico-select:before {
content: $tgico-check; content: "\e900";
} }
.tgico-checks:before { .tgico-info2:before {
content: $tgico-checks; content: "\e901";
} }
.tgico-activesessions:before { .tgico-clouddownload:before {
content: "\e902"; content: "\e902";
} }
.tgico-add:before { .tgico-readchats:before {
content: "\e903"; content: "\e903";
} }
.tgico-addmember_filled:before { .tgico-noncontacts:before {
content: "\e904"; content: "\e904";
} }
.tgico-adduser:before { .tgico-bots:before {
content: "\e905"; content: "\e905";
} }
.tgico-admin:before { .tgico-muted:before {
content: "\e906"; content: "\e906";
} }
.tgico-animals:before { .tgico-favourites:before {
content: "\e907"; content: "\e907";
} }
.tgico-archive:before { .tgico-tip:before {
content: $tgico-archive; content: "\e908";
} }
.tgico-attach:before { .tgico-loginlogodesktop:before {
content: "\e909"; content: "\e909";
} }
.tgico-avatar_archivedchats:before { .tgico-loginlogomobile:before {
content: "\e90a"; content: "\e90a";
} }
.tgico-avatar_deletedaccount:before { .tgico-calendar:before {
content: "\e90b"; content: "\e90b";
} }
.tgico-avatar_savedmessages:before { .tgico-keyboard:before {
content: "\e90c"; content: "\e90c";
} }
.tgico-back:before { .tgico-gifs:before {
content: $tgico-back; content: "\e90d";
} }
.tgico-bots:before { .tgico-stickers:before {
content: "\e90e"; content: "\e90e";
} }
.tgico-calendar:before { .tgico-deleteleft:before {
content: "\e90f"; content: "\e90f";
} }
.tgico-camera:before { .tgico-folder:before {
content: "\e910"; content: "\e910";
} }
.tgico-cameraadd:before { .tgico-revote:before {
content: "\e911"; content: "\e911";
} }
.tgico-car:before { .tgico-livelocation:before {
content: "\e912"; content: "\e912";
} }
.tgico-channel:before { .tgico-microphone2:before {
content: "\e913"; content: "\e913";
} }
.tgico-channelviews:before { .tgico-colorize:before {
content: "\e914"; content: "\e914";
} }
.tgico-chatsplaceholder:before { .tgico-poll:before {
content: "\e915"; content: "\e915";
} }
.tgico-check1:before { .tgico-minus:before {
content: "\e916"; content: "\e916";
} }
.tgico-checkbox:before { .tgico-nosound:before {
content: "\e917"; content: "\e917";
} }
.tgico-checkboxblock:before { .tgico-microphone:before {
content: "\e918"; content: "\e918";
} }
.tgico-checkboxempty:before { .tgico-largeplay:before {
content: "\e919"; content: "\e919";
} }
.tgico-checkboxon:before { .tgico-largepause:before {
content: "\e91a"; content: "\e91a";
} }
.tgico-close:before { .tgico-newchannel:before {
content: $tgico-close; content: "\e91b";
} }
.tgico-clouddownload:before { .tgico-newgroup:before {
content: "\e91c"; content: "\e91c";
} }
.tgico-colorize:before { .tgico-newprivate:before {
content: "\e91d"; content: "\e91d";
} }
.tgico-copy:before { .tgico-chatsplaceholder:before {
content: "\e91e"; content: "\e91e";
} }
.tgico-data:before { .tgico-newchat_filled:before {
content: "\e91f"; content: "\e91f";
} }
.tgico-delete:before { .tgico-addmember_filled:before {
content: "\e920"; content: "\e920";
} }
.tgico-delete_filled:before { .tgico-delete:before {
content: "\e921"; content: "\e921";
} }
.tgico-deleteleft:before { .tgico-delete_filled:before {
content: "\e922"; content: "\e922";
} }
.tgico-deleteuser:before { .tgico-send2:before {
content: "\e923"; content: "\e923";
} }
.tgico-document:before { .tgico-avatar_deletedaccount:before {
content: "\e924"; content: "\e924";
} }
.tgico-down:before { .tgico-avatar_archivedchats:before {
content: "\e925"; content: "\e925";
} }
.tgico-download:before { .tgico-avatar_savedmessages:before {
content: "\e926"; content: "\e926";
} }
.tgico-eats:before { .tgico-pinnedchat:before {
content: "\e927"; content: "\e927";
} }
.tgico-edit:before { .tgico-channelviews:before {
content: "\e928"; content: "\e928";
} }
.tgico-eye1:before { .tgico-sendingerror:before {
content: "\e929"; content: "\e929";
} }
.tgico-eye2:before { .tgico-sending:before {
content: "\e92a"; content: "\e92a";
} }
.tgico-favourites:before { .tgico-check:before {
content: "\e92b"; content: "\e92b";
} }
.tgico-flag:before { .tgico-checks:before {
content: "\e92c"; content: "\e92c";
} }
.tgico-folder:before { .tgico-radioon:before {
content: "\e92d"; content: "\e92d";
} }
.tgico-forward:before { .tgico-radiooff:before {
content: "\e92e"; content: "\e92e";
} }
.tgico-fullscreen:before { .tgico-checkboxempty:before {
content: "\e92f"; content: "\e92f";
} }
.tgico-gifs:before { .tgico-checkboxblock:before {
content: "\e930"; content: "\e930";
} }
.tgico-group:before { .tgico-checkboxon:before {
content: "\e931"; content: "\e931";
} }
.tgico-help:before { .tgico-eye2:before {
content: "\e932"; content: "\e932";
} }
.tgico-info:before { .tgico-eye1:before {
content: "\e933"; content: "\e933";
} }
.tgico-info2:before { .tgico-FullScreen:before {
content: $tgico-info2; content: "\e934";
} }
.tgico-keyboard:before { .tgico-smallscreen:before {
content: $tgico-keyboard; content: "\e935";
} }
.tgico-lamp:before { .tgico-flag:before {
content: "\e936"; content: "\e936";
} }
.tgico-language:before { .tgico-lamp:before {
content: "\e937"; content: "\e937";
} }
.tgico-largepause:before { .tgico-sport:before {
content: $tgico-largepause; content: "\e938";
} }
.tgico-largeplay:before { .tgico-car:before {
content: $tgico-largeplay; content: "\e939";
} }
.tgico-livelocation:before { .tgico-eats:before {
content: "\e93a"; content: "\e93a";
} }
.tgico-location:before { .tgico-animals:before {
content: "\e93b"; content: "\e93b";
} }
.tgico-lock:before { .tgico-smile:before {
content: "\e93c"; content: "\e93c";
} }
.tgico-logout:before { .tgico-unpin:before {
content: "\e93d"; content: "\e93d";
} }
.tgico-menu:before { .tgico-send:before {
content: "\e93e"; content: "\e93e";
} }
.tgico-message:before { .tgico-unread:before {
content: "\e93f"; content: "\e93f";
} }
.tgico-microphone:before { .tgico-settings:before {
content: "\e940"; content: "\e940";
} }
.tgico-microphone2:before { .tgico-edit:before {
content: "\e941"; content: "\e941";
} }
.tgico-minus:before { .tgico-download:before {
content: "\e942"; content: "\e942";
} }
.tgico-more:before { .tgico-cameraadd:before {
content: "\e943"; content: "\e943";
} }
.tgico-mute:before { .tgico-camera:before {
content: $tgico-mute; content: "\e944";
} }
.tgico-muted:before { .tgico-permissions:before {
content: "\e945"; content: "\e945";
} }
.tgico-newchannel:before { .tgico-admin:before {
content: "\e946"; content: "\e946";
} }
.tgico-newchat_filled:before { .tgico-stop:before {
content: "\e947"; content: "\e947";
} }
.tgico-newgroup:before { .tgico-username:before {
content: "\e948"; content: "\e948";
} }
.tgico-newprivate:before { .tgico-location:before {
content: "\e949"; content: "\e949";
} }
.tgico-next:before { .tgico-info:before {
content: $tgico-next; content: "\e94a";
} }
.tgico-noncontacts:before { .tgico-deleteuser:before {
content: "\e94b"; content: "\e94b";
} }
.tgico-nosound:before { .tgico-adduser:before {
content: $tgico-nosound; content: "\e94c";
} }
.tgico-pause:before { .tgico-recent:before {
content: $tgico-pause; content: "\e94d";
} }
.tgico-permissions:before { .tgico-channel:before {
content: "\e94e"; content: "\e94e";
} }
.tgico-phone:before { .tgico-document:before {
content: "\e94f"; content: "\e94f";
} }
.tgico-photo:before { .tgico-activesessions:before {
content: "\e950"; content: "\e950";
} }
.tgico-pin:before { .tgico-logout:before {
content: $tgico-pin; content: "\e951";
} }
.tgico-pinnedchat:before { .tgico-help:before {
content: "\e952"; content: "\e952";
} }
.tgico-play:before { .tgico-play:before {
content: $tgico-play; content: "\e953";
} }
.tgico-poll:before { .tgico-pause:before {
content: "\e954"; content: "\e954";
} }
.tgico-radiooff:before { .tgico-reply:before {
content: "\e955"; content: "\e955";
} }
.tgico-radioon:before { .tgico-forward:before {
content: "\e956"; content: "\e956";
} }
.tgico-readchats:before { .tgico-next:before {
content: $tgico-readchats; content: "\e957";
} }
.tgico-recent:before { .tgico-unlock:before {
content: "\e958"; content: "\e958";
} }
.tgico-reply:before { .tgico-lock:before {
content: "\e959"; content: "\e959";
} }
.tgico-revote:before { .tgico-data:before {
content: "\e95a"; content: "\e95a";
} }
.tgico-savedmessages:before { .tgico-user:before {
content: "\e95b"; content: "\e95b";
} }
.tgico-search:before { .tgico-group:before {
content: "\e95c"; content: "\e95c";
} }
.tgico-send:before { .tgico-mute:before {
content: "\e95d"; content: "\e95d";
} }
.tgico-send2:before { .tgico-unmute:before {
content: "\e95e"; content: "\e95e";
} }
.tgico-sending:before { .tgico-photo:before {
content: $tgico-sending; content: "\e95f";
} }
.tgico-sendingerror:before { .tgico-language:before {
content: "\e960"; content: "\e960";
} }
.tgico-settings:before { .tgico-message:before {
content: "\e961"; content: "\e961";
} }
.tgico-smallscreen:before { .tgico-pin:before {
content: "\e962"; content: "\e962";
} }
.tgico-smile:before { .tgico-attach:before {
content: $tgico-smile; content: "\e963";
} }
.tgico-sport:before { .tgico-phone:before {
content: "\e964"; content: "\e964";
} }
.tgico-stickers:before { .tgico-savedmessages:before {
content: "\e965"; content: "\e965";
} }
.tgico-stop:before { .tgico-checkbox:before {
content: "\e966"; content: "\e966";
} }
.tgico-tip:before { .tgico-copy:before {
content: "\e967"; content: "\e967";
} }
.tgico-unarchive:before { .tgico-unarchive:before {
content: $tgico-unarchive; content: "\e968";
} }
.tgico-unlock:before { .tgico-archive:before {
content: "\e969"; content: "\e969";
} }
.tgico-unmute:before { .tgico-check1:before {
content: $tgico-unmute; content: "\e96a";
} }
.tgico-unpin:before { .tgico-up:before {
content: $tgico-unpin; content: "\e96b";
} }
.tgico-unread:before { .tgico-down:before {
content: $tgico-unread; content: "\e96c";
} }
.tgico-up:before { .tgico-close:before {
content: "\e96d"; content: "\e96d";
} }
.tgico-user:before { .tgico-add:before {
content: "\e96e"; content: "\e96e";
} }
.tgico-username:before { .tgico-back:before {
content: "\e96f"; content: "\e96f";
} }
.tgico-more:before {
content: "\e970";
}
.tgico-menu:before {
content: "\e971";
}
.tgico-search:before {
content: "\e972";
}

146
src/scss/partials/_ico.scss

@ -1,25 +1,129 @@
// ! https://icomoon.io/app/#/select
$tgico-font-family: "tgico" !default; $tgico-font-family: "tgico" !default;
$tgico-font-path: "assets/fonts" !default; $tgico-font-path: "assets/fonts" !default;
$tgico-check: "\e900"; /*
$tgico-checks: "\e901"; ! CAN RUN IN DEVELOPER TOOLS TO CONVERT FONT TO VARIABLES:
$tgico-archive: "\e908"; `.tgico-select:before {
$tgico-back: "\e90d"; content: "\e900";
$tgico-sending: "\e95f"; }`
$tgico-close: "\e91b"; .replace(/([\s])|(_svg)|(1x)/g, '')
$tgico-next: "\e94a"; .replace(/\.(.+?):before\{content:"(.+?);\}/g, `$$$1: "\\$2;\n`);
$tgico-pin: "\e951"; */
$tgico-largepause: "\e938";
$tgico-largeplay: "\e939"; $tgico-select: "\e900";
$tgico-mute: "\e944"; $tgico-info2: "\e901";
$tgico-readchats: "\e957"; $tgico-clouddownload: "\e902";
$tgico-unmute: "\e96a"; $tgico-readchats: "\e903";
$tgico-unread: "\e96c"; $tgico-noncontacts: "\e904";
$tgico-unpin: "\e96b"; $tgico-bots: "\e905";
$tgico-unarchive: "\e968"; $tgico-muted: "\e906";
$tgico-smile: "\e963"; $tgico-favourites: "\e907";
$tgico-info2: "\e934"; $tgico-tip: "\e908";
$tgico-keyboard: "\e935"; $tgico-loginlogodesktop: "\e909";
$tgico-loginlogomobile: "\e90a";
$tgico-calendar: "\e90b";
$tgico-keyboard: "\e90c";
$tgico-gifs: "\e90d";
$tgico-stickers: "\e90e";
$tgico-deleteleft: "\e90f";
$tgico-folder: "\e910";
$tgico-revote: "\e911";
$tgico-livelocation: "\e912";
$tgico-microphone2: "\e913";
$tgico-colorize: "\e914";
$tgico-poll: "\e915";
$tgico-minus: "\e916";
$tgico-nosound: "\e917";
$tgico-microphone: "\e918";
$tgico-largeplay: "\e919";
$tgico-largepause: "\e91a";
$tgico-newchannel: "\e91b";
$tgico-newgroup: "\e91c";
$tgico-newprivate: "\e91d";
$tgico-chatsplaceholder: "\e91e";
$tgico-newchat_filled: "\e91f";
$tgico-addmember_filled: "\e920";
$tgico-delete: "\e921";
$tgico-delete_filled: "\e922";
$tgico-send2: "\e923";
$tgico-avatar_deletedaccount: "\e924";
$tgico-avatar_archivedchats: "\e925";
$tgico-avatar_savedmessages: "\e926";
$tgico-pinnedchat: "\e927";
$tgico-channelviews: "\e928";
$tgico-sendingerror: "\e929";
$tgico-sending: "\e92a";
$tgico-check: "\e92b";
$tgico-checks: "\e92c";
$tgico-radioon: "\e92d";
$tgico-radiooff: "\e92e";
$tgico-checkboxempty: "\e92f";
$tgico-checkboxblock: "\e930";
$tgico-checkboxon: "\e931";
$tgico-eye2: "\e932";
$tgico-eye1: "\e933";
$tgico-FullScreen: "\e934";
$tgico-smallscreen: "\e935";
$tgico-flag: "\e936";
$tgico-lamp: "\e937";
$tgico-sport: "\e938";
$tgico-car: "\e939";
$tgico-eats: "\e93a";
$tgico-animals: "\e93b";
$tgico-smile: "\e93c";
$tgico-unpin: "\e93d";
$tgico-send: "\e93e";
$tgico-unread: "\e93f";
$tgico-settings: "\e940";
$tgico-edit: "\e941";
$tgico-download: "\e942";
$tgico-cameraadd: "\e943";
$tgico-camera: "\e944";
$tgico-permissions: "\e945";
$tgico-admin: "\e946";
$tgico-stop: "\e947";
$tgico-username: "\e948";
$tgico-location: "\e949";
$tgico-info: "\e94a";
$tgico-deleteuser: "\e94b";
$tgico-adduser: "\e94c";
$tgico-recent: "\e94d";
$tgico-channel: "\e94e";
$tgico-document: "\e94f";
$tgico-activesessions: "\e950";
$tgico-logout: "\e951";
$tgico-help: "\e952";
$tgico-play: "\e953"; $tgico-play: "\e953";
$tgico-pause: "\e94d"; $tgico-pause: "\e954";
$tgico-nosound: "\e94c"; $tgico-reply: "\e955";
$tgico-forward: "\e956";
$tgico-next: "\e957";
$tgico-unlock: "\e958";
$tgico-lock: "\e959";
$tgico-data: "\e95a";
$tgico-user: "\e95b";
$tgico-group: "\e95c";
$tgico-mute: "\e95d";
$tgico-unmute: "\e95e";
$tgico-photo: "\e95f";
$tgico-language: "\e960";
$tgico-message: "\e961";
$tgico-pin: "\e962";
$tgico-attach: "\e963";
$tgico-phone: "\e964";
$tgico-savedmessages: "\e965";
$tgico-checkbox: "\e966";
$tgico-copy: "\e967";
$tgico-unarchive: "\e968";
$tgico-archive: "\e969";
$tgico-check1: "\e96a";
$tgico-up: "\e96b";
$tgico-down: "\e96c";
$tgico-close: "\e96d";
$tgico-add: "\e96e";
$tgico-back: "\e96f";
$tgico-more: "\e970";
$tgico-menu: "\e971";
$tgico-search: "\e972";

8
src/scss/partials/_rightSidebar.scss

@ -34,9 +34,9 @@
border-left: 1px solid #DADCE0; border-left: 1px solid #DADCE0;
} }
body.is-forward-active & { /* body.is-forward-active & {
z-index: 4; z-index: 4;
} } */
.sidebar-header { .sidebar-header {
flex: 0 0 auto; flex: 0 0 auto;
@ -61,9 +61,9 @@
} }
} }
#forward-container { /* #forward-container {
z-index: 5; z-index: 5;
} } */
.sidebar-search { .sidebar-search {
display: none; display: none;

8
src/scss/partials/_selector.scss

@ -35,12 +35,16 @@
display: flex; display: flex;
flex-flow: wrap; flex-flow: wrap;
input { &-input {
border: none; border: none;
padding: 7px 0px 19px 0px;
outline: none; outline: none;
flex: 1 1 auto; flex: 1 1 auto;
} }
// ! only in this container need this padding
.selector-search-input {
padding: 7px 0px 19px 0px;
}
} }
&-user { &-user {

44
src/scss/partials/popups/_forward.scss

@ -0,0 +1,44 @@
.popup-forward {
$parent: ".popup";
#{$parent} {
&-container {
width: 420px;
max-width: 420px;
//padding: 12px 20px 32.5px;
padding: .75rem 0 0 0;
max-height: unquote('min(40.625rem, 100%)');
height: 40.625rem;
}
&-header {
flex: 0 0 auto;
margin-bottom: 9px;
padding: 0 .75rem;
}
&-title {
flex-grow: 1;
}
}
.selector, .chats-container {
height: auto;
overflow: hidden;
display: flex;
width: 100%;
flex-direction: row;
}
.selector {
&-search-input {
font-size: 1.25rem;
padding: .5rem 1.5rem;
width: 100%;
}
/* ul li > .rp {
margin-left: 0;
} */
}
}

36
src/scss/style.scss

@ -24,6 +24,7 @@ $large-screen: 1680px;
//$large-screen: 16800px; //$large-screen: 16800px;
$floating-left-sidebar: 925px; $floating-left-sidebar: 925px;
$messages-container-width: 728px;
@mixin respond-to($media) { @mixin respond-to($media) {
@if $media == handhelds { @if $media == handhelds {
@ -82,7 +83,7 @@ $floating-left-sidebar: 925px;
--message-handhelds-margin: 5.5625rem; --message-handhelds-margin: 5.5625rem;
--message-beside-button-margin: 2.875rem; --message-beside-button-margin: 2.875rem;
--message-time-background: rgba(0, 0, 0, .35); --message-time-background: rgba(0, 0, 0, .35);
--messages-container-width: 728px; --messages-container-width: #{$messages-container-width};
--esg-sticker-size: 80px; --esg-sticker-size: 80px;
@include respond-to(handhelds) { @include respond-to(handhelds) {
@ -127,6 +128,7 @@ $floating-left-sidebar: 925px;
@import "partials/popups/stickers"; @import "partials/popups/stickers";
@import "partials/popups/datePicker"; @import "partials/popups/datePicker";
@import "partials/popups/createPoll"; @import "partials/popups/createPoll";
@import "partials/popups/forward";
@import "partials/pages/pages"; @import "partials/pages/pages";
@import "partials/pages/authCode"; @import "partials/pages/authCode";
@ -290,7 +292,7 @@ input {
input, textarea { input, textarea {
-webkit-appearance: none; -webkit-appearance: none;
} }
.subtitle { .subtitle {
/* font-weight: 500; */ /* font-weight: 500; */
@ -354,7 +356,7 @@ input, textarea {
} }
} }
.danger { .danger, .danger:before {
color: $color-error!important; color: $color-error!important;
} }
@ -437,10 +439,6 @@ input, textarea {
margin-right: 32px; margin-right: 32px;
} }
&.danger:before {
color: $color-error;
}
@include respond-to(handhelds) { @include respond-to(handhelds) {
padding: 0 30px 0 16px; padding: 0 30px 0 16px;
height: 50px; height: 50px;
@ -830,7 +828,7 @@ input:focus, button:focus {
} }
.btn-primary { .btn-primary {
background: $color-blue; background-color: $color-blue;
color: #fff; color: #fff;
border-radius: $border-radius-medium; border-radius: $border-radius-medium;
width: 100%; width: 100%;
@ -842,8 +840,9 @@ input:focus, button:focus {
overflow: hidden; overflow: hidden;
position: relative; position: relative;
padding: 0; // new padding: 0; // new
html.no-touch &:hover { html.no-touch &:hover {
transition: .2s background-color;
background: darken($color-blue, 8%); background: darken($color-blue, 8%);
} }
@ -852,6 +851,25 @@ input:focus, button:focus {
right: 15px; right: 15px;
left: auto; left: auto;
} }
// * tgico
&:before {
color: #707579;
font-size: 1.5rem;
margin-right: 1rem;
}
}
.btn-transparent {
color: #000;
background-color: transparent;
display: flex;
align-items: center;
justify-content: center;
html.no-touch &:hover {
background-color: var(--color-gray-hover);
}
} }
.btn-primary.btn-circle { .btn-primary.btn-circle {

Loading…
Cancel
Save