mirror of
https://github.com/telegramdesktop/tdesktop
synced 2024-12-26 16:43:33 +00:00
Export settings layout ready.
This commit is contained in:
parent
9d02e539c8
commit
df91b2bfeb
@ -1657,6 +1657,23 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_export_option_info" = "Personal info";
|
||||
"lng_export_option_contacts" = "Contacts list";
|
||||
"lng_export_option_sessions" = "Sessions list";
|
||||
"lng_export_header_chats" = "Chats export settings";
|
||||
"lng_export_option_personal_chats" = "Personal chats";
|
||||
"lng_export_option_bot_chats" = "Bot chats";
|
||||
"lng_export_option_private_groups" = "Private groups";
|
||||
"lng_export_option_private_channels" = "Private channels";
|
||||
"lng_export_option_public_groups" = "Public groups";
|
||||
"lng_export_option_public_channels" = "Public channels";
|
||||
"lng_export_option_only_my" = "Only my messages";
|
||||
"lng_export_header_media" = "Media export settings";
|
||||
"lng_export_option_photos" = "Photos";
|
||||
"lng_export_option_video_files" = "Video files";
|
||||
"lng_export_option_voice_messages" = "Voice messages";
|
||||
"lng_export_option_video_messages" = "Round video messages";
|
||||
"lng_export_option_stickers" = "Stickers";
|
||||
"lng_export_option_gifs" = "Animated GIFs";
|
||||
"lng_export_option_files" = "Files";
|
||||
"lng_export_option_size_limit" = "Size limit: {size}";
|
||||
"lng_export_start" = "Export";
|
||||
|
||||
// Wnd specific
|
||||
|
@ -147,15 +147,8 @@ void ApiWrap::startExport(
|
||||
}
|
||||
|
||||
void ApiWrap::startMainSession(FnMut<void()> done) {
|
||||
auto sizeLimit = _settings->defaultMedia.sizeLimit;
|
||||
auto hasFiles = _settings->defaultMedia.types != 0;
|
||||
for (const auto &item : _settings->customMedia) {
|
||||
sizeLimit = std::max(sizeLimit, item.second.sizeLimit);
|
||||
hasFiles = hasFiles || (item.second.types != 0);
|
||||
}
|
||||
if (!sizeLimit) {
|
||||
hasFiles = false;
|
||||
}
|
||||
const auto sizeLimit = _settings->media.sizeLimit;
|
||||
const auto hasFiles = (_settings->media.types != 0) && (sizeLimit > 0);
|
||||
|
||||
using Type = Settings::Type;
|
||||
using Flag = MTPaccount_InitTakeoutSession::Flag;
|
||||
|
@ -17,11 +17,13 @@ enum class Format;
|
||||
|
||||
struct MediaSettings {
|
||||
enum class Type {
|
||||
Photo = 0x01,
|
||||
Video = 0x02,
|
||||
Sticker = 0x04,
|
||||
GIF = 0x08,
|
||||
File = 0x10,
|
||||
Photo = 0x01,
|
||||
Video = 0x02,
|
||||
VoiceMessage = 0x04,
|
||||
VideoMessage = 0x08,
|
||||
Sticker = 0x10,
|
||||
GIF = 0x20,
|
||||
File = 0x40,
|
||||
};
|
||||
using Types = base::flags<Type>;
|
||||
friend inline constexpr auto is_flag_type(Type) { return true; };
|
||||
@ -57,8 +59,7 @@ struct Settings {
|
||||
|
||||
Types types = DefaultTypes();
|
||||
Types fullChats = DefaultFullChats();
|
||||
MediaSettings defaultMedia;
|
||||
base::flat_map<Type, MediaSettings> customMedia;
|
||||
MediaSettings media;
|
||||
|
||||
static inline Types DefaultTypes() {
|
||||
return Type::PersonalInfo
|
||||
|
@ -12,3 +12,28 @@ using "boxes/boxes.style";
|
||||
|
||||
exportPanelSize: size(364px, 480px);
|
||||
exportSettingPadding: margins(22px, 8px, 22px, 8px);
|
||||
exportSubSettingPadding: margins(56px, 4px, 22px, 12px);
|
||||
exportHeaderLabel: FlatLabel(boxTitle) {
|
||||
style: TextStyle(defaultTextStyle) {
|
||||
font: font(15px semibold);
|
||||
linkFont: font(15px semibold);
|
||||
linkFontOver: font(15px semibold underline);
|
||||
}
|
||||
}
|
||||
exportHeaderPadding: margins(22px, 20px, 22px, 9px);
|
||||
exportFileSizeSlider: MediaSlider {
|
||||
width: 3px;
|
||||
activeFg: mediaPlayerActiveFg;
|
||||
inactiveFg: mediaPlayerInactiveFg;
|
||||
activeFgOver: mediaPlayerActiveFg;
|
||||
inactiveFgOver: mediaPlayerInactiveFg;
|
||||
activeFgDisabled: mediaPlayerInactiveFg;
|
||||
inactiveFgDisabled: windowBg;
|
||||
seekSize: size(15px, 15px);
|
||||
duration: 150;
|
||||
}
|
||||
exportFileSizeLabel: LabelSimple(defaultLabelSimple) {
|
||||
font: boxTextFont;
|
||||
}
|
||||
exportFileSizePadding: margins(22px, 8px, 22px, 8px);
|
||||
exportFileSizeLabelBottom: 18px;
|
||||
|
@ -10,8 +10,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "lang/lang_keys.h"
|
||||
#include "ui/widgets/checkbox.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "ui/widgets/continuous_sliders.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/wrap/padding_wrap.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/wrap/fade_wrap.h"
|
||||
#include "platform/platform_specific.h"
|
||||
#include "styles/style_widgets.h"
|
||||
#include "styles/style_export.h"
|
||||
@ -19,6 +24,36 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
namespace Export {
|
||||
namespace View {
|
||||
namespace {
|
||||
|
||||
constexpr auto kSizeValueCount = 80;
|
||||
constexpr auto kMegabyte = 1024 * 1024;
|
||||
|
||||
int SizeLimitByIndex(int index) {
|
||||
Expects(index >= 0 && index <= kSizeValueCount);
|
||||
|
||||
const auto megabytes = [&] {
|
||||
if (index <= 10) {
|
||||
return index;
|
||||
} else if (index <= 30) {
|
||||
return 10 + (index - 10) * 2;
|
||||
} else if (index <= 40) {
|
||||
return 50 + (index - 30) * 5;
|
||||
} else if (index <= 60) {
|
||||
return 100 + (index - 40) * 10;
|
||||
} else if (index <= 70) {
|
||||
return 300 + (index - 60) * 20;
|
||||
} else {
|
||||
return 500 + (index - 70) * 100;
|
||||
}
|
||||
};
|
||||
if (!index) {
|
||||
return kMegabyte / 2;
|
||||
}
|
||||
return megabytes() * kMegabyte;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
SettingsWidget::SettingsWidget(QWidget *parent)
|
||||
: RpWidget(parent) {
|
||||
@ -35,7 +70,15 @@ SettingsWidget::SettingsWidget(QWidget *parent)
|
||||
}
|
||||
|
||||
void SettingsWidget::setupContent() {
|
||||
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
|
||||
using namespace rpl::mappers;
|
||||
|
||||
const auto scroll = Ui::CreateChild<Ui::ScrollArea>(
|
||||
this,
|
||||
st::boxLayerScroll);
|
||||
const auto wrap = scroll->setOwnedWidget(object_ptr<Ui::IgnoreMargins>(
|
||||
scroll,
|
||||
object_ptr<Ui::VerticalLayout>(scroll)));
|
||||
const auto content = static_cast<Ui::VerticalLayout*>(wrap->entity());
|
||||
|
||||
const auto buttonsPadding = st::boxButtonPadding;
|
||||
const auto buttonsHeight = buttonsPadding.top()
|
||||
@ -44,9 +87,32 @@ void SettingsWidget::setupContent() {
|
||||
const auto buttons = Ui::CreateChild<Ui::FixedHeightWidget>(
|
||||
this,
|
||||
buttonsHeight);
|
||||
const auto topShadow = Ui::CreateChild<Ui::FadeShadow>(this);
|
||||
const auto bottomShadow = Ui::CreateChild<Ui::FadeShadow>(this);
|
||||
topShadow->toggleOn(scroll->scrollTopValue(
|
||||
) | rpl::map(_1 > 0));
|
||||
bottomShadow->toggleOn(rpl::combine(
|
||||
scroll->heightValue(),
|
||||
scroll->scrollTopValue(),
|
||||
wrap->heightValue(),
|
||||
_2
|
||||
) | rpl::map([=](int top) {
|
||||
return top < scroll->scrollTopMax();
|
||||
}));
|
||||
const auto refreshButtonsCallback = [=] {
|
||||
refreshButtons(buttons);
|
||||
};
|
||||
const auto addHeader = [&](
|
||||
not_null<Ui::VerticalLayout*> container,
|
||||
LangKey key) {
|
||||
container->add(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
container,
|
||||
lang(key),
|
||||
Ui::FlatLabel::InitType::Simple,
|
||||
st::exportHeaderLabel),
|
||||
st::exportHeaderPadding);
|
||||
};
|
||||
|
||||
const auto addOption = [&](LangKey key, Types types) {
|
||||
const auto checkbox = content->add(
|
||||
@ -64,22 +130,171 @@ void SettingsWidget::setupContent() {
|
||||
} else {
|
||||
_data.types &= ~types;
|
||||
}
|
||||
_dataTypesChanges.fire_copy(_data.types);
|
||||
refreshButtonsCallback();
|
||||
}, lifetime());
|
||||
return checkbox;
|
||||
};
|
||||
const auto addBigOption = [&](LangKey key, Types types) {
|
||||
const auto checkbox = addOption(key, types);
|
||||
const auto onlyMy = content->add(
|
||||
object_ptr<Ui::SlideWrap<Ui::Checkbox>>(
|
||||
content,
|
||||
object_ptr<Ui::Checkbox>(
|
||||
content,
|
||||
lang(lng_export_option_only_my),
|
||||
((_data.fullChats & types) != types),
|
||||
st::defaultBoxCheckbox),
|
||||
st::exportSubSettingPadding));
|
||||
|
||||
base::ObservableViewer(
|
||||
onlyMy->entity()->checkedChanged
|
||||
) | rpl::start_with_next([=](bool checked) {
|
||||
if (checked) {
|
||||
_data.fullChats &= ~types;
|
||||
} else {
|
||||
_data.fullChats |= types;
|
||||
}
|
||||
}, checkbox->lifetime());
|
||||
|
||||
onlyMy->toggleOn(base::ObservableViewer(
|
||||
checkbox->checkedChanged
|
||||
));
|
||||
|
||||
onlyMy->toggle(checkbox->checked(), anim::type::instant);
|
||||
|
||||
if (types & (Type::PublicGroups | Type::PublicChannels)) {
|
||||
onlyMy->entity()->setChecked(true);
|
||||
onlyMy->entity()->setDisabled(true);
|
||||
}
|
||||
};
|
||||
addOption(lng_export_option_info, Type::PersonalInfo | Type::Userpics);
|
||||
addOption(lng_export_option_contacts, Type::Contacts);
|
||||
addOption(lng_export_option_sessions, Type::Sessions);
|
||||
addHeader(content, lng_export_header_chats);
|
||||
addOption(lng_export_option_personal_chats, Type::PersonalChats);
|
||||
addOption(lng_export_option_bot_chats, Type::BotChats);
|
||||
addBigOption(lng_export_option_private_groups, Type::PrivateGroups);
|
||||
addBigOption(lng_export_option_private_channels, Type::PrivateChannels);
|
||||
addBigOption(lng_export_option_public_groups, Type::PublicGroups);
|
||||
addBigOption(lng_export_option_public_channels, Type::PublicChannels);
|
||||
const auto mediaWrap = content->add(
|
||||
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
|
||||
content,
|
||||
object_ptr<Ui::VerticalLayout>(content)));
|
||||
const auto media = mediaWrap->entity();
|
||||
const auto addSubOption = [&](LangKey key, MediaType type) {
|
||||
const auto checkbox = media->add(
|
||||
object_ptr<Ui::Checkbox>(
|
||||
media,
|
||||
lang(key),
|
||||
((_data.media.types & type) == type),
|
||||
st::defaultBoxCheckbox),
|
||||
st::exportSettingPadding);
|
||||
base::ObservableViewer(
|
||||
checkbox->checkedChanged
|
||||
) | rpl::start_with_next([=](bool checked) {
|
||||
if (checked) {
|
||||
_data.media.types |= type;
|
||||
} else {
|
||||
_data.media.types &= ~type;
|
||||
}
|
||||
refreshButtonsCallback();
|
||||
}, lifetime());
|
||||
};
|
||||
addHeader(media, lng_export_header_media);
|
||||
addSubOption(lng_export_option_photos, MediaType::Photo);
|
||||
addSubOption(lng_export_option_video_files, MediaType::Video);
|
||||
addSubOption(lng_export_option_voice_messages, MediaType::VoiceMessage);
|
||||
addSubOption(lng_export_option_video_messages, MediaType::VideoMessage);
|
||||
addSubOption(lng_export_option_stickers, MediaType::Sticker);
|
||||
addSubOption(lng_export_option_gifs, MediaType::GIF);
|
||||
addSubOption(lng_export_option_files, MediaType::File);
|
||||
createSizeSlider(media);
|
||||
|
||||
_dataTypesChanges.events_starting_with_copy(
|
||||
_data.types
|
||||
) | rpl::start_with_next([=](Settings::Types types) {
|
||||
mediaWrap->toggle((types & (Type::PersonalChats
|
||||
| Type::BotChats
|
||||
| Type::PrivateGroups
|
||||
| Type::PrivateChannels
|
||||
| Type::PublicGroups
|
||||
| Type::PublicChannels)) != 0, anim::type::normal);
|
||||
}, mediaWrap->lifetime());
|
||||
|
||||
refreshButtonsCallback();
|
||||
|
||||
topShadow->raise();
|
||||
bottomShadow->raise();
|
||||
|
||||
sizeValue(
|
||||
) | rpl::start_with_next([=](QSize size) {
|
||||
scroll->resize(size.width(), size.height() - buttons->height());
|
||||
wrap->resizeToWidth(size.width());
|
||||
content->resizeToWidth(size.width());
|
||||
buttons->resizeToWidth(size.width());
|
||||
topShadow->resizeToWidth(size.width());
|
||||
mediaWrap->resizeToWidth(size.width());
|
||||
topShadow->moveToLeft(0, 0);
|
||||
bottomShadow->resizeToWidth(size.width());
|
||||
bottomShadow->moveToLeft(0, scroll->height() - st::lineWidth);
|
||||
buttons->moveToLeft(0, size.height() - buttons->height());
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
void SettingsWidget::createSizeSlider(
|
||||
not_null<Ui::VerticalLayout*> container) {
|
||||
using namespace rpl::mappers;
|
||||
|
||||
const auto slider = container->add(
|
||||
object_ptr<Ui::MediaSlider>(container, st::exportFileSizeSlider),
|
||||
st::exportFileSizePadding);
|
||||
slider->resize(st::exportFileSizeSlider.seekSize);
|
||||
slider->setAlwaysDisplayMarker(true);
|
||||
slider->setMoveByWheel(true);
|
||||
slider->setDirection(Ui::ContinuousSlider::Direction::Horizontal);
|
||||
for (auto i = 0; i != kSizeValueCount + 1; ++i) {
|
||||
if (_data.media.sizeLimit <= SizeLimitByIndex(i)) {
|
||||
slider->setValue(i / float64(kSizeValueCount));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const auto label = Ui::CreateChild<Ui::LabelSimple>(
|
||||
container.get(),
|
||||
st::exportFileSizeLabel);
|
||||
const auto refreshSizeLimit = [=] {
|
||||
const auto limit = _data.media.sizeLimit / kMegabyte;
|
||||
const auto size = ((limit > 0)
|
||||
? QString::number(limit)
|
||||
: QString::number(float64(_data.media.sizeLimit) / kMegabyte))
|
||||
+ " MB";
|
||||
const auto text = lng_export_option_size_limit(lt_size, size);
|
||||
label->setText(text);
|
||||
};
|
||||
slider->setAdjustCallback([=](float64 value) {
|
||||
return std::round(value * kSizeValueCount) / kSizeValueCount;
|
||||
});
|
||||
slider->setChangeProgressCallback([=](float64 value) {
|
||||
const auto index = int(std::round(value * kSizeValueCount));
|
||||
_data.media.sizeLimit = SizeLimitByIndex(index);
|
||||
refreshSizeLimit();
|
||||
});
|
||||
refreshSizeLimit();
|
||||
|
||||
rpl::combine(
|
||||
label->widthValue(),
|
||||
slider->geometryValue(),
|
||||
_2
|
||||
) | rpl::start_with_next([=](QRect geometry) {
|
||||
label->moveToRight(
|
||||
st::exportFileSizePadding.right(),
|
||||
geometry.y() - label->height() - st::exportFileSizeLabelBottom);
|
||||
}, label->lifetime());
|
||||
|
||||
}
|
||||
|
||||
void SettingsWidget::refreshButtons(not_null<Ui::RpWidget*> container) {
|
||||
container->hideChildren();
|
||||
const auto children = container->children();
|
||||
|
@ -10,6 +10,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "export/export_settings.h"
|
||||
#include "ui/rp_widget.h"
|
||||
|
||||
namespace Ui {
|
||||
class VerticalLayout;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Export {
|
||||
namespace View {
|
||||
|
||||
@ -28,6 +32,7 @@ private:
|
||||
|
||||
void setupContent();
|
||||
void refreshButtons(not_null<Ui::RpWidget*> container);
|
||||
void createSizeSlider(not_null<Ui::VerticalLayout*> container);
|
||||
|
||||
Settings _data;
|
||||
struct Wrap {
|
||||
@ -40,6 +45,7 @@ private:
|
||||
};
|
||||
rpl::variable<Wrap> _startClicks;
|
||||
rpl::variable<Wrap> _cancelClicks;
|
||||
rpl::event_stream<Settings::Types> _dataTypesChanges;
|
||||
|
||||
};
|
||||
|
||||
|
@ -14,7 +14,7 @@ constexpr auto kByWheelFinishedTimeout = 1000;
|
||||
|
||||
} // namespace
|
||||
|
||||
ContinuousSlider::ContinuousSlider(QWidget *parent) : TWidget(parent) {
|
||||
ContinuousSlider::ContinuousSlider(QWidget *parent) : RpWidget(parent) {
|
||||
setCursor(style::cur_pointer);
|
||||
}
|
||||
|
||||
@ -58,11 +58,12 @@ void ContinuousSlider::mouseMoveEvent(QMouseEvent *e) {
|
||||
}
|
||||
|
||||
float64 ContinuousSlider::computeValue(const QPoint &pos) const {
|
||||
auto seekRect = myrtlrect(getSeekRect());
|
||||
auto result = isHorizontal() ?
|
||||
const auto seekRect = myrtlrect(getSeekRect());
|
||||
const auto result = isHorizontal() ?
|
||||
(pos.x() - seekRect.x()) / float64(seekRect.width()) :
|
||||
(1. - (pos.y() - seekRect.y()) / float64(seekRect.height()));
|
||||
return snap(result, 0., 1.);
|
||||
const auto snapped = snap(result, 0., 1.);
|
||||
return _adjustCallback ? _adjustCallback(snapped) : snapped;
|
||||
}
|
||||
|
||||
void ContinuousSlider::mousePressEvent(QMouseEvent *e) {
|
||||
|
@ -8,10 +8,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#pragma once
|
||||
|
||||
#include "styles/style_widgets.h"
|
||||
#include "ui/rp_widget.h"
|
||||
|
||||
namespace Ui {
|
||||
|
||||
class ContinuousSlider : public TWidget {
|
||||
class ContinuousSlider : public RpWidget {
|
||||
public:
|
||||
ContinuousSlider(QWidget *parent);
|
||||
|
||||
@ -32,11 +33,13 @@ public:
|
||||
return _disabled;
|
||||
}
|
||||
|
||||
using Callback = Fn<void(float64)>;
|
||||
void setChangeProgressCallback(Callback &&callback) {
|
||||
void setAdjustCallback(Fn<float64(float64)> callback) {
|
||||
_adjustCallback = std::move(callback);
|
||||
}
|
||||
void setChangeProgressCallback(Fn<void(float64)> callback) {
|
||||
_changeProgressCallback = std::move(callback);
|
||||
}
|
||||
void setChangeFinishedCallback(Callback &&callback) {
|
||||
void setChangeFinishedCallback(Fn<void(float64)> callback) {
|
||||
_changeFinishedCallback = std::move(callback);
|
||||
}
|
||||
bool isChanging() const {
|
||||
@ -86,8 +89,9 @@ private:
|
||||
|
||||
std::unique_ptr<SingleTimer> _byWheelFinished;
|
||||
|
||||
Callback _changeProgressCallback;
|
||||
Callback _changeFinishedCallback;
|
||||
Fn<float64(float64)> _adjustCallback;
|
||||
Fn<void(float64)> _changeProgressCallback;
|
||||
Fn<void(float64)> _changeFinishedCallback;
|
||||
|
||||
bool _over = false;
|
||||
Animation _a_over;
|
||||
|
@ -86,7 +86,11 @@ void CrossFadeAnimation::paintLine(Painter &p, const Line &line, float64 positio
|
||||
}
|
||||
}
|
||||
|
||||
LabelSimple::LabelSimple(QWidget *parent, const style::LabelSimple &st, const QString &value) : TWidget(parent)
|
||||
LabelSimple::LabelSimple(
|
||||
QWidget *parent,
|
||||
const style::LabelSimple &st,
|
||||
const QString &value)
|
||||
: RpWidget(parent)
|
||||
, _st(st) {
|
||||
setText(value);
|
||||
}
|
||||
|
@ -47,9 +47,12 @@ private:
|
||||
|
||||
};
|
||||
|
||||
class LabelSimple : public TWidget {
|
||||
class LabelSimple : public RpWidget {
|
||||
public:
|
||||
LabelSimple(QWidget *parent, const style::LabelSimple &st = st::defaultLabelSimple, const QString &value = QString());
|
||||
LabelSimple(
|
||||
QWidget *parent,
|
||||
const style::LabelSimple &st = st::defaultLabelSimple,
|
||||
const QString &value = QString());
|
||||
|
||||
// This method also resizes the label.
|
||||
void setText(const QString &newText, bool *outTextChanged = nullptr);
|
||||
|
Loading…
Reference in New Issue
Block a user