From 9290c90bdcdf0a93f46aa426aeca4fa4716f2fc0 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 12 Jun 2025 18:41:01 +0400 Subject: [PATCH] Allow fully editing todo lists. --- Telegram/CMakeLists.txt | 4 +- Telegram/SourceFiles/api/api_editing.cpp | 19 +++ Telegram/SourceFiles/api/api_editing.h | 7 ++ Telegram/SourceFiles/api/api_todo_lists.cpp | 20 +++- Telegram/SourceFiles/api/api_todo_lists.h | 7 ++ ...do_list_box.cpp => edit_todo_list_box.cpp} | 109 +++++++++++++----- ...e_todo_list_box.h => edit_todo_list_box.h} | 9 +- .../SourceFiles/data/data_media_types.cpp | 4 + Telegram/SourceFiles/data/data_media_types.h | 1 + Telegram/SourceFiles/data/data_peer.cpp | 3 +- .../SourceFiles/history/history_widget.cpp | 5 + .../history_view_compose_controls.cpp | 7 ++ .../view/history_view_chat_section.cpp | 2 + .../view/history_view_scheduled_section.cpp | 2 + .../business/settings_shortcut_messages.cpp | 3 + .../SourceFiles/window/window_peer_menu.cpp | 41 ++++++- .../SourceFiles/window/window_peer_menu.h | 3 + 17 files changed, 204 insertions(+), 42 deletions(-) rename Telegram/SourceFiles/boxes/{create_todo_list_box.cpp => edit_todo_list_box.cpp} (91%) rename Telegram/SourceFiles/boxes/{create_todo_list_box.h => edit_todo_list_box.h} (91%) diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index e83797828e..b2f6cd3587 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -273,8 +273,6 @@ PRIVATE boxes/connection_box.h boxes/create_poll_box.cpp boxes/create_poll_box.h - boxes/create_todo_list_box.cpp - boxes/create_todo_list_box.h boxes/delete_messages_box.cpp boxes/delete_messages_box.h boxes/dictionaries_manager.cpp @@ -285,6 +283,8 @@ PRIVATE boxes/edit_caption_box.h boxes/edit_privacy_box.cpp boxes/edit_privacy_box.h + boxes/edit_todo_list_box.cpp + boxes/edit_todo_list_box.h boxes/gift_credits_box.cpp boxes/gift_credits_box.h boxes/gift_premium_box.cpp diff --git a/Telegram/SourceFiles/api/api_editing.cpp b/Telegram/SourceFiles/api/api_editing.cpp index 4f5073a3b8..ed76f847f6 100644 --- a/Telegram/SourceFiles/api/api_editing.cpp +++ b/Telegram/SourceFiles/api/api_editing.cpp @@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_file_origin.h" #include "data/data_histories.h" #include "data/data_session.h" +#include "data/data_todo_list.h" #include "data/data_web_page.h" #include "history/view/controls/history_view_compose_media_edit_manager.h" #include "history/history.h" @@ -358,4 +359,22 @@ mtpRequestId EditTextMessage( std::nullopt); } +void EditTodoList( + not_null item, + const TodoListData &data, + SendOptions options, + Fn done, + Fn fail) { + const auto callback = [=](Fn applyUpdates, mtpRequestId id) { + applyUpdates(); + done(id); + }; + EditMessage( + item, + options, + callback, + fail, + MTP_inputMediaTodo(TodoListDataToMTP(&data))); +} + } // namespace Api diff --git a/Telegram/SourceFiles/api/api_editing.h b/Telegram/SourceFiles/api/api_editing.h index 630e1cd8d5..ca3ff7c121 100644 --- a/Telegram/SourceFiles/api/api_editing.h +++ b/Telegram/SourceFiles/api/api_editing.h @@ -58,4 +58,11 @@ mtpRequestId EditTextMessage( Fn fail, bool spoilered); +void EditTodoList( + not_null item, + const TodoListData &data, + SendOptions options, + Fn done, + Fn fail); + } // namespace Api diff --git a/Telegram/SourceFiles/api/api_todo_lists.cpp b/Telegram/SourceFiles/api/api_todo_lists.cpp index 123b9d10f6..ee0d64639a 100644 --- a/Telegram/SourceFiles/api/api_todo_lists.cpp +++ b/Telegram/SourceFiles/api/api_todo_lists.cpp @@ -7,8 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "api/api_todo_lists.h" -//#include "api/api_common.h" -//#include "api/api_updates.h" +#include "api/api_editing.h" #include "apiwrap.h" #include "base/random.h" #include "data/business/data_shortcut_messages.h" // ShortcutIdToMTP @@ -134,6 +133,23 @@ void TodoLists::create( }); } +void TodoLists::edit( + not_null item, + const TodoListData &data, + SendOptions options, + Fn done, + Fn fail) { + EditTodoList(item, data, options, [=](mtpRequestId) { + if (const auto onstack = done) { + onstack(); + } + }, [=](const QString &error, mtpRequestId) { + if (const auto onstack = fail) { + onstack(error); + } + }); +} + void TodoLists::add( not_null item, const std::vector &items, diff --git a/Telegram/SourceFiles/api/api_todo_lists.h b/Telegram/SourceFiles/api/api_todo_lists.h index 7331a28407..92d6a634b2 100644 --- a/Telegram/SourceFiles/api/api_todo_lists.h +++ b/Telegram/SourceFiles/api/api_todo_lists.h @@ -22,6 +22,7 @@ class Session; namespace Api { struct SendAction; +struct SendOptions; class TodoLists final { public: @@ -32,6 +33,12 @@ public: SendAction action, Fn done, Fn fail); + void edit( + not_null item, + const TodoListData &data, + SendOptions options, + Fn done, + Fn fail); void add( not_null item, const std::vector &items, diff --git a/Telegram/SourceFiles/boxes/create_todo_list_box.cpp b/Telegram/SourceFiles/boxes/edit_todo_list_box.cpp similarity index 91% rename from Telegram/SourceFiles/boxes/create_todo_list_box.cpp rename to Telegram/SourceFiles/boxes/edit_todo_list_box.cpp index ec20b1bfff..65591aaf9a 100644 --- a/Telegram/SourceFiles/boxes/create_todo_list_box.cpp +++ b/Telegram/SourceFiles/boxes/edit_todo_list_box.cpp @@ -5,7 +5,7 @@ the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ -#include "boxes/create_todo_list_box.h" +#include "boxes/edit_todo_list_box.h" #include "base/call_delayed.h" #include "base/event_filter.h" @@ -85,7 +85,6 @@ private: not_null container, not_null session, int id, - TextWithEntities text, int position, bool locked); @@ -144,7 +143,7 @@ private: int id, TextWithEntities text, anim::type animated); - void initTaskField(not_null task); + void initTaskField(not_null task, TextWithEntities text); void checkLastTask(); void validateState(); void fixAfterErase(); @@ -249,7 +248,6 @@ Tasks::Task::Task( not_null container, not_null session, int id, - TextWithEntities text, int position, bool locked) : _id(id) @@ -270,11 +268,6 @@ Tasks::Task::Task( , _limit(session->appConfig().todoListItemTextLimit()) { InitField(outer, _field, session); _field->setMaxLength(_limit + kErrorLimit); - _field->setTextWithTags({ - text.text, - TextUtilities::ConvertEntitiesToTextTags(text.entities) - }); - _field->finishAnimating(); _field->show(); if (locked) { _field->setDisabled(true); @@ -487,7 +480,7 @@ Tasks::Tasks( for (const auto &task : existing) { addTask(task.id, task.text, anim::type::instant); } - checkLastTask(); + validateState(); } bool Tasks::full() const { @@ -539,10 +532,13 @@ std::vector Tasks::toTodoListItems() const { result.reserve(_list.size()); auto usedId = 0; for (const auto &task : _list) { + if (const auto id = task->id()) { + usedId = id; + } else if (task->isGood()) { + ++usedId; + } if (task->isGood()) { - result.push_back(task->toTodoListItem(++usedId)); - } else if (const auto id = task->id()) { - usedId = std::max(usedId, id); + result.push_back(task->toTodoListItem(usedId)); } } return result; @@ -646,17 +642,28 @@ void Tasks::addTask( _container, &_controller->session(), id, - std::move(text), _position + _list.size() + _destroyed.size(), locked)); + const auto field = _list.back()->field(); if (!locked) { - initTaskField(_list.back().get()); + initTaskField(_list.back().get(), std::move(text)); + } else { + InitMessageFieldHandlers( + _controller, + field, + Window::GifPauseReason::Layer, + [](not_null) { return true; }); + field->setTextWithTags({ + text.text, + TextUtilities::ConvertEntitiesToTextTags(text.entities) + }); } + field->finishAnimating(); _list.back()->show(animated); fixShadows(); } -void Tasks::initTaskField(not_null task) { +void Tasks::initTaskField(not_null task, TextWithEntities text) { const auto field = task->field(); if (const auto emojiPanel = _emojiPanel) { const auto emojiToggle = Ui::AddEmojiToggleToField( @@ -686,6 +693,10 @@ void Tasks::initTaskField(not_null task) { }, _emojiPanelLifetime); }, emojiToggle->lifetime()); } + field->setTextWithTags({ + text.text, + TextUtilities::ConvertEntitiesToTextTags(text.entities) + }); field->submits( ) | rpl::start_with_next([=] { const auto index = findField(field); @@ -789,7 +800,7 @@ void Tasks::checkLastTask() { } // namespace -CreateTodoListBox::CreateTodoListBox( +EditTodoListBox::EditTodoListBox( QWidget*, not_null controller, rpl::producer starsRequired, @@ -802,25 +813,41 @@ CreateTodoListBox::CreateTodoListBox( , _titleLimit(controller->session().appConfig().todoListTitleLimit()) { } -auto CreateTodoListBox::submitRequests() const -> rpl::producer { +EditTodoListBox::EditTodoListBox( + QWidget*, + not_null controller, + not_null item) +: _controller(controller) +, _sendMenuDetails([] { return SendMenu::Details(); }) +, _editingItem(item) +, _titleLimit(controller->session().appConfig().todoListTitleLimit()) { + _controller->session().changes().messageUpdates( + Data::MessageUpdate::Flag::Destroyed + ) | rpl::start_with_next([=](const Data::MessageUpdate &update) { + if (update.item == item) { + closeBox(); + } + }, lifetime()); +} + +auto EditTodoListBox::submitRequests() const -> rpl::producer { return _submitRequests.events(); } -void CreateTodoListBox::setInnerFocus() { +void EditTodoListBox::setInnerFocus() { _setInnerFocus(); } -void CreateTodoListBox::submitFailed(const QString &error) { +void EditTodoListBox::submitFailed(const QString &error) { showToast(error); } -not_null CreateTodoListBox::setupTitle( +not_null EditTodoListBox::setupTitle( not_null container) { using namespace Settings; const auto session = &_controller->session(); const auto isPremium = session->premium(); - const auto title = container->add( object_ptr( container, @@ -860,6 +887,15 @@ not_null CreateTodoListBox::setupTitle( }, emojiToggle->lifetime()); } + const auto media = _editingItem ? _editingItem->media() : nullptr; + if (const auto todolist = media ? media->todolist() : nullptr) { + const auto &text = todolist->title; + title->setTextWithTags({ + text.text, + TextUtilities::ConvertEntitiesToTextTags(text.entities) + }); + } + const auto warning = CreateWarningLabel( container, title, @@ -885,7 +921,7 @@ not_null CreateTodoListBox::setupTitle( return title; } -object_ptr CreateTodoListBox::setupContent() { +object_ptr EditTodoListBox::setupContent() { using namespace Settings; const auto id = FullMsgId{ @@ -906,11 +942,14 @@ object_ptr CreateTodoListBox::setupContent() { tr::lng_todo_create_list(), st::defaultSubsectionTitle), st::createPollFieldTitlePadding); + const auto media = _editingItem ? _editingItem->media() : nullptr; + const auto todolist = media ? media->todolist() : nullptr; const auto tasks = lifetime().make_state( this, container, _controller, - _emojiPanel ? _emojiPanel.get() : nullptr); + _emojiPanel ? _emojiPanel.get() : nullptr, + todolist ? todolist->items : std::vector()); auto limit = tasks->addedCount() | rpl::after_next([=](int count) { setCloseByEscape(!count); setCloseByOutsideClick(!count); @@ -944,14 +983,14 @@ object_ptr CreateTodoListBox::setupContent() { object_ptr( container, tr::lng_todo_create_allow_add(tr::now), - true, + !todolist || todolist->othersCanAppend(), st::defaultCheckbox), st::createPollCheckboxMargin); const auto allowMark = container->add( object_ptr( container, tr::lng_todo_create_allow_mark(tr::now), - true, + !todolist || todolist->othersCanComplete(), st::defaultCheckbox), st::createPollCheckboxMargin); @@ -1019,6 +1058,14 @@ object_ptr CreateTodoListBox::setupContent() { showError(tr::lng_todo_choose_tasks); tasks->focusFirst(); } else if (!*error) { + if (_editingItem) { + sendOptions = { + .scheduled = (_editingItem->isScheduled() + ? _editingItem->date() + : TimeId()), + .shortcutId = _editingItem->shortcutId(), + }; + } _submitRequests.fire({ collectResult(), sendOptions }); } }; @@ -1043,9 +1090,13 @@ object_ptr CreateTodoListBox::setupContent() { _sendMenuDetails()); }; const auto submit = addButton( - tr::lng_todo_create_button(), + (_editingItem + ? tr::lng_settings_save() + : tr::lng_todo_create_button()), [=] { isNormal ? send({}) : schedule(); }); - submit->setText(PaidSendButtonText(_starsRequired.value(), isNormal + submit->setText(PaidSendButtonText(_starsRequired.value(), _editingItem + ? tr::lng_settings_save() + : isNormal ? tr::lng_todo_create_button() : tr::lng_schedule_button())); const auto sendMenuDetails = [=] { @@ -1062,7 +1113,7 @@ object_ptr CreateTodoListBox::setupContent() { return result; } -void CreateTodoListBox::prepare() { +void EditTodoListBox::prepare() { setTitle(tr::lng_todo_create_title()); const auto inner = setInnerWidget(setupContent()); diff --git a/Telegram/SourceFiles/boxes/create_todo_list_box.h b/Telegram/SourceFiles/boxes/edit_todo_list_box.h similarity index 91% rename from Telegram/SourceFiles/boxes/create_todo_list_box.h rename to Telegram/SourceFiles/boxes/edit_todo_list_box.h index 3b9078150e..45ec17f9d8 100644 --- a/Telegram/SourceFiles/boxes/create_todo_list_box.h +++ b/Telegram/SourceFiles/boxes/edit_todo_list_box.h @@ -30,19 +30,23 @@ namespace SendMenu { struct Details; } // namespace SendMenu -class CreateTodoListBox : public Ui::BoxContent { +class EditTodoListBox : public Ui::BoxContent { public: struct Result { TodoListData todolist; Api::SendOptions options; }; - CreateTodoListBox( + EditTodoListBox( QWidget*, not_null controller, rpl::producer starsRequired, Api::SendType sendType, SendMenu::Details sendMenuDetails); + EditTodoListBox( + QWidget*, + not_null controller, + not_null item); [[nodiscard]] rpl::producer submitRequests() const; void submitFailed(const QString &error); @@ -68,6 +72,7 @@ private: const not_null _controller; const Api::SendType _sendType = Api::SendType(); const Fn _sendMenuDetails; + HistoryItem *_editingItem = nullptr; rpl::variable _starsRequired; base::unique_qptr _emojiPanel; Fn _setInnerFocus; diff --git a/Telegram/SourceFiles/data/data_media_types.cpp b/Telegram/SourceFiles/data/data_media_types.cpp index f54f5e6add..e4fc70bf56 100644 --- a/Telegram/SourceFiles/data/data_media_types.cpp +++ b/Telegram/SourceFiles/data/data_media_types.cpp @@ -2367,6 +2367,10 @@ TextForMimeData MediaTodoList::clipboardText() const { return TextForMimeData::Rich(std::move(result)); } +bool MediaTodoList::allowsEdit() const { + return parent()->out(); +} + bool MediaTodoList::updateInlineResultMedia(const MTPMessageMedia &media) { return false; } diff --git a/Telegram/SourceFiles/data/data_media_types.h b/Telegram/SourceFiles/data/data_media_types.h index fd4cc54d33..7f0e172306 100644 --- a/Telegram/SourceFiles/data/data_media_types.h +++ b/Telegram/SourceFiles/data/data_media_types.h @@ -625,6 +625,7 @@ public: TextWithEntities notificationText() const override; QString pinnedTextSubstring() const override; TextForMimeData clipboardText() const override; + bool allowsEdit() const override; bool updateInlineResultMedia(const MTPMessageMedia &media) override; bool updateSentMedia(const MTPMessageMedia &media) override; diff --git a/Telegram/SourceFiles/data/data_peer.cpp b/Telegram/SourceFiles/data/data_peer.cpp index 2927add840..b4f4588372 100644 --- a/Telegram/SourceFiles/data/data_peer.cpp +++ b/Telegram/SourceFiles/data/data_peer.cpp @@ -685,7 +685,8 @@ bool PeerData::canCreatePolls() const { } bool PeerData::canCreateTodoLists() const { - return Data::CanSend(this, ChatRestriction::SendPolls) || isUser(); + return session().premium() + && (Data::CanSend(this, ChatRestriction::SendPolls) || isUser()); } bool PeerData::canCreateTopics() const { diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index eb170a4250..0eb51fbb53 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -8559,6 +8559,11 @@ void HistoryWidget::editMessage( } else if (_voiceRecordBar->isActive()) { controller()->showToast(tr::lng_edit_caption_voice(tr::now)); return; + } else if (const auto media = item->media()) { + if (const auto todolist = media->todolist()) { + Window::PeerMenuEditTodoList(controller(), item); + return; + } } else if (_composeSearch) { _composeSearch->hideAnimated(); } 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 e0b3256f4d..52aecc6994 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -84,6 +84,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/effects/spoiler_mess.h" #include "webrtc/webrtc_environment.h" #include "window/window_adaptive.h" +#include "window/window_peer_menu.h" #include "window/window_session_controller.h" #include "mainwindow.h" #include "styles/style_chat.h" @@ -2952,6 +2953,12 @@ void ComposeControls::editMessage(not_null item) { if (_voiceRecordBar->isActive()) { _show->showBox(Ui::MakeInformBox(tr::lng_edit_caption_voice())); return; + } else if (const auto media = item->media()) { + if (const auto todolist = media->todolist()) { + Assert(_regularWindow != nullptr); + Window::PeerMenuEditTodoList(_regularWindow, item); + return; + } } if (!isEditingMessage()) { diff --git a/Telegram/SourceFiles/history/view/history_view_chat_section.cpp b/Telegram/SourceFiles/history/view/history_view_chat_section.cpp index 7f40aac55f..03f871bbaf 100644 --- a/Telegram/SourceFiles/history/view/history_view_chat_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_chat_section.cpp @@ -352,6 +352,8 @@ ChatWidget::ChatWidget( _composeControls->editMessage( fullId, _inner->getSelectedTextRange(item)); + } else if (media->todolist()) { + Window::PeerMenuEditTodoList(controller, item); } } }, _inner->lifetime()); diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp index 812893be3c..3842e2eb2e 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp @@ -231,6 +231,8 @@ ScheduledWidget::ScheduledWidget( _composeControls->editMessage( fullId, _inner->getSelectedTextRange(item)); + } else if (media->todolist()) { + Window::PeerMenuEditTodoList(controller, item); } } }, _inner->lifetime()); diff --git a/Telegram/SourceFiles/settings/business/settings_shortcut_messages.cpp b/Telegram/SourceFiles/settings/business/settings_shortcut_messages.cpp index 8963cff5b3..fa1fd40fd0 100644 --- a/Telegram/SourceFiles/settings/business/settings_shortcut_messages.cpp +++ b/Telegram/SourceFiles/settings/business/settings_shortcut_messages.cpp @@ -58,6 +58,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/painter.h" #include "window/themes/window_theme.h" #include "window/section_widget.h" +#include "window/window_peer_menu.h" #include "window/window_session_controller.h" #include "styles/style_boxes.h" #include "styles/style_chat_helpers.h" @@ -399,6 +400,8 @@ ShortcutMessages::ShortcutMessages( _composeControls->editMessage( fullId, _inner->getSelectedTextRange(item)); + } else if (media->todolist()) { + Window::PeerMenuEditTodoList(_controller, item); } } }, _inner->lifetime()); diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index 6457792767..e806bf7c7d 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -29,7 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/moderate_messages_box.h" #include "boxes/choose_filter_box.h" #include "boxes/create_poll_box.h" -#include "boxes/create_todo_list_box.h" +#include "boxes/edit_todo_list_box.h" #include "boxes/pin_messages_box.h" #include "boxes/premium_limits_box.h" #include "boxes/report_messages_box.h" @@ -1244,7 +1244,8 @@ void Filler::addCreateTodoList() { return; } const auto can = _topic - ? Data::CanSend(_topic, ChatRestriction::SendPolls) + ? (_peer->session().premium() + && Data::CanSend(_topic, ChatRestriction::SendPolls)) : _peer->canCreateTodoLists(); if (!can) { return; @@ -1973,19 +1974,19 @@ void PeerMenuCreateTodoList( ) | rpl::map([=] { return peer->starsPerMessageChecked(); }); - auto box = Box( + auto box = Box( controller, std::move(starsRequired), sendType, sendMenuDetails); struct State { - Fn create; + Fn create; SendPaymentHelper sendPayment; bool lock = false; }; - const auto weak = QPointer(box); + const auto weak = QPointer(box); const auto state = box->lifetime().make_state(); - state->create = [=](const CreateTodoListBox::Result &result) { + state->create = [=](const EditTodoListBox::Result &result) { const auto withPaymentApproved = crl::guard(weak, [=](int stars) { if (const auto onstack = state->create) { auto copy = result; @@ -2028,6 +2029,34 @@ void PeerMenuCreateTodoList( controller->show(std::move(box), Ui::LayerOption::CloseOther); } +void PeerMenuEditTodoList( + not_null controller, + not_null item) { + const auto media = item->media(); + const auto todolist = media ? media->todolist() : nullptr; + if (!todolist) { + return; + } else if (!item->history()->session().premium()) { + PeerMenuTodoWantsPremium(TodoWantsPremium::Add); + return; + } + auto box = Box(controller, item); + const auto weak = QPointer(box); + box->submitRequests( + ) | rpl::start_with_next([=](const EditTodoListBox::Result &result) { + const auto api = &item->history()->session().api(); + api->todoLists().edit( + item, + result.todolist, + result.options, + crl::guard(weak, [=] { weak->closeBox(); }), + crl::guard(weak, [=](const QString &error) { + weak->submitFailed(error); + })); + }, box->lifetime()); + controller->show(std::move(box), Ui::LayerOption::CloseOther); +} + bool PeerMenuShowAddTodoListTasks(not_null item) { const auto media = item ? item->media() : nullptr; const auto todolist = media ? media->todolist() : nullptr; diff --git a/Telegram/SourceFiles/window/window_peer_menu.h b/Telegram/SourceFiles/window/window_peer_menu.h index 961ee18e86..1b33297498 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.h +++ b/Telegram/SourceFiles/window/window_peer_menu.h @@ -123,6 +123,9 @@ void PeerMenuCreateTodoList( FullReplyTo replyTo = FullReplyTo(), Api::SendType sendType = Api::SendType::Normal, SendMenu::Details sendMenuDetails = SendMenu::Details()); +void PeerMenuEditTodoList( + not_null controller, + not_null item); [[nodiscard]] bool PeerMenuShowAddTodoListTasks(not_null item); void PeerMenuAddTodoListTasks( not_null controller,