Allow to choose one of four default themes.

This commit is contained in:
John Preston 2018-09-26 14:28:16 +03:00
parent cf9f7ef508
commit 9b85dd27ca
17 changed files with 452 additions and 78 deletions

Binary file not shown.

Binary file not shown.

View File

@ -50,7 +50,9 @@
<file alias="art/logo_256.png">../art/logo_256.png</file>
<file alias="art/logo_256_no_margin.png">../art/logo_256_no_margin.png</file>
<file alias="art/sunrise.jpg">../art/sunrise.jpg</file>
<file alias="day-blue.tdesktop-theme">../day-blue.tdesktop-theme</file>
<file alias="night.tdesktop-theme">../night.tdesktop-theme</file>
<file alias="night-green.tdesktop-theme">../night-green.tdesktop-theme</file>
</qresource>
<qresource prefix="/sounds">
<file alias="msg_incoming.mp3">../sounds/msg_incoming.mp3</file>

View File

@ -75,7 +75,7 @@ UserCheckbox::UserCheckbox(QWidget *parent, not_null<UserData*> user, bool check
void UserCheckbox::setChecked(bool checked, NotifyAboutChange notify) {
if (_check->checked() != checked) {
_check->setCheckedAnimated(checked);
_check->setChecked(checked, anim::type::normal);
if (notify == NotifyAboutChange::Notify) {
checkedChanged.notify(checked, true);
}

View File

@ -40,12 +40,12 @@ Button *Button::toggleOn(rpl::producer<bool> &&toggled) {
false,
[this] { rtlupdate(toggleRect()); });
addClickHandler([this] {
_toggle->setCheckedAnimated(!_toggle->checked());
_toggle->setChecked(!_toggle->checked(), anim::type::normal);
});
std::move(
toggled
) | rpl::start_with_next([this](bool toggled) {
_toggle->setCheckedAnimated(toggled);
_toggle->setChecked(toggled, anim::type::normal);
}, lifetime());
_toggle->finishAnimating();
return this;

View File

@ -152,3 +152,26 @@ settingsBioCountdown: FlatLabel(defaultFlatLabel) {
settingsBioLabelPadding: margins(22px, 11px, 22px, 0px);
settingsPrivacyEditLabelPadding: margins(22px, 11px, 22px, 11px);
settingsTheme: Checkbox(defaultCheckbox) {
textFg: windowSubTextFg;
textFgActive: windowActiveTextFg;
width: 80px;
margin: margins(0px, 0px, 0px, 0px);
textPosition: point(0px, 88px);
checkPosition: point(0px, 0px);
style: defaultTextStyle;
disabledOpacity: 0.5;
}
settingsThemePreviewSize: size(80px, 80px);
settingsThemeBubbleSize: size(40px, 14px);
settingsThemeBubbleRadius: 2px;
settingsThemeBubblePosition: point(6px, 8px);
settingsThemeBubbleSkip: 4px;
settingsThemeRadioBottom: 8px;
settingsThemeMinSkip: 4px;

View File

@ -59,6 +59,44 @@ private:
};
class DefaultTheme final : public Ui::AbstractCheckView {
public:
enum class Type {
DayBlue,
Default,
Night,
NightGreen,
};
struct Scheme {
Type type = Type();
QColor background;
QColor sent;
QColor received;
QColor radiobuttonInactive;
QColor radiobuttonActive;
QString name;
QString path;
};
DefaultTheme(Scheme scheme, bool checked);
QSize getSize() const override;
void paint(
Painter &p,
int left,
int top,
int outerWidth,
TimeMs ms) override;
QImage prepareRippleMask() const override;
bool checkRippleStartPosition(QPoint position) const override;
private:
void checkedChangedHook(anim::type animated) override;
Scheme _scheme;
Ui::RadioView _radio;
};
void ChooseFromFile(not_null<QWidget*> parent);
BackgroundRow::BackgroundRow(QWidget *parent) : RpWidget(parent)
@ -252,6 +290,66 @@ void BackgroundRow::updateImage() {
}
}
DefaultTheme::DefaultTheme(Scheme scheme, bool checked)
: AbstractCheckView(st::defaultRadio.duration, checked, nullptr)
, _scheme(scheme)
, _radio(st::defaultRadio, checked, [=] { update(); }) {
_radio.setToggledOverride(_scheme.radiobuttonActive);
_radio.setUntoggledOverride(_scheme.radiobuttonInactive);
}
QSize DefaultTheme::getSize() const {
return st::settingsThemePreviewSize;
}
void DefaultTheme::paint(
Painter &p,
int left,
int top,
int outerWidth,
TimeMs ms) {
const auto received = QRect(
st::settingsThemeBubblePosition,
st::settingsThemeBubbleSize);
const auto sent = QRect(
outerWidth - received.width() - st::settingsThemeBubblePosition.x(),
received.y() + received.height() + st::settingsThemeBubbleSkip,
received.width(),
received.height());
const auto radius = st::settingsThemeBubbleRadius;
p.fillRect(
QRect(QPoint(), st::settingsThemePreviewSize),
_scheme.background);
PainterHighQualityEnabler hq(p);
p.setPen(Qt::NoPen);
p.setBrush(_scheme.received);
p.drawRoundedRect(rtlrect(received, outerWidth), radius, radius);
p.setBrush(_scheme.sent);
p.drawRoundedRect(rtlrect(sent, outerWidth), radius, radius);
const auto radio = _radio.getSize();
_radio.paint(
p,
(outerWidth - radio.width()) / 2,
getSize().height() - radio.height() - st::settingsThemeRadioBottom,
outerWidth,
getms());
}
QImage DefaultTheme::prepareRippleMask() const {
return QImage();
}
bool DefaultTheme::checkRippleStartPosition(QPoint position) const {
return false;
}
void DefaultTheme::checkedChangedHook(anim::type animated) {
_radio.setChecked(checked(), animated);
}
void ChooseFromFile(not_null<QWidget*> parent) {
const auto imgExtensions = cImgExtensions();
auto filters = QStringList(
@ -623,6 +721,7 @@ void SetupNightMode(not_null<Ui::VerticalLayout*> container) {
const auto change = [=] {
if (!--*calling && toggled != Window::Theme::IsNightMode()) {
Window::Theme::ToggleNightMode();
Window::Theme::KeepApplied();
}
};
App::CallDelayed(
@ -655,13 +754,193 @@ void SetupUseDefaultTheme(not_null<Ui::VerticalLayout*> container) {
});
}
void SetupDefaultThemes(not_null<Ui::VerticalLayout*> container) {
using Type = DefaultTheme::Type;
using Scheme = DefaultTheme::Scheme;
const auto block = container->add(object_ptr<Ui::FixedHeightWidget>(
container));
const auto scheme = DefaultTheme::Scheme();
const auto color = [](str_const hex) {
Expects(hex.size() == 6);
const auto component = [](char a, char b) {
const auto convert = [](char ch) {
Expects((ch >= '0' && ch <= '9')
|| (ch >= 'A' && ch <= 'F')
|| (ch >= 'a' && ch <= 'f'));
return (ch >= '0' && ch <= '9')
? int(ch - '0')
: int(ch - ((ch >= 'A' && ch <= 'F') ? 'A' : 'a') + 10);
};
return convert(a) * 16 + convert(b);
};
return QColor(
component(hex[0], hex[1]),
component(hex[2], hex[3]),
component(hex[4], hex[5]));
};
static const auto schemes = {
Scheme{
Type::DayBlue,
color("7ec4ea"),
color("d7f0ff"),
color("ffffff"),
color("d7f0ff"),
color("ffffff"),
"Blue",
":/gui/day-blue.tdesktop-theme"
},
Scheme{
Type::Default,
color("90ce89"),
color("eaffdc"),
color("ffffff"),
color("eaffdc"),
color("ffffff"),
"Classic",
QString()
},
Scheme{
Type::Night,
color("485761"),
color("5ca7d4"),
color("6b808d"),
color("6b808d"),
color("5ca7d4"),
"Night #1",
":/gui/night.tdesktop-theme"
},
Scheme{
Type::NightGreen,
color("485761"),
color("74bf93"),
color("6b808d"),
color("6b808d"),
color("74bf93"),
"Night #2",
":/gui/night-green.tdesktop-theme"
},
};
const auto chosen = [&] {
if (Window::Theme::IsNonDefaultBackground()) {
return Type(-1);
}
const auto path = Window::Theme::Background()->themeAbsolutePath();
for (const auto scheme : schemes) {
if (path == scheme.path) {
return scheme.type;
}
}
return Type(-1);
};
const auto group = std::make_shared<Ui::RadioenumGroup<Type>>(chosen());
auto buttons = ranges::view::all(
schemes
) | ranges::view::transform([&](const Scheme &scheme) {
auto check = std::make_unique<DefaultTheme>(scheme, false);
const auto weak = check.get();
const auto result = Ui::CreateChild<Ui::Radioenum<Type>>(
block,
group,
scheme.type,
scheme.name,
st::settingsTheme,
std::move(check));
weak->setUpdateCallback([=] { result->update(); });
return result;
}) | ranges::to_vector;
using Update = const Window::Theme::BackgroundUpdate;
const auto apply = [=](const Scheme &scheme) {
const auto isNight = [](const Scheme &scheme) {
const auto type = scheme.type;
return (type != Type::DayBlue) && (type != Type::Default);
};
const auto currentlyIsCustom = (chosen() == Type(-1));
if (Window::Theme::IsNightMode() == isNight(scheme)) {
Window::Theme::ApplyDefaultWithPath(scheme.path);
} else {
Window::Theme::ToggleNightMode(scheme.path);
}
if (!currentlyIsCustom) {
Window::Theme::KeepApplied();
}
};
group->setChangedCallback([=](Type type) {
const auto i = ranges::find_if(schemes, [&](const Scheme &scheme) {
return (type == scheme.type && type != chosen());
});
if (i != end(schemes)) {
apply(*i);
}
});
base::ObservableViewer(
*Window::Theme::Background()
) | rpl::filter([](const Update &update) {
return (update.type == Update::Type::ApplyingTheme
|| update.type == Update::Type::New);
}) | rpl::map([=] {
return chosen();
}) | rpl::start_with_next([=](Type type) {
group->setValue(type);
}, container->lifetime());
for (const auto button : buttons) {
button->setCheckAlignment(style::al_top);
button->resizeToWidth(button->width());
}
block->resize(block->width(), buttons[0]->height());
block->widthValue(
) | rpl::start_with_next([buttons = std::move(buttons)](int width) {
Expects(!buttons.empty());
// |------| |---------| |-------| |-------|
// pad | blue | skip | classic | 3*skip | night | skip | night | pad
// |------| |---------| |-------| |-------|
const auto padding = st::settingsButton.padding;
width -= padding.left() + padding.right();
const auto desired = st::settingsThemePreviewSize.width();
const auto count = int(buttons.size());
const auto smallSkips = (count / 2);
const auto bigSkips = ((count - 1) / 2);
const auto skipRatio = 3;
const auto skipSegments = smallSkips + bigSkips * skipRatio;
const auto minSkip = st::settingsThemeMinSkip;
const auto single = [&] {
if (width >= skipSegments * minSkip + count * desired) {
return desired;
}
return (width - skipSegments * minSkip) / count;
}();
if (single <= 0) {
return;
}
const auto fullSkips = width - count * single;
const auto segment = fullSkips / float64(skipSegments);
const auto smallSkip = segment;
const auto bigSkip = segment * skipRatio;
auto left = padding.left() + 0.;
auto index = 0;
for (const auto button : buttons) {
button->resizeToWidth(single);
button->moveToLeft(int(std::round(left)), 0);
left += button->width() + ((index++ % 2) ? bigSkip : smallSkip);
}
}, block->lifetime());
AddSkip(container);
}
void SetupThemeOptions(not_null<Ui::VerticalLayout*> container) {
AddDivider(container);
AddSkip(container);
AddSubsectionTitle(container, lng_settings_themes);
SetupNightMode(container);
SetupDefaultThemes(container);
//SetupNightMode(container);
AddButton(
container,
@ -672,7 +951,7 @@ void SetupThemeOptions(not_null<Ui::VerticalLayout*> container) {
container,
[] { Window::Theme::Editor::Start(); }));
SetupUseDefaultTheme(container);
//SetupUseDefaultTheme(container);
AddSkip(container);
}

View File

@ -14,6 +14,7 @@ namespace Settings {
void SetupDataStorage(not_null<Ui::VerticalLayout*> container);
void SetupNightMode(not_null<Ui::VerticalLayout*> container);
void SetupUseDefaultTheme(not_null<Ui::VerticalLayout*> container);
void SetupDefaultThemes(not_null<Ui::VerticalLayout*> container);
class Chat : public Section {
public:

View File

@ -79,8 +79,7 @@ object_ptr<Ui::RpWidget> CreateIntroSettings(QWidget *parent) {
AddDivider(result);
AddSkip(result);
SetupInterfaceScale(result, false);
SetupNightMode(result);
SetupUseDefaultTheme(result);
SetupDefaultThemes(result);
AddSkip(result);
if (anim::Disabled()) {

View File

@ -28,14 +28,23 @@ AbstractCheckView::AbstractCheckView(int duration, bool checked, Fn<void()> upda
, _updateCallback(std::move(updateCallback)) {
}
void AbstractCheckView::setCheckedFast(bool checked) {
const auto fire = (_checked != checked);
void AbstractCheckView::setChecked(bool checked, anim::type animated) {
const auto changed = (_checked != checked);
_checked = checked;
finishAnimating();
if (_updateCallback) {
_updateCallback();
if (animated == anim::type::instant) {
finishAnimating();
if (_updateCallback) {
_updateCallback();
}
} else if (changed) {
_toggleAnimation.start(
_updateCallback,
_checked ? 0. : 1.,
_checked ? 1. : 0.,
_duration);
}
if (fire) {
if (changed) {
checkedChangedHook(animated);
_checks.fire_copy(_checked);
}
}
@ -53,14 +62,6 @@ void AbstractCheckView::update() {
}
}
void AbstractCheckView::setCheckedAnimated(bool checked) {
if (_checked != checked) {
_checked = checked;
_toggleAnimation.start(_updateCallback, _checked ? 0. : 1., _checked ? 1. : 0., _duration);
_checks.fire_copy(_checked);
}
}
void AbstractCheckView::finishAnimating() {
_toggleAnimation.finish();
}
@ -69,6 +70,10 @@ float64 AbstractCheckView::currentAnimationValue(TimeMs ms) {
return ms ? _toggleAnimation.current(ms, _checked ? 1. : 0.) : _toggleAnimation.current(_checked ? 1. : 0.);
}
bool AbstractCheckView::animating() const {
return _toggleAnimation.animating();
}
ToggleView::ToggleView(
const style::Toggle &st,
bool checked,
@ -283,9 +288,13 @@ void RadioView::paint(Painter &p, int left, int top, int outerWidth, TimeMs ms)
PainterHighQualityEnabler hq(p);
auto toggled = currentAnimationValue(ms);
auto pen = _untoggledOverride
? anim::pen(*_untoggledOverride, _st->toggledFg, toggled)
: anim::pen(_st->untoggledFg, _st->toggledFg, toggled);
auto pen = _toggledOverride
? (_untoggledOverride
? anim::pen(*_untoggledOverride, *_toggledOverride, toggled)
: anim::pen(_st->untoggledFg, *_toggledOverride, toggled))
: (_untoggledOverride
? anim::pen(*_untoggledOverride, _st->toggledFg, toggled)
: anim::pen(_st->untoggledFg, _st->toggledFg, toggled));
pen.setWidth(_st->thickness);
p.setPen(pen);
p.setBrush(_st->bg);
@ -295,9 +304,13 @@ void RadioView::paint(Painter &p, int left, int top, int outerWidth, TimeMs ms)
if (toggled > 0) {
p.setPen(Qt::NoPen);
p.setBrush(_untoggledOverride
? anim::brush(*_untoggledOverride, _st->toggledFg, toggled)
: anim::brush(_st->untoggledFg, _st->toggledFg, toggled));
p.setBrush(_toggledOverride
? (_untoggledOverride
? anim::brush(*_untoggledOverride, *_toggledOverride, toggled)
: anim::brush(_st->untoggledFg, *_toggledOverride, toggled))
: (_untoggledOverride
? anim::brush(*_untoggledOverride, _st->toggledFg, toggled)
: anim::brush(_st->untoggledFg, _st->toggledFg, toggled)));
auto skip0 = _st->diameter / 2., skip1 = _st->skip / 10., checkSkip = skip0 * (1. - toggled) + skip1 * toggled;
p.drawEllipse(rtlrect(QRectF(left, top, _st->diameter, _st->diameter).marginsRemoved(QMarginsF(checkSkip, checkSkip, checkSkip, checkSkip)), outerWidth));
@ -327,6 +340,11 @@ bool RadioView::checkRippleStartPosition(QPoint position) const {
return QRect(QPoint(0, 0), rippleSize()).contains(position);
}
void RadioView::setToggledOverride(std::optional<QColor> toggledOverride) {
_toggledOverride = toggledOverride;
update();
}
void RadioView::setUntoggledOverride(
std::optional<QColor> untoggledOverride) {
_untoggledOverride = untoggledOverride;
@ -420,7 +438,7 @@ void Checkbox::resizeToText() {
void Checkbox::setChecked(bool checked, NotifyAboutChange notify) {
if (_check->checked() != checked) {
_check->setCheckedAnimated(checked);
_check->setChecked(checked, anim::type::normal);
if (notify == NotifyAboutChange::Notify) {
checkedChanged.notify(checked, true);
}
@ -447,10 +465,10 @@ void Checkbox::paintEvent(QPaintEvent *e) {
auto check = checkRect();
auto ms = getms();
auto active = _check->currentAnimationValue(ms);
if (isDisabled()) {
p.setOpacity(_st.disabledOpacity);
} else {
auto active = _check->currentAnimationValue(ms);
auto color = anim::color(_st.rippleBg, _st.rippleBgActive, active);
paintRipple(
p,
@ -476,8 +494,7 @@ void Checkbox::paintEvent(QPaintEvent *e) {
auto availableTextWidth = qMax(width() - leftSkip, 1);
if (!_text.isEmpty()) {
Assert(!(_checkAlignment & Qt::AlignHCenter));
p.setPen(_st.textFg);
p.setPen(anim::pen(_st.textFg, _st.textFgActive, active));
auto textSkip = _st.checkPosition.x()
+ check.width()
+ _st.textPosition.x();
@ -489,13 +506,21 @@ void Checkbox::paintEvent(QPaintEvent *e) {
textTop,
availableTextWidth,
width());
} else {
} else if (_checkAlignment & Qt::AlignRight) {
_text.drawRightElided(
p,
textSkip,
textTop,
availableTextWidth,
width());
} else {
_text.drawLeft(
p,
_st.margin.left(),
textTop,
width() - _st.margin.left() - _st.margin.right(),
width(),
style::al_top);
}
}
}
@ -537,7 +562,15 @@ void Checkbox::handlePress() {
}
int Checkbox::resizeGetHeight(int newWidth) {
return _check->getSize().height();
const auto result = _check->getSize().height();
if (!(_checkAlignment & Qt::AlignHCenter)) {
return result;
}
const auto textBottom = _st.margin.top()
+ _st.textPosition.y()
+ _text.countHeight(
newWidth - _st.margin.left() - _st.margin.right());
return std::max(result, textBottom);
}
QImage Checkbox::prepareRippleMask() const {

View File

@ -17,8 +17,7 @@ class AbstractCheckView {
public:
AbstractCheckView(int duration, bool checked, Fn<void()> updateCallback);
void setCheckedFast(bool checked);
void setCheckedAnimated(bool checked);
void setChecked(bool checked, anim::type animated);
void finishAnimating();
void setUpdateCallback(Fn<void()> updateCallback);
bool checked() const {
@ -26,6 +25,7 @@ public:
}
void update();
float64 currentAnimationValue(TimeMs ms);
bool animating() const;
auto checkedValue() const {
return _checks.events_starting_with(checked());
@ -47,6 +47,9 @@ public:
virtual ~AbstractCheckView() = default;
private:
virtual void checkedChangedHook(anim::type animated) {
}
int _duration = 0;
bool _checked = false;
Fn<void()> _updateCallback;
@ -90,6 +93,7 @@ public:
void setStyle(const style::Radio &st);
void setToggledOverride(std::optional<QColor> toggledOverride);
void setUntoggledOverride(std::optional<QColor> untoggledOverride);
QSize getSize() const override;
@ -101,6 +105,7 @@ private:
QSize rippleSize() const;
not_null<const style::Radio*> _st;
std::optional<QColor> _toggledOverride;
std::optional<QColor> _untoggledOverride;
};

View File

@ -132,7 +132,7 @@ int Menu::processAction(QAction *action, int index, int width) {
auto updateCallback = [this, index] { updateItem(index); };
if (data.toggle) {
data.toggle->setUpdateCallback(updateCallback);
data.toggle->setCheckedAnimated(action->isChecked());
data.toggle->setChecked(action->isChecked(), anim::type::normal);
} else {
data.toggle = std::make_unique<ToggleView>(_st.itemToggle, action->isChecked(), updateCallback);
}

View File

@ -142,6 +142,7 @@ Radio {
Checkbox {
textFg: color;
textFgActive: color;
width: pixels;
margin: margins;

View File

@ -92,7 +92,7 @@ public:
class FixedHeightWidget : public RpWidget {
public:
FixedHeightWidget(QWidget *parent, int height)
explicit FixedHeightWidget(QWidget *parent, int height = 0)
: RpWidget(parent) {
resize(width(), height);
}

View File

@ -33,6 +33,7 @@ struct Data {
QByteArray content;
QByteArray paletteForRevert;
Cached cached;
Fn<void()> overrideKeep;
};
ChatBackground background;
@ -336,24 +337,6 @@ void adjustColor(style::color color, float64 hue, float64 saturation) {
color.set(original.red(), original.green(), original.blue(), original.alpha());
}
void ApplyDefaultWithNightMode(bool nightMode) {
if (nightMode) {
if (auto preview = PreviewFromFile(NightThemePath())) {
Apply(std::move(preview));
}
} else {
instance.createIfNull();
instance->applying.pathRelative = QString();
instance->applying.pathAbsolute = QString();
instance->applying.content = QByteArray();
instance->applying.cached = Cached();
if (instance->applying.paletteForRevert.isEmpty()) {
instance->applying.paletteForRevert = style::main_palette::save();
}
Background()->setTestingDefaultTheme();
}
}
void WriteAppliedTheme() {
auto saved = Saved();
saved.pathRelative = instance->applying.pathRelative;
@ -723,6 +706,13 @@ bool ChatBackground::isNonDefaultThemeOrBackground() {
|| _id != kDefaultBackground);
}
bool ChatBackground::isNonDefaultBackground() {
start();
return _themeAbsolutePath.isEmpty()
? (_id != kDefaultBackground)
: (_id != kThemeBackground);
}
void ChatBackground::writeNewBackgroundSettings() {
if (tile() != _tileForRevert) {
Local::writeUserSettings();
@ -755,11 +745,12 @@ bool ChatBackground::nightMode() const {
return _nightMode;
}
void ChatBackground::toggleNightMode() {
void ChatBackground::toggleNightMode(std::optional<QString> themePath) {
const auto settingDefault = themePath.has_value();
const auto oldNightMode = _nightMode;
const auto newNightMode = !_nightMode;
_nightMode = newNightMode;
auto read = Local::readThemeAfterSwitch();
auto read = settingDefault ? Saved() : Local::readThemeAfterSwitch();
auto path = read.pathAbsolute;
_nightMode = oldNightMode;
@ -784,30 +775,34 @@ void ChatBackground::toggleNightMode() {
return true;
}();
if (!alreadyOnDisk) {
path = newNightMode ? NightThemePath() : QString();
ApplyDefaultWithNightMode(newNightMode);
path = themePath
? *themePath
: (newNightMode ? NightThemePath() : QString());
ApplyDefaultWithPath(path);
}
// Theme editor could have already reverted the testing of this toggle.
if (AreTestingTheme()) {
_nightMode = newNightMode;
instance->applying.overrideKeep = [=] {
_nightMode = newNightMode;
// Restore the value, it was set inside theme testing.
(oldNightMode ? _tileNightValue : _tileDayValue) = oldTileValue;
// Restore the value, it was set inside theme testing.
(oldNightMode ? _tileNightValue : _tileDayValue) = oldTileValue;
if (!alreadyOnDisk) {
// First-time switch to default night mode should write it.
WriteAppliedTheme();
}
ClearApplying();
keepApplied(path, false);
if (tile() != _tileForRevert) {
Local::writeUserSettings();
}
Local::writeSettings();
if (!Local::readBackground()) {
setImage(kThemeBackground);
}
if (!alreadyOnDisk) {
// First-time switch to default night mode should write it.
WriteAppliedTheme();
}
ClearApplying();
keepApplied(path, settingDefault);
if (tile() != _tileForRevert) {
Local::writeUserSettings();
}
Local::writeSettings();
if (!settingDefault && !Local::readBackground()) {
setImage(kThemeBackground);
}
};
}
}
@ -863,7 +858,25 @@ bool Apply(std::unique_ptr<Preview> preview) {
}
void ApplyDefault() {
ApplyDefaultWithNightMode(IsNightMode());
ApplyDefaultWithPath(IsNightMode() ? NightThemePath() : QString());
}
void ApplyDefaultWithPath(const QString &themePath) {
if (!themePath.isEmpty()) {
if (auto preview = PreviewFromFile(themePath)) {
Apply(std::move(preview));
}
} else {
instance.createIfNull();
instance->applying.pathRelative = QString();
instance->applying.pathAbsolute = QString();
instance->applying.content = QByteArray();
instance->applying.cached = Cached();
if (instance->applying.paletteForRevert.isEmpty()) {
instance->applying.paletteForRevert = style::main_palette::save();
}
Background()->setTestingDefaultTheme();
}
}
bool ApplyEditedPalette(const QString &path, const QByteArray &content) {
@ -895,6 +908,9 @@ bool ApplyEditedPalette(const QString &path, const QByteArray &content) {
void KeepApplied() {
if (!AreTestingTheme()) {
return;
} else if (instance->applying.overrideKeep) {
instance->applying.overrideKeep();
return;
}
const auto path = instance->applying.pathAbsolute;
WriteAppliedTheme();
@ -921,6 +937,10 @@ bool IsNonDefaultThemeOrBackground() {
return Background()->isNonDefaultThemeOrBackground();
}
bool IsNonDefaultBackground() {
return Background()->isNonDefaultBackground();
}
bool IsNightMode() {
return instance ? Background()->nightMode() : false;
}
@ -932,7 +952,11 @@ void SetNightModeValue(bool nightMode) {
}
void ToggleNightMode() {
Background()->toggleNightMode();
Background()->toggleNightMode(std::nullopt);
}
void ToggleNightMode(const QString &path) {
Background()->toggleNightMode(path);
}
bool SuggestThemeReset() {

View File

@ -57,12 +57,15 @@ struct Preview {
bool Apply(const QString &filepath);
bool Apply(std::unique_ptr<Preview> preview);
void ApplyDefault();
void ApplyDefaultWithPath(const QString &themePath);
bool ApplyEditedPalette(const QString &path, const QByteArray &content);
void KeepApplied();
QString NightThemePath();
bool IsNightMode();
void SetNightModeValue(bool nightMode);
void ToggleNightMode();
void ToggleNightMode(const QString &themePath);
bool IsNonDefaultBackground();
bool IsNonDefaultThemeOrBackground();
bool SuggestThemeReset();
void Revert();
@ -140,14 +143,17 @@ private:
void setNightModeValue(bool nightMode);
bool nightMode() const;
void toggleNightMode();
void toggleNightMode(std::optional<QString> themePath);
void keepApplied(const QString &path, bool write);
bool isNonDefaultThemeOrBackground();
bool isNonDefaultBackground();
friend bool IsNightMode();
friend void SetNightModeValue(bool nightMode);
friend void ToggleNightMode();
friend void ToggleNightMode(const QString &themePath);
friend void KeepApplied();
friend bool IsNonDefaultBackground();
friend bool IsNonDefaultThemeOrBackground();
int32 _id = internal::kUninitializedBackground;

View File

@ -58,6 +58,7 @@ MainMenu::MainMenu(
const auto nightMode = Window::Theme::IsNightMode();
if (action->isChecked() != nightMode) {
Window::Theme::ToggleNightMode();
Window::Theme::KeepApplied();
}
}
});