Add Storage::UserPhotos and UserPhotosSlice.

This commit is contained in:
John Preston 2017-08-29 22:52:52 +03:00
parent 68a0e32a3d
commit 2690618da2
17 changed files with 1008 additions and 384 deletions

View File

@ -37,6 +37,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "chat_helpers/stickers.h"
#include "storage/storage_facade.h"
#include "storage/storage_shared_media.h"
#include "storage/storage_user_photos.h"
namespace {
@ -48,7 +49,7 @@ constexpr auto kStickersUpdateTimeout = 3600000; // update not more than once in
constexpr auto kUnreadMentionsPreloadIfLess = 5;
constexpr auto kUnreadMentionsFirstRequestLimit = 10;
constexpr auto kUnreadMentionsNextRequestLimit = 100;
constexpr auto kSharedMediaLimit = 10;
constexpr auto kSharedMediaLimit = 100;
} // namespace
@ -1963,7 +1964,6 @@ void ApiWrap::requestSharedMedia(
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,
@ -1992,7 +1992,6 @@ void ApiWrap::sharedMediaDone(
MsgId messageId,
SliceType slice,
const MTPmessages_Messages &result) {
auto fullCount = 0;
auto &messages = *[&] {
switch (result.type()) {
@ -2064,4 +2063,65 @@ void ApiWrap::sharedMediaDone(
));
}
void ApiWrap::requestUserPhotos(
not_null<UserData*> user,
PhotoId afterId) {
if (_userPhotosRequests.contains(user)) {
return;
}
auto limit = kSharedMediaLimit;
auto requestId = request(MTPphotos_GetUserPhotos(
user->inputUser,
MTP_int(0),
MTP_long(afterId),
MTP_int(limit)
)).done([this, user, afterId](const MTPphotos_Photos &result) {
_userPhotosRequests.remove(user);
userPhotosDone(user, afterId, result);
}).fail([this, user](const RPCError &error) {
_userPhotosRequests.remove(user);
}).send();
_userPhotosRequests.emplace(user, requestId);
}
void ApiWrap::userPhotosDone(
not_null<UserData*> user,
PhotoId photoId,
const MTPphotos_Photos &result) {
auto fullCount = 0;
auto &photos = *[&] {
switch (result.type()) {
case mtpc_photos_photos: {
auto &d = result.c_photos_photos();
App::feedUsers(d.vusers);
fullCount = d.vphotos.v.size();
return &d.vphotos.v;
} break;
case mtpc_photos_photosSlice: {
auto &d = result.c_photos_photosSlice();
App::feedUsers(d.vusers);
fullCount = d.vcount.v;
return &d.vphotos.v;
} break;
}
Unexpected("photos.Photos type in userPhotosDone()");
}();
auto photoIds = std::vector<PhotoId>();
photoIds.reserve(photos.size());
for (auto &photo : photos) {
if (auto photoData = App::feedPhoto(photo)) {
photoIds.push_back(photoData->id);
}
}
Auth().storage().add(Storage::UserPhotosAddSlice(
user->id,
std::move(photoIds),
fullCount
));
}
ApiWrap::~ApiWrap() = default;

View File

@ -128,6 +128,10 @@ public:
requestSharedMedia(peer, type, 0, SliceType::Before);
}
void requestUserPhotos(
not_null<UserData*> user,
PhotoId afterId);
~ApiWrap();
private:
@ -181,6 +185,11 @@ private:
SliceType slice,
const MTPmessages_Messages &result);
void userPhotosDone(
not_null<UserData*> user,
PhotoId photoId,
const MTPphotos_Photos &result);
not_null<AuthSession*> _session;
mtpRequestId _changelogSubscription = 0;
@ -249,6 +258,8 @@ private:
MsgId,
SliceType>, mtpRequestId> _sharedMediaRequests;
base::flat_map<not_null<UserData*>, mtpRequestId> _userPhotosRequests;
base::Observable<PeerData*> _fullPeerUpdated;
};

View File

@ -43,24 +43,6 @@ inline MediaOverviewType SharedMediaTypeToOverview(Type type) {
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
base::optional<Storage::SharedMediaType> SharedMediaOverviewType(
@ -133,7 +115,7 @@ QString SharedMediaSlice::debug() const {
? QString::number((*this)[0]) + " .. " + QString::number((*this)[size() - 1])
: (size() > 1)
? QString::number((*this)[0]) + ' ' + QString::number((*this)[1])
: ((size() > 0) ? QString((*this)[0]) : QString());
: ((size() > 0) ? QString::number((*this)[0]) : QString());
return before + middle + after;
}

View File

@ -21,7 +21,6 @@ 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(
@ -102,8 +101,6 @@ private:
Key _key;
int _limitBefore = 0;
int _limitAfter = 0;
mtpRequestId _beforeRequestId = 0;
mtpRequestId _afterRequestId = 0;
SharedMediaSlice _data;
};

View File

@ -0,0 +1,189 @@
/*
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_user_photos.h"
#include "auth_session.h"
#include "apiwrap.h"
#include "storage/storage_facade.h"
#include "storage/storage_user_photos.h"
UserPhotosSlice::UserPhotosSlice(Key key) : UserPhotosSlice(key, base::none) {
}
UserPhotosSlice::UserPhotosSlice(
Key key,
base::optional<int> fullCount)
: _key(key)
, _fullCount(fullCount) {
}
base::optional<int> UserPhotosSlice::indexOf(PhotoId photoId) const {
auto it = base::find(_ids, photoId);
if (it != _ids.end()) {
return (it - _ids.begin());
}
return base::none;
}
PhotoId UserPhotosSlice::operator[](int index) const {
Expects(index >= 0 && index < size());
return *(_ids.begin() + index);
}
base::optional<int> UserPhotosSlice::distance(const Key &a, const Key &b) const {
if (a.userId != _key.userId
|| b.userId != _key.userId) {
return base::none;
}
if (auto i = indexOf(a.photoId)) {
if (auto j = indexOf(b.photoId)) {
return *j - *i;
}
}
return base::none;
}
QString UserPhotosSlice::debug() const {
auto before = _skippedBefore
? (*_skippedBefore
? ('(' + QString::number(*_skippedBefore) + ").. ")
: QString())
: QString(".. ");
auto after = _skippedAfter
? (" ..(" + QString::number(_skippedAfter) + ')')
: QString(" ..");
auto middle = (size() > 2)
? QString::number((*this)[0]) + " .. " + QString::number((*this)[size() - 1])
: (size() > 1)
? QString::number((*this)[0]) + ' ' + QString::number((*this)[1])
: ((size() > 0) ? QString::number((*this)[0]) : QString());
return before + middle + after;
}
UserPhotosViewer::UserPhotosViewer(
Key key,
int limitBefore,
int limitAfter)
: _key(key)
, _limitBefore(limitBefore)
, _limitAfter(limitAfter)
, _data(_key) {
}
void UserPhotosViewer::start() {
auto applyUpdateCallback = [this](auto &update) {
this->applyUpdate(update);
};
subscribe(Auth().storage().userPhotosSliceUpdated(), applyUpdateCallback);
loadInitial();
}
void UserPhotosViewer::loadInitial() {
auto weak = base::make_weak_unique(this);
Auth().storage().query(Storage::UserPhotosQuery(
_key,
_limitBefore,
_limitAfter), [weak](Storage::UserPhotosResult &&result) {
if (weak) {
weak->applyStoredResult(std::move(result));
}
});
}
void UserPhotosViewer::applyStoredResult(Storage::UserPhotosResult &&result) {
mergeSliceData(
result.count,
result.photoIds,
result.skippedBefore,
result.skippedAfter);
}
void UserPhotosViewer::mergeSliceData(
base::optional<int> count,
const std::deque<PhotoId> &photoIds,
base::optional<int> skippedBefore,
int skippedAfter) {
if (photoIds.empty()) {
if (_data._fullCount != count) {
_data._fullCount = count;
if (_data._fullCount && *_data._fullCount <= _data.size()) {
_data._fullCount = _data.size();
_data._skippedBefore = _data._skippedAfter = 0;
}
updated.notify(_data);
}
sliceToLimits();
return;
}
if (count) {
_data._fullCount = count;
}
_data._skippedAfter = skippedAfter;
_data._ids = photoIds;
if (_data._fullCount) {
_data._skippedBefore = *_data._fullCount
- _data._skippedAfter
- int(_data._ids.size());
}
sliceToLimits();
updated.notify(_data);
}
void UserPhotosViewer::applyUpdate(const SliceUpdate &update) {
if (update.userId != _key.userId) {
return;
}
auto idsCount = update.photoIds ? int(update.photoIds->size()) : 0;
mergeSliceData(
update.count,
update.photoIds ? *update.photoIds : std::deque<PhotoId> {},
update.count | func::add(-idsCount),
0);
}
void UserPhotosViewer::sliceToLimits() {
auto aroundIt = base::find(_data._ids, _key.photoId);
auto removeFromBegin = (aroundIt - _data._ids.begin() - _limitBefore);
auto removeFromEnd = (_data._ids.end() - aroundIt - _limitAfter - 1);
if (removeFromEnd > 0) {
_data._ids.erase(_data._ids.end() - removeFromEnd, _data._ids.end());
_data._skippedAfter += removeFromEnd;
}
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)) {
requestPhotos();
}
}
void UserPhotosViewer::requestPhotos() {
Auth().api().requestUserPhotos(
App::user(_key.userId),
_data._ids.empty() ? 0 : _data._ids.front());
}

View File

@ -0,0 +1,90 @@
/*
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_user_photos.h"
#include "base/weak_unique_ptr.h"
class UserPhotosViewer;
class UserPhotosSlice {
public:
using Key = Storage::UserPhotosKey;
UserPhotosSlice(Key key);
UserPhotosSlice(Key key, base::optional<int> fullCount);
const Key &key() const { return _key; }
base::optional<int> fullCount() const { return _fullCount; }
base::optional<int> skippedBefore() const { return _skippedBefore; }
int skippedAfter() const { return _skippedAfter; }
base::optional<int> indexOf(PhotoId msgId) const;
int size() const { return _ids.size(); }
PhotoId operator[](int index) const;
base::optional<int> distance(const Key &a, const Key &b) const;
QString debug() const;
private:
Key _key;
std::deque<PhotoId> _ids;
base::optional<int> _fullCount;
base::optional<int> _skippedBefore;
int _skippedAfter = 0;
friend class UserPhotosViewer;
};
class UserPhotosViewer :
private base::Subscriber,
public base::enable_weak_from_this {
public:
using Key = Storage::UserPhotosKey;
UserPhotosViewer(Key key, int limitBefore, int limitAfter);
void start();
base::Observable<UserPhotosSlice> updated;
private:
using InitialResult = Storage::UserPhotosResult;
using SliceUpdate = Storage::UserPhotosSliceUpdate;
void loadInitial();
void requestPhotos();
void applyStoredResult(InitialResult &&result);
void applyUpdate(const SliceUpdate &update);
void sliceToLimits();
void mergeSliceData(
base::optional<int> count,
const std::deque<PhotoId> &photoIds,
base::optional<int> skippedBefore,
int skippedAfter);
Key _key;
int _limitBefore = 0;
int _limitAfter = 0;
UserPhotosSlice _data;
};

View File

@ -77,6 +77,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "auth_session.h"
#include "storage/storage_facade.h"
#include "storage/storage_shared_media.h"
#include "storage/storage_user_photos.h"
namespace {
@ -969,13 +970,8 @@ void MainWidget::deletePhotoLayer(PhotoData *photo) {
} else if (photo->peer && !photo->peer->isUser() && photo->peer->photoId == photo->id) {
Messenger::Instance().peerClearPhoto(photo->peer->id);
} else {
for (int i = 0, l = me->photos.size(); i != l; ++i) {
if (me->photos.at(i) == photo) {
me->photos.removeAt(i);
MTP::send(MTPphotos_DeletePhotos(MTP_vector<MTPInputPhoto>(1, MTP_inputPhoto(MTP_long(photo->id), MTP_long(photo->access)))));
break;
}
}
MTP::send(MTPphotos_DeletePhotos(MTP_vector<MTPInputPhoto>(1, MTP_inputPhoto(MTP_long(photo->id), MTP_long(photo->access)))));
Auth().storage().remove(Storage::UserPhotosRemoveOne(me->bareId(), photo->id));
}
})));
}
@ -5091,19 +5087,17 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
if (auto user = App::userLoaded(d.vuser_id.v)) {
user->setPhoto(d.vphoto);
user->loadUserpic();
if (mtpIsTrue(d.vprevious)) {
user->photosCount = -1;
user->photos.clear();
if (mtpIsTrue(d.vprevious)
|| !user->photoId
|| user->photoId == UnknownPeerPhotoId) {
Auth().storage().remove(Storage::UserPhotosRemoveAfter(
user->bareId(),
user->photoId));
} else {
if (user->photoId && user->photoId != UnknownPeerPhotoId) {
if (user->photosCount > 0) ++user->photosCount;
user->photos.push_front(App::photo(user->photoId));
} else {
user->photosCount = -1;
user->photos.clear();
}
Auth().storage().add(Storage::UserPhotosAddNew(
user->bareId(),
user->photoId));
}
Notify::mediaOverviewUpdated(user, OverviewCount);
}
} break;

View File

@ -77,6 +77,16 @@ struct MediaView::SharedMedia {
SharedMediaViewerWithLast slice;
};
struct MediaView::UserPhotos {
UserPhotos(UserPhotosViewer::Key key)
: key(key)
, slice(key, kIdsLimit, kIdsLimit) {
}
UserPhotosViewer::Key key;
UserPhotosViewer slice;
};
MediaView::MediaView() : TWidget(nullptr)
, _transparentBrush(style::transparentPlaceholderBrush())
, _animStarted(getms())
@ -121,6 +131,7 @@ MediaView::MediaView() : TWidget(nullptr)
});
} else {
_sharedMedia = nullptr;
_userPhotos = nullptr;
}
};
subscribe(Messenger::Instance().authSessionChanged(), [handleAuthSessionChange] {
@ -192,33 +203,6 @@ void MediaView::moveToScreen() {
_saveMsg.moveTo((width() - _saveMsg.width()) / 2, (height() - _saveMsg.height()) / 2);
}
void MediaView::handleSharedMediaUpdate(const SharedMediaSliceWithLast &update) {
if (isHidden() || (!_photo && !_doc) || !_sharedMedia) {
_index = _fullIndex = _fullCount = base::none;
return;
}
_sharedMediaData = update;
findCurrent();
updateControls();
preloadData(0);
//if (_user == update.peer && update.mediaTypesMask & (1 << OverviewCount)) {
// if (!_photo) return;
// _index = -1;
// for (int i = 0, l = _user->photos.size(); i < l; ++i) {
// if (_user->photos[i] == _photo) {
// _index = i;
// break;
// }
// }
// updateControls();
// preloadData(0);
//} // TODO user
}
bool MediaView::fileShown() const {
return !_current.isNull() || gifShown();
}
@ -267,7 +251,7 @@ void MediaView::documentUpdated(DocumentData *doc) {
void MediaView::changingMsgId(not_null<HistoryItem*> row, MsgId newId) {
if (row->fullId() == _msgid) {
_msgid = FullMsgId(_msgid.channel, newId);
refreshSharedMedia();
refreshMediaViewer();
}
}
@ -308,11 +292,13 @@ void MediaView::refreshNavVisibility() {
if (_sharedMediaData) {
_leftNavVisible = _index && (*_index > 0);
_rightNavVisible = _index && (*_index + 1 < _sharedMediaData->size());
} else if (_userPhotosData) {
_leftNavVisible = _index && (*_index > 0);
_rightNavVisible = _index && (*_index + 1 < _userPhotosData->size());
} else {
_leftNavVisible = false;
_rightNavVisible = false;
}
// TODO user
}
void MediaView::updateControls() {
@ -408,10 +394,24 @@ void MediaView::updateActions() {
if ((_doc && fileShown()) || (_photo && _photo->loaded())) {
_actions.push_back({ lang(lng_mediaview_copy), SLOT(onCopy()) });
}
if (_canForward) {
if (_canForwardItem) {
_actions.push_back({ lang(lng_mediaview_forward), SLOT(onForward()) });
}
if (_canDelete || (_photo && App::self() && _user == App::self()) || (_photo && _photo->peer && _photo->peer->photoId == _photo->id && (_photo->peer->isChat() || (_photo->peer->isChannel() && _photo->peer->asChannel()->amCreator())))) {
auto canDelete = [&] {
if (_canDeleteItem) {
return true;
} else if (!_msgid && _photo && App::self() && _user == App::self()) {
return _userPhotosData && _fullIndex && _fullCount;
} else if (_photo && _photo->peer && _photo->peer->photoId == _photo->id) {
if (auto chat = _photo->peer->asChat()) {
return chat->canEdit();
} else if (auto channel = _photo->peer->asChannel()) {
return channel->canEditInformation();
}
}
return false;
}();
if (canDelete) {
_actions.push_back({ lang(lng_mediaview_delete), SLOT(onDelete()) });
}
_actions.push_back({ lang(lng_mediaview_save_as), SLOT(onSaveAs()) });
@ -652,6 +652,9 @@ void MediaView::updateMixerVideoVolume() const {
void MediaView::close() {
_sharedMedia = nullptr;
_sharedMediaData = base::none;
_userPhotos = nullptr;
_userPhotosData = base::none;
if (_menu) _menu->hideMenu(true);
Messenger::Instance().hideMediaView();
}
@ -1071,10 +1074,80 @@ void MediaView::validateSharedMedia() {
}
}
void MediaView::refreshSharedMedia() {
void MediaView::handleSharedMediaUpdate(const SharedMediaSliceWithLast &update) {
if (isHidden() || (!_photo && !_doc) || !_sharedMedia) {
_sharedMediaData = base::none;
} else {
_sharedMediaData = update;
}
findCurrent();
updateControls();
preloadData(0);
}
base::optional<MediaView::UserPhotosKey> MediaView::userPhotosKey() const {
if (!_msgid && _user && _photo) {
return UserPhotosKey {
_user->bareId(),
_photo->id
};
}
return base::none;
}
bool MediaView::validUserPhotos() const {
if (auto key = userPhotosKey()) {
if (!_userPhotos) {
return false;
}
auto countDistanceInData = [](const auto &a, const auto &b) {
return [&](const UserPhotosSlice &data) {
return data.distance(a, b);
};
};
auto distance = (key == _userPhotos->key) ? 0 :
_userPhotosData
| countDistanceInData(*key, _userPhotos->key)
| func::abs;
if (distance) {
return (*distance < kIdsPreloadAfter);
}
}
return (_userPhotos == nullptr);
}
void MediaView::validateUserPhotos() {
if (auto key = userPhotosKey()) {
_userPhotos = std::make_unique<UserPhotos>(*key);
subscribe(_userPhotos->slice.updated, [this](const UserPhotosSlice &data) {
handleUserPhotosUpdate(data);
});
_userPhotos->slice.start();
} else {
_userPhotos = nullptr;
_userPhotosData = base::none;
}
}
void MediaView::handleUserPhotosUpdate(const UserPhotosSlice &update) {
if (isHidden() || !_photo || !_userPhotos) {
_userPhotosData = base::none;
} else {
_userPhotosData = update;
}
findCurrent();
updateControls();
preloadData(0);
}
void MediaView::refreshMediaViewer() {
if (!validSharedMedia()) {
validateSharedMedia();
}
if (!validUserPhotos()) {
validateUserPhotos();
}
findCurrent();
updateControls();
preloadData(0);
@ -1098,7 +1171,7 @@ void MediaView::showPhoto(not_null<PhotoData*> photo, HistoryItem *context) {
_photo = photo;
refreshSharedMedia();
refreshMediaViewer();
displayPhoto(photo, context);
preloadData(0);
@ -1121,22 +1194,8 @@ void MediaView::showPhoto(not_null<PhotoData*> photo, not_null<PeerData*> contex
_photo = photo;
refreshSharedMedia();
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;
// }
//}
refreshMediaViewer();
//if (_user->photosCount < 0) {
// loadBack();
//} // TODO user
}
displayPhoto(photo, 0);
preloadData(0);
activateControls();
@ -1178,7 +1237,7 @@ void MediaView::displayPhoto(not_null<PhotoData*> photo, HistoryItem *item) {
_photo = photo;
_radial.stop();
refreshSharedMedia();
refreshMediaViewer();
_photoRadialRect = QRect(QPoint((width() - st::radialSize.width()) / 2, (height() - st::radialSize.height()) / 2), st::radialSize);
@ -1253,7 +1312,7 @@ void MediaView::displayDocument(DocumentData *doc, HistoryItem *item) { // empty
_photo = nullptr;
_radial.stop();
refreshSharedMedia();
refreshMediaViewer();
if (_autoplayVideoDocument && _doc != _autoplayVideoDocument) {
_autoplayVideoDocument = nullptr;
@ -2146,8 +2205,25 @@ void MediaView::setZoomLevel(int newZoom) {
update();
}
MediaView::Entity MediaView::entityForSharedMediaValue(
SharedMediaSliceWithLast::Value value) const {
MediaView::Entity MediaView::entityForUserPhotos(int index) const {
Expects(!!_userPhotosData);
if (index < 0 || index >= _userPhotosData->size()) {
return { base::none, nullptr };
}
if (auto photo = App::photo((*_userPhotosData)[index])) {
return { photo, nullptr };
}
return { base::none, nullptr };
}
MediaView::Entity MediaView::entityForSharedMedia(int index) const {
Expects(!!_sharedMediaData);
if (index < 0 || index >= _sharedMediaData->size()) {
return { base::none, nullptr };
}
auto value = (*_sharedMediaData)[index];
if (auto photo = base::get_if<not_null<PhotoData*>>(&value)) {
// Last peer photo.
return { *photo, nullptr };
@ -2171,23 +2247,32 @@ MediaView::Entity MediaView::entityForSharedMediaValue(
return { base::none, nullptr };
}
MediaView::Entity MediaView::entityByIndex(int index) const {
if (_sharedMediaData) {
return entityForSharedMedia(index);
} else if (_userPhotosData) {
return entityForUserPhotos(index);
}
return { base::none, nullptr };
}
void MediaView::setContext(base::optional_variant<
not_null<HistoryItem*>,
not_null<PeerData*>> context) {
if (auto item = base::get_if<not_null<HistoryItem*>>(&context)) {
_msgid = (*item)->fullId();
_canForward = (*item)->canForward();
_canDelete = (*item)->canDelete();
_canForwardItem = (*item)->canForward();
_canDeleteItem = (*item)->canDelete();
_history = (*item)->history();
_peer = _history->peer;
} else if (auto peer = base::get_if<not_null<PeerData*>>(&context)) {
_msgid = FullMsgId();
_canForward = _canDelete = false;
_canForwardItem = _canDeleteItem = false;
_history = App::history(*peer);
_peer = *peer;
} else {
_msgid = FullMsgId();
_canForward = _canDelete = false;
_canForwardItem = _canDeleteItem = false;
_history = nullptr;
_peer = nullptr;
}
@ -2208,10 +2293,7 @@ bool MediaView::moveToNext(int32 delta) {
return false;
}
auto newIndex = *_index + delta;
if (newIndex < 0 || newIndex >= _sharedMediaData->size()) {
return false;
}
auto entity = entityForSharedMediaValue((*_sharedMediaData)[newIndex]);
auto entity = entityByIndex(*_index + delta);
if (!entity.data && !entity.item) {
return false;
}
@ -2233,94 +2315,6 @@ bool MediaView::moveToNext(int32 delta) {
}
preloadData(delta);
return true;
//if (_index < 0) { // TODO chat
// 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;
//}
//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;
}
void MediaView::preloadData(int32 delta) {
@ -2332,47 +2326,26 @@ void MediaView::preloadData(int32 delta) {
if (from > till) std::swap(from, till);
auto forgetIndex = *_index - delta * 2;
if (forgetIndex >= 0 && forgetIndex < _sharedMediaData->size()) {
auto entity = entityForSharedMediaValue((*_sharedMediaData)[forgetIndex]);
if (auto photo = base::get_if<not_null<PhotoData*>>(&entity.data)) {
(*photo)->forget();
} else if (auto document = base::get_if<not_null<DocumentData*>>(&entity.data)) {
(*document)->forget();
}
auto entity = entityByIndex(forgetIndex);
if (auto photo = base::get_if<not_null<PhotoData*>>(&entity.data)) {
(*photo)->forget();
} else if (auto document = base::get_if<not_null<DocumentData*>>(&entity.data)) {
(*document)->forget();
}
for (auto index = from; index != till; ++index) {
if (index >= 0 && index < _sharedMediaData->size()) {
auto entity = entityForSharedMediaValue((*_sharedMediaData)[index]);
if (auto photo = base::get_if<not_null<PhotoData*>>(&entity.data)) {
(*photo)->download();
} else if (auto document = base::get_if<not_null<DocumentData*>>(&entity.data)) {
if (auto sticker = (*document)->sticker()) {
sticker->img->load();
} else {
(*document)->thumb->load();
(*document)->automaticLoad(entity.item);
}
auto entity = entityByIndex(index);
if (auto photo = base::get_if<not_null<PhotoData*>>(&entity.data)) {
(*photo)->download();
} else if (auto document = base::get_if<not_null<DocumentData*>>(&entity.data)) {
if (auto sticker = (*document)->sticker()) {
sticker->img->load();
} else {
(*document)->thumb->load();
(*document)->automaticLoad(entity.item);
}
}
}
//} else if (_user) {
// for (int32 i = from; i <= to; ++i) {
// 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) {
// _user->photos[i]->download();
// }
// }
// int32 forgetIndex = indexInOverview - delta * 2;
// if (forgetIndex >= 0 && forgetIndex < _user->photos.size() && forgetIndex != indexInOverview) {
// _user->photos[forgetIndex]->forget();
// }
//} // TODO user
}
void MediaView::mousePressEvent(QMouseEvent *e) {
@ -2802,128 +2775,28 @@ void MediaView::updateImage() {
}
void MediaView::findCurrent() {
if (!_sharedMediaData) {
_index = _fullIndex = _fullCount = base::none;
return;
}
_index = _msgid
? _sharedMediaData->indexOf(_msgid)
: _photo ? _sharedMediaData->indexOf(_photo) : base::none;
if (_index && _sharedMediaData->skippedBefore()) {
_fullIndex = (*_index + *_sharedMediaData->skippedBefore());
if (_sharedMediaData) {
_index = _msgid
? _sharedMediaData->indexOf(_msgid)
: _photo ? _sharedMediaData->indexOf(_photo) : base::none;
_fullIndex = _sharedMediaData->skippedBefore()
? (_index | func::add(*_sharedMediaData->skippedBefore()))
: base::none;
_fullCount = _sharedMediaData->fullCount();
} else if (_userPhotosData) {
_index = _photo ? _userPhotosData->indexOf(_photo->id) : base::none;
_fullIndex = _userPhotosData->skippedBefore()
? (_index | func::add(*_userPhotosData->skippedBefore()))
: base::none;
_fullCount = _userPhotosData->fullCount();
} else {
_fullIndex = base::none;
_index = _fullIndex = _fullCount = base::none;
}
_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() {
//if (_loadRequest || (_overview == OverviewCount && !_user)) {
// return;
//}
//if (_index < 0 && (!_additionalChatPhoto || _photo != _additionalChatPhoto || !_history)) {
// return;
//}
//if (_history && _overview != OverviewCount && (!_history->overviewLoaded(_overview) || (_migrated && !_migrated->overviewLoaded(_overview)))) {
// if (App::main()) {
// if (_msgmigrated || (_migrated && _index == 0 && _history->overviewLoaded(_overview))) {
// App::main()->loadMediaBack(_migrated->peer, _overview);
// } else {
// App::main()->loadMediaBack(_history->peer, _overview);
// if (_migrated && _index == 0 && (_migrated->overviewCount(_overview) < 0 || _migrated->overview(_overview).isEmpty()) && !_migrated->overviewLoaded(_overview)) {
// App::main()->loadMediaBack(_migrated->peer, _overview);
// }
// }
// if (_msgmigrated && !_history->overviewCountLoaded(_overview)) {
// App::main()->preloadOverview(_history->peer, _overview);
// }
// }
//} else if (_user && _user->photosCount != 0) {
// 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));
//} // TODO user
}
void MediaView::userPhotosLoaded(UserData *u, const MTPphotos_Photos &photos, mtpRequestId req) {
if (req == _loadRequest) {
_loadRequest = 0;
}
const QVector<MTPPhoto> *v = nullptr;
switch (photos.type()) {
case mtpc_photos_photos: {
auto &d = photos.c_photos_photos();
App::feedUsers(d.vusers);
v = &d.vphotos.v;
u->photosCount = 0;
} break;
case mtpc_photos_photosSlice: {
auto &d = photos.c_photos_photosSlice();
App::feedUsers(d.vusers);
u->photosCount = d.vcount.v;
v = &d.vphotos.v;
} break;
default: return;
}
if (v->isEmpty()) {
u->photosCount = 0;
}
for (auto i = v->cbegin(), e = v->cend(); i != e; ++i) {
auto photo = App::feedPhoto(*i);
photo->thumb->load();
u->photos.push_back(photo);
}
Notify::mediaOverviewUpdated(u, OverviewCount);
}
void MediaView::updateHeader() {
auto index = _fullIndex ? *_fullIndex : -1;
auto count = _fullCount ? *_fullCount : -1;
if (_history) {
} else if (_user) {
count = _user->photosCount ? _user->photosCount : _user->photos.size(); // TODO user
}
if (index >= 0 && index < count && count > 1) {
if (_doc) {
_headerText = lng_mediaview_file_n_of_count(lt_file, _doc->name.isEmpty() ? lang(lng_mediaview_doc_image) : _doc->name, lt_n, QString::number(index + 1), lt_count, QString::number(count));
@ -2959,15 +2832,3 @@ float64 MediaView::overLevel(OverState control) const {
auto i = _animOpacities.constFind(control);
return (i == _animOpacities.cend()) ? (_over == control ? 1 : 0) : i->current();
}
MsgId MediaView::getMsgIdFromOverview(not_null<History*> history, int index) const {
//auto &overview = history->overview(_overview);
//if (index >= 0 && index < overview.size()) {
// auto it = overview.begin();
// for (auto i = 0; i != index; ++i) {
// ++it;
// }
// return *it;
//}
return 0;
}

View File

@ -23,6 +23,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "ui/widgets/dropdown_menu.h"
#include "ui/effects/radial_animation.h"
#include "history/history_shared_media.h"
#include "history/history_user_photos.h"
namespace Media {
namespace Player {
@ -156,7 +157,9 @@ private:
not_null<DocumentData*>> data;
HistoryItem *item;
};
Entity entityForSharedMediaValue(SharedMediaSliceWithLast::Value value) const;
Entity entityForUserPhotos(int index) const;
Entity entityForSharedMedia(int index) const;
Entity entityByIndex(int index) const;
void setContext(base::optional_variant<
not_null<HistoryItem*>,
not_null<PeerData*>> context);
@ -170,11 +173,18 @@ private:
using SharedMediaKey = SharedMediaViewerWithLast::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 validateSharedMedia();
void handleSharedMediaUpdate(const SharedMediaSliceWithLast &update);
struct UserPhotos;
using UserPhotosKey = UserPhotosViewer::Key;
base::optional<UserPhotosKey> userPhotosKey() const;
bool validUserPhotos() const;
void validateUserPhotos();
void handleUserPhotosUpdate(const UserPhotosSlice &update);
void refreshMediaViewer();
void refreshNavVisibility();
void dropdownHidden();
@ -186,7 +196,6 @@ private:
void displayDocument(DocumentData *document, HistoryItem *item);
void displayFinished();
void findCurrent();
void loadBack();
void updateCursor();
void setZoomLevel(int newZoom);
@ -216,8 +225,6 @@ private:
void radialStart();
TimeMs radialTimeShift() const;
void userPhotosLoaded(UserData *u, const MTPphotos_Photos &photos, mtpRequestId req);
void deletePhotosDone(const MTPVector<MTPlong> &result);
bool deletePhotosFail(const RPCError &error);
@ -239,14 +246,14 @@ private:
bool updateOverState(OverState newState);
float64 overLevel(OverState control) const;
MsgId getMsgIdFromOverview(not_null<History*> history, int index) const;
QBrush _transparentBrush;
PhotoData *_photo = nullptr;
DocumentData *_doc = nullptr;
std::unique_ptr<SharedMedia> _sharedMedia;
base::optional<SharedMediaSliceWithLast> _sharedMediaData;
std::unique_ptr<UserPhotos> _userPhotos;
base::optional<UserPhotosSlice> _userPhotosData;
QRect _closeNav, _closeNavIcon;
QRect _leftNav, _leftNavIcon, _rightNav, _rightNavIcon;
@ -325,8 +332,8 @@ private:
base::optional<int> _fullIndex; // Index in full shared media.
base::optional<int> _fullCount;
FullMsgId _msgid;
bool _canForward = false;
bool _canDelete = false;
bool _canForwardItem = false;
bool _canDeleteItem = false;
mtpRequestId _loadRequest = 0;

View File

@ -21,6 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "storage/storage_facade.h"
#include "storage/storage_shared_media.h"
#include "storage/storage_user_photos.h"
namespace Storage {
@ -39,8 +40,19 @@ public:
base::Observable<SharedMediaRemoveOne> &sharedMediaOneRemoved();
base::Observable<SharedMediaRemoveAll> &sharedMediaAllRemoved();
void add(UserPhotosAddNew &&query);
void add(UserPhotosAddSlice &&query);
void remove(UserPhotosRemoveOne &&query);
void remove(UserPhotosRemoveAfter &&query);
void query(
UserPhotosQuery &&query,
base::lambda_once<void(UserPhotosResult&&)> &&callback);
base::Observable<UserPhotosSliceUpdate> &userPhotosSliceUpdated();
private:
SharedMedia _sharedMedia;
UserPhotos _userPhotos;
};
@ -82,6 +94,32 @@ base::Observable<SharedMediaRemoveAll> &Facade::Impl::sharedMediaAllRemoved() {
return _sharedMedia.allRemoved;
}
void Facade::Impl::add(UserPhotosAddNew &&query) {
return _userPhotos.add(std::move(query));
}
void Facade::Impl::add(UserPhotosAddSlice &&query) {
return _userPhotos.add(std::move(query));
}
void Facade::Impl::remove(UserPhotosRemoveOne &&query) {
return _userPhotos.remove(std::move(query));
}
void Facade::Impl::remove(UserPhotosRemoveAfter &&query) {
return _userPhotos.remove(std::move(query));
}
void Facade::Impl::query(
UserPhotosQuery &&query,
base::lambda_once<void(UserPhotosResult&&)> &&callback) {
return _userPhotos.query(std::move(query), std::move(callback));
}
base::Observable<UserPhotosSliceUpdate> &Facade::Impl::userPhotosSliceUpdated() {
return _userPhotos.sliceUpdated;
}
Facade::Facade() : _impl(std::make_unique<Impl>()) {
}
@ -123,6 +161,32 @@ base::Observable<SharedMediaRemoveAll> &Facade::sharedMediaAllRemoved() {
return _impl->sharedMediaAllRemoved();
}
void Facade::add(UserPhotosAddNew &&query) {
return _impl->add(std::move(query));
}
void Facade::add(UserPhotosAddSlice &&query) {
return _impl->add(std::move(query));
}
void Facade::remove(UserPhotosRemoveOne &&query) {
return _impl->remove(std::move(query));
}
void Facade::remove(UserPhotosRemoveAfter &&query) {
return _impl->remove(std::move(query));
}
void Facade::query(
UserPhotosQuery &&query,
base::lambda_once<void(UserPhotosResult&&)> &&callback) {
return _impl->query(std::move(query), std::move(callback));
}
base::Observable<UserPhotosSliceUpdate> &Facade::userPhotosSliceUpdated() {
return _impl->userPhotosSliceUpdated();
}
Facade::~Facade() = default;
} // namespace Storage

View File

@ -33,6 +33,14 @@ struct SharedMediaQuery;
struct SharedMediaResult;
struct SharedMediaSliceUpdate;
struct UserPhotosAddNew;
struct UserPhotosAddSlice;
struct UserPhotosRemoveOne;
struct UserPhotosRemoveAfter;
struct UserPhotosQuery;
struct UserPhotosResult;
struct UserPhotosSliceUpdate;
class Facade {
public:
Facade();
@ -50,6 +58,16 @@ public:
base::Observable<SharedMediaRemoveOne> &sharedMediaOneRemoved();
base::Observable<SharedMediaRemoveAll> &sharedMediaAllRemoved();
void add(UserPhotosAddNew &&query);
void add(UserPhotosAddSlice &&query);
void remove(UserPhotosRemoveOne &&query);
void remove(UserPhotosRemoveAfter &&query);
void query(
UserPhotosQuery &&query,
base::lambda_once<void(UserPhotosResult&&)> &&callback);
base::Observable<UserPhotosSliceUpdate> &userPhotosSliceUpdated();
~Facade();
private:

View File

@ -73,11 +73,10 @@ int SharedMedia::List::uniteAndAdd(
}
template <typename Range>
int SharedMedia::List::addRangeItemsAndCount(
int SharedMedia::List::addRangeItemsAndCountNew(
SliceUpdate &update,
const Range &messages,
MsgRange noSkipRange,
base::optional<int> count) {
MsgRange noSkipRange) {
Expects((noSkipRange.from < noSkipRange.till)
|| (noSkipRange.from == noSkipRange.till && messages.begin() == messages.end()));
if (noSkipRange.from == noSkipRange.till) {
@ -117,7 +116,7 @@ void SharedMedia::List::addRange(
auto wasCount = _count;
auto update = SliceUpdate();
auto result = addRangeItemsAndCount(update, messages, noSkipRange, count);
auto result = addRangeItemsAndCountNew(update, messages, noSkipRange);
if (count) {
_count = count;
} else if (incrementCount && _count && result > 0) {
@ -205,14 +204,7 @@ SharedMediaResult SharedMedia::List::queryFromSlice(
auto haveEqualOrAfter = int(slice.messages.end() - position);
auto before = qMin(haveBefore, query.limitBefore);
auto equalOrAfter = qMin(haveEqualOrAfter, query.limitAfter + 1);
auto ids = std::vector<MsgId>();
ids.reserve(before + equalOrAfter);
for (
auto from = position - before, till = position + equalOrAfter;
from != till;
++from) {
ids.push_back(*from);
}
auto ids = std::vector<MsgId>(position - before, position + equalOrAfter);
result.messageIds.merge(ids.begin(), ids.end());
if (slice.range.from == 0) {
result.skippedBefore = haveBefore - before;

View File

@ -254,11 +254,10 @@ private:
const Range &messages,
MsgRange noSkipRange);
template <typename Range>
int addRangeItemsAndCount(
int addRangeItemsAndCountNew(
SliceUpdate &update,
const Range &messages,
MsgRange noSkipRange,
base::optional<int> count);
MsgRange noSkipRange);
template <typename Range>
void addRange(
const Range &messages,
@ -277,7 +276,7 @@ private:
using SliceUpdate = List::SliceUpdate;
using Lists = std::array<List, kSharedMediaTypeCount>;
std::map<PeerId, Lists>::iterator enforceLists(PeerId peerId);
std::map<PeerId, Lists>::iterator enforceLists(PeerId peer);
std::map<PeerId, Lists> _lists;

View File

@ -0,0 +1,176 @@
/*
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 "storage/storage_user_photos.h"
#include "base/task_queue.h"
namespace Storage {
void UserPhotos::List::addNew(PhotoId photoId) {
if (!base::contains(_photoIds, photoId)) {
_photoIds.push_back(photoId);
if (_count) {
++*_count;
}
sendUpdate();
}
}
void UserPhotos::List::addSlice(
std::vector<PhotoId> &&photoIds,
int count) {
for (auto photoId : photoIds) {
if (!base::contains(_photoIds, photoId)) {
_photoIds.push_front(photoId);
}
}
_count = count;
if ((_count && *_count < _photoIds.size()) || photoIds.empty()) {
_count = _photoIds.size();
}
sendUpdate();
}
void UserPhotos::List::removeOne(PhotoId photoId) {
auto position = base::find(_photoIds, photoId);
if (position == _photoIds.end()) {
_count = base::none;
} else {
if (_count) {
--*_count;
}
_photoIds.erase(position);
}
sendUpdate();
}
void UserPhotos::List::removeAfter(PhotoId photoId) {
auto position = base::find(_photoIds, photoId);
if (position == _photoIds.end()) {
_count = base::none;
_photoIds.clear();
} else {
if (_count) {
*_count -= (_photoIds.end() - position);
}
_photoIds.erase(position, _photoIds.end());
}
sendUpdate();
}
void UserPhotos::List::sendUpdate() {
auto update = SliceUpdate();
update.photoIds = &_photoIds;
update.count = _count;
sliceUpdated.notify(update, true);
}
void UserPhotos::List::query(
const UserPhotosQuery &query,
base::lambda_once<void(UserPhotosResult&&)> &&callback) {
auto result = UserPhotosResult {};
result.count = _count;
auto position = base::find(_photoIds, query.key.photoId);
if (position != _photoIds.end()) {
auto haveBefore = int(position - _photoIds.begin());
auto haveEqualOrAfter = int(_photoIds.end() - position);
auto before = qMin(haveBefore, query.limitBefore);
auto equalOrAfter = qMin(haveEqualOrAfter, query.limitAfter + 1);
result.photoIds = std::deque<PhotoId>(
position - before,
position + equalOrAfter);
auto skippedInIds = (haveBefore - before);
result.skippedBefore = _count
| func::add(-int(_photoIds.size()) + skippedInIds);
result.skippedBefore = haveBefore - before;
result.skippedAfter = (haveEqualOrAfter - equalOrAfter);
}
base::TaskQueue::Main().Put(
[
callback = std::move(callback),
result = std::move(result)
]() mutable {
callback(std::move(result));
});
}
std::map<UserId, UserPhotos::List>::iterator
UserPhotos::enforceLists(UserId user) {
auto result = _lists.find(user);
if (result != _lists.end()) {
return result;
}
result = _lists.emplace(user, List {}).first;
subscribe(result->second.sliceUpdated, [this, user](const SliceUpdate &update) {
sliceUpdated.notify(UserPhotosSliceUpdate(
user,
update.photoIds,
update.count), true);
});
return result;
}
void UserPhotos::add(UserPhotosAddNew &&query) {
auto userIt = enforceLists(query.userId);
userIt->second.addNew(query.photoId);
}
void UserPhotos::add(UserPhotosAddSlice &&query) {
auto userIt = enforceLists(query.userId);
userIt->second.addSlice(
std::move(query.photoIds),
query.count);
}
void UserPhotos::remove(UserPhotosRemoveOne &&query) {
auto userIt = _lists.find(query.userId);
if (userIt != _lists.end()) {
userIt->second.removeOne(query.photoId);
}
}
void UserPhotos::remove(UserPhotosRemoveAfter &&query) {
auto userIt = _lists.find(query.userId);
if (userIt != _lists.end()) {
userIt->second.removeAfter(query.photoId);
}
}
void UserPhotos::query(
const UserPhotosQuery &query,
base::lambda_once<void(UserPhotosResult&&)> &&callback) {
auto userIt = _lists.find(query.key.userId);
if (userIt != _lists.end()) {
userIt->second.query(query, std::move(callback));
} else {
base::TaskQueue::Main().Put(
[
callback = std::move(callback)
]() mutable {
callback(UserPhotosResult());
});
}
}
} // namespace Storage

View File

@ -0,0 +1,184 @@
/*
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_facade.h"
namespace Storage {
struct UserPhotosAddNew {
UserPhotosAddNew(UserId userId, PhotoId photoId)
: userId(userId), photoId(photoId) {
}
UserId userId = 0;
PhotoId photoId = 0;
};
struct UserPhotosAddSlice {
UserPhotosAddSlice(
UserId userId,
std::vector<PhotoId> &&photoIds,
int count)
: userId(userId)
, photoIds(std::move(photoIds))
, count(count) {
}
UserId userId = 0;
std::vector<PhotoId> photoIds;
int count = 0;
};
struct UserPhotosRemoveOne {
UserPhotosRemoveOne(
UserId userId,
PhotoId photoId)
: userId(userId)
, photoId(photoId) {
}
UserId userId = 0;
PhotoId photoId = 0;
};
struct UserPhotosRemoveAfter {
UserPhotosRemoveAfter(
UserId userId,
PhotoId photoId)
: userId(userId)
, photoId(photoId) {
}
UserId userId = 0;
PhotoId photoId = 0;
};
struct UserPhotosKey {
UserPhotosKey(
UserId userId,
PhotoId photoId)
: userId(userId)
, photoId(photoId) {
}
bool operator==(const UserPhotosKey &other) const {
return (userId == other.userId)
&& (photoId == other.photoId);
}
bool operator!=(const UserPhotosKey &other) const {
return !(*this == other);
}
PeerId userId = 0;
PhotoId photoId = 0;
};
struct UserPhotosQuery {
UserPhotosQuery(
UserPhotosKey key,
int limitBefore,
int limitAfter)
: key(key)
, limitBefore(limitBefore)
, limitAfter(limitAfter) {
}
UserPhotosKey key;
int limitBefore = 0;
int limitAfter = 0;
};
struct UserPhotosResult {
base::optional<int> count;
base::optional<int> skippedBefore;
int skippedAfter = 0;
std::deque<PhotoId> photoIds;
};
struct UserPhotosSliceUpdate {
UserPhotosSliceUpdate(
UserId userId,
const std::deque<PhotoId> *photoIds,
base::optional<int> count)
: userId(userId)
, photoIds(photoIds)
, count(count) {
}
UserId userId = 0;
const std::deque<PhotoId> *photoIds = nullptr;
base::optional<int> count;
};
class UserPhotos : private base::Subscriber {
public:
void add(UserPhotosAddNew &&query);
void add(UserPhotosAddSlice &&query);
void remove(UserPhotosRemoveOne &&query);
void remove(UserPhotosRemoveAfter &&query);
void query(
const UserPhotosQuery &query,
base::lambda_once<void(UserPhotosResult&&)> &&callback);
base::Observable<UserPhotosSliceUpdate> sliceUpdated;
private:
class List {
public:
void addNew(PhotoId photoId);
void addSlice(
std::vector<PhotoId> &&photoIds,
int count);
void removeOne(PhotoId photoId);
void removeAfter(PhotoId photoId);
void query(
const UserPhotosQuery &query,
base::lambda_once<void(UserPhotosResult&&)> &&callback);
struct SliceUpdate {
const std::deque<PhotoId> *photoIds = nullptr;
base::optional<int> count;
};
base::Observable<SliceUpdate> sliceUpdated;
private:
void sendUpdate();
base::optional<int> _count;
std::deque<PhotoId> _photoIds;
};
using SliceUpdate = List::SliceUpdate;
std::map<UserId, List>::iterator enforceLists(UserId user);
std::map<UserId, List> _lists;
};
} // namespace Storage

View File

@ -568,10 +568,6 @@ public:
bool hasCalls() const;
void setCallsStatus(CallsStatus callsStatus);
typedef QList<PhotoData*> Photos;
Photos photos;
int photosCount = -1; // -1 not loaded, 0 all loaded
bool setAbout(const QString &newAbout);
const QString &about() const {
return _about;

View File

@ -189,6 +189,8 @@
<(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_user_photos.cpp
<(src_loc)/history/history_user_photos.h
<(src_loc)/history/history_widget.cpp
<(src_loc)/history/history_widget.h
<(src_loc)/inline_bots/inline_bot_layout_internal.cpp
@ -449,6 +451,8 @@
<(src_loc)/storage/storage_facade.h
<(src_loc)/storage/storage_shared_media.cpp
<(src_loc)/storage/storage_shared_media.h
<(src_loc)/storage/storage_user_photos.cpp
<(src_loc)/storage/storage_user_photos.h
<(src_loc)/ui/effects/cross_animation.cpp
<(src_loc)/ui/effects/cross_animation.h
<(src_loc)/ui/effects/panel_animation.cpp