Load albums of last chat messages.

This commit is contained in:
John Preston 2021-10-04 23:37:55 +04:00
parent 576883ddc8
commit 730412fefe
14 changed files with 253 additions and 122 deletions

View file

@ -560,7 +560,8 @@ void ApiWrap::resolveMessageDatas() {
)).done([=]( )).done([=](
const MTPmessages_Messages &result, const MTPmessages_Messages &result,
mtpRequestId requestId) { mtpRequestId requestId) {
gotMessageDatas(nullptr, result, requestId); _session->data().processExistingMessages(nullptr, result);
finalizeMessageDataRequest(nullptr, requestId);
}).fail([=](const MTP::Error &error, mtpRequestId requestId) { }).fail([=](const MTP::Error &error, mtpRequestId requestId) {
finalizeMessageDataRequest(nullptr, requestId); finalizeMessageDataRequest(nullptr, requestId);
}).afterDelay(kSmallDelayMs).send(); }).afterDelay(kSmallDelayMs).send();
@ -586,7 +587,8 @@ void ApiWrap::resolveMessageDatas() {
)).done([=]( )).done([=](
const MTPmessages_Messages &result, const MTPmessages_Messages &result,
mtpRequestId requestId) { mtpRequestId requestId) {
gotMessageDatas(channel, result, requestId); _session->data().processExistingMessages(channel, result);
finalizeMessageDataRequest(channel, requestId);
}).fail([=](const MTP::Error &error, mtpRequestId requestId) { }).fail([=](const MTP::Error &error, mtpRequestId requestId) {
finalizeMessageDataRequest(channel, requestId); finalizeMessageDataRequest(channel, requestId);
}).afterDelay(kSmallDelayMs).send(); }).afterDelay(kSmallDelayMs).send();
@ -602,37 +604,6 @@ void ApiWrap::resolveMessageDatas() {
} }
} }
void ApiWrap::gotMessageDatas(ChannelData *channel, const MTPmessages_Messages &msgs, mtpRequestId requestId) {
const auto handleResult = [&](auto &&result) {
_session->data().processUsers(result.vusers());
_session->data().processChats(result.vchats());
_session->data().processMessages(
result.vmessages(),
NewMessageType::Existing);
};
switch (msgs.type()) {
case mtpc_messages_messages:
handleResult(msgs.c_messages_messages());
break;
case mtpc_messages_messagesSlice:
handleResult(msgs.c_messages_messagesSlice());
break;
case mtpc_messages_channelMessages: {
auto &d = msgs.c_messages_channelMessages();
if (channel) {
channel->ptsReceived(d.vpts().v);
} else {
LOG(("App Error: received messages.channelMessages when no channel was passed! (ApiWrap::gotDependencyItem)"));
}
handleResult(d);
} break;
case mtpc_messages_messagesNotModified:
LOG(("API Error: received messages.messagesNotModified! (ApiWrap::gotDependencyItem)"));
break;
}
finalizeMessageDataRequest(channel, requestId);
}
void ApiWrap::finalizeMessageDataRequest( void ApiWrap::finalizeMessageDataRequest(
ChannelData *channel, ChannelData *channel,
mtpRequestId requestId) { mtpRequestId requestId) {

View file

@ -458,7 +458,6 @@ private:
void saveDraftsToCloud(); void saveDraftsToCloud();
void resolveMessageDatas(); void resolveMessageDatas();
void gotMessageDatas(ChannelData *channel, const MTPmessages_Messages &result, mtpRequestId requestId);
void finalizeMessageDataRequest( void finalizeMessageDataRequest(
ChannelData *channel, ChannelData *channel,
mtpRequestId requestId); mtpRequestId requestId);

View file

@ -438,6 +438,49 @@ void Histories::requestFakeChatListMessage(
}); });
} }
void Histories::requestGroupAround(not_null<HistoryItem*> item) {
const auto history = item->history();
const auto id = item->id;
const auto i = _chatListGroupRequests.find(history);
if (i != end(_chatListGroupRequests)) {
if (i->second.aroundId == id) {
return;
} else {
cancelRequest(i->second.requestId);
_chatListGroupRequests.erase(i);
}
}
constexpr auto kMaxAlbumCount = 10;
const auto requestId = sendRequest(history, RequestType::History, [=](
Fn<void()> finish) {
return session().api().request(MTPmessages_GetHistory(
history->peer->input,
MTP_int(id),
MTP_int(0), // offset_date
MTP_int(-kMaxAlbumCount),
MTP_int(2 * kMaxAlbumCount - 1),
MTP_int(0), // max_id
MTP_int(0), // min_id
MTP_long(0) // hash
)).done([=](const MTPmessages_Messages &result) {
_owner->processExistingMessages(
history->peer->asChannel(),
result);
_chatListGroupRequests.remove(history);
history->migrateToOrMe()->applyChatListGroup(
history->channelId(),
result);
finish();
}).fail([=](const MTP::Error &error) {
_chatListGroupRequests.remove(history);
finish();
}).send();
});
_chatListGroupRequests.emplace(
history,
ChatListGroupRequest{ .aroundId = id, .requestId = requestId });
}
void Histories::sendPendingReadInbox(not_null<History*> history) { void Histories::sendPendingReadInbox(not_null<History*> history) {
if (const auto state = lookup(history)) { if (const auto state = lookup(history)) {
DEBUG_LOG(("Reading: send pending now with till %1 and when %2" DEBUG_LOG(("Reading: send pending now with till %1 and when %2"

View file

@ -59,6 +59,8 @@ public:
void changeDialogUnreadMark(not_null<History*> history, bool unread); void changeDialogUnreadMark(not_null<History*> history, bool unread);
void requestFakeChatListMessage(not_null<History*> history); void requestFakeChatListMessage(not_null<History*> history);
void requestGroupAround(not_null<HistoryItem*> item);
void deleteMessages( void deleteMessages(
not_null<History*> history, not_null<History*> history,
const QVector<MTPint> &ids, const QVector<MTPint> &ids,
@ -95,6 +97,10 @@ private:
bool sentReadDone = false; bool sentReadDone = false;
bool postponedRequestEntry = false; bool postponedRequestEntry = false;
}; };
struct ChatListGroupRequest {
MsgId aroundId = 0;
mtpRequestId requestId = 0;
};
void readInboxTill(not_null<History*> history, MsgId tillId, bool force); void readInboxTill(not_null<History*> history, MsgId tillId, bool force);
void sendReadRequests(); void sendReadRequests();
@ -130,6 +136,10 @@ private:
base::flat_set<not_null<History*>> _fakeChatListRequests; base::flat_set<not_null<History*>> _fakeChatListRequests;
base::flat_map<
not_null<History*>,
ChatListGroupRequest> _chatListGroupRequests;
}; };
} // namespace Data } // namespace Data

View file

@ -63,6 +63,7 @@ constexpr auto kFastRevokeRestriction = 24 * 60 * TimeId(60);
constexpr auto kMaxPreviewImages = 3; constexpr auto kMaxPreviewImages = 3;
using ItemPreview = HistoryView::ItemPreview; using ItemPreview = HistoryView::ItemPreview;
using ItemPreviewImage = HistoryView::ItemPreviewImage;
[[nodiscard]] Call ComputeCallData(const MTPDmessageActionPhoneCall &call) { [[nodiscard]] Call ComputeCallData(const MTPDmessageActionPhoneCall &call) {
auto result = Call(); auto result = Call();
@ -191,25 +192,18 @@ using ItemPreview = HistoryView::ItemPreview;
return square; return square;
} }
struct PreparedPreview { [[nodiscard]] ItemPreviewImage PreparePhotoPreview(
QImage preview;
bool loading = false;
explicit operator bool() const {
return !preview.isNull() || loading;
}
};
[[nodiscard]] PreparedPreview PreparePhotoPreview(
not_null<const HistoryItem*> item, not_null<const HistoryItem*> item,
const std::shared_ptr<PhotoMedia> &media, const std::shared_ptr<PhotoMedia> &media,
ImageRoundRadius radius) { ImageRoundRadius radius) {
const auto photo = media->owner();
const auto readyCacheKey = reinterpret_cast<uint64>(photo.get());
if (const auto small = media->image(PhotoSize::Small)) { if (const auto small = media->image(PhotoSize::Small)) {
return { PreparePreviewImage(small, radius) }; return { PreparePreviewImage(small, radius), readyCacheKey };
} else if (const auto thumbnail = media->image(PhotoSize::Thumbnail)) { } else if (const auto thumbnail = media->image(PhotoSize::Thumbnail)) {
return { PreparePreviewImage(thumbnail, radius) }; return { PreparePreviewImage(thumbnail, radius), readyCacheKey };
} else if (const auto large = media->image(PhotoSize::Large)) { } else if (const auto large = media->image(PhotoSize::Large)) {
return { PreparePreviewImage(large, radius) }; return { PreparePreviewImage(large, radius), readyCacheKey };
} }
const auto allowedToDownload = [&] { const auto allowedToDownload = [&] {
const auto photo = media->owner(); const auto photo = media->owner();
@ -223,29 +217,32 @@ struct PreparedPreview {
item->history()->peer, item->history()->peer,
photo); photo);
}(); }();
const auto cacheKey = allowedToDownload ? 0 : readyCacheKey;
if (allowedToDownload) { if (allowedToDownload) {
media->owner()->load(PhotoSize::Small, item->fullId()); media->owner()->load(PhotoSize::Small, item->fullId());
} }
if (const auto blurred = media->thumbnailInline()) { if (const auto blurred = media->thumbnailInline()) {
return { PreparePreviewImage(blurred, radius), allowedToDownload }; return { PreparePreviewImage(blurred, radius), cacheKey };
} }
return { QImage(), allowedToDownload }; return { QImage(), allowedToDownload ? 0 : cacheKey };
} }
[[nodiscard]] PreparedPreview PrepareFilePreviewImage( [[nodiscard]] ItemPreviewImage PrepareFilePreviewImage(
not_null<const HistoryItem*> item, not_null<const HistoryItem*> item,
const std::shared_ptr<DocumentMedia> &media, const std::shared_ptr<DocumentMedia> &media,
ImageRoundRadius radius) { ImageRoundRadius radius) {
Expects(media->owner()->hasThumbnail()); Expects(media->owner()->hasThumbnail());
const auto document = media->owner();
const auto readyCacheKey = reinterpret_cast<uint64>(document.get());
if (const auto thumbnail = media->thumbnail()) { if (const auto thumbnail = media->thumbnail()) {
return { PreparePreviewImage(thumbnail, radius) }; return { PreparePreviewImage(thumbnail, radius), readyCacheKey };
} }
media->owner()->loadThumbnail(item->fullId()); document->loadThumbnail(item->fullId());
if (const auto blurred = media->thumbnailInline()) { if (const auto blurred = media->thumbnailInline()) {
return { PreparePreviewImage(blurred, radius), true }; return { PreparePreviewImage(blurred, radius), 0 };
} }
return { QImage(), true }; return { QImage(), 0 };
} }
[[nodiscard]] QImage PutPlayIcon(QImage preview) { [[nodiscard]] QImage PutPlayIcon(QImage preview) {
@ -260,28 +257,17 @@ struct PreparedPreview {
return preview; return preview;
} }
[[nodiscard]] PreparedPreview PrepareFilePreview( [[nodiscard]] ItemPreviewImage PrepareFilePreview(
not_null<const HistoryItem*> item, not_null<const HistoryItem*> item,
const std::shared_ptr<DocumentMedia> &media, const std::shared_ptr<DocumentMedia> &media,
ImageRoundRadius radius) { ImageRoundRadius radius) {
if (auto result = PrepareFilePreviewImage(item, media, radius)) { auto result = PrepareFilePreviewImage(item, media, radius);
const auto document = media->owner(); const auto document = media->owner();
if (!result.preview.isNull() if (!result.data.isNull()
&& (document->isVideoFile() || document->isVideoMessage())) { && (document->isVideoFile() || document->isVideoMessage())) {
result.preview = PutPlayIcon(std::move(result.preview)); result.data = PutPlayIcon(std::move(result.data));
}
return result;
} }
Expects(media->owner()->hasThumbnail()); return result;
if (const auto thumbnail = media->thumbnail()) {
return { PreparePreviewImage(thumbnail, radius) };
}
media->owner()->loadThumbnail(item->fullId());
if (const auto blurred = media->thumbnailInline()) {
return { PreparePreviewImage(blurred, radius), true };
}
return { QImage(), true };
} }
[[nodiscard]] bool TryFilePreview(not_null<DocumentData*> document) { [[nodiscard]] bool TryFilePreview(not_null<DocumentData*> document) {
@ -290,6 +276,20 @@ struct PreparedPreview {
&& !document->isAudioFile(); && !document->isAudioFile();
} }
template <typename MediaType>
[[nodiscard]] ItemPreviewImage FindCachedPreview(
const std::vector<ItemPreviewImage> *existing,
not_null<MediaType*> data) {
if (!existing) {
return {};
}
const auto i = ranges::find(
*existing,
reinterpret_cast<uint64>(data.get()),
&ItemPreviewImage::cacheKey);
return (i != end(*existing)) ? *i : ItemPreviewImage();
}
} // namespace } // namespace
TextForMimeData WithCaptionClipboardText( TextForMimeData WithCaptionClipboardText(
@ -554,22 +554,27 @@ ItemPreview MediaPhoto::toPreview(ToPreviewOptions options) const {
return toGroupPreview(group->items, options); return toGroupPreview(group->items, options);
} }
} }
const auto caption = options.hideCaption auto images = std::vector<ItemPreviewImage>();
? QString()
: parent()->originalText().text;
auto images = std::vector<QImage>();
const auto media = _photo->createMediaView();
const auto radius = _chat
? ImageRoundRadius::Ellipse
: ImageRoundRadius::Small;
auto context = std::any(); auto context = std::any();
if (auto prepared = PreparePhotoPreview(parent(), media, radius)) { if (auto cached = FindCachedPreview(options.existing, _photo)) {
images.push_back(std::move(prepared.preview)); images.push_back(std::move(cached));
if (prepared.loading) { } else {
context = media; const auto media = _photo->createMediaView();
const auto radius = _chat
? ImageRoundRadius::Ellipse
: ImageRoundRadius::Small;
if (auto prepared = PreparePhotoPreview(parent(), media, radius)
; prepared || !prepared.cacheKey) {
images.push_back(std::move(prepared));
if (!prepared.cacheKey) {
context = media;
}
} }
} }
const auto type = tr::lng_in_dlg_photo(tr::now); const auto type = tr::lng_in_dlg_photo(tr::now);
const auto caption = options.hideCaption
? QString()
: parent()->originalText().text;
return { return {
.text = WithCaptionDialogsText(type, caption, !images.empty()), .text = WithCaptionDialogsText(type, caption, !images.empty()),
.images = std::move(images), .images = std::move(images),
@ -751,6 +756,23 @@ ItemPreview MediaFile::toPreview(ToPreviewOptions options) const {
if (const auto sticker = _document->sticker()) { if (const auto sticker = _document->sticker()) {
return Media::toPreview(options); return Media::toPreview(options);
} }
auto images = std::vector<ItemPreviewImage>();
auto context = std::any();
if (auto cached = FindCachedPreview(options.existing, _document)) {
images.push_back(std::move(cached));
} else if (TryFilePreview(_document)) {
const auto media = _document->createMediaView();
const auto radius = _document->isVideoMessage()
? ImageRoundRadius::Ellipse
: ImageRoundRadius::Small;
if (auto prepared = PrepareFilePreview(parent(), media, radius)
; prepared || !prepared.cacheKey) {
images.push_back(std::move(prepared));
if (!prepared.cacheKey) {
context = media;
}
}
}
const auto type = [&] { const auto type = [&] {
using namespace Ui::Text; using namespace Ui::Text;
if (_document->isVideoMessage()) { if (_document->isVideoMessage()) {
@ -772,22 +794,6 @@ ItemPreview MediaFile::toPreview(ToPreviewOptions options) const {
const auto caption = options.hideCaption const auto caption = options.hideCaption
? QString() ? QString()
: parent()->originalText().text; : parent()->originalText().text;
auto images = std::vector<QImage>();
const auto media = TryFilePreview(_document)
? _document->createMediaView()
: nullptr;
const auto radius = _document->isVideoMessage()
? ImageRoundRadius::Ellipse
: ImageRoundRadius::Small;
auto context = std::any();
if (media) {
if (auto prepared = PrepareFilePreview(parent(), media, radius)) {
images.push_back(std::move(prepared.preview));
if (prepared.loading) {
context = media;
}
}
}
return { return {
.text = WithCaptionDialogsText(type, caption, !images.empty()), .text = WithCaptionDialogsText(type, caption, !images.empty()),
.images = std::move(images), .images = std::move(images),

View file

@ -28,6 +28,7 @@ enum class Context : char;
class Element; class Element;
class Media; class Media;
struct ItemPreview; struct ItemPreview;
struct ItemPreviewImage;
struct ToPreviewOptions; struct ToPreviewOptions;
} // namespace HistoryView } // namespace HistoryView
@ -75,6 +76,7 @@ public:
not_null<HistoryItem*> parent() const; not_null<HistoryItem*> parent() const;
using ToPreviewOptions = HistoryView::ToPreviewOptions; using ToPreviewOptions = HistoryView::ToPreviewOptions;
using ItemPreviewImage = HistoryView::ItemPreviewImage;
using ItemPreview = HistoryView::ItemPreview; using ItemPreview = HistoryView::ItemPreview;
virtual std::unique_ptr<Media> clone(not_null<HistoryItem*> parent) = 0; virtual std::unique_ptr<Media> clone(not_null<HistoryItem*> parent) = 0;

View file

@ -1859,6 +1859,26 @@ void Session::processMessages(
processMessages(data.v, type); processMessages(data.v, type);
} }
void Session::processExistingMessages(
ChannelData *channel,
const MTPmessages_Messages &data) {
data.match([&](const MTPDmessages_channelMessages &data) {
if (channel) {
channel->ptsReceived(data.vpts().v);
} else {
LOG(("App Error: received messages.channelMessages!"));
}
}, [](const auto &) {});
data.match([&](const MTPDmessages_messagesNotModified&) {
LOG(("API Error: received messages.messagesNotModified!"));
}, [&](const auto &data) {
processUsers(data.vusers());
processChats(data.vchats());
processMessages(data.vmessages(), NewMessageType::Existing);
});
}
const Session::Messages *Session::messagesList(ChannelId channelId) const { const Session::Messages *Session::messagesList(ChannelId channelId) const {
if (channelId == NoChannel) { if (channelId == NoChannel) {
return &_messages; return &_messages;

View file

@ -341,6 +341,9 @@ public:
void processMessages( void processMessages(
const MTPVector<MTPMessage> &data, const MTPVector<MTPMessage> &data,
NewMessageType type); NewMessageType type);
void processExistingMessages(
ChannelData *channel,
const MTPmessages_Messages &data);
void processMessagesDeleted( void processMessagesDeleted(
ChannelId channelId, ChannelId channelId,
const QVector<MTPint> &data); const QVector<MTPint> &data);

View file

@ -105,6 +105,7 @@ void MessageView::paint(
return; return;
} }
if (_textCachedFor != item.get()) { if (_textCachedFor != item.get()) {
options.existing = &_imagesCache;
auto preview = item->toPreview(options); auto preview = item->toPreview(options);
if (!preview.images.empty() && preview.imagesInTextPosition > 0) { if (!preview.images.empty() && preview.imagesInTextPosition > 0) {
_senderCache.setText( _senderCache.setText(
@ -140,7 +141,11 @@ void MessageView::paint(
? st::dialogsTextPaletteOver ? st::dialogsTextPaletteOver
: st::dialogsTextPalette); : st::dialogsTextPalette);
p.setFont(st::dialogsTextFont); p.setFont(st::dialogsTextFont);
p.setPen(active ? st::dialogsTextFgActive : (selected ? st::dialogsTextFgOver : st::dialogsTextFg)); p.setPen(active
? st::dialogsTextFgActive
: selected
? st::dialogsTextFgOver
: st::dialogsTextFg);
const auto guard = gsl::finally([&] { const auto guard = gsl::finally([&] {
p.restoreTextPalette(); p.restoreTextPalette();
}); });
@ -161,7 +166,10 @@ void MessageView::paint(
if (rect.width() < st::dialogsMiniPreview) { if (rect.width() < st::dialogsMiniPreview) {
break; break;
} }
p.drawImage(rect.x(), rect.y() + st::dialogsMiniPreviewTop, image); p.drawImage(
rect.x(),
rect.y() + st::dialogsMiniPreviewTop,
image.data);
rect.setLeft(rect.x() rect.setLeft(rect.x()
+ st::dialogsMiniPreview + st::dialogsMiniPreview
+ st::dialogsMiniPreviewSkip); + st::dialogsMiniPreviewSkip);

View file

@ -18,6 +18,7 @@ namespace Ui {
namespace HistoryView { namespace HistoryView {
struct ToPreviewOptions; struct ToPreviewOptions;
struct ItemPreviewImage;
struct ItemPreview; struct ItemPreview;
} // namespace HistoryView } // namespace HistoryView
@ -31,6 +32,7 @@ public:
~MessageView(); ~MessageView();
using ToPreviewOptions = HistoryView::ToPreviewOptions; using ToPreviewOptions = HistoryView::ToPreviewOptions;
using ItemPreviewImage = HistoryView::ItemPreviewImage;
using ItemPreview = HistoryView::ItemPreview; using ItemPreview = HistoryView::ItemPreview;
void itemInvalidated(not_null<const HistoryItem*> item); void itemInvalidated(not_null<const HistoryItem*> item);
@ -50,7 +52,7 @@ private:
mutable const HistoryItem *_textCachedFor = nullptr; mutable const HistoryItem *_textCachedFor = nullptr;
mutable Ui::Text::String _senderCache; mutable Ui::Text::String _senderCache;
mutable Ui::Text::String _textCache; mutable Ui::Text::String _textCache;
mutable std::vector<QImage> _imagesCache; mutable std::vector<ItemPreviewImage> _imagesCache;
mutable std::unique_ptr<LoadingContext> _loadingContext; mutable std::unique_ptr<LoadingContext> _loadingContext;
}; };

View file

@ -1253,27 +1253,31 @@ void History::addOlderSlice(const QVector<MTPMessage> &slice) {
} }
if (const auto added = createItems(slice); !added.empty()) { if (const auto added = createItems(slice); !added.empty()) {
startBuildingFrontBlock(added.size()); addCreatedOlderSlice(added);
for (const auto &item : added) {
addItemToBlock(item);
}
finishBuildingFrontBlock();
if (loadedAtBottom()) {
// Add photos to overview and authors to lastAuthors.
addItemsToLists(added);
}
addToSharedMedia(added);
} else { } else {
// If no items were added it means we've loaded everything old. // If no items were added it means we've loaded everything old.
_loadedAtTop = true; _loadedAtTop = true;
addEdgesToSharedMedia(); addEdgesToSharedMedia();
} }
checkLocalMessages(); checkLocalMessages();
checkLastMessage(); checkLastMessage();
} }
void History::addCreatedOlderSlice(
const std::vector<not_null<HistoryItem*>> &items) {
startBuildingFrontBlock(items.size());
for (const auto &item : items) {
addItemToBlock(item);
}
finishBuildingFrontBlock();
if (loadedAtBottom()) {
// Add photos to overview and authors to lastAuthors.
addItemsToLists(items);
}
addToSharedMedia(items);
}
void History::addNewerSlice(const QVector<MTPMessage> &slice) { void History::addNewerSlice(const QVector<MTPMessage> &slice) {
bool wasLoadedAtBottom = loadedAtBottom(); bool wasLoadedAtBottom = loadedAtBottom();
@ -2266,6 +2270,14 @@ void History::setChatListMessage(HistoryItem *item) {
} }
_chatListMessage = item; _chatListMessage = item;
setChatListTimeId(item->date()); setChatListTimeId(item->date());
// If we have a single message from a group, request the full album.
if (hasOrphanMediaGroupPart()
&& !item->toPreview({
.hideSender = true,
.hideCaption = true }).images.empty()) {
owner().histories().requestGroupAround(item);
}
} else if (!_chatListMessage || *_chatListMessage) { } else if (!_chatListMessage || *_chatListMessage) {
_chatListMessage = nullptr; _chatListMessage = nullptr;
updateChatListEntry(); updateChatListEntry();
@ -2422,6 +2434,44 @@ void History::setFakeChatListMessageFrom(const MTPmessages_Messages &data) {
setChatListMessage(item); setChatListMessage(item);
} }
void History::applyChatListGroup(
ChannelId channelId,
const MTPmessages_Messages &data) {
if (!isEmpty()
|| !_chatListMessage
|| !*_chatListMessage
|| (*_chatListMessage)->history()->channelId() != channelId
|| (*_chatListMessage)->history() != this
|| !_lastMessage
|| !*_lastMessage) {
return;
}
// Apply loaded album as a last slice.
const auto processMessages = [&](const MTPVector<MTPMessage> &messages) {
auto items = std::vector<not_null<HistoryItem*>>();
items.reserve(messages.v.size());
for (const auto &message : messages.v) {
const auto id = IdFromMessage(message);
if (const auto message = owner().message(channelId, id)) {
items.push_back(message);
}
}
if (!ranges::contains(items, not_null(*_lastMessage))
|| !ranges::contains(items, not_null(*_chatListMessage))) {
return;
}
_loadedAtBottom = true;
ranges::sort(items, ranges::less{}, &HistoryItem::id);
addCreatedOlderSlice(items);
checkLocalMessages();
checkLastMessage();
};
data.match([&](const MTPDmessages_messagesNotModified &) {
}, [&](const auto &data) {
processMessages(data.vmessages());
});
}
HistoryItem *History::lastMessage() const { HistoryItem *History::lastMessage() const {
return _lastMessage.value_or(nullptr); return _lastMessage.value_or(nullptr);
} }

View file

@ -409,6 +409,10 @@ public:
void setFakeChatListMessageFrom(const MTPmessages_Messages &data); void setFakeChatListMessageFrom(const MTPmessages_Messages &data);
void checkChatListMessageRemoved(not_null<HistoryItem*> item); void checkChatListMessageRemoved(not_null<HistoryItem*> item);
void applyChatListGroup(
ChannelId channelId,
const MTPmessages_Messages &data);
void forgetScrollState() { void forgetScrollState() {
scrollTopItem = nullptr; scrollTopItem = nullptr;
} }
@ -516,6 +520,9 @@ private:
return _buildingFrontBlock != nullptr; return _buildingFrontBlock != nullptr;
} }
void addCreatedOlderSlice(
const std::vector<not_null<HistoryItem*>> &items);
void checkForLoadedAtTop(not_null<HistoryItem*> added); void checkForLoadedAtTop(not_null<HistoryItem*> added);
void mainViewRemoved( void mainViewRemoved(
not_null<HistoryBlock*> block, not_null<HistoryBlock*> block,

View file

@ -57,20 +57,30 @@ enum class PointState : char;
enum class Context : char; enum class Context : char;
class ElementDelegate; class ElementDelegate;
struct ToPreviewOptions { struct ItemPreviewImage {
bool hideSender = false; QImage data;
bool hideCaption = false; uint64 cacheKey = 0;
bool generateImages = true;
bool ignoreGroup = false; explicit operator bool() const {
return !data.isNull();
}
}; };
struct ItemPreview { struct ItemPreview {
QString text; QString text;
std::vector<QImage> images; std::vector<ItemPreviewImage> images;
int imagesInTextPosition = 0; int imagesInTextPosition = 0;
std::any loadingContext; std::any loadingContext;
}; };
struct ToPreviewOptions {
const std::vector<ItemPreviewImage> *existing = nullptr;
bool hideSender = false;
bool hideCaption = false;
bool generateImages = true;
bool ignoreGroup = false;
};
} // namespace HistoryView } // namespace HistoryView
struct HiddenSenderInfo; struct HiddenSenderInfo;

View file

@ -804,7 +804,7 @@ void Notification::updateNotifyDisplay() {
p.setTextPalette(st::dialogsTextPalette); p.setTextPalette(st::dialogsTextPalette);
p.setPen(st::dialogsTextFg); p.setPen(st::dialogsTextFg);
p.setFont(st::dialogsTextFont); p.setFont(st::dialogsTextFont);
const auto text = _item // #TODO minis use images const auto text = _item
? _item->toPreview({ ? _item->toPreview({
.hideSender = reminder, .hideSender = reminder,
.generateImages = false, .generateImages = false,