Ripple changes
Chat scroll fix Date format in chat list fix Animated send button Chat input is now lockable
This commit is contained in:
parent
d4e93c819e
commit
735721fee8
@ -14,6 +14,7 @@ import { touchSupport } from "../../lib/config";
|
|||||||
import appDocsManager from "../../lib/appManagers/appDocsManager";
|
import appDocsManager from "../../lib/appManagers/appDocsManager";
|
||||||
import emoticonsDropdown from "../emoticonsDropdown";
|
import emoticonsDropdown from "../emoticonsDropdown";
|
||||||
import PopupCreatePoll from "../popupCreatePoll";
|
import PopupCreatePoll from "../popupCreatePoll";
|
||||||
|
import { toast } from "../toast";
|
||||||
|
|
||||||
export class ChatInput {
|
export class ChatInput {
|
||||||
public pageEl = document.getElementById('page-chats') as HTMLDivElement;
|
public pageEl = document.getElementById('page-chats') as HTMLDivElement;
|
||||||
@ -95,11 +96,11 @@ export class ChatInput {
|
|||||||
reuseWorker: true
|
reuseWorker: true
|
||||||
});
|
});
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
this.btnSend.classList.remove('tgico-microphone2');
|
|
||||||
this.btnSend.classList.add('tgico-send');
|
|
||||||
console.error('Recorder constructor error:', err);
|
console.error('Recorder constructor error:', err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.updateSendBtn();
|
||||||
|
|
||||||
this.messageInput.addEventListener('keydown', (e: KeyboardEvent) => {
|
this.messageInput.addEventListener('keydown', (e: KeyboardEvent) => {
|
||||||
if(e.key == 'Enter' && !touchSupport) {
|
if(e.key == 'Enter' && !touchSupport) {
|
||||||
/* if(e.ctrlKey || e.metaKey) {
|
/* if(e.ctrlKey || e.metaKey) {
|
||||||
@ -130,14 +131,14 @@ export class ChatInput {
|
|||||||
this.messageInput.addEventListener('input', (e) => {
|
this.messageInput.addEventListener('input', (e) => {
|
||||||
//console.log('messageInput input', this.messageInput.innerText, this.serializeNodes(Array.from(this.messageInput.childNodes)));
|
//console.log('messageInput input', this.messageInput.innerText, this.serializeNodes(Array.from(this.messageInput.childNodes)));
|
||||||
|
|
||||||
let value = this.messageInput.innerText;
|
const value = this.messageInput.innerText;
|
||||||
|
|
||||||
let entities = RichTextProcessor.parseEntities(value);
|
const entities = RichTextProcessor.parseEntities(value);
|
||||||
//console.log('messageInput entities', entities);
|
//console.log('messageInput entities', entities);
|
||||||
|
|
||||||
let entityUrl = entities.find(e => e._ == 'messageEntityUrl');
|
const entityUrl = entities.find(e => e._ == 'messageEntityUrl');
|
||||||
if(entityUrl) { // need to get webpage
|
if(entityUrl) { // need to get webpage
|
||||||
let url = value.slice(entityUrl.offset, entityUrl.offset + entityUrl.length);
|
const url = value.slice(entityUrl.offset, entityUrl.offset + entityUrl.length);
|
||||||
|
|
||||||
//console.log('messageInput url:', url);
|
//console.log('messageInput url:', url);
|
||||||
|
|
||||||
@ -147,40 +148,35 @@ export class ChatInput {
|
|||||||
apiManager.invokeApi('messages.getWebPage', {
|
apiManager.invokeApi('messages.getWebPage', {
|
||||||
url: url,
|
url: url,
|
||||||
hash: 0
|
hash: 0
|
||||||
}).then((webpage: any) => {
|
}).then((webpage) => {
|
||||||
appWebPagesManager.saveWebPage(webpage);
|
webpage = appWebPagesManager.saveWebPage(webpage);
|
||||||
if(this.lastUrl != url) return;
|
if(webpage._ == 'webPage') {
|
||||||
//console.log('got webpage: ', webpage);
|
if(this.lastUrl != url) return;
|
||||||
|
//console.log('got webpage: ', webpage);
|
||||||
this.setTopInfo(webpage.site_name || webpage.title, webpage.description || webpage.url);
|
|
||||||
|
this.setTopInfo(webpage.site_name || webpage.title, webpage.description || webpage.url);
|
||||||
this.replyToMsgID = 0;
|
|
||||||
this.noWebPage = false;
|
this.replyToMsgID = 0;
|
||||||
this.willSendWebPage = webpage;
|
this.noWebPage = false;
|
||||||
|
this.willSendWebPage = webpage;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!value.trim() && !this.serializeNodes(Array.from(this.messageInput.childNodes)).trim()) {
|
if(!value.trim() && !this.serializeNodes(Array.from(this.messageInput.childNodes)).trim()) {
|
||||||
this.messageInput.innerHTML = '';
|
this.messageInput.innerHTML = '';
|
||||||
if(this.recorder) {
|
|
||||||
this.btnSend.classList.remove('tgico-send');
|
|
||||||
this.btnSend.classList.add('tgico-microphone2');
|
|
||||||
}
|
|
||||||
|
|
||||||
appMessagesManager.setTyping('sendMessageCancelAction');
|
appMessagesManager.setTyping('sendMessageCancelAction');
|
||||||
} else if(!this.btnSend.classList.contains('tgico-send') || !this.recorder) {
|
} else {
|
||||||
if(this.recorder) {
|
const time = Date.now();
|
||||||
this.btnSend.classList.add('tgico-send');
|
|
||||||
this.btnSend.classList.remove('tgico-microphone2');
|
|
||||||
}
|
|
||||||
|
|
||||||
let time = Date.now();
|
|
||||||
if(time - this.lastTimeType >= 6000) {
|
if(time - this.lastTimeType >= 6000) {
|
||||||
this.lastTimeType = time;
|
this.lastTimeType = time;
|
||||||
appMessagesManager.setTyping('sendMessageTypingAction');
|
appMessagesManager.setTyping('sendMessageTypingAction');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.updateSendBtn();
|
||||||
});
|
});
|
||||||
|
|
||||||
if(!RichTextProcessor.emojiSupported) {
|
if(!RichTextProcessor.emojiSupported) {
|
||||||
@ -517,7 +513,7 @@ export class ChatInput {
|
|||||||
const onBtnSendClick = (e: Event) => {
|
const onBtnSendClick = (e: Event) => {
|
||||||
cancelEvent(e);
|
cancelEvent(e);
|
||||||
|
|
||||||
if(this.btnSend.classList.contains('tgico-send') || !this.recorder) {
|
if(!this.recorder || this.recording || !this.isInputEmpty()) {
|
||||||
if(this.recording) {
|
if(this.recording) {
|
||||||
this.recorder.stop();
|
this.recorder.stop();
|
||||||
} else {
|
} else {
|
||||||
@ -526,9 +522,9 @@ export class ChatInput {
|
|||||||
} else {
|
} else {
|
||||||
this.recorder.start().then(() => {
|
this.recorder.start().then(() => {
|
||||||
this.recordCanceled = false;
|
this.recordCanceled = false;
|
||||||
this.btnSend.classList.add('tgico-send');
|
this.chatInput.classList.add('is-recording', 'is-locked');
|
||||||
this.chatInput.classList.add('is-recording');
|
|
||||||
this.recording = true;
|
this.recording = true;
|
||||||
|
this.updateSendBtn();
|
||||||
opusDecodeController.setKeepAlive(true);
|
opusDecodeController.setKeepAlive(true);
|
||||||
|
|
||||||
this.recordStartTime = Date.now();
|
this.recordStartTime = Date.now();
|
||||||
@ -571,7 +567,22 @@ export class ChatInput {
|
|||||||
|
|
||||||
r();
|
r();
|
||||||
}).catch((e: Error) => {
|
}).catch((e: Error) => {
|
||||||
console.error('Recorder start error:', e);
|
switch(e.name as string) {
|
||||||
|
case 'NotAllowedError': {
|
||||||
|
toast('Please allow access to your microphone');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'NotReadableError': {
|
||||||
|
toast(e.message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
console.error('Recorder start error:', e, e.name, e.message);
|
||||||
|
toast(e.message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -591,8 +602,8 @@ export class ChatInput {
|
|||||||
|
|
||||||
this.recorder.onstop = () => {
|
this.recorder.onstop = () => {
|
||||||
this.recording = false;
|
this.recording = false;
|
||||||
this.chatInput.classList.remove('is-recording');
|
this.chatInput.classList.remove('is-recording', 'is-locked');
|
||||||
this.btnSend.classList.remove('tgico-send');
|
this.updateSendBtn();
|
||||||
this.recordRippleEl.style.transform = '';
|
this.recordRippleEl.style.transform = '';
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -674,10 +685,7 @@ export class ChatInput {
|
|||||||
this.editMsgID = 0;
|
this.editMsgID = 0;
|
||||||
this.messageInput.innerHTML = '';
|
this.messageInput.innerHTML = '';
|
||||||
|
|
||||||
if(this.recorder) {
|
this.updateSendBtn();
|
||||||
this.btnSend.classList.remove('tgico-send');
|
|
||||||
this.btnSend.classList.add('tgico-microphone2');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -685,6 +693,22 @@ export class ChatInput {
|
|||||||
this.willSendWebPage = null;
|
this.willSendWebPage = null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private isInputEmpty() {
|
||||||
|
let value = this.messageInput.innerText;
|
||||||
|
|
||||||
|
return !value.trim() && !this.serializeNodes(Array.from(this.messageInput.childNodes)).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateSendBtn() {
|
||||||
|
let icon: 'send' | 'record';
|
||||||
|
|
||||||
|
if(!this.recorder || this.recording || !this.isInputEmpty()) icon = 'send';
|
||||||
|
else icon = 'record';
|
||||||
|
|
||||||
|
this.btnSend.classList.toggle('send', icon == 'send');
|
||||||
|
this.btnSend.classList.toggle('record', icon == 'record');
|
||||||
|
}
|
||||||
|
|
||||||
public serializeNodes(nodes: Node[]): string {
|
public serializeNodes(nodes: Node[]): string {
|
||||||
return nodes.reduce((str, child: any) => {
|
return nodes.reduce((str, child: any) => {
|
||||||
@ -711,10 +735,7 @@ export class ChatInput {
|
|||||||
this.willSendWebPage = null;
|
this.willSendWebPage = null;
|
||||||
this.messageInput.innerText = '';
|
this.messageInput.innerText = '';
|
||||||
|
|
||||||
if(this.recorder) {
|
this.updateSendBtn();
|
||||||
this.btnSend.classList.remove('tgico-send');
|
|
||||||
this.btnSend.classList.add('tgico-microphone2');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(clearReply || clearInput) {
|
if(clearReply || clearInput) {
|
||||||
@ -776,8 +797,7 @@ export class ChatInput {
|
|||||||
if(input !== undefined) {
|
if(input !== undefined) {
|
||||||
this.messageInput.innerHTML = input ? RichTextProcessor.wrapRichText(input) : '';
|
this.messageInput.innerHTML = input ? RichTextProcessor.wrapRichText(input) : '';
|
||||||
|
|
||||||
this.btnSend.classList.remove('tgico-microphone2');
|
this.updateSendBtn();
|
||||||
this.btnSend.classList.add('tgico-send');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//appImManager.scrollPosition.restore();
|
//appImManager.scrollPosition.restore();
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import mediaSizes from "../helpers/mediaSizes";
|
||||||
import { touchSupport } from "../lib/config";
|
import { touchSupport } from "../lib/config";
|
||||||
import { findUpClassName } from "../lib/utils";
|
import { findUpClassName } from "../lib/utils";
|
||||||
|
|
||||||
@ -15,20 +16,22 @@ export function ripple(elem: HTMLElement, callback: (id: number) => Promise<bool
|
|||||||
r.classList.add('is-square');
|
r.classList.add('is-square');
|
||||||
}
|
}
|
||||||
|
|
||||||
const duration = isSquare ? 200 : 700;
|
|
||||||
|
|
||||||
elem.append(r);
|
elem.append(r);
|
||||||
|
|
||||||
let handler: () => void;
|
let handler: () => void;
|
||||||
let drawRipple = (clientX: number, clientY: number) => {
|
let animationEndPromise: Promise<any>;
|
||||||
let startTime = Date.now();
|
const drawRipple = (clientX: number, clientY: number) => {
|
||||||
let span = document.createElement('span');
|
const startTime = Date.now();
|
||||||
|
const span = document.createElement('span');
|
||||||
|
|
||||||
let clickID = rippleClickID++;
|
const clickID = rippleClickID++;
|
||||||
|
|
||||||
//console.log('ripple drawRipple');
|
//console.log('ripple drawRipple');
|
||||||
|
|
||||||
|
let duration: number;
|
||||||
|
|
||||||
handler = () => {
|
handler = () => {
|
||||||
|
//const duration = isSquare || mediaSizes.isMobile ? 200 : 700;
|
||||||
//return;
|
//return;
|
||||||
let elapsedTime = Date.now() - startTime;
|
let elapsedTime = Date.now() - startTime;
|
||||||
if(elapsedTime < duration) {
|
if(elapsedTime < duration) {
|
||||||
@ -96,8 +99,16 @@ export function ripple(elem: HTMLElement, callback: (id: number) => Promise<bool
|
|||||||
span.style.width = span.style.height = size + 'px';
|
span.style.width = span.style.height = size + 'px';
|
||||||
span.style.left = x + 'px';
|
span.style.left = x + 'px';
|
||||||
span.style.top = y + 'px';
|
span.style.top = y + 'px';
|
||||||
|
|
||||||
|
|
||||||
|
animationEndPromise = new Promise((resolve) => {
|
||||||
|
span.addEventListener('animationend', resolve, {once: true});
|
||||||
|
});
|
||||||
|
|
||||||
r.append(span);
|
r.append(span);
|
||||||
|
|
||||||
|
duration = +window.getComputedStyle(span).getPropertyValue('animation-duration').replace('s', '') * 1000;
|
||||||
|
|
||||||
//r.classList.add('active');
|
//r.classList.add('active');
|
||||||
//handler();
|
//handler();
|
||||||
});
|
});
|
||||||
@ -121,12 +132,12 @@ export function ripple(elem: HTMLElement, callback: (id: number) => Promise<bool
|
|||||||
|
|
||||||
let {clientX, clientY} = e.touches[0];
|
let {clientX, clientY} = e.touches[0];
|
||||||
drawRipple(clientX, clientY);
|
drawRipple(clientX, clientY);
|
||||||
window.addEventListener('touchend', touchEnd, {once: true});
|
elem.addEventListener('touchend', touchEnd, {once: true});
|
||||||
|
|
||||||
window.addEventListener('touchmove', (e) => {
|
window.addEventListener('touchmove', (e) => {
|
||||||
e.cancelBubble = true;
|
e.cancelBubble = true;
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
handler && handler();
|
touchEnd();
|
||||||
window.removeEventListener('touchend', touchEnd);
|
window.removeEventListener('touchend', touchEnd);
|
||||||
}, {once: true});
|
}, {once: true});
|
||||||
}, {passive: true});
|
}, {passive: true});
|
||||||
|
@ -20,6 +20,7 @@ import { PhotoSize } from '../layer';
|
|||||||
import { deferredPromise } from '../helpers/cancellablePromise';
|
import { deferredPromise } from '../helpers/cancellablePromise';
|
||||||
import mediaSizes from '../helpers/mediaSizes';
|
import mediaSizes from '../helpers/mediaSizes';
|
||||||
import { isSafari } from '../helpers/userAgent';
|
import { isSafari } from '../helpers/userAgent';
|
||||||
|
import { months } from '../helpers/date';
|
||||||
|
|
||||||
export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTail, isOut, middleware, lazyLoadQueue, noInfo, group}: {
|
export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTail, isOut, middleware, lazyLoadQueue, noInfo, group}: {
|
||||||
doc: MyDocument,
|
doc: MyDocument,
|
||||||
@ -279,7 +280,6 @@ export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTai
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const formatDate = (timestamp: number, monthShort = false, withYear = true) => {
|
export const formatDate = (timestamp: number, monthShort = false, withYear = true) => {
|
||||||
const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'Octomber', 'November', 'December'];
|
|
||||||
const date = new Date(timestamp * 1000);
|
const date = new Date(timestamp * 1000);
|
||||||
|
|
||||||
let month = months[date.getMonth()];
|
let month = months[date.getMonth()];
|
||||||
|
32
src/helpers/date.ts
Normal file
32
src/helpers/date.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
export const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
|
||||||
|
export const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
|
||||||
|
|
||||||
|
const ONE_DAY = 86400e3;
|
||||||
|
|
||||||
|
// https://stackoverflow.com/a/6117889
|
||||||
|
export const getWeekNumber = (date: Date) => {
|
||||||
|
const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
|
||||||
|
const dayNum = d.getUTCDay() || 7;
|
||||||
|
d.setUTCDate(d.getUTCDate() + 4 - dayNum);
|
||||||
|
const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
|
||||||
|
return Math.ceil((((d.getTime() - yearStart.getTime()) / ONE_DAY) + 1) / 7);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const formatDateAccordingToToday = (time: Date) => {
|
||||||
|
const date = new Date();
|
||||||
|
const now = date.getTime() / 1000;
|
||||||
|
const timestamp = date.getTime() / 1000;
|
||||||
|
|
||||||
|
let timeStr: string;
|
||||||
|
if((now - timestamp) < ONE_DAY && date.getDate() == time.getDate()) { // if the same day
|
||||||
|
timeStr = ('0' + time.getHours()).slice(-2) + ':' + ('0' + time.getMinutes()).slice(-2);
|
||||||
|
} else if((now - timestamp) < (ONE_DAY * 7) && getWeekNumber(date) == getWeekNumber(time)) { // current week
|
||||||
|
timeStr = days[time.getDay()].slice(0, 3);
|
||||||
|
} else if(date.getFullYear() != time.getFullYear()) { // different year
|
||||||
|
timeStr = time.getDate() + '.' + (time.getMonth() + 1) + '.' + time.getFullYear();
|
||||||
|
} else { // same year
|
||||||
|
timeStr = months[time.getMonth()].slice(0, 3) + ' ' + ('0' + time.getDate()).slice(-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return timeStr;
|
||||||
|
};
|
@ -80,7 +80,7 @@ class MediaSizes extends EventListenerBase<{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.activeScreen != activeScreen) {
|
if(this.activeScreen != activeScreen && this.activeScreen !== undefined) {
|
||||||
//console.log('changeScreen', this.activeScreen, activeScreen);
|
//console.log('changeScreen', this.activeScreen, activeScreen);
|
||||||
this.setListenerResult('changeScreen', this.activeScreen, activeScreen);
|
this.setListenerResult('changeScreen', this.activeScreen, activeScreen);
|
||||||
}
|
}
|
||||||
@ -102,4 +102,7 @@ class MediaSizes extends EventListenerBase<{
|
|||||||
}
|
}
|
||||||
|
|
||||||
const mediaSizes = new MediaSizes();
|
const mediaSizes = new MediaSizes();
|
||||||
|
if(process.env.NODE_ENV != 'production') {
|
||||||
|
(window as any).mediaSizes = mediaSizes;
|
||||||
|
}
|
||||||
export default mediaSizes;
|
export default mediaSizes;
|
@ -452,11 +452,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="btn-menu" id="dialogs-contextmenu">
|
<div class="btn-menu" id="dialogs-contextmenu">
|
||||||
<div class="btn-menu-item menu-unread tgico rp"></div>
|
<div class="btn-menu-item menu-unread tgico rp"><div></div></div>
|
||||||
<div class="btn-menu-item menu-pin tgico rp"></div>
|
<div class="btn-menu-item menu-pin tgico rp"><div></div></div>
|
||||||
<div class="btn-menu-item menu-mute tgico rp"></div>
|
<div class="btn-menu-item menu-mute tgico rp"><div></div></div>
|
||||||
<div class="btn-menu-item menu-archive tgico rp"></div>
|
<div class="btn-menu-item menu-archive tgico rp"><div></div></div>
|
||||||
<div class="btn-menu-item menu-delete tgico-delete danger rp"></div>
|
<div class="btn-menu-item menu-delete tgico-delete danger rp"><div></div></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="chat-container main-column" id="column-center">
|
<div class="chat-container main-column" id="column-center">
|
||||||
@ -492,8 +492,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div id="bubbles" class="scrolled-down">
|
<div id="bubbles" class="scrolled-down">
|
||||||
<div id="bubbles-inner"></div>
|
<div id="bubbles-inner"></div>
|
||||||
|
<div id="bubbles-go-down" class="tgico-down btn-corner z-depth-1 rp hide"></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="bubbles-go-down" class="tgico-down btn-corner z-depth-1 rp hide"></div>
|
|
||||||
<div class="btn-menu" id="bubble-contextmenu">
|
<div class="btn-menu" id="bubble-contextmenu">
|
||||||
<div class="btn-menu-item menu-reply tgico-reply rp">Reply</div>
|
<div class="btn-menu-item menu-reply tgico-reply rp">Reply</div>
|
||||||
<div class="btn-menu-item menu-edit tgico-edit rp">Edit</div>
|
<div class="btn-menu-item menu-edit tgico-edit rp">Edit</div>
|
||||||
@ -535,7 +535,10 @@
|
|||||||
<button class="btn-circle z-depth-1 btn-icon tgico-delete danger" id="btn-record-cancel"></button>
|
<button class="btn-circle z-depth-1 btn-icon tgico-delete danger" id="btn-record-cancel"></button>
|
||||||
<div class="btn-send-container">
|
<div class="btn-send-container">
|
||||||
<div class="record-ripple"></div>
|
<div class="record-ripple"></div>
|
||||||
<button class="btn-circle z-depth-1 btn-icon tgico-microphone2" id="btn-send"></button>
|
<button class="btn-circle rp z-depth-1 btn-icon" id="btn-send">
|
||||||
|
<span class="tgico tgico-send"></span>
|
||||||
|
<span class="tgico tgico-microphone2"></span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="emoji-dropdown" id="emoji-dropdown" style="display: none;">
|
<div class="emoji-dropdown" id="emoji-dropdown" style="display: none;">
|
||||||
|
@ -17,6 +17,7 @@ import { touchSupport } from "../config";
|
|||||||
import { horizontalMenu } from "../../components/horizontalMenu";
|
import { horizontalMenu } from "../../components/horizontalMenu";
|
||||||
import { ripple } from "../../components/ripple";
|
import { ripple } from "../../components/ripple";
|
||||||
import { isSafari } from "../../helpers/userAgent";
|
import { isSafari } from "../../helpers/userAgent";
|
||||||
|
import { formatDateAccordingToToday, getWeekNumber } from "../../helpers/date";
|
||||||
|
|
||||||
type DialogDom = {
|
type DialogDom = {
|
||||||
avatarEl: AvatarElement,
|
avatarEl: AvatarElement,
|
||||||
@ -197,7 +198,7 @@ class DialogsContextMenu {
|
|||||||
const button = this.buttons.archive;
|
const button = this.buttons.archive;
|
||||||
const condition = dialog.folder_id == 1;
|
const condition = dialog.folder_id == 1;
|
||||||
button.classList.toggle('flip-icon', condition);
|
button.classList.toggle('flip-icon', condition);
|
||||||
button.innerText = condition ? 'Unarchive' : 'Archive';
|
(button.firstElementChild as HTMLElement).innerText = condition ? 'Unarchive' : 'Archive';
|
||||||
this.buttons.archive.style.display = '';
|
this.buttons.archive.style.display = '';
|
||||||
} else {
|
} else {
|
||||||
this.buttons.archive.style.display = 'none';
|
this.buttons.archive.style.display = 'none';
|
||||||
@ -209,7 +210,7 @@ class DialogsContextMenu {
|
|||||||
//const condition = !!dialog.pFlags?.pinned;
|
//const condition = !!dialog.pFlags?.pinned;
|
||||||
const condition = this.filterID > 1 ? appMessagesManager.filtersStorage.filters[this.filterID].pinned_peers.includes(dialog.peerID) : !!dialog.pFlags?.pinned;
|
const condition = this.filterID > 1 ? appMessagesManager.filtersStorage.filters[this.filterID].pinned_peers.includes(dialog.peerID) : !!dialog.pFlags?.pinned;
|
||||||
button.classList.toggle('flip-icon', condition);
|
button.classList.toggle('flip-icon', condition);
|
||||||
button.innerText = condition ? 'Unpin' : 'Pin';
|
(button.firstElementChild as HTMLElement).innerText = condition ? 'Unpin' : 'Pin';
|
||||||
}
|
}
|
||||||
|
|
||||||
// mute button
|
// mute button
|
||||||
@ -217,7 +218,7 @@ class DialogsContextMenu {
|
|||||||
const button = this.buttons.mute;
|
const button = this.buttons.mute;
|
||||||
const condition = dialog.notify_settings && dialog.notify_settings.mute_until > (Date.now() / 1000 | 0);
|
const condition = dialog.notify_settings && dialog.notify_settings.mute_until > (Date.now() / 1000 | 0);
|
||||||
button.classList.toggle('flip-icon', condition);
|
button.classList.toggle('flip-icon', condition);
|
||||||
button.innerText = condition ? 'Unmute' : 'Mute';
|
(button.firstElementChild as HTMLElement).innerText = condition ? 'Unmute' : 'Mute';
|
||||||
this.buttons.mute.style.display = '';
|
this.buttons.mute.style.display = '';
|
||||||
} else {
|
} else {
|
||||||
this.buttons.mute.style.display = 'none';
|
this.buttons.mute.style.display = 'none';
|
||||||
@ -228,7 +229,7 @@ class DialogsContextMenu {
|
|||||||
const button = this.buttons.unread;
|
const button = this.buttons.unread;
|
||||||
const condition = !!(dialog.pFlags?.unread_mark || dialog.unread_count);
|
const condition = !!(dialog.pFlags?.unread_mark || dialog.unread_count);
|
||||||
button.classList.toggle('flip-icon', condition);
|
button.classList.toggle('flip-icon', condition);
|
||||||
button.innerText = condition ? 'Mark as Read' : 'Mark as Unread';
|
(button.firstElementChild as HTMLElement).innerText = condition ? 'Mark as Read' : 'Mark as Unread';
|
||||||
}
|
}
|
||||||
|
|
||||||
/* // clear history button
|
/* // clear history button
|
||||||
@ -257,7 +258,7 @@ class DialogsContextMenu {
|
|||||||
//deleteButtonText = 'Delete chat';
|
//deleteButtonText = 'Delete chat';
|
||||||
this.peerType = this.selectedID == $rootScope.myID ? 'saved' : 'chat';
|
this.peerType = this.selectedID == $rootScope.myID ? 'saved' : 'chat';
|
||||||
}
|
}
|
||||||
this.buttons.delete.innerText = deleteButtonText;
|
(this.buttons.delete.firstElementChild as HTMLElement).innerText = deleteButtonText;
|
||||||
|
|
||||||
li.classList.add('menu-open');
|
li.classList.add('menu-open');
|
||||||
positionMenu(e, this.element);
|
positionMenu(e, this.element);
|
||||||
@ -1001,25 +1002,7 @@ export class AppDialogsManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!lastMessage.deleted) {
|
if(!lastMessage.deleted) {
|
||||||
let timeStr = '';
|
dom.lastTimeSpan.innerHTML = formatDateAccordingToToday(new Date(lastMessage.date * 1000));
|
||||||
let timestamp = lastMessage.date;
|
|
||||||
let now = Date.now() / 1000;
|
|
||||||
let time = new Date(lastMessage.date * 1000);
|
|
||||||
|
|
||||||
if((now - timestamp) < 86400) { // if < 1 day
|
|
||||||
timeStr = ('0' + time.getHours()).slice(-2) +
|
|
||||||
':' + ('0' + time.getMinutes()).slice(-2);
|
|
||||||
} else if((now - timestamp) < (86400 * 7)) { // week
|
|
||||||
let date = new Date(timestamp * 1000);
|
|
||||||
timeStr = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'][date.getDay()];
|
|
||||||
} else {
|
|
||||||
let months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
|
||||||
|
|
||||||
timeStr = months[time.getMonth()] +
|
|
||||||
' ' + ('0' + time.getDate()).slice(-2);
|
|
||||||
}
|
|
||||||
|
|
||||||
dom.lastTimeSpan.innerHTML = timeStr;
|
|
||||||
} else dom.lastTimeSpan.innerHTML = '';
|
} else dom.lastTimeSpan.innerHTML = '';
|
||||||
|
|
||||||
if(this.doms[peerID] == dom) {
|
if(this.doms[peerID] == dom) {
|
||||||
|
@ -40,7 +40,7 @@ import { ChatAudio } from '../../components/chat/audio';
|
|||||||
import { ChatContextMenu } from '../../components/chat/contextMenu';
|
import { ChatContextMenu } from '../../components/chat/contextMenu';
|
||||||
import { ChatSearch } from '../../components/chat/search';
|
import { ChatSearch } from '../../components/chat/search';
|
||||||
import mediaSizes from '../../helpers/mediaSizes';
|
import mediaSizes from '../../helpers/mediaSizes';
|
||||||
import { isAndroid, isApple } from '../../helpers/userAgent';
|
import { isAndroid, isApple, isSafari } from '../../helpers/userAgent';
|
||||||
|
|
||||||
//console.log('appImManager included33!');
|
//console.log('appImManager included33!');
|
||||||
|
|
||||||
@ -847,6 +847,8 @@ export class AppImManager {
|
|||||||
|
|
||||||
this.scrollable = new Scrollable(this.bubblesContainer, 'y', 'IM', this.chatInner, getScrollOffset()); */
|
this.scrollable = new Scrollable(this.bubblesContainer, 'y', 'IM', this.chatInner, getScrollOffset()); */
|
||||||
this.scroll = this.scrollable.container;
|
this.scroll = this.scrollable.container;
|
||||||
|
|
||||||
|
this.bubblesContainer.append(this.goDownBtn);
|
||||||
|
|
||||||
this.scrollable.onScrolledTop = () => this.loadMoreHistory(true);
|
this.scrollable.onScrolledTop = () => this.loadMoreHistory(true);
|
||||||
this.scrollable.onScrolledBottom = () => this.loadMoreHistory(false);
|
this.scrollable.onScrolledBottom = () => this.loadMoreHistory(false);
|
||||||
@ -1045,7 +1047,7 @@ export class AppImManager {
|
|||||||
this.scrollable.scrollIntoView(bubble);
|
this.scrollable.scrollIntoView(bubble);
|
||||||
this.highlightBubble(bubble);
|
this.highlightBubble(bubble);
|
||||||
} else if(dialog && lastMsgID == topMessage) {
|
} else if(dialog && lastMsgID == topMessage) {
|
||||||
this.log('will scroll down', this.scroll.scrollTop, this.scroll.scrollHeight);
|
//this.log('will scroll down', this.scroll.scrollTop, this.scroll.scrollHeight);
|
||||||
this.scroll.scrollTop = this.scroll.scrollHeight;
|
this.scroll.scrollTop = this.scroll.scrollHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1225,6 +1227,7 @@ export class AppImManager {
|
|||||||
|
|
||||||
const isAnyGroup = appPeersManager.isAnyGroup(peerID);
|
const isAnyGroup = appPeersManager.isAnyGroup(peerID);
|
||||||
const isChannel = appPeersManager.isChannel(peerID);
|
const isChannel = appPeersManager.isChannel(peerID);
|
||||||
|
const isBroadcast = appPeersManager.isBroadcast(peerID);
|
||||||
const hasRights = isChannel && appChatsManager.hasRights(-peerID, 'send');
|
const hasRights = isChannel && appChatsManager.hasRights(-peerID, 'send');
|
||||||
this.chatInner.classList.toggle('has-rights', hasRights);
|
this.chatInner.classList.toggle('has-rights', hasRights);
|
||||||
|
|
||||||
@ -1232,11 +1235,12 @@ export class AppImManager {
|
|||||||
|
|
||||||
this.topbar.classList.remove('is-pinned-shown');
|
this.topbar.classList.remove('is-pinned-shown');
|
||||||
this.topbar.style.display = '';
|
this.topbar.style.display = '';
|
||||||
|
|
||||||
this.chatInner.classList.toggle('is-chat', isAnyGroup || peerID == this.myID);
|
this.chatInner.classList.toggle('is-chat', isAnyGroup || peerID == this.myID);
|
||||||
this.chatInner.classList.toggle('is-channel', isChannel);
|
this.chatInner.classList.toggle('is-channel', isChannel);
|
||||||
|
this.goDownBtn.classList.toggle('is-broadcast', isBroadcast);
|
||||||
|
|
||||||
this.btnMute.classList.toggle('hide', !appPeersManager.isBroadcast(peerID));
|
this.btnMute.classList.toggle('hide', !isBroadcast);
|
||||||
this.btnJoin.classList.toggle('hide', !appChatsManager.getChat(-this.peerID)?.pFlags?.left);
|
this.btnJoin.classList.toggle('hide', !appChatsManager.getChat(-this.peerID)?.pFlags?.left);
|
||||||
|
|
||||||
this.menuButtons.mute.style.display = this.myID == this.peerID ? 'none' : '';
|
this.menuButtons.mute.style.display = this.myID == this.peerID ? 'none' : '';
|
||||||
@ -1324,12 +1328,12 @@ export class AppImManager {
|
|||||||
if(this.messagesQueuePromise && scrolledDown) {
|
if(this.messagesQueuePromise && scrolledDown) {
|
||||||
this.scrollable.scrollTo(this.scrollable.scrollHeight - 1, 'top', false, true);
|
this.scrollable.scrollTo(this.scrollable.scrollHeight - 1, 'top', false, true);
|
||||||
this.messagesQueuePromise.then(() => {
|
this.messagesQueuePromise.then(() => {
|
||||||
this.log('messagesQueuePromise after:', this.chatInner.childElementCount, this.scrollable.scrollHeight);
|
//this.log('messagesQueuePromise after:', this.chatInner.childElementCount, this.scrollable.scrollHeight);
|
||||||
this.scrollable.scrollTo(this.scrollable.scrollHeight, 'top', true, true);
|
this.scrollable.scrollTo(this.scrollable.scrollHeight, 'top', true, true);
|
||||||
|
|
||||||
setTimeout(() => {
|
/* setTimeout(() => {
|
||||||
this.log('messagesQueuePromise afterafter:', this.chatInner.childElementCount, this.scrollable.scrollHeight);
|
this.log('messagesQueuePromise afterafter:', this.chatInner.childElementCount, this.scrollable.scrollHeight);
|
||||||
}, 10);
|
}, 10); */
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1404,6 +1408,8 @@ export class AppImManager {
|
|||||||
else dateMessage.container.append(bubble);
|
else dateMessage.container.append(bubble);
|
||||||
return; */
|
return; */
|
||||||
|
|
||||||
|
//this.log('renderMessagesQueue');
|
||||||
|
|
||||||
let promises: Promise<any>[] = [];
|
let promises: Promise<any>[] = [];
|
||||||
(Array.from(bubble.querySelectorAll('img, video')) as HTMLImageElement[]).forEach(el => {
|
(Array.from(bubble.querySelectorAll('img, video')) as HTMLImageElement[]).forEach(el => {
|
||||||
if(el instanceof HTMLVideoElement) {
|
if(el instanceof HTMLVideoElement) {
|
||||||
@ -1450,12 +1456,12 @@ export class AppImManager {
|
|||||||
if(!this.messagesQueuePromise) {
|
if(!this.messagesQueuePromise) {
|
||||||
this.messagesQueuePromise = new Promise((resolve, reject) => {
|
this.messagesQueuePromise = new Promise((resolve, reject) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
let chatInner = this.chatInner;
|
const chatInner = this.chatInner;
|
||||||
let queue = this.messagesQueue.slice();
|
const queue = this.messagesQueue.slice();
|
||||||
this.messagesQueue.length = 0;
|
this.messagesQueue.length = 0;
|
||||||
|
|
||||||
let promises = queue.reduce((acc, {promises}) => acc.concat(promises), []);
|
const promises = queue.reduce((acc, {promises}) => acc.concat(promises), []);
|
||||||
//console.log('promises to call', promises, queue);
|
//this.log('promises to call', promises, queue);
|
||||||
Promise.all(promises).then(() => {
|
Promise.all(promises).then(() => {
|
||||||
if(this.chatInner != chatInner) {
|
if(this.chatInner != chatInner) {
|
||||||
//this.log.warn('chatInner changed!', this.chatInner, chatInner);
|
//this.log.warn('chatInner changed!', this.chatInner, chatInner);
|
||||||
@ -1467,13 +1473,11 @@ export class AppImManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
queue.forEach(({message, bubble, reverse}) => {
|
queue.forEach(({message, bubble, reverse}) => {
|
||||||
let dateMessage = this.getDateContainerByMessage(message, reverse);
|
const dateMessage = this.getDateContainerByMessage(message, reverse);
|
||||||
if(reverse) {
|
if(reverse) {
|
||||||
dateMessage.container.insertBefore(bubble, dateMessage.div.nextSibling);
|
dateMessage.container.insertBefore(bubble, dateMessage.div.nextSibling);
|
||||||
//this.scrollable.prepareElement(bubble, false);
|
|
||||||
} else {
|
} else {
|
||||||
dateMessage.container.append(bubble);
|
dateMessage.container.append(bubble);
|
||||||
//this.scrollable.prepareElement(bubble, true);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -2315,24 +2319,26 @@ export class AppImManager {
|
|||||||
//console.time('appImManager render history');
|
//console.time('appImManager render history');
|
||||||
|
|
||||||
return new Promise<boolean>((resolve, reject) => {
|
return new Promise<boolean>((resolve, reject) => {
|
||||||
let method = (reverse ? history.shift : history.pop).bind(history);
|
//await new Promise((resolve) => setTimeout(resolve, 1e3));
|
||||||
|
|
||||||
let realLength = this.scrollable.length;
|
//this.log('performHistoryResult: will render some messages:', history.length);
|
||||||
|
|
||||||
|
const method = (reverse ? history.shift : history.pop).bind(history);
|
||||||
|
|
||||||
|
const realLength = this.scrollable.length;
|
||||||
let previousScrollHeightMinusTop: number;
|
let previousScrollHeightMinusTop: number;
|
||||||
if(realLength > 0 && reverse) { // for safari need set when scrolling bottom too
|
if(realLength > 0 && (reverse || isSafari)) { // for safari need set when scrolling bottom too
|
||||||
this.messagesQueueOnRender = () => {
|
this.messagesQueueOnRender = () => {
|
||||||
let scrollTop = this.scrollable.scrollTop;
|
const {scrollTop, scrollHeight} = this.scrollable;
|
||||||
|
|
||||||
previousScrollHeightMinusTop = this.scrollable.scrollHeight - scrollTop;
|
previousScrollHeightMinusTop = reverse ? scrollHeight - scrollTop : scrollTop;
|
||||||
//this.chatInner.style.height = '100%';
|
|
||||||
//previousScrollHeightMinusTop = 0;
|
|
||||||
/* if(reverse) {
|
/* if(reverse) {
|
||||||
previousScrollHeightMinusTop = this.scrollable.scrollHeight - scrollTop;
|
previousScrollHeightMinusTop = this.scrollable.scrollHeight - scrollTop;
|
||||||
} else {
|
} else {
|
||||||
previousScrollHeightMinusTop = scrollTop;
|
previousScrollHeightMinusTop = scrollTop;
|
||||||
} */
|
} */
|
||||||
|
|
||||||
this.log('performHistoryResult: messagesQueueOnRender, scrollTop:', scrollTop, previousScrollHeightMinusTop);
|
//this.log('performHistoryResult: messagesQueueOnRender, scrollTop:', scrollTop, scrollHeight, previousScrollHeightMinusTop);
|
||||||
this.messagesQueueOnRender = undefined;
|
this.messagesQueueOnRender = undefined;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -2342,15 +2348,20 @@ export class AppImManager {
|
|||||||
this.renderMessage(message, reverse, true);
|
this.renderMessage(message, reverse, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
(this.messagesQueuePromise || Promise.resolve()).then(() => {
|
(this.messagesQueuePromise || Promise.resolve())
|
||||||
|
//.then(() => new Promise(resolve => setTimeout(resolve, 100)))
|
||||||
|
.then(() => {
|
||||||
if(previousScrollHeightMinusTop !== undefined) {
|
if(previousScrollHeightMinusTop !== undefined) {
|
||||||
const newScrollTop = reverse ? this.scrollable.scrollHeight - previousScrollHeightMinusTop : previousScrollHeightMinusTop;
|
const newScrollTop = reverse ? this.scrollable.scrollHeight - previousScrollHeightMinusTop : previousScrollHeightMinusTop;
|
||||||
this.log('performHistoryResult: will set scrollTop', this.scrollable.scrollHeight, newScrollTop, this.scrollable.container.clientHeight);
|
//this.log('performHistoryResult: will set scrollTop', this.scrollable.scrollHeight, newScrollTop, this.scrollable.container.clientHeight);
|
||||||
|
|
||||||
// touchSupport for safari iOS
|
// touchSupport for safari iOS
|
||||||
touchSupport && isApple && (this.scrollable.container.style.overflow = 'hidden');
|
touchSupport && isApple && (this.scrollable.container.style.overflow = 'hidden');
|
||||||
this.scrollable.scrollTop = newScrollTop;
|
this.scrollable.scrollTop = newScrollTop;
|
||||||
|
//this.scrollable.scrollTop = this.scrollable.scrollHeight;
|
||||||
touchSupport && isApple && (this.scrollable.container.style.overflow = '');
|
touchSupport && isApple && (this.scrollable.container.style.overflow = '');
|
||||||
|
|
||||||
|
//this.log('performHistoryResult: have set up scrollTop:', newScrollTop, this.scrollable.scrollTop);
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve(true);
|
resolve(true);
|
||||||
@ -2460,7 +2471,7 @@ export class AppImManager {
|
|||||||
|
|
||||||
//let removeCount = loadCount / 2;
|
//let removeCount = loadCount / 2;
|
||||||
const safeCount = realLoadCount * 2; // cause i've been runningrunningrunning all day
|
const safeCount = realLoadCount * 2; // cause i've been runningrunningrunning all day
|
||||||
this.log('getHistory: slice loadedTimes:', reverse, pageCount, this.loadedTopTimes, this.loadedBottomTimes, ids && ids.length, safeCount);
|
this.log('getHistory: slice loadedTimes:', reverse, pageCount, this.loadedTopTimes, this.loadedBottomTimes, ids?.length, safeCount);
|
||||||
if(ids && ids.length > safeCount) {
|
if(ids && ids.length > safeCount) {
|
||||||
if(reverse) {
|
if(reverse) {
|
||||||
//ids = ids.slice(-removeCount);
|
//ids = ids.slice(-removeCount);
|
||||||
|
@ -80,7 +80,7 @@ export class AppSidebarRight extends SidebarSlider {
|
|||||||
|
|
||||||
public toggleSidebar(enable?: boolean) {
|
public toggleSidebar(enable?: boolean) {
|
||||||
/////this.log('sidebarEl', this.sidebarEl, enable, isElementInViewport(this.sidebarEl));
|
/////this.log('sidebarEl', this.sidebarEl, enable, isElementInViewport(this.sidebarEl));
|
||||||
|
|
||||||
const active = document.body.classList.contains(COLUMN_ACTIVE_CLASSNAME);
|
const active = document.body.classList.contains(COLUMN_ACTIVE_CLASSNAME);
|
||||||
let willChange: boolean;
|
let willChange: boolean;
|
||||||
if(enable !== undefined) {
|
if(enable !== undefined) {
|
||||||
@ -107,17 +107,13 @@ export class AppSidebarRight extends SidebarSlider {
|
|||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
const set = () => {
|
document.body.classList.toggle(COLUMN_ACTIVE_CLASSNAME, enable);
|
||||||
document.body.classList.toggle(COLUMN_ACTIVE_CLASSNAME, enable);
|
|
||||||
};
|
|
||||||
|
|
||||||
set();
|
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
setTimeout(resolve, 200);
|
setTimeout(resolve, 200);
|
||||||
});
|
});
|
||||||
//return Promise.resolve();
|
//return Promise.resolve();
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
/* return new Promise((resolve, reject) => {
|
||||||
const hidden: {element: HTMLDivElement, height: number}[] = [];
|
const hidden: {element: HTMLDivElement, height: number}[] = [];
|
||||||
const observer = new IntersectionObserver((entries) => {
|
const observer = new IntersectionObserver((entries) => {
|
||||||
for(const entry of entries) {
|
for(const entry of entries) {
|
||||||
@ -145,11 +141,6 @@ export class AppSidebarRight extends SidebarSlider {
|
|||||||
(item.element.firstElementChild as HTMLElement).style.display = '';
|
(item.element.firstElementChild as HTMLElement).style.display = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if(active) {
|
|
||||||
appForward.close();
|
|
||||||
this.searchCloseBtn.click();
|
|
||||||
} */
|
|
||||||
|
|
||||||
resolve();
|
resolve();
|
||||||
}, 200);
|
}, 200);
|
||||||
});
|
});
|
||||||
@ -163,7 +154,7 @@ export class AppSidebarRight extends SidebarSlider {
|
|||||||
set();
|
set();
|
||||||
setTimeout(resolve, 200);
|
setTimeout(resolve, 200);
|
||||||
}
|
}
|
||||||
});
|
}); */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,6 +101,8 @@ class AppWebPagesManager {
|
|||||||
msgs: msgs
|
msgs: msgs
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return apiWebPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getWebPage(id: string) {
|
public getWebPage(id: string) {
|
||||||
|
@ -298,9 +298,19 @@
|
|||||||
#btn-send {
|
#btn-send {
|
||||||
color: #9e9e9e;
|
color: #9e9e9e;
|
||||||
|
|
||||||
&.tgico-send {
|
> .tgico {
|
||||||
|
position: absolute;
|
||||||
|
animation: hide-icon .4s forwards ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.send {
|
||||||
color: $color-blue;
|
color: $color-blue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.send .tgico-send,
|
||||||
|
&.record .tgico-microphone2 {
|
||||||
|
animation: grow-icon .4s forwards ease-in-out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#btn-record-cancel, #btn-send {
|
#btn-record-cancel, #btn-send {
|
||||||
@ -345,6 +355,14 @@
|
|||||||
left: -124px;
|
left: -124px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.is-locked {
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
.btn-icon {
|
||||||
|
color: #c6cbce;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.is-recording {
|
&.is-recording {
|
||||||
#btn-record-cancel {
|
#btn-record-cancel {
|
||||||
@ -354,6 +372,11 @@
|
|||||||
transition: width .1s, margin-right .1s, visibility 0s .1s, opacity .1s .1s;
|
transition: width .1s, margin-right .1s, visibility 0s .1s, opacity .1s .1s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// unlock
|
||||||
|
#btn-send, #btn-record-cancel {
|
||||||
|
pointer-events: all;
|
||||||
|
}
|
||||||
|
|
||||||
#attach-file {
|
#attach-file {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@ -568,13 +591,12 @@
|
|||||||
|
|
||||||
.btn-icon {
|
.btn-icon {
|
||||||
display: block;
|
display: block;
|
||||||
transition: .2s color;
|
transition: .2s color, background-color .2s;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
|
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
padding: 10px 7px 9px 7.5px;
|
|
||||||
color: #8d969c;
|
color: #8d969c;
|
||||||
|
margin-bottom: 1px;
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
color: $color-blue;
|
color: $color-blue;
|
||||||
@ -887,12 +909,25 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
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;
|
||||||
|
|
||||||
html.is-safari & {
|
html.is-safari & {
|
||||||
-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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ! WARNING, НЕЛЬЗЯ СТАВИТЬ ТРАНСФОРМ КРОМЕ TRANSLATEZ(0) НА БЛОК С OVERFLOW, ОН БУДЕТ ПРЫГАТЬ ВВЕРХ ПРИ ВКЛЮЧЕННОМ ПРАВИЛЕ И ЭТО НЕ ИСПРАВИТЬ JS'ОМ!
|
||||||
|
@include respond-to(medium-screens) {
|
||||||
|
transition: transform var(--layer-transition);
|
||||||
|
|
||||||
|
body.is-right-column-shown & {
|
||||||
|
transform: translate3d(calc(var(--right-column-width) / -2), 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.animation-level-0 & {
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
> .scrollable {
|
> .scrollable {
|
||||||
height: auto;
|
height: auto;
|
||||||
@ -908,46 +943,26 @@
|
|||||||
/* display: flex;
|
/* display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: flex-end; */
|
justify-content: flex-end; */
|
||||||
|
|
||||||
// * scrollbar takes some width, don't need to set padding for iOS
|
// * scrollbar takes some width, don't need to set padding for iOS
|
||||||
html.is-safari:not(.is-ios) & {
|
html.is-safari:not(.is-ios) & {
|
||||||
padding-left: 6px;
|
padding-left: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@include respond-to(medium-screens) {
|
|
||||||
transition: transform var(--layer-transition);
|
|
||||||
|
|
||||||
body.is-right-column-shown & {
|
|
||||||
transform: translate3d(calc(var(--right-column-width) / -2), 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
body.animation-level-0 & {
|
|
||||||
transition: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .preloader-container {
|
|
||||||
@include respond-to(medium-screens) {
|
|
||||||
transition: transform var(--layer-transition);
|
|
||||||
|
|
||||||
body.is-right-column-shown & {
|
|
||||||
transform: translate3d(calc(var(--right-column-width) / -2), 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
body.animation-level-0 & {
|
|
||||||
transition: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(.scrolled-down):not(.search-results-active) {
|
&:not(.scrolled-down):not(.search-results-active) {
|
||||||
-webkit-mask-image: -webkit-linear-gradient(bottom, transparent, #000 20px);
|
> .scrollable {
|
||||||
mask-image: linear-gradient(0deg, transparent 0, #000 20px);
|
-webkit-mask-image: -webkit-linear-gradient(bottom, transparent, #000 20px);
|
||||||
|
mask-image: linear-gradient(0deg, transparent 0, #000 20px);
|
||||||
|
}
|
||||||
|
|
||||||
& + #bubbles-go-down {
|
> #bubbles-go-down {
|
||||||
|
cursor: pointer;
|
||||||
--translateY: 0;
|
--translateY: 0;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
|
||||||
|
/* &.is-broadcast {
|
||||||
|
--translateY: 79px !important;
|
||||||
|
} */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -987,7 +1002,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@include respond-to(handhelds) {
|
@include respond-to(handhelds) {
|
||||||
padding: 0 .5rem;
|
padding: 0 .75rem 0 .5rem;
|
||||||
|
|
||||||
html.is-mac & {
|
html.is-mac & {
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
@ -1045,16 +1060,15 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
right: 17.5px;
|
right: 17.5px;
|
||||||
//bottom: 17.5px;
|
bottom: 17.5px;
|
||||||
bottom: 96.5px;
|
cursor: default;
|
||||||
cursor: pointer;
|
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
transition: var(--btn-corner-transition), opacity .2s;
|
transition: var(--btn-corner-transition), opacity .2s;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
@include respond-to(handhelds) {
|
@include respond-to(handhelds) {
|
||||||
bottom: 75.5px;
|
|
||||||
right: .5rem;
|
right: .5rem;
|
||||||
width: 2.875rem;
|
width: 2.875rem;
|
||||||
height: 2.875rem;
|
height: 2.875rem;
|
||||||
@ -1068,9 +1082,13 @@
|
|||||||
transition: transform var(--layer-transition), opacity .2s;
|
transition: transform var(--layer-transition), opacity .2s;
|
||||||
|
|
||||||
body.is-right-column-shown & {
|
body.is-right-column-shown & {
|
||||||
transform: translate3d(calc(var(--right-column-width) * -1), var(--translateY), 0);
|
transform: translate3d(calc(var(--right-column-width) * -.5), var(--translateY), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* &.is-broadcast {
|
||||||
|
--translateY: 99px !important;
|
||||||
|
} */
|
||||||
}
|
}
|
||||||
|
|
||||||
.popup {
|
.popup {
|
||||||
@ -1154,11 +1172,11 @@
|
|||||||
z-index: 5;
|
z-index: 5;
|
||||||
top: 8px;
|
top: 8px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
transform: translateY(calc(-100% - 10px));
|
transform: translate3d(0, calc(-100% - 10px), 0);
|
||||||
transition: transform .2s ease;
|
transition: transform .2s ease;
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
transform: translateY(0);
|
transform: translate3d(0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
|
@ -50,17 +50,17 @@
|
|||||||
transition: .35s opacity;
|
transition: .35s opacity;
|
||||||
//overflow: hidden;
|
//overflow: hidden;
|
||||||
|
|
||||||
@include respond-to(handhelds) {
|
.btn-menu &, .c-ripple.is-square & {
|
||||||
animation-duration: .2s;
|
animation-duration: .2s;
|
||||||
transition-duration: .1s;
|
transition-duration: .1s;
|
||||||
border-radius: 15%;
|
//border-radius: 15%;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
&.is-square .c-ripple__circle, .btn-menu & .c-ripple__circle {
|
/* @include respond-to(handhelds) {
|
||||||
animation-duration: .2s;
|
animation-duration: .2s;
|
||||||
transition-duration: .1s;
|
transition-duration: .1s;
|
||||||
border-radius: 15%;
|
//border-radius: 15%;
|
||||||
|
} */
|
||||||
}
|
}
|
||||||
|
|
||||||
&__circle.hiding, &__square.hiding {
|
&__circle.hiding, &__square.hiding {
|
||||||
@ -68,6 +68,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@include respond-to(handhelds) {
|
||||||
|
.chats-container ul li > .rp .c-ripple__circle {
|
||||||
|
animation-duration: .2s;
|
||||||
|
transition-duration: .1s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes ripple-effect {
|
@keyframes ripple-effect {
|
||||||
0% {
|
0% {
|
||||||
transform: scale(0);
|
transform: scale(0);
|
||||||
|
@ -99,6 +99,7 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: $color-blue;
|
color: $color-blue;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
html.no-touch &:hover {
|
html.no-touch &:hover {
|
||||||
background-color: rgba(112, 117, 121, 0.08);
|
background-color: rgba(112, 117, 121, 0.08);
|
||||||
|
@ -54,9 +54,9 @@ $large-screen: 1680px;
|
|||||||
:root {
|
:root {
|
||||||
--color-gray: #c4c9cc;
|
--color-gray: #c4c9cc;
|
||||||
--layer-transition: .2s ease-in-out;
|
--layer-transition: .2s ease-in-out;
|
||||||
--btn-corner-transition: transform .2s cubic-bezier(.34, 1.56, .64, 1);
|
|
||||||
//--layer-transition: .3s cubic-bezier(.33, 1, .68, 1);
|
//--layer-transition: .3s cubic-bezier(.33, 1, .68, 1);
|
||||||
//--layer-transition: none;
|
//--layer-transition: none;
|
||||||
|
--btn-corner-transition: transform .2s cubic-bezier(.34, 1.56, .64, 1);
|
||||||
--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);
|
||||||
@ -1104,6 +1104,34 @@ img.emoji {
|
|||||||
color: #707579;
|
color: #707579;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes grow-icon {
|
||||||
|
0% {
|
||||||
|
transform: scale(.5);
|
||||||
|
opacity: .8;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
transform: scale(1.1);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes hide-icon {
|
||||||
|
from {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: .4;
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
transform: scale(.5);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// *:not(input):not(textarea) {
|
// *:not(input):not(textarea) {
|
||||||
// -webkit-user-select: none; /* disable selection/Copy of UIWebView */
|
// -webkit-user-select: none; /* disable selection/Copy of UIWebView */
|
||||||
// -webkit-touch-callout: none; /* disable the IOS popup when long-press on a link */
|
// -webkit-touch-callout: none; /* disable the IOS popup when long-press on a link */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user