Implement per-topic shared media.

This commit is contained in:
John Preston 2022-10-11 19:08:19 +04:00
parent eec4b72d9a
commit 58b8eb8e96
58 changed files with 434 additions and 269 deletions

View file

@ -2913,24 +2913,26 @@ void ApiWrap::resolveJumpToHistoryDate(
} }
} }
void ApiWrap::requestSharedMediaCount(
not_null<PeerData*> peer,
Storage::SharedMediaType type) {
requestSharedMedia(peer, type, 0, SliceType::Before);
}
void ApiWrap::requestSharedMedia( void ApiWrap::requestSharedMedia(
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId topicRootId,
SharedMediaType type, SharedMediaType type,
MsgId messageId, MsgId messageId,
SliceType slice) { SliceType slice) {
const auto key = std::make_tuple(peer, type, messageId, slice); const auto key = SharedMediaRequest{
peer,
topicRootId,
type,
messageId,
slice,
};
if (_sharedMediaRequests.contains(key)) { if (_sharedMediaRequests.contains(key)) {
return; return;
} }
const auto prepared = Api::PrepareSearchRequest( const auto prepared = Api::PrepareSearchRequest(
peer, peer,
topicRootId,
type, type,
QString(), QString(),
messageId, messageId,
@ -2946,7 +2948,6 @@ void ApiWrap::requestSharedMedia(
return request( return request(
std::move(*prepared) std::move(*prepared)
).done([=](const Api::SearchRequestResult &result) { ).done([=](const Api::SearchRequestResult &result) {
const auto key = std::make_tuple(peer, type, messageId, slice);
_sharedMediaRequests.remove(key); _sharedMediaRequests.remove(key);
auto parsed = Api::ParseSearchResult( auto parsed = Api::ParseSearchResult(
peer, peer,
@ -2954,7 +2955,7 @@ void ApiWrap::requestSharedMedia(
messageId, messageId,
slice, slice,
result); result);
sharedMediaDone(peer, type, std::move(parsed)); sharedMediaDone(peer, topicRootId, type, std::move(parsed));
finish(); finish();
}).fail([=] { }).fail([=] {
_sharedMediaRequests.remove(key); _sharedMediaRequests.remove(key);
@ -2966,10 +2967,12 @@ void ApiWrap::requestSharedMedia(
void ApiWrap::sharedMediaDone( void ApiWrap::sharedMediaDone(
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId topicRootId,
SharedMediaType type, SharedMediaType type,
Api::SearchResult &&parsed) { Api::SearchResult &&parsed) {
_session->storage().add(Storage::SharedMediaAddSlice( _session->storage().add(Storage::SharedMediaAddSlice(
peer->id, peer->id,
topicRootId,
type, type,
std::move(parsed.messageIds), std::move(parsed.messageIds),
parsed.noSkipRange, parsed.noSkipRange,

View file

@ -265,12 +265,10 @@ public:
using SliceType = Data::LoadDirection; using SliceType = Data::LoadDirection;
void requestSharedMedia( void requestSharedMedia(
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId topicRootId,
Storage::SharedMediaType type, Storage::SharedMediaType type,
MsgId messageId, MsgId messageId,
SliceType slice); SliceType slice);
void requestSharedMediaCount(
not_null<PeerData*> peer,
Storage::SharedMediaType type);
void readFeaturedSetDelayed(uint64 setId); void readFeaturedSetDelayed(uint64 setId);
@ -465,6 +463,7 @@ private:
void sharedMediaDone( void sharedMediaDone(
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId topicRootId,
SharedMediaType type, SharedMediaType type,
Api::SearchResult &&parsed); Api::SearchResult &&parsed);
@ -579,11 +578,18 @@ private:
mtpRequestId _contactsRequestId = 0; mtpRequestId _contactsRequestId = 0;
mtpRequestId _contactsStatusesRequestId = 0; mtpRequestId _contactsStatusesRequestId = 0;
base::flat_set<std::tuple< struct SharedMediaRequest {
not_null<PeerData*>, not_null<PeerData*> peer;
SharedMediaType, MsgId topicRootId = 0;
MsgId, SharedMediaType mediaType = {};
SliceType>> _sharedMediaRequests; MsgId aroundId = 0;
SliceType sliceType = {};
friend inline constexpr auto operator<=>(
const SharedMediaRequest&,
const SharedMediaRequest&) = default;
};
base::flat_set<SharedMediaRequest> _sharedMediaRequests;
std::unique_ptr<DialogsLoadState> _dialogsLoadState; std::unique_ptr<DialogsLoadState> _dialogsLoadState;
TimeId _dialogsLoadTill = 0; TimeId _dialogsLoadTill = 0;

View file

@ -19,10 +19,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace { namespace {
[[nodiscard]] bool IsOldForPin(MsgId id, not_null<PeerData*> peer) { [[nodiscard]] bool IsOldForPin(
MsgId id,
not_null<PeerData*> peer,
MsgId topicRootId) {
const auto normal = peer->migrateToOrMe(); const auto normal = peer->migrateToOrMe();
const auto migrated = normal->migrateFrom(); const auto migrated = normal->migrateFrom();
const auto top = Data::ResolveTopPinnedId(normal, migrated); const auto top = Data::ResolveTopPinnedId(normal, topicRootId, migrated);
if (!top) { if (!top) {
return false; return false;
} else if (peer == migrated) { } else if (peer == migrated) {
@ -46,7 +49,7 @@ void PinMessageBox(
mtpRequestId requestId = 0; mtpRequestId requestId = 0;
}; };
const auto pinningOld = IsOldForPin(msgId, peer); const auto pinningOld = IsOldForPin(msgId, peer, MsgId(0));
const auto state = box->lifetime().make_state<State>(); const auto state = box->lifetime().make_state<State>();
const auto api = box->lifetime().make_state<MTP::Sender>( const auto api = box->lifetime().make_state<MTP::Sender>(
&peer->session().mtp()); &peer->session().mtp());

View file

@ -538,6 +538,7 @@ bool OpenMediaTimestamp(
controller, controller,
document, document,
session->data().message(itemId), session->data().message(itemId),
MsgId(0), // #TODO forum shared media
false, false,
timeMs)); timeMs));
} else if (document->isSong() || document->isVoiceMessage()) { } else if (document->isSong() || document->isVoiceMessage()) {

View file

@ -942,7 +942,7 @@ void ApplyChannelUpdate(
} }
} }
if (const auto pinned = update.vpinned_msg_id()) { if (const auto pinned = update.vpinned_msg_id()) {
SetTopPinnedMessageId(channel, pinned->v); SetTopPinnedMessageId(channel, MsgId(0), pinned->v);
} }
if (channel->isMegagroup()) { if (channel->isMegagroup()) {
auto commands = ranges::views::all( auto commands = ranges::views::all(

View file

@ -474,7 +474,7 @@ void ApplyChatUpdate(not_null<ChatData*> chat, const MTPDchatFull &update) {
chat->session().api().inviteLinks().clearMyPermanent(chat); chat->session().api().inviteLinks().clearMyPermanent(chat);
} }
if (const auto pinned = update.vpinned_msg_id()) { if (const auto pinned = update.vpinned_msg_id()) {
SetTopPinnedMessageId(chat, pinned->v); SetTopPinnedMessageId(chat, MsgId(0), pinned->v);
} }
chat->checkFolder(update.vfolder_id().value_or_empty()); chat->checkFolder(update.vfolder_id().value_or_empty());
chat->setThemeEmoji(qs(update.vtheme_emoticon().value_or_empty())); chat->setThemeEmoji(qs(update.vtheme_emoticon().value_or_empty()));

View file

@ -234,7 +234,8 @@ base::binary_guard ReadBackgroundImageAsync(
void ResolveDocument( void ResolveDocument(
Window::SessionController *controller, Window::SessionController *controller,
not_null<DocumentData*> document, not_null<DocumentData*> document,
HistoryItem *item) { HistoryItem *item,
MsgId topicRootId) {
if (document->isNull()) { if (document->isNull()) {
return; return;
} }
@ -246,7 +247,7 @@ void ResolveDocument(
&& !document->filepath().isEmpty()) { && !document->filepath().isEmpty()) {
File::Launch(document->location(false).fname); File::Launch(document->location(false).fname);
} else if (controller) { } else if (controller) {
controller->openDocument(document, msgId, true); controller->openDocument(document, msgId, topicRootId, true);
} }
}; };

View file

@ -32,6 +32,7 @@ base::binary_guard ReadBackgroundImageAsync(
void ResolveDocument( void ResolveDocument(
Window::SessionController *controller, Window::SessionController *controller,
not_null<DocumentData*> document, not_null<DocumentData*> document,
HistoryItem *item); HistoryItem *item,
MsgId topicRootId);
} // namespace Data } // namespace Data

View file

@ -1203,7 +1203,10 @@ std::optional<QString> RestrictionError(
return std::nullopt; return std::nullopt;
} }
void SetTopPinnedMessageId(not_null<PeerData*> peer, MsgId messageId) { void SetTopPinnedMessageId(
not_null<PeerData*> peer,
MsgId topicRootId,
MsgId messageId) {
if (const auto channel = peer->asChannel()) { if (const auto channel = peer->asChannel()) {
if (messageId <= channel->availableMinId()) { if (messageId <= channel->availableMinId()) {
return; return;
@ -1217,6 +1220,7 @@ void SetTopPinnedMessageId(not_null<PeerData*> peer, MsgId messageId) {
} }
session.storage().add(Storage::SharedMediaAddExisting( session.storage().add(Storage::SharedMediaAddExisting(
peer->id, peer->id,
topicRootId,
Storage::SharedMediaType::Pinned, Storage::SharedMediaType::Pinned,
messageId, messageId,
{ messageId, ServerMaxMsgId })); { messageId, ServerMaxMsgId }));
@ -1225,20 +1229,23 @@ void SetTopPinnedMessageId(not_null<PeerData*> peer, MsgId messageId) {
FullMsgId ResolveTopPinnedId( FullMsgId ResolveTopPinnedId(
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId topicRootId,
PeerData *migrated) { PeerData *migrated) {
const auto slice = peer->session().storage().snapshot( const auto slice = peer->session().storage().snapshot(
Storage::SharedMediaQuery( Storage::SharedMediaQuery(
Storage::SharedMediaKey( Storage::SharedMediaKey(
peer->id, peer->id,
topicRootId,
Storage::SharedMediaType::Pinned, Storage::SharedMediaType::Pinned,
ServerMaxMsgId - 1), ServerMaxMsgId - 1),
1, 1,
1)); 1));
const auto old = migrated const auto old = (!topicRootId && migrated)
? migrated->session().storage().snapshot( ? migrated->session().storage().snapshot(
Storage::SharedMediaQuery( Storage::SharedMediaQuery(
Storage::SharedMediaKey( Storage::SharedMediaKey(
migrated->id, migrated->id,
MsgId(0), // topicRootId
Storage::SharedMediaType::Pinned, Storage::SharedMediaType::Pinned,
ServerMaxMsgId - 1), ServerMaxMsgId - 1),
1, 1,
@ -1259,20 +1266,23 @@ FullMsgId ResolveTopPinnedId(
FullMsgId ResolveMinPinnedId( FullMsgId ResolveMinPinnedId(
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId topicRootId,
PeerData *migrated) { PeerData *migrated) {
const auto slice = peer->session().storage().snapshot( const auto slice = peer->session().storage().snapshot(
Storage::SharedMediaQuery( Storage::SharedMediaQuery(
Storage::SharedMediaKey( Storage::SharedMediaKey(
peer->id, peer->id,
topicRootId,
Storage::SharedMediaType::Pinned, Storage::SharedMediaType::Pinned,
1), 1),
1, 1,
1)); 1));
const auto old = migrated const auto old = (!topicRootId && migrated)
? migrated->session().storage().snapshot( ? migrated->session().storage().snapshot(
Storage::SharedMediaQuery( Storage::SharedMediaQuery(
Storage::SharedMediaKey( Storage::SharedMediaKey(
migrated->id, migrated->id,
MsgId(0), // topicRootId
Storage::SharedMediaType::Pinned, Storage::SharedMediaType::Pinned,
1), 1),
1, 1,
@ -1291,34 +1301,4 @@ FullMsgId ResolveMinPinnedId(
} }
} }
std::optional<int> ResolvePinnedCount(
not_null<PeerData*> peer,
PeerData *migrated) {
const auto slice = peer->session().storage().snapshot(
Storage::SharedMediaQuery(
Storage::SharedMediaKey(
peer->id,
Storage::SharedMediaType::Pinned,
0),
0,
0));
const auto old = migrated
? migrated->session().storage().snapshot(
Storage::SharedMediaQuery(
Storage::SharedMediaKey(
migrated->id,
Storage::SharedMediaType::Pinned,
0),
0,
0))
: Storage::SharedMediaResult{
.count = 0,
.skippedBefore = 0,
.skippedAfter = 0,
};
return (slice.count.has_value() && old.count.has_value())
? std::make_optional(*slice.count + *old.count)
: std::nullopt;
}
} // namespace Data } // namespace Data

View file

@ -495,15 +495,17 @@ std::optional<QString> RestrictionError(
not_null<PeerData*> peer, not_null<PeerData*> peer,
UserRestriction restriction); UserRestriction restriction);
void SetTopPinnedMessageId(not_null<PeerData*> peer, MsgId messageId); void SetTopPinnedMessageId(
not_null<PeerData*> peer,
MsgId topicRootId,
MsgId messageId);
[[nodiscard]] FullMsgId ResolveTopPinnedId( [[nodiscard]] FullMsgId ResolveTopPinnedId(
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId topicRootId,
PeerData *migrated); PeerData *migrated);
[[nodiscard]] FullMsgId ResolveMinPinnedId( [[nodiscard]] FullMsgId ResolveMinPinnedId(
not_null<PeerData*> peer, not_null<PeerData*> peer,
PeerData *migrated); MsgId topicRootId,
[[nodiscard]] std::optional<int> ResolvePinnedCount(
not_null<PeerData*> peer,
PeerData *migrated); PeerData *migrated);
} // namespace Data } // namespace Data

View file

@ -30,8 +30,7 @@ constexpr auto kRequestTimeLimit = 60 * crl::time(1000);
} }
[[nodiscard]] MsgId LocalToRemoteMsgId(MsgId id) { [[nodiscard]] MsgId LocalToRemoteMsgId(MsgId id) {
Expects(id > ServerMaxMsgId); Expects(IsScheduledMsgId(id));
Expects(id < ServerMaxMsgId + ScheduledMsgIdsRange);
return (id - ServerMaxMsgId - 1); return (id - ServerMaxMsgId - 1);
} }

View file

@ -27,6 +27,7 @@ constexpr auto kDefaultSearchTimeoutMs = crl::time(200);
std::optional<SearchRequest> PrepareSearchRequest( std::optional<SearchRequest> PrepareSearchRequest(
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId topicRootId,
Storage::SharedMediaType type, Storage::SharedMediaType type,
const QString &query, const QString &query,
MsgId messageId, MsgId messageId,
@ -90,12 +91,13 @@ std::optional<SearchRequest> PrepareSearchRequest(
offsetId.bare, offsetId.bare,
int64(0), int64(0),
int64(0x3FFFFFFF))); int64(0x3FFFFFFF)));
using Flag = MTPmessages_Search::Flag;
return MTPmessages_Search( return MTPmessages_Search(
MTP_flags(0), MTP_flags(topicRootId ? Flag::f_top_msg_id : Flag(0)),
peer->input, peer->input,
MTP_string(query), MTP_string(query),
MTP_inputPeerEmpty(), MTP_inputPeerEmpty(),
MTPint(), // top_msg_id MTP_int(topicRootId),
filter, filter,
MTP_int(0), // min_date MTP_int(0), // min_date
MTP_int(0), // max_date MTP_int(0), // max_date
@ -234,11 +236,13 @@ rpl::producer<SparseIdsMergedSlice> SearchController::idsSlice(
auto query = (const Query&)_current->first; auto query = (const Query&)_current->first;
auto createSimpleViewer = [=]( auto createSimpleViewer = [=](
PeerId peerId, PeerId peerId,
MsgId topicRootId,
SparseIdsSlice::Key simpleKey, SparseIdsSlice::Key simpleKey,
int limitBefore, int limitBefore,
int limitAfter) { int limitAfter) {
return simpleIdsSlice( return simpleIdsSlice(
peerId, peerId,
topicRootId,
simpleKey, simpleKey,
query, query,
limitBefore, limitBefore,
@ -247,6 +251,7 @@ rpl::producer<SparseIdsMergedSlice> SearchController::idsSlice(
return SparseIdsMergedSlice::CreateViewer( return SparseIdsMergedSlice::CreateViewer(
SparseIdsMergedSlice::Key( SparseIdsMergedSlice::Key(
query.peerId, query.peerId,
query.topicRootId,
query.migratedPeerId, query.migratedPeerId,
aroundId), aroundId),
limitBefore, limitBefore,
@ -256,6 +261,7 @@ rpl::producer<SparseIdsMergedSlice> SearchController::idsSlice(
rpl::producer<SparseIdsSlice> SearchController::simpleIdsSlice( rpl::producer<SparseIdsSlice> SearchController::simpleIdsSlice(
PeerId peerId, PeerId peerId,
MsgId topicRootId,
MsgId aroundId, MsgId aroundId,
const Query &query, const Query &query,
int limitBefore, int limitBefore,
@ -264,8 +270,8 @@ rpl::producer<SparseIdsSlice> SearchController::simpleIdsSlice(
Expects(IsServerMsgId(aroundId) || (aroundId == 0)); Expects(IsServerMsgId(aroundId) || (aroundId == 0));
Expects((aroundId != 0) Expects((aroundId != 0)
|| (limitBefore == 0 && limitAfter == 0)); || (limitBefore == 0 && limitAfter == 0));
Expects((query.peerId == peerId) Expects((query.peerId == peerId && query.topicRootId == topicRootId)
|| (query.migratedPeerId == peerId)); || (query.migratedPeerId == peerId && MsgId(0) == topicRootId));
auto it = _cache.find(query); auto it = _cache.find(query);
if (it == _cache.end()) { if (it == _cache.end()) {
@ -298,7 +304,8 @@ rpl::producer<SparseIdsSlice> SearchController::simpleIdsSlice(
_session->data().itemRemoved( _session->data().itemRemoved(
) | rpl::filter([=](not_null<const HistoryItem*> item) { ) | rpl::filter([=](not_null<const HistoryItem*> item) {
return (item->history()->peer->id == peerId); return (item->history()->peer->id == peerId)
&& (!topicRootId || item->topicRootId() == topicRootId);
}) | rpl::filter([=](not_null<const HistoryItem*> item) { }) | rpl::filter([=](not_null<const HistoryItem*> item) {
return builder->removeOne(item->id); return builder->removeOne(item->id);
}) | rpl::start_with_next(pushNextSnapshot, lifetime); }) | rpl::start_with_next(pushNextSnapshot, lifetime);
@ -370,6 +377,7 @@ void SearchController::requestMore(
} }
auto prepared = PrepareSearchRequest( auto prepared = PrepareSearchRequest(
listData->peer, listData->peer,
query.topicRootId,
query.type, query.type,
query.query, query.query,
key.aroundId, key.aroundId,

View file

@ -34,6 +34,7 @@ using SearchRequestResult = MTPmessages_Messages;
std::optional<SearchRequest> PrepareSearchRequest( std::optional<SearchRequest> PrepareSearchRequest(
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId topicRootId,
Storage::SharedMediaType type, Storage::SharedMediaType type,
const QString &query, const QString &query,
MsgId messageId, MsgId messageId,
@ -53,6 +54,7 @@ public:
using MediaType = Storage::SharedMediaType; using MediaType = Storage::SharedMediaType;
PeerId peerId = 0; PeerId peerId = 0;
MsgId topicRootId = 0;
PeerId migratedPeerId = 0; PeerId migratedPeerId = 0;
MediaType type = MediaType::kCount; MediaType type = MediaType::kCount;
QString query; QString query;
@ -75,6 +77,7 @@ public:
Query query() const { Query query() const {
Expects(_current != _cache.cend()); Expects(_current != _cache.cend());
return _current->first; return _current->first;
} }
@ -106,18 +109,11 @@ private:
std::optional<Data> migratedData; std::optional<Data> migratedData;
}; };
struct CacheLess { using Cache = base::flat_map<Query, std::unique_ptr<CacheEntry>>;
inline bool operator()(const Query &a, const Query &b) const {
return (a < b);
}
};
using Cache = base::flat_map<
Query,
std::unique_ptr<CacheEntry>,
CacheLess>;
rpl::producer<SparseIdsSlice> simpleIdsSlice( rpl::producer<SparseIdsSlice> simpleIdsSlice(
PeerId peerId, PeerId peerId,
MsgId topicRootId,
MsgId aroundId, MsgId aroundId,
const Query &query, const Query &query,
int limitBefore, int limitBefore,

View file

@ -109,10 +109,12 @@ rpl::producer<SparseIdsSlice> SharedMediaViewer(
limitAfter); limitAfter);
auto requestMediaAround = [ auto requestMediaAround = [
peer = session->data().peer(key.peerId), peer = session->data().peer(key.peerId),
topicRootId = key.topicRootId,
type = key.type type = key.type
](const SparseIdsSliceBuilder::AroundData &data) { ](const SparseIdsSliceBuilder::AroundData &data) {
peer->session().api().requestSharedMedia( peer->session().api().requestSharedMedia(
peer, peer,
topicRootId,
type, type,
data.aroundId, data.aroundId,
data.direction); data.direction);
@ -128,6 +130,7 @@ rpl::producer<SparseIdsSlice> SharedMediaViewer(
session->storage().sharedMediaSliceUpdated( session->storage().sharedMediaSliceUpdated(
) | rpl::filter([=](const SliceUpdate &update) { ) | rpl::filter([=](const SliceUpdate &update) {
return (update.peerId == key.peerId) return (update.peerId == key.peerId)
&& (update.topicRootId == key.topicRootId)
&& (update.type == key.type); && (update.type == key.type);
}) | rpl::filter([=](const SliceUpdate &update) { }) | rpl::filter([=](const SliceUpdate &update) {
return builder->applyUpdate(update.data); return builder->applyUpdate(update.data);
@ -146,7 +149,7 @@ rpl::producer<SparseIdsSlice> SharedMediaViewer(
session->storage().sharedMediaAllRemoved( session->storage().sharedMediaAllRemoved(
) | rpl::filter([=](const AllRemoved &update) { ) | rpl::filter([=](const AllRemoved &update) {
return (update.peerId == key.peerId) return (update.peerId == key.peerId)
&& (update.types.test(key.type)); && update.types.test(key.type);
}) | rpl::filter([=] { }) | rpl::filter([=] {
return builder->removeAll(); return builder->removeAll();
}) | rpl::start_with_next(pushNextSnapshot, lifetime); }) | rpl::start_with_next(pushNextSnapshot, lifetime);
@ -229,6 +232,7 @@ rpl::producer<SparseIdsMergedSlice> SharedMediaMergedViewer(
int limitAfter) { int limitAfter) {
auto createSimpleViewer = [=]( auto createSimpleViewer = [=](
PeerId peerId, PeerId peerId,
MsgId topicRootId,
SparseIdsSlice::Key simpleKey, SparseIdsSlice::Key simpleKey,
int limitBefore, int limitBefore,
int limitAfter) { int limitAfter) {
@ -236,6 +240,7 @@ rpl::producer<SparseIdsMergedSlice> SharedMediaMergedViewer(
session, session,
Storage::SharedMediaKey( Storage::SharedMediaKey(
peerId, peerId,
topicRootId,
key.type, key.type,
simpleKey), simpleKey),
limitBefore, limitBefore,
@ -462,7 +467,7 @@ rpl::producer<SharedMediaWithLastSlice> SharedMediaWithLastViewer(
}); });
} }
if (key.scheduled) { if (key.topicRootId == SharedMediaWithLastSlice::kScheduledTopicId) {
return SharedScheduledMediaViewer( return SharedScheduledMediaViewer(
session, session,
std::move(viewerKey), std::move(viewerKey),

View file

@ -67,36 +67,32 @@ public:
MessageId, MessageId,
not_null<PhotoData*>>; not_null<PhotoData*>>;
static constexpr auto kScheduledTopicId
= SparseIdsMergedSlice::kScheduledTopicId;
struct Key { struct Key {
Key( Key(
PeerId peerId, PeerId peerId,
MsgId topicRootId,
PeerId migratedPeerId, PeerId migratedPeerId,
Type type, Type type,
UniversalMsgId universalId, UniversalMsgId universalId)
bool scheduled = false)
: peerId(peerId) : peerId(peerId)
, topicRootId(topicRootId)
, migratedPeerId(migratedPeerId) , migratedPeerId(migratedPeerId)
, type(type) , type(type)
, universalId(universalId) , universalId(universalId) {
, scheduled(scheduled) {
Expects(v::is<MessageId>(universalId) || type == Type::ChatPhoto); Expects(v::is<MessageId>(universalId) || type == Type::ChatPhoto);
} }
bool operator==(const Key &other) const { friend inline constexpr auto operator<=>(
return (peerId == other.peerId) const Key&,
&& (migratedPeerId == other.migratedPeerId) const Key&) = default;
&& (type == other.type)
&& (universalId == other.universalId);
}
bool operator!=(const Key &other) const {
return !(*this == other);
}
PeerId peerId = 0; PeerId peerId = 0;
MsgId topicRootId = 0;
PeerId migratedPeerId = 0; PeerId migratedPeerId = 0;
Type type = Type::kCount; Type type = Type::kCount;
UniversalMsgId universalId; UniversalMsgId universalId;
bool scheduled = false;
}; };
@ -122,6 +118,7 @@ public:
static SparseIdsMergedSlice::Key ViewerKey(const Key &key) { static SparseIdsMergedSlice::Key ViewerKey(const Key &key) {
return { return {
key.peerId, key.peerId,
key.topicRootId,
key.migratedPeerId, key.migratedPeerId,
v::is<MessageId>(key.universalId) v::is<MessageId>(key.universalId)
? v::get<MessageId>(key.universalId) ? v::get<MessageId>(key.universalId)
@ -131,6 +128,7 @@ public:
static SparseIdsMergedSlice::Key EndingKey(const Key &key) { static SparseIdsMergedSlice::Key EndingKey(const Key &key) {
return { return {
key.peerId, key.peerId,
key.topicRootId,
key.migratedPeerId, key.migratedPeerId,
ServerMaxMsgId - 1 ServerMaxMsgId - 1
}; };

View file

@ -377,6 +377,7 @@ rpl::producer<SparseIdsMergedSlice> SparseIdsMergedSlice::CreateViewer(
int limitBefore, int limitBefore,
int limitAfter, int limitAfter,
Fn<SimpleViewerFunction> simpleViewer) { Fn<SimpleViewerFunction> simpleViewer) {
Expects(!key.topicRootId || !key.migratedPeerId);
Expects(IsServerMsgId(key.universalId) Expects(IsServerMsgId(key.universalId)
|| (key.universalId == 0) || (key.universalId == 0)
|| (IsServerMsgId(ServerMaxMsgId + key.universalId) && key.migratedPeerId != 0)); || (IsServerMsgId(ServerMaxMsgId + key.universalId) && key.migratedPeerId != 0));
@ -386,6 +387,7 @@ rpl::producer<SparseIdsMergedSlice> SparseIdsMergedSlice::CreateViewer(
return [=](auto consumer) { return [=](auto consumer) {
auto partViewer = simpleViewer( auto partViewer = simpleViewer(
key.peerId, key.peerId,
key.topicRootId,
SparseIdsMergedSlice::PartKey(key), SparseIdsMergedSlice::PartKey(key),
limitBefore, limitBefore,
limitAfter limitAfter
@ -402,6 +404,7 @@ rpl::producer<SparseIdsMergedSlice> SparseIdsMergedSlice::CreateViewer(
} }
auto migratedViewer = simpleViewer( auto migratedViewer = simpleViewer(
key.migratedPeerId, key.migratedPeerId,
MsgId(0), // topicRootId
SparseIdsMergedSlice::MigratedKey(key), SparseIdsMergedSlice::MigratedKey(key),
limitBefore, limitBefore,
limitAfter); limitAfter);

View file

@ -27,32 +27,29 @@ using SparseUnsortedIdsSlice = AbstractSparseIds<std::vector<MsgId>>;
class SparseIdsMergedSlice { class SparseIdsMergedSlice {
public: public:
using UniversalMsgId = MsgId; using UniversalMsgId = MsgId;
static constexpr MsgId kScheduledTopicId
= ServerMaxMsgId + ScheduledMsgIdsRange;
struct Key { struct Key {
Key( Key(
PeerId peerId, PeerId peerId,
MsgId topicRootId,
PeerId migratedPeerId, PeerId migratedPeerId,
UniversalMsgId universalId, UniversalMsgId universalId)
bool scheduled = false)
: peerId(peerId) : peerId(peerId)
, scheduled(scheduled) , topicRootId(topicRootId)
, migratedPeerId(scheduled ? 0 : migratedPeerId) , migratedPeerId(topicRootId ? 0 : migratedPeerId)
, universalId(universalId) { , universalId(universalId) {
} }
bool operator==(const Key &other) const { friend inline constexpr bool operator==(
return (peerId == other.peerId) const Key &,
&& (migratedPeerId == other.migratedPeerId) const Key &) = default;
&& (universalId == other.universalId);
}
bool operator!=(const Key &other) const {
return !(*this == other);
}
PeerId peerId = 0; PeerId peerId = 0;
bool scheduled = false; MsgId topicRootId = 0;
PeerId migratedPeerId = 0; PeerId migratedPeerId = 0;
UniversalMsgId universalId = 0; UniversalMsgId universalId = 0;
}; };
SparseIdsMergedSlice(Key key); SparseIdsMergedSlice(Key key);
@ -75,6 +72,7 @@ public:
using SimpleViewerFunction = rpl::producer<SparseIdsSlice>( using SimpleViewerFunction = rpl::producer<SparseIdsSlice>(
PeerId peerId, PeerId peerId,
MsgId topicRootId,
SparseIdsSlice::Key simpleKey, SparseIdsSlice::Key simpleKey,
int limitBefore, int limitBefore,
int limitAfter); int limitAfter);

View file

@ -331,7 +331,7 @@ void ApplyUserUpdate(not_null<UserData*> user, const MTPDuserFull &update) {
user->setBotInfoVersion(-1); user->setBotInfoVersion(-1);
} }
if (const auto pinned = update.vpinned_msg_id()) { if (const auto pinned = update.vpinned_msg_id()) {
SetTopPinnedMessageId(user, pinned->v); SetTopPinnedMessageId(user, MsgId(0), pinned->v);
} }
const auto canReceiveGifts = (update.vflags().v const auto canReceiveGifts = (update.vflags().v
& MTPDuserFull::Flag::f_premium_gifts) & MTPDuserFull::Flag::f_premium_gifts)

View file

@ -624,14 +624,14 @@ void InnerWidget::elementShowPollResults(
void InnerWidget::elementOpenPhoto( void InnerWidget::elementOpenPhoto(
not_null<PhotoData*> photo, not_null<PhotoData*> photo,
FullMsgId context) { FullMsgId context) {
_controller->openPhoto(photo, context); _controller->openPhoto(photo, context, MsgId(0));
} }
void InnerWidget::elementOpenDocument( void InnerWidget::elementOpenDocument(
not_null<DocumentData*> document, not_null<DocumentData*> document,
FullMsgId context, FullMsgId context,
bool showInMediaView) { bool showInMediaView) {
_controller->openDocument(document, context, showInMediaView); _controller->openDocument(document, context, MsgId(0), showInMediaView);
} }
void InnerWidget::elementCancelUpload(const FullMsgId &context) { void InnerWidget::elementCancelUpload(const FullMsgId &context) {
@ -1378,7 +1378,7 @@ void InnerWidget::openContextGif(FullMsgId itemId) {
if (const auto item = session().data().message(itemId)) { if (const auto item = session().data().message(itemId)) {
if (const auto media = item->media()) { if (const auto media = item->media()) {
if (const auto document = media->document()) { if (const auto document = media->document()) {
_controller->openDocument(document, itemId, true); _controller->openDocument(document, itemId, MsgId(), true);
} }
} }
} }

View file

@ -778,6 +778,7 @@ not_null<HistoryItem*> History::addNewToBack(
auto till = loadedAtBottom() ? ServerMaxMsgId : maxMsgId(); auto till = loadedAtBottom() ? ServerMaxMsgId : maxMsgId();
session().storage().add(Storage::SharedMediaAddExisting( session().storage().add(Storage::SharedMediaAddExisting(
peer->id, peer->id,
MsgId(0),
sharedMediaTypes, sharedMediaTypes,
item->id, item->id,
{ from, till })); { from, till }));
@ -1047,6 +1048,7 @@ void History::applyServiceChanges(
if (item) { if (item) {
session().storage().add(Storage::SharedMediaAddSlice( session().storage().add(Storage::SharedMediaAddSlice(
peer->id, peer->id,
MsgId(0), // topicRootId
Storage::SharedMediaType::Pinned, Storage::SharedMediaType::Pinned,
{ id }, { id },
{ id, ServerMaxMsgId })); { id, ServerMaxMsgId }));
@ -1268,6 +1270,7 @@ void History::addEdgesToSharedMedia() {
const auto type = static_cast<Storage::SharedMediaType>(i); const auto type = static_cast<Storage::SharedMediaType>(i);
session().storage().add(Storage::SharedMediaAddSlice( session().storage().add(Storage::SharedMediaAddSlice(
peer->id, peer->id,
MsgId(0), // topicRootId
type, type,
{}, {},
{ from, till })); { from, till }));
@ -1460,6 +1463,7 @@ void History::addToSharedMedia(
const auto type = static_cast<Storage::SharedMediaType>(i); const auto type = static_cast<Storage::SharedMediaType>(i);
session().storage().add(Storage::SharedMediaAddSlice( session().storage().add(Storage::SharedMediaAddSlice(
peer->id, peer->id,
MsgId(0), // topicRootId
type, type,
std::move(medias[i]), std::move(medias[i]),
{ from, till })); { from, till }));

View file

@ -2596,7 +2596,7 @@ void HistoryInner::openContextGif(FullMsgId itemId) {
if (const auto item = session().data().message(itemId)) { if (const auto item = session().data().message(itemId)) {
if (const auto media = item->media()) { if (const auto media = item->media()) {
if (const auto document = media->document()) { if (const auto document = media->document()) {
_controller->openDocument(document, itemId, true); _controller->openDocument(document, itemId, MsgId(), true);
} }
} }
} }
@ -3248,14 +3248,14 @@ void HistoryInner::elementShowPollResults(
void HistoryInner::elementOpenPhoto( void HistoryInner::elementOpenPhoto(
not_null<PhotoData*> photo, not_null<PhotoData*> photo,
FullMsgId context) { FullMsgId context) {
_controller->openPhoto(photo, context); _controller->openPhoto(photo, context, MsgId(0));
} }
void HistoryInner::elementOpenDocument( void HistoryInner::elementOpenDocument(
not_null<DocumentData*> document, not_null<DocumentData*> document,
FullMsgId context, FullMsgId context,
bool showInMediaView) { bool showInMediaView) {
_controller->openDocument(document, context, showInMediaView); _controller->openDocument(document, context, MsgId(0), showInMediaView);
} }
void HistoryInner::elementCancelUpload(const FullMsgId &context) { void HistoryInner::elementCancelUpload(const FullMsgId &context) {

View file

@ -482,6 +482,7 @@ void HistoryItem::setIsPinned(bool pinned) {
_flags |= MessageFlag::Pinned; _flags |= MessageFlag::Pinned;
history()->session().storage().add(Storage::SharedMediaAddExisting( history()->session().storage().add(Storage::SharedMediaAddExisting(
history()->peer->id, history()->peer->id,
MsgId(0), // topicRootId
Storage::SharedMediaType::Pinned, Storage::SharedMediaType::Pinned,
id, id,
{ id, id })); { id, id }));

View file

@ -1464,9 +1464,9 @@ void HistoryWidget::applyInlineBotQuery(UserData *bot, const QString &query) {
if (result.open) { if (result.open) {
const auto request = result.result->openRequest(); const auto request = result.result->openRequest();
if (const auto photo = request.photo()) { if (const auto photo = request.photo()) {
controller()->openPhoto(photo, FullMsgId()); controller()->openPhoto(photo, {}, {});
} else if (const auto document = request.document()) { } else if (const auto document = request.document()) {
controller()->openDocument(document, FullMsgId()); controller()->openDocument(document, {}, {});
} }
} else { } else {
sendInlineResult(result); sendInlineResult(result);
@ -6138,6 +6138,7 @@ void HistoryWidget::updatePinnedViewer() {
if (_pinnedClickedId && !_minPinnedId) { if (_pinnedClickedId && !_minPinnedId) {
_minPinnedId = Data::ResolveMinPinnedId( _minPinnedId = Data::ResolveMinPinnedId(
_peer, _peer,
MsgId(0), // topicRootId
_migrated ? _migrated->peer.get() : nullptr); _migrated ? _migrated->peer.get() : nullptr);
} }
if (_pinnedClickedId && _minPinnedId && _minPinnedId >= _pinnedClickedId) { if (_pinnedClickedId && _minPinnedId && _minPinnedId >= _pinnedClickedId) {
@ -6183,6 +6184,7 @@ void HistoryWidget::checkPinnedBarState() {
: session().settings().hiddenPinnedMessageId(_peer->id); : session().settings().hiddenPinnedMessageId(_peer->id);
const auto currentPinnedId = Data::ResolveTopPinnedId( const auto currentPinnedId = Data::ResolveTopPinnedId(
_peer, _peer,
MsgId(0), // topicRootId
_migrated ? _migrated->peer.get() : nullptr); _migrated ? _migrated->peer.get() : nullptr);
const auto universalPinnedId = !currentPinnedId const auto universalPinnedId = !currentPinnedId
? int32(0) ? int32(0)
@ -6217,6 +6219,7 @@ void HistoryWidget::checkPinnedBarState() {
}); });
auto pinnedRefreshed = Info::Profile::SharedMediaCountValue( auto pinnedRefreshed = Info::Profile::SharedMediaCountValue(
_peer, _peer,
MsgId(0), // topicRootId
nullptr, nullptr,
Storage::SharedMediaType::Pinned Storage::SharedMediaType::Pinned
) | rpl::distinct_until_changed( ) | rpl::distinct_until_changed(

View file

@ -2662,9 +2662,9 @@ void ComposeControls::applyInlineBotQuery(
if (result.open) { if (result.open) {
const auto request = result.result->openRequest(); const auto request = result.result->openRequest();
if (const auto photo = request.photo()) { if (const auto photo = request.photo()) {
_window->openPhoto(photo, FullMsgId()); _window->openPhoto(photo, {}, {});
} else if (const auto document = request.document()) { } else if (const auto document = request.document()) {
_window->openDocument(document, FullMsgId()); _window->openDocument(document, {}, {});
} }
} else { } else {
_inlineResultChosen.fire_copy(result); _inlineResultChosen.fire_copy(result);

View file

@ -189,13 +189,12 @@ void SaveGif(
} }
} }
void OpenGif( void OpenGif(not_null<ListWidget*> list, FullMsgId itemId) {
not_null<Window::SessionController*> controller, const auto controller = list->controller();
FullMsgId itemId) {
if (const auto item = controller->session().data().message(itemId)) { if (const auto item = controller->session().data().message(itemId)) {
if (const auto media = item->media()) { if (const auto media = item->media()) {
if (const auto document = media->document()) { if (const auto document = media->document()) {
controller->openDocument(document, itemId, true); list->elementOpenDocument(document, itemId, true);
} }
} }
} }
@ -261,8 +260,11 @@ void AddDocumentActions(
item->history()->peer, item->history()->peer,
document); document);
if (notAutoplayedGif) { if (notAutoplayedGif) {
const auto weak = Ui::MakeWeak(list.get());
menu->addAction(tr::lng_context_open_gif(tr::now), [=] { menu->addAction(tr::lng_context_open_gif(tr::now), [=] {
OpenGif(list->controller(), contextId); if (const auto strong = weak.data()) {
OpenGif(strong, contextId);
}
}, &st::menuIconShowInChat); }, &st::menuIconShowInChat);
} }
if (!list->hasCopyRestriction(item)) { if (!list->hasCopyRestriction(item)) {

View file

@ -1549,14 +1549,14 @@ void ListWidget::elementShowPollResults(
void ListWidget::elementOpenPhoto( void ListWidget::elementOpenPhoto(
not_null<PhotoData*> photo, not_null<PhotoData*> photo,
FullMsgId context) { FullMsgId context) {
_controller->openPhoto(photo, context); _delegate->listOpenPhoto(photo, context);
} }
void ListWidget::elementOpenDocument( void ListWidget::elementOpenDocument(
not_null<DocumentData*> document, not_null<DocumentData*> document,
FullMsgId context, FullMsgId context,
bool showInMediaView) { bool showInMediaView) {
_controller->openDocument(document, context, showInMediaView); _delegate->listOpenDocument(document, context, showInMediaView);
} }
void ListWidget::elementCancelUpload(const FullMsgId &context) { void ListWidget::elementCancelUpload(const FullMsgId &context) {

View file

@ -125,6 +125,13 @@ public:
virtual auto listAllowedReactionsValue() virtual auto listAllowedReactionsValue()
-> rpl::producer<Data::AllowedReactions> = 0; -> rpl::producer<Data::AllowedReactions> = 0;
virtual void listShowPremiumToast(not_null<DocumentData*> document) = 0; virtual void listShowPremiumToast(not_null<DocumentData*> document) = 0;
virtual void listOpenPhoto(
not_null<PhotoData*> photo,
FullMsgId context) = 0;
virtual void listOpenDocument(
not_null<DocumentData*> document,
FullMsgId context,
bool showInMediaView) = 0;
}; };
struct SelectionData { struct SelectionData {

View file

@ -453,28 +453,6 @@ void PinnedWidget::listDeleteRequest() {
confirmDeleteSelected(); confirmDeleteSelected();
} }
rpl::producer<int> SharedMediaCountValue(
not_null<PeerData*> peer,
PeerData *migrated,
Storage::SharedMediaType type) {
auto aroundId = 0;
auto limit = 0;
auto updated = SharedMediaMergedViewer(
&peer->session(),
SharedMediaMergedKey(
SparseIdsMergedSlice::Key(
peer->id,
migrated ? migrated->id : 0,
aroundId),
type),
limit,
limit
) | rpl::map([](const SparseIdsMergedSlice &slice) {
return slice.fullCount();
}) | rpl::filter_optional();
return rpl::single(0) | rpl::then(std::move(updated));
}
rpl::producer<Data::MessagesSlice> PinnedWidget::listSource( rpl::producer<Data::MessagesSlice> PinnedWidget::listSource(
Data::MessagePosition aroundId, Data::MessagePosition aroundId,
int limitBefore, int limitBefore,
@ -488,6 +466,7 @@ rpl::producer<Data::MessagesSlice> PinnedWidget::listSource(
SharedMediaMergedKey( SharedMediaMergedKey(
SparseIdsMergedSlice::Key( SparseIdsMergedSlice::Key(
_history->peer->id, _history->peer->id,
MsgId(0), // topicRootId
_migratedPeer ? _migratedPeer->id : 0, _migratedPeer ? _migratedPeer->id : 0,
messageId), messageId),
Storage::SharedMediaType::Pinned), Storage::SharedMediaType::Pinned),
@ -611,6 +590,19 @@ auto PinnedWidget::listAllowedReactionsValue()
void PinnedWidget::listShowPremiumToast(not_null<DocumentData*> document) { void PinnedWidget::listShowPremiumToast(not_null<DocumentData*> document) {
} }
void PinnedWidget::listOpenPhoto(
not_null<PhotoData*> photo,
FullMsgId context) {
controller()->openPhoto(photo, context, MsgId());
}
void PinnedWidget::listOpenDocument(
not_null<DocumentData*> document,
FullMsgId context,
bool showInMediaView) {
controller()->openDocument(document, context, MsgId(), showInMediaView);
}
void PinnedWidget::confirmDeleteSelected() { void PinnedWidget::confirmDeleteSelected() {
ConfirmDeleteSelectedItems(_inner); ConfirmDeleteSelectedItems(_inner);
} }

View file

@ -112,6 +112,13 @@ public:
auto listAllowedReactionsValue() auto listAllowedReactionsValue()
-> rpl::producer<Data::AllowedReactions> override; -> rpl::producer<Data::AllowedReactions> override;
void listShowPremiumToast(not_null<DocumentData*> document) override; void listShowPremiumToast(not_null<DocumentData*> document) override;
void listOpenPhoto(
not_null<PhotoData*> photo,
FullMsgId context) override;
void listOpenDocument(
not_null<DocumentData*> document,
FullMsgId context,
bool showInMediaView) override;
// CornerButtonsDelegate delegate. // CornerButtonsDelegate delegate.
void cornerButtonsShowAtPosition( void cornerButtonsShowAtPosition(

View file

@ -82,6 +82,7 @@ void PinnedTracker::refreshViewer() {
SharedMediaMergedKey( SharedMediaMergedKey(
SparseIdsMergedSlice::Key( SparseIdsMergedSlice::Key(
_history->peer->id, _history->peer->id,
MsgId(0), // topicRootId
_migratedPeer ? _migratedPeer->id : 0, _migratedPeer ? _migratedPeer->id : 0,
_viewerAroundId), _viewerAroundId),
Storage::SharedMediaType::Pinned), Storage::SharedMediaType::Pinned),

View file

@ -233,7 +233,6 @@ RepliesWidget::RepliesWidget(
setupRoot(); setupRoot();
setupRootView(); setupRootView();
setupTopicViewer();
session().api().requestFullPeer(_history->peer); session().api().requestFullPeer(_history->peer);
@ -339,14 +338,17 @@ RepliesWidget::RepliesWidget(
} }
}, lifetime()); }, lifetime());
_history->session().changes().historyUpdates( if (!_topic) {
_history, _history->session().changes().historyUpdates(
Data::HistoryUpdate::Flag::OutboxRead _history,
) | rpl::start_with_next([=] { Data::HistoryUpdate::Flag::OutboxRead
_inner->update(); ) | rpl::start_with_next([=] {
}, lifetime()); _inner->update();
}, lifetime());
}
setupComposeControls(); setupComposeControls();
setupTopicViewer();
orderWidgets(); orderWidgets();
} }
@ -890,6 +892,7 @@ void RepliesWidget::sendingFilesConfirmed(
_composeControls->cancelReplyMessage(); _composeControls->cancelReplyMessage();
refreshTopBarActiveChat(); refreshTopBarActiveChat();
} }
finishSending();
} }
bool RepliesWidget::confirmSendingFiles( bool RepliesWidget::confirmSendingFiles(
@ -2059,6 +2062,19 @@ void RepliesWidget::listShowPremiumToast(not_null<DocumentData*> document) {
_stickerToast->showFor(document); _stickerToast->showFor(document);
} }
void RepliesWidget::listOpenPhoto(
not_null<PhotoData*> photo,
FullMsgId context) {
controller()->openPhoto(photo, context, _rootId);
}
void RepliesWidget::listOpenDocument(
not_null<DocumentData*> document,
FullMsgId context,
bool showInMediaView) {
controller()->openDocument(document, context, _rootId, showInMediaView);
}
void RepliesWidget::confirmDeleteSelected() { void RepliesWidget::confirmDeleteSelected() {
ConfirmDeleteSelectedItems(_inner); ConfirmDeleteSelectedItems(_inner);
} }

View file

@ -150,6 +150,13 @@ public:
auto listAllowedReactionsValue() auto listAllowedReactionsValue()
->rpl::producer<Data::AllowedReactions> override; ->rpl::producer<Data::AllowedReactions> override;
void listShowPremiumToast(not_null<DocumentData*> document) override; void listShowPremiumToast(not_null<DocumentData*> document) override;
void listOpenPhoto(
not_null<PhotoData*> photo,
FullMsgId context) override;
void listOpenDocument(
not_null<DocumentData*> document,
FullMsgId context,
bool showInMediaView) override;
// CornerButtonsDelegate delegate. // CornerButtonsDelegate delegate.
void cornerButtonsShowAtPosition( void cornerButtonsShowAtPosition(

View file

@ -1267,6 +1267,19 @@ void ScheduledWidget::listShowPremiumToast(
_stickerToast->showFor(document); _stickerToast->showFor(document);
} }
void ScheduledWidget::listOpenPhoto(
not_null<PhotoData*> photo,
FullMsgId context) {
controller()->openPhoto(photo, context, MsgId());
}
void ScheduledWidget::listOpenDocument(
not_null<DocumentData*> document,
FullMsgId context,
bool showInMediaView) {
controller()->openDocument(document, context, MsgId(), showInMediaView);
}
void ScheduledWidget::confirmSendNowSelected() { void ScheduledWidget::confirmSendNowSelected() {
ConfirmSendNowSelectedItems(_inner); ConfirmSendNowSelectedItems(_inner);
} }

View file

@ -135,6 +135,13 @@ public:
auto listAllowedReactionsValue() auto listAllowedReactionsValue()
-> rpl::producer<Data::AllowedReactions> override; -> rpl::producer<Data::AllowedReactions> override;
void listShowPremiumToast(not_null<DocumentData*> document) override; void listShowPremiumToast(not_null<DocumentData*> document) override;
void listOpenPhoto(
not_null<PhotoData*> photo,
FullMsgId context) override;
void listOpenDocument(
not_null<DocumentData*> document,
FullMsgId context,
bool showInMediaView) override;
// CornerButtonsDelegate delegate. // CornerButtonsDelegate delegate.
void cornerButtonsShowAtPosition( void cornerButtonsShowAtPosition(

View file

@ -100,15 +100,21 @@ rpl::producer<SparseIdsMergedSlice> AbstractController::mediaSource(
return false; return false;
}(); }();
auto mediaViewer = isScheduled const auto mediaViewer = isScheduled
? SharedScheduledMediaViewer ? SharedScheduledMediaViewer
: SharedMediaMergedViewer; : SharedMediaMergedViewer;
const auto topicId = isScheduled
? SparseIdsMergedSlice::kScheduledTopicId
: topic()
? topic()->rootId()
: MsgId(0);
return mediaViewer( return mediaViewer(
&session(), &session(),
SharedMediaMergedKey( SharedMediaMergedKey(
SparseIdsMergedSlice::Key( SparseIdsMergedSlice::Key(
peer()->id, peer()->id,
topicId,
migratedPeerId(), migratedPeerId(),
aroundId), aroundId),
section().mediaType()), section().mediaType()),
@ -363,6 +369,7 @@ rpl::producer<SparseIdsMergedSlice> Controller::mediaSource(
SharedMediaMergedKey( SharedMediaMergedKey(
SparseIdsMergedSlice::Key( SparseIdsMergedSlice::Key(
query.peerId, query.peerId,
query.topicRootId,
query.migratedPeerId, query.migratedPeerId,
aroundId), aroundId),
query.type), query.type),

View file

@ -129,6 +129,9 @@ public:
PeerData *peer() const; PeerData *peer() const;
PeerId migratedPeerId() const; PeerId migratedPeerId() const;
Data::ForumTopic *topic() const {
return key().topic();
}
UserData *settingsSelf() const { UserData *settingsSelf() const {
return key().settingsSelf(); return key().settingsSelf();
} }

View file

@ -83,12 +83,13 @@ inline auto AddButton(
Ui::VerticalLayout *parent, Ui::VerticalLayout *parent,
not_null<Window::SessionNavigation*> navigation, not_null<Window::SessionNavigation*> navigation,
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId topicRootId,
PeerData *migrated, PeerData *migrated,
Type type, Type type,
Ui::MultiSlideTracker &tracker) { Ui::MultiSlideTracker &tracker) {
auto result = AddCountedButton( auto result = AddCountedButton(
parent, parent,
Profile::SharedMediaCountValue(peer, migrated, type), Profile::SharedMediaCountValue(peer, topicRootId, migrated, type),
MediaText(type), MediaText(type),
tracker)->entity(); tracker)->entity();
result->addClickHandler([=] { result->addClickHandler([=] {

View file

@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "info/media/info_media_empty_widget.h" #include "info/media/info_media_empty_widget.h"
#include "info/profile/info_profile_icon.h" #include "info/profile/info_profile_icon.h"
#include "info/info_controller.h" #include "info/info_controller.h"
#include "data/data_forum_topic.h"
#include "ui/widgets/discrete_sliders.h" #include "ui/widgets/discrete_sliders.h"
#include "ui/widgets/shadow.h" #include "ui/widgets/shadow.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
@ -87,7 +88,11 @@ void InnerWidget::createTypeButtons() {
st::infoProfileSkip)); st::infoProfileSkip));
auto tracker = Ui::MultiSlideTracker(); auto tracker = Ui::MultiSlideTracker();
auto addMediaButton = [&]( const auto peer = _controller->key().peer();
const auto topic = _controller->key().topic();
const auto topicRootId = topic ? topic->rootId() : MsgId();
const auto migrated = _controller->migrated();
const auto addMediaButton = [&](
Type buttonType, Type buttonType,
const style::icon &icon) { const style::icon &icon) {
if (buttonType == type()) { if (buttonType == type()) {
@ -96,8 +101,9 @@ void InnerWidget::createTypeButtons() {
auto result = AddButton( auto result = AddButton(
content, content,
_controller, _controller,
_controller->key().peer(), peer,
_controller->migrated(), topicRootId,
migrated,
buttonType, buttonType,
tracker); tracker);
object_ptr<Profile::FloatingIcon>( object_ptr<Profile::FloatingIcon>(

View file

@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_file_click_handler.h" #include "data/data_file_click_handler.h"
#include "data/data_file_origin.h" #include "data/data_file_origin.h"
#include "data/data_download_manager.h" #include "data/data_download_manager.h"
#include "data/data_forum_topic.h"
#include "history/history_item.h" #include "history/history_item.h"
#include "history/history.h" #include "history/history.h"
#include "history/view/history_view_cursor_state.h" #include "history/view/history_view_cursor_state.h"
@ -467,7 +468,7 @@ bool ListWidget::tooltipWindowActive() const {
} }
void ListWidget::openPhoto(not_null<PhotoData*> photo, FullMsgId id) { void ListWidget::openPhoto(not_null<PhotoData*> photo, FullMsgId id) {
_controller->parentController()->openPhoto(photo, id); _controller->parentController()->openPhoto(photo, id, topicRootId());
} }
void ListWidget::openDocument( void ListWidget::openDocument(
@ -477,6 +478,7 @@ void ListWidget::openDocument(
_controller->parentController()->openDocument( _controller->parentController()->openDocument(
document, document,
id, id,
topicRootId(),
showInMediaView); showInMediaView);
} }
@ -739,6 +741,11 @@ void ListWidget::restoreScrollState() {
_scrollTopState = ListScrollTopState(); _scrollTopState = ListScrollTopState();
} }
MsgId ListWidget::topicRootId() const {
const auto topic = _controller->key().topic();
return topic ? topic->rootId() : MsgId(0);
}
QMargins ListWidget::padding() const { QMargins ListWidget::padding() const {
return st::infoMediaMargin; return st::infoMediaMargin;
} }

View file

@ -157,6 +157,8 @@ private:
void setupSelectRestriction(); void setupSelectRestriction();
[[nodiscard]] MsgId topicRootId() const;
QMargins padding() const; QMargins padding() const;
bool isItemLayout( bool isItemLayout(
not_null<const HistoryItem*> item, not_null<const HistoryItem*> item,

View file

@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_chat.h" #include "data/data_chat.h"
#include "data/data_channel.h" #include "data/data_channel.h"
#include "data/data_forum_topic.h"
#include "data/data_user.h" #include "data/data_user.h"
#include "data/data_peer_values.h" #include "data/data_peer_values.h"
#include "data/data_document.h" #include "data/data_document.h"
@ -61,6 +62,9 @@ constexpr auto kPreloadedScreensCountFull
Provider::Provider(not_null<AbstractController*> controller) Provider::Provider(not_null<AbstractController*> controller)
: _controller(controller) : _controller(controller)
, _peer(_controller->key().peer()) , _peer(_controller->key().peer())
, _topicRootId(_controller->key().topic()
? _controller->key().topic()->rootId()
: 0)
, _migrated(_controller->migrated()) , _migrated(_controller->migrated())
, _type(_controller->section().mediaType()) , _type(_controller->section().mediaType())
, _slice(sliceKey(_universalAroundId)) { , _slice(sliceKey(_universalAroundId)) {
@ -348,14 +352,14 @@ void Provider::setSearchQuery(QString query) {
SparseIdsMergedSlice::Key Provider::sliceKey( SparseIdsMergedSlice::Key Provider::sliceKey(
UniversalMsgId universalId) const { UniversalMsgId universalId) const {
using Key = SparseIdsMergedSlice::Key; using Key = SparseIdsMergedSlice::Key;
if (_migrated) { if (!_topicRootId && _migrated) {
return Key(_peer->id, _migrated->id, universalId); return Key(_peer->id, _topicRootId, _migrated->id, universalId);
} }
if (universalId < 0) { if (universalId < 0) {
// Convert back to plain id for non-migrated histories. // Convert back to plain id for non-migrated histories.
universalId = universalId + ServerMaxMsgId; universalId = universalId + ServerMaxMsgId;
} }
return Key(_peer->id, 0, universalId); return Key(_peer->id, _topicRootId, 0, universalId);
} }
void Provider::itemRemoved(not_null<const HistoryItem*> item) { void Provider::itemRemoved(not_null<const HistoryItem*> item) {

View file

@ -104,6 +104,7 @@ private:
const not_null<AbstractController*> _controller; const not_null<AbstractController*> _controller;
const not_null<PeerData*> _peer; const not_null<PeerData*> _peer;
const MsgId _topicRootId = 0;
PeerData * const _migrated = nullptr; PeerData * const _migrated = nullptr;
const Type _type = Type::Photo; const Type _type = Type::Photo;

View file

@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "info/media/info_media_buttons.h" #include "info/media/info_media_buttons.h"
#include "boxes/abstract_box.h" #include "boxes/abstract_box.h"
#include "boxes/add_contact_box.h" #include "boxes/add_contact_box.h"
#include "data/data_forum_topic.h"
#include "ui/boxes/confirm_box.h" #include "ui/boxes/confirm_box.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "main/main_session.h" #include "main/main_session.h"
@ -77,8 +78,7 @@ object_ptr<Ui::RpWidget> InnerWidget::setupContent(
}, _cover->lifetime()); }, _cover->lifetime());
_cover->setOnlineCount(rpl::single(0)); _cover->setOnlineCount(rpl::single(0));
if (_topic) { if (_topic) {
// #TODO forum shared media result->add(setupSharedMedia(result.data()));
//result->add(setupSharedMedia(result.data()));
return result; return result;
} }
@ -127,6 +127,7 @@ object_ptr<Ui::RpWidget> InnerWidget::setupSharedMedia(
content, content,
_controller, _controller,
_peer, _peer,
_topic ? _topic->rootId() : 0,
_migrated, _migrated,
type, type,
tracker); tracker);

View file

@ -400,6 +400,7 @@ rpl::producer<int> KickedCountValue(not_null<ChannelData*> channel) {
rpl::producer<int> SharedMediaCountValue( rpl::producer<int> SharedMediaCountValue(
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId topicRootId,
PeerData *migrated, PeerData *migrated,
Storage::SharedMediaType type) { Storage::SharedMediaType type) {
auto aroundId = 0; auto aroundId = 0;
@ -409,6 +410,7 @@ rpl::producer<int> SharedMediaCountValue(
SharedMediaMergedKey( SharedMediaMergedKey(
SparseIdsMergedSlice::Key( SparseIdsMergedSlice::Key(
peer->id, peer->id,
topicRootId,
migrated ? migrated->id : 0, migrated ? migrated->id : 0,
aroundId), aroundId),
type), type),

View file

@ -85,6 +85,7 @@ rpl::producer<not_null<PeerData*>> MigratedOrMeValue(
not_null<ChannelData*> channel); not_null<ChannelData*> channel);
[[nodiscard]] rpl::producer<int> SharedMediaCountValue( [[nodiscard]] rpl::producer<int> SharedMediaCountValue(
not_null<PeerData*> peer, not_null<PeerData*> peer,
MsgId topicRootId,
PeerData *migrated, PeerData *migrated,
Storage::SharedMediaType type); Storage::SharedMediaType type);
[[nodiscard]] rpl::producer<int> CommonGroupsCountValue( [[nodiscard]] rpl::producer<int> CommonGroupsCountValue(

View file

@ -336,10 +336,11 @@ bool Result::onChoose(Layout::ItemBase *layout) {
} }
Media::View::OpenRequest Result::openRequest() { Media::View::OpenRequest Result::openRequest() {
using namespace Media::View;
if (_document) { if (_document) {
return Media::View::OpenRequest(nullptr, _document, nullptr); return OpenRequest(nullptr, _document, nullptr, MsgId());
} else if (_photo) { } else if (_photo) {
return Media::View::OpenRequest(nullptr, _photo, nullptr); return OpenRequest(nullptr, _photo, nullptr, MsgId());
} }
return {}; return {};
} }

View file

@ -86,6 +86,7 @@ struct Instance::ShuffleData {
std::vector<UniversalMsgId> nonPlayedIds; std::vector<UniversalMsgId> nonPlayedIds;
std::vector<UniversalMsgId> playedIds; std::vector<UniversalMsgId> playedIds;
History *history = nullptr; History *history = nullptr;
MsgId topicRootId = 0;
History *migrated = nullptr; History *migrated = nullptr;
bool scheduled = false; bool scheduled = false;
int indexInPlayedIds = 0; int indexInPlayedIds = 0;
@ -243,6 +244,7 @@ void Instance::setHistory(
Main::Session *sessionFallback) { Main::Session *sessionFallback) {
if (history) { if (history) {
data->history = history->migrateToOrMe(); data->history = history->migrateToOrMe();
data->topicRootId = 0;
data->migrated = data->history->migrateFrom(); data->migrated = data->history->migrateFrom();
setSession(data, &history->session()); setSession(data, &history->session());
} else { } else {
@ -349,8 +351,8 @@ bool Instance::validPlaylist(not_null<const Data*> data) const {
using Key = SliceKey; using Key = SliceKey;
const auto inSameDomain = [](const Key &a, const Key &b) { const auto inSameDomain = [](const Key &a, const Key &b) {
return (a.peerId == b.peerId) return (a.peerId == b.peerId)
&& (a.migratedPeerId == b.migratedPeerId) && (a.topicRootId == b.topicRootId)
&& (a.scheduled == b.scheduled); && (a.migratedPeerId == b.migratedPeerId);
}; };
const auto countDistanceInData = [&](const Key &a, const Key &b) { const auto countDistanceInData = [&](const Key &a, const Key &b) {
return [&](const SparseIdsMergedSlice &data) { return [&](const SparseIdsMergedSlice &data) {
@ -382,7 +384,8 @@ void Instance::validatePlaylist(not_null<Data*> data) {
if (const auto key = playlistKey(data)) { if (const auto key = playlistKey(data)) {
data->playlistRequestedKey = key; data->playlistRequestedKey = key;
const auto sharedMediaViewer = key->scheduled const auto sharedMediaViewer = (key->topicRootId
== SparseIdsMergedSlice::kScheduledTopicId)
? SharedScheduledMediaViewer ? SharedScheduledMediaViewer
: SharedMediaMergedViewer; : SharedMediaMergedViewer;
sharedMediaViewer( sharedMediaViewer(
@ -419,9 +422,11 @@ auto Instance::playlistKey(not_null<const Data*> data) const
: (contextId.msg - ServerMaxMsgId); : (contextId.msg - ServerMaxMsgId);
return SliceKey( return SliceKey(
data->history->peer->id, data->history->peer->id,
(item->isScheduled()
? SparseIdsMergedSlice::kScheduledTopicId
: data->topicRootId),
data->migrated ? data->migrated->peer->id : 0, data->migrated ? data->migrated->peer->id : 0,
universalId, universalId);
item->isScheduled());
} }
bool Instance::validOtherPlaylist(not_null<const Data*> data) const { bool Instance::validOtherPlaylist(not_null<const Data*> data) const {
@ -476,13 +481,13 @@ auto Instance::playlistOtherKey(not_null<const Data*> data) const
return SliceKey( return SliceKey(
data->history->peer->id, data->history->peer->id,
data->topicRootId,
data->migrated ? data->migrated->peer->id : 0, data->migrated ? data->migrated->peer->id : 0,
(data->playlistSlice->skippedBefore() == 0 (data->playlistSlice->skippedBefore() == 0
? ServerMaxMsgId - 1 ? ServerMaxMsgId - 1
: data->migrated : data->migrated
? (1 - ServerMaxMsgId) ? (1 - ServerMaxMsgId)
: 1), : 1));
false);
} }
HistoryItem *Instance::itemByIndex(not_null<Data*> data, int index) { HistoryItem *Instance::itemByIndex(not_null<Data*> data, int index) {
@ -892,8 +897,10 @@ void Instance::validateShuffleData(not_null<Data*> data) {
} }
const auto raw = data->shuffleData.get(); const auto raw = data->shuffleData.get();
const auto key = playlistKey(data); const auto key = playlistKey(data);
const auto scheduled = key && key->scheduled; const auto scheduled = key
&& (key->topicRootId == SparseIdsMergedSlice::kScheduledTopicId);
if (raw->history != data->history if (raw->history != data->history
|| raw->topicRootId != data->topicRootId
|| raw->migrated != data->migrated || raw->migrated != data->migrated
|| raw->scheduled != scheduled) { || raw->scheduled != scheduled) {
raw->history = data->history; raw->history = data->history;
@ -950,9 +957,9 @@ void Instance::validateShuffleData(not_null<Data*> data) {
SharedMediaMergedKey( SharedMediaMergedKey(
SliceKey( SliceKey(
raw->history->peer->id, raw->history->peer->id,
raw->topicRootId,
raw->migrated ? raw->migrated->peer->id : 0, raw->migrated ? raw->migrated->peer->id : 0,
last, last),
false),
data->overview), data->overview),
kIdsLimit, kIdsLimit,
kIdsLimit kIdsLimit

View file

@ -195,6 +195,7 @@ private:
rpl::lifetime sessionLifetime; rpl::lifetime sessionLifetime;
rpl::event_stream<> playlistChanges; rpl::event_stream<> playlistChanges;
History *history = nullptr; History *history = nullptr;
MsgId topicRootId = 0;
History *migrated = nullptr; History *migrated = nullptr;
Main::Session *session = nullptr; Main::Session *session = nullptr;
bool isPlaying = false; bool isPlaying = false;

View file

@ -28,10 +28,12 @@ public:
OpenRequest( OpenRequest(
Window::SessionController *controller, Window::SessionController *controller,
not_null<PhotoData*> photo, not_null<PhotoData*> photo,
HistoryItem *item) HistoryItem *item,
MsgId topicRootId)
: _controller(controller) : _controller(controller)
, _photo(photo) , _photo(photo)
, _item(item) { , _item(item)
, _topicRootId(topicRootId) {
} }
OpenRequest( OpenRequest(
Window::SessionController *controller, Window::SessionController *controller,
@ -46,11 +48,13 @@ public:
Window::SessionController *controller, Window::SessionController *controller,
not_null<DocumentData*> document, not_null<DocumentData*> document,
HistoryItem *item, HistoryItem *item,
MsgId topicRootId,
bool continueStreaming = false, bool continueStreaming = false,
crl::time startTime = 0) crl::time startTime = 0)
: _controller(controller) : _controller(controller)
, _document(document) , _document(document)
, _item(item) , _item(item)
, _topicRootId(topicRootId)
, _continueStreaming(continueStreaming) , _continueStreaming(continueStreaming)
, _startTime(startTime) { , _startTime(startTime) {
} }
@ -63,35 +67,39 @@ public:
, _cloudTheme(cloudTheme) { , _cloudTheme(cloudTheme) {
} }
PeerData *peer() const { [[nodiscard]] PeerData *peer() const {
return _peer; return _peer;
} }
PhotoData *photo() const { [[nodiscard]] PhotoData *photo() const {
return _photo; return _photo;
} }
HistoryItem *item() const { [[nodiscard]] HistoryItem *item() const {
return _item; return _item;
} }
DocumentData *document() const { [[nodiscard]] MsgId topicRootId() const {
return _topicRootId;
}
[[nodiscard]] DocumentData *document() const {
return _document; return _document;
} }
std::optional<Data::CloudTheme> cloudTheme() const { [[nodiscard]] std::optional<Data::CloudTheme> cloudTheme() const {
return _cloudTheme; return _cloudTheme;
} }
Window::SessionController *controller() const { [[nodiscard]] Window::SessionController *controller() const {
return _controller; return _controller;
} }
bool continueStreaming() const { [[nodiscard]] bool continueStreaming() const {
return _continueStreaming; return _continueStreaming;
} }
crl::time startTime() const { [[nodiscard]] crl::time startTime() const {
return _startTime; return _startTime;
} }
@ -101,6 +109,7 @@ private:
PhotoData *_photo = nullptr; PhotoData *_photo = nullptr;
PeerData *_peer = nullptr; PeerData *_peer = nullptr;
HistoryItem *_item = nullptr; HistoryItem *_item = nullptr;
MsgId _topicRootId = 0;
std::optional<Data::CloudTheme> _cloudTheme = std::nullopt; std::optional<Data::CloudTheme> _cloudTheme = std::nullopt;
bool _continueStreaming = false; bool _continueStreaming = false;
crl::time _startTime = 0; crl::time _startTime = 0;

View file

@ -244,7 +244,6 @@ struct OverlayWidget::PipWrap {
PipWrap( PipWrap(
QWidget *parent, QWidget *parent,
not_null<DocumentData*> document, not_null<DocumentData*> document,
FullMsgId contextId,
std::shared_ptr<Streaming::Document> shared, std::shared_ptr<Streaming::Document> shared,
FnMut<void()> closeAndContinue, FnMut<void()> closeAndContinue,
FnMut<void()> destroy); FnMut<void()> destroy);
@ -279,7 +278,6 @@ OverlayWidget::Streamed::Streamed(
OverlayWidget::PipWrap::PipWrap( OverlayWidget::PipWrap::PipWrap(
QWidget *parent, QWidget *parent,
not_null<DocumentData*> document, not_null<DocumentData*> document,
FullMsgId contextId,
std::shared_ptr<Streaming::Document> shared, std::shared_ptr<Streaming::Document> shared,
FnMut<void()> closeAndContinue, FnMut<void()> closeAndContinue,
FnMut<void()> destroy) FnMut<void()> destroy)
@ -287,7 +285,6 @@ OverlayWidget::PipWrap::PipWrap(
, wrapped( , wrapped(
&delegate, &delegate,
document, document,
contextId,
std::move(shared), std::move(shared),
std::move(closeAndContinue), std::move(closeAndContinue),
std::move(destroy)) { std::move(destroy)) {
@ -1708,7 +1705,11 @@ void OverlayWidget::handleDocumentClick() {
if (_document->loading()) { if (_document->loading()) {
saveCancel(); saveCancel();
} else { } else {
Data::ResolveDocument(findWindow(), _document, _message); Data::ResolveDocument(
findWindow(),
_document,
_message,
_topicRootId);
if (_document->loading() && !_radial.animating()) { if (_document->loading() && !_radial.animating()) {
_radial.start(_documentMedia->progress()); _radial.start(_documentMedia->progress());
} }
@ -1975,8 +1976,9 @@ auto OverlayWidget::sharedMediaKey() const -> std::optional<SharedMediaKey> {
&& !_user && !_user
&& _photo && _photo
&& _peer->userpicPhotoId() == _photo->id) { && _peer->userpicPhotoId() == _photo->id) {
return SharedMediaKey { return SharedMediaKey{
_history->peer->id, _history->peer->id,
MsgId(0), // topicRootId
_migrated ? _migrated->peer->id : 0, _migrated ? _migrated->peer->id : 0,
SharedMediaType::ChatPhoto, SharedMediaType::ChatPhoto,
_photo _photo
@ -1989,12 +1991,14 @@ auto OverlayWidget::sharedMediaKey() const -> std::optional<SharedMediaKey> {
const auto keyForType = [&](SharedMediaType type) -> SharedMediaKey { const auto keyForType = [&](SharedMediaType type) -> SharedMediaKey {
return { return {
_history->peer->id, _history->peer->id,
(isScheduled
? SparseIdsMergedSlice::kScheduledTopicId
: _topicRootId),
_migrated ? _migrated->peer->id : 0, _migrated ? _migrated->peer->id : 0,
type, type,
(_message->history() == _history (_message->history() == _history
? _message->id ? _message->id
: (_message->id - ServerMaxMsgId)), : (_message->id - ServerMaxMsgId))
isScheduled
}; };
}; };
if (!_message->isRegular() && !isScheduled) { if (!_message->isRegular() && !isScheduled) {
@ -2038,8 +2042,8 @@ bool OverlayWidget::validSharedMedia() const {
auto inSameDomain = [](const Key &a, const Key &b) { auto inSameDomain = [](const Key &a, const Key &b) {
return (a.type == b.type) return (a.type == b.type)
&& (a.peerId == b.peerId) && (a.peerId == b.peerId)
&& (a.migratedPeerId == b.migratedPeerId) && (a.topicRootId == b.topicRootId)
&& (a.scheduled == b.scheduled); && (a.migratedPeerId == b.migratedPeerId);
}; };
auto countDistanceInData = [&](const Key &a, const Key &b) { auto countDistanceInData = [&](const Key &a, const Key &b) {
return [&](const SharedMediaWithLastSlice &data) { return [&](const SharedMediaWithLastSlice &data) {
@ -2432,6 +2436,7 @@ void OverlayWidget::show(OpenRequest request) {
const auto photo = request.photo(); const auto photo = request.photo();
const auto contextItem = request.item(); const auto contextItem = request.item();
const auto contextPeer = request.peer(); const auto contextPeer = request.peer();
const auto contextTopicRootId = request.topicRootId();
if (photo) { if (photo) {
if (contextItem && contextPeer) { if (contextItem && contextPeer) {
return; return;
@ -2441,7 +2446,7 @@ void OverlayWidget::show(OpenRequest request) {
if (contextPeer) { if (contextPeer) {
setContext(contextPeer); setContext(contextPeer);
} else if (contextItem) { } else if (contextItem) {
setContext(contextItem); setContext(ItemContext{ contextItem, contextTopicRootId });
} else { } else {
setContext(v::null); setContext(v::null);
} }
@ -2457,7 +2462,7 @@ void OverlayWidget::show(OpenRequest request) {
setSession(&document->session()); setSession(&document->session());
if (contextItem) { if (contextItem) {
setContext(contextItem); setContext(ItemContext{ contextItem, contextTopicRootId });
} else { } else {
setContext(v::null); setContext(v::null);
} }
@ -3299,19 +3304,20 @@ void OverlayWidget::switchToPip() {
const auto document = _document; const auto document = _document;
const auto message = _message; const auto message = _message;
const auto topicRootId = _topicRootId;
const auto closeAndContinue = [=] { const auto closeAndContinue = [=] {
_showAsPip = false; _showAsPip = false;
show(OpenRequest( show(OpenRequest(
findWindow(false), findWindow(false),
document, document,
message, message,
topicRootId,
true)); true));
}; };
_showAsPip = true; _showAsPip = true;
_pip = std::make_unique<PipWrap>( _pip = std::make_unique<PipWrap>(
_widget, _widget,
document, document,
message ? message->fullId() : FullMsgId(),
_streamed->instance.shared(), _streamed->instance.shared(),
closeAndContinue, closeAndContinue,
[=] { _pip = nullptr; }); [=] { _pip = nullptr; });
@ -4091,9 +4097,9 @@ OverlayWidget::Entity OverlayWidget::entityForCollage(int index) const {
return { v::null, nullptr }; return { v::null, nullptr };
} }
if (const auto document = std::get_if<DocumentData*>(&items[index])) { if (const auto document = std::get_if<DocumentData*>(&items[index])) {
return { *document, _message }; return { *document, _message, _topicRootId };
} else if (const auto photo = std::get_if<PhotoData*>(&items[index])) { } else if (const auto photo = std::get_if<PhotoData*>(&items[index])) {
return { *photo, _message }; return { *photo, _message, _topicRootId };
} }
return { v::null, nullptr }; return { v::null, nullptr };
} }
@ -4104,12 +4110,12 @@ OverlayWidget::Entity OverlayWidget::entityForItemId(const FullMsgId &itemId) co
if (const auto item = _session->data().message(itemId)) { if (const auto item = _session->data().message(itemId)) {
if (const auto media = item->media()) { if (const auto media = item->media()) {
if (const auto photo = media->photo()) { if (const auto photo = media->photo()) {
return { photo, item }; return { photo, item, _topicRootId };
} else if (const auto document = media->document()) { } else if (const auto document = media->document()) {
return { document, item }; return { document, item, _topicRootId };
} }
} }
return { v::null, item }; return { v::null, item, _topicRootId };
} }
return { v::null, nullptr }; return { v::null, nullptr };
} }
@ -4128,25 +4134,29 @@ OverlayWidget::Entity OverlayWidget::entityByIndex(int index) const {
void OverlayWidget::setContext( void OverlayWidget::setContext(
std::variant< std::variant<
v::null_t, v::null_t,
not_null<HistoryItem*>, ItemContext,
not_null<PeerData*>> context) { not_null<PeerData*>> context) {
if (const auto item = std::get_if<not_null<HistoryItem*>>(&context)) { if (const auto item = std::get_if<ItemContext>(&context)) {
_message = (*item); _message = item->item;
_topicRootId = item->topicRootId;
_history = _message->history(); _history = _message->history();
_peer = _history->peer; _peer = _history->peer;
} else if (const auto peer = std::get_if<not_null<PeerData*>>(&context)) { } else if (const auto peer = std::get_if<not_null<PeerData*>>(&context)) {
_peer = *peer; _peer = *peer;
_history = _peer->owner().history(_peer); _history = _peer->owner().history(_peer);
_message = nullptr; _message = nullptr;
_topicRootId = MsgId();
} else { } else {
_message = nullptr; _message = nullptr;
_topicRootId = MsgId();
_history = nullptr; _history = nullptr;
_peer = nullptr; _peer = nullptr;
} }
_migrated = nullptr; _migrated = nullptr;
if (_history) { if (_history) {
if (_history->peer->migrateFrom()) { if (_history->peer->migrateFrom()) {
_migrated = _history->owner().history(_history->peer->migrateFrom()); _migrated = _history->owner().history(
_history->peer->migrateFrom());
} else if (_history->peer->migrateTo()) { } else if (_history->peer->migrateTo()) {
_migrated = _history; _migrated = _history;
_history = _history->owner().history(_history->peer->migrateTo()); _history = _history->owner().history(_history->peer->migrateTo());
@ -4211,7 +4221,7 @@ bool OverlayWidget::moveToEntity(const Entity &entity, int preloadDelta) {
return false; return false;
} }
if (const auto item = entity.item) { if (const auto item = entity.item) {
setContext(item); setContext(ItemContext{ item, entity.topicRootId });
} else if (_peer) { } else if (_peer) {
setContext(_peer); setContext(_peer);
} else { } else {

View file

@ -131,7 +131,8 @@ private:
v::null_t, v::null_t,
not_null<PhotoData*>, not_null<PhotoData*>,
not_null<DocumentData*>> data; not_null<DocumentData*>> data;
HistoryItem *item; HistoryItem *item = nullptr;
MsgId topicRootId = 0;
}; };
enum class SavePhotoVideo { enum class SavePhotoVideo {
None, None,
@ -241,9 +242,14 @@ private:
Entity entityByIndex(int index) const; Entity entityByIndex(int index) const;
Entity entityForItemId(const FullMsgId &itemId) const; Entity entityForItemId(const FullMsgId &itemId) const;
bool moveToEntity(const Entity &entity, int preloadDelta = 0); bool moveToEntity(const Entity &entity, int preloadDelta = 0);
struct ItemContext {
not_null<HistoryItem*> item;
MsgId topicRootId = 0;
};
void setContext(std::variant< void setContext(std::variant<
v::null_t, v::null_t,
not_null<HistoryItem*>, ItemContext,
not_null<PeerData*>> context); not_null<PeerData*>> context);
void refreshLang(); void refreshLang();
@ -519,6 +525,7 @@ private:
History *_migrated = nullptr; History *_migrated = nullptr;
History *_history = nullptr; // if conversation photos or files overview History *_history = nullptr; // if conversation photos or files overview
MsgId _topicRootId = 0;
PeerData *_peer = nullptr; PeerData *_peer = nullptr;
UserData *_user = nullptr; // if user profile photos overview UserData *_user = nullptr; // if user profile photos overview

View file

@ -906,13 +906,11 @@ void PipPanel::updateDecorations() {
Pip::Pip( Pip::Pip(
not_null<Delegate*> delegate, not_null<Delegate*> delegate,
not_null<DocumentData*> data, not_null<DocumentData*> data,
FullMsgId contextId,
std::shared_ptr<Streaming::Document> shared, std::shared_ptr<Streaming::Document> shared,
FnMut<void()> closeAndContinue, FnMut<void()> closeAndContinue,
FnMut<void()> destroy) FnMut<void()> destroy)
: _delegate(delegate) : _delegate(delegate)
, _data(data) , _data(data)
, _contextId(contextId)
, _instance(std::move(shared), [=] { waitingAnimationCallback(); }) , _instance(std::move(shared), [=] { waitingAnimationCallback(); })
, _panel( , _panel(
_delegate->pipParentWidget(), _delegate->pipParentWidget(),

View file

@ -135,7 +135,6 @@ public:
Pip( Pip(
not_null<Delegate*> delegate, not_null<Delegate*> delegate,
not_null<DocumentData*> data, not_null<DocumentData*> data,
FullMsgId contextId,
std::shared_ptr<Streaming::Document> shared, std::shared_ptr<Streaming::Document> shared,
FnMut<void()> closeAndContinue, FnMut<void()> closeAndContinue,
FnMut<void()> destroy); FnMut<void()> destroy);
@ -254,7 +253,6 @@ private:
const not_null<Delegate*> _delegate; const not_null<Delegate*> _delegate;
const not_null<DocumentData*> _data; const not_null<DocumentData*> _data;
FullMsgId _contextId;
Streaming::Instance _instance; Streaming::Instance _instance;
bool _opengl = false; bool _opengl = false;
PipPanel _panel; PipPanel _panel;

View file

@ -11,13 +11,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Storage { namespace Storage {
std::map<PeerId, SharedMedia::Lists>::iterator auto SharedMedia::enforceLists(Key key)
SharedMedia::enforceLists(PeerId peer) { -> std::map<Key, SharedMedia::Lists>::iterator {
auto result = _lists.find(peer); auto result = _lists.find(key);
if (result != _lists.end()) { if (result != _lists.end()) {
return result; return result;
} }
result = _lists.emplace(peer, Lists {}).first; result = _lists.emplace(key, Lists {}).first;
for (auto index = 0; index != kSharedMediaTypeCount; ++index) { for (auto index = 0; index != kSharedMediaTypeCount; ++index) {
auto &list = result->second[index]; auto &list = result->second[index];
auto type = static_cast<SharedMediaType>(index); auto type = static_cast<SharedMediaType>(index);
@ -25,7 +25,8 @@ std::map<PeerId, SharedMedia::Lists>::iterator
list.sliceUpdated( list.sliceUpdated(
) | rpl::map([=](const SparseIdsSliceUpdate &update) { ) | rpl::map([=](const SparseIdsSliceUpdate &update) {
return SharedMediaSliceUpdate( return SharedMediaSliceUpdate(
peer, key.peerId,
key.topicRootId,
type, type,
update); update);
}) | rpl::start_to_stream(_sliceUpdated, _lifetime); }) | rpl::start_to_stream(_sliceUpdated, _lifetime);
@ -34,22 +35,26 @@ std::map<PeerId, SharedMedia::Lists>::iterator
} }
void SharedMedia::add(SharedMediaAddNew &&query) { void SharedMedia::add(SharedMediaAddNew &&query) {
auto peer = query.peerId; auto peerIt = enforceLists({ query.peerId, MsgId(0) });
auto peerIt = enforceLists(peer); while (peerIt != end(_lists) && peerIt->first.peerId == query.peerId) {
for (auto index = 0; index != kSharedMediaTypeCount; ++index) { for (auto index = 0; index != kSharedMediaTypeCount; ++index) {
auto type = static_cast<SharedMediaType>(index); auto type = static_cast<SharedMediaType>(index);
if (query.types.test(type)) { if (query.types.test(type)) {
peerIt->second[index].addNew(query.messageId); peerIt->second[index].addNew(query.messageId);
}
} }
++peerIt;
} }
} }
void SharedMedia::add(SharedMediaAddExisting &&query) { void SharedMedia::add(SharedMediaAddExisting &&query) {
auto peerIt = enforceLists(query.peerId); auto peerIt = enforceLists({ query.peerId, query.topicRootId });
for (auto index = 0; index != kSharedMediaTypeCount; ++index) { for (auto index = 0; index != kSharedMediaTypeCount; ++index) {
auto type = static_cast<SharedMediaType>(index); auto type = static_cast<SharedMediaType>(index);
if (query.types.test(type)) { if (query.types.test(type)) {
peerIt->second[index].addExisting(query.messageId, query.noSkipRange); peerIt->second[index].addExisting(
query.messageId,
query.noSkipRange);
} }
} }
} }
@ -57,7 +62,7 @@ void SharedMedia::add(SharedMediaAddExisting &&query) {
void SharedMedia::add(SharedMediaAddSlice &&query) { void SharedMedia::add(SharedMediaAddSlice &&query) {
Expects(IsValidSharedMediaType(query.type)); Expects(IsValidSharedMediaType(query.type));
auto peerIt = enforceLists(query.peerId); auto peerIt = enforceLists({ query.peerId, query.topicRootId });
auto index = static_cast<int>(query.type); auto index = static_cast<int>(query.type);
peerIt->second[index].addSlice( peerIt->second[index].addSlice(
std::move(query.messageIds), std::move(query.messageIds),
@ -66,45 +71,48 @@ void SharedMedia::add(SharedMediaAddSlice &&query) {
} }
void SharedMedia::remove(SharedMediaRemoveOne &&query) { void SharedMedia::remove(SharedMediaRemoveOne &&query) {
auto peerIt = _lists.find(query.peerId); auto peerIt = _lists.find({ query.peerId, MsgId(0) });
if (peerIt != _lists.end()) { while (peerIt != end(_lists) && peerIt->first.peerId == query.peerId) {
for (auto index = 0; index != kSharedMediaTypeCount; ++index) { for (auto index = 0; index != kSharedMediaTypeCount; ++index) {
auto type = static_cast<SharedMediaType>(index); auto type = static_cast<SharedMediaType>(index);
if (query.types.test(type)) { if (query.types.test(type)) {
peerIt->second[index].removeOne(query.messageId); peerIt->second[index].removeOne(query.messageId);
} }
} }
_oneRemoved.fire(std::move(query)); ++peerIt;
} }
_oneRemoved.fire(std::move(query));
} }
void SharedMedia::remove(SharedMediaRemoveAll &&query) { void SharedMedia::remove(SharedMediaRemoveAll &&query) {
auto peerIt = _lists.find(query.peerId); auto peerIt = _lists.find({ query.peerId, MsgId(0) });
if (peerIt != _lists.end()) { while (peerIt != end(_lists) && peerIt->first.peerId == query.peerId) {
for (auto index = 0; index != kSharedMediaTypeCount; ++index) { for (auto index = 0; index != kSharedMediaTypeCount; ++index) {
auto type = static_cast<SharedMediaType>(index); auto type = static_cast<SharedMediaType>(index);
if (query.types.test(type)) { if (query.types.test(type)) {
peerIt->second[index].removeAll(); peerIt->second[index].removeAll();
} }
} }
_allRemoved.fire(std::move(query)); ++peerIt;
} }
_allRemoved.fire(std::move(query));
} }
void SharedMedia::invalidate(SharedMediaInvalidateBottom &&query) { void SharedMedia::invalidate(SharedMediaInvalidateBottom &&query) {
auto peerIt = _lists.find(query.peerId); auto peerIt = _lists.find({ query.peerId, MsgId(0) });
if (peerIt != _lists.end()) { while (peerIt != end(_lists) && peerIt->first.peerId == query.peerId) {
for (auto index = 0; index != kSharedMediaTypeCount; ++index) { for (auto index = 0; index != kSharedMediaTypeCount; ++index) {
peerIt->second[index].invalidateBottom(); peerIt->second[index].invalidateBottom();
} }
_bottomInvalidated.fire(std::move(query)); ++peerIt;
} }
_bottomInvalidated.fire(std::move(query));
} }
rpl::producer<SharedMediaResult> SharedMedia::query(SharedMediaQuery &&query) const { rpl::producer<SharedMediaResult> SharedMedia::query(SharedMediaQuery &&query) const {
Expects(IsValidSharedMediaType(query.key.type)); Expects(IsValidSharedMediaType(query.key.type));
auto peerIt = _lists.find(query.key.peerId); auto peerIt = _lists.find({ query.key.peerId, query.key.topicRootId });
if (peerIt != _lists.end()) { if (peerIt != _lists.end()) {
auto index = static_cast<int>(query.key.type); auto index = static_cast<int>(query.key.type);
return peerIt->second[index].query(SparseIdsListQuery( return peerIt->second[index].query(SparseIdsListQuery(
@ -121,7 +129,7 @@ rpl::producer<SharedMediaResult> SharedMedia::query(SharedMediaQuery &&query) co
SharedMediaResult SharedMedia::snapshot(const SharedMediaQuery &query) const { SharedMediaResult SharedMedia::snapshot(const SharedMediaQuery &query) const {
Expects(IsValidSharedMediaType(query.key.type)); Expects(IsValidSharedMediaType(query.key.type));
auto peerIt = _lists.find(query.key.peerId); auto peerIt = _lists.find({ query.key.peerId, query.key.topicRootId });
if (peerIt != _lists.end()) { if (peerIt != _lists.end()) {
auto index = static_cast<int>(query.key.type); auto index = static_cast<int>(query.key.type);
return peerIt->second[index].snapshot(SparseIdsListQuery( return peerIt->second[index].snapshot(SparseIdsListQuery(
@ -135,7 +143,7 @@ SharedMediaResult SharedMedia::snapshot(const SharedMediaQuery &query) const {
bool SharedMedia::empty(const SharedMediaKey &key) const { bool SharedMedia::empty(const SharedMediaKey &key) const {
Expects(IsValidSharedMediaType(key.type)); Expects(IsValidSharedMediaType(key.type));
auto peerIt = _lists.find(key.peerId); auto peerIt = _lists.find({ key.peerId, key.topicRootId });
if (peerIt != _lists.end()) { if (peerIt != _lists.end()) {
auto index = static_cast<int>(key.type); auto index = static_cast<int>(key.type);
return peerIt->second[index].empty(); return peerIt->second[index].empty();

View file

@ -39,8 +39,13 @@ constexpr bool IsValidSharedMediaType(SharedMediaType type) {
using SharedMediaTypesMask = base::enum_mask<SharedMediaType>; using SharedMediaTypesMask = base::enum_mask<SharedMediaType>;
struct SharedMediaAddNew { struct SharedMediaAddNew {
SharedMediaAddNew(PeerId peerId, SharedMediaTypesMask types, MsgId messageId) SharedMediaAddNew(
: peerId(peerId), messageId(messageId), types(types) { PeerId peerId,
SharedMediaTypesMask types,
MsgId messageId)
: peerId(peerId)
, messageId(messageId)
, types(types) {
} }
PeerId peerId = 0; PeerId peerId = 0;
@ -52,16 +57,19 @@ struct SharedMediaAddNew {
struct SharedMediaAddExisting { struct SharedMediaAddExisting {
SharedMediaAddExisting( SharedMediaAddExisting(
PeerId peerId, PeerId peerId,
MsgId topicRootId,
SharedMediaTypesMask types, SharedMediaTypesMask types,
MsgId messageId, MsgId messageId,
MsgRange noSkipRange) MsgRange noSkipRange)
: peerId(peerId) : peerId(peerId)
, messageId(messageId) , topicRootId(topicRootId)
, noSkipRange(noSkipRange) , messageId(messageId)
, types(types) { , noSkipRange(noSkipRange)
, types(types) {
} }
PeerId peerId = 0; PeerId peerId = 0;
MsgId topicRootId = 0;
MsgId messageId = 0; MsgId messageId = 0;
MsgRange noSkipRange; MsgRange noSkipRange;
SharedMediaTypesMask types; SharedMediaTypesMask types;
@ -71,18 +79,21 @@ struct SharedMediaAddExisting {
struct SharedMediaAddSlice { struct SharedMediaAddSlice {
SharedMediaAddSlice( SharedMediaAddSlice(
PeerId peerId, PeerId peerId,
MsgId topicRootId,
SharedMediaType type, SharedMediaType type,
std::vector<MsgId> &&messageIds, std::vector<MsgId> &&messageIds,
MsgRange noSkipRange, MsgRange noSkipRange,
std::optional<int> count = std::nullopt) std::optional<int> count = std::nullopt)
: peerId(peerId) : peerId(peerId)
, messageIds(std::move(messageIds)) , topicRootId(topicRootId)
, noSkipRange(noSkipRange) , messageIds(std::move(messageIds))
, type(type) , noSkipRange(noSkipRange)
, count(count) { , type(type)
, count(count) {
} }
PeerId peerId = 0; PeerId peerId = 0;
MsgId topicRootId = 0;
std::vector<MsgId> messageIds; std::vector<MsgId> messageIds;
MsgRange noSkipRange; MsgRange noSkipRange;
SharedMediaType type = SharedMediaType::kCount; SharedMediaType type = SharedMediaType::kCount;
@ -130,23 +141,21 @@ struct SharedMediaInvalidateBottom {
struct SharedMediaKey { struct SharedMediaKey {
SharedMediaKey( SharedMediaKey(
PeerId peerId, PeerId peerId,
MsgId topicRootId,
SharedMediaType type, SharedMediaType type,
MsgId messageId) MsgId messageId)
: peerId(peerId) : peerId(peerId)
, topicRootId(topicRootId)
, type(type) , type(type)
, messageId(messageId) { , messageId(messageId) {
} }
bool operator==(const SharedMediaKey &other) const { friend inline constexpr auto operator<=>(
return (peerId == other.peerId) const SharedMediaKey &,
&& (type == other.type) const SharedMediaKey &) = default;
&& (messageId == other.messageId);
}
bool operator!=(const SharedMediaKey &other) const {
return !(*this == other);
}
PeerId peerId = 0; PeerId peerId = 0;
MsgId topicRootId = 0;
SharedMediaType type = SharedMediaType::kCount; SharedMediaType type = SharedMediaType::kCount;
MsgId messageId = 0; MsgId messageId = 0;
@ -173,14 +182,17 @@ using SharedMediaResult = SparseIdsListResult;
struct SharedMediaSliceUpdate { struct SharedMediaSliceUpdate {
SharedMediaSliceUpdate( SharedMediaSliceUpdate(
PeerId peerId, PeerId peerId,
MsgId topicRootId,
SharedMediaType type, SharedMediaType type,
const SparseIdsSliceUpdate &data) const SparseIdsSliceUpdate &data)
: peerId(peerId) : peerId(peerId)
, topicRootId(topicRootId)
, type(type) , type(type)
, data(data) { , data(data) {
} }
PeerId peerId = 0; PeerId peerId = 0;
MsgId topicRootId = 0;
SharedMediaType type = SharedMediaType::kCount; SharedMediaType type = SharedMediaType::kCount;
SparseIdsSliceUpdate data; SparseIdsSliceUpdate data;
}; };
@ -205,11 +217,17 @@ public:
rpl::producer<SharedMediaInvalidateBottom> bottomInvalidated() const; rpl::producer<SharedMediaInvalidateBottom> bottomInvalidated() const;
private: private:
struct Key {
PeerId peerId = 0;
MsgId topicRootId = 0;
friend inline constexpr auto operator<=>(Key, Key) = default;
};
using Lists = std::array<SparseIdsList, kSharedMediaTypeCount>; using Lists = std::array<SparseIdsList, kSharedMediaTypeCount>;
std::map<PeerId, Lists>::iterator enforceLists(PeerId peer); std::map<Key, Lists>::iterator enforceLists(Key key);
std::map<PeerId, Lists> _lists; std::map<Key, Lists> _lists;
rpl::event_stream<SharedMediaSliceUpdate> _sliceUpdated; rpl::event_stream<SharedMediaSliceUpdate> _sliceUpdated;
rpl::event_stream<SharedMediaRemoveOne> _oneRemoved; rpl::event_stream<SharedMediaRemoveOne> _oneRemoved;

View file

@ -1443,7 +1443,7 @@ void HidePinnedBar(
close(); close();
auto &session = peer->session(); auto &session = peer->session();
const auto migrated = peer->migrateFrom(); const auto migrated = peer->migrateFrom();
const auto top = Data::ResolveTopPinnedId(peer, migrated); const auto top = Data::ResolveTopPinnedId(peer, MsgId(0), migrated);
const auto universal = !top const auto universal = !top
? MsgId(0) ? MsgId(0)
: (migrated && !peerIsChannel(top.peer)) : (migrated && !peerIsChannel(top.peer))

View file

@ -1707,11 +1707,13 @@ void SessionController::hideLayer(anim::type animated) {
void SessionController::openPhoto( void SessionController::openPhoto(
not_null<PhotoData*> photo, not_null<PhotoData*> photo,
FullMsgId contextId) { FullMsgId contextId,
MsgId topicRootId) {
_window->openInMediaView(Media::View::OpenRequest( _window->openInMediaView(Media::View::OpenRequest(
this, this,
photo, photo,
session().data().message(contextId))); session().data().message(contextId),
topicRootId));
} }
void SessionController::openPhoto( void SessionController::openPhoto(
@ -1723,18 +1725,21 @@ void SessionController::openPhoto(
void SessionController::openDocument( void SessionController::openDocument(
not_null<DocumentData*> document, not_null<DocumentData*> document,
FullMsgId contextId, FullMsgId contextId,
MsgId topicRootId,
bool showInMediaView) { bool showInMediaView) {
if (showInMediaView) { if (showInMediaView) {
_window->openInMediaView(Media::View::OpenRequest( _window->openInMediaView(Media::View::OpenRequest(
this, this,
document, document,
session().data().message(contextId))); session().data().message(contextId),
topicRootId));
return; return;
} }
Data::ResolveDocument( Data::ResolveDocument(
this, this,
document, document,
session().data().message(contextId)); session().data().message(contextId),
topicRootId);
} }
auto SessionController::cachedChatThemeValue( auto SessionController::cachedChatThemeValue(

View file

@ -441,11 +441,15 @@ public:
void showPassportForm(const Passport::FormRequest &request); void showPassportForm(const Passport::FormRequest &request);
void clearPassportForm(); void clearPassportForm();
void openPhoto(not_null<PhotoData*> photo, FullMsgId contextId); void openPhoto(
not_null<PhotoData*> photo,
FullMsgId contextId,
MsgId topicRootId);
void openPhoto(not_null<PhotoData*> photo, not_null<PeerData*> peer); void openPhoto(not_null<PhotoData*> photo, not_null<PeerData*> peer);
void openDocument( void openDocument(
not_null<DocumentData*> document, not_null<DocumentData*> document,
FullMsgId contextId, FullMsgId contextId,
MsgId topicRootId,
bool showInMediaView = false); bool showInMediaView = false);
void showChooseReportMessages( void showChooseReportMessages(