diff --git a/.env b/.env index bbd726a3..107665b0 100644 --- a/.env +++ b/.env @@ -1,5 +1,5 @@ API_ID=1025907 API_HASH=452b0359b988148995f22ff0f4229750 -VERSION=0.9.0 -VERSION_FULL=0.9.0 (13) -BUILD=13 +VERSION=0.9.1 +VERSION_FULL=0.9.1 (14) +BUILD=14 diff --git a/src/components/chat/bubbles.ts b/src/components/chat/bubbles.ts index 20e2cf14..f8ab946d 100644 --- a/src/components/chat/bubbles.ts +++ b/src/components/chat/bubbles.ts @@ -78,6 +78,7 @@ import AppMediaViewer from "../appMediaViewer"; import SetTransition from "../singleTransition"; import handleHorizontalSwipe from "../../helpers/dom/handleHorizontalSwipe"; import { cancelContextMenuOpening } from "../misc"; +import findUpAttribute from "../../helpers/dom/findUpAttribute"; const USE_MEDIA_TAILS = false; const IGNORE_ACTIONS: Set = new Set([ @@ -980,8 +981,8 @@ export default class ChatBubbles { return; } - const nameDiv = findUpClassName(target, 'peer-title') || findUpClassName(target, 'name') || findUpTag(target, 'AVATAR-ELEMENT'); - if(nameDiv) { + const nameDiv = findUpClassName(target, 'peer-title') || findUpClassName(target, 'name') || findUpTag(target, 'AVATAR-ELEMENT') || findUpAttribute(target, 'data-saved-from'); + if(nameDiv && nameDiv !== bubble) { target = nameDiv || target; const peerId = (target.dataset.peerId || target.getAttribute('peer')); const savedFrom = target.dataset.savedFrom; @@ -1517,7 +1518,7 @@ export default class ChatBubbles { bubble = this.bubbles[Math.max(...mids)]; } - const promise = this.scrollToBubbleEnd(bubble, true) || Promise.resolve(); + const promise = this.scrollToBubbleEnd(bubble) || Promise.resolve(); if(isPaddingNeeded) { promise.then(() => { // it will be called only once even if was set multiple times (that won't happen) if(middleware() && isPaddingNeeded) { @@ -1547,8 +1548,7 @@ export default class ChatBubbles { element: HTMLElement, position: ScrollLogicalPosition, forceDirection?: FocusDirection, - forceDuration?: number, - isNewMessage?: boolean + forceDuration?: number ) { // * 4 = .25rem const bubble = findUpClassName(element, 'bubble'); @@ -1562,6 +1562,7 @@ export default class ChatBubbles { } } + const isChangingHeight = this.chat.input.messageInput.classList.contains('is-changing-height') || this.chat.container.classList.contains('is-toggling-helper'); return this.scrollable.scrollIntoViewNew( element, position, @@ -1570,7 +1571,7 @@ export default class ChatBubbles { forceDirection, forceDuration, 'y', - isNewMessage ? ({rect}) => { + isChangingHeight ? ({rect}) => { // return rect.height; let height = windowSize.windowH; @@ -1586,7 +1587,7 @@ export default class ChatBubbles { ); } - public scrollToBubbleEnd(bubble = this.getLastBubble(), isNewMessage?: boolean) { + public scrollToBubbleEnd(bubble = this.getLastBubble()) { /* if(DEBUG) { this.log('scrollToNewLastBubble: will scroll into view:', bubble); } */ @@ -1594,7 +1595,7 @@ export default class ChatBubbles { if(bubble) { this.scrollingToBubble = bubble; const middleware = this.getMiddleware(); - return this.scrollToBubble(bubble, 'end', undefined, undefined, isNewMessage).then(() => { + return this.scrollToBubble(bubble, 'end', undefined, undefined).then(() => { if(!middleware()) return; this.scrollingToBubble = undefined; }); diff --git a/src/components/chat/input.ts b/src/components/chat/input.ts index 23a67a91..27dd9eb2 100644 --- a/src/components/chat/input.ts +++ b/src/components/chat/input.ts @@ -787,6 +787,16 @@ export default class ChatInput { if(!draft) { if(force) { // this situation can only happen when sending message with clearDraft + /* const height = this.chatInput.getBoundingClientRect().height; + const willChangeHeight = 78 - height; + this.willChangeHeight = willChangeHeight; */ + if(this.chat.container.classList.contains('is-helper-active')) { + this.t(); + } + + this.messageInputField.inputFake.textContent = ''; + this.messageInputField.onFakeInput(false); + ((this.chat.bubbles.messagesQueuePromise || Promise.resolve()) as Promise).then(() => { fastRaf(() => { this.onMessageSent(); @@ -2009,9 +2019,17 @@ export default class ChatInput { if(this.chat.container.classList.contains('is-helper-active')) { appNavigationController.removeByType('input-helper'); this.chat.container.classList.remove('is-helper-active'); + this.t(); } } + private t() { + const className = 'is-toggling-helper'; + SetTransition(this.chat.container, className, true, 150, () => { + this.chat.container.classList.remove(className); + }); + } + public setInputValue(value: string, clear = true, focus = true) { if(!value) value = ''; @@ -2055,7 +2073,11 @@ export default class ChatInput { replyParent.insertBefore(newReply, replyParent.lastElementChild); } - this.chat.container.classList.add('is-helper-active'); + if(!this.chat.container.classList.contains('is-helper-active')) { + this.chat.container.classList.add('is-helper-active'); + this.t(); + } + /* const scroll = appImManager.scrollable; if(scroll.isScrolledDown && !scroll.scrollLocked && !appImManager.messagesQueuePromise && !appImManager.setPeerPromise) { scroll.scrollTo(scroll.scrollHeight, 'top', true, true, 200); diff --git a/src/components/inputField.ts b/src/components/inputField.ts index ed20d2c4..e516d08b 100644 --- a/src/components/inputField.ts +++ b/src/components/inputField.ts @@ -11,6 +11,7 @@ import isInputEmpty from "../helpers/dom/isInputEmpty"; import selectElementContents from "../helpers/dom/selectElementContents"; import { i18n, LangPackKey, _i18n } from "../lib/langPack"; import RichTextProcessor from "../lib/richtextprocessor"; +import SetTransition from "./singleTransition"; let init = () => { document.addEventListener('paste', (e) => { @@ -236,22 +237,34 @@ class InputField { } } - public onFakeInput() { + public onFakeInput(setHeight = true) { const {scrollHeight: newHeight/* , clientHeight */} = this.inputFake; /* if(this.wasInputFakeClientHeight && this.wasInputFakeClientHeight !== clientHeight) { this.input.classList.add('no-scrollbar'); // ! в сафари может вообще не появиться скролл после анимации, так как ему нужен полный reflow блока с overflow. this.showScrollDebounced(); } */ - const TRANSITION_DURATION_FACTOR = 50; const currentHeight = +this.input.style.height.replace('px', ''); + if(currentHeight === newHeight) { + return; + } + + const TRANSITION_DURATION_FACTOR = 50; const transitionDuration = Math.round( TRANSITION_DURATION_FACTOR * Math.log(Math.abs(newHeight - currentHeight)), ); // this.wasInputFakeClientHeight = clientHeight; this.input.style.transitionDuration = `${transitionDuration}ms`; - this.input.style.height = newHeight ? newHeight + 'px' : ''; + + if(setHeight) { + this.input.style.height = newHeight ? newHeight + 'px' : ''; + } + + const className = 'is-changing-height'; + SetTransition(this.input, className, true, transitionDuration, () => { + this.input.classList.remove(className); + }); } get value() { diff --git a/src/lang.ts b/src/lang.ts index d4338c2b..df056464 100644 --- a/src/lang.ts +++ b/src/lang.ts @@ -615,6 +615,7 @@ const lang = { "Chat.Service.Channel.RemovedPhoto": "Channel photo removed", "Chat.Service.Channel.UpdatedVideo": "Channel video updated", "Chat.Service.BotPermissionAllowed": "You allowed this bot to message you when you logged in on %@", + "Chat.Service.Group.UpdatedPinnedMessage": "%@ pinned \"%@\"", "Chat.Service.VoiceChatFinished": "%1$@ ended the voice chat (%2$@)", "Chat.Service.VoiceChatFinishedYou": "You ended the voice chat (%@)", //"Chat.Service.VoiceChatScheduled": "%1$@ scheduled a [voice chat](open) for %2$@", diff --git a/src/lib/appManagers/appMessagesManager.ts b/src/lib/appManagers/appMessagesManager.ts index 962978a6..95092f29 100644 --- a/src/lib/appManagers/appMessagesManager.ts +++ b/src/lib/appManagers/appMessagesManager.ts @@ -2976,7 +2976,25 @@ export class AppMessagesManager { break; } - case 'messageActionPinMessage': + case 'messageActionPinMessage': { + const pinnedMessage = this.getMessageByPeer(message.peerId, message.reply_to_mid); + + args = [ + getNameDivHTML(message.fromId, plain), + ]; + + if(pinnedMessage.deleted || true) { + langPackKey = 'ActionPinnedNoText'; + } else { + const a = document.createElement('a'); + a.dataset.savedFrom = pinnedMessage.peerId + '_' + pinnedMessage.mid; + a.append(this.wrapMessageForReply(pinnedMessage, undefined, undefined, plain as any)); + args.push(a); + } + + break; + } + case 'messageActionContactSignUp': case 'messageActionChatReturn': case 'messageActionChatLeave': diff --git a/src/lib/langPack.ts b/src/lib/langPack.ts index 2e7c0eaa..1a817956 100644 --- a/src/lib/langPack.ts +++ b/src/lib/langPack.ts @@ -33,7 +33,7 @@ export const langPack: {[actionType: string]: LangPackKey} = { "messageActionChatLeaveYou": "YouLeft", "messageActionChatDeleteUser": "ActionKickUser", "messageActionChatJoinedByLink": "ActionInviteUser", - "messageActionPinMessage": "ActionPinnedNoText", + "messageActionPinMessage": "Chat.Service.Group.UpdatedPinnedMessage", "messageActionContactSignUp": "Chat.Service.PeerJoinedTelegram", "messageActionChannelCreate": "ActionCreateChannel", "messageActionChannelEditTitle": "Chat.Service.Channel.UpdatedTitle", diff --git a/src/scss/partials/_chatBubble.scss b/src/scss/partials/_chatBubble.scss index d2f5fa0b..8ae8d873 100644 --- a/src/scss/partials/_chatBubble.scss +++ b/src/scss/partials/_chatBubble.scss @@ -1963,6 +1963,7 @@ $bubble-beside-button-width: 38px; .peer-title { &:hover { text-decoration: underline; + cursor: pointer; } }