mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-15 21:57:10 +02:00
Support highlighting correct quoted part.
This commit is contained in:
parent
dcc326e17f
commit
3a67e4f1f4
8 changed files with 101 additions and 24 deletions
|
@ -2929,6 +2929,7 @@ FullReplyTo HistoryItem::replyTo() const {
|
|||
if (const auto id = fields.messageId) {
|
||||
result.messageId = { replyToPeer, id };
|
||||
result.quote = fields.quote;
|
||||
result.quoteOffset = fields.quoteOffset;
|
||||
}
|
||||
if (const auto id = fields.storyId) {
|
||||
result.storyId = { replyToPeer, id };
|
||||
|
|
|
@ -6331,7 +6331,12 @@ void HistoryWidget::editDraftOptions() {
|
|||
|
||||
void HistoryWidget::jumpToReply(FullReplyTo to) {
|
||||
if (const auto item = session().data().message(to.messageId)) {
|
||||
JumpToMessageClickHandler(item, {}, to.quote)->onClick({});
|
||||
JumpToMessageClickHandler(
|
||||
item,
|
||||
{},
|
||||
to.quote,
|
||||
to.quoteOffset
|
||||
)->onClick({});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7158,17 +7163,22 @@ void HistoryWidget::clearFieldText(
|
|||
|
||||
void HistoryWidget::replyToMessage(FullReplyTo id) {
|
||||
if (const auto item = session().data().message(id.messageId)) {
|
||||
replyToMessage(item, id.quote);
|
||||
replyToMessage(item, id.quote, id.quoteOffset);
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryWidget::replyToMessage(
|
||||
not_null<HistoryItem*> item,
|
||||
TextWithEntities quote) {
|
||||
TextWithEntities quote,
|
||||
int quoteOffset) {
|
||||
if (isJoinChannel()) {
|
||||
return;
|
||||
}
|
||||
_processingReplyTo = { .messageId = item->fullId(), .quote = quote };
|
||||
_processingReplyTo = {
|
||||
.messageId = item->fullId(),
|
||||
.quote = quote,
|
||||
.quoteOffset = quoteOffset,
|
||||
};
|
||||
_processingReplyItem = item;
|
||||
processReply();
|
||||
}
|
||||
|
|
|
@ -195,7 +195,8 @@ public:
|
|||
void replyToMessage(FullReplyTo id);
|
||||
void replyToMessage(
|
||||
not_null<HistoryItem*> item,
|
||||
TextWithEntities quote = {});
|
||||
TextWithEntities quote = {},
|
||||
int quoteOffset = 0);
|
||||
void editMessage(FullMsgId itemId);
|
||||
void editMessage(not_null<HistoryItem*> item);
|
||||
|
||||
|
|
|
@ -601,7 +601,11 @@ void DraftOptionsBox(
|
|||
rpl::lifetime resolveLifetime;
|
||||
};
|
||||
const auto state = box->lifetime().make_state<State>();
|
||||
state->quote = SelectedQuote{ replyItem, draft.reply.quote };
|
||||
state->quote = SelectedQuote{
|
||||
replyItem,
|
||||
draft.reply.quote,
|
||||
draft.reply.quoteOffset,
|
||||
};
|
||||
state->webpage = draft.webpage;
|
||||
state->preview = previewData;
|
||||
state->shown = previewData ? Section::Link : Section::Reply;
|
||||
|
|
|
@ -1659,22 +1659,71 @@ TextSelection Element::FindSelectionFromQuote(
|
|||
return {};
|
||||
}
|
||||
const auto &original = quote.item->originalText();
|
||||
auto result = TextSelection();
|
||||
auto offset = 0;
|
||||
while (true) {
|
||||
const auto i = original.text.indexOf(quote.text.text, offset);
|
||||
if (i < 0) {
|
||||
return {};
|
||||
}
|
||||
auto selection = TextSelection{
|
||||
uint16(i),
|
||||
uint16(i + quote.text.text.size()),
|
||||
const auto length = int(original.text.size());
|
||||
const auto qlength = int(quote.text.text.size());
|
||||
const auto checkAt = [&](int offset) {
|
||||
const auto selection = TextSelection{
|
||||
uint16(offset),
|
||||
uint16(offset + qlength),
|
||||
};
|
||||
if (CheckQuoteEntities(quote.text.entities, original, selection)) {
|
||||
result = selection;
|
||||
break;
|
||||
return CheckQuoteEntities(quote.text.entities, original, selection)
|
||||
? selection
|
||||
: TextSelection{ uint16(offset + 1), uint16(offset + 1) };
|
||||
};
|
||||
const auto findOneAfter = [&](int offset) {
|
||||
if (offset > length - qlength) {
|
||||
return TextSelection();
|
||||
}
|
||||
offset = i + 1;
|
||||
const auto i = original.text.indexOf(quote.text.text, offset);
|
||||
return (i >= 0) ? checkAt(i) : TextSelection();
|
||||
};
|
||||
const auto findOneBefore = [&](int offset) {
|
||||
if (!offset) {
|
||||
return TextSelection();
|
||||
}
|
||||
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);
|
||||
return (i >= 0) ? checkAt(i) : TextSelection();
|
||||
};
|
||||
const auto findAfter = [&](int offset) {
|
||||
while (true) {
|
||||
const auto result = findOneAfter(offset);
|
||||
if (!result.empty() || result == TextSelection()) {
|
||||
return result;
|
||||
}
|
||||
offset = result.from;
|
||||
}
|
||||
};
|
||||
const auto findBefore = [&](int offset) {
|
||||
while (true) {
|
||||
const auto result = findOneBefore(offset);
|
||||
if (!result.empty() || result == TextSelection()) {
|
||||
return result;
|
||||
}
|
||||
offset = result.from - 2;
|
||||
if (offset < 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
};
|
||||
const auto findTwoWays = [&](int offset) {
|
||||
const auto after = findAfter(offset);
|
||||
if (after.empty()) {
|
||||
return findBefore(offset);
|
||||
} else if (after.from == offset) {
|
||||
return after;
|
||||
}
|
||||
const auto before = findBefore(offset);
|
||||
return before.empty()
|
||||
? after
|
||||
: (offset - before.from < after.from - offset)
|
||||
? before
|
||||
: after;
|
||||
};
|
||||
auto result = findTwoWays(quote.offset);
|
||||
if (result.empty()) {
|
||||
return {};
|
||||
}
|
||||
for (const auto &modification : text.modifications()) {
|
||||
if (modification.position >= result.to) {
|
||||
|
|
|
@ -797,7 +797,12 @@ void RepliesWidget::setupComposeControls() {
|
|||
_composeControls->jumpToItemRequests(
|
||||
) | rpl::start_with_next([=](FullReplyTo to) {
|
||||
if (const auto item = session().data().message(to.messageId)) {
|
||||
JumpToMessageClickHandler(item, {}, to.quote)->onClick({});
|
||||
JumpToMessageClickHandler(
|
||||
item,
|
||||
{},
|
||||
to.quote,
|
||||
to.quoteOffset
|
||||
)->onClick({});
|
||||
}
|
||||
}, lifetime());
|
||||
|
||||
|
|
|
@ -270,6 +270,7 @@ void Reply::setLinkFrom(
|
|||
const auto quote = fields.manualQuote
|
||||
? fields.quote
|
||||
: TextWithEntities();
|
||||
const auto quoteOffset = fields.quoteOffset;
|
||||
const auto returnToId = view->data()->fullId();
|
||||
const auto externalLink = [=](ClickContext context) {
|
||||
const auto my = context.other.value<ClickHandlerContext>();
|
||||
|
@ -292,7 +293,8 @@ void Reply::setLinkFrom(
|
|||
channel,
|
||||
messageId,
|
||||
returnToId,
|
||||
quote
|
||||
quote,
|
||||
quoteOffset
|
||||
)->onClick(context);
|
||||
} else {
|
||||
controller->showPeerInfo(channel);
|
||||
|
@ -313,7 +315,7 @@ void Reply::setLinkFrom(
|
|||
const auto message = data->resolvedMessage.get();
|
||||
const auto story = data->resolvedStory.get();
|
||||
_link = message
|
||||
? JumpToMessageClickHandler(message, returnToId, quote)
|
||||
? JumpToMessageClickHandler(message, returnToId, quote, quoteOffset)
|
||||
: story
|
||||
? JumpToStoryClickHandler(story)
|
||||
: (data->external()
|
||||
|
|
|
@ -281,7 +281,12 @@ void ScheduledWidget::setupComposeControls() {
|
|||
if (item->isScheduled() && item->history() == _history) {
|
||||
showAtPosition(item->position());
|
||||
} else {
|
||||
JumpToMessageClickHandler(item, {}, to.quote)->onClick({});
|
||||
JumpToMessageClickHandler(
|
||||
item,
|
||||
{},
|
||||
to.quote,
|
||||
to.quoteOffset
|
||||
)->onClick({});
|
||||
}
|
||||
}
|
||||
}, lifetime());
|
||||
|
|
Loading…
Add table
Reference in a new issue