mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Add jump-to-end button to chat preview.
This commit is contained in:
parent
40cf96202d
commit
6fce718252
4 changed files with 130 additions and 22 deletions
|
@ -189,7 +189,8 @@ rpl::producer<MessagesSlice> HistoryMessagesViewer(
|
||||||
};
|
};
|
||||||
const auto messageId = (aroundId.fullId.msg == ShowAtUnreadMsgId)
|
const auto messageId = (aroundId.fullId.msg == ShowAtUnreadMsgId)
|
||||||
? computeUnreadAroundId()
|
? computeUnreadAroundId()
|
||||||
: (aroundId.fullId.msg == ShowAtTheEndMsgId)
|
: ((aroundId.fullId.msg == ShowAtTheEndMsgId)
|
||||||
|
|| (aroundId == MaxMessagePosition))
|
||||||
? (ServerMaxMsgId - 1)
|
? (ServerMaxMsgId - 1)
|
||||||
: (aroundId.fullId.peer == history->peer->id)
|
: (aroundId.fullId.peer == history->peer->id)
|
||||||
? aroundId.fullId.msg
|
? aroundId.fullId.msg
|
||||||
|
|
|
@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_thread.h"
|
#include "data/data_thread.h"
|
||||||
#include "history/view/reactions/history_view_reactions_button.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/view/history_view_list_widget.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
#include "history/history_item.h"
|
#include "history/history_item.h"
|
||||||
|
@ -52,7 +53,8 @@ namespace {
|
||||||
|
|
||||||
class Item final
|
class Item final
|
||||||
: public Ui::Menu::ItemBase
|
: public Ui::Menu::ItemBase
|
||||||
, private HistoryView::ListDelegate {
|
, private ListDelegate
|
||||||
|
, private CornerButtonsDelegate {
|
||||||
public:
|
public:
|
||||||
Item(not_null<Ui::RpWidget*> parent, not_null<Data::Thread*> thread);
|
Item(not_null<Ui::RpWidget*> parent, not_null<Data::Thread*> thread);
|
||||||
|
|
||||||
|
@ -73,6 +75,7 @@ private:
|
||||||
void setupHistory();
|
void setupHistory();
|
||||||
void updateInnerVisibleArea();
|
void updateInnerVisibleArea();
|
||||||
|
|
||||||
|
// ListDelegate delegate.
|
||||||
Context listContext() override;
|
Context listContext() override;
|
||||||
bool listScrollTo(int top, bool syntetic = true) override;
|
bool listScrollTo(int top, bool syntetic = true) override;
|
||||||
void listCancelRequest() override;
|
void listCancelRequest() override;
|
||||||
|
@ -164,6 +167,16 @@ private:
|
||||||
std::unique_ptr<QMimeData> data,
|
std::unique_ptr<QMimeData> data,
|
||||||
Fn<void()> finished) override;
|
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<QAction*> _dummyAction;
|
||||||
const not_null<Main::Session*> _session;
|
const not_null<Main::Session*> _session;
|
||||||
const not_null<Data::Thread*> _thread;
|
const not_null<Data::Thread*> _thread;
|
||||||
|
@ -176,7 +189,8 @@ private:
|
||||||
const std::unique_ptr<Ui::ElasticScroll> _scroll;
|
const std::unique_ptr<Ui::ElasticScroll> _scroll;
|
||||||
const std::unique_ptr<Ui::FlatButton> _markRead;
|
const std::unique_ptr<Ui::FlatButton> _markRead;
|
||||||
|
|
||||||
QPointer<HistoryView::ListWidget> _inner;
|
QPointer<ListWidget> _inner;
|
||||||
|
std::unique_ptr<CornerButtons> _cornerButtons;
|
||||||
rpl::event_stream<ChatPreviewAction> _actions;
|
rpl::event_stream<ChatPreviewAction> _actions;
|
||||||
|
|
||||||
QImage _bg;
|
QImage _bg;
|
||||||
|
@ -446,11 +460,16 @@ void Item::setupHistory() {
|
||||||
this,
|
this,
|
||||||
_session,
|
_session,
|
||||||
static_cast<ListDelegate*>(this)));
|
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) {
|
_markRead->shownValue() | rpl::start_with_next([=](bool shown) {
|
||||||
const auto top = _top->height();
|
const auto top = _top->height();
|
||||||
const auto bottom = shown ? _markRead->height() : 0;
|
const auto bottom = shown ? _markRead->height() : 0;
|
||||||
_scroll->setGeometry(rect().marginsRemoved({ 0, top, 0, bottom }));
|
_scroll->setGeometry(rect().marginsRemoved({ 0, top, 0, bottom }));
|
||||||
|
_cornerButtons->updatePositions();
|
||||||
}, _markRead->lifetime());
|
}, _markRead->lifetime());
|
||||||
|
|
||||||
_scroll->scrolls(
|
_scroll->scrolls(
|
||||||
|
@ -495,6 +514,7 @@ void Item::paintEvent(QPaintEvent *e) {
|
||||||
void Item::updateInnerVisibleArea() {
|
void Item::updateInnerVisibleArea() {
|
||||||
const auto scrollTop = _scroll->scrollTop();
|
const auto scrollTop = _scroll->scrollTop();
|
||||||
_inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height());
|
_inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height());
|
||||||
|
_cornerButtons->updateJumpDownVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
Context Item::listContext() {
|
Context Item::listContext() {
|
||||||
|
@ -592,18 +612,28 @@ MessagesBarData Item::listMessagesBar(
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto skipped = false;
|
||||||
const auto hidden = _replies && (repliesTill < 2);
|
const auto hidden = _replies && (repliesTill < 2);
|
||||||
for (auto i = 0, count = int(elements.size()); i != count; ++i) {
|
for (auto i = 0, count = int(elements.size()); i != count; ++i) {
|
||||||
const auto item = elements[i]->data();
|
const auto item = elements[i]->data();
|
||||||
if (!item->isRegular()
|
if (!item->isRegular() || (_replies && !item->replyToId())) {
|
||||||
|| item->out()
|
|
||||||
|| (_replies && !item->replyToId())) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const auto inHistory = (item->history() == _history);
|
const auto inHistory = (item->history() == _history);
|
||||||
if ((_replies && item->id > repliesTill)
|
const auto unread = (_replies && item->id > repliesTill)
|
||||||
|| (migratedTill && (inHistory || item->id > migratedTill))
|
|| (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 {
|
return {
|
||||||
.bar = {
|
.bar = {
|
||||||
.element = elements[i],
|
.element = elements[i],
|
||||||
|
@ -800,6 +830,46 @@ void Item::listLaunchDrag(
|
||||||
Fn<void()> finished) {
|
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
|
} // namespace
|
||||||
|
|
||||||
ChatPreview MakeChatPreview(
|
ChatPreview MakeChatPreview(
|
||||||
|
|
|
@ -7,9 +7,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#include "history/view/history_view_corner_buttons.h"
|
#include "history/view/history_view_corner_buttons.h"
|
||||||
|
|
||||||
#include "ui/widgets/scroll_area.h"
|
|
||||||
#include "ui/chat/chat_style.h"
|
#include "ui/chat/chat_style.h"
|
||||||
#include "ui/controls/jump_down_button.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 "base/qt/qt_key_modifiers.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
#include "history/history_item.h"
|
#include "history/history_item.h"
|
||||||
|
@ -33,17 +34,41 @@ CornerButtons::CornerButtons(
|
||||||
not_null<Ui::ScrollArea*> parent,
|
not_null<Ui::ScrollArea*> parent,
|
||||||
not_null<const Ui::ChatStyle*> st,
|
not_null<const Ui::ChatStyle*> st,
|
||||||
not_null<CornerButtonsDelegate*> delegate)
|
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)
|
, _delegate(delegate)
|
||||||
, _down(
|
, _down(
|
||||||
parent,
|
parent,
|
||||||
st->value(parent->lifetime(), st::historyToDown))
|
st->value(_stLifetime, st::historyToDown))
|
||||||
, _mentions(
|
, _mentions(
|
||||||
parent,
|
parent,
|
||||||
st->value(parent->lifetime(), st::historyUnreadMentions))
|
st->value(_stLifetime, st::historyUnreadMentions))
|
||||||
, _reactions(
|
, _reactions(
|
||||||
parent,
|
parent,
|
||||||
st->value(parent->lifetime(), st::historyUnreadReactions)) {
|
st->value(_stLifetime, st::historyUnreadReactions)) {
|
||||||
_down.widget->addClickHandler([=] { downClick(); });
|
_down.widget->addClickHandler([=] { downClick(); });
|
||||||
_mentions.widget->addClickHandler([=] { mentionsClick(); });
|
_mentions.widget->addClickHandler([=] { mentionsClick(); });
|
||||||
_reactions.widget->addClickHandler([=] { reactionsClick(); });
|
_reactions.widget->addClickHandler([=] { reactionsClick(); });
|
||||||
|
@ -68,7 +93,7 @@ bool CornerButtons::eventFilter(QObject *o, QEvent *e) {
|
||||||
&& (o == _down.widget
|
&& (o == _down.widget
|
||||||
|| o == _mentions.widget
|
|| o == _mentions.widget
|
||||||
|| o == _reactions.widget)) {
|
|| o == _reactions.widget)) {
|
||||||
return _scroll->viewportEvent(e);
|
return _scrollViewportEvent(e);
|
||||||
}
|
}
|
||||||
return QObject::eventFilter(o, e);
|
return QObject::eventFilter(o, e);
|
||||||
}
|
}
|
||||||
|
@ -200,9 +225,7 @@ void CornerButtons::showAt(MsgId id) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CornerButtons::updateVisibility(
|
void CornerButtons::updateVisibility(Type type, bool shown) {
|
||||||
CornerButtonType type,
|
|
||||||
bool shown) {
|
|
||||||
auto &button = buttonByType(type);
|
auto &button = buttonByType(type);
|
||||||
if (button.shown != shown) {
|
if (button.shown != shown) {
|
||||||
button.shown = shown;
|
button.shown = shown;
|
||||||
|
@ -291,7 +314,7 @@ void CornerButtons::updatePositions() {
|
||||||
historyDownShown);
|
historyDownShown);
|
||||||
_down.widget->moveToRight(
|
_down.widget->moveToRight(
|
||||||
st::historyToDownPosition.x(),
|
st::historyToDownPosition.x(),
|
||||||
_scroll->height() - top);
|
_parent->height() - top);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const auto right = anim::interpolate(
|
const auto right = anim::interpolate(
|
||||||
|
@ -302,7 +325,7 @@ void CornerButtons::updatePositions() {
|
||||||
0,
|
0,
|
||||||
_down.widget->height() + skip,
|
_down.widget->height() + skip,
|
||||||
historyDownShown);
|
historyDownShown);
|
||||||
const auto top = _scroll->height()
|
const auto top = _parent->height()
|
||||||
- _mentions.widget->height()
|
- _mentions.widget->height()
|
||||||
- st::historyToDownPosition.y()
|
- st::historyToDownPosition.y()
|
||||||
- shift;
|
- shift;
|
||||||
|
@ -321,7 +344,7 @@ void CornerButtons::updatePositions() {
|
||||||
0,
|
0,
|
||||||
_mentions.widget->height() + skip,
|
_mentions.widget->height() + skip,
|
||||||
unreadMentionsShown);
|
unreadMentionsShown);
|
||||||
const auto top = _scroll->height()
|
const auto top = _parent->height()
|
||||||
- _reactions.widget->height()
|
- _reactions.widget->height()
|
||||||
- st::historyToDownPosition.y()
|
- st::historyToDownPosition.y()
|
||||||
- shift;
|
- shift;
|
||||||
|
@ -355,7 +378,7 @@ Fn<void(bool found)> CornerButtons::doneJumpFrom(
|
||||||
}
|
}
|
||||||
if (!found && !ignoreMessageNotFound) {
|
if (!found && !ignoreMessageNotFound) {
|
||||||
Ui::Toast::Show(
|
Ui::Toast::Show(
|
||||||
_scroll.get(),
|
_parent.get(),
|
||||||
tr::lng_message_not_found(tr::now));
|
tr::lng_message_not_found(tr::now));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,6 +17,7 @@ struct FullMsgId;
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class ChatStyle;
|
class ChatStyle;
|
||||||
class ScrollArea;
|
class ScrollArea;
|
||||||
|
class ElasticScroll;
|
||||||
class JumpDownButton;
|
class JumpDownButton;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
|
@ -61,6 +62,10 @@ public:
|
||||||
not_null<Ui::ScrollArea*> parent,
|
not_null<Ui::ScrollArea*> parent,
|
||||||
not_null<const Ui::ChatStyle*> st,
|
not_null<const Ui::ChatStyle*> st,
|
||||||
not_null<CornerButtonsDelegate*> delegate);
|
not_null<CornerButtonsDelegate*> delegate);
|
||||||
|
CornerButtons(
|
||||||
|
not_null<Ui::ElasticScroll*> parent,
|
||||||
|
not_null<const Ui::ChatStyle*> st,
|
||||||
|
not_null<CornerButtonsDelegate*> delegate);
|
||||||
|
|
||||||
using Type = CornerButtonType;
|
using Type = CornerButtonType;
|
||||||
|
|
||||||
|
@ -91,6 +96,12 @@ public:
|
||||||
bool ignoreMessageNotFound = false);
|
bool ignoreMessageNotFound = false);
|
||||||
|
|
||||||
private:
|
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;
|
bool eventFilter(QObject *o, QEvent *e) override;
|
||||||
|
|
||||||
void computeCurrentReplyReturn();
|
void computeCurrentReplyReturn();
|
||||||
|
@ -99,9 +110,12 @@ private:
|
||||||
[[nodiscard]] History *lookupHistory() const;
|
[[nodiscard]] History *lookupHistory() const;
|
||||||
void showAt(MsgId id);
|
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;
|
const not_null<CornerButtonsDelegate*> _delegate;
|
||||||
|
|
||||||
|
rpl::lifetime _stLifetime;
|
||||||
|
|
||||||
CornerButton _down;
|
CornerButton _down;
|
||||||
CornerButton _mentions;
|
CornerButton _mentions;
|
||||||
CornerButton _reactions;
|
CornerButton _reactions;
|
||||||
|
|
Loading…
Add table
Reference in a new issue