Redesign auto download box.

This commit is contained in:
John Preston 2018-12-06 19:47:28 +04:00
parent 8e54ac4dcf
commit a0c6104fae
19 changed files with 298 additions and 219 deletions

View File

@ -998,13 +998,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_media_audio" = "Voice message";
"lng_media_auto_settings" = "Automatic media download";
"lng_media_auto_in_private" = "In private chats";
"lng_media_auto_in_groups" = "In groups";
"lng_media_auto_in_channels" = "In channels";
"lng_media_auto_title" = "Automatically download";
"lng_media_photo_title" = "Photos";
"lng_media_video_title" = "Video files";
"lng_media_audio_title" = "Voice messages";
"lng_media_gif_title" = "GIFs and animations";
"lng_media_auto_private_chats" = "Private chats";
"lng_media_auto_groups" = "Groups and channels";
"lng_media_auto_play" = "Autoplay";
"lng_media_video_messages_title" = "Round video messages";
"lng_media_file_title" = "Files";
"lng_media_music_title" = "Music";
"lng_media_animation_title" = "Animated GIFs";
"lng_media_size_limit" = "Limit by size";
"lng_media_size_up_to" = "up to {size}";
"lng_emoji_category1" = "People";
"lng_emoji_category2" = "Nature";

View File

@ -0,0 +1,167 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "boxes/auto_download_box.h"
#include "lang/lang_keys.h"
#include "auth_session.h"
#include "data/data_session.h"
#include "info/profile/info_profile_button.h"
#include "ui/widgets/continuous_sliders.h"
#include "ui/wrap/vertical_layout.h"
#include "ui/wrap/wrap.h"
#include "storage/localstorage.h"
#include "settings/settings_common.h"
#include "export/view/export_view_settings.h"
#include "styles/style_boxes.h"
#include "styles/style_settings.h"
namespace {
constexpr auto kMegabyte = 1024 * 1024;
constexpr auto kDefaultLimit = 10 * kMegabyte;
} // namespace
AutoDownloadBox::AutoDownloadBox(
QWidget*,
Data::AutoDownload::Source source)
: _source(source) {
}
void AutoDownloadBox::prepare() {
setupContent();
}
void AutoDownloadBox::setupContent() {
using namespace Settings;
using namespace Data::AutoDownload;
using namespace rpl::mappers;
using Type = Data::AutoDownload::Type;
constexpr auto kLegacyLimit = 10 * 1024 * 1024;
setTitle(langFactory(lng_media_auto_title));
const auto settings = &Auth().settings().autoDownload();
const auto checked = [=](Source source, Type type) {
return (settings->bytesLimit(source, type) > 0);
};
auto wrap = object_ptr<Ui::VerticalLayout>(this);
const auto content = wrap.data();
setInnerWidget(object_ptr<Ui::OverrideMargins>(
this,
std::move(wrap)));
const auto values = Ui::CreateChild<base::flat_map<Type, int>>(content);
const auto add = [&](Type type, LangKey label) {
const auto value = settings->bytesLimit(_source, type);
AddButton(
content,
label,
st::settingsButton
)->toggleOn(
rpl::single(value > 0)
)->toggledChanges(
) | rpl::start_with_next([=](bool enabled) {
(*values)[type] = enabled ? 1 : 0;
}, content->lifetime());
values->emplace(type, value);
};
add(Type::Photo, lng_media_photo_title);
add(Type::VoiceMessage, lng_media_audio_title);
add(Type::VideoMessage, lng_media_video_messages_title);
add(Type::Video, lng_media_video_title);
add(Type::File, lng_media_file_title);
add(Type::Music, lng_media_music_title);
add(Type::GIF, lng_media_animation_title);
const auto limits = Ui::CreateChild<rpl::event_stream<int>>(content);
using Pair = base::flat_map<Type, int>::value_type;
const auto settingsLimit = ranges::max_element(
*values,
std::less<>(),
[](Pair pair) { return pair.second; })->second;
const auto initialLimit = settingsLimit ? settingsLimit : kDefaultLimit;
const auto limit = Ui::CreateChild<int>(content, initialLimit);
AddButtonWithLabel(
content,
lng_media_size_limit,
limits->events_starting_with_copy(
initialLimit
) | rpl::map([](int value) {
return lng_media_size_up_to(
lt_size,
QString::number(value / kMegabyte) + " MB");
}),
st::autoDownloadLimitButton
)->setAttribute(Qt::WA_TransparentForMouseEvents);
const auto slider = content->add(
object_ptr<Ui::MediaSlider>(content, st::autoDownloadLimitSlider),
st::autoDownloadLimitPadding);
slider->resize(st::autoDownloadLimitSlider.seekSize);
slider->setPseudoDiscrete(
Export::View::kSizeValueCount,
Export::View::SizeLimitByIndex,
*limit,
[=](int value) {
*limit = value;
limits->fire_copy(value);
});
const auto save = [=](
Type type,
std::pair<bool, bool> pair) {
const auto limit = [](bool checked) {
return checked ? kMaxBytesLimit : 0;
};
settings->setBytesLimit(Source::User, type, limit(pair.first));
settings->setBytesLimit(Source::Group, type, limit(pair.second));
settings->setBytesLimit(Source::Channel, type, limit(pair.second));
};
addButton(langFactory(lng_connection_save), [=] {
auto allowMore = ranges::view::all(
*values
) | ranges::view::filter([&](Pair pair) {
const auto [type, enabled] = pair;
const auto value = enabled ? *limit : 0;
const auto old = settings->bytesLimit(_source, type);
return (old < value);
}) | ranges::view::transform([](Pair pair) {
return pair.first;
});
const auto allowMoreTypes = base::flat_set<Type>(
allowMore.begin(),
allowMore.end());
const auto changed = ranges::find_if(*values, [&](Pair pair) {
const auto [type, enabled] = pair;
const auto value = enabled ? *limit : 0;
return settings->bytesLimit(_source, type) != value;
}) != end(*values);
if (changed) {
for (const auto [type, enabled] : *values) {
const auto value = enabled ? *limit : 0;
settings->setBytesLimit(_source, type, value);
}
Local::writeUserSettings();
}
if (allowMoreTypes.contains(Type::Photo)) {
Auth().data().photoLoadSettingsChanged();
}
if (ranges::find_if(allowMoreTypes, _1 != Type::Photo)
!= allowMoreTypes.end()) {
Auth().data().documentLoadSettingsChanged();
}
closeBox();
});
addButton(langFactory(lng_cancel), [=] { closeBox(); });
setDimensionsToContent(st::boxWidth, content);
}

View File

@ -0,0 +1,30 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "boxes/abstract_box.h"
namespace Data {
namespace AutoDownload {
enum class Source;
} // namespace AutoDownload
} // namespace Data
class AutoDownloadBox : public BoxContent {
public:
AutoDownloadBox(QWidget*, Data::AutoDownload::Source source);
protected:
void prepare() override;
private:
void setupContent();
Data::AutoDownload::Source _source;
};

View File

@ -533,6 +533,10 @@ aboutLabel: FlatLabel(defaultFlatLabel) {
autoDownloadTopDelta: 10px;
autoDownloadTitlePosition: point(23px, 18px);
autoDownloadTitleFont: font(15px semibold);
autoDownloadLimitSlider: MediaSlider(defaultContinuousSlider) {
seekSize: size(15px, 15px);
}
autoDownloadLimitPadding: margins(22px, 8px, 22px, 8px);
confirmCaptionArea: InputField(defaultInputField) {
textMargins: margins(1px, 26px, 31px, 4px);

View File

@ -7,37 +7,24 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "boxes/connection_box.h"
#include "data/data_photo.h"
#include "data/data_document.h"
#include "boxes/confirm_box.h"
#include "lang/lang_keys.h"
#include "storage/localstorage.h"
#include "base/qthelp_url.h"
#include "mainwidget.h"
#include "messenger.h"
#include "mainwindow.h"
#include "auth_session.h"
#include "data/data_session.h"
#include "mtproto/connection.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/dropdown_menu.h"
#include "ui/wrap/fade_wrap.h"
#include "ui/wrap/padding_wrap.h"
#include "ui/wrap/slide_wrap.h"
#include "ui/wrap/vertical_layout.h"
#include "ui/toast/toast.h"
#include "ui/effects/radial_animation.h"
#include "ui/text_options.h"
#include "history/history_location_manager.h"
#include "settings/settings_common.h"
#include "application.h"
#include "styles/style_boxes.h"
#include "styles/style_chat_helpers.h"
#include "styles/style_info.h"
#include "styles/style_settings.h"
namespace {
@ -936,135 +923,6 @@ void ProxyBox::addLabel(
} // namespace
AutoDownloadBox::AutoDownloadBox(QWidget *parent) {
}
void AutoDownloadBox::prepare() {
setupContent();
}
void AutoDownloadBox::setupContent() {
using namespace Settings;
using namespace Data::AutoDownload;
using Type = Data::AutoDownload::Type;
constexpr auto kLegacyLimit = 10 * 1024 * 1024;
setTitle(langFactory(lng_media_auto_title));
const auto settings = &Auth().settings().autoDownload();
const auto checked = [=](Source source, Type type) {
return (settings->bytesLimit(source, type) > 0);
};
auto wrap = object_ptr<Ui::VerticalLayout>(this);
const auto content = wrap.data();
setInnerWidget(object_ptr<Ui::OverrideMargins>(
this,
std::move(wrap)));
using pair = std::pair<Ui::Checkbox*, Ui::Checkbox*>;
const auto pairChecked = [](pair checkboxes) {
return std::make_pair(
checkboxes.first->checked(),
checkboxes.second->checked());
};
const auto enabledSomething = [=](
Type type,
std::pair<bool, bool> pair) {
return (!checked(Source::User, type) && pair.first)
|| (!checked(Source::Group, type) && pair.second);
};
const auto changedSomething = [=](
Type type,
std::pair<bool, bool> pair) {
return (checked(Source::User, type) != pair.first)
|| (checked(Source::Group, type) != pair.second);
};
const auto save = [=](
Type type,
std::pair<bool, bool> pair) {
const auto limit = [](bool checked) {
return checked ? kMaxBytesLimit : 0;
};
settings->setBytesLimit(Source::User, type, limit(pair.first));
settings->setBytesLimit(Source::Group, type, limit(pair.second));
settings->setBytesLimit(Source::Channel, type, limit(pair.second));
};
const auto addCheckbox = [&](Type type, Source source) {
const auto label = (source == Source::User)
? lng_media_auto_private_chats
: lng_media_auto_groups;
return content->add(
object_ptr<Ui::Checkbox>(
content,
lang(label),
checked(source, type),
st::settingsSendType),
st::settingsSendTypePadding);
};
const auto addPair = [&](Type type) {
const auto first = addCheckbox(type, Source::User);
const auto second = addCheckbox(type, Source::Group);
return pair(first, second);
};
AddSubsectionTitle(content, lng_media_photo_title);
const auto photo = addPair(Type::Photo);
AddSkip(content);
AddSkip(content);
AddSubsectionTitle(content, lng_media_audio_title);
const auto audio = addPair(Type::VoiceMessage);
AddSkip(content);
AddSkip(content);
AddSubsectionTitle(content, lng_media_gif_title);
const auto gif = addPair(Type::GIF);
AddSkip(content);
addButton(langFactory(lng_connection_save), [=] {
const auto photoChecked = pairChecked(photo);
const auto audioChecked = pairChecked(audio);
const auto gifChecked = pairChecked(gif);
const auto photosEnabled = enabledSomething(
Type::Photo,
photoChecked);
const auto audioEnabled = enabledSomething(
Type::VoiceMessage,
audioChecked);
const auto gifEnabled = enabledSomething(
Type::GIF,
gifChecked);
const auto photosChanged = changedSomething(
Type::Photo,
photoChecked);
const auto documentsChanged = changedSomething(
Type::VoiceMessage,
audioChecked) || changedSomething(Type::GIF, gifChecked);
if (photosChanged || documentsChanged) {
save(Type::Photo, photoChecked);
save(Type::VoiceMessage, audioChecked);
save(Type::GIF, gifChecked);
save(Type::VideoMessage, gifChecked);
Local::writeUserSettings();
}
if (photosEnabled) {
Auth().data().photoLoadSettingsChanged();
}
if (audioEnabled) {
Auth().data().voiceLoadSettingsChanged();
}
if (gifEnabled) {
Auth().data().animationLoadSettingsChanged();
}
closeBox();
});
addButton(langFactory(lng_cancel), [=] { closeBox(); });
setDimensionsToContent(st::boxWideWidth, content);
}
ProxiesBoxController::ProxiesBoxController()
: _saveTimer([] { Local::writeSettings(); }) {
_list = ranges::view::all(
@ -1524,7 +1382,7 @@ void ProxiesBoxController::share(const ProxyData &proxy) {
? "&pass=" + qthelp::url_encode(proxy.password) : "")
+ ((proxy.type == Type::Mtproto && !proxy.password.isEmpty())
? "&secret=" + proxy.password : "");
Application::clipboard()->setText(link);
QApplication::clipboard()->setText(link);
Ui::Toast::Show(lang(lng_username_copied));
}

View File

@ -22,18 +22,6 @@ template <typename Enum>
class Radioenum;
} // namespace Ui
class AutoDownloadBox : public BoxContent {
public:
AutoDownloadBox(QWidget *parent);
protected:
void prepare() override;
private:
void setupContent();
};
class ProxiesBoxController : public base::Subscriber {
public:
using Type = ProxyData::Type;

View File

@ -247,19 +247,9 @@ void Session::photoLoadSettingsChanged() {
}
}
void Session::voiceLoadSettingsChanged() {
void Session::documentLoadSettingsChanged() {
for (const auto &[id, document] : _documents) {
if (document->isVoiceMessage()) {
document->automaticLoadSettingsChanged();
}
}
}
void Session::animationLoadSettingsChanged() {
for (const auto &[id, document] : _documents) {
if (document->isAnimation()) {
document->automaticLoadSettingsChanged();
}
document->automaticLoadSettingsChanged();
}
}

View File

@ -238,8 +238,7 @@ public:
const Dialogs::Key &key2);
void photoLoadSettingsChanged();
void voiceLoadSettingsChanged();
void animationLoadSettingsChanged();
void documentLoadSettingsChanged();
void notifyPhotoLayoutChanged(not_null<const PhotoData*> photo);
void notifyDocumentLayoutChanged(

View File

@ -31,33 +31,8 @@ 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;
}
PeerId ReadPeerId(const MTPInputPeer &data) {
return data.match([](const MTPDinputPeerUser &data) {
return peerFromUser(data.vuser_id.v);
@ -74,6 +49,33 @@ PeerId ReadPeerId(const MTPInputPeer &data) {
} // namespace
int SizeLimitByIndex(int index) {
Expects(index >= 0 && index < kSizeValueCount);
index += 1;
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;
}
}();
return megabytes * kMegabyte;
}
SettingsWidget::SettingsWidget(QWidget *parent, Settings data)
: RpWidget(parent)
, _singlePeerId(ReadPeerId(data.singlePeer))
@ -583,7 +585,7 @@ void SettingsWidget::addSizeSlider(
st::exportFileSizePadding);
slider->resize(st::exportFileSizeSlider.seekSize);
slider->setPseudoDiscrete(
kSizeValueCount + 1,
kSizeValueCount,
SizeLimitByIndex,
readData().media.sizeLimit,
[=](int limit) {
@ -599,10 +601,7 @@ void SettingsWidget::addSizeSlider(
return data.media.sizeLimit;
}) | rpl::start_with_next([=](int sizeLimit) {
const auto limit = sizeLimit / kMegabyte;
const auto size = ((limit > 0)
? QString::number(limit)
: QString::number(float64(sizeLimit) / kMegabyte))
+ " MB";
const auto size = QString::number(limit) + " MB";
const auto text = lng_export_option_size_limit(lt_size, size);
label->setText(text);
}, slider->lifetime());

View File

@ -21,6 +21,9 @@ class ScrollArea;
namespace Export {
namespace View {
constexpr auto kSizeValueCount = 80;
int SizeLimitByIndex(int index);
class SettingsWidget : public Ui::RpWidget {
public:
SettingsWidget(QWidget *parent, Settings data);

View File

@ -51,6 +51,17 @@ Button *Button::toggleOn(rpl::producer<bool> &&toggled) {
return this;
}
bool Button::toggled() const {
return _toggle ? _toggle->checked() : false;
}
rpl::producer<bool> Button::toggledChanges() const {
if (_toggle) {
return _toggle->checkedChanges();
}
return rpl::never<bool>();
}
rpl::producer<bool> Button::toggledValue() const {
if (_toggle) {
return _toggle->checkedValue();
@ -58,10 +69,6 @@ rpl::producer<bool> Button::toggledValue() const {
return rpl::never<bool>();
}
bool Button::toggled() const {
return _toggle ? _toggle->checked() : false;
}
void Button::setColorOverride(std::optional<QColor> textColorOverride) {
_textColorOverride = textColorOverride;
update();

View File

@ -27,8 +27,9 @@ public:
const style::InfoProfileButton &st);
Button *toggleOn(rpl::producer<bool> &&toggled);
rpl::producer<bool> toggledValue() const;
bool toggled() const;
rpl::producer<bool> toggledChanges() const;
rpl::producer<bool> toggledValue() const;
void setColorOverride(std::optional<QColor> textColorOverride);

View File

@ -187,3 +187,7 @@ settingsThemeBubblePosition: point(6px, 8px);
settingsThemeBubbleSkip: 4px;
settingsThemeRadioBottom: 8px;
settingsThemeMinSkip: 4px;
autoDownloadLimitButton: InfoProfileButton(settingsButton) {
padding: margins(22px, 10px, 22px, 0px);
}

View File

@ -472,6 +472,7 @@ void Advanced::setupContent() {
AddSkip(content);
}
SetupDataStorage(content);
SetupAutoDownload(content);
if (HasTray()) {
addDivider();
AddSkip(content);

View File

@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "settings/settings_common.h"
#include "boxes/connection_box.h"
#include "boxes/auto_download_box.h"
#include "boxes/stickers_box.h"
#include "boxes/background_box.h"
#include "boxes/download_path_box.h"
@ -616,20 +617,35 @@ void SetupDataStorage(not_null<Ui::VerticalLayout*> container) {
}, ask->lifetime());
AddButton(
container,
lng_media_auto_settings,
st::settingsButton
)->addClickHandler([] {
Ui::show(Box<AutoDownloadBox>());
});
SetupLocalStorage(container);
SetupExport(container);
AddSkip(container, st::settingsCheckboxesSkip);
}
void SetupAutoDownload(not_null<Ui::VerticalLayout*> container) {
AddDivider(container);
AddSkip(container);
AddSubsectionTitle(container, lng_media_auto_settings);
using Source = Data::AutoDownload::Source;
const auto add = [&](LangKey label, Source source) {
AddButton(
container,
label,
st::settingsButton
)->addClickHandler([=] {
Ui::show(Box<AutoDownloadBox>(source));
});
};
add(lng_media_auto_in_private, Source::User);
add(lng_media_auto_in_groups, Source::Group);
add(lng_media_auto_in_channels, Source::Channel);
AddSkip(container, st::settingsCheckboxesSkip);
}
void SetupChatBackground(not_null<Ui::VerticalLayout*> container) {
AddDivider(container);
AddSkip(container);

View File

@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Settings {
void SetupDataStorage(not_null<Ui::VerticalLayout*> container);
void SetupAutoDownload(not_null<Ui::VerticalLayout*> container);
void SetupDefaultThemes(not_null<Ui::VerticalLayout*> container);
void SetupSupport(not_null<Ui::VerticalLayout*> container);

View File

@ -12,7 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/peer_list_box.h"
#include "boxes/edit_privacy_box.h"
#include "boxes/passcode_box.h"
#include "boxes/autolock_box.h"
#include "boxes/auto_lock_box.h"
#include "boxes/sessions_box.h"
#include "boxes/confirm_box.h"
#include "boxes/self_destruction_box.h"

View File

@ -27,6 +27,9 @@ public:
float64 currentAnimationValue(TimeMs ms);
bool animating() const;
auto checkedChanges() const {
return _checks.events();
}
auto checkedValue() const {
return _checks.events_starting_with(checked());
}

View File

@ -8,8 +8,10 @@
<(src_loc)/boxes/abstract_box.h
<(src_loc)/boxes/add_contact_box.cpp
<(src_loc)/boxes/add_contact_box.h
<(src_loc)/boxes/autolock_box.cpp
<(src_loc)/boxes/autolock_box.h
<(src_loc)/boxes/auto_lock_box.cpp
<(src_loc)/boxes/auto_lock_box.h
<(src_loc)/boxes/auto_download_box.cpp
<(src_loc)/boxes/auto_download_box.h
<(src_loc)/boxes/background_box.cpp
<(src_loc)/boxes/background_box.h
<(src_loc)/boxes/calendar_box.cpp