Fix draft options edit, add to topics/replies.

This commit is contained in:
John Preston 2023-10-26 18:44:49 +04:00
parent a197ed9e95
commit cc8408d11c
10 changed files with 147 additions and 97 deletions

View File

@ -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);
}
}

View File

@ -147,6 +147,7 @@ public:
[[nodiscard]] rpl::producer<FullMsgId> editMsgIdValue() const;
[[nodiscard]] rpl::producer<FullMsgId> 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<bool> _visibleChanged;
rpl::event_stream<FullMsgId> _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<QEvent*> 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<Data::MessagePosition> 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 {

View File

@ -357,6 +357,7 @@ private:
const std::unique_ptr<Ui::RpWidget> _wrap;
const std::unique_ptr<Ui::RpWidget> _writeRestricted;
rpl::event_stream<FullMsgId> _scrollToItemRequests;
std::optional<Ui::RoundRect> _backgroundRect;

View File

@ -247,10 +247,9 @@ PreviewWrap::~PreviewWrap() {
rpl::producer<TextWithEntities> PreviewWrap::showQuoteSelector(
not_null<HistoryItem*> item,
const TextWithEntities &quote) {
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<TextWithEntities> 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<Ui::VerticalLayout*> container) {

View File

@ -605,13 +605,18 @@ bool AddReplyToMessageAction(
return false;
}
const auto &quote = 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<Ui::PopupMenu*> menu,
const ContextMenuRequest &request,
not_null<ListWidget*> list) {
AddReplyToMessageAction(menu, request, list);
AddGoToMessageAction(menu, request, list);
AddViewRepliesAction(menu, request, list);
AddEditMessageAction(menu, request, list);
@ -1008,6 +1012,8 @@ base::unique_qptr<Ui::PopupMenu> FillContextMenu(
list,
st::popupMenuWithIcons);
AddReplyToMessageAction(result, request, list);
if (request.overSelection
&& !list->hasCopyRestrictionForSelected()
&& !list->getSelectedText().empty()) {

View File

@ -47,6 +47,7 @@ struct ContextMenuRequest {
HistoryItem *item = nullptr;
SelectedItems selectedItems;
TextForMimeData selectedText;
TextWithEntities quote;
bool overSelection = false;
PointState pointState = PointState();
};

View File

@ -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) } };
}

View File

@ -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<Data::ReactionId>()
@ -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()

View File

@ -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;
}

View File

@ -1264,7 +1264,7 @@ messages.messageViews#b6c4f543 views:Vector<MessageViews> chats:Vector<Chat> use
messages.discussionMessage#a6341782 flags:# messages:Vector<Message> max_id:flags.0?int read_inbox_max_id:flags.1?int read_outbox_max_id:flags.2?int unread_count:int chats:Vector<Chat> users:Vector<User> = 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<MessageEntity> = 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<MessageEntity> = 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<Peer> channel_id:flags.0?long max_id:flags.2?int read_max_id:flags.3?int = MessageReplies;