Browse Source

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
master
morethanwords 4 years ago
parent
commit
abf1acc6c8
  1. 17
      src/components/appMediaViewer.ts
  2. 132
      src/components/chat/bubbles.ts
  3. 22
      src/components/chat/input.ts
  4. 4
      src/components/misc.ts
  5. 2
      src/components/preloader.ts
  6. 4
      src/helpers/fastSmoothScroll.ts
  7. 6
      src/lib/appManagers/appDraftsManager.ts
  8. 2
      src/lib/appManagers/appPeersManager.ts
  9. 4
      src/scss/partials/_badge.scss
  10. 3
      src/scss/partials/_chatBubble.scss
  11. 1
      src/scss/partials/_input.scss
  12. 4
      src/scss/partials/_leftSidebar.scss

17
src/components/appMediaViewer.ts

@ -27,6 +27,7 @@ import appSidebarRight, { AppSidebarRight } from "./sidebarRight"; @@ -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 @@ -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 @@ -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 @@ -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 @@ -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;

132
src/components/chat/bubbles.ts

@ -113,6 +113,8 @@ export default class ChatBubbles { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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');
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);
}
}
let lastMsDelay = 0;
mids.forEach((mid, idx) => {
const bubble = this.bubbles[mid];
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();
}
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(mids.length) {
dispatchHeavyAnimationEvent(animationPromise, lastMsDelay);
if(topIds.length || middleIds.length || bottomIds.length) {
dispatchHeavyAnimationEvent(Promise.all(promises), Math.max(...delays));
}
}

22
src/components/chat/input.ts

@ -491,7 +491,7 @@ export default class ChatInput { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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() {

4
src/components/misc.ts

@ -13,8 +13,8 @@ const set = (elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLVideoE @@ -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;

2
src/components/preloader.ts

@ -69,7 +69,7 @@ export default class ProgressivePreloader { @@ -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

4
src/helpers/fastSmoothScroll.ts

@ -83,7 +83,7 @@ export default function fastSmoothScroll( @@ -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( @@ -225,7 +225,7 @@ function scrollWithJs(
return t < 1;
};
if(!duration) {
if(!duration || !path) {
cancelAnimationByKey(container);
tick();
return Promise.resolve();

6
src/lib/appManagers/appDraftsManager.ts

@ -156,15 +156,13 @@ export class AppDraftsManager { @@ -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;
}

2
src/lib/appManagers/appPeersManager.ts

@ -18,7 +18,7 @@ import appUsersManager from "./appUsersManager"; @@ -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];

4
src/scss/partials/_badge.scss

@ -14,10 +14,6 @@ @@ -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 {

3
src/scss/partials/_chatBubble.scss

@ -97,7 +97,8 @@ $bubble-margin: .25rem; @@ -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;

1
src/scss/partials/_input.scss

@ -140,6 +140,7 @@ @@ -140,6 +140,7 @@
padding: 0 6px;
opacity: 1;
left: .75rem;
font-weight: 500;
}
}
}

4
src/scss/partials/_leftSidebar.scss

@ -106,6 +106,10 @@ @@ -106,6 +106,10 @@
}
}
.folders-tabs-scrollable li:first-child {
margin-left: .6875rem;
}
.item-main {
.input-search {
/* &-input {

Loading…
Cancel
Save