Skip to content

Commit

Permalink
Export settings layout ready.
Browse files Browse the repository at this point in the history
  • Loading branch information
john-preston committed Jun 16, 2018
1 parent 9d02e53 commit df91b2b
Show file tree
Hide file tree
Showing 10 changed files with 299 additions and 30 deletions.
17 changes: 17 additions & 0 deletions Telegram/Resources/langs/lang.strings
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 2 additions & 9 deletions Telegram/SourceFiles/export/export_api_wrap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
15 changes: 8 additions & 7 deletions Telegram/SourceFiles/export/export_settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -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; };
Expand Down Expand Up @@ -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
Expand Down
25 changes: 25 additions & 0 deletions Telegram/SourceFiles/export/view/export.style
Original file line number Diff line number Diff line change
Expand Up @@ -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;
217 changes: 216 additions & 1 deletion Telegram/SourceFiles/export/view/export_view_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,50 @@ For license and copyright information please follow this link:
#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"
#include "styles/style_boxes.h"

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) {
Expand All @@ -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()
Expand All @@ -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(
Expand All @@ -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();
Expand Down
6 changes: 6 additions & 0 deletions Telegram/SourceFiles/export/view/export_view_settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ For license and copyright information please follow this link:
#include "export/export_settings.h"
#include "ui/rp_widget.h"

namespace Ui {
class VerticalLayout;
} // namespace Ui

namespace Export {
namespace View {

Expand All @@ -28,6 +32,7 @@ class SettingsWidget : public Ui::RpWidget {

void setupContent();
void refreshButtons(not_null<Ui::RpWidget*> container);
void createSizeSlider(not_null<Ui::VerticalLayout*> container);

Settings _data;
struct Wrap {
Expand All @@ -40,6 +45,7 @@ class SettingsWidget : public Ui::RpWidget {
};
rpl::variable<Wrap> _startClicks;
rpl::variable<Wrap> _cancelClicks;
rpl::event_stream<Settings::Types> _dataTypesChanges;

};

Expand Down
Loading

0 comments on commit df91b2b

Please sign in to comment.