mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-07-26 15:33:02 +02:00
Improve adding tasks to todo lists.
This commit is contained in:
parent
248fe1b53f
commit
d83a80ec53
5 changed files with 93 additions and 37 deletions
|
@ -72,7 +72,7 @@ public:
|
||||||
[[nodiscard]] std::vector<TodoListItem> toTodoListItems() const;
|
[[nodiscard]] std::vector<TodoListItem> toTodoListItems() const;
|
||||||
void focusFirst();
|
void focusFirst();
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<int> usedCount() const;
|
[[nodiscard]] rpl::producer<int> addedCount() const;
|
||||||
[[nodiscard]] rpl::producer<not_null<QWidget*>> scrollToWidget() const;
|
[[nodiscard]] rpl::producer<not_null<QWidget*>> scrollToWidget() const;
|
||||||
[[nodiscard]] rpl::producer<> backspaceInFront() const;
|
[[nodiscard]] rpl::producer<> backspaceInFront() const;
|
||||||
[[nodiscard]] rpl::producer<> tabbed() const;
|
[[nodiscard]] rpl::producer<> tabbed() const;
|
||||||
|
@ -162,7 +162,7 @@ private:
|
||||||
int _tasksLimit = 0;
|
int _tasksLimit = 0;
|
||||||
std::vector<std::unique_ptr<Task>> _list;
|
std::vector<std::unique_ptr<Task>> _list;
|
||||||
std::vector<std::unique_ptr<Task>> _destroyed;
|
std::vector<std::unique_ptr<Task>> _destroyed;
|
||||||
rpl::variable<int> _usedCount = 0;
|
rpl::variable<int> _addedCount = 0;
|
||||||
bool _hasTasks = false;
|
bool _hasTasks = false;
|
||||||
bool _isValid = false;
|
bool _isValid = false;
|
||||||
rpl::event_stream<not_null<QWidget*>> _scrollToWidget;
|
rpl::event_stream<not_null<QWidget*>> _scrollToWidget;
|
||||||
|
@ -224,6 +224,26 @@ void FocusAtEnd(not_null<Ui::InputField*> field) {
|
||||||
field->ensureCursorVisible();
|
field->ensureCursorVisible();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] base::unique_qptr<ChatHelpers::TabbedPanel> MakeEmojiPanel(
|
||||||
|
not_null<QWidget*> outer,
|
||||||
|
not_null<Window::SessionController*> controller) {
|
||||||
|
auto result = base::make_unique_q<ChatHelpers::TabbedPanel>(
|
||||||
|
outer,
|
||||||
|
controller,
|
||||||
|
object_ptr<ChatHelpers::TabbedSelector>(
|
||||||
|
nullptr,
|
||||||
|
controller->uiShow(),
|
||||||
|
Window::GifPauseReason::Layer,
|
||||||
|
ChatHelpers::TabbedSelector::Mode::EmojiOnly));
|
||||||
|
result->setDesiredHeightValues(
|
||||||
|
1.,
|
||||||
|
st::emojiPanMinHeight / 2,
|
||||||
|
st::emojiPanMinHeight);
|
||||||
|
result ->hide();
|
||||||
|
result->selector()->setCurrentPeer(controller->session().user());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
Tasks::Task::Task(
|
Tasks::Task::Task(
|
||||||
not_null<QWidget*> outer,
|
not_null<QWidget*> outer,
|
||||||
not_null<Ui::VerticalLayout*> container,
|
not_null<Ui::VerticalLayout*> container,
|
||||||
|
@ -482,8 +502,8 @@ bool Tasks::isValid() const {
|
||||||
return _isValid;
|
return _isValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
rpl::producer<int> Tasks::usedCount() const {
|
rpl::producer<int> Tasks::addedCount() const {
|
||||||
return _usedCount.value();
|
return _addedCount.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
rpl::producer<not_null<QWidget*>> Tasks::scrollToWidget() const {
|
rpl::producer<not_null<QWidget*>> Tasks::scrollToWidget() const {
|
||||||
|
@ -747,7 +767,7 @@ void Tasks::validateState() {
|
||||||
_isValid = _hasTasks && ranges::none_of(_list, &Task::isTooLong);
|
_isValid = _hasTasks && ranges::none_of(_list, &Task::isTooLong);
|
||||||
|
|
||||||
const auto lastEmpty = !_list.empty() && _list.back()->isEmpty();
|
const auto lastEmpty = !_list.empty() && _list.back()->isEmpty();
|
||||||
_usedCount = _list.size()
|
_addedCount = _list.size()
|
||||||
- (lastEmpty ? 1 : 0)
|
- (lastEmpty ? 1 : 0)
|
||||||
- (_existingLocked ? _existingCount : 0);
|
- (_existingLocked ? _existingCount : 0);
|
||||||
}
|
}
|
||||||
|
@ -817,37 +837,22 @@ not_null<Ui::InputField*> CreateTodoListBox::setupTitle(
|
||||||
title->customTab(true);
|
title->customTab(true);
|
||||||
|
|
||||||
if (isPremium) {
|
if (isPremium) {
|
||||||
using Selector = ChatHelpers::TabbedSelector;
|
_emojiPanel = MakeEmojiPanel(
|
||||||
const auto outer = getDelegate()->outerContainer();
|
getDelegate()->outerContainer(),
|
||||||
_emojiPanel = base::make_unique_q<ChatHelpers::TabbedPanel>(
|
_controller);
|
||||||
outer,
|
|
||||||
_controller,
|
|
||||||
object_ptr<Selector>(
|
|
||||||
nullptr,
|
|
||||||
_controller->uiShow(),
|
|
||||||
Window::GifPauseReason::Layer,
|
|
||||||
Selector::Mode::EmojiOnly));
|
|
||||||
const auto emojiPanel = _emojiPanel.get();
|
|
||||||
emojiPanel->setDesiredHeightValues(
|
|
||||||
1.,
|
|
||||||
st::emojiPanMinHeight / 2,
|
|
||||||
st::emojiPanMinHeight);
|
|
||||||
emojiPanel->hide();
|
|
||||||
emojiPanel->selector()->setCurrentPeer(session->user());
|
|
||||||
|
|
||||||
const auto emojiToggle = Ui::AddEmojiToggleToField(
|
const auto emojiToggle = Ui::AddEmojiToggleToField(
|
||||||
title,
|
title,
|
||||||
this,
|
this,
|
||||||
_controller,
|
_controller,
|
||||||
emojiPanel,
|
_emojiPanel.get(),
|
||||||
st::createPollOptionFieldPremiumEmojiPosition);
|
st::createPollOptionFieldPremiumEmojiPosition);
|
||||||
emojiPanel->selector()->emojiChosen(
|
_emojiPanel->selector()->emojiChosen(
|
||||||
) | rpl::start_with_next([=](ChatHelpers::EmojiChosen data) {
|
) | rpl::start_with_next([=](ChatHelpers::EmojiChosen data) {
|
||||||
if (title->hasFocus()) {
|
if (title->hasFocus()) {
|
||||||
Ui::InsertEmojiAtCursor(title->textCursor(), data.emoji);
|
Ui::InsertEmojiAtCursor(title->textCursor(), data.emoji);
|
||||||
}
|
}
|
||||||
}, emojiToggle->lifetime());
|
}, emojiToggle->lifetime());
|
||||||
emojiPanel->selector()->customEmojiChosen(
|
_emojiPanel->selector()->customEmojiChosen(
|
||||||
) | rpl::start_with_next([=](ChatHelpers::FileChosen data) {
|
) | rpl::start_with_next([=](ChatHelpers::FileChosen data) {
|
||||||
if (title->hasFocus()) {
|
if (title->hasFocus()) {
|
||||||
Data::InsertCustomEmoji(title, data.document);
|
Data::InsertCustomEmoji(title, data.document);
|
||||||
|
@ -906,7 +911,7 @@ object_ptr<Ui::RpWidget> CreateTodoListBox::setupContent() {
|
||||||
container,
|
container,
|
||||||
_controller,
|
_controller,
|
||||||
_emojiPanel ? _emojiPanel.get() : nullptr);
|
_emojiPanel ? _emojiPanel.get() : nullptr);
|
||||||
auto limit = tasks->usedCount() | rpl::after_next([=](int count) {
|
auto limit = tasks->addedCount() | rpl::after_next([=](int count) {
|
||||||
setCloseByEscape(!count);
|
setCloseByEscape(!count);
|
||||||
setCloseByOutsideClick(!count);
|
setCloseByOutsideClick(!count);
|
||||||
}) | rpl::map([=](int count) {
|
}) | rpl::map([=](int count) {
|
||||||
|
@ -1094,21 +1099,32 @@ object_ptr<Ui::RpWidget> AddTodoListTasksBox::setupContent() {
|
||||||
auto result = object_ptr<Ui::VerticalLayout>(this);
|
auto result = object_ptr<Ui::VerticalLayout>(this);
|
||||||
const auto container = result.data();
|
const auto container = result.data();
|
||||||
|
|
||||||
|
if (_controller->session().premium()) {
|
||||||
|
_emojiPanel = MakeEmojiPanel(
|
||||||
|
getDelegate()->outerContainer(),
|
||||||
|
_controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto media = _item->media();
|
||||||
|
const auto todolist = media ? media->todolist() : nullptr;
|
||||||
|
Assert(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,
|
||||||
_item->media()->todolist()->items,
|
todolist->items,
|
||||||
true);
|
true);
|
||||||
auto limit = tasks->usedCount() | rpl::after_next([=](int count) {
|
const auto already = int(todolist->items.size());
|
||||||
|
auto limit = tasks->addedCount() | rpl::after_next([=](int count) {
|
||||||
setCloseByEscape(!count);
|
setCloseByEscape(!count);
|
||||||
setCloseByOutsideClick(!count);
|
setCloseByOutsideClick(!count);
|
||||||
}) | rpl::map([=](int count) {
|
}) | rpl::map([=](int count) {
|
||||||
const auto appConfig = &_controller->session().appConfig();
|
const auto appConfig = &_controller->session().appConfig();
|
||||||
const auto max = appConfig->todoListItemsLimit();
|
const auto max = appConfig->todoListItemsLimit();
|
||||||
return (count < max)
|
const auto total = already + count;
|
||||||
? tr::lng_todo_create_limit(tr::now, lt_count, max - count)
|
return (total < max)
|
||||||
|
? tr::lng_todo_create_limit(tr::now, lt_count, max - total)
|
||||||
: tr::lng_todo_create_maximum(tr::now);
|
: tr::lng_todo_create_maximum(tr::now);
|
||||||
}) | rpl::after_next([=] {
|
}) | rpl::after_next([=] {
|
||||||
container->resizeToWidth(container->widthNoMargins());
|
container->resizeToWidth(container->widthNoMargins());
|
||||||
|
|
|
@ -2721,11 +2721,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto addTodoListAction = [&](HistoryItem *item) {
|
const auto addTodoListAction = [&](HistoryItem *item) {
|
||||||
const auto media = item ? item->media() : nullptr;
|
if (!item || !Window::PeerMenuShowAddTodoListTasks(item)) {
|
||||||
const auto todolist = media ? media->todolist() : nullptr;
|
|
||||||
if (!todolist
|
|
||||||
|| !item->isRegular()
|
|
||||||
|| (!item->out() && !todolist->othersCanAppend())) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto itemId = item->fullId();
|
const auto itemId = item->fullId();
|
||||||
|
|
|
@ -626,7 +626,9 @@ bool AddReplyToMessageAction(
|
||||||
const auto peer = item ? item->history()->peer.get() : nullptr;
|
const auto peer = item ? item->history()->peer.get() : nullptr;
|
||||||
if (!item
|
if (!item
|
||||||
|| !item->isRegular()
|
|| !item->isRegular()
|
||||||
|| (context != Context::History && context != Context::Replies)) {
|
|| (context != Context::History
|
||||||
|
&& context != Context::Replies
|
||||||
|
&& context != Context::Monoforum)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const auto canSendReply = topic
|
const auto canSendReply = topic
|
||||||
|
@ -653,6 +655,30 @@ bool AddReplyToMessageAction(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AddTodoListAction(
|
||||||
|
not_null<Ui::PopupMenu*> menu,
|
||||||
|
const ContextMenuRequest &request,
|
||||||
|
not_null<ListWidget*> list) {
|
||||||
|
const auto context = list->elementContext();
|
||||||
|
const auto item = request.item;
|
||||||
|
if (!item
|
||||||
|
|| !Window::PeerMenuShowAddTodoListTasks(item)
|
||||||
|
|| (context != Context::History
|
||||||
|
&& context != Context::Replies
|
||||||
|
&& context != Context::Monoforum
|
||||||
|
&& context != Context::Pinned)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto itemId = item->fullId();
|
||||||
|
const auto controller = list->controller();
|
||||||
|
menu->addAction(tr::lng_todo_add_title(tr::now), [=] {
|
||||||
|
if (const auto item = controller->session().data().message(itemId)) {
|
||||||
|
Window::PeerMenuAddTodoListTasks(controller, item);
|
||||||
|
}
|
||||||
|
}, &st::menuIconCreateTodoList);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool AddViewRepliesAction(
|
bool AddViewRepliesAction(
|
||||||
not_null<Ui::PopupMenu*> menu,
|
not_null<Ui::PopupMenu*> menu,
|
||||||
const ContextMenuRequest &request,
|
const ContextMenuRequest &request,
|
||||||
|
@ -1281,6 +1307,7 @@ base::unique_qptr<Ui::PopupMenu> FillContextMenu(
|
||||||
st::popupMenuWithIcons);
|
st::popupMenuWithIcons);
|
||||||
|
|
||||||
AddReplyToMessageAction(result, request, list);
|
AddReplyToMessageAction(result, request, list);
|
||||||
|
AddTodoListAction(result, request, list);
|
||||||
|
|
||||||
if (request.overSelection
|
if (request.overSelection
|
||||||
&& !list->hasCopyRestrictionForSelected()
|
&& !list->hasCopyRestrictionForSelected()
|
||||||
|
|
|
@ -51,6 +51,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/delayed_activation.h"
|
#include "ui/delayed_activation.h"
|
||||||
#include "ui/vertical_list.h"
|
#include "ui/vertical_list.h"
|
||||||
#include "ui/ui_utility.h"
|
#include "ui/ui_utility.h"
|
||||||
|
#include "main/main_app_config.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "main/main_session_settings.h"
|
#include "main/main_session_settings.h"
|
||||||
#include "menu/menu_mute.h"
|
#include "menu/menu_mute.h"
|
||||||
|
@ -2027,6 +2028,16 @@ void PeerMenuCreateTodoList(
|
||||||
controller->show(std::move(box), Ui::LayerOption::CloseOther);
|
controller->show(std::move(box), Ui::LayerOption::CloseOther);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PeerMenuShowAddTodoListTasks(not_null<HistoryItem*> item) {
|
||||||
|
const auto media = item ? item->media() : nullptr;
|
||||||
|
const auto todolist = media ? media->todolist() : nullptr;
|
||||||
|
const auto appConfig = &item->history()->session().appConfig();
|
||||||
|
return item->isRegular()
|
||||||
|
&& todolist
|
||||||
|
&& (todolist->items.size() < appConfig->todoListItemsLimit())
|
||||||
|
&& (item->out() || todolist->othersCanAppend());
|
||||||
|
}
|
||||||
|
|
||||||
void PeerMenuAddTodoListTasks(
|
void PeerMenuAddTodoListTasks(
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
not_null<HistoryItem*> item) {
|
not_null<HistoryItem*> item) {
|
||||||
|
@ -2035,6 +2046,11 @@ void PeerMenuAddTodoListTasks(
|
||||||
PeerMenuTodoWantsPremium(TodoWantsPremium::Add);
|
PeerMenuTodoWantsPremium(TodoWantsPremium::Add);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const auto media = item->media();
|
||||||
|
const auto todolist = media ? media->todolist() : nullptr;
|
||||||
|
if (!todolist) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto box = Box<AddTodoListTasksBox>(controller, item);
|
auto box = Box<AddTodoListTasksBox>(controller, item);
|
||||||
const auto raw = box.data();
|
const auto raw = box.data();
|
||||||
box->submitRequests(
|
box->submitRequests(
|
||||||
|
|
|
@ -123,6 +123,7 @@ 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());
|
||||||
|
[[nodiscard]] bool PeerMenuShowAddTodoListTasks(not_null<HistoryItem*> item);
|
||||||
void PeerMenuAddTodoListTasks(
|
void PeerMenuAddTodoListTasks(
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
not_null<HistoryItem*> item);
|
not_null<HistoryItem*> item);
|
||||||
|
|
Loading…
Add table
Reference in a new issue