diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index e2ebfc26f..ef7dccd1d 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -325,7 +325,7 @@ void ApiWrap::requestContacts() { if (contact.type() != mtpc_contact) continue; const auto userId = contact.c_contact().vuser_id.v; - if (userId == Auth().userId() && App::self()) { + if (userId == _session->userId() && App::self()) { App::self()->setContactStatus( UserData::ContactStatus::Contact); } @@ -527,7 +527,7 @@ void ApiWrap::gotUserFull(UserData *user, const MTPUserFull &result, mtpRequestI App::feedUsers(MTP_vector(1, d.vuser)); if (d.has_profile_photo()) { - App::feedPhoto(d.vprofile_photo); + _session->data().photo(d.vprofile_photo); } App::feedUserLink(MTP_int(peerToUser(user->id)), d.vlink.c_contacts_link().vmy_link, d.vlink.c_contacts_link().vforeign_link); if (App::main()) { @@ -606,6 +606,65 @@ void ApiWrap::requestPeer(PeerData *peer) { } } +void ApiWrap::markMediaRead( + const base::flat_set> &items) { + auto markedIds = QVector(); + auto channelMarkedIds = base::flat_map< + not_null, + QVector>(); + markedIds.reserve(items.size()); + for (const auto item : items) { + if (!item->isMediaUnread() || (item->out() && !item->mentionsMe())) { + continue; + } + item->markMediaRead(); + if (!IsServerMsgId(item->id)) { + continue; + } + if (const auto channel = item->history()->peer->asChannel()) { + channelMarkedIds[channel].push_back(MTP_int(item->id)); + } else { + markedIds.push_back(MTP_int(item->id)); + } + } + if (!markedIds.isEmpty()) { + request(MTPmessages_ReadMessageContents( + MTP_vector(markedIds) + )).done([=](const MTPmessages_AffectedMessages &result) { + applyAffectedMessages(result); + }).send(); + } + for (const auto &channelIds : channelMarkedIds) { + request(MTPchannels_ReadMessageContents( + channelIds.first->inputChannel, + MTP_vector(channelIds.second) + )).send(); + } +} + +void ApiWrap::markMediaRead(not_null item) { + if (!item->isMediaUnread() || (item->out() && !item->mentionsMe())) { + return; + } + item->markMediaRead(); + if (!IsServerMsgId(item->id)) { + return; + } + const auto ids = MTP_vector(1, MTP_int(item->id)); + if (const auto channel = item->history()->peer->asChannel()) { + request(MTPchannels_ReadMessageContents( + channel->inputChannel, + ids + )).send(); + } else { + request(MTPmessages_ReadMessageContents( + ids + )).done([=](const MTPmessages_AffectedMessages &result) { + applyAffectedMessages(result); + }).send(); + } +} + void ApiWrap::requestPeers(const QList &peers) { QVector chats; QVector channels; @@ -1612,31 +1671,29 @@ void ApiWrap::resolveWebPages() { using MessageIdsByChannel = QMap; MessageIdsByChannel idsByChannel; // temp_req_id = -index - 2 - auto &items = App::webPageItems(); ids.reserve(_webPagesPending.size()); int32 t = unixtime(), m = INT_MAX; for (auto i = _webPagesPending.begin(); i != _webPagesPending.cend(); ++i) { if (i.value() > 0) continue; if (i.key()->pendingTill <= t) { - auto j = items.constFind(i.key()); - if (j != items.cend() && !j.value().empty()) { - for_const (auto item, j.value()) { - if (item->id > 0) { - if (item->channelId() == NoChannel) { - ids.push_back(MTP_int(item->id)); - i.value() = -1; - } else { - auto channel = item->history()->peer->asChannel(); - auto channelMap = idsByChannel.find(channel); - if (channelMap == idsByChannel.cend()) { - channelMap = idsByChannel.insert(channel, IndexAndMessageIds(idsByChannel.size(), QVector(1, MTP_int(item->id)))); - } else { - channelMap.value().second.push_back(MTP_int(item->id)); - } - i.value() = -channelMap.value().first - 2; - } - break; + const auto item = _session->data().findWebPageItem(i.key()); + if (item) { + if (item->channelId() == NoChannel) { + ids.push_back(MTP_int(item->id)); + i.value() = -1; + } else { + auto channel = item->history()->peer->asChannel(); + auto channelMap = idsByChannel.find(channel); + if (channelMap == idsByChannel.cend()) { + channelMap = idsByChannel.insert( + channel, + IndexAndMessageIds( + idsByChannel.size(), + QVector(1, MTP_int(item->id)))); + } else { + channelMap.value().second.push_back(MTP_int(item->id)); } + i.value() = -channelMap.value().first - 2; } } } else { @@ -1728,27 +1785,22 @@ void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &msgs v->at(index), NewMessageExisting); if (item) { - Auth().data().requestItemViewResize(item); + _session->data().requestItemViewResize(item); } } - auto &items = App::webPageItems(); for (auto i = _webPagesPending.begin(); i != _webPagesPending.cend();) { if (i.value() == req) { if (i.key()->pendingTill > 0) { i.key()->pendingTill = -1; - auto j = items.constFind(i.key()); - if (j != items.cend()) { - for_const (auto item, j.value()) { - Auth().data().requestItemViewResize(item); - } - } + _session->data().notifyWebPageUpdateDelayed(i.key()); } i = _webPagesPending.erase(i); } else { ++i; } } + _session->data().sendWebPageGameNotifications(); } void ApiWrap::stickersSaveOrder() { @@ -2081,11 +2133,11 @@ void ApiWrap::applyUpdateNoPtsCheck(const MTPUpdate &update) { case mtpc_updateReadMessagesContents: { auto &d = update.c_updateReadMessagesContents(); auto possiblyReadMentions = base::flat_set(); - for_const (auto &msgId, d.vmessages.v) { + for (const auto &msgId : d.vmessages.v) { if (auto item = App::histItemById(NoChannel, msgId.v)) { if (item->isMediaUnread()) { item->markMediaRead(); - _session->data().requestItemRepaint(item); + _session->data().requestItemViewRepaint(item); if (item->out() && item->history()->peer->isUser()) { auto when = App::main()->requestingDifference() ? 0 : unixtime(); @@ -2276,7 +2328,9 @@ void ApiWrap::preloadEnoughUnreadMentions(not_null history) { _unreadMentionsRequests.emplace(history, requestId); } -void ApiWrap::checkForUnreadMentions(const base::flat_set &possiblyReadMentions, ChannelData *channel) { +void ApiWrap::checkForUnreadMentions( + const base::flat_set &possiblyReadMentions, + ChannelData *channel) { for (auto msgId : possiblyReadMentions) { requestMessageData(channel, msgId, [](ChannelData *channel, MsgId msgId) { if (auto item = App::histItemById(channel, msgId)) { @@ -2510,7 +2564,7 @@ void ApiWrap::userPhotosDone( auto photoIds = std::vector(); photoIds.reserve(photos.size()); for (auto &photo : photos) { - if (auto photoData = App::feedPhoto(photo)) { + if (auto photoData = _session->data().photo(photo)) { photoIds.push_back(photoData->id); } } @@ -2774,9 +2828,7 @@ void ApiWrap::shareContact( not_null user, const SendOptions &options) { const auto userId = peerToUser(user->id); - const auto phone = user->phone().isEmpty() - ? App::phoneFromSharedContact(userId) - : user->phone(); + const auto phone = Auth().data().findContactPhone(user); if (phone.isEmpty()) { return; } diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index bef746bc2..99b64fd9c 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -73,6 +73,9 @@ public: void processFullPeer(PeerData *peer, const MTPmessages_ChatFull &result); void processFullPeer(UserData *user, const MTPUserFull &result); + void markMediaRead(const base::flat_set> &items); + void markMediaRead(not_null item); + void requestSelfParticipant(ChannelData *channel); void kickParticipant(not_null chat, not_null user); void kickParticipant( diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index e7899c828..22bdf6b7e 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -55,25 +55,9 @@ namespace { using MutedPeers = QMap, bool>; MutedPeers mutedPeers; - PhotosData photosData; - DocumentsData documentsData; - using LocationsData = QHash; LocationsData locationsData; - using WebPagesData = QHash; - WebPagesData webPagesData; - - using GamesData = QHash; - GamesData gamesData; - - PhotoItems photoItems; - DocumentItems documentItems; - WebPageItems webPageItems; - GameItems gameItems; - SharedContactItems sharedContactItems; - GifItems gifItems; - using DependentItemsSet = OrderedSet; using DependentItems = QMap; DependentItems dependentItems; @@ -114,11 +98,6 @@ namespace { int32 serviceImageCacheSize = 0; - using LastPhotosList = QLinkedList; - LastPhotosList lastPhotos; - using LastPhotosMap = QHash; - LastPhotosMap lastPhotosMap; - } // namespace namespace App { @@ -928,8 +907,9 @@ namespace { auto entities = m.has_entities() ? TextUtilities::EntitiesFromMTP(m.ventities.v) : EntitiesInText(); + const auto media = m.has_media() ? &m.vmedia : nullptr; existing->setText({ text, entities }); - existing->updateMedia(m.has_media() ? (&m.vmedia) : nullptr); + existing->updateSentMedia(m.has_media() ? &m.vmedia : nullptr); existing->updateReplyMarkup(m.has_reply_markup() ? (&m.vreply_markup) : nullptr); @@ -1146,207 +1126,6 @@ namespace { } } - PhotoData *feedPhoto(const MTPPhoto &photo, PhotoData *convert) { - switch (photo.type()) { - case mtpc_photo: { - return feedPhoto(photo.c_photo(), convert); - } break; - case mtpc_photoEmpty: { - return App::photoSet(photo.c_photoEmpty().vid.v, convert, 0, 0, ImagePtr(), ImagePtr(), ImagePtr()); - } break; - } - return App::photo(0); - } - - PhotoData *feedPhoto(const MTPPhoto &photo, const PreparedPhotoThumbs &thumbs) { - const QPixmap *thumb = 0, *medium = 0, *full = 0; - int32 thumbLevel = -1, mediumLevel = -1, fullLevel = -1; - for (PreparedPhotoThumbs::const_iterator i = thumbs.cbegin(), e = thumbs.cend(); i != e; ++i) { - int32 newThumbLevel = -1, newMediumLevel = -1, newFullLevel = -1; - switch (i.key()) { - case 's': newThumbLevel = 0; newMediumLevel = 5; newFullLevel = 4; break; // box 100x100 - case 'm': newThumbLevel = 2; newMediumLevel = 0; newFullLevel = 3; break; // box 320x320 - case 'x': newThumbLevel = 5; newMediumLevel = 3; newFullLevel = 1; break; // box 800x800 - case 'y': newThumbLevel = 6; newMediumLevel = 6; newFullLevel = 0; break; // box 1280x1280 - case 'w': newThumbLevel = 8; newMediumLevel = 8; newFullLevel = 2; break; // box 2560x2560 // if loading this fix HistoryPhoto::updateFrom - case 'a': newThumbLevel = 1; newMediumLevel = 4; newFullLevel = 8; break; // crop 160x160 - case 'b': newThumbLevel = 3; newMediumLevel = 1; newFullLevel = 7; break; // crop 320x320 - case 'c': newThumbLevel = 4; newMediumLevel = 2; newFullLevel = 6; break; // crop 640x640 - case 'd': newThumbLevel = 7; newMediumLevel = 7; newFullLevel = 5; break; // crop 1280x1280 - } - if (newThumbLevel < 0 || newMediumLevel < 0 || newFullLevel < 0) { - continue; - } - if (thumbLevel < 0 || newThumbLevel < thumbLevel) { - thumbLevel = newThumbLevel; - thumb = &i.value(); - } - if (mediumLevel < 0 || newMediumLevel < mediumLevel) { - mediumLevel = newMediumLevel; - medium = &i.value(); - } - if (fullLevel < 0 || newFullLevel < fullLevel) { - fullLevel = newFullLevel; - full = &i.value(); - } - } - if (!thumb || !medium || !full) { - return App::photo(0); - } - switch (photo.type()) { - case mtpc_photo: { - const auto &ph(photo.c_photo()); - return App::photoSet(ph.vid.v, 0, ph.vaccess_hash.v, ph.vdate.v, ImagePtr(*thumb, "JPG"), ImagePtr(*medium, "JPG"), ImagePtr(*full, "JPG")); - } break; - case mtpc_photoEmpty: return App::photo(photo.c_photoEmpty().vid.v); - } - return App::photo(0); - } - - PhotoData *feedPhoto(const MTPDphoto &photo, PhotoData *convert) { - auto &sizes = photo.vsizes.v; - const MTPPhotoSize *thumb = 0, *medium = 0, *full = 0; - int32 thumbLevel = -1, mediumLevel = -1, fullLevel = -1; - for (QVector::const_iterator i = sizes.cbegin(), e = sizes.cend(); i != e; ++i) { - char size = 0; - switch (i->type()) { - case mtpc_photoSize: { - auto &s = i->c_photoSize().vtype.v; - if (s.size()) size = s[0]; - } break; - - case mtpc_photoCachedSize: { - auto &s = i->c_photoCachedSize().vtype.v; - if (s.size()) size = s[0]; - } break; - } - if (!size) continue; - - int32 newThumbLevel = -1, newMediumLevel = -1, newFullLevel = -1; - switch (size) { - case 's': newThumbLevel = 0; newMediumLevel = 5; newFullLevel = 4; break; // box 100x100 - case 'm': newThumbLevel = 2; newMediumLevel = 0; newFullLevel = 3; break; // box 320x320 - case 'x': newThumbLevel = 5; newMediumLevel = 3; newFullLevel = 1; break; // box 800x800 - case 'y': newThumbLevel = 6; newMediumLevel = 6; newFullLevel = 0; break; // box 1280x1280 - case 'w': newThumbLevel = 8; newMediumLevel = 8; newFullLevel = 2; break; // box 2560x2560 - case 'a': newThumbLevel = 1; newMediumLevel = 4; newFullLevel = 8; break; // crop 160x160 - case 'b': newThumbLevel = 3; newMediumLevel = 1; newFullLevel = 7; break; // crop 320x320 - case 'c': newThumbLevel = 4; newMediumLevel = 2; newFullLevel = 6; break; // crop 640x640 - case 'd': newThumbLevel = 7; newMediumLevel = 7; newFullLevel = 5; break; // crop 1280x1280 - } - if (newThumbLevel < 0 || newMediumLevel < 0 || newFullLevel < 0) { - continue; - } - if (thumbLevel < 0 || newThumbLevel < thumbLevel) { - thumbLevel = newThumbLevel; - thumb = &(*i); - } - if (mediumLevel < 0 || newMediumLevel < mediumLevel) { - mediumLevel = newMediumLevel; - medium = &(*i); - } - if (fullLevel < 0 || newFullLevel < fullLevel) { - fullLevel = newFullLevel; - full = &(*i); - } - } - if (thumb && medium && full) { - return App::photoSet(photo.vid.v, convert, photo.vaccess_hash.v, photo.vdate.v, App::image(*thumb), App::image(*medium), App::image(*full)); - } - return App::photoSet(photo.vid.v, convert, 0, 0, ImagePtr(), ImagePtr(), ImagePtr()); - } - - DocumentData *feedDocument(const MTPdocument &document, const QPixmap &thumb) { - switch (document.type()) { - case mtpc_document: { - auto &d = document.c_document(); - return App::documentSet(d.vid.v, 0, d.vaccess_hash.v, d.vversion.v, d.vdate.v, d.vattributes.v, qs(d.vmime_type), ImagePtr(thumb, "JPG"), d.vdc_id.v, d.vsize.v, StorageImageLocation()); - } break; - case mtpc_documentEmpty: return App::document(document.c_documentEmpty().vid.v); - } - return App::document(0); - } - - DocumentData *feedDocument(const MTPdocument &document, DocumentData *convert) { - switch (document.type()) { - case mtpc_document: { - return feedDocument(document.c_document(), convert); - } break; - case mtpc_documentEmpty: { - return App::documentSet(document.c_documentEmpty().vid.v, convert, 0, 0, 0, QVector(), QString(), ImagePtr(), 0, 0, StorageImageLocation()); - } break; - } - return App::document(0); - } - - DocumentData *feedDocument(const MTPDdocument &document, DocumentData *convert) { - return App::documentSet( - document.vid.v, - convert, - document.vaccess_hash.v, - document.vversion.v, - document.vdate.v, - document.vattributes.v, - qs(document.vmime_type), - App::image(document.vthumb), - document.vdc_id.v, - document.vsize.v, - StorageImageLocation::FromMTP(document.vthumb)); - } - - WebPageData *feedWebPage(const MTPDwebPage &webpage, WebPageData *convert) { - auto description = TextWithEntities { webpage.has_description() ? TextUtilities::Clean(qs(webpage.vdescription)) : QString() }; - auto siteName = webpage.has_site_name() ? qs(webpage.vsite_name) : QString(); - auto parseFlags = TextParseLinks | TextParseMultiline | TextParseRichText; - if (siteName == qstr("Twitter") || siteName == qstr("Instagram")) { - parseFlags |= TextParseHashtags | TextParseMentions; - } - TextUtilities::ParseEntities(description, parseFlags); - return App::webPageSet(webpage.vid.v, convert, webpage.has_type() ? qs(webpage.vtype) : qsl("article"), qs(webpage.vurl), qs(webpage.vdisplay_url), siteName, webpage.has_title() ? qs(webpage.vtitle) : QString(), description, webpage.has_photo() ? App::feedPhoto(webpage.vphoto) : nullptr, webpage.has_document() ? App::feedDocument(webpage.vdocument) : nullptr, webpage.has_duration() ? webpage.vduration.v : 0, webpage.has_author() ? qs(webpage.vauthor) : QString(), 0); - } - - WebPageData *feedWebPage(const MTPDwebPagePending &webpage, WebPageData *convert) { - constexpr auto kDefaultPendingTimeout = 60; - return App::webPageSet( - webpage.vid.v, - convert, - QString(), - QString(), - QString(), - QString(), - QString(), - TextWithEntities(), - nullptr, - nullptr, - 0, - QString(), - webpage.vdate.v - ? webpage.vdate.v - : (unixtime() + kDefaultPendingTimeout)); - } - - WebPageData *feedWebPage(const MTPWebPage &webpage) { - switch (webpage.type()) { - case mtpc_webPage: return App::feedWebPage(webpage.c_webPage()); - case mtpc_webPageEmpty: { - WebPageData *page = App::webPage(webpage.c_webPageEmpty().vid.v); - if (page->pendingTill > 0) page->pendingTill = -1; // failed - return page; - } break; - case mtpc_webPagePending: return App::feedWebPage(webpage.c_webPagePending()); - case mtpc_webPageNotModified: LOG(("API Error: webPageNotModified is unexpected in feedWebPage().")); break; - } - return nullptr; - } - - WebPageData *feedWebPage(WebPageId webPageId, const QString &siteName, const TextWithEntities &content) { - return App::webPageSet(webPageId, nullptr, qsl("article"), QString(), QString(), siteName, QString(), content, nullptr, nullptr, 0, QString(), 0); - } - - GameData *feedGame(const MTPDgame &game, GameData *convert) { - return App::gameSet(game.vid.v, convert, game.vaccess_hash.v, qs(game.vshort_name), qs(game.vtitle), qs(game.vdescription), App::feedPhoto(game.vphoto), game.has_document() ? App::feedDocument(game.vdocument) : nullptr); - } - PeerData *peer(const PeerId &id, PeerData::LoadedStatus restriction) { if (!id) return nullptr; @@ -1402,361 +1181,6 @@ namespace { return nullptr; } - void updateImage(ImagePtr &old, ImagePtr now) { - if (now->isNull()) return; - if (old->isNull()) { - old = now; - } else if (DelayedStorageImage *img = old->toDelayedStorageImage()) { - StorageImageLocation loc = now->location(); - if (!loc.isNull()) { - img->setStorageLocation(loc); - } - } - } - - PhotoData *photo(const PhotoId &photo) { - auto i = ::photosData.constFind(photo); - if (i == ::photosData.cend()) { - i = ::photosData.insert(photo, new PhotoData(photo)); - } - return i.value(); - } - - PhotoData *photoSet( - const PhotoId &photo, - PhotoData *convert, - const uint64 &access, - int32 date, - const ImagePtr &thumb, - const ImagePtr &medium, - const ImagePtr &full) { - if (convert) { - if (convert->id != photo) { - const auto i = ::photosData.find(convert->id); - if (i != ::photosData.cend() && i.value() == convert) { - ::photosData.erase(i); - } - convert->id = photo; - convert->uploadingData = nullptr; - } - if (date) { - convert->access = access; - convert->date = date; - updateImage(convert->thumb, thumb); - updateImage(convert->medium, medium); - updateImage(convert->full, full); - } - } - const auto i = ::photosData.constFind(photo); - PhotoData *result; - auto inLastIter = lastPhotosMap.end(); - if (i == ::photosData.cend()) { - if (convert) { - result = convert; - } else { - result = new PhotoData(photo, access, date, thumb, medium, full); - } - ::photosData.insert(photo, result); - } else { - result = i.value(); - if (result != convert && date) { - result->access = access; - result->date = date; - updateImage(result->thumb, thumb); - updateImage(result->medium, medium); - updateImage(result->full, full); - } - inLastIter = lastPhotosMap.find(result); - } - if (inLastIter == lastPhotosMap.end()) { // insert new one - if (lastPhotos.size() == MaxPhotosInMemory) { - lastPhotos.front()->forget(); - lastPhotosMap.remove(lastPhotos.front()); - lastPhotos.pop_front(); - } - lastPhotosMap.insert(result, lastPhotos.insert(lastPhotos.end(), result)); - } else { - lastPhotos.erase(inLastIter.value()); // move to back - (*inLastIter) = lastPhotos.insert(lastPhotos.end(), result); - } - return result; - } - - DocumentData *document(const DocumentId &document) { - auto i = ::documentsData.constFind(document); - if (i == ::documentsData.cend()) { - i = ::documentsData.insert(document, DocumentData::create(document)); - } - return i.value(); - } - - DocumentData *documentSet( - const DocumentId &document, - DocumentData *convert, - const uint64 &access, - int32 version, - int32 date, - const QVector &attributes, - const QString &mime, - const ImagePtr &thumb, - int32 dc, - int32 size, - const StorageImageLocation &thumbLocation) { - bool versionChanged = false; - bool sentSticker = false; - if (convert) { - const auto oldKey = convert->mediaKey(); - const auto idChanged = (convert->id != document); - if (idChanged) { - const auto i = ::documentsData.find(convert->id); - if (i != ::documentsData.cend() && i.value() == convert) { - ::documentsData.erase(i); - } - - convert->id = document; - convert->status = FileReady; - convert->uploadingData = nullptr; - sentSticker = (convert->sticker() != 0); - } - if (date) { - convert->setattributes(attributes); - versionChanged = convert->setRemoteVersion(version); - convert->setRemoteLocation(dc, access); - convert->date = date; - convert->setMimeString(mime); - if (!thumb->isNull() && (convert->thumb->isNull() || convert->thumb->width() < thumb->width() || convert->thumb->height() < thumb->height() || versionChanged)) { - updateImage(convert->thumb, thumb); - } - convert->size = size; - convert->recountIsImage(); - if (convert->sticker() && convert->sticker()->loc.isNull() && !thumbLocation.isNull()) { - convert->sticker()->loc = thumbLocation; - } - - const auto newKey = convert->mediaKey(); - if (idChanged) { - if (convert->isVoiceMessage()) { - Local::copyAudio(oldKey, newKey); - } else if (convert->sticker() || convert->isAnimation()) { - Local::copyStickerImage(oldKey, newKey); - } - } - } - - if (Auth().data().savedGifs().indexOf(convert) >= 0) { // id changed - Local::writeSavedGifs(); - } - } - const auto i = ::documentsData.constFind(document); - DocumentData *result; - if (i == ::documentsData.cend()) { - if (convert) { - result = convert; - } else { - result = DocumentData::create(document, dc, access, version, attributes); - result->date = date; - result->setMimeString(mime); - result->thumb = thumb; - result->size = size; - result->recountIsImage(); - if (result->sticker()) { - result->sticker()->loc = thumbLocation; - } - } - ::documentsData.insert(document, result); - } else { - result = i.value(); - if (result != convert && date) { - result->setattributes(attributes); - versionChanged = result->setRemoteVersion(version); - if (!result->isValid()) { - result->setRemoteLocation(dc, access); - } - result->date = date; - result->setMimeString(mime); - if (!thumb->isNull() && (result->thumb->isNull() || result->thumb->width() < thumb->width() || result->thumb->height() < thumb->height() || versionChanged)) { - result->thumb = thumb; - } - result->size = size; - result->recountIsImage(); - if (result->sticker() && result->sticker()->loc.isNull() && !thumbLocation.isNull()) { - result->sticker()->loc = thumbLocation; - } - } - } - if (sentSticker && App::main()) { - App::main()->incrementSticker(result); - } - if (versionChanged) { - if (result->sticker() && result->sticker()->set.type() == mtpc_inputStickerSetID) { - auto it = Auth().data().stickerSets().constFind(result->sticker()->set.c_inputStickerSetID().vid.v); - if (it != Auth().data().stickerSets().cend()) { - if (it->id == Stickers::CloudRecentSetId) { - Local::writeRecentStickers(); - } else if (it->id == Stickers::FavedSetId) { - Local::writeFavedStickers(); - } else if (it->flags & MTPDstickerSet::Flag::f_archived) { - Local::writeArchivedStickers(); - } else if (it->flags & MTPDstickerSet::Flag::f_installed) { - Local::writeInstalledStickers(); - } - if (it->flags & MTPDstickerSet_ClientFlag::f_featured) { - Local::writeFeaturedStickers(); - } - } - } - auto &items = App::documentItems(); - auto i = items.constFind(result); - if (i != items.cend()) { - for_const (auto item, i.value()) { - Auth().data().requestItemViewResize(item); - } - } - } - return result; - } - - WebPageData *webPage(const WebPageId &webPage) { - auto i = webPagesData.constFind(webPage); - if (i == webPagesData.cend()) { - i = webPagesData.insert(webPage, new WebPageData(webPage)); - } - return i.value(); - } - - WebPageData *webPageSet( - const WebPageId &webPage, - WebPageData *convert, - const QString &type, - const QString &url, - const QString &displayUrl, - const QString &siteName, - const QString &title, - const TextWithEntities &description, - PhotoData *photo, - DocumentData *document, - int duration, - const QString &author, - int pendingTill) { - if (convert) { - if (convert->id != webPage) { - const auto i = webPagesData.find(convert->id); - if (i != webPagesData.cend() && i.value() == convert) { - webPagesData.erase(i); - } - convert->id = webPage; - } - convert->applyChanges( - type, - url, - displayUrl, - siteName, - title, - description, - photo, - document, - duration, - author, - pendingTill); - } - const auto i = webPagesData.constFind(webPage); - WebPageData *result; - if (i == webPagesData.cend()) { - if (convert) { - result = convert; - } else { - result = new WebPageData( - webPage, - toWebPageType(type), - url, - displayUrl, - siteName, - title, - description, - document, - photo, - duration, - author, - (pendingTill >= -1) ? pendingTill : -1); - if (pendingTill > 0) { - Auth().api().requestWebPageDelayed(result); - } - } - webPagesData.insert(webPage, result); - } else { - result = i.value(); - if (result != convert) { - result->applyChanges( - type, - url, - displayUrl, - siteName, - title, - description, - photo, - document, - duration, - author, - pendingTill); - } - } - return result; - } - - GameData *game(const GameId &game) { - auto i = gamesData.constFind(game); - if (i == gamesData.cend()) { - i = gamesData.insert(game, new GameData(game)); - } - return i.value(); - } - - GameData *gameSet(const GameId &game, GameData *convert, const uint64 &accessHash, const QString &shortName, const QString &title, const QString &description, PhotoData *photo, DocumentData *document) { - if (convert) { - if (convert->id != game) { - auto i = gamesData.find(convert->id); - if (i != gamesData.cend() && i.value() == convert) { - gamesData.erase(i); - } - convert->id = game; - convert->accessHash = 0; - } - if (!convert->accessHash && accessHash) { - convert->accessHash = accessHash; - convert->shortName = TextUtilities::Clean(shortName); - convert->title = TextUtilities::SingleLine(title); - convert->description = TextUtilities::Clean(description); - convert->photo = photo; - convert->document = document; - if (App::main()) App::main()->gameUpdated(convert); - } - } - auto i = gamesData.constFind(game); - GameData *result; - if (i == gamesData.cend()) { - if (convert) { - result = convert; - } else { - result = new GameData(game, accessHash, shortName, title, description, photo, document); - } - gamesData.insert(game, result); - } else { - result = i.value(); - if (result != convert) { - if (!result->accessHash && accessHash) { - result->accessHash = accessHash; - result->shortName = TextUtilities::Clean(shortName); - result->title = TextUtilities::SingleLine(title); - result->description = TextUtilities::Clean(description); - result->photo = photo; - result->document = document; - if (App::main()) App::main()->gameUpdated(result); - } - } - } - return result; - } - LocationData *location(const LocationCoords &coords) { auto i = locationsData.constFind(coords); if (i == locationsData.cend()) { @@ -1766,14 +1190,6 @@ namespace { } void forgetMedia() { - lastPhotos.clear(); - lastPhotosMap.clear(); - for_const (auto photo, ::photosData) { - photo->forget(); - } - for_const (auto document, ::documentsData) { - document->forget(); - } for_const (auto location, ::locationsData) { location->thumb->forget(); } @@ -1914,22 +1330,6 @@ namespace { delete peer; } ::peersData.clear(); - for_const (auto game, ::gamesData) { - delete game; - } - ::gamesData.clear(); - for_const (auto webpage, ::webPagesData) { - delete webpage; - } - ::webPagesData.clear(); - for_const (auto photo, ::photosData) { - delete photo; - } - ::photosData.clear(); - for_const (auto document, ::documentsData) { - delete document; - } - ::documentsData.clear(); if (AuthSession::Exists()) { Auth().api().clearWebPageRequests(); @@ -1939,14 +1339,6 @@ namespace { cSetAutoDownloadPhoto(0); cSetAutoDownloadAudio(0); cSetAutoDownloadGif(0); - ::photoItems.clear(); - ::documentItems.clear(); - ::webPageItems.clear(); - ::gameItems.clear(); - ::sharedContactItems.clear(); - ::gifItems.clear(); - lastPhotos.clear(); - lastPhotosMap.clear(); ::self = nullptr; Global::RefSelfChanged().notify(true); } @@ -2367,118 +1759,6 @@ namespace { return QPixmap::fromImage(std::move(image), Qt::ColorOnly); } - void regPhotoItem(PhotoData *data, HistoryItem *item) { - ::photoItems[data].insert(item); - } - - void unregPhotoItem(PhotoData *data, HistoryItem *item) { - ::photoItems[data].remove(item); - } - - const PhotoItems &photoItems() { - return ::photoItems; - } - - const PhotosData &photosData() { - return ::photosData; - } - - void regDocumentItem(DocumentData *data, HistoryItem *item) { - ::documentItems[data].insert(item); - } - - void unregDocumentItem(DocumentData *data, HistoryItem *item) { - ::documentItems[data].remove(item); - } - - const DocumentItems &documentItems() { - return ::documentItems; - } - - const DocumentsData &documentsData() { - return ::documentsData; - } - - void regWebPageItem(WebPageData *data, HistoryItem *item) { - ::webPageItems[data].insert(item); - } - - void unregWebPageItem(WebPageData *data, HistoryItem *item) { - ::webPageItems[data].remove(item); - } - - const WebPageItems &webPageItems() { - return ::webPageItems; - } - - void regGameItem(GameData *data, HistoryItem *item) { - ::gameItems[data].insert(item); - } - - void unregGameItem(GameData *data, HistoryItem *item) { - ::gameItems[data].remove(item); - } - - const GameItems &gameItems() { - return ::gameItems; - } - - void regSharedContactItem(int32 userId, HistoryItem *item) { - auto user = App::userLoaded(userId); - auto canShareThisContact = user ? user->canShareThisContact() : false; - ::sharedContactItems[userId].insert(item); - if (canShareThisContact != (user ? user->canShareThisContact() : false)) { - Notify::peerUpdatedDelayed(user, Notify::PeerUpdate::Flag::UserCanShareContact); - } - } - - void unregSharedContactItem(int32 userId, HistoryItem *item) { - auto user = App::userLoaded(userId); - auto canShareThisContact = user ? user->canShareThisContact() : false; - ::sharedContactItems[userId].remove(item); - if (canShareThisContact != (user ? user->canShareThisContact() : false)) { - Notify::peerUpdatedDelayed(user, Notify::PeerUpdate::Flag::UserCanShareContact); - } - } - - const SharedContactItems &sharedContactItems() { - return ::sharedContactItems; - } - - void regGifItem(Media::Clip::Reader *reader, HistoryItem *item) { - ::gifItems.insert(reader, item); - } - - void unregGifItem(Media::Clip::Reader *reader) { - ::gifItems.remove(reader); - } - - void stopGifItems() { - if (!::gifItems.isEmpty()) { - auto gifs = ::gifItems; - for_const (auto item, gifs) { - // #TODO GIFs - //if (auto media = item->getMedia()) { - // if (!media->isRoundVideoPlaying()) { - // media->stopInline(); - // } - //} - } - } - } - - QString phoneFromSharedContact(int32 userId) { - auto i = ::sharedContactItems.constFind(userId); - if (i != ::sharedContactItems.cend() && !i->empty()) { - if (const auto media = (*i->cbegin())->media()) { - if (const auto contact = media->sharedContact()) { - return contact->phoneNumber; - } - } - } - return QString(); - } - void regMuted(not_null peer, TimeMs changeIn) { ::mutedPeers.insert(peer, true); App::main()->updateMutedIn(changeIn); diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h index 79069beeb..4912bc1ca 100644 --- a/Telegram/SourceFiles/app.h +++ b/Telegram/SourceFiles/app.h @@ -25,16 +25,8 @@ class Element; } // namespace HistoryView using HistoryItemsMap = base::flat_set>; -using PhotoItems = QHash; -using DocumentItems = QHash; -using WebPageItems = QHash; -using GameItems = QHash; -using SharedContactItems = QHash; using GifItems = QHash; -using PhotosData = QHash; -using DocumentsData = QHash; - enum RoundCorners { SmallMaskCorners = 0x00, // for images LargeMaskCorners, @@ -103,18 +95,6 @@ namespace App { ImagePtr image(const MTPPhotoSize &size); - PhotoData *feedPhoto(const MTPPhoto &photo, const PreparedPhotoThumbs &thumbs); - PhotoData *feedPhoto(const MTPPhoto &photo, PhotoData *convert = nullptr); - PhotoData *feedPhoto(const MTPDphoto &photo, PhotoData *convert = nullptr); - DocumentData *feedDocument(const MTPdocument &document, const QPixmap &thumb); - DocumentData *feedDocument(const MTPdocument &document, DocumentData *convert = nullptr); - DocumentData *feedDocument(const MTPDdocument &document, DocumentData *convert = nullptr); - WebPageData *feedWebPage(const MTPDwebPage &webpage, WebPageData *convert = nullptr); - WebPageData *feedWebPage(const MTPDwebPagePending &webpage, WebPageData *convert = nullptr); - WebPageData *feedWebPage(const MTPWebPage &webpage); - WebPageData *feedWebPage(WebPageId webPageId, const QString &siteName, const TextWithEntities &content); - GameData *feedGame(const MTPDgame &game, GameData *convert = nullptr); - PeerData *peer(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded); inline UserData *user(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded) { return asUser(peer(id, restriction)); @@ -160,53 +140,7 @@ namespace App { UserData *self(); PeerData *peerByName(const QString &username); QString peerName(const PeerData *peer, bool forDialogs = false); - PhotoData *photo(const PhotoId &photo); - PhotoData *photoSet( - const PhotoId &photo, - PhotoData *convert, - const uint64 &access, - int32 date, - const ImagePtr &thumb, - const ImagePtr &medium, - const ImagePtr &full); - DocumentData *document(const DocumentId &document); - DocumentData *documentSet( - const DocumentId &document, - DocumentData *convert, - const uint64 &access, - int32 version, - int32 date, - const QVector &attributes, - const QString &mime, - const ImagePtr &thumb, - int32 dc, - int32 size, - const StorageImageLocation &thumbLocation); - WebPageData *webPage(const WebPageId &webPage); - WebPageData *webPageSet( - const WebPageId &webPage, - WebPageData *convert, - const QString &type, - const QString &url, - const QString &displayUrl, - const QString &siteName, - const QString &title, - const TextWithEntities &description, - PhotoData *photo, - DocumentData *document, - int duration, - const QString &author, - int pendingTill); - GameData *game(const GameId &game); - GameData *gameSet( - const GameId &game, - GameData *convert, - const uint64 &accessHash, - const QString &shortName, - const QString &title, - const QString &description, - PhotoData *photo, - DocumentData *document); + LocationData *location(const LocationCoords &coords); void forgetMedia(); @@ -288,34 +222,6 @@ namespace App { QImage readImage(const QString &file, QByteArray *format = nullptr, bool opaque = true, bool *animated = nullptr, QByteArray *content = 0); QPixmap pixmapFromImageInPlace(QImage &&image); - void regPhotoItem(PhotoData *data, HistoryItem *item); - void unregPhotoItem(PhotoData *data, HistoryItem *item); - const PhotoItems &photoItems(); - const PhotosData &photosData(); - - void regDocumentItem(DocumentData *data, HistoryItem *item); - void unregDocumentItem(DocumentData *data, HistoryItem *item); - const DocumentItems &documentItems(); - const DocumentsData &documentsData(); - - void regWebPageItem(WebPageData *data, HistoryItem *item); - void unregWebPageItem(WebPageData *data, HistoryItem *item); - const WebPageItems &webPageItems(); - - void regGameItem(GameData *data, HistoryItem *item); - void unregGameItem(GameData *data, HistoryItem *item); - const GameItems &gameItems(); - - void regSharedContactItem(int32 userId, HistoryItem *item); - void unregSharedContactItem(int32 userId, HistoryItem *item); - const SharedContactItems &sharedContactItems(); - QString phoneFromSharedContact(int32 userId); - - void regGifItem(Media::Clip::Reader *reader, HistoryItem *item); - void unregGifItem(Media::Clip::Reader *reader); - void stopRoundVideoPlayback(); - void stopGifItems(); - void regMuted(not_null peer, TimeMs changeIn); void unregMuted(not_null peer); void updateMuted(); diff --git a/Telegram/SourceFiles/auth_session.cpp b/Telegram/SourceFiles/auth_session.cpp index 4edca028a..450aed20a 100644 --- a/Telegram/SourceFiles/auth_session.cpp +++ b/Telegram/SourceFiles/auth_session.cpp @@ -268,7 +268,7 @@ AuthSession &Auth() { AuthSession::AuthSession(UserId userId) : _userId(userId) , _autoLockTimer([this] { checkAutoLock(); }) -, _data(std::make_unique()) +, _data(std::make_unique(this)) , _api(std::make_unique(this)) , _calls(std::make_unique()) , _downloader(std::make_unique()) diff --git a/Telegram/SourceFiles/auth_session.h b/Telegram/SourceFiles/auth_session.h index fd9b87175..ea67eb585 100644 --- a/Telegram/SourceFiles/auth_session.h +++ b/Telegram/SourceFiles/auth_session.h @@ -182,7 +182,9 @@ private: class AuthSession; AuthSession &Auth(); -class AuthSession final : private base::Subscriber { +class AuthSession final + : public base::has_weak_ptr + , private base::Subscriber { public: AuthSession(UserId userId); diff --git a/Telegram/SourceFiles/boxes/connection_box.cpp b/Telegram/SourceFiles/boxes/connection_box.cpp index 49cfcffce..e2ce01b63 100644 --- a/Telegram/SourceFiles/boxes/connection_box.cpp +++ b/Telegram/SourceFiles/boxes/connection_box.cpp @@ -14,6 +14,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "storage/localstorage.h" #include "mainwidget.h" #include "mainwindow.h" +#include "auth_session.h" +#include "data/data_session.h" #include "ui/widgets/checkbox.h" #include "ui/widgets/buttons.h" #include "ui/widgets/input_fields.h" @@ -291,55 +293,63 @@ void AutoDownloadBox::resizeEvent(QResizeEvent *e) { } void AutoDownloadBox::onSave() { - bool changed = false; - int32 autoDownloadPhoto = (_photoPrivate->checked() ? 0 : dbiadNoPrivate) | (_photoGroups->checked() ? 0 : dbiadNoGroups); + auto photosChanged = false; + auto documentsChanged = false; + auto autoplayChanged = false; + auto photosEnabled = false; + auto voiceEnabled = false; + auto animationsEnabled = false; + auto autoDownloadPhoto = (_photoPrivate->checked() ? 0 : dbiadNoPrivate) + | (_photoGroups->checked() ? 0 : dbiadNoGroups); if (cAutoDownloadPhoto() != autoDownloadPhoto) { - bool enabledPrivate = ((cAutoDownloadPhoto() & dbiadNoPrivate) && !(autoDownloadPhoto & dbiadNoPrivate)); - bool enabledGroups = ((cAutoDownloadPhoto() & dbiadNoGroups) && !(autoDownloadPhoto & dbiadNoGroups)); + const auto enabledPrivate = (cAutoDownloadPhoto() & dbiadNoPrivate) + && !(autoDownloadPhoto & dbiadNoPrivate); + const auto enabledGroups = (cAutoDownloadPhoto() & dbiadNoGroups) + && !(autoDownloadPhoto & dbiadNoGroups); + photosEnabled = enabledPrivate || enabledGroups; + photosChanged = true; cSetAutoDownloadPhoto(autoDownloadPhoto); - if (enabledPrivate || enabledGroups) { - const PhotosData &data(App::photosData()); - for (PhotosData::const_iterator i = data.cbegin(), e = data.cend(); i != e; ++i) { - i.value()->automaticLoadSettingsChanged(); - } - } - changed = true; } - int32 autoDownloadAudio = (_audioPrivate->checked() ? 0 : dbiadNoPrivate) | (_audioGroups->checked() ? 0 : dbiadNoGroups); + auto autoDownloadAudio = (_audioPrivate->checked() ? 0 : dbiadNoPrivate) + | (_audioGroups->checked() ? 0 : dbiadNoGroups); if (cAutoDownloadAudio() != autoDownloadAudio) { - bool enabledPrivate = ((cAutoDownloadAudio() & dbiadNoPrivate) && !(autoDownloadAudio & dbiadNoPrivate)); - bool enabledGroups = ((cAutoDownloadAudio() & dbiadNoGroups) && !(autoDownloadAudio & dbiadNoGroups)); + const auto enabledPrivate = (cAutoDownloadAudio() & dbiadNoPrivate) + && !(autoDownloadAudio & dbiadNoPrivate); + const auto enabledGroups = (cAutoDownloadAudio() & dbiadNoGroups) + && !(autoDownloadAudio & dbiadNoGroups); + voiceEnabled = enabledPrivate || enabledGroups; + documentsChanged = true; cSetAutoDownloadAudio(autoDownloadAudio); - if (enabledPrivate || enabledGroups) { - for (auto document : App::documentsData()) { - if (document->isVoiceMessage()) { - document->automaticLoadSettingsChanged(); - } - } - } - changed = true; } - int32 autoDownloadGif = (_gifPrivate->checked() ? 0 : dbiadNoPrivate) | (_gifGroups->checked() ? 0 : dbiadNoGroups); + auto autoDownloadGif = (_gifPrivate->checked() ? 0 : dbiadNoPrivate) + | (_gifGroups->checked() ? 0 : dbiadNoGroups); if (cAutoDownloadGif() != autoDownloadGif) { - bool enabledPrivate = ((cAutoDownloadGif() & dbiadNoPrivate) && !(autoDownloadGif & dbiadNoPrivate)); - bool enabledGroups = ((cAutoDownloadGif() & dbiadNoGroups) && !(autoDownloadGif & dbiadNoGroups)); + const auto enabledPrivate = (cAutoDownloadGif() & dbiadNoPrivate) + && !(autoDownloadGif & dbiadNoPrivate); + const auto enabledGroups = (cAutoDownloadGif() & dbiadNoGroups) + && !(autoDownloadGif & dbiadNoGroups); + animationsEnabled = enabledPrivate || enabledGroups; + documentsChanged = true; cSetAutoDownloadGif(autoDownloadGif); - if (enabledPrivate || enabledGroups) { - for (auto document : App::documentsData()) { - if (document->isAnimation()) { - document->automaticLoadSettingsChanged(); - } - } - } - changed = true; } if (cAutoPlayGif() != _gifPlay->checked()) { cSetAutoPlayGif(_gifPlay->checked()); if (!cAutoPlayGif()) { - App::stopGifItems(); + Auth().data().stopAutoplayAnimations(); } - changed = true; + autoplayChanged = true; + } + if (photosChanged || documentsChanged || autoplayChanged) { + Local::writeUserSettings(); + } + if (photosEnabled) { + Auth().data().photoLoadSettingsChanged(); + } + if (voiceEnabled) { + Auth().data().voiceLoadSettingsChanged(); + } + if (animationsEnabled) { + Auth().data().animationLoadSettingsChanged(); } - if (changed) Local::writeUserSettings(); closeBox(); } diff --git a/Telegram/SourceFiles/boxes/sticker_set_box.cpp b/Telegram/SourceFiles/boxes/sticker_set_box.cpp index bad87847f..10dd3696d 100644 --- a/Telegram/SourceFiles/boxes/sticker_set_box.cpp +++ b/Telegram/SourceFiles/boxes/sticker_set_box.cpp @@ -122,8 +122,8 @@ void StickerSetBox::Inner::gotSet(const MTPmessages_StickerSet &set) { _pack.reserve(v.size()); _packOvers.reserve(v.size()); for (int i = 0, l = v.size(); i < l; ++i) { - auto doc = App::feedDocument(v.at(i)); - if (!doc || !doc->sticker()) continue; + auto doc = Auth().data().document(v.at(i)); + if (!doc->sticker()) continue; _pack.push_back(doc); _packOvers.push_back(Animation()); @@ -139,7 +139,7 @@ void StickerSetBox::Inner::gotSet(const MTPmessages_StickerSet &set) { Stickers::Pack p; p.reserve(stickers.size()); for (auto j = 0, c = stickers.size(); j != c; ++j) { - auto doc = App::document(stickers[j].v); + auto doc = Auth().data().document(stickers[j].v); if (!doc || !doc->sticker()) continue; p.push_back(doc); diff --git a/Telegram/SourceFiles/calls/calls_panel.cpp b/Telegram/SourceFiles/calls/calls_panel.cpp index c0667c2aa..93eaf8374 100644 --- a/Telegram/SourceFiles/calls/calls_panel.cpp +++ b/Telegram/SourceFiles/calls/calls_panel.cpp @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "calls/calls_panel.h" #include "data/data_photo.h" +#include "data/data_session.h" #include "calls/calls_emoji_fingerprint.h" #include "styles/style_calls.h" #include "styles/style_history.h" @@ -430,7 +431,7 @@ void Panel::processUserPhoto() { _user->loadUserpic(true); } const auto photo = _user->userpicPhotoId() - ? App::photo(_user->userpicPhotoId()) + ? Auth().data().photo(_user->userpicPhotoId()).get() : nullptr; if (isGoodUserPhoto(photo)) { photo->full->load(true); @@ -442,7 +443,7 @@ void Panel::processUserPhoto() { void Panel::refreshUserPhoto() { const auto photo = _user->userpicPhotoId() - ? App::photo(_user->userpicPhotoId()) + ? Auth().data().photo(_user->userpicPhotoId()).get() : nullptr; const auto isNewPhoto = [&](not_null photo) { return photo->full->loaded() diff --git a/Telegram/SourceFiles/chat_helpers/stickers.cpp b/Telegram/SourceFiles/chat_helpers/stickers.cpp index ae083da79..ca521ca90 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers.cpp @@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "apiwrap.h" #include "storage/localstorage.h" #include "mainwidget.h" +#include "auth_session.h" #include "mainwindow.h" #include "ui/toast/toast.h" #include "styles/style_chat_helpers.h" @@ -389,7 +390,7 @@ void SetPackAndEmoji(Set &set, Pack &&pack, const QVector &packs auto p = Pack(); p.reserve(stickers.size()); for (auto j = 0, c = stickers.size(); j != c; ++j) { - auto document = App::document(stickers[j].v); + auto document = Auth().data().document(stickers[j].v); if (!document || !document->sticker()) continue; p.push_back(document); @@ -420,8 +421,8 @@ void SpecialSetReceived(uint64 setId, const QString &setTitle, const QVectorsticker()) continue; + auto document = Auth().data().document(mtpDocument); + if (!document->sticker()) continue; pack.push_back(document); if (custom != sets.cend()) { @@ -583,8 +584,8 @@ void GifsReceived(const QVector &items, int32 hash) { saved.reserve(items.size()); for_const (auto &gif, items) { - auto document = App::feedDocument(gif); - if (!document || !document->isGifv()) { + auto document = Auth().data().document(gif); + if (!document->isGifv()) { LOG(("API Error: bad document returned in HistoryWidget::savedGifsGot!")); continue; } @@ -719,8 +720,8 @@ Set *FeedSetFull(const MTPmessages_StickerSet &data) { auto pack = Pack(); pack.reserve(d_docs.size()); for (auto i = 0, l = d_docs.size(); i != l; ++i) { - auto doc = App::feedDocument(d_docs.at(i)); - if (!doc || !doc->sticker()) continue; + auto doc = Auth().data().document(d_docs.at(i)); + if (!doc->sticker()) continue; pack.push_back(doc); if (custom != sets.cend()) { @@ -766,7 +767,7 @@ Set *FeedSetFull(const MTPmessages_StickerSet &data) { Pack p; p.reserve(stickers.size()); for (auto j = 0, c = stickers.size(); j != c; ++j) { - auto doc = App::document(stickers[j].v); + auto doc = Auth().data().document(stickers[j].v); if (!doc || !doc->sticker()) continue; p.push_back(doc); @@ -812,7 +813,7 @@ RecentStickerPack &GetRecentPack() { auto &recent = cRefRecentStickers(); recent.reserve(p.size()); for (const auto &preloaded : p) { - const auto document = App::document(preloaded.first); + const auto document = Auth().data().document(preloaded.first); if (!document || !document->sticker()) continue; recent.push_back(qMakePair(document, preloaded.second)); diff --git a/Telegram/SourceFiles/data/data_document.cpp b/Telegram/SourceFiles/data/data_document.cpp index 037c0c4d3..d23f30129 100644 --- a/Telegram/SourceFiles/data/data_document.cpp +++ b/Telegram/SourceFiles/data/data_document.cpp @@ -248,7 +248,7 @@ void DocumentOpenClickHandler::doOpen( Media::Player::mixer()->play(audio); Media::Player::Updated().notify(audio); if (App::main()) { - App::main()->mediaMarkRead(data); + Auth().data().markMediaRead(data); } } } else if (playMusic) { @@ -276,13 +276,13 @@ void DocumentOpenClickHandler::doOpen( File::Launch(filepath); } } - if (App::main()) App::main()->mediaMarkRead(data); + Auth().data().markMediaRead(data); } else if (data->isVoiceMessage() || data->isAudioFile() || data->isVideoFile()) { auto filepath = location.name(); if (documentIsValidMediaFile(filepath)) { File::Launch(filepath); } - if (App::main()) App::main()->mediaMarkRead(data); + Auth().data().markMediaRead(data); } else if (data->size < App::kImageSizeLimit) { if (!data->data().isEmpty() && playAnimation) { if (action == ActionOnLoadPlayInline && context) { @@ -571,7 +571,7 @@ void DocumentData::performActionOnLoad() { } } else if (Media::Player::IsStopped(state.state)) { Media::Player::mixer()->play(AudioMsgId(this, _actionOnLoadMsgId)); - if (App::main()) App::main()->mediaMarkRead(this); + Auth().data().markMediaRead(this); } } } else if (playMusic) { @@ -607,7 +607,7 @@ void DocumentData::performActionOnLoad() { if (documentIsValidMediaFile(already)) { File::Launch(already); } - if (App::main()) App::main()->mediaMarkRead(this); + Auth().data().markMediaRead(this); } else if (loc.accessEnable()) { if (showImage && QImageReader(loc.name()).canRead()) { if (_actionOnLoad == ActionOnLoadPlayInline && item) { @@ -640,7 +640,7 @@ bool DocumentData::loaded(FilePathResolveType type) const { } destroyLoaderDelayed(); } - notifyLayoutChanged(); + Auth().data().notifyDocumentLayoutChanged(this); } return !data().isEmpty() || !filepath(type).isEmpty(); } @@ -695,7 +695,12 @@ bool DocumentData::waitingForAlbum() const { return uploading() && uploadingData->waitingForAlbum; } -void DocumentData::save(const QString &toFile, ActionOnLoad action, const FullMsgId &actionMsgId, LoadFromCloudSetting fromCloud, bool autoLoading) { +void DocumentData::save( + const QString &toFile, + ActionOnLoad action, + const FullMsgId &actionMsgId, + LoadFromCloudSetting fromCloud, + bool autoLoading) { if (loaded(FilePathResolveChecked)) { auto &l = location(true); if (!toFile.isEmpty()) { @@ -745,18 +750,20 @@ void DocumentData::save(const QString &toFile, ActionOnLoad action, const FullMs _loader->connect(_loader, SIGNAL(failed(FileLoader*,bool)), App::main(), SLOT(documentLoadFailed(FileLoader*,bool))); _loader->start(); } - notifyLayoutChanged(); + Auth().data().notifyDocumentLayoutChanged(this); } void DocumentData::cancel() { - if (!loading()) return; + if (!loading()) { + return; + } auto loader = std::unique_ptr(std::exchange(_loader, CancelledMtpFileLoader)); loader->cancel(); loader->stop(); Auth().downloader().delayedDestroyLoader(std::move(loader)); - notifyLayoutChanged(); + Auth().data().notifyDocumentLayoutChanged(this); if (auto main = App::main()) { main->documentLoadProgress(this); } @@ -764,19 +771,6 @@ void DocumentData::cancel() { _actionOnLoad = ActionOnLoadNone; } -void DocumentData::notifyLayoutChanged() const { - auto &items = App::documentItems(); - for (auto item : items.value(const_cast(this))) { - Auth().data().markItemLayoutChange(item); - } - - if (auto items = InlineBots::Layout::documentItems()) { - for (auto item : items->value(const_cast(this))) { - item->layoutChanged(); - } - } -} - VoiceWaveform documentWaveformDecode(const QByteArray &encoded5bit) { auto bitsCount = static_cast(encoded5bit.size() * 8); auto valuesCount = bitsCount / 5; diff --git a/Telegram/SourceFiles/data/data_document.h b/Telegram/SourceFiles/data/data_document.h index 9be8a9d08..982ff627e 100644 --- a/Telegram/SourceFiles/data/data_document.h +++ b/Telegram/SourceFiles/data/data_document.h @@ -290,8 +290,6 @@ private: FullMsgId _actionOnLoadMsgId; mutable FileLoader *_loader = nullptr; - void notifyLayoutChanged() const; - void destroyLoaderDelayed( mtpFileLoader *newValue = nullptr) const; diff --git a/Telegram/SourceFiles/data/data_groups.cpp b/Telegram/SourceFiles/data/data_groups.cpp index bb1d883da..bfdfd8695 100644 --- a/Telegram/SourceFiles/data/data_groups.cpp +++ b/Telegram/SourceFiles/data/data_groups.cpp @@ -8,16 +8,32 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_groups.h" #include "history/history_item.h" +#include "data/data_media_types.h" +#include "data/data_session.h" namespace Data { +Groups::Groups(not_null data) : _data(data) { +} + +bool Groups::isGrouped(not_null item) const { + if (!item->groupId()) { + return false; + } + const auto media = item->media(); + return media && media->canBeGrouped(); +} + void Groups::registerMessage(not_null item) { - const auto groupId = item->groupId(); - if (!groupId) { + if (!isGrouped(item)) { return; } - const auto i = _data.emplace(groupId, Group()).first; - i->second.items.push_back(item); + const auto i = _groups.emplace(item->groupId(), Group()).first; + auto &items = i->second.items; + items.insert(findPositionForItem(items, item), item); + if (items.size() > 1) { + refreshViews(items); + } } void Groups::unregisterMessage(not_null item) { @@ -25,25 +41,88 @@ void Groups::unregisterMessage(not_null item) { if (!groupId) { return; } - const auto i = _data.find(groupId); - if (i != _data.end()) { - auto &group = i->second; - group.items.erase( - ranges::remove(group.items, item), - group.items.end()); - if (group.items.empty()) { - _data.erase(i); + const auto i = _groups.find(groupId); + if (i != end(_groups)) { + auto &items = i->second.items; + const auto removed = ranges::remove(items, item); + const auto last = end(items); + if (removed != last) { + items.erase(removed, last); + if (!items.empty()) { + refreshViews(items); + } else { + _groups.erase(i); + } } } } +void Groups::refreshMessage(not_null item) { + if (!isGrouped(item)) { + unregisterMessage(item); + return; + } + if (!IsServerMsgId(item->id)) { + return; + } + const auto groupId = item->groupId(); + const auto i = _groups.find(groupId); + if (i == end(_groups)) { + registerMessage(item); + return; + } + auto &items = i->second.items; + const auto position = findPositionForItem(items, item); + auto current = ranges::find(items, item); + if (current == end(items)) { + items.insert(position, item); + } else if (position == current + 1) { + return; + } else if (position > current + 1) { + for (++current; current != position; ++current) { + std::swap(*(current - 1), *current); + } + } else if (position < current) { + for (; current != position; --current) { + std::swap(*(current - 1), *current); + } + } else { + Unexpected("Position of item in Groups::refreshMessage()."); + } + refreshViews(items); +} + +HistoryItemsList::const_iterator Groups::findPositionForItem( + const HistoryItemsList &group, + not_null item) { + const auto itemId = item->id; + const auto last = end(group); + if (!IsServerMsgId(itemId)) { + return last; + } + auto result = begin(group); + while (result != last) { + const auto alreadyId = (*result)->id; + if (IsServerMsgId(alreadyId) && alreadyId > itemId) { + return result; + } + } + return last; +} + const Group *Groups::find(not_null item) const { const auto groupId = item->groupId(); if (!groupId) { return nullptr; } - const auto i = _data.find(groupId); - return (i != _data.end()) ? &i->second : nullptr; + const auto i = _groups.find(groupId); + return (i != _groups.end()) ? &i->second : nullptr; +} + +void Groups::refreshViews(const HistoryItemsList &items) { + for (const auto item : items) { + _data->requestItemViewRefresh(item); + } } } // namespace Data diff --git a/Telegram/SourceFiles/data/data_groups.h b/Telegram/SourceFiles/data/data_groups.h index fc4a232e8..6686f3059 100644 --- a/Telegram/SourceFiles/data/data_groups.h +++ b/Telegram/SourceFiles/data/data_groups.h @@ -11,6 +11,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Data { +class Session; + struct Group { HistoryItemsList items; @@ -18,13 +20,23 @@ struct Group { class Groups { public: + Groups(not_null data); + + bool isGrouped(not_null item) const; void registerMessage(not_null item); void unregisterMessage(not_null item); + void refreshMessage(not_null item); const Group *find(not_null item) const; private: - std::map _data; + HistoryItemsList::const_iterator findPositionForItem( + const HistoryItemsList &group, + not_null item); + void refreshViews(const HistoryItemsList &items); + + not_null _data; + std::map _groups; std::map _alias; }; diff --git a/Telegram/SourceFiles/data/data_media_types.cpp b/Telegram/SourceFiles/data/data_media_types.cpp index ee4f11788..200ff73b2 100644 --- a/Telegram/SourceFiles/data/data_media_types.cpp +++ b/Telegram/SourceFiles/data/data_media_types.cpp @@ -10,9 +10,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_media_types.h" #include "history/history_item.h" #include "history/history_location_manager.h" +#include "history/view/history_view_element.h" #include "storage/storage_shared_media.h" #include "storage/localstorage.h" +#include "data/data_session.h" #include "lang/lang_keys.h" +#include "auth_session.h" #include "layout.h" namespace Data { @@ -70,9 +73,22 @@ Invoice ComputeInvoiceData(const MTPDmessageMediaInvoice &data) { // We don't use size from WebDocument, because it is not reliable. // It can be > 0 and different from the real size that we get in upload.WebFile result. auto filesize = 0; // doc.vsize.v; - auto full = ImagePtr(WebFileImageLocation(imageSize.width(), imageSize.height(), doc.vdc_id.v, doc.vurl.v, doc.vaccess_hash.v), filesize); + auto full = ImagePtr( + WebFileImageLocation( + imageSize.width(), + imageSize.height(), + doc.vdc_id.v, + doc.vurl.v, + doc.vaccess_hash.v), + filesize); auto photoId = rand_value(); - result.photo = App::photoSet(photoId, 0, 0, unixtime(), thumb, medium, full); + result.photo = Auth().data().photo( + photoId, + uint64(0), + unixtime(), + thumb, + medium, + full); } } return result; @@ -162,6 +178,10 @@ Storage::SharedMediaTypesMask Media::sharedMediaTypes() const { return {}; } +bool Media::canBeGrouped() const { + return false; +} + QString Media::caption() const { return QString(); } @@ -209,6 +229,11 @@ bool Media::consumeMessageText(const TextWithEntities &text) { return false; } +std::unique_ptr Media::createView( + not_null message) { + return createView(message, message->data()); +} + MediaPhoto::MediaPhoto( not_null parent, not_null photo, @@ -216,7 +241,6 @@ MediaPhoto::MediaPhoto( : Media(parent) , _photo(photo) , _caption(caption) { - App::regPhotoItem(_photo, parent); } MediaPhoto::MediaPhoto( @@ -226,11 +250,9 @@ MediaPhoto::MediaPhoto( : Media(parent) , _photo(photo) , _chat(chat) { - App::regPhotoItem(_photo, parent); } MediaPhoto::~MediaPhoto() { - App::unregPhotoItem(_photo, parent()); } std::unique_ptr MediaPhoto::clone(not_null parent) { @@ -257,6 +279,10 @@ Storage::SharedMediaTypesMask MediaPhoto::sharedMediaTypes() const { .added(Type::PhotoVideo); } +bool MediaPhoto::canBeGrouped() const { + return true; +} + QString MediaPhoto::caption() const { return _caption; } @@ -293,7 +319,7 @@ bool MediaPhoto::updateInlineResultMedia(const MTPMessageMedia &media) { } auto &photo = media.c_messageMediaPhoto(); if (photo.has_photo() && !photo.has_ttl_seconds()) { - if (auto existing = App::feedPhoto(photo.vphoto)) { + if (auto existing = Auth().data().photo(photo.vphoto)) { if (existing == _photo) { return true; } else { @@ -321,7 +347,7 @@ bool MediaPhoto::updateSentMedia(const MTPMessageMedia &media) { return false; } const auto &photo = mediaPhoto.vphoto; - App::feedPhoto(photo, _photo); + Auth().data().photoConvert(_photo, photo); if (photo.type() != mtpc_photo) { return false; @@ -370,7 +396,8 @@ bool MediaPhoto::updateSentMedia(const MTPMessageMedia &media) { } std::unique_ptr MediaPhoto::createView( - not_null message) { + not_null message, + not_null realParent) { if (_chat) { return std::make_unique( message, @@ -378,7 +405,11 @@ std::unique_ptr MediaPhoto::createView( _photo, st::msgServicePhotoWidth); } - return std::make_unique(message, _photo, _caption); + return std::make_unique( + message, + realParent, + _photo, + _caption); } MediaFile::MediaFile( @@ -389,7 +420,7 @@ MediaFile::MediaFile( , _document(document) , _caption(caption) , _emoji(document->sticker() ? document->sticker()->alt : QString()) { - App::regDocumentItem(_document, parent); + Auth().data().registerDocumentItem(_document, parent); if (!_emoji.isEmpty()) { if (const auto emoji = Ui::Emoji::Find(_emoji)) { @@ -399,7 +430,7 @@ MediaFile::MediaFile( } MediaFile::~MediaFile() { - App::unregDocumentItem(_document, parent()); + Auth().data().unregisterDocumentItem(_document, parent()); } std::unique_ptr MediaFile::clone(not_null parent) { @@ -438,6 +469,10 @@ Storage::SharedMediaTypesMask MediaFile::sharedMediaTypes() const { return Type::File; } +bool MediaFile::canBeGrouped() const { + return _document->isVideoFile(); +} + QString MediaFile::chatsListText() const { if (const auto sticker = _document->sticker()) { return Media::chatsListText(); @@ -545,12 +580,11 @@ bool MediaFile::updateInlineResultMedia(const MTPMessageMedia &media) { } auto &data = media.c_messageMediaDocument(); if (data.has_document() && !data.has_ttl_seconds()) { - if (const auto document = App::feedDocument(data.vdocument)) { - if (document == _document) { - return false; - } else { - document->collectLocalData(_document); - } + const auto document = Auth().data().document(data.vdocument); + if (document == _document) { + return false; + } else { + document->collectLocalData(_document); } } else { LOG(("API Error: " @@ -571,25 +605,30 @@ bool MediaFile::updateSentMedia(const MTPMessageMedia &media) { "or with ttl_seconds in updateSentMedia()")); return false; } - const auto changed = App::feedDocument(data.vdocument, _document); - if (!changed->data().isEmpty()) { - if (changed->isVoiceMessage()) { - Local::writeAudio(changed->mediaKey(), changed->data()); + Auth().data().documentConvert(_document, data.vdocument); + if (!_document->data().isEmpty()) { + if (_document->isVoiceMessage()) { + Local::writeAudio(_document->mediaKey(), _document->data()); } else { - Local::writeStickerImage(changed->mediaKey(), changed->data()); + Local::writeStickerImage(_document->mediaKey(), _document->data()); } } return true; } std::unique_ptr MediaFile::createView( - not_null message) { + not_null message, + not_null realParent) { if (_document->sticker()) { return std::make_unique(message, _document); } else if (_document->isAnimation()) { return std::make_unique(message, _document, _caption); } else if (_document->isVideoFile()) { - return std::make_unique(message, _document, _caption); + return std::make_unique( + message, + realParent, + _document, + _caption); } return std::make_unique(message, _document, _caption); } @@ -601,12 +640,18 @@ MediaContact::MediaContact( const QString &lastName, const QString &phoneNumber) : Media(parent) { + Auth().data().registerContactItem(userId, parent); + _contact.userId = userId; _contact.firstName = firstName; _contact.lastName = lastName; _contact.phoneNumber = phoneNumber; } +MediaContact::~MediaContact() { + Auth().data().unregisterContactItem(_contact.userId, parent()); +} + std::unique_ptr MediaContact::clone(not_null parent) { return std::make_unique( parent, @@ -637,15 +682,16 @@ bool MediaContact::updateSentMedia(const MTPMessageMedia &media) { return false; } if (_contact.userId != media.c_messageMediaContact().vuser_id.v) { - //detachFromParent(); // #TODO contacts + Auth().data().unregisterContactItem(_contact.userId, parent()); _contact.userId = media.c_messageMediaContact().vuser_id.v; - //attachToParent(); + Auth().data().registerContactItem(_contact.userId, parent()); } return true; } std::unique_ptr MediaContact::createView( - not_null message) { + not_null message, + not_null realParent) { return std::make_unique( message, _contact.userId, @@ -704,7 +750,8 @@ bool MediaLocation::updateSentMedia(const MTPMessageMedia &media) { } std::unique_ptr MediaLocation::createView( - not_null message) { + not_null message, + not_null realParent) { return std::make_unique( message, _location, @@ -760,7 +807,8 @@ bool MediaCall::updateSentMedia(const MTPMessageMedia &media) { } std::unique_ptr MediaCall::createView( - not_null message) { + not_null message, + not_null realParent) { return std::make_unique(message, &_call); } @@ -784,6 +832,11 @@ MediaWebPage::MediaWebPage( not_null page) : Media(parent) , _page(page) { + Auth().data().registerWebPageItem(_page, parent); +} + +MediaWebPage::~MediaWebPage() { + Auth().data().unregisterWebPageItem(_page, parent()); } std::unique_ptr MediaWebPage::clone(not_null parent) { @@ -815,7 +868,8 @@ bool MediaWebPage::updateSentMedia(const MTPMessageMedia &media) { } std::unique_ptr MediaWebPage::createView( - not_null message) { + not_null message, + not_null realParent) { return std::make_unique(message, _page); } @@ -874,15 +928,13 @@ bool MediaGame::updateSentMedia(const MTPMessageMedia &media) { if (media.type() != mtpc_messageMediaGame) { return false; } - const auto &game = media.c_messageMediaGame().vgame; - if (game.type() == mtpc_game) { - App::feedGame(game.c_game(), _game); - } + Auth().data().gameConvert(_game, media.c_messageMediaGame().vgame); return true; } std::unique_ptr MediaGame::createView( - not_null message) { + not_null message, + not_null realParent) { return std::make_unique(message, _game, _consumedText); } @@ -925,7 +977,8 @@ bool MediaInvoice::updateSentMedia(const MTPMessageMedia &media) { } std::unique_ptr MediaInvoice::createView( - not_null message) { + not_null message, + not_null realParent) { return std::make_unique(message, &_invoice); } diff --git a/Telegram/SourceFiles/data/data_media_types.h b/Telegram/SourceFiles/data/data_media_types.h index 7121a9233..8c30e901c 100644 --- a/Telegram/SourceFiles/data/data_media_types.h +++ b/Telegram/SourceFiles/data/data_media_types.h @@ -81,6 +81,7 @@ public: virtual bool uploading() const; virtual Storage::SharedMediaTypesMask sharedMediaTypes() const; + virtual bool canBeGrouped() const; virtual QString caption() const; virtual bool hasReplyPreview() const; virtual ImagePtr replyPreview() const; @@ -105,7 +106,10 @@ public: virtual bool updateInlineResultMedia(const MTPMessageMedia &media) = 0; virtual bool updateSentMedia(const MTPMessageMedia &media) = 0; virtual std::unique_ptr createView( - not_null message) = 0; + not_null message, + not_null realParent) = 0; + std::unique_ptr createView( + not_null message); private: const not_null _parent; @@ -130,6 +134,7 @@ public: bool uploading() const override; Storage::SharedMediaTypesMask sharedMediaTypes() const override; + bool canBeGrouped() const override; QString caption() const override; QString chatsListText() const override; QString notificationText() const override; @@ -141,7 +146,8 @@ public: bool updateInlineResultMedia(const MTPMessageMedia &media) override; bool updateSentMedia(const MTPMessageMedia &media) override; std::unique_ptr createView( - not_null message) override; + not_null message, + not_null realParent) override; private: not_null _photo; @@ -164,6 +170,7 @@ public: bool uploading() const override; Storage::SharedMediaTypesMask sharedMediaTypes() const override; + bool canBeGrouped() const override; QString chatsListText() const override; QString notificationText() const override; QString pinnedTextSubstring() const override; @@ -175,7 +182,8 @@ public: bool updateInlineResultMedia(const MTPMessageMedia &media) override; bool updateSentMedia(const MTPMessageMedia &media) override; std::unique_ptr createView( - not_null message) override; + not_null message, + not_null realParent) override; private: not_null _document; @@ -192,6 +200,7 @@ public: const QString &firstName, const QString &lastName, const QString &phoneNumber); + ~MediaContact(); std::unique_ptr clone(not_null parent) override; @@ -202,7 +211,8 @@ public: bool updateInlineResultMedia(const MTPMessageMedia &media) override; bool updateSentMedia(const MTPMessageMedia &media) override; std::unique_ptr createView( - not_null message) override; + not_null message, + not_null realParent) override; private: SharedContact _contact; @@ -230,7 +240,8 @@ public: bool updateInlineResultMedia(const MTPMessageMedia &media) override; bool updateSentMedia(const MTPMessageMedia &media) override; std::unique_ptr createView( - not_null message) override; + not_null message, + not_null realParent) override; private: not_null _location; @@ -256,7 +267,8 @@ public: bool updateInlineResultMedia(const MTPMessageMedia &media) override; bool updateSentMedia(const MTPMessageMedia &media) override; std::unique_ptr createView( - not_null message) override; + not_null message, + not_null realParent) override; static QString Text( not_null item, @@ -272,6 +284,7 @@ public: MediaWebPage( not_null parent, not_null page); + ~MediaWebPage(); std::unique_ptr clone(not_null parent) override; @@ -283,7 +296,8 @@ public: bool updateInlineResultMedia(const MTPMessageMedia &media) override; bool updateSentMedia(const MTPMessageMedia &media) override; std::unique_ptr createView( - not_null message) override; + not_null message, + not_null realParent) override; private: not_null _page; @@ -310,7 +324,8 @@ public: bool updateInlineResultMedia(const MTPMessageMedia &media) override; bool updateSentMedia(const MTPMessageMedia &media) override; std::unique_ptr createView( - not_null message) override; + not_null message, + not_null realParent) override; private: not_null _game; @@ -337,7 +352,8 @@ public: bool updateInlineResultMedia(const MTPMessageMedia &media) override; bool updateSentMedia(const MTPMessageMedia &media) override; std::unique_ptr createView( - not_null message) override; + not_null message, + not_null realParent) override; private: Invoice _invoice; diff --git a/Telegram/SourceFiles/data/data_peer.cpp b/Telegram/SourceFiles/data/data_peer.cpp index 1df8f58eb..a7cf254f0 100644 --- a/Telegram/SourceFiles/data/data_peer.cpp +++ b/Telegram/SourceFiles/data/data_peer.cpp @@ -171,7 +171,7 @@ void PeerData::setUserpic( void PeerData::setUserpicPhoto(const MTPPhoto &data) { auto photoId = [&]() -> PhotoId { - if (auto photo = App::feedPhoto(data)) { + if (const auto photo = Auth().data().photo(data)) { photo->peer = this; return photo->id; } @@ -353,7 +353,7 @@ const Text &BotCommand::descriptionText() const { bool UserData::canShareThisContact() const { return canShareThisContactFast() - || !App::phoneFromSharedContact(peerToUser(id)).isEmpty(); + || !Auth().data().findContactPhone(peerToUser(id)).isEmpty(); } void UserData::setContactStatus(ContactStatus status) { diff --git a/Telegram/SourceFiles/data/data_photo.cpp b/Telegram/SourceFiles/data/data_photo.cpp index 3bf4cab7a..6ac365fba 100644 --- a/Telegram/SourceFiles/data/data_photo.cpp +++ b/Telegram/SourceFiles/data/data_photo.cpp @@ -32,14 +32,14 @@ void PhotoData::automaticLoadSettingsChanged() { void PhotoData::download() { full->loadEvenCancelled(); - notifyLayoutChanged(); + Auth().data().notifyPhotoLayoutChanged(this); } bool PhotoData::loaded() const { bool wasLoading = loading(); if (full->loaded()) { if (wasLoading) { - notifyLayoutChanged(); + Auth().data().notifyPhotoLayoutChanged(this); } return true; } @@ -58,17 +58,7 @@ bool PhotoData::displayLoading() const { void PhotoData::cancel() { full->cancel(); - notifyLayoutChanged(); -} - -void PhotoData::notifyLayoutChanged() const { - auto &items = App::photoItems(); - auto i = items.constFind(const_cast(this)); - if (i != items.cend()) { - for_const (auto item, i.value()) { - Auth().data().markItemLayoutChange(item); - } - } + Auth().data().notifyPhotoLayoutChanged(this); } float64 PhotoData::progress() const { diff --git a/Telegram/SourceFiles/data/data_photo.h b/Telegram/SourceFiles/data/data_photo.h index 885ebb1ea..150f46941 100644 --- a/Telegram/SourceFiles/data/data_photo.h +++ b/Telegram/SourceFiles/data/data_photo.h @@ -49,9 +49,6 @@ public: std::unique_ptr uploadingData; -private: - void notifyLayoutChanged() const; - }; class PhotoClickHandler : public FileClickHandler { diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index dddf57e78..c0c16ccd1 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -8,15 +8,57 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_session.h" #include "observer_peer.h" +#include "auth_session.h" +#include "apiwrap.h" #include "history/history_item_components.h" +#include "history/history_media.h" #include "history/view/history_view_element.h" +#include "inline_bots/inline_bot_layout_item.h" +#include "storage/localstorage.h" +#include "data/data_media_types.h" #include "data/data_feed.h" +#include "data/data_photo.h" +#include "data/data_document.h" +#include "data/data_web_page.h" +#include "data/data_game.h" namespace Data { +namespace { using ViewElement = HistoryView::Element; -Session::Session() { +// s: box 100x100 +// m: box 320x320 +// x: box 800x800 +// y: box 1280x1280 +// w: box 2560x2560 // if loading this fix HistoryPhoto::updateFrom +// a: crop 160x160 +// b: crop 320x320 +// c: crop 640x640 +// d: crop 1280x1280 +const auto ThumbLevels = QByteArray::fromRawData("sambcxydw", 9); +const auto MediumLevels = QByteArray::fromRawData("mbcxasydw", 9); +const auto FullLevels = QByteArray::fromRawData("yxwmsdcba", 9); + +void UpdateImage(ImagePtr &old, ImagePtr now) { + if (now->isNull()) { + return; + } + if (old->isNull()) { + old = now; + } else if (const auto delayed = old->toDelayedStorageImage()) { + const auto location = now->location(); + if (!location.isNull()) { + delayed->setStorageLocation(location); + } + } +} + +} // namespace + +Session::Session(not_null session) +: _session(session) +, _groups(this) { Notify::PeerUpdateViewer( Notify::PeerUpdate::Flag::UserIsContact ) | rpl::map([](const Notify::PeerUpdate &update) { @@ -30,33 +72,78 @@ Session::Session() { Session::~Session() = default; -void Session::registerItemView(not_null view) { - _views[view->data()].push_back(view); -} - -void Session::unregisterItemView(not_null view) { - const auto i = _views.find(view->data()); - if (i != _views.end()) { - auto &list = i->second; - list.erase(ranges::remove(list, view), end(list)); - if (list.empty()) { - _views.erase(i); +template +void Session::enumerateItemViews( + not_null item, + Method method) { + if (const auto i = _views.find(item); i != _views.end()) { + for (const auto view : i->second) { + method(view); } } - if (App::hoveredItem() == view) { - App::hoveredItem(nullptr); +} + +void Session::photoLoadSettingsChanged() { + for (const auto &[id, photo] : _photos) { + photo->automaticLoadSettingsChanged(); } - if (App::pressedItem() == view) { - App::pressedItem(nullptr); +} + +void Session::voiceLoadSettingsChanged() { + for (const auto &[id, document] : _documents) { + if (document->isVoiceMessage()) { + document->automaticLoadSettingsChanged(); + } } - if (App::hoveredLinkItem() == view) { - App::hoveredLinkItem(nullptr); +} + +void Session::animationLoadSettingsChanged() { + for (const auto &[id, document] : _documents) { + if (document->isAnimation()) { + document->automaticLoadSettingsChanged(); + } } - if (App::pressedLinkItem() == view) { - App::pressedLinkItem(nullptr); +} + +void Session::notifyPhotoLayoutChanged(not_null photo) { + if (const auto i = _photoViews.find(photo); i != end(_photoViews)) { + for (const auto view : i->second) { + markViewLayoutChange(view); + } } - if (App::mousedItem() == view) { - App::mousedItem(nullptr); +} + +void Session::notifyDocumentLayoutChanged( + not_null document) { + const auto i = _documentViews.find(document); + if (i != end(_documentViews)) { + for (const auto view : i->second) { + markViewLayoutChange(view); + } + } + if (const auto items = InlineBots::Layout::documentItems()) { + if (const auto i = items->find(document); i != items->end()) { + for (const auto item : i->second) { + item->layoutChanged(); + } + } + } +} + +void Session::requestDocumentViewRepaint( + not_null document) { + const auto i = _documentViews.find(document); + if (i != end(_documentViews)) { + for (const auto view : i->second) { + requestViewRepaint(view); + } + } +} + +void Session::markMediaRead(not_null document) { + const auto i = _documentItems.find(document); + if (i != end(_documentItems)) { + _session->api().markMediaRead({ begin(i->second), end(i->second) }); } } @@ -87,12 +174,12 @@ rpl::producer Session::itemIdChanged() const { return _itemIdChanges.events(); } -void Session::requestItemRepaint(not_null item) { - _itemRepaintRequest.fire_copy(item); +void Session::requestItemViewRepaint(not_null item) { + _itemViewRepaintRequest.fire_copy(item); } -rpl::producer> Session::itemRepaintRequest() const { - return _itemRepaintRequest.events(); +rpl::producer> Session::itemViewRepaintRequest() const { + return _itemViewRepaintRequest.events(); } void Session::requestViewRepaint(not_null view) { @@ -218,11 +305,10 @@ rpl::producer<> Session::savedGifsUpdated() const { } void Session::userIsContactUpdated(not_null user) { - const auto &items = App::sharedContactItems(); - const auto i = items.constFind(peerToUser(user->id)); - if (i != items.cend()) { - for (const auto item : std::as_const(i.value())) { - requestItemViewResize(item); + const auto i = _contactViews.find(peerToUser(user->id)); + if (i != _contactViews.end()) { + for (const auto view : i->second) { + requestViewResize(view); } } } @@ -359,7 +445,7 @@ void Session::setIsPinned(const Dialogs::Key &key, bool pinned) { key.entry()->cachePinnedIndex(_pinnedDialogs.size()); } } - } else if (!pinned && already != _pinnedDialogs.end()) { + } else if (!pinned && already != end(_pinnedDialogs)) { key.entry()->cachePinnedIndex(0); _pinnedDialogs.erase(already); auto index = 0; @@ -369,6 +455,954 @@ void Session::setIsPinned(const Dialogs::Key &key, bool pinned) { } } +not_null Session::photo(PhotoId id) { + auto i = _photos.find(id); + if (i == _photos.end()) { + i = _photos.emplace(id, std::make_unique(id)).first; + } + return i->second.get(); +} + +not_null Session::photo(const MTPPhoto &data) { + switch (data.type()) { + case mtpc_photo: + return photo(data.c_photo()); + + case mtpc_photoEmpty: + return photo(data.c_photoEmpty().vid.v); + } + Unexpected("Type in Session::photo()."); +} + +not_null Session::photo(const MTPDphoto &data) { + const auto result = photo(data.vid.v); + photoApplyFields(result, data); + return result; +} + +not_null Session::photo( + const MTPPhoto &data, + const PreparedPhotoThumbs &thumbs) { + auto thumb = (const QPixmap*)nullptr; + auto medium = (const QPixmap*)nullptr; + auto full = (const QPixmap*)nullptr; + auto thumbLevel = -1; + auto mediumLevel = -1; + auto fullLevel = -1; + for (auto i = thumbs.cbegin(), e = thumbs.cend(); i != e; ++i) { + const auto newThumbLevel = ThumbLevels.indexOf(i.key()); + const auto newMediumLevel = MediumLevels.indexOf(i.key()); + const auto newFullLevel = FullLevels.indexOf(i.key()); + if (newThumbLevel < 0 || newMediumLevel < 0 || newFullLevel < 0) { + continue; + } + if (thumbLevel < 0 || newThumbLevel < thumbLevel) { + thumbLevel = newThumbLevel; + thumb = &i.value(); + } + if (mediumLevel < 0 || newMediumLevel < mediumLevel) { + mediumLevel = newMediumLevel; + medium = &i.value(); + } + if (fullLevel < 0 || newFullLevel < fullLevel) { + fullLevel = newFullLevel; + full = &i.value(); + } + } + if (!thumb || !medium || !full) { + return photo(0); + } + switch (data.type()) { + case mtpc_photo: + return photo( + data.c_photo().vid.v, + data.c_photo().vaccess_hash.v, + data.c_photo().vdate.v, + ImagePtr(*thumb, "JPG"), + ImagePtr(*medium, "JPG"), + ImagePtr(*full, "JPG")); + + case mtpc_photoEmpty: + return photo(data.c_photoEmpty().vid.v); + } + Unexpected("Type in Session::photo() with prepared thumbs."); +} + +not_null Session::photo( + PhotoId id, + const uint64 &access, + TimeId date, + const ImagePtr &thumb, + const ImagePtr &medium, + const ImagePtr &full) { + const auto result = photo(id); + photoApplyFields( + result, + access, + date, + thumb, + medium, + full); + return result; +} + +void Session::photoConvert( + not_null original, + const MTPPhoto &data) { + const auto id = [&] { + switch (data.type()) { + case mtpc_photo: return data.c_photo().vid.v; + case mtpc_photoEmpty: return data.c_photoEmpty().vid.v; + } + Unexpected("Type in Session::photoConvert()."); + }(); + if (original->id != id) { + auto i = _photos.find(id); + if (i == _photos.end()) { + const auto j = _photos.find(original->id); + Assert(j != _photos.end()); + auto owned = std::move(j->second); + _photos.erase(j); + i = _photos.emplace(id, std::move(owned)).first; + } + + original->id = id; + original->uploadingData = nullptr; + + if (i->second.get() != original) { + photoApplyFields(i->second.get(), data); + } + } + photoApplyFields(original, data); +} + +void Session::photoApplyFields( + not_null photo, + const MTPPhoto &data) { + if (data.type() == mtpc_photo) { + photoApplyFields(photo, data.c_photo()); + } +} + +void Session::photoApplyFields( + not_null photo, + const MTPDphoto &data) { + auto thumb = (const MTPPhotoSize*)nullptr; + auto medium = (const MTPPhotoSize*)nullptr; + auto full = (const MTPPhotoSize*)nullptr; + auto thumbLevel = -1; + auto mediumLevel = -1; + auto fullLevel = -1; + for (const auto &sizeData : data.vsizes.v) { + const auto sizeLetter = [&] { + switch (sizeData.type()) { + case mtpc_photoSizeEmpty: return char(0); + case mtpc_photoSize: { + const auto &data = sizeData.c_photoSize(); + return data.vtype.v.isEmpty() ? char(0) : data.vtype.v[0]; + } break; + case mtpc_photoCachedSize: { + const auto &data = sizeData.c_photoCachedSize(); + return data.vtype.v.isEmpty() ? char(0) : data.vtype.v[0]; + } break; + } + Unexpected("Type in photo size."); + }(); + if (!sizeLetter) continue; + + const auto newThumbLevel = ThumbLevels.indexOf(sizeLetter); + const auto newMediumLevel = MediumLevels.indexOf(sizeLetter); + const auto newFullLevel = FullLevels.indexOf(sizeLetter); + if (newThumbLevel < 0 || newMediumLevel < 0 || newFullLevel < 0) { + continue; + } + if (thumbLevel < 0 || newThumbLevel < thumbLevel) { + thumbLevel = newThumbLevel; + thumb = &sizeData; + } + if (mediumLevel < 0 || newMediumLevel < mediumLevel) { + mediumLevel = newMediumLevel; + medium = &sizeData; + } + if (fullLevel < 0 || newFullLevel < fullLevel) { + fullLevel = newFullLevel; + full = &sizeData; + } + } + if (thumb && medium && full) { + photoApplyFields( + photo, + data.vaccess_hash.v, + data.vdate.v, + App::image(*thumb), + App::image(*medium), + App::image(*full)); + } +} + +void Session::photoApplyFields( + not_null photo, + const uint64 &access, + TimeId date, + const ImagePtr &thumb, + const ImagePtr &medium, + const ImagePtr &full) { + if (!date) { + return; + } + photo->access = access; + photo->date = date; + UpdateImage(photo->thumb, thumb); + UpdateImage(photo->medium, medium); + UpdateImage(photo->full, full); +} + +not_null Session::document(DocumentId id) { + auto i = _documents.find(id); + if (i == _documents.cend()) { + i = _documents.emplace(id, DocumentData::create(id)).first; + } + return i->second.get(); +} + +not_null Session::document(const MTPDocument &data) { + switch (data.type()) { + case mtpc_document: + return document(data.c_document()); + + case mtpc_documentEmpty: + return document(data.c_documentEmpty().vid.v); + } + Unexpected("Type in Session::document()."); +} + +not_null Session::document(const MTPDdocument &data) { + const auto result = document(data.vid.v); + documentApplyFields(result, data); + return result; +} + +not_null Session::document( + const MTPdocument &data, + const QPixmap &thumb) { + switch (data.type()) { + case mtpc_documentEmpty: + return document(data.c_documentEmpty().vid.v); + + case mtpc_document: { + const auto &fields = data.c_document(); + return document( + fields.vid.v, + fields.vaccess_hash.v, + fields.vversion.v, + fields.vdate.v, + fields.vattributes.v, + qs(fields.vmime_type), + ImagePtr(thumb, "JPG"), + fields.vdc_id.v, + fields.vsize.v, + StorageImageLocation()); + } break; + } + Unexpected("Type in Session::document() with thumb."); +} + +not_null Session::document( + DocumentId id, + const uint64 &access, + int32 version, + TimeId date, + const QVector &attributes, + const QString &mime, + const ImagePtr &thumb, + int32 dc, + int32 size, + const StorageImageLocation &thumbLocation) { + const auto result = document(id); + documentApplyFields( + result, + access, + version, + date, + attributes, + mime, + thumb, + dc, + size, + thumbLocation); + return result; +} + +void Session::documentConvert( + not_null original, + const MTPDocument &data) { + const auto id = [&] { + switch (data.type()) { + case mtpc_document: return data.c_document().vid.v; + case mtpc_documentEmpty: return data.c_documentEmpty().vid.v; + } + Unexpected("Type in Session::documentConvert()."); + }(); + const auto oldKey = original->mediaKey(); + const auto idChanged = (original->id != id); + const auto sentSticker = idChanged && (original->sticker() != nullptr); + if (idChanged) { + auto i = _documents.find(id); + if (i == _documents.end()) { + const auto j = _documents.find(original->id); + Assert(j != _documents.end()); + auto owned = std::move(j->second); + _documents.erase(j); + i = _documents.emplace(id, std::move(owned)).first; + } + + original->id = id; + original->status = FileReady; + original->uploadingData = nullptr; + + if (i->second.get() != original) { + documentApplyFields(i->second.get(), data); + } + } + documentApplyFields(original, data); + if (idChanged) { + // #TODO check audio, sticker, GIF animation, saved GIF?.. + const auto newKey = original->mediaKey(); + if (oldKey != newKey) { + if (original->isVoiceMessage()) { + Local::copyAudio(oldKey, newKey); + } else if (original->sticker() || original->isAnimation()) { + Local::copyStickerImage(oldKey, newKey); + } + } + if (savedGifs().indexOf(original) >= 0) { + Local::writeSavedGifs(); + } + } +} + +void Session::documentApplyFields( + not_null document, + const MTPDocument &data) { + if (data.type() == mtpc_document) { + documentApplyFields(document, data.c_document()); + } +} + +void Session::documentApplyFields( + not_null document, + const MTPDdocument &data) { + documentApplyFields( + document, + data.vaccess_hash.v, + data.vversion.v, + data.vdate.v, + data.vattributes.v, + qs(data.vmime_type), + App::image(data.vthumb), + data.vdc_id.v, + data.vsize.v, + StorageImageLocation::FromMTP(data.vthumb)); +} + +void Session::documentApplyFields( + not_null document, + const uint64 &access, + int32 version, + TimeId date, + const QVector &attributes, + const QString &mime, + const ImagePtr &thumb, + int32 dc, + int32 size, + const StorageImageLocation &thumbLocation) { + if (!date) { + return; + } + document->setattributes(attributes); + document->setRemoteVersion(version); + if (dc != 0 && access != 0) { + // #TODO was "!document->isValid()" - check if it is fine for convert + document->setRemoteLocation(dc, access); + } + document->date = date; + document->setMimeString(mime); + if (!thumb->isNull() + && (document->thumb->isNull() + || document->thumb->width() < thumb->width() + || document->thumb->height() < thumb->height())) { + document->thumb = thumb; + } + document->size = size; + document->recountIsImage(); + if (document->sticker() + && document->sticker()->loc.isNull() + && !thumbLocation.isNull()) { + document->sticker()->loc = thumbLocation; + } +} + +not_null Session::webpage(WebPageId id) { + auto i = _webpages.find(id); + if (i == _webpages.cend()) { + i = _webpages.emplace(id, std::make_unique(id)).first; + } + return i->second.get(); +} + +not_null Session::webpage(const MTPWebPage &data) { + switch (data.type()) { + case mtpc_webPage: + return webpage(data.c_webPage()); + case mtpc_webPageEmpty: { + const auto result = webpage(data.c_webPageEmpty().vid.v); + if (result->pendingTill > 0) { + result->pendingTill = -1; // failed + } + return result; + } break; + case mtpc_webPagePending: + return webpage(data.c_webPagePending()); + case mtpc_webPageNotModified: + LOG(("API Error: " + "webPageNotModified is unexpected in Session::webpage().")); + return webpage(0); + } + Unexpected("Type in Session::webpage()."); +} + +not_null Session::webpage(const MTPDwebPage &data) { + const auto result = webpage(data.vid.v); + webpageApplyFields(result, data); + return result; +} + +not_null Session::webpage(const MTPDwebPagePending &data) { + constexpr auto kDefaultPendingTimeout = 60; + const auto result = webpage(data.vid.v); + webpageApplyFields( + result, + QString(), + QString(), + QString(), + QString(), + QString(), + TextWithEntities(), + nullptr, + nullptr, + 0, + QString(), + data.vdate.v + ? data.vdate.v + : (unixtime() + kDefaultPendingTimeout)); + return result; +} + +not_null Session::webpage( + WebPageId id, + const QString &siteName, + const TextWithEntities &content) { + return webpage( + id, + qsl("article"), + QString(), + QString(), + siteName, + QString(), + content, + nullptr, + nullptr, + 0, + QString(), + TimeId(0)); +} + +not_null Session::webpage( + WebPageId id, + const QString &type, + const QString &url, + const QString &displayUrl, + const QString &siteName, + const QString &title, + const TextWithEntities &description, + PhotoData *photo, + DocumentData *document, + int duration, + const QString &author, + TimeId pendingTill) { + const auto result = webpage(id); + webpageApplyFields( + result, + type, + url, + displayUrl, + siteName, + title, + description, + photo, + document, + duration, + author, + pendingTill); + return result; +} + +void Session::webpageApplyFields( + not_null page, + const MTPDwebPage &data) { + auto description = TextWithEntities { + data.has_description() + ? TextUtilities::Clean(qs(data.vdescription)) + : QString() + }; + const auto siteName = data.has_site_name() + ? qs(data.vsite_name) + : QString(); + auto parseFlags = TextParseLinks | TextParseMultiline | TextParseRichText; + if (siteName == qstr("Twitter") || siteName == qstr("Instagram")) { + parseFlags |= TextParseHashtags | TextParseMentions; + } + TextUtilities::ParseEntities(description, parseFlags); + const auto pendingTill = TimeId(0); + webpageApplyFields( + page, + data.has_type() ? qs(data.vtype) : qsl("article"), + qs(data.vurl), + qs(data.vdisplay_url), + siteName, + data.has_title() ? qs(data.vtitle) : QString(), + description, + data.has_photo() ? photo(data.vphoto).get() : nullptr, + data.has_document() ? document(data.vdocument).get() : nullptr, + data.has_duration() ? data.vduration.v : 0, + data.has_author() ? qs(data.vauthor) : QString(), + pendingTill); +} + +void Session::webpageApplyFields( + not_null page, + const QString &type, + const QString &url, + const QString &displayUrl, + const QString &siteName, + const QString &title, + const TextWithEntities &description, + PhotoData *photo, + DocumentData *document, + int duration, + const QString &author, + TimeId pendingTill) { + if (!page->pendingTill && pendingTill > 0) { + _session->api().requestWebPageDelayed(page); + } + const auto changed = page->applyChanges( + type, + url, + displayUrl, + siteName, + title, + description, + photo, + document, + duration, + author, + pendingTill); + if (changed) { + notifyWebPageUpdateDelayed(page); + } +} + +not_null Session::game(GameId id) { + auto i = _games.find(id); + if (i == _games.cend()) { + i = _games.emplace(id, std::make_unique(id)).first; + } + return i->second.get(); +} + +not_null Session::game(const MTPDgame &data) { + const auto result = game(data.vid.v); + gameApplyFields(result, data); + return result; +} + +not_null Session::game( + GameId id, + const uint64 &accessHash, + const QString &shortName, + const QString &title, + const QString &description, + PhotoData *photo, + DocumentData *document) { + const auto result = game(id); + gameApplyFields( + result, + accessHash, + shortName, + title, + description, + photo, + document); + return result; +} + +void Session::gameConvert( + not_null original, + const MTPGame &data) { + Expects(data.type() == mtpc_game); + + const auto id = data.c_game().vid.v; + if (original->id != id) { + auto i = _games.find(id); + if (i == _games.end()) { + const auto j = _games.find(original->id); + Assert(j != _games.end()); + auto owned = std::move(j->second); + _games.erase(j); + i = _games.emplace(id, std::move(owned)).first; + } + + original->id = id; + original->accessHash = 0; + + if (i->second.get() != original) { + gameApplyFields(i->second.get(), data.c_game()); + } + } + gameApplyFields(original, data.c_game()); +} + +void Session::gameApplyFields( + not_null game, + const MTPDgame &data) { + gameApplyFields( + game, + data.vaccess_hash.v, + qs(data.vshort_name), + qs(data.vtitle), + qs(data.vdescription), + photo(data.vphoto), + data.has_document() ? document(data.vdocument).get() : nullptr); +} + +void Session::gameApplyFields( + not_null game, + const uint64 &accessHash, + const QString &shortName, + const QString &title, + const QString &description, + PhotoData *photo, + DocumentData *document) { + if (game->accessHash || !accessHash) { + return; + } + game->accessHash = accessHash; + game->shortName = TextUtilities::Clean(shortName); + game->title = TextUtilities::SingleLine(title); + game->description = TextUtilities::Clean(description); + game->photo = photo; + game->document = document; + notifyGameUpdateDelayed(game); +} + +void Session::registerPhotoView( + not_null photo, + not_null view) { + _photoViews[photo].insert(view); +} + +void Session::unregisterPhotoView( + not_null photo, + not_null view) { + const auto i = _photoViews.find(photo); + if (i != _photoViews.end()) { + auto &items = i->second; + if (items.remove(view) && items.empty()) { + _photoViews.erase(i); + } + } +} + +void Session::registerDocumentView( + not_null document, + not_null view) { + _documentViews[document].insert(view); +} + +void Session::unregisterDocumentView( + not_null document, + not_null view) { + const auto i = _documentViews.find(document); + if (i != _documentViews.end()) { + auto &items = i->second; + if (items.remove(view) && items.empty()) { + _documentViews.erase(i); + } + } +} + +void Session::registerDocumentItem( + not_null document, + not_null item) { + _documentItems[document].insert(item); +} + +void Session::unregisterDocumentItem( + not_null document, + not_null item) { + const auto i = _documentItems.find(document); + if (i != _documentItems.end()) { + auto &items = i->second; + if (items.remove(item) && items.empty()) { + _documentItems.erase(i); + } + } +} + +void Session::registerWebPageView( + not_null page, + not_null view) { + _webpageViews[page].insert(view); +} + +void Session::unregisterWebPageView( + not_null page, + not_null view) { + const auto i = _webpageViews.find(page); + if (i != _webpageViews.end()) { + auto &items = i->second; + if (items.remove(view) && items.empty()) { + _webpageViews.erase(i); + } + } +} + +void Session::registerWebPageItem( + not_null page, + not_null item) { + _webpageItems[page].insert(item); +} + +void Session::unregisterWebPageItem( + not_null page, + not_null item) { + const auto i = _webpageItems.find(page); + if (i != _webpageItems.end()) { + auto &items = i->second; + if (items.remove(item) && items.empty()) { + _webpageItems.erase(i); + } + } +} + +void Session::registerGameView( + not_null game, + not_null view) { + _gameViews[game].insert(view); +} + +void Session::unregisterGameView( + not_null game, + not_null view) { + const auto i = _gameViews.find(game); + if (i != _gameViews.end()) { + auto &items = i->second; + if (items.remove(view) && items.empty()) { + _gameViews.erase(i); + } + } +} + +void Session::registerContactView( + UserId contactId, + not_null view) { + if (!contactId) { + return; + } + _contactViews[contactId].insert(view); +} + +void Session::unregisterContactView( + UserId contactId, + not_null view) { + if (!contactId) { + return; + } + const auto i = _contactViews.find(contactId); + if (i != _contactViews.end()) { + auto &items = i->second; + if (items.remove(view) && items.empty()) { + _contactViews.erase(i); + } + } +} + +void Session::registerContactItem( + UserId contactId, + not_null item) { + if (!contactId) { + return; + } + const auto contact = App::userLoaded(contactId); + const auto canShare = contact ? contact->canShareThisContact() : false; + + _contactItems[contactId].insert(item); + + if (contact && canShare != contact->canShareThisContact()) { + Notify::peerUpdatedDelayed( + contact, + Notify::PeerUpdate::Flag::UserCanShareContact); + } + + if (const auto i = _views.find(item); i != _views.end()) { + for (const auto view : i->second) { + if (const auto media = view->media()) { + media->updateSharedContactUserId(contactId); + } + } + } +} + +void Session::unregisterContactItem( + UserId contactId, + not_null item) { + if (!contactId) { + return; + } + const auto contact = App::userLoaded(contactId); + const auto canShare = contact ? contact->canShareThisContact() : false; + + const auto i = _contactItems.find(contactId); + if (i != _contactItems.end()) { + auto &items = i->second; + if (items.remove(item) && items.empty()) { + _contactItems.erase(i); + } + } + + if (contact && canShare != contact->canShareThisContact()) { + Notify::peerUpdatedDelayed( + contact, + Notify::PeerUpdate::Flag::UserCanShareContact); + } +} + +void Session::registerAutoplayAnimation( + not_null<::Media::Clip::Reader*> reader, + not_null view) { + _autoplayAnimations.emplace(reader, view); +} + +void Session::unregisterAutoplayAnimation( + not_null<::Media::Clip::Reader*> reader) { + _autoplayAnimations.remove(reader); +} + +void Session::stopAutoplayAnimations() { + for (const auto [reader, view] : base::take(_autoplayAnimations)) { + if (const auto media = view->media()) { + if (!media->isRoundVideoPlaying()) { + media->stopInline(); + } + } + } +} + +HistoryItem *Session::findWebPageItem(not_null page) const { + const auto i = _webpageItems.find(page); + if (i != _webpageItems.end()) { + for (const auto item : i->second) { + if (IsServerMsgId(item->id)) { + return item; + } + } + } + return nullptr; +} + +QString Session::findContactPhone(not_null contact) const { + const auto result = contact->phone(); + return result.isEmpty() + ? findContactPhone(contact->bareId()) + : App::formatPhone(result); +} + +QString Session::findContactPhone(UserId contactId) const { + const auto i = _contactItems.find(contactId); + if (i != _contactItems.end()) { + if (const auto media = (*begin(i->second))->media()) { + if (const auto contact = media->sharedContact()) { + return contact->phoneNumber; + } + } + } + return QString(); +} + +void Session::notifyWebPageUpdateDelayed(not_null page) { + const auto invoke = _webpagesUpdated.empty() && _gamesUpdated.empty(); + _webpagesUpdated.insert(page); + if (invoke) { + crl::on_main(_session, [=] { sendWebPageGameNotifications(); }); + } +} + +void Session::notifyGameUpdateDelayed(not_null game) { + const auto invoke = _webpagesUpdated.empty() && _gamesUpdated.empty(); + _gamesUpdated.insert(game); + if (invoke) { + crl::on_main(_session, [=] { sendWebPageGameNotifications(); }); + } +} + +void Session::sendWebPageGameNotifications() { + for (const auto page : base::take(_webpagesUpdated)) { + const auto i = _webpageViews.find(page); + if (i != _webpageViews.end()) { + for (const auto view : i->second) { + requestViewResize(view); + } + } + } + for (const auto game : base::take(_gamesUpdated)) { + if (const auto i = _gameViews.find(game); i != _gameViews.end()) { + for (const auto view : i->second) { + requestViewResize(view); + } + } + } +} + +void Session::registerItemView(not_null view) { + _views[view->data()].push_back(view); +} + +void Session::unregisterItemView(not_null view) { + const auto i = _views.find(view->data()); + if (i != end(_views)) { + auto &list = i->second; + list.erase(ranges::remove(list, view), end(list)); + if (list.empty()) { + _views.erase(i); + } + } + if (App::hoveredItem() == view) { + App::hoveredItem(nullptr); + } + if (App::pressedItem() == view) { + App::pressedItem(nullptr); + } + if (App::hoveredLinkItem() == view) { + App::hoveredLinkItem(nullptr); + } + if (App::pressedLinkItem() == view) { + App::pressedLinkItem(nullptr); + } + if (App::mousedItem() == view) { + App::mousedItem(nullptr); + } +} + not_null Session::feed(FeedId id) { if (const auto result = feedLoaded(id)) { return result; @@ -381,7 +1415,16 @@ not_null Session::feed(FeedId id) { Data::Feed *Session::feedLoaded(FeedId id) { const auto it = _feeds.find(id); - return (it == _feeds.end()) ? nullptr : it->second.get(); + return (it == end(_feeds)) ? nullptr : it->second.get(); +} + +void Session::forgetMedia() { + for (const auto &[id, photo] : _photos) { + photo->forget(); + } + for (const auto &[id, document] : _documents) { + document->forget(); + } } void Session::setMimeForwardIds(MessageIdsList &&list) { diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index d5ef5d0f1..ecc8b31ca 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -18,6 +18,14 @@ struct Group; class Element; } // namespace HistoryView +class AuthSession; + +namespace Media { +namespace Clip { +class Reader; +} // namespace Clip +} // namespace Media + namespace Data { class Feed; @@ -26,7 +34,7 @@ class Session final { public: using ViewElement = HistoryView::Element; - Session(); + explicit Session(not_null session); ~Session(); base::Variable &contactsLoaded() { @@ -53,26 +61,14 @@ public: not_null item; MsgId oldId = 0; }; - - void registerItemView(not_null view); - void unregisterItemView(not_null view); - template - void enumerateItemViews(not_null item, Method method) { - if (const auto i = _views.find(item); i != _views.end()) { - for (const auto view : i->second) { - method(view); - } - } - } - void markItemIdChange(IdChange event); rpl::producer itemIdChanged() const; void markItemLayoutChange(not_null item); rpl::producer> itemLayoutChanged() const; void markViewLayoutChange(not_null view); rpl::producer> viewLayoutChanged() const; - void requestItemRepaint(not_null item); - rpl::producer> itemRepaintRequest() const; + void requestItemViewRepaint(not_null item); + rpl::producer> itemViewRepaintRequest() const; void requestViewRepaint(not_null view); rpl::producer> viewRepaintRequest() const; void requestItemViewResize(not_null item); @@ -194,9 +190,162 @@ public: const Dialogs::Key &key1, const Dialogs::Key &key2); + void photoLoadSettingsChanged(); + void voiceLoadSettingsChanged(); + void animationLoadSettingsChanged(); + + void notifyPhotoLayoutChanged(not_null photo); + void notifyDocumentLayoutChanged( + not_null document); + void requestDocumentViewRepaint(not_null document); + void markMediaRead(not_null document); + + not_null photo(PhotoId id); + not_null photo(const MTPPhoto &data); + not_null photo(const MTPDphoto &data); + not_null photo( + const MTPPhoto &data, + const PreparedPhotoThumbs &thumbs); + not_null photo( + PhotoId id, + const uint64 &access, + TimeId date, + const ImagePtr &thumb, + const ImagePtr &medium, + const ImagePtr &full); + void photoConvert( + not_null original, + const MTPPhoto &data); + + not_null document(DocumentId id); + not_null document(const MTPDocument &data); + not_null document(const MTPDdocument &data); + not_null document( + const MTPdocument &data, + const QPixmap &thumb); + not_null document( + DocumentId id, + const uint64 &access, + int32 version, + TimeId date, + const QVector &attributes, + const QString &mime, + const ImagePtr &thumb, + int32 dc, + int32 size, + const StorageImageLocation &thumbLocation); + void documentConvert( + not_null original, + const MTPDocument &data); + + not_null webpage(WebPageId id); + not_null webpage(const MTPWebPage &data); + not_null webpage(const MTPDwebPage &data); + not_null webpage(const MTPDwebPagePending &data); + not_null webpage( + WebPageId id, + const QString &siteName, + const TextWithEntities &content); + not_null webpage( + WebPageId id, + const QString &type, + const QString &url, + const QString &displayUrl, + const QString &siteName, + const QString &title, + const TextWithEntities &description, + PhotoData *photo, + DocumentData *document, + int duration, + const QString &author, + TimeId pendingTill); + + not_null game(GameId id); + not_null game(const MTPDgame &data); + not_null game( + GameId id, + const uint64 &accessHash, + const QString &shortName, + const QString &title, + const QString &description, + PhotoData *photo, + DocumentData *document); + void gameConvert( + not_null original, + const MTPGame &data); + + void registerPhotoView( + not_null photo, + not_null view); + void unregisterPhotoView( + not_null photo, + not_null view); + void registerDocumentView( + not_null document, + not_null view); + void unregisterDocumentView( + not_null document, + not_null view); + void registerDocumentItem( + not_null document, + not_null item); + void unregisterDocumentItem( + not_null document, + not_null item); + void registerWebPageView( + not_null page, + not_null view); + void unregisterWebPageView( + not_null page, + not_null view); + void registerWebPageItem( + not_null page, + not_null item); + void unregisterWebPageItem( + not_null page, + not_null item); + void registerGameView( + not_null game, + not_null view); + void unregisterGameView( + not_null game, + not_null view); + void registerContactView( + UserId contactId, + not_null view); + void unregisterContactView( + UserId contactId, + not_null view); + void registerContactItem( + UserId contactId, + not_null item); + void unregisterContactItem( + UserId contactId, + not_null item); + void registerAutoplayAnimation( + not_null<::Media::Clip::Reader*> reader, + not_null view); + void unregisterAutoplayAnimation( + not_null<::Media::Clip::Reader*> reader); + + HistoryItem *findWebPageItem(not_null page) const; + QString findContactPhone(not_null contact) const; + QString findContactPhone(UserId contactId) const; + + void notifyWebPageUpdateDelayed(not_null page); + void notifyGameUpdateDelayed(not_null game); + void sendWebPageGameNotifications(); + + void stopAutoplayAnimations(); + + void registerItemView(not_null view); + void unregisterItemView(not_null view); + not_null feed(FeedId id); Data::Feed *feedLoaded(FeedId id); + void forgetMedia(); + void setMimeForwardIds(MessageIdsList &&list); MessageIdsList takeMimeForwardIds(); @@ -208,6 +357,67 @@ public: } private: + void photoApplyFields( + not_null photo, + const MTPPhoto &data); + void photoApplyFields( + not_null photo, + const MTPDphoto &data); + void photoApplyFields( + not_null photo, + const uint64 &access, + TimeId date, + const ImagePtr &thumb, + const ImagePtr &medium, + const ImagePtr &full); + + void documentApplyFields( + not_null document, + const MTPDocument &data); + void documentApplyFields( + not_null document, + const MTPDdocument &data); + void documentApplyFields( + not_null document, + const uint64 &access, + int32 version, + TimeId date, + const QVector &attributes, + const QString &mime, + const ImagePtr &thumb, + int32 dc, + int32 size, + const StorageImageLocation &thumbLocation); + + void webpageApplyFields( + not_null page, + const MTPDwebPage &data); + void webpageApplyFields( + not_null page, + const QString &type, + const QString &url, + const QString &displayUrl, + const QString &siteName, + const QString &title, + const TextWithEntities &description, + PhotoData *photo, + DocumentData *document, + int duration, + const QString &author, + TimeId pendingTill); + + void gameApplyFields( + not_null game, + const MTPDgame &data); + void gameApplyFields( + not_null game, + const uint64 &accessHash, + const QString &shortName, + const QString &title, + const QString &description, + PhotoData *photo, + DocumentData *document); + bool stickersUpdateNeeded(TimeMs lastUpdate, TimeMs now) const { constexpr auto kStickersUpdateTimeout = TimeMs(3600'000); return (lastUpdate == 0) @@ -218,6 +428,11 @@ private: void clearPinnedDialogs(); void setIsPinned(const Dialogs::Key &key, bool pinned); + template + void enumerateItemViews(not_null item, Method method); + + not_null _session; + base::Variable _contactsLoaded = { false }; base::Variable _allChatsLoaded = { false }; base::Observable _moreChatsLoaded; @@ -226,7 +441,7 @@ private: rpl::event_stream _itemIdChanges; rpl::event_stream> _itemLayoutChanges; rpl::event_stream> _viewLayoutChanges; - rpl::event_stream> _itemRepaintRequest; + rpl::event_stream> _itemViewRepaintRequest; rpl::event_stream> _viewRepaintRequest; rpl::event_stream> _itemViewResizeRequest; rpl::event_stream> _viewResizeRequest; @@ -252,6 +467,49 @@ private: Stickers::Order _archivedStickerSetsOrder; Stickers::SavedGifs _savedGifs; + std::unordered_map< + PhotoId, + std::unique_ptr> _photos; + std::map< + not_null, + base::flat_set>> _photoViews; + std::unordered_map< + DocumentId, + std::unique_ptr> _documents; + std::map< + not_null, + base::flat_set>> _documentItems; + std::map< + not_null, + base::flat_set>> _documentViews; + std::unordered_map< + WebPageId, + std::unique_ptr> _webpages; + std::map< + not_null, + base::flat_set>> _webpageItems; + std::map< + not_null, + base::flat_set>> _webpageViews; + std::unordered_map< + GameId, + std::unique_ptr> _games; + std::map< + not_null, + base::flat_set>> _gameViews; + std::map< + UserId, + base::flat_set>> _contactItems; + std::map< + UserId, + base::flat_set>> _contactViews; + base::flat_map< + not_null<::Media::Clip::Reader*>, + not_null> _autoplayAnimations; + + base::flat_set> _webpagesUpdated; + base::flat_set> _gamesUpdated; + std::deque _pinnedDialogs; base::flat_map> _feeds; Groups _groups; diff --git a/Telegram/SourceFiles/data/data_shared_media.cpp b/Telegram/SourceFiles/data/data_shared_media.cpp index f55c6a165..9c727772b 100644 --- a/Telegram/SourceFiles/data/data_shared_media.cpp +++ b/Telegram/SourceFiles/data/data_shared_media.cpp @@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_media_types.h" #include "data/data_media_types.h" #include "data/data_sparse_ids.h" +#include "data/data_session.h" #include "info/info_memento.h" #include "info/info_controller.h" #include "window/window_controller.h" @@ -284,7 +285,7 @@ SharedMediaWithLastSlice::Value SharedMediaWithLastSlice::operator[](int index) } return (index < _slice.size()) ? Value(_slice[index]) - : Value(App::photo(*_lastPhotoId)); + : Value(Auth().data().photo(*_lastPhotoId)); } base::optional SharedMediaWithLastSlice::distance( diff --git a/Telegram/SourceFiles/data/data_web_page.cpp b/Telegram/SourceFiles/data/data_web_page.cpp index cf0737f6b..430e460c5 100644 --- a/Telegram/SourceFiles/data/data_web_page.cpp +++ b/Telegram/SourceFiles/data/data_web_page.cpp @@ -44,7 +44,7 @@ bool WebPageData::applyChanges( const QString &newAuthor, int newPendingTill) { if (newPendingTill != 0 - && (!url.isEmpty() || newUrl.isEmpty()) + && (!url.isEmpty() || pendingTill < 0) && (!pendingTill || pendingTill == newPendingTill || newPendingTill < -1)) { @@ -103,7 +103,5 @@ bool WebPageData::applyChanges( author = resultAuthor; pendingTill = newPendingTill; ++version; - if (App::main()) App::main()->webPageUpdated(this); - return true; } \ No newline at end of file diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index e257d8ea1..5906aa38e 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -94,7 +94,7 @@ DialogsInner::DialogsInner(QWidget *parent, not_null contro ) | rpl::start_with_next( [this](auto item) { itemRemoved(item); }, lifetime()); - Auth().data().itemRepaintRequest( + Auth().data().itemViewRepaintRequest( ) | rpl::start_with_next([this](auto item) { const auto history = item->history(); if (history->textCachedFor == item) { @@ -2316,7 +2316,9 @@ bool DialogsInner::chooseRow() { if (const auto history = chosen.key.history()) { App::main()->choosePeer(history->peer->id, chosen.messageId); } else if (const auto feed = chosen.key.feed()) { - _controller->showSection(HistoryFeed::Memento(feed)); + _controller->showSection( + HistoryFeed::Memento(feed), + Window::SectionShow::Way::ClearStack); } if (openSearchResult) { emit searchResultChosen(); diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index ebba8739a..09fea4e7d 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -349,8 +349,8 @@ void handlePendingHistoryUpdate() { } Auth().data().pendingHistoryResize().notify(true); - for (const auto item : base::take(Global::RefPendingRepaintItems())) { - Auth().data().requestItemRepaint(item); + //for (const auto item : base::take(Global::RefPendingRepaintItems())) { + // Auth().data().requestItemViewRepaint(item); // Start the video if it is waiting for that. //if (item->pendingInitDimensions()) { // #TODO floating player video @@ -372,7 +372,7 @@ void handlePendingHistoryUpdate() { // } // } //} - } + //} } void unreadCounterUpdated() { @@ -572,8 +572,6 @@ struct Data { HiddenPinnedMessagesMap HiddenPinnedMessages; - PendingItemsMap PendingRepaintItems; - Stickers::Sets StickerSets; Stickers::Order StickerSetsOrder; TimeMs LastStickersUpdate = 0; @@ -695,8 +693,6 @@ DefineRefVar(Global, base::Observable, PhoneCallsEnabledChanged); DefineVar(Global, HiddenPinnedMessagesMap, HiddenPinnedMessages); -DefineRefVar(Global, PendingItemsMap, PendingRepaintItems); - DefineVar(Global, Stickers::Sets, StickerSets); DefineVar(Global, Stickers::Order, StickerSetsOrder); DefineVar(Global, TimeMs, LastStickersUpdate); diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h index 1ac8d1472..96762e543 100644 --- a/Telegram/SourceFiles/facades.h +++ b/Telegram/SourceFiles/facades.h @@ -355,9 +355,6 @@ DeclareRefVar(base::Observable, PhoneCallsEnabledChanged); typedef QMap HiddenPinnedMessagesMap; DeclareVar(HiddenPinnedMessagesMap, HiddenPinnedMessages); -typedef OrderedSet PendingItemsMap; -DeclareRefVar(PendingItemsMap, PendingRepaintItems); - typedef QMap CircleMasksMap; DeclareRefVar(CircleMasksMap, CircleMasks); diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp index df5420546..dc286e23f 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_inner.cpp @@ -14,8 +14,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_item_components.h" #include "history/admin_log/history_admin_log_section.h" #include "history/admin_log/history_admin_log_filter.h" +#include "history/view/history_view_message.h" #include "history/view/history_view_service_message.h" -#include "history/view/history_view_element.h" #include "chat_helpers/message_field.h" #include "mainwindow.h" #include "mainwidget.h" @@ -213,7 +213,7 @@ InnerWidget::InnerWidget( , _emptyText(st::historyAdminLogEmptyWidth - st::historyAdminLogEmptyPadding.left() - st::historyAdminLogEmptyPadding.left()) { setMouseTracking(true); _scrollDateHideTimer.setCallback([this] { scrollDateHideByTimer(); }); - Auth().data().itemRepaintRequest( + Auth().data().itemViewRepaintRequest( ) | rpl::start_with_next([this](auto item) { if (item->isLogEntry() && _history == item->history()) { repaintItem(viewForItem(item)); @@ -441,6 +441,20 @@ QPoint InnerWidget::tooltipPos() const { return _mousePosition; } +std::unique_ptr InnerWidget::elementCreate( + not_null message) { + return std::make_unique( + message, + HistoryView::Context::AdminLog); +} + +std::unique_ptr InnerWidget::elementCreate( + not_null message) { + return std::make_unique( + message, + HistoryView::Context::AdminLog); +} + void InnerWidget::saveState(not_null memento) { memento->setFilter(std::move(_filter)); memento->setAdmins(std::move(_admins)); @@ -544,7 +558,7 @@ void InnerWidget::addEvents(Direction direction, const QVector callback); - // AbstractTooltipShower interface + // Ui::AbstractTooltipShower interface. QString tooltipText() const override; QPoint tooltipPos() const override; + // HistoryView::ElementDelegate interface. + std::unique_ptr elementCreate( + not_null message) override; + std::unique_ptr elementCreate( + not_null message) override; + ~InnerWidget(); protected: diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp b/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp index 17c54a655..587cde149 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp @@ -12,11 +12,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_service.h" #include "history/history_message.h" #include "history/history.h" +#include "data/data_session.h" #include "lang/lang_keys.h" #include "boxes/sticker_set_box.h" #include "core/tl_help.h" #include "base/overload.h" #include "messenger.h" +#include "auth_session.h" namespace AdminLog { namespace { @@ -119,7 +121,12 @@ PhotoData *GenerateChatPhoto(ChannelId channelId, uint64 logEntryId, MTPint date photoSizes.reserve(2); photoSizes.push_back(MTP_photoSize(MTP_string("a"), photo.vphoto_small, MTP_int(160), MTP_int(160), MTP_int(0))); photoSizes.push_back(MTP_photoSize(MTP_string("c"), photo.vphoto_big, MTP_int(640), MTP_int(640), MTP_int(0))); - return App::feedPhoto(MTP_photo(MTP_flags(0), MTP_long(photoId), MTP_long(0), date, MTP_vector(photoSizes))); + return Auth().data().photo(MTP_photo( + MTP_flags(0), + MTP_long(photoId), + MTP_long(0), + date, + MTP_vector(photoSizes))); } const auto CollectChanges = [](auto &phraseMap, auto plusFlags, auto minusFlags) { @@ -284,10 +291,10 @@ TextWithEntities GenerateParticipantChangeText(not_null channel, c } // namespace OwnedItem::OwnedItem( - not_null controller, + not_null delegate, not_null data) : _data(data) -, _view(_data->createView(controller, HistoryView::Context::AdminLog)) { +, _view(_data->createView(delegate)) { } OwnedItem::OwnedItem(OwnedItem &&other) @@ -309,7 +316,7 @@ OwnedItem::~OwnedItem() { } void GenerateItems( - not_null controller, + not_null delegate, not_null history, LocalIdManager &idManager, const MTPDchannelAdminLogEvent &event, @@ -322,7 +329,7 @@ void GenerateItems( auto &action = event.vaction; auto date = event.vdate; auto addPart = [&](not_null item) { - return callback(OwnedItem(controller, item)); + return callback(OwnedItem(delegate, item)); }; using Flag = MTPDmessage::Flag; diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_item.h b/Telegram/SourceFiles/history/admin_log/history_admin_log_item.h index 245f3b251..ed20f43fa 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_item.h +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_item.h @@ -7,11 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once -namespace Window { -class Controller; -} // namespace Window - namespace HistoryView { +class ElementDelegate; class Element; } // namespace HistoryView @@ -21,7 +18,7 @@ class OwnedItem; class LocalIdManager; void GenerateItems( - not_null controller, + not_null delegate, not_null history, LocalIdManager &idManager, const MTPDchannelAdminLogEvent &event, @@ -31,7 +28,7 @@ void GenerateItems( class OwnedItem { public: OwnedItem( - not_null controller, + not_null delegate, not_null data); OwnedItem(const OwnedItem &other) = delete; OwnedItem &operator=(const OwnedItem &other) = delete; diff --git a/Telegram/SourceFiles/history/feed/history_feed_section.cpp b/Telegram/SourceFiles/history/feed/history_feed_section.cpp index f46363c69..98ba8203e 100644 --- a/Telegram/SourceFiles/history/feed/history_feed_section.cpp +++ b/Telegram/SourceFiles/history/feed/history_feed_section.cpp @@ -10,6 +10,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/view/history_view_top_bar_widget.h" #include "history/view/history_view_list_widget.h" #include "history/view/history_view_element.h" +#include "history/view/history_view_message.h" +#include "history/view/history_view_service_message.h" #include "lang/lang_keys.h" #include "ui/widgets/buttons.h" #include "ui/widgets/shadow.h" @@ -162,6 +164,20 @@ rpl::producer Widget::listSource( limitAfter); } +std::unique_ptr Widget::elementCreate( + not_null message) { + return std::make_unique( + message, + HistoryView::Context::Feed); +} + +std::unique_ptr Widget::elementCreate( + not_null message) { + return std::make_unique( + message, + HistoryView::Context::Feed); +} + std::unique_ptr Widget::createMemento() { auto result = std::make_unique(_feed); saveState(result.get()); diff --git a/Telegram/SourceFiles/history/feed/history_feed_section.h b/Telegram/SourceFiles/history/feed/history_feed_section.h index c4964b304..1689349ec 100644 --- a/Telegram/SourceFiles/history/feed/history_feed_section.h +++ b/Telegram/SourceFiles/history/feed/history_feed_section.h @@ -67,6 +67,11 @@ public: int limitBefore, int limitAfter) override; + std::unique_ptr elementCreate( + not_null message) override; + std::unique_ptr elementCreate( + not_null message) override; + protected: void resizeEvent(QResizeEvent *e) override; void paintEvent(QPaintEvent *e) override; diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index 6c53d55d5..46c82848f 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_media_types.h" #include "history/history_service.h" #include "history/history_item_components.h" +#include "history/history_inner_widget.h" #include "dialogs/dialogs_indexed_list.h" #include "styles/style_dialogs.h" #include "data/data_drafts.h" @@ -59,7 +60,7 @@ History::History(const PeerId &peerId) , _sendActionText(st::dialogsTextWidthMin) { if (const auto user = peer->asUser()) { if (user->botInfo) { - outboxReadBefore = INT_MAX; + outboxReadBefore = std::numeric_limits::max(); } } } @@ -736,13 +737,26 @@ HistoryItem *History::createItem( const auto media = message.c_message().has_media() ? &message.c_message().vmedia : nullptr; - result->updateMedia(media); + result->updateSentMedia(media); } return result; } return HistoryItem::Create(this, message); } +std::vector> History::createItems( + const QVector &data) { + auto result = std::vector>(); + result.reserve(data.size()); + for (auto i = data.cend(), e = data.cbegin(); i != e;) { + const auto detachExistingItem = true; + if (const auto item = createItem(*--i, detachExistingItem)) { + result.push_back(item); + } + } + return result; +} + not_null History::createItemForwarded( MsgId id, MTPDmessage::Flags flags, @@ -1081,10 +1095,6 @@ not_null History::addNewItem( addItemToBlock(item); - const auto [groupFrom, groupTill] = recountGroupingFromTill(item->mainView()); - if (groupFrom != groupTill || groupFrom->data()->groupId()) { - recountGrouping(groupFrom, groupTill); - } if (!unread && IsServerMsgId(item->id)) { if (const auto sharedMediaTypes = item->sharedMediaTypes()) { auto from = loadedAtTop() ? 0 : minMsgId(); @@ -1308,7 +1318,7 @@ void History::applyServiceChanges( if (d.vphoto.type() == mtpc_photo) { auto &sizes = d.vphoto.c_photo().vsizes.v; if (!sizes.isEmpty()) { - auto photo = App::feedPhoto(d.vphoto.c_photo()); + auto photo = Auth().data().photo(d.vphoto.c_photo()); if (photo) photo->peer = peer; auto &smallSize = sizes.front(); auto &bigSize = sizes.back(); @@ -1446,8 +1456,7 @@ void History::addItemToBlock(not_null item) { auto block = prepareBlockForAddingItem(); block->messages.push_back(item->createView( - App::wnd()->controller(), - HistoryView::Context::History)); + HistoryInner::ElementDelegate())); const auto view = block->messages.back().get(); view->attachToBlock(block, block->messages.size() - 1); view->previousInBlocksChanged(); @@ -1457,21 +1466,16 @@ void History::addItemToBlock(not_null item) { } } -template -void History::addToSharedMedia( - std::vector (&medias)[kSharedMediaTypeCount], - bool force) { +void History::addEdgesToSharedMedia() { auto from = loadedAtTop() ? 0 : minMsgId(); auto till = loadedAtBottom() ? ServerMaxMsgId : maxMsgId(); for (auto i = 0; i != Storage::kSharedMediaTypeCount; ++i) { - if (force || !medias[i].empty()) { - auto type = static_cast(i); - Auth().storage().add(Storage::SharedMediaAddSlice( - peer->id, - type, - std::move(medias[i]), - { from, till })); - } + const auto type = static_cast(i); + Auth().storage().add(Storage::SharedMediaAddSlice( + peer->id, + type, + {}, + { from, till })); } } @@ -1492,119 +1496,40 @@ void History::addOlderSlice(const QVector &slice) { logged.push_back(QString::number(minMsgId())); logged.push_back(QString::number(maxMsgId())); - auto minAdded = -1; - auto maxAdded = -1; + if (const auto added = createItems(slice); !added.empty()) { + auto minAdded = -1; + auto maxAdded = -1; - startBuildingFrontBlock(slice.size()); - - for (auto i = slice.cend(), e = slice.cbegin(); i != e;) { - --i; - const auto detachExistingItem = true; - const auto adding = createItem(*i, detachExistingItem); - if (!adding) continue; - - if (!firstAdded) firstAdded = adding; - lastAdded = adding; - - if (minAdded < 0 || minAdded > adding->id) { - minAdded = adding->id; + startBuildingFrontBlock(added.size()); + for (const auto item : added) { + addItemToBlock(item); + if (minAdded < 0 || minAdded > item->id) { + minAdded = item->id; + } + if (maxAdded < 0 || maxAdded < item->id) { + maxAdded = item->id; + } } - if (maxAdded < 0 || maxAdded < adding->id) { - maxAdded = adding->id; + auto block = finishBuildingFrontBlock(); + + if (loadedAtBottom()) { + // Add photos to overview and authors to lastAuthors. + addItemsToLists(added); } - addItemToBlock(adding); - } + logged.push_back(QString::number(minAdded)); + logged.push_back(QString::number(maxAdded)); + CrashReports::SetAnnotation( + "old_minmaxwas_minmaxadd", + logged.join(";")); - auto block = finishBuildingFrontBlock(); - if (!block) { + addToSharedMedia(added); + + CrashReports::ClearAnnotation("old_minmaxwas_minmaxadd"); + } else { // If no items were added it means we've loaded everything old. oldLoaded = true; - } else if (loadedAtBottom()) { // add photos to overview and authors to lastAuthors - bool channel = isChannel(); - std::deque> *lastAuthors = nullptr; - base::flat_set> *markupSenders = nullptr; - if (peer->isChat()) { - lastAuthors = &peer->asChat()->lastAuthors; - markupSenders = &peer->asChat()->markupSenders; - } else if (peer->isMegagroup()) { - // We don't add users to mgInfo->lastParticipants here. - // We're scrolling back and we see messages from users that - // could be gone from the megagroup already. It is fine for - // chat->lastAuthors, because they're used only for field - // autocomplete, but this is bad for megagroups, because its - // lastParticipants are displayed in Profile as members list. - markupSenders = &peer->asChannel()->mgInfo->markupSenders; - } - for (auto i = block->messages.size(); i > 0; --i) { - const auto item = block->messages[i - 1]->data(); - item->addToUnreadMentions(UnreadMentionType::Existing); - if (item->from()->id) { - if (lastAuthors) { // chats - if (auto user = item->from()->asUser()) { - if (!base::contains(*lastAuthors, user)) { - lastAuthors->push_back(user); - } - } - } - } - if (item->author()->id) { - if (markupSenders) { // chats with bots - if (!lastKeyboardInited && item->definesReplyKeyboard() && !item->out()) { - auto markupFlags = item->replyKeyboardFlags(); - if (!(markupFlags & MTPDreplyKeyboardMarkup::Flag::f_selective) || item->mentionsMe()) { - bool wasKeyboardHide = markupSenders->contains(item->author()); - if (!wasKeyboardHide) { - markupSenders->insert(item->author()); - } - if (!(markupFlags & MTPDreplyKeyboardMarkup_ClientFlag::f_zero)) { - if (!lastKeyboardInited) { - bool botNotInChat = false; - if (peer->isChat()) { - botNotInChat = (!peer->canWrite() || !peer->asChat()->participants.empty()) && item->author()->isUser() && !peer->asChat()->participants.contains(item->author()->asUser()); - } else if (peer->isMegagroup()) { - botNotInChat = (!peer->canWrite() || peer->asChannel()->mgInfo->botStatus != 0) && item->author()->isUser() && !peer->asChannel()->mgInfo->bots.contains(item->author()->asUser()); - } - if (wasKeyboardHide || botNotInChat) { - clearLastKeyboard(); - } else { - lastKeyboardInited = true; - lastKeyboardId = item->id; - lastKeyboardFrom = item->author()->id; - lastKeyboardUsed = false; - } - } - } - } - } - } else if (!lastKeyboardInited && item->definesReplyKeyboard() && !item->out()) { // conversations with bots - MTPDreplyKeyboardMarkup::Flags markupFlags = item->replyKeyboardFlags(); - if (!(markupFlags & MTPDreplyKeyboardMarkup::Flag::f_selective) || item->mentionsMe()) { - if (markupFlags & MTPDreplyKeyboardMarkup_ClientFlag::f_zero) { - clearLastKeyboard(); - } else { - lastKeyboardInited = true; - lastKeyboardId = item->id; - lastKeyboardFrom = item->author()->id; - lastKeyboardUsed = false; - } - } - } - } - } - } - - logged.push_back(QString::number(minAdded)); - logged.push_back(QString::number(maxAdded)); - CrashReports::SetAnnotation("old_minmaxwas_minmaxadd", logged.join(";")); - - addBlockToSharedMedia(block); - - CrashReports::ClearAnnotation("old_minmaxwas_minmaxadd"); - - if (lastAdded) { - const auto [from, till] = recountGroupingFromTill(lastAdded->mainView()); - recountGrouping(firstAdded->mainView(), till); + addEdgesToSharedMedia(); } if (isChannel()) { @@ -1624,11 +1549,9 @@ void History::addNewerSlice(const QVector &slice) { } } - auto firstAdded = (HistoryItem*)nullptr; - auto lastAdded = (HistoryItem*)nullptr; + if (const auto added = createItems(slice); !added.empty()) { + Assert(!isBuildingFrontBlock()); - Assert(!isBuildingFrontBlock()); - if (!slice.isEmpty()) { auto logged = QStringList(); logged.push_back(QString::number(minMsgId())); logged.push_back(QString::number(maxMsgId())); @@ -1636,58 +1559,35 @@ void History::addNewerSlice(const QVector &slice) { auto minAdded = -1; auto maxAdded = -1; - std::vector medias[Storage::kSharedMediaTypeCount]; - for (auto i = slice.cend(), e = slice.cbegin(); i != e;) { - --i; - const auto detachExistingItem = true; - const auto adding = createItem(*i, detachExistingItem); - if (!adding) continue; - - if (!firstAdded) firstAdded = adding; - lastAdded = adding; - - if (minAdded < 0 || minAdded > adding->id) { - minAdded = adding->id; + for (const auto item : added) { + addItemToBlock(item); + if (minAdded < 0 || minAdded > item->id) { + minAdded = item->id; } - if (maxAdded < 0 || maxAdded < adding->id) { - maxAdded = adding->id; - } - - addItemToBlock(adding); - if (auto types = adding->sharedMediaTypes()) { - for (auto i = 0; i != Storage::kSharedMediaTypeCount; ++i) { - auto type = static_cast(i); - if (types.test(type)) { - if (medias[i].empty()) { - medias[i].reserve(slice.size()); - } - medias[i].push_back(adding->id); - } - } + if (maxAdded < 0 || maxAdded < item->id) { + maxAdded = item->id; } } + logged.push_back(QString::number(minAdded)); logged.push_back(QString::number(maxAdded)); - CrashReports::SetAnnotation("new_minmaxwas_minmaxadd", logged.join(";")); + CrashReports::SetAnnotation( + "new_minmaxwas_minmaxadd", + logged.join(";")); - if (!firstAdded) { - newLoaded = true; - setLastMessage(lastAvailableMessage()); - } - addToSharedMedia(medias, wasLoadedAtBottom != loadedAtBottom()); + addToSharedMedia(added); CrashReports::ClearAnnotation("new_minmaxwas_minmaxadd"); + } else { + newLoaded = true; + setLastMessage(lastAvailableMessage()); + addEdgesToSharedMedia(); } if (!wasLoadedAtBottom) { checkAddAllToUnreadMentions(); } - if (firstAdded) { - const auto [from, till] = recountGroupingFromTill(firstAdded->mainView()); - recountGrouping(from, lastAdded->mainView()); - } - if (isChannel()) asChannelHistory()->checkJoinedMessage(); checkLastMsg(); } @@ -1703,6 +1603,80 @@ void History::checkLastMsg() { } } +void History::addItemsToLists( + const std::vector> &items) { + std::deque> *lastAuthors = nullptr; + base::flat_set> *markupSenders = nullptr; + if (peer->isChat()) { + lastAuthors = &peer->asChat()->lastAuthors; + markupSenders = &peer->asChat()->markupSenders; + } else if (peer->isMegagroup()) { + // We don't add users to mgInfo->lastParticipants here. + // We're scrolling back and we see messages from users that + // could be gone from the megagroup already. It is fine for + // chat->lastAuthors, because they're used only for field + // autocomplete, but this is bad for megagroups, because its + // lastParticipants are displayed in Profile as members list. + markupSenders = &peer->asChannel()->mgInfo->markupSenders; + } + for (const auto item : base::reversed(items)) { + item->addToUnreadMentions(UnreadMentionType::Existing); + if (item->from()->id) { + if (lastAuthors) { // chats + if (auto user = item->from()->asUser()) { + if (!base::contains(*lastAuthors, user)) { + lastAuthors->push_back(user); + } + } + } + } + if (item->author()->id) { + if (markupSenders) { // chats with bots + if (!lastKeyboardInited && item->definesReplyKeyboard() && !item->out()) { + auto markupFlags = item->replyKeyboardFlags(); + if (!(markupFlags & MTPDreplyKeyboardMarkup::Flag::f_selective) || item->mentionsMe()) { + bool wasKeyboardHide = markupSenders->contains(item->author()); + if (!wasKeyboardHide) { + markupSenders->insert(item->author()); + } + if (!(markupFlags & MTPDreplyKeyboardMarkup_ClientFlag::f_zero)) { + if (!lastKeyboardInited) { + bool botNotInChat = false; + if (peer->isChat()) { + botNotInChat = (!peer->canWrite() || !peer->asChat()->participants.empty()) && item->author()->isUser() && !peer->asChat()->participants.contains(item->author()->asUser()); + } else if (peer->isMegagroup()) { + botNotInChat = (!peer->canWrite() || peer->asChannel()->mgInfo->botStatus != 0) && item->author()->isUser() && !peer->asChannel()->mgInfo->bots.contains(item->author()->asUser()); + } + if (wasKeyboardHide || botNotInChat) { + clearLastKeyboard(); + } else { + lastKeyboardInited = true; + lastKeyboardId = item->id; + lastKeyboardFrom = item->author()->id; + lastKeyboardUsed = false; + } + } + } + } + } + } else if (!lastKeyboardInited && item->definesReplyKeyboard() && !item->out()) { // conversations with bots + MTPDreplyKeyboardMarkup::Flags markupFlags = item->replyKeyboardFlags(); + if (!(markupFlags & MTPDreplyKeyboardMarkup::Flag::f_selective) || item->mentionsMe()) { + if (markupFlags & MTPDreplyKeyboardMarkup_ClientFlag::f_zero) { + clearLastKeyboard(); + } else { + lastKeyboardInited = true; + lastKeyboardId = item->id; + lastKeyboardFrom = item->author()->id; + lastKeyboardUsed = false; + } + } + } + } + } + +} + void History::checkAddAllToUnreadMentions() { if (!loadedAtBottom()) { return; @@ -1716,25 +1690,34 @@ void History::checkAddAllToUnreadMentions() { } } -void History::addBlockToSharedMedia(HistoryBlock *block) { +void History::addToSharedMedia( + const std::vector> &items) { std::vector medias[Storage::kSharedMediaTypeCount]; - if (block) { - for (const auto &message : block->messages) { - const auto item = message->data(); - if (auto types = item->sharedMediaTypes()) { - for (auto i = 0; i != Storage::kSharedMediaTypeCount; ++i) { - auto type = static_cast(i); - if (types.test(type)) { - if (medias[i].empty()) { - medias[i].reserve(block->messages.size()); - } - medias[i].push_back(item->id); + for (const auto item : items) { + if (const auto types = item->sharedMediaTypes()) { + for (auto i = 0; i != Storage::kSharedMediaTypeCount; ++i) { + const auto type = static_cast(i); + if (types.test(type)) { + if (medias[i].empty()) { + medias[i].reserve(items.size()); } + medias[i].push_back(item->id); } } } } - addToSharedMedia(medias, !block); + const auto from = loadedAtTop() ? 0 : minMsgId(); + const auto till = loadedAtBottom() ? ServerMaxMsgId : maxMsgId(); + for (auto i = 0; i != Storage::kSharedMediaTypeCount; ++i) { + if (!medias[i].empty()) { + const auto type = static_cast(i); + Auth().storage().add(Storage::SharedMediaAddSlice( + peer->id, + type, + std::move(medias[i]), + { from, till })); + } + } } int History::countUnread(MsgId upTo) { @@ -2026,8 +2009,7 @@ not_null History::addNewInTheMiddle( const auto it = block->messages.insert( block->messages.begin() + itemIndex, item->createView( - App::wnd()->controller(), - HistoryView::Context::History)); + HistoryInner::ElementDelegate())); (*it)->attachToBlock(block.get(), itemIndex); (*it)->previousInBlocksChanged(); if (itemIndex + 1 < block->messages.size()) { @@ -2041,70 +2023,65 @@ not_null History::addNewInTheMiddle( (*it)->nextInBlocksChanged(); } - const auto [groupFrom, groupTill] = recountGroupingFromTill(item->mainView()); - if (groupFrom != groupTill || groupFrom->data()->groupId()) { - recountGrouping(groupFrom, groupTill); - } - return item; } - -HistoryView::Element *History::findNextItem( - not_null view) const { - const auto nextBlockIndex = view->block()->indexInHistory() + 1; - const auto nextItemIndex = view->indexInBlock() + 1; - if (nextItemIndex < int(view->block()->messages.size())) { - return view->block()->messages[nextItemIndex].get(); - } else if (nextBlockIndex < int(blocks.size())) { - return blocks[nextBlockIndex]->messages.front().get(); - } - return nullptr; -} - -HistoryView::Element *History::findPreviousItem( - not_null view) const { - const auto blockIndex = view->block()->indexInHistory(); - const auto itemIndex = view->indexInBlock(); - if (itemIndex > 0) { - return view->block()->messages[itemIndex - 1].get(); - } else if (blockIndex > 0) { - return blocks[blockIndex - 1]->messages.back().get(); - } - return nullptr; -} - -not_null History::findGroupFirst( - not_null view) const { - const auto group = view->Get(); - Assert(group != nullptr); - Assert(group->leader != nullptr); - - const auto leaderGroup = (group->leader == view) - ? group - : group->leader->Get(); - Assert(leaderGroup != nullptr); - - return leaderGroup->others.empty() - ? group->leader - : leaderGroup->others.front().get(); -} - -not_null History::findGroupLast( - not_null view) const { - const auto group = view->Get(); - Assert(group != nullptr); - - return group->leader; -} - -void History::recountGroupingAround(not_null item) { - Expects(item->history() == this); - - if (item->mainView() && item->groupId()) { - const auto [groupFrom, groupTill] = recountGroupingFromTill(item->mainView()); - recountGrouping(groupFrom, groupTill); - } -} +// +//HistoryView::Element *History::findNextItem( +// not_null view) const { +// const auto nextBlockIndex = view->block()->indexInHistory() + 1; +// const auto nextItemIndex = view->indexInBlock() + 1; +// if (nextItemIndex < int(view->block()->messages.size())) { +// return view->block()->messages[nextItemIndex].get(); +// } else if (nextBlockIndex < int(blocks.size())) { +// return blocks[nextBlockIndex]->messages.front().get(); +// } +// return nullptr; +//} +// +//HistoryView::Element *History::findPreviousItem( +// not_null view) const { +// const auto blockIndex = view->block()->indexInHistory(); +// const auto itemIndex = view->indexInBlock(); +// if (itemIndex > 0) { +// return view->block()->messages[itemIndex - 1].get(); +// } else if (blockIndex > 0) { +// return blocks[blockIndex - 1]->messages.back().get(); +// } +// return nullptr; +//} +// +//not_null History::findGroupFirst( +// not_null view) const { +// const auto group = view->Get(); +// Assert(group != nullptr); +// Assert(group->leader != nullptr); +// +// const auto leaderGroup = (group->leader == view) +// ? group +// : group->leader->Get(); +// Assert(leaderGroup != nullptr); +// +// return leaderGroup->others.empty() +// ? group->leader +// : leaderGroup->others.front().get(); +//} +// +//not_null History::findGroupLast( +// not_null view) const { +// const auto group = view->Get(); +// Assert(group != nullptr); +// +// return group->leader; +//} +// +//void History::recountGroupingAround(not_null item) { +// Expects(item->history() == this); +// +// if (item->mainView() && item->groupId()) { +// const auto [groupFrom, groupTill] = recountGroupingFromTill(item->mainView()); +// recountGrouping(groupFrom, groupTill); +// } +//} int History::chatListUnreadCount() const { const auto result = unreadCount(); @@ -2135,65 +2112,65 @@ void History::paintUserpic( int size) const { peer->paintUserpic(p, x, y, size); } - -auto History::recountGroupingFromTill(not_null view) --> std::pair, not_null> { - const auto recountFromItem = [&] { - if (const auto prev = findPreviousItem(view)) { - if (prev->data()->groupId()) { - return findGroupFirst(prev); - } - } - return view; - }(); - if (recountFromItem == view && !view->data()->groupId()) { - return { view, view }; - } - const auto recountTillItem = [&] { - if (const auto next = findNextItem(view)) { - if (next->data()->groupId()) { - return findGroupLast(next); - } - } - return view; - }(); - return { recountFromItem, recountTillItem }; -} - -void History::recountGrouping( - not_null from, - not_null till) { - from->validateGroupId(); - auto others = std::vector>(); - auto currentGroupId = from->data()->groupId(); - auto prev = from; - while (prev != till) { - auto item = findNextItem(prev); - item->validateGroupId(); - const auto groupId = item->data()->groupId(); - if (currentGroupId) { - if (groupId == currentGroupId) { - others.push_back(prev); - } else { - for (const auto other : others) { - other->makeGroupMember(prev); - } - prev->makeGroupLeader(base::take(others)); - currentGroupId = groupId; - } - } else if (groupId) { - currentGroupId = groupId; - } - prev = item; - } - - if (currentGroupId) { - for (const auto other : others) { - other->makeGroupMember(prev); - } - till->makeGroupLeader(base::take(others)); - } -} +// +//auto History::recountGroupingFromTill(not_null view) +//-> std::pair, not_null> { +// const auto recountFromItem = [&] { +// if (const auto prev = findPreviousItem(view)) { +// if (prev->data()->groupId()) { +// return findGroupFirst(prev); +// } +// } +// return view; +// }(); +// if (recountFromItem == view && !view->data()->groupId()) { +// return { view, view }; +// } +// const auto recountTillItem = [&] { +// if (const auto next = findNextItem(view)) { +// if (next->data()->groupId()) { +// return findGroupLast(next); +// } +// } +// return view; +// }(); +// return { recountFromItem, recountTillItem }; +//} +// +//void History::recountGrouping( +// not_null from, +// not_null till) { +// from->validateGroupId(); +// auto others = std::vector>(); +// auto currentGroupId = from->data()->groupId(); +// auto prev = from; +// while (prev != till) { +// auto item = findNextItem(prev); +// item->validateGroupId(); +// const auto groupId = item->data()->groupId(); +// if (currentGroupId) { +// if (groupId == currentGroupId) { +// others.push_back(prev); +// } else { +// for (const auto other : others) { +// other->makeGroupMember(prev); +// } +// prev->makeGroupLeader(base::take(others)); +// currentGroupId = groupId; +// } +// } else if (groupId) { +// currentGroupId = groupId; +// } +// prev = item; +// } +// +// if (currentGroupId) { +// for (const auto other : others) { +// other->makeGroupMember(prev); +// } +// till->makeGroupLeader(base::take(others)); +// } +//} void History::startBuildingFrontBlock(int expectedItemsCount) { Assert(!isBuildingFrontBlock()); @@ -2451,14 +2428,6 @@ void History::clear(bool leaveItems) { } else { setLastMessage(nullptr); notifies.clear(); - auto &pending = Global::RefPendingRepaintItems(); - for (auto i = pending.begin(); i != pending.end();) { - if ((*i)->history() == this) { - i = pending.erase(i); - } else { - ++i; - } - } Auth().storage().remove(Storage::SharedMediaRemoveAll(peer->id)); Auth().data().markHistoryCleared(this); } @@ -2621,18 +2590,6 @@ void HistoryBlock::clear(bool leaveItems) { void HistoryBlock::remove(not_null view) { Expects(view->block() == this); - auto [groupFrom, groupTill] = _history->recountGroupingFromTill(view); - const auto groupHistory = _history; - const auto needGroupRecount = (groupFrom != groupTill); - if (needGroupRecount) { - if (groupFrom == view) { - groupFrom = groupHistory->findNextItem(groupFrom); - } - if (groupTill == view) { - groupTill = groupHistory->findPreviousItem(groupTill); - } - } - const auto item = view->data(); auto blockIndex = indexInHistory(); auto itemIndex = view->indexInBlock(); @@ -2664,10 +2621,6 @@ void HistoryBlock::remove(not_null view) { } else if (!_history->blocks.empty() && !_history->blocks.back()->messages.empty()) { _history->blocks.back()->messages.back()->nextInBlocksChanged(); } - - if (needGroupRecount) { - groupHistory->recountGrouping(groupFrom, groupTill); - } } HistoryBlock::~HistoryBlock() { diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h index 12c7b75a8..186ba1fc3 100644 --- a/Telegram/SourceFiles/history/history.h +++ b/Telegram/SourceFiles/history/history.h @@ -167,6 +167,8 @@ public: HistoryItem *createItem( const MTPMessage &message, bool detachExistingItem); + std::vector> createItems( + const QVector &data); void addOlderSlice(const QVector &slice); void addNewerSlice(const QVector &slice); @@ -448,8 +450,10 @@ private: template void addToSharedMedia(std::vector (&medias)[kSharedMediaTypeCount], bool force); - void addBlockToSharedMedia(HistoryBlock *block); + void addToSharedMedia(const std::vector> &items); + void addEdgesToSharedMedia(); + void addItemsToLists(const std::vector> &items); void clearSendAction(not_null from); HistoryView::Element *findPreviousItem( diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 57fd50d10..c4c86db42 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -14,8 +14,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_message.h" #include "history/history_media_types.h" #include "history/history_item_components.h" +#include "history/view/history_view_message.h" #include "history/view/history_view_service_message.h" -#include "history/view/history_view_element.h" #include "ui/text_options.h" #include "ui/widgets/popup_menu.h" #include "window/window_controller.h" @@ -414,31 +414,31 @@ TextSelection HistoryInner::computeRenderSelection( } return TextSelection(); }; - const auto group = view->Get(); - if (group) { - if (group->leader != view) { - return TextSelection(); - } - auto result = TextSelection(); - auto allFullSelected = true; - const auto count = int(group->others.size()); - for (auto i = 0; i != count; ++i) { - if (itemSelection(group->others[i]->data()) == FullSelection) { - result = AddGroupItemSelection(result, i); - } else { - allFullSelected = false; - } - } - const auto leaderSelection = itemSelection(view->data()); - if (leaderSelection == FullSelection) { - return allFullSelected - ? FullSelection - : AddGroupItemSelection(result, count); - } else if (leaderSelection != TextSelection()) { - return leaderSelection; - } - return result; - } + // #TODO group selection + //if (const auto group = view->Get()) { + // if (group->leader != view) { + // return TextSelection(); + // } + // auto result = TextSelection(); + // auto allFullSelected = true; + // const auto count = int(group->others.size()); + // for (auto i = 0; i != count; ++i) { + // if (itemSelection(group->others[i]->data()) == FullSelection) { + // result = AddGroupItemSelection(result, i); + // } else { + // allFullSelected = false; + // } + // } + // const auto leaderSelection = itemSelection(view->data()); + // if (leaderSelection == FullSelection) { + // return allFullSelected + // ? FullSelection + // : AddGroupItemSelection(result, count); + // } else if (leaderSelection != TextSelection()) { + // return leaderSelection; + // } + // return result; + //} return itemSelection(view->data()); } @@ -597,7 +597,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) { } if (!readMentions.empty() && App::wnd()->doWeReadMentions()) { - App::main()->mediaMarkRead(readMentions); + Auth().api().markMediaRead(readMentions); } if (mtop >= 0 || htop >= 0) { @@ -1697,9 +1697,8 @@ void HistoryInner::saveContextGif(FullMsgId itemId) { void HistoryInner::copyContextText(FullMsgId itemId) { if (const auto item = App::histItemById(itemId)) { if (const auto view = item->mainView()) { - const auto group = view->getFullGroup(); - const auto leader = group ? group->leader : view; - setToClipboard(leader->selectedText(FullSelection)); + // #TODO check for a group + setToClipboard(view->selectedText(FullSelection)); } } } @@ -1764,24 +1763,25 @@ TextWithEntities HistoryInner::getSelectedText() const { continue; } - if (const auto group = view->getFullGroup()) { - if (groupLeadersAdded.contains(group->leader)) { - continue; - } - const auto leaderSelection = computeRenderSelection( - &selected, - group->leader); - if (leaderSelection == FullSelection) { - groupLeadersAdded.emplace(group->leader); - addItem(group->leader, FullSelection); - } else if (view == group->leader) { - const auto leaderFullSelection = AddGroupItemSelection( - TextSelection(), - int(group->others.size())); - addItem(view, leaderFullSelection); - } else { - addItem(view, FullSelection); - } + if (const auto group = Auth().data().groups().find(item)) { + // #TODO group copy + //if (groupLeadersAdded.contains(group->leader)) { + // continue; + //} + //const auto leaderSelection = computeRenderSelection( + // &selected, + // group->leader); + //if (leaderSelection == FullSelection) { + // groupLeadersAdded.emplace(group->leader); + // addItem(group->leader, FullSelection); + //} else if (view == group->leader) { + // const auto leaderFullSelection = AddGroupItemSelection( + // TextSelection(), + // int(group->others.size())); + // addItem(view, leaderFullSelection); + //} else { + // addItem(view, FullSelection); + //} } else { addItem(view, FullSelection); } @@ -2901,3 +2901,24 @@ void HistoryInner::onParentGeometryChanged() { mouseActionUpdate(mousePos); } } + +not_null HistoryInner::ElementDelegate() { + class Result : public HistoryView::ElementDelegate { + public: + std::unique_ptr elementCreate( + not_null message) override { + return std::make_unique( + message, + HistoryView::Context::History); + } + std::unique_ptr elementCreate( + not_null message) override { + return std::make_unique( + message, + HistoryView::Context::History); + } + + }; + static Result result; + return &result; +} diff --git a/Telegram/SourceFiles/history/history_inner_widget.h b/Telegram/SourceFiles/history/history_inner_widget.h index 220490db5..759993f10 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.h +++ b/Telegram/SourceFiles/history/history_inner_widget.h @@ -13,6 +13,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/view/history_view_cursor_state.h" #include "history/view/history_view_top_bar_widget.h" +namespace HistoryView { +class ElementDelegate; +} // namespace HistoryView + namespace Window { class Controller; } // namespace Window @@ -83,10 +87,13 @@ public: // to move scroll position so that mouse points to the same button row. int moveScrollFollowingInlineKeyboard(const HistoryItem *item, int oldKeyboardTop, int newKeyboardTop); - // AbstractTooltipShower interface + // Ui::AbstractTooltipShower interface. QString tooltipText() const override; QPoint tooltipPos() const override; + // HistoryView::ElementDelegate interface. + static not_null ElementDelegate(); + ~HistoryInner(); protected: diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index f5293a7f6..ba45ddcc5 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -110,7 +110,8 @@ void HistoryItem::finishEdition(int oldKeyboardTop) { } void HistoryItem::setGroupId(MessageGroupId groupId) { - Auth().data().groups().unregisterMessage(this); + Expects(!_groupId); + _groupId = groupId; Auth().data().groups().registerMessage(this); } @@ -218,7 +219,7 @@ void HistoryItem::addLogEntryOriginal( Expects(isLogEntry()); AddComponents(HistoryMessageLogEntryOriginal::Bit()); - Get()->page = App::feedWebPage( + Get()->page = Auth().data().webpage( localId, label, content); @@ -286,7 +287,6 @@ void HistoryItem::destroy() { } } } - Global::RefPendingRepaintItems().remove(this); delete this; } @@ -339,7 +339,7 @@ void HistoryItem::setRealId(MsgId newId) { } Auth().data().markItemIdChange({ this, oldId }); - Auth().data().requestItemRepaint(this); + Auth().data().requestItemViewRepaint(this); } bool HistoryItem::isPinned() const { @@ -585,21 +585,17 @@ void HistoryItem::setUnreadBarCount(int count) { Expects(!isLogEntry()); if (count > 0) { - HistoryMessageUnreadBar *bar; if (!Has()) { AddComponents(HistoryMessageUnreadBar::Bit()); Auth().data().requestItemViewResize(this); // #TODO recount attach to previous - - bar = Get(); - } else { - bar = Get(); - if (bar->_freezed) { - return; - } - Global::RefPendingRepaintItems().insert(this); + } + const auto bar = Get(); + if (bar->_freezed) { + return; } bar->init(count); + Auth().data().requestItemViewRepaint(this); } else { destroyUnreadBar(); } @@ -668,13 +664,12 @@ void HistoryItem::clipCallback(Media::Clip::Notification notification) { // if (!stopped) { // Auth().data().requestItemViewResize(this); // Auth().data().markItemLayoutChange(this); - // Global::RefPendingRepaintItems().insert(this); // } //} break; //case NotificationRepaint: { // if (!reader->currentDisplayed()) { - // Auth().data().requestItemRepaint(this); + // Auth().data().requestItemViewRepaint(this); // } //} break; //} diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index cec76382e..09ab8720f 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -10,7 +10,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/runtime_composer.h" #include "base/flags.h" #include "base/value_ordering.h" -#include "history/history_media_pointer.h" #include "history/view/history_view_cursor_state.h" enum class UnreadMentionType; @@ -49,6 +48,7 @@ class Controller; namespace HistoryView { enum class Context : char; +class ElementDelegate; } // namespace HistoryView class HistoryItem : public RuntimeComposer { @@ -148,7 +148,7 @@ public: } virtual void applyEdition(const MTPDmessageService &message) { } - virtual void updateMedia(const MTPMessageMedia *media) { + virtual void updateSentMedia(const MTPMessageMedia *media) { } virtual void updateReplyMarkup(const MTPReplyMarkup *markup) { } @@ -272,8 +272,7 @@ public: HistoryItem *nextItem() const; virtual std::unique_ptr createView( - not_null controller, - HistoryView::Context context) = 0; + not_null delegate) = 0; virtual ~HistoryItem(); diff --git a/Telegram/SourceFiles/history/history_item_components.cpp b/Telegram/SourceFiles/history/history_item_components.cpp index 0913bf5d4..7481f5765 100644 --- a/Telegram/SourceFiles/history/history_item_components.cpp +++ b/Telegram/SourceFiles/history/history_item_components.cpp @@ -562,11 +562,13 @@ ReplyKeyboard::ButtonCoords ReplyKeyboard::findButtonCoordsByClickHandler(const return { -1, -1 }; } -void ReplyKeyboard::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) { - if (!p) return; +void ReplyKeyboard::clickHandlerPressedChanged( + const ClickHandlerPtr &handler, + bool pressed) { + if (!handler) return; - _savedPressed = pressed ? p : ClickHandlerPtr(); - auto coords = findButtonCoordsByClickHandler(p); + _savedPressed = pressed ? handler : ClickHandlerPtr(); + auto coords = findButtonCoordsByClickHandler(handler); if (coords.i >= 0) { auto &button = _rows[coords.i][coords.j]; if (pressed) { @@ -584,7 +586,7 @@ void ReplyKeyboard::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pr if (button.ripple) { button.ripple->lastStop(); } - if (_savedActive != p) { + if (_savedActive != handler) { startAnimation(coords.i, coords.j, -1); } } diff --git a/Telegram/SourceFiles/history/history_media.cpp b/Telegram/SourceFiles/history/history_media.cpp index 00440f022..1d8d4af6e 100644 --- a/Telegram/SourceFiles/history/history_media.cpp +++ b/Telegram/SourceFiles/history/history_media.cpp @@ -16,7 +16,7 @@ Storage::SharedMediaTypesMask HistoryMedia::sharedMediaTypes() const { } bool HistoryMedia::isDisplayed() const { - return !_parent->isHiddenByGroup(); + return true; } QSize HistoryMedia::countCurrentSize(int newWidth) { diff --git a/Telegram/SourceFiles/history/history_media.h b/Telegram/SourceFiles/history/history_media.h index 738e30c12..4ba597038 100644 --- a/Telegram/SourceFiles/history/history_media.h +++ b/Telegram/SourceFiles/history/history_media.h @@ -58,11 +58,6 @@ public: } virtual HistoryMediaType type() const = 0; - virtual std::unique_ptr clone( - not_null newParent, - not_null realParent) const { - Unexpected("Attempt to clone a media that can't be grouped."); - } virtual TextWithEntities selectedText(TextSelection selection) const = 0; @@ -82,7 +77,7 @@ public: virtual bool allowsFastShare() const { return false; } - virtual void refreshParentId(not_null realParent) { + virtual void refreshParentId(not_null realParent) { } virtual void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const = 0; virtual HistoryTextState getState(QPoint point, HistoryStateRequest request) const = 0; @@ -148,14 +143,6 @@ public: return false; } - virtual void attachToParent() { - } - virtual void detachFromParent() { - } - - virtual bool canBeGrouped() const { - return false; - } virtual QSize sizeForGrouping() const { Unexpected("Grouping method call."); } @@ -177,8 +164,9 @@ public: virtual std::unique_ptr takeLastFromGroup() { return nullptr; } - virtual bool applyGroup(const std::vector> &others) { - return others.empty(); + virtual bool applyGroup( + const std::vector> &items) { + return false; } virtual bool animating() const { @@ -242,6 +230,10 @@ public: return true; } + // Should be called only by Data::Session. + virtual void updateSharedContactUserId(UserId userId) { + } + virtual ~HistoryMedia() = default; protected: diff --git a/Telegram/SourceFiles/history/history_media_grouped.cpp b/Telegram/SourceFiles/history/history_media_grouped.cpp index 66b8e3471..43bf630c1 100644 --- a/Telegram/SourceFiles/history/history_media_grouped.cpp +++ b/Telegram/SourceFiles/history/history_media_grouped.cpp @@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_media_types.h" #include "history/history_message.h" #include "history/view/history_view_element.h" +#include "data/data_media_types.h" #include "storage/storage_shared_media.h" #include "lang/lang_keys.h" #include "ui/grouped_layout.h" @@ -18,16 +19,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/style_history.h" #include "layout.h" -HistoryGroupedMedia::Part::Part(not_null view) -: view(view) { +HistoryGroupedMedia::Part::Part(not_null item) +: item(item) { } HistoryGroupedMedia::HistoryGroupedMedia( not_null parent, - const std::vector> &others) + const std::vector> &items) : HistoryMedia(parent) , _caption(st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right()) { - const auto result = applyGroup(others); + const auto result = applyGroup(items); Ensures(result); } @@ -124,9 +125,10 @@ QSize HistoryGroupedMedia::countCurrentSize(int newWidth) { return { newWidth, newHeight }; } -void HistoryGroupedMedia::refreshParentId(not_null realParent) { +void HistoryGroupedMedia::refreshParentId( + not_null realParent) { for (const auto &part : _parts) { - part.content->refreshParentId(part.view); + part.content->refreshParentId(part.item); } } @@ -193,7 +195,7 @@ HistoryTextState HistoryGroupedMedia::getPartState( part.geometry, point, request); - result.itemId = part.view->data()->fullId(); + result.itemId = part.item->fullId(); return result; } } @@ -284,21 +286,8 @@ void HistoryGroupedMedia::clickHandlerPressedChanged( for (const auto &part : _parts) { part.content->clickHandlerPressedChanged(p, pressed); if (pressed && part.content->dragItemByHandler(p)) { - App::pressedLinkItem(part.view); - } - } -} - -void HistoryGroupedMedia::attachToParent() { - for (const auto &part : _parts) { - part.content->attachToParent(); - } -} - -void HistoryGroupedMedia::detachFromParent() { - for (const auto &part : _parts) { - if (part.content) { - part.content->detachFromParent(); + // #TODO drag by item from album + // App::pressedLinkItem(part.view); } } } @@ -308,42 +297,32 @@ std::unique_ptr HistoryGroupedMedia::takeLastFromGroup() { } bool HistoryGroupedMedia::applyGroup( - const std::vector> &others) { - if (others.empty()) { + const std::vector> &items) { + if (items.empty()) { return false; } - const auto pushElement = [&](not_null view) { - const auto media = view->media(); - Assert(media != nullptr && media->canBeGrouped()); - - _parts.push_back(Part(view)); - _parts.back().content = media->clone(_parent, view); - }; - if (_parts.empty()) { - pushElement(_parent); - } else if (validateGroupParts(others)) { + if (validateGroupParts(items)) { return true; } - // We're updating other elements, so we just need to preserve the main. - auto mainPart = std::move(_parts.back()); - _parts.erase(_parts.begin(), _parts.end()); - _parts.reserve(others.size() + 1); - for (const auto view : others) { - pushElement(view); - } - _parts.push_back(std::move(mainPart)); - //_parent->setPendingInitDimensions(); // #TODO group view + const auto pushElement = [&](not_null item) { + const auto media = item->media(); + Assert(media != nullptr && media->canBeGrouped()); + + _parts.push_back(Part(item)); + _parts.back().content = media->createView(_parent, item); + }; + ranges::for_each(items, pushElement); return true; } bool HistoryGroupedMedia::validateGroupParts( - const std::vector> &others) const { - if (_parts.size() != others.size() + 1) { + const std::vector> &items) const { + if (_parts.size() != items.size()) { return false; } - for (auto i = 0, count = int(others.size()); i != count; ++i) { - if (_parts[i].view != others[i]) { + for (auto i = 0, count = int(items.size()); i != count; ++i) { + if (_parts[i].item != items[i]) { return false; } } @@ -382,15 +361,16 @@ DocumentData *HistoryGroupedMedia::getDocument() const { HistoryMessageEdited *HistoryGroupedMedia::displayedEditBadge() const { if (!_caption.isEmpty()) { - return _parts.front().view->data()->Get(); + return _parts.front().item->Get(); } return nullptr; } void HistoryGroupedMedia::updateNeedBubbleState() { const auto getItemCaption = [](const Part &part) { - if (const auto media = part.view->media()) { - return media->getCaption(); + if (const auto media = part.item->media()) { + return TextWithEntities{ media->caption(), EntitiesInText() }; + // #TODO group caption } return part.content->getCaption(); }; diff --git a/Telegram/SourceFiles/history/history_media_grouped.h b/Telegram/SourceFiles/history/history_media_grouped.h index ef02d87be..8abd0ecc0 100644 --- a/Telegram/SourceFiles/history/history_media_grouped.h +++ b/Telegram/SourceFiles/history/history_media_grouped.h @@ -15,13 +15,13 @@ class HistoryGroupedMedia : public HistoryMedia { public: HistoryGroupedMedia( not_null parent, - const std::vector> &others); + const std::vector> &items); HistoryMediaType type() const override { return MediaTypeGrouped; } - void refreshParentId(not_null realParent) override; + void refreshParentId(not_null realParent) override; void draw( Painter &p, @@ -58,11 +58,9 @@ public: const ClickHandlerPtr &p, bool pressed) override; - void attachToParent() override; - void detachFromParent() override; std::unique_ptr takeLastFromGroup() override; bool applyGroup( - const std::vector> &others) override; + const std::vector> &items) override; bool hasReplyPreview() const override; ImagePtr replyPreview() override; @@ -74,10 +72,6 @@ public: } HistoryMessageEdited *displayedEditBadge() const override; - bool canBeGrouped() const override { - return true; - } - bool skipBubbleTail() const override { return isBubbleBottom() && _caption.isEmpty(); } @@ -92,9 +86,9 @@ public: private: struct Part { - Part(not_null view); + Part(not_null item); - not_null view; + not_null item; std::unique_ptr content; RectParts sides = RectPart::None; @@ -112,7 +106,7 @@ private: bool computeNeedBubble() const; not_null main() const; bool validateGroupParts( - const std::vector> &others) const; + const std::vector> &items) const; HistoryTextState getPartState( QPoint point, HistoryStateRequest request) const; diff --git a/Telegram/SourceFiles/history/history_media_pointer.cpp b/Telegram/SourceFiles/history/history_media_pointer.cpp deleted file mode 100644 index 4f8167c54..000000000 --- a/Telegram/SourceFiles/history/history_media_pointer.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* -This file is part of Telegram Desktop, -the official desktop application for the Telegram messaging service. - -For license and copyright information please follow this link: -https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL -*/ -#include "history/history_media_pointer.h" - -#include "history/history_media.h" - -HistoryMediaPtr::HistoryMediaPtr() = default; - -HistoryMediaPtr::HistoryMediaPtr(std::unique_ptr pointer) -: _pointer(std::move(pointer)) { - if (_pointer) { - _pointer->attachToParent(); - } -} - -void HistoryMediaPtr::reset(std::unique_ptr pointer) { - *this = std::move(pointer); -} - -HistoryMediaPtr &HistoryMediaPtr::operator=(std::unique_ptr pointer) { - if (_pointer) { - _pointer->detachFromParent(); - } - _pointer = std::move(pointer); - if (_pointer) { - _pointer->attachToParent(); - } - return *this; -} - -HistoryMediaPtr::~HistoryMediaPtr() { - reset(); -} diff --git a/Telegram/SourceFiles/history/history_media_pointer.h b/Telegram/SourceFiles/history/history_media_pointer.h deleted file mode 100644 index 01e4e4b69..000000000 --- a/Telegram/SourceFiles/history/history_media_pointer.h +++ /dev/null @@ -1,45 +0,0 @@ -/* -This file is part of Telegram Desktop, -the official desktop application for the Telegram messaging service. - -For license and copyright information please follow this link: -https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL -*/ -#pragma once - -class HistoryMedia; - -// HistoryMedia has a special owning smart pointer -// which regs/unregs this media to the holding HistoryItem -class HistoryMediaPtr { -public: - HistoryMediaPtr(); - HistoryMediaPtr(const HistoryMediaPtr &other) = delete; - HistoryMediaPtr &operator=(const HistoryMediaPtr &other) = delete; - HistoryMediaPtr(std::unique_ptr other); - HistoryMediaPtr &operator=(std::unique_ptr other); - - HistoryMedia *get() const { - return _pointer.get(); - } - void reset(std::unique_ptr pointer = nullptr); - bool isNull() const { - return !_pointer; - } - - HistoryMedia *operator->() const { - return get(); - } - HistoryMedia &operator*() const { - Expects(!isNull()); - return *get(); - } - explicit operator bool() const { - return !isNull(); - } - ~HistoryMediaPtr(); - -private: - std::unique_ptr _pointer; - -}; diff --git a/Telegram/SourceFiles/history/history_media_types.cpp b/Telegram/SourceFiles/history/history_media_types.cpp index 6012b37f7..fb75b3a38 100644 --- a/Telegram/SourceFiles/history/history_media_types.cpp +++ b/Telegram/SourceFiles/history/history_media_types.cpp @@ -62,6 +62,39 @@ int gifMaxStatusWidth(DocumentData *document) { return result; } +std::unique_ptr CreateAttach( + not_null parent, + DocumentData *document, + PhotoData *photo) { + if (document) { + if (document->sticker()) { + return std::make_unique(parent, document); + } else if (document->isAnimation()) { + return std::make_unique( + parent, + document, + QString()); + } else if (document->isVideoFile()) { + return std::make_unique( + parent, + parent->data(), + document, + QString()); + } + return std::make_unique( + parent, + document, + QString()); + } else if (photo) { + return std::make_unique( + parent, + parent->data(), + photo, + QString()); + } + return nullptr; +} + } // namespace TextWithEntities WithCaptionSelectedText( @@ -115,8 +148,8 @@ void HistoryFileMedia::setLinks( _cancell = std::move(cancell); } -void HistoryFileMedia::refreshParentId(not_null realParent) { - const auto contextId = realParent->data()->fullId(); +void HistoryFileMedia::refreshParentId(not_null realParent) { + const auto contextId = realParent->fullId(); _openl->setMessageId(contextId); _savel->setMessageId(contextId); _cancell->setMessageId(contextId); @@ -189,13 +222,13 @@ HistoryFileMedia::~HistoryFileMedia() = default; HistoryPhoto::HistoryPhoto( not_null parent, + not_null realParent, not_null photo, const QString &caption) : HistoryFileMedia(parent) , _data(photo) , _caption(st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right()) { - const auto item = parent->data(); - const auto fullId = item->fullId(); + const auto fullId = realParent->fullId(); setLinks( std::make_shared(_data, fullId), std::make_shared(_data, fullId), @@ -204,9 +237,9 @@ HistoryPhoto::HistoryPhoto( _caption.setText( st::messageTextStyle, caption + _parent->skipBlock(), - Ui::ItemTextNoMonoOptions(item)); + Ui::ItemTextNoMonoOptions(_parent->data())); } - init(); + create(realParent->fullId()); } HistoryPhoto::HistoryPhoto( @@ -217,41 +250,15 @@ HistoryPhoto::HistoryPhoto( : HistoryFileMedia(parent) , _data(photo) , _serviceWidth(width) { - const auto fullId = parent->data()->fullId(); + create(parent->data()->fullId(), chat); +} + +void HistoryPhoto::create(FullMsgId contextId, PeerData *chat) { + Auth().data().registerPhotoView(_data, _parent); setLinks( - std::make_shared(_data, fullId, chat), - std::make_shared(_data, fullId, chat), - std::make_shared(_data, fullId, chat)); - init(); -} - -HistoryPhoto::HistoryPhoto( - not_null parent, - not_null chat, - const MTPDphoto &photo, - int width) -: HistoryPhoto(parent, chat, App::feedPhoto(photo), width) { -} - -HistoryPhoto::HistoryPhoto( - not_null parent, - not_null realParent, - const HistoryPhoto &other) -: HistoryFileMedia(parent) -, _data(other._data) -, _pixw(other._pixw) -, _pixh(other._pixh) -, _caption(other._caption) { - const auto fullId = realParent->data()->fullId(); - setLinks( - std::make_shared(_data, fullId), - std::make_shared(_data, fullId), - std::make_shared(_data, fullId)); - - init(); -} - -void HistoryPhoto::init() { + std::make_shared(_data, contextId, chat), + std::make_shared(_data, contextId, chat), + std::make_shared(_data, contextId, chat)); _data->thumb->load(); } @@ -707,40 +714,44 @@ ImagePtr HistoryPhoto::replyPreview() { return _data->makeReplyPreview(); } -HistoryVideo::HistoryVideo( - not_null parent, - not_null document, - const QString &caption) -: HistoryFileMedia(parent) -, _data(document) -, _thumbw(1) -, _caption(st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right()) { - const auto item = parent->data(); - if (!caption.isEmpty()) { - _caption.setText( - st::messageTextStyle, - caption + _parent->skipBlock(), - Ui::ItemTextNoMonoOptions(item)); - } +HistoryPhoto::~HistoryPhoto() { + Auth().data().unregisterPhotoView(_data, _parent); +} - setDocumentLinks(_data, item); +DocumentViewRegister::DocumentViewRegister( + not_null parent, + not_null document) +: _savedParent(parent) +, _savedDocument(document) { + Auth().data().registerDocumentView(_savedDocument, _savedParent); +} - setStatusSize(FileStatusSizeReady); - - _data->thumb->load(); +DocumentViewRegister::~DocumentViewRegister() { + Auth().data().unregisterDocumentView(_savedDocument, _savedParent); } HistoryVideo::HistoryVideo( not_null parent, - not_null realParent, - const HistoryVideo &other) + not_null realParent, + not_null document, + const QString &caption) : HistoryFileMedia(parent) -, _data(other._data) -, _thumbw(other._thumbw) -, _caption(other._caption) { - setDocumentLinks(_data, realParent->data()); +, DocumentViewRegister(parent, document) +, _data(document) +, _thumbw(1) +, _caption(st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right()) { + if (!caption.isEmpty()) { + _caption.setText( + st::messageTextStyle, + caption + _parent->skipBlock(), + Ui::ItemTextNoMonoOptions(_parent->data())); + } - setStatusSize(other._statusSize); + setDocumentLinks(_data, realParent); + + setStatusSize(FileStatusSizeReady); + + _data->thumb->load(); } QSize HistoryVideo::countOptimalSize() { @@ -1198,6 +1209,7 @@ HistoryDocument::HistoryDocument( not_null document, const QString &caption) : HistoryFileMedia(parent) +, DocumentViewRegister(parent, document) , _data(document) { const auto item = parent->data(); @@ -1900,19 +1912,19 @@ void HistoryDocument::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool HistoryFileMedia::clickHandlerPressedChanged(p, pressed); } -void HistoryDocument::refreshParentId(not_null realParent) { +void HistoryDocument::refreshParentId(not_null realParent) { HistoryFileMedia::refreshParentId(realParent); - const auto contextId = realParent->data()->fullId(); + const auto fullId = realParent->fullId(); if (auto thumbed = Get()) { if (thumbed->_linksavel) { - thumbed->_linksavel->setMessageId(contextId); - thumbed->_linkcancell->setMessageId(contextId); + thumbed->_linksavel->setMessageId(fullId); + thumbed->_linkcancell->setMessageId(fullId); } } if (auto voice = Get()) { if (voice->_seekl) { - voice->_seekl->setMessageId(contextId); + voice->_seekl->setMessageId(fullId); } } } @@ -1944,6 +1956,7 @@ HistoryGif::HistoryGif( not_null document, const QString &caption) : HistoryFileMedia(parent) +, DocumentViewRegister(parent, document) , _data(document) , _caption(st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right()) { const auto item = parent->data(); @@ -2667,7 +2680,7 @@ bool HistoryGif::playInline(bool autoplay) { stopInline(); } else if (_data->loaded(DocumentData::FilePathResolveChecked)) { if (!cAutoPlayGif()) { - App::stopGifItems(); + Auth().data().stopAutoplayAnimations(); } const auto mode = (!autoplay && _data->isVideoMessage()) ? Mode::Video @@ -2682,7 +2695,7 @@ bool HistoryGif::playInline(bool autoplay) { Auth().data().requestViewRepaint(_parent); }); if (App::main()) { - App::main()->mediaMarkRead(_data); + Auth().data().markMediaRead(_data); } App::wnd()->controller()->enableGifPauseReason(Window::GifPauseReason::RoundPlaying); } @@ -2709,12 +2722,12 @@ void HistoryGif::stopInline() { void HistoryGif::setClipReader(Media::Clip::ReaderPointer gif) { if (_gif) { - App::unregGifItem(_gif.get()); + Auth().data().unregisterAutoplayAnimation(_gif.get()); } _gif = std::move(gif); - //if (_gif) { // #TODO GIFs - // App::regGifItem(_gif.get(), _parent); - //} + if (_gif) { + Auth().data().registerAutoplayAnimation(_gif.get(), _parent); + } } HistoryGif::~HistoryGif() { @@ -2745,6 +2758,7 @@ HistorySticker::HistorySticker( not_null parent, not_null document) : HistoryMedia(parent) +, DocumentViewRegister(parent, document) , _data(document) , _emoji(_data->sticker()->alt) { _data->thumb->load(); @@ -3033,6 +3047,8 @@ HistoryContact::HistoryContact( , _fname(first) , _lname(last) , _phone(App::formatPhone(phone)) { + Auth().data().registerContactView(userId, parent); + _name.setText( st::semiboldTextStyle, lng_full_name(lt_first_name, first, lt_last_name, last).trimmed(), @@ -3040,6 +3056,18 @@ HistoryContact::HistoryContact( _phonew = st::normalFont->width(_phone); } +HistoryContact::~HistoryContact() { + Auth().data().unregisterContactView(_userId, _parent); +} + +void HistoryContact::updateSharedContactUserId(UserId userId) { + if (_userId != userId) { + Auth().data().unregisterContactView(_userId, _parent); + _userId = userId; + Auth().data().registerContactView(_userId, _parent); + } +} + QSize HistoryContact::countOptimalSize() { const auto item = _parent->data(); auto maxWidth = st::msgFileMinWidth; @@ -3173,20 +3201,6 @@ TextWithEntities HistoryContact::selectedText(TextSelection selection) const { return { qsl("[ ") + lang(lng_in_dlg_contact) + qsl(" ]\n") + _name.originalText() + '\n' + _phone, EntitiesInText() }; } -void HistoryContact::attachToParent() { - //if (_userId) { - // App::regSharedContactItem(_userId, _parent); - //} // #TODO contacts -} - -void HistoryContact::detachFromParent() { - //if (_userId) { - // App::unregSharedContactItem(_userId, _parent); - //} // #TODO contacts -} - -HistoryContact::~HistoryContact() = default; - HistoryCall::HistoryCall( not_null parent, not_null call) @@ -3306,6 +3320,7 @@ HistoryWebPage::HistoryWebPage( , _data(data) , _title(st::msgMinWidth - st::webPageLeft) , _description(st::msgMinWidth - st::webPageLeft) { + Auth().data().registerWebPageView(_data, _parent); } QSize HistoryWebPage::countOptimalSize() { @@ -3316,10 +3331,7 @@ QSize HistoryWebPage::countOptimalSize() { if (versionChanged) { _dataVersion = _data->version; _openl = nullptr; - if (_attach) { - _attach->detachFromParent(); - _attach = nullptr; - } + _attach = nullptr; _title = Text(st::msgMinWidth - st::webPageLeft); _description = Text(st::msgMinWidth - st::webPageLeft); _siteNameWidth = 0; @@ -3349,22 +3361,7 @@ QSize HistoryWebPage::countOptimalSize() { // init attach if (!_attach && !_asArticle) { - if (_data->document) { - if (_data->document->sticker()) { - _attach = std::make_unique(_parent, _data->document); - } else if (_data->document->isAnimation()) { - _attach = std::make_unique(_parent, _data->document, QString()); - } else if (_data->document->isVideoFile()) { - _attach = std::make_unique(_parent, _data->document, QString()); - } else { - _attach = std::make_unique(_parent, _data->document, QString()); - } - } else if (_data->photo) { - _attach = std::make_unique(_parent, _data->photo, QString()); - } - if (_attach) { - _attach->attachToParent(); - } + _attach = CreateAttach(_parent, _data->document, _data->photo); } auto textFloatsAroundInfo = !_asArticle && !_attach && isBubbleBottom(); @@ -3570,7 +3567,7 @@ TextSelection HistoryWebPage::fromDescriptionSelection( return HistoryView::ShiftItemSelection(selection, _title); } -void HistoryWebPage::refreshParentId(not_null realParent) { +void HistoryWebPage::refreshParentId(not_null realParent) { if (_attach) { _attach->refreshParentId(realParent); } @@ -3829,16 +3826,6 @@ bool HistoryWebPage::isDisplayed() const { && !item->Has(); } -void HistoryWebPage::attachToParent() { - //App::regWebPageItem(_data, _parent); // #TODO webpages - if (_attach) _attach->attachToParent(); -} - -void HistoryWebPage::detachFromParent() { - //App::unregWebPageItem(_data, _parent); // #TODO webpages - if (_attach) _attach->detachFromParent(); -} - TextWithEntities HistoryWebPage::selectedText(TextSelection selection) const { if (selection == FullSelection && !isLogEntryOriginal()) { return TextWithEntities(); @@ -3890,6 +3877,10 @@ int HistoryWebPage::bottomInfoPadding() const { return result; } +HistoryWebPage::~HistoryWebPage() { + Auth().data().unregisterWebPageView(_data, _parent); +} + HistoryGame::HistoryGame( not_null parent, not_null data, @@ -3904,6 +3895,7 @@ HistoryGame::HistoryGame( consumed, Ui::ItemTextOptions(parent->data())); } + Auth().data().registerGameView(_data, _parent); } QSize HistoryGame::countOptimalSize() { @@ -3923,19 +3915,7 @@ QSize HistoryGame::countOptimalSize() { // init attach if (!_attach) { - if (_data->document) { - if (_data->document->sticker()) { - _attach = std::make_unique(_parent, _data->document); - } else if (_data->document->isAnimation()) { - _attach = std::make_unique(_parent, _data->document, QString()); - } else if (_data->document->isVideoFile()) { - _attach = std::make_unique(_parent, _data->document, QString()); - } else { - _attach = std::make_unique(_parent, _data->document, QString()); - } - } else if (_data->photo) { - _attach = std::make_unique(_parent, _data->photo, QString()); - } + _attach = CreateAttach(_parent, _data->document, _data->photo); } // init strings @@ -4003,9 +3983,9 @@ QSize HistoryGame::countOptimalSize() { return { maxWidth, minHeight }; } -void HistoryGame::refreshParentId(not_null realParent) { +void HistoryGame::refreshParentId(not_null realParent) { if (_openl) { - _openl->setMessageId(_parent->data()->fullId()); + _openl->setMessageId(realParent->fullId()); } if (_attach) { _attach->refreshParentId(realParent); @@ -4242,16 +4222,6 @@ void HistoryGame::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pres } } -void HistoryGame::attachToParent() { - // App::regGameItem(_data, _parent); // #TODO regitems - if (_attach) _attach->attachToParent(); -} - -void HistoryGame::detachFromParent() { - // App::unregGameItem(_data, _parent); // #TODO regitems - if (_attach) _attach->detachFromParent(); -} - TextWithEntities HistoryGame::selectedText(TextSelection selection) const { if (selection == FullSelection) { return TextWithEntities(); @@ -4295,6 +4265,10 @@ int HistoryGame::bottomInfoPadding() const { return result; } +HistoryGame::~HistoryGame() { + Auth().data().unregisterGameView(_data, _parent); +} + HistoryInvoice::HistoryInvoice( not_null parent, not_null invoice) @@ -4473,7 +4447,7 @@ TextSelection HistoryInvoice::fromDescriptionSelection( return HistoryView::ShiftItemSelection(selection, _title); } -void HistoryInvoice::refreshParentId(not_null realParent) { +void HistoryInvoice::refreshParentId(not_null realParent) { if (_attach) { _attach->refreshParentId(realParent); } @@ -4638,14 +4612,6 @@ void HistoryInvoice::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool p } } -void HistoryInvoice::attachToParent() { - if (_attach) _attach->attachToParent(); -} - -void HistoryInvoice::detachFromParent() { - if (_attach) _attach->detachFromParent(); -} - TextWithEntities HistoryInvoice::selectedText(TextSelection selection) const { if (selection == FullSelection) { return TextWithEntities(); diff --git a/Telegram/SourceFiles/history/history_media_types.h b/Telegram/SourceFiles/history/history_media_types.h index 2d9170e14..5eee32f5d 100644 --- a/Telegram/SourceFiles/history/history_media_types.h +++ b/Telegram/SourceFiles/history/history_media_types.h @@ -56,7 +56,7 @@ public: void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override; void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override; - void refreshParentId(not_null realParent) override; + void refreshParentId(not_null realParent) override; bool allowsFastShare() const override { return true; @@ -129,6 +129,7 @@ class HistoryPhoto : public HistoryFileMedia { public: HistoryPhoto( not_null parent, + not_null realParent, not_null photo, const QString &caption); HistoryPhoto( @@ -136,25 +137,10 @@ public: not_null chat, not_null photo, int width); - HistoryPhoto( - not_null parent, - not_null chat, - const MTPDphoto &photo, - int width); - HistoryPhoto( - not_null parent, - not_null realParent, - const HistoryPhoto &other); - void init(); HistoryMediaType type() const override { return MediaTypePhoto; } - std::unique_ptr clone( - not_null newParent, - not_null realParent) const override { - return std::make_unique(newParent, realParent, *this); - } void draw(Painter &p, const QRect &clip, TextSelection selection, TimeMs ms) const override; HistoryTextState getState(QPoint point, HistoryStateRequest request) const override; @@ -177,9 +163,6 @@ public: return _data; } - bool canBeGrouped() const override { - return true; - } QSize sizeForGrouping() const override; void drawGrouped( Painter &p, @@ -214,12 +197,16 @@ public: return _data->loaded(); } + ~HistoryPhoto(); + protected: float64 dataProgress() const override; bool dataFinished() const override; bool dataLoaded() const override; private: + void create(FullMsgId contextId, PeerData *chat = nullptr); + QSize countOptimalSize() override; QSize countCurrentSize(int newWidth) override; @@ -238,25 +225,30 @@ private: }; -class HistoryVideo : public HistoryFileMedia { +class DocumentViewRegister { +public: + DocumentViewRegister( + not_null parent, + not_null document); + ~DocumentViewRegister(); + +private: + not_null _savedParent; + not_null _savedDocument; + +}; + +class HistoryVideo : public HistoryFileMedia, public DocumentViewRegister { public: HistoryVideo( not_null parent, + not_null realParent, not_null document, const QString &caption); - HistoryVideo( - not_null parent, - not_null realParent, - const HistoryVideo &other); HistoryMediaType type() const override { return MediaTypeVideo; } - std::unique_ptr clone( - not_null newParent, - not_null realParent) const override { - return std::make_unique(newParent, realParent, *this); - } void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override; HistoryTextState getState(QPoint point, HistoryStateRequest request) const override; @@ -279,9 +271,6 @@ public: return _data; } - bool canBeGrouped() const override { - return true; - } QSize sizeForGrouping() const override; void drawGrouped( Painter &p, @@ -342,6 +331,7 @@ private: class HistoryDocument : public HistoryFileMedia + , public DocumentViewRegister , public RuntimeComposer { public: HistoryDocument( @@ -400,7 +390,7 @@ public: void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override; - void refreshParentId(not_null realParent) override; + void refreshParentId(not_null realParent) override; protected: float64 dataProgress() const override; @@ -426,7 +416,7 @@ private: }; -class HistoryGif : public HistoryFileMedia { +class HistoryGif : public HistoryFileMedia, public DocumentViewRegister { public: HistoryGif( not_null parent, @@ -529,7 +519,7 @@ private: }; -class HistorySticker : public HistoryMedia { +class HistorySticker : public HistoryMedia, public DocumentViewRegister { public: HistorySticker( not_null parent, @@ -597,6 +587,7 @@ public: const QString &first, const QString &last, const QString &phone); + ~HistoryContact(); HistoryMediaType type() const override { return MediaTypeContact; @@ -614,9 +605,6 @@ public: TextWithEntities selectedText(TextSelection selection) const override; - void attachToParent() override; - void detachFromParent() override; - bool needsBubble() const override { return true; } @@ -634,7 +622,8 @@ public: return _phone; } - ~HistoryContact(); + // Should be called only by Data::Session. + void updateSharedContactUserId(UserId userId) override; private: QSize countOptimalSize() override; @@ -709,7 +698,7 @@ public: return MediaTypeWebPage; } - void refreshParentId(not_null realParent) override; + void refreshParentId(not_null realParent) override; void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override; HistoryTextState getState(QPoint point, HistoryStateRequest request) const override; @@ -753,9 +742,6 @@ public: if (_attach) _attach->stopInline(); } - void attachToParent() override; - void detachFromParent() override; - bool hasReplyPreview() const override; ImagePtr replyPreview() override; @@ -777,6 +763,8 @@ public: return _attach.get(); } + ~HistoryWebPage(); + private: QSize countOptimalSize() override; QSize countCurrentSize(int newWidth) override; @@ -818,7 +806,7 @@ public: return MediaTypeGame; } - void refreshParentId(not_null realParent) override; + void refreshParentId(not_null realParent) override; void draw(Painter &p, const QRect &r, TextSelection selection, TimeMs ms) const override; HistoryTextState getState(QPoint point, HistoryStateRequest request) const override; @@ -864,9 +852,6 @@ public: if (_attach) _attach->stopInline(); } - void attachToParent() override; - void detachFromParent() override; - bool hasReplyPreview() const override { return (_data->photo && !_data->photo->thumb->isNull()) || (_data->document && !_data->document->thumb->isNull()); } @@ -890,6 +875,8 @@ public: return _attach.get(); } + ~HistoryGame(); + private: QSize countOptimalSize() override; QSize countCurrentSize(int newWidth) override; @@ -921,7 +908,7 @@ public: return MediaTypeInvoice; } - void refreshParentId(not_null realParent) override; + void refreshParentId(not_null realParent) override; MsgId getReceiptMsgId() const { return _receiptMsgId; @@ -956,9 +943,6 @@ public: void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override; void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override; - void attachToParent() override; - void detachFromParent() override; - bool hasReplyPreview() const override { return _attach && _attach->hasReplyPreview(); } diff --git a/Telegram/SourceFiles/history/history_message.cpp b/Telegram/SourceFiles/history/history_message.cpp index 8e230b548..2a94b719c 100644 --- a/Telegram/SourceFiles/history/history_message.cpp +++ b/Telegram/SourceFiles/history/history_message.cpp @@ -314,7 +314,9 @@ HistoryMessage::HistoryMessage( createComponents(config); - initMedia(msg.has_media() ? (&msg.vmedia) : nullptr); + if (msg.has_media()) { + setMedia(msg.vmedia); + } auto text = TextUtilities::Clean(qs(msg.vmessage)); auto entities = msg.has_entities() @@ -702,84 +704,136 @@ QString FormatViewsCount(int views) { return qsl("1"); } -void HistoryMessage::initMedia(const MTPMessageMedia *media) { +void HistoryMessage::refreshMedia(const MTPMessageMedia *media) { + const auto wasGrouped = Auth().data().groups().isGrouped(this); _media = nullptr; + if (media) { + setMedia(*media); + } + if (wasGrouped) { + Auth().data().groups().refreshMessage(this); + } +} - switch (media ? media->type() : mtpc_messageMediaEmpty) { +void HistoryMessage::setMedia(const MTPMessageMedia &media) { + _media = CreateMedia(this, media); + if (const auto invoice = _media->invoice()) { + if (invoice->receiptMsgId) { + replaceBuyWithReceiptInMarkup(); + } + } +} + +std::unique_ptr HistoryMessage::CreateMedia( + not_null item, + const MTPMessageMedia &media) { + switch (media.type()) { case mtpc_messageMediaContact: { - auto &d = media->c_messageMediaContact(); - _media = std::make_unique(this, d.vuser_id.v, qs(d.vfirst_name), qs(d.vlast_name), qs(d.vphone_number)); + const auto &data = media.c_messageMediaContact(); + return std::make_unique( + item, + data.vuser_id.v, + qs(data.vfirst_name), + qs(data.vlast_name), + qs(data.vphone_number)); } break; case mtpc_messageMediaGeo: { - auto &point = media->c_messageMediaGeo().vgeo; - if (point.type() == mtpc_geoPoint) { - _media = std::make_unique(this, LocationCoords(point.c_geoPoint())); + const auto &data = media.c_messageMediaGeo().vgeo; + if (data.type() == mtpc_geoPoint) { + return std::make_unique( + item, + LocationCoords(data.c_geoPoint())); } } break; case mtpc_messageMediaGeoLive: { - auto &point = media->c_messageMediaGeoLive().vgeo; - if (point.type() == mtpc_geoPoint) { - _media = std::make_unique(this, LocationCoords(point.c_geoPoint())); + const auto &data = media.c_messageMediaGeoLive().vgeo; + if (data.type() == mtpc_geoPoint) { + return std::make_unique( + item, + LocationCoords(data.c_geoPoint())); } } break; case mtpc_messageMediaVenue: { - auto &d = media->c_messageMediaVenue(); - if (d.vgeo.type() == mtpc_geoPoint) { - _media = std::make_unique(this, LocationCoords(d.vgeo.c_geoPoint()), qs(d.vtitle), qs(d.vaddress)); + const auto &data = media.c_messageMediaVenue(); + if (data.vgeo.type() == mtpc_geoPoint) { + return std::make_unique( + item, + LocationCoords(data.vgeo.c_geoPoint()), + qs(data.vtitle), + qs(data.vaddress)); } } break; case mtpc_messageMediaPhoto: { - auto &photo = media->c_messageMediaPhoto(); - if (photo.has_ttl_seconds()) { - LOG(("App Error: Unexpected MTPMessageMediaPhoto with ttl_seconds in HistoryMessage.")); - } else if (photo.has_photo() && photo.vphoto.type() == mtpc_photo) { - _media = std::make_unique( - this, - App::feedPhoto(photo.vphoto.c_photo()), - photo.has_caption() ? qs(photo.vcaption) : QString()); + const auto &data = media.c_messageMediaPhoto(); + if (data.has_ttl_seconds()) { + LOG(("App Error: " + "Unexpected MTPMessageMediaPhoto " + "with ttl_seconds in HistoryMessage.")); + } else if (data.has_photo() && data.vphoto.type() == mtpc_photo) { + return std::make_unique( + item, + Auth().data().photo(data.vphoto.c_photo()), + data.has_caption() ? qs(data.vcaption) : QString()); } else { - LOG(("API Error: Got MTPMessageMediaPhoto without photo and without ttl_seconds.")); + LOG(("API Error: " + "Got MTPMessageMediaPhoto " + "without photo and without ttl_seconds.")); } } break; case mtpc_messageMediaDocument: { - auto &document = media->c_messageMediaDocument(); - if (document.has_ttl_seconds()) { - LOG(("App Error: Unexpected MTPMessageMediaDocument with ttl_seconds in HistoryMessage.")); - } else if (document.has_document() && document.vdocument.type() == mtpc_document) { - _media = std::make_unique( - this, - App::feedDocument(document.vdocument.c_document()), - document.has_caption() ? qs(document.vcaption) : QString()); + const auto &data = media.c_messageMediaDocument(); + if (data.has_ttl_seconds()) { + LOG(("App Error: " + "Unexpected MTPMessageMediaDocument " + "with ttl_seconds in HistoryMessage.")); + } else if (data.has_document() + && data.vdocument.type() == mtpc_document) { + return std::make_unique( + item, + Auth().data().document(data.vdocument.c_document()), + data.has_caption() ? qs(data.vcaption) : QString()); } else { - LOG(("API Error: Got MTPMessageMediaDocument without document and without ttl_seconds.")); + LOG(("API Error: " + "Got MTPMessageMediaDocument " + "without document and without ttl_seconds.")); } } break; case mtpc_messageMediaWebPage: { - auto &d = media->c_messageMediaWebPage().vwebpage; - switch (d.type()) { + const auto &data = media.c_messageMediaWebPage().vwebpage; + switch (data.type()) { case mtpc_webPageEmpty: break; - case mtpc_webPagePending: { - _media = std::make_unique(this, App::feedWebPage(d.c_webPagePending())); - } break; - case mtpc_webPage: { - _media = std::make_unique(this, App::feedWebPage(d.c_webPage())); - } break; - case mtpc_webPageNotModified: LOG(("API Error: webPageNotModified is unexpected in message media.")); break; + case mtpc_webPagePending: + return std::make_unique( + item, + Auth().data().webpage(data.c_webPagePending())); + break; + case mtpc_webPage: + return std::make_unique( + item, + Auth().data().webpage(data.c_webPage())); + break; + case mtpc_webPageNotModified: + LOG(("API Error: " + "webPageNotModified is unexpected in message media.")); + break; } } break; case mtpc_messageMediaGame: { - auto &d = media->c_messageMediaGame().vgame; - if (d.type() == mtpc_game) { - _media = std::make_unique(this, App::feedGame(d.c_game())); + const auto &data = media.c_messageMediaGame().vgame; + if (data.type() == mtpc_game) { + return std::make_unique( + item, + Auth().data().game(data.c_game())); } } break; case mtpc_messageMediaInvoice: { - _media = std::make_unique(this, media->c_messageMediaInvoice()); - if (_media->invoice()->receiptMsgId) { - replaceBuyWithReceiptInMarkup(); - } + return std::make_unique( + item, + media.c_messageMediaInvoice()); } break; }; + + return nullptr; } void HistoryMessage::replaceBuyWithReceiptInMarkup() { @@ -822,7 +876,7 @@ void HistoryMessage::applyEdition(const MTPDmessage &message) { } setText(textWithEntities); setReplyMarkup(message.has_reply_markup() ? (&message.vreply_markup) : nullptr); - initMedia(message.has_media() ? (&message.vmedia) : nullptr); + refreshMedia(message.has_media() ? (&message.vmedia) : nullptr); setViewsCount(message.has_views() ? message.vviews.v : -1); finishEdition(keyboardTop); @@ -836,22 +890,22 @@ void HistoryMessage::applyEdition(const MTPDmessageService &message) { void HistoryMessage::applyEditionToEmpty() { setEmptyText(); - initMedia(nullptr); + refreshMedia(nullptr); setReplyMarkup(nullptr); setViewsCount(-1); finishEditionToEmpty(); } -void HistoryMessage::updateMedia(const MTPMessageMedia *media) { +void HistoryMessage::updateSentMedia(const MTPMessageMedia *media) { if (_flags & MTPDmessage_ClientFlag::f_from_inline_bot) { if (!media || !_media || !_media->updateInlineResultMedia(*media)) { - initMedia(media); + refreshMedia(media); } _flags &= ~MTPDmessage_ClientFlag::f_from_inline_bot; } else { if (!media || !_media || !_media->updateSentMedia(*media)) { - initMedia(media); + refreshMedia(media); } } Auth().data().requestItemViewResize(this); @@ -897,7 +951,7 @@ Storage::SharedMediaTypesMask HistoryMessage::sharedMediaTypes() const { // mediaRemovedSkipBlock = _media->isDisplayed() && _media->isBubbleBottom(); // _media.reset(); //} - //initMedia(media); + //refreshMedia(media); //auto mediaDisplayed = _media && _media->isDisplayed(); //if (mediaDisplayed && _media->isBubbleBottom() && !mediaRemovedSkipBlock) { // _text.removeSkipBlock(); @@ -996,15 +1050,23 @@ bool HistoryMessage::textHasLinks() const { } void HistoryMessage::setViewsCount(int32 count) { - auto views = Get(); - if (!views || views->_views == count || (count >= 0 && views->_views > count)) return; + const auto views = Get(); + if (!views + || views->_views == count + || (count >= 0 && views->_views > count)) { + return; + } - int32 was = views->_viewsWidth; + const auto was = views->_viewsWidth; views->_views = count; - views->_viewsText = (views->_views >= 0) ? FormatViewsCount(views->_views) : QString(); - views->_viewsWidth = views->_viewsText.isEmpty() ? 0 : st::msgDateFont->width(views->_viewsText); + views->_viewsText = (views->_views >= 0) + ? FormatViewsCount(views->_views) + : QString(); + views->_viewsWidth = views->_viewsText.isEmpty() + ? 0 + : st::msgDateFont->width(views->_viewsText); if (was == views->_viewsWidth) { - Auth().data().requestItemRepaint(this); + Auth().data().requestItemViewRepaint(this); } else { Auth().data().requestItemViewResize(this); } @@ -1012,6 +1074,7 @@ void HistoryMessage::setViewsCount(int32 count) { void HistoryMessage::setRealId(MsgId newId) { HistoryItem::setRealId(newId); + Auth().data().groups().refreshMessage(this); Auth().data().requestItemViewResize(this); } @@ -1026,9 +1089,8 @@ QString HistoryMessage::notificationHeader() const { } std::unique_ptr HistoryMessage::createView( - not_null controller, - HistoryView::Context context) { - return controller->createMessageView(this, context); + not_null delegate) { + return delegate->elementCreate(this); } HistoryMessage::~HistoryMessage() { diff --git a/Telegram/SourceFiles/history/history_message.h b/Telegram/SourceFiles/history/history_message.h index 37ee6b9f6..dbdfa26a9 100644 --- a/Telegram/SourceFiles/history/history_message.h +++ b/Telegram/SourceFiles/history/history_message.h @@ -143,7 +143,11 @@ public: markup); } - void initMedia(const MTPMessageMedia *media); + void refreshMedia(const MTPMessageMedia *media); + void setMedia(const MTPMessageMedia &media); + static std::unique_ptr CreateMedia( + not_null item, + const MTPMessageMedia &media); int32 plainMaxWidth() const; @@ -163,7 +167,7 @@ public: void applyEdition(const MTPDmessage &message) override; void applyEdition(const MTPDmessageService &message) override; - void updateMedia(const MTPMessageMedia *media) override; + void updateSentMedia(const MTPMessageMedia *media) override; void updateReplyMarkup(const MTPReplyMarkup *markup) override { setReplyMarkup(markup); } @@ -191,8 +195,7 @@ public: } std::unique_ptr createView( - not_null controller, - HistoryView::Context context) override; + not_null delegate) override; ~HistoryMessage(); diff --git a/Telegram/SourceFiles/history/history_service.cpp b/Telegram/SourceFiles/history/history_service.cpp index 95e1e80e7..03debb0be 100644 --- a/Telegram/SourceFiles/history/history_service.cpp +++ b/Telegram/SourceFiles/history/history_service.cpp @@ -208,7 +208,7 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) { _media = std::make_unique( this, history()->peer, - App::feedPhoto(photo.c_photo())); + Auth().data().photo(photo.c_photo())); } } break; @@ -452,9 +452,8 @@ QString HistoryService::inReplyText() const { } std::unique_ptr HistoryService::createView( - not_null controller, - HistoryView::Context context) { - return controller->createMessageView(this, context); + not_null delegate) { + return delegate->elementCreate(this); } void HistoryService::setServiceText(const PreparedText &prepared) { diff --git a/Telegram/SourceFiles/history/history_service.h b/Telegram/SourceFiles/history/history_service.h index 89be2f5e0..a49723c74 100644 --- a/Telegram/SourceFiles/history/history_service.h +++ b/Telegram/SourceFiles/history/history_service.h @@ -97,8 +97,7 @@ public: QString inReplyText() const override; std::unique_ptr createView( - not_null controller, - HistoryView::Context context) override; + not_null delegate) override; ~HistoryService(); diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index da4b41335..0965a7f71 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -559,7 +559,7 @@ HistoryWidget::HistoryWidget(QWidget *parent, not_null cont ) | rpl::start_with_next( [this](auto item) { itemRemoved(item); }, lifetime()); - Auth().data().itemRepaintRequest( + Auth().data().itemViewRepaintRequest( ) | rpl::start_with_next( [this](auto item) { repaintHistoryItem(item); }, lifetime()); @@ -777,8 +777,10 @@ void HistoryWidget::scrollToAnimationCallback(FullMsgId attachToId) { void HistoryWidget::enqueueMessageHighlight( not_null view) { - if (const auto group = view->getFullGroup()) { - view = group->leader; + if (const auto group = Auth().data().groups().find(view->data())) { + if (const auto leader = group->items.back()->mainView()) { + view = leader; + } } auto enqueueMessageId = [this](MsgId universalId) { if (_highlightQueue.empty() && !_highlightTimer.isActive()) { @@ -845,8 +847,9 @@ void HistoryWidget::checkNextHighlight() { } void HistoryWidget::updateHighlightedMessage() { - auto item = getItemFromHistoryOrMigrated(_highlightedMessageId); - if (!item || !item->mainView()) { + const auto item = getItemFromHistoryOrMigrated(_highlightedMessageId); + const auto view = item ? item->mainView() : nullptr; + if (!view) { return stopMessageHighlight(); } auto duration = st::activeFadeInDuration + st::activeFadeOutDuration; @@ -854,7 +857,7 @@ void HistoryWidget::updateHighlightedMessage() { return stopMessageHighlight(); } - Auth().data().requestItemRepaint(item); + Auth().data().requestViewRepaint(view); } TimeMs HistoryWidget::highlightStartTime(not_null item) const { @@ -884,8 +887,10 @@ void HistoryWidget::clearHighlightMessages() { int HistoryWidget::itemTopForHighlight( not_null view) const { - if (const auto group = view->getFullGroup()) { - view = group->leader; + if (const auto group = Auth().data().groups().find(view->data())) { + if (const auto leader = group->items.back()->mainView()) { + view = leader; + } } auto itemTop = _list->itemTop(view); Assert(itemTop >= 0); @@ -1649,7 +1654,7 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re } if (!cAutoPlayGif()) { - App::stopGifItems(); + Auth().data().stopAutoplayAnimations(); } clearReplyReturns(); @@ -2187,7 +2192,7 @@ void HistoryWidget::newUnreadMsg(History *history, HistoryItem *item) { } if (App::wnd()->doWeReadServerHistory()) { if (item->mentionsMe() && item->isMediaUnread()) { - App::main()->mediaMarkRead(item); + Auth().api().markMediaRead(item); } Auth().api().readServerHistoryForce(history); return; @@ -3367,8 +3372,15 @@ void HistoryWidget::app_sendBotCallback( flags |= MTPmessages_GetBotCallbackAnswer::Flag::f_data; sendData = button->data; } - button->requestId = MTP::send(MTPmessages_GetBotCallbackAnswer(MTP_flags(flags), _peer->input, MTP_int(msg->id), MTP_bytes(sendData)), rpcDone(&HistoryWidget::botCallbackDone, info), rpcFail(&HistoryWidget::botCallbackFail, info)); - Auth().data().requestItemRepaint(msg); + button->requestId = MTP::send( + MTPmessages_GetBotCallbackAnswer( + MTP_flags(flags), + _peer->input, + MTP_int(msg->id), + MTP_bytes(sendData)), + rpcDone(&HistoryWidget::botCallbackDone, info), + rpcFail(&HistoryWidget::botCallbackFail, info)); + Auth().data().requestItemViewRepaint(msg); if (_replyToId == msg->id) { cancelReply(); @@ -3379,14 +3391,18 @@ void HistoryWidget::app_sendBotCallback( } } -void HistoryWidget::botCallbackDone(BotCallbackInfo info, const MTPmessages_BotCallbackAnswer &answer, mtpRequestId req) { +void HistoryWidget::botCallbackDone( + BotCallbackInfo info, + const MTPmessages_BotCallbackAnswer &answer, + mtpRequestId req) { auto item = App::histItemById(info.msgId); if (item) { - if (auto markup = item->Get()) { - if (info.row < markup->rows.size() && info.col < markup->rows.at(info.row).size()) { - if (markup->rows.at(info.row).at(info.col).requestId == req) { - markup->rows.at(info.row).at(info.col).requestId = 0; - Auth().data().requestItemRepaint(item); + if (const auto markup = item->Get()) { + if (info.row < markup->rows.size() + && info.col < markup->rows[info.row].size()) { + if (markup->rows[info.row][info.col].requestId == req) { + markup->rows[info.row][info.col].requestId = 0; + Auth().data().requestItemViewRepaint(item); } } } @@ -3414,14 +3430,18 @@ void HistoryWidget::botCallbackDone(BotCallbackInfo info, const MTPmessages_BotC } } -bool HistoryWidget::botCallbackFail(BotCallbackInfo info, const RPCError &error, mtpRequestId req) { +bool HistoryWidget::botCallbackFail( + BotCallbackInfo info, + const RPCError &error, + mtpRequestId req) { // show error? - if (auto item = App::histItemById(info.msgId)) { - if (auto markup = item->Get()) { - if (info.row < markup->rows.size() && info.col < markup->rows.at(info.row).size()) { - if (markup->rows.at(info.row).at(info.col).requestId == req) { - markup->rows.at(info.row).at(info.col).requestId = 0; - Auth().data().requestItemRepaint(item); + if (const auto item = App::histItemById(info.msgId)) { + if (const auto markup = item->Get()) { + if (info.row < markup->rows.size() + && info.col < markup->rows[info.row].size()) { + if (markup->rows[info.row][info.col].requestId == req) { + markup->rows[info.row][info.col].requestId = 0; + Auth().data().requestItemViewRepaint(item); } } } @@ -4364,7 +4384,7 @@ void HistoryWidget::onPhotoProgress(const FullMsgId &newId) { ? item->media()->photo() : nullptr; updateSendAction(item->history(), SendAction::Type::UploadPhoto, 0); - Auth().data().requestItemRepaint(item); + Auth().data().requestItemViewRepaint(item); } } @@ -4382,14 +4402,17 @@ void HistoryWidget::onDocumentProgress(const FullMsgId &newId) { item->history(), sendAction, progress); - Auth().data().requestItemRepaint(item); + Auth().data().requestItemViewRepaint(item); } } void HistoryWidget::onPhotoFailed(const FullMsgId &newId) { if (const auto item = App::histItemById(newId)) { - updateSendAction(item->history(), SendAction::Type::UploadPhoto, -1); - Auth().data().requestItemRepaint(item); + updateSendAction( + item->history(), + SendAction::Type::UploadPhoto, + -1); + Auth().data().requestItemViewRepaint(item); } } @@ -4401,7 +4424,7 @@ void HistoryWidget::onDocumentFailed(const FullMsgId &newId) { ? SendAction::Type::UploadVoice : SendAction::Type::UploadFile; updateSendAction(item->history(), sendAction, -1); - Auth().data().requestItemRepaint(item); + Auth().data().requestItemViewRepaint(item); } } @@ -4510,7 +4533,7 @@ void HistoryWidget::repaintHistoryItem( // It is possible that repaintHistoryItem() will be called from // _scroll->setOwnedWidget() because it calls onScroll() that // sendSynteticMouseEvent() and it could lead to some Info layout - // calling Auth().data().requestItemRepaint(), while we still are + // calling Auth().data().requestItemViewRepaint(), while we still are // in progrss of showing the history. Just ignore them for now :/ if (!_list) { return; @@ -5909,7 +5932,7 @@ void HistoryWidget::onPreviewCheck() { if (i == _previewCache.cend()) { _previewRequest = MTP::send(MTPmessages_GetWebPagePreview(MTP_string(_previewLinks)), rpcDone(&HistoryWidget::gotPreview, _previewLinks)); } else if (i.value()) { - _previewData = App::webPage(i.value()); + _previewData = Auth().data().webpage(i.value()); updatePreview(); } else { if (_previewData && _previewData->pendingTill >= 0) previewCancel(); @@ -5929,16 +5952,19 @@ void HistoryWidget::gotPreview(QString links, const MTPMessageMedia &result, mtp _previewRequest = 0; } if (result.type() == mtpc_messageMediaWebPage) { - auto data = App::feedWebPage(result.c_messageMediaWebPage().vwebpage); - _previewCache.insert(links, data->id); - if (data->pendingTill > 0 && data->pendingTill <= unixtime()) { - data->pendingTill = -1; + const auto &data = result.c_messageMediaWebPage().vwebpage; + const auto page = Auth().data().webpage(data); + _previewCache.insert(links, page->id); + if (page->pendingTill > 0 && page->pendingTill <= unixtime()) { + page->pendingTill = -1; } if (links == _previewLinks && !_previewCancelled) { - _previewData = (data->id && data->pendingTill >= 0) ? data : 0; + _previewData = (page->id && page->pendingTill >= 0) + ? page.get() + : nullptr; updatePreview(); } - if (App::main()) App::main()->webPagesOrGamesUpdate(); + Auth().data().sendWebPageGameNotifications(); } else if (result.type() == mtpc_messageMediaEmpty) { _previewCache.insert(links, 0); if (links == _previewLinks && !_previewCancelled) { diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp index 9e7f2540e..b4225ef4a 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.cpp +++ b/Telegram/SourceFiles/history/view/history_view_element.cpp @@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_media_grouped.h" #include "history/history.h" #include "data/data_session.h" +#include "data/data_groups.h" #include "data/data_media_types.h" #include "auth_session.h" #include "layout.h" @@ -55,10 +56,9 @@ TextSelection ShiftItemSelection( Element::Element(not_null data, Context context) : _data(data) -, _media(_data->media() ? _data->media()->createView(this) : nullptr) , _context(context) { Auth().data().registerItemView(this); - initGroup(); + refreshMedia(); } not_null Element::data() const { @@ -145,93 +145,110 @@ int Element::infoWidth() const { bool Element::isHiddenByGroup() const { return _flags & Flag::HiddenByGroup; } +// +//void Element::makeGroupMember(not_null leader) { +// Expects(leader != this); +// +// const auto group = Get(); +// Assert(group != nullptr); +// if (group->leader == this) { +// if (auto single = _media ? _media->takeLastFromGroup() : nullptr) { +// _media = std::move(single); +// } +// _flags |= Flag::HiddenByGroup; +// Auth().data().requestViewResize(this); +// +// group->leader = leader; +// base::take(group->others); +// } else if (group->leader != leader) { +// group->leader = leader; +// } +// +// Ensures(isHiddenByGroup()); +// Ensures(group->others.empty()); +//} +// +//void Element::makeGroupLeader(std::vector> &&others) { +// const auto group = Get(); +// Assert(group != nullptr); +// +// const auto leaderChanged = (group->leader != this); +// if (leaderChanged) { +// group->leader = this; +// _flags &= ~Flag::HiddenByGroup; +// Auth().data().requestViewResize(this); +// } +// group->others = std::move(others); +// if (!_media || !_media->applyGroup(group->others)) { +// resetGroupMedia(group->others); +// data()->invalidateChatsListEntry(); +// } +// +// Ensures(!isHiddenByGroup()); +//} +// +//bool Element::groupIdValidityChanged() { +// if (Has()) { +// if (_media && _media->canBeGrouped()) { +// return false; +// } +// RemoveComponents(Group::Bit()); +// Auth().data().requestViewResize(this); +// return true; +// } +// return false; +//} +// +//void Element::validateGroupId() { +// // Just ignore the result. +// groupIdValidityChanged(); +//} +// +//Group *Element::getFullGroup() { +// if (const auto group = Get()) { +// if (group->leader == this) { +// return group; +// } +// return group->leader->Get(); +// } +// return nullptr; +//} -void Element::makeGroupMember(not_null leader) { - Expects(leader != this); +void Element::refreshMedia() { + _flags &= ~Flag::HiddenByGroup; - const auto group = Get(); - Assert(group != nullptr); - if (group->leader == this) { - if (auto single = _media ? _media->takeLastFromGroup() : nullptr) { - _media = std::move(single); + const auto item = data(); + const auto media = item->media(); + if (media && media->canBeGrouped()) { + if (const auto group = Auth().data().groups().find(item)) { + if (group->items.back() != item) { + _media = nullptr; + _flags |= Flag::HiddenByGroup; + } else { + _media = std::make_unique( + this, + group->items); + Auth().data().requestViewResize(this); + } + return; } - _flags |= Flag::HiddenByGroup; - Auth().data().requestViewResize(this); - - group->leader = leader; - base::take(group->others); - } else if (group->leader != leader) { - group->leader = leader; } - - Ensures(isHiddenByGroup()); - Ensures(group->others.empty()); -} - -void Element::makeGroupLeader(std::vector> &&others) { - const auto group = Get(); - Assert(group != nullptr); - - const auto leaderChanged = (group->leader != this); - if (leaderChanged) { - group->leader = this; - _flags &= ~Flag::HiddenByGroup; - Auth().data().requestViewResize(this); - } - group->others = std::move(others); - if (!_media || !_media->applyGroup(group->others)) { - resetGroupMedia(group->others); - data()->invalidateChatsListEntry(); - } - - Ensures(!isHiddenByGroup()); -} - -bool Element::groupIdValidityChanged() { - if (Has()) { - if (_media && _media->canBeGrouped()) { - return false; - } - RemoveComponents(Group::Bit()); - Auth().data().requestViewResize(this); - return true; - } - return false; -} - -void Element::validateGroupId() { - // Just ignore the result. - groupIdValidityChanged(); -} - -Group *Element::getFullGroup() { - if (const auto group = Get()) { - if (group->leader == this) { - return group; - } - return group->leader->Get(); - } - return nullptr; -} - -void Element::initGroup() { - if (const auto groupId = _data->groupId()) { - AddComponents(Group::Bit()); - const auto group = Get(); - group->groupId = groupId; - group->leader = this; + if (_data->media()) { + _media = _data->media()->createView(this); + } else { + _media = nullptr; } } -void Element::resetGroupMedia( - const std::vector> &others) { - if (!others.empty()) { - _media = std::make_unique(this, others); - } else if (_media) { - _media = _media->takeLastFromGroup(); - } - Auth().data().requestViewResize(this); -} +//void Element::resetGroupMedia( +// const std::vector> &others) { +// if (!others.empty()) { +// _media = std::make_unique(this, others); +// } else if (_media) { +// _media = _media->takeLastFromGroup(); +// } +// Auth().data().requestViewResize(this); +//} void Element::previousInBlocksChanged() { recountDisplayDateInBlocks(); @@ -245,12 +262,13 @@ void Element::nextInBlocksChanged() { void Element::refreshDataId() { if (const auto media = this->media()) { - media->refreshParentId(this); - if (const auto group = Get()) { - if (group->leader != this) { - group->leader->refreshDataId(); - } - } + media->refreshParentId(data()); + // #TODO refresh sent album items + //if (const auto group = Get()) { + // if (group->leader != this) { + // group->leader->refreshDataId(); + // } + //} } } @@ -325,20 +343,20 @@ void Element::setDisplayDate(bool displayDate) { void Element::setAttachToNext(bool attachToNext) { if (attachToNext && !(_flags & Flag::AttachedToNext)) { _flags |= Flag::AttachedToNext; - Auth().data().requestItemRepaint(data()); + Auth().data().requestViewResize(this); } else if (!attachToNext && (_flags & Flag::AttachedToNext)) { _flags &= ~Flag::AttachedToNext; - Auth().data().requestItemRepaint(data()); + Auth().data().requestViewResize(this); } } void Element::setAttachToPrevious(bool attachToPrevious) { if (attachToPrevious && !(_flags & Flag::AttachedToPrevious)) { _flags |= Flag::AttachedToPrevious; - setPendingResize(); + Auth().data().requestViewResize(this); } else if (!attachToPrevious && (_flags & Flag::AttachedToPrevious)) { _flags &= ~Flag::AttachedToPrevious; - setPendingResize(); + Auth().data().requestViewResize(this); } } @@ -502,7 +520,7 @@ void Element::clickHandlerActiveChanged( } } App::hoveredLinkItem(active ? this : nullptr); - Auth().data().requestItemRepaint(_data); + Auth().data().requestViewRepaint(this); if (const auto media = this->media()) { media->clickHandlerActiveChanged(handler, active); } @@ -517,7 +535,7 @@ void Element::clickHandlerPressedChanged( } } App::pressedLinkItem(pressed ? this : nullptr); - Auth().data().requestItemRepaint(_data); + Auth().data().requestViewRepaint(this); if (const auto media = this->media()) { media->clickHandlerPressedChanged(handler, pressed); } diff --git a/Telegram/SourceFiles/history/view/history_view_element.h b/Telegram/SourceFiles/history/view/history_view_element.h index 5862cdb37..4545add3f 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.h +++ b/Telegram/SourceFiles/history/view/history_view_element.h @@ -13,6 +13,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL class HistoryBlock; class HistoryItem; +class HistoryMessage; +class HistoryService; class HistoryMedia; class HistoryWebPage; struct HistoryTextState; @@ -21,6 +23,16 @@ enum InfoDisplayType : char; namespace HistoryView { +class Element; +class ElementDelegate { +public: + virtual std::unique_ptr elementCreate( + not_null message) = 0; + virtual std::unique_ptr elementCreate( + not_null message) = 0; + +}; + TextSelection UnshiftItemSelection( TextSelection selection, uint16 byLength); @@ -35,11 +47,11 @@ TextSelection ShiftItemSelection( const Text &byText); class Element; -struct Group : public RuntimeComponent { - MessageGroupId groupId = MessageGroupId::None; - Element *leader = nullptr; - std::vector> others; -}; +//struct Group : public RuntimeComponent { +// MessageGroupId groupId = MessageGroupId::None; +// Element *leader = nullptr; +// std::vector> others; +//}; enum class Context : char { History, @@ -86,11 +98,11 @@ public: virtual int infoWidth() const; bool isHiddenByGroup() const; - void makeGroupMember(not_null leader); - void makeGroupLeader(std::vector> &&others); - bool groupIdValidityChanged(); - void validateGroupId(); - Group *getFullGroup(); + //void makeGroupMember(not_null leader); + //void makeGroupLeader(std::vector> &&others); + //bool groupIdValidityChanged(); + //void validateGroupId(); + //Group *getFullGroup(); // For blocks context this should be called only from recountAttachToPreviousInBlocks(). void setAttachToPrevious(bool attachToNext); @@ -197,8 +209,8 @@ private: virtual QSize performCountOptimalSize() = 0; virtual QSize performCountCurrentSize(int newWidth) = 0; - void initGroup(); - void resetGroupMedia(const std::vector> &others); + void refreshMedia(); + //void resetGroupMedia(const std::vector> &others); const not_null _data; std::unique_ptr _media; diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index abb4b9e55..bc50f44a8 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -221,7 +221,7 @@ ListWidget::ListWidget( , _scrollDateCheck([this] { scrollDateCheck(); }) { setMouseTracking(true); _scrollDateHideTimer.setCallback([this] { scrollDateHideByTimer(); }); - Auth().data().itemRepaintRequest( + Auth().data().itemViewRepaintRequest( ) | rpl::start_with_next([this](auto item) { if (const auto view = viewForItem(item)) { repaintItem(view); @@ -306,7 +306,7 @@ not_null ListWidget::enforceViewForItem( } const auto [i, ok] = _views.emplace( item, - item->createView(_controller, _context)); + item->createView(_delegate)); return i->second.get(); } diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.h b/Telegram/SourceFiles/history/view/history_view_list_widget.h index 101073bee..1a3b95531 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.h +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.h @@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/timer.h" #include "data/data_messages.h" #include "history/view/history_view_cursor_state.h" +#include "history/view/history_view_element.h" namespace Ui { class PopupMenu; @@ -25,9 +26,8 @@ class Controller; namespace HistoryView { enum class Context : char; -class Element; -class ListDelegate { +class ListDelegate : public ElementDelegate { public: virtual Context listContext() = 0; virtual void listScrollTo(int top) = 0; @@ -36,6 +36,7 @@ public: Data::MessagePosition aroundId, int limitBefore, int limitAfter) = 0; + }; class ListMemento { diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index 73000510b..bea34717c 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -57,7 +57,7 @@ const style::TextStyle &KeyboardStyle::textStyle() const { } void KeyboardStyle::repaint(not_null item) const { - Auth().data().requestItemRepaint(item); + Auth().data().requestItemViewRepaint(item); } int KeyboardStyle::buttonRadius() const { diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp index fb7b71582..73fbc1c2e 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp +++ b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp @@ -569,7 +569,7 @@ void ListWidget::start() { ) | rpl::start_with_next([this](auto item) { itemRemoved(item); }, lifetime()); - Auth().data().itemRepaintRequest( + Auth().data().itemViewRepaintRequest( ) | rpl::start_with_next([this](auto item) { repaintItem(item); }, lifetime()); diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.cpp index dca4fd3cc..cfc37d613 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.cpp @@ -210,19 +210,26 @@ const DocumentItems *documentItems() { namespace internal { -void regDocumentItem(DocumentData *document, ItemBase *item) { +void regDocumentItem( + not_null document, + not_null item) { documentItemsMap.createIfNull(); (*documentItemsMap)[document].insert(item); } -void unregDocumentItem(DocumentData *document, ItemBase *item) { +void unregDocumentItem( + not_null document, + not_null item) { if (documentItemsMap) { auto i = documentItemsMap->find(document); if (i != documentItemsMap->cend()) { - if (i->remove(item) && i->isEmpty()) { + if (i->second.remove(item) && i->second.empty()) { documentItemsMap->erase(i); } } + if (documentItemsMap->empty()) { + documentItemsMap.clear(); + } } } diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.h b/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.h index 1d0aba85b..c362b3622 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.h +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.h @@ -115,13 +115,19 @@ private: }; -using DocumentItems = QMap>; +using DocumentItems = std::map< + not_null, + base::flat_set>>; const DocumentItems *documentItems(); namespace internal { -void regDocumentItem(DocumentData *document, ItemBase *item); -void unregDocumentItem(DocumentData *document, ItemBase *item); +void regDocumentItem( + not_null document, + not_null item); +void unregDocumentItem( + not_null document, + not_null item); } // namespace internal } // namespace Layout diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp index c1e9ee56f..3f2656a3e 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp @@ -9,11 +9,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_photo.h" #include "data/data_document.h" +#include "data/data_session.h" #include "inline_bots/inline_bot_layout_item.h" #include "inline_bots/inline_bot_send_data.h" #include "storage/file_download.h" #include "core/file_utilities.h" #include "mainwidget.h" +#include "auth_session.h" namespace InlineBots { @@ -78,10 +80,10 @@ std::unique_ptr Result::create(uint64 queryId, const MTPBotInlineResult if (r.has_title()) result->_title = qs(r.vtitle); if (r.has_description()) result->_description = qs(r.vdescription); if (r.has_photo()) { - result->_photo = App::feedPhoto(r.vphoto); + result->_photo = Auth().data().photo(r.vphoto); } if (r.has_document()) { - result->_document = App::feedDocument(r.vdocument); + result->_document = Auth().data().document(r.vdocument); } message = &r.vsend_message; } break; @@ -315,7 +317,13 @@ void Result::createPhoto() { ImagePtr full = ImagePtr(_content_url, _width, _height); auto photoId = rand_value(); - _photo = App::photoSet(photoId, 0, 0, unixtime(), _thumb, medium, full); + _photo = Auth().data().photo( + photoId, + uint64(0), + unixtime(), + _thumb, + medium, + full); _photo->thumb = _thumb; } @@ -354,15 +362,32 @@ void Result::createDocument() { } auto documentId = rand_value(); - _document = App::documentSet(documentId, nullptr, 0, 0, unixtime(), attributes, mime, _thumb, MTP::maindc(), 0, StorageImageLocation()); + _document = Auth().data().document( + documentId, + uint64(0), + int32(0), + unixtime(), + attributes, + mime, + _thumb, + MTP::maindc(), + int32(0), + StorageImageLocation()); _document->setContentUrl(_content_url); } void Result::createGame() { if (_game) return; - auto gameId = rand_value(); - _game = App::gameSet(gameId, nullptr, 0, QString(), _title, _description, _photo, _document); + const auto gameId = rand_value(); + _game = Auth().data().game( + gameId, + 0, + QString(), + _title, + _description, + _photo, + _document); } } // namespace InlineBots diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 838ceb89c..c6c3dcc17 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -256,9 +256,6 @@ MainWidget::MainWidget( connect(&_updateMutedTimer, SIGNAL(timeout()), this, SLOT(onUpdateMuted())); connect(&_viewsIncrementTimer, SIGNAL(timeout()), this, SLOT(onViewsIncrement())); - _webPageOrGameUpdater.setSingleShot(true); - connect(&_webPageOrGameUpdater, SIGNAL(timeout()), this, SLOT(webPagesOrGamesUpdate())); - using Update = Window::Theme::BackgroundUpdate; subscribe(Window::Theme::Background(), [this](const Update &update) { if (update.type == Update::Type::New || update.type == Update::Type::Changed) { @@ -689,44 +686,6 @@ void MainWidget::finishForwarding(not_null history) { _history->peerMessagesUpdated(history->peer->id); } -void MainWidget::webPageUpdated(WebPageData *data) { - _webPagesUpdated.insert(data->id); - _webPageOrGameUpdater.start(0); -} - -void MainWidget::gameUpdated(GameData *data) { - _gamesUpdated.insert(data->id); - _webPageOrGameUpdater.start(0); -} - -void MainWidget::webPagesOrGamesUpdate() { - _webPageOrGameUpdater.stop(); - if (!_webPagesUpdated.isEmpty()) { - auto &items = App::webPageItems(); - for_const (auto webPageId, _webPagesUpdated) { - auto j = items.constFind(App::webPage(webPageId)); - if (j != items.cend()) { - for_const (auto item, j.value()) { - Auth().data().requestItemViewResize(item); - } - } - } - _webPagesUpdated.clear(); - } - if (!_gamesUpdated.isEmpty()) { - auto &items = App::gameItems(); - for_const (auto gameId, _gamesUpdated) { - auto j = items.constFind(App::game(gameId)); - if (j != items.cend()) { - for_const (auto item, j.value()) { - Auth().data().requestItemViewResize(item); - } - } - } - _gamesUpdated.clear(); - } -} - void MainWidget::updateMutedIn(TimeMs delay) { accumulate_max(delay, 24 * 3600 * 1000LL); if (!_updateMutedTimer.isActive() @@ -1435,8 +1394,11 @@ void MainWidget::sendMessage(const MessageToSend &message) { if (message.webPageId == CancelledWebPageId) { sendFlags |= MTPmessages_SendMessage::Flag::f_no_webpage; } else if (message.webPageId) { - auto page = App::webPage(message.webPageId); - media = MTP_messageMediaWebPage(MTP_webPagePending(MTP_long(page->id), MTP_int(page->pendingTill))); + auto page = Auth().data().webpage(message.webPageId); + media = MTP_messageMediaWebPage( + MTP_webPagePending( + MTP_long(page->id), + MTP_int(page->pendingTill))); flags |= MTPDmessage::Flag::f_media; } bool channelPost = peer->isChannel() && !peer->isMegagroup(); @@ -1600,20 +1562,14 @@ void MainWidget::messagesAffected( } } -void MainWidget::messagesContentsRead( - const MTPmessages_AffectedMessages &result) { - const auto &data = result.c_messages_affectedMessages(); - ptsUpdateAndApply(data.vpts.v, data.vpts_count.v); -} - void MainWidget::handleAudioUpdate(const AudioMsgId &audioId) { using State = Media::Player::State; + const auto document = audioId.audio(); auto state = Media::Player::mixer()->currentState(audioId.type()); if (state.id == audioId && state.state == State::StoppedAtStart) { state.state = State::Stopped; Media::Player::mixer()->clearStoppedAtStart(audioId); - auto document = audioId.audio(); auto filepath = document->filepath(DocumentData::FilePathResolveSaveFromData); if (!filepath.isEmpty()) { if (documentIsValidMediaFile(filepath)) { @@ -1628,13 +1584,15 @@ void MainWidget::handleAudioUpdate(const AudioMsgId &audioId) { } } - if (auto item = App::histItemById(audioId.contextId())) { - Auth().data().requestItemRepaint(item); + if (const auto item = App::histItemById(audioId.contextId())) { + Auth().data().requestItemViewRepaint(item); item->audioTrackUpdated(); } - if (auto items = InlineBots::Layout::documentItems()) { - for (auto item : items->value(audioId.audio())) { - item->update(); + if (const auto items = InlineBots::Layout::documentItems()) { + if (const auto i = items->find(document); i != items->end()) { + for (const auto item : i->second) { + item->update(); + } } } } @@ -1795,7 +1753,7 @@ void MainWidget::callTopBarHeightUpdated(int callTopBarHeight) { void MainWidget::documentLoadProgress(FileLoader *loader) { if (auto documentId = loader ? loader->objId() : 0) { - documentLoadProgress(App::document(documentId)); + documentLoadProgress(Auth().data().document(documentId)); } } @@ -1804,13 +1762,7 @@ void MainWidget::documentLoadProgress(DocumentData *document) { document->performActionOnLoad(); } - auto &items = App::documentItems(); - auto i = items.constFind(document); - if (i != items.cend()) { - for_const (auto item, i.value()) { - Auth().data().requestItemRepaint(item); - } - } + Auth().data().requestDocumentViewRepaint(document); Auth().documentUpdated.notify(document, true); if (!document->loaded() && document->isAudioFile()) { @@ -1822,7 +1774,7 @@ void MainWidget::documentLoadFailed(FileLoader *loader, bool started) { auto documentId = loader ? loader->objId() : 0; if (!documentId) return; - auto document = App::document(documentId); + auto document = Auth().data().document(documentId); if (started) { auto failedFileName = loader->fileName(); Ui::show(Box(lang(lng_download_finish_failed), base::lambda_guarded(this, [this, document, failedFileName] { @@ -1862,63 +1814,6 @@ void MainWidget::inlineResultLoadFailed(FileLoader *loader, bool started) { //Ui::repaintInlineItem(); } -void MainWidget::mediaMarkRead(not_null data) { - auto &items = App::documentItems(); - auto i = items.constFind(data); - if (i != items.cend()) { - mediaMarkRead({ i.value().begin(), i.value().end() }); - } -} - -void MainWidget::mediaMarkRead( - const base::flat_set> &items) { - QVector markedIds; - base::flat_map, QVector> channelMarkedIds; - markedIds.reserve(items.size()); - for (const auto item : items) { - if (!item->isMediaUnread() || (item->out() && !item->mentionsMe())) { - continue; - } - item->markMediaRead(); - if (item->id > 0) { - if (const auto channel = item->history()->peer->asChannel()) { - channelMarkedIds[channel].push_back(MTP_int(item->id)); - } else { - markedIds.push_back(MTP_int(item->id)); - } - } - } - if (!markedIds.isEmpty()) { - MTP::send( - MTPmessages_ReadMessageContents(MTP_vector(markedIds)), - rpcDone(&MainWidget::messagesContentsRead)); - } - for (const auto &channelIds : channelMarkedIds) { - MTP::send(MTPchannels_ReadMessageContents( - channelIds.first->inputChannel, - MTP_vector(channelIds.second))); - } -} - -void MainWidget::mediaMarkRead(not_null item) { - if ((!item->out() || item->mentionsMe()) && item->isMediaUnread()) { - item->markMediaRead(); - if (item->id > 0) { - const auto ids = MTP_vector(1, MTP_int(item->id)); - if (const auto channel = item->history()->peer->asChannel()) { - MTP::send( - MTPchannels_ReadMessageContents( - channel->inputChannel, - ids)); - } else { - MTP::send( - MTPmessages_ReadMessageContents(ids), - rpcDone(&MainWidget::messagesContentsRead)); - } - } - } -} - void MainWidget::onSendFileConfirm( const std::shared_ptr &file) { _history->sendFileConfirmed(file); @@ -4808,8 +4703,9 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) { const auto entities = d.has_entities() ? TextUtilities::EntitiesFromMTP(d.ventities.v) : EntitiesInText(); + const auto media = d.has_media() ? &d.vmedia : nullptr; item->setText({ text, entities }); - item->updateMedia(d.has_media() ? (&d.vmedia) : nullptr); + item->updateSentMedia(media); if (!wasAlready) { item->indexAsNewItem(); } @@ -4927,7 +4823,8 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { auto &d = update.c_updateChannelReadMessagesContents(); auto channel = App::channelLoaded(d.vchannel_id.v); if (!channel) { - if (!_byMinChannelTimer.isActive()) { // getDifference after timeout + if (!_byMinChannelTimer.isActive()) { + // getDifference after timeout. _byMinChannelTimer.start(WaitForSkippedTimeout); } return; @@ -4937,7 +4834,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { if (auto item = App::histItemById(channel, msgId.v)) { if (item->isMediaUnread()) { item->markMediaRead(); - Auth().data().requestItemRepaint(item); + Auth().data().requestItemViewRepaint(item); } } else { // Perhaps it was an unread mention! @@ -5040,9 +4937,9 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { auto &d = update.c_updateWebPage(); // Update web page anyway. - App::feedWebPage(d.vwebpage); + Auth().data().webpage(d.vwebpage); _history->updatePreview(); - webPagesOrGamesUpdate(); + Auth().data().sendWebPageGameNotifications(); ptsUpdateAndApply(d.vpts.v, d.vpts_count.v, update); } break; @@ -5051,9 +4948,9 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { auto &d = update.c_updateChannelWebPage(); // Update web page anyway. - App::feedWebPage(d.vwebpage); + Auth().data().webpage(d.vwebpage); _history->updatePreview(); - webPagesOrGamesUpdate(); + Auth().data().sendWebPageGameNotifications(); auto channel = App::channelLoaded(d.vchannel_id.v); if (channel && !_handlingChannelDifference) { @@ -5419,8 +5316,8 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { it->stickers.clear(); it->stickers.reserve(v.size()); for (int i = 0, l = v.size(); i < l; ++i) { - auto doc = App::feedDocument(v.at(i)); - if (!doc || !doc->sticker()) continue; + const auto doc = Auth().data().document(v.at(i)); + if (!doc->sticker()) continue; it->stickers.push_back(doc); if (doc->sticker()->set.type() != mtpc_inputStickerSetID) { @@ -5439,8 +5336,8 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { Stickers::Pack p; p.reserve(stickers.size()); for (auto j = 0, c = stickers.size(); j != c; ++j) { - auto doc = App::document(stickers[j].v); - if (!doc || !doc->sticker()) continue; + auto doc = Auth().data().document(stickers[j].v); + if (!doc->sticker()) continue; p.push_back(doc); } diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index ea11e2c11..4aa5df27a 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -279,12 +279,6 @@ public: void cancelForwarding(not_null history); void finishForwarding(not_null history); - void mediaMarkRead(not_null data); - void mediaMarkRead(const base::flat_set> &items); - void mediaMarkRead(not_null item); - - void webPageUpdated(WebPageData *page); - void gameUpdated(GameData *game); void updateMutedIn(TimeMs delay); // Does offerPeer or showPeerHistory. @@ -349,8 +343,6 @@ signals: void dialogsUpdated(); public slots: - void webPagesOrGamesUpdate(); - void documentLoadProgress(FileLoader *loader); void documentLoadFailed(FileLoader *loader, bool started); void inlineResultLoadProgress(FileLoader *loader); @@ -456,7 +448,6 @@ private: void messagesAffected( not_null peer, const MTPmessages_AffectedMessages &result); - void messagesContentsRead(const MTPmessages_AffectedMessages &result); Window::SectionSlideParams prepareShowAnimation( bool willHaveTopBarShadow); @@ -552,10 +543,6 @@ private: not_null _controller; bool _started = false; - OrderedSet _webPagesUpdated; - OrderedSet _gamesUpdated; - QTimer _webPageOrGameUpdater; - SingleTimer _updateMutedTimer; QString _inviteHash; diff --git a/Telegram/SourceFiles/media/player/media_player_float.cpp b/Telegram/SourceFiles/media/player/media_player_float.cpp index 1d30bbd67..60d230827 100644 --- a/Telegram/SourceFiles/media/player/media_player_float.cpp +++ b/Telegram/SourceFiles/media/player/media_player_float.cpp @@ -47,7 +47,7 @@ Float::Float( rpl::merge( Auth().data().itemLayoutChanged(), - Auth().data().itemRepaintRequest() + Auth().data().itemViewRepaintRequest() ) | rpl::start_with_next([this](auto item) { if (_item == item) { repaintItem(); diff --git a/Telegram/SourceFiles/media/view/media_view_group_thumbs.cpp b/Telegram/SourceFiles/media/view/media_view_group_thumbs.cpp index e78cb8de4..15dd1864c 100644 --- a/Telegram/SourceFiles/media/view/media_view_group_thumbs.cpp +++ b/Telegram/SourceFiles/media/view/media_view_group_thumbs.cpp @@ -12,8 +12,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_photo.h" #include "data/data_document.h" #include "data/data_media_types.h" +#include "data/data_session.h" #include "history/history.h" #include "history/history_media.h" +#include "auth_session.h" #include "styles/style_mediaview.h" namespace Media { @@ -470,7 +472,7 @@ void GroupThumbs::animatePreviouslyAlive( auto GroupThumbs::createThumb(Key key) -> std::unique_ptr { if (const auto photoId = base::get_if(&key)) { - const auto photo = App::photo(*photoId); + const auto photo = Auth().data().photo(*photoId); return createThumb(key, photo->date ? photo->thumb : ImagePtr()); } else if (const auto msgId = base::get_if(&key)) { if (const auto item = App::histItemById(*msgId)) { diff --git a/Telegram/SourceFiles/mediaview.cpp b/Telegram/SourceFiles/mediaview.cpp index eff81df00..6cb58d781 100644 --- a/Telegram/SourceFiles/mediaview.cpp +++ b/Telegram/SourceFiles/mediaview.cpp @@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_message.h" #include "history/history_media_types.h" #include "data/data_media_types.h" +#include "data/data_session.h" #include "window/themes/window_theme_preview.h" #include "window/window_peer_menu.h" #include "observer_peer.h" @@ -1299,7 +1300,7 @@ void MediaView::initGroupThumbs() { _groupThumbs->activateRequests( ) | rpl::start_with_next([this](Media::View::GroupThumbs::Key key) { if (const auto photoId = base::get_if(&key)) { - const auto photo = App::photo(*photoId); + const auto photo = Auth().data().photo(*photoId); moveToEntity({ photo, nullptr }); } else if (const auto itemId = base::get_if(&key)) { moveToEntity(entityForItemId(*itemId)); @@ -2425,7 +2426,7 @@ MediaView::Entity MediaView::entityForUserPhotos(int index) const { if (index < 0 || index >= _userPhotosData->size()) { return { base::none, nullptr }; } - if (auto photo = App::photo((*_userPhotosData)[index])) { + if (auto photo = Auth().data().photo((*_userPhotosData)[index])) { return { photo, nullptr }; } return { base::none, nullptr }; diff --git a/Telegram/SourceFiles/messenger.cpp b/Telegram/SourceFiles/messenger.cpp index 83563c925..5494a4d5d 100644 --- a/Telegram/SourceFiles/messenger.cpp +++ b/Telegram/SourceFiles/messenger.cpp @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include #include "data/data_photo.h" #include "data/data_document.h" +#include "data/data_session.h" #include "base/timer.h" #include "storage/localstorage.h" #include "platform/platform_specific.h" @@ -530,8 +531,8 @@ void Messenger::chatPhotoCleared(PeerId peer, const MTPUpdates &updates) { void Messenger::selfPhotoDone(const MTPphotos_Photo &result) { if (!App::self()) return; - const auto &photo(result.c_photos_photo()); - App::feedPhoto(photo.vphoto); + const auto &photo = result.c_photos_photo(); + Auth().data().photo(photo.vphoto); App::feedUsers(photo.vusers); cancelPhotoUpdate(App::self()->id); emit peerPhotoDone(App::self()->id); diff --git a/Telegram/SourceFiles/overview/overview_layout.cpp b/Telegram/SourceFiles/overview/overview_layout.cpp index e87b50f1f..71325ad41 100644 --- a/Telegram/SourceFiles/overview/overview_layout.cpp +++ b/Telegram/SourceFiles/overview/overview_layout.cpp @@ -127,7 +127,7 @@ ItemBase::ItemBase(not_null parent) : _parent(parent) { void ItemBase::clickHandlerActiveChanged( const ClickHandlerPtr &action, bool active) { - Auth().data().requestItemRepaint(_parent); + Auth().data().requestItemViewRepaint(_parent); if (_check) { _check->setActive(active); } @@ -136,7 +136,7 @@ void ItemBase::clickHandlerActiveChanged( void ItemBase::clickHandlerPressedChanged( const ClickHandlerPtr &action, bool pressed) { - Auth().data().requestItemRepaint(_parent); + Auth().data().requestItemViewRepaint(_parent); if (_check) { _check->setPressed(pressed); } @@ -168,7 +168,7 @@ const style::RoundCheckbox &ItemBase::checkboxStyle() const { void ItemBase::ensureCheckboxCreated() { if (!_check) { _check = std::make_unique( - [this] { Auth().data().requestItemRepaint(_parent); }, + [=] { Auth().data().requestItemViewRepaint(_parent); }, checkboxStyle()); } } @@ -203,7 +203,7 @@ void RadialProgressItem::clickHandlerActiveChanged(const ClickHandlerPtr &action if (action == _openl || action == _savel || action == _cancell) { if (iconAnimated()) { _a_iconOver.start( - [this] { Auth().data().requestItemRepaint(parent()); }, + [=] { Auth().data().requestItemViewRepaint(parent()); }, active ? 0. : 1., active ? 1. : 0., st::msgFileOverDuration); @@ -219,7 +219,7 @@ void RadialProgressItem::setLinks(ClickHandlerPtr &&openl, ClickHandlerPtr &&sav void RadialProgressItem::step_radial(TimeMs ms, bool timer) { if (timer) { - Auth().data().requestItemRepaint(parent()); + Auth().data().requestItemViewRepaint(parent()); } else { _radial->update(dataProgress(), dataFinished(), ms); if (!_radial->animating()) { diff --git a/Telegram/SourceFiles/settings/settings_cover.cpp b/Telegram/SourceFiles/settings/settings_cover.cpp index 5b4f89f6f..5d988324a 100644 --- a/Telegram/SourceFiles/settings/settings_cover.cpp +++ b/Telegram/SourceFiles/settings/settings_cover.cpp @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "settings/settings_cover.h" #include "data/data_photo.h" +#include "data/data_session.h" #include "ui/widgets/labels.h" #include "ui/widgets/buttons.h" #include "ui/special_buttons.h" @@ -84,7 +85,7 @@ PhotoData *CoverWidget::validatePhoto() const { Expects(_self != nullptr); const auto photo = _self->userpicPhotoId() - ? App::photo(_self->userpicPhotoId()) + ? Auth().data().photo(_self->userpicPhotoId()).get() : nullptr; _userpicButton->setPointerCursor(photo != nullptr && photo->date != 0); if (_self->userpicPhotoUnknown() || (photo && !photo->date)) { diff --git a/Telegram/SourceFiles/settings/settings_info_widget.cpp b/Telegram/SourceFiles/settings/settings_info_widget.cpp index bff14d728..d48cb644c 100644 --- a/Telegram/SourceFiles/settings/settings_info_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_info_widget.cpp @@ -14,8 +14,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/username_box.h" #include "boxes/add_contact_box.h" #include "boxes/change_phone_box.h" +#include "data/data_session.h" #include "observer_peer.h" #include "messenger.h" +#include "auth_session.h" namespace Settings { @@ -47,12 +49,8 @@ void InfoWidget::refreshControls() { void InfoWidget::refreshMobileNumber() { TextWithEntities phoneText; - if (auto user = self()->asUser()) { - if (!user->phone().isEmpty()) { - phoneText.text = App::formatPhone(user->phone()); - } else { - phoneText.text = App::phoneFromSharedContact(peerToUser(user->id)); - } + if (const auto user = self()->asUser()) { + phoneText.text = Auth().data().findContactPhone(user); } setLabeledText( _mobileNumber, diff --git a/Telegram/SourceFiles/storage/file_upload.cpp b/Telegram/SourceFiles/storage/file_upload.cpp index ef0af0eaa..994194c35 100644 --- a/Telegram/SourceFiles/storage/file_upload.cpp +++ b/Telegram/SourceFiles/storage/file_upload.cpp @@ -10,6 +10,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "storage/localimageloader.h" #include "data/data_document.h" #include "data/data_photo.h" +#include "data/data_session.h" +#include "auth_session.h" namespace Storage { namespace { @@ -116,14 +118,11 @@ Uploader::Uploader() { void Uploader::uploadMedia(const FullMsgId &msgId, const SendMediaReady &media) { if (media.type == SendMediaType::Photo) { - App::feedPhoto(media.photo, media.photoThumbs); + Auth().data().photo(media.photo, media.photoThumbs); } else if (media.type == SendMediaType::File || media.type == SendMediaType::Audio) { - DocumentData *document; - if (media.photoThumbs.isEmpty()) { - document = App::feedDocument(media.document); - } else { - document = App::feedDocument(media.document, media.photoThumbs.begin().value()); - } + const auto document = media.photoThumbs.isEmpty() + ? Auth().data().document(media.document) + : Auth().data().document(media.document, media.photoThumbs.begin().value()); if (!media.data.isEmpty()) { document->setData(media.data); } @@ -139,10 +138,12 @@ void Uploader::upload( const FullMsgId &msgId, const std::shared_ptr &file) { if (file->type == SendMediaType::Photo) { - auto photo = App::feedPhoto(file->photo, file->photoThumbs); + auto photo = Auth().data().photo(file->photo, file->photoThumbs); photo->uploadingData = std::make_unique(file->partssize); } else if (file->type == SendMediaType::File || file->type == SendMediaType::Audio) { - auto document = file->thumb.isNull() ? App::feedDocument(file->document) : App::feedDocument(file->document, file->thumb); + auto document = file->thumb.isNull() + ? Auth().data().document(file->document) + : Auth().data().document(file->document, file->thumb); document->uploadingData = std::make_unique(document->size); if (!file->content.isEmpty()) { document->setData(file->content); @@ -161,7 +162,7 @@ void Uploader::currentFailed() { if (j->second.type() == SendMediaType::Photo) { emit photoFailed(j->first); } else if (j->second.type() == SendMediaType::File) { - const auto document = App::document(j->second.id()); + const auto document = Auth().data().document(j->second.id()); if (document->uploading()) { document->status = FileUploadFailed; } @@ -451,7 +452,7 @@ void Uploader::partLoaded(const MTPBool &result, mtpRequestId requestId) { sentSizes[dc] -= sentPartSize; if (file.type() == SendMediaType::Photo) { file.fileSentSize += sentPartSize; - const auto photo = App::photo(file.id()); + const auto photo = Auth().data().photo(file.id()); if (photo->uploading() && file.file) { photo->uploadingData->size = file.file->partssize; photo->uploadingData->offset = file.fileSentSize; @@ -459,7 +460,7 @@ void Uploader::partLoaded(const MTPBool &result, mtpRequestId requestId) { emit photoProgress(fullId); } else if (file.type() == SendMediaType::File || file.type() == SendMediaType::Audio) { - const auto document = App::document(file.id()); + const auto document = Auth().data().document(file.id()); if (document->uploading()) { const auto doneParts = file.docSentParts - int(docRequestsSent.size()); diff --git a/Telegram/SourceFiles/storage/localstorage.cpp b/Telegram/SourceFiles/storage/localstorage.cpp index 415800ca4..d8d67db18 100644 --- a/Telegram/SourceFiles/storage/localstorage.cpp +++ b/Telegram/SourceFiles/storage/localstorage.cpp @@ -3146,13 +3146,7 @@ public: voice->waveform[0] = -2; voice->wavemax = 0; } - auto &items = App::documentItems(); - auto i = items.constFind(_doc); - if (i != items.cend()) { - for_const (auto item, i.value()) { - Auth().data().requestItemRepaint(item); - } - } + Auth().data().requestDocumentViewRepaint(_doc); } } virtual ~CountWaveformTask() { @@ -3411,8 +3405,8 @@ void _readStickerSets(FileKey &stickersKey, Stickers::Order *outOrder = nullptr, for (int32 k = 0; k < stickersCount; ++k) { quint64 id; stickers.stream >> id; - DocumentData *doc = App::document(id); - if (!doc || !doc->sticker()) continue; + const auto doc = Auth().data().document(id); + if (!doc->sticker()) continue; pack.push_back(doc); } @@ -3562,7 +3556,17 @@ void importOldRecentStickers() { attributes.push_back(MTP_documentAttributeImageSize(MTP_int(width), MTP_int(height))); } - DocumentData *doc = App::documentSet(id, 0, access, 0, date, attributes, mime, ImagePtr(), dc, size, StorageImageLocation()); + const auto doc = Auth().data().document( + id, + access, + int32(0), + date, + attributes, + mime, + ImagePtr(), + dc, + size, + StorageImageLocation()); if (!doc->sticker()) continue; if (value > 0) { diff --git a/Telegram/SourceFiles/storage/serialize_document.cpp b/Telegram/SourceFiles/storage/serialize_document.cpp index a6dc79a16..04f980632 100644 --- a/Telegram/SourceFiles/storage/serialize_document.cpp +++ b/Telegram/SourceFiles/storage/serialize_document.cpp @@ -9,6 +9,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "storage/serialize_common.h" #include "chat_helpers/stickers.h" +#include "data/data_session.h" +#include "auth_session.h" namespace { @@ -119,7 +121,17 @@ DocumentData *Document::readFromStreamHelper(int streamAppVersion, QDataStream & if (!dc && !access) { return nullptr; } - return App::documentSet(id, nullptr, access, version, date, attributes, mime, thumb.isNull() ? ImagePtr() : ImagePtr(thumb), dc, size, thumb); + return Auth().data().document( + id, + access, + version, + date, + attributes, + mime, + thumb.isNull() ? ImagePtr() : ImagePtr(thumb), + dc, + size, + thumb); } DocumentData *Document::readStickerFromStream(int streamAppVersion, QDataStream &stream, const StickerSetInfo &info) { diff --git a/Telegram/SourceFiles/ui/special_buttons.cpp b/Telegram/SourceFiles/ui/special_buttons.cpp index 1224a628e..82cb8b714 100644 --- a/Telegram/SourceFiles/ui/special_buttons.cpp +++ b/Telegram/SourceFiles/ui/special_buttons.cpp @@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/effects/ripple_animation.h" #include "ui/empty_userpic.h" #include "data/data_photo.h" +#include "data/data_session.h" #include "core/file_utilities.h" #include "boxes/photo_crop_box.h" #include "boxes/confirm_box.h" @@ -479,7 +480,7 @@ void UserpicButton::openPeerPhoto() { if (!id) { return; } - const auto photo = App::photo(id); + const auto photo = Auth().data().photo(id); if (photo->date) { Messenger::Instance().showPhoto(photo, _peer); } diff --git a/Telegram/SourceFiles/window/window_controller.cpp b/Telegram/SourceFiles/window/window_controller.cpp index 70c39d050..a57544868 100644 --- a/Telegram/SourceFiles/window/window_controller.cpp +++ b/Telegram/SourceFiles/window/window_controller.cpp @@ -9,11 +9,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "window/main_window.h" #include "info/info_memento.h" -#include "history/view/history_view_element.h" -#include "history/view/history_view_message.h" -#include "history/view/history_view_service_message.h" #include "history/history.h" #include "history/history_item.h" +#include "history/view/history_view_element.h" #include "mainwidget.h" #include "mainwindow.h" #include "styles/style_window.h" @@ -407,16 +405,4 @@ not_null Controller::chats() const { return App::wnd()->chatsWidget(); } -std::unique_ptr Controller::createMessageView( - not_null message, - HistoryView::Context context) { - return std::make_unique(message, context); -} - -std::unique_ptr Controller::createMessageView( - not_null message, - HistoryView::Context context) { - return std::make_unique(message, context); -} - } // namespace Window diff --git a/Telegram/SourceFiles/window/window_controller.h b/Telegram/SourceFiles/window/window_controller.h index 0a5cfebde..13aeb7f4a 100644 --- a/Telegram/SourceFiles/window/window_controller.h +++ b/Telegram/SourceFiles/window/window_controller.h @@ -14,10 +14,6 @@ class MainWidget; class HistoryMessage; class HistoryService; -namespace HistoryView { -enum class Context : char; -} // namespace HistoryView - namespace Window { class LayerWidget; @@ -201,13 +197,6 @@ public: return this; } - std::unique_ptr createMessageView( - not_null message, - HistoryView::Context context); - std::unique_ptr createMessageView( - not_null message, - HistoryView::Context context); - private: int minimalThreeColumnWidth() const; not_null chats() const; diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index 95159458b..928810501 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -469,12 +469,10 @@ void PeerMenuDeleteContact(not_null user) { } void PeerMenuAddContact(not_null user) { - auto firstName = user->firstName; - auto lastName = user->lastName; - auto phone = user->phone().isEmpty() - ? App::phoneFromSharedContact(user->bareId()) - : user->phone(); - Ui::show(Box(firstName, lastName, phone)); + Ui::show(Box( + user->firstName, + user->lastName, + Auth().data().findContactPhone(user))); } void PeerMenuShareContactBox(not_null user) { diff --git a/Telegram/gyp/telegram_sources.txt b/Telegram/gyp/telegram_sources.txt index 7cdd6e0ac..39fe5908a 100644 --- a/Telegram/gyp/telegram_sources.txt +++ b/Telegram/gyp/telegram_sources.txt @@ -258,8 +258,6 @@ <(src_loc)/history/history_media.cpp <(src_loc)/history/history_media_grouped.h <(src_loc)/history/history_media_grouped.cpp -<(src_loc)/history/history_media_pointer.h -<(src_loc)/history/history_media_pointer.cpp <(src_loc)/history/history_media_types.cpp <(src_loc)/history/history_media_types.h <(src_loc)/history/history_message.cpp