Show completed-by names in tasks.

This commit is contained in:
John Preston 2025-07-01 12:10:08 +04:00
parent 7284926db4
commit 7006a07dd3
2 changed files with 60 additions and 29 deletions

View file

@ -62,8 +62,10 @@ struct TodoList::Task {
not_null<TodoListData*> todolist, not_null<TodoListData*> todolist,
const TodoListItem &original, const TodoListItem &original,
Ui::Text::MarkedContext context); Ui::Text::MarkedContext context);
void setCompletedBy(PeerData *by);
Ui::Text::String text; Ui::Text::String text;
Ui::Text::String name;
PeerData *completedBy = nullptr; PeerData *completedBy = nullptr;
mutable Ui::PeerUserpicView userpic; mutable Ui::PeerUserpicView userpic;
TimeId completionDate = 0; TimeId completionDate = 0;
@ -73,7 +75,9 @@ struct TodoList::Task {
mutable std::unique_ptr<Ui::RippleAnimation> ripple; mutable std::unique_ptr<Ui::RippleAnimation> ripple;
}; };
TodoList::Task::Task() : text(st::msgMinWidth / 2) { TodoList::Task::Task()
: text(st::msgMinWidth / 2)
, name(st::msgMinWidth / 2) {
} }
void TodoList::Task::fillData( void TodoList::Task::fillData(
@ -81,9 +85,7 @@ void TodoList::Task::fillData(
const TodoListItem &original, const TodoListItem &original,
Ui::Text::MarkedContext context) { Ui::Text::MarkedContext context) {
id = original.id; id = original.id;
if (original.completedBy) { setCompletedBy(original.completedBy);
completedBy = original.completedBy;
}
completionDate = original.completionDate; completionDate = original.completionDate;
if (!text.isEmpty() && text.toTextWithEntities() == original.text) { if (!text.isEmpty() && text.toTextWithEntities() == original.text) {
return; return;
@ -95,6 +97,14 @@ void TodoList::Task::fillData(
context); context);
} }
void TodoList::Task::setCompletedBy(PeerData *by) {
if (!by || completedBy == by) {
return;
}
completedBy = by;
name.setText(st::historyPollAnswerStyle, completedBy->name());
}
TodoList::TodoList( TodoList::TodoList(
not_null<Element*> parent, not_null<Element*> parent,
not_null<TodoListData*> todolist, not_null<TodoListData*> todolist,
@ -118,7 +128,7 @@ void TodoList::setupPreviousState(const std::vector<TodoTaskInfo> &info) {
for (auto &task : _tasks) { for (auto &task : _tasks) {
const auto i = ranges::find(info, task.id, &TodoTaskInfo::id); const auto i = ranges::find(info, task.id, &TodoTaskInfo::id);
if (i != end(info)) { if (i != end(info)) {
task.completedBy = i->completedBy; task.setCompletedBy(i->completedBy);
task.completionDate = i->completionDate; task.completionDate = i->completionDate;
} }
} }
@ -135,17 +145,17 @@ QSize TodoList::countOptimalSize() {
accumulate_max( accumulate_max(
maxWidth, maxWidth,
paddings paddings
+ st::historyPollAnswerPadding.left() + st::historyChecklistTaskPadding.left()
+ task.text.maxWidth() + task.text.maxWidth()
+ st::historyPollAnswerPadding.right()); + st::historyChecklistTaskPadding.right());
} }
const auto tasksHeight = ranges::accumulate(ranges::views::all( const auto tasksHeight = ranges::accumulate(ranges::views::all(
_tasks _tasks
) | ranges::views::transform([](const Task &task) { ) | ranges::views::transform([](const Task &task) {
return st::historyPollAnswerPadding.top() return st::historyChecklistTaskPadding.top()
+ task.text.minHeight() + task.text.minHeight()
+ st::historyPollAnswerPadding.bottom(); + st::historyChecklistTaskPadding.bottom();
}), 0); }), 0);
const auto bottomButtonHeight = st::historyPollBottomButtonSkip; const auto bottomButtonHeight = st::historyPollBottomButtonSkip;
@ -167,7 +177,8 @@ QSize TodoList::countOptimalSize() {
bool TodoList::canComplete() const { bool TodoList::canComplete() const {
return (_parent->data()->out() || _todolist->othersCanComplete()) return (_parent->data()->out() || _todolist->othersCanComplete())
&& _parent->data()->isRegular(); && _parent->data()->isRegular()
&& !_parent->data()->Has<HistoryMessageForwarded>();
} }
int TodoList::countTaskTop( int TodoList::countTaskTop(
@ -199,11 +210,11 @@ int TodoList::countTaskHeight(
const Task &task, const Task &task,
int innerWidth) const { int innerWidth) const {
const auto answerWidth = innerWidth const auto answerWidth = innerWidth
- st::historyPollAnswerPadding.left() - st::historyChecklistTaskPadding.left()
- st::historyPollAnswerPadding.right(); - st::historyChecklistTaskPadding.right();
return st::historyPollAnswerPadding.top() return st::historyChecklistTaskPadding.top()
+ task.text.countHeight(answerWidth) + task.text.countHeight(answerWidth)
+ st::historyPollAnswerPadding.bottom(); + st::historyChecklistTaskPadding.bottom();
} }
QSize TodoList::countCurrentSize(int newWidth) { QSize TodoList::countCurrentSize(int newWidth) {
@ -289,6 +300,7 @@ void TodoList::updateTasks(bool skipAnimations) {
animated = true; animated = true;
} }
} }
updateCompletionStatus();
if (animated) { if (animated) {
maybeStartFireworks(); maybeStartFireworks();
} }
@ -306,6 +318,8 @@ void TodoList::updateTasks(bool skipAnimations) {
for (auto &task : _tasks) { for (auto &task : _tasks) {
task.handler = createTaskClickHandler(task); task.handler = createTaskClickHandler(task);
} }
updateCompletionStatus();
} }
ClickHandlerPtr TodoList::createTaskClickHandler( ClickHandlerPtr TodoList::createTaskClickHandler(
@ -348,7 +362,7 @@ void TodoList::toggleCompletion(int id) {
const auto selected = (i->completionDate != 0); const auto selected = (i->completionDate != 0);
i->completionDate = selected ? TimeId() : base::unixtime::now(); i->completionDate = selected ? TimeId() : base::unixtime::now();
if (!selected) { if (!selected) {
i->completedBy = _parent->history()->session().user(); i->setCompletedBy(_parent->history()->session().user());
} }
startToggleAnimation(*i); startToggleAnimation(*i);
repaint(); repaint();
@ -472,10 +486,10 @@ int TodoList::paintTask(
const PaintContext &context) const { const PaintContext &context) const {
const auto height = countTaskHeight(task, width); const auto height = countTaskHeight(task, width);
const auto stm = context.messageStyle(); const auto stm = context.messageStyle();
const auto aleft = left + st::historyPollAnswerPadding.left(); const auto aleft = left + st::historyChecklistTaskPadding.left();
const auto awidth = width const auto awidth = width
- st::historyPollAnswerPadding.left() - st::historyChecklistTaskPadding.left()
- st::historyPollAnswerPadding.right(); - st::historyChecklistTaskPadding.right();
if (task.ripple) { if (task.ripple) {
p.setOpacity(st::historyPollRippleOpacity); p.setOpacity(st::historyPollRippleOpacity);
@ -497,10 +511,20 @@ int TodoList::paintTask(
paintStatus(p, task, left, top, context); paintStatus(p, task, left, top, context);
} }
top += st::historyPollAnswerPadding.top(); top += task.completionDate
? st::historyChecklistCheckedTop
: st::historyChecklistTaskPadding.top();
p.setPen(stm->historyTextFg); p.setPen(stm->historyTextFg);
task.text.drawLeft(p, aleft, top, awidth, outerWidth); task.text.drawLeft(p, aleft, top, awidth, outerWidth);
if (task.completionDate) {
const auto nameTop = top
+ height
- st::historyChecklistTaskPadding.bottom()
+ st::historyChecklistCheckedTop
- st::normalFont->height;
p.setPen(stm->msgDateFg);
task.name.drawLeft(p, aleft, nameTop, awidth, outerWidth);
}
return height; return height;
} }
@ -510,7 +534,7 @@ void TodoList::paintRadio(
int left, int left,
int top, int top,
const PaintContext &context) const { const PaintContext &context) const {
top += st::historyPollAnswerPadding.top(); top += st::historyChecklistTaskPadding.top();
const auto stm = context.messageStyle(); const auto stm = context.messageStyle();
@ -608,7 +632,7 @@ void TodoList::paintStatus(
int left, int left,
int top, int top,
const PaintContext &context) const { const PaintContext &context) const {
top += st::historyPollAnswerPadding.top(); top += st::historyChecklistTaskPadding.top();
const auto stm = context.messageStyle(); const auto stm = context.messageStyle();
@ -668,25 +692,29 @@ TextState TodoList::textState(QPoint point, StateRequest request) const {
return result; return result;
} }
const auto aleft = padding.left() const auto aleft = padding.left()
+ st::historyPollAnswerPadding.left(); + st::historyChecklistTaskPadding.left();
const auto awidth = paintw const auto awidth = paintw
- st::historyPollAnswerPadding.left() - st::historyChecklistTaskPadding.left()
- st::historyPollAnswerPadding.right(); - st::historyChecklistTaskPadding.right();
tshift += questionH + st::historyPollSubtitleSkip; tshift += questionH + st::historyPollSubtitleSkip;
tshift += st::msgDateFont->height + st::historyPollAnswersSkip; tshift += st::msgDateFont->height + st::historyPollAnswersSkip;
for (const auto &task : _tasks) { for (const auto &task : _tasks) {
const auto height = countTaskHeight(task, paintw); const auto height = countTaskHeight(task, paintw);
if (point.y() >= tshift && point.y() < tshift + height) { if (point.y() >= tshift && point.y() < tshift + height) {
const auto atop = tshift + st::historyPollAnswerPadding.top(); const auto atop = tshift
+ (task.completionDate
? st::historyChecklistCheckedTop
: st::historyChecklistTaskPadding.top());
auto taskTextResult = task.text.getState( auto taskTextResult = task.text.getState(
point - QPoint(aleft, atop), point - QPoint(aleft, atop),
awidth, awidth,
request.forText()); request.forText());
if (taskTextResult.link) { if (taskTextResult.link) {
return TextState(_parent, taskTextResult); result.link = taskTextResult.link;
} else {
_lastLinkPoint = point;
result.link = task.handler;
} }
_lastLinkPoint = point;
result.link = task.handler;
if (task.completionDate) { if (task.completionDate) {
result.customTooltip = true; result.customTooltip = true;
using Flag = Ui::Text::StateRequest::Flag; using Flag = Ui::Text::StateRequest::Flag;

View file

@ -657,6 +657,9 @@ historyPollOutChosenSelected: icon {{ "poll_select_check", historyFileOutIconFgS
historyPollInChosen: icon {{ "poll_select_check", historyFileInIconFg }}; historyPollInChosen: icon {{ "poll_select_check", historyFileInIconFg }};
historyPollInChosenSelected: icon {{ "poll_select_check", historyFileInIconFgSelected }}; historyPollInChosenSelected: icon {{ "poll_select_check", historyFileInIconFgSelected }};
historyChecklistTaskPadding: margins(32px, 12px, 0px, 12px);
historyChecklistCheckedTop: 4px;
historyViewButtonHeight: 48px; historyViewButtonHeight: 48px;
historyViewButtonMargins: margins(10px, 5px, 10px, 10px); historyViewButtonMargins: margins(10px, 5px, 10px, 10px);
historyViewButtonTextStyle: semiboldTextStyle; historyViewButtonTextStyle: semiboldTextStyle;