2
0
mirror of https://github.com/telegramdesktop/tdesktop synced 2025-08-30 22:16:14 +00:00

New structs for media autodownload settings.

This commit is contained in:
John Preston
2018-11-30 16:49:30 +04:00
parent 8708a001c7
commit e3cc8652e4
14 changed files with 542 additions and 88 deletions

View File

@@ -0,0 +1,279 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "data/data_auto_download.h"
#include "data/data_peer.h"
#include "data/data_photo.h"
#include "data/data_document.h"
#include "ui/image/image_source.h"
#include "ui/image/image.h"
namespace Data {
namespace AutoDownload {
namespace {
constexpr auto kDefaultMaxSize = 10 * 1024 * 1024;
constexpr auto kVersion = char(1);
template <typename Enum>
auto enums_view(int from, int till) {
using namespace ranges::view;
return ints(from, till) | transform([](int index) {
return static_cast<Enum>(index);
});
}
template <typename Enum>
auto enums_view(int till) {
return enums_view<Enum>(0, till);
}
void SetDefaultsForSource(Full &data, Source source) {
data.setBytesLimit(source, Type::Photo, kDefaultMaxSize);
data.setBytesLimit(source, Type::VoiceMessage, kDefaultMaxSize);
data.setBytesLimit(source, Type::VideoMessage, kDefaultMaxSize);
data.setBytesLimit(source, Type::GIF, kDefaultMaxSize);
}
const Full &Defaults() {
static auto Result = [] {
auto result = Full::FullDisabled();
for (const auto source : enums_view<Source>(kSourcesCount)) {
SetDefaultsForSource(result, source);
}
return result;
}();
return Result;
}
Source SourceFromPeer(not_null<PeerData*> peer) {
if (peer->isUser()) {
return Source::User;
} else if (peer->isChat() || peer->isMegagroup()) {
return Source::Group;
} else {
return Source::Channel;
}
}
Type TypeFromDocument(not_null<DocumentData*> document) {
if (document->isSong()) {
return Type::Music;
} else if (document->isVoiceMessage()) {
return Type::VoiceMessage;
} else if (document->isVideoMessage()) {
return Type::VideoMessage;
} else if (document->isAnimation()) {
return Type::GIF;
} else if (document->isVideoFile()) {
return Type::Video;
}
return Type::File;
}
} // namespace
void Single::setBytesLimit(int bytesLimit) {
Expects(bytesLimit >= 0 && bytesLimit <= kMaxBytesLimit);
_limit = bytesLimit;
}
bool Single::hasValue() const {
return (_limit >= 0);
}
bool Single::shouldDownload(int fileSize) const {
Expects(hasValue());
return (_limit > 0) && (fileSize <= _limit);
}
int Single::bytesLimit() const {
Expects(hasValue());
return _limit;
}
qint32 Single::serialize() const {
return _limit;
}
bool Single::setFromSerialized(qint32 serialized) {
if (serialized < -1 || serialized > kMaxBytesLimit) {
return false;
}
_limit = serialized;
return true;
}
const Single &Set::single(Type type) const {
Expects(static_cast<int>(type) >= 0
&& static_cast<int>(type) < kTypesCount);
return _data[static_cast<int>(type)];
}
Single &Set::single(Type type) {
return const_cast<Single&>(static_cast<const Set*>(this)->single(type));
}
void Set::setBytesLimit(Type type, int bytesLimit) {
single(type).setBytesLimit(bytesLimit);
}
bool Set::hasValue(Type type) const {
return single(type).hasValue();
}
bool Set::shouldDownload(Type type, int fileSize) const {
return single(type).shouldDownload(fileSize);
}
int Set::bytesLimit(Type type) const {
return single(type).bytesLimit();
}
qint32 Set::serialize(Type type) const {
return single(type).serialize();
}
bool Set::setFromSerialized(Type type, qint32 serialized) {
if (static_cast<int>(type) < 0
|| static_cast<int>(type) >= kTypesCount) {
return false;
}
return single(type).setFromSerialized(serialized);
}
const Set &Full::set(Source source) const {
Expects(static_cast<int>(source) >= 0
&& static_cast<int>(source) < kSourcesCount);
return _data[static_cast<int>(source)];
}
Set &Full::set(Source source) {
return const_cast<Set&>(static_cast<const Full*>(this)->set(source));
}
const Set &Full::setOrDefault(Source source, Type type) const {
const auto &my = set(source);
const auto &result = my.hasValue(type) ? my : Defaults().set(source);
Ensures(result.hasValue(type));
return result;
}
void Full::setBytesLimit(Source source, Type type, int bytesLimit) {
set(source).setBytesLimit(type, bytesLimit);
}
bool Full::shouldDownload(Source source, Type type, int fileSize) const {
return setOrDefault(source, type).shouldDownload(type, fileSize);
}
int Full::bytesLimit(Source source, Type type) const {
return setOrDefault(source, type).bytesLimit(type);
}
QByteArray Full::serialize() const {
auto result = QByteArray();
auto size = sizeof(qint8);
size += kSourcesCount * kTypesCount * sizeof(qint32);
result.reserve(size);
{
auto buffer = QBuffer(&result);
buffer.open(QIODevice::WriteOnly);
auto stream = QDataStream(&buffer);
stream << qint8(kVersion);
for (const auto source : enums_view<Source>(kSourcesCount)) {
for (const auto type : enums_view<Type>(kTypesCount)) {
stream << set(source).serialize(type);
}
}
}
return result;
}
bool Full::setFromSerialized(const QByteArray &serialized) {
if (serialized.isEmpty()) {
return false;
}
auto stream = QDataStream(serialized);
auto version = qint8();
stream >> version;
if (stream.status() != QDataStream::Ok) {
return false;
} else if (version != kVersion) {
return false;
}
auto temp = Full();
for (const auto source : enums_view<Source>(kSourcesCount)) {
for (const auto type : enums_view<Type>(kTypesCount)) {
auto value = qint32();
stream >> value;
if (!temp.set(source).setFromSerialized(type, value)) {
return false;
}
}
}
_data = temp._data;
return true;
}
Full Full::FullDisabled() {
auto result = Full();
for (const auto source : enums_view<Source>(kSourcesCount)) {
for (const auto type : enums_view<Type>(kTypesCount)) {
result.setBytesLimit(source, type, 0);
}
}
return result;
}
bool Should(
const Full &data,
not_null<PeerData*> peer,
not_null<DocumentData*> document) {
if (document->sticker()) {
return true;
}
return data.shouldDownload(
SourceFromPeer(peer),
TypeFromDocument(document),
document->size);
}
bool Should(
const Full &data,
not_null<DocumentData*> document) {
if (document->sticker()) {
return true;
}
const auto type = TypeFromDocument(document);
const auto size = document->size;
return data.shouldDownload(Source::User, type, size)
|| data.shouldDownload(Source::Group, type, size)
|| data.shouldDownload(Source::Channel, type, size);
}
bool Should(
const Full &data,
not_null<PeerData*> peer,
not_null<Images::Source*> image) {
return data.shouldDownload(
SourceFromPeer(peer),
Type::Photo,
image->bytesSize());
}
} // namespace AutoDownload
} // namespace Data

View File

@@ -0,0 +1,110 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include <array>
namespace Images {
class Source;
} // namespace Images
namespace Data {
namespace AutoDownload {
constexpr auto kMaxBytesLimit = 3000 * 512 * 1024;
enum class Source {
User = 0x00,
Group = 0x01,
Channel = 0x02,
};
constexpr auto kSourcesCount = 3;
enum class Type {
Photo = 0x00,
Video = 0x01,
VoiceMessage = 0x02,
VideoMessage = 0x03,
Music = 0x04,
GIF = 0x05,
File = 0x06,
};
constexpr auto kTypesCount = 7;
class Single {
public:
void setBytesLimit(int bytesLimit);
bool hasValue() const;
bool shouldDownload(int fileSize) const;
int bytesLimit() const;
qint32 serialize() const;
bool setFromSerialized(qint32 serialized);
private:
int _limit = -1;
};
class Set {
public:
void setBytesLimit(Type type, int bytesLimit);
bool hasValue(Type type) const;
bool shouldDownload(Type type, int fileSize) const;
int bytesLimit(Type type) const;
qint32 serialize(Type type) const;
bool setFromSerialized(Type type, qint32 serialized);
private:
const Single &single(Type type) const;
Single &single(Type type);
std::array<Single, kTypesCount> _data;
};
class Full {
public:
void setBytesLimit(Source source, Type type, int bytesLimit);
bool shouldDownload(Source source, Type type, int fileSize) const;
int bytesLimit(Source source, Type type) const;
QByteArray serialize() const;
bool setFromSerialized(const QByteArray &serialized);
static Full FullDisabled();
private:
const Set &set(Source source) const;
Set &set(Source source);
const Set &setOrDefault(Source source, Type type) const;
std::array<Set, kSourcesCount> _data;
};
bool Should(
const Full &data,
not_null<PeerData*> peer,
not_null<DocumentData*> document);
bool Should(
const Full &data,
not_null<DocumentData*> document);
bool Should(
const Full &data,
not_null<PeerData*> peer,
not_null<Images::Source*> image);
} // namespace AutoDownload
} // namespace Data

View File

@@ -635,43 +635,44 @@ void DocumentData::automaticLoad(
if (loaded() || status != FileReady) return;
if (saveToCache() && _loader != CancelledMtpFileLoader) {
if (type == StickerDocument) {
save(origin, QString(), _actionOnLoad, _actionOnLoadMsgId);
} else if (isAnimation()) {
bool loadFromCloud = false;
if (item) {
if (item->history()->peer->isUser()) {
loadFromCloud = !(cAutoDownloadGif() & dbiadNoPrivate);
} else {
loadFromCloud = !(cAutoDownloadGif() & dbiadNoGroups);
}
} else { // if load at least anywhere
loadFromCloud = !(cAutoDownloadGif() & dbiadNoPrivate) || !(cAutoDownloadGif() & dbiadNoGroups);
}
save(origin, QString(), _actionOnLoad, _actionOnLoadMsgId, loadFromCloud ? LoadFromCloudOrLocal : LoadFromLocalOnly, true);
} else if (isVoiceMessage()) {
if (item) {
bool loadFromCloud = false;
if (item->history()->peer->isUser()) {
loadFromCloud = !(cAutoDownloadAudio() & dbiadNoPrivate);
} else {
loadFromCloud = !(cAutoDownloadAudio() & dbiadNoGroups);
}
save(origin, QString(), _actionOnLoad, _actionOnLoadMsgId, loadFromCloud ? LoadFromCloudOrLocal : LoadFromLocalOnly, true);
}
if (type == StickerDocument
|| isAnimation()
|| (isVoiceMessage() && item)) {
const auto shouldLoadFromCloud = item
? Data::AutoDownload::Should(
Auth().settings().autoDownload(),
item->history()->peer,
this)
: Data::AutoDownload::Should(
Auth().settings().autoDownload(),
this);
const auto loadFromCloud = shouldLoadFromCloud
? LoadFromCloudOrLocal
: LoadFromLocalOnly;
save(
origin,
QString(),
_actionOnLoad,
_actionOnLoadMsgId,
loadFromCloud,
true);
}
}
}
void DocumentData::automaticLoadSettingsChanged() {
if (loaded() || status != FileReady || (!isAnimation() && !isVoiceMessage()) || !saveToCache() || _loader != CancelledMtpFileLoader) {
if (_loader != CancelledMtpFileLoader
|| status != FileReady
|| loaded()) {
return;
}
_loader = nullptr;
}
void DocumentData::performActionOnLoad() {
if (_actionOnLoad == ActionOnLoadNone) return;
if (_actionOnLoad == ActionOnLoadNone) {
return;
}
auto loc = location(true);
auto already = loc.name();

View File

@@ -84,7 +84,7 @@ public:
void automaticLoad(
Data::FileOrigin origin,
const HistoryItem *item); // auto load sticker or video
const HistoryItem *item);
void automaticLoadSettingsChanged();
enum FilePathResolveType {