diff --git a/Telegram/SourceFiles/history/view/history_view_compose_controls.cpp b/Telegram/SourceFiles/history/view/history_view_compose_controls.cpp index 7d85a66093..14cb51e580 100644 --- a/Telegram/SourceFiles/history/view/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/history_view_compose_controls.cpp @@ -33,6 +33,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace HistoryView { +namespace { + +using MessageToEdit = ComposeControls::MessageToEdit; + +} // namespace + class FieldHeader : public Ui::RpWidget { public: FieldHeader(QWidget *parent, not_null data); @@ -42,6 +48,7 @@ public: bool isDisplayed() const; bool isEditingMessage() const; rpl::producer editMsgId() const; + MessageToEdit queryToEdit(); protected: void paintEvent(QPaintEvent *e) override; @@ -81,7 +88,7 @@ FieldHeader::FieldHeader(QWidget *parent, not_null data) }, lifetime()); _cancel->addClickHandler([=] { - _editMsgId = nullptr; + _editMsgId = {}; }); } @@ -132,6 +139,22 @@ rpl::producer FieldHeader::editMsgId() const { return _editMsgId.value(); } +MessageToEdit FieldHeader::queryToEdit() { + const auto item = _data->message(_editMsgId.current()); + if (!isEditingMessage() || !item) { + return {}; + } + return { + item->fullId(), + { + item->isScheduled() ? item->date() : 0, + false, + false, + false, + }, + }; +} + ComposeControls::ComposeControls( not_null parent, not_null window, @@ -202,12 +225,28 @@ rpl::producer<> ComposeControls::cancelRequests() const { } rpl::producer<> ComposeControls::sendRequests() const { + auto filter = rpl::filter([=] { + return _send->type() == Ui::SendButton::Type::Schedule; + }); auto submits = base::qt_signal_producer( _field.get(), &Ui::InputField::submitted); return rpl::merge( - _send->clicks() | rpl::to_empty, - std::move(submits) | rpl::to_empty); + _send->clicks() | filter | rpl::to_empty, + std::move(submits) | filter | rpl::to_empty); +} + +rpl::producer ComposeControls::editRequests() const { + auto toValue = rpl::map([=] { return _header->queryToEdit(); }); + auto filter = rpl::filter([=] { + return _send->type() == Ui::SendButton::Type::Save; + }); + auto submits = base::qt_signal_producer( + _field.get(), + &Ui::InputField::submitted); + return rpl::merge( + _send->clicks() | filter | toValue, + std::move(submits) | filter | toValue); } rpl::producer<> ComposeControls::attachRequests() const { @@ -307,12 +346,12 @@ void ComposeControls::init() { }, _wrap->lifetime()); _header->editMsgId( - ) | rpl::start_with_next([=](auto item) { + ) | rpl::start_with_next([=](auto id) { updateHeight(); updateSendButtonType(); if (_header->isEditingMessage()) { - setTextFromEditingMessage(item); + setTextFromEditingMessage(_window->session().data().message(id)); } else { setText(_localSavedText); _localSavedText = {}; @@ -552,7 +591,12 @@ void ComposeControls::updateHeight() { } void ComposeControls::editMessage(FullMsgId edit) { + cancelEditMessage(); _header->editMessage(std::move(edit)); } +void ComposeControls::cancelEditMessage() { + _header->editMessage({}); +} + } // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/history_view_compose_controls.h b/Telegram/SourceFiles/history/view/history_view_compose_controls.h index c78794d556..99019c0331 100644 --- a/Telegram/SourceFiles/history/view/history_view_compose_controls.h +++ b/Telegram/SourceFiles/history/view/history_view_compose_controls.h @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +#include "api/api_common.h" #include "base/unique_qptr.h" #include "ui/rp_widget.h" #include "ui/effects/animations.h" @@ -54,6 +55,12 @@ public: Scheduled, }; + struct MessageToEdit { + FullMsgId fullId; + Api::SendOptions options; + TextWithTags textWithTags; + }; + ComposeControls( not_null parent, not_null window, @@ -72,6 +79,7 @@ public: void focus(); [[nodiscard]] rpl::producer<> cancelRequests() const; [[nodiscard]] rpl::producer<> sendRequests() const; + [[nodiscard]] rpl::producer editRequests() const; [[nodiscard]] rpl::producer<> attachRequests() const; [[nodiscard]] rpl::producer> fileChosen() const; [[nodiscard]] rpl::producer> photoChosen() const; @@ -93,6 +101,7 @@ public: void showFinished(); void editMessage(FullMsgId edit); + void cancelEditMessage(); [[nodiscard]] TextWithTags getTextWithAppliedMarkdown() const; void clear(); diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp index bb5626944b..011532ac71 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp @@ -17,10 +17,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/scroll_area.h" #include "ui/widgets/shadow.h" #include "ui/layers/generic_box.h" +#include "ui/text_options.h" #include "ui/toast/toast.h" #include "ui/special_buttons.h" #include "ui/ui_utility.h" #include "api/api_common.h" +#include "api/api_editing.h" #include "api/api_sending.h" #include "apiwrap.h" #include "boxes/confirm_box.h" @@ -34,6 +36,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_session.h" #include "data/data_user.h" #include "data/data_scheduled_messages.h" +#include "data/data_user.h" #include "storage/storage_media_prepare.h" #include "storage/storage_account.h" #include "inline_bots/inline_bot_result.h" @@ -163,6 +166,15 @@ void ScheduledWidget::setupComposeControls() { send(); }, lifetime()); + _composeControls->editRequests( + ) | rpl::start_with_next([=](auto data) { + if (const auto item = session().data().message(data.fullId)) { + if (item->isScheduled()) { + edit(item, data.options); + } + } + }, lifetime()); + _composeControls->attachRequests( ) | rpl::filter([=] { return !_choosingAttach; @@ -506,6 +518,71 @@ void ScheduledWidget::send(Api::SendOptions options) { _composeControls->focus(); } +void ScheduledWidget::edit( + not_null item, + Api::SendOptions options) { + + const auto textWithTags = _composeControls->getTextWithAppliedMarkdown(); + const auto prepareFlags = Ui::ItemTextOptions( + _history, + session().user()).flags; + auto sending = TextWithEntities(); + auto left = TextWithEntities { + textWithTags.text, + TextUtilities::ConvertTextTagsToEntities(textWithTags.tags) }; + TextUtilities::PrepareForSending(left, prepareFlags); + + if (!TextUtilities::CutPart(sending, left, MaxMessageSize)) { + if (item) { + Ui::show(Box(item, false)); + } else { + _composeControls->focus(); + } + return; + } else if (!left.text.isEmpty()) { + Ui::show(Box(tr::lng_edit_too_long(tr::now))); + return; + } + + const auto saveEditMsgRequestId = lifetime().make_state(0); + + const auto done = [=](const MTPUpdates &result, mtpRequestId requestId) { + if (requestId == *saveEditMsgRequestId) { + *saveEditMsgRequestId = 0; + _composeControls->cancelEditMessage(); + } + }; + + const auto fail = [=](const RPCError &error, mtpRequestId requestId) { + if (requestId == *saveEditMsgRequestId) { + *saveEditMsgRequestId = 0; + } + + const auto &err = error.type(); + if (ranges::contains(Api::kDefaultEditMessagesErrors, err)) { + Ui::show(Box(tr::lng_edit_error(tr::now))); + } else if (err == u"MESSAGE_NOT_MODIFIED"_q) { + _composeControls->cancelEditMessage(); + } else if (err == u"MESSAGE_EMPTY"_q) { + _composeControls->focus(); + } else { + Ui::show(Box(tr::lng_edit_error(tr::now))); + } + update(); + return true; + }; + + *saveEditMsgRequestId = Api::EditTextMessage( + item, + sending, + options, + crl::guard(this, done), + crl::guard(this, fail)); + + _composeControls->hidePanelsAnimated(); + _composeControls->focus(); +} + void ScheduledWidget::sendExistingDocument( not_null document) { const auto callback = [=](Api::SendOptions options) { diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.h b/Telegram/SourceFiles/history/view/history_view_scheduled_section.h index c4a25db078..ea978fa4ff 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.h +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.h @@ -141,6 +141,9 @@ private: void send(); void send(Api::SendOptions options); + void edit( + not_null item, + Api::SendOptions options); void highlightSingleNewMessage(const Data::MessagesSlice &slice); void chooseAttach(); [[nodiscard]] SendMenuType sendMenuType() const;