mirror of https://github.com/procxx/kepka.git
Add general StorageFileLocation abstraction.
This commit is contained in:
parent
d36f6a0322
commit
eba2a98703
|
@ -43,13 +43,6 @@ inline MediaKey mediaKey(LocationType type, int32 dc, const uint64 &id) {
|
||||||
return MediaKey(mediaMix32To64(type, dc), id);
|
return MediaKey(mediaMix32To64(type, dc), id);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline StorageKey mediaKey(const MTPDfileLocation &location) {
|
|
||||||
return storageKey(
|
|
||||||
location.vdc_id.v,
|
|
||||||
location.vvolume_id.v,
|
|
||||||
location.vlocal_id.v);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct DocumentAdditionalData {
|
struct DocumentAdditionalData {
|
||||||
virtual ~DocumentAdditionalData() = default;
|
virtual ~DocumentAdditionalData() = default;
|
||||||
|
|
||||||
|
|
|
@ -247,19 +247,19 @@ bool PeerData::userpicLoaded() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PeerData::useEmptyUserpic() const {
|
bool PeerData::useEmptyUserpic() const {
|
||||||
return _userpicLocation.isNull()
|
return !_userpicLocation.valid()
|
||||||
|| !_userpic
|
|| !_userpic
|
||||||
|| !_userpic->loaded();
|
|| !_userpic->loaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
StorageKey PeerData::userpicUniqueKey() const {
|
InMemoryKey PeerData::userpicUniqueKey() const {
|
||||||
if (useEmptyUserpic()) {
|
if (useEmptyUserpic()) {
|
||||||
if (!_userpicEmpty) {
|
if (!_userpicEmpty) {
|
||||||
refreshEmptyUserpic();
|
refreshEmptyUserpic();
|
||||||
}
|
}
|
||||||
return _userpicEmpty->uniqueKey();
|
return _userpicEmpty->uniqueKey();
|
||||||
}
|
}
|
||||||
return storageKey(_userpicLocation);
|
return inMemoryKey(_userpicLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PeerData::saveUserpic(const QString &path, int size) const {
|
void PeerData::saveUserpic(const QString &path, int size) const {
|
||||||
|
|
|
@ -234,7 +234,7 @@ public:
|
||||||
void loadUserpic(bool loadFirst = false, bool prior = true);
|
void loadUserpic(bool loadFirst = false, bool prior = true);
|
||||||
[[nodiscard]] bool userpicLoaded() const;
|
[[nodiscard]] bool userpicLoaded() const;
|
||||||
[[nodiscard]] bool useEmptyUserpic() const;
|
[[nodiscard]] bool useEmptyUserpic() const;
|
||||||
[[nodiscard]] StorageKey userpicUniqueKey() const;
|
[[nodiscard]] InMemoryKey userpicUniqueKey() const;
|
||||||
void saveUserpic(const QString &path, int size) const;
|
void saveUserpic(const QString &path, int size) const;
|
||||||
void saveUserpicRounded(const QString &path, int size) const;
|
void saveUserpicRounded(const QString &path, int size) const;
|
||||||
[[nodiscard]] QPixmap genUserpic(int size) const;
|
[[nodiscard]] QPixmap genUserpic(int size) const;
|
||||||
|
|
|
@ -53,7 +53,11 @@ LocationKey ComputeLocationKey(const Data::FileLocation &value) {
|
||||||
result.type |= (uint64(uint32(data.vlocal_id.v)) << 32);
|
result.type |= (uint64(uint32(data.vlocal_id.v)) << 32);
|
||||||
result.id = data.vvolume_id.v;
|
result.id = data.vvolume_id.v;
|
||||||
}, [&](const MTPDinputDocumentFileLocation &data) {
|
}, [&](const MTPDinputDocumentFileLocation &data) {
|
||||||
|
const auto letter = data.vthumb_size.v.isEmpty()
|
||||||
|
? char(0)
|
||||||
|
: data.vthumb_size.v[0];
|
||||||
result.type |= (2ULL << 24);
|
result.type |= (2ULL << 24);
|
||||||
|
result.type |= (uint64(uint32(letter)) << 16);
|
||||||
result.id = data.vid.v;
|
result.id = data.vid.v;
|
||||||
}, [&](const MTPDinputSecureFileLocation &data) {
|
}, [&](const MTPDinputSecureFileLocation &data) {
|
||||||
result.type |= (3ULL << 24);
|
result.type |= (3ULL << 24);
|
||||||
|
@ -63,6 +67,23 @@ LocationKey ComputeLocationKey(const Data::FileLocation &value) {
|
||||||
result.id = data.vid.v;
|
result.id = data.vid.v;
|
||||||
}, [&](const MTPDinputTakeoutFileLocation &data) {
|
}, [&](const MTPDinputTakeoutFileLocation &data) {
|
||||||
result.type |= (5ULL << 24);
|
result.type |= (5ULL << 24);
|
||||||
|
}, [&](const MTPDinputPhotoFileLocation &data) {
|
||||||
|
const auto letter = data.vthumb_size.v.isEmpty()
|
||||||
|
? char(0)
|
||||||
|
: data.vthumb_size.v[0];
|
||||||
|
result.type |= (6ULL << 24);
|
||||||
|
result.type |= (uint64(uint32(letter)) << 16);
|
||||||
|
result.id = data.vid.v;
|
||||||
|
}, [&](const MTPDinputPeerPhotoFileLocation &data) {
|
||||||
|
const auto letter = data.is_big() ? char(1) : char(0);
|
||||||
|
result.type |= (7ULL << 24);
|
||||||
|
result.type |= (uint64(uint32(data.vlocal_id.v)) << 32);
|
||||||
|
result.type |= (uint64(uint32(letter)) << 16);
|
||||||
|
result.id = data.vvolume_id.v;
|
||||||
|
}, [&](const MTPDinputStickerSetThumb &data) {
|
||||||
|
result.type |= (8ULL << 24);
|
||||||
|
result.type |= (uint64(uint32(data.vlocal_id.v)) << 32);
|
||||||
|
result.id = data.vvolume_id.v;
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -440,12 +440,9 @@ void Manager::Private::showNextNotification() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
StorageKey key;
|
const auto key = data.hideNameAndPhoto
|
||||||
if (data.hideNameAndPhoto) {
|
? InMemoryKey()
|
||||||
key = StorageKey(0, 0);
|
: data.peer->userpicUniqueKey();
|
||||||
} else {
|
|
||||||
key = data.peer->userpicUniqueKey();
|
|
||||||
}
|
|
||||||
notification->setImage(_cachedUserpics.get(key, data.peer));
|
notification->setImage(_cachedUserpics.get(key, data.peer));
|
||||||
|
|
||||||
auto i = _notifications.find(peerId);
|
auto i = _notifications.find(peerId);
|
||||||
|
|
|
@ -459,14 +459,11 @@ bool Manager::Private::showNotification(PeerData *peer, MsgId msgId, const QStri
|
||||||
hr = SetAudioSilent(toastXml.Get());
|
hr = SetAudioSilent(toastXml.Get());
|
||||||
if (!SUCCEEDED(hr)) return false;
|
if (!SUCCEEDED(hr)) return false;
|
||||||
|
|
||||||
StorageKey key;
|
const auto key = hideNameAndPhoto
|
||||||
if (hideNameAndPhoto) {
|
? InMemoryKey()
|
||||||
key = StorageKey(0, 0);
|
: peer->userpicUniqueKey();
|
||||||
} else {
|
const auto userpicPath = _cachedUserpics.get(key, peer);
|
||||||
key = peer->userpicUniqueKey();
|
const auto userpicPathWide = QDir::toNativeSeparators(userpicPath).toStdWString();
|
||||||
}
|
|
||||||
auto userpicPath = _cachedUserpics.get(key, peer);
|
|
||||||
auto userpicPathWide = QDir::toNativeSeparators(userpicPath).toStdWString();
|
|
||||||
|
|
||||||
hr = SetImageSrc(userpicPathWide.c_str(), toastXml.Get());
|
hr = SetImageSrc(userpicPathWide.c_str(), toastXml.Get());
|
||||||
if (!SUCCEEDED(hr)) return false;
|
if (!SUCCEEDED(hr)) return false;
|
||||||
|
|
|
@ -508,10 +508,10 @@ enum { // Local Storage Keys
|
||||||
lskUserMap = 0x00,
|
lskUserMap = 0x00,
|
||||||
lskDraft = 0x01, // data: PeerId peer
|
lskDraft = 0x01, // data: PeerId peer
|
||||||
lskDraftPosition = 0x02, // data: PeerId peer
|
lskDraftPosition = 0x02, // data: PeerId peer
|
||||||
lskImages = 0x03, // data: StorageKey location
|
lskLegacyImages = 0x03, // legacy
|
||||||
lskLocations = 0x04, // no data
|
lskLocations = 0x04, // no data
|
||||||
lskStickerImages = 0x05, // data: StorageKey location
|
lskLegacyStickerImages = 0x05, // legacy
|
||||||
lskAudios = 0x06, // data: StorageKey location
|
lskLegacyAudios = 0x06, // legacy
|
||||||
lskRecentStickersOld = 0x07, // no data
|
lskRecentStickersOld = 0x07, // no data
|
||||||
lskBackgroundOld = 0x08, // no data
|
lskBackgroundOld = 0x08, // no data
|
||||||
lskUserSettings = 0x09, // no data
|
lskUserSettings = 0x09, // no data
|
||||||
|
@ -2332,9 +2332,9 @@ ReadMapState _readMap(const QByteArray &pass) {
|
||||||
draftCursorsMap.insert(p, key);
|
draftCursorsMap.insert(p, key);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case lskImages:
|
case lskLegacyImages:
|
||||||
case lskStickerImages:
|
case lskLegacyStickerImages:
|
||||||
case lskAudios: {
|
case lskLegacyAudios: {
|
||||||
quint32 count = 0;
|
quint32 count = 0;
|
||||||
map.stream >> count;
|
map.stream >> count;
|
||||||
for (quint32 i = 0; i < count; ++i) {
|
for (quint32 i = 0; i < count; ++i) {
|
||||||
|
@ -3188,30 +3188,6 @@ FileLocation readFileLocation(MediaKey location, bool check) {
|
||||||
return FileLocation();
|
return FileLocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
qint32 _storageImageSize(qint32 rawlen) {
|
|
||||||
// fulllen + storagekey + type + len + data
|
|
||||||
qint32 result = sizeof(uint32) + sizeof(quint64) * 2 + sizeof(quint32) + sizeof(quint32) + rawlen;
|
|
||||||
if (result & 0x0F) result += 0x10 - (result & 0x0F);
|
|
||||||
result += tdfMagicLen + sizeof(qint32) + sizeof(quint32) + 0x10 + 0x10; // magic + version + len of encrypted + part of sha1 + md5
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
qint32 _storageStickerSize(qint32 rawlen) {
|
|
||||||
// fulllen + storagekey + len + data
|
|
||||||
qint32 result = sizeof(uint32) + sizeof(quint64) * 2 + sizeof(quint32) + rawlen;
|
|
||||||
if (result & 0x0F) result += 0x10 - (result & 0x0F);
|
|
||||||
result += tdfMagicLen + sizeof(qint32) + sizeof(quint32) + 0x10 + 0x10; // magic + version + len of encrypted + part of sha1 + md5
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
qint32 _storageAudioSize(qint32 rawlen) {
|
|
||||||
// fulllen + storagekey + len + data
|
|
||||||
qint32 result = sizeof(uint32) + sizeof(quint64) * 2 + sizeof(quint32) + rawlen;
|
|
||||||
if (result & 0x0F) result += 0x10 - (result & 0x0F);
|
|
||||||
result += tdfMagicLen + sizeof(qint32) + sizeof(quint32) + 0x10 + 0x10; // magic + version + len of encrypted + part of sha1 + md5
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Storage::EncryptionKey cacheKey() {
|
Storage::EncryptionKey cacheKey() {
|
||||||
Expects(LocalKey != nullptr);
|
Expects(LocalKey != nullptr);
|
||||||
|
|
||||||
|
|
|
@ -160,11 +160,12 @@ void EmptyUserpic::PaintSavedMessages(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StorageKey EmptyUserpic::uniqueKey() const {
|
InMemoryKey EmptyUserpic::uniqueKey() const {
|
||||||
auto first = 0xFFFFFFFF00000000ULL | anim::getPremultiplied(_color->c);
|
const auto first = (uint64(0xFFFFFFFFU) << 32)
|
||||||
|
| anim::getPremultiplied(_color->c);
|
||||||
auto second = uint64(0);
|
auto second = uint64(0);
|
||||||
memcpy(&second, _string.constData(), qMin(sizeof(second), _string.size() * sizeof(QChar)));
|
memcpy(&second, _string.constData(), qMin(sizeof(second), _string.size() * sizeof(QChar)));
|
||||||
return StorageKey(first, second);
|
return InMemoryKey(first, second);
|
||||||
}
|
}
|
||||||
|
|
||||||
QPixmap EmptyUserpic::generate(int size) {
|
QPixmap EmptyUserpic::generate(int size) {
|
||||||
|
|
|
@ -32,7 +32,7 @@ public:
|
||||||
int outerWidth,
|
int outerWidth,
|
||||||
int size) const;
|
int size) const;
|
||||||
QPixmap generate(int size);
|
QPixmap generate(int size);
|
||||||
StorageKey uniqueKey() const;
|
InMemoryKey uniqueKey() const;
|
||||||
|
|
||||||
static void PaintSavedMessages(
|
static void PaintSavedMessages(
|
||||||
Painter &p,
|
Painter &p,
|
||||||
|
|
|
@ -22,11 +22,11 @@ namespace {
|
||||||
// After 128 MB of unpacked images we try to clear some memory.
|
// After 128 MB of unpacked images we try to clear some memory.
|
||||||
constexpr auto kMemoryForCache = 128 * 1024 * 1024;
|
constexpr auto kMemoryForCache = 128 * 1024 * 1024;
|
||||||
|
|
||||||
QMap<QString, Image*> LocalFileImages;
|
std::map<QString, std::unique_ptr<Image>> LocalFileImages;
|
||||||
QMap<QString, Image*> WebUrlImages;
|
std::map<QString, std::unique_ptr<Image>> WebUrlImages;
|
||||||
QMap<StorageKey, Image*> StorageImages;
|
std::unordered_map<InMemoryKey, std::unique_ptr<Image>> StorageImages;
|
||||||
QMap<StorageKey, Image*> WebCachedImages;
|
std::unordered_map<InMemoryKey, std::unique_ptr<Image>> WebCachedImages;
|
||||||
QMap<StorageKey, Image*> GeoPointImages;
|
std::unordered_map<InMemoryKey, std::unique_ptr<Image>> GeoPointImages;
|
||||||
|
|
||||||
int64 ComputeUsage(QSize size) {
|
int64 ComputeUsage(QSize size) {
|
||||||
return int64(size.width()) * size.height() * 4;
|
return int64(size.width()) * size.height() * 4;
|
||||||
|
@ -60,25 +60,15 @@ uint64 SinglePixKey(Options options) {
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void ClearRemote() {
|
void ClearRemote() {
|
||||||
for (auto image : base::take(StorageImages)) {
|
base::take(StorageImages);
|
||||||
delete image;
|
base::take(WebUrlImages);
|
||||||
}
|
base::take(WebCachedImages);
|
||||||
for (auto image : base::take(WebUrlImages)) {
|
base::take(GeoPointImages);
|
||||||
delete image;
|
|
||||||
}
|
|
||||||
for (auto image : base::take(WebCachedImages)) {
|
|
||||||
delete image;
|
|
||||||
}
|
|
||||||
for (auto image : base::take(GeoPointImages)) {
|
|
||||||
delete image;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearAll() {
|
void ClearAll() {
|
||||||
ActiveCache().clear();
|
ActiveCache().clear();
|
||||||
for (auto image : base::take(LocalFileImages)) {
|
base::take(LocalFileImages);
|
||||||
delete image;
|
|
||||||
}
|
|
||||||
ClearRemote();
|
ClearRemote();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,54 +76,61 @@ ImagePtr Create(const QString &file, QByteArray format) {
|
||||||
if (file.startsWith(qstr("http://"), Qt::CaseInsensitive)
|
if (file.startsWith(qstr("http://"), Qt::CaseInsensitive)
|
||||||
|| file.startsWith(qstr("https://"), Qt::CaseInsensitive)) {
|
|| file.startsWith(qstr("https://"), Qt::CaseInsensitive)) {
|
||||||
const auto &key = file;
|
const auto &key = file;
|
||||||
auto i = WebUrlImages.constFind(key);
|
const auto i = WebUrlImages.find(key);
|
||||||
if (i == WebUrlImages.cend()) {
|
const auto image = (i != end(WebUrlImages))
|
||||||
i = WebUrlImages.insert(
|
? i->second.get()
|
||||||
|
: WebUrlImages.emplace(
|
||||||
key,
|
key,
|
||||||
new Image(std::make_unique<WebUrlSource>(file)));
|
std::make_unique<Image>(std::make_unique<WebUrlSource>(file))
|
||||||
}
|
).first->second.get();
|
||||||
return ImagePtr(i.value());
|
return ImagePtr(image);
|
||||||
} else {
|
}
|
||||||
QFileInfo f(file);
|
QFileInfo f(file);
|
||||||
const auto key = qsl("//:%1//:%2//:"
|
const auto key = qsl("//:%1//:%2//:"
|
||||||
).arg(f.size()
|
).arg(f.size()
|
||||||
).arg(f.lastModified().toTime_t()
|
).arg(f.lastModified().toTime_t()
|
||||||
) + file;
|
) + file;
|
||||||
auto i = LocalFileImages.constFind(key);
|
const auto i = LocalFileImages.find(key);
|
||||||
if (i == LocalFileImages.cend()) {
|
const auto image = (i != end(LocalFileImages))
|
||||||
i = LocalFileImages.insert(
|
? i->second.get()
|
||||||
key,
|
: LocalFileImages.emplace(
|
||||||
new Image(std::make_unique<LocalFileSource>(
|
key,
|
||||||
|
std::make_unique<Image>(
|
||||||
|
std::make_unique<LocalFileSource>(
|
||||||
file,
|
file,
|
||||||
QByteArray(),
|
QByteArray(),
|
||||||
format)));
|
format))
|
||||||
}
|
).first->second.get();
|
||||||
return ImagePtr(i.value());
|
return ImagePtr(image);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ImagePtr Create(const QString &url, QSize box) {
|
ImagePtr Create(const QString &url, QSize box) {
|
||||||
const auto key = qsl("//:%1//:%2//:").arg(box.width()).arg(box.height()) + url;
|
const auto key = qsl("//:%1//:%2//:").arg(box.width()).arg(box.height()) + url;
|
||||||
auto i = WebUrlImages.constFind(key);
|
const auto i = WebUrlImages.find(key);
|
||||||
if (i == WebUrlImages.cend()) {
|
const auto image = (i != end(WebUrlImages))
|
||||||
i = WebUrlImages.insert(
|
? i->second.get()
|
||||||
|
: WebUrlImages.emplace(
|
||||||
key,
|
key,
|
||||||
new Image(std::make_unique<WebUrlSource>(url, box)));
|
std::make_unique<Image>(std::make_unique<WebUrlSource>(url, box))
|
||||||
}
|
).first->second.get();
|
||||||
return ImagePtr(i.value());
|
return ImagePtr(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImagePtr Create(const QString &url, int width, int height) {
|
ImagePtr Create(const QString &url, int width, int height) {
|
||||||
const auto key = url;
|
const auto &key = url;
|
||||||
auto i = WebUrlImages.constFind(key);
|
const auto i = WebUrlImages.find(key);
|
||||||
if (i == WebUrlImages.cend()) {
|
const auto found = (i != end(WebUrlImages));
|
||||||
i = WebUrlImages.insert(
|
const auto image = found
|
||||||
|
? i->second.get()
|
||||||
|
: WebUrlImages.emplace(
|
||||||
key,
|
key,
|
||||||
new Image(std::make_unique<WebUrlSource>(url, width, height)));
|
std::make_unique<Image>(
|
||||||
} else {
|
std::make_unique<WebUrlSource>(url, width, height))
|
||||||
i.value()->setInformation(0, width, height);
|
).first->second.get();
|
||||||
|
if (found) {
|
||||||
|
image->setInformation(0, width, height);
|
||||||
}
|
}
|
||||||
return ImagePtr(i.value());
|
return ImagePtr(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImagePtr Create(const QByteArray &filecontent, QByteArray format) {
|
ImagePtr Create(const QByteArray &filecontent, QByteArray format) {
|
||||||
|
@ -165,34 +162,40 @@ ImagePtr Create(int width, int height) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ImagePtr Create(const StorageImageLocation &location, int size) {
|
ImagePtr Create(const StorageImageLocation &location, int size) {
|
||||||
const auto key = storageKey(location);
|
const auto key = inMemoryKey(location);
|
||||||
auto i = StorageImages.constFind(key);
|
const auto i = StorageImages.find(key);
|
||||||
if (i == StorageImages.cend()) {
|
const auto found = (i != end(StorageImages));
|
||||||
i = StorageImages.insert(
|
const auto image = found
|
||||||
|
? i->second.get()
|
||||||
|
: StorageImages.emplace(
|
||||||
key,
|
key,
|
||||||
new Image(std::make_unique<StorageSource>(location, size)));
|
std::make_unique<Image>(
|
||||||
} else {
|
std::make_unique<StorageSource>(location, size))
|
||||||
i.value()->refreshFileReference(location.fileReference());
|
).first->second.get();
|
||||||
|
if (found) {
|
||||||
|
image->refreshFileReference(location.fileReference());
|
||||||
}
|
}
|
||||||
return ImagePtr(i.value());
|
return ImagePtr(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImagePtr Create(
|
ImagePtr Create(
|
||||||
const StorageImageLocation &location,
|
const StorageImageLocation &location,
|
||||||
const QByteArray &bytes) {
|
const QByteArray &bytes) {
|
||||||
const auto key = storageKey(location);
|
const auto key = inMemoryKey(location);
|
||||||
auto i = StorageImages.constFind(key);
|
const auto i = StorageImages.find(key);
|
||||||
if (i == StorageImages.cend()) {
|
const auto found = (i != end(StorageImages));
|
||||||
i = StorageImages.insert(
|
const auto image = found
|
||||||
|
? i->second.get()
|
||||||
|
: StorageImages.emplace(
|
||||||
key,
|
key,
|
||||||
new Image(std::make_unique<StorageSource>(
|
std::make_unique<Image>(
|
||||||
location,
|
std::make_unique<StorageSource>(location, bytes.size()))
|
||||||
bytes.size())));
|
).first->second.get();
|
||||||
} else {
|
if (found) {
|
||||||
i.value()->refreshFileReference(location.fileReference());
|
image->refreshFileReference(location.fileReference());
|
||||||
}
|
}
|
||||||
i.value()->setImageBytes(bytes);
|
image->setImageBytes(bytes);
|
||||||
return ImagePtr(i.value());
|
return ImagePtr(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
QSize getImageSize(const QVector<MTPDocumentAttribute> &attributes) {
|
QSize getImageSize(const QVector<MTPDocumentAttribute> &attributes) {
|
||||||
|
@ -284,17 +287,18 @@ ImagePtr Create(
|
||||||
const WebFileLocation &location,
|
const WebFileLocation &location,
|
||||||
QSize box,
|
QSize box,
|
||||||
int size) {
|
int size) {
|
||||||
const auto key = storageKey(location);
|
const auto key = inMemoryKey(location);
|
||||||
auto i = WebCachedImages.constFind(key);
|
const auto i = WebCachedImages.find(key);
|
||||||
if (i == WebCachedImages.cend()) {
|
const auto image = (i != end(WebCachedImages))
|
||||||
i = WebCachedImages.insert(
|
? i->second.get()
|
||||||
|
: WebCachedImages.emplace(
|
||||||
key,
|
key,
|
||||||
new Image(std::make_unique<WebCachedSource>(
|
std::make_unique<Image>(std::make_unique<WebCachedSource>(
|
||||||
location,
|
location,
|
||||||
box,
|
box,
|
||||||
size)));
|
size))
|
||||||
}
|
).first->second.get();
|
||||||
return ImagePtr(i.value());
|
return ImagePtr(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImagePtr Create(
|
ImagePtr Create(
|
||||||
|
@ -302,29 +306,32 @@ ImagePtr Create(
|
||||||
int width,
|
int width,
|
||||||
int height,
|
int height,
|
||||||
int size) {
|
int size) {
|
||||||
const auto key = storageKey(location);
|
const auto key = inMemoryKey(location);
|
||||||
auto i = WebCachedImages.constFind(key);
|
const auto i = WebCachedImages.find(key);
|
||||||
if (i == WebCachedImages.cend()) {
|
const auto image = (i != end(WebCachedImages))
|
||||||
i = WebCachedImages.insert(
|
? i->second.get()
|
||||||
|
: WebCachedImages.emplace(
|
||||||
key,
|
key,
|
||||||
new Image(std::make_unique<WebCachedSource>(
|
std::make_unique<Image>(std::make_unique<WebCachedSource>(
|
||||||
location,
|
location,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
size)));
|
size))
|
||||||
}
|
).first->second.get();
|
||||||
return ImagePtr(i.value());
|
return ImagePtr(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImagePtr Create(const GeoPointLocation &location) {
|
ImagePtr Create(const GeoPointLocation &location) {
|
||||||
const auto key = storageKey(location);
|
const auto key = inMemoryKey(location);
|
||||||
auto i = GeoPointImages.constFind(key);
|
const auto i = GeoPointImages.find(key);
|
||||||
if (i == GeoPointImages.cend()) {
|
const auto image = (i != end(GeoPointImages))
|
||||||
i = GeoPointImages.insert(
|
? i->second.get()
|
||||||
|
: GeoPointImages.emplace(
|
||||||
key,
|
key,
|
||||||
new Image(std::make_unique<GeoPointSource>(location)));
|
std::make_unique<Image>(
|
||||||
}
|
std::make_unique<GeoPointSource>(location))
|
||||||
return ImagePtr(i.value());
|
).first->second.get();
|
||||||
|
return ImagePtr(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Images
|
} // namespace Images
|
||||||
|
|
|
@ -27,36 +27,115 @@ ImagePtr::operator bool() const {
|
||||||
return !_data->isNull();
|
return !_data->isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
StorageImageLocation StorageImageLocation::Null;
|
|
||||||
WebFileLocation WebFileLocation::Null;
|
WebFileLocation WebFileLocation::Null;
|
||||||
|
|
||||||
StorageImageLocation::StorageImageLocation(
|
bool StorageFileLocation::valid() const {
|
||||||
int32 width,
|
switch (_type) {
|
||||||
int32 height,
|
case Type::General:
|
||||||
int32 dc,
|
return (_dcId != 0) && (_volumeId != 0) && (_localId != 0);
|
||||||
const uint64 &volume,
|
|
||||||
int32 local,
|
case Type::Encrypted:
|
||||||
const uint64 &secret,
|
case Type::Secure:
|
||||||
const QByteArray &fileReference)
|
case Type::Document:
|
||||||
: _widthheight(packIntInt(width, height))
|
return (_dcId != 0) && (_id != 0);
|
||||||
, _dclocal(packIntInt(dc, local))
|
|
||||||
, _volume(volume)
|
case Type::Photo:
|
||||||
, _secret(secret)
|
return (_dcId != 0) && (_id != 0) && (_sizeLetter != 0);
|
||||||
, _fileReference(fileReference) {
|
|
||||||
|
case Type::Takeout:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case Type::PeerPhoto:
|
||||||
|
case Type::StickerSetThumb:
|
||||||
|
return (_dcId != 0) && (_id != 0);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
InMemoryKey StorageFileLocation::inMemoryKey() const {
|
||||||
|
switch (_type) {
|
||||||
|
case Type::General:
|
||||||
|
case Type::PeerPhoto:
|
||||||
|
case Type::StickerSetThumb:
|
||||||
|
return InMemoryKey(
|
||||||
|
(uint64(_type) << 56) | (uint64(_dcId) << 40) | uint32(_localId),
|
||||||
|
_volumeId);
|
||||||
|
|
||||||
|
case Type::Encrypted:
|
||||||
|
case Type::Secure:
|
||||||
|
return InMemoryKey(
|
||||||
|
(uint64(_type) << 56) | (uint64(_dcId) << 40),
|
||||||
|
_id);
|
||||||
|
|
||||||
|
case Type::Document:
|
||||||
|
case Type::Photo:
|
||||||
|
return InMemoryKey(
|
||||||
|
(uint64(_type) << 56) | (uint64(_dcId) << 40) | _sizeLetter,
|
||||||
|
_id);
|
||||||
|
|
||||||
|
case Type::Takeout:
|
||||||
|
return InMemoryKey(
|
||||||
|
(uint64(_type) << 56),
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
return InMemoryKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const StorageFileLocation &a, const StorageFileLocation &b) {
|
||||||
|
const auto valid = a.valid();
|
||||||
|
if (valid != b.valid()) {
|
||||||
|
return false;
|
||||||
|
} else if (!valid) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const auto type = a._type;
|
||||||
|
if (type != b._type) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
using Type = StorageFileLocation::Type;
|
||||||
|
switch (type) {
|
||||||
|
case Type::General:
|
||||||
|
return (a._dcId == b._dcId)
|
||||||
|
&& (a._volumeId == b._volumeId)
|
||||||
|
&& (a._localId == b._localId);
|
||||||
|
|
||||||
|
case Type::Encrypted:
|
||||||
|
case Type::Secure:
|
||||||
|
return (a._dcId == b._dcId) && (a._id == b._id);
|
||||||
|
|
||||||
|
case Type::Photo:
|
||||||
|
case Type::Document:
|
||||||
|
return (a._dcId == b._dcId)
|
||||||
|
&& (a._id == b._id)
|
||||||
|
&& (a._sizeLetter == b._sizeLetter);
|
||||||
|
|
||||||
|
case Type::Takeout:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case Type::PeerPhoto:
|
||||||
|
return (a._dcId == b._dcId)
|
||||||
|
&& (a._volumeId == b._volumeId)
|
||||||
|
&& (a._localId == b._localId)
|
||||||
|
&& (a._id == b._id)
|
||||||
|
&& (a._sizeLetter == b._sizeLetter);
|
||||||
|
|
||||||
|
case Type::StickerSetThumb:
|
||||||
|
return (a._dcId == b._dcId)
|
||||||
|
&& (a._volumeId == b._volumeId)
|
||||||
|
&& (a._localId == b._localId)
|
||||||
|
&& (a._id == b._id);
|
||||||
|
};
|
||||||
|
Unexpected("Type in StorageFileLocation::operator==.");
|
||||||
}
|
}
|
||||||
|
|
||||||
StorageImageLocation::StorageImageLocation(
|
StorageImageLocation::StorageImageLocation(
|
||||||
int32 width,
|
const StorageFileLocation &file,
|
||||||
int32 height,
|
int width,
|
||||||
const MTPDfileLocation &location)
|
int height)
|
||||||
: StorageImageLocation(
|
: _file(file)
|
||||||
width,
|
, _width(width)
|
||||||
height,
|
, _height(height) {
|
||||||
location.vdc_id.v,
|
|
||||||
location.vvolume_id.v,
|
|
||||||
location.vlocal_id.v,
|
|
||||||
location.vsecret.v,
|
|
||||||
location.vfile_reference.v) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ReadAccessEnabler::ReadAccessEnabler(const PsFileBookmark *bookmark)
|
ReadAccessEnabler::ReadAccessEnabler(const PsFileBookmark *bookmark)
|
||||||
|
|
|
@ -19,128 +19,122 @@ enum LoadToCacheSetting {
|
||||||
LoadToCacheAsWell,
|
LoadToCacheAsWell,
|
||||||
};
|
};
|
||||||
|
|
||||||
inline uint32 packInt(int32 a) {
|
using InMemoryKey = std::pair<uint64, uint64>;
|
||||||
return (a < 0) ? uint32(int64(a) + 0x100000000LL) : uint32(a);
|
|
||||||
}
|
class StorageFileLocation {
|
||||||
inline int32 unpackInt(uint32 a) {
|
public:
|
||||||
return (a > 0x7FFFFFFFU) ? int32(int64(a) - 0x100000000LL) : int32(a);
|
// Those are used in serialization, don't change.
|
||||||
}
|
enum class Type : uchar {
|
||||||
inline uint64 packUIntUInt(uint32 a, uint32 b) {
|
General = 0x00,
|
||||||
return (uint64(a) << 32) | uint64(b);
|
Encrypted = 0x01,
|
||||||
}
|
Document = 0x02,
|
||||||
inline uint64 packUIntInt(uint32 a, int32 b) {
|
Secure = 0x03,
|
||||||
return packUIntUInt(a, packInt(b));
|
Takeout = 0x04,
|
||||||
}
|
Photo = 0x05,
|
||||||
inline uint64 packIntUInt(int32 a, uint32 b) {
|
PeerPhoto = 0x06,
|
||||||
return packUIntUInt(packInt(a), b);
|
StickerSetThumb = 0x07,
|
||||||
}
|
};
|
||||||
inline uint64 packIntInt(int32 a, int32 b) {
|
|
||||||
return packUIntUInt(packInt(a), packInt(b));
|
StorageFileLocation() = default;
|
||||||
}
|
StorageFileLocation(MTP::DcId dcId, const MTPInputFileLocation &tl);
|
||||||
inline uint32 unpackUIntFirst(uint64 v) {
|
|
||||||
return uint32(v >> 32);
|
[[nodiscard]] MTP::DcId dcId() const;
|
||||||
}
|
[[nodiscard]] MTPInputFileLocation tl() const;
|
||||||
inline int32 unpackIntFirst(uint64 v) {
|
|
||||||
return unpackInt(unpackUIntFirst(v));
|
[[nodiscard]] QByteArray serialize() const;
|
||||||
}
|
[[nodiscard]] static std::optional<StorageFileLocation> FromSerialized(
|
||||||
inline uint32 unpackUIntSecond(uint64 v) {
|
const QByteArray &serialized);
|
||||||
return uint32(v & 0xFFFFFFFFULL);
|
|
||||||
}
|
[[nodiscard]] bool valid() const;
|
||||||
inline int32 unpackIntSecond(uint64 v) {
|
[[nodiscard]] InMemoryKey inMemoryKey() const;
|
||||||
return unpackInt(unpackUIntSecond(v));
|
|
||||||
|
[[nodiscard]] QByteArray fileReference() const;
|
||||||
|
bool refreshFileReference(const QByteArray &data) {
|
||||||
|
if (data.isEmpty() || _fileReference == data) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_fileReference = data;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend bool operator==(
|
||||||
|
const StorageFileLocation &a,
|
||||||
|
const StorageFileLocation &b);
|
||||||
|
|
||||||
|
uint16 _dcId = 0;
|
||||||
|
Type _type = Type::General;
|
||||||
|
uint8 _sizeLetter = 0;
|
||||||
|
int32 _localId = 0;
|
||||||
|
uint64 _id = 0;
|
||||||
|
uint64 _accessHash = 0;
|
||||||
|
uint64 _volumeId = 0;
|
||||||
|
QByteArray _fileReference;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
inline bool operator!=(
|
||||||
|
const StorageFileLocation &a,
|
||||||
|
const StorageFileLocation &b) {
|
||||||
|
return !(a == b);
|
||||||
}
|
}
|
||||||
|
|
||||||
class StorageImageLocation {
|
class StorageImageLocation {
|
||||||
public:
|
public:
|
||||||
StorageImageLocation() = default;
|
StorageImageLocation() = default;
|
||||||
StorageImageLocation(
|
StorageImageLocation(
|
||||||
int32 width,
|
const StorageFileLocation &file,
|
||||||
int32 height,
|
int width,
|
||||||
int32 dc,
|
int height);
|
||||||
const uint64 &volume,
|
|
||||||
int32 local,
|
|
||||||
const uint64 &secret,
|
|
||||||
const QByteArray &fileReference);
|
|
||||||
StorageImageLocation(
|
|
||||||
int32 width,
|
|
||||||
int32 height,
|
|
||||||
const MTPDfileLocation &location);
|
|
||||||
|
|
||||||
bool isNull() const {
|
[[nodiscard]] QByteArray serialize() const;
|
||||||
return !_dclocal;
|
[[nodiscard]] static std::optional<StorageImageLocation> FromSerialized(
|
||||||
|
const QByteArray &serialized);
|
||||||
|
|
||||||
|
[[nodiscard]] const StorageFileLocation &file() const {
|
||||||
|
return _file;
|
||||||
}
|
}
|
||||||
int32 width() const {
|
[[nodiscard]] int width() const {
|
||||||
return unpackIntFirst(_widthheight);
|
return _width;
|
||||||
}
|
}
|
||||||
int32 height() const {
|
[[nodiscard]] int height() const {
|
||||||
return unpackIntSecond(_widthheight);
|
return _height;
|
||||||
}
|
|
||||||
void setSize(int32 width, int32 height) {
|
|
||||||
_widthheight = packIntInt(width, height);
|
|
||||||
}
|
|
||||||
int32 dc() const {
|
|
||||||
return unpackIntFirst(_dclocal);
|
|
||||||
}
|
|
||||||
uint64 volume() const {
|
|
||||||
return _volume;
|
|
||||||
}
|
|
||||||
int32 local() const {
|
|
||||||
return unpackIntSecond(_dclocal);
|
|
||||||
}
|
|
||||||
uint64 secret() const {
|
|
||||||
return _secret;
|
|
||||||
}
|
|
||||||
QByteArray fileReference() const {
|
|
||||||
return _fileReference;
|
|
||||||
}
|
|
||||||
void refreshFileReference(const QByteArray &data) {
|
|
||||||
if (!data.isEmpty()) {
|
|
||||||
_fileReference = data;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static StorageImageLocation FromMTP(
|
void setSize(int width, int height) {
|
||||||
int32 width,
|
_width = width;
|
||||||
int32 height,
|
_height = height;
|
||||||
const MTPFileLocation &location) {
|
|
||||||
if (location.type() == mtpc_fileLocation) {
|
|
||||||
const auto &data = location.c_fileLocation();
|
|
||||||
return StorageImageLocation(width, height, data);
|
|
||||||
}
|
|
||||||
return StorageImageLocation(width, height, 0, 0, 0, 0, {});
|
|
||||||
}
|
|
||||||
static StorageImageLocation FromMTP(const MTPPhotoSize &size) {
|
|
||||||
switch (size.type()) {
|
|
||||||
case mtpc_photoSize: {
|
|
||||||
const auto &data = size.c_photoSize();
|
|
||||||
return FromMTP(data.vw.v, data.vh.v, data.vlocation);
|
|
||||||
} break;
|
|
||||||
case mtpc_photoCachedSize: {
|
|
||||||
const auto &data = size.c_photoCachedSize();
|
|
||||||
return FromMTP(data.vw.v, data.vh.v, data.vlocation);
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
return StorageImageLocation();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static StorageImageLocation Null;
|
[[nodiscard]] bool valid() const {
|
||||||
|
return _file.valid();
|
||||||
|
}
|
||||||
|
[[nodiscard]] InMemoryKey inMemoryKey() const {
|
||||||
|
return _file.inMemoryKey();
|
||||||
|
}
|
||||||
|
[[nodiscard]] QByteArray fileReference() const {
|
||||||
|
return _file.fileReference();
|
||||||
|
}
|
||||||
|
bool refreshFileReference(const QByteArray &data) {
|
||||||
|
return _file.refreshFileReference(data);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint64 _widthheight = 0;
|
|
||||||
uint64 _dclocal = 0;
|
|
||||||
uint64 _volume = 0;
|
|
||||||
uint64 _secret = 0;
|
|
||||||
QByteArray _fileReference;
|
|
||||||
|
|
||||||
friend inline bool operator==(
|
friend inline bool operator==(
|
||||||
const StorageImageLocation &a,
|
const StorageImageLocation &a,
|
||||||
const StorageImageLocation &b) {
|
const StorageImageLocation &b) {
|
||||||
return (a._dclocal == b._dclocal) && (a._volume == b._volume);
|
return (a._file == b._file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StorageFileLocation _file;
|
||||||
|
int _width = 0;
|
||||||
|
int _height = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool operator!=(const StorageImageLocation &a, const StorageImageLocation &b) {
|
inline bool operator!=(
|
||||||
|
const StorageImageLocation &a,
|
||||||
|
const StorageImageLocation &b) {
|
||||||
return !(a == b);
|
return !(a == b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,29 +224,27 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef QPair<uint64, uint64> StorageKey;
|
inline InMemoryKey inMemoryKey(const StorageFileLocation &location) {
|
||||||
inline uint64 storageMix32To64(int32 a, int32 b) {
|
return location.inMemoryKey();
|
||||||
return (uint64(*reinterpret_cast<uint32*>(&a)) << 32) | uint64(*reinterpret_cast<uint32*>(&b));
|
|
||||||
}
|
}
|
||||||
inline StorageKey storageKey(int32 dc, const uint64 &volume, int32 local) {
|
|
||||||
return StorageKey(storageMix32To64(dc, local), volume);
|
inline InMemoryKey inMemoryKey(const StorageImageLocation &location) {
|
||||||
|
return location.inMemoryKey();
|
||||||
}
|
}
|
||||||
inline StorageKey storageKey(const MTPDfileLocation &location) {
|
|
||||||
return storageKey(location.vdc_id.v, location.vvolume_id.v, location.vlocal_id.v);
|
inline InMemoryKey inMemoryKey(const WebFileLocation &location) {
|
||||||
|
auto result = InMemoryKey();
|
||||||
|
const auto &url = location.url();
|
||||||
|
const auto sha = hashSha1(url.data(), url.size());
|
||||||
|
bytes::copy(
|
||||||
|
bytes::object_as_span(&result),
|
||||||
|
bytes::make_span(sha).subspan(0, sizeof(result)));
|
||||||
|
result.first |= (uint64(uint16(location.dc())) << 56);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
inline StorageKey storageKey(const StorageImageLocation &location) {
|
|
||||||
return storageKey(location.dc(), location.volume(), location.local());
|
inline InMemoryKey inMemoryKey(const GeoPointLocation &location) {
|
||||||
}
|
return InMemoryKey(
|
||||||
inline StorageKey storageKey(const WebFileLocation &location) {
|
|
||||||
auto url = location.url();
|
|
||||||
auto sha = hashSha1(url.data(), url.size());
|
|
||||||
return storageKey(
|
|
||||||
location.dc(),
|
|
||||||
*reinterpret_cast<const uint64*>(sha.data()),
|
|
||||||
*reinterpret_cast<const int32*>(sha.data() + sizeof(uint64)));
|
|
||||||
}
|
|
||||||
inline StorageKey storageKey(const GeoPointLocation &location) {
|
|
||||||
return StorageKey(
|
|
||||||
(uint64(std::round(std::abs(location.lat + 360.) * 1000000)) << 32)
|
(uint64(std::round(std::abs(location.lat + 360.) * 1000000)) << 32)
|
||||||
| uint64(std::round(std::abs(location.lon + 360.) * 1000000)),
|
| uint64(std::round(std::abs(location.lon + 360.) * 1000000)),
|
||||||
(uint64(location.width) << 32) | uint64(location.height));
|
(uint64(location.width) << 32) | uint64(location.height));
|
||||||
|
|
|
@ -885,7 +885,7 @@ void UserpicButton::prepareUserpicPixmap() {
|
||||||
});
|
});
|
||||||
_userpicUniqueKey = _userpicHasImage
|
_userpicUniqueKey = _userpicHasImage
|
||||||
? _peer->userpicUniqueKey()
|
? _peer->userpicUniqueKey()
|
||||||
: StorageKey();
|
: InMemoryKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
FeedUserpicButton::FeedUserpicButton(
|
FeedUserpicButton::FeedUserpicButton(
|
||||||
|
|
|
@ -213,7 +213,7 @@ private:
|
||||||
QPixmap _userpic, _oldUserpic;
|
QPixmap _userpic, _oldUserpic;
|
||||||
bool _userpicHasImage = false;
|
bool _userpicHasImage = false;
|
||||||
bool _userpicCustom = false;
|
bool _userpicCustom = false;
|
||||||
StorageKey _userpicUniqueKey;
|
InMemoryKey _userpicUniqueKey;
|
||||||
Animation _a_appearance;
|
Animation _a_appearance;
|
||||||
QImage _result;
|
QImage _result;
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ CachedUserpics::CachedUserpics(Type type)
|
||||||
QDir().mkpath(cWorkingDir() + qsl("tdata/temp"));
|
QDir().mkpath(cWorkingDir() + qsl("tdata/temp"));
|
||||||
}
|
}
|
||||||
|
|
||||||
QString CachedUserpics::get(const StorageKey &key, PeerData *peer) {
|
QString CachedUserpics::get(const InMemoryKey &key, PeerData *peer) {
|
||||||
auto ms = crl::now();
|
auto ms = crl::now();
|
||||||
auto i = _images.find(key);
|
auto i = _images.find(key);
|
||||||
if (i != _images.cend()) {
|
if (i != _images.cend()) {
|
||||||
|
@ -102,7 +102,7 @@ void CachedUserpics::onClear() {
|
||||||
CachedUserpics::~CachedUserpics() {
|
CachedUserpics::~CachedUserpics() {
|
||||||
if (_someSavedFlag) {
|
if (_someSavedFlag) {
|
||||||
crl::time result = 0;
|
crl::time result = 0;
|
||||||
for_const (auto &item, _images) {
|
for (const auto &item : std::as_const(_images)) {
|
||||||
QFile(item.path).remove();
|
QFile(item.path).remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ public:
|
||||||
};
|
};
|
||||||
CachedUserpics(Type type);
|
CachedUserpics(Type type);
|
||||||
|
|
||||||
QString get(const StorageKey &key, PeerData *peer);
|
QString get(const InMemoryKey &key, PeerData *peer);
|
||||||
|
|
||||||
~CachedUserpics();
|
~CachedUserpics();
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ private:
|
||||||
crl::time until;
|
crl::time until;
|
||||||
QString path;
|
QString path;
|
||||||
};
|
};
|
||||||
using Images = QMap<StorageKey, Image>;
|
using Images = QMap<InMemoryKey, Image>;
|
||||||
Images _images;
|
Images _images;
|
||||||
bool _someSavedFlag = false;
|
bool _someSavedFlag = false;
|
||||||
base::Timer _clearTimer;
|
base::Timer _clearTimer;
|
||||||
|
|
Loading…
Reference in New Issue