From 68a0e32a3d5d22bcac9176dde87c301560e80e4f Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 29 Aug 2017 18:15:54 +0300 Subject: [PATCH] Add SharedMediaSliceWithLast for chat photos. --- .../history/history_shared_media.cpp | 323 +++++++++++++++-- .../history/history_shared_media.h | 327 +++++++++++------- Telegram/SourceFiles/mediaview.cpp | 298 +++++++--------- Telegram/SourceFiles/mediaview.h | 42 ++- 4 files changed, 634 insertions(+), 356 deletions(-) diff --git a/Telegram/SourceFiles/history/history_shared_media.cpp b/Telegram/SourceFiles/history/history_shared_media.cpp index 2a70bb8b2..3050d6802 100644 --- a/Telegram/SourceFiles/history/history_shared_media.cpp +++ b/Telegram/SourceFiles/history/history_shared_media.cpp @@ -24,6 +24,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "apiwrap.h" #include "storage/storage_facade.h" #include "storage/storage_shared_media.h" +#include "history/history_media_types.h" namespace { @@ -78,6 +79,45 @@ void SharedMediaShowOverview( } } +SharedMediaSlice::SharedMediaSlice(Key key) : SharedMediaSlice(key, base::none) { +} + +SharedMediaSlice::SharedMediaSlice( + Key key, + base::optional fullCount) + : _key(key) + , _fullCount(fullCount) { +} + +base::optional SharedMediaSlice::indexOf(MsgId msgId) const { + auto it = _ids.find(msgId); + if (it != _ids.end()) { + return (it - _ids.begin()); + } + return base::none; +} + +MsgId SharedMediaSlice::operator[](int index) const { + Expects(index >= 0 && index < size()); + + return *(_ids.begin() + index); +} + +base::optional SharedMediaSlice::distance(const Key &a, const Key &b) const { + if (a.type != _key.type + || b.type != _key.type + || a.peerId != _key.peerId + || b.peerId != _key.peerId) { + return base::none; + } + if (auto i = indexOf(a.messageId)) { + if (auto j = indexOf(b.messageId)) { + return *j - *i; + } + } + return base::none; +} + QString SharedMediaSlice::debug() const { auto before = _skippedBefore ? (*_skippedBefore @@ -97,7 +137,6 @@ QString SharedMediaSlice::debug() const { return before + middle + after; } - SharedMediaViewer::SharedMediaViewer( Key key, int limitBefore, @@ -312,6 +351,93 @@ void SharedMediaViewer::requestMessages(RequestDirection direction) { requestAroundData.second); } +SharedMediaSliceMerged::SharedMediaSliceMerged(Key key) : SharedMediaSliceMerged( + key, + SharedMediaSlice(PartKey(key)), + MigratedSlice(key)) { +} + +SharedMediaSliceMerged::SharedMediaSliceMerged( + Key key, + SharedMediaSlice part, + base::optional migrated) + : _key(key) + , _part(std::move(part)) + , _migrated(std::move(migrated)) { +} + +base::optional SharedMediaSliceMerged::fullCount() const { + return Add( + _part.fullCount(), + _migrated ? _migrated->fullCount() : 0); +} + +base::optional SharedMediaSliceMerged::skippedBefore() const { + return Add( + isolatedInMigrated() ? 0 : _part.skippedBefore(), + _migrated + ? (isolatedInPart() + ? _migrated->fullCount() + : _migrated->skippedBefore()) + : 0 + ); +} + +base::optional SharedMediaSliceMerged::skippedAfter() const { + return Add( + isolatedInMigrated() ? _part.fullCount() : _part.skippedAfter(), + isolatedInPart() ? 0 : _migrated->skippedAfter() + ); +} + +base::optional SharedMediaSliceMerged::indexOf(FullMsgId fullId) const { + return isFromPart(fullId) + ? (_part.indexOf(fullId.msg) | func::add(migratedSize())) + : isolatedInPart() + ? base::none + : isFromMigrated(fullId) + ? _migrated->indexOf(fullId.msg) + : base::none; +} + +int SharedMediaSliceMerged::size() const { + return (isolatedInPart() ? 0 : migratedSize()) + + (isolatedInMigrated() ? 0 : _part.size()); +} + +FullMsgId SharedMediaSliceMerged::operator[](int index) const { + Expects(index >= 0 && index < size()); + + if (auto size = migratedSize()) { + if (index < size) { + return ComputeId(*_migrated, index); + } + index -= size; + } + return ComputeId(_part, index); +} + +base::optional SharedMediaSliceMerged::distance(const Key &a, const Key &b) const { + if (a.type != _key.type + || b.type != _key.type + || a.peerId != _key.peerId + || b.peerId != _key.peerId + || a.migratedPeerId != _key.migratedPeerId + || b.migratedPeerId != _key.migratedPeerId) { + return base::none; + } + if (auto i = indexOf(ComputeId(a))) { + if (auto j = indexOf(ComputeId(b))) { + return *j - *i; + } + } + return base::none; +} + +QString SharedMediaSliceMerged::debug() const { + return (_migrated ? (_migrated->debug() + '|') : QString()) + _part.debug(); +} + SharedMediaViewerMerged::SharedMediaViewerMerged( Key key, int limitBefore, @@ -319,59 +445,35 @@ SharedMediaViewerMerged::SharedMediaViewerMerged( : _key(key) , _limitBefore(limitBefore) , _limitAfter(limitAfter) - , _part(PartKey(_key), _limitBefore, _limitAfter) + , _part(SharedMediaSliceMerged::PartKey(_key), _limitBefore, _limitAfter) , _migrated(MigratedViewer(_key, _limitBefore, _limitAfter)) - , _data(_key, SharedMediaSlice(PartKey(_key)), MigratedSlice(_key)) { + , _data(_key) { Expects(IsServerMsgId(key.universalId) || (key.universalId == 0) || (IsServerMsgId(-key.universalId) && key.migratedPeerId != 0)); Expects((key.universalId != 0) || (limitBefore == 0 && limitAfter == 0)); } -SharedMediaSlice::Key SharedMediaViewerMerged::PartKey(const Key &key) { - return { - key.peerId, - key.type, - (key.universalId < 0) ? 1 : key.universalId - }; -} - -SharedMediaSlice::Key SharedMediaViewerMerged::MigratedKey(const Key &key) { - return { - key.migratedPeerId, - key.type, - (key.universalId <= 0) ? (-key.universalId) : (ServerMaxMsgId - 1) - }; -} - std::unique_ptr SharedMediaViewerMerged::MigratedViewer( const Key &key, int limitBefore, int limitAfter) { return key.migratedPeerId ? std::make_unique( - MigratedKey(key), + SharedMediaSliceMerged::MigratedKey(key), limitBefore, limitAfter) : nullptr; } -base::optional SharedMediaViewerMerged::MigratedSlice( - const Key &key) { - if (!key.migratedPeerId) { - return base::none; - } - return SharedMediaSlice(MigratedKey(key)); -} - void SharedMediaViewerMerged::start() { subscribe(_part.updated, [this](const SharedMediaSlice &update) { - _data = SharedMediaSliceMerged(_key, update, _data._migrated); + _data = SharedMediaSliceMerged(_key, update, std::move(_data._migrated)); updated.notify(_data); }); if (_migrated) { subscribe(_migrated->updated, [this](const SharedMediaSlice &update) { - _data = SharedMediaSliceMerged(_key, _data._part, update); + _data = SharedMediaSliceMerged(_key, std::move(_data._part), update); updated.notify(_data); }); } @@ -380,3 +482,164 @@ void SharedMediaViewerMerged::start() { _migrated->start(); } } + +SharedMediaSliceWithLast::SharedMediaSliceWithLast(Key key) : SharedMediaSliceWithLast( + key, + SharedMediaSliceMerged(ViewerKey(key)), + EndingSlice(key)) { +} + +SharedMediaSliceWithLast::SharedMediaSliceWithLast( + Key key, + SharedMediaSliceMerged slice, + base::optional ending) + : _key(key) + , _slice(std::move(slice)) + , _ending(std::move(ending)) + , _lastPhotoId(LastPeerPhotoId(key.peerId)) + , _isolatedLastPhoto(_key.type == Type::ChatPhoto + ? IsLastIsolated(_slice, _ending, _lastPhotoId) + : false) { +} + +base::optional SharedMediaSliceWithLast::fullCount() const { + return Add( + _slice.fullCount(), + _isolatedLastPhoto | [](bool isolated) { return isolated ? 1 : 0; }); +} + +base::optional SharedMediaSliceWithLast::skippedBefore() const { + return _slice.skippedBefore(); +} + +base::optional SharedMediaSliceWithLast::skippedAfter() const { + return isolatedInSlice() + ? Add( + _slice.skippedAfter(), + lastPhotoSkip()) + : (lastPhotoSkip() | [](int) { return 0; }); +} + +base::optional SharedMediaSliceWithLast::indexOf(Value value) const { + return base::get_if(&value) + ? _slice.indexOf(*base::get_if(&value)) + : (isolatedInSlice() + || (*base::get_if>(&value))->id != _lastPhotoId) + ? base::none + : Add(_slice.size() - 1, lastPhotoSkip()); +} + +int SharedMediaSliceWithLast::size() const { + return _slice.size() + + ((!isolatedInSlice() && lastPhotoSkip() == 1) ? 1 : 0); +} + +SharedMediaSliceWithLast::Value SharedMediaSliceWithLast::operator[](int index) const { + Expects(index >= 0 && index < size()); + + return (index < _slice.size()) + ? Value(_slice[index]) + : Value(App::photo(_lastPhotoId)); +} + +base::optional SharedMediaSliceWithLast::distance(const Key &a, const Key &b) const { + if (a.type != _key.type + || b.type != _key.type + || a.peerId != _key.peerId + || b.peerId != _key.peerId + || a.migratedPeerId != _key.migratedPeerId + || b.migratedPeerId != _key.migratedPeerId) { + return base::none; + } + if (auto i = indexOf(ComputeId(a))) { + if (auto j = indexOf(ComputeId(b))) { + return *j - *i; + } + } + return base::none; +} + +QString SharedMediaSliceWithLast::debug() const { + return _slice.debug() + (_isolatedLastPhoto + ? (*_isolatedLastPhoto ? "@" : "") + : "?"); +} + +PhotoId SharedMediaSliceWithLast::LastPeerPhotoId(PeerId peerId) { + if (auto peer = App::peerLoaded(peerId)) { + return peer->photoId; + } + return UnknownPeerPhotoId; +} + +base::optional SharedMediaSliceWithLast::IsLastIsolated( + const SharedMediaSliceMerged &slice, + const base::optional &ending, + PhotoId lastPeerPhotoId) { + if (lastPeerPhotoId == UnknownPeerPhotoId) { + return base::none; + } else if (!lastPeerPhotoId) { + return false; + } + return LastFullMsgId(ending ? *ending : slice) + | [](FullMsgId msgId) { return App::histItemById(msgId); } + | [](HistoryItem *item) { return item ? item->getMedia() : nullptr; } + | [](HistoryMedia *media) { + return (media && media->type() == MediaTypePhoto) + ? static_cast(media)->photo() + : nullptr; + } + | [](PhotoData *photo) { return photo ? photo->id : 0; } + | [&](PhotoId photoId) { return lastPeerPhotoId != photoId; }; +} + +base::optional SharedMediaSliceWithLast::LastFullMsgId( + const SharedMediaSliceMerged &slice) { + if (slice.fullCount() == 0) { + return FullMsgId(); + } else if (slice.size() == 0 || slice.skippedAfter() != 0) { + return base::none; + } + return slice[slice.size() - 1]; +} + +SharedMediaViewerWithLast::SharedMediaViewerWithLast( + Key key, + int limitBefore, + int limitAfter) + : _key(key) + , _limitBefore(limitBefore) + , _limitAfter(limitAfter) + , _viewer(SharedMediaSliceWithLast::ViewerKey(_key), _limitBefore, _limitAfter) + , _ending(EndingViewer(_key, _limitBefore, _limitAfter)) + , _data(_key) { +} + +std::unique_ptr SharedMediaViewerWithLast::EndingViewer( + const Key &key, + int limitBefore, + int limitAfter) { + return base::get_if(&key.universalId) + ? std::make_unique( + SharedMediaSliceWithLast::EndingKey(key), + 1, + 1) + : nullptr; +} + +void SharedMediaViewerWithLast::start() { + subscribe(_viewer.updated, [this](const SharedMediaSliceMerged &update) { + _data = SharedMediaSliceWithLast(_key, update, std::move(_data._ending)); + updated.notify(_data); + }); + if (_ending) { + subscribe(_ending->updated, [this](const SharedMediaSliceMerged &update) { + _data = SharedMediaSliceWithLast(_key, std::move(_data._slice), update); + updated.notify(_data); + }); + } + _viewer.start(); + if (_ending) { + _ending->start(); + } +} diff --git a/Telegram/SourceFiles/history/history_shared_media.h b/Telegram/SourceFiles/history/history_shared_media.h index b9b8b62c0..67872caae 100644 --- a/Telegram/SourceFiles/history/history_shared_media.h +++ b/Telegram/SourceFiles/history/history_shared_media.h @@ -35,57 +35,18 @@ class SharedMediaSlice { public: using Key = Storage::SharedMediaKey; - SharedMediaSlice( - Key key, - base::optional fullCount = base::none) - : _key(key) - , _fullCount(fullCount) { - } + SharedMediaSlice(Key key); + SharedMediaSlice(Key key, base::optional fullCount); - const Key &key() const { - return _key; - } + const Key &key() const { return _key; } - base::optional fullCount() const { - return _fullCount; - } - base::optional skippedBefore() const { - return _skippedBefore; - } - base::optional skippedAfter() const { - return _skippedAfter; - } - base::optional indexOf(MsgId msgId) const { - auto it = _ids.find(msgId); - if (it != _ids.end()) { - return (it - _ids.begin()); - } - return base::none; - } - int size() const { - return _ids.size(); - } - - MsgId operator[](int index) const { - Expects(index >= 0 && index < size()); - - return *(_ids.begin() + index); - } - - base::optional distance(const Key &a, const Key &b) const { - if (a.type != _key.type - || b.type != _key.type - || a.peerId != _key.peerId - || b.peerId != _key.peerId) { - return base::none; - } - if (auto i = indexOf(a.messageId)) { - if (auto j = indexOf(b.messageId)) { - return *j - *i; - } - } - return base::none; - } + base::optional fullCount() const { return _fullCount; } + base::optional skippedBefore() const { return _skippedBefore; } + base::optional skippedAfter() const { return _skippedAfter; } + base::optional indexOf(MsgId msgId) const; + int size() const { return _ids.size(); } + MsgId operator[](int index) const; + base::optional distance(const Key &a, const Key &b) const; QString debug() const; @@ -108,12 +69,7 @@ public: using Type = Storage::SharedMediaType; using Key = Storage::SharedMediaKey; - SharedMediaViewer( - Key key, - int limitBefore, - int limitAfter); - SharedMediaViewer(const SharedMediaViewer &other) = delete; - SharedMediaViewer(SharedMediaViewer &&other) = default; + SharedMediaViewer(Key key, int limitBefore, int limitAfter); void start(); @@ -182,84 +138,46 @@ public: UniversalMsgId universalId = 0; }; + + SharedMediaSliceMerged(Key key); SharedMediaSliceMerged( Key key, SharedMediaSlice part, - base::optional migrated) - : _key(key) - , _part(part) - , _migrated(migrated) { - } + base::optional migrated); - base::optional fullCount() const { - return Add( - _part.fullCount(), - _migrated ? _migrated->fullCount() : 0); - } - base::optional skippedBefore() const { - return Add( - isolatedInMigrated() ? 0 : _part.skippedBefore(), - _migrated - ? (isolatedInPart() - ? _migrated->fullCount() - : _migrated->skippedBefore()) - : 0 - ); - } - base::optional skippedAfter() const { - return Add( - isolatedInMigrated() ? _part.fullCount() : _part.skippedAfter(), - isolatedInPart() ? 0 : _migrated->skippedAfter() - ); - } - base::optional indexOf(FullMsgId fullId) const { - return isFromPart(fullId) - ? (_part.indexOf(fullId.msg) | func::add(migratedSize())) - : isolatedInPart() - ? base::none - : isFromMigrated(fullId) - ? _migrated->indexOf(fullId.msg) - : base::none; - } - int size() const { - return (isolatedInPart() ? 0 : migratedSize()) - + (isolatedInMigrated() ? 0 : _part.size()); - } + const Key &key() const { return _key; } - FullMsgId operator[](int index) const { - Expects(index >= 0 && index < size()); + base::optional fullCount() const; + base::optional skippedBefore() const; + base::optional skippedAfter() const; + base::optional indexOf(FullMsgId fullId) const; + int size() const; + FullMsgId operator[](int index) const; + base::optional distance(const Key &a, const Key &b) const; - if (auto size = migratedSize()) { - if (index < size) { - return ComputeId(*_migrated, index); - } - index -= size; - } - return ComputeId(_part, index); - } - - base::optional distance(const Key &a, const Key &b) const { - if (a.type != _key.type - || b.type != _key.type - || a.peerId != _key.peerId - || b.peerId != _key.peerId - || a.migratedPeerId != _key.migratedPeerId - || b.migratedPeerId != _key.migratedPeerId) { - return base::none; - } - if (auto i = indexOf(ComputeId(a))) { - if (auto j = indexOf(ComputeId(b))) { - return *j - *i; - } - } - return base::none; - } - - QString debug() const { - return (_migrated ? (_migrated->debug() + '|') : QString()) + _part.debug(); - } + QString debug() const; private: + static SharedMediaSlice::Key PartKey(const Key &key) { + return { + key.peerId, + key.type, + (key.universalId < 0) ? 1 : key.universalId + }; + } + static SharedMediaSlice::Key MigratedKey(const Key &key) { + return { + key.migratedPeerId, + key.type, + (key.universalId <= 0) ? (-key.universalId) : (ServerMaxMsgId - 1) + }; + } + static base::optional MigratedSlice(const Key &key) { + return key.migratedPeerId + ? base::make_optional(SharedMediaSlice(MigratedKey(key))) + : base::none; + } + static bool IsFromSlice(const SharedMediaSlice &slice, FullMsgId fullId) { auto peer = slice.key().peerId; return peerIsChannel(peer) @@ -320,21 +238,16 @@ public: Key key, int limitBefore, int limitAfter); - SharedMediaViewerMerged(const SharedMediaViewerMerged &other) = delete; - SharedMediaViewerMerged(SharedMediaViewerMerged &&other) = default; void start(); base::Observable updated; private: - static SharedMediaSlice::Key PartKey(const Key &key); - static SharedMediaSlice::Key MigratedKey(const Key &key); static std::unique_ptr MigratedViewer( const Key &key, int limitBefore, int limitAfter); - static base::optional MigratedSlice(const Key &key); Key _key; int _limitBefore = 0; @@ -344,3 +257,157 @@ private: SharedMediaSliceMerged _data; }; + +class SharedMediaViewerWithLast; +class SharedMediaSliceWithLast { +public: + using Type = Storage::SharedMediaType; + + // base::none in those mean CurrentPeerPhoto. + using Value = base::variant>; + using MessageId = SharedMediaSliceMerged::UniversalMsgId; + using UniversalMsgId = base::variant< + MessageId, + not_null>; + + struct Key { + Key( + PeerId peerId, + PeerId migratedPeerId, + Type type, + UniversalMsgId universalId) + : peerId(peerId) + , migratedPeerId(migratedPeerId) + , type(type) + , universalId(universalId) { + Expects(base::get_if(&universalId) != nullptr + || type == Type::ChatPhoto); + } + + bool operator==(const Key &other) const { + return (peerId == other.peerId) + && (migratedPeerId == other.migratedPeerId) + && (type == other.type) + && (universalId == other.universalId); + } + + PeerId peerId = 0; + PeerId migratedPeerId = 0; + Type type = Type::kCount; + UniversalMsgId universalId; + + }; + + SharedMediaSliceWithLast(Key key); + SharedMediaSliceWithLast( + Key key, + SharedMediaSliceMerged slice, + base::optional ending); + + base::optional fullCount() const; + base::optional skippedBefore() const; + base::optional skippedAfter() const; + base::optional indexOf(Value fullId) const; + int size() const; + Value operator[](int index) const; + base::optional distance(const Key &a, const Key &b) const; + + QString debug() const; + +private: + static SharedMediaSliceMerged::Key ViewerKey(const Key &key) { + return { + key.peerId, + key.migratedPeerId, + key.type, + base::get_if(&key.universalId) + ? (*base::get_if(&key.universalId)) + : ServerMaxMsgId - 1 + }; + } + static SharedMediaSliceMerged::Key EndingKey(const Key &key) { + return { + key.peerId, + key.migratedPeerId, + key.type, + ServerMaxMsgId - 1 + }; + } + static base::optional EndingSlice(const Key &key) { + return base::get_if(&key.universalId) + ? base::make_optional(SharedMediaSliceMerged(EndingKey(key))) + : base::none; + } + + static PhotoId LastPeerPhotoId(PeerId peerId); + static base::optional IsLastIsolated( + const SharedMediaSliceMerged &slice, + const base::optional &ending, + PhotoId lastPeerPhotoId); + static base::optional LastFullMsgId( + const SharedMediaSliceMerged &slice); + static base::optional Add( + const base::optional &a, + const base::optional &b) { + return (a && b) ? base::make_optional(*a + *b) : base::none; + } + static Value ComputeId(PeerId peerId, MsgId msgId) { + return FullMsgId( + peerIsChannel(peerId) ? peerToBareInt(peerId) : 0, + msgId); + } + static Value ComputeId(const Key &key) { + if (auto messageId = base::get_if(&key.universalId)) { + return (*messageId > 0) + ? ComputeId(key.peerId, *messageId) + : ComputeId(key.migratedPeerId, -*messageId); + } + return *base::get_if>(&key.universalId); + } + + bool isolatedInSlice() const { + return (_slice.skippedAfter() != 0); + } + base::optional lastPhotoSkip() const { + return _isolatedLastPhoto + | [](bool isolated) { return isolated ? 1 : 0; }; + } + + Key _key; + SharedMediaSliceMerged _slice; + base::optional _ending; + PhotoId _lastPhotoId = 0; + base::optional _isolatedLastPhoto; + + friend class SharedMediaViewerWithLast; + +}; + +class SharedMediaViewerWithLast : private base::Subscriber { +public: + using Type = SharedMediaSliceWithLast::Type; + using Key = SharedMediaSliceWithLast::Key; + + SharedMediaViewerWithLast( + Key key, + int limitBefore, + int limitAfter); + + void start(); + + base::Observable updated; + +private: + static std::unique_ptr EndingViewer( + const Key &key, + int limitBefore, + int limitAfter); + + Key _key; + int _limitBefore = 0; + int _limitAfter = 0; + SharedMediaViewerMerged _viewer; + std::unique_ptr _ending; + SharedMediaSliceWithLast _data; + +}; diff --git a/Telegram/SourceFiles/mediaview.cpp b/Telegram/SourceFiles/mediaview.cpp index aacc02591..64a6658e2 100644 --- a/Telegram/SourceFiles/mediaview.cpp +++ b/Telegram/SourceFiles/mediaview.cpp @@ -68,13 +68,13 @@ constexpr auto kIdsPreloadAfter = 28; } // namespace struct MediaView::SharedMedia { - SharedMedia(SharedMediaViewerMerged::Key key) + SharedMedia(SharedMediaViewerWithLast::Key key) : key(key) , slice(key, kIdsLimit, kIdsLimit) { } - SharedMediaViewerMerged::Key key; - SharedMediaViewerMerged slice; + SharedMediaViewerWithLast::Key key; + SharedMediaViewerWithLast slice; }; MediaView::MediaView() : TWidget(nullptr) @@ -192,21 +192,11 @@ void MediaView::moveToScreen() { _saveMsg.moveTo((width() - _saveMsg.width()) / 2, (height() - _saveMsg.height()) / 2); } -void MediaView::handleSharedMediaUpdate(const SharedMediaSliceMerged &update) { +void MediaView::handleSharedMediaUpdate(const SharedMediaSliceWithLast &update) { if (isHidden() || (!_photo && !_doc) || !_sharedMedia) { _index = _fullIndex = _fullCount = base::none; return; } - //if (_photo && _overview == OverviewChatPhotos && _history && !_history->peer->isUser()) { // TODO chat - // auto lastChatPhoto = computeLastOverviewChatPhoto(); - // if (_index < 0 && _photo == lastChatPhoto.photo && _photo == _additionalChatPhoto) { - // auto firstOpened = _firstOpenedPeerPhoto; - // showPhoto(_photo, lastChatPhoto.item); - // _firstOpenedPeerPhoto = firstOpened; - // return; - // } - // computeAdditionalChatPhoto(_history->peer, lastChatPhoto.photo); - //} _sharedMediaData = update; @@ -628,10 +618,9 @@ void MediaView::clearData() { stopGif(); delete _menu; _menu = nullptr; - _history = _migrated = nullptr; - _peer = _from = nullptr; - _user = nullptr; - _photo = _additionalChatPhoto = nullptr; + setContext(base::none); + _from = nullptr; + _photo = nullptr; _doc = nullptr; _fullScreenVideo = false; _caption.clear(); @@ -962,8 +951,7 @@ void MediaView::onDelete() { auto deletingPeerPhoto = [this]() { if (!_msgid) return true; if (_photo && _history) { - auto lastPhoto = computeLastOverviewChatPhoto(); - if (lastPhoto.photo == _photo && _history->peer->photoId == _photo->id) { + if (_history->peer->photoId == _photo->id) { return _firstOpenedPeerPhoto; } } @@ -1025,6 +1013,14 @@ base::optional MediaView::sharedMediaType() const { } base::optional MediaView::sharedMediaKey() const { + if (!_msgid && _peer && !_user && _photo && _peer->photoId == _photo->id) { + return SharedMediaKey { + _history->peer->id, + _migrated ? _migrated->peer->id : 0, + SharedMediaType::ChatPhoto, + _peer->photoId + }; + } if (!IsServerMsgId(_msgid.msg)) { return base::none; } @@ -1046,7 +1042,7 @@ bool MediaView::validSharedMedia() const { return false; } auto countDistanceInData = [](const auto &a, const auto &b) { - return [&](const SharedMediaSliceMerged &data) { + return [&](const SharedMediaSliceWithLast &data) { return data.distance(a, b); }; }; @@ -1065,7 +1061,7 @@ bool MediaView::validSharedMedia() const { void MediaView::validateSharedMedia() { if (auto key = sharedMediaKey()) { _sharedMedia = std::make_unique(*key); - subscribe(_sharedMedia->slice.updated, [this](const SharedMediaSliceMerged &data) { + subscribe(_sharedMedia->slice.updated, [this](const SharedMediaSliceWithLast &data) { handleSharedMediaUpdate(data); }); _sharedMedia->slice.start(); @@ -1085,20 +1081,9 @@ void MediaView::refreshSharedMedia() { } void MediaView::showPhoto(not_null photo, HistoryItem *context) { - _history = context ? context->history().get() : nullptr; - _migrated = nullptr; - if (_history) { - if (_history->peer->migrateFrom()) { - _migrated = App::history(_history->peer->migrateFrom()->id); - } else if (_history->peer->migrateTo()) { - _migrated = _history; - _history = App::history(_history->peer->migrateTo()->id); - } - } - _additionalChatPhoto = nullptr; + setContext(context); + _firstOpenedPeerPhoto = false; - _peer = 0; - _user = 0; _saveMsgStarted = 0; _loadRequest = 0; _over = OverNone; @@ -1111,31 +1096,19 @@ void MediaView::showPhoto(not_null photo, HistoryItem *context) { } if (!_animOpacities.isEmpty()) _animOpacities.clear(); - _msgid = context ? context->fullId() : FullMsgId(); - _canForward = context ? context->canForward() : false; - _canDelete = context ? context->canDelete() : false; _photo = photo; refreshSharedMedia(); - if (_history) { - if (context && !context->toHistoryMessage()) { - if (!_history->peer->isUser()) { - computeAdditionalChatPhoto(_history->peer, computeLastOverviewChatPhoto().photo); - } - } - } displayPhoto(photo, context); preloadData(0); activateControls(); } -void MediaView::showPhoto(not_null photo, PeerData *context) { - _history = _migrated = nullptr; - _additionalChatPhoto = nullptr; +void MediaView::showPhoto(not_null photo, not_null context) { + setContext(context); + _firstOpenedPeerPhoto = true; - _peer = context; - _user = context->asUser(); _saveMsgStarted = 0; _loadRequest = 0; _over = OverNone; @@ -1146,8 +1119,6 @@ void MediaView::showPhoto(not_null photo, PeerData *context) { } if (!_animOpacities.isEmpty()) _animOpacities.clear(); - _msgid = {}; - _canForward = _canDelete = false; _photo = photo; refreshSharedMedia(); @@ -1165,29 +1136,6 @@ void MediaView::showPhoto(not_null photo, PeerData *context) { //if (_user->photosCount < 0) { // loadBack(); //} // TODO user - } else if ((_history = App::historyLoaded(_peer))) { - if (_history->peer->migrateFrom()) { - _migrated = App::history(_history->peer->migrateFrom()->id); - } else if (_history->peer->migrateTo()) { - _migrated = _history; - _history = App::history(_history->peer->migrateTo()->id); - } - - auto lastChatPhoto = computeLastOverviewChatPhoto(); - if (_photo == lastChatPhoto.photo) { - showPhoto(_photo, lastChatPhoto.item); - _firstOpenedPeerPhoto = true; - return; - } - - computeAdditionalChatPhoto(_history->peer, lastChatPhoto.photo); - //if (_additionalChatPhoto == _photo) { // TODO chat - // _overview = OverviewChatPhotos; - // findCurrent(); - //} else { - _additionalChatPhoto = nullptr; - _history = _migrated = nullptr; - //} } displayPhoto(photo, 0); preloadData(0); @@ -1195,21 +1143,14 @@ void MediaView::showPhoto(not_null photo, PeerData *context) { } void MediaView::showDocument(not_null document, HistoryItem *context) { - _photo = 0; - _history = context ? context->history().get() : nullptr; - _migrated = nullptr; - if (_history) { - if (_history->peer->migrateFrom()) { - _migrated = App::history(_history->peer->migrateFrom()->id); - } else if (_history->peer->migrateTo()) { - _migrated = _history; - _history = App::history(_history->peer->migrateTo()->id); - } + if (context) { + setContext(context); + } else { + setContext(base::none); } - _additionalChatPhoto = nullptr; + + _photo = nullptr; _saveMsgStarted = 0; - _peer = 0; - _user = 0; _loadRequest = 0; _down = OverNone; _pressed = false; @@ -1221,10 +1162,6 @@ void MediaView::showDocument(not_null document, HistoryItem *cont } if (!_animOpacities.isEmpty()) _animOpacities.clear(); - _msgid = context ? context->fullId() : FullMsgId(); - _canForward = context ? context->canForward() : false; - _canDelete = context ? context->canDelete() : false; - if (document->isVideo() || document->isRoundVideo()) { _autoplayVideoDocument = document; } @@ -2209,6 +2146,63 @@ void MediaView::setZoomLevel(int newZoom) { update(); } +MediaView::Entity MediaView::entityForSharedMediaValue( + SharedMediaSliceWithLast::Value value) const { + if (auto photo = base::get_if>(&value)) { + // Last peer photo. + return { *photo, nullptr }; + } else if (auto itemId = base::get_if(&value)) { + if (auto item = App::histItemById(*itemId)) { + if (auto media = item->getMedia()) { + switch (media->type()) { + case MediaTypePhoto: return { + static_cast(item->getMedia())->photo(), + item + }; + case MediaTypeFile: + case MediaTypeVideo: + case MediaTypeGif: + case MediaTypeSticker: return { media->getDocument(), item }; + } + } + return { base::none, item }; + } + } + return { base::none, nullptr }; +} + +void MediaView::setContext(base::optional_variant< + not_null, + not_null> context) { + if (auto item = base::get_if>(&context)) { + _msgid = (*item)->fullId(); + _canForward = (*item)->canForward(); + _canDelete = (*item)->canDelete(); + _history = (*item)->history(); + _peer = _history->peer; + } else if (auto peer = base::get_if>(&context)) { + _msgid = FullMsgId(); + _canForward = _canDelete = false; + _history = App::history(*peer); + _peer = *peer; + } else { + _msgid = FullMsgId(); + _canForward = _canDelete = false; + _history = nullptr; + _peer = nullptr; + } + _migrated = nullptr; + if (_history) { + if (_history->peer->migrateFrom()) { + _migrated = App::history(_history->peer->migrateFrom()->id); + } else if (_history->peer->migrateTo()) { + _migrated = _history; + _history = App::history(_history->peer->migrateTo()->id); + } + } + _user = _peer ? _peer->asUser() : nullptr; +} + bool MediaView::moveToNext(int32 delta) { if (!_index) { return false; @@ -2217,27 +2211,28 @@ bool MediaView::moveToNext(int32 delta) { if (newIndex < 0 || newIndex >= _sharedMediaData->size()) { return false; } - if (auto item = App::histItemById((*_sharedMediaData)[newIndex])) { - _index = newIndex; - _msgid = item->fullId(); - _canForward = item->canForward(); - _canDelete = item->canDelete(); - stopGif(); - if (auto media = item->getMedia()) { - switch (media->type()) { - case MediaTypePhoto: displayPhoto(static_cast(item->getMedia())->photo(), item); preloadData(delta); break; - case MediaTypeFile: - case MediaTypeVideo: - case MediaTypeGif: - case MediaTypeSticker: displayDocument(media->getDocument(), item); preloadData(delta); break; - } - } else { - displayDocument(nullptr, item); - preloadData(delta); - } - return true; + auto entity = entityForSharedMediaValue((*_sharedMediaData)[newIndex]); + if (!entity.data && !entity.item) { + return false; } - return false; + _index = newIndex; + if (auto item = entity.item) { + setContext(item); + } else if (_peer) { + setContext(_peer); + } else { + setContext(base::none); + } + stopGif(); + if (auto photo = base::get_if>(&entity.data)) { + displayPhoto(*photo, entity.item); + } else if (auto document = base::get_if>(&entity.data)) { + displayDocument(*document, entity.item); + } else { + displayDocument(nullptr, entity.item); + } + preloadData(delta); + return true; //if (_index < 0) { // TODO chat // if (delta == -1 && _photo == _additionalChatPhoto) { @@ -2338,34 +2333,25 @@ void MediaView::preloadData(int32 delta) { auto forgetIndex = *_index - delta * 2; if (forgetIndex >= 0 && forgetIndex < _sharedMediaData->size()) { - if (auto item = App::histItemById((*_sharedMediaData)[forgetIndex])) { - if (auto media = item->getMedia()) { - switch (media->type()) { - case MediaTypePhoto: static_cast(media)->photo()->forget(); break; - case MediaTypeFile: - case MediaTypeVideo: - case MediaTypeGif: - case MediaTypeSticker: media->getDocument()->forget(); break; - } - } + auto entity = entityForSharedMediaValue((*_sharedMediaData)[forgetIndex]); + if (auto photo = base::get_if>(&entity.data)) { + (*photo)->forget(); + } else if (auto document = base::get_if>(&entity.data)) { + (*document)->forget(); } } for (auto index = from; index != till; ++index) { if (index >= 0 && index < _sharedMediaData->size()) { - if (auto item = App::histItemById((*_sharedMediaData)[index])) { - if (auto media = item->getMedia()) { - switch (media->type()) { - case MediaTypePhoto: static_cast(media)->photo()->download(); break; - case MediaTypeFile: - case MediaTypeVideo: - case MediaTypeGif: { - auto doc = media->getDocument(); - doc->thumb->load(); - doc->automaticLoad(item); - } break; - case MediaTypeSticker: media->getDocument()->sticker()->img->load(); break; - } + auto entity = entityForSharedMediaValue((*_sharedMediaData)[index]); + if (auto photo = base::get_if>(&entity.data)) { + (*photo)->download(); + } else if (auto document = base::get_if>(&entity.data)) { + if (auto sticker = (*document)->sticker()) { + sticker->img->load(); + } else { + (*document)->thumb->load(); + (*document)->automaticLoad(entity.item); } } } @@ -2820,7 +2806,9 @@ void MediaView::findCurrent() { _index = _fullIndex = _fullCount = base::none; return; } - _index = _sharedMediaData->indexOf(_msgid); + _index = _msgid + ? _sharedMediaData->indexOf(_msgid) + : _photo ? _sharedMediaData->indexOf(_photo) : base::none; if (_index && _sharedMediaData->skippedBefore()) { _fullIndex = (*_index + *_sharedMediaData->skippedBefore()); } else { @@ -2893,44 +2881,6 @@ void MediaView::loadBack() { //} // TODO user } -MediaView::LastChatPhoto MediaView::computeLastOverviewChatPhoto() { - LastChatPhoto emptyResult = { nullptr, nullptr }; - auto lastPhotoInOverview = [&emptyResult](auto history, auto list) -> LastChatPhoto { - auto end = list.end(); - if (auto item = App::histItemById(history->channelId(), *--end)) { - if (auto media = item->getMedia()) { - if (media->type() == MediaTypePhoto && !item->toHistoryMessage()) { - return { item, static_cast(media)->photo() }; - } - } - } - return emptyResult; - }; - - if (!_history) return emptyResult; - auto &list = _history->overview(OverviewChatPhotos); - if (!list.isEmpty()) { - return lastPhotoInOverview(_history, list); - } - - if (!_migrated || !_history->overviewLoaded(OverviewChatPhotos)) return emptyResult; - auto &migratedList = _migrated->overview(OverviewChatPhotos); - if (!migratedList.isEmpty()) { - return lastPhotoInOverview(_migrated, migratedList); - } - return emptyResult; -} - -void MediaView::computeAdditionalChatPhoto(PeerData *peer, PhotoData *lastOverviewPhoto) { - if (!peer->photoId || peer->photoId == UnknownPeerPhotoId) { - _additionalChatPhoto = nullptr; - } else if (lastOverviewPhoto && lastOverviewPhoto->id == peer->photoId) { - _additionalChatPhoto = nullptr; - } else { - _additionalChatPhoto = App::photo(peer->photoId); - } -} - void MediaView::userPhotosLoaded(UserData *u, const MTPphotos_Photos &photos, mtpRequestId req) { if (req == _loadRequest) { _loadRequest = 0; diff --git a/Telegram/SourceFiles/mediaview.h b/Telegram/SourceFiles/mediaview.h index bc5c7c53c..638b22225 100644 --- a/Telegram/SourceFiles/mediaview.h +++ b/Telegram/SourceFiles/mediaview.h @@ -57,14 +57,9 @@ public: void setVisible(bool visible) override; - void updateOver(QPoint mpos); - void showPhoto(not_null photo, HistoryItem *context); - void showPhoto(not_null photo, PeerData *context); + void showPhoto(not_null photo, not_null context); void showDocument(not_null document, HistoryItem *context); - void moveToScreen(); - bool moveToNext(int32 delta); - void preloadData(int32 delta); void leaveToChildEvent(QEvent *e, QWidget *child) override { // e -- from enterEvent() of child TWidget updateOverState(OverNone); @@ -151,20 +146,35 @@ private: OverVideo, }; + void updateOver(QPoint mpos); + void moveToScreen(); + bool moveToNext(int32 delta); + void preloadData(int32 delta); + struct Entity { + base::optional_variant< + not_null, + not_null> data; + HistoryItem *item; + }; + Entity entityForSharedMediaValue(SharedMediaSliceWithLast::Value value) const; + void setContext(base::optional_variant< + not_null, + not_null> context); + void refreshLang(); void showSaveMsgFile(); void updateMixerVideoVolume() const; struct SharedMedia; - using SharedMediaType = SharedMediaViewerMerged::Type; - using SharedMediaKey = SharedMediaViewerMerged::Key; + using SharedMediaType = SharedMediaViewerWithLast::Type; + using SharedMediaKey = SharedMediaViewerWithLast::Key; base::optional sharedMediaType() const; base::optional sharedMediaKey() const; void validateSharedMedia(); bool validSharedMedia() const; std::unique_ptr createSharedMedia() const; void refreshSharedMedia(); - void handleSharedMediaUpdate(const SharedMediaSliceMerged &update); + void handleSharedMediaUpdate(const SharedMediaSliceWithLast &update); void refreshNavVisibility(); void dropdownHidden(); @@ -206,14 +216,6 @@ private: void radialStart(); TimeMs radialTimeShift() const; - // Computes the last OverviewChatPhotos PhotoData* from _history or _migrated. - struct LastChatPhoto { - HistoryItem *item; - PhotoData *photo; - }; - LastChatPhoto computeLastOverviewChatPhoto(); - void computeAdditionalChatPhoto(PeerData *peer, PhotoData *lastOverviewPhoto); - void userPhotosLoaded(UserData *u, const MTPphotos_Photos &photos, mtpRequestId req); void deletePhotosDone(const MTPVector &result); @@ -244,7 +246,7 @@ private: PhotoData *_photo = nullptr; DocumentData *_doc = nullptr; std::unique_ptr _sharedMedia; - base::optional _sharedMediaData; + base::optional _sharedMediaData; QRect _closeNav, _closeNavIcon; QRect _leftNav, _leftNavIcon, _rightNav, _rightNavIcon; @@ -310,10 +312,6 @@ private: PeerData *_peer = nullptr; UserData *_user = nullptr; // if user profile photos overview - // There can be additional first photo in chat photos overview, that is not - // in the _history->overview(OverviewChatPhotos) (if the item was deleted). - PhotoData *_additionalChatPhoto = nullptr; - // We save the information about the reason of the current mediaview show: // did we open a peer profile photo or a photo from some message. // We use it when trying to delete a photo: if we've opened a peer photo,