mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-04-01 14:50:24 +00:00
Manage unread bar using HistoryView::Element-s.
This commit is contained in:
parent
861ab85ca1
commit
ebd4651ac2
@ -1225,6 +1225,9 @@ namespace {
|
||||
}
|
||||
|
||||
History *historyLoaded(const PeerId &peer) {
|
||||
if (!peer) {
|
||||
return nullptr;
|
||||
}
|
||||
return ::histories.find(peer);
|
||||
}
|
||||
|
||||
|
@ -190,27 +190,33 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
void UpdateComponents(uint64 mask = 0) {
|
||||
if (!_meta()->equals(mask)) {
|
||||
RuntimeComposerBase tmp(mask);
|
||||
tmp.swap(*this);
|
||||
if (_data != zerodata() && tmp._data != zerodata()) {
|
||||
auto meta = _meta(), wasmeta = tmp._meta();
|
||||
for (int i = 0; i < meta->last; ++i) {
|
||||
auto offset = meta->offsets[i];
|
||||
auto wasoffset = wasmeta->offsets[i];
|
||||
if (offset >= sizeof(_meta()) && wasoffset >= sizeof(_meta())) {
|
||||
RuntimeComponentWraps[i].Move(_dataptrunsafe(offset), tmp._dataptrunsafe(wasoffset));
|
||||
}
|
||||
bool UpdateComponents(uint64 mask = 0) {
|
||||
if (_meta()->equals(mask)) {
|
||||
return false;
|
||||
}
|
||||
RuntimeComposerBase result(mask);
|
||||
result.swap(*this);
|
||||
if (_data != zerodata() && result._data != zerodata()) {
|
||||
const auto meta = _meta();
|
||||
const auto wasmeta = result._meta();
|
||||
for (auto i = 0; i != meta->last; ++i) {
|
||||
const auto offset = meta->offsets[i];
|
||||
const auto wasoffset = wasmeta->offsets[i];
|
||||
if (offset >= sizeof(_meta())
|
||||
&& wasoffset >= sizeof(_meta())) {
|
||||
RuntimeComponentWraps[i].Move(
|
||||
_dataptrunsafe(offset),
|
||||
result._dataptrunsafe(wasoffset));
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void AddComponents(uint64 mask = 0) {
|
||||
UpdateComponents(_meta()->maskadd(mask));
|
||||
bool AddComponents(uint64 mask = 0) {
|
||||
return UpdateComponents(_meta()->maskadd(mask));
|
||||
}
|
||||
void RemoveComponents(uint64 mask = 0) {
|
||||
UpdateComponents(_meta()->maskremove(mask));
|
||||
bool RemoveComponents(uint64 mask = 0) {
|
||||
return UpdateComponents(_meta()->maskremove(mask));
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -222,7 +222,7 @@ InnerWidget::InnerWidget(
|
||||
Auth().data().viewResizeRequest(
|
||||
) | rpl::start_with_next([this](auto view) {
|
||||
if (view->delegate() == this) {
|
||||
updateSize();
|
||||
resizeItem(view);
|
||||
}
|
||||
}, lifetime());
|
||||
Auth().data().itemViewRefreshRequest(
|
||||
@ -1618,6 +1618,10 @@ void InnerWidget::repaintItem(const Element *view) {
|
||||
update(0, itemTop(view), width(), view->height());
|
||||
}
|
||||
|
||||
void InnerWidget::resizeItem(not_null<Element*> view) {
|
||||
updateSize();
|
||||
}
|
||||
|
||||
void InnerWidget::refreshItem(not_null<const Element*> view) {
|
||||
// No need to refresh views in admin log.
|
||||
}
|
||||
|
@ -123,6 +123,7 @@ private:
|
||||
int itemTop(not_null<const Element*> view) const;
|
||||
void repaintItem(const Element *view);
|
||||
void refreshItem(not_null<const Element*> view);
|
||||
void resizeItem(not_null<Element*> view);
|
||||
QPoint mapPointToItem(QPoint point, const Element *view) const;
|
||||
|
||||
void showContextMenu(QContextMenuEvent *e, bool showFromTouch = false);
|
||||
|
@ -79,13 +79,8 @@ void History::clearLastKeyboard() {
|
||||
lastKeyboardFrom = 0;
|
||||
}
|
||||
|
||||
bool History::canHaveFromPhotos() const {
|
||||
if (peer->isUser() && !peer->isSelf() && !Adaptive::ChatWide()) {
|
||||
return false;
|
||||
} else if (isChannel() && !peer->isMegagroup()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
int History::height() const {
|
||||
return _height;
|
||||
}
|
||||
|
||||
void History::setHasPendingResizedItems() {
|
||||
@ -259,9 +254,22 @@ bool History::mySendActionUpdated(SendAction::Type type, bool doing) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool History::paintSendAction(Painter &p, int x, int y, int availableWidth, int outerWidth, style::color color, TimeMs ms) {
|
||||
bool History::paintSendAction(
|
||||
Painter &p,
|
||||
int x,
|
||||
int y,
|
||||
int availableWidth,
|
||||
int outerWidth,
|
||||
style::color color,
|
||||
TimeMs ms) {
|
||||
if (_sendActionAnimation) {
|
||||
_sendActionAnimation.paint(p, color, x, y + st::normalFont->ascent, outerWidth, ms);
|
||||
_sendActionAnimation.paint(
|
||||
p,
|
||||
color,
|
||||
x,
|
||||
y + st::normalFont->ascent,
|
||||
outerWidth,
|
||||
ms);
|
||||
auto animationWidth = _sendActionAnimation.width();
|
||||
x += animationWidth;
|
||||
availableWidth -= animationWidth;
|
||||
@ -572,7 +580,11 @@ not_null<History*> Histories::findOrInsert(const PeerId &peerId) {
|
||||
return i.value();
|
||||
}
|
||||
|
||||
not_null<History*> Histories::findOrInsert(const PeerId &peerId, int32 unreadCount, int32 maxInboxRead, int32 maxOutboxRead) {
|
||||
not_null<History*> Histories::findOrInsert(
|
||||
const PeerId &peerId,
|
||||
int unreadCount,
|
||||
MsgId maxInboxRead,
|
||||
MsgId maxOutboxRead) {
|
||||
auto i = map.constFind(peerId);
|
||||
if (i == map.cend()) {
|
||||
auto history = peerIsChannel(peerId)
|
||||
@ -1397,6 +1409,23 @@ void History::clearSendAction(not_null<UserData*> from) {
|
||||
}
|
||||
}
|
||||
|
||||
void History::mainViewRemoved(
|
||||
not_null<HistoryBlock*> block,
|
||||
not_null<HistoryView::Element*> view) {
|
||||
if (lastSentMsg == view->data()) {
|
||||
lastSentMsg = nullptr;
|
||||
}
|
||||
if (_firstUnreadView == view) {
|
||||
getNextFirstUnreadMessage();
|
||||
}
|
||||
if (_unreadBarView == view) {
|
||||
_unreadBarView = nullptr;
|
||||
}
|
||||
if (scrollTopItem == view) {
|
||||
getNextScrollTopItem(block, view->indexInBlock());
|
||||
}
|
||||
}
|
||||
|
||||
void History::newItemAdded(not_null<HistoryItem*> item) {
|
||||
App::checkImageCacheSize();
|
||||
item->indexAsNewItem();
|
||||
@ -1408,9 +1437,7 @@ void History::newItemAdded(not_null<HistoryItem*> item) {
|
||||
from->madeAction(itemServerTime.v);
|
||||
}
|
||||
if (item->out()) {
|
||||
if (unreadBar) {
|
||||
unreadBar->destroyUnreadBar();
|
||||
}
|
||||
destroyUnreadBar();
|
||||
if (!item->unread()) {
|
||||
outboxRead(item);
|
||||
}
|
||||
@ -1739,18 +1766,23 @@ int History::countUnread(MsgId upTo) {
|
||||
return result;
|
||||
}
|
||||
|
||||
void History::updateShowFrom() {
|
||||
if (showFrom) return;
|
||||
void History::calculateFirstUnreadMessage() {
|
||||
if (_firstUnreadView) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto i = blocks.cend(); i != blocks.cbegin();) {
|
||||
--i;
|
||||
const auto &messages = (*i)->messages;
|
||||
for (auto j = messages.cend(); j != messages.cbegin();) {
|
||||
--j;
|
||||
const auto item = (*j)->data();
|
||||
if (item->id > 0 && (!item->out() || !showFrom)) {
|
||||
const auto view = j->get();
|
||||
const auto item = view->data();
|
||||
if (!IsServerMsgId(item->id)) {
|
||||
continue;
|
||||
} else if (!item->out() || !_firstUnreadView) {
|
||||
if (item->id >= inboxReadBefore) {
|
||||
showFrom = item;
|
||||
_firstUnreadView = view;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
@ -1776,7 +1808,7 @@ MsgId History::inboxRead(MsgId upTo) {
|
||||
}
|
||||
}
|
||||
|
||||
showFrom = nullptr;
|
||||
_firstUnreadView = nullptr;
|
||||
Auth().notifications().clearFromHistory(this);
|
||||
|
||||
return upTo;
|
||||
@ -1805,13 +1837,19 @@ HistoryItem *History::lastAvailableMessage() const {
|
||||
void History::setUnreadCount(int newUnreadCount) {
|
||||
if (_unreadCount != newUnreadCount) {
|
||||
if (newUnreadCount == 1) {
|
||||
if (loadedAtBottom()) showFrom = lastAvailableMessage();
|
||||
if (loadedAtBottom()) {
|
||||
_firstUnreadView = !isEmpty()
|
||||
? blocks.back()->messages.back().get()
|
||||
: nullptr;
|
||||
}
|
||||
inboxReadBefore = qMax(inboxReadBefore, msgIdForRead());
|
||||
} else if (!newUnreadCount) {
|
||||
showFrom = nullptr;
|
||||
_firstUnreadView = nullptr;
|
||||
inboxReadBefore = qMax(inboxReadBefore, msgIdForRead() + 1);
|
||||
} else {
|
||||
if (!showFrom && !unreadBar && loadedAtBottom()) updateShowFrom();
|
||||
if (!_firstUnreadView && !_unreadBarView && loadedAtBottom()) {
|
||||
calculateFirstUnreadMessage();
|
||||
}
|
||||
}
|
||||
if (inChatList(Dialogs::Mode::All)) {
|
||||
App::histories().unreadIncrement(newUnreadCount - _unreadCount, mute());
|
||||
@ -1820,22 +1858,17 @@ void History::setUnreadCount(int newUnreadCount) {
|
||||
}
|
||||
}
|
||||
_unreadCount = newUnreadCount;
|
||||
if (auto main = App::main()) {
|
||||
main->unreadCountChanged(this);
|
||||
}
|
||||
if (unreadBar) {
|
||||
int32 count = _unreadCount;
|
||||
if (peer->migrateTo()) {
|
||||
if (History *h = App::historyLoaded(peer->migrateTo()->id)) {
|
||||
count += h->unreadCount();
|
||||
}
|
||||
}
|
||||
if (_unreadBarView) {
|
||||
const auto count = chatListUnreadCount();
|
||||
if (count > 0) {
|
||||
unreadBar->setUnreadBarCount(count);
|
||||
_unreadBarView->setUnreadBarCount(count);
|
||||
} else {
|
||||
unreadBar->setUnreadBarFreezed();
|
||||
_unreadBarView->setUnreadBarFreezed();
|
||||
}
|
||||
}
|
||||
if (const auto main = App::main()) {
|
||||
main->unreadCountChanged(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1858,18 +1891,21 @@ bool History::changeMute(bool newMute) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void History::getNextShowFrom(HistoryBlock *block, int i) {
|
||||
const auto setFromMessage = [&](const auto &message) {
|
||||
const auto item = message->data();
|
||||
if (item->id > 0) {
|
||||
showFrom = item;
|
||||
void History::getNextFirstUnreadMessage() {
|
||||
Expects(_firstUnreadView != nullptr);
|
||||
|
||||
const auto block = _firstUnreadView->block();
|
||||
const auto index = _firstUnreadView->indexInBlock();
|
||||
const auto setFromMessage = [&](const auto &view) {
|
||||
if (IsServerMsgId(view->data()->id)) {
|
||||
_firstUnreadView = view.get();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
if (i >= 0) {
|
||||
auto l = block->messages.size();
|
||||
for (++i; i < l; ++i) {
|
||||
if (index >= 0) {
|
||||
const auto count = int(block->messages.size());
|
||||
for (auto i = index + 1; i != count; ++i) {
|
||||
const auto &message = block->messages[i];
|
||||
if (setFromMessage(block->messages[i])) {
|
||||
return;
|
||||
@ -1877,15 +1913,15 @@ void History::getNextShowFrom(HistoryBlock *block, int i) {
|
||||
}
|
||||
}
|
||||
|
||||
for (auto j = block->indexInHistory() + 1, s = int(blocks.size()); j < s; ++j) {
|
||||
block = blocks[j].get();
|
||||
for (const auto &message : block->messages) {
|
||||
const auto count = int(blocks.size());
|
||||
for (auto j = block->indexInHistory() + 1; j != count; ++j) {
|
||||
for (const auto &message : blocks[j]->messages) {
|
||||
if (setFromMessage(message)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
showFrom = nullptr;
|
||||
_firstUnreadView = nullptr;
|
||||
}
|
||||
|
||||
QDateTime History::adjustChatListDate() const {
|
||||
@ -1976,26 +2012,44 @@ void History::getNextScrollTopItem(HistoryBlock *block, int32 i) {
|
||||
}
|
||||
|
||||
void History::addUnreadBar() {
|
||||
if (unreadBar || !showFrom || !showFrom->mainView() || !unreadCount()) {
|
||||
if (_unreadBarView || !_firstUnreadView || !unreadCount()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int32 count = unreadCount();
|
||||
if (peer->migrateTo()) {
|
||||
if (History *h = App::historyLoaded(peer->migrateTo()->id)) {
|
||||
count += h->unreadCount();
|
||||
}
|
||||
if (const auto count = chatListUnreadCount()) {
|
||||
_unreadBarView = _firstUnreadView;
|
||||
_unreadBarView->setUnreadBarCount(count);
|
||||
}
|
||||
showFrom->setUnreadBarCount(count);
|
||||
unreadBar = showFrom;
|
||||
}
|
||||
|
||||
void History::destroyUnreadBar() {
|
||||
if (unreadBar) {
|
||||
unreadBar->destroyUnreadBar();
|
||||
if (const auto view = base::take(_unreadBarView)) {
|
||||
view->destroyUnreadBar();
|
||||
}
|
||||
}
|
||||
|
||||
bool History::hasNotFreezedUnreadBar() const {
|
||||
if (_firstUnreadView) {
|
||||
if (const auto view = _unreadBarView) {
|
||||
if (const auto bar = view->Get<HistoryView::UnreadBar>()) {
|
||||
return !bar->freezed;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void History::unsetFirstUnreadMessage() {
|
||||
_firstUnreadView = nullptr;
|
||||
}
|
||||
|
||||
HistoryView::Element *History::unreadBar() const {
|
||||
return _unreadBarView;
|
||||
}
|
||||
|
||||
HistoryView::Element *History::firstUnreadMessage() const {
|
||||
return _firstUnreadView;
|
||||
}
|
||||
|
||||
not_null<HistoryItem*> History::addNewInTheMiddle(
|
||||
not_null<HistoryItem*> item,
|
||||
int blockIndex,
|
||||
@ -2028,10 +2082,16 @@ not_null<HistoryItem*> History::addNewInTheMiddle(
|
||||
|
||||
int History::chatListUnreadCount() const {
|
||||
const auto result = unreadCount();
|
||||
if (const auto from = peer->migrateFrom()) {
|
||||
if (const auto migrated = App::historyLoaded(from)) {
|
||||
return result + migrated->unreadCount();
|
||||
const auto addFromId = [&] {
|
||||
if (const auto from = peer->migrateFrom()) {
|
||||
return from->id;
|
||||
} else if (const auto to = peer->migrateTo()) {
|
||||
return to->id;
|
||||
}
|
||||
return PeerId(0);
|
||||
}();
|
||||
if (const auto migrated = App::historyLoaded(addFromId)) {
|
||||
return result + migrated->unreadCount();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -2108,10 +2168,10 @@ bool History::isReadyFor(MsgId msgId) {
|
||||
return loadedAtBottom();
|
||||
}
|
||||
if (msgId == ShowAtUnreadMsgId) {
|
||||
if (peer->migrateFrom()) { // old group history
|
||||
if (History *h = App::historyLoaded(peer->migrateFrom()->id)) {
|
||||
if (h->unreadCount()) {
|
||||
return h->isReadyFor(msgId);
|
||||
if (const auto migratePeer = peer->migrateFrom()) {
|
||||
if (const auto migrated = App::historyLoaded(migratePeer)) {
|
||||
if (migrated->unreadCount()) {
|
||||
return migrated->isReadyFor(msgId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2136,12 +2196,14 @@ void History::getReadyFor(MsgId msgId) {
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (msgId == ShowAtUnreadMsgId && peer->migrateFrom()) {
|
||||
if (auto h = App::historyLoaded(peer->migrateFrom()->id)) {
|
||||
if (h->unreadCount()) {
|
||||
clear(true);
|
||||
h->getReadyFor(msgId);
|
||||
return;
|
||||
if (msgId == ShowAtUnreadMsgId) {
|
||||
if (const auto migratePeer = peer->migrateFrom()) {
|
||||
if (const auto migrated = App::historyLoaded(migratePeer)) {
|
||||
if (migrated->unreadCount()) {
|
||||
clear(true);
|
||||
migrated->getReadyFor(msgId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2194,7 +2256,7 @@ bool History::needUpdateInChatList() const {
|
||||
}
|
||||
|
||||
void History::fixLastMessage(bool wasAtBottom) {
|
||||
setLastMessage(wasAtBottom ? lastAvailableMessage() : 0);
|
||||
setLastMessage(wasAtBottom ? lastAvailableMessage() : nullptr);
|
||||
}
|
||||
|
||||
MsgId History::minMsgId() const {
|
||||
@ -2227,22 +2289,21 @@ MsgId History::msgIdForRead() const {
|
||||
return result;
|
||||
}
|
||||
|
||||
int History::resizeGetHeight(int newWidth) {
|
||||
const auto resizeAllItems = (width != newWidth);
|
||||
void History::resizeToWidth(int newWidth) {
|
||||
const auto resizeAllItems = (_width != newWidth);
|
||||
|
||||
if (!resizeAllItems && !hasPendingResizedItems()) {
|
||||
return height;
|
||||
return;
|
||||
}
|
||||
_flags &= ~(Flag::f_has_pending_resized_items);
|
||||
|
||||
width = newWidth;
|
||||
_width = newWidth;
|
||||
int y = 0;
|
||||
for (const auto &block : blocks) {
|
||||
block->setY(y);
|
||||
y += block->resizeGetHeight(newWidth, resizeAllItems);
|
||||
}
|
||||
height = y;
|
||||
return height;
|
||||
_height = y;
|
||||
}
|
||||
|
||||
ChannelHistory *History::asChannelHistory() {
|
||||
@ -2295,11 +2356,11 @@ bool History::removeOrphanMediaGroupPart() {
|
||||
}
|
||||
|
||||
void History::clear(bool leaveItems) {
|
||||
if (unreadBar) {
|
||||
unreadBar = nullptr;
|
||||
if (_unreadBarView) {
|
||||
_unreadBarView = nullptr;
|
||||
}
|
||||
if (showFrom) {
|
||||
showFrom = nullptr;
|
||||
if (_firstUnreadView) {
|
||||
_firstUnreadView = nullptr;
|
||||
}
|
||||
if (lastSentMsg) {
|
||||
lastSentMsg = nullptr;
|
||||
@ -2475,22 +2536,11 @@ void HistoryBlock::clear(bool leaveItems) {
|
||||
void HistoryBlock::remove(not_null<Element*> view) {
|
||||
Expects(view->block() == this);
|
||||
|
||||
const auto item = view->data();
|
||||
auto blockIndex = indexInHistory();
|
||||
auto itemIndex = view->indexInBlock();
|
||||
if (_history->showFrom == item) {
|
||||
_history->getNextShowFrom(this, itemIndex);
|
||||
}
|
||||
if (_history->lastSentMsg == item) {
|
||||
_history->lastSentMsg = nullptr;
|
||||
}
|
||||
if (_history->unreadBar == item) {
|
||||
_history->unreadBar = nullptr;
|
||||
}
|
||||
if (_history->scrollTopItem && _history->scrollTopItem->data() == item) {
|
||||
_history->getNextScrollTopItem(this, itemIndex);
|
||||
}
|
||||
_history->mainViewRemoved(this, view);
|
||||
|
||||
const auto blockIndex = indexInHistory();
|
||||
const auto itemIndex = view->indexInBlock();
|
||||
const auto item = view->data();
|
||||
item->clearMainView();
|
||||
messages.erase(messages.begin() + itemIndex);
|
||||
for (auto i = itemIndex, l = int(messages.size()); i < l; ++i) {
|
||||
|
@ -47,7 +47,11 @@ public:
|
||||
|
||||
History *find(const PeerId &peerId);
|
||||
not_null<History*> findOrInsert(const PeerId &peerId);
|
||||
not_null<History*> findOrInsert(const PeerId &peerId, int32 unreadCount, int32 maxInboxRead, int32 maxOutboxRead);
|
||||
not_null<History*> findOrInsert(
|
||||
const PeerId &peerId,
|
||||
int unreadCount,
|
||||
MsgId maxInboxRead,
|
||||
MsgId maxOutboxRead);
|
||||
|
||||
void clear();
|
||||
void remove(const PeerId &peer);
|
||||
@ -153,8 +157,6 @@ public:
|
||||
|
||||
void applyGroupAdminChanges(const base::flat_map<UserId, bool> &changes);
|
||||
|
||||
virtual ~History();
|
||||
|
||||
HistoryItem *addNewMessage(const MTPMessage &msg, NewMessageType type);
|
||||
HistoryItem *addToHistory(const MTPMessage &msg);
|
||||
not_null<HistoryItem*> addNewService(MsgId msgId, QDateTime date, const QString &text, MTPDmessage::Flags flags = 0, bool newMsg = true);
|
||||
@ -176,14 +178,11 @@ public:
|
||||
void newItemAdded(not_null<HistoryItem*> item);
|
||||
|
||||
int countUnread(MsgId upTo);
|
||||
void updateShowFrom();
|
||||
MsgId inboxRead(MsgId upTo);
|
||||
MsgId inboxRead(HistoryItem *wasRead);
|
||||
MsgId outboxRead(MsgId upTo);
|
||||
MsgId outboxRead(HistoryItem *wasRead);
|
||||
|
||||
HistoryItem *lastAvailableMessage() const;
|
||||
|
||||
int unreadCount() const {
|
||||
return _unreadCount;
|
||||
}
|
||||
@ -192,9 +191,13 @@ public:
|
||||
return _mute;
|
||||
}
|
||||
bool changeMute(bool newMute);
|
||||
void getNextShowFrom(HistoryBlock *block, int i);
|
||||
void addUnreadBar();
|
||||
void destroyUnreadBar();
|
||||
bool hasNotFreezedUnreadBar() const;
|
||||
HistoryView::Element *unreadBar() const;
|
||||
void calculateFirstUnreadMessage();
|
||||
void unsetFirstUnreadMessage();
|
||||
HistoryView::Element *firstUnreadMessage() const;
|
||||
void clearNotifications();
|
||||
|
||||
bool loadedAtBottom() const; // last message is in the list
|
||||
@ -210,7 +213,7 @@ public:
|
||||
MsgId maxMsgId() const;
|
||||
MsgId msgIdForRead() const;
|
||||
|
||||
int resizeGetHeight(int newWidth);
|
||||
void resizeToWidth(int newWidth);
|
||||
|
||||
void removeNotification(HistoryItem *item) {
|
||||
if (!notifies.isEmpty()) {
|
||||
@ -254,10 +257,6 @@ public:
|
||||
|
||||
void clearLastKeyboard();
|
||||
|
||||
// optimization for userpics displayed on the left
|
||||
// if this returns false there is no need to even try to handle them
|
||||
bool canHaveFromPhotos() const;
|
||||
|
||||
int getUnreadMentionsLoadedCount() const {
|
||||
return _unreadMentions.size();
|
||||
}
|
||||
@ -278,25 +277,6 @@ public:
|
||||
void eraseFromUnreadMentions(MsgId msgId);
|
||||
void addUnreadMentionsSlice(const MTPmessages_Messages &result);
|
||||
|
||||
std::deque<std::unique_ptr<HistoryBlock>> blocks;
|
||||
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
int32 msgCount = 0;
|
||||
MsgId inboxReadBefore = 1;
|
||||
MsgId outboxReadBefore = 1;
|
||||
HistoryItem *showFrom = nullptr;
|
||||
HistoryItem *unreadBar = nullptr;
|
||||
|
||||
not_null<PeerData*> peer;
|
||||
bool oldLoaded = false;
|
||||
bool newLoaded = true;
|
||||
HistoryItem *lastMsg = nullptr;
|
||||
HistoryItem *lastSentMsg = nullptr;
|
||||
|
||||
typedef QList<HistoryItem*> NotifyQueue;
|
||||
NotifyQueue notifies;
|
||||
|
||||
Data::Draft *localDraft() const {
|
||||
return _localDraft.get();
|
||||
}
|
||||
@ -340,9 +320,33 @@ public:
|
||||
int y,
|
||||
int size) const override;
|
||||
|
||||
// some fields below are a property of a currently displayed instance of this
|
||||
// conversation history not a property of the conversation history itself
|
||||
public:
|
||||
void forgetScrollState() {
|
||||
scrollTopItem = nullptr;
|
||||
}
|
||||
|
||||
// find the correct scrollTopItem and scrollTopOffset using given top
|
||||
// of the displayed window relative to the history start coordinate
|
||||
void countScrollState(int top);
|
||||
|
||||
virtual ~History();
|
||||
|
||||
// Still public data.
|
||||
std::deque<std::unique_ptr<HistoryBlock>> blocks;
|
||||
|
||||
int height() const;
|
||||
int32 msgCount = 0;
|
||||
MsgId inboxReadBefore = 1;
|
||||
MsgId outboxReadBefore = 1;
|
||||
|
||||
not_null<PeerData*> peer;
|
||||
bool oldLoaded = false;
|
||||
bool newLoaded = true;
|
||||
HistoryItem *lastMsg = nullptr;
|
||||
HistoryItem *lastSentMsg = nullptr;
|
||||
|
||||
typedef QList<HistoryItem*> NotifyQueue;
|
||||
NotifyQueue notifies;
|
||||
|
||||
// we save the last showAtMsgId to restore the state when switching
|
||||
// between different conversation histories
|
||||
MsgId showAtMsgId = ShowAtUnreadMsgId;
|
||||
@ -352,25 +356,7 @@ public:
|
||||
// resulting scrollTop = top(scrollTopItem) + scrollTopOffset
|
||||
HistoryView::Element *scrollTopItem = nullptr;
|
||||
int scrollTopOffset = 0;
|
||||
void forgetScrollState() {
|
||||
scrollTopItem = nullptr;
|
||||
}
|
||||
|
||||
// find the correct scrollTopItem and scrollTopOffset using given top
|
||||
// of the displayed window relative to the history start coord
|
||||
void countScrollState(int top);
|
||||
|
||||
protected:
|
||||
// when this item is destroyed scrollTopItem just points to the next one
|
||||
// and scrollTopOffset remains the same
|
||||
// if we are at the bottom of the window scrollTopItem == nullptr and
|
||||
// scrollTopOffset is undefined
|
||||
void getNextScrollTopItem(HistoryBlock *block, int32 i);
|
||||
|
||||
// helper method for countScrollState(int top)
|
||||
void countScrollTopItem(int top);
|
||||
|
||||
public:
|
||||
bool lastKeyboardInited = false;
|
||||
bool lastKeyboardUsed = false;
|
||||
MsgId lastKeyboardId = 0;
|
||||
@ -382,11 +368,18 @@ public:
|
||||
Text cloudDraftTextCache;
|
||||
|
||||
protected:
|
||||
// when this item is destroyed scrollTopItem just points to the next one
|
||||
// and scrollTopOffset remains the same
|
||||
// if we are at the bottom of the window scrollTopItem == nullptr and
|
||||
// scrollTopOffset is undefined
|
||||
void getNextScrollTopItem(HistoryBlock *block, int32 i);
|
||||
|
||||
// helper method for countScrollState(int top)
|
||||
void countScrollTopItem(int top);
|
||||
|
||||
void clearOnDestroy();
|
||||
HistoryItem *addNewToLastBlock(const MTPMessage &msg, NewMessageType type);
|
||||
|
||||
friend class HistoryBlock;
|
||||
|
||||
// this method just removes a block from the blocks list
|
||||
// when the last item from this block was detached and
|
||||
// calls the required previousItemChanged()
|
||||
@ -425,6 +418,20 @@ protected:
|
||||
}
|
||||
|
||||
private:
|
||||
friend class HistoryBlock;
|
||||
|
||||
enum class Flag {
|
||||
f_has_pending_resized_items = (1 << 0),
|
||||
};
|
||||
using Flags = base::flags<Flag>;
|
||||
friend inline constexpr auto is_flag_type(Flag) {
|
||||
return true;
|
||||
};
|
||||
|
||||
void mainViewRemoved(
|
||||
not_null<HistoryBlock*> block,
|
||||
not_null<HistoryView::Element*> view);
|
||||
|
||||
QDateTime adjustChatListDate() const override;
|
||||
void removeDialog() override;
|
||||
void changedInChatListHook(Dialogs::Mode list, bool added) override;
|
||||
@ -451,15 +458,20 @@ private:
|
||||
void addItemsToLists(const std::vector<not_null<HistoryItem*>> &items);
|
||||
void clearSendAction(not_null<UserData*> from);
|
||||
|
||||
enum class Flag {
|
||||
f_has_pending_resized_items = (1 << 0),
|
||||
};
|
||||
using Flags = base::flags<Flag>;
|
||||
friend inline constexpr auto is_flag_type(Flag) { return true; };
|
||||
HistoryItem *lastAvailableMessage() const;
|
||||
void getNextFirstUnreadMessage();
|
||||
|
||||
// Creates if necessary a new block for adding item.
|
||||
// Depending on isBuildingFrontBlock() gets front or back block.
|
||||
HistoryBlock *prepareBlockForAddingItem();
|
||||
|
||||
Flags _flags = 0;
|
||||
bool _mute = false;
|
||||
int _unreadCount = 0;
|
||||
int _width = 0;
|
||||
int _height = 0;
|
||||
HistoryView::Element *_unreadBarView = nullptr;
|
||||
HistoryView::Element *_firstUnreadView = nullptr;
|
||||
|
||||
base::optional<int> _unreadMentionsCount;
|
||||
base::flat_set<MsgId> _unreadMentions;
|
||||
@ -473,10 +485,6 @@ private:
|
||||
};
|
||||
std::unique_ptr<BuildingBlock> _buildingFrontBlock;
|
||||
|
||||
// Creates if necessary a new block for adding item.
|
||||
// Depending on isBuildingFrontBlock() gets front or back block.
|
||||
HistoryBlock *prepareBlockForAddingItem();
|
||||
|
||||
std::unique_ptr<Data::Draft> _localDraft, _cloudDraft;
|
||||
std::unique_ptr<Data::Draft> _editDraft;
|
||||
MessageIdsList _forwardDraft;
|
||||
|
@ -217,7 +217,7 @@ void HistoryInner::enumerateItemsInHistory(History *history, int historytop, Met
|
||||
if (historytop < 0 || history->isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (_visibleAreaBottom <= historytop || historytop + history->height <= _visibleAreaTop) {
|
||||
if (_visibleAreaBottom <= historytop || historytop + history->height() <= _visibleAreaTop) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -302,9 +302,18 @@ void HistoryInner::enumerateItemsInHistory(History *history, int historytop, Met
|
||||
}
|
||||
}
|
||||
|
||||
bool HistoryInner::canHaveFromUserpics() const {
|
||||
if (_peer->isUser() && !_peer->isSelf() && !Adaptive::ChatWide()) {
|
||||
return false;
|
||||
} else if (_peer->isChannel() && !_peer->isMegagroup()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Method>
|
||||
void HistoryInner::enumerateUserpics(Method method) {
|
||||
if ((!_history || !_history->canHaveFromPhotos()) && (!_migrated || !_migrated->canHaveFromPhotos())) {
|
||||
if (!canHaveFromUserpics()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -620,7 +629,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
|
||||
p,
|
||||
st::historyPhotoLeft,
|
||||
userpicTop,
|
||||
message->history()->width,
|
||||
width(),
|
||||
st::msgPhotoSize);
|
||||
}
|
||||
return true;
|
||||
@ -635,6 +644,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
|
||||
//// if item top is before this value always show date as a floating date
|
||||
//int showFloatingBefore = height() - 2 * (_visibleAreaBottom - _visibleAreaTop) - dateHeight;
|
||||
|
||||
|
||||
auto scrollDateOpacity = _scrollDateOpacity.current(ms, _scrollDateShown ? 1. : 0.);
|
||||
enumerateDates([&](not_null<Element*> view, int itemtop, int dateTop) {
|
||||
// stop the enumeration if the date is above the painted rect
|
||||
@ -661,16 +671,17 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
|
||||
auto opacity = (dateInPlace/* || noFloatingDate*/) ? 1. : scrollDateOpacity;
|
||||
if (opacity > 0.) {
|
||||
p.setOpacity(opacity);
|
||||
int dateY = /*noFloatingDate ? itemtop :*/ (dateTop - st::msgServiceMargin.top());
|
||||
int width = item->history()->width;
|
||||
const auto dateY = false // noFloatingDate
|
||||
? itemtop
|
||||
: (dateTop - st::msgServiceMargin.top());
|
||||
if (const auto date = item->Get<HistoryMessageDate>()) {
|
||||
date->paint(p, dateY, width);
|
||||
date->paint(p, dateY, _contentWidth);
|
||||
} else {
|
||||
HistoryView::ServiceMessagePainter::paintDate(
|
||||
p,
|
||||
item->date,
|
||||
dateY,
|
||||
width);
|
||||
_contentWidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1825,15 +1836,17 @@ void HistoryInner::keyPressEvent(QKeyEvent *e) {
|
||||
}
|
||||
|
||||
void HistoryInner::recountHistoryGeometry() {
|
||||
int visibleHeight = _scroll->height();
|
||||
_contentWidth = _scroll->width();
|
||||
|
||||
const auto visibleHeight = _scroll->height();
|
||||
int oldHistoryPaddingTop = qMax(visibleHeight - historyHeight() - st::historyPaddingBottom, 0);
|
||||
if (_botAbout && !_botAbout->info->text.isEmpty()) {
|
||||
accumulate_max(oldHistoryPaddingTop, st::msgMargin.top() + st::msgMargin.bottom() + st::msgPadding.top() + st::msgPadding.bottom() + st::msgNameFont->height + st::botDescSkip + _botAbout->height);
|
||||
}
|
||||
|
||||
_history->resizeGetHeight(_scroll->width());
|
||||
_history->resizeToWidth(_contentWidth);
|
||||
if (_migrated) {
|
||||
_migrated->resizeGetHeight(_scroll->width());
|
||||
_migrated->resizeToWidth(_contentWidth);
|
||||
}
|
||||
|
||||
// with migrated history we perhaps do not need to display first _history message
|
||||
@ -2339,7 +2352,7 @@ void HistoryInner::onUpdateSelected() {
|
||||
}
|
||||
dateWidth += st::msgServicePadding.left() + st::msgServicePadding.right();
|
||||
auto dateLeft = st::msgServiceMargin.left();
|
||||
auto maxwidth = item->history()->width;
|
||||
auto maxwidth = _contentWidth;
|
||||
if (Adaptive::ChatWide()) {
|
||||
maxwidth = qMin(maxwidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left()));
|
||||
}
|
||||
@ -2549,9 +2562,9 @@ void HistoryInner::updateDragSelection(Element *dragSelFrom, Element *dragSelTo,
|
||||
int HistoryInner::historyHeight() const {
|
||||
int result = 0;
|
||||
if (!_history || _history->isEmpty()) {
|
||||
result += _migrated ? _migrated->height : 0;
|
||||
result += _migrated ? _migrated->height() : 0;
|
||||
} else {
|
||||
result += _history->height - _historySkipHeight + (_migrated ? _migrated->height : 0);
|
||||
result += _history->height() - _historySkipHeight + (_migrated ? _migrated->height() : 0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -2574,7 +2587,7 @@ int HistoryInner::migratedTop() const {
|
||||
|
||||
int HistoryInner::historyTop() const {
|
||||
int mig = migratedTop();
|
||||
return (_history && !_history->isEmpty()) ? (mig >= 0 ? (mig + _migrated->height - _historySkipHeight) : _historyPaddingTop) : -1;
|
||||
return (_history && !_history->isEmpty()) ? (mig >= 0 ? (mig + _migrated->height() - _historySkipHeight) : _historyPaddingTop) : -1;
|
||||
}
|
||||
|
||||
int HistoryInner::historyDrawTop() const {
|
||||
|
@ -181,6 +181,7 @@ private:
|
||||
template <typename Method>
|
||||
void enumerateDates(Method method);
|
||||
|
||||
bool canHaveFromUserpics() const;
|
||||
void mouseActionStart(const QPoint &screenPos, Qt::MouseButton button);
|
||||
void mouseActionUpdate(const QPoint &screenPos);
|
||||
void mouseActionFinish(const QPoint &screenPos, Qt::MouseButton button);
|
||||
@ -276,6 +277,7 @@ private:
|
||||
not_null<PeerData*> _peer;
|
||||
not_null<History*> _history;
|
||||
History *_migrated = nullptr;
|
||||
int _contentWidth = 0;
|
||||
int _historyPaddingTop = 0;
|
||||
|
||||
// with migrated history we perhaps do not need to display first _history message
|
||||
|
@ -577,47 +577,6 @@ bool HistoryItem::unread() const {
|
||||
return (_flags & MTPDmessage_ClientFlag::f_clientside_unread);
|
||||
}
|
||||
|
||||
void HistoryItem::destroyUnreadBar() {
|
||||
if (Has<HistoryMessageUnreadBar>()) {
|
||||
Assert(!isLogEntry());
|
||||
|
||||
RemoveComponents(HistoryMessageUnreadBar::Bit());
|
||||
Auth().data().requestItemResize(this);
|
||||
if (_history->unreadBar == this) {
|
||||
_history->unreadBar = nullptr;
|
||||
}
|
||||
// #TODO recount attach to previous
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryItem::setUnreadBarCount(int count) {
|
||||
Expects(!isLogEntry());
|
||||
|
||||
if (count > 0) {
|
||||
if (!Has<HistoryMessageUnreadBar>()) {
|
||||
AddComponents(HistoryMessageUnreadBar::Bit());
|
||||
Auth().data().requestItemResize(this);
|
||||
// #TODO recount attach to previous
|
||||
}
|
||||
const auto bar = Get<HistoryMessageUnreadBar>();
|
||||
if (bar->_freezed) {
|
||||
return;
|
||||
}
|
||||
bar->init(count);
|
||||
Auth().data().requestItemRepaint(this);
|
||||
} else {
|
||||
destroyUnreadBar();
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryItem::setUnreadBarFreezed() {
|
||||
Expects(!isLogEntry());
|
||||
|
||||
if (const auto bar = Get<HistoryMessageUnreadBar>()) {
|
||||
bar->_freezed = true;
|
||||
}
|
||||
}
|
||||
|
||||
MessageGroupId HistoryItem::groupId() const {
|
||||
return _groupId;
|
||||
}
|
||||
|
@ -244,17 +244,6 @@ public:
|
||||
QString authorOriginal() const;
|
||||
MsgId idOriginal() const;
|
||||
|
||||
// count > 0 - creates the unread bar if necessary and
|
||||
// sets unread messages count if bar is not freezed yet
|
||||
// count <= 0 - destroys the unread bar
|
||||
void setUnreadBarCount(int count);
|
||||
void destroyUnreadBar();
|
||||
|
||||
// marks the unread bar as freezed so that unread
|
||||
// messages count will not change for this bar
|
||||
// when the new messages arrive in this chat history
|
||||
void setUnreadBarFreezed();
|
||||
|
||||
int displayedDateHeight() const;
|
||||
bool displayDate() const;
|
||||
|
||||
|
@ -798,36 +798,6 @@ void HistoryMessageReplyMarkup::create(
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryMessageUnreadBar::init(int count) {
|
||||
if (_freezed) return;
|
||||
_text = lng_unread_bar(lt_count, count);
|
||||
_width = st::semiboldFont->width(_text);
|
||||
}
|
||||
|
||||
int HistoryMessageUnreadBar::height() {
|
||||
return st::historyUnreadBarHeight + st::historyUnreadBarMargin;
|
||||
}
|
||||
|
||||
int HistoryMessageUnreadBar::marginTop() {
|
||||
return st::lineWidth + st::historyUnreadBarMargin;
|
||||
}
|
||||
|
||||
void HistoryMessageUnreadBar::paint(Painter &p, int y, int w) const {
|
||||
p.fillRect(0, y + marginTop(), w, height() - marginTop() - st::lineWidth, st::historyUnreadBarBg);
|
||||
p.fillRect(0, y + height() - st::lineWidth, w, st::lineWidth, st::historyUnreadBarBorder);
|
||||
p.setFont(st::historyUnreadBarFont);
|
||||
p.setPen(st::historyUnreadBarFg);
|
||||
|
||||
int left = st::msgServiceMargin.left();
|
||||
int maxwidth = w;
|
||||
if (Adaptive::ChatWide()) {
|
||||
maxwidth = qMin(maxwidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left()));
|
||||
}
|
||||
w = maxwidth;
|
||||
|
||||
p.drawText((w - _width) / 2, y + marginTop() + (st::historyUnreadBarHeight - 2 * st::lineWidth - st::historyUnreadBarFont->height) / 2 + st::historyUnreadBarFont->ascent, _text);
|
||||
}
|
||||
|
||||
void HistoryMessageDate::init(const QDateTime &date) {
|
||||
_text = langDayOfMonthFull(date.date());
|
||||
_width = st::msgServiceFont->width(_text);
|
||||
|
@ -335,29 +335,6 @@ struct HistoryMessageDate : public RuntimeComponent<HistoryMessageDate, HistoryI
|
||||
int _width = 0;
|
||||
};
|
||||
|
||||
// Any HistoryItem can have this Component for
|
||||
// displaying the unread messages bar above the message.
|
||||
struct HistoryMessageUnreadBar : public RuntimeComponent<HistoryMessageUnreadBar, HistoryItem> {
|
||||
void init(int count);
|
||||
|
||||
static int height();
|
||||
static int marginTop();
|
||||
|
||||
void paint(Painter &p, int y, int w) const;
|
||||
|
||||
QString _text;
|
||||
int _width = 0;
|
||||
|
||||
// If unread bar is freezed the new messages do not
|
||||
// increment the counter displayed by this bar.
|
||||
//
|
||||
// It happens when we've opened the conversation and
|
||||
// we've seen the bar and new messages are marked as read
|
||||
// as soon as they are added to the chat history.
|
||||
bool _freezed = false;
|
||||
|
||||
};
|
||||
|
||||
// Special type of Component for the channel actions log.
|
||||
struct HistoryMessageLogEntryOriginal
|
||||
: public RuntimeComponent<HistoryMessageLogEntryOriginal, HistoryItem> {
|
||||
|
@ -2363,9 +2363,8 @@ void HistoryGif::draw(Painter &p, const QRect &r, TextSelection selection, TimeM
|
||||
} else if (!inWebPage) {
|
||||
auto fullRight = paintx + usex + usew;
|
||||
auto fullBottom = painty + painth;
|
||||
auto maxRight = item->history()->width - st::msgMargin.left();
|
||||
// #TODO view media
|
||||
if (item->history()->canHaveFromPhotos()) {
|
||||
auto maxRight = _parent->width() - st::msgMargin.left();
|
||||
if (_parent->hasFromPhoto()) {
|
||||
maxRight -= st::msgMargin.right();
|
||||
} else {
|
||||
maxRight -= st::msgMargin.left();
|
||||
@ -2505,9 +2504,8 @@ HistoryTextState HistoryGif::getState(QPoint point, HistoryStateRequest request)
|
||||
if (isRound || _caption.isEmpty()) {
|
||||
auto fullRight = usex + paintx + usew;
|
||||
auto fullBottom = painty + painth;
|
||||
// #TODO view media
|
||||
auto maxRight = _parent->data()->history()->width - st::msgMargin.left();
|
||||
if (_parent->data()->history()->canHaveFromPhotos()) {
|
||||
auto maxRight = _parent->width() - st::msgMargin.left();
|
||||
if (_parent->hasFromPhoto()) {
|
||||
maxRight -= st::msgMargin.right();
|
||||
} else {
|
||||
maxRight -= st::msgMargin.left();
|
||||
|
@ -2204,6 +2204,13 @@ void HistoryWidget::destroyUnreadBar() {
|
||||
|
||||
void HistoryWidget::newUnreadMsg(History *history, HistoryItem *item) {
|
||||
if (_history == history) {
|
||||
// If we get here in non-resized state we can't rely on results of
|
||||
// doWeReadServerHistory() and mark chat as read.
|
||||
// If we receive N messages being not at bottom:
|
||||
// - on first message we set unreadcount += 1, firstUnreadMessage.
|
||||
// - on second we get wrong doWeReadServerHistory() and read both.
|
||||
Auth().data().sendHistoryChangeNotifications();
|
||||
|
||||
if (_scroll->scrollTop() + 1 > _scroll->scrollTopMax()) {
|
||||
destroyUnreadBar();
|
||||
}
|
||||
@ -2229,10 +2236,12 @@ void HistoryWidget::historyToDown(History *history) {
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryWidget::unreadCountChanged(History *history) {
|
||||
void HistoryWidget::unreadCountChanged(not_null<History*> history) {
|
||||
if (history == _history || history == _migrated) {
|
||||
updateHistoryDownVisibility();
|
||||
_historyDown->setUnreadCount(_history->unreadCount() + (_migrated ? _migrated->unreadCount() : 0));
|
||||
_historyDown->setUnreadCount(
|
||||
_history->unreadCount()
|
||||
+ (_migrated ? _migrated->unreadCount() : 0));
|
||||
}
|
||||
}
|
||||
|
||||
@ -2452,16 +2461,15 @@ bool HistoryWidget::doWeReadServerHistory() const {
|
||||
int scrollTop = _scroll->scrollTop();
|
||||
if (scrollTop + 1 > _scroll->scrollTopMax()) return true;
|
||||
|
||||
auto showFrom = (_migrated && _migrated->showFrom) ? _migrated->showFrom : (_history ? _history->showFrom : nullptr);
|
||||
if (showFrom && showFrom->mainView()) {
|
||||
int scrollBottom = scrollTop + _scroll->height();
|
||||
if (scrollBottom > _list->itemTop(showFrom)) return true;
|
||||
if (const auto unread = firstUnreadMessage()) {
|
||||
const auto scrollBottom = scrollTop + _scroll->height();
|
||||
if (scrollBottom > _list->itemTop(unread)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (historyHasNotFreezedUnreadBar(_history)) {
|
||||
return true;
|
||||
}
|
||||
if (historyHasNotFreezedUnreadBar(_migrated)) {
|
||||
if (_history->hasNotFreezedUnreadBar()
|
||||
|| (_migrated && _migrated->hasNotFreezedUnreadBar())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -2473,15 +2481,6 @@ bool HistoryWidget::doWeReadMentions() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HistoryWidget::historyHasNotFreezedUnreadBar(History *history) const {
|
||||
if (history && history->showFrom && history->showFrom->mainView() && history->unreadBar) {
|
||||
if (auto unreadBar = history->unreadBar->Get<HistoryMessageUnreadBar>()) {
|
||||
return !unreadBar->_freezed;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void HistoryWidget::firstLoadMessages() {
|
||||
if (!_history || _firstLoadRequest) return;
|
||||
|
||||
@ -2707,10 +2706,12 @@ void HistoryWidget::visibleAreaUpdated() {
|
||||
auto scrollBottom = scrollTop + _scroll->height();
|
||||
_list->visibleAreaUpdated(scrollTop, scrollBottom);
|
||||
if (_history->loadedAtBottom() && (_history->unreadCount() > 0 || (_migrated && _migrated->unreadCount() > 0))) {
|
||||
auto showFrom = (_migrated && _migrated->showFrom) ? _migrated->showFrom : (_history ? _history->showFrom : nullptr);
|
||||
auto showFromVisible = (showFrom && showFrom->mainView() && scrollBottom > _list->itemTop(showFrom));
|
||||
auto atBottom = (scrollTop >= _scroll->scrollTopMax());
|
||||
if ((showFromVisible || atBottom) && App::wnd()->doWeReadServerHistory()) {
|
||||
const auto unread = firstUnreadMessage();
|
||||
const auto unreadVisible = unread
|
||||
&& (scrollBottom > _list->itemTop(unread));
|
||||
const auto atBottom = (scrollTop >= _scroll->scrollTopMax());
|
||||
if ((unreadVisible || atBottom)
|
||||
&& App::wnd()->doWeReadServerHistory()) {
|
||||
Auth().api().readServerHistory(_history);
|
||||
}
|
||||
}
|
||||
@ -4694,8 +4695,8 @@ int HistoryWidget::countInitialScrollTop() {
|
||||
result = itemTopForHighlight(view);
|
||||
enqueueMessageHighlight(view);
|
||||
}
|
||||
} else if (_history->unreadBar || (_migrated && _migrated->unreadBar)) {
|
||||
result = unreadBarTop();
|
||||
} else if (const auto top = unreadBarTop()) {
|
||||
result = *top;
|
||||
} else {
|
||||
return countAutomaticScrollTop();
|
||||
}
|
||||
@ -4704,28 +4705,18 @@ int HistoryWidget::countInitialScrollTop() {
|
||||
|
||||
int HistoryWidget::countAutomaticScrollTop() {
|
||||
auto result = ScrollMax;
|
||||
if (_migrated && _migrated->showFrom) {
|
||||
result = _list->itemTop(_migrated->showFrom);
|
||||
if (result < _scroll->scrollTopMax() + HistoryMessageUnreadBar::height() - HistoryMessageUnreadBar::marginTop()) {
|
||||
_migrated->addUnreadBar();
|
||||
if (const auto unread = firstUnreadMessage()) {
|
||||
result = _list->itemTop(unread);
|
||||
const auto possibleUnreadBarTop = _scroll->scrollTopMax()
|
||||
+ HistoryView::UnreadBar::height()
|
||||
- HistoryView::UnreadBar::marginTop();
|
||||
if (result < possibleUnreadBarTop) {
|
||||
const auto history = unread->data()->history();
|
||||
history->addUnreadBar();
|
||||
if (hasPendingResizedItems()) {
|
||||
updateListSize();
|
||||
}
|
||||
if (_migrated->unreadBar) {
|
||||
setMsgId(ShowAtUnreadMsgId);
|
||||
result = countInitialScrollTop();
|
||||
App::wnd()->checkHistoryActivation();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
} else if (_history->showFrom) {
|
||||
result = _list->itemTop(_history->showFrom);
|
||||
if (result < _scroll->scrollTopMax() + HistoryMessageUnreadBar::height() - HistoryMessageUnreadBar::marginTop()) {
|
||||
_history->addUnreadBar();
|
||||
if (hasPendingResizedItems()) {
|
||||
updateListSize();
|
||||
}
|
||||
if (_history->unreadBar) {
|
||||
if (history->unreadBar() != nullptr) {
|
||||
setMsgId(ShowAtUnreadMsgId);
|
||||
result = countInitialScrollTop();
|
||||
App::wnd()->checkHistoryActivation();
|
||||
@ -4792,7 +4783,23 @@ void HistoryWidget::updateHistoryGeometry(bool initial, bool loadedDown, const S
|
||||
updateListSize();
|
||||
_updateHistoryGeometryRequired = false;
|
||||
|
||||
if ((!initial && !wasAtBottom) || (loadedDown && (!_history->showFrom || _history->unreadBar || _history->loadedAtBottom()) && (!_migrated || !_migrated->showFrom || _migrated->unreadBar || _history->loadedAtBottom()))) {
|
||||
if ((!initial && !wasAtBottom)
|
||||
|| (loadedDown
|
||||
&& (!_history->firstUnreadMessage()
|
||||
|| _history->unreadBar()
|
||||
|| _history->loadedAtBottom())
|
||||
&& (!_migrated
|
||||
|| !_migrated->firstUnreadMessage()
|
||||
|| _migrated->unreadBar()
|
||||
|| _history->loadedAtBottom()))) {
|
||||
const auto historyScrollTop = _list->historyScrollTop();
|
||||
if (!wasAtBottom && historyScrollTop == ScrollMax) {
|
||||
// History scroll top was not inited yet.
|
||||
// If we're showing locally unread messages, we get here
|
||||
// from destroyUnreadBar() before we have time to scroll
|
||||
// to good initial position, like top of an unread bar.
|
||||
return;
|
||||
}
|
||||
auto toY = qMin(_list->historyScrollTop(), _scroll->scrollTopMax());
|
||||
if (change.type == ScrollChangeAdd) {
|
||||
toY += change.value;
|
||||
@ -4815,7 +4822,9 @@ void HistoryWidget::updateHistoryGeometry(bool initial, bool loadedDown, const S
|
||||
_historyInited = true;
|
||||
_scrollToAnimation.finish();
|
||||
}
|
||||
auto newScrollTop = initial ? countInitialScrollTop() : countAutomaticScrollTop();
|
||||
auto newScrollTop = initial
|
||||
? countInitialScrollTop()
|
||||
: countAutomaticScrollTop();
|
||||
if (_scroll->scrollTop() == newScrollTop) {
|
||||
visibleAreaUpdated();
|
||||
} else {
|
||||
@ -4841,25 +4850,33 @@ bool HistoryWidget::hasPendingResizedItems() const {
|
||||
|| (_migrated && _migrated->hasPendingResizedItems());
|
||||
}
|
||||
|
||||
int HistoryWidget::unreadBarTop() const {
|
||||
auto getUnreadBar = [this]() -> HistoryItem* {
|
||||
if (_migrated && _migrated->unreadBar) {
|
||||
return _migrated->unreadBar;
|
||||
}
|
||||
if (_history->unreadBar) {
|
||||
return _history->unreadBar;
|
||||
base::optional<int> HistoryWidget::unreadBarTop() const {
|
||||
auto getUnreadBar = [this]() -> HistoryView::Element* {
|
||||
if (const auto bar = _migrated ? _migrated->unreadBar() : nullptr) {
|
||||
return bar;
|
||||
} else if (const auto bar = _history->unreadBar()) {
|
||||
return bar;
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
if (const auto bar = getUnreadBar()) {
|
||||
auto result = _list->itemTop(bar)
|
||||
+ HistoryMessageUnreadBar::marginTop();
|
||||
if (bar->Has<HistoryMessageDate>()) {
|
||||
result += bar->Get<HistoryMessageDate>()->height();
|
||||
const auto result = _list->itemTop(bar)
|
||||
+ HistoryView::UnreadBar::marginTop();
|
||||
if (bar->data()->Has<HistoryMessageDate>()) {
|
||||
return result + bar->data()->Get<HistoryMessageDate>()->height();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return -1;
|
||||
return base::none;
|
||||
}
|
||||
|
||||
HistoryView::Element *HistoryWidget::firstUnreadMessage() const {
|
||||
if (_migrated) {
|
||||
if (const auto result = _migrated->firstUnreadMessage()) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return _history ? _history->firstUnreadMessage() : nullptr;
|
||||
}
|
||||
|
||||
void HistoryWidget::addMessagesToFront(PeerData *peer, const QVector<MTPMessage> &messages) {
|
||||
@ -4879,14 +4896,18 @@ void HistoryWidget::addMessagesToBack(PeerData *peer, const QVector<MTPMessage>
|
||||
}
|
||||
|
||||
void HistoryWidget::countHistoryShowFrom() {
|
||||
if (_migrated && _showAtMsgId == ShowAtUnreadMsgId && _migrated->unreadCount()) {
|
||||
_migrated->updateShowFrom();
|
||||
if (_migrated
|
||||
&& _showAtMsgId == ShowAtUnreadMsgId
|
||||
&& _migrated->unreadCount()) {
|
||||
_migrated->calculateFirstUnreadMessage();
|
||||
}
|
||||
if ((_migrated && _migrated->showFrom) || _showAtMsgId != ShowAtUnreadMsgId || !_history->unreadCount()) {
|
||||
_history->showFrom = nullptr;
|
||||
return;
|
||||
if ((_migrated && _migrated->firstUnreadMessage())
|
||||
|| (_showAtMsgId != ShowAtUnreadMsgId)
|
||||
|| !_history->unreadCount()) {
|
||||
_history->unsetFirstUnreadMessage();
|
||||
} else {
|
||||
_history->calculateFirstUnreadMessage();
|
||||
}
|
||||
_history->updateShowFrom();
|
||||
}
|
||||
|
||||
void HistoryWidget::updateBotKeyboard(History *h, bool force) {
|
||||
@ -4989,26 +5010,30 @@ void HistoryWidget::updateHistoryDownPosition() {
|
||||
void HistoryWidget::updateHistoryDownVisibility() {
|
||||
if (_a_show.animating()) return;
|
||||
|
||||
auto haveUnreadBelowBottom = [this](History *history) {
|
||||
auto haveUnreadBelowBottom = [&](History *history) {
|
||||
if (!_list || !history || history->unreadCount() <= 0) {
|
||||
return false;
|
||||
}
|
||||
if (!history->showFrom || !history->showFrom->mainView()) {
|
||||
const auto unread = history->firstUnreadMessage();
|
||||
if (!unread) {
|
||||
return false;
|
||||
}
|
||||
return (_list->itemTop(history->showFrom) >= _scroll->scrollTop() + _scroll->height());
|
||||
const auto top = _list->itemTop(unread);
|
||||
return (top >= _scroll->scrollTop() + _scroll->height());
|
||||
};
|
||||
auto historyDownIsVisible = [this, &haveUnreadBelowBottom] {
|
||||
if (!_history || _firstLoadRequest) {
|
||||
auto historyDownIsVisible = [&] {
|
||||
if (!_list || _firstLoadRequest) {
|
||||
return false;
|
||||
}
|
||||
if (!_history->loadedAtBottom() || _replyReturn) {
|
||||
return true;
|
||||
}
|
||||
if (_scroll->scrollTop() + st::historyToDownShownAfter < _scroll->scrollTopMax()) {
|
||||
const auto top = _scroll->scrollTop() + st::historyToDownShownAfter;
|
||||
if (top < _scroll->scrollTopMax()) {
|
||||
return true;
|
||||
}
|
||||
if (haveUnreadBelowBottom(_history) || haveUnreadBelowBottom(_migrated)) {
|
||||
if (haveUnreadBelowBottom(_history)
|
||||
|| haveUnreadBelowBottom(_migrated)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -5338,7 +5363,8 @@ bool HistoryWidget::pinnedMsgVisibilityUpdated() {
|
||||
updatePinnedBar();
|
||||
result = true;
|
||||
|
||||
if (_scroll->scrollTop() != unreadBarTop()) {
|
||||
const auto barTop = unreadBarTop();
|
||||
if (!barTop || _scroll->scrollTop() != *barTop) {
|
||||
synteticScrollToY(_scroll->scrollTop() + st::historyReplyHeight);
|
||||
}
|
||||
} else if (_pinnedBar->msgId != pinnedId) {
|
||||
@ -5356,7 +5382,8 @@ bool HistoryWidget::pinnedMsgVisibilityUpdated() {
|
||||
} else if (_pinnedBar) {
|
||||
destroyPinnedBar();
|
||||
result = true;
|
||||
if (_scroll->scrollTop() != unreadBarTop()) {
|
||||
const auto barTop = unreadBarTop();
|
||||
if (!barTop || _scroll->scrollTop() != *barTop) {
|
||||
synteticScrollToY(_scroll->scrollTop() - st::historyReplyHeight);
|
||||
}
|
||||
updateControlsGeometry();
|
||||
|
@ -203,7 +203,7 @@ public:
|
||||
|
||||
void newUnreadMsg(History *history, HistoryItem *item);
|
||||
void historyToDown(History *history);
|
||||
void unreadCountChanged(History *history);
|
||||
void unreadCountChanged(not_null<History*> history);
|
||||
|
||||
QRect historyRect() const;
|
||||
void pushTabbedSelectorToThirdSection(
|
||||
@ -534,7 +534,6 @@ private:
|
||||
void updateTabbedSelectorToggleTooltipGeometry();
|
||||
void checkTabbedSelectorToggleTooltip();
|
||||
|
||||
bool historyHasNotFreezedUnreadBar(History *history) const;
|
||||
bool canWriteMessage() const;
|
||||
bool isRestrictedWrite() const;
|
||||
void orderWidgets();
|
||||
@ -670,9 +669,10 @@ private:
|
||||
|
||||
// Counts scrollTop for placing the scroll right at the unread
|
||||
// messages bar, choosing from _history and _migrated unreadBar.
|
||||
int unreadBarTop() const;
|
||||
base::optional<int> unreadBarTop() const;
|
||||
int itemTopForHighlight(not_null<HistoryView::Element*> view) const;
|
||||
void scrollToCurrentVoiceMessage(FullMsgId fromId, FullMsgId toId);
|
||||
HistoryView::Element *firstUnreadMessage() const;
|
||||
|
||||
// Scroll to current y without updating the _lastUserScrolled time.
|
||||
// Used to distinguish between user scrolls and syntetic scrolls.
|
||||
|
@ -15,8 +15,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_groups.h"
|
||||
#include "data/data_media_types.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "auth_session.h"
|
||||
#include "layout.h"
|
||||
#include "styles/style_history.h"
|
||||
|
||||
namespace HistoryView {
|
||||
namespace {
|
||||
@ -54,6 +56,60 @@ TextSelection ShiftItemSelection(
|
||||
return ShiftItemSelection(selection, byText.length());
|
||||
}
|
||||
|
||||
void UnreadBar::init(int count) {
|
||||
if (freezed) {
|
||||
return;
|
||||
}
|
||||
text = lng_unread_bar(lt_count, count);
|
||||
width = st::semiboldFont->width(text);
|
||||
}
|
||||
|
||||
int UnreadBar::height() {
|
||||
return st::historyUnreadBarHeight + st::historyUnreadBarMargin;
|
||||
}
|
||||
|
||||
int UnreadBar::marginTop() {
|
||||
return st::lineWidth + st::historyUnreadBarMargin;
|
||||
}
|
||||
|
||||
void UnreadBar::paint(Painter &p, int y, int w) const {
|
||||
const auto bottom = y + height();
|
||||
y += marginTop();
|
||||
p.fillRect(
|
||||
0,
|
||||
y,
|
||||
w,
|
||||
height() - marginTop() - st::lineWidth,
|
||||
st::historyUnreadBarBg);
|
||||
p.fillRect(
|
||||
0,
|
||||
bottom - st::lineWidth,
|
||||
w,
|
||||
st::lineWidth,
|
||||
st::historyUnreadBarBorder);
|
||||
p.setFont(st::historyUnreadBarFont);
|
||||
p.setPen(st::historyUnreadBarFg);
|
||||
|
||||
int left = st::msgServiceMargin.left();
|
||||
int maxwidth = w;
|
||||
if (Adaptive::ChatWide()) {
|
||||
maxwidth = qMin(
|
||||
maxwidth,
|
||||
st::msgMaxWidth
|
||||
+ 2 * st::msgPhotoSkip
|
||||
+ 2 * st::msgMargin.left());
|
||||
}
|
||||
w = maxwidth;
|
||||
|
||||
const auto skip = st::historyUnreadBarHeight
|
||||
- 2 * st::lineWidth
|
||||
- st::historyUnreadBarFont->height;
|
||||
p.drawText(
|
||||
(w - width) / 2,
|
||||
y + (skip / 2) + st::historyUnreadBarFont->ascent,
|
||||
text);
|
||||
}
|
||||
|
||||
Element::Element(
|
||||
not_null<ElementDelegate*> delegate,
|
||||
not_null<HistoryItem*> data)
|
||||
@ -99,8 +155,8 @@ int Element::marginTop() const {
|
||||
}
|
||||
}
|
||||
result += item->displayedDateHeight();
|
||||
if (const auto unreadbar = item->Get<HistoryMessageUnreadBar>()) {
|
||||
result += unreadbar->height();
|
||||
if (const auto bar = Get<UnreadBar>()) {
|
||||
result += bar->height();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -198,7 +254,7 @@ void Element::refreshDataId() {
|
||||
|
||||
bool Element::computeIsAttachToPrevious(not_null<Element*> previous) {
|
||||
const auto item = data();
|
||||
if (!item->Has<HistoryMessageDate>() && !item->Has<HistoryMessageUnreadBar>()) {
|
||||
if (!item->Has<HistoryMessageDate>() && !Has<UnreadBar>()) {
|
||||
const auto prev = previous->data();
|
||||
const auto possible = !item->serviceMsg() && !prev->serviceMsg()
|
||||
&& !item->isEmpty() && !prev->isEmpty()
|
||||
@ -217,6 +273,42 @@ bool Element::computeIsAttachToPrevious(not_null<Element*> previous) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void Element::destroyUnreadBar() {
|
||||
if (!Has<UnreadBar>()) {
|
||||
return;
|
||||
}
|
||||
RemoveComponents(UnreadBar::Bit());
|
||||
Auth().data().requestViewResize(this);
|
||||
if (data()->mainView() == this) {
|
||||
recountAttachToPreviousInBlocks();
|
||||
}
|
||||
}
|
||||
|
||||
void Element::setUnreadBarCount(int count) {
|
||||
Expects(count > 0);
|
||||
|
||||
const auto changed = AddComponents(UnreadBar::Bit());
|
||||
const auto bar = Get<UnreadBar>();
|
||||
if (bar->freezed) {
|
||||
return;
|
||||
}
|
||||
bar->init(count);
|
||||
if (changed) {
|
||||
if (data()->mainView() == this) {
|
||||
recountAttachToPreviousInBlocks();
|
||||
}
|
||||
Auth().data().requestViewResize(this);
|
||||
} else {
|
||||
Auth().data().requestViewRepaint(this);
|
||||
}
|
||||
}
|
||||
|
||||
void Element::setUnreadBarFreezed() {
|
||||
if (const auto bar = Get<UnreadBar>()) {
|
||||
bar->freezed = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Element::recountAttachToPreviousInBlocks() {
|
||||
auto attachToPrevious = false;
|
||||
if (const auto previous = previousInBlocks()) {
|
||||
|
@ -55,6 +55,29 @@ TextSelection ShiftItemSelection(
|
||||
TextSelection selection,
|
||||
const Text &byText);
|
||||
|
||||
// Any HistoryView::Element can have this Component for
|
||||
// displaying the unread messages bar above the message.
|
||||
struct UnreadBar : public RuntimeComponent<UnreadBar, Element> {
|
||||
void init(int count);
|
||||
|
||||
static int height();
|
||||
static int marginTop();
|
||||
|
||||
void paint(Painter &p, int y, int w) const;
|
||||
|
||||
QString text;
|
||||
int width = 0;
|
||||
|
||||
// If unread bar is freezed the new messages do not
|
||||
// increment the counter displayed by this bar.
|
||||
//
|
||||
// It happens when we've opened the conversation and
|
||||
// we've seen the bar and new messages are marked as read
|
||||
// as soon as they are added to the chat history.
|
||||
bool freezed = false;
|
||||
|
||||
};
|
||||
|
||||
class Element
|
||||
: public Object
|
||||
, public RuntimeComposer<Element>
|
||||
@ -110,6 +133,16 @@ public:
|
||||
|
||||
bool computeIsAttachToPrevious(not_null<Element*> previous);
|
||||
|
||||
// count > 0 - creates the unread bar if necessary and
|
||||
// sets unread messages count if bar is not freezed yet
|
||||
void setUnreadBarCount(int count);
|
||||
void destroyUnreadBar();
|
||||
|
||||
// marks the unread bar as freezed so that unread
|
||||
// messages count will not change for this bar
|
||||
// when the new messages arrive in this chat history
|
||||
void setUnreadBarFreezed();
|
||||
|
||||
virtual void draw(
|
||||
Painter &p,
|
||||
QRect clip,
|
||||
@ -195,7 +228,7 @@ private:
|
||||
void recountDisplayDateInBlocks();
|
||||
|
||||
// This should be called only from previousInBlocksChanged() or when
|
||||
// HistoryMessageDate or HistoryMessageUnreadBar bit is changed in the Composer mask
|
||||
// HistoryMessageDate or UnreadBar bit is changed in the Composer mask
|
||||
// then the result should be cached in a client side flag MTPDmessage_ClientFlag::f_attach_to_previous.
|
||||
void recountAttachToPreviousInBlocks();
|
||||
|
||||
|
@ -231,7 +231,7 @@ ListWidget::ListWidget(
|
||||
Auth().data().viewResizeRequest(
|
||||
) | rpl::start_with_next([this](auto view) {
|
||||
if (view->delegate() == this) {
|
||||
updateSize();
|
||||
resizeItem(view);
|
||||
}
|
||||
}, lifetime());
|
||||
Auth().data().itemViewRefreshRequest(
|
||||
@ -572,24 +572,7 @@ void ListWidget::updateItemsGeometry() {
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
updateSize();
|
||||
refreshAttachmentsFromTill(first, count);
|
||||
}
|
||||
|
||||
void ListWidget::updateSize() {
|
||||
@ -1452,6 +1435,61 @@ void ListWidget::repaintItem(const Element *view) {
|
||||
update(0, itemTop(view), width(), view->height());
|
||||
}
|
||||
|
||||
void ListWidget::resizeItem(not_null<Element*> view) {
|
||||
const auto index = ranges::find(_items, view) - begin(_items);
|
||||
if (index < int(_items.size())) {
|
||||
refreshAttachmentsAtIndex(index);
|
||||
}
|
||||
}
|
||||
|
||||
void ListWidget::refreshAttachmentsAtIndex(int index) {
|
||||
Expects(index >= 0 && index < _items.size());
|
||||
|
||||
const auto from = [&] {
|
||||
if (index > 0) {
|
||||
for (auto i = index - 1; i != 0; --i) {
|
||||
if (!_items[i]->isHiddenByGroup()) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}();
|
||||
const auto till = [&] {
|
||||
for (auto i = index + 1, count = int(_items.size()); i != count; ) {
|
||||
if (!_items[i]->isHiddenByGroup()) {
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
return index + 1;
|
||||
}();
|
||||
refreshAttachmentsFromTill(from, till);
|
||||
}
|
||||
|
||||
void ListWidget::refreshAttachmentsFromTill(int from, int till) {
|
||||
Expects(from >= 0 && from <= till && till <= int(_items.size()));
|
||||
|
||||
if (from == till) {
|
||||
return;
|
||||
}
|
||||
auto view = _items[from].get();
|
||||
for (auto i = from + 1; i != till; ++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;
|
||||
}
|
||||
}
|
||||
updateSize();
|
||||
}
|
||||
|
||||
void ListWidget::refreshItem(not_null<const Element*> view) {
|
||||
const auto i = ranges::find(_items, view);
|
||||
const auto index = i - begin(_items);
|
||||
@ -1467,7 +1505,7 @@ void ListWidget::refreshItem(not_null<const Element*> view) {
|
||||
|
||||
viewReplaced(view, i->second.get());
|
||||
|
||||
updateItemsGeometry();
|
||||
refreshAttachmentsAtIndex(index);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -165,6 +165,7 @@ private:
|
||||
void performDrag();
|
||||
int itemTop(not_null<const Element*> view) const;
|
||||
void repaintItem(const Element *view);
|
||||
void resizeItem(not_null<Element*> view);
|
||||
void refreshItem(not_null<const Element*> view);
|
||||
void itemRemoved(not_null<const HistoryItem*> item);
|
||||
QPoint mapPointToItem(QPoint point, const Element *view) const;
|
||||
@ -194,6 +195,8 @@ private:
|
||||
void updateVisibleTopItem();
|
||||
void updateItemsGeometry();
|
||||
void updateSize();
|
||||
void refreshAttachmentsFromTill(int from, int till);
|
||||
void refreshAttachmentsAtIndex(int index);
|
||||
|
||||
void toggleScrollDateShown();
|
||||
void repaintScrollDateCallback();
|
||||
|
@ -360,14 +360,14 @@ void Message::draw(
|
||||
}
|
||||
|
||||
auto dateh = 0;
|
||||
if (auto date = item->Get<HistoryMessageDate>()) {
|
||||
if (const auto date = item->Get<HistoryMessageDate>()) {
|
||||
dateh = date->height();
|
||||
}
|
||||
if (auto unreadbar = item->Get<HistoryMessageUnreadBar>()) {
|
||||
auto unreadbarh = unreadbar->height();
|
||||
if (const auto bar = Get<UnreadBar>()) {
|
||||
auto unreadbarh = bar->height();
|
||||
if (clip.intersects(QRect(0, dateh, width(), unreadbarh))) {
|
||||
p.translate(0, dateh);
|
||||
unreadbar->paint(p, 0, width());
|
||||
bar->paint(p, 0, width());
|
||||
p.translate(0, -dateh);
|
||||
}
|
||||
}
|
||||
|
@ -315,8 +315,8 @@ QSize Service::performCountCurrentSize(int newWidth) {
|
||||
const auto media = this->media();
|
||||
|
||||
auto newHeight = item->displayedDateHeight();
|
||||
if (auto unreadbar = item->Get<HistoryMessageUnreadBar>()) {
|
||||
newHeight += unreadbar->height();
|
||||
if (const auto bar = Get<UnreadBar>()) {
|
||||
newHeight += bar->height();
|
||||
}
|
||||
|
||||
if (item->_text.isEmpty()) {
|
||||
@ -382,10 +382,10 @@ void Service::draw(
|
||||
clip.translate(0, -dateh);
|
||||
height -= dateh;
|
||||
}
|
||||
if (auto unreadbar = item->Get<HistoryMessageUnreadBar>()) {
|
||||
unreadbarh = unreadbar->height();
|
||||
if (const auto bar = Get<UnreadBar>()) {
|
||||
unreadbarh = bar->height();
|
||||
if (clip.intersects(QRect(0, 0, width(), unreadbarh))) {
|
||||
unreadbar->paint(p, 0, width());
|
||||
bar->paint(p, 0, width());
|
||||
}
|
||||
p.translate(0, unreadbarh);
|
||||
clip.translate(0, -unreadbarh);
|
||||
@ -405,7 +405,7 @@ void Service::draw(
|
||||
auto dt = (animms > st::activeFadeInDuration) ? (1. - (animms - st::activeFadeInDuration) / float64(st::activeFadeOutDuration)) : (animms / float64(st::activeFadeInDuration));
|
||||
auto o = p.opacity();
|
||||
p.setOpacity(o * dt);
|
||||
p.fillRect(0, skiptop, item->history()->width, fillheight, st::defaultTextPalette.selectOverlay);
|
||||
p.fillRect(0, skiptop, width(), fillheight, st::defaultTextPalette.selectOverlay);
|
||||
p.setOpacity(o);
|
||||
}
|
||||
}
|
||||
@ -448,8 +448,8 @@ bool Service::hasPoint(QPoint point) const {
|
||||
if (auto dateh = item->displayedDateHeight()) {
|
||||
g.setTop(g.top() + dateh);
|
||||
}
|
||||
if (auto unreadbar = item->Get<HistoryMessageUnreadBar>()) {
|
||||
g.setTop(g.top() + unreadbar->height());
|
||||
if (const auto bar = Get<UnreadBar>()) {
|
||||
g.setTop(g.top() + bar->height());
|
||||
}
|
||||
if (media) {
|
||||
g.setHeight(g.height() - (st::msgServiceMargin.top() + media->height()));
|
||||
@ -472,8 +472,8 @@ HistoryTextState Service::getState(QPoint point, HistoryStateRequest request) co
|
||||
point.setY(point.y() - dateh);
|
||||
g.setHeight(g.height() - dateh);
|
||||
}
|
||||
if (auto unreadbar = item->Get<HistoryMessageUnreadBar>()) {
|
||||
auto unreadbarh = unreadbar->height();
|
||||
if (const auto bar = Get<UnreadBar>()) {
|
||||
auto unreadbarh = bar->height();
|
||||
point.setY(point.y() - unreadbarh);
|
||||
g.setHeight(g.height() - unreadbarh);
|
||||
}
|
||||
|
@ -1516,7 +1516,7 @@ void MainWidget::saveRecentHashtags(const QString &text) {
|
||||
}
|
||||
}
|
||||
|
||||
void MainWidget::unreadCountChanged(History *history) {
|
||||
void MainWidget::unreadCountChanged(not_null<History*> history) {
|
||||
_history->unreadCountChanged(history);
|
||||
}
|
||||
|
||||
|
@ -242,7 +242,7 @@ public:
|
||||
void sendMessage(const MessageToSend &message);
|
||||
void saveRecentHashtags(const QString &text);
|
||||
|
||||
void unreadCountChanged(History *history);
|
||||
void unreadCountChanged(not_null<History*> history);
|
||||
|
||||
TimeMs highlightStartTime(not_null<const HistoryItem*> item) const;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user