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

View File

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

View File

@ -19,10 +19,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
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 migrated = normal->migrateFrom();
const auto top = Data::ResolveTopPinnedId(normal, migrated);
const auto top = Data::ResolveTopPinnedId(normal, topicRootId, migrated);
if (!top) {
return false;
} else if (peer == migrated) {
@ -46,7 +49,7 @@ void PinMessageBox(
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 api = box->lifetime().make_state<MTP::Sender>(
&peer->session().mtp());

View File

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

View File

@ -942,7 +942,7 @@ void ApplyChannelUpdate(
}
}
if (const auto pinned = update.vpinned_msg_id()) {
SetTopPinnedMessageId(channel, pinned->v);
SetTopPinnedMessageId(channel, MsgId(0), pinned->v);
}
if (channel->isMegagroup()) {
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);
}
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->setThemeEmoji(qs(update.vtheme_emoticon().value_or_empty()));

View File

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

View File

@ -1203,7 +1203,10 @@ std::optional<QString> RestrictionError(
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 (messageId <= channel->availableMinId()) {
return;
@ -1217,6 +1220,7 @@ void SetTopPinnedMessageId(not_null<PeerData*> peer, MsgId messageId) {
}
session.storage().add(Storage::SharedMediaAddExisting(
peer->id,
topicRootId,
Storage::SharedMediaType::Pinned,
messageId,
{ messageId, ServerMaxMsgId }));
@ -1225,20 +1229,23 @@ void SetTopPinnedMessageId(not_null<PeerData*> peer, MsgId messageId) {
FullMsgId ResolveTopPinnedId(
not_null<PeerData*> peer,
MsgId topicRootId,
PeerData *migrated) {
const auto slice = peer->session().storage().snapshot(
Storage::SharedMediaQuery(
Storage::SharedMediaKey(
peer->id,
topicRootId,
Storage::SharedMediaType::Pinned,
ServerMaxMsgId - 1),
1,
1));
const auto old = migrated
const auto old = (!topicRootId && migrated)
? migrated->session().storage().snapshot(
Storage::SharedMediaQuery(
Storage::SharedMediaKey(
migrated->id,
MsgId(0), // topicRootId
Storage::SharedMediaType::Pinned,
ServerMaxMsgId - 1),
1,
@ -1259,20 +1266,23 @@ FullMsgId ResolveTopPinnedId(
FullMsgId ResolveMinPinnedId(
not_null<PeerData*> peer,
MsgId topicRootId,
PeerData *migrated) {
const auto slice = peer->session().storage().snapshot(
Storage::SharedMediaQuery(
Storage::SharedMediaKey(
peer->id,
topicRootId,
Storage::SharedMediaType::Pinned,
1),
1,
1));
const auto old = migrated
const auto old = (!topicRootId && migrated)
? migrated->session().storage().snapshot(
Storage::SharedMediaQuery(
Storage::SharedMediaKey(
migrated->id,
MsgId(0), // topicRootId
Storage::SharedMediaType::Pinned,
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -624,14 +624,14 @@ void InnerWidget::elementShowPollResults(
void InnerWidget::elementOpenPhoto(
not_null<PhotoData*> photo,
FullMsgId context) {
_controller->openPhoto(photo, context);
_controller->openPhoto(photo, context, MsgId(0));
}
void InnerWidget::elementOpenDocument(
not_null<DocumentData*> document,
FullMsgId context,
bool showInMediaView) {
_controller->openDocument(document, context, showInMediaView);
_controller->openDocument(document, context, MsgId(0), showInMediaView);
}
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 media = item->media()) {
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();
session().storage().add(Storage::SharedMediaAddExisting(
peer->id,
MsgId(0),
sharedMediaTypes,
item->id,
{ from, till }));
@ -1047,6 +1048,7 @@ void History::applyServiceChanges(
if (item) {
session().storage().add(Storage::SharedMediaAddSlice(
peer->id,
MsgId(0), // topicRootId
Storage::SharedMediaType::Pinned,
{ id },
{ id, ServerMaxMsgId }));
@ -1268,6 +1270,7 @@ void History::addEdgesToSharedMedia() {
const auto type = static_cast<Storage::SharedMediaType>(i);
session().storage().add(Storage::SharedMediaAddSlice(
peer->id,
MsgId(0), // topicRootId
type,
{},
{ from, till }));
@ -1460,6 +1463,7 @@ void History::addToSharedMedia(
const auto type = static_cast<Storage::SharedMediaType>(i);
session().storage().add(Storage::SharedMediaAddSlice(
peer->id,
MsgId(0), // topicRootId
type,
std::move(medias[i]),
{ from, till }));

View File

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

View File

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

View File

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

View File

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

View File

@ -189,13 +189,12 @@ void SaveGif(
}
}
void OpenGif(
not_null<Window::SessionController*> controller,
FullMsgId itemId) {
void OpenGif(not_null<ListWidget*> list, FullMsgId itemId) {
const auto controller = list->controller();
if (const auto item = controller->session().data().message(itemId)) {
if (const auto media = item->media()) {
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,
document);
if (notAutoplayedGif) {
const auto weak = Ui::MakeWeak(list.get());
menu->addAction(tr::lng_context_open_gif(tr::now), [=] {
OpenGif(list->controller(), contextId);
if (const auto strong = weak.data()) {
OpenGif(strong, contextId);
}
}, &st::menuIconShowInChat);
}
if (!list->hasCopyRestriction(item)) {

View File

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

View File

@ -125,6 +125,13 @@ public:
virtual auto listAllowedReactionsValue()
-> rpl::producer<Data::AllowedReactions> = 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 {

View File

@ -453,28 +453,6 @@ void PinnedWidget::listDeleteRequest() {
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(
Data::MessagePosition aroundId,
int limitBefore,
@ -488,6 +466,7 @@ rpl::producer<Data::MessagesSlice> PinnedWidget::listSource(
SharedMediaMergedKey(
SparseIdsMergedSlice::Key(
_history->peer->id,
MsgId(0), // topicRootId
_migratedPeer ? _migratedPeer->id : 0,
messageId),
Storage::SharedMediaType::Pinned),
@ -611,6 +590,19 @@ auto PinnedWidget::listAllowedReactionsValue()
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() {
ConfirmDeleteSelectedItems(_inner);
}

View File

@ -112,6 +112,13 @@ public:
auto listAllowedReactionsValue()
-> rpl::producer<Data::AllowedReactions> 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.
void cornerButtonsShowAtPosition(

View File

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

View File

@ -233,7 +233,6 @@ RepliesWidget::RepliesWidget(
setupRoot();
setupRootView();
setupTopicViewer();
session().api().requestFullPeer(_history->peer);
@ -339,14 +338,17 @@ RepliesWidget::RepliesWidget(
}
}, lifetime());
_history->session().changes().historyUpdates(
_history,
Data::HistoryUpdate::Flag::OutboxRead
) | rpl::start_with_next([=] {
_inner->update();
}, lifetime());
if (!_topic) {
_history->session().changes().historyUpdates(
_history,
Data::HistoryUpdate::Flag::OutboxRead
) | rpl::start_with_next([=] {
_inner->update();
}, lifetime());
}
setupComposeControls();
setupTopicViewer();
orderWidgets();
}
@ -890,6 +892,7 @@ void RepliesWidget::sendingFilesConfirmed(
_composeControls->cancelReplyMessage();
refreshTopBarActiveChat();
}
finishSending();
}
bool RepliesWidget::confirmSendingFiles(
@ -2059,6 +2062,19 @@ void RepliesWidget::listShowPremiumToast(not_null<DocumentData*> 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() {
ConfirmDeleteSelectedItems(_inner);
}

View File

@ -150,6 +150,13 @@ public:
auto listAllowedReactionsValue()
->rpl::producer<Data::AllowedReactions> 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.
void cornerButtonsShowAtPosition(

View File

@ -1267,6 +1267,19 @@ void ScheduledWidget::listShowPremiumToast(
_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() {
ConfirmSendNowSelectedItems(_inner);
}

View File

@ -135,6 +135,13 @@ public:
auto listAllowedReactionsValue()
-> rpl::producer<Data::AllowedReactions> 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.
void cornerButtonsShowAtPosition(

View File

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

View File

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

View File

@ -83,12 +83,13 @@ inline auto AddButton(
Ui::VerticalLayout *parent,
not_null<Window::SessionNavigation*> navigation,
not_null<PeerData*> peer,
MsgId topicRootId,
PeerData *migrated,
Type type,
Ui::MultiSlideTracker &tracker) {
auto result = AddCountedButton(
parent,
Profile::SharedMediaCountValue(peer, migrated, type),
Profile::SharedMediaCountValue(peer, topicRootId, migrated, type),
MediaText(type),
tracker)->entity();
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/profile/info_profile_icon.h"
#include "info/info_controller.h"
#include "data/data_forum_topic.h"
#include "ui/widgets/discrete_sliders.h"
#include "ui/widgets/shadow.h"
#include "ui/widgets/buttons.h"
@ -87,7 +88,11 @@ void InnerWidget::createTypeButtons() {
st::infoProfileSkip));
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,
const style::icon &icon) {
if (buttonType == type()) {
@ -96,8 +101,9 @@ void InnerWidget::createTypeButtons() {
auto result = AddButton(
content,
_controller,
_controller->key().peer(),
_controller->migrated(),
peer,
topicRootId,
migrated,
buttonType,
tracker);
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_origin.h"
#include "data/data_download_manager.h"
#include "data/data_forum_topic.h"
#include "history/history_item.h"
#include "history/history.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) {
_controller->parentController()->openPhoto(photo, id);
_controller->parentController()->openPhoto(photo, id, topicRootId());
}
void ListWidget::openDocument(
@ -477,6 +478,7 @@ void ListWidget::openDocument(
_controller->parentController()->openDocument(
document,
id,
topicRootId(),
showInMediaView);
}
@ -739,6 +741,11 @@ void ListWidget::restoreScrollState() {
_scrollTopState = ListScrollTopState();
}
MsgId ListWidget::topicRootId() const {
const auto topic = _controller->key().topic();
return topic ? topic->rootId() : MsgId(0);
}
QMargins ListWidget::padding() const {
return st::infoMediaMargin;
}

View File

@ -157,6 +157,8 @@ private:
void setupSelectRestriction();
[[nodiscard]] MsgId topicRootId() const;
QMargins padding() const;
bool isItemLayout(
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_chat.h"
#include "data/data_channel.h"
#include "data/data_forum_topic.h"
#include "data/data_user.h"
#include "data/data_peer_values.h"
#include "data/data_document.h"
@ -61,6 +62,9 @@ constexpr auto kPreloadedScreensCountFull
Provider::Provider(not_null<AbstractController*> controller)
: _controller(controller)
, _peer(_controller->key().peer())
, _topicRootId(_controller->key().topic()
? _controller->key().topic()->rootId()
: 0)
, _migrated(_controller->migrated())
, _type(_controller->section().mediaType())
, _slice(sliceKey(_universalAroundId)) {
@ -348,14 +352,14 @@ void Provider::setSearchQuery(QString query) {
SparseIdsMergedSlice::Key Provider::sliceKey(
UniversalMsgId universalId) const {
using Key = SparseIdsMergedSlice::Key;
if (_migrated) {
return Key(_peer->id, _migrated->id, universalId);
if (!_topicRootId && _migrated) {
return Key(_peer->id, _topicRootId, _migrated->id, universalId);
}
if (universalId < 0) {
// Convert back to plain id for non-migrated histories.
universalId = universalId + ServerMaxMsgId;
}
return Key(_peer->id, 0, universalId);
return Key(_peer->id, _topicRootId, 0, universalId);
}
void Provider::itemRemoved(not_null<const HistoryItem*> item) {

View File

@ -104,6 +104,7 @@ private:
const not_null<AbstractController*> _controller;
const not_null<PeerData*> _peer;
const MsgId _topicRootId = 0;
PeerData * const _migrated = nullptr;
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 "boxes/abstract_box.h"
#include "boxes/add_contact_box.h"
#include "data/data_forum_topic.h"
#include "ui/boxes/confirm_box.h"
#include "mainwidget.h"
#include "main/main_session.h"
@ -77,8 +78,7 @@ object_ptr<Ui::RpWidget> InnerWidget::setupContent(
}, _cover->lifetime());
_cover->setOnlineCount(rpl::single(0));
if (_topic) {
// #TODO forum shared media
//result->add(setupSharedMedia(result.data()));
result->add(setupSharedMedia(result.data()));
return result;
}
@ -127,6 +127,7 @@ object_ptr<Ui::RpWidget> InnerWidget::setupSharedMedia(
content,
_controller,
_peer,
_topic ? _topic->rootId() : 0,
_migrated,
type,
tracker);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1443,7 +1443,7 @@ void HidePinnedBar(
close();
auto &session = peer->session();
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
? MsgId(0)
: (migrated && !peerIsChannel(top.peer))

View File

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

View File

@ -441,11 +441,15 @@ public:
void showPassportForm(const Passport::FormRequest &request);
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 openDocument(
not_null<DocumentData*> document,
FullMsgId contextId,
MsgId topicRootId,
bool showInMediaView = false);
void showChooseReportMessages(