mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-07-27 07:52:57 +02:00
Highlight tasks from reply/service messages.
This commit is contained in:
parent
b5c9b6f552
commit
bff86b90fb
25 changed files with 170 additions and 122 deletions
|
@ -172,6 +172,16 @@ inline QDebug operator<<(QDebug debug, const FullMsgId &fullMsgId) {
|
|||
|
||||
Q_DECLARE_METATYPE(FullMsgId);
|
||||
|
||||
struct MessageHighlightId {
|
||||
TextWithEntities quote;
|
||||
int quoteOffset = 0;
|
||||
int todoItemId = 0;
|
||||
|
||||
[[nodiscard]] bool empty() const {
|
||||
return quote.empty() && !todoItemId;
|
||||
}
|
||||
};
|
||||
|
||||
struct FullReplyTo {
|
||||
FullMsgId messageId;
|
||||
TextWithEntities quote;
|
||||
|
@ -181,6 +191,9 @@ struct FullReplyTo {
|
|||
int quoteOffset = 0;
|
||||
int todoItemId = 0;
|
||||
|
||||
[[nodiscard]] MessageHighlightId highlight() const {
|
||||
return { quote, quoteOffset, todoItemId };
|
||||
}
|
||||
[[nodiscard]] bool replying() const {
|
||||
return messageId || (storyId && storyId.peer);
|
||||
}
|
||||
|
|
|
@ -898,10 +898,7 @@ void Widget::chosenRow(const ChosenRow &row) {
|
|||
} else if (const auto topic = row.key.topic()) {
|
||||
auto params = Window::SectionShow(
|
||||
Window::SectionShow::Way::ClearStack);
|
||||
params.highlightPart.text = _searchState.query;
|
||||
if (!params.highlightPart.empty()) {
|
||||
params.highlightPartOffsetHint = kSearchQueryOffsetHint;
|
||||
}
|
||||
params.highlight = Window::SearchHighlightId(_searchState.query);
|
||||
if (row.newWindow) {
|
||||
controller()->showInNewWindow(
|
||||
Window::SeparateId(topic),
|
||||
|
@ -972,10 +969,7 @@ void Widget::chosenRow(const ChosenRow &row) {
|
|||
) ? ShowAtUnreadMsgId : row.message.fullId.msg;
|
||||
auto params = Window::SectionShow(
|
||||
Window::SectionShow::Way::ClearStack);
|
||||
params.highlightPart.text = _searchState.query;
|
||||
if (!params.highlightPart.empty()) {
|
||||
params.highlightPartOffsetHint = kSearchQueryOffsetHint;
|
||||
}
|
||||
params.highlight = Window::SearchHighlightId(_searchState.query);
|
||||
if (row.newWindow) {
|
||||
controller()->showInNewWindow(peer, showAtMsgId);
|
||||
} else {
|
||||
|
|
|
@ -622,10 +622,10 @@ void HistoryInner::setupSwipeReplyAndBack() {
|
|||
: still)->fullId();
|
||||
_widget->replyToMessage({
|
||||
.messageId = replyToItemId,
|
||||
.quote = selected.text,
|
||||
.quoteOffset = selected.offset,
|
||||
.quote = selected.highlight.quote,
|
||||
.quoteOffset = selected.highlight.quoteOffset,
|
||||
});
|
||||
if (!selected.text.empty()) {
|
||||
if (!selected.highlight.quote.empty()) {
|
||||
_widget->clearSelected();
|
||||
}
|
||||
};
|
||||
|
@ -2712,16 +2712,14 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
|||
Ui::Text::FixAmpersandInAction);
|
||||
const auto replyToItem = selected.item ? selected.item : item;
|
||||
const auto itemId = replyToItem->fullId();
|
||||
const auto quote = selected.text;
|
||||
const auto quoteOffset = selected.offset;
|
||||
_menu->addAction(std::move(text), [=] {
|
||||
_widget->replyToMessage({
|
||||
.messageId = itemId,
|
||||
.quote = quote,
|
||||
.quoteOffset = quoteOffset,
|
||||
.quote = selected.highlight.quote,
|
||||
.quoteOffset = selected.highlight.quoteOffset,
|
||||
.todoItemId = todoListTaskId,
|
||||
});
|
||||
if (!quote.empty()) {
|
||||
if (!selected.highlight.quote.empty()) {
|
||||
_widget->clearSelected();
|
||||
}
|
||||
}, &st::menuIconReply);
|
||||
|
|
|
@ -909,12 +909,26 @@ void HistoryItem::updateServiceDependent(bool force) {
|
|||
}
|
||||
|
||||
if (!dependent->lnk) {
|
||||
auto todoItemId = 0;
|
||||
if (const auto done = Get<HistoryServiceTodoCompletions>()) {
|
||||
const auto &items = !done->completed.empty()
|
||||
? done->completed
|
||||
: done->incompleted;
|
||||
if (items.size() == 1) {
|
||||
todoItemId = items.front();
|
||||
}
|
||||
} else if (const auto append = Get<HistoryServiceTodoAppendTasks>()) {
|
||||
if (append->list.size() == 1) {
|
||||
todoItemId = append->list.front().id;
|
||||
}
|
||||
}
|
||||
dependent->lnk = JumpToMessageClickHandler(
|
||||
(dependent->peerId
|
||||
? _history->owner().peer(dependent->peerId)
|
||||
: _history->peer),
|
||||
dependent->msgId,
|
||||
fullId());
|
||||
fullId(),
|
||||
{ .todoItemId = todoItemId });
|
||||
}
|
||||
auto gotDependencyItem = false;
|
||||
if (!dependent->msg) {
|
||||
|
|
|
@ -713,22 +713,19 @@ bool IsItemScheduledUntilOnline(not_null<const HistoryItem*> item) {
|
|||
ClickHandlerPtr JumpToMessageClickHandler(
|
||||
not_null<HistoryItem*> item,
|
||||
FullMsgId returnToId,
|
||||
TextWithEntities highlightPart,
|
||||
int highlightPartOffsetHint) {
|
||||
MessageHighlightId highlight) {
|
||||
return JumpToMessageClickHandler(
|
||||
item->history()->peer,
|
||||
item->id,
|
||||
returnToId,
|
||||
std::move(highlightPart),
|
||||
highlightPartOffsetHint);
|
||||
std::move(highlight));
|
||||
}
|
||||
|
||||
ClickHandlerPtr JumpToMessageClickHandler(
|
||||
not_null<PeerData*> peer,
|
||||
MsgId msgId,
|
||||
FullMsgId returnToId,
|
||||
TextWithEntities highlightPart,
|
||||
int highlightPartOffsetHint) {
|
||||
MessageHighlightId highlight) {
|
||||
return std::make_shared<LambdaClickHandler>([=] {
|
||||
const auto separate = Core::App().separateWindowFor(peer);
|
||||
const auto controller = separate
|
||||
|
@ -738,8 +735,7 @@ ClickHandlerPtr JumpToMessageClickHandler(
|
|||
auto params = Window::SectionShow{
|
||||
Window::SectionShow::Way::Forward
|
||||
};
|
||||
params.highlightPart = highlightPart;
|
||||
params.highlightPartOffsetHint = highlightPartOffsetHint;
|
||||
params.highlight = highlight;
|
||||
params.origin = Window::SectionShow::OriginMessage{
|
||||
returnToId
|
||||
};
|
||||
|
|
|
@ -229,13 +229,11 @@ private:
|
|||
not_null<PeerData*> peer,
|
||||
MsgId msgId,
|
||||
FullMsgId returnToId = FullMsgId(),
|
||||
TextWithEntities highlightPart = {},
|
||||
int highlightPartOffsetHint = 0);
|
||||
MessageHighlightId highlight = {});
|
||||
[[nodiscard]] ClickHandlerPtr JumpToMessageClickHandler(
|
||||
not_null<HistoryItem*> item,
|
||||
FullMsgId returnToId = FullMsgId(),
|
||||
TextWithEntities highlightPart = {},
|
||||
int highlightPartOffsetHint = 0);
|
||||
MessageHighlightId highlight = {});
|
||||
[[nodiscard]] ClickHandlerPtr JumpToStoryClickHandler(
|
||||
not_null<Data::Story*> story);
|
||||
ClickHandlerPtr JumpToStoryClickHandler(
|
||||
|
|
|
@ -65,6 +65,7 @@ Ui::ChatPaintHighlight ElementHighlighter::state(
|
|||
if (item->fullId() == _highlighted.itemId) {
|
||||
auto result = _animation.state();
|
||||
result.range = _highlighted.part;
|
||||
result.todoItemId = _highlighted.todoListId;
|
||||
return result;
|
||||
}
|
||||
return {};
|
||||
|
@ -82,19 +83,27 @@ ElementHighlighter::Highlight ElementHighlighter::computeHighlight(
|
|||
const auto i = ranges::find(group->items, item);
|
||||
if (i != end(group->items)) {
|
||||
const auto index = int(i - begin(group->items));
|
||||
if (quote.text.empty()) {
|
||||
if (quote.highlight.empty()) {
|
||||
return { leaderId, AddGroupItemSelection({}, index) };
|
||||
} else if (const auto leaderView = _viewForItem(leader)) {
|
||||
return { leaderId, leaderView->selectionFromQuote(quote) };
|
||||
return {
|
||||
leaderId,
|
||||
leaderView->selectionFromQuote(quote),
|
||||
quote.highlight.todoItemId,
|
||||
};
|
||||
}
|
||||
}
|
||||
return { leaderId };
|
||||
} else if (quote.text.empty()) {
|
||||
return { item->fullId() };
|
||||
return { leaderId, {}, quote.highlight.todoItemId };
|
||||
} else if (quote.highlight.quote.empty()) {
|
||||
return { item->fullId(), {}, quote.highlight.todoItemId };
|
||||
} else if (const auto view = _viewForItem(item)) {
|
||||
return { item->fullId(), view->selectionFromQuote(quote) };
|
||||
return {
|
||||
item->fullId(),
|
||||
view->selectionFromQuote(quote),
|
||||
quote.highlight.todoItemId,
|
||||
};
|
||||
}
|
||||
return { item->fullId() };
|
||||
return { item->fullId(), {}, quote.highlight.todoItemId };
|
||||
}
|
||||
|
||||
void ElementHighlighter::highlight(Highlight data) {
|
||||
|
@ -108,7 +117,7 @@ void ElementHighlighter::highlight(Highlight data) {
|
|||
}
|
||||
}
|
||||
_highlighted = data;
|
||||
_animation.start(!data.part.empty()
|
||||
_animation.start((!data.part.empty() || data.todoListId)
|
||||
&& !IsSubGroupSelection(data.part));
|
||||
|
||||
repaintHighlightedItem(view);
|
||||
|
|
|
@ -65,6 +65,7 @@ private:
|
|||
struct Highlight {
|
||||
FullMsgId itemId;
|
||||
TextSelection part;
|
||||
int todoListId = 0;
|
||||
|
||||
explicit operator bool() const {
|
||||
return itemId.operator bool();
|
||||
|
|
|
@ -5640,8 +5640,7 @@ void HistoryWidget::switchToSearch(QString query) {
|
|||
const auto item = activation.item;
|
||||
auto params = ::Window::SectionShow(
|
||||
::Window::SectionShow::Way::ClearStack);
|
||||
params.highlightPart = { activation.query };
|
||||
params.highlightPartOffsetHint = kSearchQueryOffsetHint;
|
||||
params.highlight = Window::SearchHighlightId(activation.query);
|
||||
controller()->showPeerHistory(
|
||||
item->history()->peer->id,
|
||||
params,
|
||||
|
@ -6743,8 +6742,7 @@ int HistoryWidget::countInitialScrollTop() {
|
|||
|
||||
enqueueMessageHighlight({
|
||||
item,
|
||||
base::take(_showAtMsgParams.highlightPart),
|
||||
base::take(_showAtMsgParams.highlightPartOffsetHint),
|
||||
base::take(_showAtMsgParams.highlight),
|
||||
});
|
||||
const auto result = itemTopForHighlight(view);
|
||||
createUnreadBarIfBelowVisibleArea(result);
|
||||
|
@ -7501,12 +7499,7 @@ void HistoryWidget::editDraftOptions() {
|
|||
|
||||
void HistoryWidget::jumpToReply(FullReplyTo to) {
|
||||
if (const auto item = session().data().message(to.messageId)) {
|
||||
JumpToMessageClickHandler(
|
||||
item,
|
||||
{},
|
||||
to.quote,
|
||||
to.quoteOffset
|
||||
)->onClick({});
|
||||
JumpToMessageClickHandler(item, {}, to.highlight())->onClick({});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -783,7 +783,7 @@ void DraftOptionsBox(
|
|||
box->setTitle(hasLink
|
||||
? tr::lng_link_options_header()
|
||||
: hasReply
|
||||
? (state->quote.current().text.empty()
|
||||
? (state->quote.current().highlight.quote.empty()
|
||||
? tr::lng_reply_options_header()
|
||||
: tr::lng_reply_options_quote())
|
||||
: (forwardCount == 1)
|
||||
|
@ -807,10 +807,12 @@ void DraftOptionsBox(
|
|||
auto result = draft.reply;
|
||||
if (const auto current = state->quote.current()) {
|
||||
result.messageId = current.item->fullId();
|
||||
result.quote = current.text;
|
||||
result.quoteOffset = current.offset;
|
||||
result.quote = current.highlight.quote;
|
||||
result.quoteOffset = current.highlight.quoteOffset;
|
||||
// result.todoItemId = current.highlight.todoItemId;
|
||||
} else {
|
||||
result.quote = {};
|
||||
// result.todoItemId = 0;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
@ -1112,7 +1114,7 @@ void DraftOptionsBox(
|
|||
state->quote.value(),
|
||||
state->shown.value()
|
||||
) | rpl::map([=](const SelectedQuote "e, Section shown) {
|
||||
return (quote.text.empty() || shown != Section::Reply)
|
||||
return (quote.highlight.quote.empty() || shown != Section::Reply)
|
||||
? tr::lng_settings_save()
|
||||
: tr::lng_reply_quote_selected();
|
||||
}) | rpl::flatten_latest();
|
||||
|
|
|
@ -119,12 +119,10 @@ rpl::producer<Ui::MessageBarContent> RootViewContent(
|
|||
ChatMemento::ChatMemento(
|
||||
ChatViewId id,
|
||||
MsgId highlightId,
|
||||
const TextWithEntities &highlightPart,
|
||||
int highlightPartOffsetHint)
|
||||
MessageHighlightId highlight)
|
||||
: _id(id)
|
||||
, _highlightPart(highlightPart)
|
||||
, _highlightPartOffsetHint(highlightPartOffsetHint)
|
||||
, _highlightId(highlightId) {
|
||||
, _highlightId(highlightId)
|
||||
, _highlight(std::move(highlight)) {
|
||||
if (highlightId || _id.sublist) {
|
||||
_list.setAroundPosition({
|
||||
.fullId = FullMsgId(_id.history->peer->id, highlightId),
|
||||
|
@ -876,12 +874,7 @@ void ChatWidget::setupComposeControls() {
|
|||
_composeControls->jumpToItemRequests(
|
||||
) | rpl::start_with_next([=](FullReplyTo to) {
|
||||
if (const auto item = session().data().message(to.messageId)) {
|
||||
JumpToMessageClickHandler(
|
||||
item,
|
||||
{},
|
||||
to.quote,
|
||||
to.quoteOffset
|
||||
)->onClick({});
|
||||
JumpToMessageClickHandler(item, {}, to.highlight())->onClick({});
|
||||
}
|
||||
}, lifetime());
|
||||
|
||||
|
@ -1039,8 +1032,9 @@ void ChatWidget::setupSwipeReplyAndBack() {
|
|||
: still)->fullId();
|
||||
_inner->replyToMessageRequestNotify({
|
||||
.messageId = replyToItemId,
|
||||
.quote = selected.text,
|
||||
.quoteOffset = selected.offset,
|
||||
.quote = selected.highlight.quote,
|
||||
.quoteOffset = selected.highlight.quoteOffset,
|
||||
.todoItemId = selected.highlight.todoItemId,
|
||||
});
|
||||
};
|
||||
return result;
|
||||
|
@ -2639,8 +2633,7 @@ void ChatWidget::restoreState(not_null<ChatMemento*> memento) {
|
|||
auto params = Window::SectionShow(
|
||||
Window::SectionShow::Way::Forward,
|
||||
anim::type::instant);
|
||||
params.highlightPart = memento->highlightPart();
|
||||
params.highlightPartOffsetHint = memento->highlightPartOffsetHint();
|
||||
params.highlight = memento->highlight();
|
||||
showAtPosition(Data::MessagePosition{
|
||||
.fullId = FullMsgId(_peer->id, highlight),
|
||||
.date = TimeId(0),
|
||||
|
@ -3443,8 +3436,7 @@ bool ChatWidget::searchInChatEmbedded(
|
|||
const auto item = activation.item;
|
||||
auto params = ::Window::SectionShow(
|
||||
::Window::SectionShow::Way::ClearStack);
|
||||
params.highlightPart = { activation.query };
|
||||
params.highlightPartOffsetHint = kSearchQueryOffsetHint;
|
||||
params.highlight = Window::SearchHighlightId(activation.query);
|
||||
controller()->showPeerHistory(
|
||||
item->history()->peer->id,
|
||||
params,
|
||||
|
|
|
@ -461,8 +461,7 @@ public:
|
|||
explicit ChatMemento(
|
||||
ChatViewId id,
|
||||
MsgId highlightId = 0,
|
||||
const TextWithEntities &highlightPart = {},
|
||||
int highlightPartOffsetHint = 0);
|
||||
MessageHighlightId highlight = {});
|
||||
|
||||
struct Comments {
|
||||
};
|
||||
|
@ -511,20 +510,16 @@ public:
|
|||
[[nodiscard]] MsgId highlightId() const {
|
||||
return _highlightId;
|
||||
}
|
||||
[[nodiscard]] const TextWithEntities &highlightPart() const {
|
||||
return _highlightPart;
|
||||
}
|
||||
[[nodiscard]] int highlightPartOffsetHint() const {
|
||||
return _highlightPartOffsetHint;
|
||||
[[nodiscard]] const MessageHighlightId &highlight() const {
|
||||
return _highlight;
|
||||
}
|
||||
|
||||
private:
|
||||
void setupTopicViewer();
|
||||
|
||||
ChatViewId _id;
|
||||
const TextWithEntities _highlightPart;
|
||||
const int _highlightPartOffsetHint = 0;
|
||||
const MsgId _highlightId = 0;
|
||||
const MessageHighlightId _highlight;
|
||||
ListMemento _list;
|
||||
std::shared_ptr<Data::RepliesList> _replies;
|
||||
QVector<FullMsgId> _replyReturns;
|
||||
|
|
|
@ -643,18 +643,18 @@ bool AddReplyToMessageAction(
|
|||
? request.link->property(kTodoListItemIdProperty).toInt()
|
||||
: 0;
|
||||
const auto "e = request.quote;
|
||||
auto text = (quote.text.empty()
|
||||
? tr::lng_context_reply_msg
|
||||
: todoListTaskId
|
||||
auto text = (todoListTaskId
|
||||
? tr::lng_context_reply_to_task
|
||||
: quote.highlight.quote.empty()
|
||||
? tr::lng_context_reply_msg
|
||||
: tr::lng_context_quote_and_reply)(
|
||||
tr::now,
|
||||
Ui::Text::FixAmpersandInAction);
|
||||
menu->addAction(std::move(text), [=, itemId = item->fullId()] {
|
||||
list->replyToMessageRequestNotify({
|
||||
.messageId = itemId,
|
||||
.quote = quote.text,
|
||||
.quoteOffset = quote.offset,
|
||||
.quote = quote.highlight.quote,
|
||||
.quoteOffset = quote.highlight.quoteOffset,
|
||||
.todoItemId = todoListTaskId,
|
||||
}, base::IsCtrlPressed());
|
||||
}, &st::menuIconReply);
|
||||
|
|
|
@ -1341,9 +1341,18 @@ void Element::validateText() {
|
|||
|
||||
if (const auto done = item->Get<HistoryServiceTodoCompletions>()) {
|
||||
if (!done->completed.empty() && !done->incompleted.empty()) {
|
||||
const auto todoItemId = (done->incompleted.size() == 1)
|
||||
? done->incompleted.front()
|
||||
: 0;
|
||||
setServicePreMessage(
|
||||
item->composeTodoIncompleted(done),
|
||||
done->lnk);
|
||||
JumpToMessageClickHandler(
|
||||
(done->peerId
|
||||
? history()->owner().peer(done->peerId)
|
||||
: history()->peer),
|
||||
done->msgId,
|
||||
item->fullId(),
|
||||
{ .todoItemId = todoItemId }));
|
||||
} else {
|
||||
setServicePreMessage({});
|
||||
}
|
||||
|
@ -2190,17 +2199,18 @@ TextSelection Element::FindSelectionFromQuote(
|
|||
const SelectedQuote "e) {
|
||||
Expects(quote.item != nullptr);
|
||||
|
||||
if (quote.text.empty()) {
|
||||
const auto &rich = quote.highlight.quote;
|
||||
if (rich.empty()) {
|
||||
return {};
|
||||
}
|
||||
const auto &original = quote.item->originalText();
|
||||
if (quote.offset == kSearchQueryOffsetHint) {
|
||||
if (quote.highlight.quoteOffset == kSearchQueryOffsetHint) {
|
||||
return ApplyModificationsFrom(
|
||||
FindSearchQueryHighlight(original.text, quote.text.text),
|
||||
FindSearchQueryHighlight(original.text, rich.text),
|
||||
text);
|
||||
}
|
||||
const auto length = int(original.text.size());
|
||||
const auto qlength = int(quote.text.text.size());
|
||||
const auto qlength = int(rich.text.size());
|
||||
const auto checkAt = [&](int offset) {
|
||||
return TextSelection{
|
||||
uint16(offset),
|
||||
|
@ -2211,7 +2221,7 @@ TextSelection Element::FindSelectionFromQuote(
|
|||
if (offset > length - qlength) {
|
||||
return TextSelection();
|
||||
}
|
||||
const auto i = original.text.indexOf(quote.text.text, offset);
|
||||
const auto i = original.text.indexOf(rich.text, offset);
|
||||
return (i >= 0) ? checkAt(i) : TextSelection();
|
||||
};
|
||||
const auto findOneBefore = [&](int offset) {
|
||||
|
@ -2220,7 +2230,7 @@ TextSelection Element::FindSelectionFromQuote(
|
|||
}
|
||||
const auto end = std::min(offset + qlength - 1, length);
|
||||
const auto from = end - length - 1;
|
||||
const auto i = original.text.lastIndexOf(quote.text.text, from);
|
||||
const auto i = original.text.lastIndexOf(rich.text, from);
|
||||
return (i >= 0) ? checkAt(i) : TextSelection();
|
||||
};
|
||||
const auto findAfter = [&](int offset) {
|
||||
|
@ -2258,7 +2268,7 @@ TextSelection Element::FindSelectionFromQuote(
|
|||
? before
|
||||
: after;
|
||||
};
|
||||
auto result = findTwoWays(quote.offset);
|
||||
auto result = findTwoWays(quote.highlight.quoteOffset);
|
||||
if (result.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -357,12 +357,11 @@ struct TopicButton {
|
|||
|
||||
struct SelectedQuote {
|
||||
HistoryItem *item = nullptr;
|
||||
TextWithEntities text;
|
||||
int offset = 0;
|
||||
MessageHighlightId highlight;
|
||||
bool overflown = false;
|
||||
|
||||
explicit operator bool() const {
|
||||
return item && !text.empty();
|
||||
return item && !highlight.quote.empty();
|
||||
}
|
||||
friend inline bool operator==(SelectedQuote, SelectedQuote) = default;
|
||||
};
|
||||
|
|
|
@ -818,10 +818,9 @@ bool ListWidget::isBelowPosition(Data::MessagePosition position) const {
|
|||
|
||||
void ListWidget::highlightMessage(
|
||||
FullMsgId itemId,
|
||||
const TextWithEntities &part,
|
||||
int partOffsetHint) {
|
||||
const MessageHighlightId &highlight) {
|
||||
if (const auto view = viewForItem(itemId)) {
|
||||
_highlighter.highlight({ view->data(), part, partOffsetHint });
|
||||
_highlighter.highlight({ view->data(), highlight });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -899,11 +898,8 @@ bool ListWidget::showAtPositionNow(
|
|||
}
|
||||
if (position != Data::MaxMessagePosition
|
||||
&& position != Data::UnreadMessagePosition) {
|
||||
const auto hasHighlight = !params.highlightPart.empty();
|
||||
highlightMessage(
|
||||
position.fullId,
|
||||
params.highlightPart,
|
||||
params.highlightPartOffsetHint);
|
||||
const auto hasHighlight = !params.highlight.empty();
|
||||
highlightMessage(position.fullId, params.highlight);
|
||||
if (hasHighlight) {
|
||||
// We may want to scroll to a different part of the message.
|
||||
scrollTop = scrollTopForPosition(position);
|
||||
|
|
|
@ -314,8 +314,7 @@ public:
|
|||
bool isBelowPosition(Data::MessagePosition position) const;
|
||||
void highlightMessage(
|
||||
FullMsgId itemId,
|
||||
const TextWithEntities &part,
|
||||
int partOffsetHint);
|
||||
const MessageHighlightId &highlight);
|
||||
|
||||
void showAtPosition(
|
||||
Data::MessagePosition position,
|
||||
|
|
|
@ -3303,7 +3303,7 @@ TextSelection Message::selectionFromQuote(
|
|||
const SelectedQuote "e) const {
|
||||
Expects(quote.item != nullptr);
|
||||
|
||||
if (quote.text.empty()) {
|
||||
if (quote.highlight.quote.empty()) {
|
||||
return {};
|
||||
}
|
||||
const auto item = quote.item;
|
||||
|
|
|
@ -384,10 +384,11 @@ void Reply::setLinkFrom(
|
|||
const auto &fields = data->fields();
|
||||
const auto externalChannelId = peerToChannel(fields.externalPeerId);
|
||||
const auto messageId = fields.messageId;
|
||||
const auto quote = fields.manualQuote
|
||||
? fields.quote
|
||||
: TextWithEntities();
|
||||
const auto quoteOffset = fields.quoteOffset;
|
||||
const auto highlight = MessageHighlightId{
|
||||
.quote = fields.manualQuote ? fields.quote : TextWithEntities(),
|
||||
.quoteOffset = int(fields.quoteOffset),
|
||||
.todoItemId = fields.todoItemId,
|
||||
};
|
||||
const auto returnToId = view->data()->fullId();
|
||||
const auto externalLink = [=](ClickContext context) {
|
||||
const auto my = context.other.value<ClickHandlerContext>();
|
||||
|
@ -410,8 +411,7 @@ void Reply::setLinkFrom(
|
|||
channel,
|
||||
messageId,
|
||||
returnToId,
|
||||
quote,
|
||||
quoteOffset
|
||||
highlight
|
||||
)->onClick(context);
|
||||
} else {
|
||||
controller->showPeerInfo(channel);
|
||||
|
@ -432,7 +432,7 @@ void Reply::setLinkFrom(
|
|||
const auto message = data->resolvedMessage.get();
|
||||
const auto story = data->resolvedStory.get();
|
||||
_link = message
|
||||
? JumpToMessageClickHandler(message, returnToId, quote, quoteOffset)
|
||||
? JumpToMessageClickHandler(message, returnToId, highlight)
|
||||
: story
|
||||
? JumpToStoryClickHandler(story)
|
||||
: (data->external()
|
||||
|
|
|
@ -430,12 +430,8 @@ void ScheduledWidget::setupComposeControls() {
|
|||
if (item->isScheduled() && item->history() == _history) {
|
||||
showAtPosition(item->position());
|
||||
} else {
|
||||
JumpToMessageClickHandler(
|
||||
item,
|
||||
{},
|
||||
to.quote,
|
||||
to.quoteOffset
|
||||
)->onClick({});
|
||||
const auto highlight = to.highlight();
|
||||
JumpToMessageClickHandler(item, {}, highlight)->onClick({});
|
||||
}
|
||||
}
|
||||
}, lifetime());
|
||||
|
|
|
@ -482,6 +482,7 @@ void TodoList::draw(Painter &p, const PaintContext &context) const {
|
|||
paintw,
|
||||
width(),
|
||||
context);
|
||||
appendTaskHighlight(task.id, tshift, height, context);
|
||||
if (was) {
|
||||
heavy = true;
|
||||
} else if (!task.userpic.null()) {
|
||||
|
@ -576,6 +577,33 @@ int TodoList::paintTask(
|
|||
return height;
|
||||
}
|
||||
|
||||
void TodoList::appendTaskHighlight(
|
||||
int id,
|
||||
int top,
|
||||
int height,
|
||||
const PaintContext &context) const {
|
||||
if (context.highlight.todoItemId != id
|
||||
|| context.highlight.collapsion <= 0.) {
|
||||
return;
|
||||
}
|
||||
const auto to = context.highlightInterpolateTo;
|
||||
const auto toProgress = (1. - context.highlight.collapsion);
|
||||
if (toProgress >= 1.) {
|
||||
context.highlightPathCache->addRect(to);
|
||||
} else if (toProgress <= 0.) {
|
||||
context.highlightPathCache->addRect(0, top, width(), height);
|
||||
} else {
|
||||
const auto lerp = [=](int from, int to) {
|
||||
return from + (to - from) * toProgress;
|
||||
};
|
||||
context.highlightPathCache->addRect(
|
||||
lerp(0, to.x()),
|
||||
lerp(top, to.y()),
|
||||
lerp(width(), to.width()),
|
||||
lerp(height, to.height()));
|
||||
}
|
||||
}
|
||||
|
||||
void TodoList::paintRadio(
|
||||
Painter &p,
|
||||
const Task &task,
|
||||
|
|
|
@ -117,6 +117,11 @@ private:
|
|||
int top,
|
||||
int paintw,
|
||||
const PaintContext &context) const;
|
||||
void appendTaskHighlight(
|
||||
int id,
|
||||
int top,
|
||||
int height,
|
||||
const PaintContext &context) const;
|
||||
|
||||
void radialAnimationCallback() const;
|
||||
|
||||
|
|
|
@ -153,6 +153,7 @@ struct ChatPaintHighlight {
|
|||
float64 opacity = 0.;
|
||||
float64 collapsion = 0.;
|
||||
TextSelection range;
|
||||
int todoItemId = 0;
|
||||
};
|
||||
|
||||
struct ChatPaintContext {
|
||||
|
|
|
@ -358,6 +358,14 @@ void DateClickHandler::onClick(ClickContext context) const {
|
|||
}
|
||||
}
|
||||
|
||||
MessageHighlightId SearchHighlightId(const QString &query) {
|
||||
auto result = MessageHighlightId{ .quote = { query } };
|
||||
if (!result.quote.empty()) {
|
||||
result.quoteOffset = kSearchQueryOffsetHint;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
SessionNavigation::SessionNavigation(not_null<Main::Session*> session)
|
||||
: _session(session)
|
||||
, _api(&_session->mtp()) {
|
||||
|
@ -1146,8 +1154,7 @@ void SessionNavigation::showRepliesForMessage(
|
|||
.repliesRootId = rootId,
|
||||
},
|
||||
commentId,
|
||||
params.highlightPart,
|
||||
params.highlightPartOffsetHint);
|
||||
params.highlight);
|
||||
memento->setFromTopic(topic);
|
||||
showSection(std::move(memento), params);
|
||||
return;
|
||||
|
@ -1269,8 +1276,7 @@ void SessionNavigation::showSublist(
|
|||
.sublist = sublist,
|
||||
},
|
||||
itemId,
|
||||
params.highlightPart,
|
||||
params.highlightPartOffsetHint);
|
||||
params.highlight);
|
||||
showSection(std::move(memento), params);
|
||||
}
|
||||
|
||||
|
|
|
@ -166,8 +166,9 @@ struct SectionShow {
|
|||
return copy;
|
||||
}
|
||||
|
||||
TextWithEntities highlightPart;
|
||||
MessageHighlightId highlight;
|
||||
int highlightPartOffsetHint = 0;
|
||||
int highlightTodoItemId = 0;
|
||||
std::optional<TimeId> videoTimestamp;
|
||||
Way way = Way::Forward;
|
||||
anim::type animated = anim::type::normal;
|
||||
|
@ -182,6 +183,8 @@ struct SectionShow {
|
|||
|
||||
};
|
||||
|
||||
[[nodiscard]] MessageHighlightId SearchHighlightId(const QString &query);
|
||||
|
||||
class SessionController;
|
||||
|
||||
class SessionNavigation : public base::has_weak_ptr {
|
||||
|
|
Loading…
Add table
Reference in a new issue