diff --git a/src/components/chat/bubbles.ts b/src/components/chat/bubbles.ts index 7b33a55f3..82e566e66 100644 --- a/src/components/chat/bubbles.ts +++ b/src/components/chat/bubbles.ts @@ -4155,7 +4155,8 @@ export default class ChatBubbles { if(wrapped?.onclick === 'im') { const map: {[type: string]: LangPackKey} = { telegram_channel: 'Chat.Message.ViewChannel', - telegram_megagroup: 'OpenGroup' + telegram_megagroup: 'OpenGroup', + telegram_bot: 'Chat.Message.ViewBot' }; const langPackKey = map[webPage.type] || 'OpenMessage'; diff --git a/src/components/chat/input.ts b/src/components/chat/input.ts index 582c824ea..a13ae1e82 100644 --- a/src/components/chat/input.ts +++ b/src/components/chat/input.ts @@ -237,6 +237,8 @@ export default class ChatInput { private sendAs: ChatSendAs; public sendAsPeerId: PeerId; + private replyInTopicOverlay: HTMLDivElement; + constructor( private chat: Chat, private appImManager: AppImManager, @@ -480,6 +482,10 @@ export default class ChatInput { this.newMessageWrapper = document.createElement('div'); this.newMessageWrapper.classList.add('new-message-wrapper'); + this.replyInTopicOverlay = document.createElement('div'); + this.replyInTopicOverlay.classList.add('reply-in-topic-overlay', 'hide'); + this.replyInTopicOverlay.append(i18n('Chat.Input.ReplyToAnswer')); + this.btnToggleEmoticons = ButtonIcon('none toggle-emoticons', {noRipple: true}); this.inputMessageContainer = document.createElement('div'); @@ -983,7 +989,7 @@ export default class ChatInput { }); }, {listenerSetter: this.listenerSetter}); - this.controlContainer.append(this.botStartBtn); + this.controlContainer.append(this.botStartBtn, this.replyInTopicOverlay); // * pinned part start this.pinnedControlBtn = Button('btn-primary btn-transparent text-bold chat-input-control-button', {icon: 'unpin'}); @@ -1095,6 +1101,13 @@ export default class ChatInput { this.center(true); } + public isReplyInTopicOverlayNeeded() { + return this.chat.isForum && + !this.chat.isForumTopic && + !this.replyToMsgId && + this.chat.type === 'chat'; + } + public async getNeededFakeContainer(startParam = this.startParam) { if(this.chat.selection.isSelecting) { return this.fakeSelectionWrapper; @@ -1102,7 +1115,8 @@ export default class ChatInput { startParam !== undefined || !(await this.chat.canSend()) || this.chat.type === 'pinned' || - await this.chat.isStartButtonNeeded() + await this.chat.isStartButtonNeeded() || + this.isReplyInTopicOverlayNeeded() ) { return this.controlContainer; } @@ -1442,12 +1456,21 @@ export default class ChatInput { this.messageInput.dataset.peerId = '' + peerId; } + let haveSomethingInControl = false; if(this.pinnedControlBtn) { - this.pinnedControlBtn.classList.toggle('hide', this.chat.type !== 'pinned'); + const good = this.chat.type === 'pinned'; + haveSomethingInControl ||= good; + this.pinnedControlBtn.classList.toggle('hide', !good); this.pinnedControlBtn.replaceChildren(i18n(canPinMessage ? 'Chat.Input.UnpinAll' : 'Chat.Pinned.DontShow')); } - this.botStartBtn.classList.toggle('hide', this.chat.type === 'pinned'); + { + const good = this.chat.isForum && !this.chat.isForumTopic && this.chat.type === 'chat'; + haveSomethingInControl ||= good; + this.replyInTopicOverlay.classList.toggle('hide', !good); + } + + this.botStartBtn.classList.toggle('hide', haveSomethingInControl); // * testing // this.startParam = this.appPeersManager.isBot(peerId) ? '123' : undefined; @@ -2945,11 +2968,16 @@ export default class ChatInput { } this.setTopInfo('reply', f, peerTitleEl, message && (message as Message.message).message, undefined, message); - this.replyToMsgId = mid; + this.setReplyToMsgId(mid) }; f(); } + public setReplyToMsgId(mid: number) { + this.replyToMsgId = mid; + this.center(true); + } + public clearHelper(type?: ChatInputHelperType) { if(this.helperType === 'edit' && type !== 'edit') { this.clearInput(); @@ -2962,7 +2990,7 @@ export default class ChatInput { } if(type !== 'reply') { - this.replyToMsgId = undefined; + this.setReplyToMsgId(undefined); this.forwarding = undefined; } diff --git a/src/config/app.ts b/src/config/app.ts index 610455c38..8204a80f5 100644 --- a/src/config/app.ts +++ b/src/config/app.ts @@ -21,7 +21,7 @@ const App = { version: process.env.VERSION, versionFull: process.env.VERSION_FULL, build: +process.env.BUILD, - langPackVersion: '0.7.1', + langPackVersion: '0.7.2', langPack: 'webk', langPackCode: 'en', domains: MAIN_DOMAINS, diff --git a/src/lang.ts b/src/lang.ts index 4b45e59b1..671075a19 100644 --- a/src/lang.ts +++ b/src/lang.ts @@ -929,6 +929,7 @@ const lang = { 'Chat.DropQuickDesc': 'in a quick way', 'Chat.DropAsFilesDesc': 'without compression', 'Chat.Edit.Cancel.Text': 'Are you sure you want to discard all changes?', + 'Chat.Input.ReplyToAnswer': 'Reply to message in topics', 'Chat.SendVoice.PrivacyError': '%@ doesn\'t accept voice and video messages', 'Chat.Service.Call.Cancelled': 'Cancelled', 'Chat.Service.Call.Missed': 'Missed', diff --git a/src/lib/appManagers/appMessagesManager.ts b/src/lib/appManagers/appMessagesManager.ts index 978fe1a1e..9cd714233 100644 --- a/src/lib/appManagers/appMessagesManager.ts +++ b/src/lib/appManagers/appMessagesManager.ts @@ -1567,13 +1567,21 @@ export class AppMessagesManager extends AppManager { } private generateReplyHeader(peerId: PeerId, replyToMsgId: number, replyToTopId?: number) { + const isForum = this.appPeersManager.isForum(peerId); + if(isForum && !replyToTopId) { + const originalMessage = this.getMessageByPeer(peerId, replyToMsgId); + if(originalMessage) { + replyToTopId = getMessageThreadId(originalMessage, true); + } + } + const header: MessageReplyHeader = { _: 'messageReplyHeader', reply_to_msg_id: replyToMsgId || replyToTopId, pFlags: {} }; - if(replyToTopId && this.appPeersManager.isForum(peerId) && GENERAL_TOPIC_ID !== replyToTopId) { + if(replyToTopId && isForum && GENERAL_TOPIC_ID !== replyToTopId) { header.pFlags.forum_topic = true; } diff --git a/src/lib/appManagers/utils/users/canSendToUser.ts b/src/lib/appManagers/utils/users/canSendToUser.ts index 99ba4f5ec..8d0430781 100644 --- a/src/lib/appManagers/utils/users/canSendToUser.ts +++ b/src/lib/appManagers/utils/users/canSendToUser.ts @@ -8,5 +8,5 @@ import {User} from '../../../../layer'; import {REPLIES_PEER_ID} from '../../../mtproto/mtproto_config'; export default function canSendToUser(user: User.user) { - return !user.pFlags.deleted && user.id.toPeerId() !== REPLIES_PEER_ID; + return !!(user && !user.pFlags.deleted && user.id.toPeerId() !== REPLIES_PEER_ID); } diff --git a/src/scss/partials/_chat.scss b/src/scss/partials/_chat.scss index 48a64646c..a2454e4a7 100644 --- a/src/scss/partials/_chat.scss +++ b/src/scss/partials/_chat.scss @@ -521,6 +521,23 @@ $chat-input-border-radius: 1rem; opacity: 1; } + .reply-in-topic-overlay { + // position: absolute; + // top: 0; + // right: 0; + // bottom: 0; + // left: 0; + background-color: inherit; + border-radius: inherit; + z-index: 3; + display: flex; + align-items: center; + justify-content: center; + color: var(--secondary-text-color); + pointer-events: none; + padding: 0 1rem; + } + .bubbles.is-selecting:not(.backwards) ~ & { .selection-wrapper { opacity: 1;