diff --git a/Telegram/SourceFiles/api/api_editing.cpp b/Telegram/SourceFiles/api/api_editing.cpp index ed76f847f6..6f1c322718 100644 --- a/Telegram/SourceFiles/api/api_editing.cpp +++ b/Telegram/SourceFiles/api/api_editing.cpp @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "apiwrap.h" #include "api/api_media.h" #include "api/api_text_entities.h" +#include "base/random.h" #include "ui/boxes/confirm_box.h" #include "data/business/data_shortcut_messages.h" #include "data/components/scheduled_messages.h" @@ -20,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_web_page.h" #include "history/view/controls/history_view_compose_media_edit_manager.h" #include "history/history.h" +#include "history/history_item_components.h" #include "lang/lang_keys.h" #include "main/main_session.h" #include "mtproto/mtproto_response.h" @@ -46,6 +48,230 @@ template constexpr auto ErrorWithoutId = is_callable_plain_v; +template +mtpRequestId SuggestMessage( + not_null item, + const TextWithEntities &textWithEntities, + Data::WebPageDraft webpage, + SendOptions options, + DoneCallback &&done, + FailCallback &&fail) { + Expects(options.suggest.exists); + Expects(!options.scheduled); + + const auto session = &item->history()->session(); + const auto api = &session->api(); + + const auto text = textWithEntities.text; + const auto sentEntities = EntitiesToMTP( + session, + textWithEntities.entities, + ConvertOption::SkipLocal); + + const auto emptyFlag = MTPmessages_SendMessage::Flag(0); + auto replyTo = FullReplyTo{ + .messageId = item->fullId(), + .monoforumPeerId = (item->history()->amMonoforumAdmin() + ? item->sublistPeerId() + : PeerId()), + }; + const auto flags = emptyFlag + | MTPmessages_SendMessage::Flag::f_reply_to + | MTPmessages_SendMessage::Flag::f_suggested_post + | (webpage.removed + ? MTPmessages_SendMessage::Flag::f_no_webpage + : emptyFlag) + | (((!webpage.removed && !webpage.url.isEmpty() && webpage.invert) + || options.invertCaption) + ? MTPmessages_SendMessage::Flag::f_invert_media + : emptyFlag) + | (!sentEntities.v.isEmpty() + ? MTPmessages_SendMessage::Flag::f_entities + : emptyFlag) + | (options.starsApproved + ? MTPmessages_SendMessage::Flag::f_allow_paid_stars + : emptyFlag); + const auto randomId = base::RandomValue(); + return api->request(MTPmessages_SendMessage( + MTP_flags(flags), + item->history()->peer->input, + ReplyToForMTP(item->history(), replyTo), + MTP_string(text), + MTP_long(randomId), + MTPReplyMarkup(), + sentEntities, + MTPint(), // schedule_date + MTPInputPeer(), // send_as + MTPInputQuickReplyShortcut(), // quick_reply_shortcut + MTPlong(), // effect + MTP_long(options.starsApproved), + Api::SuggestToMTP(options.suggest) + )).done([=]( + const MTPUpdates &result, + [[maybe_unused]] mtpRequestId requestId) { + const auto apply = [=] { api->applyUpdates(result); }; + + if constexpr (WithId) { + done(apply, requestId); + } else if constexpr (WithoutId) { + done(apply); + } else if constexpr (WithoutCallback) { + done(); + apply(); + } else { + t_bad_callback(done); + } + }).fail([=](const MTP::Error &error, mtpRequestId requestId) { + if constexpr (ErrorWithId) { + fail(error.type(), requestId); + } else if constexpr (ErrorWithoutId) { + fail(error.type()); + } else if constexpr (WithoutCallback) { + fail(); + } else { + t_bad_callback(fail); + } + }).send(); +} + +template +mtpRequestId SuggestMedia( + not_null item, + const TextWithEntities &textWithEntities, + Data::WebPageDraft webpage, + SendOptions options, + DoneCallback &&done, + FailCallback &&fail, + std::optional inputMedia) { + Expects(options.suggest.exists); + Expects(!options.scheduled); + + const auto session = &item->history()->session(); + const auto api = &session->api(); + + const auto text = textWithEntities.text; + const auto sentEntities = EntitiesToMTP( + session, + textWithEntities.entities, + ConvertOption::SkipLocal); + + const auto updateRecentStickers = inputMedia + ? Api::HasAttachedStickers(*inputMedia) + : false; + + const auto emptyFlag = MTPmessages_SendMedia::Flag(0); + auto replyTo = FullReplyTo{ + .messageId = item->fullId(), + .monoforumPeerId = (item->history()->amMonoforumAdmin() + ? item->sublistPeerId() + : PeerId()), + }; + const auto flags = emptyFlag + | MTPmessages_SendMedia::Flag::f_reply_to + | MTPmessages_SendMedia::Flag::f_suggested_post + | (((!webpage.removed && !webpage.url.isEmpty() && webpage.invert) + || options.invertCaption) + ? MTPmessages_SendMedia::Flag::f_invert_media + : emptyFlag) + | (!sentEntities.v.isEmpty() + ? MTPmessages_SendMedia::Flag::f_entities + : emptyFlag) + | (options.starsApproved + ? MTPmessages_SendMedia::Flag::f_allow_paid_stars + : emptyFlag); + const auto randomId = base::RandomValue(); + return api->request(MTPmessages_SendMedia( + MTP_flags(flags), + item->history()->peer->input, + ReplyToForMTP(item->history(), replyTo), + inputMedia.value_or(Data::WebPageForMTP(webpage, text.isEmpty())), + MTP_string(text), + MTP_long(randomId), + MTPReplyMarkup(), + sentEntities, + MTPint(), // schedule_date + MTPInputPeer(), // send_as + MTPInputQuickReplyShortcut(), // quick_reply_shortcut + MTPlong(), // effect + MTP_long(options.starsApproved), + Api::SuggestToMTP(options.suggest) + )).done([=]( + const MTPUpdates &result, + [[maybe_unused]] mtpRequestId requestId) { + const auto apply = [=] { api->applyUpdates(result); }; + + if constexpr (WithId) { + done(apply, requestId); + } else if constexpr (WithoutId) { + done(apply); + } else if constexpr (WithoutCallback) { + done(); + apply(); + } else { + t_bad_callback(done); + } + + if (updateRecentStickers) { + api->requestSpecialStickersForce(false, false, true); + } + }).fail([=](const MTP::Error &error, mtpRequestId requestId) { + if constexpr (ErrorWithId) { + fail(error.type(), requestId); + } else if constexpr (ErrorWithoutId) { + fail(error.type()); + } else if constexpr (WithoutCallback) { + fail(); + } else { + t_bad_callback(fail); + } + }).send(); +} + +template +mtpRequestId SuggestMessageOrMedia( + not_null item, + const TextWithEntities &textWithEntities, + Data::WebPageDraft webpage, + SendOptions options, + DoneCallback &&done, + FailCallback &&fail, + std::optional inputMedia) { + const auto wasMedia = item->media(); + if (!inputMedia && wasMedia && wasMedia->allowsEditCaption()) { + if (const auto photo = wasMedia->photo()) { + inputMedia = MTP_inputMediaPhoto( + MTP_flags(0), + photo->mtpInput(), + MTPint()); // ttl_seconds + } else if (const auto document = wasMedia->document()) { + inputMedia = MTP_inputMediaDocument( + MTP_flags(0), + document->mtpInput(), + MTPInputPhoto(), // video_cover + MTPint(), // video_timestamp + MTPint(), // ttl_seconds + MTPstring()); // query + } + } + if (inputMedia || (!webpage.removed && !webpage.url.isEmpty())) { + return SuggestMedia( + item, + textWithEntities, + webpage, + options, + std::move(done), + std::move(fail), + inputMedia); + } + return SuggestMessage( + item, + textWithEntities, + webpage, + options, + std::move(done), + std::move(fail)); +} + template mtpRequestId EditMessage( not_null item, @@ -55,6 +281,18 @@ mtpRequestId EditMessage( DoneCallback &&done, FailCallback &&fail, std::optional inputMedia = std::nullopt) { + if (item->computeSuggestionActions() + == SuggestionActions::AcceptAndDecline) { + return SuggestMessageOrMedia( + item, + textWithEntities, + webpage, + options, + std::move(done), + std::move(fail), + inputMedia); + } + const auto session = &item->history()->session(); const auto api = &session->api(); @@ -71,31 +309,31 @@ mtpRequestId EditMessage( const auto emptyFlag = MTPmessages_EditMessage::Flag(0); const auto flags = emptyFlag - | ((!text.isEmpty() || media) - ? MTPmessages_EditMessage::Flag::f_message - : emptyFlag) - | ((media && inputMedia.has_value()) - ? MTPmessages_EditMessage::Flag::f_media - : emptyFlag) - | (webpage.removed - ? MTPmessages_EditMessage::Flag::f_no_webpage - : emptyFlag) - | ((!webpage.removed && !webpage.url.isEmpty()) - ? MTPmessages_EditMessage::Flag::f_media - : emptyFlag) - | (((!webpage.removed && !webpage.url.isEmpty() && webpage.invert) - || options.invertCaption) - ? MTPmessages_EditMessage::Flag::f_invert_media - : emptyFlag) - | (!sentEntities.v.isEmpty() - ? MTPmessages_EditMessage::Flag::f_entities - : emptyFlag) - | (options.scheduled - ? MTPmessages_EditMessage::Flag::f_schedule_date - : emptyFlag) - | (item->isBusinessShortcut() - ? MTPmessages_EditMessage::Flag::f_quick_reply_shortcut_id - : emptyFlag); + | ((!text.isEmpty() || media) + ? MTPmessages_EditMessage::Flag::f_message + : emptyFlag) + | ((media && inputMedia.has_value()) + ? MTPmessages_EditMessage::Flag::f_media + : emptyFlag) + | (webpage.removed + ? MTPmessages_EditMessage::Flag::f_no_webpage + : emptyFlag) + | ((!webpage.removed && !webpage.url.isEmpty()) + ? MTPmessages_EditMessage::Flag::f_media + : emptyFlag) + | (((!webpage.removed && !webpage.url.isEmpty() && webpage.invert) + || options.invertCaption) + ? MTPmessages_EditMessage::Flag::f_invert_media + : emptyFlag) + | (!sentEntities.v.isEmpty() + ? MTPmessages_EditMessage::Flag::f_entities + : emptyFlag) + | (options.scheduled + ? MTPmessages_EditMessage::Flag::f_schedule_date + : emptyFlag) + | (item->isBusinessShortcut() + ? MTPmessages_EditMessage::Flag::f_quick_reply_shortcut_id + : emptyFlag); const auto id = item->isScheduled() ? session->scheduledMessages().lookupId(item) diff --git a/Telegram/SourceFiles/api/api_suggest_post.cpp b/Telegram/SourceFiles/api/api_suggest_post.cpp index 8734cd8986..a6a1f09379 100644 --- a/Telegram/SourceFiles/api/api_suggest_post.cpp +++ b/Telegram/SourceFiles/api/api_suggest_post.cpp @@ -9,8 +9,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "apiwrap.h" #include "base/unixtime.h" +#include "chat_helpers/message_field.h" #include "core/click_handler_types.h" +#include "data/data_changes.h" #include "data/data_session.h" +#include "data/data_saved_sublist.h" #include "history/view/history_view_suggest_options.h" #include "history/history.h" #include "history/history_item.h" @@ -134,9 +137,8 @@ void RequestApprovalDate( using namespace HistoryView; auto dateBox = Box(ChooseSuggestTimeBox, SuggestTimeBoxArgs{ .session = &controller->session(), - .title = tr::lng_suggest_options_date(), - .submit = tr::lng_settings_save(), .done = done, + .mode = SuggestMode::New, }); *weak = dateBox.data(); controller->uiShow()->show(std::move(dateBox)); @@ -266,10 +268,9 @@ void SuggestApprovalDate( using namespace HistoryView; auto dateBox = Box(ChooseSuggestTimeBox, SuggestTimeBoxArgs{ .session = &controller->session(), - .title = tr::lng_suggest_menu_edit_time(), - .submit = tr::lng_profile_suggest_button(), .done = done, .value = suggestion->date, + .mode = SuggestMode::Change, }); *weak = dateBox.data(); controller->uiShow()->show(std::move(dateBox)); @@ -311,6 +312,7 @@ void SuggestApprovalPrice( .stars = uint32(suggestion->stars), .date = suggestion->date, }, + .mode = SuggestMode::Change, }); *weak = dateBox.data(); controller->uiShow()->show(std::move(dateBox)); @@ -373,9 +375,47 @@ std::shared_ptr SuggestChangesClickHandler( const auto menu = Ui::CreateChild( window->widget(), st::popupMenuWithIcons); - menu->addAction(tr::lng_suggest_menu_edit_message(tr::now), [=] { - - }, &st::menuIconEdit); + if (HistoryView::CanEditSuggestedMessage(item)) { + menu->addAction(tr::lng_suggest_menu_edit_message(tr::now), [=] { + const auto item = session->data().message(id); + if (!item) { + return; + } + const auto suggestion = item->Get(); + if (!suggestion) { + return; + } + const auto history = item->history(); + const auto editData = PrepareEditText(item); + const auto cursor = MessageCursor{ + int(editData.text.size()), + int(editData.text.size()), + Ui::kQFixedMax + }; + const auto monoforumPeerId = history->amMonoforumAdmin() + ? item->sublistPeerId() + : PeerId(); + const auto previewDraft = Data::WebPageDraft::FromItem(item); + history->setLocalEditDraft(std::make_unique( + editData, + FullReplyTo{ + .messageId = FullMsgId(history->peer->id, item->id), + .monoforumPeerId = monoforumPeerId, + }, + SuggestPostOptions{ + .exists = 1, + .stars = uint32(suggestion->stars), + .date = suggestion->date, + }, + cursor, + previewDraft)); + history->session().changes().entryUpdated( + (monoforumPeerId + ? item->savedSublist() + : (Data::Thread*)history.get()), + Data::EntryUpdate::Flag::LocalDraftSet); + }, &st::menuIconEdit); + } menu->addAction(tr::lng_suggest_menu_edit_price(tr::now), [=] { if (const auto item = session->data().message(id)) { SuggestApprovalPrice(window, item); diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 3f8b82b933..0fe7e05bdf 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -2410,6 +2410,9 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { highlightId); }, &st::menuIconViewReplies); } + _menu->addAction(u"Add Offer"_q, [=] { + + }, &st::menuIconDiscussion); const auto t = base::unixtime::now(); const auto editItem = (albumPartItem && albumPartItem->allowsEdit(t)) ? albumPartItem diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index a7551d89d8..62bb3b6e94 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -544,6 +544,13 @@ public: [[nodiscard]] bool canUpdateDate() const; void customEmojiRepaint(); + [[nodiscard]] SuggestionActions computeSuggestionActions() const; + [[nodiscard]] SuggestionActions computeSuggestionActions( + const HistoryMessageSuggestedPost *suggest) const; + [[nodiscard]] SuggestionActions computeSuggestionActions( + bool accepted, + bool rejected) const; + [[nodiscard]] bool needsUpdateForVideoQualities(const MTPMessage &data); [[nodiscard]] TimeId ttlDestroyAt() const { @@ -582,12 +589,6 @@ private: void setReplyMarkup( HistoryMessageMarkupData &&markup, bool ignoreSuggestButtons = false); - [[nodiscard]] SuggestionActions computeSuggestionActions() const; - [[nodiscard]] SuggestionActions computeSuggestionActions( - const HistoryMessageSuggestedPost *suggest) const; - [[nodiscard]] SuggestionActions computeSuggestionActions( - bool accepted, - bool rejected) const; void updateSuggestControls(const HistoryMessageSuggestedPost *suggest); void changeReplyToTopCounter( diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 4d251798a9..17eabdada5 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -2269,6 +2269,12 @@ bool HistoryWidget::applyDraft(FieldHistoryAction fieldHistoryAction) { if (!_replyEditMsg) { requestMessageData(_editMsgId); } + if (editDraft && editDraft->suggest) { + using namespace HistoryView; + applySuggestOptions(editDraft->suggest, SuggestMode::Change); + } else { + cancelSuggestPost(); + } } else { const auto draft = _history->localDraft(MsgId(), PeerId()); _processingReplyTo = draft ? draft->reply : FullReplyTo(); @@ -2276,7 +2282,8 @@ bool HistoryWidget::applyDraft(FieldHistoryAction fieldHistoryAction) { _processingReplyItem = session().data().message( _processingReplyTo.messageId); } else if (draft && draft->suggest) { - applySuggestOptions(draft->suggest); + using namespace HistoryView; + applySuggestOptions(draft->suggest, SuggestMode::New); } processReply(); } @@ -2352,7 +2359,9 @@ void HistoryWidget::showHistory( if (_peer->id == peerId) { updateForwarding(); - if (showAtMsgId == ShowAtUnreadMsgId + if (params.reapplyLocalDraft) { + return; + } else if (showAtMsgId == ShowAtUnreadMsgId && insideJumpToEndInsteadOfToUnread()) { DEBUG_LOG(("JumpToEnd(%1, %2, %3): " "Jumping to end instead of unread." @@ -3164,14 +3173,17 @@ void HistoryWidget::refreshSendGiftToggle() { } } -void HistoryWidget::applySuggestOptions(SuggestPostOptions suggest) { +void HistoryWidget::applySuggestOptions( + SuggestPostOptions suggest, + HistoryView::SuggestMode mode) { Expects(suggest.exists); using namespace HistoryView; _suggestOptions = std::make_unique( controller(), _peer, - suggest); + suggest, + mode); _suggestOptions->updates() | rpl::start_with_next([=] { updateField(); saveDraftWithTextNow(); @@ -3193,7 +3205,8 @@ void HistoryWidget::refreshSuggestPostToggle() { _toggleSuggestPost.create(this, st::historySuggestPostToggle); _toggleSuggestPost->setVisible(!_suggestOptions); _toggleSuggestPost->addClickHandler([=] { - applySuggestOptions({ .exists = 1 }); + using namespace HistoryView; + applySuggestOptions({ .exists = 1 }, SuggestMode::New); cancelReply(); _processingReplyTo = FullReplyTo(); _processingReplyItem = nullptr; @@ -4419,7 +4432,7 @@ TextWithEntities HistoryWidget::prepareTextForEditMsg() const { return left; } -void HistoryWidget::saveEditMsg() { +void HistoryWidget::saveEditMessage(Api::SendOptions options) { Expects(_history != nullptr); if (_saveEditMsgRequestId) { @@ -4442,9 +4455,11 @@ void HistoryWidget::saveEditMsg() { || webPageDraft.url.isEmpty() || !webPageDraft.manual) && !hasMediaWithCaption) { - const auto suggestModerateActions = false; - controller()->show( - Box(item, suggestModerateActions)); + if (item->computeSuggestionActions() == SuggestionActions::None) { + const auto suggestModerateActions = false; + controller()->show( + Box(item, suggestModerateActions)); + } return; } else { const auto maxCaptionSize = !hasMediaWithCaption @@ -4506,11 +4521,27 @@ void HistoryWidget::saveEditMsg() { })(); }; + options.invertCaption = _mediaEditManager.invertCaption(); + options.suggest = suggestOptions(); + + const auto withPaymentApproved = [=](int approved) { + auto copy = options; + copy.starsApproved = approved; + saveEditMessage(copy); + }; + const auto checked = checkSendPayment( + 1 + int(_forwardPanel->items().size()), + options.starsApproved, + withPaymentApproved); + if (!checked) { + return; + } + _saveEditMsgRequestId = Api::EditTextMessage( item, sending, webPageDraft, - { .invertCaption = _mediaEditManager.invertCaption() }, + options, done, fail, _mediaEditManager.spoilered()); @@ -4611,7 +4642,7 @@ void HistoryWidget::send(Api::SendOptions options) { if (!_history) { return; } else if (_editMsgId) { - saveEditMsg(); + saveEditMessage({}); return; } else if (!options.scheduled && showSlowmodeError()) { return; @@ -7386,10 +7417,14 @@ void HistoryWidget::mousePressEvent(QMouseEvent *e) { } else if (_previewDrawPreview) { editDraftOptions(); } else if (_editMsgId) { - controller()->showPeerHistory( - _peer, - Window::SectionShow::Way::Forward, - _editMsgId); + if (_suggestOptions) { + _suggestOptions->edit(); + } else { + controller()->showPeerHistory( + _peer, + Window::SectionShow::Way::Forward, + _editMsgId); + } } else if (_replyTo && ((e->modifiers() & Qt::ControlModifier) || (e->button() != Qt::LeftButton))) { @@ -8834,6 +8869,7 @@ void HistoryWidget::cancelEdit() { _replyEditMsg = nullptr; setEditMsgId(0); _history->clearLocalEditDraft(MsgId(), PeerId()); + cancelSuggestPost(); applyDraft(); if (_saveEditMsgRequestId) { @@ -9367,14 +9403,18 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) { const auto paused = p.inactive(); const auto pausedSpoiler = paused || On(PowerSaving::kChatSpoiler); auto replyLeft = st::historyReplySkip; - (_editMsgId - ? st::historyEditIcon - : (_replyTo && !_replyTo.quote.empty()) - ? st::historyQuoteIcon - : st::historyReplyIcon).paint( - p, - st::historyReplyIconPosition + QPoint(0, backy), - width()); + if (_suggestOptions) { + _suggestOptions->paintIcon(p, 0, backy, width()); + } else { + (_editMsgId + ? st::historyEditIcon + : (_replyTo && !_replyTo.quote.empty()) + ? st::historyQuoteIcon + : st::historyReplyIcon).paint( + p, + st::historyReplyIconPosition + QPoint(0, backy), + width()); + } if (drawMsgText) { if (hasPreview) { if (preview) { @@ -9412,37 +9452,41 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) { } replyLeft += st::historyReplyPreview + st::msgReplyBarSkip; } - p.setPen(st::historyReplyNameFg); - if (_editMsgId) { - paintEditHeader(p, rect, replyLeft, backy); + if (_suggestOptions) { + _suggestOptions->paintLines(p, replyLeft, backy, width()); } else { - _replyToName.drawElided( - p, - replyLeft, - backy + st::msgReplyPadding.top(), - width() + p.setPen(st::historyReplyNameFg); + if (_editMsgId) { + paintEditHeader(p, rect, replyLeft, backy); + } else { + _replyToName.drawElided( + p, + replyLeft, + backy + st::msgReplyPadding.top(), + width() + - replyLeft + - _fieldBarCancel->width() + - st::msgReplyPadding.right()); + } + p.setPen(st::historyComposeAreaFg); + _replyEditMsgText.draw(p, { + .position = QPoint( + replyLeft, + st::msgReplyPadding.top() + + st::msgServiceNameFont->height + + backy), + .availableWidth = width() - replyLeft - _fieldBarCancel->width() - - st::msgReplyPadding.right()); + - st::msgReplyPadding.right(), + .palette = &st::historyComposeAreaPalette, + .spoiler = Ui::Text::DefaultSpoilerCache(), + .now = now, + .pausedEmoji = paused || On(PowerSaving::kEmojiChat), + .pausedSpoiler = pausedSpoiler, + .elisionLines = 1, + }); } - p.setPen(st::historyComposeAreaFg); - _replyEditMsgText.draw(p, { - .position = QPoint( - replyLeft, - st::msgReplyPadding.top() - + st::msgServiceNameFont->height - + backy), - .availableWidth = width() - - replyLeft - - _fieldBarCancel->width() - - st::msgReplyPadding.right(), - .palette = &st::historyComposeAreaPalette, - .spoiler = Ui::Text::DefaultSpoilerCache(), - .now = now, - .pausedEmoji = paused || On(PowerSaving::kEmojiChat), - .pausedSpoiler = pausedSpoiler, - .elisionLines = 1, - }); } else { p.setFont(st::msgDateFont); p.setPen(st::historyComposeAreaFgService); diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index ac39ce3988..ec81821ee6 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -110,6 +110,7 @@ class ComposeSearch; class SubsectionTabs; struct SelectedQuote; class SuggestOptions; +enum class SuggestMode; } // namespace HistoryView namespace HistoryView::Controls { @@ -589,7 +590,7 @@ private: void createUnreadBarAndResize(); [[nodiscard]] TextWithEntities prepareTextForEditMsg() const; - void saveEditMsg(); + void saveEditMessage(Api::SendOptions options = {}); void setupPreview(); void editDraftOptions(); @@ -682,7 +683,9 @@ private: void refreshScheduledToggle(); void refreshSendGiftToggle(); void refreshSuggestPostToggle(); - void applySuggestOptions(SuggestPostOptions suggest); + void applySuggestOptions( + SuggestPostOptions suggest, + HistoryView::SuggestMode mode); void setupSendAsToggle(); void refreshSendAsToggle(); void refreshAttachBotsMenu(); diff --git a/Telegram/SourceFiles/history/view/history_view_chat_section.cpp b/Telegram/SourceFiles/history/view/history_view_chat_section.cpp index a4d8b228ce..15840ea3a6 100644 --- a/Telegram/SourceFiles/history/view/history_view_chat_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_chat_section.cpp @@ -2381,13 +2381,14 @@ bool ChatWidget::showInternal( const Window::SectionShow ¶ms) { if (auto logMemento = dynamic_cast(memento.get())) { if (logMemento->id() == _id) { - restoreState(logMemento); - if (!logMemento->highlightId()) { - showAtPosition(Data::UnreadMessagePosition); - } if (params.reapplyLocalDraft) { _composeControls->applyDraft( ComposeControls::FieldHistoryAction::NewEntry); + } else { + restoreState(logMemento); + if (!logMemento->highlightId()) { + showAtPosition(Data::UnreadMessagePosition); + } } return true; } diff --git a/Telegram/SourceFiles/history/view/history_view_suggest_options.cpp b/Telegram/SourceFiles/history/view/history_view_suggest_options.cpp index 0550266b2b..f8b3b89f81 100644 --- a/Telegram/SourceFiles/history/view/history_view_suggest_options.cpp +++ b/Telegram/SourceFiles/history/view/history_view_suggest_options.cpp @@ -9,6 +9,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/unixtime.h" #include "data/data_channel.h" +#include "data/data_media_types.h" +#include "history/history_item.h" #include "lang/lang_keys.h" #include "main/main_app_config.h" #include "main/main_session.h" @@ -36,8 +38,12 @@ void ChooseSuggestTimeBox( ? std::clamp(args.value, now + min, now + max) : (now + 86400); Ui::ChooseDateTimeBox(box, { - .title = std::move(args.title), - .submit = std::move(args.submit), + .title = ((args.mode == SuggestMode::New) + ? tr::lng_suggest_options_date() + : tr::lng_suggest_menu_edit_time()), + .submit = ((args.mode == SuggestMode::New) + ? tr::lng_settings_save() + : tr::lng_suggest_options_update()), .done = std::move(args.done), .min = [=] { return now + min; }, .time = value, @@ -56,7 +62,9 @@ void ChooseSuggestPriceBox( const auto limit = args.session->appConfig().suggestedPostStarsMax(); - box->setTitle(tr::lng_suggest_options_title()); + box->setTitle((args.mode == SuggestMode::New) + ? tr::lng_suggest_options_title() + : tr::lng_suggest_options_change()); const auto container = box->verticalLayout(); @@ -117,10 +125,9 @@ void ChooseSuggestPriceBox( }; auto dateBox = Box(ChooseSuggestTimeBox, SuggestTimeBoxArgs{ .session = args.session, - .title = tr::lng_suggest_options_date(), - .submit = tr::lng_settings_save(), .done = done, .value = state->date.current(), + .mode = args.mode, }); *weak = dateBox.data(); box->uiShow()->show(std::move(dateBox)); @@ -150,25 +157,38 @@ void ChooseSuggestPriceBox( }); } +bool CanEditSuggestedMessage(not_null item) { + const auto media = item->media(); + return !media || media->allowsEditCaption(); +} + SuggestOptions::SuggestOptions( not_null controller, not_null peer, - SuggestPostOptions values) + SuggestPostOptions values, + SuggestMode mode) : _controller(controller) , _peer(peer) +, _mode(mode) , _values(values) { updateTexts(); } SuggestOptions::~SuggestOptions() = default; -void SuggestOptions::paintBar(QPainter &p, int x, int y, int outerWidth) { +void SuggestOptions::paintIcon(QPainter &p, int x, int y, int outerWidth) { st::historyDirectMessage.icon.paint( p, QPoint(x, y) + st::historySuggestIconPosition, outerWidth); +} - x += st::historyReplySkip; +void SuggestOptions::paintBar(QPainter &p, int x, int y, int outerWidth) { + paintIcon(p, x, y, outerWidth); + paintLines(p, x + st::historyReplySkip, y, outerWidth); +} + +void SuggestOptions::paintLines(QPainter &p, int x, int y, int outerWidth) { auto available = outerWidth - x - st::historyReplyCancel.width @@ -207,7 +227,9 @@ void SuggestOptions::edit() { void SuggestOptions::updateTexts() { _title.setText( st::semiboldTextStyle, - tr::lng_suggest_bar_title(tr::now)); + ((_mode == SuggestMode::New) + ? tr::lng_suggest_bar_title(tr::now) + : tr::lng_suggest_options_change(tr::now))); _text.setMarkedText(st::defaultTextStyle, composeText()); } diff --git a/Telegram/SourceFiles/history/view/history_view_suggest_options.h b/Telegram/SourceFiles/history/view/history_view_suggest_options.h index c326696d6b..fbf15d12b7 100644 --- a/Telegram/SourceFiles/history/view/history_view_suggest_options.h +++ b/Telegram/SourceFiles/history/view/history_view_suggest_options.h @@ -23,12 +23,16 @@ class SessionController; namespace HistoryView { +enum class SuggestMode { + New, + Change, +}; + struct SuggestTimeBoxArgs { not_null session; - rpl::producer title; - rpl::producer submit; Fn done; TimeId value = 0; + SuggestMode mode = SuggestMode::New; }; void ChooseSuggestTimeBox( not_null box, @@ -39,22 +43,29 @@ struct SuggestPriceBoxArgs { bool updating = false; Fn done; SuggestPostOptions value; + SuggestMode mode = SuggestMode::New; }; void ChooseSuggestPriceBox( not_null box, SuggestPriceBoxArgs &&args); +[[nodiscard]] bool CanEditSuggestedMessage(not_null item); + class SuggestOptions final { public: SuggestOptions( not_null controller, not_null peer, - SuggestPostOptions values); + SuggestPostOptions values, + SuggestMode mode); ~SuggestOptions(); void paintBar(QPainter &p, int x, int y, int outerWidth); void edit(); + void paintIcon(QPainter &p, int x, int y, int outerWidth); + void paintLines(QPainter &p, int x, int y, int outerWidth); + [[nodiscard]] SuggestPostOptions values() const; [[nodiscard]] rpl::producer<> updates() const; @@ -68,6 +79,7 @@ private: const not_null _controller; const not_null _peer; + const SuggestMode _mode = SuggestMode::New; Ui::Text::String _title; Ui::Text::String _text; diff --git a/Telegram/SourceFiles/history/view/media/history_view_suggest_decision.cpp b/Telegram/SourceFiles/history/view/media/history_view_suggest_decision.cpp index 7623f8eab9..9a81e9afa9 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_suggest_decision.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_suggest_decision.cpp @@ -316,38 +316,32 @@ auto GenerateSuggestRequestMedia( style::al_top); auto entries = std::vector(); - if (!changes || changes->price) { - entries.push_back({ - (changes - ? tr::lng_suggest_change_price_label - : tr::lng_suggest_action_price_label)(tr::now), - Ui::Text::Bold(suggest->stars - ? tr::lng_prize_credits_amount( - tr::now, - lt_count, - suggest->stars) - : tr::lng_suggest_action_price_free(tr::now)), - }); - } - if (!changes || changes->date) { - entries.push_back({ - (changes - ? tr::lng_suggest_change_time_label - : tr::lng_suggest_action_time_label)(tr::now), - Ui::Text::Bold(suggest->date - ? Ui::FormatDateTime(base::unixtime::parse(suggest->date)) - : tr::lng_suggest_action_time_any(tr::now)), - }); - } - if (!entries.empty()) { - push(std::make_unique( - std::move(entries), - ((changes && changes->message) - ? st::chatSuggestTableMiddleMargin - : st::chatSuggestTableLastMargin), - fadedFg, - normalFg)); - } + entries.push_back({ + ((changes && changes->price) + ? tr::lng_suggest_change_price_label + : tr::lng_suggest_action_price_label)(tr::now), + Ui::Text::Bold(suggest->stars + ? tr::lng_prize_credits_amount( + tr::now, + lt_count, + suggest->stars) + : tr::lng_suggest_action_price_free(tr::now)), + }); + entries.push_back({ + ((changes && changes->date) + ? tr::lng_suggest_change_time_label + : tr::lng_suggest_action_time_label)(tr::now), + Ui::Text::Bold(suggest->date + ? Ui::FormatDateTime(base::unixtime::parse(suggest->date)) + : tr::lng_suggest_action_time_any(tr::now)), + }); + push(std::make_unique( + std::move(entries), + ((changes && changes->message) + ? st::chatSuggestTableMiddleMargin + : st::chatSuggestTableLastMargin), + fadedFg, + normalFg)); if (changes && changes->message) { push(std::make_unique( tr::lng_suggest_change_text_label(