Jump to near reply inside a replies thread.

This commit is contained in:
John Preston 2020-08-31 15:17:02 +04:00
parent f8b83dd186
commit 1849f01b15
8 changed files with 89 additions and 71 deletions

View file

@ -102,10 +102,10 @@ bool RepliesList::buildFromData(not_null<Viewer*> viewer) {
const auto i = around
? ranges::lower_bound(_list, around, std::greater<>())
: end(_list);
const auto availableBefore = (i - begin(_list));
const auto availableAfter = (end(_list) - i);
const auto useBefore = std::min(availableBefore, viewer->limitBefore);
const auto useAfter = std::min(availableAfter, viewer->limitAfter + 1);
const auto availableBefore = (end(_list) - i);
const auto availableAfter = (i - begin(_list));
const auto useBefore = std::min(availableBefore, viewer->limitBefore + 1);
const auto useAfter = std::min(availableAfter, viewer->limitAfter);
const auto slice = &viewer->slice;
if (_skippedBefore.has_value()) {
slice->skippedBefore
@ -115,20 +115,23 @@ bool RepliesList::buildFromData(not_null<Viewer*> viewer) {
slice->skippedAfter
= (*_skippedAfter + (availableAfter - useAfter));
}
const auto channelId = _history->channelId();
slice->ids.clear();
slice->ids.reserve(useBefore + useAfter);
for (auto j = i - useBefore, e = i + useAfter; j != e; ++j) {
slice->ids.reserve(useAfter + useBefore);
for (auto j = i - useAfter, e = i + useBefore; j != e; ++j) {
slice->ids.emplace_back(channelId, *j);
}
ranges::reverse(slice->ids);
slice->fullCount = _fullCount.current();
if (_skippedBefore != 0 && useBefore < viewer->limitBefore) {
if (_skippedBefore != 0 && useBefore < viewer->limitBefore + 1) {
loadBefore();
}
if (_skippedAfter != 0 && useAfter < viewer->limitAfter + 1) {
if (_skippedAfter != 0 && useAfter < viewer->limitAfter) {
loadAfter();
}
return true;
}
@ -365,6 +368,11 @@ bool RepliesList::processMessagesIsEmpty(const MTPmessages_Messages &result) {
refreshed.insert(refreshed.end(), _list.begin(), _list.end());
_list = std::move(refreshed);
}
if (_fullCount.current() && _skippedBefore && !_skippedAfter) {
_skippedAfter = *_fullCount.current() - *_skippedBefore - _list.size();
} else if (_fullCount.current() && _skippedAfter && !_skippedBefore) {
_skippedBefore = *_fullCount.current() - *_skippedAfter - _list.size();
}
return false;
}

View file

@ -929,15 +929,13 @@ ClickHandlerPtr goToMessageClickHandler(
return std::make_shared<LambdaClickHandler>([=] {
if (const auto main = App::main()) { // multi good
if (&main->session() == &peer->session()) {
if (const auto returnTo = peer->owner().message(returnToId)) {
if (returnTo->history()->peer == peer) {
main->pushReplyReturn(returnTo);
}
}
main->controller()->showPeerHistory(
peer,
Window::SectionShow::Way::Forward,
msgId);
auto params = Window::SectionShow{
Window::SectionShow::Way::Forward
};
params.origin = Window::SectionShow::OriginMessage{
returnToId
};
main->controller()->showPeerHistory(peer, params, msgId);
}
}
});

View file

@ -930,6 +930,26 @@ std::unique_ptr<Window::SectionMemento> RepliesWidget::createMemento() {
return result;
}
bool RepliesWidget::showMessage(
PeerId peerId,
const Window::SectionShow &params,
MsgId messageId) {
if (peerId != _history->peer->id) {
return false;
}
const auto id = FullMsgId{
_history->channelId(),
messageId
};
const auto message = _history->owner().message(id);
if (!message || message->replyToTop() != _rootId) {
return false;
}
_highlightMessageId = id;
showAtPosition(Data::MessagePosition(message->date(), id));
return true;
}
void RepliesWidget::saveState(not_null<RepliesMemento*> memento) {
memento->setReplies(_replies);
_inner->saveState(memento->list());
@ -1092,37 +1112,6 @@ rpl::producer<Data::MessagesSlice> RepliesWidget::listSource(
return _replies->source(aroundId, limitBefore, limitAfter);
}
void RepliesWidget::highlightSingleNewMessage(
const Data::MessagesSlice &slice) {
const auto guard = gsl::finally([&] { _lastSlice = slice; });
if (_lastSlice.ids.empty()
|| (slice.ids.size() != _lastSlice.ids.size() + 1)) {
return;
}
auto firstDifferent = 0;
while (firstDifferent != _lastSlice.ids.size()) {
if (slice.ids[firstDifferent] != _lastSlice.ids[firstDifferent]) {
break;
}
++firstDifferent;
}
auto lastDifferent = slice.ids.size() - 1;
while (lastDifferent != firstDifferent) {
if (slice.ids[lastDifferent] != _lastSlice.ids[lastDifferent - 1]) {
break;
}
--lastDifferent;
}
if (firstDifferent != lastDifferent) {
return;
}
const auto newId = slice.ids[firstDifferent];
if (const auto item = session().data().message(newId)) {
// _highlightMessageId = newId;
showAtPosition(item->position());
}
}
bool RepliesWidget::listAllowsMultiSelect() {
return true;
}

View file

@ -80,6 +80,10 @@ public:
not_null<Window::SectionMemento*> memento,
const Window::SectionShow &params) override;
std::unique_ptr<Window::SectionMemento> createMemento() override;
bool showMessage(
PeerId peerId,
const Window::SectionShow &params,
MsgId messageId) override;
void setInternalState(
const QRect &geometry,
@ -156,7 +160,6 @@ private:
not_null<HistoryItem*> item,
Api::SendOptions options,
mtpRequestId *const saveEditMsgRequestId);
void highlightSingleNewMessage(const Data::MessagesSlice &slice);
void chooseAttach();
[[nodiscard]] SendMenu::Type sendMenuType() const;

View file

@ -1221,10 +1221,6 @@ Image *MainWidget::newBackgroundThumb() {
: nullptr;
}
void MainWidget::pushReplyReturn(not_null<HistoryItem*> item) {
_history->pushReplyReturn(item);
}
void MainWidget::setInnerFocus() {
if (_hider || !_history->peer()) {
if (!_hider && _mainSection) {
@ -1381,6 +1377,20 @@ void MainWidget::ui_showPeerHistory(
return;
}
}
if (IsServerMsgId(showAtMsgId)
&& _mainSection
&& _mainSection->showMessage(peerId, params, showAtMsgId)) {
return;
}
using OriginMessage = SectionShow::OriginMessage;
if (const auto origin = std::get_if<OriginMessage>(&params.origin)) {
if (const auto returnTo = session().data().message(origin->id)) {
if (returnTo->history()->peer->id == peerId) {
_history->pushReplyReturn(returnTo);
}
}
}
_controller->dialogsListFocused().set(false, true);
_a_dialogsWidth.stop();
@ -2642,15 +2652,13 @@ void MainWidget::openPeerByName(
}
const auto returnToId = clickFromMessageId;
InvokeQueued(this, [=] {
if (const auto returnTo = session().data().message(returnToId)) {
if (returnTo->history()->peer == peer) {
pushReplyReturn(returnTo);
}
}
_controller->showPeerHistory(
peer->id,
SectionShow::Way::Forward,
msgId);
auto params = SectionShow{
SectionShow::Way::Forward
};
params.origin = SectionShow::OriginMessage{
returnToId
};
_controller->showPeerHistory(peer->id, params, msgId);
});
}
} else {

View file

@ -204,8 +204,6 @@ public:
void checkChatBackground();
Image *newBackgroundThumb();
void pushReplyReturn(not_null<HistoryItem*> item);
// Does offerPeer or showPeerHistory.
void choosePeer(PeerId peerId, MsgId showAtMsgId);
void clearBotStartToken(PeerData *peer);

View file

@ -40,20 +40,20 @@ class AbstractSectionWidget
public:
AbstractSectionWidget(
QWidget *parent,
not_null<Window::SessionController*> controller)
not_null<SessionController*> controller)
: RpWidget(parent)
, _controller(controller) {
}
[[nodiscard]] Main::Session &session() const;
[[nodiscard]] not_null<Window::SessionController*> controller() const {
[[nodiscard]] not_null<SessionController*> controller() const {
return _controller;
}
// Tabbed selector management.
virtual bool pushTabbedSelectorToThirdSection(
not_null<PeerData*> peer,
const Window::SectionShow &params) {
const SectionShow &params) {
return false;
}
virtual bool returnTabbedSelector() {
@ -61,7 +61,7 @@ public:
}
private:
const not_null<Window::SessionController*> _controller;
const not_null<SessionController*> _controller;
};
@ -82,7 +82,7 @@ class SectionWidget : public AbstractSectionWidget {
public:
SectionWidget(
QWidget *parent,
not_null<Window::SessionController*> controller);
not_null<SessionController*> controller);
virtual Dialogs::RowDescriptor activeChat() const {
return {};
@ -118,6 +118,13 @@ public:
not_null<SectionMemento*> memento,
const SectionShow &params) = 0;
virtual bool showMessage(
PeerId peerId,
const SectionShow &params,
MsgId messageId) {
return false;
}
// Create a memento of that section to store it in the history stack.
// This method may modify the section ("take" heavy items).
virtual std::unique_ptr<SectionMemento> createMemento();
@ -135,7 +142,7 @@ public:
}
static void PaintBackground(
not_null<Window::SessionController*> controller,
not_null<SessionController*> controller,
not_null<QWidget*> widget,
QRect clip);
@ -150,7 +157,7 @@ protected:
// Called after the hideChildren() call in showAnimated().
virtual void showAnimatedHook(
const Window::SectionSlideParams &params) {
const SectionSlideParams &params) {
}
// Called after the showChildren() call in showFinished().

View file

@ -84,6 +84,12 @@ struct SectionShow {
Backward,
ClearStack,
};
struct OriginMessage {
FullMsgId id;
};
using Origin = std::variant<v::null_t, OriginMessage>;
SectionShow(
Way way = Way::Forward,
anim::type animated = anim::type::normal,
@ -112,6 +118,7 @@ struct SectionShow {
anim::type animated = anim::type::normal;
anim::activation activation = anim::activation::normal;
bool thirdColumn = false;
Origin origin;
};