Add jump-to-end button to chat preview.

This commit is contained in:
John Preston 2024-09-05 14:40:05 +04:00
parent 40cf96202d
commit 6fce718252
4 changed files with 130 additions and 22 deletions

View file

@ -189,7 +189,8 @@ rpl::producer<MessagesSlice> HistoryMessagesViewer(
};
const auto messageId = (aroundId.fullId.msg == ShowAtUnreadMsgId)
? computeUnreadAroundId()
: (aroundId.fullId.msg == ShowAtTheEndMsgId)
: ((aroundId.fullId.msg == ShowAtTheEndMsgId)
|| (aroundId == MaxMessagePosition))
? (ServerMaxMsgId - 1)
: (aroundId.fullId.peer == history->peer->id)
? aroundId.fullId.msg

View file

@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_session.h"
#include "data/data_thread.h"
#include "history/view/reactions/history_view_reactions_button.h"
#include "history/view/history_view_corner_buttons.h"
#include "history/view/history_view_list_widget.h"
#include "history/history.h"
#include "history/history_item.h"
@ -52,7 +53,8 @@ namespace {
class Item final
: public Ui::Menu::ItemBase
, private HistoryView::ListDelegate {
, private ListDelegate
, private CornerButtonsDelegate {
public:
Item(not_null<Ui::RpWidget*> parent, not_null<Data::Thread*> thread);
@ -73,6 +75,7 @@ private:
void setupHistory();
void updateInnerVisibleArea();
// ListDelegate delegate.
Context listContext() override;
bool listScrollTo(int top, bool syntetic = true) override;
void listCancelRequest() override;
@ -164,6 +167,16 @@ private:
std::unique_ptr<QMimeData> data,
Fn<void()> finished) override;
// CornerButtonsDelegate delegate.
void cornerButtonsShowAtPosition(
Data::MessagePosition position) override;
Data::Thread *cornerButtonsThread() override;
FullMsgId cornerButtonsCurrentId() override;
bool cornerButtonsIgnoreVisibility() override;
std::optional<bool> cornerButtonsDownShown() override;
bool cornerButtonsUnreadMayBeShown() override;
bool cornerButtonsHas(CornerButtonType type) override;
const not_null<QAction*> _dummyAction;
const not_null<Main::Session*> _session;
const not_null<Data::Thread*> _thread;
@ -176,7 +189,8 @@ private:
const std::unique_ptr<Ui::ElasticScroll> _scroll;
const std::unique_ptr<Ui::FlatButton> _markRead;
QPointer<HistoryView::ListWidget> _inner;
QPointer<ListWidget> _inner;
std::unique_ptr<CornerButtons> _cornerButtons;
rpl::event_stream<ChatPreviewAction> _actions;
QImage _bg;
@ -446,11 +460,16 @@ void Item::setupHistory() {
this,
_session,
static_cast<ListDelegate*>(this)));
_cornerButtons = std::make_unique<CornerButtons>(
_scroll.get(),
_chatStyle.get(),
static_cast<CornerButtonsDelegate*>(this));
_markRead->shownValue() | rpl::start_with_next([=](bool shown) {
const auto top = _top->height();
const auto bottom = shown ? _markRead->height() : 0;
_scroll->setGeometry(rect().marginsRemoved({ 0, top, 0, bottom }));
_cornerButtons->updatePositions();
}, _markRead->lifetime());
_scroll->scrolls(
@ -495,6 +514,7 @@ void Item::paintEvent(QPaintEvent *e) {
void Item::updateInnerVisibleArea() {
const auto scrollTop = _scroll->scrollTop();
_inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height());
_cornerButtons->updateJumpDownVisibility();
}
Context Item::listContext() {
@ -592,18 +612,28 @@ MessagesBarData Item::listMessagesBar(
return {};
}
auto skipped = false;
const auto hidden = _replies && (repliesTill < 2);
for (auto i = 0, count = int(elements.size()); i != count; ++i) {
const auto item = elements[i]->data();
if (!item->isRegular()
|| item->out()
|| (_replies && !item->replyToId())) {
if (!item->isRegular() || (_replies && !item->replyToId())) {
continue;
}
const auto inHistory = (item->history() == _history);
if ((_replies && item->id > repliesTill)
const auto unread = (_replies && item->id > repliesTill)
|| (migratedTill && (inHistory || item->id > migratedTill))
|| (historyTill && inHistory && item->id > historyTill)) {
|| (historyTill && inHistory && item->id > historyTill);
if (!unread) {
skipped = true;
}
if (item->out()) {
continue;
}
if (unread) {
if (!skipped) {
// Don't show jumping unread bar if scrolling up from bottom.
return {};
}
return {
.bar = {
.element = elements[i],
@ -800,6 +830,46 @@ void Item::listLaunchDrag(
Fn<void()> finished) {
}
void Item::cornerButtonsShowAtPosition(Data::MessagePosition position) {
if (position == Data::UnreadMessagePosition) {
position = Data::MaxMessagePosition;
}
_inner->showAtPosition(
position,
{},
_cornerButtons->doneJumpFrom(position.fullId, {}, true));
}
Data::Thread *Item::cornerButtonsThread() {
return _thread;
}
FullMsgId Item::cornerButtonsCurrentId() {
return {};
}
bool Item::cornerButtonsIgnoreVisibility() {
return false;
}
std::optional<bool> Item::cornerButtonsDownShown() {
const auto top = _scroll->scrollTop() + st::historyToDownShownAfter;
if (top < _scroll->scrollTopMax()) {
return true;
} else if (_inner->loadedAtBottomKnown()) {
return !_inner->loadedAtBottom();
}
return std::nullopt;
}
bool Item::cornerButtonsUnreadMayBeShown() {
return _inner->loadedAtBottomKnown();
}
bool Item::cornerButtonsHas(CornerButtonType type) {
return (type == CornerButtonType::Down);
}
} // namespace
ChatPreview MakeChatPreview(

View file

@ -7,9 +7,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "history/view/history_view_corner_buttons.h"
#include "ui/widgets/scroll_area.h"
#include "ui/chat/chat_style.h"
#include "ui/controls/jump_down_button.h"
#include "ui/widgets/elastic_scroll.h"
#include "ui/widgets/scroll_area.h"
#include "base/qt/qt_key_modifiers.h"
#include "history/history.h"
#include "history/history_item.h"
@ -33,17 +34,41 @@ CornerButtons::CornerButtons(
not_null<Ui::ScrollArea*> parent,
not_null<const Ui::ChatStyle*> st,
not_null<CornerButtonsDelegate*> delegate)
: _scroll(parent)
: CornerButtons(
parent,
[=](QEvent *e) { return parent->viewportEvent(e); },
st,
delegate) {
}
CornerButtons::CornerButtons(
not_null<Ui::ElasticScroll*> parent,
not_null<const Ui::ChatStyle*> st,
not_null<CornerButtonsDelegate*> delegate)
: CornerButtons(
parent,
[=](QEvent *e) { return parent->viewportEvent(e); },
st,
delegate) {
}
CornerButtons::CornerButtons(
not_null<QWidget*> parent,
Fn<bool(QEvent*)> scrollViewportEvent,
not_null<const Ui::ChatStyle*> st,
not_null<CornerButtonsDelegate*> delegate)
: _parent(parent)
, _scrollViewportEvent(std::move(scrollViewportEvent))
, _delegate(delegate)
, _down(
parent,
st->value(parent->lifetime(), st::historyToDown))
st->value(_stLifetime, st::historyToDown))
, _mentions(
parent,
st->value(parent->lifetime(), st::historyUnreadMentions))
st->value(_stLifetime, st::historyUnreadMentions))
, _reactions(
parent,
st->value(parent->lifetime(), st::historyUnreadReactions)) {
st->value(_stLifetime, st::historyUnreadReactions)) {
_down.widget->addClickHandler([=] { downClick(); });
_mentions.widget->addClickHandler([=] { mentionsClick(); });
_reactions.widget->addClickHandler([=] { reactionsClick(); });
@ -68,7 +93,7 @@ bool CornerButtons::eventFilter(QObject *o, QEvent *e) {
&& (o == _down.widget
|| o == _mentions.widget
|| o == _reactions.widget)) {
return _scroll->viewportEvent(e);
return _scrollViewportEvent(e);
}
return QObject::eventFilter(o, e);
}
@ -200,9 +225,7 @@ void CornerButtons::showAt(MsgId id) {
}
}
void CornerButtons::updateVisibility(
CornerButtonType type,
bool shown) {
void CornerButtons::updateVisibility(Type type, bool shown) {
auto &button = buttonByType(type);
if (button.shown != shown) {
button.shown = shown;
@ -291,7 +314,7 @@ void CornerButtons::updatePositions() {
historyDownShown);
_down.widget->moveToRight(
st::historyToDownPosition.x(),
_scroll->height() - top);
_parent->height() - top);
}
{
const auto right = anim::interpolate(
@ -302,7 +325,7 @@ void CornerButtons::updatePositions() {
0,
_down.widget->height() + skip,
historyDownShown);
const auto top = _scroll->height()
const auto top = _parent->height()
- _mentions.widget->height()
- st::historyToDownPosition.y()
- shift;
@ -321,7 +344,7 @@ void CornerButtons::updatePositions() {
0,
_mentions.widget->height() + skip,
unreadMentionsShown);
const auto top = _scroll->height()
const auto top = _parent->height()
- _reactions.widget->height()
- st::historyToDownPosition.y()
- shift;
@ -355,7 +378,7 @@ Fn<void(bool found)> CornerButtons::doneJumpFrom(
}
if (!found && !ignoreMessageNotFound) {
Ui::Toast::Show(
_scroll.get(),
_parent.get(),
tr::lng_message_not_found(tr::now));
}
};

View file

@ -17,6 +17,7 @@ struct FullMsgId;
namespace Ui {
class ChatStyle;
class ScrollArea;
class ElasticScroll;
class JumpDownButton;
} // namespace Ui
@ -61,6 +62,10 @@ public:
not_null<Ui::ScrollArea*> parent,
not_null<const Ui::ChatStyle*> st,
not_null<CornerButtonsDelegate*> delegate);
CornerButtons(
not_null<Ui::ElasticScroll*> parent,
not_null<const Ui::ChatStyle*> st,
not_null<CornerButtonsDelegate*> delegate);
using Type = CornerButtonType;
@ -91,6 +96,12 @@ public:
bool ignoreMessageNotFound = false);
private:
CornerButtons(
not_null<QWidget*> parent,
Fn<bool(QEvent*)> scrollViewportEvent,
not_null<const Ui::ChatStyle*> st,
not_null<CornerButtonsDelegate*> delegate);
bool eventFilter(QObject *o, QEvent *e) override;
void computeCurrentReplyReturn();
@ -99,9 +110,12 @@ private:
[[nodiscard]] History *lookupHistory() const;
void showAt(MsgId id);
const not_null<Ui::ScrollArea*> _scroll;
const not_null<QWidget*> _parent;
const Fn<bool(QEvent*)> _scrollViewportEvent;
const not_null<CornerButtonsDelegate*> _delegate;
rpl::lifetime _stLifetime;
CornerButton _down;
CornerButton _mentions;
CornerButton _reactions;