diff --git a/Telegram/Resources/export_html/css/style.css b/Telegram/Resources/export_html/css/style.css
index 31136ab9c1..1e4bcfaced 100644
--- a/Telegram/Resources/export_html/css/style.css
+++ b/Telegram/Resources/export_html/css/style.css
@@ -119,45 +119,45 @@ pre {
}
.color_red,
.userpic1,
-.media_call .thumb,
-.media_file .thumb,
-.media_live_location .thumb {
+.media_call .fill,
+.media_file .fill,
+.media_live_location .fill {
background-color: #ff5555;
}
.color_green,
.userpic2,
-.media_call.success .thumb {
+.media_call.success .fill {
background-color: #64bf47;
}
.color_yellow,
.userpic3,
-.media_venue .thumb {
+.media_venue .fill {
background-color: #ffab00;
}
.color_blue,
.userpic4,
-.media_audio_file .thumb,
-.media_voice_message .thumb {
+.media_audio_file .fill,
+.media_voice_message .fill {
background-color: #4f9cd9;
}
.color_purple,
.userpic5,
-.media_game .thumb {
+.media_game .fill {
background-color: #9884e8;
}
.color_pink,
.userpic6,
-.media_invoice .thumb {
+.media_invoice .fill {
background-color: #e671a5;
}
.color_sea,
.userpic7,
-.media_location .thumb {
+.media_location .fill {
background-color: #47bcd1;
}
.color_orange,
.userpic8,
-.media_contact .thumb {
+.media_contact .fill {
background-color: #ff8c44;
}
.personal_info {
@@ -289,10 +289,13 @@ a.block_link:hover {
margin: 0 -10px;
padding: 5px 10px;
}
+.default .media .fill,
.default .media .thumb {
width: 48px;
height: 48px;
border-radius: 50%;
+}
+.default .media .fill {
background-repeat: no-repeat;
background-position: 12px 12px;
background-size: 24px 24px;
@@ -399,30 +402,30 @@ a.block_link:hover {
.page_header a.content {
background-image: url(../images/back@2x.png);
}
-.media_call .thumb {
+.media_call .fill {
background-image: url(../images/media_call@2x.png)
}
-.media_contact .thumb {
+.media_contact .fill {
background-image: url(../images/media_contact@2x.png)
}
-.media_file .thumb {
+.media_file .fill {
background-image: url(../images/media_file@2x.png)
}
-.media_game .thumb {
+.media_game .fill {
background-image: url(../images/media_game@2x.png)
}
-.media_live_location .thumb,
-.media_location .thumb,
-.media_venue .thumb {
+.media_live_location .fill,
+.media_location .fill,
+.media_venue .fill {
background-image: url(../images/media_location@2x.png)
}
-.media_audio_file .thumb {
+.media_audio_file .fill {
background-image: url(../images/media_music@2x.png)
}
-.media_invoice .thumb {
+.media_invoice .fill {
background-image: url(../images/media_shop@2x.png)
}
-.media_voice_message .thumb {
+.media_voice_message .fill {
background-image: url(../images/media_voice@2x.png)
}
}
diff --git a/Telegram/SourceFiles/export/data/export_data_types.cpp b/Telegram/SourceFiles/export/data/export_data_types.cpp
index eba6f47c48..949530e5d1 100644
--- a/Telegram/SourceFiles/export/data/export_data_types.cpp
+++ b/Telegram/SourceFiles/export/data/export_data_types.cpp
@@ -389,17 +389,36 @@ Document ParseDocument(
data.match([&](const MTPDdocument &data) {
result.id = data.vid.v;
result.date = data.vdate.v;
+ result.mime = ParseString(data.vmime_type);
+ ParseAttributes(result, data.vattributes);
+
result.file.size = data.vsize.v;
result.file.location.dcId = data.vdc_id.v;
result.file.location.data = MTP_inputDocumentFileLocation(
data.vid,
data.vaccess_hash,
data.vversion);
- result.mime = ParseString(data.vmime_type);
- ParseAttributes(result, data.vattributes);
- result.file.suggestedPath = suggestedFolder
+ const auto path = result.file.suggestedPath = suggestedFolder
+ DocumentFolder(result) + '/'
+ CleanDocumentName(ComputeDocumentName(context, result));
+
+ result.thumb = data.vthumb.match([](const MTPDphotoSizeEmpty &) {
+ return Image();
+ }, [&](const auto &data) {
+ auto result = Image();
+ result.width = data.vw.v;
+ result.height = data.vh.v;
+ result.file.location = ParseLocation(data.vlocation);
+ if constexpr (MTPDphotoCachedSize::Is()) {
+ result.file.content = data.vbytes.v;
+ result.file.size = result.file.content.size();
+ } else {
+ result.file.content = QByteArray();
+ result.file.size = data.vsize.v;
+ }
+ result.file.suggestedPath = path + "_thumb.jpg";
+ return result;
+ });
}, [&](const MTPDdocumentEmpty &data) {
result.id = data.vid.v;
});
@@ -735,6 +754,24 @@ const File &Media::file() const {
});
}
+Image &Media::thumb() {
+ return content.match([](Document &data) -> Image& {
+ return data.thumb;
+ }, [](auto&) -> Image& {
+ static Image result;
+ return result;
+ });
+}
+
+const Image &Media::thumb() const {
+ return content.match([](const Document &data) -> const Image& {
+ return data.thumb;
+ }, [](const auto &) -> const Image& {
+ static const Image result;
+ return result;
+ });
+}
+
Media ParseMedia(
ParseMediaContext &context,
const MTPMessageMedia &data,
@@ -936,6 +973,14 @@ const File &Message::file() const {
return media.file();
}
+Image &Message::thumb() {
+ return media.thumb();
+}
+
+const Image &Message::thumb() const {
+ return media.thumb();
+}
+
Message ParseMessage(
ParseMediaContext &context,
const MTPMessage &data,
diff --git a/Telegram/SourceFiles/export/data/export_data_types.h b/Telegram/SourceFiles/export/data/export_data_types.h
index 7facf8ec73..d14dc0dddf 100644
--- a/Telegram/SourceFiles/export/data/export_data_types.h
+++ b/Telegram/SourceFiles/export/data/export_data_types.h
@@ -114,6 +114,7 @@ struct Document {
TimeId date = 0;
File file;
+ Image thumb;
Utf8String name;
Utf8String mime;
@@ -292,6 +293,8 @@ struct Media {
File &file();
const File &file() const;
+ Image &thumb();
+ const Image &thumb() const;
};
struct ParseMediaContext {
@@ -478,6 +481,8 @@ struct Message {
File &file();
const File &file() const;
+ Image &thumb();
+ const Image &thumb() const;
};
Message ParseMessage(
diff --git a/Telegram/SourceFiles/export/export_api_wrap.cpp b/Telegram/SourceFiles/export/export_api_wrap.cpp
index 34ddd1b5ad..148fe2472e 100644
--- a/Telegram/SourceFiles/export/export_api_wrap.cpp
+++ b/Telegram/SourceFiles/export/export_api_wrap.cpp
@@ -139,7 +139,7 @@ struct ApiWrap::UserpicsProcess {
base::optional slice;
uint64 maxId = 0;
bool lastSlice = false;
- int fileIndex = -1;
+ int fileIndex = 0;
};
struct ApiWrap::OtherDataProcess {
@@ -210,7 +210,7 @@ struct ApiWrap::ChatProcess {
Data::ParseMediaContext context;
base::optional slice;
bool lastSlice = false;
- int fileIndex = -1;
+ int fileIndex = 0;
};
@@ -727,7 +727,7 @@ void ApiWrap::loadUserpicsFiles(Data::UserpicsSlice &&slice) {
_userpicsProcess->lastSlice = true;
}
_userpicsProcess->slice = std::move(slice);
- _userpicsProcess->fileIndex = -1;
+ _userpicsProcess->fileIndex = 0;
loadNextUserpic();
}
@@ -735,14 +735,11 @@ void ApiWrap::loadNextUserpic() {
Expects(_userpicsProcess != nullptr);
Expects(_userpicsProcess->slice.has_value());
- auto &list = _userpicsProcess->slice->list;
- while (true) {
- const auto index = ++_userpicsProcess->fileIndex;
- if (index >= list.size()) {
- break;
- }
+ for (auto &list = _userpicsProcess->slice->list
+ ; _userpicsProcess->fileIndex < list.size()
+ ; ++_userpicsProcess->fileIndex) {
const auto ready = processFileLoad(
- list[index].image.file,
+ list[_userpicsProcess->fileIndex].image.file,
[=](FileProgress value) { return loadUserpicProgress(value); },
[=](const QString &path) { loadUserpicDone(path); });
if (!ready) {
@@ -1213,7 +1210,7 @@ void ApiWrap::loadMessagesFiles(Data::MessagesSlice &&slice) {
_chatProcess->lastSlice = true;
}
_chatProcess->slice = std::move(slice);
- _chatProcess->fileIndex = -1;
+ _chatProcess->fileIndex = 0;
loadNextMessageFile();
}
@@ -1222,23 +1219,31 @@ void ApiWrap::loadNextMessageFile() {
Expects(_chatProcess != nullptr);
Expects(_chatProcess->slice.has_value());
- auto &list = _chatProcess->slice->list;
- while (true) {
- const auto index = ++_chatProcess->fileIndex;
- if (index >= list.size()) {
- break;
- }
+ for (auto &list = _chatProcess->slice->list
+ ; _chatProcess->fileIndex < list.size()
+ ; ++_chatProcess->fileIndex) {
const auto fileProgress = [=](FileProgress value) {
return loadMessageFileProgress(value);
};
const auto ready = processFileLoad(
- list[index].file(),
+ list[_chatProcess->fileIndex].file(),
fileProgress,
[=](const QString &path) { loadMessageFileDone(path); },
- &list[index]);
+ &list[_chatProcess->fileIndex]);
if (!ready) {
return;
}
+ const auto thumbProgress = [=](FileProgress value) {
+ return loadMessageThumbProgress(value);
+ };
+ const auto thumbReady = processFileLoad(
+ list[_chatProcess->fileIndex].thumb().file,
+ thumbProgress,
+ [=](const QString &path) { loadMessageThumbDone(path); },
+ &list[_chatProcess->fileIndex]);
+ if (!thumbReady) {
+ return;
+ }
}
finishMessagesSlice();
}
@@ -1296,6 +1301,25 @@ void ApiWrap::loadMessageFileDone(const QString &relativePath) {
loadNextMessageFile();
}
+bool ApiWrap::loadMessageThumbProgress(FileProgress progress) {
+ return loadMessageFileProgress(progress);
+}
+
+void ApiWrap::loadMessageThumbDone(const QString &relativePath) {
+ Expects(_chatProcess != nullptr);
+ Expects(_chatProcess->slice.has_value());
+ Expects((_chatProcess->fileIndex >= 0)
+ && (_chatProcess->fileIndex < _chatProcess->slice->list.size()));
+
+ const auto index = _chatProcess->fileIndex;
+ auto &file = _chatProcess->slice->list[index].thumb().file;
+ file.relativePath = relativePath;
+ if (relativePath.isEmpty()) {
+ file.skipReason = Data::File::SkipReason::Unavailable;
+ }
+ loadNextMessageFile();
+}
+
void ApiWrap::finishMessages() {
Expects(_chatProcess != nullptr);
Expects(!_chatProcess->slice.has_value());
@@ -1311,7 +1335,8 @@ bool ApiWrap::processFileLoad(
Data::Message *message) {
using SkipReason = Data::File::SkipReason;
- if (!file.relativePath.isEmpty()) {
+ if (!file.relativePath.isEmpty()
+ || file.skipReason != SkipReason::None) {
return true;
} else if (!file.location && file.content.isEmpty()) {
file.skipReason = SkipReason::Unavailable;
diff --git a/Telegram/SourceFiles/export/export_api_wrap.h b/Telegram/SourceFiles/export/export_api_wrap.h
index 6362efb9a4..cdddc9df6a 100644
--- a/Telegram/SourceFiles/export/export_api_wrap.h
+++ b/Telegram/SourceFiles/export/export_api_wrap.h
@@ -150,6 +150,8 @@ private:
void loadNextMessageFile();
bool loadMessageFileProgress(FileProgress value);
void loadMessageFileDone(const QString &relativePath);
+ bool loadMessageThumbProgress(FileProgress value);
+ void loadMessageThumbDone(const QString &relativePath);
void finishMessagesSlice();
void finishMessages();
diff --git a/Telegram/SourceFiles/export/output/export_output_html.cpp b/Telegram/SourceFiles/export/output/export_output_html.cpp
index e226fc0fd4..b0b1dfad65 100644
--- a/Telegram/SourceFiles/export/output/export_output_html.cpp
+++ b/Telegram/SourceFiles/export/output/export_output_html.cpp
@@ -262,10 +262,6 @@ Data::Utf8String FormatUsername(const Data::Utf8String &username) {
return username.isEmpty() ? username : ('@' + username);
}
-QByteArray FormatFilePath(const Data::File &file) {
- return file.relativePath.toUtf8();
-}
-
bool DisplayDate(TimeId date, TimeId previousDate) {
if (!previousDate) {
return true;
@@ -353,6 +349,7 @@ struct MediaData {
QByteArray description;
QByteArray status;
QByteArray classes;
+ QString thumb;
QString link;
};
@@ -884,33 +881,6 @@ auto HtmlWriter::Wrap::pushMessage(
"of Telegram Desktop. Please update the application.") };
}
- using SkipReason = Data::File::SkipReason;
- const auto formatPath = [&](
- const Data::File &file,
- const QByteArray &label,
- const QByteArray &name = QByteArray()) {
- Expects(!file.relativePath.isEmpty()
- || file.skipReason != SkipReason::None);
-
- const auto pre = name.isEmpty()
- ? QByteArray()
- : SerializeString(name + ' ');
- switch (file.skipReason) {
- case SkipReason::Unavailable:
- return pre + "(" + label + " unavailable, "
- "please try again later)";
- case SkipReason::FileSize:
- return pre + "(" + label + " exceeds maximum size. "
- "Change data exporting settings to download.)";
- case SkipReason::FileType:
- return pre + "(" + label + " not included. "
- "Change data exporting settings to download.)";
- case SkipReason::None: return SerializeLink(
- FormatFilePath(file),
- relativePath(file.relativePath));
- }
- Unexpected("Skip reason while writing file path.");
- };
const auto wrapReplyToLink = [&](const QByteArray &text) {
return " 0) {
+ pushPath(data.thumb.file, "thumbnail");
+ }
const auto pushType = [&](const QByteArray &value) {
push("media_type", value);
};