mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-15 21:57:10 +02:00
Implement per-topic shared media.
This commit is contained in:
parent
eec4b72d9a
commit
58b8eb8e96
58 changed files with 434 additions and 269 deletions
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 }));
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 }));
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -82,6 +82,7 @@ void PinnedTracker::refreshViewer() {
|
|||
SharedMediaMergedKey(
|
||||
SparseIdsMergedSlice::Key(
|
||||
_history->peer->id,
|
||||
MsgId(0), // topicRootId
|
||||
_migratedPeer ? _migratedPeer->id : 0,
|
||||
_viewerAroundId),
|
||||
Storage::SharedMediaType::Pinned),
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -129,6 +129,9 @@ public:
|
|||
|
||||
PeerData *peer() const;
|
||||
PeerId migratedPeerId() const;
|
||||
Data::ForumTopic *topic() const {
|
||||
return key().topic();
|
||||
}
|
||||
UserData *settingsSelf() const {
|
||||
return key().settingsSelf();
|
||||
}
|
||||
|
|
|
@ -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([=] {
|
||||
|
|
|
@ -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>(
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -157,6 +157,8 @@ private:
|
|||
|
||||
void setupSelectRestriction();
|
||||
|
||||
[[nodiscard]] MsgId topicRootId() const;
|
||||
|
||||
QMargins padding() const;
|
||||
bool isItemLayout(
|
||||
not_null<const HistoryItem*> item,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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 {};
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Add table
Reference in a new issue