Use plain HistoryItem in channel admin events log.

Instead of using a complex AdminLog::Item use just HistoryItem*.
This commit is contained in:
John Preston 2017-06-22 02:54:38 +03:00
parent e39b95175b
commit 5c87b42135
14 changed files with 313 additions and 319 deletions

View File

@ -63,6 +63,16 @@ public:
base::Observable<gsl::not_null<const HistoryItem*>> &repaintLogEntry() {
return _repaintLogEntry;
}
base::Observable<void> &pendingHistoryResize() {
return _pendingHistoryResize;
}
struct ItemVisibilityQuery {
gsl::not_null<HistoryItem*> item;
gsl::not_null<bool*> isVisible;
};
base::Observable<ItemVisibilityQuery> &queryItemVisibility() {
return _queryItemVisibility;
}
void copyFrom(const AuthSessionData &other) {
_variables = other._variables;
@ -139,6 +149,8 @@ private:
base::Observable<void> _savedGifsUpdated;
base::Observable<gsl::not_null<History*>> _historyCleared;
base::Observable<gsl::not_null<const HistoryItem*>> _repaintLogEntry;
base::Observable<void> _pendingHistoryResize;
base::Observable<ItemVisibilityQuery> _queryItemVisibility;
Variables _variables;
TimeMs _lastTimeVideoPlayedAt = 0;

View File

@ -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);

View File

@ -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<Window::Controller*> con
setMouseTracking(true);
_scrollDateHideTimer.setCallback([this] { scrollDateHideByTimer(); });
subscribe(AuthSession::Current().data().repaintLogEntry(), [this](gsl::not_null<const HistoryItem*> 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<HistoryMessageForwarded>()) {
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<Item>(_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<HistorySticker*>(_itemPressed->getMedia())) {
// _mouseAction = MouseAction::PrepareDrag; // start sticker drag or by-date drag
//} else { // TODO
if (dynamic_cast<HistorySticker*>(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*> item) const {
return _itemsTop + item->top();
int InnerWidget::itemTop(gsl::not_null<const HistoryItem*> 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

View File

@ -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*> item) const;
void repaintItem(Item *item);
QPoint mapPointToItem(QPoint point, Item *item) const;
int itemTop(gsl::not_null<const HistoryItem*> 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*> _history;
base::lambda<void()> _cancelledCallback;
base::lambda<void(int top)> _scrollTo;
std::vector<std::unique_ptr<Item>> _items;
std::map<gsl::not_null<HistoryItem*>, gsl::not_null<Item*>, std::less<>> _itemsByHistoryItems;
std::vector<HistoryItemOwned> _items;
std::map<uint64, HistoryItem*> _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;

View File

@ -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<ChannelData*> chann
} // namespace
Item::Item(gsl::not_null<History*> 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*> history, LocalIdManager &idManager, const MTPDchannelAdminLogEvent &event, base::lambda<void(HistoryItemOwned item)> 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<HistoryItem*> 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*> 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*> 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*> 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*> 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<HistoryMessageForwarded>()) {
return forwarded->_text.originalText(AllTextSelection, ExpandLinksNone);
}
}
return QString();
}
Item::~Item() {
for (auto part : _parts) {
part->destroy();
}
}
} // namespace AdminLog

View File

@ -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*> history, LocalIdManager &idManager, const MTPDchannelAdminLogEvent &event, base::lambda<void(HistoryItemOwned item)> 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*> history, LocalIdManager &idManager, const MTPDchannelAdminLogEvent &event);
uint64 id() const {
return _id;
explicit HistoryItemOwned(gsl::not_null<HistoryItem*> 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<ChannelData*> channel() {
return _history->peer->asChannel();
}
void addPart(HistoryItem *item);
uint64 _id = 0;
QDateTime _date;
gsl::not_null<History*> _history;
gsl::not_null<UserData*> _from;
std::vector<HistoryItem*> _parts;
int _top = 0;
int _height = 0;
HistoryItem *_data = nullptr;
};

View File

@ -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);
}
}

View File

@ -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();

View File

@ -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<HistoryMessageDate>() && !Has<HistoryMessageUnreadBar>()) {
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<HistoryMessageUnreadBar>()) {
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<HistoryMessageUnreadBar>()) {
@ -988,6 +998,7 @@ void HistoryItem::setUnreadBarCount(int count) {
}
void HistoryItem::setUnreadBarFreezed() {
Expects(!isLogEntry());
if (auto bar = Get<HistoryMessageUnreadBar>()) {
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<HistoryMessageDate>()) {
void HistoryItem::setDisplayDate(bool displayDate) {
if (displayDate && !Has<HistoryMessageDate>()) {
AddComponents(HistoryMessageDate::Bit());
Get<HistoryMessageDate>()->init(date);
setPendingInitDimensions();
} else if (!displayingDate && Has<HistoryMessageDate>()) {
} else if (!displayDate && Has<HistoryMessageDate>()) {
RemoveComponents(HistoryMessageDate::Bit());
setPendingInitDimensions();
}

View File

@ -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<HistoryMessageDate>()
// after that always use Has<HistoryMessageDate>().
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 {

View File

@ -681,6 +681,19 @@ HistoryWidget::HistoryWidget(QWidget *parent, gsl::not_null<Window::Controller*>
// 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<const HistoryItem*> 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();

View File

@ -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();

View File

@ -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();

View File

@ -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();