Improve items resize in history and feed.

This commit is contained in:
John Preston 2018-01-19 20:10:58 +03:00
parent e6baf8ef5b
commit b91ebad8be
31 changed files with 311 additions and 333 deletions

View file

@ -2584,8 +2584,16 @@ void ApiWrap::requestFeedMessages(
return; return;
} }
const auto addOffset = 0; // We request messages with overlapping and skip overlapped in response.
const auto limit = kFeedMessagesLimit; const auto limit = kFeedMessagesLimit;
const auto addOffset = [&] {
switch (slice) {
case SliceType::Before: return -2;
case SliceType::Around: return -limit / 2;
case SliceType::After: return 1 - limit;
}
Unexpected("Direction in PrepareSearchRequest");
}();
const auto sourcesHash = int32(0); const auto sourcesHash = int32(0);
const auto hash = int32(0); const auto hash = int32(0);
const auto flags = (messageId && messageId.fullId.channel) const auto flags = (messageId && messageId.fullId.channel)
@ -2634,16 +2642,24 @@ void ApiWrap::feedMessagesDone(
auto ids = std::vector<Data::MessagePosition>(); auto ids = std::vector<Data::MessagePosition>();
auto noSkipRange = Data::MessagesRange(messageId, messageId); auto noSkipRange = Data::MessagesRange(messageId, messageId);
auto accumulateFrom = [](auto &from, const auto &candidate) { const auto accumulateFrom = [](auto &from, const auto &candidate) {
if (!from || from > candidate) { if (!from || from > candidate) {
from = candidate; from = candidate;
} }
}; };
auto accumulateTill = [](auto &till, const auto &candidate) { const auto accumulateTill = [](auto &till, const auto &candidate) {
if (!till || till < candidate) { if (!till || till < candidate) {
till = candidate; till = candidate;
} }
}; };
const auto checkPosition = [&](const auto &position) {
if (slice == SliceType::Before && !(position < messageId)) {
return false;
} else if (slice == SliceType::After && !(messageId < position)) {
return false;
}
return true;
};
App::feedUsers(data.vusers); App::feedUsers(data.vusers);
App::feedChats(data.vchats); App::feedChats(data.vchats);
if (!messages.empty()) { if (!messages.empty()) {
@ -2651,6 +2667,9 @@ void ApiWrap::feedMessagesDone(
for (const auto &msg : messages) { for (const auto &msg : messages) {
if (const auto item = App::histories().addNewMessage(msg, type)) { if (const auto item = App::histories().addNewMessage(msg, type)) {
const auto position = item->position(); const auto position = item->position();
if (!checkPosition(position)) {
continue;
}
ids.push_back(position); ids.push_back(position);
accumulateFrom(noSkipRange.from, position); accumulateFrom(noSkipRange.from, position);
accumulateTill(noSkipRange.till, position); accumulateTill(noSkipRange.till, position);
@ -2658,14 +2677,14 @@ void ApiWrap::feedMessagesDone(
} }
ranges::reverse(ids); ranges::reverse(ids);
} }
if (data.has_min_position()) { if (data.has_min_position() && !ids.empty()) {
accumulateFrom( accumulateFrom(
noSkipRange.from, noSkipRange.from,
Data::FeedPositionFromMTP(data.vmin_position)); Data::FeedPositionFromMTP(data.vmin_position));
} else { } else {
noSkipRange.from = Data::MinMessagePosition; noSkipRange.from = Data::MinMessagePosition;
} }
if (data.has_max_position()) { if (data.has_max_position() && !ids.empty()) {
accumulateTill( accumulateTill(
noSkipRange.till, noSkipRange.till,
Data::FeedPositionFromMTP(data.vmax_position)); Data::FeedPositionFromMTP(data.vmax_position));

View file

@ -1241,9 +1241,9 @@ namespace {
return nullptr; return nullptr;
} }
void historyRegItem(HistoryItem *item) { void historyRegItem(not_null<HistoryItem*> item) {
MsgsData *data = fetchMsgsData(item->channelId()); const auto data = fetchMsgsData(item->channelId());
MsgsData::const_iterator i = data->constFind(item->id); const auto i = data->constFind(item->id);
if (i == data->cend()) { if (i == data->cend()) {
data->insert(item->id, item); data->insert(item->id, item);
} else if (i.value() != item) { } else if (i.value() != item) {
@ -1253,17 +1253,17 @@ namespace {
} }
} }
void historyUnregItem(HistoryItem *item) { void historyUnregItem(not_null<HistoryItem*> item) {
auto data = fetchMsgsData(item->channelId(), false); const auto data = fetchMsgsData(item->channelId(), false);
if (!data) return; if (!data) return;
auto i = data->find(item->id); const auto i = data->find(item->id);
if (i != data->cend()) { if (i != data->cend()) {
if (i.value() == item) { if (i.value() == item) {
data->erase(i); data->erase(i);
} }
} }
auto j = ::dependentItems.find(item); const auto j = ::dependentItems.find(item);
if (j != ::dependentItems.cend()) { if (j != ::dependentItems.cend()) {
DependentItemsSet items; DependentItemsSet items;
std::swap(items, j.value()); std::swap(items, j.value());
@ -1281,10 +1281,10 @@ namespace {
} }
} }
void historyUpdateDependent(HistoryItem *item) { void historyUpdateDependent(not_null<HistoryItem*> item) {
DependentItems::iterator j = ::dependentItems.find(item); const auto j = ::dependentItems.find(item);
if (j != ::dependentItems.cend()) { if (j != ::dependentItems.cend()) {
for_const (HistoryItem *dependent, j.value()) { for_const (const auto dependent, j.value()) {
dependent->updateDependencyItem(); dependent->updateDependencyItem();
} }
} }

View file

@ -164,9 +164,9 @@ namespace App {
inline HistoryItem *histItemById(const FullMsgId &msgId) { inline HistoryItem *histItemById(const FullMsgId &msgId) {
return histItemById(msgId.channel, msgId.msg); return histItemById(msgId.channel, msgId.msg);
} }
void historyRegItem(HistoryItem *item); void historyRegItem(not_null<HistoryItem*> item);
void historyUnregItem(HistoryItem *item); void historyUnregItem(not_null<HistoryItem*> item);
void historyUpdateDependent(HistoryItem *item); void historyUpdateDependent(not_null<HistoryItem*> item);
void historyClearMsgs(); void historyClearMsgs();
void historyClearItems(); void historyClearItems();
void historyRegDependency(HistoryItem *dependent, HistoryItem *dependency); void historyRegDependency(HistoryItem *dependent, HistoryItem *dependency);

View file

@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/empty_userpic.h" #include "ui/empty_userpic.h"
#include "core/click_handler_types.h" #include "core/click_handler_types.h"
#include "storage/localstorage.h" #include "storage/localstorage.h"
#include "data/data_session.h"
#include "auth_session.h" #include "auth_session.h"
#include "observer_peer.h" #include "observer_peer.h"
@ -598,6 +599,7 @@ void DeleteMessagesBox::deleteAndClear() {
App::main()->deleteMessages(i.key(), i.value(), forEveryone); App::main()->deleteMessages(i.key(), i.value(), forEveryone);
} }
Ui::hideLayer(); Ui::hideLayer();
Auth().data().sendHistoryChangeNotifications();
} }
ConfirmInviteBox::ConfirmInviteBox(QWidget*, const QString &title, bool isChannel, const MTPChatPhoto &photo, int count, const QVector<UserData*> &participants) ConfirmInviteBox::ConfirmInviteBox(QWidget*, const QString &title, bool isChannel, const MTPChatPhoto &photo, int count, const QVector<UserData*> &participants)

View file

@ -158,9 +158,17 @@ rpl::producer<not_null<const ViewElement*>> Session::viewLayoutChanged() const {
void Session::notifyItemIdChange(IdChange event) { void Session::notifyItemIdChange(IdChange event) {
_itemIdChanges.fire_copy(event); _itemIdChanges.fire_copy(event);
enumerateItemViews(
event.item, const auto refreshViewDataId = [](not_null<ViewElement*> view) {
[](not_null<ViewElement*> view) { view->refreshDataId(); }); view->refreshDataId();
};
enumerateItemViews(event.item, refreshViewDataId);
if (const auto group = Auth().data().groups().find(event.item)) {
const auto leader = group->items.back();
if (leader != event.item) {
enumerateItemViews(leader, refreshViewDataId);
}
}
} }
rpl::producer<Session::IdChange> Session::itemIdChanged() const { rpl::producer<Session::IdChange> Session::itemIdChanged() const {
@ -198,9 +206,7 @@ rpl::producer<not_null<const HistoryItem*>> Session::itemResizeRequest() const {
} }
void Session::requestViewResize(not_null<ViewElement*> view) { void Session::requestViewResize(not_null<ViewElement*> view) {
if (view == view->data()->mainView()) { view->setPendingResize();
view->setPendingResize();
}
_viewResizeRequest.fire_copy(view); _viewResizeRequest.fire_copy(view);
} }
@ -252,8 +258,8 @@ rpl::producer<not_null<const History*>> Session::historyCleared() const {
} }
void Session::notifyHistoryChangeDelayed(not_null<History*> history) { void Session::notifyHistoryChangeDelayed(not_null<History*> history) {
history->setHasPendingResizedItems();
_historiesChanged.insert(history); _historiesChanged.insert(history);
history->setPendingResize();
} }
rpl::producer<not_null<History*>> Session::historyChanged() const { rpl::producer<not_null<History*>> Session::historyChanged() const {

View file

@ -47,9 +47,6 @@ public:
return _moreChatsLoaded; return _moreChatsLoaded;
} }
base::Observable<void> &pendingHistoryResize() {
return _pendingHistoryResize;
}
struct ItemVisibilityQuery { struct ItemVisibilityQuery {
not_null<HistoryItem*> item; not_null<HistoryItem*> item;
not_null<bool*> isVisible; not_null<bool*> isVisible;
@ -440,7 +437,6 @@ private:
base::Variable<bool> _contactsLoaded = { false }; base::Variable<bool> _contactsLoaded = { false };
base::Variable<bool> _allChatsLoaded = { false }; base::Variable<bool> _allChatsLoaded = { false };
base::Observable<void> _moreChatsLoaded; base::Observable<void> _moreChatsLoaded;
base::Observable<void> _pendingHistoryResize;
base::Observable<ItemVisibilityQuery> _queryItemVisibility; base::Observable<ItemVisibilityQuery> _queryItemVisibility;
rpl::event_stream<IdChange> _itemIdChanges; rpl::event_stream<IdChange> _itemIdChanges;
rpl::event_stream<not_null<const ViewElement*>> _viewLayoutChanges; rpl::event_stream<not_null<const ViewElement*>> _viewLayoutChanges;

View file

@ -340,12 +340,7 @@ void historyMuteUpdated(History *history) {
if (MainWidget *m = App::main()) m->notify_historyMuteUpdated(history); if (MainWidget *m = App::main()) m->notify_historyMuteUpdated(history);
} }
void handlePendingHistoryUpdate() { //void handlePendingHistoryUpdate() {
if (!AuthSession::Exists()) {
return;
}
Auth().data().pendingHistoryResize().notify(true);
//for (const auto item : base::take(Global::RefPendingRepaintItems())) { //for (const auto item : base::take(Global::RefPendingRepaintItems())) {
// Auth().data().requestItemRepaint(item); // Auth().data().requestItemRepaint(item);
@ -370,7 +365,7 @@ void handlePendingHistoryUpdate() {
// } // }
//} //}
//} //}
} //}
void unreadCounterUpdated() { void unreadCounterUpdated() {
Global::RefHandleUnreadCounterUpdate().call(); Global::RefHandleUnreadCounterUpdate().call();
@ -515,7 +510,6 @@ namespace Global {
namespace internal { namespace internal {
struct Data { struct Data {
SingleQueuedInvokation HandleHistoryUpdate = { [] { Messenger::Instance().call_handleHistoryUpdate(); } };
SingleQueuedInvokation HandleUnreadCounterUpdate = { [] { Messenger::Instance().call_handleUnreadCounterUpdate(); } }; SingleQueuedInvokation HandleUnreadCounterUpdate = { [] { Messenger::Instance().call_handleUnreadCounterUpdate(); } };
SingleQueuedInvokation HandleDelayedPeerUpdates = { [] { Messenger::Instance().call_handleDelayedPeerUpdates(); } }; SingleQueuedInvokation HandleDelayedPeerUpdates = { [] { Messenger::Instance().call_handleDelayedPeerUpdates(); } };
SingleQueuedInvokation HandleObservables = { [] { Messenger::Instance().call_handleObservables(); } }; SingleQueuedInvokation HandleObservables = { [] { Messenger::Instance().call_handleObservables(); } };
@ -636,7 +630,6 @@ void finish() {
GlobalData = nullptr; GlobalData = nullptr;
} }
DefineRefVar(Global, SingleQueuedInvokation, HandleHistoryUpdate);
DefineRefVar(Global, SingleQueuedInvokation, HandleUnreadCounterUpdate); DefineRefVar(Global, SingleQueuedInvokation, HandleUnreadCounterUpdate);
DefineRefVar(Global, SingleQueuedInvokation, HandleDelayedPeerUpdates); DefineRefVar(Global, SingleQueuedInvokation, HandleDelayedPeerUpdates);
DefineRefVar(Global, SingleQueuedInvokation, HandleObservables); DefineRefVar(Global, SingleQueuedInvokation, HandleObservables);

View file

@ -224,12 +224,8 @@ bool switchInlineBotButtonReceived(const QString &query, UserData *samePeerBot =
void migrateUpdated(PeerData *peer); void migrateUpdated(PeerData *peer);
void historyMuteUpdated(History *history); void historyMuteUpdated(History *history);
// handle pending resize() / paint() on history items
void handlePendingHistoryUpdate();
void unreadCounterUpdated(); void unreadCounterUpdated();
enum class ScreenCorner { enum class ScreenCorner {
TopLeft = 0, TopLeft = 0,
TopRight = 1, TopRight = 1,
@ -298,7 +294,6 @@ bool started();
void start(); void start();
void finish(); void finish();
DeclareRefVar(SingleQueuedInvokation, HandleHistoryUpdate);
DeclareRefVar(SingleQueuedInvokation, HandleUnreadCounterUpdate); DeclareRefVar(SingleQueuedInvokation, HandleUnreadCounterUpdate);
DeclareRefVar(SingleQueuedInvokation, HandleDelayedPeerUpdates); DeclareRefVar(SingleQueuedInvokation, HandleDelayedPeerUpdates);
DeclareRefVar(SingleQueuedInvokation, HandleObservables); DeclareRefVar(SingleQueuedInvokation, HandleObservables);

View file

@ -215,9 +215,30 @@ InnerWidget::InnerWidget(
_scrollDateHideTimer.setCallback([this] { scrollDateHideByTimer(); }); _scrollDateHideTimer.setCallback([this] { scrollDateHideByTimer(); });
Auth().data().viewRepaintRequest( Auth().data().viewRepaintRequest(
) | rpl::start_with_next([this](auto view) { ) | rpl::start_with_next([this](auto view) {
repaintItem(view); // #TODO check my view if (view->delegate() == this) {
repaintItem(view);
}
}, lifetime());
Auth().data().viewResizeRequest(
) | rpl::start_with_next([this](auto view) {
if (view->delegate() == this) {
updateSize();
}
}, lifetime());
Auth().data().itemViewRefreshRequest(
) | rpl::start_with_next([this](auto item) {
if (const auto view = viewForItem(item)) {
refreshItem(view);
}
}, lifetime());
Auth().data().itemPlayInlineRequest(
) | rpl::start_with_next([this](auto item) {
if (const auto view = viewForItem(item)) {
if (const auto media = view->media()) {
media->playInline(true);
}
}
}, lifetime()); }, lifetime());
subscribe(Auth().data().pendingHistoryResize(), [this] { handlePendingHistoryResize(); });
subscribe(Auth().data().queryItemVisibility(), [this](const Data::Session::ItemVisibilityQuery &query) { subscribe(Auth().data().queryItemVisibility(), [this](const Data::Session::ItemVisibilityQuery &query) {
if (_history != query.item->history() || !query.item->isLogEntry() || !isVisible()) { if (_history != query.item->history() || !query.item->isLogEntry() || !isVisible()) {
return; return;
@ -439,18 +460,18 @@ QPoint InnerWidget::tooltipPos() const {
return _mousePosition; return _mousePosition;
} }
HistoryView::Context InnerWidget::elementContext() {
return HistoryView::Context::AdminLog;
}
std::unique_ptr<HistoryView::Element> InnerWidget::elementCreate( std::unique_ptr<HistoryView::Element> InnerWidget::elementCreate(
not_null<HistoryMessage*> message) { not_null<HistoryMessage*> message) {
return std::make_unique<HistoryView::Message>( return std::make_unique<HistoryView::Message>(this, message);
message,
HistoryView::Context::AdminLog);
} }
std::unique_ptr<HistoryView::Element> InnerWidget::elementCreate( std::unique_ptr<HistoryView::Element> InnerWidget::elementCreate(
not_null<HistoryService*> message) { not_null<HistoryService*> message) {
return std::make_unique<HistoryView::Service>( return std::make_unique<HistoryView::Service>(this, message);
message,
HistoryView::Context::AdminLog);
} }
void InnerWidget::saveState(not_null<SectionMemento*> memento) { void InnerWidget::saveState(not_null<SectionMemento*> memento) {
@ -599,7 +620,9 @@ void InnerWidget::updateMinMaxIds() {
void InnerWidget::itemsAdded(Direction direction, int addedCount) { void InnerWidget::itemsAdded(Direction direction, int addedCount) {
Expects(addedCount >= 0); Expects(addedCount >= 0);
auto checkFrom = (direction == Direction::Up) ? (_items.size() - addedCount) : 1; // Should be ": 0", but zero is skipped anyway. auto checkFrom = (direction == Direction::Up)
? (_items.size() - addedCount)
: 1; // Should be ": 0", but zero is skipped anyway.
auto checkTo = (direction == Direction::Up) ? (_items.size() + 1) : (addedCount + 1); auto checkTo = (direction == Direction::Up) ? (_items.size() + 1) : (addedCount + 1);
for (auto i = checkFrom; i != checkTo; ++i) { for (auto i = checkFrom; i != checkTo; ++i) {
if (i > 0) { if (i > 0) {
@ -628,11 +651,17 @@ void InnerWidget::updateSize() {
int InnerWidget::resizeGetHeight(int newWidth) { int InnerWidget::resizeGetHeight(int newWidth) {
update(); update();
const auto resizeAllItems = (_itemsWidth != newWidth);
auto newHeight = 0; auto newHeight = 0;
for (auto &item : base::reversed(_items)) { for (auto &item : base::reversed(_items)) {
item->setY(newHeight); item->setY(newHeight);
newHeight += item->resizeGetHeight(newWidth); if (item->pendingResize() || resizeAllItems) {
newHeight += item->resizeGetHeight(newWidth);
} else {
newHeight += item->height();
}
} }
_itemsWidth = newWidth;
_itemsHeight = newHeight; _itemsHeight = newHeight;
_itemsTop = (_minHeight > _itemsHeight + st::historyPaddingBottom) ? (_minHeight - _itemsHeight - st::historyPaddingBottom) : 0; _itemsTop = (_minHeight > _itemsHeight + st::historyPaddingBottom) ? (_minHeight - _itemsHeight - st::historyPaddingBottom) : 0;
return _itemsTop + _itemsHeight + st::historyPaddingBottom; return _itemsTop + _itemsHeight + st::historyPaddingBottom;
@ -1575,6 +1604,10 @@ void InnerWidget::repaintItem(const Element *view) {
update(0, itemTop(view), width(), view->height()); update(0, itemTop(view), width(), view->height());
} }
void InnerWidget::refreshItem(not_null<const Element*> view) {
// No need to refresh views in admin log.
}
QPoint InnerWidget::mapPointToItem(QPoint point, const Element *view) const { QPoint InnerWidget::mapPointToItem(QPoint point, const Element *view) const {
if (!view) { if (!view) {
return QPoint(); return QPoint();
@ -1582,13 +1615,6 @@ QPoint InnerWidget::mapPointToItem(QPoint point, const Element *view) const {
return point - QPoint(0, itemTop(view)); return point - QPoint(0, itemTop(view));
} }
void InnerWidget::handlePendingHistoryResize() {
if (_history->hasPendingResizedItems()) {
_history->resizeGetHeight(width());
updateSize();
}
}
InnerWidget::~InnerWidget() = default; InnerWidget::~InnerWidget() = default;
} // namespace AdminLog } // namespace AdminLog

View file

@ -69,6 +69,7 @@ public:
QPoint tooltipPos() const override; QPoint tooltipPos() const override;
// HistoryView::ElementDelegate interface. // HistoryView::ElementDelegate interface.
HistoryView::Context elementContext() override;
std::unique_ptr<HistoryView::Element> elementCreate( std::unique_ptr<HistoryView::Element> elementCreate(
not_null<HistoryMessage*> message) override; not_null<HistoryMessage*> message) override;
std::unique_ptr<HistoryView::Element> elementCreate( std::unique_ptr<HistoryView::Element> elementCreate(
@ -119,8 +120,8 @@ private:
void performDrag(); void performDrag();
int itemTop(not_null<const Element*> view) const; int itemTop(not_null<const Element*> view) const;
void repaintItem(const Element *view); void repaintItem(const Element *view);
void refreshItem(not_null<const Element*> view);
QPoint mapPointToItem(QPoint point, const Element *view) const; QPoint mapPointToItem(QPoint point, const Element *view) const;
void handlePendingHistoryResize();
void showContextMenu(QContextMenuEvent *e, bool showFromTouch = false); void showContextMenu(QContextMenuEvent *e, bool showFromTouch = false);
void savePhotoToFile(PhotoData *photo); void savePhotoToFile(PhotoData *photo);
@ -191,6 +192,7 @@ private:
std::map<uint64, not_null<Element*>> _itemsByIds; std::map<uint64, not_null<Element*>> _itemsByIds;
std::map<not_null<HistoryItem*>, not_null<Element*>, std::less<>> _itemsByData; std::map<not_null<HistoryItem*>, not_null<Element*>, std::less<>> _itemsByData;
int _itemsTop = 0; int _itemsTop = 0;
int _itemsWidth = 0;
int _itemsHeight = 0; int _itemsHeight = 0;
LocalIdManager _idManager; LocalIdManager _idManager;

View file

@ -164,18 +164,18 @@ rpl::producer<Data::MessagesSlice> Widget::listSource(
limitAfter); limitAfter);
} }
HistoryView::Context Widget::elementContext() {
return HistoryView::Context::Feed;
}
std::unique_ptr<HistoryView::Element> Widget::elementCreate( std::unique_ptr<HistoryView::Element> Widget::elementCreate(
not_null<HistoryMessage*> message) { not_null<HistoryMessage*> message) {
return std::make_unique<HistoryView::Message>( return std::make_unique<HistoryView::Message>(this, message);
message,
HistoryView::Context::Feed);
} }
std::unique_ptr<HistoryView::Element> Widget::elementCreate( std::unique_ptr<HistoryView::Element> Widget::elementCreate(
not_null<HistoryService*> message) { not_null<HistoryService*> message) {
return std::make_unique<HistoryView::Service>( return std::make_unique<HistoryView::Service>(this, message);
message,
HistoryView::Context::Feed);
} }
std::unique_ptr<Window::SectionMemento> Widget::createMemento() { std::unique_ptr<Window::SectionMemento> Widget::createMemento() {

View file

@ -67,6 +67,8 @@ public:
int limitBefore, int limitBefore,
int limitAfter) override; int limitAfter) override;
// HistoryView::ElementDelegate interface.
HistoryView::Context elementContext() override;
std::unique_ptr<HistoryView::Element> elementCreate( std::unique_ptr<HistoryView::Element> elementCreate(
not_null<HistoryMessage*> message) override; not_null<HistoryMessage*> message) override;
std::unique_ptr<HistoryView::Element> elementCreate( std::unique_ptr<HistoryView::Element> elementCreate(

View file

@ -90,7 +90,6 @@ bool History::canHaveFromPhotos() const {
void History::setHasPendingResizedItems() { void History::setHasPendingResizedItems() {
_flags |= Flag::f_has_pending_resized_items; _flags |= Flag::f_has_pending_resized_items;
Global::RefHandleHistoryUpdate().call();
} }
void History::setLocalDraft(std::unique_ptr<Data::Draft> &&draft) { void History::setLocalDraft(std::unique_ptr<Data::Draft> &&draft) {
@ -2021,7 +2020,7 @@ not_null<HistoryItem*> History::addNewInTheMiddle(
} else if (blockIndex + 1 < blocks.size() && !blocks[blockIndex + 1]->messages.empty()) { } else if (blockIndex + 1 < blocks.size() && !blocks[blockIndex + 1]->messages.empty()) {
blocks[blockIndex + 1]->messages.front()->previousInBlocksChanged(); blocks[blockIndex + 1]->messages.front()->previousInBlocksChanged();
} else { } else {
(*it)->nextInBlocksChanged(); (*it)->nextInBlocksRemoved();
} }
return item; return item;
@ -2080,7 +2079,7 @@ HistoryBlock *History::finishBuildingFrontBlock() {
// the old first item of a first block was changed // the old first item of a first block was changed
first->previousInBlocksChanged(); first->previousInBlocksChanged();
} else { } else {
block->messages.back()->nextInBlocksChanged(); block->messages.back()->nextInBlocksRemoved();
} }
} }
@ -2229,12 +2228,12 @@ MsgId History::msgIdForRead() const {
} }
int History::resizeGetHeight(int newWidth) { int History::resizeGetHeight(int newWidth) {
bool resizeAllItems = (_flags & Flag::f_pending_resize) || (width != newWidth); const auto resizeAllItems = (width != newWidth);
if (!resizeAllItems && !hasPendingResizedItems()) { if (!resizeAllItems && !hasPendingResizedItems()) {
return height; return height;
} }
_flags &= ~(Flag::f_pending_resize | Flag::f_has_pending_resized_items); _flags &= ~(Flag::f_has_pending_resized_items);
width = newWidth; width = newWidth;
int y = 0; int y = 0;
@ -2330,7 +2329,7 @@ void History::clear(bool leaveItems) {
} }
clearLastKeyboard(); clearLastKeyboard();
} }
setPendingResize(); Auth().data().notifyHistoryChangeDelayed(this);
newLoaded = oldLoaded = false; newLoaded = oldLoaded = false;
forgetScrollState(); forgetScrollState();
@ -2436,7 +2435,7 @@ void History::removeBlock(not_null<HistoryBlock*> block) {
} }
blocks[index]->messages.front()->previousInBlocksChanged(); blocks[index]->messages.front()->previousInBlocksChanged();
} else if (!blocks.empty() && !blocks.back()->messages.empty()) { } else if (!blocks.empty() && !blocks.back()->messages.empty()) {
blocks.back()->messages.back()->nextInBlocksChanged(); blocks.back()->messages.back()->nextInBlocksRemoved();
} }
} }
@ -2505,7 +2504,7 @@ void HistoryBlock::remove(not_null<Element*> view) {
} else if (blockIndex + 1 < _history->blocks.size()) { } else if (blockIndex + 1 < _history->blocks.size()) {
_history->blocks[blockIndex + 1]->messages.front()->previousInBlocksChanged(); _history->blocks[blockIndex + 1]->messages.front()->previousInBlocksChanged();
} else if (!_history->blocks.empty() && !_history->blocks.back()->messages.empty()) { } else if (!_history->blocks.empty() && !_history->blocks.back()->messages.empty()) {
_history->blocks.back()->messages.back()->nextInBlocksChanged(); _history->blocks.back()->messages.back()->nextInBlocksRemoved();
} }
} }
@ -2528,7 +2527,7 @@ void HistoryBlock::refreshView(not_null<Element*> view) {
} else if (blockIndex + 1 < _history->blocks.size()) { } else if (blockIndex + 1 < _history->blocks.size()) {
_history->blocks[blockIndex + 1]->messages.front()->previousInBlocksChanged(); _history->blocks[blockIndex + 1]->messages.front()->previousInBlocksChanged();
} else if (!_history->blocks.empty() && !_history->blocks.back()->messages.empty()) { } else if (!_history->blocks.empty() && !_history->blocks.back()->messages.empty()) {
_history->blocks.back()->messages.back()->nextInBlocksChanged(); _history->blocks.back()->messages.back()->nextInBlocksRemoved();
} }
} }

View file

@ -241,10 +241,6 @@ public:
return _flags & Flag::f_has_pending_resized_items; return _flags & Flag::f_has_pending_resized_items;
} }
void setHasPendingResizedItems(); void setHasPendingResizedItems();
void setPendingResize() {
_flags |= Flag::f_pending_resize;
setHasPendingResizedItems();
}
void paintDialog(Painter &p, int32 w, bool sel) const; void paintDialog(Painter &p, int32 w, bool sel) const;
bool mySendActionUpdated(SendAction::Type type, bool doing); bool mySendActionUpdated(SendAction::Type type, bool doing);
@ -457,7 +453,6 @@ private:
enum class Flag { enum class Flag {
f_has_pending_resized_items = (1 << 0), f_has_pending_resized_items = (1 << 0),
f_pending_resize = (1 << 1),
}; };
using Flags = base::flags<Flag>; using Flags = base::flags<Flag>;
friend inline constexpr auto is_flag_type(Flag) { return true; }; friend inline constexpr auto is_flag_type(Flag) { return true; };

View file

@ -2911,20 +2911,20 @@ void HistoryInner::onParentGeometryChanged() {
not_null<HistoryView::ElementDelegate*> HistoryInner::ElementDelegate() { not_null<HistoryView::ElementDelegate*> HistoryInner::ElementDelegate() {
class Result : public HistoryView::ElementDelegate { class Result : public HistoryView::ElementDelegate {
public: public:
HistoryView::Context elementContext() override {
return HistoryView::Context::History;
}
std::unique_ptr<HistoryView::Element> elementCreate( std::unique_ptr<HistoryView::Element> elementCreate(
not_null<HistoryMessage*> message) override { not_null<HistoryMessage*> message) override {
return std::make_unique<HistoryView::Message>( return std::make_unique<HistoryView::Message>(this, message);
message,
HistoryView::Context::History);
} }
std::unique_ptr<HistoryView::Element> elementCreate( std::unique_ptr<HistoryView::Element> elementCreate(
not_null<HistoryService*> message) override { not_null<HistoryService*> message) override {
return std::make_unique<HistoryView::Service>( return std::make_unique<HistoryView::Service>(this, message);
message,
HistoryView::Context::History);
} }
}; };
static Result result; static Result result;
return &result; return &result;
} }

View file

@ -2672,7 +2672,6 @@ bool HistoryGif::playInline(bool autoplay) {
? Mode::Video ? Mode::Video
: Mode::Gif; : Mode::Gif;
setClipReader(Media::Clip::MakeReader(_data, _parent->data()->fullId(), [this](Media::Clip::Notification notification) { setClipReader(Media::Clip::MakeReader(_data, _parent->data()->fullId(), [this](Media::Clip::Notification notification) {
// #TODO GIFs
_parent->clipCallback(notification); _parent->clipCallback(notification);
}, mode)); }, mode));
if (mode == Mode::Video) { if (mode == Mode::Video) {

View file

@ -647,7 +647,6 @@ HistoryWidget::HistoryWidget(QWidget *parent, not_null<Window::Controller*> cont
} }
} }
})); }));
subscribe(Auth().data().pendingHistoryResize(), [this] { handlePendingHistoryUpdate(); });
subscribe(Auth().data().queryItemVisibility(), [this](const Data::Session::ItemVisibilityQuery &query) { subscribe(Auth().data().queryItemVisibility(), [this](const Data::Session::ItemVisibilityQuery &query) {
if (_a_show.animating() if (_a_show.animating()
|| _history != query.item->history() || _history != query.item->history()
@ -4503,7 +4502,7 @@ void HistoryWidget::onReportSpamClear() {
void HistoryWidget::handleHistoryChange(not_null<const History*> history) { void HistoryWidget::handleHistoryChange(not_null<const History*> history) {
if (_list && (_history == history || _migrated == history)) { if (_list && (_history == history || _migrated == history)) {
updateHistoryGeometry(); handlePendingHistoryUpdate();
updateBotKeyboard(); updateBotKeyboard();
if (!_scroll->isHidden()) { if (!_scroll->isHidden()) {
const auto unblock = isBlocked(); const auto unblock = isBlocked();
@ -4566,12 +4565,8 @@ PeerData *HistoryWidget::ui_getPeerForMouseAction() {
void HistoryWidget::handlePendingHistoryUpdate() { void HistoryWidget::handlePendingHistoryUpdate() {
if (hasPendingResizedItems() || _updateHistoryGeometryRequired) { if (hasPendingResizedItems() || _updateHistoryGeometryRequired) {
if (_list) { updateHistoryGeometry();
updateHistoryGeometry(); _list->update();
_list->update();
} else {
_updateHistoryGeometryRequired = false;
}
} }
} }
@ -4742,7 +4737,9 @@ int HistoryWidget::countAutomaticScrollTop() {
} }
void HistoryWidget::updateHistoryGeometry(bool initial, bool loadedDown, const ScrollChange &change) { void HistoryWidget::updateHistoryGeometry(bool initial, bool loadedDown, const ScrollChange &change) {
if (!_history || (initial && _historyInited) || (!initial && !_historyInited)) return; if (!_history || (initial && _historyInited) || (!initial && !_historyInited)) {
return;
}
if (_firstLoadRequest || _a_show.animating()) { if (_firstLoadRequest || _a_show.animating()) {
return; // scrollTopMax etc are not working after recountHistoryGeometry() return; // scrollTopMax etc are not working after recountHistoryGeometry()
} }
@ -6176,36 +6173,6 @@ void HistoryWidget::confirmDeleteSelectedItems() {
App::main()->deleteLayer(_list->getSelectedItems()); App::main()->deleteLayer(_list->getSelectedItems());
} }
void HistoryWidget::deleteSelectedItems(bool forEveryone) {
Ui::hideLayer();
if (!_list) return;
const auto items = _list->getSelectedItems();
const auto selected = ranges::view::all(
items
) | ranges::view::transform([](const FullMsgId &fullId) {
return App::histItemById(fullId);
}) | ranges::view::filter([](HistoryItem *item) {
return item != nullptr;
}) | ranges::to_vector;
if (selected.empty()) return;
QMap<PeerData*, QVector<MTPint>> idsByPeer;
for (const auto item : selected) {
idsByPeer[item->history()->peer].push_back(MTP_int(item->id));
}
onClearSelected();
for (const auto item : selected) {
item->destroy();
}
for (auto i = idsByPeer.cbegin(), e = idsByPeer.cend(); i != e; ++i) {
App::main()->deleteMessages(i.key(), i.value(), forEveryone);
}
}
void HistoryWidget::onListEscapePressed() { void HistoryWidget::onListEscapePressed() {
if (_nonEmptySelection && _list) { if (_nonEmptySelection && _list) {
onClearSelected(); onClearSelected();

View file

@ -329,7 +329,6 @@ public:
bool isItemVisible(HistoryItem *item); bool isItemVisible(HistoryItem *item);
void confirmDeleteSelectedItems(); void confirmDeleteSelectedItems();
void deleteSelectedItems(bool forEveryone);
// Float player interface. // Float player interface.
bool wheelEventFromFloatPlayer(QEvent *e) override; bool wheelEventFromFloatPlayer(QEvent *e) override;

View file

@ -55,13 +55,20 @@ TextSelection ShiftItemSelection(
return ShiftItemSelection(selection, byText.length()); return ShiftItemSelection(selection, byText.length());
} }
Element::Element(not_null<HistoryItem*> data, Context context) Element::Element(
: _data(data) not_null<ElementDelegate*> delegate,
, _context(context) { not_null<HistoryItem*> data)
: _delegate(delegate)
, _data(data)
, _context(delegate->elementContext()) {
Auth().data().registerItemView(this); Auth().data().registerItemView(this);
refreshMedia(); refreshMedia();
} }
not_null<ElementDelegate*> Element::delegate() const {
return _delegate;
}
not_null<HistoryItem*> Element::data() const { not_null<HistoryItem*> Element::data() const {
return _data; return _data;
} }
@ -146,74 +153,6 @@ int Element::infoWidth() const {
bool Element::isHiddenByGroup() const { bool Element::isHiddenByGroup() const {
return _flags & Flag::HiddenByGroup; return _flags & Flag::HiddenByGroup;
} }
//
//void Element::makeGroupMember(not_null<Element*> leader) {
// Expects(leader != this);
//
// const auto group = Get<Group>();
// Assert(group != nullptr);
// if (group->leader == this) {
// if (auto single = _media ? _media->takeLastFromGroup() : nullptr) {
// _media = std::move(single);
// }
// _flags |= Flag::HiddenByGroup;
// Auth().data().requestViewResize(this);
//
// group->leader = leader;
// base::take(group->others);
// } else if (group->leader != leader) {
// group->leader = leader;
// }
//
// Ensures(isHiddenByGroup());
// Ensures(group->others.empty());
//}
//
//void Element::makeGroupLeader(std::vector<not_null<HistoryItem*>> &&others) {
// const auto group = Get<Group>();
// Assert(group != nullptr);
//
// const auto leaderChanged = (group->leader != this);
// if (leaderChanged) {
// group->leader = this;
// _flags &= ~Flag::HiddenByGroup;
// Auth().data().requestViewResize(this);
// }
// group->others = std::move(others);
// if (!_media || !_media->applyGroup(group->others)) {
// resetGroupMedia(group->others);
// data()->invalidateChatsListEntry();
// }
//
// Ensures(!isHiddenByGroup());
//}
//
//bool Element::groupIdValidityChanged() {
// if (Has<Group>()) {
// if (_media && _media->canBeGrouped()) {
// return false;
// }
// RemoveComponents(Group::Bit());
// Auth().data().requestViewResize(this);
// return true;
// }
// return false;
//}
//
//void Element::validateGroupId() {
// // Just ignore the result.
// groupIdValidityChanged();
//}
//
//Group *Element::getFullGroup() {
// if (const auto group = Get<Group>()) {
// if (group->leader == this) {
// return group;
// }
// return group->leader->Get<Group>();
// }
// return nullptr;
//}
void Element::refreshMedia() { void Element::refreshMedia() {
_flags &= ~Flag::HiddenByGroup; _flags &= ~Flag::HiddenByGroup;
@ -241,23 +180,12 @@ void Element::refreshMedia() {
} }
} }
//void Element::resetGroupMedia(
// const std::vector<not_null<Element*>> &others) {
// if (!others.empty()) {
// _media = std::make_unique<HistoryGroupedMedia>(this, others);
// } else if (_media) {
// _media = _media->takeLastFromGroup();
// }
// Auth().data().requestViewResize(this);
//}
void Element::previousInBlocksChanged() { void Element::previousInBlocksChanged() {
recountDisplayDateInBlocks(); recountDisplayDateInBlocks();
recountAttachToPreviousInBlocks(); recountAttachToPreviousInBlocks();
} }
// Called only if there is no more next item! Not always when it changes! void Element::nextInBlocksRemoved() {
void Element::nextInBlocksChanged() {
setAttachToNext(false); setAttachToNext(false);
} }
@ -306,16 +234,9 @@ void Element::clipCallback(Media::Clip::Notification notification) {
} }
} }
void Element::refreshDataId() { void Element::refreshDataId() {
if (const auto media = this->media()) { if (const auto media = this->media()) {
media->refreshParentId(data()); media->refreshParentId(data());
// #TODO refresh sent album items
//if (const auto group = Get<Group>()) {
// if (group->leader != this) {
// group->leader->refreshDataId();
// }
//}
} }
} }
@ -323,10 +244,11 @@ bool Element::computeIsAttachToPrevious(not_null<Element*> previous) {
const auto item = data(); const auto item = data();
if (!item->Has<HistoryMessageDate>() && !item->Has<HistoryMessageUnreadBar>()) { if (!item->Has<HistoryMessageDate>() && !item->Has<HistoryMessageUnreadBar>()) {
const auto prev = previous->data(); const auto prev = previous->data();
const auto possible = !item->isPost() && !prev->isPost() const auto possible = !item->serviceMsg() && !prev->serviceMsg()
&& !item->serviceMsg() && !prev->serviceMsg()
&& !item->isEmpty() && !prev->isEmpty() && !item->isEmpty() && !prev->isEmpty()
&& (qAbs(prev->date.secsTo(item->date)) < kAttachMessageToPreviousSecondsDelta); && (qAbs(prev->date.secsTo(item->date)) < kAttachMessageToPreviousSecondsDelta)
&& (_context == Context::Feed
|| (!item->isPost() && !prev->isPost()));
if (possible) { if (possible) {
if (item->history()->peer->isSelf()) { if (item->history()->peer->isSelf()) {
return prev->senderOriginal() == item->senderOriginal() return prev->senderOriginal() == item->senderOriginal()
@ -390,20 +312,20 @@ void Element::setDisplayDate(bool displayDate) {
void Element::setAttachToNext(bool attachToNext) { void Element::setAttachToNext(bool attachToNext) {
if (attachToNext && !(_flags & Flag::AttachedToNext)) { if (attachToNext && !(_flags & Flag::AttachedToNext)) {
_flags |= Flag::AttachedToNext; _flags |= Flag::AttachedToNext;
Auth().data().requestViewResize(this); setPendingResize();
} else if (!attachToNext && (_flags & Flag::AttachedToNext)) { } else if (!attachToNext && (_flags & Flag::AttachedToNext)) {
_flags &= ~Flag::AttachedToNext; _flags &= ~Flag::AttachedToNext;
Auth().data().requestViewResize(this); setPendingResize();
} }
} }
void Element::setAttachToPrevious(bool attachToPrevious) { void Element::setAttachToPrevious(bool attachToPrevious) {
if (attachToPrevious && !(_flags & Flag::AttachedToPrevious)) { if (attachToPrevious && !(_flags & Flag::AttachedToPrevious)) {
_flags |= Flag::AttachedToPrevious; _flags |= Flag::AttachedToPrevious;
Auth().data().requestViewResize(this); setPendingResize();
} else if (!attachToPrevious && (_flags & Flag::AttachedToPrevious)) { } else if (!attachToPrevious && (_flags & Flag::AttachedToPrevious)) {
_flags &= ~Flag::AttachedToPrevious; _flags &= ~Flag::AttachedToPrevious;
Auth().data().requestViewResize(this); setPendingResize();
} }
} }

View file

@ -23,9 +23,16 @@ enum InfoDisplayType : char;
namespace HistoryView { namespace HistoryView {
enum class Context : char {
History,
Feed,
AdminLog
};
class Element; class Element;
class ElementDelegate { class ElementDelegate {
public: public:
virtual Context elementContext() = 0;
virtual std::unique_ptr<Element> elementCreate( virtual std::unique_ptr<Element> elementCreate(
not_null<HistoryMessage*> message) = 0; not_null<HistoryMessage*> message) = 0;
virtual std::unique_ptr<Element> elementCreate( virtual std::unique_ptr<Element> elementCreate(
@ -46,25 +53,14 @@ TextSelection ShiftItemSelection(
TextSelection selection, TextSelection selection,
const Text &byText); const Text &byText);
class Element;
//struct Group : public RuntimeComponent<Group, Element> {
// MessageGroupId groupId = MessageGroupId::None;
// Element *leader = nullptr;
// std::vector<not_null<HistoryItem*>> others;
//};
enum class Context : char {
History,
Feed,
AdminLog
};
class Element class Element
: public Object : public Object
, public RuntimeComposer<Element> , public RuntimeComposer<Element>
, public ClickHandlerHost { , public ClickHandlerHost {
public: public:
Element(not_null<HistoryItem*> data, Context context); Element(
not_null<ElementDelegate*> delegate,
not_null<HistoryItem*> data);
enum class Flag : uchar { enum class Flag : uchar {
NeedsResize = 0x01, NeedsResize = 0x01,
@ -75,6 +71,7 @@ public:
using Flags = base::flags<Flag>; using Flags = base::flags<Flag>;
friend inline constexpr auto is_flag_type(Flag) { return true; } friend inline constexpr auto is_flag_type(Flag) { return true; }
not_null<ElementDelegate*> delegate() const;
not_null<HistoryItem*> data() const; not_null<HistoryItem*> data() const;
HistoryMedia *media() const; HistoryMedia *media() const;
Context context() const; Context context() const;
@ -98,17 +95,12 @@ public:
virtual int infoWidth() const; virtual int infoWidth() const;
bool isHiddenByGroup() const; bool isHiddenByGroup() const;
//void makeGroupMember(not_null<Element*> leader);
//void makeGroupLeader(std::vector<not_null<HistoryItem*>> &&others);
//bool groupIdValidityChanged();
//void validateGroupId();
//Group *getFullGroup();
// For blocks context this should be called only from recountAttachToPreviousInBlocks(). // For blocks context this should be called only from recountAttachToPreviousInBlocks().
void setAttachToPrevious(bool attachToNext); void setAttachToPrevious(bool attachToNext);
// For blocks context this should be called only from recountAttachToPreviousInBlocks() // For blocks context this should be called only from recountAttachToPreviousInBlocks()
// of the next item or when the next item is removed through nextInBlocksChanged() call. // of the next item or when the next item is removed through nextInBlocksRemoved() call.
void setAttachToNext(bool attachToNext); void setAttachToNext(bool attachToNext);
// For blocks context this should be called only from recountDisplayDate(). // For blocks context this should be called only from recountDisplayDate().
@ -186,7 +178,7 @@ public:
Element *previousInBlocks() const; Element *previousInBlocks() const;
Element *nextInBlocks() const; Element *nextInBlocks() const;
void previousInBlocksChanged(); void previousInBlocksChanged();
void nextInBlocksChanged(); void nextInBlocksRemoved();
void clipCallback(Media::Clip::Notification notification); void clipCallback(Media::Clip::Notification notification);
@ -214,8 +206,8 @@ private:
virtual QSize performCountCurrentSize(int newWidth) = 0; virtual QSize performCountCurrentSize(int newWidth) = 0;
void refreshMedia(); void refreshMedia();
//void resetGroupMedia(const std::vector<not_null<HistoryItem*>> &others);
const not_null<ElementDelegate*> _delegate;
const not_null<HistoryItem*> _data; const not_null<HistoryItem*> _data;
std::unique_ptr<HistoryMedia> _media; std::unique_ptr<HistoryMedia> _media;

View file

@ -223,9 +223,30 @@ ListWidget::ListWidget(
_scrollDateHideTimer.setCallback([this] { scrollDateHideByTimer(); }); _scrollDateHideTimer.setCallback([this] { scrollDateHideByTimer(); });
Auth().data().viewRepaintRequest( Auth().data().viewRepaintRequest(
) | rpl::start_with_next([this](auto view) { ) | rpl::start_with_next([this](auto view) {
repaintItem(view); if (view->delegate() == _delegate) {
repaintItem(view);
}
}, lifetime());
Auth().data().viewResizeRequest(
) | rpl::start_with_next([this](auto view) {
if (view->delegate() == _delegate) {
updateSize();
}
}, lifetime());
Auth().data().itemViewRefreshRequest(
) | rpl::start_with_next([this](auto item) {
if (const auto view = viewForItem(item)) {
refreshItem(view);
}
}, lifetime());
Auth().data().itemPlayInlineRequest(
) | rpl::start_with_next([this](auto item) {
if (const auto view = viewForItem(item)) {
if (const auto media = view->media()) {
media->playInline(true);
}
}
}, lifetime()); }, lifetime());
subscribe(Auth().data().pendingHistoryResize(), [this] { handlePendingHistoryResize(); });
subscribe(Auth().data().queryItemVisibility(), [this](const Data::Session::ItemVisibilityQuery &query) { subscribe(Auth().data().queryItemVisibility(), [this](const Data::Session::ItemVisibilityQuery &query) {
if (const auto view = viewForItem(query.item)) { if (const auto view = viewForItem(query.item)) {
const auto top = itemTop(view); const auto top = itemTop(view);
@ -262,7 +283,7 @@ void ListWidget::refreshRows() {
} }
updateAroundPositionFromRows(); updateAroundPositionFromRows();
RpWidget::resizeToWidth(width()); updateItemsGeometry();
restoreScrollState(); restoreScrollState();
mouseActionUpdate(QCursor::pos()); mouseActionUpdate(QCursor::pos());
} }
@ -505,27 +526,34 @@ void ListWidget::restoreState(not_null<ListMemento*> memento) {
refreshViewer(); refreshViewer();
} }
void ListWidget::itemsAdded(Direction direction, int addedCount) { void ListWidget::updateItemsGeometry() {
Expects(addedCount >= 0); const auto count = int(_items.size());
const auto first = [&] {
auto checkFrom = (direction == Direction::Up) for (auto i = 0; i != count; ++i) {
? (_items.size() - addedCount) const auto view = _items[i].get();
: 1; // Should be ": 0", but zero is skipped anyway. if (view->isHiddenByGroup()) {
auto checkTo = (direction == Direction::Up) view->setDisplayDate(false);
? (_items.size() + 1)
: (addedCount + 1);
for (auto i = checkFrom; i != checkTo; ++i) {
if (i > 0) {
const auto view = _items[i - 1].get();
if (i < _items.size()) {
// #TODO feeds show
auto previous = _items[i].get();
view->setDisplayDate(view->data()->date.date() != previous->data()->date.date());
auto attachToPrevious = view->computeIsAttachToPrevious(previous);
view->setAttachToPrevious(attachToPrevious);
previous->setAttachToNext(attachToPrevious);
} else { } else {
view->setDisplayDate(true); view->setDisplayDate(true);
return i;
}
}
return count;
}();
if (first < count) {
auto view = _items[first].get();
for (auto i = first + 1; i != count; ++i) {
const auto next = _items[i].get();
if (next->isHiddenByGroup()) {
next->setDisplayDate(false);
} else {
const auto viewDate = view->data()->date;
const auto nextDate = next->data()->date;
next->setDisplayDate(nextDate.date() != viewDate.date());
auto attached = next->computeIsAttachToPrevious(view);
next->setAttachToPrevious(attached);
view->setAttachToNext(attached);
view = next;
} }
} }
} }
@ -541,11 +569,17 @@ void ListWidget::updateSize() {
int ListWidget::resizeGetHeight(int newWidth) { int ListWidget::resizeGetHeight(int newWidth) {
update(); update();
const auto resizeAllItems = (_itemsWidth != newWidth);
auto newHeight = 0; auto newHeight = 0;
for (auto &view : _items) { for (auto &view : _items) {
view->setY(newHeight); view->setY(newHeight);
newHeight += view->resizeGetHeight(newWidth); if (view->pendingResize() || resizeAllItems) {
newHeight += view->resizeGetHeight(newWidth);
} else {
newHeight += view->height();
}
} }
_itemsWidth = newWidth;
_itemsHeight = newHeight; _itemsHeight = newHeight;
_itemsTop = (_minHeight > _itemsHeight + st::historyPaddingBottom) ? (_minHeight - _itemsHeight - st::historyPaddingBottom) : 0; _itemsTop = (_minHeight > _itemsHeight + st::historyPaddingBottom) ? (_minHeight - _itemsHeight - st::historyPaddingBottom) : 0;
return _itemsTop + _itemsHeight + st::historyPaddingBottom; return _itemsTop + _itemsHeight + st::historyPaddingBottom;
@ -1386,6 +1420,10 @@ void ListWidget::repaintItem(const Element *view) {
update(0, itemTop(view), width(), view->height()); update(0, itemTop(view), width(), view->height());
} }
void ListWidget::refreshItem(not_null<const Element*> view) {
// #TODO
}
QPoint ListWidget::mapPointToItem( QPoint ListWidget::mapPointToItem(
QPoint point, QPoint point,
const Element *view) const { const Element *view) const {
@ -1395,14 +1433,6 @@ QPoint ListWidget::mapPointToItem(
return point - QPoint(0, itemTop(view)); return point - QPoint(0, itemTop(view));
} }
void ListWidget::handlePendingHistoryResize() {
// #TODO resize
//if (_history->hasPendingResizedItems()) {
// _history->resizeGetHeight(width());
// updateSize();
//}
}
ListWidget::~ListWidget() = default; ListWidget::~ListWidget() = default;
} // namespace HistoryView } // namespace HistoryView

View file

@ -155,8 +155,8 @@ private:
void performDrag(); void performDrag();
int itemTop(not_null<const Element*> view) const; int itemTop(not_null<const Element*> view) const;
void repaintItem(const Element *view); void repaintItem(const Element *view);
void refreshItem(not_null<const Element*> view);
QPoint mapPointToItem(QPoint point, const Element *view) const; QPoint mapPointToItem(QPoint point, const Element *view) const;
void handlePendingHistoryResize();
void showContextMenu(QContextMenuEvent *e, bool showFromTouch = false); void showContextMenu(QContextMenuEvent *e, bool showFromTouch = false);
void savePhotoToFile(PhotoData *photo); void savePhotoToFile(PhotoData *photo);
@ -180,7 +180,7 @@ private:
void checkMoveToOtherViewer(); void checkMoveToOtherViewer();
void updateVisibleTopItem(); void updateVisibleTopItem();
void itemsAdded(Direction direction, int addedCount); void updateItemsGeometry();
void updateSize(); void updateSize();
void toggleScrollDateShown(); void toggleScrollDateShown();
@ -226,6 +226,7 @@ private:
std::vector<not_null<Element*>> _items; std::vector<not_null<Element*>> _items;
std::map<not_null<HistoryItem*>, std::unique_ptr<Element>, std::less<>> _views; std::map<not_null<HistoryItem*>, std::unique_ptr<Element>, std::less<>> _views;
int _itemsTop = 0; int _itemsTop = 0;
int _itemsWidth = 0;
int _itemsHeight = 0; int _itemsHeight = 0;
int _minHeight = 0; int _minHeight = 0;

View file

@ -192,8 +192,10 @@ LogEntryOriginal &LogEntryOriginal::operator=(LogEntryOriginal &&other) {
LogEntryOriginal::~LogEntryOriginal() = default; LogEntryOriginal::~LogEntryOriginal() = default;
Message::Message(not_null<HistoryMessage*> data, Context context) Message::Message(
: Element(data, context) { not_null<ElementDelegate*> delegate,
not_null<HistoryMessage*> data)
: Element(delegate, data) {
initLogEntryOriginal(); initLogEntryOriginal();
} }
@ -637,6 +639,9 @@ bool Message::displayFromPhoto() const {
} }
bool Message::hasFromPhoto() const { bool Message::hasFromPhoto() const {
if (isHiddenByGroup()) {
return false;
}
switch (context()) { switch (context()) {
case Context::AdminLog: case Context::AdminLog:
case Context::Feed: case Context::Feed:
@ -1486,13 +1491,6 @@ TextSelection Message::unskipTextSelection(TextSelection selection) const {
QRect Message::countGeometry() const { QRect Message::countGeometry() const {
const auto item = message(); const auto item = message();
const auto media = this->media();
auto maxwidth = qMin(st::msgMaxWidth, maxWidth());
if (media && media->width() < maxwidth) {
maxwidth = qMax(media->width(), qMin(maxwidth, plainMaxWidth()));
}
const auto outbg = hasOutLayout(); const auto outbg = hasOutLayout();
auto contentLeft = (outbg && !Adaptive::ChatWide()) auto contentLeft = (outbg && !Adaptive::ChatWide())
? st::msgMargin.right() ? st::msgMargin.right()
@ -1503,15 +1501,25 @@ QRect Message::countGeometry() const {
// contentLeft += st::msgPhotoSkip - (hmaxwidth - hwidth); // contentLeft += st::msgPhotoSkip - (hmaxwidth - hwidth);
} }
auto contentWidth = width() - st::msgMargin.left() - st::msgMargin.right(); const auto media = this->media();
const auto mediaWidth = media ? media->width() : width();
const auto availableWidth = width() - st::msgMargin.left() - st::msgMargin.right();
auto contentWidth = availableWidth;
if (item->history()->peer->isSelf() && !outbg) { if (item->history()->peer->isSelf() && !outbg) {
contentWidth -= st::msgPhotoSkip; contentWidth -= st::msgPhotoSkip;
} }
if (contentWidth > maxwidth) { accumulate_min(contentWidth, maxWidth());
if (outbg && !Adaptive::ChatWide()) { accumulate_min(contentWidth, st::msgMaxWidth);
contentLeft += contentWidth - maxwidth; if (mediaWidth < contentWidth) {
const auto textualWidth = plainMaxWidth();
if (mediaWidth < textualWidth) {
accumulate_min(contentWidth, textualWidth);
} else {
contentWidth = mediaWidth;
} }
contentWidth = maxwidth; }
if (contentWidth < availableWidth && outbg && !Adaptive::ChatWide()) {
contentLeft += availableWidth - contentWidth;
} }
const auto contentTop = marginTop(); const auto contentTop = marginTop();
@ -1523,47 +1531,59 @@ QRect Message::countGeometry() const {
} }
int Message::resizeContentGetHeight(int newWidth) { int Message::resizeContentGetHeight(int newWidth) {
const auto item = message(); if (isHiddenByGroup()) {
const auto media = this->media(); return 0;
} else if (newWidth < st::msgMinWidth) {
if (newWidth < st::msgMinWidth) {
return height(); return height();
} }
auto newHeight = minHeight(); auto newHeight = minHeight();
const auto item = message();
const auto media = this->media();
const auto mediaDisplayed = media ? media->isDisplayed() : false;
const auto bubble = drawBubble();
// This code duplicates countGeometry() but also resizes media.
auto contentWidth = newWidth - (st::msgMargin.left() + st::msgMargin.right()); auto contentWidth = newWidth - (st::msgMargin.left() + st::msgMargin.right());
if (item->history()->peer->isSelf() && !hasOutLayout()) { if (item->history()->peer->isSelf() && !hasOutLayout()) {
contentWidth -= st::msgPhotoSkip; contentWidth -= st::msgPhotoSkip;
} }
if (contentWidth < st::msgPadding.left() + st::msgPadding.right() + 1) { accumulate_min(contentWidth, maxWidth());
contentWidth = st::msgPadding.left() + st::msgPadding.right() + 1; accumulate_min(contentWidth, st::msgMaxWidth);
} else if (contentWidth > st::msgMaxWidth) { if (mediaDisplayed) {
contentWidth = st::msgMaxWidth; media->resizeGetHeight(bubble
? std::min(contentWidth, maxWidth())
: contentWidth);
if (media->width() < contentWidth) {
const auto textualWidth = plainMaxWidth();
if (media->width() < textualWidth) {
accumulate_min(contentWidth, textualWidth);
} else {
contentWidth = media->width();
}
}
} }
if (drawBubble()) {
if (bubble) {
auto forwarded = item->Get<HistoryMessageForwarded>(); auto forwarded = item->Get<HistoryMessageForwarded>();
auto reply = item->Get<HistoryMessageReply>(); auto reply = item->Get<HistoryMessageReply>();
auto via = item->Get<HistoryMessageVia>(); auto via = item->Get<HistoryMessageVia>();
auto entry = logEntryOriginal(); auto entry = logEntryOriginal();
auto mediaDisplayed = false;
if (media) {
mediaDisplayed = media->isDisplayed();
}
// Entry page is always a bubble bottom. // Entry page is always a bubble bottom.
auto mediaOnBottom = (mediaDisplayed && media->isBubbleBottom()) || (entry/* && entry->isBubbleBottom()*/); auto mediaOnBottom = (mediaDisplayed && media->isBubbleBottom()) || (entry/* && entry->isBubbleBottom()*/);
auto mediaOnTop = (mediaDisplayed && media->isBubbleTop()) || (entry && entry->isBubbleTop()); auto mediaOnTop = (mediaDisplayed && media->isBubbleTop()) || (entry && entry->isBubbleTop());
if (contentWidth >= maxWidth()) { if (contentWidth == maxWidth()) {
if (mediaDisplayed) { if (mediaDisplayed) {
media->resizeGetHeight(maxWidth()); media->resizeGetHeight(contentWidth);
if (entry) { if (entry) {
newHeight += entry->resizeGetHeight(countGeometry().width()); newHeight += entry->resizeGetHeight(contentWidth);
} }
} else if (entry) { } else if (entry) {
// In case of text-only message it is counted in minHeight already. // In case of text-only message it is counted in minHeight already.
entry->resizeGetHeight(countGeometry().width()); entry->resizeGetHeight(contentWidth);
} }
} else { } else {
if (hasVisibleText()) { if (hasVisibleText()) {
@ -1588,7 +1608,7 @@ int Message::resizeContentGetHeight(int newWidth) {
if (mediaDisplayed) { if (mediaDisplayed) {
newHeight += media->resizeGetHeight(contentWidth); newHeight += media->resizeGetHeight(contentWidth);
if (entry) { if (entry) {
newHeight += entry->resizeGetHeight(countGeometry().width()); newHeight += entry->resizeGetHeight(contentWidth);
} }
} else if (entry) { } else if (entry) {
newHeight += entry->resizeGetHeight(contentWidth); newHeight += entry->resizeGetHeight(contentWidth);
@ -1596,20 +1616,20 @@ int Message::resizeContentGetHeight(int newWidth) {
} }
if (displayFromName()) { if (displayFromName()) {
fromNameUpdated(countGeometry().width()); fromNameUpdated(contentWidth);
newHeight += st::msgNameFont->height; newHeight += st::msgNameFont->height;
} else if (via && !forwarded) { } else if (via && !forwarded) {
via->resize(countGeometry().width() - st::msgPadding.left() - st::msgPadding.right()); via->resize(contentWidth - st::msgPadding.left() - st::msgPadding.right());
newHeight += st::msgNameFont->height; newHeight += st::msgNameFont->height;
} }
if (displayForwardedFrom()) { if (displayForwardedFrom()) {
auto fwdheight = ((forwarded->text.maxWidth() > (countGeometry().width() - st::msgPadding.left() - st::msgPadding.right())) ? 2 : 1) * st::semiboldFont->height; auto fwdheight = ((forwarded->text.maxWidth() > (contentWidth - st::msgPadding.left() - st::msgPadding.right())) ? 2 : 1) * st::semiboldFont->height;
newHeight += fwdheight; newHeight += fwdheight;
} }
if (reply) { if (reply) {
reply->resize(countGeometry().width() - st::msgPadding.left() - st::msgPadding.right()); reply->resize(contentWidth - st::msgPadding.left() - st::msgPadding.right());
newHeight += st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom(); newHeight += st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom();
} }
} else if (media && media->isDisplayed()) { } else if (media && media->isDisplayed()) {
@ -1618,10 +1638,9 @@ int Message::resizeContentGetHeight(int newWidth) {
newHeight = 0; newHeight = 0;
} }
if (const auto keyboard = item->inlineReplyKeyboard()) { if (const auto keyboard = item->inlineReplyKeyboard()) {
const auto g = countGeometry();
const auto keyboardHeight = st::msgBotKbButton.margin + keyboard->naturalHeight(); const auto keyboardHeight = st::msgBotKbButton.margin + keyboard->naturalHeight();
newHeight += keyboardHeight; newHeight += keyboardHeight;
keyboard->resize(g.width(), keyboardHeight - st::msgBotKbButton.margin); keyboard->resize(contentWidth, keyboardHeight - st::msgBotKbButton.margin);
} }
newHeight += marginTop() + marginBottom(); newHeight += marginTop() + marginBottom();

View file

@ -28,7 +28,9 @@ struct LogEntryOriginal
class Message : public Element { class Message : public Element {
public: public:
Message(not_null<HistoryMessage*> data, Context context); Message(
not_null<ElementDelegate*> delegate,
not_null<HistoryMessage*> data);
void draw( void draw(
Painter &p, Painter &p,

View file

@ -292,8 +292,10 @@ void serviceColorsUpdated() {
} }
} }
Service::Service(not_null<HistoryService*> data, Context context) Service::Service(
: Element(data, context) { not_null<ElementDelegate*> delegate,
not_null<HistoryService*> data)
: Element(delegate, data) {
} }
not_null<HistoryService*> Service::message() const { not_null<HistoryService*> Service::message() const {

View file

@ -15,7 +15,9 @@ namespace HistoryView {
class Service : public Element { class Service : public Element {
public: public:
Service(not_null<HistoryService*> data, Context context); Service(
not_null<ElementDelegate*> delegate,
not_null<HistoryService*> data);
void draw( void draw(
Painter &p, Painter &p,

View file

@ -881,6 +881,7 @@ void MainWidget::cancelUploadLayer(not_null<HistoryItem*> item) {
if (wasLast && !history->lastMsg) { if (wasLast && !history->lastMsg) {
checkPeerHistory(history->peer); checkPeerHistory(history->peer);
} }
Auth().data().sendHistoryChangeNotifications();
} }
Auth().uploader().unpause(); Auth().uploader().unpause();
}), base::lambda_guarded(this, [] { }), base::lambda_guarded(this, [] {
@ -1069,7 +1070,12 @@ void MainWidget::deleteAllFromUser(ChannelData *channel, UserData *from) {
} }
} }
} }
MTP::send(MTPchannels_DeleteUserHistory(channel->inputChannel, from->inputUser), rpcDone(&MainWidget::deleteAllFromUserPart, { channel, from })); MTP::send(
MTPchannels_DeleteUserHistory(
channel->inputChannel,
from->inputUser),
rpcDone(&MainWidget::deleteAllFromUserPart, { channel, from }));
Auth().data().sendHistoryChangeNotifications();
} }
void MainWidget::deleteAllFromUserPart(DeleteAllFromUserParams params, const MTPmessages_AffectedHistory &result) { void MainWidget::deleteAllFromUserPart(DeleteAllFromUserParams params, const MTPmessages_AffectedHistory &result) {
@ -1525,8 +1531,9 @@ void MainWidget::searchMessages(const QString &query, PeerData *inPeer) {
} }
} }
void MainWidget::itemEdited(HistoryItem *item) { void MainWidget::itemEdited(not_null<HistoryItem*> item) {
if (_history->peer() == item->history()->peer || (_history->peer() && _history->peer() == item->history()->peer->migrateTo())) { if (_history->peer() == item->history()->peer
|| (_history->peer() && _history->peer() == item->history()->peer->migrateTo())) {
_history->itemEdited(item); _history->itemEdited(item);
} }
} }
@ -2158,6 +2165,9 @@ void MainWidget::ui_showPeerHistory(
} }
} }
if (_history->isHidden()) { if (_history->isHidden()) {
if (!Adaptive::OneColumn() && way == Way::ClearStack) {
return false;
}
return (_mainSection != nullptr) return (_mainSection != nullptr)
|| (Adaptive::OneColumn() && !_dialogs->isHidden()); || (Adaptive::OneColumn() && !_dialogs->isHidden());
} }
@ -2530,7 +2540,9 @@ void MainWidget::showNewSection(
|| memento.instant()) { || memento.instant()) {
return false; return false;
} }
if (Adaptive::OneColumn() if (!Adaptive::OneColumn() && params.way == SectionShow::Way::ClearStack) {
return false;
} else if (Adaptive::OneColumn()
|| (newThirdSection && _thirdSection) || (newThirdSection && _thirdSection)
|| (newMainSection && isMainSectionShown())) { || (newMainSection && isMainSectionShown())) {
return true; return true;

View file

@ -252,7 +252,7 @@ public:
void jumpToDate(not_null<PeerData*> peer, const QDate &date); void jumpToDate(not_null<PeerData*> peer, const QDate &date);
void searchMessages(const QString &query, PeerData *inPeer); void searchMessages(const QString &query, PeerData *inPeer);
void itemEdited(HistoryItem *item); void itemEdited(not_null<HistoryItem*> item);
void checkLastUpdate(bool afterSleep); void checkLastUpdate(bool afterSleep);

View file

@ -611,10 +611,6 @@ void Messenger::handleAppDeactivated() {
Ui::Tooltip::Hide(); Ui::Tooltip::Hide();
} }
void Messenger::call_handleHistoryUpdate() {
Notify::handlePendingHistoryUpdate();
}
void Messenger::call_handleUnreadCounterUpdate() { void Messenger::call_handleUnreadCounterUpdate() {
Global::RefUnreadCounterUpdate().notify(true); Global::RefUnreadCounterUpdate().notify(true);
} }

View file

@ -178,7 +178,6 @@ public:
void handleAppActivated(); void handleAppActivated();
void handleAppDeactivated(); void handleAppDeactivated();
void call_handleHistoryUpdate();
void call_handleUnreadCounterUpdate(); void call_handleUnreadCounterUpdate();
void call_handleDelayedPeerUpdates(); void call_handleDelayedPeerUpdates();
void call_handleObservables(); void call_handleObservables();

View file

@ -367,6 +367,7 @@ Video::Video(
, _duration(formatDurationText(_data->duration())) , _duration(formatDurationText(_data->duration()))
, _thumbLoaded(false) { , _thumbLoaded(false) {
setDocumentLinks(_data); setDocumentLinks(_data);
_data->thumb->load();
} }
void Video::initDimensions() { void Video::initDimensions() {