mirror of https://github.com/procxx/kepka.git
Add support for JSON single-chat export.
This commit is contained in:
parent
02586ebe4b
commit
1686eb394d
|
@ -2150,6 +2150,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_export_option_size_limit" = "Size limit: {size}";
|
"lng_export_option_size_limit" = "Size limit: {size}";
|
||||||
"lng_export_header_format" = "Location and format";
|
"lng_export_header_format" = "Location and format";
|
||||||
"lng_export_option_location" = "Download path: {path}";
|
"lng_export_option_location" = "Download path: {path}";
|
||||||
|
"lng_export_option_format_location" = "Format: {format}, Path: {path}";
|
||||||
|
"lng_export_option_choose_format" = "Choose export format";
|
||||||
"lng_export_option_html" = "Human-readable HTML";
|
"lng_export_option_html" = "Human-readable HTML";
|
||||||
"lng_export_option_json" = "Machine-readable JSON";
|
"lng_export_option_json" = "Machine-readable JSON";
|
||||||
"lng_export_limits" = "From: {from}, to: {till}";
|
"lng_export_limits" = "From: {from}, to: {till}";
|
||||||
|
|
|
@ -24,7 +24,6 @@ Settings NormalizeSettings(const Settings &settings) {
|
||||||
return base::duplicate(settings);
|
return base::duplicate(settings);
|
||||||
}
|
}
|
||||||
auto result = base::duplicate(settings);
|
auto result = base::duplicate(settings);
|
||||||
result.format = Output::Format::Html;
|
|
||||||
result.types = result.fullChats = Settings::Type::AnyChatsMask;
|
result.types = result.fullChats = Settings::Type::AnyChatsMask;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -630,7 +630,9 @@ Result JsonWriter::start(
|
||||||
_environment = environment;
|
_environment = environment;
|
||||||
_stats = stats;
|
_stats = stats;
|
||||||
_output = fileWithRelativePath(mainFileRelativePath());
|
_output = fileWithRelativePath(mainFileRelativePath());
|
||||||
|
if (_settings.onlySinglePeer()) {
|
||||||
|
return Result::Success();
|
||||||
|
}
|
||||||
auto block = pushNesting(Context::kObject);
|
auto block = pushNesting(Context::kObject);
|
||||||
block.append(prepareObjectItemStart("about"));
|
block.append(prepareObjectItemStart("about"));
|
||||||
block.append(SerializeString(_environment.aboutTelegram));
|
block.append(SerializeString(_environment.aboutTelegram));
|
||||||
|
@ -993,10 +995,12 @@ Result JsonWriter::writeDialogsStart(const Data::DialogsInfo &data) {
|
||||||
Result JsonWriter::writeDialogStart(const Data::DialogInfo &data) {
|
Result JsonWriter::writeDialogStart(const Data::DialogInfo &data) {
|
||||||
Expects(_output != nullptr);
|
Expects(_output != nullptr);
|
||||||
|
|
||||||
|
if (!_settings.onlySinglePeer()) {
|
||||||
const auto result = validateDialogsMode(data.isLeftChannel);
|
const auto result = validateDialogsMode(data.isLeftChannel);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
using Type = Data::DialogInfo::Type;
|
using Type = Data::DialogInfo::Type;
|
||||||
const auto TypeString = [](Type type) {
|
const auto TypeString = [](Type type) {
|
||||||
|
@ -1014,7 +1018,9 @@ Result JsonWriter::writeDialogStart(const Data::DialogInfo &data) {
|
||||||
Unexpected("Dialog type in TypeString.");
|
Unexpected("Dialog type in TypeString.");
|
||||||
};
|
};
|
||||||
|
|
||||||
auto block = prepareArrayItemStart();
|
auto block = _settings.onlySinglePeer()
|
||||||
|
? QByteArray()
|
||||||
|
: prepareArrayItemStart();
|
||||||
block.append(pushNesting(Context::kObject));
|
block.append(pushNesting(Context::kObject));
|
||||||
if (data.type != Type::Self) {
|
if (data.type != Type::Self) {
|
||||||
block.append(prepareObjectItemStart("name")
|
block.append(prepareObjectItemStart("name")
|
||||||
|
@ -1073,6 +1079,9 @@ Result JsonWriter::writeDialogEnd() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result JsonWriter::writeDialogsEnd() {
|
Result JsonWriter::writeDialogsEnd() {
|
||||||
|
if (_settings.onlySinglePeer()) {
|
||||||
|
return Result::Success();
|
||||||
|
}
|
||||||
return writeChatsEnd();
|
return writeChatsEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1099,6 +1108,10 @@ Result JsonWriter::writeChatsEnd() {
|
||||||
Result JsonWriter::finish() {
|
Result JsonWriter::finish() {
|
||||||
Expects(_output != nullptr);
|
Expects(_output != nullptr);
|
||||||
|
|
||||||
|
if (_settings.onlySinglePeer()) {
|
||||||
|
Assert(_context.nesting.empty());
|
||||||
|
return Result::Success();
|
||||||
|
}
|
||||||
auto block = popNesting();
|
auto block = popNesting();
|
||||||
Assert(_context.nesting.empty());
|
Assert(_context.nesting.empty());
|
||||||
return _output->writeBlock(block);
|
return _output->writeBlock(block);
|
||||||
|
|
|
@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/wrap/padding_wrap.h"
|
#include "ui/wrap/padding_wrap.h"
|
||||||
#include "ui/wrap/slide_wrap.h"
|
#include "ui/wrap/slide_wrap.h"
|
||||||
#include "ui/wrap/fade_wrap.h"
|
#include "ui/wrap/fade_wrap.h"
|
||||||
|
#include "ui/layers/generic_box.h"
|
||||||
#include "ui/text/text_utilities.h"
|
#include "ui/text/text_utilities.h"
|
||||||
#include "platform/platform_specific.h"
|
#include "platform/platform_specific.h"
|
||||||
#include "core/file_utilities.h"
|
#include "core/file_utilities.h"
|
||||||
|
@ -35,7 +36,7 @@ namespace {
|
||||||
|
|
||||||
constexpr auto kMegabyte = 1024 * 1024;
|
constexpr auto kMegabyte = 1024 * 1024;
|
||||||
|
|
||||||
PeerId ReadPeerId(const MTPInputPeer &data) {
|
[[nodiscard]] PeerId ReadPeerId(const MTPInputPeer &data) {
|
||||||
return data.match([](const MTPDinputPeerUser &data) {
|
return data.match([](const MTPDinputPeerUser &data) {
|
||||||
return peerFromUser(data.vuser_id().v);
|
return peerFromUser(data.vuser_id().v);
|
||||||
}, [](const MTPDinputPeerUserFromMessage &data) {
|
}, [](const MTPDinputPeerUserFromMessage &data) {
|
||||||
|
@ -53,6 +54,29 @@ PeerId ReadPeerId(const MTPInputPeer &data) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] void ChooseFormatBox(
|
||||||
|
not_null<Ui::GenericBox*> box,
|
||||||
|
Output::Format format,
|
||||||
|
Fn<void(Output::Format)> done) {
|
||||||
|
using Format = Output::Format;
|
||||||
|
const auto group = std::make_shared<Ui::RadioenumGroup<Format>>(format);
|
||||||
|
const auto addFormatOption = [&](QString label, Format format) {
|
||||||
|
const auto radio = box->addRow(
|
||||||
|
object_ptr<Ui::Radioenum<Format>>(
|
||||||
|
box,
|
||||||
|
group,
|
||||||
|
format,
|
||||||
|
label,
|
||||||
|
st::defaultBoxCheckbox),
|
||||||
|
st::exportSettingPadding);
|
||||||
|
};
|
||||||
|
box->setTitle(tr::lng_export_option_choose_format());
|
||||||
|
addFormatOption(tr::lng_export_option_html(tr::now), Format::Html);
|
||||||
|
addFormatOption(tr::lng_export_option_json(tr::now), Format::Json);
|
||||||
|
box->addButton(tr::lng_settings_save(), [=] { done(group->value()); });
|
||||||
|
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
int SizeLimitByIndex(int index) {
|
int SizeLimitByIndex(int index) {
|
||||||
|
@ -221,7 +245,7 @@ void SettingsWidget::setupOtherOptions(
|
||||||
void SettingsWidget::setupPathAndFormat(
|
void SettingsWidget::setupPathAndFormat(
|
||||||
not_null<Ui::VerticalLayout*> container) {
|
not_null<Ui::VerticalLayout*> container) {
|
||||||
if (_singlePeerId != 0) {
|
if (_singlePeerId != 0) {
|
||||||
addLocationLabel(container);
|
addFormatAndLocationLabel(container);
|
||||||
addLimitsLabel(container);
|
addLimitsLabel(container);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -278,6 +302,72 @@ void SettingsWidget::addLocationLabel(
|
||||||
#endif // OS_MAC_STORE
|
#endif // OS_MAC_STORE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SettingsWidget::chooseFormat() {
|
||||||
|
const auto shared = std::make_shared<QPointer<Ui::GenericBox>>();
|
||||||
|
const auto callback = [=](Format format) {
|
||||||
|
changeData([&](Settings &data) {
|
||||||
|
data.format = format;
|
||||||
|
});
|
||||||
|
if (const auto weak = shared->data()) {
|
||||||
|
weak->closeBox();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
auto box = Box(
|
||||||
|
ChooseFormatBox,
|
||||||
|
readData().format,
|
||||||
|
callback);
|
||||||
|
*shared = Ui::MakeWeak(box.data());
|
||||||
|
_showBoxCallback(std::move(box));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SettingsWidget::addFormatAndLocationLabel(
|
||||||
|
not_null<Ui::VerticalLayout*> container) {
|
||||||
|
#ifndef OS_MAC_STORE
|
||||||
|
auto pathLink = value() | rpl::map([](const Settings &data) {
|
||||||
|
return data.path;
|
||||||
|
}) | rpl::distinct_until_changed(
|
||||||
|
) | rpl::map([](const QString &path) {
|
||||||
|
const auto text = IsDefaultPath(path)
|
||||||
|
? u"Downloads/Telegram Desktop"_q
|
||||||
|
: path;
|
||||||
|
return Ui::Text::Link(
|
||||||
|
QDir::toNativeSeparators(text),
|
||||||
|
u"internal:edit_export_path"_q);
|
||||||
|
});
|
||||||
|
auto formatLink = value() | rpl::map([](const Settings &data) {
|
||||||
|
return data.format;
|
||||||
|
}) | rpl::distinct_until_changed(
|
||||||
|
) | rpl::map([](Format format) {
|
||||||
|
const auto text = (format == Format::Html) ? "HTML" : "JSON";
|
||||||
|
return Ui::Text::Link(text, u"internal:edit_format"_q);
|
||||||
|
});
|
||||||
|
const auto label = container->add(
|
||||||
|
object_ptr<Ui::FlatLabel>(
|
||||||
|
container,
|
||||||
|
tr::lng_export_option_format_location(
|
||||||
|
lt_format,
|
||||||
|
std::move(formatLink),
|
||||||
|
lt_path,
|
||||||
|
std::move(pathLink),
|
||||||
|
Ui::Text::WithEntities),
|
||||||
|
st::exportLocationLabel),
|
||||||
|
st::exportLocationPadding);
|
||||||
|
label->setClickHandlerFilter([=](
|
||||||
|
const ClickHandlerPtr &handler,
|
||||||
|
Qt::MouseButton) {
|
||||||
|
const auto url = handler->dragText();
|
||||||
|
if (url == qstr("internal:edit_export_path")) {
|
||||||
|
chooseFolder();
|
||||||
|
} else if (url == qstr("internal:edit_format")) {
|
||||||
|
chooseFormat();
|
||||||
|
} else {
|
||||||
|
Unexpected("Click handler URL in export limits edit.");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
#endif // OS_MAC_STORE
|
||||||
|
}
|
||||||
|
|
||||||
void SettingsWidget::addLimitsLabel(
|
void SettingsWidget::addLimitsLabel(
|
||||||
not_null<Ui::VerticalLayout*> container) {
|
not_null<Ui::VerticalLayout*> container) {
|
||||||
auto fromLink = value() | rpl::map([](const Settings &data) {
|
auto fromLink = value() | rpl::map([](const Settings &data) {
|
||||||
|
@ -351,7 +441,6 @@ void SettingsWidget::addLimitsLabel(
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingsWidget::editDateLimit(
|
void SettingsWidget::editDateLimit(
|
||||||
|
|
|
@ -77,9 +77,12 @@ private:
|
||||||
void addSizeSlider(not_null<Ui::VerticalLayout*> container);
|
void addSizeSlider(not_null<Ui::VerticalLayout*> container);
|
||||||
void addLocationLabel(
|
void addLocationLabel(
|
||||||
not_null<Ui::VerticalLayout*> container);
|
not_null<Ui::VerticalLayout*> container);
|
||||||
|
void addFormatAndLocationLabel(
|
||||||
|
not_null<Ui::VerticalLayout*> container);
|
||||||
void addLimitsLabel(
|
void addLimitsLabel(
|
||||||
not_null<Ui::VerticalLayout*> container);
|
not_null<Ui::VerticalLayout*> container);
|
||||||
void chooseFolder();
|
void chooseFolder();
|
||||||
|
void chooseFormat();
|
||||||
void refreshButtons(
|
void refreshButtons(
|
||||||
not_null<Ui::RpWidget*> container,
|
not_null<Ui::RpWidget*> container,
|
||||||
bool canStart);
|
bool canStart);
|
||||||
|
|
Loading…
Reference in New Issue