Add some HTML design to export, except messages.
NB Testing the layout, the app is not in a working condition.
@ -1,3 +0,0 @@
|
|||||||
.page_wrap {
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
247
Telegram/Resources/export_html/css/style.css
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font: 12px/18px 'Open Sans',"Lucida Grande","Lucida Sans Unicode",Arial,Helvetica,Verdana,sans-serif;
|
||||||
|
}
|
||||||
|
.clearfix:after {
|
||||||
|
content: " ";
|
||||||
|
visibility: hidden;
|
||||||
|
display: block;
|
||||||
|
height: 0;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
.pull_left {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
.pull_right {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
.page_wrap {
|
||||||
|
background-color: #ffffff;
|
||||||
|
color: #000000;
|
||||||
|
}
|
||||||
|
.page_wrap a {
|
||||||
|
color: #168acd;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.page_wrap a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
.page_header {
|
||||||
|
position: fixed;
|
||||||
|
background-color: #ffffff;
|
||||||
|
width: 100%;
|
||||||
|
border-bottom: 1px solid #e3e6e8;
|
||||||
|
}
|
||||||
|
.page_header .content {
|
||||||
|
width: 480px;
|
||||||
|
margin: 0 auto;
|
||||||
|
border-radius: 0 !important;
|
||||||
|
}
|
||||||
|
.page_header a.content {
|
||||||
|
background-image: url(../images/back.png);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: 24px 21px;
|
||||||
|
background-size: 24px 24px;
|
||||||
|
}
|
||||||
|
.bold {
|
||||||
|
color: #212121;
|
||||||
|
}
|
||||||
|
.details {
|
||||||
|
color: #70777b;
|
||||||
|
}
|
||||||
|
.page_header .content .text {
|
||||||
|
padding: 24px 24px 22px 24px;
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 700;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.page_header a.content .text {
|
||||||
|
padding: 24px 24px 22px 82px;
|
||||||
|
}
|
||||||
|
.page_body {
|
||||||
|
padding-top: 64px;
|
||||||
|
width: 480px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
.page_about {
|
||||||
|
padding: 24px 24px;
|
||||||
|
}
|
||||||
|
.with_divider {
|
||||||
|
border-top: 1px solid #e3e6e8;
|
||||||
|
}
|
||||||
|
.userpic_link {
|
||||||
|
display: block;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.userpic_link:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.userpic {
|
||||||
|
display: block;
|
||||||
|
border-radius: 50%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.userpic .initials {
|
||||||
|
display: block;
|
||||||
|
color: #fff;
|
||||||
|
text-align: center;
|
||||||
|
text-transform: uppercase;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
.userpic1 {
|
||||||
|
background-color: #ff5555;
|
||||||
|
}
|
||||||
|
.userpic2 {
|
||||||
|
background-color: #64bf47;
|
||||||
|
}
|
||||||
|
.userpic3 {
|
||||||
|
background-color: #ffab00;
|
||||||
|
}
|
||||||
|
.userpic4 {
|
||||||
|
background-color: #4f9cd9;
|
||||||
|
}
|
||||||
|
.userpic5 {
|
||||||
|
background-color: #9884e8;
|
||||||
|
}
|
||||||
|
.userpic6 {
|
||||||
|
background-color: #e671a5;
|
||||||
|
}
|
||||||
|
.userpic7 {
|
||||||
|
background-color: #47bcd1;
|
||||||
|
}
|
||||||
|
.userpic8 {
|
||||||
|
background-color: #ff8c44;
|
||||||
|
}
|
||||||
|
.personal_info {
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
.personal_info .userpic .initials {
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
||||||
|
.personal_info .rows {
|
||||||
|
float: left;
|
||||||
|
padding-right: 24px;
|
||||||
|
}
|
||||||
|
.personal_info .names {
|
||||||
|
width: 164px;
|
||||||
|
}
|
||||||
|
.personal_info .info {
|
||||||
|
width: 124px;
|
||||||
|
}
|
||||||
|
.personal_info .bio {
|
||||||
|
width: 400px;
|
||||||
|
}
|
||||||
|
.personal_info .row {
|
||||||
|
padding-bottom: 16px;
|
||||||
|
}
|
||||||
|
a.block_link {
|
||||||
|
display: block;
|
||||||
|
text-decoration: none !important;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
a.block_link:hover {
|
||||||
|
text-decoration: none !important;
|
||||||
|
background-color: #f5f7f8;
|
||||||
|
}
|
||||||
|
.sections {
|
||||||
|
padding: 11px 0;
|
||||||
|
}
|
||||||
|
.section {
|
||||||
|
height: 48px;
|
||||||
|
background-position: 24px 12px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: 24px 24px;
|
||||||
|
}
|
||||||
|
.section .counter {
|
||||||
|
float: right;
|
||||||
|
padding: 14px 24px 0;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
.section .label {
|
||||||
|
padding: 15px 0 0 82px;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
.section.calls {
|
||||||
|
background-image: url(../images/calls.png);
|
||||||
|
}
|
||||||
|
.section.chats {
|
||||||
|
background-image: url(../images/chats.png);
|
||||||
|
}
|
||||||
|
.section.contacts {
|
||||||
|
background-image: url(../images/contacts.png);
|
||||||
|
}
|
||||||
|
.section.frequent {
|
||||||
|
background-image: url(../images/frequent.png);
|
||||||
|
}
|
||||||
|
.section.photos {
|
||||||
|
background-image: url(../images/photos.png);
|
||||||
|
}
|
||||||
|
.section.sessions {
|
||||||
|
background-image: url(../images/sessions.png);
|
||||||
|
}
|
||||||
|
.section.web {
|
||||||
|
background-image: url(../images/web.png);
|
||||||
|
}
|
||||||
|
@media only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min-device-pixel-ratio: 2) {
|
||||||
|
.section.calls {
|
||||||
|
background-image: url(../images/calls@2x.png);
|
||||||
|
}
|
||||||
|
.section.chats {
|
||||||
|
background-image: url(../images/chats@2x.png);
|
||||||
|
}
|
||||||
|
.section.contacts {
|
||||||
|
background-image: url(../images/contacts@2x.png);
|
||||||
|
}
|
||||||
|
.section.frequent {
|
||||||
|
background-image: url(../images/frequent@2x.png);
|
||||||
|
}
|
||||||
|
.section.photos {
|
||||||
|
background-image: url(../images/photos@2x.png);
|
||||||
|
}
|
||||||
|
.section.sessions {
|
||||||
|
background-image: url(../images/sessions@2x.png);
|
||||||
|
}
|
||||||
|
.section.web {
|
||||||
|
background-image: url(../images/web@2x.png);
|
||||||
|
}
|
||||||
|
.page_header a.content {
|
||||||
|
background-image: url(../images/back@2x.png);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.list_page .page_about {
|
||||||
|
padding: 16px 24px 0;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
.list_page .entry_list {
|
||||||
|
padding: 16px 0;
|
||||||
|
}
|
||||||
|
.list_page .entry {
|
||||||
|
padding: 10px 16px;
|
||||||
|
}
|
||||||
|
.list_page .entry .userpic .initials {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
.list_page .entry .body {
|
||||||
|
margin-left: 66px;
|
||||||
|
}
|
||||||
|
.list_page .entry .name {
|
||||||
|
padding: 4px 0 2px;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.list_page .entry .subname {
|
||||||
|
padding-top: 4px;
|
||||||
|
}
|
||||||
|
.list_page .entry .details_entry {
|
||||||
|
padding-top: 4px;
|
||||||
|
}
|
||||||
|
.list_page .entry .info {
|
||||||
|
font-size: 11px;
|
||||||
|
padding-top: 5px;
|
||||||
|
}
|
||||||
|
.history {
|
||||||
|
padding: 16px 0;
|
||||||
|
}
|
BIN
Telegram/Resources/export_html/images/back.png
Normal file
After Width: | Height: | Size: 312 B |
BIN
Telegram/Resources/export_html/images/back@2x.png
Normal file
After Width: | Height: | Size: 518 B |
BIN
Telegram/Resources/export_html/images/calls.png
Normal file
After Width: | Height: | Size: 656 B |
BIN
Telegram/Resources/export_html/images/calls@2x.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Telegram/Resources/export_html/images/chats.png
Normal file
After Width: | Height: | Size: 283 B |
BIN
Telegram/Resources/export_html/images/chats@2x.png
Normal file
After Width: | Height: | Size: 454 B |
BIN
Telegram/Resources/export_html/images/contacts.png
Normal file
After Width: | Height: | Size: 508 B |
BIN
Telegram/Resources/export_html/images/contacts@2x.png
Normal file
After Width: | Height: | Size: 1023 B |
BIN
Telegram/Resources/export_html/images/frequent.png
Normal file
After Width: | Height: | Size: 771 B |
BIN
Telegram/Resources/export_html/images/frequent@2x.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
Telegram/Resources/export_html/images/photos.png
Normal file
After Width: | Height: | Size: 415 B |
BIN
Telegram/Resources/export_html/images/photos@2x.png
Normal file
After Width: | Height: | Size: 750 B |
BIN
Telegram/Resources/export_html/images/sessions.png
Normal file
After Width: | Height: | Size: 134 B |
BIN
Telegram/Resources/export_html/images/sessions@2x.png
Normal file
After Width: | Height: | Size: 216 B |
BIN
Telegram/Resources/export_html/images/web.png
Normal file
After Width: | Height: | Size: 266 B |
BIN
Telegram/Resources/export_html/images/web@2x.png
Normal file
After Width: | Height: | Size: 447 B |
@ -1,6 +1,22 @@
|
|||||||
<RCC>
|
<RCC>
|
||||||
<qresource prefix="/export">
|
<qresource prefix="/export">
|
||||||
<file alias="css/style.css">../css/export_style.css</file>
|
<file alias="css/style.css">../export_html/css/style.css</file>
|
||||||
|
<file alias="images/back.png">../export_html/images/back.png</file>
|
||||||
|
<file alias="images/back@2x.png">../export_html/images/back@2x.png</file>
|
||||||
|
<file alias="images/calls.png">../export_html/images/calls.png</file>
|
||||||
|
<file alias="images/calls@2x.png">../export_html/images/calls@2x.png</file>
|
||||||
|
<file alias="images/chats.png">../export_html/images/chats.png</file>
|
||||||
|
<file alias="images/chats@2x.png">../export_html/images/chats@2x.png</file>
|
||||||
|
<file alias="images/contacts.png">../export_html/images/contacts.png</file>
|
||||||
|
<file alias="images/contacts@2x.png">../export_html/images/contacts@2x.png</file>
|
||||||
|
<file alias="images/frequent.png">../export_html/images/frequent.png</file>
|
||||||
|
<file alias="images/frequent@2x.png">../export_html/images/frequent@2x.png</file>
|
||||||
|
<file alias="images/photos.png">../export_html/images/photos.png</file>
|
||||||
|
<file alias="images/photos@2x.png">../export_html/images/photos@2x.png</file>
|
||||||
|
<file alias="images/sessions.png">../export_html/images/sessions.png</file>
|
||||||
|
<file alias="images/sessions@2x.png">../export_html/images/sessions@2x.png</file>
|
||||||
|
<file alias="images/web.png">../export_html/images/web.png</file>
|
||||||
|
<file alias="images/web@2x.png">../export_html/images/web@2x.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
<qresource prefix="/gui">
|
<qresource prefix="/gui">
|
||||||
<file alias="fonts/OpenSans-Regular.ttf">../fonts/OpenSans-Regular.ttf</file>
|
<file alias="fonts/OpenSans-Regular.ttf">../fonts/OpenSans-Regular.ttf</file>
|
||||||
|
@ -8,15 +8,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
#include "export/data/export_data_types.h"
|
#include "export/data/export_data_types.h"
|
||||||
|
|
||||||
#include "export/export_settings.h"
|
#include "export/export_settings.h"
|
||||||
|
#include "export/output/export_output_file.h"
|
||||||
#include "core/mime_type.h"
|
#include "core/mime_type.h"
|
||||||
|
|
||||||
#include <QtCore/QDateTime>
|
#include <QtCore/QDateTime>
|
||||||
#include <QtCore/QRegularExpression>
|
#include <QtCore/QRegularExpression>
|
||||||
|
#include <QtGui/QImageReader>
|
||||||
|
|
||||||
namespace App { // Hackish..
|
namespace App { // Hackish..
|
||||||
QString formatPhone(QString phone);
|
QString formatPhone(QString phone);
|
||||||
} // namespace App
|
} // namespace App
|
||||||
QString FillAmountAndCurrency(uint64 amount, const QString ¤cy);
|
QString FillAmountAndCurrency(uint64 amount, const QString ¤cy);
|
||||||
|
QString formatSizeText(qint64 size);
|
||||||
|
|
||||||
namespace Export {
|
namespace Export {
|
||||||
namespace Data {
|
namespace Data {
|
||||||
@ -24,6 +27,7 @@ namespace {
|
|||||||
|
|
||||||
constexpr auto kUserPeerIdShift = (1ULL << 32);
|
constexpr auto kUserPeerIdShift = (1ULL << 32);
|
||||||
constexpr auto kChatPeerIdShift = (2ULL << 32);
|
constexpr auto kChatPeerIdShift = (2ULL << 32);
|
||||||
|
constexpr auto kMaxImageSize = 10000;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@ -39,6 +43,43 @@ int32 BarePeerId(PeerId peerId) {
|
|||||||
return int32(peerId & 0xFFFFFFFFULL);
|
return int32(peerId & 0xFFFFFFFFULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int PeerColorIndex(int32 bareId) {
|
||||||
|
const auto index = std::abs(bareId) % 7;
|
||||||
|
const int map[] = { 0, 7, 4, 1, 6, 3, 5 };
|
||||||
|
return map[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
int StringBarePeerId(const Utf8String &data) {
|
||||||
|
auto result = 0xFF;
|
||||||
|
for (const auto ch : data) {
|
||||||
|
result *= 239;
|
||||||
|
result += ch;
|
||||||
|
result &= 0xFF;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ApplicationColorIndex(int applicationId) {
|
||||||
|
static const auto official = std::map<int, int> {
|
||||||
|
{ 1, 0 }, // iOS
|
||||||
|
{ 7, 0 }, // iOS X
|
||||||
|
{ 6, 1 }, // Android
|
||||||
|
{ 21724, 1 }, // Android X
|
||||||
|
{ 2834, 2 }, // macOS
|
||||||
|
{ 2496, 3 }, // Webogram
|
||||||
|
{ 2040, 4 }, // Desktop
|
||||||
|
{ 1429, 5 }, // Windows Phone
|
||||||
|
};
|
||||||
|
if (const auto i = official.find(applicationId); i != end(official)) {
|
||||||
|
return i->second;
|
||||||
|
}
|
||||||
|
return PeerColorIndex(applicationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
int DomainApplicationId(const Utf8String &data) {
|
||||||
|
return 0x1000 + StringBarePeerId(data);
|
||||||
|
}
|
||||||
|
|
||||||
bool IsChatPeerId(PeerId peerId) {
|
bool IsChatPeerId(PeerId peerId) {
|
||||||
return (peerId & kChatPeerIdShift) == kChatPeerIdShift;
|
return (peerId & kChatPeerIdShift) == kChatPeerIdShift;
|
||||||
}
|
}
|
||||||
@ -440,6 +481,43 @@ UserpicsSlice ParseUserpicsSlice(
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString WriteImageThumb(
|
||||||
|
const QString &basePath,
|
||||||
|
const QString &largePath,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
const QString &postfix) {
|
||||||
|
if (largePath.isEmpty()) {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
const auto path = basePath + largePath;
|
||||||
|
QImageReader reader(path);
|
||||||
|
if (!reader.canRead()) {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
const auto size = reader.size();
|
||||||
|
if (size.isEmpty()
|
||||||
|
|| size.width() >= kMaxImageSize
|
||||||
|
|| size.height() >= kMaxImageSize) {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
auto image = reader.read();
|
||||||
|
if (image.isNull()) {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
const auto format = reader.format();
|
||||||
|
const auto lastSlash = largePath.lastIndexOf('/');
|
||||||
|
const auto firstDot = largePath.indexOf('.', lastSlash + 1);
|
||||||
|
const auto thumb = (firstDot >= 0)
|
||||||
|
? largePath.mid(0, firstDot) + postfix + largePath.mid(firstDot)
|
||||||
|
: largePath + postfix;
|
||||||
|
const auto result = Output::File::PrepareRelativePath(basePath, thumb);
|
||||||
|
if (!image.save(basePath + result, reader.format(), reader.quality())) {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
ContactInfo ParseContactInfo(const MTPUser &data) {
|
ContactInfo ParseContactInfo(const MTPUser &data) {
|
||||||
auto result = ContactInfo();
|
auto result = ContactInfo();
|
||||||
data.match([&](const MTPDuser &data) {
|
data.match([&](const MTPDuser &data) {
|
||||||
@ -459,6 +537,13 @@ ContactInfo ParseContactInfo(const MTPUser &data) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ContactColorIndex(const ContactInfo &data) {
|
||||||
|
if (data.userId != 0) {
|
||||||
|
return PeerColorIndex(data.userId);
|
||||||
|
}
|
||||||
|
return PeerColorIndex(StringBarePeerId(data.phoneNumber));
|
||||||
|
}
|
||||||
|
|
||||||
User ParseUser(const MTPUser &data) {
|
User ParseUser(const MTPUser &data) {
|
||||||
auto result = User();
|
auto result = User();
|
||||||
result.info = ParseContactInfo(data);
|
result.info = ParseContactInfo(data);
|
||||||
@ -1066,6 +1151,7 @@ bool AppendTopPeers(ContactsList &to, const MTPcontacts_TopPeers &data) {
|
|||||||
Session ParseSession(const MTPAuthorization &data) {
|
Session ParseSession(const MTPAuthorization &data) {
|
||||||
return data.match([&](const MTPDauthorization &data) {
|
return data.match([&](const MTPDauthorization &data) {
|
||||||
auto result = Session();
|
auto result = Session();
|
||||||
|
result.applicationId = data.vapi_id.v;
|
||||||
result.platform = ParseString(data.vplatform);
|
result.platform = ParseString(data.vplatform);
|
||||||
result.deviceModel = ParseString(data.vdevice_model);
|
result.deviceModel = ParseString(data.vdevice_model);
|
||||||
result.systemVersion = ParseString(data.vsystem_version);
|
result.systemVersion = ParseString(data.vsystem_version);
|
||||||
@ -1170,7 +1256,12 @@ DialogsInfo ParseDialogsInfo(const MTPmessages_Dialogs &data) {
|
|||||||
info.type = peer.user()
|
info.type = peer.user()
|
||||||
? DialogTypeFromUser(*peer.user())
|
? DialogTypeFromUser(*peer.user())
|
||||||
: DialogTypeFromChat(*peer.chat());
|
: DialogTypeFromChat(*peer.chat());
|
||||||
info.name = peer.name();
|
info.name = peer.user()
|
||||||
|
? peer.user()->info.firstName
|
||||||
|
: peer.name();
|
||||||
|
info.lastName = peer.user()
|
||||||
|
? peer.user()->info.lastName
|
||||||
|
: Utf8String();
|
||||||
info.input = peer.input();
|
info.input = peer.input();
|
||||||
}
|
}
|
||||||
info.topMessageId = fields.vtop_message.v;
|
info.topMessageId = fields.vtop_message.v;
|
||||||
@ -1297,5 +1388,9 @@ Utf8String FormatMoneyAmount(uint64 amount, const Utf8String ¤cy) {
|
|||||||
QString::fromUtf8(currency)).toUtf8();
|
QString::fromUtf8(currency)).toUtf8();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Utf8String FormatFileSize(int64 size) {
|
||||||
|
return formatSizeText(size).toUtf8();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
} // namespace Export
|
} // namespace Export
|
||||||
|
@ -26,6 +26,9 @@ using PeerId = uint64;
|
|||||||
PeerId UserPeerId(int32 userId);
|
PeerId UserPeerId(int32 userId);
|
||||||
PeerId ChatPeerId(int32 chatId);
|
PeerId ChatPeerId(int32 chatId);
|
||||||
int32 BarePeerId(PeerId peerId);
|
int32 BarePeerId(PeerId peerId);
|
||||||
|
int PeerColorIndex(int32 bareId);
|
||||||
|
int ApplicationColorIndex(int applicationId);
|
||||||
|
int DomainApplicationId(const Utf8String &data);
|
||||||
|
|
||||||
Utf8String ParseString(const MTPstring &data);
|
Utf8String ParseString(const MTPstring &data);
|
||||||
|
|
||||||
@ -77,6 +80,13 @@ struct Image {
|
|||||||
File file;
|
File file;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
QString WriteImageThumb(
|
||||||
|
const QString &basePath,
|
||||||
|
const QString &largePath,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
const QString &postfix = "_thumb");
|
||||||
|
|
||||||
struct ContactInfo {
|
struct ContactInfo {
|
||||||
int32 userId = 0;
|
int32 userId = 0;
|
||||||
Utf8String firstName;
|
Utf8String firstName;
|
||||||
@ -88,6 +98,7 @@ struct ContactInfo {
|
|||||||
};
|
};
|
||||||
|
|
||||||
ContactInfo ParseContactInfo(const MTPUser &data);
|
ContactInfo ParseContactInfo(const MTPUser &data);
|
||||||
|
int ContactColorIndex(const ContactInfo &data);
|
||||||
|
|
||||||
struct Photo {
|
struct Photo {
|
||||||
uint64 id = 0;
|
uint64 id = 0;
|
||||||
@ -230,6 +241,7 @@ std::vector<int> SortedContactsIndices(const ContactsList &data);
|
|||||||
bool AppendTopPeers(ContactsList &to, const MTPcontacts_TopPeers &data);
|
bool AppendTopPeers(ContactsList &to, const MTPcontacts_TopPeers &data);
|
||||||
|
|
||||||
struct Session {
|
struct Session {
|
||||||
|
int applicationId = 0;
|
||||||
Utf8String platform;
|
Utf8String platform;
|
||||||
Utf8String deviceModel;
|
Utf8String deviceModel;
|
||||||
Utf8String systemVersion;
|
Utf8String systemVersion;
|
||||||
@ -485,6 +497,7 @@ struct DialogInfo {
|
|||||||
};
|
};
|
||||||
Type type = Type::Unknown;
|
Type type = Type::Unknown;
|
||||||
Utf8String name;
|
Utf8String name;
|
||||||
|
Utf8String lastName;
|
||||||
|
|
||||||
MTPInputPeer input = MTP_inputPeerEmpty();
|
MTPInputPeer input = MTP_inputPeerEmpty();
|
||||||
int32 topMessageId = 0;
|
int32 topMessageId = 0;
|
||||||
@ -526,14 +539,13 @@ MessagesSlice ParseMessagesSlice(
|
|||||||
const QString &mediaFolder);
|
const QString &mediaFolder);
|
||||||
|
|
||||||
Utf8String FormatPhoneNumber(const Utf8String &phoneNumber);
|
Utf8String FormatPhoneNumber(const Utf8String &phoneNumber);
|
||||||
|
|
||||||
Utf8String FormatDateTime(
|
Utf8String FormatDateTime(
|
||||||
TimeId date,
|
TimeId date,
|
||||||
QChar dateSeparator = QChar('.'),
|
QChar dateSeparator = QChar('.'),
|
||||||
QChar timeSeparator = QChar(':'),
|
QChar timeSeparator = QChar(':'),
|
||||||
QChar separator = QChar(' '));
|
QChar separator = QChar(' '));
|
||||||
|
|
||||||
Utf8String FormatMoneyAmount(uint64 amount, const Utf8String ¤cy);
|
Utf8String FormatMoneyAmount(uint64 amount, const Utf8String ¤cy);
|
||||||
|
Utf8String FormatFileSize(int64 size);
|
||||||
|
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
} // namespace Export
|
} // namespace Export
|
||||||
|
@ -56,19 +56,11 @@ std::unique_ptr<AbstractWriter> CreateWriter(Format format) {
|
|||||||
Unexpected("Format in Export::Output::CreateWriter.");
|
Unexpected("Format in Export::Output::CreateWriter.");
|
||||||
}
|
}
|
||||||
|
|
||||||
Stats AbstractWriter::produceTestExample(const QString &path) {
|
Stats AbstractWriter::produceTestExample(
|
||||||
|
const QString &path,
|
||||||
|
const Environment &environment) {
|
||||||
auto result = Stats();
|
auto result = Stats();
|
||||||
const auto folder = QDir(path).absolutePath();
|
const auto folder = QDir(path).absolutePath();
|
||||||
auto environment = Environment();
|
|
||||||
environment.internalLinksDomain = "https://t.me/";
|
|
||||||
environment.aboutTelegram = "About Telegram";
|
|
||||||
environment.aboutContacts = "About contacts";
|
|
||||||
environment.aboutFrequent = "About frequent";
|
|
||||||
environment.aboutSessions = "About sessions";
|
|
||||||
environment.aboutWebSessions = "About web sessions";
|
|
||||||
environment.aboutChats = "About chats";
|
|
||||||
environment.aboutLeftChats = "About left chats";
|
|
||||||
|
|
||||||
auto settings = Settings();
|
auto settings = Settings();
|
||||||
settings.format = format();
|
settings.format = format();
|
||||||
settings.path = (folder.endsWith('/') ? folder : (folder + '/'))
|
settings.path = (folder.endsWith('/') ? folder : (folder + '/'))
|
||||||
|
@ -90,7 +90,9 @@ public:
|
|||||||
|
|
||||||
virtual ~AbstractWriter() = default;
|
virtual ~AbstractWriter() = default;
|
||||||
|
|
||||||
Stats produceTestExample(const QString &path);
|
Stats produceTestExample(
|
||||||
|
const QString &path,
|
||||||
|
const Environment &environment);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -14,6 +14,29 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
|
|
||||||
namespace Export {
|
namespace Export {
|
||||||
namespace Output {
|
namespace Output {
|
||||||
|
namespace details {
|
||||||
|
|
||||||
|
class HtmlContext {
|
||||||
|
public:
|
||||||
|
[[nodiscard]] QByteArray pushTag(
|
||||||
|
const QByteArray &tag,
|
||||||
|
std::map<QByteArray, QByteArray> &&attributes = {});
|
||||||
|
[[nodiscard]] QByteArray popTag();
|
||||||
|
[[nodiscard]] QByteArray indent() const;
|
||||||
|
[[nodiscard]] bool empty() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Tag {
|
||||||
|
QByteArray name;
|
||||||
|
bool block = true;
|
||||||
|
};
|
||||||
|
std::vector<Tag> _tags;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UserpicData;
|
||||||
|
|
||||||
|
} // namespace details
|
||||||
|
|
||||||
class HtmlWriter : public AbstractWriter {
|
class HtmlWriter : public AbstractWriter {
|
||||||
public:
|
public:
|
||||||
@ -59,9 +82,11 @@ public:
|
|||||||
~HtmlWriter();
|
~HtmlWriter();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
using Context = details::HtmlContext;
|
||||||
|
using UserpicData = details::UserpicData;
|
||||||
class Wrap;
|
class Wrap;
|
||||||
|
|
||||||
Result copyFile(
|
[[nodiscard]] Result copyFile(
|
||||||
const QString &source,
|
const QString &source,
|
||||||
const QString &relativePath) const;
|
const QString &relativePath) const;
|
||||||
|
|
||||||
@ -70,34 +95,66 @@ private:
|
|||||||
std::unique_ptr<Wrap> fileWithRelativePath(const QString &path) const;
|
std::unique_ptr<Wrap> fileWithRelativePath(const QString &path) const;
|
||||||
QString messagesFile(int index) const;
|
QString messagesFile(int index) const;
|
||||||
|
|
||||||
Result writeSavedContacts(const Data::ContactsList &data);
|
[[nodiscard]] Result writeSavedContacts(const Data::ContactsList &data);
|
||||||
Result writeFrequentContacts(const Data::ContactsList &data);
|
[[nodiscard]] Result writeFrequentContacts(const Data::ContactsList &data);
|
||||||
|
|
||||||
Result writeSessions(const Data::SessionsList &data);
|
[[nodiscard]] Result writeSessions(const Data::SessionsList &data);
|
||||||
Result writeWebSessions(const Data::SessionsList &data);
|
[[nodiscard]] Result writeWebSessions(const Data::SessionsList &data);
|
||||||
|
|
||||||
Result writeChatsStart(
|
[[nodiscard]] Result writeChatsStart(
|
||||||
const Data::DialogsInfo &data,
|
const Data::DialogsInfo &data,
|
||||||
const QByteArray &listName,
|
const QByteArray &listName,
|
||||||
const QByteArray &about,
|
const QByteArray &about,
|
||||||
const QString &fileName);
|
const QString &fileName);
|
||||||
Result writeChatStart(const Data::DialogInfo &data);
|
[[nodiscard]] Result writeChatStart(const Data::DialogInfo &data);
|
||||||
Result writeChatSlice(const Data::MessagesSlice &data);
|
[[nodiscard]] Result writeChatSlice(const Data::MessagesSlice &data);
|
||||||
Result writeChatEnd();
|
[[nodiscard]] Result writeChatEnd();
|
||||||
Result writeChatsEnd();
|
[[nodiscard]] Result writeChatsEnd();
|
||||||
Result switchToNextChatFile(int index);
|
[[nodiscard]] Result switchToNextChatFile(int index);
|
||||||
|
|
||||||
|
void pushSection(
|
||||||
|
int priority,
|
||||||
|
const QByteArray &label,
|
||||||
|
const QByteArray &type,
|
||||||
|
int count,
|
||||||
|
const QString &path);
|
||||||
|
[[nodiscard]] Result writeSections();
|
||||||
|
|
||||||
|
[[nodiscard]] Result writeDefaultPersonal(
|
||||||
|
const Data::PersonalInfo &data);
|
||||||
|
[[nodiscard]] Result writeDelayedPersonal(const QString &userpicPath);
|
||||||
|
[[nodiscard]] Result writePreparedPersonal(
|
||||||
|
const Data::PersonalInfo &data,
|
||||||
|
const QString &userpicPath);
|
||||||
|
void pushUserpicsSection();
|
||||||
|
|
||||||
|
[[nodiscard]] QString writeUserpicThumb(
|
||||||
|
const QString &largePath,
|
||||||
|
const UserpicData &userpic,
|
||||||
|
const QString &postfix = "_thumb");
|
||||||
|
|
||||||
|
[[nodiscard]] QString userpicsFilePath() const;
|
||||||
|
|
||||||
Settings _settings;
|
Settings _settings;
|
||||||
Environment _environment;
|
Environment _environment;
|
||||||
Stats *_stats = nullptr;
|
Stats *_stats = nullptr;
|
||||||
|
|
||||||
|
struct SavedSection;
|
||||||
|
std::vector<SavedSection> _savedSections;
|
||||||
|
|
||||||
std::unique_ptr<Wrap> _summary;
|
std::unique_ptr<Wrap> _summary;
|
||||||
|
bool _summaryNeedDivider = false;
|
||||||
|
bool _haveSections = false;
|
||||||
|
|
||||||
|
int _selfColorIndex = 0;
|
||||||
|
std::unique_ptr<Data::PersonalInfo> _delayedPersonalInfo;
|
||||||
|
|
||||||
int _userpicsCount = 0;
|
int _userpicsCount = 0;
|
||||||
std::unique_ptr<Wrap> _userpics;
|
std::unique_ptr<Wrap> _userpics;
|
||||||
|
|
||||||
int _dialogsCount = 0;
|
int _dialogsCount = 0;
|
||||||
int _dialogIndex = 0;
|
int _dialogIndex = 0;
|
||||||
|
QString _dialogsRelativePath;
|
||||||
Data::DialogInfo _dialog;
|
Data::DialogInfo _dialog;
|
||||||
|
|
||||||
int _messagesCount = 0;
|
int _messagesCount = 0;
|
||||||
|
@ -69,6 +69,8 @@ void SuggestBox::prepare() {
|
|||||||
}, content->lifetime());
|
}, content->lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
Environment PrepareEnvironment() {
|
Environment PrepareEnvironment() {
|
||||||
auto result = Environment();
|
auto result = Environment();
|
||||||
const auto utfLang = [](LangKey key) {
|
const auto utfLang = [](LangKey key) {
|
||||||
@ -85,8 +87,6 @@ Environment PrepareEnvironment() {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
QPointer<BoxContent> SuggestStart() {
|
QPointer<BoxContent> SuggestStart() {
|
||||||
ClearSuggestStart();
|
ClearSuggestStart();
|
||||||
return Ui::show(Box<SuggestBox>(), LayerOption::KeepOther).data();
|
return Ui::show(Box<SuggestBox>(), LayerOption::KeepOther).data();
|
||||||
|
@ -19,8 +19,12 @@ class SeparatePanel;
|
|||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Export {
|
namespace Export {
|
||||||
|
|
||||||
|
struct Environment;
|
||||||
|
|
||||||
namespace View {
|
namespace View {
|
||||||
|
|
||||||
|
Environment PrepareEnvironment();
|
||||||
QPointer<BoxContent> SuggestStart();
|
QPointer<BoxContent> SuggestStart();
|
||||||
void ClearSuggestStart();
|
void ClearSuggestStart();
|
||||||
|
|
||||||
|
@ -90,6 +90,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
#include "styles/style_history.h"
|
#include "styles/style_history.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
#include "export/output/export_output_html.h"
|
||||||
|
#include "export/output/export_output_stats.h"
|
||||||
|
#include "export/view/export_view_panel_controller.h"
|
||||||
|
#include "platform/platform_specific.h"
|
||||||
|
#else
|
||||||
|
#error "test"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
bool IsForceLogoutNotification(const MTPDupdateServiceNotification &data) {
|
bool IsForceLogoutNotification(const MTPDupdateServiceNotification &data) {
|
||||||
@ -252,6 +261,10 @@ MainWidget::MainWidget(
|
|||||||
Messenger::Instance().mtp()->setUpdatesHandler(rpcDone(&MainWidget::updateReceived));
|
Messenger::Instance().mtp()->setUpdatesHandler(rpcDone(&MainWidget::updateReceived));
|
||||||
Messenger::Instance().mtp()->setGlobalFailHandler(rpcFail(&MainWidget::updateFail));
|
Messenger::Instance().mtp()->setGlobalFailHandler(rpcFail(&MainWidget::updateFail));
|
||||||
|
|
||||||
|
Export::Output::HtmlWriter writer;
|
||||||
|
writer.produceTestExample(psDownloadPath(), Export::View::PrepareEnvironment());
|
||||||
|
crl::on_main([] { App::quit(); });
|
||||||
|
|
||||||
_ptsWaiter.setRequesting(true);
|
_ptsWaiter.setRequesting(true);
|
||||||
updateScrollColors();
|
updateScrollColors();
|
||||||
setupConnectingWidget();
|
setupConnectingWidget();
|
||||||
|
@ -109,7 +109,9 @@
|
|||||||
'<@(style_files)',
|
'<@(style_files)',
|
||||||
'<!@(<(list_sources_command) <(qt_moc_list_sources_arg))',
|
'<!@(<(list_sources_command) <(qt_moc_list_sources_arg))',
|
||||||
'telegram_sources.txt',
|
'telegram_sources.txt',
|
||||||
'<(res_loc)/css/export_style.css',
|
'<(res_loc)/export_html/css/style.css',
|
||||||
|
'<(res_loc)/export_html/images/back.png',
|
||||||
|
'<(res_loc)/export_html/images/back@2x.png',
|
||||||
],
|
],
|
||||||
'sources!': [
|
'sources!': [
|
||||||
'<!@(<(list_sources_command) <(qt_moc_list_sources_arg) --exclude_for <(build_os))',
|
'<!@(<(list_sources_command) <(qt_moc_list_sources_arg) --exclude_for <(build_os))',
|
||||||
|