Allow HistoryView::ListWidget without SessionController.

This commit is contained in:
John Preston 2024-05-02 19:39:19 +04:00
parent e5132e3fe8
commit ef2aa05197
14 changed files with 312 additions and 125 deletions

View file

@ -90,6 +90,95 @@ constexpr auto kClearUserpicsAfter = 50;
} // namespace
const crl::time ListWidget::kItemRevealDuration = crl::time(150);
WindowListDelegate::WindowListDelegate(
not_null<Window::SessionController*> window)
: _window(window) {
}
not_null<Window::SessionController*> WindowListDelegate::listWindow() {
return _window;
}
not_null<const Ui::ChatStyle*> WindowListDelegate::listChatStyle() {
return _window->chatStyle();
}
rpl::producer<bool> WindowListDelegate::listChatWideValue() {
return _window->adaptive().chatWideValue();
}
auto WindowListDelegate::listMakeReactionsManager(
QWidget *wheelEventsTarget,
Fn<void(QRect)> update)
-> std::unique_ptr<Reactions::Manager> {
return std::make_unique<Reactions::Manager>(
wheelEventsTarget,
std::move(update),
_window->cachedReactionIconFactory().createMethod());
}
void WindowListDelegate::listVisibleAreaUpdated() {
_window->floatPlayerAreaUpdated();
}
std::shared_ptr<Ui::Show> WindowListDelegate::listUiShow() {
return _window->uiShow();
}
void WindowListDelegate::listShowPollResults(
not_null<PollData*> poll,
FullMsgId context) {
_window->showPollResults(poll, context);
}
void WindowListDelegate::listCancelUploadLayer(not_null<HistoryItem*> item) {
_window->cancelUploadLayer(item);
}
bool WindowListDelegate::listAnimationsPaused() {
return _window->isGifPausedAtLeastFor(Window::GifPauseReason::Any);
}
auto WindowListDelegate::listSendingAnimation()
-> Ui::MessageSendingAnimationController * {
return &_window->sendingAnimation();
}
Ui::ChatPaintContext WindowListDelegate::listPreparePaintContext(
Ui::ChatPaintContextArgs &&args) {
return _window->preparePaintContext(std::move(args));
}
bool WindowListDelegate::listMarkingContentRead() {
return _window->widget()->markingAsRead();
}
bool WindowListDelegate::listIgnorePaintEvent(QWidget *w, QPaintEvent *e) {
return _window->contentOverlapped(w, e);
}
bool WindowListDelegate::listShowReactPremiumError(
not_null<HistoryItem*> item,
const Data::ReactionId &id) {
return Window::ShowReactPremiumError(_window, item, id);
}
void WindowListDelegate::listWindowSetInnerFocus() {
_window->widget()->setInnerFocus();
}
bool WindowListDelegate::listAllowsDragForward() {
return _window->adaptive().isOneColumn();
}
void WindowListDelegate::listLaunchDrag(
std::unique_ptr<QMimeData> data,
Fn<void()> finished) {
_window->widget()->launchDrag(std::move(data), std::move(finished));
}
ListWidget::MouseState::MouseState() : pointState(PointState::Outside) {
}
@ -104,8 +193,6 @@ ListWidget::MouseState::MouseState(
, pointState(pointState) {
}
const crl::time ListWidget::kItemRevealDuration = crl::time(150);
template <ListWidget::EnumItemsDirection direction, typename Method>
void ListWidget::enumerateItems(Method method) {
constexpr auto TopToBottom = (direction == EnumItemsDirection::TopToBottom);
@ -283,31 +370,29 @@ void ListWidget::enumerateDates(Method method) {
ListWidget::ListWidget(
QWidget *parent,
not_null<Window::SessionController*> controller,
not_null<Main::Session*> session,
not_null<ListDelegate*> delegate)
: RpWidget(parent)
, _delegate(delegate)
, _controller(controller)
, _session(session)
, _emojiInteractions(std::make_unique<EmojiInteractions>(
&controller->session(),
session,
[=](not_null<const Element*> view) { return itemTop(view); }))
, _context(_delegate->listContext())
, _itemAverageHeight(itemMinimalHeight())
, _pathGradient(
MakePathShiftGradient(
controller->chatStyle(),
_delegate->listChatStyle(),
[=] { update(); }))
, _reactionsManager(
std::make_unique<Reactions::Manager>(
this,
[=](QRect updated) { update(updated); },
controller->cachedReactionIconFactory().createMethod()))
, _reactionsManager(_delegate->listMakeReactionsManager(
this,
[=](QRect updated) { update(updated); }))
, _translateTracker(MaybeTranslateTracker(_delegate->listTranslateHistory()))
, _scrollDateCheck([this] { scrollDateCheck(); })
, _applyUpdatedScrollState([this] { applyUpdatedScrollState(); })
, _selectEnabled(_delegate->listAllowsMultiSelect())
, _highlighter(
&session().data(),
&_session->data(),
[=](const HistoryItem *item) { return viewForItem(item); },
[=](const Element *view) { repaintItem(view); })
, _touchSelectTimer([=] { onTouchSelect(); })
@ -315,25 +400,25 @@ ListWidget::ListWidget(
setAttribute(Qt::WA_AcceptTouchEvents);
setMouseTracking(true);
_scrollDateHideTimer.setCallback([this] { scrollDateHideByTimer(); });
session().data().viewRepaintRequest(
_session->data().viewRepaintRequest(
) | rpl::start_with_next([this](auto view) {
if (view->delegate() == this) {
repaintItem(view);
}
}, lifetime());
session().data().viewResizeRequest(
_session->data().viewResizeRequest(
) | rpl::start_with_next([this](auto view) {
if (view->delegate() == this) {
resizeItem(view);
}
}, lifetime());
session().data().itemViewRefreshRequest(
_session->data().itemViewRefreshRequest(
) | rpl::start_with_next([this](auto item) {
if (const auto view = viewForItem(item)) {
refreshItem(view);
}
}, lifetime());
session().data().viewLayoutChanged(
_session->data().viewLayoutChanged(
) | rpl::start_with_next([this](auto view) {
if (view->delegate() == this) {
if (view->isUnderCursor()) {
@ -341,37 +426,37 @@ ListWidget::ListWidget(
}
}
}, lifetime());
session().data().itemDataChanges(
_session->data().itemDataChanges(
) | rpl::start_with_next([=](not_null<HistoryItem*> item) {
if (const auto view = viewForItem(item)) {
view->itemDataChanged();
}
}, lifetime());
session().downloaderTaskFinished(
_session->downloaderTaskFinished(
) | rpl::start_with_next([=] {
update();
}, lifetime());
session().data().peerDecorationsUpdated(
_session->data().peerDecorationsUpdated(
) | rpl::start_with_next([=] {
update();
}, lifetime());
session().data().itemRemoved(
_session->data().itemRemoved(
) | rpl::start_with_next([=](not_null<const HistoryItem*> item) {
itemRemoved(item);
}, lifetime());
using MessageUpdateFlag = Data::MessageUpdate::Flag;
session().changes().realtimeMessageUpdates(
_session->changes().realtimeMessageUpdates(
MessageUpdateFlag::NewUnreadReaction
) | rpl::start_with_next([=](const Data::MessageUpdate &update) {
maybeMarkReactionsRead(update.item);
}, lifetime());
if (const auto history = _delegate->listTranslateHistory()) {
session().changes().historyUpdates(
_session->changes().historyUpdates(
history,
Data::HistoryUpdate::Flag::TranslatedTo
) | rpl::start_with_next([=] {
@ -379,7 +464,7 @@ ListWidget::ListWidget(
}, lifetime());
}
session().data().itemVisibilityQueries(
_session->data().itemVisibilityQueries(
) | rpl::start_with_next([=](
const Data::Session::ItemVisibilityQuery &query) {
if (const auto view = viewForItem(query.item)) {
@ -392,25 +477,27 @@ ListWidget::ListWidget(
}
}, lifetime());
_reactionsManager->chosen(
) | rpl::start_with_next([=](ChosenReaction reaction) {
_reactionsManager->updateButton({});
reactionChosen(reaction);
}, lifetime());
Reactions::SetupManagerList(
_reactionsManager.get(),
_reactionsItem.value());
Core::App().settings().cornerReactionValue(
) | rpl::start_with_next([=](bool value) {
_useCornerReaction = value;
if (!value) {
if (_reactionsManager) {
_reactionsManager->chosen(
) | rpl::start_with_next([=](ChosenReaction reaction) {
_reactionsManager->updateButton({});
}
}, lifetime());
reactionChosen(reaction);
}, lifetime());
controller->adaptive().chatWideValue(
Reactions::SetupManagerList(
_reactionsManager.get(),
_reactionsItem.value());
Core::App().settings().cornerReactionValue(
) | rpl::start_with_next([=](bool value) {
_useCornerReaction = value;
if (!value) {
_reactionsManager->updateButton({});
}
}, lifetime());
}
_delegate->listChatWideValue(
) | rpl::start_with_next([=](bool wide) {
_isChatWide = wide;
}, lifetime());
@ -427,11 +514,11 @@ ListWidget::ListWidget(
}
Main::Session &ListWidget::session() const {
return _controller->session();
return *_session;
}
not_null<Window::SessionController*> ListWidget::controller() const {
return _controller;
return _delegate->listWindow();
}
not_null<ListDelegate*> ListWidget::delegate() const {
@ -1006,7 +1093,7 @@ void ListWidget::visibleTopBottomUpdated(
} else {
scrollDateHideByTimer();
}
_controller->floatPlayerAreaUpdated();
_delegate->listVisibleAreaUpdated();
session().data().itemVisibilitiesUpdated();
_applyUpdatedScrollState.call();
@ -1439,7 +1526,7 @@ bool ListWidget::showCopyRestriction(HistoryItem *item) {
if (type == CopyRestrictionType::None) {
return false;
}
_controller->showToast((type == CopyRestrictionType::Channel)
_delegate->listUiShow()->showToast((type == CopyRestrictionType::Channel)
? tr::lng_error_nocopy_channel(tr::now)
: tr::lng_error_nocopy_group(tr::now));
return true;
@ -1450,7 +1537,7 @@ bool ListWidget::showCopyMediaRestriction(not_null<HistoryItem*> item) {
if (type == CopyRestrictionType::None) {
return false;
}
_controller->showToast((type == CopyRestrictionType::Channel)
_delegate->listUiShow()->showToast((type == CopyRestrictionType::Channel)
? tr::lng_error_nocopy_channel(tr::now)
: tr::lng_error_nocopy_group(tr::now));
return true;
@ -1676,7 +1763,7 @@ void ListWidget::elementStartStickerLoop(not_null<const Element*> view) {
void ListWidget::elementShowPollResults(
not_null<PollData*> poll,
FullMsgId context) {
_controller->showPollResults(poll, context);
_delegate->listShowPollResults(poll, context);
}
void ListWidget::elementOpenPhoto(
@ -1694,7 +1781,7 @@ void ListWidget::elementOpenDocument(
void ListWidget::elementCancelUpload(const FullMsgId &context) {
if (const auto item = session().data().message(context)) {
_controller->cancelUploadLayer(item);
_delegate->listCancelUploadLayer(item);
}
}
@ -1706,7 +1793,7 @@ void ListWidget::elementShowTooltip(
}
bool ListWidget::elementAnimationsPaused() {
return _controller->isGifPausedAtLeastFor(Window::GifPauseReason::Any);
return _delegate->listAnimationsPaused();
}
bool ListWidget::elementHideReply(not_null<const Element*> view) {
@ -1838,8 +1925,8 @@ void ListWidget::startItemRevealAnimations() {
void ListWidget::startMessageSendingAnimation(
not_null<HistoryItem*> item) {
auto &sendingAnimation = controller()->sendingAnimation();
if (!sendingAnimation.checkExpectedType(item)) {
const auto sendingAnimation = _delegate->listSendingAnimation();
if (!sendingAnimation || !sendingAnimation->checkExpectedType(item)) {
return;
}
@ -1855,7 +1942,7 @@ void ListWidget::startMessageSendingAnimation(
return mapToGlobal(QPoint(0, itemTop(view) - additional));
});
sendingAnimation.startAnimation({
sendingAnimation->startAnimation({
.globalEndTopLeft = std::move(globalEndTopLeft),
.view = [=] { return viewForItem(item); },
.paintContext = [=] { return preparePaintContext({}); },
@ -2010,7 +2097,7 @@ TextSelection ListWidget::itemRenderSelection(
Ui::ChatPaintContext ListWidget::preparePaintContext(
const QRect &clip) const {
return controller()->preparePaintContext({
return _delegate->listPreparePaintContext({
.theme = _delegate->listChatTheme(),
.clip = clip,
.visibleAreaPositionGlobal = mapToGlobal(QPoint(0, _visibleTop)),
@ -2022,7 +2109,7 @@ Ui::ChatPaintContext ListWidget::preparePaintContext(
bool ListWidget::markingContentsRead() const {
return _showFinished
&& !_refreshingViewer
&& controller()->widget()->markingAsRead();
&& _delegate->listMarkingContentRead();
}
bool ListWidget::markingMessagesRead() const {
@ -2053,12 +2140,9 @@ void ListWidget::checkActivation() {
}
void ListWidget::paintEvent(QPaintEvent *e) {
if ((_context != Context::ShortcutMessages)
&& _controller->contentOverlapped(this, e)) {
if (_delegate->listIgnorePaintEvent(this, e)) {
return;
}
if (_translateTracker) {
} else if (_translateTracker) {
_translateTracker->startBunch();
}
auto readTill = (HistoryItem*)nullptr;
@ -2100,20 +2184,25 @@ void ListWidget::paintEvent(QPaintEvent *e) {
_delegate->listPaintEmpty(p, context);
return;
}
_reactionsManager->startEffectsCollection();
if (_reactionsManager) {
_reactionsManager->startEffectsCollection();
}
const auto session = &controller()->session();
const auto session = &this->session();
auto top = itemTop(from->get());
context = context.translated(0, -top);
p.translate(0, top);
const auto &sendingAnimation = _controller->sendingAnimation();
const auto sendingAnimation = _delegate->listSendingAnimation();
for (auto i = from; i != to; ++i) {
const auto view = *i;
const auto item = view->data();
const auto height = view->height();
if (!sendingAnimation.hasAnimatedMessage(item)) {
context.reactionInfo
= _reactionsManager->currentReactionPaintInfo();
if (!sendingAnimation
|| !sendingAnimation->hasAnimatedMessage(item)) {
if (_reactionsManager) {
context.reactionInfo
= _reactionsManager->currentReactionPaintInfo();
}
context.outbg = view->hasOutLayout();
context.selection = itemRenderSelection(view);
context.highlight = _highlighter.state(item);
@ -2125,17 +2214,19 @@ void ListWidget::paintEvent(QPaintEvent *e) {
const auto isSponsored = item->isSponsored();
const auto isUnread = _delegate->listElementShownUnread(view)
&& item->isRegular();
const auto withReaction = item->hasUnreadReaction();
const auto withReaction = context.reactionInfo
&& item->hasUnreadReaction();
const auto yShown = [&](int y) {
return (_visibleBottom >= y && _visibleTop <= y);
};
const auto markShown = isSponsored
? view->markSponsoredViewed(_visibleBottom - top)
: withReaction
? yShown(top + context.reactionInfo->position.y())
: isUnread
? yShown(top + height)
: yShown(top + height / 2);
const auto markShown = (_context != Context::ChatPreview)
&& (isSponsored
? view->markSponsoredViewed(_visibleBottom - top)
: withReaction
? yShown(top + context.reactionInfo->position.y())
: isUnread
? yShown(top + height)
: yShown(top + height / 2));
if (markShown) {
if (isSponsored) {
session->sponsoredMessages().view(item->fullId());
@ -2157,9 +2248,11 @@ void ListWidget::paintEvent(QPaintEvent *e) {
if (item->hasExtendedMediaPreview()) {
session->api().views().pollExtendedMedia(item);
}
_reactionsManager->recordCurrentReactionEffect(
item->fullId(),
QPoint(0, top));
if (_reactionsManager) {
_reactionsManager->recordCurrentReactionEffect(
item->fullId(),
QPoint(0, top));
}
top += height;
context.translate(0, -height);
p.translate(0, height);
@ -2170,7 +2263,9 @@ void ListWidget::paintEvent(QPaintEvent *e) {
paintUserpics(p, context, clip);
paintDates(p, context, clip);
_reactionsManager->paint(p, context);
if (_reactionsManager) {
_reactionsManager->paint(p, context);
}
_emojiInteractions->paint(p);
}
@ -2181,7 +2276,7 @@ void ListWidget::paintUserpics(
if (_context == Context::ShortcutMessages) {
return;
}
const auto session = &controller()->session();
const auto session = &this->session();
enumerateUserpics([&](not_null<Element*> view, int userpicTop) {
// stop the enumeration if the userpic is below the painted rect
if (userpicTop >= clip.top() + clip.height()) {
@ -2530,7 +2625,7 @@ void ListWidget::toggleFavoriteReaction(not_null<Element*> view) const {
Data::LookupPossibleReactions(item).recent,
favorite,
&Data::Reaction::id)
|| Window::ShowReactPremiumError(_controller, item, favorite)) {
|| _delegate->listShowReactPremiumError(item, favorite)) {
return;
} else if (!ranges::contains(item->chosenReactions(), favorite)) {
if (const auto top = itemTop(view); top >= 0) {
@ -2599,6 +2694,7 @@ void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
if (link
&& !link->property(
kSendReactionEmojiProperty).value<Data::ReactionId>().empty()
&& _reactionsManager
&& _reactionsManager->showContextMenu(
this,
e,
@ -2624,13 +2720,13 @@ void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
this,
overItem,
clickedReaction,
_controller,
controller(),
_whoReactedMenuLifetime);
e->accept();
return;
}
auto request = ContextMenuRequest(_controller);
auto request = ContextMenuRequest(controller());
request.link = link;
request.view = _overElement;
@ -2666,12 +2762,12 @@ void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
const auto attached = reactItem
? AttachSelectorToMenu(
_menu.get(),
_controller,
controller(),
desiredPosition,
reactItem,
[=](ChosenReaction reaction) { reactionChosen(reaction); },
ItemReactionsAbout(reactItem),
_controller->cachedReactionIconFactory().createMethod())
controller()->cachedReactionIconFactory().createMethod())
: AttachSelectorResult::Skipped;
if (attached == AttachSelectorResult::Failed) {
_menu = nullptr;
@ -2688,10 +2784,7 @@ void ListWidget::reactionChosen(ChosenReaction reaction) {
const auto item = session().data().message(reaction.context);
if (!item) {
return;
} else if (Window::ShowReactPremiumError(
_controller,
item,
reaction.id)) {
} else if (_delegate->listShowReactPremiumError(item, reaction.id)) {
if (_menu) {
_menu->hideMenu();
}
@ -2945,7 +3038,9 @@ void ListWidget::enterEventHook(QEnterEvent *e) {
}
void ListWidget::leaveEventHook(QEvent *e) {
_reactionsManager->updateButton({ .cursorLeft = true });
if (_reactionsManager) {
_reactionsManager->updateButton({ .cursorLeft = true });
}
if (const auto view = _overElement) {
if (_overState.pointState != PointState::Outside) {
repaintItem(view);
@ -3160,9 +3255,9 @@ void ListWidget::mouseActionStart(
const auto pressElement = _overElement;
_mouseAction = MouseAction::None;
_pressWasInactive = Ui::WasInactivePress(_controller->widget());
_pressWasInactive = Ui::WasInactivePress(window());
if (_pressWasInactive) {
Ui::MarkInactivePress(_controller->widget(), false);
Ui::MarkInactivePress(window(), false);
}
if (ClickHandler::getPressed()) {
@ -3334,7 +3429,7 @@ void ListWidget::mouseActionFinish(
} else if (_selectedTextItem && !_pressWasInactive) {
if (_selectedTextRange.from == _selectedTextRange.to) {
clearTextSelection();
_controller->widget()->setInnerFocus();
_delegate->listWindowSetInnerFocus();
}
}
}
@ -3362,7 +3457,7 @@ ClickHandlerContext ListWidget::prepareClickHandlerContext(FullMsgId id) {
? (ElementDelegate*)weak
: nullptr;
},
.sessionWindow = base::make_weak(_controller),
.sessionWindow = base::make_weak(controller()),
};
}
@ -3372,7 +3467,9 @@ void ListWidget::mouseActionUpdate() {
std::clamp(mousePosition.x(), 0, width()),
std::clamp(mousePosition.y(), _visibleTop, _visibleBottom));
const auto reactionState = _reactionsManager->buttonTextState(point);
const auto reactionState = _reactionsManager
? _reactionsManager->buttonTextState(point)
: TextState();
const auto reactionItem = session().data().message(reactionState.itemId);
const auto reactionView = viewForItem(reactionItem);
const auto view = reactionView
@ -3392,12 +3489,14 @@ void ListWidget::mouseActionUpdate() {
_overElement = view;
repaintItem(_overElement);
}
_reactionsManager->updateButton(view
? reactionButtonParameters(
view,
itemPoint,
reactionState)
: Reactions::ButtonParameters());
if (_reactionsManager) {
_reactionsManager->updateButton(view
? reactionButtonParameters(
view,
itemPoint,
reactionState)
: Reactions::ButtonParameters());
}
if (viewChanged && view) {
_reactionsItem = item;
}
@ -3624,7 +3723,7 @@ std::unique_ptr<QMimeData> ListWidget::prepareDrag() {
if (!urls.isEmpty()) {
mimeData->setUrls(urls);
}
if (uponSelected && !_controller->adaptive().isOneColumn()) {
if (uponSelected && !_delegate->listAllowsDragForward()) {
const auto canForwardAll = [&] {
for (const auto &[itemId, data] : _selected) {
if (!data.canForward) {
@ -3689,8 +3788,10 @@ std::unique_ptr<QMimeData> ListWidget::prepareDrag() {
void ListWidget::performDrag() {
if (auto mimeData = prepareDrag()) {
// This call enters event loop and can destroy any QObject.
_reactionsManager->updateButton({});
_controller->widget()->launchDrag(
if (_reactionsManager) {
_reactionsManager->updateButton({});
}
_delegate->listLaunchDrag(
std::move(mimeData),
crl::guard(this, [=] { mouseActionUpdate(QCursor::pos()); }));
}
@ -3708,7 +3809,10 @@ void ListWidget::repaintItem(const Element *view) {
const auto range = view->verticalRepaintRange();
update(0, top + range.top, width(), range.height);
const auto id = view->data()->fullId();
if (const auto area = _reactionsManager->lookupEffectArea(id)) {
const auto area = _reactionsManager
? _reactionsManager->lookupEffectArea(id)
: std::nullopt;
if (area) {
update(*area);
}
}
@ -3866,7 +3970,9 @@ void ListWidget::itemRemoved(not_null<const HistoryItem*> item) {
viewReplaced(view, nullptr);
_views.erase(i);
_reactionsManager->remove(item->fullId());
if (_reactionsManager) {
_reactionsManager->remove(item->fullId());
}
updateItemsGeometry();
}
@ -3992,7 +4098,7 @@ void ConfirmDeleteSelectedItems(not_null<ListWidget*> widget) {
}
}
auto box = Box<DeleteMessagesBox>(
&widget->controller()->session(),
&widget->session(),
widget->getSelectedIds());
box->setDeleteConfirmedCallback(crl::guard(widget, [=] {
widget->cancelSelection();

View file

@ -25,11 +25,14 @@ class Session;
} // namespace Main
namespace Ui {
class Show;
class PopupMenu;
class ChatTheme;
struct ChatPaintContext;
struct ChatPaintContextArgs;
enum class TouchScrollState;
struct PeerUserpicView;
class MessageSendingAnimationController;
} // namespace Ui
namespace Window {
@ -40,6 +43,7 @@ namespace Data {
struct Group;
struct Reaction;
struct AllowedReactions;
struct ReactionId;
} // namespace Data
namespace HistoryView::Reactions {
@ -154,6 +158,71 @@ public:
virtual History *listTranslateHistory() = 0;
virtual void listAddTranslatedItems(
not_null<TranslateTracker*> tracker) = 0;
// Methods that use Window::SessionController by default.
virtual not_null<Window::SessionController*> listWindow() = 0;
virtual not_null<const Ui::ChatStyle*> listChatStyle() = 0;
virtual rpl::producer<bool> listChatWideValue() = 0;
virtual std::unique_ptr<Reactions::Manager> listMakeReactionsManager(
QWidget *wheelEventsTarget,
Fn<void(QRect)> update) = 0;
virtual void listVisibleAreaUpdated() = 0;
virtual std::shared_ptr<Ui::Show> listUiShow() = 0;
virtual void listShowPollResults(
not_null<PollData*> poll,
FullMsgId context) = 0;
virtual void listCancelUploadLayer(not_null<HistoryItem*> item) = 0;
virtual bool listAnimationsPaused() = 0;
virtual auto listSendingAnimation()
-> Ui::MessageSendingAnimationController* = 0;
virtual Ui::ChatPaintContext listPreparePaintContext(
Ui::ChatPaintContextArgs &&args) = 0;
virtual bool listMarkingContentRead() = 0;
virtual bool listIgnorePaintEvent(QWidget *w, QPaintEvent *e) = 0;
virtual bool listShowReactPremiumError(
not_null<HistoryItem*> item,
const Data::ReactionId &id) = 0;
virtual void listWindowSetInnerFocus() = 0;
virtual bool listAllowsDragForward() = 0;
virtual void listLaunchDrag(
std::unique_ptr<QMimeData> data,
Fn<void()> finished) = 0;
};
class WindowListDelegate : public ListDelegate {
public:
explicit WindowListDelegate(not_null<Window::SessionController*> window);
not_null<Window::SessionController*> listWindow() override;
not_null<const Ui::ChatStyle*> listChatStyle() override;
rpl::producer<bool> listChatWideValue() override;
std::unique_ptr<Reactions::Manager> listMakeReactionsManager(
QWidget *wheelEventsTarget,
Fn<void(QRect)> update) override;
void listVisibleAreaUpdated() override;
std::shared_ptr<Ui::Show> listUiShow() override;
void listShowPollResults(
not_null<PollData*> poll,
FullMsgId context) override;
void listCancelUploadLayer(not_null<HistoryItem*> item) override;
bool listAnimationsPaused() override;
Ui::MessageSendingAnimationController *listSendingAnimation() override;
Ui::ChatPaintContext listPreparePaintContext(
Ui::ChatPaintContextArgs &&args) override;
bool listMarkingContentRead() override;
bool listIgnorePaintEvent(QWidget *w, QPaintEvent *e) override;
bool listShowReactPremiumError(
not_null<HistoryItem*> item,
const Data::ReactionId &id) override;
void listWindowSetInnerFocus() override;
bool listAllowsDragForward() override;
void listLaunchDrag(
std::unique_ptr<QMimeData> data,
Fn<void()> finished) override;
private:
const not_null<Window::SessionController*> _window;
};
struct SelectionData {
@ -211,7 +280,7 @@ class ListWidget final
public:
ListWidget(
QWidget *parent,
not_null<Window::SessionController*> controller,
not_null<Main::Session*> session,
not_null<ListDelegate*> delegate);
static const crl::time kItemRevealDuration;
@ -648,7 +717,7 @@ private:
static constexpr auto kMinimalIdsLimit = 24;
const not_null<ListDelegate*> _delegate;
const not_null<Window::SessionController*> _controller;
const not_null<Main::Session*> _session;
const std::unique_ptr<EmojiInteractions> _emojiInteractions;
const Context _context;

View file

@ -94,6 +94,7 @@ PinnedWidget::PinnedWidget(
not_null<Window::SessionController*> controller,
not_null<Data::Thread*> thread)
: Window::SectionWidget(parent, controller, thread->peer())
, WindowListDelegate(controller)
, _thread(thread->migrateToOrMe())
, _history(thread->owningHistory())
, _migratedPeer(thread->asHistory()
@ -161,7 +162,7 @@ PinnedWidget::PinnedWidget(
_inner = _scroll->setOwnedWidget(object_ptr<ListWidget>(
this,
controller,
&controller->session(),
static_cast<ListDelegate*>(this)));
_scroll->move(0, _topBar->height());
_scroll->show();

View file

@ -36,7 +36,7 @@ class TranslateBar;
class PinnedWidget final
: public Window::SectionWidget
, private ListDelegate
, private WindowListDelegate
, private CornerButtonsDelegate {
public:
PinnedWidget(

View file

@ -205,6 +205,7 @@ RepliesWidget::RepliesWidget(
not_null<History*> history,
MsgId rootId)
: Window::SectionWidget(parent, controller, history->peer)
, WindowListDelegate(controller)
, _history(history)
, _rootId(rootId)
, _root(lookupRoot())
@ -299,7 +300,7 @@ RepliesWidget::RepliesWidget(
_inner = _scroll->setOwnedWidget(object_ptr<ListWidget>(
this,
controller,
&controller->session(),
static_cast<ListDelegate*>(this)));
_scroll->move(0, _topBar->height());
_scroll->show();

View file

@ -71,7 +71,7 @@ class TranslateBar;
class RepliesWidget final
: public Window::SectionWidget
, private ListDelegate
, private WindowListDelegate
, private CornerButtonsDelegate {
public:
RepliesWidget(

View file

@ -97,6 +97,7 @@ ScheduledWidget::ScheduledWidget(
not_null<History*> history,
const Data::ForumTopic *forumTopic)
: Window::SectionWidget(parent, controller, history->peer)
, WindowListDelegate(controller)
, _history(history)
, _forumTopic(forumTopic)
, _scroll(
@ -167,7 +168,7 @@ ScheduledWidget::ScheduledWidget(
_inner = _scroll->setOwnedWidget(object_ptr<ListWidget>(
this,
controller,
&controller->session(),
static_cast<ListDelegate*>(this)));
_scroll->move(0, _topBar->height());
_scroll->show();

View file

@ -52,7 +52,7 @@ class StickerToast;
class ScheduledWidget final
: public Window::SectionWidget
, private ListDelegate
, private WindowListDelegate
, private CornerButtonsDelegate {
public:
ScheduledWidget(

View file

@ -67,6 +67,7 @@ SublistWidget::SublistWidget(
not_null<Window::SessionController*> controller,
not_null<Data::SavedSublist*> sublist)
: Window::SectionWidget(parent, controller, sublist->peer())
, WindowListDelegate(controller)
, _sublist(sublist)
, _history(sublist->owner().history(sublist->session().user()))
, _topBar(this, controller)
@ -133,7 +134,7 @@ SublistWidget::SublistWidget(
_inner = _scroll->setOwnedWidget(object_ptr<ListWidget>(
this,
controller,
&controller->session(),
static_cast<ListDelegate*>(this)));
_scroll->move(0, _topBar->height());
_scroll->show();

View file

@ -37,7 +37,7 @@ class ComposeSearch;
class SublistWidget final
: public Window::SectionWidget
, private ListDelegate
, private WindowListDelegate
, private CornerButtonsDelegate {
public:
SublistWidget(

View file

@ -72,7 +72,7 @@ using namespace HistoryView;
class ShortcutMessages
: public AbstractSection
, private ListDelegate
, private WindowListDelegate
, private CornerButtonsDelegate {
public:
ShortcutMessages(
@ -164,6 +164,7 @@ private:
History *listTranslateHistory() override;
void listAddTranslatedItems(
not_null<TranslateTracker*> tracker) override;
bool listIgnorePaintEvent(QWidget *w, QPaintEvent *e) override;
// CornerButtonsDelegate delegate.
void cornerButtonsShowAtPosition(
@ -330,6 +331,7 @@ ShortcutMessages::ShortcutMessages(
rpl::producer<Container> containerValue,
BusinessShortcutId shortcutId)
: AbstractSection(parent)
, WindowListDelegate(controller)
, _controller(controller)
, _session(&controller->session())
, _scroll(scroll)
@ -370,7 +372,7 @@ ShortcutMessages::ShortcutMessages(
_inner = Ui::CreateChild<ListWidget>(
this,
controller,
&controller->session(),
static_cast<ListDelegate*>(this));
_inner->overrideIsChatWide(false);
@ -1053,6 +1055,10 @@ void ShortcutMessages::listAddTranslatedItems(
not_null<TranslateTracker*> tracker) {
}
bool ShortcutMessages::listIgnorePaintEvent(QWidget *w, QPaintEvent *e) {
return false;
}
void ShortcutMessages::cornerButtonsShowAtPosition(
Data::MessagePosition position) {
showAtPosition(position);

View file

@ -223,6 +223,14 @@ struct ChatPaintContext {
};
struct ChatPaintContextArgs {
not_null<ChatTheme*> theme;
QRect clip;
QPoint visibleAreaPositionGlobal;
int visibleAreaTop = 0;
int visibleAreaWidth = 0;
};
[[nodiscard]] int HistoryServiceMsgRadius();
[[nodiscard]] int HistoryServiceMsgInvertedRadius();
[[nodiscard]] int HistoryServiceMsgInvertedShrink();

View file

@ -2951,7 +2951,7 @@ void SessionController::openPeerStories(
}
HistoryView::PaintContext SessionController::preparePaintContext(
PaintContextArgs &&args) {
Ui::ChatPaintContextArgs &&args) {
const auto visibleAreaTopLocal = content()->mapFromGlobal(
args.visibleAreaPositionGlobal).y();
const auto viewport = QRect(

View file

@ -64,6 +64,7 @@ struct ChatThemeBackground;
struct ChatThemeBackgroundData;
class MessageSendingAnimationController;
struct BoostCounters;
struct ChatPaintContextArgs;
} // namespace Ui
namespace Data {
@ -586,15 +587,8 @@ public:
PeerId peerId,
std::optional<Data::StorySourcesList> list = std::nullopt);
struct PaintContextArgs {
not_null<Ui::ChatTheme*> theme;
QRect clip;
QPoint visibleAreaPositionGlobal;
int visibleAreaTop = 0;
int visibleAreaWidth = 0;
};
[[nodiscard]] Ui::ChatPaintContext preparePaintContext(
PaintContextArgs &&args);
Ui::ChatPaintContextArgs &&args);
[[nodiscard]] not_null<const Ui::ChatStyle*> chatStyle() const {
return _chatStyle.get();
}