mirror of https://github.com/procxx/kepka.git
Use plain HistoryItem in channel admin events log.
Instead of using a complex AdminLog::Item use just HistoryItem*.
This commit is contained in:
parent
e39b95175b
commit
5c87b42135
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue