Changed jumping logic
Scale animation on first chat opening Draft: save entities on saving Fix blinking media on chat opening Changed peer name colors to macOS version
This commit is contained in:
parent
3183c2a688
commit
abf1acc6c8
@ -27,6 +27,7 @@ import appSidebarRight, { AppSidebarRight } from "./sidebarRight";
|
||||
import SwipeHandler from "./swipeHandler";
|
||||
import { months, ONE_DAY } from "../helpers/date";
|
||||
import { SearchSuperContext } from "./appSearchSuper.";
|
||||
import { DEBUG } from "../lib/mtproto/mtproto_config";
|
||||
|
||||
// TODO: масштабирование картинок (не SVG) при ресайзе, и правильный возврат на исходную позицию
|
||||
// TODO: картинки "обрезаются" если возвращаются или появляются с места, где есть их перекрытие (топбар, поле ввода)
|
||||
@ -332,7 +333,9 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
|
||||
mover = this.setNewMover();
|
||||
} */
|
||||
|
||||
this.log('setMoverToTarget', target, closing, wasActive, fromRight);
|
||||
/* if(DEBUG) {
|
||||
this.log('setMoverToTarget', target, closing, wasActive, fromRight);
|
||||
} */
|
||||
|
||||
let realParent: HTMLElement;
|
||||
|
||||
@ -805,7 +808,9 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
|
||||
prevTargets: TargetType[] = [], nextTargets: TargetType[] = [], needLoadMore = true) {
|
||||
if(this.setMoverPromise) return this.setMoverPromise;
|
||||
|
||||
this.log('openMedia:', media, fromId, prevTargets, nextTargets);
|
||||
/* if(DEBUG) {
|
||||
this.log('openMedia:', media, fromId, prevTargets, nextTargets);
|
||||
} */
|
||||
|
||||
this.setAuthorInfo(fromId, timestamp);
|
||||
|
||||
@ -1263,7 +1268,9 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet
|
||||
minDate: this.searchContext.minDate,
|
||||
maxDate: this.searchContext.maxDate
|
||||
}).then(value => {
|
||||
this.log('loaded more media by maxId:', maxId, value, older, this.reverse);
|
||||
/* if(DEBUG) {
|
||||
this.log('loaded more media by maxId:', maxId, value, older, this.reverse);
|
||||
} */
|
||||
|
||||
if(value.next_rate) {
|
||||
this.searchContext.nextRate = value.next_rate;
|
||||
@ -1414,7 +1421,9 @@ export class AppMediaViewerAvatar extends AppMediaViewerBase<'', 'delete', AppMe
|
||||
return;
|
||||
}
|
||||
|
||||
this.log('loaded more media by maxId:', /* maxId, */value, older, this.reverse);
|
||||
// if(DEBUG) {
|
||||
// this.log('loaded more media by maxId:', /* maxId, */value, older, this.reverse);
|
||||
// }
|
||||
|
||||
if(value.photos.length < loadCount) {
|
||||
this.loadedAllMediaDown = true;
|
||||
|
@ -113,6 +113,8 @@ export default class ChatBubbles {
|
||||
public isHeavyAnimationInProgress = false;
|
||||
public scrollingToNewBubble: HTMLElement;
|
||||
|
||||
public isFirstLoad = true;
|
||||
|
||||
constructor(private chat: Chat, private appMessagesManager: AppMessagesManager, private appStickersManager: AppStickersManager, private appUsersManager: AppUsersManager, private appInlineBotsManager: AppInlineBotsManager, private appPhotosManager: AppPhotosManager, private appDocsManager: AppDocsManager, private appPeersManager: AppPeersManager, private appChatsManager: AppChatsManager) {
|
||||
//this.chat.log.error('Bubbles construction');
|
||||
|
||||
@ -371,10 +373,21 @@ export default class ChatBubbles {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
let middleware: ReturnType<ChatBubbles['getMiddleware']>;
|
||||
useHeavyAnimationCheck(() => {
|
||||
this.isHeavyAnimationInProgress = true;
|
||||
this.lazyLoadQueue.lock();
|
||||
middleware = this.getMiddleware();
|
||||
}, () => {
|
||||
this.isHeavyAnimationInProgress = false;
|
||||
|
||||
if(middleware && middleware()) {
|
||||
this.lazyLoadQueue.unlock();
|
||||
this.lazyLoadQueue.refresh();
|
||||
}
|
||||
|
||||
middleware = null;
|
||||
}, this.listenerSetter);
|
||||
}
|
||||
|
||||
@ -1274,6 +1287,8 @@ export default class ChatBubbles {
|
||||
if(maxBubbleId <= 0) {
|
||||
maxBubbleId = Math.max(...Object.keys(this.bubbles).map(mid => +mid));
|
||||
}
|
||||
} else {
|
||||
this.isFirstLoad = true;
|
||||
}
|
||||
|
||||
const oldChatInner = this.chatInner;
|
||||
@ -1288,14 +1303,12 @@ export default class ChatBubbles {
|
||||
|
||||
// clear
|
||||
if(!cached) {
|
||||
this.scrollable.container.innerHTML = '';
|
||||
//oldChatInner.remove();
|
||||
|
||||
if(!samePeer) {
|
||||
this.scrollable.container.innerHTML = '';
|
||||
//oldChatInner.remove();
|
||||
this.chat.finishPeerChange(isTarget, isJump, lastMsgId);
|
||||
this.preloader.attach(this.bubblesContainer);
|
||||
}
|
||||
|
||||
this.preloader.attach(this.bubblesContainer);
|
||||
}
|
||||
|
||||
//console.timeEnd('appImManager setPeer pre promise');
|
||||
@ -1304,13 +1317,13 @@ export default class ChatBubbles {
|
||||
const setPeerPromise = promise.then(() => {
|
||||
////this.log('setPeer removing preloader');
|
||||
|
||||
this.scrollable.container.innerHTML = '';
|
||||
//oldChatInner.remove();
|
||||
|
||||
if(cached) {
|
||||
if(!samePeer) {
|
||||
this.chat.finishPeerChange(isTarget, isJump, lastMsgId); // * костыль
|
||||
}
|
||||
|
||||
this.scrollable.container.innerHTML = '';
|
||||
//oldChatInner.remove();
|
||||
} else {
|
||||
this.preloader.detach();
|
||||
}
|
||||
@ -1399,7 +1412,9 @@ export default class ChatBubbles {
|
||||
else dateMessage.container.append(bubble);
|
||||
return; */
|
||||
|
||||
//this.log('renderMessagesQueue');
|
||||
/* if(DEBUG && message.mid === 4314759167) {
|
||||
this.log('renderMessagesQueue', message, bubble, reverse, promises);
|
||||
} */
|
||||
|
||||
this.messagesQueue.push({message, bubble, reverse, promises});
|
||||
|
||||
@ -2488,13 +2503,16 @@ export default class ChatBubbles {
|
||||
let resultPromise: Promise<any>;
|
||||
|
||||
//const isFirstMessageRender = !!additionMsgID && result instanceof Promise && !appMessagesManager.getMessage(additionMsgID).grouped_id;
|
||||
const isFirstMessageRender = additionMsgIds?.length;
|
||||
if(isFirstMessageRender) {
|
||||
const isAdditionRender = additionMsgIds?.length;
|
||||
const isFirstMessageRender = (this.isFirstLoad && backLimit) || isAdditionRender;
|
||||
if(isAdditionRender) {
|
||||
resultPromise = result as Promise<any>;
|
||||
result = {history: additionMsgIds};
|
||||
//additionMsgID = 0;
|
||||
}
|
||||
|
||||
this.isFirstLoad = false;
|
||||
|
||||
const processResult = (historyResult: typeof result) => {
|
||||
if(this.chat.type === 'discussion' && 'offsetIdOffset' in historyResult) {
|
||||
const isTopEnd = historyResult.offsetIdOffset >= (historyResult.count - loadCount);
|
||||
@ -2531,7 +2549,7 @@ export default class ChatBubbles {
|
||||
////console.timeEnd('render history total');
|
||||
|
||||
return getHeavyAnimationPromise().then(() => {
|
||||
return this.performHistoryResult(result.history || [], reverse, isBackLimit, !isFirstMessageRender && additionMsgId);
|
||||
return this.performHistoryResult(result.history || [], reverse, isBackLimit, !isAdditionRender && additionMsgId);
|
||||
});
|
||||
}, (err) => {
|
||||
this.log.error('getHistory error:', err);
|
||||
@ -2552,44 +2570,84 @@ export default class ChatBubbles {
|
||||
//this.log('getHistory cached result by maxId:', maxId, reverse, isBackLimit, result, peerId, justLoad);
|
||||
processResult(result);
|
||||
promise = getHeavyAnimationPromise().then(() => {
|
||||
return this.performHistoryResult((result as HistoryResult).history || [], reverse, isBackLimit, !isFirstMessageRender && additionMsgId);
|
||||
return this.performHistoryResult((result as HistoryResult).history || [], reverse, isBackLimit, !isAdditionRender && additionMsgId);
|
||||
});
|
||||
//return (reverse ? this.getHistoryTopPromise = promise : this.getHistoryBottomPromise = promise);
|
||||
//return this.performHistoryResult(result.history || [], reverse, isBackLimit, additionMsgID, true);
|
||||
}
|
||||
|
||||
const waitPromise = isFirstMessageRender ? processPromise(resultPromise) : promise;
|
||||
const waitPromise = isAdditionRender ? processPromise(resultPromise) : promise;
|
||||
|
||||
if(isFirstMessageRender) {
|
||||
waitPromise.then(() => {
|
||||
if(rootScope.settings.animationsEnabled) {
|
||||
const mids = getObjectKeysAndSort(this.bubbles, 'desc').filter(mid => !additionMsgIds.includes(mid));
|
||||
const animationPromise = deferredPromise<void>();
|
||||
if(rootScope.settings.animationsEnabled && Object.keys(this.bubbles).length) {
|
||||
let sortedMids = getObjectKeysAndSort(this.bubbles, 'desc');
|
||||
|
||||
let lastMsDelay = 0;
|
||||
mids.forEach((mid, idx) => {
|
||||
const bubble = this.bubbles[mid];
|
||||
if(isAdditionRender && additionMsgIds.length) {
|
||||
sortedMids = sortedMids.filter(mid => !additionMsgIds.includes(mid));
|
||||
}
|
||||
|
||||
let targetMid: number;
|
||||
if(backLimit) {
|
||||
targetMid = maxId;
|
||||
} else {
|
||||
if(additionMsgId) {
|
||||
targetMid = additionMsgId;
|
||||
} else { // * if maxId === 0
|
||||
targetMid = Math.max(...sortedMids);
|
||||
}
|
||||
}
|
||||
|
||||
const topIds = sortedMids.slice(sortedMids.findIndex(mid => targetMid > mid));
|
||||
const middleIds = isAdditionRender ? [] : [targetMid];
|
||||
const bottomIds = sortedMids.slice(0, sortedMids.findIndex(mid => targetMid >= mid)).reverse();
|
||||
|
||||
/* this.log('getHistory: targeting mid:', targetMid,
|
||||
topIds.map(m => this.appMessagesManager.getLocalMessageId(m)),
|
||||
bottomIds.map(m => this.appMessagesManager.getLocalMessageId(m))); */
|
||||
|
||||
const delay = isAdditionRender ? 10 : 40;
|
||||
const offsetIndex = isAdditionRender ? 0 : 1;
|
||||
const animateAsLadder = (mids: number[], offsetIndex = 0) => {
|
||||
const animationPromise = deferredPromise<void>();
|
||||
let lastMsDelay = 0;
|
||||
mids.forEach((mid, idx) => {
|
||||
const bubble = this.bubbles[mid];
|
||||
|
||||
lastMsDelay = ((idx + offsetIndex) || 0.1) * delay;
|
||||
//lastMsDelay = (idx || 0.1) * 1000;
|
||||
//if(idx || isSafari) {
|
||||
// ! 0.1 = 1ms задержка для Safari, без этого первое сообщение над самым нижним может появиться позже другого с animation-delay, LOL !
|
||||
bubble.style.animationDelay = lastMsDelay + 'ms';
|
||||
//}
|
||||
|
||||
lastMsDelay = ((idx || 0.1) * 10);
|
||||
//if(idx || isSafari) {
|
||||
// ! 0.1 = 1ms задержка для Safari, без этого первое сообщение над самым нижним может появиться позже другого с animation-delay, LOL !
|
||||
bubble.style.animationDelay = lastMsDelay + 'ms';
|
||||
//}
|
||||
bubble.classList.add('zoom-fade');
|
||||
bubble.addEventListener('animationend', () => {
|
||||
bubble.style.animationDelay = '';
|
||||
bubble.classList.remove('zoom-fade');
|
||||
|
||||
bubble.classList.add('zoom-fade');
|
||||
bubble.addEventListener('animationend', () => {
|
||||
bubble.style.animationDelay = '';
|
||||
bubble.classList.remove('zoom-fade');
|
||||
if(idx === (mids.length - 1)) {
|
||||
animationPromise.resolve();
|
||||
}
|
||||
}, {once: true});
|
||||
//this.log('supa', bubble);
|
||||
});
|
||||
|
||||
if(idx === (mids.length - 1)) {
|
||||
animationPromise.resolve();
|
||||
}
|
||||
}, {once: true});
|
||||
//this.log('supa', bubble);
|
||||
});
|
||||
if(!mids.length) {
|
||||
animationPromise.resolve();
|
||||
}
|
||||
|
||||
if(mids.length) {
|
||||
dispatchHeavyAnimationEvent(animationPromise, lastMsDelay);
|
||||
return {lastMsDelay, animationPromise};
|
||||
};
|
||||
|
||||
const topRes = animateAsLadder(topIds, offsetIndex);
|
||||
const middleRes = animateAsLadder(middleIds);
|
||||
const bottomRes = animateAsLadder(bottomIds, offsetIndex);
|
||||
const promises = [topRes.animationPromise, middleRes.animationPromise, bottomRes.animationPromise];
|
||||
const delays: number[] = [topRes.lastMsDelay, middleRes.lastMsDelay, bottomRes.lastMsDelay];
|
||||
|
||||
if(topIds.length || middleIds.length || bottomIds.length) {
|
||||
dispatchHeavyAnimationEvent(Promise.all(promises), Math.max(...delays));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -491,7 +491,7 @@ export default class ChatInput {
|
||||
}
|
||||
|
||||
public saveDraft() {
|
||||
if(!this.chat.peerId) return;
|
||||
if(!this.chat.peerId || this.editMsgId) return;
|
||||
|
||||
const entities: MessageEntity[] = [];
|
||||
const str = getRichValue(this.messageInputField.input, entities);
|
||||
@ -537,17 +537,18 @@ export default class ChatInput {
|
||||
}
|
||||
|
||||
public setDraft(draft?: MyDraftMessage, fromUpdate = true) {
|
||||
if(!isInputEmpty(this.messageInput)) return;
|
||||
if(!isInputEmpty(this.messageInput)) return false;
|
||||
|
||||
if(!draft) {
|
||||
draft = this.appDraftsManager.getDraft(this.chat.peerId, this.chat.threadId);
|
||||
|
||||
if(!draft) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
this.setInputValue(draft.rMessage, fromUpdate, fromUpdate);
|
||||
return true;
|
||||
}
|
||||
|
||||
public finishPeerChange() {
|
||||
@ -954,7 +955,9 @@ export default class ChatInput {
|
||||
}
|
||||
}
|
||||
|
||||
this.saveDraftDebounced();
|
||||
if(!this.editMsgId) {
|
||||
this.saveDraftDebounced();
|
||||
}
|
||||
|
||||
this.updateSendBtn();
|
||||
};
|
||||
@ -1105,7 +1108,7 @@ export default class ChatInput {
|
||||
}
|
||||
};
|
||||
|
||||
public clearInput() {
|
||||
public clearInput(canSetDraft = true) {
|
||||
if(isTouchSupported) {
|
||||
this.messageInput.innerText = '';
|
||||
} else {
|
||||
@ -1118,7 +1121,14 @@ export default class ChatInput {
|
||||
this.canUndoFromHTML = '';
|
||||
}
|
||||
|
||||
this.onMessageInput();
|
||||
let set = false;
|
||||
if(canSetDraft) {
|
||||
set = this.setDraft(undefined, false);
|
||||
}
|
||||
|
||||
if(!set) {
|
||||
this.onMessageInput();
|
||||
}
|
||||
}
|
||||
|
||||
public isInputEmpty() {
|
||||
|
@ -13,8 +13,8 @@ const set = (elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLVideoE
|
||||
};
|
||||
|
||||
// проблема функции в том, что она не подходит для ссылок, пригодна только для blob'ов, потому что обычным ссылкам нужен 'load' каждый раз.
|
||||
export function renderImageFromUrl(elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLVideoElement, url: string, callback?: (err?: Event) => void): boolean {
|
||||
if((loadedURLs[url]/* && false */) || elem instanceof HTMLVideoElement) {
|
||||
export function renderImageFromUrl(elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLVideoElement, url: string, callback?: (err?: Event) => void, useCache = false): boolean {
|
||||
if(((loadedURLs[url]/* && false */) && useCache) || elem instanceof HTMLVideoElement) {
|
||||
set(elem, url);
|
||||
callback && callback();
|
||||
return true;
|
||||
|
@ -69,7 +69,7 @@ export default class ProgressivePreloader {
|
||||
promise.notify = null;
|
||||
|
||||
if(tempId === this.tempId) {
|
||||
if(successfully) {
|
||||
if(successfully && this.cancelable) {
|
||||
this.setProgress(100);
|
||||
|
||||
setTimeout(() => { // * wait for transition complete
|
||||
|
@ -83,7 +83,7 @@ export default function fastSmoothScroll(
|
||||
});
|
||||
});
|
||||
|
||||
return dispatchHeavyAnimationEvent(promise);
|
||||
return axis === 'y' ? dispatchHeavyAnimationEvent(promise) : promise;
|
||||
}
|
||||
|
||||
function scrollWithJs(
|
||||
@ -225,7 +225,7 @@ function scrollWithJs(
|
||||
return t < 1;
|
||||
};
|
||||
|
||||
if(!duration) {
|
||||
if(!duration || !path) {
|
||||
cancelAnimationByKey(container);
|
||||
tick();
|
||||
return Promise.resolve();
|
||||
|
@ -156,15 +156,13 @@ export class AppDraftsManager {
|
||||
} else {
|
||||
draftObj = {_: 'draftMessage'} as any as DraftMessage.draftMessage;
|
||||
let message = localDraft.message;
|
||||
let entities: MessageEntity[] = [];
|
||||
//message = RichTextProcessor.parseEmojis(message);
|
||||
//message = RichTextProcessor.parseMarkdown(message, entities, true);
|
||||
let entities: MessageEntity[] = localDraft.entities;
|
||||
|
||||
if(localDraft.reply_to_msg_id) {
|
||||
params.reply_to_msg_id = draftObj.reply_to_msg_id = localDraft.reply_to_msg_id;
|
||||
}
|
||||
|
||||
if(entities.length) {
|
||||
if(entities?.length) {
|
||||
params.entities = draftObj.entities = entities;
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ import appUsersManager from "./appUsersManager";
|
||||
#2996ad 11 sea
|
||||
#ce671b 5 orange
|
||||
*/
|
||||
const DialogColorsFg = ['#c03d33', '#4fad2d', '#d09306', '#168acd', '#8544d6', '#cd4073', '#2996ad', '#ce671b'];
|
||||
const DialogColorsFg = ['#fc5c51', '#0fb297', '#d09306', '#3d72ed', '#895dd5', '#cd4073', '#00c1a6', '#fa790f'];
|
||||
const DialogColors = ['red', 'green', 'yellow', 'blue', 'violet', 'pink', 'cyan', 'orange'];
|
||||
const DialogColorsMap = [0, 7, 4, 1, 6, 3, 5];
|
||||
|
||||
|
@ -14,10 +14,6 @@
|
||||
min-width: 1.25rem;
|
||||
line-height: 1.25rem !important;
|
||||
padding: 0 5.75px;
|
||||
|
||||
html.is-safari & {
|
||||
line-height: 22px !important;
|
||||
}
|
||||
}
|
||||
|
||||
&-24 {
|
||||
|
@ -97,7 +97,8 @@ $bubble-margin: .25rem;
|
||||
} */
|
||||
|
||||
&.is-highlighted:after {
|
||||
background-color: rgba(0, 132, 255, .3);
|
||||
//background-color: rgba(0, 132, 255, .3);
|
||||
background-color: rgba(77, 142, 80, .4);
|
||||
|
||||
body:not(.animation-level-0) & {
|
||||
animation: bubbleSelected 2s linear;
|
||||
|
@ -140,6 +140,7 @@
|
||||
padding: 0 6px;
|
||||
opacity: 1;
|
||||
left: .75rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -106,6 +106,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
.folders-tabs-scrollable li:first-child {
|
||||
margin-left: .6875rem;
|
||||
}
|
||||
|
||||
.item-main {
|
||||
.input-search {
|
||||
/* &-input {
|
||||
|
Loading…
x
Reference in New Issue
Block a user