diff --git a/Telegram/SourceFiles/auth_session.h b/Telegram/SourceFiles/auth_session.h index 1599a66f3..d67675671 100644 --- a/Telegram/SourceFiles/auth_session.h +++ b/Telegram/SourceFiles/auth_session.h @@ -63,6 +63,16 @@ public: base::Observable> &repaintLogEntry() { return _repaintLogEntry; } + base::Observable &pendingHistoryResize() { + return _pendingHistoryResize; + } + struct ItemVisibilityQuery { + gsl::not_null item; + gsl::not_null isVisible; + }; + base::Observable &queryItemVisibility() { + return _queryItemVisibility; + } void copyFrom(const AuthSessionData &other) { _variables = other._variables; @@ -139,6 +149,8 @@ private: base::Observable _savedGifsUpdated; base::Observable> _historyCleared; base::Observable> _repaintLogEntry; + base::Observable _pendingHistoryResize; + base::Observable _queryItemVisibility; Variables _variables; TimeMs _lastTimeVideoPlayedAt = 0; diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index ca17f1085..2215999ad 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -25,6 +25,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "mainwindow.h" #include "mainwidget.h" #include "messenger.h" +#include "auth_session.h" #include "boxes/confirm_box.h" #include "layerwidget.h" #include "lang/lang_keys.h" @@ -368,9 +369,8 @@ void historyMuteUpdated(History *history) { } void handlePendingHistoryUpdate() { - if (auto main = App::main()) { - main->notify_handlePendingHistoryUpdate(); - } + AuthSession::Current().data().pendingHistoryResize().notify(true); + for (auto item : base::take(Global::RefPendingRepaintItems())) { Ui::repaintHistoryItem(item); diff --git a/Telegram/SourceFiles/history/history_admin_log_inner.cpp b/Telegram/SourceFiles/history/history_admin_log_inner.cpp index 2fa9c13f6..6b0542886 100644 --- a/Telegram/SourceFiles/history/history_admin_log_inner.cpp +++ b/Telegram/SourceFiles/history/history_admin_log_inner.cpp @@ -22,7 +22,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "styles/style_history.h" #include "history/history_media_types.h" -#include "history/history_admin_log_item.h" #include "history/history_admin_log_section.h" #include "mainwindow.h" #include "window/window_controller.h" @@ -46,9 +45,18 @@ InnerWidget::InnerWidget(QWidget *parent, gsl::not_null con setMouseTracking(true); _scrollDateHideTimer.setCallback([this] { scrollDateHideByTimer(); }); subscribe(AuthSession::Current().data().repaintLogEntry(), [this](gsl::not_null historyItem) { - auto it = _itemsByHistoryItems.find(historyItem); - if (it != _itemsByHistoryItems.cend()) { - repaintItem(it->second); + if (_history == historyItem->history()) { + repaintItem(historyItem); + } + }); + subscribe(AuthSession::Current().data().pendingHistoryResize(), [this] { handlePendingHistoryResize(); }); + subscribe(AuthSession::Current().data().queryItemVisibility(), [this](const AuthSessionData::ItemVisibilityQuery &query) { + if (_history != query.item->history() || !query.item->isLogEntry() || !isVisible()) { + return; + } + auto top = itemTop(query.item); + if (top >= 0 && top + query.item->height() > _visibleTop && top < _visibleBottom) { + *query.isVisible = true; } }); } @@ -64,11 +72,11 @@ void InnerWidget::setVisibleTopBottom(int visibleTop, int visibleBottom) { void InnerWidget::updateVisibleTopItem() { auto start = std::rbegin(_items), end = std::rend(_items); auto from = std::upper_bound(start, end, _visibleTop, [](int top, auto &elem) { - return top <= elem->top() + elem->height(); + return top <= elem->y() + elem->height(); }); if (from != end) { - _visibleTopItem = from->get(); - _visibleTopFromItem = _visibleTop - _visibleTopItem->top(); + _visibleTopItem = *from; + _visibleTopFromItem = _visibleTop - _visibleTopItem->y(); } else { _visibleTopItem = nullptr; _visibleTopFromItem = _visibleTop; @@ -144,13 +152,15 @@ void InnerWidget::applyFilter(MTPDchannelAdminLogEventsFilter::Flags flags, cons QString InnerWidget::tooltipText() const { if (_mouseCursorState == HistoryInDateCursorState && _mouseAction == MouseAction::None) { - if (_itemOver) { - auto dateText = _itemOver->date().toString(QLocale::system().dateTimeFormat(QLocale::LongFormat)); + if (auto item = App::hoveredItem()) { + auto dateText = item->date.toString(QLocale::system().dateTimeFormat(QLocale::LongFormat)); return dateText; } } else if (_mouseCursorState == HistoryInForwardedCursorState && _mouseAction == MouseAction::None) { - if (_itemOver) { - auto forwarded = _itemOver->getForwardedInfoText(); + if (auto item = App::hoveredItem()) { + if (auto forwarded = item->Get()) { + return forwarded->_text.originalText(AllTextSelection, ExpandLinksNone); + } } } else if (auto lnk = ClickHandler::getActive()) { return lnk->tooltip(); @@ -226,11 +236,26 @@ void InnerWidget::preloadMore(Direction direction) { _items.reserve(_items.size() + events.size()); for_const (auto &event, events) { t_assert(event.type() == mtpc_channelAdminLogEvent); - _items.push_back(std::make_unique(_history, _idManager, event.c_channelAdminLogEvent())); + auto &data = event.c_channelAdminLogEvent(); + auto count = 0; + GenerateItems(_history, _idManager, data, [this, id = data.vid.v, &count](HistoryItemOwned item) { + _items.push_back(std::move(item)); + _itemsByIds.emplace(id, item.get()); + ++count; + }); + if (count > 1) { + // Reverse the inner order of the added messages, because we load events + // from bottom to top but inside one event they go from top to bottom. + auto full = _items.size(); + auto from = full - count; + for (auto i = 0, toReverse = count / 2; i != toReverse; ++i) { + std::swap(_items[from + i], _items[full - i - 1]); + } + } } if (!_items.empty()) { - _maxId = _items.front()->id(); - _minId = _items.back()->id(); + _maxId = (--_itemsByIds.end())->first; + _minId = _itemsByIds.begin()->first; if (_minId == 1) { _upLoaded = true; } @@ -262,7 +287,7 @@ int InnerWidget::resizeGetHeight(int newWidth) { auto newHeight = 0; for (auto &item : base::reversed(_items)) { - item->setTop(newHeight); + item->setY(newHeight); newHeight += item->resizeGetHeight(newWidth); } _itemsHeight = newHeight; @@ -357,7 +382,10 @@ void InnerWidget::enterEventHook(QEvent *e) { } void InnerWidget::leaveEventHook(QEvent *e) { - repaintItem(base::take(_itemOver)); + if (auto item = App::hoveredItem()) { + repaintItem(item); + App::hoveredItem(nullptr); + } ClickHandler::clearActive(); Ui::Tooltip::Hide(); if (!ClickHandler::getPressed() && _cursor != style::cur_default) { @@ -372,14 +400,14 @@ void InnerWidget::mouseActionStart(const QPoint &screenPos, Qt::MouseButton butt if (button != Qt::LeftButton) return; ClickHandler::pressed(); - if (_itemPressed != _itemOver) { - repaintItem(_itemPressed); - _itemPressed = _itemOver; - repaintItem(_itemPressed); + if (App::pressedItem() != App::hoveredItem()) { + repaintItem(App::pressedItem()); + App::pressedItem(App::hoveredItem()); + repaintItem(App::pressedItem()); } _mouseAction = MouseAction::None; - _mouseActionItem = _itemNearest; + _mouseActionItem = App::mousedItem(); _dragStartPosition = mapPointToItem(mapFromGlobal(screenPos), _mouseActionItem); _pressWasInactive = _controller->window()->wasInactivePress(); if (_pressWasInactive) _controller->window()->setInactivePress(false); @@ -392,7 +420,7 @@ void InnerWidget::mouseActionStart(const QPoint &screenPos, Qt::MouseButton butt if (_trippleClickTimer.isActive() && (screenPos - _trippleClickPoint).manhattanLength() < QApplication::startDragDistance()) { HistoryStateRequest request; request.flags = Text::StateRequest::Flag::LookupSymbol; - dragState = _mouseActionItem->getState(_dragStartPosition, request).data; + dragState = _mouseActionItem->getState(_dragStartPosition, request); if (dragState.cursor == HistoryInTextCursorState) { auto selection = TextSelection { dragState.symbol, dragState.symbol }; repaintItem(std::exchange(_selectedItem, _mouseActionItem)); @@ -403,13 +431,13 @@ void InnerWidget::mouseActionStart(const QPoint &screenPos, Qt::MouseButton butt mouseActionUpdate(_mousePosition); _trippleClickTimer.callOnce(QApplication::doubleClickInterval()); } - } else if (_itemPressed) { + } else if (App::pressedItem()) { HistoryStateRequest request; request.flags = Text::StateRequest::Flag::LookupSymbol; - dragState = _mouseActionItem->getState(_dragStartPosition, request).data; + dragState = _mouseActionItem->getState(_dragStartPosition, request); } if (_mouseSelectType != TextSelectType::Paragraphs) { - if (_itemPressed) { + if (App::pressedItem()) { _mouseTextSymbol = dragState.symbol; auto uponSelected = (dragState.cursor == HistoryInTextCursorState); if (uponSelected) { @@ -422,16 +450,16 @@ void InnerWidget::mouseActionStart(const QPoint &screenPos, Qt::MouseButton butt if (uponSelected) { _mouseAction = MouseAction::PrepareDrag; // start text drag } else if (!_pressWasInactive) { - //if (dynamic_cast(_itemPressed->getMedia())) { - // _mouseAction = MouseAction::PrepareDrag; // start sticker drag or by-date drag - //} else { // TODO + if (dynamic_cast(App::pressedItem()->getMedia())) { + _mouseAction = MouseAction::PrepareDrag; // start sticker drag or by-date drag + } else { if (dragState.afterSymbol) ++_mouseTextSymbol; auto selection = TextSelection { _mouseTextSymbol, _mouseTextSymbol }; repaintItem(std::exchange(_selectedItem, _mouseActionItem)); _selectedText = selection; _mouseAction = MouseAction::Selecting; repaintItem(_mouseActionItem); - //} // TODO + } } } } @@ -464,7 +492,10 @@ void InnerWidget::mouseActionFinish(const QPoint &screenPos, Qt::MouseButton but if (_mouseAction == MouseAction::Dragging) { activated.clear(); } - repaintItem(base::take(_itemPressed)); + if (App::pressedItem()) { + repaintItem(App::pressedItem()); + App::pressedItem(nullptr); + } _wasSelectedText = false; @@ -504,26 +535,27 @@ void InnerWidget::updateSelected() { auto from = (point.y() >= _itemsTop && point.y() < _itemsTop + _itemsHeight) ? std::upper_bound(start, end, point.y(), [this](int top, auto &elem) { return top <= itemTop(elem.get()) + elem->height(); }) : end; - if (from != end) { - _itemNearest = from->get(); - itemPoint = mapPointToItem(point, _itemNearest); - if (_itemNearest->hasPoint(itemPoint)) { - if (_itemOver != _itemNearest) { - repaintItem(std::exchange(_itemOver, _itemNearest)); - repaintItem(_itemNearest); + auto item = (from != end) ? from->get() : nullptr; + if (item) { + App::mousedItem(item); + itemPoint = mapPointToItem(point, item); + if (item->hasPoint(itemPoint)) { + if (App::hoveredItem() != item) { + repaintItem(App::hoveredItem()); + App::hoveredItem(item); + repaintItem(App::hoveredItem()); } - } else { - repaintItem(base::take(_itemOver)); + } else if (App::hoveredItem()) { + repaintItem(App::hoveredItem()); + App::hoveredItem(nullptr); } - } else { - _itemNearest = nullptr; } - Item::TextState dragState; + HistoryTextState dragState; ClickHandlerHost *lnkhost = nullptr; - auto selectingText = (_itemNearest == _mouseActionItem && _itemNearest == _itemOver && _selectedItem); - if (_itemNearest) { - if (_itemNearest != _mouseActionItem || (itemPoint - _dragStartPosition).manhattanLength() >= QApplication::startDragDistance()) { + auto selectingText = (item == _mouseActionItem && item == App::hoveredItem() && _selectedItem); + if (item) { + if (item != _mouseActionItem || (itemPoint - _dragStartPosition).manhattanLength() >= QApplication::startDragDistance()) { if (_mouseAction == MouseAction::PrepareDrag) { _mouseAction = MouseAction::Dragging; InvokeQueued(this, [this] { performDrag(); }); @@ -579,60 +611,60 @@ void InnerWidget::updateSelected() { // } // return true; //}); // TODO - if (!dragState.data.link) { + if (!dragState.link) { HistoryStateRequest request; if (_mouseAction == MouseAction::Selecting) { request.flags |= Text::StateRequest::Flag::LookupSymbol; } else { selectingText = false; } - dragState = _itemNearest->getState(itemPoint, request); - lnkhost = dragState.handler; - if (!dragState.data.link && itemPoint.x() >= st::historyPhotoLeft && itemPoint.x() < st::historyPhotoLeft + st::msgPhotoSize) { - //if (auto msg = item->toHistoryMessage()) { - // if (msg->hasFromPhoto()) { - // enumerateUserpics([&dragState, &lnkhost, &point](HistoryMessage *message, int userpicTop) -> bool { - // // stop enumeration if the userpic is below our point - // if (userpicTop > point.y()) { - // return false; - // } + dragState = item->getState(itemPoint, request); + lnkhost = item; + if (!dragState.link && itemPoint.x() >= st::historyPhotoLeft && itemPoint.x() < st::historyPhotoLeft + st::msgPhotoSize) { + if (auto msg = item->toHistoryMessage()) { + if (msg->hasFromPhoto()) { + //enumerateUserpics([&dragState, &lnkhost, &point](HistoryMessage *message, int userpicTop) -> bool { + // // stop enumeration if the userpic is below our point + // if (userpicTop > point.y()) { + // return false; + // } - // // stop enumeration if we've found a userpic under the cursor - // if (point.y() >= userpicTop && point.y() < userpicTop + st::msgPhotoSize) { - // dragState.link = message->from()->openLink(); - // lnkhost = message; - // return false; - // } - // return true; - // }); - // } - //} // TODO + // // stop enumeration if we've found a userpic under the cursor + // if (point.y() >= userpicTop && point.y() < userpicTop + st::msgPhotoSize) { + // dragState.link = message->from()->openLink(); + // lnkhost = message; + // return false; + // } + // return true; + //}); // TODO + } + } } } } - auto lnkChanged = ClickHandler::setActive(dragState.data.link, lnkhost); - if (lnkChanged || dragState.data.cursor != _mouseCursorState) { + auto lnkChanged = ClickHandler::setActive(dragState.link, lnkhost); + if (lnkChanged || dragState.cursor != _mouseCursorState) { Ui::Tooltip::Hide(); } - if (dragState.data.link || dragState.data.cursor == HistoryInDateCursorState || dragState.data.cursor == HistoryInForwardedCursorState) { + if (dragState.link || dragState.cursor == HistoryInDateCursorState || dragState.cursor == HistoryInForwardedCursorState) { Ui::Tooltip::Show(1000, this); } auto cursor = style::cur_default; if (_mouseAction == MouseAction::None) { - _mouseCursorState = dragState.data.cursor; - if (dragState.data.link) { + _mouseCursorState = dragState.cursor; + if (dragState.link) { cursor = style::cur_pointer; } else if (_mouseCursorState == HistoryInTextCursorState) { cursor = style::cur_text; } else if (_mouseCursorState == HistoryInDateCursorState) { // cursor = style::cur_cross; } - } else if (_itemNearest) { + } else if (item) { if (_mouseAction == MouseAction::Selecting) { if (selectingText) { - auto second = dragState.data.symbol; - if (dragState.data.afterSymbol && _mouseSelectType == TextSelectType::Letters) { + auto second = dragState.symbol; + if (dragState.afterSymbol && _mouseSelectType == TextSelectType::Letters) { ++second; } auto selection = _mouseActionItem->adjustSelection({ qMin(second, _mouseTextSymbol), qMax(second, _mouseTextSymbol) }, _mouseSelectType); @@ -656,9 +688,13 @@ void InnerWidget::updateSelected() { } // Voice message seek support. - if (_itemPressed) { - auto adjustedPoint = mapPointToItem(point, _itemPressed); - _itemPressed->updatePressed(adjustedPoint); + if (auto pressedItem = App::pressedLinkItem()) { + if (!pressedItem->detached()) { + if (pressedItem->history() == _history) { + auto adjustedPoint = mapPointToItem(point, pressedItem); + pressedItem->updatePressed(adjustedPoint); + } + } } //if (_mouseAction == MouseAction::Selecting) { @@ -763,24 +799,31 @@ void InnerWidget::performDrag() { //} // TODO } -int InnerWidget::itemTop(gsl::not_null item) const { - return _itemsTop + item->top(); +int InnerWidget::itemTop(gsl::not_null item) const { + return _itemsTop + item->y(); } -void InnerWidget::repaintItem(Item *item) { +void InnerWidget::repaintItem(const HistoryItem *item) { if (!item) { return; } update(0, itemTop(item), width(), item->height()); } -QPoint InnerWidget::mapPointToItem(QPoint point, Item *item) const { +QPoint InnerWidget::mapPointToItem(QPoint point, const HistoryItem *item) const { if (!item) { return QPoint(); } return point - QPoint(0, itemTop(item)); } +void InnerWidget::handlePendingHistoryResize() { + if (_history->hasPendingResizedItems()) { + _history->resizeGetHeight(width()); + updateSize(); + } +} + InnerWidget::~InnerWidget() = default; } // namespace AdminLog diff --git a/Telegram/SourceFiles/history/history_admin_log_inner.h b/Telegram/SourceFiles/history/history_admin_log_inner.h index d93b76d1d..eb4fe4ed0 100644 --- a/Telegram/SourceFiles/history/history_admin_log_inner.h +++ b/Telegram/SourceFiles/history/history_admin_log_inner.h @@ -20,6 +20,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #pragma once +#include "history/history_admin_log_item.h" #include "ui/widgets/tooltip.h" #include "mtproto/sender.h" #include "base/timer.h" @@ -35,7 +36,6 @@ class Controller; namespace AdminLog { class SectionMemento; -class Item; class LocalIdManager { public: @@ -118,9 +118,10 @@ private: void mouseActionCancel(); void updateSelected(); void performDrag(); - int itemTop(gsl::not_null item) const; - void repaintItem(Item *item); - QPoint mapPointToItem(QPoint point, Item *item) const; + int itemTop(gsl::not_null item) const; + void repaintItem(const HistoryItem *item); + QPoint mapPointToItem(QPoint point, const HistoryItem *item) const; + void handlePendingHistoryResize(); void checkPreloadMore(); void updateVisibleTopItem(); @@ -142,8 +143,8 @@ private: gsl::not_null _history; base::lambda _cancelledCallback; base::lambda _scrollTo; - std::vector> _items; - std::map, gsl::not_null, std::less<>> _itemsByHistoryItems; + std::vector _items; + std::map _itemsByIds; int _itemsTop = 0; int _itemsHeight = 0; @@ -151,14 +152,14 @@ private: int _minHeight = 0; int _visibleTop = 0; int _visibleBottom = 0; - Item *_visibleTopItem = nullptr; + HistoryItem *_visibleTopItem = nullptr; int _visibleTopFromItem = 0; bool _scrollDateShown = false; Animation _scrollDateOpacity; SingleQueuedInvokation _scrollDateCheck; base::Timer _scrollDateHideTimer; - Item *_scrollDateLastItem = nullptr; + HistoryItem *_scrollDateLastItem = nullptr; int _scrollDateLastItemTop = 0; ClickHandlerPtr _scrollDateLink; @@ -174,15 +175,12 @@ private: TextSelectType _mouseSelectType = TextSelectType::Letters; QPoint _dragStartPosition; QPoint _mousePosition; - Item *_mouseActionItem = nullptr; + HistoryItem *_mouseActionItem = nullptr; HistoryCursorState _mouseCursorState = HistoryDefaultCursorState; uint16 _mouseTextSymbol = 0; bool _pressWasInactive = false; - Item *_itemNearest = nullptr; - Item *_itemOver = nullptr; - Item *_itemPressed = nullptr; - Item *_selectedItem = nullptr; + HistoryItem *_selectedItem = nullptr; TextSelection _selectedText; bool _wasSelectedText = false; // was some text selected in current drag action Qt::CursorShape _cursor = style::cur_default; diff --git a/Telegram/SourceFiles/history/history_admin_log_item.cpp b/Telegram/SourceFiles/history/history_admin_log_item.cpp index 01a7fec65..c02cb70a8 100644 --- a/Telegram/SourceFiles/history/history_admin_log_item.cpp +++ b/Telegram/SourceFiles/history/history_admin_log_item.cpp @@ -20,6 +20,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #include "history/history_admin_log_item.h" +#include "history/history_admin_log_inner.h" #include "lang/lang_keys.h" #include "messenger.h" @@ -233,35 +234,39 @@ TextWithEntities GenerateParticipantChangeText(gsl::not_null chann } // namespace -Item::Item(gsl::not_null history, LocalIdManager &idManager, const MTPDchannelAdminLogEvent &event) -: _id(event.vid.v) -, _date(::date(event.vdate)) -, _history(history) -, _from(App::user(event.vuser_id.v)) { +void GenerateItems(gsl::not_null history, LocalIdManager &idManager, const MTPDchannelAdminLogEvent &event, base::lambda callback) { + Expects(history->peer->isChannel()); + + auto id = event.vid.v; + auto from = App::user(event.vuser_id.v); + auto channel = history->peer->asChannel(); auto &action = event.vaction; auto date = event.vdate; + auto addPart = [&callback](gsl::not_null item) { + return callback(HistoryItemOwned(item)); + }; using ServiceFlag = MTPDmessageService::Flag; using Flag = MTPDmessage::Flag; - auto fromName = App::peerName(_from); - auto fromLink = _from->openLink(); + auto fromName = App::peerName(from); + auto fromLink = peerOpenClickHandler(from); auto fromLinkText = textcmdLink(1, fromName); - auto addSimpleServiceMessage = [this, &idManager, date, fromLink](const QString &text, PhotoData *photo = nullptr) { + auto addSimpleServiceMessage = [&](const QString &text, PhotoData *photo = nullptr) { auto message = HistoryService::PreparedText { text }; message.links.push_back(fromLink); - addPart(HistoryService::create(_history, idManager.next(), ::date(date), message, 0, peerToUser(_from->id), photo)); + addPart(HistoryService::create(history, idManager.next(), ::date(date), message, 0, peerToUser(from->id), photo)); }; - auto createChangeTitle = [this, addSimpleServiceMessage, fromLinkText](const MTPDchannelAdminLogEventActionChangeTitle &action) { - auto text = (channel()->isMegagroup() ? lng_action_changed_title : lng_admin_log_changed_title_channel)(lt_from, fromLinkText, lt_title, qs(action.vnew_value)); + auto createChangeTitle = [&](const MTPDchannelAdminLogEventActionChangeTitle &action) { + auto text = (channel->isMegagroup() ? lng_action_changed_title : lng_admin_log_changed_title_channel)(lt_from, fromLinkText, lt_title, qs(action.vnew_value)); addSimpleServiceMessage(text); }; - auto createChangeAbout = [this, &idManager, date, addSimpleServiceMessage, fromLinkText](const MTPDchannelAdminLogEventActionChangeAbout &action) { + auto createChangeAbout = [&](const MTPDchannelAdminLogEventActionChangeAbout &action) { auto newValue = qs(action.vnew_value); auto oldValue = qs(action.vprev_value); - auto text = (channel()->isMegagroup() + auto text = (channel->isMegagroup() ? (newValue.isEmpty() ? lng_admin_log_removed_description_group : lng_admin_log_changed_description_group) : (newValue.isEmpty() ? lng_admin_log_removed_description_channel : lng_admin_log_changed_description_channel) )(lt_from, fromLinkText); @@ -271,18 +276,18 @@ Item::Item(gsl::not_null history, LocalIdManager &idManager, const MTP auto bodyReplyTo = 0; auto bodyViaBotId = 0; auto newDescription = PrepareText(newValue, QString()); - auto body = HistoryMessage::create(_history, idManager.next(), bodyFlags, bodyReplyTo, bodyViaBotId, ::date(date), peerToUser(_from->id), newDescription); + auto body = HistoryMessage::create(history, idManager.next(), bodyFlags, bodyReplyTo, bodyViaBotId, ::date(date), peerToUser(from->id), newDescription); if (!oldValue.isEmpty()) { auto oldDescription = PrepareText(oldValue, QString()); - body->addLogEntryOriginal(_id, lang(lng_admin_log_previous_description), oldDescription); + body->addLogEntryOriginal(id, lang(lng_admin_log_previous_description), oldDescription); } addPart(body); }; - auto createChangeUsername = [this, &idManager, date, addSimpleServiceMessage, fromLinkText](const MTPDchannelAdminLogEventActionChangeUsername &action) { + auto createChangeUsername = [&](const MTPDchannelAdminLogEventActionChangeUsername &action) { auto newValue = qs(action.vnew_value); auto oldValue = qs(action.vprev_value); - auto text = (channel()->isMegagroup() + auto text = (channel->isMegagroup() ? (newValue.isEmpty() ? lng_admin_log_removed_link_group : lng_admin_log_changed_link_group) : (newValue.isEmpty() ? lng_admin_log_removed_link_channel : lng_admin_log_changed_link_channel) )(lt_from, fromLinkText); @@ -292,44 +297,44 @@ Item::Item(gsl::not_null history, LocalIdManager &idManager, const MTP auto bodyReplyTo = 0; auto bodyViaBotId = 0; auto newLink = newValue.isEmpty() ? TextWithEntities() : PrepareText(Messenger::Instance().createInternalLinkFull(newValue), QString()); - auto body = HistoryMessage::create(_history, idManager.next(), bodyFlags, bodyReplyTo, bodyViaBotId, ::date(date), peerToUser(_from->id), newLink); + auto body = HistoryMessage::create(history, idManager.next(), bodyFlags, bodyReplyTo, bodyViaBotId, ::date(date), peerToUser(from->id), newLink); if (!oldValue.isEmpty()) { auto oldLink = PrepareText(Messenger::Instance().createInternalLinkFull(oldValue), QString()); - body->addLogEntryOriginal(_id, lang(lng_admin_log_previous_link), oldLink); + body->addLogEntryOriginal(id, lang(lng_admin_log_previous_link), oldLink); } addPart(body); }; - auto createChangePhoto = [this, date, addSimpleServiceMessage, fromLinkText](const MTPDchannelAdminLogEventActionChangePhoto &action) { + auto createChangePhoto = [&](const MTPDchannelAdminLogEventActionChangePhoto &action) { t_assert(action.vnew_photo.type() == mtpc_chatPhoto); - auto photo = GenerateChatPhoto(channel()->bareId(), _id, date, action.vnew_photo.c_chatPhoto()); + auto photo = GenerateChatPhoto(channel->bareId(), id, date, action.vnew_photo.c_chatPhoto()); - auto text = (channel()->isMegagroup() ? lng_admin_log_changed_photo_group : lng_admin_log_changed_photo_channel)(lt_from, fromLinkText); + auto text = (channel->isMegagroup() ? lng_admin_log_changed_photo_group : lng_admin_log_changed_photo_channel)(lt_from, fromLinkText); addSimpleServiceMessage(text, photo); }; - auto createToggleInvites = [this, addSimpleServiceMessage, fromLinkText](const MTPDchannelAdminLogEventActionToggleInvites &action) { + auto createToggleInvites = [&](const MTPDchannelAdminLogEventActionToggleInvites &action) { auto enabled = (action.vnew_value.type() == mtpc_boolTrue); auto text = (enabled ? lng_admin_log_invites_enabled : lng_admin_log_invites_disabled)(lt_from, fromLinkText); addSimpleServiceMessage(text); }; - auto createToggleSignatures = [this, addSimpleServiceMessage, fromLinkText](const MTPDchannelAdminLogEventActionToggleSignatures &action) { + auto createToggleSignatures = [&](const MTPDchannelAdminLogEventActionToggleSignatures &action) { auto enabled = (action.vnew_value.type() == mtpc_boolTrue); auto text = (enabled ? lng_admin_log_signatures_enabled : lng_admin_log_signatures_disabled)(lt_from, fromLinkText); addSimpleServiceMessage(text); }; - auto createUpdatePinned = [this, &idManager, date, addSimpleServiceMessage, fromLinkText](const MTPDchannelAdminLogEventActionUpdatePinned &action) { + auto createUpdatePinned = [&](const MTPDchannelAdminLogEventActionUpdatePinned &action) { auto text = lng_admin_log_pinned_message(lt_from, fromLinkText); addSimpleServiceMessage(text); auto applyServiceAction = false; auto detachExistingItem = false; - addPart(_history->createItem(PrepareLogMessage(action.vmessage, idManager.next(), date.v), applyServiceAction, detachExistingItem)); + addPart(history->createItem(PrepareLogMessage(action.vmessage, idManager.next(), date.v), applyServiceAction, detachExistingItem)); }; - auto createEditMessage = [this, &idManager, date, addSimpleServiceMessage, fromLinkText](const MTPDchannelAdminLogEventActionEditMessage &action) { + auto createEditMessage = [&](const MTPDchannelAdminLogEventActionEditMessage &action) { auto newValue = ExtractEditedText(action.vnew_message); auto canHaveCaption = MediaCanHaveCaption(action.vnew_message); auto text = (canHaveCaption @@ -341,54 +346,54 @@ Item::Item(gsl::not_null history, LocalIdManager &idManager, const MTP auto oldValue = ExtractEditedText(action.vprev_message); auto applyServiceAction = false; auto detachExistingItem = false; - auto body = _history->createItem(PrepareLogMessage(action.vnew_message, idManager.next(), date.v), applyServiceAction, detachExistingItem); + auto body = history->createItem(PrepareLogMessage(action.vnew_message, idManager.next(), date.v), applyServiceAction, detachExistingItem); if (!oldValue.text.isEmpty()) { - body->addLogEntryOriginal(_id, lang(canHaveCaption ? lng_admin_log_previous_caption : lng_admin_log_previous_message), oldValue); + body->addLogEntryOriginal(id, lang(canHaveCaption ? lng_admin_log_previous_caption : lng_admin_log_previous_message), oldValue); } addPart(body); }; - auto createDeleteMessage = [this, &idManager, date, addSimpleServiceMessage, fromLinkText](const MTPDchannelAdminLogEventActionDeleteMessage &action) { + auto createDeleteMessage = [&](const MTPDchannelAdminLogEventActionDeleteMessage &action) { auto text = lng_admin_log_deleted_message(lt_from, fromLinkText); addSimpleServiceMessage(text); auto applyServiceAction = false; auto detachExistingItem = false; - addPart(_history->createItem(PrepareLogMessage(action.vmessage, idManager.next(), date.v), applyServiceAction, detachExistingItem)); + addPart(history->createItem(PrepareLogMessage(action.vmessage, idManager.next(), date.v), applyServiceAction, detachExistingItem)); }; - auto createParticipantJoin = [this, &idManager, addSimpleServiceMessage, fromLinkText]() { + auto createParticipantJoin = [&]() { auto text = lng_admin_log_participant_joined(lt_from, fromLinkText); addSimpleServiceMessage(text); }; - auto createParticipantLeave = [this, &idManager, addSimpleServiceMessage, fromLinkText]() { + auto createParticipantLeave = [&]() { auto text = lng_admin_log_participant_left(lt_from, fromLinkText); addSimpleServiceMessage(text); }; - auto createParticipantInvite = [this, &idManager, date](const MTPDchannelAdminLogEventActionParticipantInvite &action) { + auto createParticipantInvite = [&](const MTPDchannelAdminLogEventActionParticipantInvite &action) { auto bodyFlags = Flag::f_entities | Flag::f_from_id; auto bodyReplyTo = 0; auto bodyViaBotId = 0; - auto bodyText = GenerateParticipantChangeText(channel(), action.vparticipant); - addPart(HistoryMessage::create(_history, idManager.next(), bodyFlags, bodyReplyTo, bodyViaBotId, ::date(date), peerToUser(_from->id), bodyText)); + auto bodyText = GenerateParticipantChangeText(channel, action.vparticipant); + addPart(HistoryMessage::create(history, idManager.next(), bodyFlags, bodyReplyTo, bodyViaBotId, ::date(date), peerToUser(from->id), bodyText)); }; - auto createParticipantToggleBan = [this, &idManager, date](const MTPDchannelAdminLogEventActionParticipantToggleBan &action) { + auto createParticipantToggleBan = [&](const MTPDchannelAdminLogEventActionParticipantToggleBan &action) { auto bodyFlags = Flag::f_entities | Flag::f_from_id; auto bodyReplyTo = 0; auto bodyViaBotId = 0; - auto bodyText = GenerateParticipantChangeText(channel(), action.vnew_participant, &action.vprev_participant); - addPart(HistoryMessage::create(_history, idManager.next(), bodyFlags, bodyReplyTo, bodyViaBotId, ::date(date), peerToUser(_from->id), bodyText)); + auto bodyText = GenerateParticipantChangeText(channel, action.vnew_participant, &action.vprev_participant); + addPart(HistoryMessage::create(history, idManager.next(), bodyFlags, bodyReplyTo, bodyViaBotId, ::date(date), peerToUser(from->id), bodyText)); }; - auto createParticipantToggleAdmin = [this, &idManager, date](const MTPDchannelAdminLogEventActionParticipantToggleAdmin &action) { + auto createParticipantToggleAdmin = [&](const MTPDchannelAdminLogEventActionParticipantToggleAdmin &action) { auto bodyFlags = Flag::f_entities | Flag::f_from_id; auto bodyReplyTo = 0; auto bodyViaBotId = 0; - auto bodyText = GenerateParticipantChangeText(channel(), action.vnew_participant, &action.vprev_participant); - addPart(HistoryMessage::create(_history, idManager.next(), bodyFlags, bodyReplyTo, bodyViaBotId, ::date(date), peerToUser(_from->id), bodyText)); + auto bodyText = GenerateParticipantChangeText(channel, action.vnew_participant, &action.vprev_participant); + addPart(HistoryMessage::create(history, idManager.next(), bodyFlags, bodyReplyTo, bodyViaBotId, ::date(date), peerToUser(from->id), bodyText)); }; switch (action.type()) { @@ -410,78 +415,4 @@ Item::Item(gsl::not_null history, LocalIdManager &idManager, const MTP } } -void Item::addPart(HistoryItem *item) { - _parts.push_back(item); -} - -int Item::resizeGetHeight(int newWidth) { - _height = 0; - for (auto part : _parts) { - _height += part->resizeGetHeight(newWidth); - } - return _height; -} - -void Item::draw(Painter &p, QRect clip, TextSelection selection, TimeMs ms) { - auto top = 0; - for (auto part : _parts) { - auto height = part->height(); - if (clip.top() < top + height && clip.top() + clip.height() > top) { - p.translate(0, top); - part->draw(p, clip.translated(0, -top), selection, ms); - p.translate(0, -top); - } - top += height; - } -} - -bool Item::hasPoint(QPoint point) const { - auto top = 0; - for (auto part : _parts) { - auto height = part->height(); - if (point.y() >= top && point.y() < top + height) { - return part->hasPoint(point - QPoint(0, top)); - } - top += height; - } - return false; -} - -Item::TextState Item::getState(QPoint point, HistoryStateRequest request) const { - auto top = 0; - for (auto part : _parts) { - auto height = part->height(); - if (point.y() >= top && point.y() < top + height) { - auto result = TextState(); - result.data = part->getState(point - QPoint(0, top), request); - result.handler = part; - return result; - } - top += height; - } - return Item::TextState(); -} - -TextSelection Item::adjustSelection(TextSelection selection, TextSelectType type) const { - return selection; -} - -void Item::updatePressed(QPoint point) { -} - -QString Item::getForwardedInfoText() const { - for (auto part : _parts) { - if (auto forwarded = part->Get()) { - return forwarded->_text.originalText(AllTextSelection, ExpandLinksNone); - } - } - return QString(); -} - -Item::~Item() { - for (auto part : _parts) { - part->destroy(); - } -} - } // namespace AdminLog diff --git a/Telegram/SourceFiles/history/history_admin_log_item.h b/Telegram/SourceFiles/history/history_admin_log_item.h index 58a069bfc..cd617884d 100644 --- a/Telegram/SourceFiles/history/history_admin_log_item.h +++ b/Telegram/SourceFiles/history/history_admin_log_item.h @@ -20,59 +20,44 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #pragma once -#include "history/history_admin_log_inner.h" - namespace AdminLog { -class Item { +class HistoryItemOwned; +class LocalIdManager; + +void GenerateItems(gsl::not_null history, LocalIdManager &idManager, const MTPDchannelAdminLogEvent &event, base::lambda callback); + +// Smart pointer wrapper for HistoryItem* that destroys the owned item. +class HistoryItemOwned { public: - struct TextState { - HistoryTextState data; - ClickHandlerHost *handler = nullptr; - }; - - Item(gsl::not_null history, LocalIdManager &idManager, const MTPDchannelAdminLogEvent &event); - - uint64 id() const { - return _id; + explicit HistoryItemOwned(gsl::not_null data) : _data(data) { } - QDateTime date() const { - return _date; + HistoryItemOwned(const HistoryItemOwned &other) = delete; + HistoryItemOwned &operator=(const HistoryItemOwned &other) = delete; + HistoryItemOwned(HistoryItemOwned &&other) : _data(base::take(other._data)) { } - int top() const { - return _top; + HistoryItemOwned &operator=(HistoryItemOwned &&other) { + _data = base::take(other._data); + return *this; } - void setTop(int top) { - _top = top; - } - int height() const { - return _height; + ~HistoryItemOwned() { + if (_data) { + _data->destroy(); + } } - int resizeGetHeight(int newWidth); - void draw(Painter &p, QRect clip, TextSelection selection, TimeMs ms); - bool hasPoint(QPoint point) const; - TextState getState(QPoint point, HistoryStateRequest request) const; - TextSelection adjustSelection(TextSelection selection, TextSelectType type) const; - void updatePressed(QPoint point); - - QString getForwardedInfoText() const; - - ~Item(); + HistoryItem *get() const { + return _data; + } + HistoryItem *operator->() const { + return get(); + } + operator HistoryItem*() const { + return get(); + } private: - gsl::not_null channel() { - return _history->peer->asChannel(); - } - void addPart(HistoryItem *item); - - uint64 _id = 0; - QDateTime _date; - gsl::not_null _history; - gsl::not_null _from; - std::vector _parts; - int _top = 0; - int _height = 0; + HistoryItem *_data = nullptr; }; diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 311e7249f..030bfd199 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -780,7 +780,7 @@ void HistoryInner::touchScrollUpdated(const QPoint &screenPos) { touchUpdateSpeed(); } -QPoint HistoryInner::mapMouseToItem(QPoint p, HistoryItem *item) { +QPoint HistoryInner::mapPointToItem(QPoint p, HistoryItem *item) { int32 msgy = itemTop(item); if (msgy < 0) return QPoint(0, 0); @@ -809,7 +809,7 @@ void HistoryInner::mouseActionStart(const QPoint &screenPos, Qt::MouseButton but _mouseAction = MouseAction::None; _mouseActionItem = App::mousedItem(); - _dragStartPosition = mapMouseToItem(mapFromGlobal(screenPos), _mouseActionItem); + _dragStartPosition = mapPointToItem(mapFromGlobal(screenPos), _mouseActionItem); _pressWasInactive = _controller->window()->wasInactivePress(); if (_pressWasInactive) _controller->window()->setInactivePress(false); @@ -1037,7 +1037,7 @@ void HistoryInner::mouseActionFinish(const QPoint &screenPos, Qt::MouseButton bu // if we are in selecting items mode perhaps we want to // toggle selection instead of activating the pressed link if (_mouseAction == MouseAction::PrepareDrag && !_pressWasInactive && !_selected.isEmpty() && _selected.cbegin().value() == FullSelection && button != Qt::RightButton) { - if (HistoryMedia *media = pressed->getMedia()) { + if (auto media = pressed->getMedia()) { if (media->toggleSelectionByHandlerClick(activated)) { activated.clear(); } @@ -1174,7 +1174,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { uint16 selFrom = _selected.cbegin().value().from, selTo = _selected.cbegin().value().to; hasSelected = (selTo > selFrom) ? 1 : 0; if (App::mousedItem() && App::mousedItem() == App::hoveredItem()) { - QPoint mousePos(mapMouseToItem(mapFromGlobal(_mousePosition), App::mousedItem())); + auto mousePos = mapPointToItem(mapFromGlobal(_mousePosition), App::mousedItem()); HistoryStateRequest request; request.flags |= Text::StateRequest::Flag::LookupSymbol; auto dragState = App::mousedItem()->getState(mousePos, request); @@ -2006,7 +2006,7 @@ void HistoryInner::onUpdateSelected() { item = block->items[_curItem]; App::mousedItem(item); - m = mapMouseToItem(point, item); + m = mapPointToItem(point, item); if (item->hasPoint(m)) { if (App::hoveredItem() != item) { repaintItem(App::hoveredItem()); @@ -2208,7 +2208,7 @@ void HistoryInner::onUpdateSelected() { if (auto pressedItem = App::pressedLinkItem()) { if (!pressedItem->detached()) { if (pressedItem->history() == _history || pressedItem->history() == _migrated) { - auto adjustedPoint = mapMouseToItem(point, pressedItem); + auto adjustedPoint = mapPointToItem(point, pressedItem); pressedItem->updatePressed(adjustedPoint); } } diff --git a/Telegram/SourceFiles/history/history_inner_widget.h b/Telegram/SourceFiles/history/history_inner_widget.h index 1374d0ffb..de11669df 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.h +++ b/Telegram/SourceFiles/history/history_inner_widget.h @@ -45,7 +45,7 @@ public: TextWithEntities getSelectedText() const; void touchScrollUpdated(const QPoint &screenPos); - QPoint mapMouseToItem(QPoint p, HistoryItem *item); + QPoint mapPointToItem(QPoint p, HistoryItem *item); void recountHeight(); void updateSize(); diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index f1292a114..d33a4338c 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -724,34 +724,31 @@ void HistoryItem::detachFast() { } void HistoryItem::previousItemChanged() { + Expects(!isLogEntry()); recountDisplayDate(); recountAttachToPrevious(); } // Called only if there is no more next item! Not always when it changes! void HistoryItem::nextItemChanged() { + Expects(!isLogEntry()); setAttachToNext(false); } void HistoryItem::recountAttachToPrevious() { - bool attach = false; + Expects(!isLogEntry()); + auto attachToPrevious = false; if (auto previous = previousItem()) { if (!Has() && !Has()) { - attach = !isPost() && !previous->isPost() + attachToPrevious = !isPost() && !previous->isPost() && !serviceMsg() && !previous->serviceMsg() && !isEmpty() && !previous->isEmpty() && previous->from() == from() && (qAbs(previous->date.secsTo(date)) < kAttachMessageToPreviousSecondsDelta); } - previous->setAttachToNext(attach); - } - if (attach && !(_flags & MTPDmessage_ClientFlag::f_attach_to_previous)) { - _flags |= MTPDmessage_ClientFlag::f_attach_to_previous; - setPendingInitDimensions(); - } else if (!attach && (_flags & MTPDmessage_ClientFlag::f_attach_to_previous)) { - _flags &= ~MTPDmessage_ClientFlag::f_attach_to_previous; - setPendingInitDimensions(); + previous->setAttachToNext(attachToPrevious); } + setAttachToPrevious(attachToPrevious); } void HistoryItem::setAttachToNext(bool attachToNext) { @@ -764,6 +761,16 @@ void HistoryItem::setAttachToNext(bool attachToNext) { } } +void HistoryItem::setAttachToPrevious(bool attachToPrevious) { + if (attachToPrevious && !(_flags & MTPDmessage_ClientFlag::f_attach_to_previous)) { + _flags |= MTPDmessage_ClientFlag::f_attach_to_previous; + setPendingInitDimensions(); + } else if (!attachToPrevious && (_flags & MTPDmessage_ClientFlag::f_attach_to_previous)) { + _flags &= ~MTPDmessage_ClientFlag::f_attach_to_previous; + setPendingInitDimensions(); + } +} + void HistoryItem::setId(MsgId newId) { history()->changeMsgId(id, newId); id = newId; @@ -954,6 +961,8 @@ bool HistoryItem::unread() const { void HistoryItem::destroyUnreadBar() { if (Has()) { + t_assert(!isLogEntry()); + RemoveComponents(HistoryMessageUnreadBar::Bit()); setPendingInitDimensions(); if (_history->unreadBar == this) { @@ -965,6 +974,7 @@ void HistoryItem::destroyUnreadBar() { } void HistoryItem::setUnreadBarCount(int count) { + Expects(!isLogEntry()); if (count > 0) { HistoryMessageUnreadBar *bar; if (!Has()) { @@ -988,6 +998,7 @@ void HistoryItem::setUnreadBarCount(int count) { } void HistoryItem::setUnreadBarFreezed() { + Expects(!isLogEntry()); if (auto bar = Get()) { bar->_freezed = true; } @@ -1010,14 +1021,14 @@ void HistoryItem::clipCallback(Media::Clip::Notification notification) { case NotificationReinit: { auto stopped = false; if (reader->autoPausedGif()) { - if (auto m = App::main()) { - if (!m->isItemVisible(this)) { // stop animation if it is not visible - media->stopInline(); - if (auto document = media->getDocument()) { // forget data from memory - document->forget(); - } - stopped = true; + auto amVisible = false; + AuthSession::Current().data().queryItemVisibility().notify({ this, &amVisible }, true); + if (!amVisible) { // stop animation if it is not visible + media->stopInline(); + if (auto document = media->getDocument()) { // forget data from memory + document->forget(); } + stopped = true; } } else if (reader->mode() == Media::Clip::Reader::Mode::Video && reader->state() == Media::Clip::State::Finished) { // Stop finished video message. @@ -1065,7 +1076,8 @@ void HistoryItem::audioTrackUpdated() { } void HistoryItem::recountDisplayDate() { - bool displayingDate = ([this]() { + Expects(!isLogEntry()); + setDisplayDate(([this]() { if (isEmpty()) { return false; } @@ -1074,13 +1086,15 @@ void HistoryItem::recountDisplayDate() { return previous->isEmpty() || (previous->date.date() != date.date()); } return true; - })(); + })()); +} - if (displayingDate && !Has()) { +void HistoryItem::setDisplayDate(bool displayDate) { + if (displayDate && !Has()) { AddComponents(HistoryMessageDate::Bit()); Get()->init(date); setPendingInitDimensions(); - } else if (!displayingDate && Has()) { + } else if (!displayDate && Has()) { RemoveComponents(HistoryMessageDate::Bit()); setPendingInitDimensions(); } diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index 21c9947e7..aff016c1f 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -542,6 +542,7 @@ public: return !_block; } void attachToBlock(HistoryBlock *block, int index) { + Expects(!isLogEntry()); Expects(_block == nullptr); Expects(_indexInBlock < 0); Expects(block != nullptr); @@ -820,7 +821,7 @@ public: } void setPendingResize() { _flags |= MTPDmessage_ClientFlag::f_pending_resize; - if (!detached()) { + if (!detached() || isLogEntry()) { _history->setHasPendingResizedItems(); } } @@ -879,6 +880,19 @@ public: void clipCallback(Media::Clip::Notification notification); void audioTrackUpdated(); + void setLogEntryDisplayDate(bool displayDate) { + Expects(isLogEntry()); + setDisplayDate(displayDate); + } + void setLogEntryAttachToPrevious(bool attachToPrevious) { + Expects(isLogEntry()); + setAttachToNext(attachToPrevious); + } + void setLogEntryAttachToNext(bool attachToNext) { + Expects(isLogEntry()); + setAttachToNext(attachToNext); + } + ~HistoryItem(); protected: @@ -929,18 +943,27 @@ protected: return nullptr; } - // this should be called only from previousItemChanged() + // This should be called only from previousItemChanged() // to add required bits to the Composer mask - // after that always use Has() + // after that always use Has(). void recountDisplayDate(); - // this should be called only from previousItemChanged() or when + // This should be called only from previousItemChanged() or when // HistoryMessageDate or HistoryMessageUnreadBar bit is changed in the Composer mask - // then the result should be cached in a client side flag MTPDmessage_ClientFlag::f_attach_to_previous + // then the result should be cached in a client side flag MTPDmessage_ClientFlag::f_attach_to_previous. void recountAttachToPrevious(); - // this should be called only recountAttachToPrevious() of the next item - // or when the next item is removed through nextItemChanged() call + // This should be called only from recountDisplayDate(). + // Also this is called from setLogEntryDisplayDate() for channel log entries. + void setDisplayDate(bool displayDate); + + // This should be called only from recountAttachToPrevious(). + // Also this is called from setLogEntryAttachToPrevious() for channel log entries. + void setAttachToPrevious(bool attachToNext); + + // This should be called only from recountAttachToPrevious() of the next item + // or when the next item is removed through nextItemChanged() call. + // Also this is called from setLogEntryAttachToNext() for channel log entries. void setAttachToNext(bool attachToNext); const HistoryMessageReplyMarkup *inlineReplyMarkup() const { diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index cd98a5e66..0cc7c018c 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -681,6 +681,19 @@ HistoryWidget::HistoryWidget(QWidget *parent, gsl::not_null // So we force HistoryWidget::resizeEvent() here, without WA_UpdatesDisabled. myEnsureResized(this); }); + subscribe(AuthSession::Current().data().pendingHistoryResize(), [this] { handlePendingHistoryUpdate(); }); + subscribe(AuthSession::Current().data().queryItemVisibility(), [this](const AuthSessionData::ItemVisibilityQuery &query) { + if (_a_show.animating() || _history != query.item->history() || query.item->detached() || !isVisible()) { + return; + } + auto top = _list->itemTop(query.item); + if (top >= 0) { + auto scrollTop = _scroll->scrollTop(); + if (top + query.item->height() > scrollTop && top < scrollTop + _scroll->height()) { + *query.isVisible = true; + } + } + }); orderWidgets(); } @@ -701,7 +714,7 @@ void HistoryWidget::scrollToCurrentVoiceMessage(FullMsgId fromId, FullMsgId toId // If history has pending resize items, the scrollTopItem won't be updated. // And the scrollTop will be reset back to scrollTopItem + scrollTopOffset. - notify_handlePendingHistoryUpdate(); + handlePendingHistoryUpdate(); auto toTop = _list->itemTop(to); if (toTop >= 0 && !isItemCompletelyHidden(from)) { @@ -4782,17 +4795,6 @@ void HistoryWidget::grabFinish() { _topShadow->show(); } -bool HistoryWidget::isItemVisible(HistoryItem *item) { - if (isHidden() || _a_show.animating() || !_list) { - return false; - } - int32 top = _list->itemTop(item), st = _scroll->scrollTop(); - if (top < 0 || top + item->height() <= st || top >= st + _scroll->height()) { - return false; - } - return true; -} - void HistoryWidget::ui_repaintHistoryItem(gsl::not_null item) { if (_peer && _list && (item->history() == _history || (_migrated && item->history() == _migrated))) { auto ms = getms(); @@ -4825,7 +4827,7 @@ void HistoryWidget::notify_historyItemLayoutChanged(const HistoryItem *item) { } } -void HistoryWidget::notify_handlePendingHistoryUpdate() { +void HistoryWidget::handlePendingHistoryUpdate() { if (hasPendingResizedItems() || _updateHistoryGeometryRequired) { if (_list) { updateHistoryGeometry(); diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h index d5bdc8851..46cfa0db7 100644 --- a/Telegram/SourceFiles/historywidget.h +++ b/Telegram/SourceFiles/historywidget.h @@ -356,7 +356,6 @@ public: bool notify_switchInlineBotButtonReceived(const QString &query, UserData *samePeerBot, MsgId samePeerReplyTo); void notify_userIsBotChanged(UserData *user); void notify_migrateUpdated(PeerData *peer); - void notify_handlePendingHistoryUpdate(); bool cmd_search(); bool cmd_next_chat(); @@ -484,6 +483,7 @@ private: bool allFilesForCompress = true; }; + void handlePendingHistoryUpdate(); void fullPeerUpdated(PeerData *peer); void topBarClick(); void toggleTabbedSelectorMode(); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 693adcfe6..07ad694bf 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -819,13 +819,6 @@ void MainWidget::onFilesOrForwardDrop(const PeerId &peerId, const QMimeData *dat } } -bool MainWidget::isItemVisible(HistoryItem *item) { - if (isHidden() || _a_show.animating()) { - return false; - } - return _history->isItemVisible(item); -} - void MainWidget::notify_botCommandsChanged(UserData *bot) { _history->notify_botCommandsChanged(bot); } @@ -901,10 +894,6 @@ void MainWidget::notify_historyMuteUpdated(History *history) { _dialogs->notify_historyMuteUpdated(history); } -void MainWidget::notify_handlePendingHistoryUpdate() { - _history->notify_handlePendingHistoryUpdate(); -} - bool MainWidget::cmd_search() { if (Ui::isLayerShown() || Ui::isMediaViewShown()) return false; return _history->cmd_search(); diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index a2364f9af..e594fc499 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -378,8 +378,6 @@ public: bool contentOverlapped(const QRect &globalRect); - bool isItemVisible(HistoryItem *item); - void documentLoadProgress(DocumentData *document); void app_sendBotCallback(const HistoryMessageReplyMarkup::Button *button, const HistoryItem *msg, int row, int col); @@ -398,7 +396,6 @@ public: void notify_migrateUpdated(PeerData *peer); void notify_historyItemLayoutChanged(const HistoryItem *item); void notify_historyMuteUpdated(History *history); - void notify_handlePendingHistoryUpdate(); bool cmd_search(); bool cmd_next_chat();