Try scrolling to the task on jump.

This commit is contained in:
John Preston 2025-07-07 17:20:47 +04:00
parent bff86b90fb
commit f2e53ea490
4 changed files with 98 additions and 10 deletions

View file

@ -1498,12 +1498,21 @@ int HistoryWidget::itemTopForHighlight(
const auto heightLeft = (visibleAreaHeight - viewHeight);
if (heightLeft >= 0) {
return std::max(itemTop - (heightLeft / 2), 0);
} else if (const auto sel = itemHighlight(item).range
; !sel.empty() && !IsSubGroupSelection(sel)) {
} else if (const auto highlight = itemHighlight(item)
; (!highlight.range.empty() || highlight.todoItemId)
&& !IsSubGroupSelection(highlight.range)) {
const auto sel = highlight.range;
const auto single = st::messageTextStyle.font->height;
const auto begin = HistoryView::FindViewY(view, sel.from) - single;
const auto end = HistoryView::FindViewY(view, sel.to, begin + single)
+ 2 * single;
const auto todoy = sel.empty()
? HistoryView::FindViewTaskY(view, highlight.todoItemId)
: 0;
const auto begin = sel.empty()
? (todoy - 4 * single)
: HistoryView::FindViewY(view, sel.from) - single;
const auto end = sel.empty()
? (todoy + 4 * single)
: (HistoryView::FindViewY(view, sel.to, begin + single)
+ 2 * single);
auto result = itemTop;
if (end > visibleAreaHeight) {
result = std::max(result, itemTop + end - visibleAreaHeight);

View file

@ -46,6 +46,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_channel.h"
#include "data/data_saved_sublist.h"
#include "data/data_session.h"
#include "data/data_todo_list.h"
#include "data/data_forum.h"
#include "data/data_forum_topic.h"
#include "data/data_message_reactions.h"
@ -2455,6 +2456,70 @@ int FindViewY(not_null<Element*> view, uint16 symbol, int yfrom) {
return origin.y() + (yfrom + ytill) / 2;
}
int FindViewTaskY(not_null<Element*> view, int taskId, int yfrom) {
auto request = HistoryView::StateRequest();
request.flags = Ui::Text::StateRequest::Flag::LookupLink;
const auto single = st::messageTextStyle.font->height;
const auto inner = view->innerGeometry();
const auto origin = inner.topLeft();
const auto top = 0;
const auto bottom = view->height();
if (origin.y() < top
|| origin.y() + inner.height() > bottom
|| inner.height() <= 0) {
return yfrom;
}
const auto media = view->data()->media();
const auto todolist = media ? media->todolist() : nullptr;
if (!todolist) {
return yfrom;
}
const auto &items = todolist->items;
const auto indexOf = [&](int id) -> int {
return ranges::find(items, id, &TodoListItem::id) - begin(items);
};
const auto index = indexOf(taskId);
const auto count = int(items.size());
if (index == count) {
return yfrom;
}
yfrom = std::max(yfrom - origin.y(), 0);
auto ytill = inner.height() - 1;
const auto middle = (yfrom + ytill) / 2;
const auto fory = [&](int y) {
const auto state = view->textState(origin + QPoint(0, y), request);
const auto &link = state.link;
const auto id = link
? link->property(kTodoListItemIdProperty).toInt()
: -1;
const auto index = (id >= 0) ? indexOf(id) : int(items.size());
return (index < count) ? index : (y < middle) ? -1 : count;
};
auto indexfrom = fory(yfrom);
auto indextill = fory(ytill);
if ((yfrom >= ytill) || (indexfrom >= index)) {
return origin.y() + yfrom;
} else if (indextill <= index) {
return origin.y() + ytill;
}
while (ytill - yfrom >= 2 * single) {
const auto middle = (yfrom + ytill) / 2;
const auto found = fory(middle);
if (found == index
|| indexfrom > found
|| indextill < found) {
return origin.y() + middle;
} else if (found < index) {
yfrom = middle;
indexfrom = found;
} else {
ytill = middle;
indextill = found;
}
}
return origin.y() + (yfrom + ytill) / 2;
}
Window::SessionController *ExtractController(const ClickContext &context) {
const auto my = context.other.value<ClickHandlerContext>();
if (const auto controller = my.sessionWindow.get()) {

View file

@ -747,6 +747,11 @@ private:
uint16 symbol,
int yfrom = 0);
[[nodiscard]] int FindViewTaskY(
not_null<Element*> view,
int taskId,
int yfrom = 0);
[[nodiscard]] Window::SessionController *ExtractController(
const ClickContext &context);

View file

@ -716,12 +716,21 @@ std::optional<int> ListWidget::scrollTopForView(
const auto heightLeft = (available - height);
if (heightLeft >= 0) {
return std::max(top - (heightLeft / 2), 0);
} else if (const auto sel = _highlighter.state(view->data()).range
; !sel.empty() && !IsSubGroupSelection(sel)) {
} else if (const auto highlight = _highlighter.state(view->data())
; (!highlight.range.empty() || highlight.todoItemId)
&& !IsSubGroupSelection(highlight.range)) {
const auto sel = highlight.range;
const auto single = st::messageTextStyle.font->height;
const auto begin = HistoryView::FindViewY(view, sel.from) - single;
const auto end = HistoryView::FindViewY(view, sel.to, begin + single)
+ 2 * single;
const auto todoy = sel.empty()
? HistoryView::FindViewTaskY(view, highlight.todoItemId)
: 0;
const auto begin = sel.empty()
? (todoy - 4 * single)
: HistoryView::FindViewY(view, sel.from) - single;
const auto end = sel.empty()
? (todoy + 4 * single)
: (HistoryView::FindViewY(view, sel.to, begin + single)
+ 2 * single);
auto result = top;
if (end > available) {
result = std::max(result, top + end - available);