diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index 272c9b29b7..9fe1f12067 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -1096,6 +1096,12 @@ namespace { } } + void updateEditedMessageToEmpty(PeerId peerId, MsgId msgId) { + if (auto existing = App::histItemById(peerToChannel(peerId), msgId)) { + existing->applyEditionToEmpty(); + } + } + void addSavedGif(DocumentData *doc) { SavedGifs &saved(cRefSavedGifs()); int32 index = saved.indexOf(doc); diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h index 5613e68b23..86fefb6138 100644 --- a/Telegram/SourceFiles/app.h +++ b/Telegram/SourceFiles/app.h @@ -77,6 +77,7 @@ namespace App { void feedParticipantAdmin(const MTPDupdateChatParticipantAdmin &d, bool emitPeerUpdated = true); bool checkEntitiesAndViewsUpdate(const MTPDmessage &m); // returns true if item found and it is not detached void updateEditedMessage(const MTPDmessage &m); + void updateEditedMessageToEmpty(PeerId peerId, MsgId msgId); void addSavedGif(DocumentData *doc); void checkSavedGif(HistoryItem *item); void feedMsgs(const QVector &msgs, NewMessageType type); diff --git a/Telegram/SourceFiles/dialogs/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/dialogs_layout.cpp index 8cc4688f0f..9577393dec 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_layout.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_layout.cpp @@ -52,7 +52,7 @@ void paintRowDate(Painter &p, const QDateTime &date, QRect &rectForName, bool ac } template -void paintRow(Painter &p, History *history, HistoryItem *item, Data::Draft *draft, int w, bool active, bool selected, bool onlyBackground, PaintItemCallback paintItemCallback) { +void paintRow(Painter &p, History *history, HistoryItem *item, Data::Draft *draft, QDateTime date, int w, bool active, bool selected, bool onlyBackground, PaintItemCallback paintItemCallback) { QRect fullRect(0, 0, w, st::dialogsRowHeight); p.fillRect(fullRect, active ? st::dialogsBgActive : (selected ? st::dialogsBgOver : st::dialogsBg)); if (onlyBackground) return; @@ -75,7 +75,7 @@ void paintRow(Painter &p, History *history, HistoryItem *item, Data::Draft *draf int texttop = st::dialogsPadding.y() + st::msgNameFont->height + st::dialogsSkip; if (draft) { - paintRowDate(p, draft->date, rectForName, active); + paintRowDate(p, date, rectForName, active); // draw check if (draft->saveRequestId) { @@ -110,7 +110,7 @@ void paintRow(Painter &p, History *history, HistoryItem *item, Data::Draft *draf history->typingText.drawElided(p, nameleft, texttop, namewidth); } } else if (!item->isEmpty()) { - paintRowDate(p, item->date, rectForName, active); + paintRowDate(p, date, rectForName, active); // draw check if (item->needCheck()) { @@ -211,20 +211,33 @@ void RowPainter::paint(Painter &p, const Row *row, int w, bool active, bool sele auto history = row->history(); auto item = history->lastMsg; auto cloudDraft = history->cloudDraft(); - if (item && cloudDraft && cloudDraft->date < item->date) { + if (Data::draftIsNull(cloudDraft)) { + cloudDraft = nullptr; + } + auto displayDate = [item, cloudDraft]() { + if (item) { + if (cloudDraft) { + return (item->date > cloudDraft->date) ? item->date : cloudDraft->date; + } + return item->date; + } + return cloudDraft ? cloudDraft->date : QDateTime(); + }; + int unreadCount = history->unreadCount(); + if (history->peer->migrateFrom()) { + if (auto migrated = App::historyLoaded(history->peer->migrateFrom()->id)) { + unreadCount += migrated->unreadCount(); + } + } + + if (item && cloudDraft && unreadCount > 0) { cloudDraft = nullptr; // Draw item, if draft is older. } - paintRow(p, history, item, cloudDraft, w, active, selected, onlyBackground, [&p, w, active, history](int nameleft, int namewidth, HistoryItem *item) { - int32 unread = history->unreadCount(); - if (history->peer->migrateFrom()) { - if (History *h = App::historyLoaded(history->peer->migrateFrom()->id)) { - unread += h->unreadCount(); - } - } + paintRow(p, history, item, cloudDraft, displayDate(), w, active, selected, onlyBackground, [&p, w, active, history, unreadCount](int nameleft, int namewidth, HistoryItem *item) { int availableWidth = namewidth; int texttop = st::dialogsPadding.y() + st::msgNameFont->height + st::dialogsSkip; - if (unread) { - auto counter = QString::number(unread); + if (unreadCount) { + auto counter = QString::number(unreadCount); auto mutedCounter = history->mute(); int unreadRight = w - st::dialogsPadding.x(); int unreadTop = texttop + st::dialogsTextFont->ascent - st::dialogsUnreadFont->ascent - st::dialogsUnreadTop; @@ -244,7 +257,7 @@ void RowPainter::paint(Painter &p, const Row *row, int w, bool active, bool sele void RowPainter::paint(Painter &p, const FakeRow *row, int w, bool active, bool selected, bool onlyBackground) { auto item = row->item(); auto history = item->history(); - paintRow(p, history, item, nullptr, w, active, selected, onlyBackground, [&p, row, active](int nameleft, int namewidth, HistoryItem *item) { + paintRow(p, history, item, nullptr, item->date, w, active, selected, onlyBackground, [&p, row, active](int nameleft, int namewidth, HistoryItem *item) { int lastWidth = namewidth, texttop = st::dialogsPadding.y() + st::msgNameFont->height + st::dialogsSkip; item->drawInDialog(p, QRect(nameleft, texttop, lastWidth, st::dialogsTextFont->height), active, row->_cacheFor, row->_cache); }); diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index 0ae57b2db8..b2c3f25307 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -2641,6 +2641,49 @@ void HistoryItem::finishCreate() { App::historyRegItem(this); } +void HistoryItem::finishEdition(int oldKeyboardTop) { + setPendingInitDimensions(); + if (App::main()) { + App::main()->dlgUpdated(history(), id); + } + + // invalidate cache for drawInDialog + if (history()->textCachedFor == this) { + history()->textCachedFor = nullptr; + } + + if (oldKeyboardTop >= 0) { + if (auto keyboard = Get()) { + keyboard->oldTop = oldKeyboardTop; + } + } + + App::historyUpdateDependent(this); +} + +void HistoryItem::finishEditionToEmpty() { + recountDisplayDate(); + finishEdition(-1); + + _history->removeNotification(this); + if (history()->isChannel()) { + if (history()->peer->isMegagroup() && history()->peer->asChannel()->mgInfo->pinnedMsgId == id) { + history()->peer->asChannel()->mgInfo->pinnedMsgId = 0; + } + } + if (history()->lastKeyboardId == id) { + history()->clearLastKeyboard(); + if (App::main()) App::main()->updateBotKeyboard(history()); + } + if ((!out() || isPost()) && unread() && history()->unreadCount() > 0) { + history()->setUnreadCount(history()->unreadCount() - 1); + } + + if (auto next = nextItem()) { + next->previousItemChanged(); + } +} + void HistoryItem::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) { if (auto markup = Get()) { if (markup->inlineKeyboard) { @@ -2712,8 +2755,12 @@ void HistoryItem::previousItemChanged() { void HistoryItem::recountAttachToPrevious() { bool attach = false; if (!isPost() && !Has() && !Has()) { - if (HistoryItem *prev = previous()) { - attach = !prev->isPost() && !prev->serviceMsg() && prev->from() == from() && qAbs(prev->date.secsTo(date)) < AttachMessageToPreviousSecondsDelta; + if (auto previos = previousItem()) { + attach = !previos->isPost() + && !previos->serviceMsg() + && !previos->isEmpty() + && previos->from() == from() + && (qAbs(previos->date.secsTo(date)) < AttachMessageToPreviousSecondsDelta); } } if (attach && !(_flags & MTPDmessage_ClientFlag::f_attach_to_previous)) { @@ -2861,8 +2908,8 @@ void HistoryItem::recountDisplayDate() { bool displayingDate = ([this]() { if (isEmpty()) return false; - if (auto prev = previous()) { - return prev->isEmpty() || (prev->date.date() != date.date()); + if (auto previous = previousItem()) { + return previous->isEmpty() || (previous->date.date() != date.date()); } return true; })(); @@ -6754,10 +6801,13 @@ void HistoryMessage::initDimensions() { if (_namew > _maxw) _maxw = _namew; } } - } else { + } else if (_media) { _media->initDimensions(); _maxw = _media->maxWidth(); _minh = _media->minHeight(); + } else { + _maxw = st::msgMinWidth; + _minh = 0; } if (reply && !_text.isEmpty()) { int replyw = st::msgPadding.left() + reply->_maxReplyWidth - st::msgReplyPadding.left() - st::msgReplyPadding.right() + st::msgPadding.right(); @@ -6841,23 +6891,16 @@ void HistoryMessage::applyEdition(const MTPDmessage &message) { setReplyMarkup(message.has_reply_markup() ? (&message.vreply_markup) : nullptr); setViewsCount(message.has_views() ? message.vviews.v : -1); - setPendingInitDimensions(); - if (App::main()) { - App::main()->dlgUpdated(history(), id); - } + finishEdition(keyboardTop); +} - // invalidate cache for drawInDialog - if (history()->textCachedFor == this) { - history()->textCachedFor = nullptr; - } +void HistoryMessage::applyEditionToEmpty() { + setEmptyText(); + setMedia(nullptr); + setReplyMarkup(nullptr); + setViewsCount(-1); - if (keyboardTop >= 0) { - if (auto keyboard = Get()) { - keyboard->oldTop = keyboardTop; - } - } - - App::historyUpdateDependent(this); + finishEditionToEmpty(); } void HistoryMessage::updateMedia(const MTPMessageMedia *media) { @@ -6999,6 +7042,15 @@ void HistoryMessage::setText(const TextWithEntities &textWithEntities) { _textHeight = 0; } +void HistoryMessage::setEmptyText() { + textstyleSet(&((out() && !isPost()) ? st::outTextStyle : st::inTextStyle)); + _text.setMarkedText(st::msgFont, { QString(), EntitiesInText() }, itemTextOptions(this)); + textstyleRestore(); + + _textWidth = -1; + _textHeight = 0; +} + void HistoryMessage::setReplyMarkup(const MTPReplyMarkup *markup) { if (!markup) { if (_flags & MTPDmessage::Flag::f_reply_markup) { @@ -7276,7 +7328,7 @@ void HistoryMessage::draw(Painter &p, const QRect &r, TextSelection selection, u } else { HistoryMessage::drawInfo(p, r.x() + r.width(), r.y() + r.height(), 2 * r.x() + r.width(), selected, InfoDisplayDefault); } - } else { + } else if (_media) { int32 top = marginTop(); p.translate(left, top); _media->draw(p, r.translated(-left, -top), toMediaSelection(selection), ms); @@ -7437,8 +7489,10 @@ int HistoryMessage::performResizeGetHeight(int width) { } reply->resize(w - st::msgPadding.left() - st::msgPadding.right()); } - } else { + } else if (_media) { _height = _media->resizeGetHeight(width); + } else { + _height = 0; } if (auto keyboard = inlineReplyKeyboard()) { int32 l = 0, w = 0; @@ -7462,8 +7516,10 @@ bool HistoryMessage::hasPoint(int x, int y) const { int top = marginTop(); QRect r(left, top, width, height - top - marginBottom()); return r.contains(x, y); - } else { + } else if (_media) { return _media->hasPoint(x - left, y - marginTop()); + } else { + return false; } } @@ -7579,7 +7635,7 @@ HistoryTextState HistoryMessage::getState(int x, int y, HistoryStateRequest requ if (inDate) { result.cursor = HistoryInDateCursorState; } - } else { + } else if (_media) { result = _media->getState(x - left, y - marginTop(), request); result.symbol += _text.length(); } @@ -7611,7 +7667,7 @@ void HistoryMessage::drawInDialog(Painter &p, const QRect &r, bool act, const Hi if (cacheFor != this) { cacheFor = this; QString msg(inDialogsText()); - if ((!_history->peer->isUser() || out()) && !isPost()) { + if ((!_history->peer->isUser() || out()) && !isPost() && !isEmpty()) { TextCustomTagsMap custom; custom.insert(QChar('c'), qMakePair(textcmdStartLink(1), textcmdStopLink())); msg = lng_message_with_from(lt_from, textRichPrepare((author() == App::self()) ? lang(lng_from_you) : author()->shortName()), lt_message, textRichPrepare(msg)); @@ -7644,7 +7700,7 @@ bool HistoryMessage::displayFromPhoto() const { } bool HistoryMessage::hasFromPhoto() const { - return (Adaptive::Wide() || (!out() && !history()->peer->isUser())) && !isPost(); + return (Adaptive::Wide() || (!out() && !history()->peer->isUser())) && !isPost() && !isEmpty(); } HistoryMessage::~HistoryMessage() { @@ -8109,6 +8165,25 @@ QString HistoryService::notificationText() const { return msg; } +void HistoryService::applyEditionToEmpty() { + TextWithEntities textWithEntities = { QString(), EntitiesInText() }; + setServiceText(QString()); + removeMedia(); + + finishEditionToEmpty(); +} + +void HistoryService::removeMedia() { + if (!_media) return; + + bool mediaWasDisplayed = _media->isDisplayed(); + _media.clear(); + if (mediaWasDisplayed) { + _textWidth = -1; + _textHeight = 0; + } +} + int32 HistoryService::addToOverview(AddToOverviewMethod method) { if (!indexInOverview()) return 0; diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h index 2d5c3eb15c..4d170eb2fb 100644 --- a/Telegram/SourceFiles/history.h +++ b/Telegram/SourceFiles/history.h @@ -608,11 +608,16 @@ public: int32 y, height; History *history; - HistoryBlock *previous() const { + HistoryBlock *previousBlock() const { t_assert(_indexInHistory >= 0); return (_indexInHistory > 0) ? history->blocks.at(_indexInHistory - 1) : nullptr; } + HistoryBlock *nextBlock() const { + t_assert(_indexInHistory >= 0); + + return (_indexInHistory + 1 < history->blocks.size()) ? history->blocks.at(_indexInHistory + 1) : nullptr; + } void setIndexInHistory(int index) { _indexInHistory = index; } @@ -1189,6 +1194,8 @@ public: } virtual void applyEdition(const MTPDmessage &message) { } + virtual void applyEditionToEmpty() { + } virtual void updateMedia(const MTPMessageMedia *media) { } virtual int32 addToOverview(AddToOverviewMethod method) { @@ -1415,6 +1422,9 @@ protected: virtual int resizeGetHeight_(int width) = 0; + void finishEdition(int oldKeyboardTop); + void finishEditionToEmpty(); + PeerData *_from; History *_history; HistoryBlock *_block = nullptr; @@ -1423,14 +1433,26 @@ protected: mutable int32 _authorNameVersion; - HistoryItem *previous() const { + HistoryItem *previousItem() const { if (_block && _indexInBlock >= 0) { if (_indexInBlock > 0) { return _block->items.at(_indexInBlock - 1); } - if (HistoryBlock *previousBlock = _block->previous()) { - t_assert(!previousBlock->items.isEmpty()); - return previousBlock->items.back(); + if (auto previous = _block->previousBlock()) { + t_assert(!previous->items.isEmpty()); + return previous->items.back(); + } + } + return nullptr; + } + HistoryItem *nextItem() const { + if (_block && _indexInBlock >= 0) { + if (_indexInBlock + 1 < _block->items.size()) { + return _block->items.at(_indexInBlock + 1); + } + if (auto next = _block->nextBlock()) { + t_assert(!next->items.isEmpty()); + return next->items.front(); } } return nullptr; @@ -2530,7 +2552,7 @@ public: return _text.isEmpty(); } bool drawBubble() const { - return _media ? (!emptyText() || _media->needsBubble()) : true; + return _media ? (!emptyText() || _media->needsBubble()) : !isEmpty(); } bool hasBubble() const override { return drawBubble(); @@ -2575,6 +2597,7 @@ public: QString notificationText() const override; void applyEdition(const MTPDmessage &message) override; + void applyEditionToEmpty() override; void updateMedia(const MTPMessageMedia *media) override; int32 addToOverview(AddToOverviewMethod method) override; void eraseFromOverview() override; @@ -2650,6 +2673,8 @@ private: HistoryMessage(History *history, MsgId msgId, MTPDmessage::Flags flags, MsgId replyTo, int32 viaBotId, QDateTime date, int32 from, PhotoData *photo, const QString &caption, const MTPReplyMarkup &markup); // local photo friend class HistoryItemInstantiated; + void setEmptyText(); + void initDimensions() override; int resizeGetHeight_(int width) override; int performResizeGetHeight(int width); @@ -2772,6 +2797,8 @@ public: void drawInDialog(Painter &p, const QRect &r, bool act, const HistoryItem *&cacheFor, Text &cache) const override; QString notificationText() const override; + void applyEditionToEmpty() override; + int32 addToOverview(AddToOverviewMethod method) override; void eraseFromOverview() override; @@ -2799,6 +2826,8 @@ protected: void initDimensions() override; int resizeGetHeight_(int width) override; + void removeMedia(); + void setMessageByAction(const MTPmessageAction &action); bool updatePinned(bool force = false); bool updatePinnedText(const QString *pfrom = nullptr, QString *ptext = nullptr); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 4a1f6524d1..5aa691f180 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -4507,6 +4507,11 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { // update before applying skipped if (d.vmessage.type() == mtpc_message) { // apply message edit App::updateEditedMessage(d.vmessage.c_message()); + } else if (d.vmessage.type() == mtpc_messageService) { + auto &message = d.vmessage.c_messageService(); + if (message.vaction.type() == mtpc_messageActionHistoryClear) { + App::updateEditedMessageToEmpty(peerFromMessage(d.vmessage), message.vid.v); + } } ptsApplySkippedUpdates(); } break;