mirror of https://github.com/procxx/kepka.git
Add SharedMediaSlice to observe shared media.
Start testing / using it in MediaView.
This commit is contained in:
parent
41ed2d1b84
commit
2363a6bd44
|
@ -35,6 +35,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "window/notifications_manager.h"
|
#include "window/notifications_manager.h"
|
||||||
#include "chat_helpers/message_field.h"
|
#include "chat_helpers/message_field.h"
|
||||||
#include "chat_helpers/stickers.h"
|
#include "chat_helpers/stickers.h"
|
||||||
|
#include "storage/storage_facade.h"
|
||||||
|
#include "storage/storage_shared_media.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -46,6 +48,7 @@ constexpr auto kStickersUpdateTimeout = 3600000; // update not more than once in
|
||||||
constexpr auto kUnreadMentionsPreloadIfLess = 5;
|
constexpr auto kUnreadMentionsPreloadIfLess = 5;
|
||||||
constexpr auto kUnreadMentionsFirstRequestLimit = 10;
|
constexpr auto kUnreadMentionsFirstRequestLimit = 10;
|
||||||
constexpr auto kUnreadMentionsNextRequestLimit = 100;
|
constexpr auto kUnreadMentionsNextRequestLimit = 100;
|
||||||
|
constexpr auto kSharedMediaLimit = 10;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
@ -1911,4 +1914,154 @@ void ApiWrap::sendSaveChatAdminsRequests(not_null<ChatData*> chat) {
|
||||||
requestSendDelayed();
|
requestSendDelayed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ApiWrap::requestSharedMedia(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
SharedMediaType type,
|
||||||
|
MsgId messageId,
|
||||||
|
SliceType slice) {
|
||||||
|
auto key = std::make_tuple(peer, type, messageId, slice);
|
||||||
|
if (_sharedMediaRequests.contains(key)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto filter = [&] {
|
||||||
|
using Type = SharedMediaType;
|
||||||
|
switch (type) {
|
||||||
|
case Type::Photo: return MTP_inputMessagesFilterPhotos();
|
||||||
|
case Type::Video: return MTP_inputMessagesFilterVideo();
|
||||||
|
case Type::MusicFile: return MTP_inputMessagesFilterMusic();
|
||||||
|
case Type::File: return MTP_inputMessagesFilterDocument();
|
||||||
|
case Type::VoiceFile: return MTP_inputMessagesFilterVoice();
|
||||||
|
case Type::RoundVoiceFile: return MTP_inputMessagesFilterRoundVoice();
|
||||||
|
case Type::GIF: return MTP_inputMessagesFilterGif();
|
||||||
|
case Type::Link: return MTP_inputMessagesFilterUrl();
|
||||||
|
case Type::ChatPhoto: return MTP_inputMessagesFilterChatPhotos();
|
||||||
|
}
|
||||||
|
return MTP_inputMessagesFilterEmpty();
|
||||||
|
}();
|
||||||
|
if (filter.type() == mtpc_inputMessagesFilterEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto minId = 0;
|
||||||
|
auto maxId = 0;
|
||||||
|
auto limit = messageId ? kSharedMediaLimit : 0;
|
||||||
|
auto offsetId = [&] {
|
||||||
|
switch (slice) {
|
||||||
|
case SliceType::Before:
|
||||||
|
case SliceType::Around: return messageId;
|
||||||
|
case SliceType::After: return messageId + 1;
|
||||||
|
}
|
||||||
|
Unexpected("Slice type in ApiWrap::requestSharedMedia");
|
||||||
|
}();
|
||||||
|
auto addOffset = [&] {
|
||||||
|
switch (slice) {
|
||||||
|
case SliceType::Before: return 0;
|
||||||
|
case SliceType::Around: return -limit / 2;
|
||||||
|
case SliceType::After: return -limit;
|
||||||
|
}
|
||||||
|
Unexpected("Slice type in ApiWrap::requestSharedMedia");
|
||||||
|
}();
|
||||||
|
|
||||||
|
LOG(("REQUESTING SHARED MEDIA: %1, %2, %3").arg(static_cast<int>(type)).arg(messageId).arg(static_cast<int>(slice)));
|
||||||
|
auto requestId = request(MTPmessages_Search(
|
||||||
|
MTP_flags(0),
|
||||||
|
peer->input,
|
||||||
|
MTPstring(),
|
||||||
|
MTP_inputUserEmpty(),
|
||||||
|
filter,
|
||||||
|
MTP_int(0),
|
||||||
|
MTP_int(0),
|
||||||
|
MTP_int(offsetId),
|
||||||
|
MTP_int(addOffset),
|
||||||
|
MTP_int(limit),
|
||||||
|
MTP_int(maxId),
|
||||||
|
MTP_int(minId)
|
||||||
|
)).done([this, peer, type, messageId, slice](const MTPmessages_Messages &result) {
|
||||||
|
_sharedMediaRequests.remove(std::make_tuple(peer, type, messageId, slice));
|
||||||
|
sharedMediaDone(peer, type, messageId, slice, result);
|
||||||
|
}).fail([this, key](const RPCError &error) {
|
||||||
|
_sharedMediaRequests.remove(key);
|
||||||
|
}).send();
|
||||||
|
_sharedMediaRequests.emplace(key, requestId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApiWrap::sharedMediaDone(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
SharedMediaType type,
|
||||||
|
MsgId messageId,
|
||||||
|
SliceType slice,
|
||||||
|
const MTPmessages_Messages &result) {
|
||||||
|
|
||||||
|
auto fullCount = 0;
|
||||||
|
auto &messages = *[&] {
|
||||||
|
switch (result.type()) {
|
||||||
|
case mtpc_messages_messages: {
|
||||||
|
auto &d = result.c_messages_messages();
|
||||||
|
App::feedUsers(d.vusers);
|
||||||
|
App::feedChats(d.vchats);
|
||||||
|
fullCount = d.vmessages.v.size();
|
||||||
|
return &d.vmessages.v;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case mtpc_messages_messagesSlice: {
|
||||||
|
auto &d = result.c_messages_messagesSlice();
|
||||||
|
App::feedUsers(d.vusers);
|
||||||
|
App::feedChats(d.vchats);
|
||||||
|
fullCount = d.vcount.v;
|
||||||
|
return &d.vmessages.v;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case mtpc_messages_channelMessages: {
|
||||||
|
auto &d = result.c_messages_channelMessages();
|
||||||
|
if (auto channel = peer->asChannel()) {
|
||||||
|
channel->ptsReceived(d.vpts.v);
|
||||||
|
} else {
|
||||||
|
LOG(("API Error: received messages.channelMessages when no channel was passed! (ApiWrap::sharedMediaDone)"));
|
||||||
|
}
|
||||||
|
App::feedUsers(d.vusers);
|
||||||
|
App::feedChats(d.vchats);
|
||||||
|
fullCount = d.vcount.v;
|
||||||
|
return &d.vmessages.v;
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
Unexpected("messages.Messages type in sharedMediaDone()");
|
||||||
|
}();
|
||||||
|
|
||||||
|
auto noSkipRange = MsgRange { messageId, messageId };
|
||||||
|
auto messageIds = std::vector<MsgId>();
|
||||||
|
auto addType = NewMessageExisting;
|
||||||
|
messageIds.reserve(messages.size());
|
||||||
|
for (auto &message : messages) {
|
||||||
|
if (auto item = App::histories().addNewMessage(message, addType)) {
|
||||||
|
if (item->sharedMediaTypes().test(type)) {
|
||||||
|
auto itemId = item->id;
|
||||||
|
messageIds.push_back(itemId);
|
||||||
|
accumulate_min(noSkipRange.from, itemId);
|
||||||
|
accumulate_max(noSkipRange.till, itemId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (messageId && messageIds.empty()) {
|
||||||
|
noSkipRange = [&]() -> MsgRange {
|
||||||
|
switch (slice) {
|
||||||
|
case SliceType::Before: // All old loaded.
|
||||||
|
return { 0, noSkipRange.till };
|
||||||
|
case SliceType::Around: // All loaded.
|
||||||
|
return { 0, ServerMaxMsgId };
|
||||||
|
case SliceType::After: // All new loaded.
|
||||||
|
return { noSkipRange.from, ServerMaxMsgId };
|
||||||
|
}
|
||||||
|
Unexpected("Slice type in ApiWrap::sharedMediaDone");
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
Auth().storage().add(Storage::SharedMediaAddSlice(
|
||||||
|
peer->id,
|
||||||
|
type,
|
||||||
|
std::move(messageIds),
|
||||||
|
noSkipRange,
|
||||||
|
fullCount
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
ApiWrap::~ApiWrap() = default;
|
ApiWrap::~ApiWrap() = default;
|
||||||
|
|
|
@ -28,6 +28,10 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
class AuthSession;
|
class AuthSession;
|
||||||
|
|
||||||
|
namespace Storage {
|
||||||
|
enum class SharedMediaType : char;
|
||||||
|
} // namespace Storage
|
||||||
|
|
||||||
namespace Api {
|
namespace Api {
|
||||||
|
|
||||||
inline const MTPVector<MTPChat> *getChatsFromMessagesChats(const MTPmessages_Chats &chats) {
|
inline const MTPVector<MTPChat> *getChatsFromMessagesChats(const MTPmessages_Chats &chats) {
|
||||||
|
@ -108,6 +112,22 @@ public:
|
||||||
bool adminsEnabled,
|
bool adminsEnabled,
|
||||||
base::flat_set<not_null<UserData*>> &&admins);
|
base::flat_set<not_null<UserData*>> &&admins);
|
||||||
|
|
||||||
|
enum class SliceType {
|
||||||
|
Around,
|
||||||
|
Before,
|
||||||
|
After,
|
||||||
|
};
|
||||||
|
void requestSharedMedia(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
Storage::SharedMediaType type,
|
||||||
|
MsgId messageId,
|
||||||
|
SliceType slice);
|
||||||
|
void requestSharedMediaCount(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
Storage::SharedMediaType type) {
|
||||||
|
requestSharedMedia(peer, type, 0, SliceType::Before);
|
||||||
|
}
|
||||||
|
|
||||||
~ApiWrap();
|
~ApiWrap();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -117,6 +137,7 @@ private:
|
||||||
Callbacks callbacks;
|
Callbacks callbacks;
|
||||||
};
|
};
|
||||||
using MessageDataRequests = QMap<MsgId, MessageDataRequest>;
|
using MessageDataRequests = QMap<MsgId, MessageDataRequest>;
|
||||||
|
using SharedMediaType = Storage::SharedMediaType;
|
||||||
|
|
||||||
void requestAppChangelogs();
|
void requestAppChangelogs();
|
||||||
void addLocalChangelogs(int oldAppVersion);
|
void addLocalChangelogs(int oldAppVersion);
|
||||||
|
@ -153,6 +174,13 @@ private:
|
||||||
void saveChatAdmins(not_null<ChatData*> chat);
|
void saveChatAdmins(not_null<ChatData*> chat);
|
||||||
void sendSaveChatAdminsRequests(not_null<ChatData*> chat);
|
void sendSaveChatAdminsRequests(not_null<ChatData*> chat);
|
||||||
|
|
||||||
|
void sharedMediaDone(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
SharedMediaType type,
|
||||||
|
MsgId messageId,
|
||||||
|
SliceType slice,
|
||||||
|
const MTPmessages_Messages &result);
|
||||||
|
|
||||||
not_null<AuthSession*> _session;
|
not_null<AuthSession*> _session;
|
||||||
mtpRequestId _changelogSubscription = 0;
|
mtpRequestId _changelogSubscription = 0;
|
||||||
|
|
||||||
|
@ -205,9 +233,21 @@ private:
|
||||||
|
|
||||||
base::flat_map<not_null<History*>, mtpRequestId> _unreadMentionsRequests;
|
base::flat_map<not_null<History*>, mtpRequestId> _unreadMentionsRequests;
|
||||||
|
|
||||||
base::flat_map<not_null<ChatData*>, mtpRequestId> _chatAdminsEnabledRequests;
|
base::flat_map<
|
||||||
base::flat_map<not_null<ChatData*>, base::flat_set<not_null<UserData*>>> _chatAdminsToSave;
|
not_null<ChatData*>,
|
||||||
base::flat_map<not_null<ChatData*>, base::flat_set<mtpRequestId>> _chatAdminsSaveRequests;
|
mtpRequestId> _chatAdminsEnabledRequests;
|
||||||
|
base::flat_map<
|
||||||
|
not_null<ChatData*>,
|
||||||
|
base::flat_set<not_null<UserData*>>> _chatAdminsToSave;
|
||||||
|
base::flat_map<
|
||||||
|
not_null<ChatData*>,
|
||||||
|
base::flat_set<mtpRequestId>> _chatAdminsSaveRequests;
|
||||||
|
|
||||||
|
base::flat_map<std::tuple<
|
||||||
|
not_null<PeerData*>,
|
||||||
|
SharedMediaType,
|
||||||
|
MsgId,
|
||||||
|
SliceType>, mtpRequestId> _sharedMediaRequests;
|
||||||
|
|
||||||
base::Observable<PeerData*> _fullPeerUpdated;
|
base::Observable<PeerData*> _fullPeerUpdated;
|
||||||
|
|
||||||
|
|
|
@ -227,7 +227,7 @@ public:
|
||||||
void checkAutoLockIn(TimeMs time);
|
void checkAutoLockIn(TimeMs time);
|
||||||
|
|
||||||
base::Observable<DocumentData*> documentUpdated;
|
base::Observable<DocumentData*> documentUpdated;
|
||||||
base::Observable<std::pair<HistoryItem*, MsgId>> messageIdChanging;
|
base::Observable<std::pair<not_null<HistoryItem*>, MsgId>> messageIdChanging;
|
||||||
|
|
||||||
~AuthSession();
|
~AuthSession();
|
||||||
|
|
||||||
|
|
|
@ -366,9 +366,9 @@ class Observable : public internal::BaseObservable<EventType, Handler, base::typ
|
||||||
public:
|
public:
|
||||||
Observable() = default;
|
Observable() = default;
|
||||||
Observable(const Observable &other) = delete;
|
Observable(const Observable &other) = delete;
|
||||||
Observable(Observable &&other) = delete;
|
Observable(Observable &&other) = default;
|
||||||
Observable &operator=(const Observable &other) = delete;
|
Observable &operator=(const Observable &other) = delete;
|
||||||
Observable &operator=(Observable &&other) = delete;
|
Observable &operator=(Observable &&other) = default;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,6 @@ enum {
|
||||||
SearchManyPerPage = 100,
|
SearchManyPerPage = 100,
|
||||||
LinksOverviewPerPage = 12,
|
LinksOverviewPerPage = 12,
|
||||||
MediaOverviewStartPerPage = 5,
|
MediaOverviewStartPerPage = 5,
|
||||||
MediaOverviewPreloadCount = 4,
|
|
||||||
|
|
||||||
AudioVoiceMsgMaxLength = 100 * 60, // 100 minutes
|
AudioVoiceMsgMaxLength = 100 * 60, // 100 minutes
|
||||||
AudioVoiceMsgUpdateView = 100, // 100ms
|
AudioVoiceMsgUpdateView = 100, // 100ms
|
||||||
|
|
|
@ -0,0 +1,409 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#include "history/history_shared_media.h"
|
||||||
|
|
||||||
|
#include "auth_session.h"
|
||||||
|
#include "apiwrap.h"
|
||||||
|
#include "storage/storage_facade.h"
|
||||||
|
#include "storage/storage_shared_media.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using Type = SharedMediaViewer::Type;
|
||||||
|
|
||||||
|
inline MediaOverviewType SharedMediaTypeToOverview(Type type) {
|
||||||
|
switch (type) {
|
||||||
|
case Type::Photo: return OverviewPhotos;
|
||||||
|
case Type::Video: return OverviewVideos;
|
||||||
|
case Type::MusicFile: return OverviewMusicFiles;
|
||||||
|
case Type::File: return OverviewFiles;
|
||||||
|
case Type::VoiceFile: return OverviewVoiceFiles;
|
||||||
|
case Type::Link: return OverviewLinks;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return OverviewCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
not_null<History*> GetActualHistory(not_null<History*> history) {
|
||||||
|
if (auto to = history->peer->migrateTo()) {
|
||||||
|
return App::history(to);
|
||||||
|
}
|
||||||
|
return history;
|
||||||
|
}
|
||||||
|
|
||||||
|
History *GetMigratedHistory(
|
||||||
|
not_null<History*> passedHistory,
|
||||||
|
not_null<History*> actualHistory) {
|
||||||
|
if (actualHistory != passedHistory) {
|
||||||
|
return passedHistory;
|
||||||
|
} else if (auto from = actualHistory->peer->migrateFrom()) {
|
||||||
|
return App::history(from);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
SharedMediaViewer::SharedMediaViewer(
|
||||||
|
Key key,
|
||||||
|
int limitBefore,
|
||||||
|
int limitAfter)
|
||||||
|
: _key(key)
|
||||||
|
, _limitBefore(limitBefore)
|
||||||
|
, _limitAfter(limitAfter)
|
||||||
|
, _data(_key) {
|
||||||
|
}
|
||||||
|
|
||||||
|
base::optional<Storage::SharedMediaType> SharedMediaOverviewType(
|
||||||
|
Storage::SharedMediaType type) {
|
||||||
|
if (SharedMediaTypeToOverview(type) != OverviewCount) {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
return base::none;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SharedMediaShowOverview(
|
||||||
|
Storage::SharedMediaType type,
|
||||||
|
not_null<History*> history) {
|
||||||
|
if (SharedMediaOverviewType(type)) {
|
||||||
|
Ui::showPeerOverview(history, SharedMediaTypeToOverview(type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SharedMediaViewer::start() {
|
||||||
|
auto applyUpdateCallback = [this](auto &update) {
|
||||||
|
this->applyUpdate(update);
|
||||||
|
};
|
||||||
|
subscribe(Auth().storage().sharedMediaSliceUpdated(), applyUpdateCallback);
|
||||||
|
subscribe(Auth().storage().sharedMediaOneRemoved(), applyUpdateCallback);
|
||||||
|
subscribe(Auth().storage().sharedMediaAllRemoved(), applyUpdateCallback);
|
||||||
|
|
||||||
|
loadInitial();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SharedMediaViewer::loadInitial() {
|
||||||
|
auto weak = base::make_weak_unique(this);
|
||||||
|
Auth().storage().query(Storage::SharedMediaQuery(
|
||||||
|
_key,
|
||||||
|
_limitBefore,
|
||||||
|
_limitAfter), [weak](Storage::SharedMediaResult &&result) {
|
||||||
|
if (weak) {
|
||||||
|
weak->applyStoredResult(std::move(result));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void SharedMediaViewer::applyStoredResult(Storage::SharedMediaResult &&result) {
|
||||||
|
mergeSliceData(
|
||||||
|
result.count,
|
||||||
|
result.messageIds,
|
||||||
|
result.skippedBefore,
|
||||||
|
result.skippedAfter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SharedMediaViewer::mergeSliceData(
|
||||||
|
base::optional<int> count,
|
||||||
|
const base::flat_set<MsgId> &messageIds,
|
||||||
|
base::optional<int> skippedBefore,
|
||||||
|
base::optional<int> skippedAfter) {
|
||||||
|
if (messageIds.empty()) {
|
||||||
|
if (count && *_data._fullCount != *count) {
|
||||||
|
_data._fullCount = count;
|
||||||
|
updated.notify(_data);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (count) {
|
||||||
|
_data._fullCount = count;
|
||||||
|
}
|
||||||
|
auto wasMinId = _data._ids.empty() ? -1 : _data._ids.front();
|
||||||
|
auto wasMaxId = _data._ids.empty() ? -1 : _data._ids.back();
|
||||||
|
_data._ids.merge(messageIds.begin(), messageIds.end());
|
||||||
|
|
||||||
|
auto adjustSkippedBefore = [&](MsgId oldId, int oldSkippedBefore) {
|
||||||
|
auto it = _data._ids.find(oldId);
|
||||||
|
Assert(it != _data._ids.end());
|
||||||
|
_data._skippedBefore = oldSkippedBefore - (it - _data._ids.begin());
|
||||||
|
accumulate_max(*_data._skippedBefore, 0);
|
||||||
|
};
|
||||||
|
if (skippedBefore) {
|
||||||
|
adjustSkippedBefore(messageIds.front(), *skippedBefore);
|
||||||
|
} else if (wasMinId >= 0 && _data._skippedBefore) {
|
||||||
|
adjustSkippedBefore(wasMinId, *_data._skippedBefore);
|
||||||
|
} else {
|
||||||
|
_data._skippedBefore = base::none;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto adjustSkippedAfter = [&](MsgId oldId, int oldSkippedAfter) {
|
||||||
|
auto it = _data._ids.find(oldId);
|
||||||
|
Assert(it != _data._ids.end());
|
||||||
|
_data._skippedAfter = oldSkippedAfter - (_data._ids.end() - it - 1);
|
||||||
|
accumulate_max(*_data._skippedAfter, 0);
|
||||||
|
};
|
||||||
|
if (skippedAfter) {
|
||||||
|
adjustSkippedAfter(messageIds.back(), *skippedAfter);
|
||||||
|
} else if (wasMaxId >= 0 && _data._skippedAfter) {
|
||||||
|
adjustSkippedAfter(wasMaxId, *_data._skippedAfter);
|
||||||
|
} else {
|
||||||
|
_data._skippedAfter = base::none;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_data._fullCount) {
|
||||||
|
if (_data._skippedBefore && !_data._skippedAfter) {
|
||||||
|
_data._skippedAfter = *_data._fullCount
|
||||||
|
- *_data._skippedBefore
|
||||||
|
- int(_data._ids.size());
|
||||||
|
} else if (_data._skippedAfter && !_data._skippedBefore) {
|
||||||
|
_data._skippedBefore = *_data._fullCount
|
||||||
|
- *_data._skippedAfter
|
||||||
|
- int(_data._ids.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sliceToLimits();
|
||||||
|
|
||||||
|
updated.notify(_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SharedMediaViewer::applyUpdate(const SliceUpdate &update) {
|
||||||
|
if (update.peerId != _key.peerId || update.type != _key.type) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto intersects = [](MsgRange range1, MsgRange range2) {
|
||||||
|
return (range1.from <= range2.till) && (range2.from <= range1.till);
|
||||||
|
};
|
||||||
|
if (!intersects(update.range, {
|
||||||
|
_data._ids.empty() ? _key.messageId : _data._ids.front(),
|
||||||
|
_data._ids.empty() ? _key.messageId : _data._ids.back() })) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto skippedBefore = (update.range.from == 0)
|
||||||
|
? 0
|
||||||
|
: base::optional<int> {};
|
||||||
|
auto skippedAfter = (update.range.till == ServerMaxMsgId)
|
||||||
|
? 0
|
||||||
|
: base::optional<int> {};
|
||||||
|
mergeSliceData(
|
||||||
|
update.count,
|
||||||
|
update.messages ? *update.messages : base::flat_set<MsgId> {},
|
||||||
|
skippedBefore,
|
||||||
|
skippedAfter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SharedMediaViewer::applyUpdate(const OneRemoved &update) {
|
||||||
|
if (update.peerId != _key.peerId || !update.types.test(_key.type)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto changed = false;
|
||||||
|
if (_data._fullCount && *_data._fullCount > 0) {
|
||||||
|
--*_data._fullCount;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (_data._ids.contains(update.messageId)) {
|
||||||
|
_data._ids.remove(update.messageId);
|
||||||
|
changed = true;
|
||||||
|
} else if (!_data._ids.empty()) {
|
||||||
|
if (_data._ids.front() > update.messageId
|
||||||
|
&& _data._skippedBefore
|
||||||
|
&& *_data._skippedBefore > 0) {
|
||||||
|
--*_data._skippedBefore;
|
||||||
|
changed = true;
|
||||||
|
} else if (_data._ids.back() < update.messageId
|
||||||
|
&& _data._skippedAfter
|
||||||
|
&& *_data._skippedAfter > 0) {
|
||||||
|
--*_data._skippedAfter;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (changed) {
|
||||||
|
updated.notify(_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SharedMediaViewer::applyUpdate(const AllRemoved &update) {
|
||||||
|
if (update.peerId != _key.peerId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_data = SharedMediaSlice(_key, 0);
|
||||||
|
updated.notify(_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SharedMediaViewer::sliceToLimits() {
|
||||||
|
auto aroundIt = base::lower_bound(_data._ids, _key.messageId);
|
||||||
|
auto removeFromBegin = (aroundIt - _data._ids.begin() - _limitBefore);
|
||||||
|
auto removeFromEnd = (_data._ids.end() - aroundIt - _limitAfter - 1);
|
||||||
|
if (removeFromBegin > 0) {
|
||||||
|
_data._ids.erase(_data._ids.begin(), _data._ids.begin() + removeFromBegin);
|
||||||
|
if (_data._skippedBefore) {
|
||||||
|
*_data._skippedBefore += removeFromBegin;
|
||||||
|
}
|
||||||
|
} else if (removeFromBegin < 0 && (!_data._skippedBefore || *_data._skippedBefore > 0)) {
|
||||||
|
requestMessages(RequestDirection::Before);
|
||||||
|
}
|
||||||
|
if (removeFromEnd > 0) {
|
||||||
|
_data._ids.erase(_data._ids.end() - removeFromEnd, _data._ids.end());
|
||||||
|
if (_data._skippedAfter) {
|
||||||
|
*_data._skippedAfter += removeFromEnd;
|
||||||
|
}
|
||||||
|
} else if (removeFromEnd < 0 && (!_data._skippedAfter || *_data._skippedAfter > 0)) {
|
||||||
|
requestMessages(RequestDirection::After);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SharedMediaViewer::requestMessages(RequestDirection direction) {
|
||||||
|
using SliceType = ApiWrap::SliceType;
|
||||||
|
auto requestAroundData = [&]() -> std::pair<MsgId, SliceType> {
|
||||||
|
if (_data._ids.empty()) {
|
||||||
|
return { _key.messageId, SliceType::Around };
|
||||||
|
} else if (direction == RequestDirection::Before) {
|
||||||
|
return { _data._ids.front(), SliceType::Before };
|
||||||
|
}
|
||||||
|
return { _data._ids.back(), SliceType::After };
|
||||||
|
}();
|
||||||
|
Auth().api().requestSharedMedia(
|
||||||
|
App::peer(_key.peerId),
|
||||||
|
_key.type,
|
||||||
|
requestAroundData.first,
|
||||||
|
requestAroundData.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//base::optional<int> SharedMediaViewerMerged::Data::fullCount() const {
|
||||||
|
// if (_historyCount && _migratedCount) {
|
||||||
|
// return (*_historyCount + *_migratedCount);
|
||||||
|
// }
|
||||||
|
// return base::none;
|
||||||
|
//}
|
||||||
|
//base::optional<int> SharedMediaViewerMerged::Data::skippedBefore() const {
|
||||||
|
// if (_ids.empty()) {
|
||||||
|
// return base::none;
|
||||||
|
// } else if (!IsServerMsgId(_ids.front())) {
|
||||||
|
// return _migratedSkippedBefore;
|
||||||
|
// } else if (_historySkippedBefore && _migratedCount) {
|
||||||
|
// return *_historySkippedBefore + *_migratedCount;
|
||||||
|
// }
|
||||||
|
// return base::none;
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//base::optional<int> SharedMediaViewerMerged::Data::skippedAfter() const {
|
||||||
|
// if (_ids.empty()) {
|
||||||
|
// return base::none;
|
||||||
|
// } else if (IsServerMsgId(_ids.back())) {
|
||||||
|
// return _historySkippedAfter;
|
||||||
|
// } else if (_migratedSkippedAfter && _historyCount) {
|
||||||
|
// return *_migratedSkippedAfter + *_historyCount;
|
||||||
|
// }
|
||||||
|
// return base::none;
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//SharedMediaViewerMerged::SharedMediaViewerMerged(
|
||||||
|
// Type type,
|
||||||
|
// not_null<History*> history,
|
||||||
|
// MsgId aroundId,
|
||||||
|
// int limitBefore,
|
||||||
|
// int limitAfter)
|
||||||
|
//: _type(type)
|
||||||
|
//, _history(GetActualHistory(history))
|
||||||
|
//, _migrated(GetMigratedHistory(history, _history))
|
||||||
|
//, _universalAroundId((_history == _migrated) ? -aroundId : aroundId)
|
||||||
|
//, _limitBefore(limitBefore)
|
||||||
|
//, _limitAfter(limitAfter)
|
||||||
|
//, _data(_history, _migrated) {
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//bool SharedMediaViewerMerged::hasOverview() const {
|
||||||
|
// return SharedMediaTypeToOverview(_type) != OverviewCount;
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//void SharedMediaViewerMerged::showOverview() const {
|
||||||
|
// if (hasOverview()) {
|
||||||
|
// Ui::showPeerOverview(_history, SharedMediaTypeToOverview(_type));
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//bool SharedMediaViewerMerged::moveTo(const SharedMediaViewerMerged &other) {
|
||||||
|
// if (_history != other._history || _type != other._type) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// _universalAroundId = other._universalAroundId;
|
||||||
|
// if (!containsAroundId()) {
|
||||||
|
// clearAfterMove();
|
||||||
|
// }
|
||||||
|
// load();
|
||||||
|
// return true;
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//bool SharedMediaViewerMerged::containsAroundId() const {
|
||||||
|
// if (_data._ids.empty()) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// auto min = _data._ids.front();
|
||||||
|
// auto max = _data._ids.back();
|
||||||
|
// if (IsServerMsgId(_universalAroundId)) {
|
||||||
|
// return (!IsServerMsgId(min) || min <= aroundId())
|
||||||
|
// && (IsServerMsgId(max) && max >= aroundId());
|
||||||
|
// }
|
||||||
|
// return (!IsServerMsgId(min) && -min <= aroundId())
|
||||||
|
// && (IsServerMsgId(max) || -max >= aroundId());
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//bool SharedMediaViewerMerged::amAroundMigrated() const {
|
||||||
|
// return !IsServerMsgId(_universalAroundId);
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//not_null<History*> SharedMediaViewerMerged::aroundHistory() const {
|
||||||
|
// return amAroundMigrated() ? _migrated : _history;
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//MsgId SharedMediaViewerMerged::aroundId() const {
|
||||||
|
// return amAroundMigrated() ? -_universalAroundId : _universalAroundId;
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//void SharedMediaViewerMerged::clearAfterMove() {
|
||||||
|
// _data = Data(_history, _migrated, _data._historyCount, _data._migratedCount);
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//void SharedMediaViewerMerged::load() {
|
||||||
|
// auto weak = base::make_weak_unique(this);
|
||||||
|
// auto peer = aroundHistory()->peer;
|
||||||
|
// Auth().storage().query(Storage::SharedMediaQuery(
|
||||||
|
// peer->id,
|
||||||
|
// _type,
|
||||||
|
// aroundId(),
|
||||||
|
// _limitBefore,
|
||||||
|
// _limitAfter), [weak, peer](Storage::SharedMediaResult &&result) {
|
||||||
|
// if (weak) {
|
||||||
|
// weak->applyStoredResult(peer, std::move(result));
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//void SharedMediaViewerMerged::applyStoredResult(
|
||||||
|
// not_null<PeerData*> peer,
|
||||||
|
// Storage::SharedMediaResult &&result) {
|
||||||
|
// if (aroundHistory()->peer != peer) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// auto aroundMigrated = amAroundMigrated();
|
||||||
|
// if (result.count) {
|
||||||
|
// (aroundMigrated ? _data._migratedCount : _data._historyCount) = result.count;
|
||||||
|
// }
|
||||||
|
//}
|
|
@ -0,0 +1,316 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "storage/storage_shared_media.h"
|
||||||
|
#include "mtproto/sender.h"
|
||||||
|
#include "base/weak_unique_ptr.h"
|
||||||
|
|
||||||
|
base::optional<Storage::SharedMediaType> SharedMediaOverviewType(
|
||||||
|
Storage::SharedMediaType type);
|
||||||
|
void SharedMediaShowOverview(
|
||||||
|
Storage::SharedMediaType type,
|
||||||
|
not_null<History*> history);
|
||||||
|
|
||||||
|
class SharedMediaViewer;
|
||||||
|
class SharedMediaSlice {
|
||||||
|
public:
|
||||||
|
using Key = Storage::SharedMediaKey;
|
||||||
|
|
||||||
|
SharedMediaSlice(
|
||||||
|
Key key,
|
||||||
|
base::optional<int> fullCount = base::none)
|
||||||
|
: _key(key)
|
||||||
|
, _fullCount(fullCount) {
|
||||||
|
}
|
||||||
|
|
||||||
|
base::optional<int> fullCount() const {
|
||||||
|
return _fullCount;
|
||||||
|
}
|
||||||
|
base::optional<int> skippedBefore() const {
|
||||||
|
return _skippedBefore;
|
||||||
|
}
|
||||||
|
base::optional<int> skippedAfter() const {
|
||||||
|
return _skippedAfter;
|
||||||
|
}
|
||||||
|
base::optional<int> indexOf(MsgId msgId) const {
|
||||||
|
auto it = _ids.find(msgId);
|
||||||
|
if (it != _ids.end()) {
|
||||||
|
return (it - _ids.begin());
|
||||||
|
}
|
||||||
|
return base::none;
|
||||||
|
}
|
||||||
|
int size() const {
|
||||||
|
return _ids.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
using iterator = base::flat_set<MsgId>::const_iterator;
|
||||||
|
|
||||||
|
iterator begin() const {
|
||||||
|
return _ids.begin();
|
||||||
|
}
|
||||||
|
iterator end() const {
|
||||||
|
return _ids.end();
|
||||||
|
}
|
||||||
|
iterator cbegin() const {
|
||||||
|
return begin();
|
||||||
|
}
|
||||||
|
iterator cend() const {
|
||||||
|
return end();
|
||||||
|
}
|
||||||
|
|
||||||
|
base::optional<int> distance(const Key &a, const Key &b) const {
|
||||||
|
if (a.type != _key.type
|
||||||
|
|| b.type != _key.type
|
||||||
|
|| a.peerId != _key.peerId
|
||||||
|
|| b.peerId != _key.peerId) {
|
||||||
|
return base::none;
|
||||||
|
}
|
||||||
|
auto i = _ids.find(a.messageId);
|
||||||
|
auto j = _ids.find(b.messageId);
|
||||||
|
if (i == _ids.end() || j == _ids.end()) {
|
||||||
|
return base::none;
|
||||||
|
}
|
||||||
|
return j - i;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Key _key;
|
||||||
|
base::flat_set<MsgId> _ids;
|
||||||
|
MsgRange _range;
|
||||||
|
base::optional<int> _fullCount;
|
||||||
|
base::optional<int> _skippedBefore;
|
||||||
|
base::optional<int> _skippedAfter;
|
||||||
|
|
||||||
|
friend class SharedMediaViewer;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class SharedMediaViewer :
|
||||||
|
private base::Subscriber,
|
||||||
|
public base::enable_weak_from_this {
|
||||||
|
public:
|
||||||
|
using Type = Storage::SharedMediaType;
|
||||||
|
using Key = Storage::SharedMediaKey;
|
||||||
|
|
||||||
|
SharedMediaViewer(
|
||||||
|
Key key,
|
||||||
|
int limitBefore,
|
||||||
|
int limitAfter);
|
||||||
|
|
||||||
|
void start();
|
||||||
|
|
||||||
|
base::Observable<SharedMediaSlice> updated;
|
||||||
|
|
||||||
|
private:
|
||||||
|
using InitialResult = Storage::SharedMediaResult;
|
||||||
|
using SliceUpdate = Storage::SharedMediaSliceUpdate;
|
||||||
|
using OneRemoved = Storage::SharedMediaRemoveOne;
|
||||||
|
using AllRemoved = Storage::SharedMediaRemoveAll;
|
||||||
|
|
||||||
|
void loadInitial();
|
||||||
|
enum class RequestDirection {
|
||||||
|
Before,
|
||||||
|
After,
|
||||||
|
};
|
||||||
|
void requestMessages(RequestDirection direction);
|
||||||
|
void applyStoredResult(InitialResult &&result);
|
||||||
|
void applyUpdate(const SliceUpdate &update);
|
||||||
|
void applyUpdate(const OneRemoved &update);
|
||||||
|
void applyUpdate(const AllRemoved &update);
|
||||||
|
void sliceToLimits();
|
||||||
|
|
||||||
|
void mergeSliceData(
|
||||||
|
base::optional<int> count,
|
||||||
|
const base::flat_set<MsgId> &messageIds,
|
||||||
|
base::optional<int> skippedBefore = base::none,
|
||||||
|
base::optional<int> skippedAfter = base::none);
|
||||||
|
|
||||||
|
|
||||||
|
Key _key;
|
||||||
|
int _limitBefore = 0;
|
||||||
|
int _limitAfter = 0;
|
||||||
|
mtpRequestId _beforeRequestId = 0;
|
||||||
|
mtpRequestId _afterRequestId = 0;
|
||||||
|
SharedMediaSlice _data;
|
||||||
|
|
||||||
|
};
|
||||||
|
//
|
||||||
|
//class SharedMediaSliceMerged :
|
||||||
|
// private MTP::Sender,
|
||||||
|
// private base::Subscriber,
|
||||||
|
// public base::enable_weak_from_this {
|
||||||
|
//public:
|
||||||
|
// class Data;
|
||||||
|
//
|
||||||
|
//private:
|
||||||
|
// friend class Data;
|
||||||
|
// using UniversalMsgId = MsgId;
|
||||||
|
//
|
||||||
|
//public:
|
||||||
|
// using Type = Storage::SharedMediaType;
|
||||||
|
//
|
||||||
|
// SharedMediaSliceMerged(
|
||||||
|
// Type type,
|
||||||
|
// not_null<History*> history,
|
||||||
|
// MsgId aroundId,
|
||||||
|
// int limitBefore,
|
||||||
|
// int limitAfter);
|
||||||
|
//
|
||||||
|
// bool hasOverview() const;
|
||||||
|
// void showOverview() const;
|
||||||
|
// bool moveTo(const SharedMediaSliceMerged &other);
|
||||||
|
//
|
||||||
|
// void load();
|
||||||
|
//
|
||||||
|
// class Data {
|
||||||
|
// public:
|
||||||
|
// base::optional<int> fullCount() const;
|
||||||
|
// base::optional<int> skippedBefore() const;
|
||||||
|
// base::optional<int> skippedAfter() const;
|
||||||
|
// int size() const {
|
||||||
|
// return _ids.size();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// class iterator {
|
||||||
|
// public:
|
||||||
|
// FullMsgId operator*() const {
|
||||||
|
// auto id = _data->_ids[_index];
|
||||||
|
// Assert(IsServerMsgId(id)
|
||||||
|
// || (_data->_migrated != nullptr && IsServerMsgId(-id)));
|
||||||
|
// return IsServerMsgId(id)
|
||||||
|
// ? FullMsgId(_data->_history->channelId(), id)
|
||||||
|
// : FullMsgId(_data->_migrated->channelId(), -id);
|
||||||
|
// }
|
||||||
|
// iterator &operator--() {
|
||||||
|
// --_index;
|
||||||
|
// return *this;
|
||||||
|
// }
|
||||||
|
// iterator operator--(int) {
|
||||||
|
// auto result = *this;
|
||||||
|
// --*this;
|
||||||
|
// return result;
|
||||||
|
// }
|
||||||
|
// iterator &operator++() {
|
||||||
|
// ++_index;
|
||||||
|
// return *this;
|
||||||
|
// }
|
||||||
|
// iterator operator++(int) {
|
||||||
|
// auto result = *this;
|
||||||
|
// ++*this;
|
||||||
|
// return result;
|
||||||
|
// }
|
||||||
|
// iterator &operator+=(int offset) {
|
||||||
|
// _index += offset;
|
||||||
|
// return *this;
|
||||||
|
// }
|
||||||
|
// iterator operator+(int offset) const {
|
||||||
|
// auto result = *this;
|
||||||
|
// return result += offset;
|
||||||
|
// }
|
||||||
|
// bool operator==(iterator other) const {
|
||||||
|
// return (_data == other._data) && (_index == other._index);
|
||||||
|
// }
|
||||||
|
// bool operator!=(iterator other) const {
|
||||||
|
// return !(*this == other);
|
||||||
|
// }
|
||||||
|
// bool operator<(iterator other) const {
|
||||||
|
// return (_data < other._data)
|
||||||
|
// || (_data == other._data && _index < other._index);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private:
|
||||||
|
// friend class Data;
|
||||||
|
//
|
||||||
|
// iterator(not_null<const Data*> data, int index)
|
||||||
|
// : _data(data)
|
||||||
|
// , _index(index) {
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// not_null<const Data*> _data;
|
||||||
|
// int _index = 0;
|
||||||
|
//
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// iterator begin() const {
|
||||||
|
// return iterator(this, 0);
|
||||||
|
// }
|
||||||
|
// iterator end() const {
|
||||||
|
// iterator(this, _ids.size());
|
||||||
|
// }
|
||||||
|
// iterator cbegin() const {
|
||||||
|
// return begin();
|
||||||
|
// }
|
||||||
|
// iterator cend() const {
|
||||||
|
// return end();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private:
|
||||||
|
// friend class iterator;
|
||||||
|
// friend class SharedMediaSliceMerged;
|
||||||
|
//
|
||||||
|
// Data(
|
||||||
|
// not_null<History*> history,
|
||||||
|
// History *migrated,
|
||||||
|
// base::optional<int> historyCount = base::none,
|
||||||
|
// base::optional<int> migratedCount = base::none)
|
||||||
|
// : _history(history)
|
||||||
|
// , _migrated(migrated)
|
||||||
|
// , _historyCount(historyCount)
|
||||||
|
// , _migratedCount(migratedCount) {
|
||||||
|
// if (!_migrated) {
|
||||||
|
// _migratedCount = 0;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// not_null<History*> _history;
|
||||||
|
// History *_migrated = nullptr;
|
||||||
|
// std::vector<UniversalMsgId> _ids;
|
||||||
|
// base::optional<int> _historyCount;
|
||||||
|
// base::optional<int> _historySkippedBefore;
|
||||||
|
// base::optional<int> _historySkippedAfter;
|
||||||
|
// base::optional<int> _migratedCount;
|
||||||
|
// base::optional<int> _migratedSkippedBefore;
|
||||||
|
// base::optional<int> _migratedSkippedAfter;
|
||||||
|
//
|
||||||
|
// };
|
||||||
|
// base::Observable<Data> updated;
|
||||||
|
//
|
||||||
|
//private:
|
||||||
|
// bool amAroundMigrated() const;
|
||||||
|
// not_null<History*> aroundHistory() const;
|
||||||
|
// MsgId aroundId() const;
|
||||||
|
//
|
||||||
|
// void applyStoredResult(
|
||||||
|
// not_null<PeerData*> peer,
|
||||||
|
// Storage::SharedMediaResult &&result);
|
||||||
|
// bool containsAroundId() const;
|
||||||
|
// void clearAfterMove();
|
||||||
|
//
|
||||||
|
// Type _type = Type::kCount;
|
||||||
|
// not_null<History*> _history;
|
||||||
|
// History *_migrated = nullptr;
|
||||||
|
// UniversalMsgId _universalAroundId = 0;
|
||||||
|
// int _limitBefore = 0;
|
||||||
|
// int _limitAfter = 0;
|
||||||
|
// Data _data;
|
||||||
|
//
|
||||||
|
//};
|
|
@ -44,6 +44,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
constexpr auto kPreloadCount = 4;
|
||||||
|
|
||||||
TextParseOptions _captionTextOptions = {
|
TextParseOptions _captionTextOptions = {
|
||||||
TextParseLinks | TextParseMentions | TextParseHashtags | TextParseMultiline | TextParseRichText, // flags
|
TextParseLinks | TextParseMentions | TextParseHashtags | TextParseMultiline | TextParseRichText, // flags
|
||||||
0, // maxw
|
0, // maxw
|
||||||
|
@ -57,21 +59,24 @@ TextParseOptions _captionBotOptions = {
|
||||||
Qt::LayoutDirectionAuto, // dir
|
Qt::LayoutDirectionAuto, // dir
|
||||||
};
|
};
|
||||||
|
|
||||||
bool typeHasMediaOverview(MediaOverviewType type) {
|
// Preload X message ids before and after current.
|
||||||
switch (type) {
|
constexpr auto kIdsLimit = 32;
|
||||||
case OverviewPhotos:
|
|
||||||
case OverviewVideos:
|
// Preload next messages if we went further from current than that.
|
||||||
case OverviewMusicFiles:
|
constexpr auto kIdsPreloadAfter = 28;
|
||||||
case OverviewFiles:
|
|
||||||
case OverviewVoiceFiles:
|
|
||||||
case OverviewLinks: return true;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
struct MediaView::SharedMedia {
|
||||||
|
SharedMedia(SharedMediaViewer::Key key)
|
||||||
|
: key(key)
|
||||||
|
, slice(key, kIdsLimit, kIdsLimit) {
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedMediaViewer::Key key;
|
||||||
|
SharedMediaViewer slice;
|
||||||
|
};
|
||||||
|
|
||||||
MediaView::MediaView() : TWidget(nullptr)
|
MediaView::MediaView() : TWidget(nullptr)
|
||||||
, _transparentBrush(style::transparentPlaceholderBrush())
|
, _transparentBrush(style::transparentPlaceholderBrush())
|
||||||
, _animStarted(getms())
|
, _animStarted(getms())
|
||||||
|
@ -111,9 +116,11 @@ MediaView::MediaView() : TWidget(nullptr)
|
||||||
documentUpdated(document);
|
documentUpdated(document);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
subscribe(Auth().messageIdChanging, [this](std::pair<HistoryItem*, MsgId> update) {
|
subscribe(Auth().messageIdChanging, [this](std::pair<not_null<HistoryItem*>, MsgId> update) {
|
||||||
changingMsgId(update.first, update.second);
|
changingMsgId(update.first, update.second);
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
_sharedMedia = nullptr;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
subscribe(Messenger::Instance().authSessionChanged(), [handleAuthSessionChange] {
|
subscribe(Messenger::Instance().authSessionChanged(), [handleAuthSessionChange] {
|
||||||
|
@ -121,11 +128,6 @@ MediaView::MediaView() : TWidget(nullptr)
|
||||||
});
|
});
|
||||||
handleAuthSessionChange();
|
handleAuthSessionChange();
|
||||||
|
|
||||||
auto observeEvents = Notify::PeerUpdate::Flag::SharedMediaChanged;
|
|
||||||
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) {
|
|
||||||
mediaOverviewUpdated(update);
|
|
||||||
}));
|
|
||||||
|
|
||||||
setWindowFlags(Qt::FramelessWindowHint | Qt::BypassWindowManagerHint | Qt::Tool | Qt::NoDropShadowWindowHint);
|
setWindowFlags(Qt::FramelessWindowHint | Qt::BypassWindowManagerHint | Qt::Tool | Qt::NoDropShadowWindowHint);
|
||||||
moveToScreen();
|
moveToScreen();
|
||||||
setAttribute(Qt::WA_NoSystemBackground, true);
|
setAttribute(Qt::WA_NoSystemBackground, true);
|
||||||
|
@ -190,54 +192,41 @@ void MediaView::moveToScreen() {
|
||||||
_saveMsg.moveTo((width() - _saveMsg.width()) / 2, (height() - _saveMsg.height()) / 2);
|
_saveMsg.moveTo((width() - _saveMsg.width()) / 2, (height() - _saveMsg.height()) / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaView::mediaOverviewUpdated(const Notify::PeerUpdate &update) {
|
void MediaView::handleSharedMediaUpdate(const SharedMediaSlice &update) {
|
||||||
if (isHidden() || (!_photo && !_doc)) return;
|
if (isHidden() || (!_photo && !_doc) || !_sharedMedia) {
|
||||||
if (_photo && _overview == OverviewChatPhotos && _history && !_history->peer->isUser()) {
|
_index = _fullIndex = _fullCount = base::none;
|
||||||
auto lastChatPhoto = computeLastOverviewChatPhoto();
|
|
||||||
if (_index < 0 && _photo == lastChatPhoto.photo && _photo == _additionalChatPhoto) {
|
|
||||||
auto firstOpened = _firstOpenedPeerPhoto;
|
|
||||||
showPhoto(_photo, lastChatPhoto.item);
|
|
||||||
_firstOpenedPeerPhoto = firstOpened;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
computeAdditionalChatPhoto(_history->peer, lastChatPhoto.photo);
|
//if (_photo && _overview == OverviewChatPhotos && _history && !_history->peer->isUser()) { // TODO chat
|
||||||
}
|
// auto lastChatPhoto = computeLastOverviewChatPhoto();
|
||||||
|
// if (_index < 0 && _photo == lastChatPhoto.photo && _photo == _additionalChatPhoto) {
|
||||||
|
// auto firstOpened = _firstOpenedPeerPhoto;
|
||||||
|
// showPhoto(_photo, lastChatPhoto.item);
|
||||||
|
// _firstOpenedPeerPhoto = firstOpened;
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// computeAdditionalChatPhoto(_history->peer, lastChatPhoto.photo);
|
||||||
|
//}
|
||||||
|
|
||||||
if (_history && (_history->peer == update.peer || (_migrated && _migrated->peer == update.peer)) && (update.mediaTypesMask & (1 << _overview)) && _msgid) {
|
_sharedMediaData = update;
|
||||||
_index = -1;
|
|
||||||
auto i = 0;
|
findCurrent();
|
||||||
if (_msgmigrated) {
|
|
||||||
for_const (auto msgId, _migrated->overview(_overview)) {
|
|
||||||
if (msgId == _msgid) {
|
|
||||||
_index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for_const (auto msgId, _history->overview(_overview)) {
|
|
||||||
if (msgId == _msgid) {
|
|
||||||
_index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
updateControls();
|
updateControls();
|
||||||
preloadData(0);
|
preloadData(0);
|
||||||
} else if (_user == update.peer && update.mediaTypesMask & (1 << OverviewCount)) {
|
|
||||||
if (!_photo) return;
|
|
||||||
|
|
||||||
_index = -1;
|
//if (_user == update.peer && update.mediaTypesMask & (1 << OverviewCount)) {
|
||||||
for (int i = 0, l = _user->photos.size(); i < l; ++i) {
|
// if (!_photo) return;
|
||||||
if (_user->photos[i] == _photo) {
|
|
||||||
_index = i;
|
// _index = -1;
|
||||||
break;
|
// for (int i = 0, l = _user->photos.size(); i < l; ++i) {
|
||||||
}
|
// if (_user->photos[i] == _photo) {
|
||||||
}
|
// _index = i;
|
||||||
updateControls();
|
// break;
|
||||||
preloadData(0);
|
// }
|
||||||
}
|
// }
|
||||||
|
// updateControls();
|
||||||
|
// preloadData(0);
|
||||||
|
//} // TODO user
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MediaView::fileShown() const {
|
bool MediaView::fileShown() const {
|
||||||
|
@ -285,17 +274,10 @@ void MediaView::documentUpdated(DocumentData *doc) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaView::changingMsgId(HistoryItem *row, MsgId newId) {
|
void MediaView::changingMsgId(not_null<HistoryItem*> row, MsgId newId) {
|
||||||
if (row->id == _msgid) {
|
if (row->id == _msgid) {
|
||||||
_msgid = newId;
|
_msgid = newId;
|
||||||
}
|
validateSharedMedia();
|
||||||
|
|
||||||
// Send a fake update.
|
|
||||||
if (!isHidden()) {
|
|
||||||
Notify::PeerUpdate update(row->history()->peer);
|
|
||||||
update.flags |= Notify::PeerUpdate::Flag::SharedMediaChanged;
|
|
||||||
update.mediaTypesMask |= (1 << _overview);
|
|
||||||
mediaOverviewUpdated(update);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,6 +314,17 @@ void MediaView::updateDocSize() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MediaView::refreshNavVisibility() {
|
||||||
|
if (_sharedMediaData) {
|
||||||
|
_leftNavVisible = _index && (*_index > 0);
|
||||||
|
_rightNavVisible = _index && (*_index + 1 < _sharedMediaData->size());
|
||||||
|
} else {
|
||||||
|
_leftNavVisible = false;
|
||||||
|
_rightNavVisible = false;
|
||||||
|
}
|
||||||
|
// TODO user
|
||||||
|
}
|
||||||
|
|
||||||
void MediaView::updateControls() {
|
void MediaView::updateControls() {
|
||||||
if (_doc && fileBubbleShown()) {
|
if (_doc && fileBubbleShown()) {
|
||||||
if (_doc->loading()) {
|
if (_doc->loading()) {
|
||||||
|
@ -393,28 +386,7 @@ void MediaView::updateControls() {
|
||||||
_dateNav = myrtlrect(st::mediaviewTextLeft, height() - st::mediaviewTextTop, st::mediaviewFont->width(_dateText), st::mediaviewFont->height);
|
_dateNav = myrtlrect(st::mediaviewTextLeft, height() - st::mediaviewTextTop, st::mediaviewFont->width(_dateText), st::mediaviewFont->height);
|
||||||
}
|
}
|
||||||
updateHeader();
|
updateHeader();
|
||||||
if (_photo || (_history && _overview != OverviewCount)) {
|
refreshNavVisibility();
|
||||||
_leftNavVisible = (_index > 0) || (_index == 0 && (
|
|
||||||
(!_msgmigrated && _history && _history->overview(_overview).size() < _history->overviewCount(_overview)) ||
|
|
||||||
(_msgmigrated && _migrated && _migrated->overview(_overview).size() < _migrated->overviewCount(_overview)) ||
|
|
||||||
(!_msgmigrated && _history && _migrated && (!_migrated->overview(_overview).isEmpty() || _migrated->overviewCount(_overview) > 0)))) ||
|
|
||||||
(_index < 0 && _photo == _additionalChatPhoto &&
|
|
||||||
((_history && _history->overviewCount(_overview) > 0) ||
|
|
||||||
(_migrated && _history->overviewLoaded(_overview) && _migrated->overviewCount(_overview) > 0))
|
|
||||||
);
|
|
||||||
_rightNavVisible = (_index >= 0) && (
|
|
||||||
(!_msgmigrated && _history && _index + 1 < _history->overview(_overview).size()) ||
|
|
||||||
(_msgmigrated && _migrated && _index + 1 < _migrated->overview(_overview).size()) ||
|
|
||||||
(_msgmigrated && _migrated && _history && (!_history->overview(_overview).isEmpty() || _history->overviewCount(_overview) > 0)) ||
|
|
||||||
(!_msgmigrated && _history && _index + 1 == _history->overview(_overview).size() && _additionalChatPhoto) ||
|
|
||||||
(_msgmigrated && _migrated && _index + 1 == _migrated->overview(_overview).size() && _history->overviewCount(_overview) == 0 && _additionalChatPhoto) ||
|
|
||||||
(!_history && _user && (_index + 1 < _user->photos.size() || _index + 1 < _user->photosCount)));
|
|
||||||
if (_msgmigrated && !_history->overviewLoaded(_overview)) {
|
|
||||||
_leftNavVisible = _rightNavVisible = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_leftNavVisible = _rightNavVisible = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_caption.isEmpty()) {
|
if (!_caption.isEmpty()) {
|
||||||
int32 skipw = qMax(_dateNav.left() + _dateNav.width(), _headerNav.left() + _headerNav.width());
|
int32 skipw = qMax(_dateNav.left() + _dateNav.width(), _headerNav.left() + _headerNav.width());
|
||||||
|
@ -453,7 +425,10 @@ void MediaView::updateActions() {
|
||||||
_actions.push_back({ lang(lng_mediaview_delete), SLOT(onDelete()) });
|
_actions.push_back({ lang(lng_mediaview_delete), SLOT(onDelete()) });
|
||||||
}
|
}
|
||||||
_actions.push_back({ lang(lng_mediaview_save_as), SLOT(onSaveAs()) });
|
_actions.push_back({ lang(lng_mediaview_save_as), SLOT(onSaveAs()) });
|
||||||
if (_history && typeHasMediaOverview(_overview)) {
|
|
||||||
|
if (auto overviewType =
|
||||||
|
sharedMediaType()
|
||||||
|
| SharedMediaOverviewType) {
|
||||||
_actions.push_back({ lang(_doc ? lng_mediaview_files_all : lng_mediaview_photos_all), SLOT(onOverview()) });
|
_actions.push_back({ lang(_doc ? lng_mediaview_files_all : lng_mediaview_photos_all), SLOT(onOverview()) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -687,6 +662,7 @@ void MediaView::updateMixerVideoVolume() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaView::close() {
|
void MediaView::close() {
|
||||||
|
_sharedMedia = nullptr;
|
||||||
if (_menu) _menu->hideMenu(true);
|
if (_menu) _menu->hideMenu(true);
|
||||||
Messenger::Instance().hideMediaView();
|
Messenger::Instance().hideMediaView();
|
||||||
}
|
}
|
||||||
|
@ -1002,12 +978,13 @@ void MediaView::onDelete() {
|
||||||
|
|
||||||
void MediaView::onOverview() {
|
void MediaView::onOverview() {
|
||||||
if (_menu) _menu->hideMenu(true);
|
if (_menu) _menu->hideMenu(true);
|
||||||
if (!_history || !typeHasMediaOverview(_overview)) {
|
|
||||||
update();
|
update();
|
||||||
return;
|
if (auto overviewType =
|
||||||
}
|
sharedMediaType()
|
||||||
|
| SharedMediaOverviewType) {
|
||||||
close();
|
close();
|
||||||
if (_history->peer) App::main()->showMediaOverview(_history->peer, _overview);
|
SharedMediaShowOverview(*overviewType, _history);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaView::onCopy() {
|
void MediaView::onCopy() {
|
||||||
|
@ -1025,7 +1002,81 @@ void MediaView::onCopy() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaView::showPhoto(PhotoData *photo, HistoryItem *context) {
|
base::optional<MediaView::SharedMediaType> MediaView::sharedMediaType() const {
|
||||||
|
using Type = SharedMediaType;
|
||||||
|
auto channelId = _msgmigrated ? NoChannel : _channel;
|
||||||
|
if (auto item = App::histItemById(channelId, _msgid)) {
|
||||||
|
if (_photo) {
|
||||||
|
if (item->toHistoryMessage()) {
|
||||||
|
return Type::Photo;
|
||||||
|
}
|
||||||
|
return Type::ChatPhoto;
|
||||||
|
} else if (_doc) {
|
||||||
|
if (_doc->isGifv()) {
|
||||||
|
return Type::GIF;
|
||||||
|
} else if (_doc->isVideo()) {
|
||||||
|
return Type::Video;
|
||||||
|
}
|
||||||
|
return Type::File;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return base::none;
|
||||||
|
}
|
||||||
|
|
||||||
|
base::optional<MediaView::SharedMediaKey> MediaView::sharedMediaKey() const {
|
||||||
|
auto keyForType = [this](SharedMediaType type) -> SharedMediaKey {
|
||||||
|
return { (_msgmigrated ? _migrated : _history)->peer->id, type, _msgid };
|
||||||
|
};
|
||||||
|
return
|
||||||
|
sharedMediaType()
|
||||||
|
| keyForType;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MediaView::validSharedMedia() const {
|
||||||
|
if (auto key = sharedMediaKey()) {
|
||||||
|
if (!_sharedMedia) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto countDistanceInData = [](const auto &a, const auto &b) {
|
||||||
|
return [&](const SharedMediaSlice &data) {
|
||||||
|
return data.distance(a, b);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
auto distance = (key == _sharedMedia->key) ? 0 :
|
||||||
|
_sharedMediaData
|
||||||
|
| countDistanceInData(*key, _sharedMedia->key)
|
||||||
|
| base::abs;
|
||||||
|
if (distance) {
|
||||||
|
return (*distance < kIdsPreloadAfter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (_sharedMedia == nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MediaView::validateSharedMedia() {
|
||||||
|
if (auto key = sharedMediaKey()) {
|
||||||
|
_sharedMedia = std::make_unique<SharedMedia>(*key);
|
||||||
|
subscribe(_sharedMedia->slice.updated, [this](const SharedMediaSlice &data) {
|
||||||
|
handleSharedMediaUpdate(data);
|
||||||
|
});
|
||||||
|
_sharedMedia->slice.start();
|
||||||
|
} else {
|
||||||
|
_sharedMedia = nullptr;
|
||||||
|
_sharedMediaData = base::none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MediaView::refreshSharedMedia() {
|
||||||
|
if (!validSharedMedia()) {
|
||||||
|
validateSharedMedia();
|
||||||
|
}
|
||||||
|
findCurrent();
|
||||||
|
updateControls();
|
||||||
|
preloadData(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MediaView::showPhoto(not_null<PhotoData*> photo, HistoryItem *context) {
|
||||||
_history = context ? context->history().get() : nullptr;
|
_history = context ? context->history().get() : nullptr;
|
||||||
_migrated = nullptr;
|
_migrated = nullptr;
|
||||||
if (_history) {
|
if (_history) {
|
||||||
|
@ -1052,23 +1103,20 @@ void MediaView::showPhoto(PhotoData *photo, HistoryItem *context) {
|
||||||
}
|
}
|
||||||
if (!_animOpacities.isEmpty()) _animOpacities.clear();
|
if (!_animOpacities.isEmpty()) _animOpacities.clear();
|
||||||
|
|
||||||
_index = -1;
|
|
||||||
_msgid = context ? context->id : 0;
|
_msgid = context ? context->id : 0;
|
||||||
_msgmigrated = context ? (context->history() == _migrated) : false;
|
_msgmigrated = context ? (context->history() == _migrated) : false;
|
||||||
_channel = _history ? _history->channelId() : NoChannel;
|
_channel = _history ? _history->channelId() : NoChannel;
|
||||||
_canForward = context ? context->canForward() : false;
|
_canForward = context ? context->canForward() : false;
|
||||||
_canDelete = context ? context->canDelete() : false;
|
_canDelete = context ? context->canDelete() : false;
|
||||||
_photo = photo;
|
_photo = photo;
|
||||||
|
|
||||||
|
validateSharedMedia();
|
||||||
if (_history) {
|
if (_history) {
|
||||||
if (context && !context->toHistoryMessage()) {
|
if (context && !context->toHistoryMessage()) {
|
||||||
_overview = OverviewChatPhotos;
|
|
||||||
if (!_history->peer->isUser()) {
|
if (!_history->peer->isUser()) {
|
||||||
computeAdditionalChatPhoto(_history->peer, computeLastOverviewChatPhoto().photo);
|
computeAdditionalChatPhoto(_history->peer, computeLastOverviewChatPhoto().photo);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
_overview = OverviewPhotos;
|
|
||||||
}
|
}
|
||||||
findCurrent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
displayPhoto(photo, context);
|
displayPhoto(photo, context);
|
||||||
|
@ -1076,7 +1124,7 @@ void MediaView::showPhoto(PhotoData *photo, HistoryItem *context) {
|
||||||
activateControls();
|
activateControls();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaView::showPhoto(PhotoData *photo, PeerData *context) {
|
void MediaView::showPhoto(not_null<PhotoData*> photo, PeerData *context) {
|
||||||
_history = _migrated = nullptr;
|
_history = _migrated = nullptr;
|
||||||
_additionalChatPhoto = nullptr;
|
_additionalChatPhoto = nullptr;
|
||||||
_firstOpenedPeerPhoto = true;
|
_firstOpenedPeerPhoto = true;
|
||||||
|
@ -1096,23 +1144,23 @@ void MediaView::showPhoto(PhotoData *photo, PeerData *context) {
|
||||||
_msgmigrated = false;
|
_msgmigrated = false;
|
||||||
_channel = NoChannel;
|
_channel = NoChannel;
|
||||||
_canForward = _canDelete = false;
|
_canForward = _canDelete = false;
|
||||||
_index = -1;
|
|
||||||
_photo = photo;
|
_photo = photo;
|
||||||
_overview = OverviewCount;
|
|
||||||
if (_user) {
|
|
||||||
if (_user->photos.isEmpty() && _user->photosCount < 0 && _user->photoId && _user->photoId != UnknownPeerPhotoId) {
|
|
||||||
_index = 0;
|
|
||||||
}
|
|
||||||
for (int i = 0, l = _user->photos.size(); i < l; ++i) {
|
|
||||||
if (_user->photos.at(i) == photo) {
|
|
||||||
_index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_user->photosCount < 0) {
|
validateSharedMedia();
|
||||||
loadBack();
|
if (_user) {
|
||||||
}
|
//if (_user->photos.isEmpty() && _user->photosCount < 0 && _user->photoId && _user->photoId != UnknownPeerPhotoId) {
|
||||||
|
// _fullIndex = 0;
|
||||||
|
//}
|
||||||
|
//for (int i = 0, l = _user->photos.size(); i < l; ++i) {
|
||||||
|
// if (_user->photos.at(i) == photo) {
|
||||||
|
// _fullIndex = i;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
//if (_user->photosCount < 0) {
|
||||||
|
// loadBack();
|
||||||
|
//} // TODO user
|
||||||
} else if ((_history = App::historyLoaded(_peer))) {
|
} else if ((_history = App::historyLoaded(_peer))) {
|
||||||
if (_history->peer->migrateFrom()) {
|
if (_history->peer->migrateFrom()) {
|
||||||
_migrated = App::history(_history->peer->migrateFrom()->id);
|
_migrated = App::history(_history->peer->migrateFrom()->id);
|
||||||
|
@ -1129,20 +1177,20 @@ void MediaView::showPhoto(PhotoData *photo, PeerData *context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
computeAdditionalChatPhoto(_history->peer, lastChatPhoto.photo);
|
computeAdditionalChatPhoto(_history->peer, lastChatPhoto.photo);
|
||||||
if (_additionalChatPhoto == _photo) {
|
//if (_additionalChatPhoto == _photo) { // TODO chat
|
||||||
_overview = OverviewChatPhotos;
|
// _overview = OverviewChatPhotos;
|
||||||
findCurrent();
|
// findCurrent();
|
||||||
} else {
|
//} else {
|
||||||
_additionalChatPhoto = nullptr;
|
_additionalChatPhoto = nullptr;
|
||||||
_history = _migrated = nullptr;
|
_history = _migrated = nullptr;
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
displayPhoto(photo, 0);
|
displayPhoto(photo, 0);
|
||||||
preloadData(0);
|
preloadData(0);
|
||||||
activateControls();
|
activateControls();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaView::showDocument(DocumentData *doc, HistoryItem *context) {
|
void MediaView::showDocument(not_null<DocumentData*> document, HistoryItem *context) {
|
||||||
_photo = 0;
|
_photo = 0;
|
||||||
_history = context ? context->history().get() : nullptr;
|
_history = context ? context->history().get() : nullptr;
|
||||||
_migrated = nullptr;
|
_migrated = nullptr;
|
||||||
|
@ -1169,25 +1217,21 @@ void MediaView::showDocument(DocumentData *doc, HistoryItem *context) {
|
||||||
}
|
}
|
||||||
if (!_animOpacities.isEmpty()) _animOpacities.clear();
|
if (!_animOpacities.isEmpty()) _animOpacities.clear();
|
||||||
|
|
||||||
_index = -1;
|
|
||||||
_msgid = context ? context->id : 0;
|
_msgid = context ? context->id : 0;
|
||||||
_msgmigrated = context ? (context->history() == _migrated) : false;
|
_msgmigrated = context ? (context->history() == _migrated) : false;
|
||||||
_channel = _history ? _history->channelId() : NoChannel;
|
_channel = _history ? _history->channelId() : NoChannel;
|
||||||
_canForward = context ? context->canForward() : false;
|
_canForward = context ? context->canForward() : false;
|
||||||
_canDelete = context ? context->canDelete() : false;
|
_canDelete = context ? context->canDelete() : false;
|
||||||
if (_history) {
|
|
||||||
_overview = doc->isGifv() ? OverviewGIFs : doc->isVideo() ? OverviewVideos : OverviewFiles;
|
if (document->isVideo() || document->isRoundVideo()) {
|
||||||
findCurrent();
|
_autoplayVideoDocument = document;
|
||||||
}
|
}
|
||||||
if (doc->isVideo() || doc->isRoundVideo()) {
|
displayDocument(document, context);
|
||||||
_autoplayVideoDocument = doc;
|
|
||||||
}
|
|
||||||
displayDocument(doc, context);
|
|
||||||
preloadData(0);
|
preloadData(0);
|
||||||
activateControls();
|
activateControls();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaView::displayPhoto(PhotoData *photo, HistoryItem *item) {
|
void MediaView::displayPhoto(not_null<PhotoData*> photo, HistoryItem *item) {
|
||||||
stopGif();
|
stopGif();
|
||||||
destroyThemePreview();
|
destroyThemePreview();
|
||||||
_doc = nullptr;
|
_doc = nullptr;
|
||||||
|
@ -1195,6 +1239,8 @@ void MediaView::displayPhoto(PhotoData *photo, HistoryItem *item) {
|
||||||
_photo = photo;
|
_photo = photo;
|
||||||
_radial.stop();
|
_radial.stop();
|
||||||
|
|
||||||
|
validateSharedMedia();
|
||||||
|
|
||||||
_photoRadialRect = QRect(QPoint((width() - st::radialSize.width()) / 2, (height() - st::radialSize.height()) / 2), st::radialSize);
|
_photoRadialRect = QRect(QPoint((width() - st::radialSize.width()) / 2, (height() - st::radialSize.height()) / 2), st::radialSize);
|
||||||
|
|
||||||
_zoom = 0;
|
_zoom = 0;
|
||||||
|
@ -1268,6 +1314,8 @@ void MediaView::displayDocument(DocumentData *doc, HistoryItem *item) { // empty
|
||||||
_photo = nullptr;
|
_photo = nullptr;
|
||||||
_radial.stop();
|
_radial.stop();
|
||||||
|
|
||||||
|
validateSharedMedia();
|
||||||
|
|
||||||
if (_autoplayVideoDocument && _doc != _autoplayVideoDocument) {
|
if (_autoplayVideoDocument && _doc != _autoplayVideoDocument) {
|
||||||
_autoplayVideoDocument = nullptr;
|
_autoplayVideoDocument = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -2160,51 +2208,14 @@ void MediaView::setZoomLevel(int newZoom) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MediaView::moveToNext(int32 delta) {
|
bool MediaView::moveToNext(int32 delta) {
|
||||||
if (_index < 0) {
|
if (!_index) {
|
||||||
if (delta == -1 && _photo == _additionalChatPhoto) {
|
|
||||||
auto lastChatPhoto = computeLastOverviewChatPhoto();
|
|
||||||
if (lastChatPhoto.item) {
|
|
||||||
if (lastChatPhoto.item->history() == _history) {
|
|
||||||
_index = _history->overview(_overview).size() - 1;
|
|
||||||
_msgmigrated = false;
|
|
||||||
} else {
|
|
||||||
_index = _migrated->overview(_overview).size() - 1;
|
|
||||||
_msgmigrated = true;
|
|
||||||
}
|
|
||||||
_msgid = lastChatPhoto.item->id;
|
|
||||||
_channel = _history ? _history->channelId() : NoChannel;
|
|
||||||
_canForward = lastChatPhoto.item->canForward();
|
|
||||||
_canDelete = lastChatPhoto.item->canDelete();
|
|
||||||
displayPhoto(lastChatPhoto.photo, lastChatPhoto.item);
|
|
||||||
preloadData(delta);
|
|
||||||
return true;
|
|
||||||
} else if (_history && (_history->overviewCount(OverviewChatPhotos) != 0 || (
|
|
||||||
_migrated && _migrated->overviewCount(OverviewChatPhotos) != 0))) {
|
|
||||||
loadBack();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (_overview == OverviewCount && (_history || !_user)) {
|
auto newIndex = *_index + delta;
|
||||||
|
if (newIndex < 0 || newIndex >= _sharedMediaData->size()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (_msgmigrated && !_history->overviewLoaded(_overview)) {
|
if (auto item = App::histItemById(_history->channelId(), *(_sharedMediaData->begin() + newIndex))) {
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 newIndex = _index + delta;
|
|
||||||
if (_history && _overview != OverviewCount) {
|
|
||||||
bool newMigrated = _msgmigrated;
|
|
||||||
if (!newMigrated && newIndex < 0 && _migrated) {
|
|
||||||
newIndex += _migrated->overview(_overview).size();
|
|
||||||
newMigrated = true;
|
|
||||||
} else if (newMigrated && newIndex >= _migrated->overview(_overview).size()) {
|
|
||||||
newIndex -= _migrated->overview(_overview).size() + (_history->overviewCount(_overview) - _history->overview(_overview).size());
|
|
||||||
newMigrated = false;
|
|
||||||
}
|
|
||||||
if (newIndex >= 0 && newIndex < (newMigrated ? _migrated : _history)->overview(_overview).size()) {
|
|
||||||
if (auto item = App::histItemById(newMigrated ? 0 : _channel, getMsgIdFromOverview(newMigrated ? _migrated : _history, newIndex))) {
|
|
||||||
_index = newIndex;
|
_index = newIndex;
|
||||||
_msgid = item->id;
|
_msgid = item->id;
|
||||||
_msgmigrated = (item->history() == _migrated);
|
_msgmigrated = (item->history() == _migrated);
|
||||||
|
@ -2224,58 +2235,110 @@ bool MediaView::moveToNext(int32 delta) {
|
||||||
displayDocument(nullptr, item);
|
displayDocument(nullptr, item);
|
||||||
preloadData(delta);
|
preloadData(delta);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
} else if (!newMigrated && newIndex == _history->overview(_overview).size() && _additionalChatPhoto) {
|
return false;
|
||||||
_index = -1;
|
|
||||||
_msgid = 0;
|
//if (_index < 0) { // TODO chat
|
||||||
_msgmigrated = false;
|
// if (delta == -1 && _photo == _additionalChatPhoto) {
|
||||||
_canForward = false;
|
// auto lastChatPhoto = computeLastOverviewChatPhoto();
|
||||||
_canDelete = false;
|
// if (lastChatPhoto.item) {
|
||||||
displayPhoto(_additionalChatPhoto, 0);
|
// if (lastChatPhoto.item->history() == _history) {
|
||||||
}
|
// _index = _history->overview(_overview).size() - 1;
|
||||||
if (delta < 0 && _index < MediaOverviewStartPerPage) {
|
// _msgmigrated = false;
|
||||||
loadBack();
|
// } else {
|
||||||
}
|
// _index = _migrated->overview(_overview).size() - 1;
|
||||||
} else if (_user) {
|
// _msgmigrated = true;
|
||||||
if (newIndex >= 0 && newIndex < _user->photos.size()) {
|
// }
|
||||||
_index = newIndex;
|
// _msgid = lastChatPhoto.item->id;
|
||||||
displayPhoto(_user->photos[_index], 0);
|
// _channel = _history ? _history->channelId() : NoChannel;
|
||||||
preloadData(delta);
|
// _canForward = lastChatPhoto.item->canForward();
|
||||||
}
|
// _canDelete = lastChatPhoto.item->canDelete();
|
||||||
if (delta > 0 && _index > _user->photos.size() - MediaOverviewStartPerPage) {
|
// displayPhoto(lastChatPhoto.photo, lastChatPhoto.item);
|
||||||
loadBack();
|
// preloadData(delta);
|
||||||
}
|
// return true;
|
||||||
}
|
// } else if (_history && (_history->overviewCount(OverviewChatPhotos) != 0 || (
|
||||||
|
// _migrated && _migrated->overviewCount(OverviewChatPhotos) != 0))) {
|
||||||
|
// loadBack();
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return false;
|
||||||
|
//}
|
||||||
|
//if (_overview == OverviewCount && (_history || !_user)) {
|
||||||
|
// return false;
|
||||||
|
//}
|
||||||
|
//if (_msgmigrated && !_history->overviewLoaded(_overview)) {
|
||||||
|
// return true;
|
||||||
|
//}
|
||||||
|
|
||||||
|
//int32 newIndex = _index + delta;
|
||||||
|
//if (_history && _overview != OverviewCount) {
|
||||||
|
// bool newMigrated = _msgmigrated;
|
||||||
|
// if (!newMigrated && newIndex < 0 && _migrated) {
|
||||||
|
// newIndex += _migrated->overview(_overview).size();
|
||||||
|
// newMigrated = true;
|
||||||
|
// } else if (newMigrated && newIndex >= _migrated->overview(_overview).size()) {
|
||||||
|
// newIndex -= _migrated->overview(_overview).size() + (_history->overviewCount(_overview) - _history->overview(_overview).size());
|
||||||
|
// newMigrated = false;
|
||||||
|
// }
|
||||||
|
// if (newIndex >= 0 && newIndex < (newMigrated ? _migrated : _history)->overview(_overview).size()) {
|
||||||
|
// if (auto item = App::histItemById(newMigrated ? 0 : _channel, getMsgIdFromOverview(newMigrated ? _migrated : _history, newIndex))) {
|
||||||
|
// _index = newIndex;
|
||||||
|
// _msgid = item->id;
|
||||||
|
// _msgmigrated = (item->history() == _migrated);
|
||||||
|
// _channel = _history ? _history->channelId() : NoChannel;
|
||||||
|
// _canForward = item->canForward();
|
||||||
|
// _canDelete = item->canDelete();
|
||||||
|
// stopGif();
|
||||||
|
// if (auto media = item->getMedia()) {
|
||||||
|
// switch (media->type()) {
|
||||||
|
// case MediaTypePhoto: displayPhoto(static_cast<HistoryPhoto*>(item->getMedia())->photo(), item); preloadData(delta); break;
|
||||||
|
// case MediaTypeFile:
|
||||||
|
// case MediaTypeVideo:
|
||||||
|
// case MediaTypeGif:
|
||||||
|
// case MediaTypeSticker: displayDocument(media->getDocument(), item); preloadData(delta); break;
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// displayDocument(nullptr, item);
|
||||||
|
// preloadData(delta);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } else if (!newMigrated && newIndex == _history->overview(_overview).size() && _additionalChatPhoto) {
|
||||||
|
// _index = -1;
|
||||||
|
// _msgid = 0;
|
||||||
|
// _msgmigrated = false;
|
||||||
|
// _canForward = false;
|
||||||
|
// _canDelete = false;
|
||||||
|
// displayPhoto(_additionalChatPhoto, 0);
|
||||||
|
// }
|
||||||
|
// if (delta < 0 && _index < MediaOverviewStartPerPage) {
|
||||||
|
// loadBack();
|
||||||
|
// }
|
||||||
|
//} else if (_user) {
|
||||||
|
// if (newIndex >= 0 && newIndex < _user->photos.size()) {
|
||||||
|
// _index = newIndex;
|
||||||
|
// displayPhoto(_user->photos[_index], 0);
|
||||||
|
// preloadData(delta);
|
||||||
|
// }
|
||||||
|
// if (delta > 0 && _index > _user->photos.size() - MediaOverviewStartPerPage) {
|
||||||
|
// loadBack();
|
||||||
|
// }
|
||||||
|
//}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaView::preloadData(int32 delta) {
|
void MediaView::preloadData(int32 delta) {
|
||||||
int indexInOverview = _index;
|
if (!_index) {
|
||||||
bool indexOfMigratedItem = _msgmigrated;
|
return;
|
||||||
if (_index < 0) {
|
|
||||||
if (_overview != OverviewChatPhotos || !_history) return;
|
|
||||||
indexInOverview = _history->overview(OverviewChatPhotos).size();
|
|
||||||
indexOfMigratedItem = false;
|
|
||||||
}
|
}
|
||||||
if (!_user && _overview == OverviewCount) return;
|
auto from = *_index + (delta ? delta : -1);
|
||||||
|
auto till = *_index + (delta ? delta * kPreloadCount : 1);
|
||||||
|
if (from > till) std::swap(from, till);
|
||||||
|
|
||||||
auto from = indexInOverview + (delta ? delta : -1);
|
auto forgetIndex = *_index - delta * 2;
|
||||||
auto to = indexInOverview + (delta ? delta * MediaOverviewPreloadCount : 1);
|
if (forgetIndex >= 0 && forgetIndex < _sharedMediaData->size()) {
|
||||||
if (from > to) qSwap(from, to);
|
if (auto item = App::histItemById(_history->channelId(), *(_sharedMediaData->begin() + forgetIndex))) {
|
||||||
if (_history && _overview != OverviewCount) {
|
|
||||||
auto forgetIndex = indexInOverview - delta * 2;
|
|
||||||
auto forgetHistory = indexOfMigratedItem ? _migrated : _history;
|
|
||||||
if (_migrated) {
|
|
||||||
if (indexOfMigratedItem && forgetIndex >= _migrated->overview(_overview).size()) {
|
|
||||||
forgetHistory = _history;
|
|
||||||
forgetIndex -= _migrated->overview(_overview).size() + (_history->overviewCount(_overview) - _history->overview(_overview).size());
|
|
||||||
} else if (!indexOfMigratedItem && forgetIndex < 0) {
|
|
||||||
forgetHistory = _migrated;
|
|
||||||
forgetIndex += _migrated->overview(_overview).size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (forgetIndex >= 0 && forgetIndex < forgetHistory->overview(_overview).size() && (forgetHistory != (indexOfMigratedItem ? _migrated : _history) || forgetIndex != indexInOverview)) {
|
|
||||||
if (auto item = App::histItemById(forgetHistory->channelId(), getMsgIdFromOverview(forgetHistory, forgetIndex))) {
|
|
||||||
if (auto media = item->getMedia()) {
|
if (auto media = item->getMedia()) {
|
||||||
switch (media->type()) {
|
switch (media->type()) {
|
||||||
case MediaTypePhoto: static_cast<HistoryPhoto*>(media)->photo()->forget(); break;
|
case MediaTypePhoto: static_cast<HistoryPhoto*>(media)->photo()->forget(); break;
|
||||||
|
@ -2288,20 +2351,9 @@ void MediaView::preloadData(int32 delta) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int32 i = from; i <= to; ++i) {
|
for (auto index = from; index != till; ++index) {
|
||||||
History *previewHistory = indexOfMigratedItem ? _migrated : _history;
|
if (index >= 0 && index < _sharedMediaData->size()) {
|
||||||
int32 previewIndex = i;
|
if (auto item = App::histItemById(_history->channelId(), *(_sharedMediaData->begin() + index))) {
|
||||||
if (_migrated) {
|
|
||||||
if (indexOfMigratedItem && previewIndex >= _migrated->overview(_overview).size()) {
|
|
||||||
previewHistory = _history;
|
|
||||||
previewIndex -= _migrated->overview(_overview).size() + (_history->overviewCount(_overview) - _history->overview(_overview).size());
|
|
||||||
} else if (!indexOfMigratedItem && previewIndex < 0) {
|
|
||||||
previewHistory = _migrated;
|
|
||||||
previewIndex += _migrated->overview(_overview).size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (previewIndex >= 0 && previewIndex < previewHistory->overview(_overview).size() && (previewHistory != (indexOfMigratedItem ? _migrated : _history) || previewIndex != indexInOverview)) {
|
|
||||||
if (auto item = App::histItemById(previewHistory->channelId(), getMsgIdFromOverview(previewHistory, previewIndex))) {
|
|
||||||
if (auto media = item->getMedia()) {
|
if (auto media = item->getMedia()) {
|
||||||
switch (media->type()) {
|
switch (media->type()) {
|
||||||
case MediaTypePhoto: static_cast<HistoryPhoto*>(media)->photo()->download(); break;
|
case MediaTypePhoto: static_cast<HistoryPhoto*>(media)->photo()->download(); break;
|
||||||
|
@ -2318,22 +2370,23 @@ void MediaView::preloadData(int32 delta) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (_user) {
|
|
||||||
for (int32 i = from; i <= to; ++i) {
|
//} else if (_user) {
|
||||||
if (i >= 0 && i < _user->photos.size() && i != indexInOverview) {
|
// for (int32 i = from; i <= to; ++i) {
|
||||||
_user->photos[i]->thumb->load();
|
// if (i >= 0 && i < _user->photos.size() && i != indexInOverview) {
|
||||||
}
|
// _user->photos[i]->thumb->load();
|
||||||
}
|
// }
|
||||||
for (int32 i = from; i <= to; ++i) {
|
// }
|
||||||
if (i >= 0 && i < _user->photos.size() && i != indexInOverview) {
|
// for (int32 i = from; i <= to; ++i) {
|
||||||
_user->photos[i]->download();
|
// if (i >= 0 && i < _user->photos.size() && i != indexInOverview) {
|
||||||
}
|
// _user->photos[i]->download();
|
||||||
}
|
// }
|
||||||
int32 forgetIndex = indexInOverview - delta * 2;
|
// }
|
||||||
if (forgetIndex >= 0 && forgetIndex < _user->photos.size() && forgetIndex != indexInOverview) {
|
// int32 forgetIndex = indexInOverview - delta * 2;
|
||||||
_user->photos[forgetIndex]->forget();
|
// if (forgetIndex >= 0 && forgetIndex < _user->photos.size() && forgetIndex != indexInOverview) {
|
||||||
}
|
// _user->photos[forgetIndex]->forget();
|
||||||
}
|
// }
|
||||||
|
//} // TODO user
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaView::mousePressEvent(QMouseEvent *e) {
|
void MediaView::mousePressEvent(QMouseEvent *e) {
|
||||||
|
@ -2763,69 +2816,81 @@ void MediaView::updateImage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaView::findCurrent() {
|
void MediaView::findCurrent() {
|
||||||
auto i = 0;
|
if (!_sharedMediaData) {
|
||||||
if (_msgmigrated) {
|
_index = _fullIndex = _fullCount = base::none;
|
||||||
for (auto msgId : _migrated->overview(_overview)) {
|
return;
|
||||||
if (msgId == _msgid) {
|
|
||||||
_index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
if (!_history->overviewCountLoaded(_overview)) {
|
|
||||||
loadBack();
|
|
||||||
} else if (_history->overviewLoaded(_overview) && !_migrated->overviewLoaded(_overview)) { // all loaded
|
|
||||||
if (!_migrated->overviewCountLoaded(_overview) || (_index < 2 && _migrated->overviewCount(_overview) > 0)) {
|
|
||||||
loadBack();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
_index = _sharedMediaData->indexOf(_msgid);
|
||||||
|
if (_index && _sharedMediaData->skippedBefore()) {
|
||||||
|
_fullIndex = (*_index + *_sharedMediaData->skippedBefore());
|
||||||
} else {
|
} else {
|
||||||
for (auto msgId : _history->overview(_overview)) {
|
_fullIndex = base::none;
|
||||||
if (msgId == _msgid) {
|
|
||||||
_index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
if (!_history->overviewLoaded(_overview)) {
|
|
||||||
if (!_history->overviewCountLoaded(_overview) || (_index < 2 && _history->overviewCount(_overview) > 0) || (_index < 1 && _migrated && !_migrated->overviewLoaded(_overview))) {
|
|
||||||
loadBack();
|
|
||||||
}
|
|
||||||
} else if (_index < 1 && _migrated && !_migrated->overviewLoaded(_overview)) {
|
|
||||||
loadBack();
|
|
||||||
}
|
|
||||||
if (_migrated && !_migrated->overviewCountLoaded(_overview)) {
|
|
||||||
App::main()->preloadOverview(_migrated->peer, _overview);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
_fullCount = _sharedMediaData->fullCount();
|
||||||
|
|
||||||
|
//auto i = 0;
|
||||||
|
//if (_msgmigrated) {
|
||||||
|
// for (auto msgId : _migrated->overview(_overview)) {
|
||||||
|
// if (msgId == _msgid) {
|
||||||
|
// _index = i;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// ++i;
|
||||||
|
// }
|
||||||
|
// if (!_history->overviewCountLoaded(_overview)) {
|
||||||
|
// loadBack();
|
||||||
|
// } else if (_history->overviewLoaded(_overview) && !_migrated->overviewLoaded(_overview)) { // all loaded
|
||||||
|
// if (!_migrated->overviewCountLoaded(_overview) || (_index < 2 && _migrated->overviewCount(_overview) > 0)) {
|
||||||
|
// loadBack();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//} else {
|
||||||
|
// for (auto msgId : _history->overview(_overview)) {
|
||||||
|
// if (msgId == _msgid) {
|
||||||
|
// _index = i;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// ++i;
|
||||||
|
// }
|
||||||
|
// if (!_history->overviewLoaded(_overview)) {
|
||||||
|
// if (!_history->overviewCountLoaded(_overview) || (_index < 2 && _history->overviewCount(_overview) > 0) || (_index < 1 && _migrated && !_migrated->overviewLoaded(_overview))) {
|
||||||
|
// loadBack();
|
||||||
|
// }
|
||||||
|
// } else if (_index < 1 && _migrated && !_migrated->overviewLoaded(_overview)) {
|
||||||
|
// loadBack();
|
||||||
|
// }
|
||||||
|
// if (_migrated && !_migrated->overviewCountLoaded(_overview)) {
|
||||||
|
// App::main()->preloadOverview(_migrated->peer, _overview);
|
||||||
|
// }
|
||||||
|
//} // TODO user
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaView::loadBack() {
|
void MediaView::loadBack() {
|
||||||
if (_loadRequest || (_overview == OverviewCount && !_user)) {
|
//if (_loadRequest || (_overview == OverviewCount && !_user)) {
|
||||||
return;
|
// return;
|
||||||
}
|
//}
|
||||||
if (_index < 0 && (!_additionalChatPhoto || _photo != _additionalChatPhoto || !_history)) {
|
//if (_index < 0 && (!_additionalChatPhoto || _photo != _additionalChatPhoto || !_history)) {
|
||||||
return;
|
// return;
|
||||||
}
|
//}
|
||||||
|
|
||||||
if (_history && _overview != OverviewCount && (!_history->overviewLoaded(_overview) || (_migrated && !_migrated->overviewLoaded(_overview)))) {
|
//if (_history && _overview != OverviewCount && (!_history->overviewLoaded(_overview) || (_migrated && !_migrated->overviewLoaded(_overview)))) {
|
||||||
if (App::main()) {
|
// if (App::main()) {
|
||||||
if (_msgmigrated || (_migrated && _index == 0 && _history->overviewLoaded(_overview))) {
|
// if (_msgmigrated || (_migrated && _index == 0 && _history->overviewLoaded(_overview))) {
|
||||||
App::main()->loadMediaBack(_migrated->peer, _overview);
|
// App::main()->loadMediaBack(_migrated->peer, _overview);
|
||||||
} else {
|
// } else {
|
||||||
App::main()->loadMediaBack(_history->peer, _overview);
|
// App::main()->loadMediaBack(_history->peer, _overview);
|
||||||
if (_migrated && _index == 0 && (_migrated->overviewCount(_overview) < 0 || _migrated->overview(_overview).isEmpty()) && !_migrated->overviewLoaded(_overview)) {
|
// if (_migrated && _index == 0 && (_migrated->overviewCount(_overview) < 0 || _migrated->overview(_overview).isEmpty()) && !_migrated->overviewLoaded(_overview)) {
|
||||||
App::main()->loadMediaBack(_migrated->peer, _overview);
|
// App::main()->loadMediaBack(_migrated->peer, _overview);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
if (_msgmigrated && !_history->overviewCountLoaded(_overview)) {
|
// if (_msgmigrated && !_history->overviewCountLoaded(_overview)) {
|
||||||
App::main()->preloadOverview(_history->peer, _overview);
|
// App::main()->preloadOverview(_history->peer, _overview);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
} else if (_user && _user->photosCount != 0) {
|
//} else if (_user && _user->photosCount != 0) {
|
||||||
int32 limit = (_index < MediaOverviewStartPerPage && _user->photos.size() > MediaOverviewStartPerPage) ? SearchPerPage : MediaOverviewStartPerPage;
|
// int32 limit = (_index < MediaOverviewStartPerPage && _user->photos.size() > MediaOverviewStartPerPage) ? SearchPerPage : MediaOverviewStartPerPage;
|
||||||
_loadRequest = MTP::send(MTPphotos_GetUserPhotos(_user->inputUser, MTP_int(_user->photos.size()), MTP_long(0), MTP_int(limit)), rpcDone(&MediaView::userPhotosLoaded, _user));
|
// _loadRequest = MTP::send(MTPphotos_GetUserPhotos(_user->inputUser, MTP_int(_user->photos.size()), MTP_long(0), MTP_int(limit)), rpcDone(&MediaView::userPhotosLoaded, _user));
|
||||||
}
|
//} // TODO user
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaView::LastChatPhoto MediaView::computeLastOverviewChatPhoto() {
|
MediaView::LastChatPhoto MediaView::computeLastOverviewChatPhoto() {
|
||||||
|
@ -2903,34 +2968,11 @@ void MediaView::userPhotosLoaded(UserData *u, const MTPphotos_Photos &photos, mt
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaView::updateHeader() {
|
void MediaView::updateHeader() {
|
||||||
int32 index = _index, count = 0, addcount = (_migrated && _overview != OverviewCount) ? _migrated->overviewCount(_overview) : 0;
|
auto index = _fullIndex ? *_fullIndex : -1;
|
||||||
|
auto count = _fullCount ? *_fullCount : -1;
|
||||||
if (_history) {
|
if (_history) {
|
||||||
if (_overview != OverviewCount) {
|
|
||||||
bool lastOverviewPhotoLoaded = (!_history->overview(_overview).isEmpty() || (
|
|
||||||
_migrated && _history->overviewCount(_overview) == 0 && !_migrated->overview(_overview).isEmpty()));
|
|
||||||
count = _history->overviewCount(_overview);
|
|
||||||
if (addcount >= 0 && count >= 0) {
|
|
||||||
count += addcount;
|
|
||||||
}
|
|
||||||
if (index >= 0 && (_msgmigrated ? (count >= 0 && addcount >= 0 && _history->overviewLoaded(_overview)) : (count >= 0))) {
|
|
||||||
if (_msgmigrated) {
|
|
||||||
index += addcount - _migrated->overview(_overview).size();
|
|
||||||
} else {
|
|
||||||
index += count - _history->overview(_overview).size();
|
|
||||||
}
|
|
||||||
if (_additionalChatPhoto && lastOverviewPhotoLoaded) {
|
|
||||||
++count;
|
|
||||||
}
|
|
||||||
} else if (index < 0 && _additionalChatPhoto && _photo == _additionalChatPhoto && lastOverviewPhotoLoaded) {
|
|
||||||
// Additional chat photo (not in the list => place it at the end of the list).
|
|
||||||
index = count;
|
|
||||||
++count;
|
|
||||||
} else {
|
|
||||||
count = 0; // unknown yet
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (_user) {
|
} else if (_user) {
|
||||||
count = _user->photosCount ? _user->photosCount : _user->photos.size();
|
count = _user->photosCount ? _user->photosCount : _user->photos.size(); // TODO user
|
||||||
}
|
}
|
||||||
if (index >= 0 && index < count && count > 1) {
|
if (index >= 0 && index < count && count > 1) {
|
||||||
if (_doc) {
|
if (_doc) {
|
||||||
|
@ -2951,8 +2993,10 @@ void MediaView::updateHeader() {
|
||||||
_headerText = lang(lng_mediaview_single_photo);
|
_headerText = lang(lng_mediaview_single_photo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_headerHasLink = _history && typeHasMediaOverview(_overview);
|
_headerHasLink = (
|
||||||
int32 hwidth = st::mediaviewThickFont->width(_headerText);
|
sharedMediaType()
|
||||||
|
| SharedMediaOverviewType) != base::none;
|
||||||
|
auto hwidth = st::mediaviewThickFont->width(_headerText);
|
||||||
if (hwidth > width() / 3) {
|
if (hwidth > width() / 3) {
|
||||||
hwidth = width() / 3;
|
hwidth = width() / 3;
|
||||||
_headerText = st::mediaviewThickFont->elided(_headerText, hwidth, Qt::ElideMiddle);
|
_headerText = st::mediaviewThickFont->elided(_headerText, hwidth, Qt::ElideMiddle);
|
||||||
|
@ -2966,13 +3010,13 @@ float64 MediaView::overLevel(OverState control) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
MsgId MediaView::getMsgIdFromOverview(not_null<History*> history, int index) const {
|
MsgId MediaView::getMsgIdFromOverview(not_null<History*> history, int index) const {
|
||||||
auto &overview = history->overview(_overview);
|
//auto &overview = history->overview(_overview);
|
||||||
if (index >= 0 && index < overview.size()) {
|
//if (index >= 0 && index < overview.size()) {
|
||||||
auto it = overview.begin();
|
// auto it = overview.begin();
|
||||||
for (auto i = 0; i != index; ++i) {
|
// for (auto i = 0; i != index; ++i) {
|
||||||
++it;
|
// ++it;
|
||||||
}
|
// }
|
||||||
return *it;
|
// return *it;
|
||||||
}
|
//}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
#include "ui/widgets/dropdown_menu.h"
|
#include "ui/widgets/dropdown_menu.h"
|
||||||
#include "ui/effects/radial_animation.h"
|
#include "ui/effects/radial_animation.h"
|
||||||
|
#include "history/history_shared_media.h"
|
||||||
|
|
||||||
namespace Media {
|
namespace Media {
|
||||||
namespace Player {
|
namespace Player {
|
||||||
|
@ -58,9 +59,9 @@ public:
|
||||||
|
|
||||||
void updateOver(QPoint mpos);
|
void updateOver(QPoint mpos);
|
||||||
|
|
||||||
void showPhoto(PhotoData *photo, HistoryItem *context);
|
void showPhoto(not_null<PhotoData*> photo, HistoryItem *context);
|
||||||
void showPhoto(PhotoData *photo, PeerData *context);
|
void showPhoto(not_null<PhotoData*> photo, PeerData *context);
|
||||||
void showDocument(DocumentData *doc, HistoryItem *context);
|
void showDocument(not_null<DocumentData*> document, HistoryItem *context);
|
||||||
void moveToScreen();
|
void moveToScreen();
|
||||||
bool moveToNext(int32 delta);
|
bool moveToNext(int32 delta);
|
||||||
void preloadData(int32 delta);
|
void preloadData(int32 delta);
|
||||||
|
@ -154,13 +155,25 @@ private:
|
||||||
void showSaveMsgFile();
|
void showSaveMsgFile();
|
||||||
void updateMixerVideoVolume() const;
|
void updateMixerVideoVolume() const;
|
||||||
|
|
||||||
|
struct SharedMedia;
|
||||||
|
using SharedMediaType = SharedMediaViewer::Type;
|
||||||
|
using SharedMediaKey = SharedMediaViewer::Key;
|
||||||
|
base::optional<SharedMediaType> sharedMediaType() const;
|
||||||
|
base::optional<SharedMediaKey> sharedMediaKey() const;
|
||||||
|
void validateSharedMedia();
|
||||||
|
bool validSharedMedia() const;
|
||||||
|
std::unique_ptr<SharedMedia> createSharedMedia() const;
|
||||||
|
void refreshSharedMedia();
|
||||||
|
void handleSharedMediaUpdate(const SharedMediaSlice &update);
|
||||||
|
void refreshNavVisibility();
|
||||||
|
|
||||||
void dropdownHidden();
|
void dropdownHidden();
|
||||||
void updateDocSize();
|
void updateDocSize();
|
||||||
void updateControls();
|
void updateControls();
|
||||||
void updateActions();
|
void updateActions();
|
||||||
|
|
||||||
void displayPhoto(PhotoData *photo, HistoryItem *item);
|
void displayPhoto(not_null<PhotoData*> photo, HistoryItem *item);
|
||||||
void displayDocument(DocumentData *doc, HistoryItem *item);
|
void displayDocument(DocumentData *document, HistoryItem *item);
|
||||||
void displayFinished();
|
void displayFinished();
|
||||||
void findCurrent();
|
void findCurrent();
|
||||||
void loadBack();
|
void loadBack();
|
||||||
|
@ -184,7 +197,7 @@ private:
|
||||||
void updateThemePreviewGeometry();
|
void updateThemePreviewGeometry();
|
||||||
|
|
||||||
void documentUpdated(DocumentData *doc);
|
void documentUpdated(DocumentData *doc);
|
||||||
void changingMsgId(HistoryItem *row, MsgId newId);
|
void changingMsgId(not_null<HistoryItem*> row, MsgId newId);
|
||||||
|
|
||||||
// Radial animation interface.
|
// Radial animation interface.
|
||||||
float64 radialProgress() const;
|
float64 radialProgress() const;
|
||||||
|
@ -230,7 +243,9 @@ private:
|
||||||
|
|
||||||
PhotoData *_photo = nullptr;
|
PhotoData *_photo = nullptr;
|
||||||
DocumentData *_doc = nullptr;
|
DocumentData *_doc = nullptr;
|
||||||
MediaOverviewType _overview = OverviewCount;
|
std::unique_ptr<SharedMedia> _sharedMedia;
|
||||||
|
base::optional<SharedMediaSlice> _sharedMediaData;
|
||||||
|
|
||||||
QRect _closeNav, _closeNavIcon;
|
QRect _closeNav, _closeNavIcon;
|
||||||
QRect _leftNav, _leftNavIcon, _rightNav, _rightNavIcon;
|
QRect _leftNav, _leftNavIcon, _rightNav, _rightNavIcon;
|
||||||
QRect _headerNav, _nameNav, _dateNav;
|
QRect _headerNav, _nameNav, _dateNav;
|
||||||
|
@ -308,7 +323,9 @@ private:
|
||||||
PeerData *_from = nullptr;
|
PeerData *_from = nullptr;
|
||||||
Text _fromName;
|
Text _fromName;
|
||||||
|
|
||||||
int _index = -1; // index in photos or files array, -1 if just photo
|
base::optional<int> _index; // Index in current _sharedMedia data.
|
||||||
|
base::optional<int> _fullIndex; // Index in full shared media.
|
||||||
|
base::optional<int> _fullCount;
|
||||||
MsgId _msgid = 0; // msgId of current photo or file
|
MsgId _msgid = 0; // msgId of current photo or file
|
||||||
bool _msgmigrated = false; // msgId is from _migrated history
|
bool _msgmigrated = false; // msgId is from _migrated history
|
||||||
ChannelId _channel = NoChannel;
|
ChannelId _channel = NoChannel;
|
||||||
|
|
|
@ -96,7 +96,7 @@ OverviewInner::OverviewInner(OverviewWidget *overview, Ui::ScrollArea *scroll, P
|
||||||
subscribe(App::wnd()->dragFinished(), [this] {
|
subscribe(App::wnd()->dragFinished(), [this] {
|
||||||
dragActionUpdate(QCursor::pos());
|
dragActionUpdate(QCursor::pos());
|
||||||
});
|
});
|
||||||
subscribe(Auth().messageIdChanging, [this](std::pair<HistoryItem*, MsgId> update) {
|
subscribe(Auth().messageIdChanging, [this](std::pair<not_null<HistoryItem*>, MsgId> update) {
|
||||||
changingMsgId(update.first, update.second);
|
changingMsgId(update.first, update.second);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,10 @@ public:
|
||||||
SharedMediaQuery &&query,
|
SharedMediaQuery &&query,
|
||||||
base::lambda_once<void(SharedMediaResult&&)> &&callback);
|
base::lambda_once<void(SharedMediaResult&&)> &&callback);
|
||||||
|
|
||||||
|
base::Observable<SharedMediaSliceUpdate> &sharedMediaSliceUpdated();
|
||||||
|
base::Observable<SharedMediaRemoveOne> &sharedMediaOneRemoved();
|
||||||
|
base::Observable<SharedMediaRemoveAll> &sharedMediaAllRemoved();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SharedMedia _sharedMedia;
|
SharedMedia _sharedMedia;
|
||||||
|
|
||||||
|
@ -66,6 +70,17 @@ void Facade::Impl::query(
|
||||||
_sharedMedia.query(query, std::move(callback));
|
_sharedMedia.query(query, std::move(callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
base::Observable<SharedMediaSliceUpdate> &Facade::Impl::sharedMediaSliceUpdated() {
|
||||||
|
return _sharedMedia.sliceUpdated;
|
||||||
|
}
|
||||||
|
|
||||||
|
base::Observable<SharedMediaRemoveOne> &Facade::Impl::sharedMediaOneRemoved() {
|
||||||
|
return _sharedMedia.oneRemoved;
|
||||||
|
}
|
||||||
|
|
||||||
|
base::Observable<SharedMediaRemoveAll> &Facade::Impl::sharedMediaAllRemoved() {
|
||||||
|
return _sharedMedia.allRemoved;
|
||||||
|
}
|
||||||
|
|
||||||
Facade::Facade() : _impl(std::make_unique<Impl>()) {
|
Facade::Facade() : _impl(std::make_unique<Impl>()) {
|
||||||
}
|
}
|
||||||
|
@ -96,6 +111,18 @@ void Facade::query(
|
||||||
_impl->query(std::move(query), std::move(callback));
|
_impl->query(std::move(query), std::move(callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
base::Observable<SharedMediaSliceUpdate> &Facade::sharedMediaSliceUpdated() {
|
||||||
|
return _impl->sharedMediaSliceUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
|
base::Observable<SharedMediaRemoveOne> &Facade::sharedMediaOneRemoved() {
|
||||||
|
return _impl->sharedMediaOneRemoved();
|
||||||
|
}
|
||||||
|
|
||||||
|
base::Observable<SharedMediaRemoveAll> &Facade::sharedMediaAllRemoved() {
|
||||||
|
return _impl->sharedMediaAllRemoved();
|
||||||
|
}
|
||||||
|
|
||||||
Facade::~Facade() = default;
|
Facade::~Facade() = default;
|
||||||
|
|
||||||
} // namespace Storage
|
} // namespace Storage
|
||||||
|
|
|
@ -31,6 +31,7 @@ struct SharedMediaRemoveOne;
|
||||||
struct SharedMediaRemoveAll;
|
struct SharedMediaRemoveAll;
|
||||||
struct SharedMediaQuery;
|
struct SharedMediaQuery;
|
||||||
struct SharedMediaResult;
|
struct SharedMediaResult;
|
||||||
|
struct SharedMediaSliceUpdate;
|
||||||
|
|
||||||
class Facade {
|
class Facade {
|
||||||
public:
|
public:
|
||||||
|
@ -45,6 +46,10 @@ public:
|
||||||
SharedMediaQuery &&query,
|
SharedMediaQuery &&query,
|
||||||
base::lambda_once<void(SharedMediaResult&&)> &&callback);
|
base::lambda_once<void(SharedMediaResult&&)> &&callback);
|
||||||
|
|
||||||
|
base::Observable<SharedMediaSliceUpdate> &sharedMediaSliceUpdated();
|
||||||
|
base::Observable<SharedMediaRemoveOne> &sharedMediaOneRemoved();
|
||||||
|
base::Observable<SharedMediaRemoveAll> &sharedMediaAllRemoved();
|
||||||
|
|
||||||
~Facade();
|
~Facade();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -47,15 +47,16 @@ void SharedMedia::List::Slice::merge(
|
||||||
|
|
||||||
template <typename Range>
|
template <typename Range>
|
||||||
int SharedMedia::List::uniteAndAdd(
|
int SharedMedia::List::uniteAndAdd(
|
||||||
|
SliceUpdate &update,
|
||||||
base::flat_set<Slice>::iterator uniteFrom,
|
base::flat_set<Slice>::iterator uniteFrom,
|
||||||
base::flat_set<Slice>::iterator uniteTill,
|
base::flat_set<Slice>::iterator uniteTill,
|
||||||
const Range &messages,
|
const Range &messages,
|
||||||
MsgRange noSkipRange) {
|
MsgRange noSkipRange) {
|
||||||
|
auto uniteFromIndex = uniteFrom - _slices.begin();
|
||||||
auto was = uniteFrom->messages.size();
|
auto was = uniteFrom->messages.size();
|
||||||
_slices.modify(uniteFrom, [&](Slice &slice) {
|
_slices.modify(uniteFrom, [&](Slice &slice) {
|
||||||
slice.merge(messages, noSkipRange);
|
slice.merge(messages, noSkipRange);
|
||||||
});
|
});
|
||||||
auto result = uniteFrom->messages.size() - was;
|
|
||||||
auto firstToErase = uniteFrom + 1;
|
auto firstToErase = uniteFrom + 1;
|
||||||
if (firstToErase != uniteTill) {
|
if (firstToErase != uniteTill) {
|
||||||
for (auto it = firstToErase; it != uniteTill; ++it) {
|
for (auto it = firstToErase; it != uniteTill; ++it) {
|
||||||
|
@ -64,21 +65,21 @@ int SharedMedia::List::uniteAndAdd(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
_slices.erase(firstToErase, uniteTill);
|
_slices.erase(firstToErase, uniteTill);
|
||||||
|
uniteFrom = _slices.begin() + uniteFromIndex;
|
||||||
}
|
}
|
||||||
return result;
|
update.messages = &uniteFrom->messages;
|
||||||
|
update.range = uniteFrom->range;
|
||||||
|
return uniteFrom->messages.size() - was;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Range>
|
template <typename Range>
|
||||||
int SharedMedia::List::addRangeItemsAndCount(
|
int SharedMedia::List::addRangeItemsAndCount(
|
||||||
|
SliceUpdate &update,
|
||||||
const Range &messages,
|
const Range &messages,
|
||||||
MsgRange noSkipRange,
|
MsgRange noSkipRange,
|
||||||
base::optional<int> count) {
|
base::optional<int> count) {
|
||||||
Expects((noSkipRange.from < noSkipRange.till)
|
Expects((noSkipRange.from < noSkipRange.till)
|
||||||
|| (noSkipRange.from == noSkipRange.till && messages.begin() == messages.end()));
|
|| (noSkipRange.from == noSkipRange.till && messages.begin() == messages.end()));
|
||||||
|
|
||||||
if (count) {
|
|
||||||
_count = count;
|
|
||||||
}
|
|
||||||
if (noSkipRange.from == noSkipRange.till) {
|
if (noSkipRange.from == noSkipRange.till) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -92,7 +93,7 @@ int SharedMedia::List::addRangeItemsAndCount(
|
||||||
noSkipRange.till,
|
noSkipRange.till,
|
||||||
[](MsgId till, const Slice &slice) { return till < slice.range.from; });
|
[](MsgId till, const Slice &slice) { return till < slice.range.from; });
|
||||||
if (uniteFrom < uniteTill) {
|
if (uniteFrom < uniteTill) {
|
||||||
return uniteAndAdd(uniteFrom, uniteTill, messages, noSkipRange);
|
return uniteAndAdd(update, uniteFrom, uniteTill, messages, noSkipRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto sliceMessages = base::flat_set<MsgId> {
|
auto sliceMessages = base::flat_set<MsgId> {
|
||||||
|
@ -101,29 +102,39 @@ int SharedMedia::List::addRangeItemsAndCount(
|
||||||
auto slice = _slices.emplace(
|
auto slice = _slices.emplace(
|
||||||
std::move(sliceMessages),
|
std::move(sliceMessages),
|
||||||
noSkipRange);
|
noSkipRange);
|
||||||
|
update.messages = &slice->messages;
|
||||||
|
update.range = slice->range;
|
||||||
return slice->messages.size();
|
return slice->messages.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Range>
|
template <typename Range>
|
||||||
int SharedMedia::List::addRange(
|
void SharedMedia::List::addRange(
|
||||||
const Range &messages,
|
const Range &messages,
|
||||||
MsgRange noSkipRange,
|
MsgRange noSkipRange,
|
||||||
base::optional<int> count) {
|
base::optional<int> count,
|
||||||
auto result = addRangeItemsAndCount(messages, noSkipRange, count);
|
bool incrementCount) {
|
||||||
|
Expects(!count || !incrementCount);
|
||||||
|
|
||||||
|
auto wasCount = _count;
|
||||||
|
auto update = SliceUpdate();
|
||||||
|
auto result = addRangeItemsAndCount(update, messages, noSkipRange, count);
|
||||||
|
if (count) {
|
||||||
|
_count = count;
|
||||||
|
} else if (incrementCount && _count && result > 0) {
|
||||||
|
*_count += result;
|
||||||
|
}
|
||||||
if (_slices.size() == 1) {
|
if (_slices.size() == 1) {
|
||||||
if (_slices.front().range == MsgRange { 0, ServerMaxMsgId }) {
|
if (_slices.front().range == MsgRange { 0, ServerMaxMsgId }) {
|
||||||
_count = _slices.front().messages.size();
|
_count = _slices.front().messages.size();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
update.count = _count;
|
||||||
|
sliceUpdated.notify(update, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SharedMedia::List::addNew(MsgId messageId) {
|
void SharedMedia::List::addNew(MsgId messageId) {
|
||||||
auto range = { messageId };
|
auto range = { messageId };
|
||||||
auto added = addRange(range, { messageId, ServerMaxMsgId }, base::none);
|
addRange(range, { messageId, ServerMaxMsgId }, base::none, true);
|
||||||
if (added > 0 && _count) {
|
|
||||||
*_count += added;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SharedMedia::List::addExisting(
|
void SharedMedia::List::addExisting(
|
||||||
|
@ -169,9 +180,9 @@ void SharedMedia::List::query(
|
||||||
|
|
||||||
auto slice = base::lower_bound(
|
auto slice = base::lower_bound(
|
||||||
_slices,
|
_slices,
|
||||||
query.messageId,
|
query.key.messageId,
|
||||||
[](const Slice &slice, MsgId id) { return slice.range.till < id; });
|
[](const Slice &slice, MsgId id) { return slice.range.till < id; });
|
||||||
if (slice != _slices.end() && slice->range.from <= query.messageId) {
|
if (slice != _slices.end() && slice->range.from <= query.key.messageId) {
|
||||||
result = queryFromSlice(query, *slice);
|
result = queryFromSlice(query, *slice);
|
||||||
} else {
|
} else {
|
||||||
result.count = _count;
|
result.count = _count;
|
||||||
|
@ -189,18 +200,20 @@ SharedMediaResult SharedMedia::List::queryFromSlice(
|
||||||
const SharedMediaQuery &query,
|
const SharedMediaQuery &query,
|
||||||
const Slice &slice) {
|
const Slice &slice) {
|
||||||
auto result = SharedMediaResult {};
|
auto result = SharedMediaResult {};
|
||||||
auto position = base::lower_bound(slice.messages, query.messageId);
|
auto position = base::lower_bound(slice.messages, query.key.messageId);
|
||||||
auto haveBefore = position - slice.messages.begin();
|
auto haveBefore = int(position - slice.messages.begin());
|
||||||
auto haveEqualOrAfter = slice.messages.end() - position;
|
auto haveEqualOrAfter = int(slice.messages.end() - position);
|
||||||
auto before = qMin(haveBefore, query.limitBefore);
|
auto before = qMin(haveBefore, query.limitBefore);
|
||||||
auto equalOrAfter = qMin(haveEqualOrAfter, query.limitAfter + 1);
|
auto equalOrAfter = qMin(haveEqualOrAfter, query.limitAfter + 1);
|
||||||
result.messageIds.reserve(before + equalOrAfter);
|
auto ids = std::vector<MsgId>();
|
||||||
|
ids.reserve(before + equalOrAfter);
|
||||||
for (
|
for (
|
||||||
auto from = position - before, till = position + equalOrAfter;
|
auto from = position - before, till = position + equalOrAfter;
|
||||||
from != till;
|
from != till;
|
||||||
++from) {
|
++from) {
|
||||||
result.messageIds.push_back(*from);
|
ids.push_back(*from);
|
||||||
}
|
}
|
||||||
|
result.messageIds.merge(ids.begin(), ids.end());
|
||||||
if (slice.range.from == 0) {
|
if (slice.range.from == 0) {
|
||||||
result.skippedBefore = haveBefore - before;
|
result.skippedBefore = haveBefore - before;
|
||||||
}
|
}
|
||||||
|
@ -212,21 +225,41 @@ SharedMediaResult SharedMedia::List::queryFromSlice(
|
||||||
if (!result.skippedBefore && result.skippedAfter) {
|
if (!result.skippedBefore && result.skippedAfter) {
|
||||||
result.skippedBefore = *result.count
|
result.skippedBefore = *result.count
|
||||||
- *result.skippedAfter
|
- *result.skippedAfter
|
||||||
- result.messageIds.size();
|
- int(result.messageIds.size());
|
||||||
} else if (!result.skippedAfter && result.skippedBefore) {
|
} else if (!result.skippedAfter && result.skippedBefore) {
|
||||||
result.skippedAfter = *result.count
|
result.skippedAfter = *result.count
|
||||||
- *result.skippedBefore
|
- *result.skippedBefore
|
||||||
- result.messageIds.size();
|
- int(result.messageIds.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SharedMedia::add(SharedMediaAddNew &&query) {
|
std::map<PeerId, SharedMedia::Lists>::iterator
|
||||||
auto peerIt = _lists.find(query.peerId);
|
SharedMedia::enforceLists(PeerId peer) {
|
||||||
if (peerIt == _lists.end()) {
|
auto result = _lists.find(peer);
|
||||||
peerIt = _lists.emplace(query.peerId, Lists {}).first;
|
if (result != _lists.end()) {
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
result = _lists.emplace(peer, Lists {}).first;
|
||||||
|
for (auto index = 0; index != kSharedMediaTypeCount; ++index) {
|
||||||
|
auto &list = result->second[index];
|
||||||
|
auto type = static_cast<SharedMediaType>(index);
|
||||||
|
subscribe(list.sliceUpdated, [this, type, peer](const SliceUpdate &update) {
|
||||||
|
sliceUpdated.notify(SharedMediaSliceUpdate(
|
||||||
|
peer,
|
||||||
|
type,
|
||||||
|
update.messages,
|
||||||
|
update.range,
|
||||||
|
update.count), true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SharedMedia::add(SharedMediaAddNew &&query) {
|
||||||
|
auto peer = query.peerId;
|
||||||
|
auto peerIt = enforceLists(peer);
|
||||||
for (auto index = 0; index != kSharedMediaTypeCount; ++index) {
|
for (auto index = 0; index != kSharedMediaTypeCount; ++index) {
|
||||||
auto type = static_cast<SharedMediaType>(index);
|
auto type = static_cast<SharedMediaType>(index);
|
||||||
if (query.types.test(type)) {
|
if (query.types.test(type)) {
|
||||||
|
@ -236,10 +269,7 @@ void SharedMedia::add(SharedMediaAddNew &&query) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SharedMedia::add(SharedMediaAddExisting &&query) {
|
void SharedMedia::add(SharedMediaAddExisting &&query) {
|
||||||
auto peerIt = _lists.find(query.peerId);
|
auto peerIt = enforceLists(query.peerId);
|
||||||
if (peerIt == _lists.end()) {
|
|
||||||
peerIt = _lists.emplace(query.peerId, Lists {}).first;
|
|
||||||
}
|
|
||||||
for (auto index = 0; index != kSharedMediaTypeCount; ++index) {
|
for (auto index = 0; index != kSharedMediaTypeCount; ++index) {
|
||||||
auto type = static_cast<SharedMediaType>(index);
|
auto type = static_cast<SharedMediaType>(index);
|
||||||
if (query.types.test(type)) {
|
if (query.types.test(type)) {
|
||||||
|
@ -250,10 +280,7 @@ void SharedMedia::add(SharedMediaAddExisting &&query) {
|
||||||
|
|
||||||
void SharedMedia::add(SharedMediaAddSlice &&query) {
|
void SharedMedia::add(SharedMediaAddSlice &&query) {
|
||||||
Expects(IsValidSharedMediaType(query.type));
|
Expects(IsValidSharedMediaType(query.type));
|
||||||
auto peerIt = _lists.find(query.peerId);
|
auto peerIt = enforceLists(query.peerId);
|
||||||
if (peerIt == _lists.end()) {
|
|
||||||
peerIt = _lists.emplace(query.peerId, Lists {}).first;
|
|
||||||
}
|
|
||||||
auto index = static_cast<int>(query.type);
|
auto index = static_cast<int>(query.type);
|
||||||
peerIt->second[index].addSlice(std::move(query.messageIds), query.noSkipRange, query.count);
|
peerIt->second[index].addSlice(std::move(query.messageIds), query.noSkipRange, query.count);
|
||||||
}
|
}
|
||||||
|
@ -265,6 +292,7 @@ void SharedMedia::remove(SharedMediaRemoveOne &&query) {
|
||||||
auto type = static_cast<SharedMediaType>(index);
|
auto type = static_cast<SharedMediaType>(index);
|
||||||
if (query.types.test(type)) {
|
if (query.types.test(type)) {
|
||||||
peerIt->second[index].removeOne(query.messageId);
|
peerIt->second[index].removeOne(query.messageId);
|
||||||
|
oneRemoved.notify(query, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -276,16 +304,17 @@ void SharedMedia::remove(SharedMediaRemoveAll &&query) {
|
||||||
for (auto index = 0; index != kSharedMediaTypeCount; ++index) {
|
for (auto index = 0; index != kSharedMediaTypeCount; ++index) {
|
||||||
peerIt->second[index].removeAll();
|
peerIt->second[index].removeAll();
|
||||||
}
|
}
|
||||||
|
allRemoved.notify(query, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SharedMedia::query(
|
void SharedMedia::query(
|
||||||
const SharedMediaQuery &query,
|
const SharedMediaQuery &query,
|
||||||
base::lambda_once<void(SharedMediaResult&&)> &&callback) {
|
base::lambda_once<void(SharedMediaResult&&)> &&callback) {
|
||||||
Expects(IsValidSharedMediaType(query.type));
|
Expects(IsValidSharedMediaType(query.key.type));
|
||||||
auto peerIt = _lists.find(query.peerId);
|
auto peerIt = _lists.find(query.key.peerId);
|
||||||
if (peerIt != _lists.end()) {
|
if (peerIt != _lists.end()) {
|
||||||
auto index = static_cast<int>(query.type);
|
auto index = static_cast<int>(query.key.type);
|
||||||
peerIt->second[index].query(query, std::move(callback));
|
peerIt->second[index].query(query, std::move(callback));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,25 +122,44 @@ struct SharedMediaRemoveAll {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SharedMediaQuery {
|
struct SharedMediaKey {
|
||||||
SharedMediaQuery(
|
SharedMediaKey(
|
||||||
PeerId peerId,
|
PeerId peerId,
|
||||||
SharedMediaType type,
|
SharedMediaType type,
|
||||||
MsgId messageId,
|
MsgId messageId)
|
||||||
int limitBefore,
|
|
||||||
int limitAfter)
|
|
||||||
: peerId(peerId)
|
: peerId(peerId)
|
||||||
, messageId(messageId)
|
, type(type)
|
||||||
, limitBefore(limitBefore)
|
, messageId(messageId) {
|
||||||
, limitAfter(limitAfter)
|
}
|
||||||
, type(type) {
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
PeerId peerId = 0;
|
PeerId peerId = 0;
|
||||||
|
SharedMediaType type = SharedMediaType::kCount;
|
||||||
MsgId messageId = 0;
|
MsgId messageId = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SharedMediaQuery {
|
||||||
|
SharedMediaQuery(
|
||||||
|
SharedMediaKey key,
|
||||||
|
int limitBefore,
|
||||||
|
int limitAfter)
|
||||||
|
: key(key)
|
||||||
|
, limitBefore(limitBefore)
|
||||||
|
, limitAfter(limitAfter) {
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedMediaKey key;
|
||||||
int limitBefore = 0;
|
int limitBefore = 0;
|
||||||
int limitAfter = 0;
|
int limitAfter = 0;
|
||||||
SharedMediaType type = SharedMediaType::kCount;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -148,10 +167,31 @@ struct SharedMediaResult {
|
||||||
base::optional<int> count;
|
base::optional<int> count;
|
||||||
base::optional<int> skippedBefore;
|
base::optional<int> skippedBefore;
|
||||||
base::optional<int> skippedAfter;
|
base::optional<int> skippedAfter;
|
||||||
std::vector<MsgId> messageIds;
|
base::flat_set<MsgId> messageIds;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SharedMedia {
|
struct SharedMediaSliceUpdate {
|
||||||
|
SharedMediaSliceUpdate(
|
||||||
|
PeerId peerId,
|
||||||
|
SharedMediaType type,
|
||||||
|
const base::flat_set<MsgId> *messages,
|
||||||
|
MsgRange range,
|
||||||
|
base::optional<int> count)
|
||||||
|
: peerId(peerId)
|
||||||
|
, type(type)
|
||||||
|
, messages(messages)
|
||||||
|
, range(range)
|
||||||
|
, count(count) {
|
||||||
|
}
|
||||||
|
|
||||||
|
PeerId peerId = 0;
|
||||||
|
SharedMediaType type = SharedMediaType::kCount;
|
||||||
|
const base::flat_set<MsgId> *messages = nullptr;
|
||||||
|
MsgRange range;
|
||||||
|
base::optional<int> count;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SharedMedia : private base::Subscriber {
|
||||||
public:
|
public:
|
||||||
using Type = SharedMediaType;
|
using Type = SharedMediaType;
|
||||||
|
|
||||||
|
@ -164,6 +204,10 @@ public:
|
||||||
const SharedMediaQuery &query,
|
const SharedMediaQuery &query,
|
||||||
base::lambda_once<void(SharedMediaResult&&)> &&callback);
|
base::lambda_once<void(SharedMediaResult&&)> &&callback);
|
||||||
|
|
||||||
|
base::Observable<SharedMediaSliceUpdate> sliceUpdated;
|
||||||
|
base::Observable<SharedMediaRemoveOne> oneRemoved;
|
||||||
|
base::Observable<SharedMediaRemoveAll> allRemoved;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class List {
|
class List {
|
||||||
public:
|
public:
|
||||||
|
@ -179,6 +223,13 @@ private:
|
||||||
const SharedMediaQuery &query,
|
const SharedMediaQuery &query,
|
||||||
base::lambda_once<void(SharedMediaResult&&)> &&callback);
|
base::lambda_once<void(SharedMediaResult&&)> &&callback);
|
||||||
|
|
||||||
|
struct SliceUpdate {
|
||||||
|
const base::flat_set<MsgId> *messages = nullptr;
|
||||||
|
MsgRange range;
|
||||||
|
base::optional<int> count;
|
||||||
|
};
|
||||||
|
base::Observable<SliceUpdate> sliceUpdated;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Slice {
|
struct Slice {
|
||||||
Slice(base::flat_set<MsgId> &&messages, MsgRange range);
|
Slice(base::flat_set<MsgId> &&messages, MsgRange range);
|
||||||
|
@ -197,20 +248,23 @@ private:
|
||||||
|
|
||||||
template <typename Range>
|
template <typename Range>
|
||||||
int uniteAndAdd(
|
int uniteAndAdd(
|
||||||
|
SliceUpdate &update,
|
||||||
base::flat_set<Slice>::iterator uniteFrom,
|
base::flat_set<Slice>::iterator uniteFrom,
|
||||||
base::flat_set<Slice>::iterator uniteTill,
|
base::flat_set<Slice>::iterator uniteTill,
|
||||||
const Range &messages,
|
const Range &messages,
|
||||||
MsgRange noSkipRange);
|
MsgRange noSkipRange);
|
||||||
template <typename Range>
|
template <typename Range>
|
||||||
int addRangeItemsAndCount(
|
int addRangeItemsAndCount(
|
||||||
|
SliceUpdate &update,
|
||||||
const Range &messages,
|
const Range &messages,
|
||||||
MsgRange noSkipRange,
|
MsgRange noSkipRange,
|
||||||
base::optional<int> count);
|
base::optional<int> count);
|
||||||
template <typename Range>
|
template <typename Range>
|
||||||
int addRange(
|
void addRange(
|
||||||
const Range &messages,
|
const Range &messages,
|
||||||
MsgRange noSkipRange,
|
MsgRange noSkipRange,
|
||||||
base::optional<int> count);
|
base::optional<int> count,
|
||||||
|
bool incrementCount = false);
|
||||||
|
|
||||||
SharedMediaResult queryFromSlice(
|
SharedMediaResult queryFromSlice(
|
||||||
const SharedMediaQuery &query,
|
const SharedMediaQuery &query,
|
||||||
|
@ -220,8 +274,11 @@ private:
|
||||||
base::flat_set<Slice> _slices;
|
base::flat_set<Slice> _slices;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
using SliceUpdate = List::SliceUpdate;
|
||||||
using Lists = std::array<List, kSharedMediaTypeCount>;
|
using Lists = std::array<List, kSharedMediaTypeCount>;
|
||||||
|
|
||||||
|
std::map<PeerId, Lists>::iterator enforceLists(PeerId peerId);
|
||||||
|
|
||||||
std::map<PeerId, Lists> _lists;
|
std::map<PeerId, Lists> _lists;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -186,6 +186,8 @@
|
||||||
<(src_loc)/history/history_service.h
|
<(src_loc)/history/history_service.h
|
||||||
<(src_loc)/history/history_service_layout.cpp
|
<(src_loc)/history/history_service_layout.cpp
|
||||||
<(src_loc)/history/history_service_layout.h
|
<(src_loc)/history/history_service_layout.h
|
||||||
|
<(src_loc)/history/history_shared_media.cpp
|
||||||
|
<(src_loc)/history/history_shared_media.h
|
||||||
<(src_loc)/history/history_widget.cpp
|
<(src_loc)/history/history_widget.cpp
|
||||||
<(src_loc)/history/history_widget.h
|
<(src_loc)/history/history_widget.h
|
||||||
<(src_loc)/inline_bots/inline_bot_layout_internal.cpp
|
<(src_loc)/inline_bots/inline_bot_layout_internal.cpp
|
||||||
|
|
Loading…
Reference in New Issue