tdesktop/Telegram/SourceFiles/settings/settings_notifications.cpp

873 lines
28 KiB
C++

/*
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 "settings/settings_notifications.h"
#include "settings/settings_common.h"
#include "ui/effects/animations.h"
#include "ui/wrap/vertical_layout.h"
#include "ui/wrap/slide_wrap.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/discrete_sliders.h"
#include "lang/lang_keys.h"
#include "window/notifications_manager.h"
#include "window/window_session_controller.h"
#include "platform/platform_notifications_manager.h"
#include "base/platform/base_platform_info.h"
#include "mainwindow.h"
#include "core/application.h"
#include "main/main_session.h"
#include "main/main_account.h"
#include "main/main_domain.h"
#include "apiwrap.h"
#include "facades.h"
#include "app.h"
#include "styles/style_settings.h"
#include "styles/style_boxes.h"
#include "styles/style_window.h"
#include "styles/style_dialogs.h"
#include <QTimer>
namespace Settings {
namespace {
constexpr auto kMaxNotificationsCount = 5;
[[nodiscard]] int CurrentCount() {
return snap(
Core::App().settings().notificationsCount(),
1,
kMaxNotificationsCount);
}
using ChangeType = Window::Notifications::ChangeType;
class NotificationsCount : public Ui::RpWidget {
public:
NotificationsCount(
QWidget *parent,
not_null<Window::SessionController*> controller);
void setCount(int count);
~NotificationsCount();
protected:
void paintEvent(QPaintEvent *e) override;
void mousePressEvent(QMouseEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
void leaveEventHook(QEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
int resizeGetHeight(int newWidth) override;
private:
using ScreenCorner = Core::Settings::ScreenCorner;
void setOverCorner(ScreenCorner corner);
void clearOverCorner();
class SampleWidget;
void removeSample(SampleWidget *widget);
QRect getScreenRect() const;
QRect getScreenRect(int width) const;
int getContentLeft() const;
void prepareNotificationSampleSmall();
void prepareNotificationSampleLarge();
void prepareNotificationSampleUserpic();
const not_null<Window::SessionController*> _controller;
QPixmap _notificationSampleUserpic;
QPixmap _notificationSampleSmall;
QPixmap _notificationSampleLarge;
ScreenCorner _chosenCorner;
std::vector<Ui::Animations::Simple> _sampleOpacities;
bool _isOverCorner = false;
ScreenCorner _overCorner = ScreenCorner::TopLeft;
bool _isDownCorner = false;
ScreenCorner _downCorner = ScreenCorner::TopLeft;
int _oldCount;
QVector<SampleWidget*> _cornerSamples[4];
};
class NotificationsCount::SampleWidget : public QWidget {
public:
SampleWidget(NotificationsCount *owner, const QPixmap &cache);
void detach();
void showFast();
void hideFast();
protected:
void paintEvent(QPaintEvent *e) override;
private:
void startAnimation();
void animationCallback();
void destroyDelayed();
NotificationsCount *_owner;
QPixmap _cache;
Ui::Animations::Simple _opacity;
bool _hiding = false;
bool _deleted = false;
};
NotificationsCount::NotificationsCount(
QWidget *parent,
not_null<Window::SessionController*> controller)
: _controller(controller)
, _chosenCorner(Core::App().settings().notificationsCorner())
, _oldCount(CurrentCount()) {
setMouseTracking(true);
_sampleOpacities.resize(kMaxNotificationsCount);
prepareNotificationSampleSmall();
prepareNotificationSampleLarge();
}
void NotificationsCount::paintEvent(QPaintEvent *e) {
Painter p(this);
auto contentLeft = getContentLeft();
auto screenRect = getScreenRect();
p.fillRect(
screenRect.x(),
screenRect.y(),
st::notificationsBoxScreenSize.width(),
st::notificationsBoxScreenSize.height(),
st::notificationsBoxScreenBg);
auto monitorTop = 0;
st::notificationsBoxMonitor.paint(p, contentLeft, monitorTop, width());
for (int corner = 0; corner != 4; ++corner) {
auto screenCorner = static_cast<ScreenCorner>(corner);
auto isLeft = Core::Settings::IsLeftCorner(screenCorner);
auto isTop = Core::Settings::IsTopCorner(screenCorner);
auto sampleLeft = isLeft ? (screenRect.x() + st::notificationsSampleSkip) : (screenRect.x() + screenRect.width() - st::notificationsSampleSkip - st::notificationSampleSize.width());
auto sampleTop = isTop ? (screenRect.y() + st::notificationsSampleTopSkip) : (screenRect.y() + screenRect.height() - st::notificationsSampleBottomSkip - st::notificationSampleSize.height());
if (corner == static_cast<int>(_chosenCorner)) {
auto count = _oldCount;
for (int i = 0; i != kMaxNotificationsCount; ++i) {
auto opacity = _sampleOpacities[i].value((i < count) ? 1. : 0.);
p.setOpacity(opacity);
p.drawPixmapLeft(sampleLeft, sampleTop, width(), _notificationSampleSmall);
sampleTop += (isTop ? 1 : -1) * (st::notificationSampleSize.height() + st::notificationsSampleMargin);
}
p.setOpacity(1.);
} else {
p.setOpacity(st::notificationSampleOpacity);
p.drawPixmapLeft(sampleLeft, sampleTop, width(), _notificationSampleSmall);
p.setOpacity(1.);
}
}
}
void NotificationsCount::setCount(int count) {
auto moreSamples = (count > _oldCount);
auto from = moreSamples ? 0. : 1.;
auto to = moreSamples ? 1. : 0.;
auto indexDelta = moreSamples ? 1 : -1;
auto animatedDelta = moreSamples ? 0 : -1;
for (; _oldCount != count; _oldCount += indexDelta) {
_sampleOpacities[_oldCount + animatedDelta].start([this] { update(); }, from, to, st::notifyFastAnim);
}
if (count != Core::App().settings().notificationsCount()) {
Core::App().settings().setNotificationsCount(count);
Core::App().saveSettingsDelayed();
Core::App().notifications().settingsChanged().notify(
ChangeType::MaxCount);
}
}
int NotificationsCount::getContentLeft() const {
return (width() - st::notificationsBoxMonitor.width()) / 2;
}
QRect NotificationsCount::getScreenRect() const {
return getScreenRect(width());
}
QRect NotificationsCount::getScreenRect(int width) const {
auto screenLeft = (width - st::notificationsBoxScreenSize.width()) / 2;
auto screenTop = st::notificationsBoxScreenTop;
return QRect(screenLeft, screenTop, st::notificationsBoxScreenSize.width(), st::notificationsBoxScreenSize.height());
}
int NotificationsCount::resizeGetHeight(int newWidth) {
update();
return st::notificationsBoxMonitor.height();
}
void NotificationsCount::prepareNotificationSampleSmall() {
auto width = st::notificationSampleSize.width();
auto height = st::notificationSampleSize.height();
auto sampleImage = QImage(width * cIntRetinaFactor(), height * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
sampleImage.setDevicePixelRatio(cRetinaFactor());
sampleImage.fill(st::notificationBg->c);
{
Painter p(&sampleImage);
PainterHighQualityEnabler hq(p);
p.setPen(Qt::NoPen);
auto padding = height / 8;
auto userpicSize = height - 2 * padding;
p.setBrush(st::notificationSampleUserpicFg);
p.drawEllipse(style::rtlrect(padding, padding, userpicSize, userpicSize, width));
auto rowLeft = height;
auto rowHeight = padding;
auto nameTop = (height - 5 * padding) / 2;
auto nameWidth = height;
p.setBrush(st::notificationSampleNameFg);
p.drawRoundedRect(style::rtlrect(rowLeft, nameTop, nameWidth, rowHeight, width), rowHeight / 2, rowHeight / 2);
auto rowWidth = (width - rowLeft - 3 * padding);
auto rowTop = nameTop + rowHeight + padding;
p.setBrush(st::notificationSampleTextFg);
p.drawRoundedRect(style::rtlrect(rowLeft, rowTop, rowWidth, rowHeight, width), rowHeight / 2, rowHeight / 2);
rowTop += rowHeight + padding;
p.drawRoundedRect(style::rtlrect(rowLeft, rowTop, rowWidth, rowHeight, width), rowHeight / 2, rowHeight / 2);
auto closeLeft = width - 2 * padding;
p.fillRect(style::rtlrect(closeLeft, padding, padding, padding, width), st::notificationSampleCloseFg);
}
_notificationSampleSmall = App::pixmapFromImageInPlace(std::move(sampleImage));
_notificationSampleSmall.setDevicePixelRatio(cRetinaFactor());
}
void NotificationsCount::prepareNotificationSampleUserpic() {
if (_notificationSampleUserpic.isNull()) {
_notificationSampleUserpic = App::pixmapFromImageInPlace(
Core::App().logoNoMargin().scaled(
st::notifyPhotoSize * cIntRetinaFactor(),
st::notifyPhotoSize * cIntRetinaFactor(),
Qt::IgnoreAspectRatio,
Qt::SmoothTransformation));
_notificationSampleUserpic.setDevicePixelRatio(cRetinaFactor());
}
}
void NotificationsCount::prepareNotificationSampleLarge() {
int w = st::notifyWidth, h = st::notifyMinHeight;
auto sampleImage = QImage(
w * cIntRetinaFactor(),
h * cIntRetinaFactor(),
QImage::Format_ARGB32_Premultiplied);
sampleImage.setDevicePixelRatio(cRetinaFactor());
sampleImage.fill(st::notificationBg->c);
{
Painter p(&sampleImage);
p.fillRect(0, 0, w - st::notifyBorderWidth, st::notifyBorderWidth, st::notifyBorder->b);
p.fillRect(w - st::notifyBorderWidth, 0, st::notifyBorderWidth, h - st::notifyBorderWidth, st::notifyBorder->b);
p.fillRect(st::notifyBorderWidth, h - st::notifyBorderWidth, w - st::notifyBorderWidth, st::notifyBorderWidth, st::notifyBorder->b);
p.fillRect(0, st::notifyBorderWidth, st::notifyBorderWidth, h - st::notifyBorderWidth, st::notifyBorder->b);
prepareNotificationSampleUserpic();
p.drawPixmap(st::notifyPhotoPos.x(), st::notifyPhotoPos.y(), _notificationSampleUserpic);
int itemWidth = w - st::notifyPhotoPos.x() - st::notifyPhotoSize - st::notifyTextLeft - st::notifyClosePos.x() - st::notifyClose.width;
auto rectForName = style::rtlrect(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyTextTop, itemWidth, st::msgNameFont->height, w);
auto notifyText = st::dialogsTextFont->elided(tr::lng_notification_sample(tr::now), itemWidth);
p.setFont(st::dialogsTextFont);
p.setPen(st::dialogsTextFgService);
p.drawText(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyItemTop + st::msgNameFont->height + st::dialogsTextFont->ascent, notifyText);
p.setPen(st::dialogsNameFg);
p.setFont(st::msgNameFont);
auto notifyTitle = st::msgNameFont->elided(qsl("Telegram Desktop"), rectForName.width());
p.drawText(rectForName.left(), rectForName.top() + st::msgNameFont->ascent, notifyTitle);
st::notifyClose.icon.paint(p, w - st::notifyClosePos.x() - st::notifyClose.width + st::notifyClose.iconPosition.x(), st::notifyClosePos.y() + st::notifyClose.iconPosition.y(), w);
}
_notificationSampleLarge = App::pixmapFromImageInPlace(std::move(sampleImage));
}
void NotificationsCount::removeSample(SampleWidget *widget) {
for (auto &samples : _cornerSamples) {
for (int i = 0, size = samples.size(); i != size; ++i) {
if (samples[i] == widget) {
for (int j = i + 1; j != size; ++j) {
samples[j]->detach();
}
samples.resize(i);
break;
}
}
}
}
void NotificationsCount::mouseMoveEvent(QMouseEvent *e) {
auto screenRect = getScreenRect();
auto cornerWidth = screenRect.width() / 3;
auto cornerHeight = screenRect.height() / 3;
auto topLeft = style::rtlrect(screenRect.x(), screenRect.y(), cornerWidth, cornerHeight, width());
auto topRight = style::rtlrect(screenRect.x() + screenRect.width() - cornerWidth, screenRect.y(), cornerWidth, cornerHeight, width());
auto bottomRight = style::rtlrect(screenRect.x() + screenRect.width() - cornerWidth, screenRect.y() + screenRect.height() - cornerHeight, cornerWidth, cornerHeight, width());
auto bottomLeft = style::rtlrect(screenRect.x(), screenRect.y() + screenRect.height() - cornerHeight, cornerWidth, cornerHeight, width());
if (topLeft.contains(e->pos())) {
setOverCorner(ScreenCorner::TopLeft);
} else if (topRight.contains(e->pos())) {
setOverCorner(ScreenCorner::TopRight);
} else if (bottomRight.contains(e->pos())) {
setOverCorner(ScreenCorner::BottomRight);
} else if (bottomLeft.contains(e->pos())) {
setOverCorner(ScreenCorner::BottomLeft);
} else {
clearOverCorner();
}
}
void NotificationsCount::leaveEventHook(QEvent *e) {
clearOverCorner();
}
void NotificationsCount::setOverCorner(ScreenCorner corner) {
if (_isOverCorner) {
if (corner == _overCorner) {
return;
}
for_const (auto widget, _cornerSamples[static_cast<int>(_overCorner)]) {
widget->hideFast();
}
} else {
_isOverCorner = true;
setCursor(style::cur_pointer);
Global::SetNotificationsDemoIsShown(true);
Core::App().notifications().settingsChanged().notify(
ChangeType::DemoIsShown);
}
_overCorner = corner;
auto &samples = _cornerSamples[static_cast<int>(_overCorner)];
auto samplesAlready = samples.size();
auto samplesNeeded = _oldCount;
auto samplesLeave = qMin(samplesAlready, samplesNeeded);
for (int i = 0; i != samplesLeave; ++i) {
samples[i]->showFast();
}
if (samplesNeeded > samplesLeave) {
auto r = psDesktopRect();
auto isLeft = Core::Settings::IsLeftCorner(_overCorner);
auto isTop = Core::Settings::IsTopCorner(_overCorner);
auto sampleLeft = (isLeft == rtl()) ? (r.x() + r.width() - st::notifyWidth - st::notifyDeltaX) : (r.x() + st::notifyDeltaX);
auto sampleTop = isTop ? (r.y() + st::notifyDeltaY) : (r.y() + r.height() - st::notifyDeltaY - st::notifyMinHeight);
for (int i = samplesLeave; i != samplesNeeded; ++i) {
auto widget = std::make_unique<SampleWidget>(this, _notificationSampleLarge);
widget->move(sampleLeft, sampleTop + (isTop ? 1 : -1) * i * (st::notifyMinHeight + st::notifyDeltaY));
widget->showFast();
samples.push_back(widget.release());
}
} else {
for (int i = samplesLeave; i != samplesAlready; ++i) {
samples[i]->hideFast();
}
}
}
void NotificationsCount::clearOverCorner() {
if (_isOverCorner) {
_isOverCorner = false;
setCursor(style::cur_default);
Global::SetNotificationsDemoIsShown(false);
Core::App().notifications().settingsChanged().notify(ChangeType::DemoIsShown);
for_const (const auto &samples, _cornerSamples) {
for_const (const auto widget, samples) {
widget->hideFast();
}
}
}
}
void NotificationsCount::mousePressEvent(QMouseEvent *e) {
_isDownCorner = _isOverCorner;
_downCorner = _overCorner;
}
void NotificationsCount::mouseReleaseEvent(QMouseEvent *e) {
auto isDownCorner = base::take(_isDownCorner);
if (isDownCorner
&& _isOverCorner
&& _downCorner == _overCorner
&& _downCorner != _chosenCorner) {
_chosenCorner = _downCorner;
update();
if (_chosenCorner != Core::App().settings().notificationsCorner()) {
Core::App().settings().setNotificationsCorner(_chosenCorner);
Core::App().saveSettingsDelayed();
Core::App().notifications().settingsChanged().notify(
ChangeType::Corner);
}
}
}
NotificationsCount::~NotificationsCount() {
for_const (auto &samples, _cornerSamples) {
for_const (auto widget, samples) {
widget->detach();
}
}
clearOverCorner();
}
NotificationsCount::SampleWidget::SampleWidget(
NotificationsCount *owner,
const QPixmap &cache)
: QWidget(Core::App().getModalParent())
, _owner(owner)
, _cache(cache) {
const QSize size(
cache.width() / cache.devicePixelRatio(),
cache.height() / cache.devicePixelRatio());
resize(size);
setMinimumSize(size);
setMaximumSize(size);
setWindowFlags(Qt::WindowFlags(Qt::FramelessWindowHint)
| Qt::WindowStaysOnTopHint
| Qt::BypassWindowManagerHint
| Qt::NoDropShadowWindowHint
| Qt::Tool);
setAttribute(Qt::WA_MacAlwaysShowToolWindow);
setAttribute(Qt::WA_TransparentForMouseEvents);
setAttribute(Qt::WA_OpaquePaintEvent);
setWindowOpacity(0.);
show();
}
void NotificationsCount::SampleWidget::detach() {
_owner = nullptr;
hideFast();
}
void NotificationsCount::SampleWidget::showFast() {
_hiding = false;
startAnimation();
}
void NotificationsCount::SampleWidget::hideFast() {
_hiding = true;
startAnimation();
}
void NotificationsCount::SampleWidget::paintEvent(QPaintEvent *e) {
Painter p(this);
p.drawPixmap(0, 0, _cache);
}
void NotificationsCount::SampleWidget::startAnimation() {
_opacity.start(
[=] { animationCallback(); },
_hiding ? 1. : 0.,
_hiding ? 0. : 1.,
st::notifyFastAnim);
}
void NotificationsCount::SampleWidget::animationCallback() {
setWindowOpacity(_opacity.value(_hiding ? 0. : 1.));
if (!_opacity.animating() && _hiding) {
if (_owner) {
_owner->removeSample(this);
}
hide();
destroyDelayed();
}
}
void NotificationsCount::SampleWidget::destroyDelayed() {
if (_deleted) return;
_deleted = true;
// Ubuntu has a lag if deleteLater() called immediately.
#if defined Q_OS_UNIX && !defined Q_OS_MAC
QTimer::singleShot(1000, [this] { delete this; });
#else // Q_OS_UNIX && !Q_OS_MAC
deleteLater();
#endif // Q_OS_UNIX && !Q_OS_MAC
}
void SetupAdvancedNotifications(
not_null<Window::SessionController*> controller,
not_null<Ui::VerticalLayout*> container) {
AddSkip(container, st::settingsCheckboxesSkip);
AddDivider(container);
AddSkip(container, st::settingsCheckboxesSkip);
AddSubsectionTitle(container, tr::lng_settings_notifications_position());
AddSkip(container, st::settingsCheckboxesSkip);
const auto position = container->add(
object_ptr<NotificationsCount>(container, controller));
AddSkip(container, st::settingsCheckboxesSkip);
AddSubsectionTitle(container, tr::lng_settings_notifications_count());
const auto count = container->add(
object_ptr<Ui::SettingsSlider>(container, st::settingsSlider),
st::settingsBigScalePadding);
for (int i = 0; i != kMaxNotificationsCount; ++i) {
count->addSection(QString::number(i + 1));
}
count->setActiveSectionFast(CurrentCount() - 1);
count->sectionActivated(
) | rpl::start_with_next([=](int section) {
position->setCount(section + 1);
}, count->lifetime());
AddSkip(container, st::settingsCheckboxesSkip);
}
void SetupMultiAccountNotifications(
not_null<Window::SessionController*> controller,
not_null<Ui::VerticalLayout*> container) {
if (Core::App().domain().accounts().size() < 2) {
return;
}
AddSubsectionTitle(container, tr::lng_settings_show_from());
const auto fromAll = container->add(
object_ptr<Ui::Checkbox>(
container,
tr::lng_settings_notify_all(tr::now),
Core::App().settings().notifyFromAll(),
st::settingsCheckbox),
st::settingsCheckboxPadding);
fromAll->checkedChanges(
) | rpl::filter([](bool checked) {
return (checked != Core::App().settings().notifyFromAll());
}) | rpl::start_with_next([=](bool checked) {
Core::App().settings().setNotifyFromAll(checked);
Core::App().saveSettingsDelayed();
if (!checked) {
auto &notifications = Core::App().notifications();
const auto &list = Core::App().domain().accounts();
for (const auto &[index, account] : list) {
if (account.get() == &Core::App().domain().active()) {
continue;
} else if (const auto session = account->maybeSession()) {
notifications.clearFromSession(session);
}
}
}
}, fromAll->lifetime());
AddSkip(container);
AddDividerText(container, tr::lng_settings_notify_all_about());
AddSkip(container);
}
void SetupNotificationsContent(
not_null<Window::SessionController*> controller,
not_null<Ui::VerticalLayout*> container) {
SetupMultiAccountNotifications(controller, container);
AddSubsectionTitle(container, tr::lng_settings_notify_title());
const auto session = &controller->session();
const auto checkbox = [&](const QString &label, bool checked) {
return object_ptr<Ui::Checkbox>(
container,
label,
checked,
st::settingsCheckbox);
};
const auto addCheckbox = [&](const QString &label, bool checked) {
return container->add(
checkbox(label, checked),
st::settingsCheckboxPadding);
};
const auto addSlidingCheckbox = [&](const QString &label, bool checked) {
return container->add(
object_ptr<Ui::SlideWrap<Ui::Checkbox>>(
container,
checkbox(label, checked),
st::settingsCheckboxPadding));
};
const auto &settings = Core::App().settings();
const auto desktop = addCheckbox(
tr::lng_settings_desktop_notify(tr::now),
settings.desktopNotify());
const auto name = addSlidingCheckbox(
tr::lng_settings_show_name(tr::now),
(settings.notifyView() <= dbinvShowName));
const auto preview = addSlidingCheckbox(
tr::lng_settings_show_preview(tr::now),
(settings.notifyView() <= dbinvShowPreview));
const auto sound = addCheckbox(
tr::lng_settings_sound_notify(tr::now),
settings.soundNotify());
const auto flashbounce = addCheckbox(
(Platform::IsWindows()
? tr::lng_settings_alert_windows
: Platform::IsMac()
? tr::lng_settings_alert_mac
: tr::lng_settings_alert_linux)(tr::now),
settings.flashBounceNotify());
AddSkip(container, st::settingsCheckboxesSkip);
AddDivider(container);
AddSkip(container, st::settingsCheckboxesSkip);
AddSubsectionTitle(container, tr::lng_settings_badge_title());
const auto muted = addCheckbox(
tr::lng_settings_include_muted(tr::now),
settings.includeMutedCounter());
const auto count = addCheckbox(
tr::lng_settings_count_unread(tr::now),
settings.countUnreadMessages());
AddSkip(container, st::settingsCheckboxesSkip);
AddDivider(container);
AddSkip(container, st::settingsCheckboxesSkip);
AddSubsectionTitle(container, tr::lng_settings_events_title());
const auto joined = addCheckbox(
tr::lng_settings_events_joined(tr::now),
!session->api().contactSignupSilentCurrent().value_or(false));
session->api().contactSignupSilent(
) | rpl::start_with_next([=](bool silent) {
joined->setChecked(!silent);
}, joined->lifetime());
joined->checkedChanges(
) | rpl::filter([=](bool enabled) {
const auto silent = session->api().contactSignupSilentCurrent();
return (enabled == silent.value_or(false));
}) | rpl::start_with_next([=](bool enabled) {
session->api().saveContactSignupSilent(!enabled);
}, joined->lifetime());
const auto pinned = addCheckbox(
tr::lng_settings_events_pinned(tr::now),
settings.notifyAboutPinned());
settings.notifyAboutPinnedChanges(
) | rpl::start_with_next([=](bool notify) {
pinned->setChecked(notify);
}, pinned->lifetime());
pinned->checkedChanges(
) | rpl::filter([=](bool notify) {
return (notify != Core::App().settings().notifyAboutPinned());
}) | rpl::start_with_next([=](bool notify) {
Core::App().settings().setNotifyAboutPinned(notify);
Core::App().saveSettingsDelayed();
}, joined->lifetime());
const auto nativeText = [&] {
if (!Platform::Notifications::Supported()) {
return QString();
} else if (Platform::IsWindows()) {
return tr::lng_settings_use_windows(tr::now);
} else if (Platform::IsLinux() && !Platform::IsWayland()) {
return tr::lng_settings_use_native_notifications(tr::now);
}
return QString();
}();
const auto native = [&]() -> Ui::Checkbox* {
if (nativeText.isEmpty()) {
return nullptr;
}
AddSkip(container, st::settingsCheckboxesSkip);
AddDivider(container);
AddSkip(container, st::settingsCheckboxesSkip);
AddSubsectionTitle(container, tr::lng_settings_native_title());
return addCheckbox(nativeText, settings.nativeNotifications());
}();
const auto advancedSlide = !Platform::IsMac10_8OrGreater()
&& !Platform::IsWayland()
? container->add(
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
container,
object_ptr<Ui::VerticalLayout>(container)))
: nullptr;
const auto advancedWrap = advancedSlide
? advancedSlide->entity()
: nullptr;
if (advancedWrap) {
SetupAdvancedNotifications(controller, advancedWrap);
}
if (!name->entity()->checked()) {
preview->hide(anim::type::instant);
}
if (!desktop->checked()) {
name->hide(anim::type::instant);
preview->hide(anim::type::instant);
}
if (native && advancedSlide && settings.nativeNotifications()) {
advancedSlide->hide(anim::type::instant);
}
using Change = Window::Notifications::ChangeType;
const auto changed = [=](Change change) {
Core::App().saveSettingsDelayed();
Core::App().notifications().settingsChanged().notify(change);
};
desktop->checkedChanges(
) | rpl::filter([](bool checked) {
return (checked != Core::App().settings().desktopNotify());
}) | rpl::start_with_next([=](bool checked) {
Core::App().settings().setDesktopNotify(checked);
changed(Change::DesktopEnabled);
}, desktop->lifetime());
name->entity()->checkedChanges(
) | rpl::map([=](bool checked) {
if (!checked) {
return dbinvShowNothing;
} else if (!preview->entity()->checked()) {
return dbinvShowName;
}
return dbinvShowPreview;
}) | rpl::filter([=](DBINotifyView value) {
return (value != Core::App().settings().notifyView());
}) | rpl::start_with_next([=](DBINotifyView value) {
Core::App().settings().setNotifyView(value);
changed(Change::ViewParams);
}, name->lifetime());
preview->entity()->checkedChanges(
) | rpl::map([=](bool checked) {
if (checked) {
return dbinvShowPreview;
} else if (name->entity()->checked()) {
return dbinvShowName;
}
return dbinvShowNothing;
}) | rpl::filter([=](DBINotifyView value) {
return (value != Core::App().settings().notifyView());
}) | rpl::start_with_next([=](DBINotifyView value) {
Core::App().settings().setNotifyView(value);
changed(Change::ViewParams);
}, preview->lifetime());
sound->checkedChanges(
) | rpl::filter([](bool checked) {
return (checked != Core::App().settings().soundNotify());
}) | rpl::start_with_next([=](bool checked) {
Core::App().settings().setSoundNotify(checked);
changed(Change::SoundEnabled);
}, sound->lifetime());
flashbounce->checkedChanges(
) | rpl::filter([](bool checked) {
return (checked != Core::App().settings().flashBounceNotify());
}) | rpl::start_with_next([=](bool checked) {
Core::App().settings().setFlashBounceNotify(checked);
changed(Change::FlashBounceEnabled);
}, flashbounce->lifetime());
muted->checkedChanges(
) | rpl::filter([=](bool checked) {
return (checked != Core::App().settings().includeMutedCounter());
}) | rpl::start_with_next([=](bool checked) {
Core::App().settings().setIncludeMutedCounter(checked);
changed(Change::IncludeMuted);
}, muted->lifetime());
count->checkedChanges(
) | rpl::filter([=](bool checked) {
return (checked != Core::App().settings().countUnreadMessages());
}) | rpl::start_with_next([=](bool checked) {
Core::App().settings().setCountUnreadMessages(checked);
changed(Change::CountMessages);
}, count->lifetime());
base::ObservableViewer(
Core::App().notifications().settingsChanged()
) | rpl::start_with_next([=](Change change) {
if (change == Change::DesktopEnabled) {
desktop->setChecked(Core::App().settings().desktopNotify());
name->toggle(
Core::App().settings().desktopNotify(),
anim::type::normal);
preview->toggle(
(Core::App().settings().desktopNotify()
&& name->entity()->checked()),
anim::type::normal);
} else if (change == Change::ViewParams) {
preview->toggle(name->entity()->checked(), anim::type::normal);
} else if (change == Change::SoundEnabled) {
sound->setChecked(Core::App().settings().soundNotify());
} else if (change == Change::FlashBounceEnabled) {
flashbounce->setChecked(Core::App().settings().flashBounceNotify());
}
}, desktop->lifetime());
if (native) {
native->checkedChanges(
) | rpl::filter([](bool checked) {
return (checked != Core::App().settings().nativeNotifications());
}) | rpl::start_with_next([=](bool checked) {
Core::App().settings().setNativeNotifications(checked);
Core::App().saveSettingsDelayed();
Core::App().notifications().createManager();
if (advancedSlide) {
advancedSlide->toggle(
!Core::App().settings().nativeNotifications(),
anim::type::normal);
}
}, native->lifetime());
}
}
void SetupNotifications(
not_null<Window::SessionController*> controller,
not_null<Ui::VerticalLayout*> container) {
AddSkip(container, st::settingsCheckboxesSkip);
auto wrap = object_ptr<Ui::VerticalLayout>(container);
SetupNotificationsContent(controller, wrap.data());
container->add(object_ptr<Ui::OverrideMargins>(
container,
std::move(wrap)));
AddSkip(container, st::settingsCheckboxesSkip);
}
} // namespace
Notifications::Notifications(
QWidget *parent,
not_null<Window::SessionController*> controller)
: Section(parent) {
setupContent(controller);
}
void Notifications::setupContent(
not_null<Window::SessionController*> controller) {
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
SetupNotifications(controller, content);
Ui::ResizeFitChild(this, content);
}
} // namespace Settings