diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index 3d4402b11..4eb3493f1 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -46,6 +46,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "numbers.h" #include "observer_peer.h" #include "auth_session.h" +#include "storage/storage_facade.h" +#include "storage/storage_shared_media.h" #include "window/themes/window_theme.h" #include "window/notifications_manager.h" #include "platform/platform_notifications_manager.h" @@ -1029,6 +1031,13 @@ namespace { existing->setViewsCount(m.has_views() ? m.vviews.v : -1); existing->addToOverview(AddToOverviewNew); + if (auto sharedMediaTypes = existing->sharedMediaTypes()) { + Auth().storage().add(Storage::SharedMediaAddNew( + peerId, + sharedMediaTypes, + existing->id)); + } + if (!existing->detached()) { App::checkSavedGif(existing); return true; diff --git a/Telegram/SourceFiles/history/history_shared_media.cpp b/Telegram/SourceFiles/history/history_shared_media.cpp index 774fb9d83..2a70bb8b2 100644 --- a/Telegram/SourceFiles/history/history_shared_media.cpp +++ b/Telegram/SourceFiles/history/history_shared_media.cpp @@ -62,6 +62,42 @@ History *GetMigratedHistory( } // namespace +base::optional SharedMediaOverviewType( + Storage::SharedMediaType type) { + if (SharedMediaTypeToOverview(type) != OverviewCount) { + return type; + } + return base::none; +} + +void SharedMediaShowOverview( + Storage::SharedMediaType type, + not_null history) { + if (SharedMediaOverviewType(type)) { + Ui::showPeerOverview(history, SharedMediaTypeToOverview(type)); + } +} + +QString SharedMediaSlice::debug() const { + auto before = _skippedBefore + ? (*_skippedBefore + ? ('(' + QString::number(*_skippedBefore) + ").. ") + : QString()) + : QString(".. "); + auto after = _skippedAfter + ? (*_skippedAfter + ? (" ..(" + QString::number(*_skippedAfter) + ')') + : QString()) + : QString(" .."); + auto middle = (size() > 2) + ? QString::number((*this)[0]) + " .. " + QString::number((*this)[size() - 1]) + : (size() > 1) + ? QString::number((*this)[0]) + ' ' + QString::number((*this)[1]) + : ((size() > 0) ? QString((*this)[0]) : QString()); + return before + middle + after; +} + + SharedMediaViewer::SharedMediaViewer( Key key, int limitBefore, @@ -70,22 +106,8 @@ SharedMediaViewer::SharedMediaViewer( , _limitBefore(limitBefore) , _limitAfter(limitAfter) , _data(_key) { -} - -base::optional SharedMediaOverviewType( - Storage::SharedMediaType type) { - if (SharedMediaTypeToOverview(type) != OverviewCount) { - return type; - } - return base::none; -} - -void SharedMediaShowOverview( - Storage::SharedMediaType type, - not_null history) { - if (SharedMediaOverviewType(type)) { - Ui::showPeerOverview(history, SharedMediaTypeToOverview(type)); - } + Expects(IsServerMsgId(key.messageId) || (key.messageId == 0)); + Expects((key.messageId != 0) || (limitBefore == 0 && limitAfter == 0)); } void SharedMediaViewer::start() { @@ -125,10 +147,15 @@ void SharedMediaViewer::mergeSliceData( base::optional skippedBefore, base::optional skippedAfter) { if (messageIds.empty()) { - if (count && *_data._fullCount != *count) { + if (count && _data._fullCount != count) { _data._fullCount = count; + if (*_data._fullCount <= _data.size()) { + _data._fullCount = _data.size(); + _data._skippedBefore = _data._skippedAfter = 0; + } updated.notify(_data); } + sliceToLimits(); return; } if (count) { @@ -285,125 +312,71 @@ void SharedMediaViewer::requestMessages(RequestDirection direction) { requestAroundData.second); } -// -//base::optional SharedMediaViewerMerged::Data::fullCount() const { -// if (_historyCount && _migratedCount) { -// return (*_historyCount + *_migratedCount); -// } -// return base::none; -//} -//base::optional SharedMediaViewerMerged::Data::skippedBefore() const { -// if (_ids.empty()) { -// return base::none; -// } else if (!IsServerMsgId(_ids.front())) { -// return _migratedSkippedBefore; -// } else if (_historySkippedBefore && _migratedCount) { -// return *_historySkippedBefore + *_migratedCount; -// } -// return base::none; -//} -// -//base::optional SharedMediaViewerMerged::Data::skippedAfter() const { -// if (_ids.empty()) { -// return base::none; -// } else if (IsServerMsgId(_ids.back())) { -// return _historySkippedAfter; -// } else if (_migratedSkippedAfter && _historyCount) { -// return *_migratedSkippedAfter + *_historyCount; -// } -// return base::none; -//} -// -//SharedMediaViewerMerged::SharedMediaViewerMerged( -// Type type, -// not_null history, -// MsgId aroundId, -// int limitBefore, -// int limitAfter) -//: _type(type) -//, _history(GetActualHistory(history)) -//, _migrated(GetMigratedHistory(history, _history)) -//, _universalAroundId((_history == _migrated) ? -aroundId : aroundId) -//, _limitBefore(limitBefore) -//, _limitAfter(limitAfter) -//, _data(_history, _migrated) { -//} -// -//bool SharedMediaViewerMerged::hasOverview() const { -// return SharedMediaTypeToOverview(_type) != OverviewCount; -//} -// -//void SharedMediaViewerMerged::showOverview() const { -// if (hasOverview()) { -// Ui::showPeerOverview(_history, SharedMediaTypeToOverview(_type)); -// } -//} -// -//bool SharedMediaViewerMerged::moveTo(const SharedMediaViewerMerged &other) { -// if (_history != other._history || _type != other._type) { -// return false; -// } -// _universalAroundId = other._universalAroundId; -// if (!containsAroundId()) { -// clearAfterMove(); -// } -// load(); -// return true; -//} -// -//bool SharedMediaViewerMerged::containsAroundId() const { -// if (_data._ids.empty()) { -// return false; -// } -// auto min = _data._ids.front(); -// auto max = _data._ids.back(); -// if (IsServerMsgId(_universalAroundId)) { -// return (!IsServerMsgId(min) || min <= aroundId()) -// && (IsServerMsgId(max) && max >= aroundId()); -// } -// return (!IsServerMsgId(min) && -min <= aroundId()) -// && (IsServerMsgId(max) || -max >= aroundId()); -//} -// -//bool SharedMediaViewerMerged::amAroundMigrated() const { -// return !IsServerMsgId(_universalAroundId); -//} -// -//not_null SharedMediaViewerMerged::aroundHistory() const { -// return amAroundMigrated() ? _migrated : _history; -//} -// -//MsgId SharedMediaViewerMerged::aroundId() const { -// return amAroundMigrated() ? -_universalAroundId : _universalAroundId; -//} -// -//void SharedMediaViewerMerged::clearAfterMove() { -// _data = Data(_history, _migrated, _data._historyCount, _data._migratedCount); -//} -// -//void SharedMediaViewerMerged::load() { -// auto weak = base::make_weak_unique(this); -// auto peer = aroundHistory()->peer; -// Auth().storage().query(Storage::SharedMediaQuery( -// peer->id, -// _type, -// aroundId(), -// _limitBefore, -// _limitAfter), [weak, peer](Storage::SharedMediaResult &&result) { -// if (weak) { -// weak->applyStoredResult(peer, std::move(result)); -// } -// }); -//} -// -//void SharedMediaViewerMerged::applyStoredResult( -// not_null peer, -// Storage::SharedMediaResult &&result) { -// if (aroundHistory()->peer != peer) { -// return; -// } -// auto aroundMigrated = amAroundMigrated(); -// if (result.count) { -// (aroundMigrated ? _data._migratedCount : _data._historyCount) = result.count; -// } -//} +SharedMediaViewerMerged::SharedMediaViewerMerged( + Key key, + int limitBefore, + int limitAfter) + : _key(key) + , _limitBefore(limitBefore) + , _limitAfter(limitAfter) + , _part(PartKey(_key), _limitBefore, _limitAfter) + , _migrated(MigratedViewer(_key, _limitBefore, _limitAfter)) + , _data(_key, SharedMediaSlice(PartKey(_key)), MigratedSlice(_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), + 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); + updated.notify(_data); + }); + if (_migrated) { + subscribe(_migrated->updated, [this](const SharedMediaSlice &update) { + _data = SharedMediaSliceMerged(_key, _data._part, update); + updated.notify(_data); + }); + } + _part.start(); + if (_migrated) { + _migrated->start(); + } +} diff --git a/Telegram/SourceFiles/history/history_shared_media.h b/Telegram/SourceFiles/history/history_shared_media.h index bc94d74ca..b9b8b62c0 100644 --- a/Telegram/SourceFiles/history/history_shared_media.h +++ b/Telegram/SourceFiles/history/history_shared_media.h @@ -42,6 +42,10 @@ public: , _fullCount(fullCount) { } + const Key &key() const { + return _key; + } + base::optional fullCount() const { return _fullCount; } @@ -62,19 +66,10 @@ public: return _ids.size(); } - using iterator = base::flat_set::const_iterator; + MsgId operator[](int index) const { + Expects(index >= 0 && index < size()); - iterator begin() const { - return _ids.begin(); - } - iterator end() const { - return _ids.end(); - } - iterator cbegin() const { - return begin(); - } - iterator cend() const { - return end(); + return *(_ids.begin() + index); } base::optional distance(const Key &a, const Key &b) const { @@ -84,14 +79,16 @@ public: || b.peerId != _key.peerId) { return base::none; } - auto i = _ids.find(a.messageId); - auto j = _ids.find(b.messageId); - if (i == _ids.end() || j == _ids.end()) { - return base::none; + if (auto i = indexOf(a.messageId)) { + if (auto j = indexOf(b.messageId)) { + return *j - *i; + } } - return j - i; + return base::none; } + QString debug() const; + private: Key _key; base::flat_set _ids; @@ -115,6 +112,8 @@ public: Key key, int limitBefore, int limitAfter); + SharedMediaViewer(const SharedMediaViewer &other) = delete; + SharedMediaViewer(SharedMediaViewer &&other) = default; void start(); @@ -144,7 +143,6 @@ private: base::optional skippedBefore = base::none, base::optional skippedAfter = base::none); - Key _key; int _limitBefore = 0; int _limitAfter = 0; @@ -153,164 +151,196 @@ private: SharedMediaSlice _data; }; -// -//class SharedMediaSliceMerged : -// private MTP::Sender, -// private base::Subscriber, -// public base::enable_weak_from_this { -//public: -// class Data; -// -//private: -// friend class Data; -// using UniversalMsgId = MsgId; -// -//public: -// using Type = Storage::SharedMediaType; -// -// SharedMediaSliceMerged( -// Type type, -// not_null history, -// MsgId aroundId, -// int limitBefore, -// int limitAfter); -// -// bool hasOverview() const; -// void showOverview() const; -// bool moveTo(const SharedMediaSliceMerged &other); -// -// void load(); -// -// class Data { -// public: -// base::optional fullCount() const; -// base::optional skippedBefore() const; -// base::optional skippedAfter() const; -// int size() const { -// return _ids.size(); -// } -// -// class iterator { -// public: -// FullMsgId operator*() const { -// auto id = _data->_ids[_index]; -// Assert(IsServerMsgId(id) -// || (_data->_migrated != nullptr && IsServerMsgId(-id))); -// return IsServerMsgId(id) -// ? FullMsgId(_data->_history->channelId(), id) -// : FullMsgId(_data->_migrated->channelId(), -id); -// } -// iterator &operator--() { -// --_index; -// return *this; -// } -// iterator operator--(int) { -// auto result = *this; -// --*this; -// return result; -// } -// iterator &operator++() { -// ++_index; -// return *this; -// } -// iterator operator++(int) { -// auto result = *this; -// ++*this; -// return result; -// } -// iterator &operator+=(int offset) { -// _index += offset; -// return *this; -// } -// iterator operator+(int offset) const { -// auto result = *this; -// return result += offset; -// } -// bool operator==(iterator other) const { -// return (_data == other._data) && (_index == other._index); -// } -// bool operator!=(iterator other) const { -// return !(*this == other); -// } -// bool operator<(iterator other) const { -// return (_data < other._data) -// || (_data == other._data && _index < other._index); -// } -// -// private: -// friend class Data; -// -// iterator(not_null data, int index) -// : _data(data) -// , _index(index) { -// } -// -// not_null _data; -// int _index = 0; -// -// }; -// -// iterator begin() const { -// return iterator(this, 0); -// } -// iterator end() const { -// iterator(this, _ids.size()); -// } -// iterator cbegin() const { -// return begin(); -// } -// iterator cend() const { -// return end(); -// } -// -// private: -// friend class iterator; -// friend class SharedMediaSliceMerged; -// -// Data( -// not_null history, -// History *migrated, -// base::optional historyCount = base::none, -// base::optional migratedCount = base::none) -// : _history(history) -// , _migrated(migrated) -// , _historyCount(historyCount) -// , _migratedCount(migratedCount) { -// if (!_migrated) { -// _migratedCount = 0; -// } -// } -// -// not_null _history; -// History *_migrated = nullptr; -// std::vector _ids; -// base::optional _historyCount; -// base::optional _historySkippedBefore; -// base::optional _historySkippedAfter; -// base::optional _migratedCount; -// base::optional _migratedSkippedBefore; -// base::optional _migratedSkippedAfter; -// -// }; -// base::Observable updated; -// -//private: -// bool amAroundMigrated() const; -// not_null aroundHistory() const; -// MsgId aroundId() const; -// -// void applyStoredResult( -// not_null peer, -// Storage::SharedMediaResult &&result); -// bool containsAroundId() const; -// void clearAfterMove(); -// -// Type _type = Type::kCount; -// not_null _history; -// History *_migrated = nullptr; -// UniversalMsgId _universalAroundId = 0; -// int _limitBefore = 0; -// int _limitAfter = 0; -// Data _data; -// -//}; + +class SharedMediaViewerMerged; +class SharedMediaSliceMerged { +public: + using Type = Storage::SharedMediaType; + using UniversalMsgId = MsgId; + struct Key { + Key( + PeerId peerId, + PeerId migratedPeerId, + Type type, + UniversalMsgId universalId) + : peerId(peerId) + , migratedPeerId(migratedPeerId) + , type(type) + , universalId(universalId) { + } + + 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 = 0; + + }; + SharedMediaSliceMerged( + Key key, + SharedMediaSlice part, + base::optional migrated) + : _key(key) + , _part(part) + , _migrated(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()); + } + + FullMsgId 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 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(); + } + +private: + static bool IsFromSlice(const SharedMediaSlice &slice, FullMsgId fullId) { + auto peer = slice.key().peerId; + return peerIsChannel(peer) + ? (peer == peerFromChannel(fullId.channel)) + : !fullId.channel; + } + static FullMsgId ComputeId(PeerId peerId, MsgId msgId) { + return FullMsgId( + peerIsChannel(peerId) ? peerToBareInt(peerId) : 0, + msgId); + } + static FullMsgId ComputeId(const SharedMediaSlice &slice, int index) { + return ComputeId(slice.key().peerId, slice[index]); + }; + static FullMsgId ComputeId(const Key &key) { + return (key.universalId > 0) + ? ComputeId(key.peerId, key.universalId) + : ComputeId(key.migratedPeerId, -key.universalId); + } + static base::optional Add( + const base::optional &a, + const base::optional &b) { + return (a && b) ? base::make_optional(*a + *b) : base::none; + } + + bool isFromPart(FullMsgId fullId) const { + return IsFromSlice(_part, fullId); + } + bool isFromMigrated(FullMsgId fullId) const { + return _migrated ? IsFromSlice(*_migrated, fullId) : false; + } + int migratedSize() const { + return isolatedInPart() ? 0 : _migrated->size(); + } + bool isolatedInPart() const { + return IsServerMsgId(_key.universalId) + && (!_migrated || _part.skippedBefore() != 0); + } + bool isolatedInMigrated() const { + return IsServerMsgId(-_key.universalId) + && (_migrated->skippedAfter() != 0); + } + + Key _key; + SharedMediaSlice _part; + base::optional _migrated; + + friend class SharedMediaViewerMerged; + +}; + +class SharedMediaViewerMerged : private base::Subscriber { +public: + using Type = SharedMediaSliceMerged::Type; + using Key = SharedMediaSliceMerged::Key; + + SharedMediaViewerMerged( + 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; + int _limitAfter = 0; + SharedMediaViewer _part; + std::unique_ptr _migrated; + SharedMediaSliceMerged _data; + +}; diff --git a/Telegram/SourceFiles/mediaview.cpp b/Telegram/SourceFiles/mediaview.cpp index 97457cfdd..aacc02591 100644 --- a/Telegram/SourceFiles/mediaview.cpp +++ b/Telegram/SourceFiles/mediaview.cpp @@ -68,13 +68,13 @@ constexpr auto kIdsPreloadAfter = 28; } // namespace struct MediaView::SharedMedia { - SharedMedia(SharedMediaViewer::Key key) + SharedMedia(SharedMediaViewerMerged::Key key) : key(key) , slice(key, kIdsLimit, kIdsLimit) { } - SharedMediaViewer::Key key; - SharedMediaViewer slice; + SharedMediaViewerMerged::Key key; + SharedMediaViewerMerged slice; }; MediaView::MediaView() : TWidget(nullptr) @@ -192,7 +192,7 @@ void MediaView::moveToScreen() { _saveMsg.moveTo((width() - _saveMsg.width()) / 2, (height() - _saveMsg.height()) / 2); } -void MediaView::handleSharedMediaUpdate(const SharedMediaSlice &update) { +void MediaView::handleSharedMediaUpdate(const SharedMediaSliceMerged &update) { if (isHidden() || (!_photo && !_doc) || !_sharedMedia) { _index = _fullIndex = _fullCount = base::none; return; @@ -275,9 +275,9 @@ void MediaView::documentUpdated(DocumentData *doc) { } void MediaView::changingMsgId(not_null row, MsgId newId) { - if (row->id == _msgid) { - _msgid = newId; - validateSharedMedia(); + if (row->fullId() == _msgid) { + _msgid = FullMsgId(_msgid.channel, newId); + refreshSharedMedia(); } } @@ -367,7 +367,7 @@ void MediaView::updateControls() { d = date(_photo->date); } else if (_doc) { d = date(_doc->date); - } else if (HistoryItem *item = App::histItemById(_msgmigrated ? 0 : _channel, _msgid)) { + } else if (auto item = App::histItemById(_msgid)) { d = item->date; } if (d.date() == dNow.date()) { @@ -409,7 +409,7 @@ void MediaView::updateActions() { if (_doc && _doc->loading()) { _actions.push_back({ lang(lng_cancel), SLOT(onSaveCancel()) }); } - if (_msgid > 0 && _msgid < ServerMaxMsgId) { + if (IsServerMsgId(_msgid.msg)) { _actions.push_back({ lang(lng_context_to_msg), SLOT(onToMessage()) }); } if (_doc && !_doc->filepath(DocumentData::FilePathResolveChecked).isEmpty()) { @@ -535,12 +535,12 @@ void MediaView::step_radial(TimeMs ms, bool timer) { _autoplayVideoDocument = _doc; } if (!_doc->data().isEmpty() && (_doc->isAnimation() || _doc->isVideo())) { - displayDocument(_doc, App::histItemById(_msgmigrated ? 0 : _channel, _msgid)); + displayDocument(_doc, App::histItemById(_msgid)); } else { auto &location = _doc->location(true); if (location.accessEnable()) { if (_doc->isAnimation() || _doc->isVideo() || _doc->isTheme() || QImageReader(location.name()).canRead()) { - displayDocument(_doc, App::histItemById(_msgmigrated ? 0 : _channel, _msgid)); + displayDocument(_doc, App::histItemById(_msgid)); } location.accessDisable(); } @@ -731,7 +731,7 @@ void MediaView::onScreenResized(int screen) { } if (!ignore) { moveToScreen(); - auto item = (_msgid ? App::histItemById(_msgmigrated ? 0 : _channel, _msgid) : nullptr); + auto item = (_msgid ? App::histItemById(_msgid) : nullptr); if (_photo) { displayPhoto(_photo, item); } else if (_doc) { @@ -741,7 +741,7 @@ void MediaView::onScreenResized(int screen) { } void MediaView::onToMessage() { - if (auto item = _msgid ? App::histItemById(_msgmigrated ? 0 : _channel, _msgid) : 0) { + if (auto item = _msgid ? App::histItemById(_msgid) : 0) { close(); Ui::showPeerHistoryAtItem(item); } @@ -830,7 +830,7 @@ void MediaView::clipCallback(Media::Clip::Notification notification) { switch (notification) { case NotificationReinit: { - if (auto item = App::histItemById(_msgmigrated ? 0 : _channel, _msgid)) { + if (auto item = App::histItemById(_msgid)) { if (_gif->state() == State::Error) { stopGif(); updateControls(); @@ -944,8 +944,10 @@ void MediaView::onShowInFolder() { } void MediaView::onForward() { - auto item = App::histItemById(_msgmigrated ? 0 : _channel, _msgid); - if (!_msgid || !item || item->id < 0 || item->serviceMsg()) return; + auto item = App::histItemById(_msgid); + if (!item || !IsServerMsgId(item->id) || item->serviceMsg()) { + return; + } close(); if (auto main = App::main()) { @@ -970,7 +972,7 @@ void MediaView::onDelete() { if (deletingPeerPhoto()) { App::main()->deletePhotoLayer(_photo); - } else if (auto item = App::histItemById(_msgmigrated ? 0 : _channel, _msgid)) { + } else if (auto item = App::histItemById(_msgid)) { App::contextItem(item); App::main()->deleteLayer(); } @@ -1004,8 +1006,7 @@ void MediaView::onCopy() { base::optional MediaView::sharedMediaType() const { using Type = SharedMediaType; - auto channelId = _msgmigrated ? NoChannel : _channel; - if (auto item = App::histItemById(channelId, _msgid)) { + if (auto item = App::histItemById(_msgid)) { if (_photo) { if (item->toHistoryMessage()) { return Type::Photo; @@ -1024,8 +1025,15 @@ base::optional MediaView::sharedMediaType() const { } base::optional MediaView::sharedMediaKey() const { + if (!IsServerMsgId(_msgid.msg)) { + return base::none; + } auto keyForType = [this](SharedMediaType type) -> SharedMediaKey { - return { (_msgmigrated ? _migrated : _history)->peer->id, type, _msgid }; + return { + _history->peer->id, + _migrated ? _migrated->peer->id : 0, + type, + (_msgid.channel == _history->channelId()) ? _msgid.msg : -_msgid.msg }; }; return sharedMediaType() @@ -1038,7 +1046,7 @@ bool MediaView::validSharedMedia() const { return false; } auto countDistanceInData = [](const auto &a, const auto &b) { - return [&](const SharedMediaSlice &data) { + return [&](const SharedMediaSliceMerged &data) { return data.distance(a, b); }; }; @@ -1046,7 +1054,7 @@ bool MediaView::validSharedMedia() const { auto distance = (key == _sharedMedia->key) ? 0 : _sharedMediaData | countDistanceInData(*key, _sharedMedia->key) - | base::abs; + | func::abs; if (distance) { return (*distance < kIdsPreloadAfter); } @@ -1057,7 +1065,7 @@ bool MediaView::validSharedMedia() const { void MediaView::validateSharedMedia() { if (auto key = sharedMediaKey()) { _sharedMedia = std::make_unique(*key); - subscribe(_sharedMedia->slice.updated, [this](const SharedMediaSlice &data) { + subscribe(_sharedMedia->slice.updated, [this](const SharedMediaSliceMerged &data) { handleSharedMediaUpdate(data); }); _sharedMedia->slice.start(); @@ -1103,14 +1111,12 @@ void MediaView::showPhoto(not_null photo, HistoryItem *context) { } if (!_animOpacities.isEmpty()) _animOpacities.clear(); - _msgid = context ? context->id : 0; - _msgmigrated = context ? (context->history() == _migrated) : false; - _channel = _history ? _history->channelId() : NoChannel; + _msgid = context ? context->fullId() : FullMsgId(); _canForward = context ? context->canForward() : false; _canDelete = context ? context->canDelete() : false; _photo = photo; - validateSharedMedia(); + refreshSharedMedia(); if (_history) { if (context && !context->toHistoryMessage()) { if (!_history->peer->isUser()) { @@ -1140,13 +1146,11 @@ void MediaView::showPhoto(not_null photo, PeerData *context) { } if (!_animOpacities.isEmpty()) _animOpacities.clear(); - _msgid = 0; - _msgmigrated = false; - _channel = NoChannel; + _msgid = {}; _canForward = _canDelete = false; _photo = photo; - validateSharedMedia(); + refreshSharedMedia(); if (_user) { //if (_user->photos.isEmpty() && _user->photosCount < 0 && _user->photoId && _user->photoId != UnknownPeerPhotoId) { // _fullIndex = 0; @@ -1217,9 +1221,7 @@ void MediaView::showDocument(not_null document, HistoryItem *cont } if (!_animOpacities.isEmpty()) _animOpacities.clear(); - _msgid = context ? context->id : 0; - _msgmigrated = context ? (context->history() == _migrated) : false; - _channel = _history ? _history->channelId() : NoChannel; + _msgid = context ? context->fullId() : FullMsgId(); _canForward = context ? context->canForward() : false; _canDelete = context ? context->canDelete() : false; @@ -1239,7 +1241,7 @@ void MediaView::displayPhoto(not_null photo, HistoryItem *item) { _photo = photo; _radial.stop(); - validateSharedMedia(); + refreshSharedMedia(); _photoRadialRect = QRect(QPoint((width() - st::radialSize.width()) / 2, (height() - st::radialSize.height()) / 2), st::radialSize); @@ -1299,7 +1301,7 @@ void MediaView::destroyThemePreview() { } void MediaView::displayDocument(DocumentData *doc, HistoryItem *item) { // empty messages shown as docs: doc can be NULL - auto documentChanged = (!doc || doc != _doc || (item && (item->id != _msgid || (item->history() != (_msgmigrated ? _migrated : _history))))); + auto documentChanged = (!doc || doc != _doc || (item && item->fullId() != _msgid)); if (documentChanged || (!doc->isAnimation() && !doc->isVideo())) { _fullScreenVideo = false; _current = QPixmap(); @@ -1314,7 +1316,7 @@ void MediaView::displayDocument(DocumentData *doc, HistoryItem *item) { // empty _photo = nullptr; _radial.stop(); - validateSharedMedia(); + refreshSharedMedia(); if (_autoplayVideoDocument && _doc != _autoplayVideoDocument) { _autoplayVideoDocument = nullptr; @@ -1521,7 +1523,7 @@ void MediaView::createClipReader() { _current = _doc->thumb->pixNoCache(_doc->thumb->width(), _doc->thumb->height(), videoThumbOptions(), st::mediaviewFileIconSize, st::mediaviewFileIconSize); } auto mode = (_doc->isVideo() || _doc->isRoundVideo()) ? Media::Clip::Reader::Mode::Video : Media::Clip::Reader::Mode::Gif; - _gif = Media::Clip::MakeReader(_doc, FullMsgId(_channel, _msgid), [this](Media::Clip::Notification notification) { + _gif = Media::Clip::MakeReader(_doc, _msgid, [this](Media::Clip::Notification notification) { clipCallback(notification); }, mode); @@ -1611,7 +1613,7 @@ void MediaView::setClipControllerGeometry() { void MediaView::onVideoPauseResume() { if (!_gif) return; - if (auto item = App::histItemById(_msgmigrated ? 0 : _channel, _msgid)) { + if (auto item = App::histItemById(_msgid)) { if (_gif->state() == Media::Clip::State::Error) { displayDocument(_doc, item); } else if (_gif->state() == Media::Clip::State::Finished) { @@ -1637,7 +1639,7 @@ void MediaView::restartVideoAtSeekPosition(TimeMs positionMs) { auto rounding = (_doc && _doc->isRoundVideo()) ? ImageRoundRadius::Ellipse : ImageRoundRadius::None; _current = _gif->current(_gif->width() / cIntRetinaFactor(), _gif->height() / cIntRetinaFactor(), _gif->width() / cIntRetinaFactor(), _gif->height() / cIntRetinaFactor(), rounding, ImageRoundCorner::All, getms()); } - _gif = Media::Clip::MakeReader(_doc, FullMsgId(_channel, _msgid), [this](Media::Clip::Notification notification) { + _gif = Media::Clip::MakeReader(_doc, _msgid, [this](Media::Clip::Notification notification) { clipCallback(notification); }, Media::Clip::Reader::Mode::Video, positionMs); @@ -2215,11 +2217,9 @@ bool MediaView::moveToNext(int32 delta) { if (newIndex < 0 || newIndex >= _sharedMediaData->size()) { return false; } - if (auto item = App::histItemById(_history->channelId(), *(_sharedMediaData->begin() + newIndex))) { + if (auto item = App::histItemById((*_sharedMediaData)[newIndex])) { _index = newIndex; - _msgid = item->id; - _msgmigrated = (item->history() == _migrated); - _channel = _history ? _history->channelId() : NoChannel; + _msgid = item->fullId(); _canForward = item->canForward(); _canDelete = item->canDelete(); stopGif(); @@ -2338,7 +2338,7 @@ void MediaView::preloadData(int32 delta) { auto forgetIndex = *_index - delta * 2; if (forgetIndex >= 0 && forgetIndex < _sharedMediaData->size()) { - if (auto item = App::histItemById(_history->channelId(), *(_sharedMediaData->begin() + forgetIndex))) { + if (auto item = App::histItemById((*_sharedMediaData)[forgetIndex])) { if (auto media = item->getMedia()) { switch (media->type()) { case MediaTypePhoto: static_cast(media)->photo()->forget(); break; @@ -2353,7 +2353,7 @@ void MediaView::preloadData(int32 delta) { for (auto index = from; index != till; ++index) { if (index >= 0 && index < _sharedMediaData->size()) { - if (auto item = App::histItemById(_history->channelId(), *(_sharedMediaData->begin() + index))) { + if (auto item = App::histItemById((*_sharedMediaData)[index])) { if (auto media = item->getMedia()) { switch (media->type()) { case MediaTypePhoto: static_cast(media)->photo()->download(); break; @@ -2568,7 +2568,7 @@ void MediaView::updateOver(QPoint pos) { updateOverState(OverRightNav); } else if (_nameNav.contains(pos)) { updateOverState(OverName); - } else if ((_msgid > 0 && _msgid < ServerMaxMsgId) && _dateNav.contains(pos)) { + } else if (IsServerMsgId(_msgid.msg) && _dateNav.contains(pos)) { updateOverState(OverDate); } else if (_headerHasLink && _headerNav.contains(pos)) { updateOverState(OverHeader); @@ -2985,7 +2985,8 @@ void MediaView::updateHeader() { _headerText = _doc->name.isEmpty() ? lang(lng_mediaview_doc_image) : _doc->name; } else if (_user) { _headerText = lang(lng_mediaview_profile_photo); - } else if ((_channel && !_history->isMegagroup()) || (_peer && _peer->isChannel() && !_peer->isMegagroup())) { + } else if ((_history && _history->channelId() && !_history->isMegagroup()) + || (_peer && _peer->isChannel() && !_peer->isMegagroup())) { _headerText = lang(lng_mediaview_channel_photo); } else if (_peer) { _headerText = lang(lng_mediaview_group_photo); diff --git a/Telegram/SourceFiles/mediaview.h b/Telegram/SourceFiles/mediaview.h index c17df973d..bc5c7c53c 100644 --- a/Telegram/SourceFiles/mediaview.h +++ b/Telegram/SourceFiles/mediaview.h @@ -156,15 +156,15 @@ private: void updateMixerVideoVolume() const; struct SharedMedia; - using SharedMediaType = SharedMediaViewer::Type; - using SharedMediaKey = SharedMediaViewer::Key; + using SharedMediaType = SharedMediaViewerMerged::Type; + using SharedMediaKey = SharedMediaViewerMerged::Key; base::optional sharedMediaType() const; base::optional sharedMediaKey() const; void validateSharedMedia(); bool validSharedMedia() const; std::unique_ptr createSharedMedia() const; void refreshSharedMedia(); - void handleSharedMediaUpdate(const SharedMediaSlice &update); + void handleSharedMediaUpdate(const SharedMediaSliceMerged &update); void refreshNavVisibility(); void dropdownHidden(); @@ -244,7 +244,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; @@ -326,9 +326,7 @@ private: base::optional _index; // Index in current _sharedMedia data. base::optional _fullIndex; // Index in full shared media. base::optional _fullCount; - MsgId _msgid = 0; // msgId of current photo or file - bool _msgmigrated = false; // msgId is from _migrated history - ChannelId _channel = NoChannel; + FullMsgId _msgid; bool _canForward = false; bool _canDelete = false; diff --git a/Telegram/SourceFiles/stdafx.h b/Telegram/SourceFiles/stdafx.h index d4e504eab..b33aa3e77 100644 --- a/Telegram/SourceFiles/stdafx.h +++ b/Telegram/SourceFiles/stdafx.h @@ -74,6 +74,9 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "base/variant.h" #include "base/optional.h" #include "base/algorithm.h" +#include "base/functors.h" + +namespace func = base::functors; #include "base/flat_set.h" #include "base/flat_map.h" diff --git a/Telegram/SourceFiles/storage/storage_shared_media.cpp b/Telegram/SourceFiles/storage/storage_shared_media.cpp index abfe86eb2..da68ecdc9 100644 --- a/Telegram/SourceFiles/storage/storage_shared_media.cpp +++ b/Telegram/SourceFiles/storage/storage_shared_media.cpp @@ -316,6 +316,13 @@ void SharedMedia::query( if (peerIt != _lists.end()) { auto index = static_cast(query.key.type); peerIt->second[index].query(query, std::move(callback)); + } else { + base::TaskQueue::Main().Put( + [ + callback = std::move(callback) + ]() mutable { + callback(SharedMediaResult()); + }); } } diff --git a/Telegram/SourceFiles/structs.h b/Telegram/SourceFiles/structs.h index e8d2b0254..dd1708aef 100644 --- a/Telegram/SourceFiles/structs.h +++ b/Telegram/SourceFiles/structs.h @@ -89,6 +89,9 @@ struct FullMsgId { FullMsgId() = default; FullMsgId(ChannelId channel, MsgId msg) : channel(channel), msg(msg) { } + explicit operator bool() const { + return msg != 0; + } ChannelId channel = NoChannel; MsgId msg = 0; }; diff --git a/Telegram/gyp/telegram_sources.txt b/Telegram/gyp/telegram_sources.txt index a16df536d..724847c8f 100644 --- a/Telegram/gyp/telegram_sources.txt +++ b/Telegram/gyp/telegram_sources.txt @@ -5,6 +5,7 @@ <(src_loc)/base/enum_mask.h <(src_loc)/base/flat_map.h <(src_loc)/base/flat_set.h +<(src_loc)/base/functors.h <(src_loc)/base/lambda.h <(src_loc)/base/lambda_guard.h <(src_loc)/base/index_based_iterator.h