Add support for JSON single-chat export.

This commit is contained in:
John Preston 2020-06-01 16:16:14 +04:00
parent 02586ebe4b
commit 1686eb394d
5 changed files with 115 additions and 9 deletions

View file

@ -2150,6 +2150,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_export_option_size_limit" = "Size limit: {size}";
"lng_export_header_format" = "Location and format";
"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_json" = "Machine-readable JSON";
"lng_export_limits" = "From: {from}, to: {till}";

View file

@ -24,7 +24,6 @@ Settings NormalizeSettings(const Settings &settings) {
return base::duplicate(settings);
}
auto result = base::duplicate(settings);
result.format = Output::Format::Html;
result.types = result.fullChats = Settings::Type::AnyChatsMask;
return result;
}

View file

@ -630,7 +630,9 @@ Result JsonWriter::start(
_environment = environment;
_stats = stats;
_output = fileWithRelativePath(mainFileRelativePath());
if (_settings.onlySinglePeer()) {
return Result::Success();
}
auto block = pushNesting(Context::kObject);
block.append(prepareObjectItemStart("about"));
block.append(SerializeString(_environment.aboutTelegram));
@ -993,9 +995,11 @@ Result JsonWriter::writeDialogsStart(const Data::DialogsInfo &data) {
Result JsonWriter::writeDialogStart(const Data::DialogInfo &data) {
Expects(_output != nullptr);
const auto result = validateDialogsMode(data.isLeftChannel);
if (!result) {
return result;
if (!_settings.onlySinglePeer()) {
const auto result = validateDialogsMode(data.isLeftChannel);
if (!result) {
return result;
}
}
using Type = Data::DialogInfo::Type;
@ -1014,7 +1018,9 @@ Result JsonWriter::writeDialogStart(const Data::DialogInfo &data) {
Unexpected("Dialog type in TypeString.");
};
auto block = prepareArrayItemStart();
auto block = _settings.onlySinglePeer()
? QByteArray()
: prepareArrayItemStart();
block.append(pushNesting(Context::kObject));
if (data.type != Type::Self) {
block.append(prepareObjectItemStart("name")
@ -1073,6 +1079,9 @@ Result JsonWriter::writeDialogEnd() {
}
Result JsonWriter::writeDialogsEnd() {
if (_settings.onlySinglePeer()) {
return Result::Success();
}
return writeChatsEnd();
}
@ -1099,6 +1108,10 @@ Result JsonWriter::writeChatsEnd() {
Result JsonWriter::finish() {
Expects(_output != nullptr);
if (_settings.onlySinglePeer()) {
Assert(_context.nesting.empty());
return Result::Success();
}
auto block = popNesting();
Assert(_context.nesting.empty());
return _output->writeBlock(block);

View file

@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/wrap/padding_wrap.h"
#include "ui/wrap/slide_wrap.h"
#include "ui/wrap/fade_wrap.h"
#include "ui/layers/generic_box.h"
#include "ui/text/text_utilities.h"
#include "platform/platform_specific.h"
#include "core/file_utilities.h"
@ -35,7 +36,7 @@ namespace {
constexpr auto kMegabyte = 1024 * 1024;
PeerId ReadPeerId(const MTPInputPeer &data) {
[[nodiscard]] PeerId ReadPeerId(const MTPInputPeer &data) {
return data.match([](const MTPDinputPeerUser &data) {
return peerFromUser(data.vuser_id().v);
}, [](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
int SizeLimitByIndex(int index) {
@ -221,7 +245,7 @@ void SettingsWidget::setupOtherOptions(
void SettingsWidget::setupPathAndFormat(
not_null<Ui::VerticalLayout*> container) {
if (_singlePeerId != 0) {
addLocationLabel(container);
addFormatAndLocationLabel(container);
addLimitsLabel(container);
return;
}
@ -278,6 +302,72 @@ void SettingsWidget::addLocationLabel(
#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(
not_null<Ui::VerticalLayout*> container) {
auto fromLink = value() | rpl::map([](const Settings &data) {
@ -351,7 +441,6 @@ void SettingsWidget::addLimitsLabel(
}
return false;
});
}
void SettingsWidget::editDateLimit(

View file

@ -77,9 +77,12 @@ private:
void addSizeSlider(not_null<Ui::VerticalLayout*> container);
void addLocationLabel(
not_null<Ui::VerticalLayout*> container);
void addFormatAndLocationLabel(
not_null<Ui::VerticalLayout*> container);
void addLimitsLabel(
not_null<Ui::VerticalLayout*> container);
void chooseFolder();
void chooseFormat();
void refreshButtons(
not_null<Ui::RpWidget*> container,
bool canStart);