From cc8408d11c0de9e252476d88a444936786a1729b Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 26 Oct 2023 18:44:49 +0400 Subject: [PATCH] Fix draft options edit, add to topics/replies. --- .../SourceFiles/history/history_widget.cpp | 10 +- .../history_view_compose_controls.cpp | 105 +++++++++++------- .../controls/history_view_compose_controls.h | 1 + .../controls/history_view_draft_options.cpp | 8 +- .../view/history_view_context_menu.cpp | 12 +- .../history/view/history_view_context_menu.h | 1 + .../history/view/history_view_element.cpp | 2 +- .../history/view/history_view_list_widget.cpp | 4 + .../history/view/history_view_message.cpp | 99 ++++++++++------- Telegram/SourceFiles/mtproto/scheme/api.tl | 2 +- 10 files changed, 147 insertions(+), 97 deletions(-) diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 7f2f9077af..a916c48921 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -6246,6 +6246,11 @@ void HistoryWidget::mousePressEvent(QMouseEvent *e) { return; } else if (_previewDrawPreview) { editDraftOptions(); + } else if (_editMsgId) { + controller()->showPeerHistory( + _peer, + Window::SectionShow::Way::Forward, + _editMsgId); } else if (isReadyToForward) { if (e->button() != Qt::LeftButton) { _forwardPanel->editToNextOption(); @@ -6259,11 +6264,6 @@ void HistoryWidget::mousePressEvent(QMouseEvent *e) { _kbReplyTo->history()->peer->id, Window::SectionShow::Way::Forward, _kbReplyTo->id); - } else if (_editMsgId) { - controller()->showPeerHistory( - _peer, - Window::SectionShow::Way::Forward, - _editMsgId); } } diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp index c203735c8f..a54b671921 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -147,6 +147,7 @@ public: [[nodiscard]] rpl::producer editMsgIdValue() const; [[nodiscard]] rpl::producer scrollToItemRequests() const; [[nodiscard]] rpl::producer<> editPhotoRequests() const; + [[nodiscard]] rpl::producer<> editOptionsRequests() const; [[nodiscard]] MessageToEdit queryToEdit(); [[nodiscard]] FullReplyTo getDraftReply() const; @@ -221,6 +222,7 @@ private: rpl::event_stream _visibleChanged; rpl::event_stream _scrollToItemRequests; + rpl::event_stream<> _editOptionsRequests; rpl::event_stream<> _editPhotoRequests; }; @@ -333,7 +335,8 @@ void FieldHeader::init() { return (ranges::contains(kMouseEvents, type) || leaving) && (isEditingMessage() || readyToForward() - || replyingToMessage()); + || replyingToMessage() + || _preview.parsed); }) | rpl::start_with_next([=](not_null event) { const auto updateOver = [&](bool inClickable, bool inPhotoEdit) { if (_inClickable != inClickable) { @@ -377,40 +380,14 @@ void FieldHeader::init() { _editPhotoRequests.fire({}); } else if (isLeftButton && inPreviewRect) { const auto reply = replyingToMessage(); - if (!isEditingMessage() && readyToForward()) { + if (_preview.parsed) { + _editOptionsRequests.fire({}); + } else if (isEditingMessage()) { + _scrollToItemRequests.fire(_editMsgId.current()); + } else if (readyToForward()) { _forwardPanel->editOptions(_show); - } else if (!isEditingMessage() && reply) { - //using namespace Controls; - //const auto highlight = [=] { - // _scrollToItemRequests.fire_copy(reply.messageId); - //}; - //const auto history = _history; - //const auto topicRootId = _topicRootId; - //const auto done = [=]( - // FullReplyTo replyTo, - // Data::WebPageDraft webpage) { - // if (replyTo) { - // replyToMessage(replyTo); - // } else { - // _replyCancelled.fire({}); - // } - - //}; - //const auto clearOldReplyTo = [=, id = reply.messageId] { - // ClearDraftReplyTo(history, topicRootId, id); - //}; - //EditDraftOptions( - // _show, - // _history, - // Data::Draft( reply, - // done, - // highlight, - // clearOldReplyTo); - } else { - auto id = isEditingMessage() - ? _editMsgId.current() - : replyingToMessage().messageId; - _scrollToItemRequests.fire(std::move(id)); + } else if (reply) { + _editOptionsRequests.fire({}); } } } else if (type == QEvent::MouseButtonRelease) { @@ -429,9 +406,12 @@ void FieldHeader::updateShownMessageText() { .session = &_data->session(), .customEmojiRepaint = [=] { customEmojiRepaint(); }, }; + const auto reply = replyingToMessage(); _shownMessageText.setMarkedText( st::messageTextStyle, - _shownMessage->inReplyText(), + ((isEditingMessage() || reply.quote.empty()) + ? _shownMessage->inReplyText() + : reply.quote), Ui::DialogTextOptions(), context); } @@ -779,6 +759,10 @@ rpl::producer<> FieldHeader::editPhotoRequests() const { return _editPhotoRequests.events(); } +rpl::producer<> FieldHeader::editOptionsRequests() const { + return _editOptionsRequests.events(); +} + MessageToEdit FieldHeader::queryToEdit() { const auto item = _data->message(_editMsgId.current()); if (!isEditingMessage() || !item) { @@ -1372,6 +1356,41 @@ void ComposeControls::init() { crl::guard(_wrap.get(), [=] { cancelEditMessage(); })); }, _wrap->lifetime()); + _header->editOptionsRequests( + ) | rpl::start_with_next([=] { + const auto history = _history; + const auto reply = _header->replyingToMessage(); + const auto webpage = _preview->draft(); + + const auto done = [=]( + FullReplyTo replyTo, + Data::WebPageDraft webpage) { + if (replyTo) { + replyToMessage(replyTo); + } else { + cancelReplyMessage(); + } + _preview->apply(webpage); + }; + const auto replyToId = reply.messageId; + const auto highlight = crl::guard(_wrap.get(), [=] { + _scrollToItemRequests.fire_copy(replyToId); + }); + + using namespace HistoryView::Controls; + EditDraftOptions({ + .show = _show, + .history = history, + .draft = Data::Draft(_field, reply, _preview->draft()), + .usedLink = _preview->link(), + .links = _preview->links(), + .resolver = _preview->resolver(), + .done = done, + .highlight = highlight, + .clearOldDraft = [=] { ClearDraftReplyTo(history, replyToId); }, + }); + }, _wrap->lifetime()); + _header->previewCancelled( ) | rpl::start_with_next([=] { if (_preview) { @@ -2882,13 +2901,15 @@ Data::WebPageDraft ComposeControls::webPageDraft() const { } rpl::producer ComposeControls::scrollRequests() const { - return _header->scrollToItemRequests( - ) | rpl::map([=](FullMsgId id) -> Data::MessagePosition { - if (const auto item = session().data().message(id)) { - return item->position(); - } - return {}; - }); + return rpl::merge( + _header->scrollToItemRequests(), + _scrollToItemRequests.events() + ) | rpl::map([=](FullMsgId id) -> Data::MessagePosition { + if (const auto item = session().data().message(id)) { + return item->position(); + } + return {}; + }); } bool ComposeControls::isEditingMessage() const { diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h index d6a132af26..18a76132ef 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h @@ -357,6 +357,7 @@ private: const std::unique_ptr _wrap; const std::unique_ptr _writeRestricted; + rpl::event_stream _scrollToItemRequests; std::optional _backgroundRect; diff --git a/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp b/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp index bee32e72b5..8d01071578 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp @@ -247,10 +247,9 @@ PreviewWrap::~PreviewWrap() { rpl::producer PreviewWrap::showQuoteSelector( not_null item, const TextWithEntities "e) { - auto element = item->createView(_delegate.get()); - _selection.reset(element->selectionFromQuote(quote)); - _element = std::move(element); + _selection.reset(TextSelection()); + _element = item->createView(_delegate.get()); _link = _pressedLink = nullptr; if (const auto was = base::take(_draftItem)) { @@ -266,6 +265,7 @@ rpl::producer PreviewWrap::showQuoteSelector( initElement(); + _selection = _element->selectionFromQuote(quote); return _selection.value( ) | rpl::map([=](TextSelection selection) { return _element->selectedQuote(selection); @@ -596,7 +596,7 @@ auto PreviewDelegate::elementPathShiftGradient() } Context PreviewDelegate::elementContext() { - return Context::History; + return Context::Replies; } void AddFilledSkip(not_null container) { diff --git a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp index 958611083d..8bad63c021 100644 --- a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp +++ b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp @@ -605,13 +605,18 @@ bool AddReplyToMessageAction( return false; } + const auto "e = request.quote; + auto text = quote.empty() + ? tr::lng_context_reply_msg(tr::now) + : tr::lng_context_quote_and_reply(tr::now); + text.replace('&', u"&&"_q); const auto owner = &item->history()->owner(); const auto itemId = item->fullId(); - menu->addAction(tr::lng_context_reply_msg(tr::now), [=] { + menu->addAction(text, [=] { if (!item) { return; } else { - list->replyToMessageRequestNotify({ itemId }); + list->replyToMessageRequestNotify({ itemId, quote }); } }, &st::menuIconReply); return true; @@ -936,7 +941,6 @@ void AddTopMessageActions( not_null menu, const ContextMenuRequest &request, not_null list) { - AddReplyToMessageAction(menu, request, list); AddGoToMessageAction(menu, request, list); AddViewRepliesAction(menu, request, list); AddEditMessageAction(menu, request, list); @@ -1008,6 +1012,8 @@ base::unique_qptr FillContextMenu( list, st::popupMenuWithIcons); + AddReplyToMessageAction(result, request, list); + if (request.overSelection && !list->hasCopyRestrictionForSelected() && !list->getSelectedText().empty()) { diff --git a/Telegram/SourceFiles/history/view/history_view_context_menu.h b/Telegram/SourceFiles/history/view/history_view_context_menu.h index d534d9c248..64040ae413 100644 --- a/Telegram/SourceFiles/history/view/history_view_context_menu.h +++ b/Telegram/SourceFiles/history/view/history_view_context_menu.h @@ -47,6 +47,7 @@ struct ContextMenuRequest { HistoryItem *item = nullptr; SelectedItems selectedItems; TextForMimeData selectedText; + TextWithEntities quote; bool overSelection = false; PointState pointState = PointState(); }; diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp index 1f3acc5433..61900f20fa 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.cpp +++ b/Telegram/SourceFiles/history/view/history_view_element.cpp @@ -802,7 +802,7 @@ auto Element::contextDependentServiceText() -> TextWithLinks { if (!info) { return {}; } - if (_delegate->elementContext() == Context::Replies) { + if (_context == Context::Replies) { if (info->created()) { return { { tr::lng_action_topic_created_inside(tr::now) } }; } diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index e3e979285e..2938fffdd3 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -2576,6 +2576,7 @@ void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { : _overElement ? _overElement->data().get() : nullptr; + const auto overItemView = viewForItem(overItem); const auto clickedReaction = link ? link->property( kReactionsCountEmojiProperty).value() @@ -2602,6 +2603,9 @@ void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { request.view = _overElement; request.item = overItem; request.pointState = _overState.pointState; + request.quote = (overItemView && _selectedTextItem == overItem) + ? overItemView->selectedQuote(_selectedTextRange) + : TextWithEntities(); request.selectedText = _selectedText; request.selectedItems = collectSelectedItems(); const auto hasSelection = !request.selectedItems.empty() diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index 042cfb21bb..f215e2bdd6 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -94,7 +94,7 @@ const auto kPsaTooltipPrefix = "cloud_lng_tooltip_psa_"; const auto i = ranges::find(left, cut); if (i != left.end()) { left.erase(i); - } else if (!ranges::contains(allowed, cut.type())) { + } else if (ranges::contains(allowed, cut.type())) { return false; } } @@ -2615,7 +2615,8 @@ TextForMimeData Message::selectedText(TextSelection selection) const { const auto media = this->media(); auto logEntryOriginalResult = TextForMimeData(); const auto mediaDisplayed = (media && media->isDisplayed()); - const auto textSelection = (mediaDisplayed && invertMedia()) + const auto mediaBefore = mediaDisplayed && invertMedia(); + const auto textSelection = mediaBefore ? media->skipSelection(selection) : selection; const auto mediaSelection = !invertMedia() @@ -2628,19 +2629,15 @@ TextForMimeData Message::selectedText(TextSelection selection) const { ? media->selectedText(mediaSelection) : TextForMimeData(); if (auto entry = logEntryOriginal()) { - const auto originalSelection = (mediaDisplayed && invertMedia()) + const auto originalSelection = mediaBefore ? skipTextSelection(textSelection) : mediaDisplayed ? media->skipSelection(mediaSelection) : skipTextSelection(selection); logEntryOriginalResult = entry->selectedText(originalSelection); } - auto &first = (mediaDisplayed && invertMedia()) - ? mediaResult - : textResult; - auto &second = (mediaDisplayed && invertMedia()) - ? textResult - : mediaResult; + auto &first = mediaBefore ? mediaResult : textResult; + auto &second = mediaBefore ? textResult : mediaResult; auto result = first; if (result.empty()) { result = std::move(second); @@ -2664,7 +2661,13 @@ TextWithEntities Message::selectedQuote(TextSelection selection) const { || selection == FullSelection) { return {}; } else if (hasVisibleText()) { - return selectedQuote(text(), selection); + const auto media = this->media(); + const auto mediaDisplayed = media && media->isDisplayed(); + const auto mediaBefore = mediaDisplayed && invertMedia(); + const auto textSelection = mediaBefore + ? media->skipSelection(selection) + : selection; + return selectedQuote(text(), textSelection); } else if (const auto media = this->media()) { if (media->isDisplayed() || isHiddenByGroup()) { return media->selectedQuote(selection); @@ -2737,7 +2740,11 @@ TextSelection Message::selectionFromQuote( if (&translated != &original || quote.empty()) { return {}; } else if (hasVisibleText()) { - return selectionFromQuote(text(), quote); + const auto media = this->media(); + const auto mediaDisplayed = media && media->isDisplayed(); + const auto mediaBefore = mediaDisplayed && invertMedia(); + const auto result = selectionFromQuote(text(), quote); + return mediaBefore ? media->unskipSelection(result) : result; } else if (const auto media = this->media()) { if (media->isDisplayed() || isHiddenByGroup()) { return media->selectionFromQuote(quote); @@ -2793,43 +2800,53 @@ TextSelection Message::adjustSelection( TextSelection selection, TextSelectType type) const { const auto media = this->media(); - - auto result = hasVisibleText() - ? text().adjustSelection(selection, type) + const auto mediaDisplayed = media && media->isDisplayed(); + const auto mediaBefore = mediaDisplayed && invertMedia(); + const auto textSelection = mediaBefore + ? media->skipSelection(selection) : selection; - auto beforeMediaLength = visibleTextLength(); - if (selection.to <= beforeMediaLength) { - return result; - } - auto mediaDisplayed = media && media->isDisplayed(); + auto textAdjusted = hasVisibleText() + ? text().adjustSelection(textSelection, type) + : textSelection; + auto textResult = mediaBefore + ? media->unskipSelection(textAdjusted) + : textAdjusted; + auto mediaResult = TextSelection(); + auto mediaSelection = mediaBefore + ? selection + : skipTextSelection(selection); if (mediaDisplayed) { - auto mediaSelection = unskipTextSelection( - media->adjustSelection(skipTextSelection(selection), type)); - if (selection.from >= beforeMediaLength) { - result = mediaSelection; - } else { - result.to = mediaSelection.to; - } - } - auto beforeEntryLength = beforeMediaLength + visibleMediaTextLength(); - if (selection.to <= beforeEntryLength) { - return result; + auto mediaAdjusted = media->adjustSelection(mediaSelection, type); + mediaResult = mediaBefore + ? mediaAdjusted + : unskipTextSelection(mediaAdjusted); } + auto entryResult = TextSelection(); if (const auto entry = logEntryOriginal()) { - auto entrySelection = mediaDisplayed - ? media->skipSelection(skipTextSelection(selection)) - : skipTextSelection(selection); - auto logEntryOriginalSelection = entry->adjustSelection(entrySelection, type); + auto entrySelection = !mediaDisplayed + ? skipTextSelection(selection) + : mediaBefore + ? skipTextSelection(textSelection) + : media->skipSelection(mediaSelection); + auto entryAdjusted = entry->adjustSelection(entrySelection, type); + entryResult = unskipTextSelection(entryAdjusted); if (mediaDisplayed) { - logEntryOriginalSelection = media->unskipSelection(logEntryOriginalSelection); - } - logEntryOriginalSelection = unskipTextSelection(logEntryOriginalSelection); - if (selection.from >= beforeEntryLength) { - result = logEntryOriginalSelection; - } else { - result.to = logEntryOriginalSelection.to; + entryResult = media->unskipSelection(entryResult); } } + auto result = textResult; + if (!mediaResult.empty()) { + result = result.empty() ? mediaResult : TextSelection{ + std::min(result.from, mediaResult.from), + std::max(result.to, mediaResult.to), + }; + } + if (!entryResult.empty()) { + result = result.empty() ? entryResult : TextSelection{ + std::min(result.from, entryResult.from), + std::max(result.to, entryResult.to), + }; + } return result; } diff --git a/Telegram/SourceFiles/mtproto/scheme/api.tl b/Telegram/SourceFiles/mtproto/scheme/api.tl index 8a0ff53bfd..41afd10252 100644 --- a/Telegram/SourceFiles/mtproto/scheme/api.tl +++ b/Telegram/SourceFiles/mtproto/scheme/api.tl @@ -1264,7 +1264,7 @@ messages.messageViews#b6c4f543 views:Vector chats:Vector use messages.discussionMessage#a6341782 flags:# messages:Vector max_id:flags.0?int read_inbox_max_id:flags.1?int read_outbox_max_id:flags.2?int unread_count:int chats:Vector users:Vector = messages.DiscussionMessage; -messageReplyHeader#6eebcabd flags:# reply_to_scheduled:flags.2?true forum_topic:flags.3?true reply_to_msg_id:flags.4?int reply_to_peer_id:flags.0?Peer reply_from:flags.5?MessageFwdHeader reply_media:flags.8?MessageMedia reply_to_top_id:flags.1?int quote_text:flags.6?string quote_entities:flags.7?Vector = MessageReplyHeader; +messageReplyHeader#6eebcabd flags:# reply_to_scheduled:flags.2?true forum_topic:flags.3?true quote:flags.9?true reply_to_msg_id:flags.4?int reply_to_peer_id:flags.0?Peer reply_from:flags.5?MessageFwdHeader reply_media:flags.8?MessageMedia reply_to_top_id:flags.1?int quote_text:flags.6?string quote_entities:flags.7?Vector = MessageReplyHeader; messageReplyStoryHeader#9c98bfc1 user_id:long story_id:int = MessageReplyHeader; messageReplies#83d60fc2 flags:# comments:flags.0?true replies:int replies_pts:int recent_repliers:flags.1?Vector channel_id:flags.0?long max_id:flags.2?int read_max_id:flags.3?int = MessageReplies;