mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-07-27 07:52:57 +02:00
Allow fully editing todo lists.
This commit is contained in:
parent
d83a80ec53
commit
9290c90bdc
17 changed files with 204 additions and 42 deletions
|
@ -273,8 +273,6 @@ PRIVATE
|
||||||
boxes/connection_box.h
|
boxes/connection_box.h
|
||||||
boxes/create_poll_box.cpp
|
boxes/create_poll_box.cpp
|
||||||
boxes/create_poll_box.h
|
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.cpp
|
||||||
boxes/delete_messages_box.h
|
boxes/delete_messages_box.h
|
||||||
boxes/dictionaries_manager.cpp
|
boxes/dictionaries_manager.cpp
|
||||||
|
@ -285,6 +283,8 @@ PRIVATE
|
||||||
boxes/edit_caption_box.h
|
boxes/edit_caption_box.h
|
||||||
boxes/edit_privacy_box.cpp
|
boxes/edit_privacy_box.cpp
|
||||||
boxes/edit_privacy_box.h
|
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.cpp
|
||||||
boxes/gift_credits_box.h
|
boxes/gift_credits_box.h
|
||||||
boxes/gift_premium_box.cpp
|
boxes/gift_premium_box.cpp
|
||||||
|
|
|
@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
#include "data/data_histories.h"
|
#include "data/data_histories.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
|
#include "data/data_todo_list.h"
|
||||||
#include "data/data_web_page.h"
|
#include "data/data_web_page.h"
|
||||||
#include "history/view/controls/history_view_compose_media_edit_manager.h"
|
#include "history/view/controls/history_view_compose_media_edit_manager.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
|
@ -358,4 +359,22 @@ mtpRequestId EditTextMessage(
|
||||||
std::nullopt);
|
std::nullopt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EditTodoList(
|
||||||
|
not_null<HistoryItem*> item,
|
||||||
|
const TodoListData &data,
|
||||||
|
SendOptions options,
|
||||||
|
Fn<void(mtpRequestId requestId)> done,
|
||||||
|
Fn<void(const QString &error, mtpRequestId requestId)> fail) {
|
||||||
|
const auto callback = [=](Fn<void()> applyUpdates, mtpRequestId id) {
|
||||||
|
applyUpdates();
|
||||||
|
done(id);
|
||||||
|
};
|
||||||
|
EditMessage(
|
||||||
|
item,
|
||||||
|
options,
|
||||||
|
callback,
|
||||||
|
fail,
|
||||||
|
MTP_inputMediaTodo(TodoListDataToMTP(&data)));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Api
|
} // namespace Api
|
||||||
|
|
|
@ -58,4 +58,11 @@ mtpRequestId EditTextMessage(
|
||||||
Fn<void(const QString &error, mtpRequestId requestId)> fail,
|
Fn<void(const QString &error, mtpRequestId requestId)> fail,
|
||||||
bool spoilered);
|
bool spoilered);
|
||||||
|
|
||||||
|
void EditTodoList(
|
||||||
|
not_null<HistoryItem*> item,
|
||||||
|
const TodoListData &data,
|
||||||
|
SendOptions options,
|
||||||
|
Fn<void(mtpRequestId requestId)> done,
|
||||||
|
Fn<void(const QString &error, mtpRequestId requestId)> fail);
|
||||||
|
|
||||||
} // namespace Api
|
} // namespace Api
|
||||||
|
|
|
@ -7,8 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#include "api/api_todo_lists.h"
|
#include "api/api_todo_lists.h"
|
||||||
|
|
||||||
//#include "api/api_common.h"
|
#include "api/api_editing.h"
|
||||||
//#include "api/api_updates.h"
|
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "base/random.h"
|
#include "base/random.h"
|
||||||
#include "data/business/data_shortcut_messages.h" // ShortcutIdToMTP
|
#include "data/business/data_shortcut_messages.h" // ShortcutIdToMTP
|
||||||
|
@ -134,6 +133,23 @@ void TodoLists::create(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TodoLists::edit(
|
||||||
|
not_null<HistoryItem*> item,
|
||||||
|
const TodoListData &data,
|
||||||
|
SendOptions options,
|
||||||
|
Fn<void()> done,
|
||||||
|
Fn<void(QString)> 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(
|
void TodoLists::add(
|
||||||
not_null<HistoryItem*> item,
|
not_null<HistoryItem*> item,
|
||||||
const std::vector<TodoListItem> &items,
|
const std::vector<TodoListItem> &items,
|
||||||
|
|
|
@ -22,6 +22,7 @@ class Session;
|
||||||
namespace Api {
|
namespace Api {
|
||||||
|
|
||||||
struct SendAction;
|
struct SendAction;
|
||||||
|
struct SendOptions;
|
||||||
|
|
||||||
class TodoLists final {
|
class TodoLists final {
|
||||||
public:
|
public:
|
||||||
|
@ -32,6 +33,12 @@ public:
|
||||||
SendAction action,
|
SendAction action,
|
||||||
Fn<void()> done,
|
Fn<void()> done,
|
||||||
Fn<void(QString)> fail);
|
Fn<void(QString)> fail);
|
||||||
|
void edit(
|
||||||
|
not_null<HistoryItem*> item,
|
||||||
|
const TodoListData &data,
|
||||||
|
SendOptions options,
|
||||||
|
Fn<void()> done,
|
||||||
|
Fn<void(QString)> fail);
|
||||||
void add(
|
void add(
|
||||||
not_null<HistoryItem*> item,
|
not_null<HistoryItem*> item,
|
||||||
const std::vector<TodoListItem> &items,
|
const std::vector<TodoListItem> &items,
|
||||||
|
|
|
@ -5,7 +5,7 @@ the official desktop application for the Telegram messaging service.
|
||||||
For license and copyright information please follow this link:
|
For license and copyright information please follow this link:
|
||||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
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/call_delayed.h"
|
||||||
#include "base/event_filter.h"
|
#include "base/event_filter.h"
|
||||||
|
@ -85,7 +85,6 @@ private:
|
||||||
not_null<Ui::VerticalLayout*> container,
|
not_null<Ui::VerticalLayout*> container,
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
int id,
|
int id,
|
||||||
TextWithEntities text,
|
|
||||||
int position,
|
int position,
|
||||||
bool locked);
|
bool locked);
|
||||||
|
|
||||||
|
@ -144,7 +143,7 @@ private:
|
||||||
int id,
|
int id,
|
||||||
TextWithEntities text,
|
TextWithEntities text,
|
||||||
anim::type animated);
|
anim::type animated);
|
||||||
void initTaskField(not_null<Task*> task);
|
void initTaskField(not_null<Task*> task, TextWithEntities text);
|
||||||
void checkLastTask();
|
void checkLastTask();
|
||||||
void validateState();
|
void validateState();
|
||||||
void fixAfterErase();
|
void fixAfterErase();
|
||||||
|
@ -249,7 +248,6 @@ Tasks::Task::Task(
|
||||||
not_null<Ui::VerticalLayout*> container,
|
not_null<Ui::VerticalLayout*> container,
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
int id,
|
int id,
|
||||||
TextWithEntities text,
|
|
||||||
int position,
|
int position,
|
||||||
bool locked)
|
bool locked)
|
||||||
: _id(id)
|
: _id(id)
|
||||||
|
@ -270,11 +268,6 @@ Tasks::Task::Task(
|
||||||
, _limit(session->appConfig().todoListItemTextLimit()) {
|
, _limit(session->appConfig().todoListItemTextLimit()) {
|
||||||
InitField(outer, _field, session);
|
InitField(outer, _field, session);
|
||||||
_field->setMaxLength(_limit + kErrorLimit);
|
_field->setMaxLength(_limit + kErrorLimit);
|
||||||
_field->setTextWithTags({
|
|
||||||
text.text,
|
|
||||||
TextUtilities::ConvertEntitiesToTextTags(text.entities)
|
|
||||||
});
|
|
||||||
_field->finishAnimating();
|
|
||||||
_field->show();
|
_field->show();
|
||||||
if (locked) {
|
if (locked) {
|
||||||
_field->setDisabled(true);
|
_field->setDisabled(true);
|
||||||
|
@ -487,7 +480,7 @@ Tasks::Tasks(
|
||||||
for (const auto &task : existing) {
|
for (const auto &task : existing) {
|
||||||
addTask(task.id, task.text, anim::type::instant);
|
addTask(task.id, task.text, anim::type::instant);
|
||||||
}
|
}
|
||||||
checkLastTask();
|
validateState();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Tasks::full() const {
|
bool Tasks::full() const {
|
||||||
|
@ -539,10 +532,13 @@ std::vector<TodoListItem> Tasks::toTodoListItems() const {
|
||||||
result.reserve(_list.size());
|
result.reserve(_list.size());
|
||||||
auto usedId = 0;
|
auto usedId = 0;
|
||||||
for (const auto &task : _list) {
|
for (const auto &task : _list) {
|
||||||
|
if (const auto id = task->id()) {
|
||||||
|
usedId = id;
|
||||||
|
} else if (task->isGood()) {
|
||||||
|
++usedId;
|
||||||
|
}
|
||||||
if (task->isGood()) {
|
if (task->isGood()) {
|
||||||
result.push_back(task->toTodoListItem(++usedId));
|
result.push_back(task->toTodoListItem(usedId));
|
||||||
} else if (const auto id = task->id()) {
|
|
||||||
usedId = std::max(usedId, id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -646,17 +642,28 @@ void Tasks::addTask(
|
||||||
_container,
|
_container,
|
||||||
&_controller->session(),
|
&_controller->session(),
|
||||||
id,
|
id,
|
||||||
std::move(text),
|
|
||||||
_position + _list.size() + _destroyed.size(),
|
_position + _list.size() + _destroyed.size(),
|
||||||
locked));
|
locked));
|
||||||
|
const auto field = _list.back()->field();
|
||||||
if (!locked) {
|
if (!locked) {
|
||||||
initTaskField(_list.back().get());
|
initTaskField(_list.back().get(), std::move(text));
|
||||||
|
} else {
|
||||||
|
InitMessageFieldHandlers(
|
||||||
|
_controller,
|
||||||
|
field,
|
||||||
|
Window::GifPauseReason::Layer,
|
||||||
|
[](not_null<DocumentData*>) { return true; });
|
||||||
|
field->setTextWithTags({
|
||||||
|
text.text,
|
||||||
|
TextUtilities::ConvertEntitiesToTextTags(text.entities)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
field->finishAnimating();
|
||||||
_list.back()->show(animated);
|
_list.back()->show(animated);
|
||||||
fixShadows();
|
fixShadows();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tasks::initTaskField(not_null<Task*> task) {
|
void Tasks::initTaskField(not_null<Task*> task, TextWithEntities text) {
|
||||||
const auto field = task->field();
|
const auto field = task->field();
|
||||||
if (const auto emojiPanel = _emojiPanel) {
|
if (const auto emojiPanel = _emojiPanel) {
|
||||||
const auto emojiToggle = Ui::AddEmojiToggleToField(
|
const auto emojiToggle = Ui::AddEmojiToggleToField(
|
||||||
|
@ -686,6 +693,10 @@ void Tasks::initTaskField(not_null<Task*> task) {
|
||||||
}, _emojiPanelLifetime);
|
}, _emojiPanelLifetime);
|
||||||
}, emojiToggle->lifetime());
|
}, emojiToggle->lifetime());
|
||||||
}
|
}
|
||||||
|
field->setTextWithTags({
|
||||||
|
text.text,
|
||||||
|
TextUtilities::ConvertEntitiesToTextTags(text.entities)
|
||||||
|
});
|
||||||
field->submits(
|
field->submits(
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
const auto index = findField(field);
|
const auto index = findField(field);
|
||||||
|
@ -789,7 +800,7 @@ void Tasks::checkLastTask() {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
CreateTodoListBox::CreateTodoListBox(
|
EditTodoListBox::EditTodoListBox(
|
||||||
QWidget*,
|
QWidget*,
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
rpl::producer<int> starsRequired,
|
rpl::producer<int> starsRequired,
|
||||||
|
@ -802,25 +813,41 @@ CreateTodoListBox::CreateTodoListBox(
|
||||||
, _titleLimit(controller->session().appConfig().todoListTitleLimit()) {
|
, _titleLimit(controller->session().appConfig().todoListTitleLimit()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CreateTodoListBox::submitRequests() const -> rpl::producer<Result> {
|
EditTodoListBox::EditTodoListBox(
|
||||||
|
QWidget*,
|
||||||
|
not_null<Window::SessionController*> controller,
|
||||||
|
not_null<HistoryItem*> 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<Result> {
|
||||||
return _submitRequests.events();
|
return _submitRequests.events();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateTodoListBox::setInnerFocus() {
|
void EditTodoListBox::setInnerFocus() {
|
||||||
_setInnerFocus();
|
_setInnerFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateTodoListBox::submitFailed(const QString &error) {
|
void EditTodoListBox::submitFailed(const QString &error) {
|
||||||
showToast(error);
|
showToast(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
not_null<Ui::InputField*> CreateTodoListBox::setupTitle(
|
not_null<Ui::InputField*> EditTodoListBox::setupTitle(
|
||||||
not_null<Ui::VerticalLayout*> container) {
|
not_null<Ui::VerticalLayout*> container) {
|
||||||
using namespace Settings;
|
using namespace Settings;
|
||||||
|
|
||||||
const auto session = &_controller->session();
|
const auto session = &_controller->session();
|
||||||
const auto isPremium = session->premium();
|
const auto isPremium = session->premium();
|
||||||
|
|
||||||
const auto title = container->add(
|
const auto title = container->add(
|
||||||
object_ptr<Ui::InputField>(
|
object_ptr<Ui::InputField>(
|
||||||
container,
|
container,
|
||||||
|
@ -860,6 +887,15 @@ not_null<Ui::InputField*> CreateTodoListBox::setupTitle(
|
||||||
}, emojiToggle->lifetime());
|
}, 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(
|
const auto warning = CreateWarningLabel(
|
||||||
container,
|
container,
|
||||||
title,
|
title,
|
||||||
|
@ -885,7 +921,7 @@ not_null<Ui::InputField*> CreateTodoListBox::setupTitle(
|
||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
object_ptr<Ui::RpWidget> CreateTodoListBox::setupContent() {
|
object_ptr<Ui::RpWidget> EditTodoListBox::setupContent() {
|
||||||
using namespace Settings;
|
using namespace Settings;
|
||||||
|
|
||||||
const auto id = FullMsgId{
|
const auto id = FullMsgId{
|
||||||
|
@ -906,11 +942,14 @@ object_ptr<Ui::RpWidget> CreateTodoListBox::setupContent() {
|
||||||
tr::lng_todo_create_list(),
|
tr::lng_todo_create_list(),
|
||||||
st::defaultSubsectionTitle),
|
st::defaultSubsectionTitle),
|
||||||
st::createPollFieldTitlePadding);
|
st::createPollFieldTitlePadding);
|
||||||
|
const auto media = _editingItem ? _editingItem->media() : nullptr;
|
||||||
|
const auto todolist = media ? media->todolist() : nullptr;
|
||||||
const auto tasks = lifetime().make_state<Tasks>(
|
const auto tasks = lifetime().make_state<Tasks>(
|
||||||
this,
|
this,
|
||||||
container,
|
container,
|
||||||
_controller,
|
_controller,
|
||||||
_emojiPanel ? _emojiPanel.get() : nullptr);
|
_emojiPanel ? _emojiPanel.get() : nullptr,
|
||||||
|
todolist ? todolist->items : std::vector<TodoListItem>());
|
||||||
auto limit = tasks->addedCount() | rpl::after_next([=](int count) {
|
auto limit = tasks->addedCount() | rpl::after_next([=](int count) {
|
||||||
setCloseByEscape(!count);
|
setCloseByEscape(!count);
|
||||||
setCloseByOutsideClick(!count);
|
setCloseByOutsideClick(!count);
|
||||||
|
@ -944,14 +983,14 @@ object_ptr<Ui::RpWidget> CreateTodoListBox::setupContent() {
|
||||||
object_ptr<Ui::Checkbox>(
|
object_ptr<Ui::Checkbox>(
|
||||||
container,
|
container,
|
||||||
tr::lng_todo_create_allow_add(tr::now),
|
tr::lng_todo_create_allow_add(tr::now),
|
||||||
true,
|
!todolist || todolist->othersCanAppend(),
|
||||||
st::defaultCheckbox),
|
st::defaultCheckbox),
|
||||||
st::createPollCheckboxMargin);
|
st::createPollCheckboxMargin);
|
||||||
const auto allowMark = container->add(
|
const auto allowMark = container->add(
|
||||||
object_ptr<Ui::Checkbox>(
|
object_ptr<Ui::Checkbox>(
|
||||||
container,
|
container,
|
||||||
tr::lng_todo_create_allow_mark(tr::now),
|
tr::lng_todo_create_allow_mark(tr::now),
|
||||||
true,
|
!todolist || todolist->othersCanComplete(),
|
||||||
st::defaultCheckbox),
|
st::defaultCheckbox),
|
||||||
st::createPollCheckboxMargin);
|
st::createPollCheckboxMargin);
|
||||||
|
|
||||||
|
@ -1019,6 +1058,14 @@ object_ptr<Ui::RpWidget> CreateTodoListBox::setupContent() {
|
||||||
showError(tr::lng_todo_choose_tasks);
|
showError(tr::lng_todo_choose_tasks);
|
||||||
tasks->focusFirst();
|
tasks->focusFirst();
|
||||||
} else if (!*error) {
|
} else if (!*error) {
|
||||||
|
if (_editingItem) {
|
||||||
|
sendOptions = {
|
||||||
|
.scheduled = (_editingItem->isScheduled()
|
||||||
|
? _editingItem->date()
|
||||||
|
: TimeId()),
|
||||||
|
.shortcutId = _editingItem->shortcutId(),
|
||||||
|
};
|
||||||
|
}
|
||||||
_submitRequests.fire({ collectResult(), sendOptions });
|
_submitRequests.fire({ collectResult(), sendOptions });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1043,9 +1090,13 @@ object_ptr<Ui::RpWidget> CreateTodoListBox::setupContent() {
|
||||||
_sendMenuDetails());
|
_sendMenuDetails());
|
||||||
};
|
};
|
||||||
const auto submit = addButton(
|
const auto submit = addButton(
|
||||||
tr::lng_todo_create_button(),
|
(_editingItem
|
||||||
|
? tr::lng_settings_save()
|
||||||
|
: tr::lng_todo_create_button()),
|
||||||
[=] { isNormal ? send({}) : schedule(); });
|
[=] { 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_todo_create_button()
|
||||||
: tr::lng_schedule_button()));
|
: tr::lng_schedule_button()));
|
||||||
const auto sendMenuDetails = [=] {
|
const auto sendMenuDetails = [=] {
|
||||||
|
@ -1062,7 +1113,7 @@ object_ptr<Ui::RpWidget> CreateTodoListBox::setupContent() {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateTodoListBox::prepare() {
|
void EditTodoListBox::prepare() {
|
||||||
setTitle(tr::lng_todo_create_title());
|
setTitle(tr::lng_todo_create_title());
|
||||||
|
|
||||||
const auto inner = setInnerWidget(setupContent());
|
const auto inner = setInnerWidget(setupContent());
|
|
@ -30,19 +30,23 @@ namespace SendMenu {
|
||||||
struct Details;
|
struct Details;
|
||||||
} // namespace SendMenu
|
} // namespace SendMenu
|
||||||
|
|
||||||
class CreateTodoListBox : public Ui::BoxContent {
|
class EditTodoListBox : public Ui::BoxContent {
|
||||||
public:
|
public:
|
||||||
struct Result {
|
struct Result {
|
||||||
TodoListData todolist;
|
TodoListData todolist;
|
||||||
Api::SendOptions options;
|
Api::SendOptions options;
|
||||||
};
|
};
|
||||||
|
|
||||||
CreateTodoListBox(
|
EditTodoListBox(
|
||||||
QWidget*,
|
QWidget*,
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
rpl::producer<int> starsRequired,
|
rpl::producer<int> starsRequired,
|
||||||
Api::SendType sendType,
|
Api::SendType sendType,
|
||||||
SendMenu::Details sendMenuDetails);
|
SendMenu::Details sendMenuDetails);
|
||||||
|
EditTodoListBox(
|
||||||
|
QWidget*,
|
||||||
|
not_null<Window::SessionController*> controller,
|
||||||
|
not_null<HistoryItem*> item);
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<Result> submitRequests() const;
|
[[nodiscard]] rpl::producer<Result> submitRequests() const;
|
||||||
void submitFailed(const QString &error);
|
void submitFailed(const QString &error);
|
||||||
|
@ -68,6 +72,7 @@ private:
|
||||||
const not_null<Window::SessionController*> _controller;
|
const not_null<Window::SessionController*> _controller;
|
||||||
const Api::SendType _sendType = Api::SendType();
|
const Api::SendType _sendType = Api::SendType();
|
||||||
const Fn<SendMenu::Details()> _sendMenuDetails;
|
const Fn<SendMenu::Details()> _sendMenuDetails;
|
||||||
|
HistoryItem *_editingItem = nullptr;
|
||||||
rpl::variable<int> _starsRequired;
|
rpl::variable<int> _starsRequired;
|
||||||
base::unique_qptr<ChatHelpers::TabbedPanel> _emojiPanel;
|
base::unique_qptr<ChatHelpers::TabbedPanel> _emojiPanel;
|
||||||
Fn<void()> _setInnerFocus;
|
Fn<void()> _setInnerFocus;
|
|
@ -2367,6 +2367,10 @@ TextForMimeData MediaTodoList::clipboardText() const {
|
||||||
return TextForMimeData::Rich(std::move(result));
|
return TextForMimeData::Rich(std::move(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MediaTodoList::allowsEdit() const {
|
||||||
|
return parent()->out();
|
||||||
|
}
|
||||||
|
|
||||||
bool MediaTodoList::updateInlineResultMedia(const MTPMessageMedia &media) {
|
bool MediaTodoList::updateInlineResultMedia(const MTPMessageMedia &media) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -625,6 +625,7 @@ public:
|
||||||
TextWithEntities notificationText() const override;
|
TextWithEntities notificationText() const override;
|
||||||
QString pinnedTextSubstring() const override;
|
QString pinnedTextSubstring() const override;
|
||||||
TextForMimeData clipboardText() const override;
|
TextForMimeData clipboardText() const override;
|
||||||
|
bool allowsEdit() const override;
|
||||||
|
|
||||||
bool updateInlineResultMedia(const MTPMessageMedia &media) override;
|
bool updateInlineResultMedia(const MTPMessageMedia &media) override;
|
||||||
bool updateSentMedia(const MTPMessageMedia &media) override;
|
bool updateSentMedia(const MTPMessageMedia &media) override;
|
||||||
|
|
|
@ -685,7 +685,8 @@ bool PeerData::canCreatePolls() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PeerData::canCreateTodoLists() 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 {
|
bool PeerData::canCreateTopics() const {
|
||||||
|
|
|
@ -8559,6 +8559,11 @@ void HistoryWidget::editMessage(
|
||||||
} else if (_voiceRecordBar->isActive()) {
|
} else if (_voiceRecordBar->isActive()) {
|
||||||
controller()->showToast(tr::lng_edit_caption_voice(tr::now));
|
controller()->showToast(tr::lng_edit_caption_voice(tr::now));
|
||||||
return;
|
return;
|
||||||
|
} else if (const auto media = item->media()) {
|
||||||
|
if (const auto todolist = media->todolist()) {
|
||||||
|
Window::PeerMenuEditTodoList(controller(), item);
|
||||||
|
return;
|
||||||
|
}
|
||||||
} else if (_composeSearch) {
|
} else if (_composeSearch) {
|
||||||
_composeSearch->hideAnimated();
|
_composeSearch->hideAnimated();
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,6 +84,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/effects/spoiler_mess.h"
|
#include "ui/effects/spoiler_mess.h"
|
||||||
#include "webrtc/webrtc_environment.h"
|
#include "webrtc/webrtc_environment.h"
|
||||||
#include "window/window_adaptive.h"
|
#include "window/window_adaptive.h"
|
||||||
|
#include "window/window_peer_menu.h"
|
||||||
#include "window/window_session_controller.h"
|
#include "window/window_session_controller.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "styles/style_chat.h"
|
#include "styles/style_chat.h"
|
||||||
|
@ -2952,6 +2953,12 @@ void ComposeControls::editMessage(not_null<HistoryItem*> item) {
|
||||||
if (_voiceRecordBar->isActive()) {
|
if (_voiceRecordBar->isActive()) {
|
||||||
_show->showBox(Ui::MakeInformBox(tr::lng_edit_caption_voice()));
|
_show->showBox(Ui::MakeInformBox(tr::lng_edit_caption_voice()));
|
||||||
return;
|
return;
|
||||||
|
} else if (const auto media = item->media()) {
|
||||||
|
if (const auto todolist = media->todolist()) {
|
||||||
|
Assert(_regularWindow != nullptr);
|
||||||
|
Window::PeerMenuEditTodoList(_regularWindow, item);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isEditingMessage()) {
|
if (!isEditingMessage()) {
|
||||||
|
|
|
@ -352,6 +352,8 @@ ChatWidget::ChatWidget(
|
||||||
_composeControls->editMessage(
|
_composeControls->editMessage(
|
||||||
fullId,
|
fullId,
|
||||||
_inner->getSelectedTextRange(item));
|
_inner->getSelectedTextRange(item));
|
||||||
|
} else if (media->todolist()) {
|
||||||
|
Window::PeerMenuEditTodoList(controller, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, _inner->lifetime());
|
}, _inner->lifetime());
|
||||||
|
|
|
@ -231,6 +231,8 @@ ScheduledWidget::ScheduledWidget(
|
||||||
_composeControls->editMessage(
|
_composeControls->editMessage(
|
||||||
fullId,
|
fullId,
|
||||||
_inner->getSelectedTextRange(item));
|
_inner->getSelectedTextRange(item));
|
||||||
|
} else if (media->todolist()) {
|
||||||
|
Window::PeerMenuEditTodoList(controller, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, _inner->lifetime());
|
}, _inner->lifetime());
|
||||||
|
|
|
@ -58,6 +58,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
#include "window/themes/window_theme.h"
|
#include "window/themes/window_theme.h"
|
||||||
#include "window/section_widget.h"
|
#include "window/section_widget.h"
|
||||||
|
#include "window/window_peer_menu.h"
|
||||||
#include "window/window_session_controller.h"
|
#include "window/window_session_controller.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
#include "styles/style_chat_helpers.h"
|
#include "styles/style_chat_helpers.h"
|
||||||
|
@ -399,6 +400,8 @@ ShortcutMessages::ShortcutMessages(
|
||||||
_composeControls->editMessage(
|
_composeControls->editMessage(
|
||||||
fullId,
|
fullId,
|
||||||
_inner->getSelectedTextRange(item));
|
_inner->getSelectedTextRange(item));
|
||||||
|
} else if (media->todolist()) {
|
||||||
|
Window::PeerMenuEditTodoList(_controller, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, _inner->lifetime());
|
}, _inner->lifetime());
|
||||||
|
|
|
@ -29,7 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "boxes/moderate_messages_box.h"
|
#include "boxes/moderate_messages_box.h"
|
||||||
#include "boxes/choose_filter_box.h"
|
#include "boxes/choose_filter_box.h"
|
||||||
#include "boxes/create_poll_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/pin_messages_box.h"
|
||||||
#include "boxes/premium_limits_box.h"
|
#include "boxes/premium_limits_box.h"
|
||||||
#include "boxes/report_messages_box.h"
|
#include "boxes/report_messages_box.h"
|
||||||
|
@ -1244,7 +1244,8 @@ void Filler::addCreateTodoList() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto can = _topic
|
const auto can = _topic
|
||||||
? Data::CanSend(_topic, ChatRestriction::SendPolls)
|
? (_peer->session().premium()
|
||||||
|
&& Data::CanSend(_topic, ChatRestriction::SendPolls))
|
||||||
: _peer->canCreateTodoLists();
|
: _peer->canCreateTodoLists();
|
||||||
if (!can) {
|
if (!can) {
|
||||||
return;
|
return;
|
||||||
|
@ -1973,19 +1974,19 @@ void PeerMenuCreateTodoList(
|
||||||
) | rpl::map([=] {
|
) | rpl::map([=] {
|
||||||
return peer->starsPerMessageChecked();
|
return peer->starsPerMessageChecked();
|
||||||
});
|
});
|
||||||
auto box = Box<CreateTodoListBox>(
|
auto box = Box<EditTodoListBox>(
|
||||||
controller,
|
controller,
|
||||||
std::move(starsRequired),
|
std::move(starsRequired),
|
||||||
sendType,
|
sendType,
|
||||||
sendMenuDetails);
|
sendMenuDetails);
|
||||||
struct State {
|
struct State {
|
||||||
Fn<void(const CreateTodoListBox::Result &)> create;
|
Fn<void(const EditTodoListBox::Result &)> create;
|
||||||
SendPaymentHelper sendPayment;
|
SendPaymentHelper sendPayment;
|
||||||
bool lock = false;
|
bool lock = false;
|
||||||
};
|
};
|
||||||
const auto weak = QPointer<CreateTodoListBox>(box);
|
const auto weak = QPointer<EditTodoListBox>(box);
|
||||||
const auto state = box->lifetime().make_state<State>();
|
const auto state = box->lifetime().make_state<State>();
|
||||||
state->create = [=](const CreateTodoListBox::Result &result) {
|
state->create = [=](const EditTodoListBox::Result &result) {
|
||||||
const auto withPaymentApproved = crl::guard(weak, [=](int stars) {
|
const auto withPaymentApproved = crl::guard(weak, [=](int stars) {
|
||||||
if (const auto onstack = state->create) {
|
if (const auto onstack = state->create) {
|
||||||
auto copy = result;
|
auto copy = result;
|
||||||
|
@ -2028,6 +2029,34 @@ void PeerMenuCreateTodoList(
|
||||||
controller->show(std::move(box), Ui::LayerOption::CloseOther);
|
controller->show(std::move(box), Ui::LayerOption::CloseOther);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PeerMenuEditTodoList(
|
||||||
|
not_null<Window::SessionController*> controller,
|
||||||
|
not_null<HistoryItem*> 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<EditTodoListBox>(controller, item);
|
||||||
|
const auto weak = QPointer<EditTodoListBox>(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<HistoryItem*> item) {
|
bool PeerMenuShowAddTodoListTasks(not_null<HistoryItem*> item) {
|
||||||
const auto media = item ? item->media() : nullptr;
|
const auto media = item ? item->media() : nullptr;
|
||||||
const auto todolist = media ? media->todolist() : nullptr;
|
const auto todolist = media ? media->todolist() : nullptr;
|
||||||
|
|
|
@ -123,6 +123,9 @@ void PeerMenuCreateTodoList(
|
||||||
FullReplyTo replyTo = FullReplyTo(),
|
FullReplyTo replyTo = FullReplyTo(),
|
||||||
Api::SendType sendType = Api::SendType::Normal,
|
Api::SendType sendType = Api::SendType::Normal,
|
||||||
SendMenu::Details sendMenuDetails = SendMenu::Details());
|
SendMenu::Details sendMenuDetails = SendMenu::Details());
|
||||||
|
void PeerMenuEditTodoList(
|
||||||
|
not_null<Window::SessionController*> controller,
|
||||||
|
not_null<HistoryItem*> item);
|
||||||
[[nodiscard]] bool PeerMenuShowAddTodoListTasks(not_null<HistoryItem*> item);
|
[[nodiscard]] bool PeerMenuShowAddTodoListTasks(not_null<HistoryItem*> item);
|
||||||
void PeerMenuAddTodoListTasks(
|
void PeerMenuAddTodoListTasks(
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
|
|
Loading…
Add table
Reference in a new issue