mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Toggle wallpaper dark mode / edit dimming.
This commit is contained in:
parent
ac57d46f30
commit
65f54d937f
9 changed files with 384 additions and 79 deletions
|
@ -17,6 +17,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/toast/toast.h"
|
#include "ui/toast/toast.h"
|
||||||
#include "ui/image/image.h"
|
#include "ui/image/image.h"
|
||||||
#include "ui/widgets/checkbox.h"
|
#include "ui/widgets/checkbox.h"
|
||||||
|
#include "ui/widgets/continuous_sliders.h"
|
||||||
|
#include "ui/wrap/slide_wrap.h"
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
#include "ui/ui_utility.h"
|
#include "ui/ui_utility.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
|
@ -34,12 +36,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "base/unixtime.h"
|
#include "base/unixtime.h"
|
||||||
#include "boxes/background_preview_box.h"
|
#include "boxes/background_preview_box.h"
|
||||||
#include "window/window_session_controller.h"
|
#include "window/window_session_controller.h"
|
||||||
|
#include "window/themes/window_themes_embedded.h"
|
||||||
#include "settings/settings_common.h"
|
#include "settings/settings_common.h"
|
||||||
#include "storage/file_upload.h"
|
#include "storage/file_upload.h"
|
||||||
#include "storage/localimageloader.h"
|
#include "storage/localimageloader.h"
|
||||||
#include "styles/style_chat.h"
|
#include "styles/style_chat.h"
|
||||||
#include "styles/style_layers.h"
|
#include "styles/style_layers.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
|
#include "styles/style_settings.h"
|
||||||
|
|
||||||
#include <QtGui/QClipboard>
|
#include <QtGui/QClipboard>
|
||||||
#include <QtGui/QGuiApplication>
|
#include <QtGui/QGuiApplication>
|
||||||
|
@ -47,6 +51,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr auto kMaxWallPaperSlugLength = 255;
|
constexpr auto kMaxWallPaperSlugLength = 255;
|
||||||
|
constexpr auto kDefaultDimming = 50;
|
||||||
|
|
||||||
[[nodiscard]] bool IsValidWallPaperSlug(const QString &slug) {
|
[[nodiscard]] bool IsValidWallPaperSlug(const QString &slug) {
|
||||||
if (slug.isEmpty() || slug.size() > kMaxWallPaperSlugLength) {
|
if (slug.isEmpty() || slug.size() > kMaxWallPaperSlugLength) {
|
||||||
|
@ -154,6 +159,13 @@ constexpr auto kMaxWallPaperSlugLength = 255;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
struct BackgroundPreviewBox::OverridenStyle {
|
||||||
|
style::Box box;
|
||||||
|
style::IconButton toggle;
|
||||||
|
style::MediaSlider slider;
|
||||||
|
style::FlatLabel subtitle;
|
||||||
|
};
|
||||||
|
|
||||||
BackgroundPreviewBox::BackgroundPreviewBox(
|
BackgroundPreviewBox::BackgroundPreviewBox(
|
||||||
QWidget*,
|
QWidget*,
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
|
@ -183,9 +195,11 @@ BackgroundPreviewBox::BackgroundPreviewBox(
|
||||||
true))
|
true))
|
||||||
, _paper(paper)
|
, _paper(paper)
|
||||||
, _media(_paper.document() ? _paper.document()->createMediaView() : nullptr)
|
, _media(_paper.document() ? _paper.document()->createMediaView() : nullptr)
|
||||||
, _radial([=](crl::time now) { radialAnimationCallback(now); }) {
|
, _radial([=](crl::time now) { radialAnimationCallback(now); })
|
||||||
_chatStyle->apply(controller->defaultChatTheme().get());
|
, _appNightMode(Window::Theme::IsNightModeValue())
|
||||||
|
, _boxDarkMode(_appNightMode.current())
|
||||||
|
, _dimmingIntensity(std::clamp(paper.patternIntensity(), 0, 100))
|
||||||
|
, _dimmed(_forPeer && paper.document() && !paper.isPattern()) {
|
||||||
if (_media) {
|
if (_media) {
|
||||||
_media->thumbnailWanted(_paper.fileOrigin());
|
_media->thumbnailWanted(_paper.fileOrigin());
|
||||||
}
|
}
|
||||||
|
@ -194,6 +208,201 @@ BackgroundPreviewBox::BackgroundPreviewBox(
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
update();
|
update();
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
|
_appNightMode.changes(
|
||||||
|
) | rpl::start_with_next([=](bool night) {
|
||||||
|
_boxDarkMode = night;
|
||||||
|
update();
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
|
_boxDarkMode.changes(
|
||||||
|
) | rpl::start_with_next([=](bool dark) {
|
||||||
|
applyDarkMode(dark);
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
|
const auto prepare = [=](bool dark, auto pointer) {
|
||||||
|
const auto weak = Ui::MakeWeak(this);
|
||||||
|
crl::async([=] {
|
||||||
|
auto result = std::make_unique<style::palette>();
|
||||||
|
Window::Theme::PreparePaletteCallback(dark, {})(*result);
|
||||||
|
crl::on_main([=, result = std::move(result)]() mutable {
|
||||||
|
if (const auto strong = weak.data()) {
|
||||||
|
strong->*pointer = std::move(result);
|
||||||
|
strong->paletteReady();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
prepare(false, &BackgroundPreviewBox::_lightPalette);
|
||||||
|
prepare(true, &BackgroundPreviewBox::_darkPalette);
|
||||||
|
}
|
||||||
|
|
||||||
|
BackgroundPreviewBox::~BackgroundPreviewBox() = default;
|
||||||
|
|
||||||
|
void BackgroundPreviewBox::applyDarkMode(bool dark) {
|
||||||
|
const auto equals = (dark == Window::Theme::IsNightMode());
|
||||||
|
const auto &palette = (dark ? _darkPalette : _lightPalette);
|
||||||
|
if (!equals && !palette) {
|
||||||
|
_waitingForPalette = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_waitingForPalette = false;
|
||||||
|
if (equals) {
|
||||||
|
setStyle(st::defaultBox);
|
||||||
|
_chatStyle->applyCustomPalette(nullptr);
|
||||||
|
_paletteServiceBg = rpl::single(
|
||||||
|
rpl::empty
|
||||||
|
) | rpl::then(
|
||||||
|
style::PaletteChanged()
|
||||||
|
) | rpl::map([=] {
|
||||||
|
return st::msgServiceBg->c;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setStyle(overridenStyle(dark));
|
||||||
|
_chatStyle->applyCustomPalette(palette.get());
|
||||||
|
_paletteServiceBg = palette->msgServiceBg()->c;
|
||||||
|
}
|
||||||
|
resetTitle();
|
||||||
|
rebuildButtons(dark);
|
||||||
|
update();
|
||||||
|
if (const auto parent = parentWidget()) {
|
||||||
|
parent->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_dimmed) {
|
||||||
|
createDimmingSlider(dark);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BackgroundPreviewBox::createDimmingSlider(bool dark) {
|
||||||
|
const auto created = !_dimmingWrap;
|
||||||
|
if (created) {
|
||||||
|
_dimmingWrap.create(this, object_ptr<Ui::RpWidget>(this));
|
||||||
|
_dimmingContent = _dimmingWrap->entity();
|
||||||
|
}
|
||||||
|
_dimmingSlider = nullptr;
|
||||||
|
for (const auto &child : _dimmingContent->children()) {
|
||||||
|
if (child->isWidgetType()) {
|
||||||
|
static_cast<QWidget*>(child)->hide();
|
||||||
|
child->deleteLater();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const auto equals = (dark == Window::Theme::IsNightMode());
|
||||||
|
const auto inner = Ui::CreateChild<Ui::VerticalLayout>(_dimmingContent);
|
||||||
|
inner->show();
|
||||||
|
Settings::AddSubsectionTitle(
|
||||||
|
inner,
|
||||||
|
rpl::single(u"Background dimming"_q),
|
||||||
|
style::margins(0, st::settingsSectionSkip, 0, 0),
|
||||||
|
equals ? nullptr : dark ? &_dark->subtitle : &_light->subtitle);
|
||||||
|
_dimmingSlider = inner->add(
|
||||||
|
object_ptr<Ui::MediaSlider>(
|
||||||
|
inner,
|
||||||
|
(equals
|
||||||
|
? st::defaultContinuousSlider
|
||||||
|
: dark
|
||||||
|
? _dark->slider
|
||||||
|
: _light->slider)),
|
||||||
|
st::localStorageLimitMargin);
|
||||||
|
_dimmingSlider->setValue(_dimmingIntensity / 100.);
|
||||||
|
_dimmingSlider->setAlwaysDisplayMarker(true);
|
||||||
|
_dimmingSlider->resize(st::defaultContinuousSlider.seekSize);
|
||||||
|
const auto handle = [=](float64 value) {
|
||||||
|
const auto intensity = std::clamp(
|
||||||
|
int(base::SafeRound(value * 100)),
|
||||||
|
0,
|
||||||
|
100);
|
||||||
|
_paper = _paper.withPatternIntensity(intensity);
|
||||||
|
_dimmingIntensity = intensity;
|
||||||
|
update();
|
||||||
|
};
|
||||||
|
_dimmingSlider->setChangeProgressCallback(handle);
|
||||||
|
_dimmingSlider->setChangeFinishedCallback(handle);
|
||||||
|
inner->resizeToWidth(st::boxWideWidth);
|
||||||
|
Ui::SendPendingMoveResizeEvents(inner);
|
||||||
|
inner->move(0, 0);
|
||||||
|
_dimmingContent->resize(inner->size());
|
||||||
|
|
||||||
|
_dimmingContent->paintRequest(
|
||||||
|
) | rpl::start_with_next([=](QRect clip) {
|
||||||
|
auto p = QPainter(_dimmingContent);
|
||||||
|
const auto palette = (dark ? _darkPalette : _lightPalette).get();
|
||||||
|
p.fillRect(clip, equals ? st::boxBg : palette->boxBg());
|
||||||
|
}, _dimmingContent->lifetime());
|
||||||
|
|
||||||
|
_dimmingToggleScheduled = true;
|
||||||
|
|
||||||
|
if (created) {
|
||||||
|
rpl::combine(
|
||||||
|
heightValue(),
|
||||||
|
_dimmingWrap->heightValue(),
|
||||||
|
rpl::mappers::_1 - rpl::mappers::_2
|
||||||
|
) | rpl::start_with_next([=](int top) {
|
||||||
|
_dimmingWrap->move(0, top);
|
||||||
|
}, _dimmingWrap->lifetime());
|
||||||
|
|
||||||
|
_dimmingWrap->toggle(!dark, anim::type::instant);
|
||||||
|
_dimmingHeight = _dimmingWrap->heightValue();
|
||||||
|
_dimmingHeight.changes() | rpl::start_with_next([=] {
|
||||||
|
update();
|
||||||
|
}, _dimmingWrap->lifetime());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BackgroundPreviewBox::paletteReady() {
|
||||||
|
if (_waitingForPalette) {
|
||||||
|
applyDarkMode(_boxDarkMode.current());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const style::Box &BackgroundPreviewBox::overridenStyle(bool dark) {
|
||||||
|
auto &st = dark ? _dark : _light;
|
||||||
|
if (!st) {
|
||||||
|
st = std::make_unique<OverridenStyle>(prepareOverridenStyle(dark));
|
||||||
|
}
|
||||||
|
return st->box;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto BackgroundPreviewBox::prepareOverridenStyle(bool dark)
|
||||||
|
-> OverridenStyle {
|
||||||
|
const auto p = (dark ? _darkPalette : _lightPalette).get();
|
||||||
|
Assert(p != nullptr);
|
||||||
|
|
||||||
|
const auto &toggle = dark
|
||||||
|
? st::backgroundSwitchToLight
|
||||||
|
: st::backgroundSwitchToDark;
|
||||||
|
auto result = OverridenStyle{
|
||||||
|
.box = st::defaultBox,
|
||||||
|
.toggle = toggle,
|
||||||
|
.slider = st::defaultContinuousSlider,
|
||||||
|
.subtitle = st::settingsSubsectionTitle,
|
||||||
|
};
|
||||||
|
result.box.button.textFg = p->lightButtonFg();
|
||||||
|
result.box.button.textFgOver = p->lightButtonFgOver();
|
||||||
|
result.box.button.numbersTextFg = p->lightButtonFg();
|
||||||
|
result.box.button.numbersTextFgOver = p->lightButtonFgOver();
|
||||||
|
result.box.button.textBg = p->lightButtonBg();
|
||||||
|
result.box.button.textBgOver = p->lightButtonBgOver();
|
||||||
|
result.box.button.ripple.color = p->lightButtonBgRipple();
|
||||||
|
result.box.title.textFg = p->boxTitleFg();
|
||||||
|
result.box.bg = p->boxBg();
|
||||||
|
result.box.titleAdditionalFg = p->boxTitleAdditionalFg();
|
||||||
|
|
||||||
|
result.toggle.ripple.color = p->windowBgOver();
|
||||||
|
result.toggle.icon = toggle.icon.withPalette(*p);
|
||||||
|
result.toggle.iconOver = toggle.iconOver.withPalette(*p);
|
||||||
|
|
||||||
|
result.slider.activeFg = p->mediaPlayerActiveFg();
|
||||||
|
result.slider.inactiveFg = p->mediaPlayerInactiveFg();
|
||||||
|
result.slider.activeFgOver = p->mediaPlayerActiveFg();
|
||||||
|
result.slider.inactiveFgOver = p->mediaPlayerInactiveFg();
|
||||||
|
result.slider.activeFgDisabled = p->mediaPlayerInactiveFg();
|
||||||
|
result.slider.inactiveFgDisabled = p->windowBg();
|
||||||
|
result.slider.receivedTillFg = p->mediaPlayerInactiveFg();
|
||||||
|
|
||||||
|
result.subtitle.textFg = p->windowActiveTextFg();
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackgroundPreviewBox::generateBackground() {
|
void BackgroundPreviewBox::generateBackground() {
|
||||||
|
@ -215,9 +424,12 @@ not_null<HistoryView::ElementDelegate*> BackgroundPreviewBox::delegate() {
|
||||||
return static_cast<HistoryView::ElementDelegate*>(this);
|
return static_cast<HistoryView::ElementDelegate*>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackgroundPreviewBox::prepare() {
|
void BackgroundPreviewBox::resetTitle() {
|
||||||
setTitle(tr::lng_background_header());
|
setTitle(tr::lng_background_header());
|
||||||
|
}
|
||||||
|
|
||||||
|
void BackgroundPreviewBox::rebuildButtons(bool dark) {
|
||||||
|
clearButtons();
|
||||||
addButton(_forPeer
|
addButton(_forPeer
|
||||||
? tr::lng_background_apply_button()
|
? tr::lng_background_apply_button()
|
||||||
: tr::lng_background_apply(), [=] { apply(); });
|
: tr::lng_background_apply(), [=] { apply(); });
|
||||||
|
@ -225,18 +437,28 @@ void BackgroundPreviewBox::prepare() {
|
||||||
if (!_forPeer && _paper.hasShareUrl()) {
|
if (!_forPeer && _paper.hasShareUrl()) {
|
||||||
addLeftButton(tr::lng_background_share(), [=] { share(); });
|
addLeftButton(tr::lng_background_share(), [=] { share(); });
|
||||||
}
|
}
|
||||||
updateServiceBg(_paper.backgroundColors());
|
const auto equals = (dark == Window::Theme::IsNightMode());
|
||||||
|
auto toggle = object_ptr<Ui::IconButton>(this, equals
|
||||||
|
? (dark ? st::backgroundSwitchToLight : st::backgroundSwitchToDark)
|
||||||
|
: dark ? _dark->toggle : _light->toggle);
|
||||||
|
toggle->setClickedCallback([=] {
|
||||||
|
_boxDarkMode = !_boxDarkMode.current();
|
||||||
|
});
|
||||||
|
addTopButton(std::move(toggle));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BackgroundPreviewBox::prepare() {
|
||||||
|
applyDarkMode(Window::Theme::IsNightMode());
|
||||||
|
|
||||||
_paper.loadDocument();
|
_paper.loadDocument();
|
||||||
const auto document = _paper.document();
|
if (const auto document = _paper.document()) {
|
||||||
if (document && document->loading()) {
|
if (document->loading()) {
|
||||||
_radial.start(_media->progress());
|
_radial.start(_media->progress());
|
||||||
}
|
}
|
||||||
if (!_paper.isPattern()
|
|
||||||
&& (_paper.localThumbnail()
|
|
||||||
|| (document && document->hasThumbnail()))) {
|
|
||||||
createBlurCheckbox();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateServiceBg(_paper.backgroundColors());
|
||||||
|
|
||||||
setScaledFromThumb();
|
setScaledFromThumb();
|
||||||
checkLoadedDocument();
|
checkLoadedDocument();
|
||||||
|
|
||||||
|
@ -249,31 +471,42 @@ void BackgroundPreviewBox::prepare() {
|
||||||
setDimensions(st::boxWideWidth, st::boxWideWidth);
|
setDimensions(st::boxWideWidth, st::boxWideWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackgroundPreviewBox::createBlurCheckbox() {
|
void BackgroundPreviewBox::recreateBlurCheckbox() {
|
||||||
|
const auto document = _paper.document();
|
||||||
|
if (_paper.isPattern()
|
||||||
|
|| (!_paper.localThumbnail()
|
||||||
|
&& (!document || !document->hasThumbnail()))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto blurred = _blur ? _blur->checked() : _paper.isBlurred();
|
||||||
_blur = Ui::MakeChatServiceCheckbox(
|
_blur = Ui::MakeChatServiceCheckbox(
|
||||||
this,
|
this,
|
||||||
tr::lng_background_blur(tr::now),
|
tr::lng_background_blur(tr::now),
|
||||||
st::backgroundCheckbox,
|
st::backgroundCheckbox,
|
||||||
st::backgroundCheck,
|
st::backgroundCheck,
|
||||||
_paper.isBlurred(),
|
blurred,
|
||||||
[=] { return _serviceBg.value_or(QColor(255, 255, 255, 0)); });
|
[=] { return _serviceBg.value_or(QColor(255, 255, 255, 0)); });
|
||||||
|
_blur->show();
|
||||||
|
|
||||||
rpl::combine(
|
rpl::combine(
|
||||||
sizeValue(),
|
sizeValue(),
|
||||||
_blur->sizeValue()
|
_blur->sizeValue(),
|
||||||
) | rpl::start_with_next([=](QSize outer, QSize inner) {
|
_dimmingHeight.value()
|
||||||
|
) | rpl::start_with_next([=](QSize outer, QSize inner, int dimming) {
|
||||||
|
const auto bottom = st::historyPaddingBottom;
|
||||||
_blur->move(
|
_blur->move(
|
||||||
(outer.width() - inner.width()) / 2,
|
(outer.width() - inner.width()) / 2,
|
||||||
outer.height() - st::historyPaddingBottom - inner.height());
|
outer.height() - dimming - bottom - inner.height());
|
||||||
}, _blur->lifetime());
|
}, _blur->lifetime());
|
||||||
|
|
||||||
_blur->checkedChanges(
|
_blur->checkedChanges(
|
||||||
) | rpl::start_with_next([=](bool checked) {
|
) | rpl::start_with_next([=](bool checked) {
|
||||||
checkBlurAnimationStart();
|
checkBlurAnimationStart();
|
||||||
update();
|
update();
|
||||||
}, lifetime());
|
}, _blur->lifetime());
|
||||||
|
|
||||||
_blur->setDisabled(true);
|
_blur->setDisabled(_paper.document() && _full.isNull());
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackgroundPreviewBox::apply() {
|
void BackgroundPreviewBox::apply() {
|
||||||
|
@ -418,6 +651,13 @@ void BackgroundPreviewBox::paintEvent(QPaintEvent *e) {
|
||||||
}
|
}
|
||||||
if (!_scaled.isNull()) {
|
if (!_scaled.isNull()) {
|
||||||
paintImage(p);
|
paintImage(p);
|
||||||
|
const auto dimming = (_dimmed && _boxDarkMode.current())
|
||||||
|
? _dimmingIntensity
|
||||||
|
: 0;
|
||||||
|
if (dimming > 0) {
|
||||||
|
const auto alpha = 255 * dimming / 100;
|
||||||
|
p.fillRect(e->rect(), QColor(0, 0, 0, alpha));
|
||||||
|
}
|
||||||
paintRadial(p);
|
paintRadial(p);
|
||||||
} else if (_generated.isNull()) {
|
} else if (_generated.isNull()) {
|
||||||
p.fillRect(e->rect(), st::boxBg);
|
p.fillRect(e->rect(), st::boxBg);
|
||||||
|
@ -427,6 +667,15 @@ void BackgroundPreviewBox::paintEvent(QPaintEvent *e) {
|
||||||
paintRadial(p);
|
paintRadial(p);
|
||||||
}
|
}
|
||||||
paintTexts(p, ms);
|
paintTexts(p, ms);
|
||||||
|
if (_dimmingToggleScheduled) {
|
||||||
|
crl::on_main(this, [=] {
|
||||||
|
if (!_dimmingToggleScheduled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_dimmingToggleScheduled = false;
|
||||||
|
_dimmingWrap->toggle(_boxDarkMode.current(), anim::type::normal);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackgroundPreviewBox::paintImage(Painter &p) {
|
void BackgroundPreviewBox::paintImage(Painter &p) {
|
||||||
|
@ -476,7 +725,9 @@ void BackgroundPreviewBox::paintRadial(Painter &p) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int BackgroundPreviewBox::textsTop() const {
|
int BackgroundPreviewBox::textsTop() const {
|
||||||
const auto bottom = _blur ? _blur->y() : height();
|
const auto bottom = _blur
|
||||||
|
? _blur->y()
|
||||||
|
: (height() - _dimmingHeight.current());
|
||||||
return bottom
|
return bottom
|
||||||
- st::historyPaddingBottom
|
- st::historyPaddingBottom
|
||||||
- (_service ? _service->height() : 0)
|
- (_service ? _service->height() : 0)
|
||||||
|
@ -569,8 +820,8 @@ void BackgroundPreviewBox::setScaledFromImage(
|
||||||
}
|
}
|
||||||
_scaled = Ui::PixmapFromImage(std::move(image));
|
_scaled = Ui::PixmapFromImage(std::move(image));
|
||||||
_blurred = Ui::PixmapFromImage(std::move(blurred));
|
_blurred = Ui::PixmapFromImage(std::move(blurred));
|
||||||
if (_blur && (!_paper.document() || !_full.isNull())) {
|
if (_blur) {
|
||||||
_blur->setDisabled(false);
|
_blur->setDisabled(_paper.document() && _full.isNull());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -595,22 +846,21 @@ void BackgroundPreviewBox::updateServiceBg(const std::vector<QColor> &bg) {
|
||||||
if (!count) {
|
if (!count) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto red = 0, green = 0, blue = 0;
|
auto red = 0LL, green = 0LL, blue = 0LL;
|
||||||
for (const auto &color : bg) {
|
for (const auto &color : bg) {
|
||||||
red += color.red();
|
red += color.red();
|
||||||
green += color.green();
|
green += color.green();
|
||||||
blue += color.blue();
|
blue += color.blue();
|
||||||
}
|
}
|
||||||
rpl::single(
|
|
||||||
rpl::empty
|
_serviceBgLifetime = _paletteServiceBg.value(
|
||||||
) | rpl::then(
|
) | rpl::start_with_next([=](QColor color) {
|
||||||
style::PaletteChanged()
|
|
||||||
) | rpl::start_with_next([=] {
|
|
||||||
_serviceBg = Ui::ThemeAdjustedColor(
|
_serviceBg = Ui::ThemeAdjustedColor(
|
||||||
st::msgServiceBg->c,
|
color,
|
||||||
QColor(red / count, green / count, blue / count));
|
QColor(red / count, green / count, blue / count));
|
||||||
_chatStyle->applyAdjustedServiceBg(*_serviceBg);
|
_chatStyle->applyAdjustedServiceBg(*_serviceBg);
|
||||||
}, lifetime());
|
recreateBlurCheckbox();
|
||||||
|
});
|
||||||
|
|
||||||
_service = GenerateServiceItem(
|
_service = GenerateServiceItem(
|
||||||
delegate(),
|
delegate(),
|
||||||
|
|
|
@ -26,6 +26,9 @@ class SessionController;
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class Checkbox;
|
class Checkbox;
|
||||||
class ChatStyle;
|
class ChatStyle;
|
||||||
|
class MediaSlider;
|
||||||
|
template <typename Widget>
|
||||||
|
class SlideWrap;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
struct BackgroundPreviewArgs {
|
struct BackgroundPreviewArgs {
|
||||||
|
@ -42,6 +45,7 @@ public:
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
const Data::WallPaper &paper,
|
const Data::WallPaper &paper,
|
||||||
BackgroundPreviewArgs args = {});
|
BackgroundPreviewArgs args = {});
|
||||||
|
~BackgroundPreviewBox();
|
||||||
|
|
||||||
static bool Start(
|
static bool Start(
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
|
@ -54,6 +58,8 @@ protected:
|
||||||
void paintEvent(QPaintEvent *e) override;
|
void paintEvent(QPaintEvent *e) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct OverridenStyle;
|
||||||
|
|
||||||
using Element = HistoryView::Element;
|
using Element = HistoryView::Element;
|
||||||
not_null<HistoryView::ElementDelegate*> delegate();
|
not_null<HistoryView::ElementDelegate*> delegate();
|
||||||
HistoryView::Context elementContext() override;
|
HistoryView::Context elementContext() override;
|
||||||
|
@ -75,11 +81,20 @@ private:
|
||||||
void paintImage(Painter &p);
|
void paintImage(Painter &p);
|
||||||
void paintRadial(Painter &p);
|
void paintRadial(Painter &p);
|
||||||
void paintTexts(Painter &p, crl::time ms);
|
void paintTexts(Painter &p, crl::time ms);
|
||||||
void createBlurCheckbox();
|
void recreateBlurCheckbox();
|
||||||
int textsTop() const;
|
int textsTop() const;
|
||||||
void startFadeInFrom(QPixmap previous);
|
void startFadeInFrom(QPixmap previous);
|
||||||
void checkBlurAnimationStart();
|
void checkBlurAnimationStart();
|
||||||
|
|
||||||
|
[[nodiscard]] const style::Box &overridenStyle(bool dark);
|
||||||
|
void paletteReady();
|
||||||
|
void applyDarkMode(bool dark);
|
||||||
|
[[nodiscard]] OverridenStyle prepareOverridenStyle(bool dark);
|
||||||
|
|
||||||
|
void resetTitle();
|
||||||
|
void rebuildButtons(bool dark);
|
||||||
|
void createDimmingSlider(bool dark);
|
||||||
|
|
||||||
const not_null<Window::SessionController*> _controller;
|
const not_null<Window::SessionController*> _controller;
|
||||||
PeerData * const _forPeer = nullptr;
|
PeerData * const _forPeer = nullptr;
|
||||||
FullMsgId _fromMessageId;
|
FullMsgId _fromMessageId;
|
||||||
|
@ -98,8 +113,25 @@ private:
|
||||||
std::optional<QColor> _serviceBg;
|
std::optional<QColor> _serviceBg;
|
||||||
object_ptr<Ui::Checkbox> _blur = { nullptr };
|
object_ptr<Ui::Checkbox> _blur = { nullptr };
|
||||||
|
|
||||||
|
rpl::variable<bool> _appNightMode;
|
||||||
|
rpl::variable<bool> _boxDarkMode;
|
||||||
|
std::unique_ptr<OverridenStyle> _light, _dark;
|
||||||
|
std::unique_ptr<style::palette> _lightPalette, _darkPalette;
|
||||||
|
bool _waitingForPalette = false;
|
||||||
|
|
||||||
|
object_ptr<Ui::SlideWrap<Ui::RpWidget>> _dimmingWrap = { nullptr };
|
||||||
|
Ui::RpWidget *_dimmingContent = nullptr;
|
||||||
|
Ui::MediaSlider *_dimmingSlider = nullptr;
|
||||||
|
int _dimmingIntensity = 0;
|
||||||
|
rpl::variable<int> _dimmingHeight = 0;
|
||||||
|
bool _dimmed = false;
|
||||||
|
bool _dimmingToggleScheduled = false;
|
||||||
|
|
||||||
FullMsgId _uploadId;
|
FullMsgId _uploadId;
|
||||||
float64 _uploadProgress = 0.;
|
float64 _uploadProgress = 0.;
|
||||||
rpl::lifetime _uploadLifetime;
|
rpl::lifetime _uploadLifetime;
|
||||||
|
|
||||||
|
rpl::variable<QColor> _paletteServiceBg;
|
||||||
|
rpl::lifetime _serviceBgLifetime;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -56,7 +56,9 @@ ThemeDocument::ThemeDocument(
|
||||||
_patternOpacity = params->patternOpacity();
|
_patternOpacity = params->patternOpacity();
|
||||||
_gradientRotation = params->gradientRotation();
|
_gradientRotation = params->gradientRotation();
|
||||||
_blurredWallPaper = params->isBlurred();
|
_blurredWallPaper = params->isBlurred();
|
||||||
_dimmingIntensity = (params->isPattern() || !_serviceWidth)
|
_dimmingIntensity = (!params->document()
|
||||||
|
|| params->isPattern()
|
||||||
|
|| !_serviceWidth)
|
||||||
? 0
|
? 0
|
||||||
: std::max(params->patternIntensity(), 0);
|
: std::max(params->patternIntensity(), 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1308,3 +1308,18 @@ moreChatsBarClose: IconButton(defaultIconButton) {
|
||||||
color: windowBgOver;
|
color: windowBgOver;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
backgroundSwitchToDark: IconButton(defaultIconButton) {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
|
||||||
|
icon: boxTitleCloseIcon;
|
||||||
|
iconOver: boxTitleCloseIconOver;
|
||||||
|
|
||||||
|
rippleAreaPosition: point(4px, 4px);
|
||||||
|
rippleAreaSize: 40px;
|
||||||
|
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||||
|
color: windowBgOver;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
backgroundSwitchToLight: backgroundSwitchToDark;
|
||||||
|
|
|
@ -425,11 +425,12 @@ ChatStyle::ChatStyle(not_null<const style::palette*> isolated)
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatStyle::apply(not_null<ChatTheme*> theme) {
|
void ChatStyle::apply(not_null<ChatTheme*> theme) {
|
||||||
const auto themePalette = theme->palette();
|
applyCustomPalette(theme->palette());
|
||||||
assignPalette(themePalette
|
}
|
||||||
? themePalette
|
|
||||||
: style::main_palette::get().get());
|
void ChatStyle::applyCustomPalette(const style::palette *palette) {
|
||||||
if (themePalette) {
|
assignPalette(palette ? palette : style::main_palette::get().get());
|
||||||
|
if (palette) {
|
||||||
_defaultPaletteChangeLifetime.destroy();
|
_defaultPaletteChangeLifetime.destroy();
|
||||||
} else {
|
} else {
|
||||||
style::PaletteChanged(
|
style::PaletteChanged(
|
||||||
|
|
|
@ -165,6 +165,7 @@ public:
|
||||||
explicit ChatStyle(not_null<const style::palette*> isolated);
|
explicit ChatStyle(not_null<const style::palette*> isolated);
|
||||||
|
|
||||||
void apply(not_null<ChatTheme*> theme);
|
void apply(not_null<ChatTheme*> theme);
|
||||||
|
void applyCustomPalette(const style::palette *palette);
|
||||||
void applyAdjustedServiceBg(QColor serviceBg);
|
void applyAdjustedServiceBg(QColor serviceBg);
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<> paletteChanged() const {
|
[[nodiscard]] rpl::producer<> paletteChanged() const {
|
||||||
|
|
|
@ -18,6 +18,8 @@ namespace Theme {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr auto kMaxAccentColors = 3;
|
constexpr auto kMaxAccentColors = 3;
|
||||||
|
constexpr auto kDayBaseFile = ":/gui/day-custom-base.tdesktop-theme"_cs;
|
||||||
|
constexpr auto kNightBaseFile = ":/gui/night-custom-base.tdesktop-theme"_cs;
|
||||||
|
|
||||||
const auto kColorizeIgnoredKeys = base::flat_set<QLatin1String>{ {
|
const auto kColorizeIgnoredKeys = base::flat_set<QLatin1String>{ {
|
||||||
qstr("boxTextFgGood"),
|
qstr("boxTextFgGood"),
|
||||||
|
@ -311,6 +313,40 @@ std::vector<QColor> DefaultAccentColors(EmbeddedType type) {
|
||||||
Unexpected("Type in Window::Theme::AccentColors.");
|
Unexpected("Type in Window::Theme::AccentColors.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Fn<void(style::palette&)> PreparePaletteCallback(
|
||||||
|
bool dark,
|
||||||
|
std::optional<QColor> accent) {
|
||||||
|
return [=](style::palette &palette) {
|
||||||
|
using namespace Theme;
|
||||||
|
const auto &embedded = EmbeddedThemes();
|
||||||
|
const auto i = ranges::find(
|
||||||
|
embedded,
|
||||||
|
dark ? EmbeddedType::Night : EmbeddedType::Default,
|
||||||
|
&EmbeddedScheme::type);
|
||||||
|
Assert(i != end(embedded));
|
||||||
|
const auto colorizer = accent
|
||||||
|
? ColorizerFrom(*i, *accent)
|
||||||
|
: style::colorizer();
|
||||||
|
|
||||||
|
auto instance = Instance();
|
||||||
|
const auto loaded = LoadFromFile(
|
||||||
|
(dark ? kNightBaseFile : kDayBaseFile).utf16(),
|
||||||
|
&instance,
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
colorizer);
|
||||||
|
Assert(loaded);
|
||||||
|
palette.finalize();
|
||||||
|
palette = instance.palette;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Fn<void(style::palette&)> PrepareCurrentPaletteCallback() {
|
||||||
|
return [=, data = style::main_palette::save()](style::palette &palette) {
|
||||||
|
palette.load(data);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
QByteArray AccentColors::serialize() const {
|
QByteArray AccentColors::serialize() const {
|
||||||
auto result = QByteArray();
|
auto result = QByteArray();
|
||||||
if (_data.empty()) {
|
if (_data.empty()) {
|
||||||
|
|
|
@ -63,5 +63,10 @@ void Colorize(
|
||||||
[[nodiscard]] std::vector<EmbeddedScheme> EmbeddedThemes();
|
[[nodiscard]] std::vector<EmbeddedScheme> EmbeddedThemes();
|
||||||
[[nodiscard]] std::vector<QColor> DefaultAccentColors(EmbeddedType type);
|
[[nodiscard]] std::vector<QColor> DefaultAccentColors(EmbeddedType type);
|
||||||
|
|
||||||
|
[[nodiscard]] Fn<void(style::palette&)> PreparePaletteCallback(
|
||||||
|
bool dark,
|
||||||
|
std::optional<QColor> accent);
|
||||||
|
[[nodiscard]] Fn<void(style::palette&)> PrepareCurrentPaletteCallback();
|
||||||
|
|
||||||
} // namespace Theme
|
} // namespace Theme
|
||||||
} // namespace Window
|
} // namespace Window
|
|
@ -94,47 +94,10 @@ namespace {
|
||||||
|
|
||||||
constexpr auto kCustomThemesInMemory = 5;
|
constexpr auto kCustomThemesInMemory = 5;
|
||||||
constexpr auto kMaxChatEntryHistorySize = 50;
|
constexpr auto kMaxChatEntryHistorySize = 50;
|
||||||
constexpr auto kDayBaseFile = ":/gui/day-custom-base.tdesktop-theme"_cs;
|
|
||||||
constexpr auto kNightBaseFile = ":/gui/night-custom-base.tdesktop-theme"_cs;
|
|
||||||
|
|
||||||
[[nodiscard]] Fn<void(style::palette&)> PrepareCurrentCallback() {
|
|
||||||
const auto copy = std::make_shared<style::palette>();
|
|
||||||
return [=, data = style::main_palette::save()](style::palette &palette) {
|
|
||||||
palette.load(data);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] Fn<void(style::palette&)> PreparePaletteCallback(
|
|
||||||
bool dark,
|
|
||||||
std::optional<QColor> accent) {
|
|
||||||
return [=](style::palette &palette) {
|
|
||||||
using namespace Theme;
|
|
||||||
const auto &embedded = EmbeddedThemes();
|
|
||||||
const auto i = ranges::find(
|
|
||||||
embedded,
|
|
||||||
dark ? EmbeddedType::Night : EmbeddedType::Default,
|
|
||||||
&EmbeddedScheme::type);
|
|
||||||
Assert(i != end(embedded));
|
|
||||||
const auto colorizer = accent
|
|
||||||
? ColorizerFrom(*i, *accent)
|
|
||||||
: style::colorizer();
|
|
||||||
|
|
||||||
auto instance = Instance();
|
|
||||||
const auto loaded = LoadFromFile(
|
|
||||||
(dark ? kNightBaseFile : kDayBaseFile).utf16(),
|
|
||||||
&instance,
|
|
||||||
nullptr,
|
|
||||||
nullptr,
|
|
||||||
colorizer);
|
|
||||||
Assert(loaded);
|
|
||||||
palette.finalize();
|
|
||||||
palette = instance.palette;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] Ui::ChatThemeBubblesData PrepareBubblesData(
|
[[nodiscard]] Ui::ChatThemeBubblesData PrepareBubblesData(
|
||||||
const Data::CloudTheme &theme,
|
const Data::CloudTheme &theme,
|
||||||
Data::CloudThemeType type) {
|
Data::CloudThemeType type) {
|
||||||
const auto i = theme.settings.find(type);
|
const auto i = theme.settings.find(type);
|
||||||
return {
|
return {
|
||||||
.colors = (i != end(theme.settings)
|
.colors = (i != end(theme.settings)
|
||||||
|
@ -2264,8 +2227,8 @@ void SessionController::cacheChatTheme(
|
||||||
auto descriptor = Ui::ChatThemeDescriptor{
|
auto descriptor = Ui::ChatThemeDescriptor{
|
||||||
.key = key.theme,
|
.key = key.theme,
|
||||||
.preparePalette = (data.id
|
.preparePalette = (data.id
|
||||||
? PreparePaletteCallback(dark, i->second.accentColor)
|
? Theme::PreparePaletteCallback(dark, i->second.accentColor)
|
||||||
: PrepareCurrentCallback()),
|
: Theme::PrepareCurrentPaletteCallback()),
|
||||||
.backgroundData = backgroundData(theme),
|
.backgroundData = backgroundData(theme),
|
||||||
.bubblesData = PrepareBubblesData(data, type),
|
.bubblesData = PrepareBubblesData(data, type),
|
||||||
.basedOnDark = dark,
|
.basedOnDark = dark,
|
||||||
|
|
Loading…
Add table
Reference in a new issue