mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2026-07-25 06:54:43 +00:00
Migrate all notification settings to builder.
This commit is contained in:
@@ -1571,6 +1571,8 @@ PRIVATE
|
|||||||
settings/builder/settings_builder.h
|
settings/builder/settings_builder.h
|
||||||
settings/builder/settings_main_builder.cpp
|
settings/builder/settings_main_builder.cpp
|
||||||
settings/builder/settings_main_builder.h
|
settings/builder/settings_main_builder.h
|
||||||
|
settings/builder/settings_notifications_builder.cpp
|
||||||
|
settings/builder/settings_notifications_builder.h
|
||||||
settings/settings_notifications.cpp
|
settings/settings_notifications.cpp
|
||||||
settings/settings_notifications.h
|
settings/settings_notifications.h
|
||||||
settings/settings_notifications_type.cpp
|
settings/settings_notifications_type.cpp
|
||||||
|
|||||||
@@ -250,6 +250,75 @@ Ui::SettingsButton *SectionBuilder::addPremiumButton(PremiumButtonArgs &&args) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ui::SettingsButton *SectionBuilder::addToggle(ToggleArgs &&args) {
|
||||||
|
return v::match(_context, [&](const WidgetContext &ctx)
|
||||||
|
-> Ui::SettingsButton* {
|
||||||
|
const auto &st = args.st ? *args.st : st::settingsButton;
|
||||||
|
const auto button = ctx.container->add(CreateButtonWithIcon(
|
||||||
|
ctx.container,
|
||||||
|
rpl::duplicate(args.title),
|
||||||
|
st,
|
||||||
|
std::move(args.icon)));
|
||||||
|
button->toggleOn(std::move(args.toggled));
|
||||||
|
return button;
|
||||||
|
}, [&](const SearchContext &ctx) -> Ui::SettingsButton* {
|
||||||
|
if (!args.id.isEmpty()) {
|
||||||
|
ctx.entries->push_back({
|
||||||
|
.id = std::move(args.id),
|
||||||
|
.title = ResolveTitle(std::move(args.title)),
|
||||||
|
.keywords = std::move(args.keywords),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ui::SlideWrap<Ui::SettingsButton> *SectionBuilder::addSlideToggle(
|
||||||
|
SlideToggleArgs &&args) {
|
||||||
|
return v::match(_context, [&](const WidgetContext &ctx)
|
||||||
|
-> Ui::SlideWrap<Ui::SettingsButton>* {
|
||||||
|
const auto &st = args.st ? *args.st : st::settingsButton;
|
||||||
|
const auto wrap = ctx.container->add(
|
||||||
|
object_ptr<Ui::SlideWrap<Ui::SettingsButton>>(
|
||||||
|
ctx.container,
|
||||||
|
CreateButtonWithIcon(
|
||||||
|
ctx.container,
|
||||||
|
rpl::duplicate(args.title),
|
||||||
|
st,
|
||||||
|
std::move(args.icon))));
|
||||||
|
if (args.shown) {
|
||||||
|
wrap->toggleOn(std::move(args.shown));
|
||||||
|
}
|
||||||
|
const auto button = wrap->entity();
|
||||||
|
button->toggleOn(std::move(args.toggled));
|
||||||
|
return wrap;
|
||||||
|
}, [&](const SearchContext &ctx) -> Ui::SlideWrap<Ui::SettingsButton>* {
|
||||||
|
if (!args.id.isEmpty()) {
|
||||||
|
ctx.entries->push_back({
|
||||||
|
.id = std::move(args.id),
|
||||||
|
.title = ResolveTitle(std::move(args.title)),
|
||||||
|
.keywords = std::move(args.keywords),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void SectionBuilder::addSubsectionTitle(rpl::producer<QString> text) {
|
||||||
|
v::match(_context, [&](const WidgetContext &ctx) {
|
||||||
|
AddSubsectionTitle(ctx.container, std::move(text));
|
||||||
|
}, [](const SearchContext &) {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ui::VerticalLayout *SectionBuilder::container() const {
|
||||||
|
return v::match(_context, [](const WidgetContext &ctx) {
|
||||||
|
return ctx.container.get();
|
||||||
|
}, [](const SearchContext &) -> Ui::VerticalLayout* {
|
||||||
|
return nullptr;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Window::SessionController *SectionBuilder::controller() const {
|
Window::SessionController *SectionBuilder::controller() const {
|
||||||
return v::match(_context, [](const WidgetContext &ctx) {
|
return v::match(_context, [](const WidgetContext &ctx) {
|
||||||
return ctx.controller.get();
|
return ctx.controller.get();
|
||||||
|
|||||||
@@ -121,11 +121,34 @@ public:
|
|||||||
};
|
};
|
||||||
Ui::SettingsButton *addPremiumButton(PremiumButtonArgs &&args);
|
Ui::SettingsButton *addPremiumButton(PremiumButtonArgs &&args);
|
||||||
|
|
||||||
|
struct ToggleArgs {
|
||||||
|
QString id;
|
||||||
|
rpl::producer<QString> title;
|
||||||
|
const style::SettingsButton *st = nullptr;
|
||||||
|
IconDescriptor icon;
|
||||||
|
rpl::producer<bool> toggled;
|
||||||
|
QStringList keywords;
|
||||||
|
};
|
||||||
|
Ui::SettingsButton *addToggle(ToggleArgs &&args);
|
||||||
|
|
||||||
|
struct SlideToggleArgs {
|
||||||
|
QString id;
|
||||||
|
rpl::producer<QString> title;
|
||||||
|
const style::SettingsButton *st = nullptr;
|
||||||
|
IconDescriptor icon;
|
||||||
|
rpl::producer<bool> toggled;
|
||||||
|
rpl::producer<bool> shown;
|
||||||
|
QStringList keywords;
|
||||||
|
};
|
||||||
|
Ui::SlideWrap<Ui::SettingsButton> *addSlideToggle(SlideToggleArgs &&args);
|
||||||
|
|
||||||
|
void addSubsectionTitle(rpl::producer<QString> text);
|
||||||
void addDivider();
|
void addDivider();
|
||||||
void addDividerText(rpl::producer<QString> text);
|
void addDividerText(rpl::producer<QString> text);
|
||||||
void addSkip();
|
void addSkip();
|
||||||
void addSkip(int height);
|
void addSkip(int height);
|
||||||
|
|
||||||
|
[[nodiscard]] Ui::VerticalLayout *container() const;
|
||||||
[[nodiscard]] Window::SessionController *controller() const;
|
[[nodiscard]] Window::SessionController *controller() const;
|
||||||
[[nodiscard]] Fn<void(Type)> showOther() const;
|
[[nodiscard]] Fn<void(Type)> showOther() const;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,770 @@
|
|||||||
|
/*
|
||||||
|
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/builder/settings_notifications_builder.h"
|
||||||
|
|
||||||
|
#include "api/api_authorizations.h"
|
||||||
|
#include "api/api_ringtones.h"
|
||||||
|
#include "apiwrap.h"
|
||||||
|
#include "base/platform/base_platform_info.h"
|
||||||
|
#include "boxes/ringtones_box.h"
|
||||||
|
#include "core/application.h"
|
||||||
|
#include "data/data_chat_filters.h"
|
||||||
|
#include "data/data_session.h"
|
||||||
|
#include "data/notify/data_notify_settings.h"
|
||||||
|
#include "data/notify/data_peer_notify_volume.h"
|
||||||
|
#include "lang/lang_keys.h"
|
||||||
|
#include "main/main_account.h"
|
||||||
|
#include "main/main_domain.h"
|
||||||
|
#include "main/main_session.h"
|
||||||
|
#include "mainwindow.h"
|
||||||
|
#include "platform/platform_notifications_manager.h"
|
||||||
|
#include "platform/platform_specific.h"
|
||||||
|
#include "settings/builder/settings_builder.h"
|
||||||
|
#include "settings/settings_notifications_common.h"
|
||||||
|
#include "settings/settings_notifications_type.h"
|
||||||
|
#include "ui/vertical_list.h"
|
||||||
|
#include "ui/widgets/buttons.h"
|
||||||
|
#include "ui/widgets/checkbox.h"
|
||||||
|
#include "ui/widgets/continuous_sliders.h"
|
||||||
|
#include "ui/widgets/discrete_sliders.h"
|
||||||
|
#include "ui/wrap/slide_wrap.h"
|
||||||
|
#include "ui/wrap/vertical_layout.h"
|
||||||
|
#include "window/notifications_manager.h"
|
||||||
|
#include "window/window_session_controller.h"
|
||||||
|
#include "styles/style_settings.h"
|
||||||
|
#include "styles/style_menu_icons.h"
|
||||||
|
|
||||||
|
#include <QtGui/QGuiApplication>
|
||||||
|
#include <QtGui/QScreen>
|
||||||
|
|
||||||
|
namespace Settings::Builder {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr auto kDefaultDisplayIndex = -1;
|
||||||
|
|
||||||
|
using NotifyView = Core::Settings::NotifyView;
|
||||||
|
using ChangeType = Window::Notifications::ChangeType;
|
||||||
|
|
||||||
|
void BuildMultiAccountSection(
|
||||||
|
SectionBuilder &builder,
|
||||||
|
Window::SessionController *controller) {
|
||||||
|
if (Core::App().domain().accounts().size() < 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.addSubsectionTitle(tr::lng_settings_show_from());
|
||||||
|
|
||||||
|
const auto container = builder.container();
|
||||||
|
if (!container) {
|
||||||
|
builder.addToggle({
|
||||||
|
.id = u"notifications/multi_account"_q,
|
||||||
|
.title = tr::lng_settings_notify_all(),
|
||||||
|
.toggled = rpl::single(Core::App().settings().notifyFromAll()),
|
||||||
|
.keywords = { u"all accounts"_q, u"multiple"_q },
|
||||||
|
});
|
||||||
|
builder.addSkip();
|
||||||
|
builder.addDividerText(tr::lng_settings_notify_all_about());
|
||||||
|
builder.addSkip();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto fromAll = builder.addToggle({
|
||||||
|
.id = u"notifications/multi_account"_q,
|
||||||
|
.title = tr::lng_settings_notify_all(),
|
||||||
|
.st = &st::settingsButtonNoIcon,
|
||||||
|
.toggled = rpl::single(Core::App().settings().notifyFromAll()),
|
||||||
|
.keywords = { u"all accounts"_q, u"multiple"_q },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (fromAll) {
|
||||||
|
fromAll->toggledChanges(
|
||||||
|
) | rpl::filter([](bool checked) {
|
||||||
|
return (checked != Core::App().settings().notifyFromAll());
|
||||||
|
}) | rpl::on_next([=](bool checked) {
|
||||||
|
Core::App().settings().setNotifyFromAll(checked);
|
||||||
|
Core::App().saveSettingsDelayed();
|
||||||
|
if (!checked) {
|
||||||
|
auto ¬ifications = 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());
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.addSkip();
|
||||||
|
builder.addDividerText(tr::lng_settings_notify_all_about());
|
||||||
|
builder.addSkip();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildGlobalNotificationsSection(
|
||||||
|
SectionBuilder &builder,
|
||||||
|
Window::SessionController *controller) {
|
||||||
|
builder.addSubsectionTitle(tr::lng_settings_notify_global());
|
||||||
|
|
||||||
|
const auto container = builder.container();
|
||||||
|
const auto &settings = Core::App().settings();
|
||||||
|
|
||||||
|
const auto desktopToggles = container
|
||||||
|
? container->lifetime().make_state<rpl::event_stream<bool>>()
|
||||||
|
: nullptr;
|
||||||
|
const auto desktop = builder.addToggle({
|
||||||
|
.id = u"notifications/desktop"_q,
|
||||||
|
.title = tr::lng_settings_desktop_notify(),
|
||||||
|
.icon = { &st::menuIconNotifications },
|
||||||
|
.toggled = desktopToggles
|
||||||
|
? desktopToggles->events_starting_with(settings.desktopNotify())
|
||||||
|
: rpl::single(settings.desktopNotify()),
|
||||||
|
.keywords = { u"desktop"_q, u"popup"_q, u"show"_q },
|
||||||
|
});
|
||||||
|
|
||||||
|
const auto flashbounceToggles = container
|
||||||
|
? container->lifetime().make_state<rpl::event_stream<bool>>()
|
||||||
|
: nullptr;
|
||||||
|
const auto flashbounce = builder.addToggle({
|
||||||
|
.id = u"notifications/flash"_q,
|
||||||
|
.title = (Platform::IsWindows()
|
||||||
|
? tr::lng_settings_alert_windows
|
||||||
|
: Platform::IsMac()
|
||||||
|
? tr::lng_settings_alert_mac
|
||||||
|
: tr::lng_settings_alert_linux)(),
|
||||||
|
.icon = { &st::menuIconDockBounce },
|
||||||
|
.toggled = flashbounceToggles
|
||||||
|
? flashbounceToggles->events_starting_with(settings.flashBounceNotify())
|
||||||
|
: rpl::single(settings.flashBounceNotify()),
|
||||||
|
.keywords = { u"flash"_q, u"bounce"_q, u"taskbar"_q },
|
||||||
|
});
|
||||||
|
|
||||||
|
const auto soundAllowed = container
|
||||||
|
? container->lifetime().make_state<rpl::event_stream<bool>>()
|
||||||
|
: nullptr;
|
||||||
|
const auto allowed = [=] {
|
||||||
|
return Core::App().settings().soundNotify();
|
||||||
|
};
|
||||||
|
const auto sound = builder.addToggle({
|
||||||
|
.id = u"notifications/sound"_q,
|
||||||
|
.title = tr::lng_settings_sound_allowed(),
|
||||||
|
.icon = { &st::menuIconUnmute },
|
||||||
|
.toggled = soundAllowed
|
||||||
|
? soundAllowed->events_starting_with(allowed())
|
||||||
|
: rpl::single(allowed()),
|
||||||
|
.keywords = { u"sound"_q, u"audio"_q, u"mute"_q },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (container && controller) {
|
||||||
|
const auto session = &controller->session();
|
||||||
|
Ui::AddRingtonesVolumeSlider(
|
||||||
|
container,
|
||||||
|
rpl::single(true),
|
||||||
|
tr::lng_settings_master_volume_notifications(),
|
||||||
|
Data::VolumeController{
|
||||||
|
.volume = []() -> ushort {
|
||||||
|
const auto volume
|
||||||
|
= Core::App().settings().notificationsVolume();
|
||||||
|
return volume ? volume : 100;
|
||||||
|
},
|
||||||
|
.saveVolume = [=](ushort volume) {
|
||||||
|
Core::App().notifications().playSound(
|
||||||
|
session,
|
||||||
|
0,
|
||||||
|
volume / 100.);
|
||||||
|
Core::App().settings().setNotificationsVolume(volume);
|
||||||
|
Core::App().saveSettingsDelayed();
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.addSkip();
|
||||||
|
|
||||||
|
if (desktop) {
|
||||||
|
const auto changed = [=](ChangeType change) {
|
||||||
|
Core::App().saveSettingsDelayed();
|
||||||
|
Core::App().notifications().notifySettingsChanged(change);
|
||||||
|
};
|
||||||
|
|
||||||
|
desktop->toggledChanges(
|
||||||
|
) | rpl::filter([](bool checked) {
|
||||||
|
return (checked != Core::App().settings().desktopNotify());
|
||||||
|
}) | rpl::on_next([=](bool checked) {
|
||||||
|
Core::App().settings().setDesktopNotify(checked);
|
||||||
|
changed(ChangeType::DesktopEnabled);
|
||||||
|
}, desktop->lifetime());
|
||||||
|
|
||||||
|
if (sound) {
|
||||||
|
sound->toggledChanges(
|
||||||
|
) | rpl::filter([](bool checked) {
|
||||||
|
return (checked != Core::App().settings().soundNotify());
|
||||||
|
}) | rpl::on_next([=](bool checked) {
|
||||||
|
Core::App().settings().setSoundNotify(checked);
|
||||||
|
changed(ChangeType::SoundEnabled);
|
||||||
|
}, sound->lifetime());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flashbounce) {
|
||||||
|
flashbounce->toggledChanges(
|
||||||
|
) | rpl::filter([](bool checked) {
|
||||||
|
return (checked != Core::App().settings().flashBounceNotify());
|
||||||
|
}) | rpl::on_next([=](bool checked) {
|
||||||
|
Core::App().settings().setFlashBounceNotify(checked);
|
||||||
|
changed(ChangeType::FlashBounceEnabled);
|
||||||
|
}, flashbounce->lifetime());
|
||||||
|
}
|
||||||
|
|
||||||
|
Core::App().notifications().settingsChanged(
|
||||||
|
) | rpl::on_next([=](ChangeType change) {
|
||||||
|
if (change == ChangeType::DesktopEnabled) {
|
||||||
|
desktopToggles->fire(Core::App().settings().desktopNotify());
|
||||||
|
} else if (change == ChangeType::SoundEnabled) {
|
||||||
|
soundAllowed->fire(allowed());
|
||||||
|
} else if (change == ChangeType::FlashBounceEnabled) {
|
||||||
|
flashbounceToggles->fire(
|
||||||
|
Core::App().settings().flashBounceNotify());
|
||||||
|
}
|
||||||
|
}, desktop->lifetime());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildNotifyViewSection(
|
||||||
|
SectionBuilder &builder,
|
||||||
|
Window::SessionController *controller,
|
||||||
|
rpl::lifetime &lifetime) {
|
||||||
|
const auto container = builder.container();
|
||||||
|
if (!container || !controller) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &settings = Core::App().settings();
|
||||||
|
const auto checkboxes = SetupNotifyViewOptions(
|
||||||
|
controller,
|
||||||
|
container,
|
||||||
|
(settings.notifyView() <= NotifyView::ShowName),
|
||||||
|
(settings.notifyView() <= NotifyView::ShowPreview));
|
||||||
|
const auto name = checkboxes.name;
|
||||||
|
const auto preview = checkboxes.preview;
|
||||||
|
const auto previewWrap = checkboxes.wrap;
|
||||||
|
|
||||||
|
const auto previewDivider = container->add(
|
||||||
|
object_ptr<Ui::SlideWrap<Ui::BoxContentDivider>>(
|
||||||
|
container,
|
||||||
|
object_ptr<Ui::BoxContentDivider>(container)));
|
||||||
|
previewWrap->toggle(settings.desktopNotify(), anim::type::instant);
|
||||||
|
previewDivider->toggle(!settings.desktopNotify(), anim::type::instant);
|
||||||
|
|
||||||
|
const auto changed = [=](ChangeType change) {
|
||||||
|
Core::App().saveSettingsDelayed();
|
||||||
|
Core::App().notifications().notifySettingsChanged(change);
|
||||||
|
};
|
||||||
|
|
||||||
|
name->checkedChanges(
|
||||||
|
) | rpl::map([=](bool checked) {
|
||||||
|
if (!checked) {
|
||||||
|
preview->setChecked(false);
|
||||||
|
return NotifyView::ShowNothing;
|
||||||
|
} else if (!preview->checked()) {
|
||||||
|
return NotifyView::ShowName;
|
||||||
|
}
|
||||||
|
return NotifyView::ShowPreview;
|
||||||
|
}) | rpl::filter([=](NotifyView value) {
|
||||||
|
return (value != Core::App().settings().notifyView());
|
||||||
|
}) | rpl::on_next([=](NotifyView value) {
|
||||||
|
Core::App().settings().setNotifyView(value);
|
||||||
|
changed(ChangeType::ViewParams);
|
||||||
|
}, name->lifetime());
|
||||||
|
|
||||||
|
preview->checkedChanges(
|
||||||
|
) | rpl::map([=](bool checked) {
|
||||||
|
if (checked) {
|
||||||
|
name->setChecked(true);
|
||||||
|
return NotifyView::ShowPreview;
|
||||||
|
} else if (name->checked()) {
|
||||||
|
return NotifyView::ShowName;
|
||||||
|
}
|
||||||
|
return NotifyView::ShowNothing;
|
||||||
|
}) | rpl::filter([=](NotifyView value) {
|
||||||
|
return (value != Core::App().settings().notifyView());
|
||||||
|
}) | rpl::on_next([=](NotifyView value) {
|
||||||
|
Core::App().settings().setNotifyView(value);
|
||||||
|
changed(ChangeType::ViewParams);
|
||||||
|
}, preview->lifetime());
|
||||||
|
|
||||||
|
Core::App().notifications().settingsChanged(
|
||||||
|
) | rpl::on_next([=](ChangeType change) {
|
||||||
|
if (change == ChangeType::DesktopEnabled) {
|
||||||
|
previewWrap->toggle(
|
||||||
|
Core::App().settings().desktopNotify(),
|
||||||
|
anim::type::normal);
|
||||||
|
previewDivider->toggle(
|
||||||
|
!Core::App().settings().desktopNotify(),
|
||||||
|
anim::type::normal);
|
||||||
|
}
|
||||||
|
}, lifetime);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildNotifyTypeSection(
|
||||||
|
SectionBuilder &builder,
|
||||||
|
Window::SessionController *controller) {
|
||||||
|
const auto container = builder.container();
|
||||||
|
const auto showOther = builder.showOther();
|
||||||
|
|
||||||
|
builder.addSkip(st::notifyPreviewBottomSkip);
|
||||||
|
builder.addSubsectionTitle(tr::lng_settings_notify_title());
|
||||||
|
|
||||||
|
if (container && controller && showOther) {
|
||||||
|
controller->session().data().notifySettings().loadExceptions();
|
||||||
|
AddTypeButton(container, controller, Data::DefaultNotify::User, showOther);
|
||||||
|
AddTypeButton(container, controller, Data::DefaultNotify::Group, showOther);
|
||||||
|
AddTypeButton(container, controller, Data::DefaultNotify::Broadcast, showOther);
|
||||||
|
} else {
|
||||||
|
builder.addSettingsButton({
|
||||||
|
.id = u"notifications/private"_q,
|
||||||
|
.title = tr::lng_notification_private_chats(),
|
||||||
|
.icon = { &st::menuIconProfile },
|
||||||
|
.keywords = { u"private"_q, u"chats"_q, u"direct"_q },
|
||||||
|
});
|
||||||
|
builder.addSettingsButton({
|
||||||
|
.id = u"notifications/groups"_q,
|
||||||
|
.title = tr::lng_notification_groups(),
|
||||||
|
.icon = { &st::menuIconGroups },
|
||||||
|
.keywords = { u"groups"_q, u"chats"_q },
|
||||||
|
});
|
||||||
|
builder.addSettingsButton({
|
||||||
|
.id = u"notifications/channels"_q,
|
||||||
|
.title = tr::lng_notification_channels(),
|
||||||
|
.icon = { &st::menuIconChannel },
|
||||||
|
.keywords = { u"channels"_q, u"broadcast"_q },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildEventNotificationsSection(
|
||||||
|
SectionBuilder &builder,
|
||||||
|
Window::SessionController *controller) {
|
||||||
|
builder.addSkip(st::settingsCheckboxesSkip);
|
||||||
|
builder.addDivider();
|
||||||
|
builder.addSkip(st::settingsCheckboxesSkip);
|
||||||
|
builder.addSubsectionTitle(tr::lng_settings_events_title());
|
||||||
|
|
||||||
|
if (!controller) {
|
||||||
|
builder.addToggle({
|
||||||
|
.id = u"notifications/events/joined"_q,
|
||||||
|
.title = tr::lng_settings_events_joined(),
|
||||||
|
.icon = { &st::menuIconInvite },
|
||||||
|
.toggled = rpl::single(false),
|
||||||
|
.keywords = { u"joined"_q, u"contacts"_q, u"signup"_q },
|
||||||
|
});
|
||||||
|
builder.addToggle({
|
||||||
|
.id = u"notifications/events/pinned"_q,
|
||||||
|
.title = tr::lng_settings_events_pinned(),
|
||||||
|
.icon = { &st::menuIconPin },
|
||||||
|
.toggled = rpl::single(Core::App().settings().notifyAboutPinned()),
|
||||||
|
.keywords = { u"pinned"_q, u"message"_q },
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto session = &controller->session();
|
||||||
|
const auto &settings = Core::App().settings();
|
||||||
|
|
||||||
|
auto joinSilent = rpl::single(
|
||||||
|
session->api().contactSignupSilentCurrent().value_or(false)
|
||||||
|
) | rpl::then(session->api().contactSignupSilent());
|
||||||
|
|
||||||
|
const auto joined = builder.addToggle({
|
||||||
|
.id = u"notifications/events/joined"_q,
|
||||||
|
.title = tr::lng_settings_events_joined(),
|
||||||
|
.icon = { &st::menuIconInvite },
|
||||||
|
.toggled = std::move(joinSilent) | rpl::map([](bool s) { return !s; }),
|
||||||
|
.keywords = { u"joined"_q, u"contacts"_q, u"signup"_q },
|
||||||
|
});
|
||||||
|
if (joined) {
|
||||||
|
joined->toggledChanges(
|
||||||
|
) | rpl::filter([=](bool enabled) {
|
||||||
|
const auto silent = session->api().contactSignupSilentCurrent();
|
||||||
|
return (enabled == silent.value_or(false));
|
||||||
|
}) | rpl::on_next([=](bool enabled) {
|
||||||
|
session->api().saveContactSignupSilent(!enabled);
|
||||||
|
}, joined->lifetime());
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto pinned = builder.addToggle({
|
||||||
|
.id = u"notifications/events/pinned"_q,
|
||||||
|
.title = tr::lng_settings_events_pinned(),
|
||||||
|
.icon = { &st::menuIconPin },
|
||||||
|
.toggled = rpl::single(
|
||||||
|
settings.notifyAboutPinned()
|
||||||
|
) | rpl::then(settings.notifyAboutPinnedChanges()),
|
||||||
|
.keywords = { u"pinned"_q, u"message"_q },
|
||||||
|
});
|
||||||
|
if (pinned) {
|
||||||
|
pinned->toggledChanges(
|
||||||
|
) | rpl::filter([=](bool notify) {
|
||||||
|
return (notify != Core::App().settings().notifyAboutPinned());
|
||||||
|
}) | rpl::on_next([=](bool notify) {
|
||||||
|
Core::App().settings().setNotifyAboutPinned(notify);
|
||||||
|
Core::App().saveSettingsDelayed();
|
||||||
|
}, pinned->lifetime());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildCallNotificationsSection(
|
||||||
|
SectionBuilder &builder,
|
||||||
|
Window::SessionController *controller) {
|
||||||
|
builder.addSkip(st::settingsCheckboxesSkip);
|
||||||
|
builder.addDivider();
|
||||||
|
builder.addSkip(st::settingsCheckboxesSkip);
|
||||||
|
builder.addSubsectionTitle(tr::lng_settings_notifications_calls_title());
|
||||||
|
|
||||||
|
if (!controller) {
|
||||||
|
builder.addToggle({
|
||||||
|
.id = u"notifications/calls/accept"_q,
|
||||||
|
.title = tr::lng_settings_call_accept_calls(),
|
||||||
|
.icon = { &st::menuIconCallsReceive },
|
||||||
|
.toggled = rpl::single(true),
|
||||||
|
.keywords = { u"calls"_q, u"receive"_q, u"incoming"_q },
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto session = &controller->session();
|
||||||
|
const auto authorizations = &session->api().authorizations();
|
||||||
|
authorizations->reload();
|
||||||
|
|
||||||
|
const auto acceptCalls = builder.addToggle({
|
||||||
|
.id = u"notifications/calls/accept"_q,
|
||||||
|
.title = tr::lng_settings_call_accept_calls(),
|
||||||
|
.icon = { &st::menuIconCallsReceive },
|
||||||
|
.toggled = authorizations->callsDisabledHereValue()
|
||||||
|
| rpl::map([](bool disabled) { return !disabled; }),
|
||||||
|
.keywords = { u"calls"_q, u"receive"_q, u"incoming"_q },
|
||||||
|
});
|
||||||
|
if (acceptCalls) {
|
||||||
|
const auto container = builder.container();
|
||||||
|
acceptCalls->toggledChanges(
|
||||||
|
) | rpl::filter([=](bool toggled) {
|
||||||
|
return (toggled == authorizations->callsDisabledHere());
|
||||||
|
}) | rpl::on_next([=](bool toggled) {
|
||||||
|
authorizations->toggleCallsDisabledHere(!toggled);
|
||||||
|
}, container->lifetime());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildBadgeCounterSection(
|
||||||
|
SectionBuilder &builder,
|
||||||
|
Window::SessionController *controller) {
|
||||||
|
builder.addSkip(st::settingsCheckboxesSkip);
|
||||||
|
builder.addDivider();
|
||||||
|
builder.addSkip(st::settingsCheckboxesSkip);
|
||||||
|
builder.addSubsectionTitle(tr::lng_settings_badge_title());
|
||||||
|
|
||||||
|
const auto &settings = Core::App().settings();
|
||||||
|
|
||||||
|
const auto muted = builder.addToggle({
|
||||||
|
.id = u"notifications/badge/muted"_q,
|
||||||
|
.title = tr::lng_settings_include_muted(),
|
||||||
|
.st = &st::settingsButtonNoIcon,
|
||||||
|
.toggled = rpl::single(settings.includeMutedCounter()),
|
||||||
|
.keywords = { u"muted"_q, u"badge"_q, u"counter"_q },
|
||||||
|
});
|
||||||
|
|
||||||
|
const auto hasFolders = controller
|
||||||
|
&& controller->session().data().chatsFilters().has();
|
||||||
|
const auto mutedFolders = hasFolders ? builder.addToggle({
|
||||||
|
.id = u"notifications/badge/muted_folders"_q,
|
||||||
|
.title = tr::lng_settings_include_muted_folders(),
|
||||||
|
.st = &st::settingsButtonNoIcon,
|
||||||
|
.toggled = rpl::single(settings.includeMutedCounterFolders()),
|
||||||
|
.keywords = { u"muted"_q, u"folders"_q },
|
||||||
|
}) : nullptr;
|
||||||
|
|
||||||
|
const auto count = builder.addToggle({
|
||||||
|
.id = u"notifications/badge/count"_q,
|
||||||
|
.title = tr::lng_settings_count_unread(),
|
||||||
|
.st = &st::settingsButtonNoIcon,
|
||||||
|
.toggled = rpl::single(settings.countUnreadMessages()),
|
||||||
|
.keywords = { u"unread"_q, u"messages"_q, u"count"_q },
|
||||||
|
});
|
||||||
|
|
||||||
|
const auto changed = [=](ChangeType change) {
|
||||||
|
Core::App().saveSettingsDelayed();
|
||||||
|
Core::App().notifications().notifySettingsChanged(change);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (muted) {
|
||||||
|
muted->toggledChanges(
|
||||||
|
) | rpl::filter([=](bool checked) {
|
||||||
|
return (checked != Core::App().settings().includeMutedCounter());
|
||||||
|
}) | rpl::on_next([=](bool checked) {
|
||||||
|
Core::App().settings().setIncludeMutedCounter(checked);
|
||||||
|
changed(ChangeType::IncludeMuted);
|
||||||
|
}, muted->lifetime());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mutedFolders) {
|
||||||
|
mutedFolders->toggledChanges(
|
||||||
|
) | rpl::filter([=](bool checked) {
|
||||||
|
return (checked
|
||||||
|
!= Core::App().settings().includeMutedCounterFolders());
|
||||||
|
}) | rpl::on_next([=](bool checked) {
|
||||||
|
Core::App().settings().setIncludeMutedCounterFolders(checked);
|
||||||
|
changed(ChangeType::IncludeMuted);
|
||||||
|
}, mutedFolders->lifetime());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count) {
|
||||||
|
count->toggledChanges(
|
||||||
|
) | rpl::filter([=](bool checked) {
|
||||||
|
return (checked != Core::App().settings().countUnreadMessages());
|
||||||
|
}) | rpl::on_next([=](bool checked) {
|
||||||
|
Core::App().settings().setCountUnreadMessages(checked);
|
||||||
|
changed(ChangeType::CountMessages);
|
||||||
|
}, count->lifetime());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildSystemIntegrationAndAdvancedSection(
|
||||||
|
SectionBuilder &builder,
|
||||||
|
Window::SessionController *controller) {
|
||||||
|
const auto container = builder.container();
|
||||||
|
|
||||||
|
auto nativeText = [&]() -> rpl::producer<QString> {
|
||||||
|
if (!Platform::Notifications::Supported()
|
||||||
|
|| Core::App().notifications().nativeEnforced()) {
|
||||||
|
return rpl::producer<QString>();
|
||||||
|
} else if (Platform::IsWindows()) {
|
||||||
|
return tr::lng_settings_use_windows();
|
||||||
|
}
|
||||||
|
return tr::lng_settings_use_native_notifications();
|
||||||
|
}();
|
||||||
|
|
||||||
|
if (nativeText) {
|
||||||
|
builder.addSkip(st::settingsCheckboxesSkip);
|
||||||
|
builder.addDivider();
|
||||||
|
builder.addSkip(st::settingsCheckboxesSkip);
|
||||||
|
builder.addSubsectionTitle(tr::lng_settings_native_title());
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &settings = Core::App().settings();
|
||||||
|
const auto native = nativeText ? builder.addToggle({
|
||||||
|
.id = u"notifications/native"_q,
|
||||||
|
.title = std::move(nativeText),
|
||||||
|
.st = &st::settingsButtonNoIcon,
|
||||||
|
.toggled = rpl::single(settings.nativeNotifications()),
|
||||||
|
.keywords = { u"native"_q, u"system"_q, u"windows"_q },
|
||||||
|
}) : nullptr;
|
||||||
|
|
||||||
|
if (Core::App().notifications().nativeEnforced()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!container || !controller) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto advancedSlide = container->add(
|
||||||
|
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
|
||||||
|
container,
|
||||||
|
object_ptr<Ui::VerticalLayout>(container)));
|
||||||
|
const auto advancedWrap = advancedSlide->entity();
|
||||||
|
|
||||||
|
if (native) {
|
||||||
|
native->toggledChanges(
|
||||||
|
) | rpl::filter([](bool checked) {
|
||||||
|
return (checked != Core::App().settings().nativeNotifications());
|
||||||
|
}) | rpl::on_next([=](bool checked) {
|
||||||
|
Core::App().settings().setNativeNotifications(checked);
|
||||||
|
Core::App().saveSettingsDelayed();
|
||||||
|
Core::App().notifications().createManager();
|
||||||
|
advancedSlide->toggle(!checked, anim::type::normal);
|
||||||
|
}, native->lifetime());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Platform::IsWindows()) {
|
||||||
|
const auto skipInFocus = advancedWrap->add(object_ptr<Ui::SettingsButton>(
|
||||||
|
advancedWrap,
|
||||||
|
tr::lng_settings_skip_in_focus(),
|
||||||
|
st::settingsButtonNoIcon
|
||||||
|
))->toggleOn(rpl::single(Core::App().settings().skipToastsInFocus()));
|
||||||
|
|
||||||
|
skipInFocus->toggledChanges(
|
||||||
|
) | rpl::filter([](bool checked) {
|
||||||
|
return (checked != Core::App().settings().skipToastsInFocus());
|
||||||
|
}) | rpl::on_next([=](bool checked) {
|
||||||
|
Core::App().settings().setSkipToastsInFocus(checked);
|
||||||
|
Core::App().saveSettingsDelayed();
|
||||||
|
if (checked && Platform::Notifications::SkipToastForCustom()) {
|
||||||
|
Core::App().notifications().notifySettingsChanged(
|
||||||
|
ChangeType::DesktopEnabled);
|
||||||
|
}
|
||||||
|
}, skipInFocus->lifetime());
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto screens = QGuiApplication::screens();
|
||||||
|
if (screens.size() > 1) {
|
||||||
|
Ui::AddSkip(advancedWrap, st::settingsCheckboxesSkip);
|
||||||
|
Ui::AddDivider(advancedWrap);
|
||||||
|
Ui::AddSkip(advancedWrap, st::settingsCheckboxesSkip);
|
||||||
|
Ui::AddSubsectionTitle(
|
||||||
|
advancedWrap,
|
||||||
|
tr::lng_settings_notifications_display());
|
||||||
|
|
||||||
|
const auto currentChecksum
|
||||||
|
= Core::App().settings().notificationsDisplayChecksum();
|
||||||
|
auto currentIndex = (currentChecksum == 0)
|
||||||
|
? kDefaultDisplayIndex
|
||||||
|
: 0;
|
||||||
|
for (auto i = 0; i < screens.size(); ++i) {
|
||||||
|
if (Platform::ScreenNameChecksum(screens[i]) == currentChecksum) {
|
||||||
|
currentIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto group = std::make_shared<Ui::RadiobuttonGroup>(
|
||||||
|
currentIndex);
|
||||||
|
|
||||||
|
advancedWrap->add(
|
||||||
|
object_ptr<Ui::Radiobutton>(
|
||||||
|
advancedWrap,
|
||||||
|
group,
|
||||||
|
kDefaultDisplayIndex,
|
||||||
|
tr::lng_settings_notifications_display_default(tr::now),
|
||||||
|
st::settingsSendType),
|
||||||
|
st::settingsSendTypePadding);
|
||||||
|
|
||||||
|
for (auto i = 0; i < screens.size(); ++i) {
|
||||||
|
const auto &screen = screens[i];
|
||||||
|
const auto name = Platform::ScreenDisplayLabel(screen);
|
||||||
|
const auto geometry = screen->geometry();
|
||||||
|
const auto resolution = QString::number(geometry.width())
|
||||||
|
+ QChar(0x00D7)
|
||||||
|
+ QString::number(geometry.height());
|
||||||
|
const auto label = name.isEmpty()
|
||||||
|
? QString("Display (%1)").arg(resolution)
|
||||||
|
: QString("%1 (%2)").arg(name).arg(resolution);
|
||||||
|
advancedWrap->add(
|
||||||
|
object_ptr<Ui::Radiobutton>(
|
||||||
|
advancedWrap,
|
||||||
|
group,
|
||||||
|
i,
|
||||||
|
label,
|
||||||
|
st::settingsSendType),
|
||||||
|
st::settingsSendTypePadding);
|
||||||
|
}
|
||||||
|
group->setChangedCallback([=](int selectedIndex) {
|
||||||
|
if (selectedIndex == kDefaultDisplayIndex) {
|
||||||
|
Core::App().settings().setNotificationsDisplayChecksum(0);
|
||||||
|
Core::App().saveSettings();
|
||||||
|
Core::App().notifications().notifySettingsChanged(
|
||||||
|
ChangeType::Corner);
|
||||||
|
} else {
|
||||||
|
const auto screens = QGuiApplication::screens();
|
||||||
|
if (selectedIndex >= 0 && selectedIndex < screens.size()) {
|
||||||
|
const auto checksum = Platform::ScreenNameChecksum(
|
||||||
|
screens[selectedIndex]);
|
||||||
|
Core::App().settings().setNotificationsDisplayChecksum(
|
||||||
|
checksum);
|
||||||
|
Core::App().saveSettings();
|
||||||
|
Core::App().notifications().notifySettingsChanged(
|
||||||
|
ChangeType::Corner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ui::AddSkip(advancedWrap, st::settingsCheckboxesSkip);
|
||||||
|
Ui::AddDivider(advancedWrap);
|
||||||
|
Ui::AddSkip(advancedWrap, st::settingsCheckboxesSkip);
|
||||||
|
Ui::AddSubsectionTitle(
|
||||||
|
advancedWrap,
|
||||||
|
tr::lng_settings_notifications_position());
|
||||||
|
Ui::AddSkip(advancedWrap, st::settingsCheckboxesSkip);
|
||||||
|
|
||||||
|
const auto position = advancedWrap->add(
|
||||||
|
object_ptr<NotificationsCount>(advancedWrap, controller));
|
||||||
|
|
||||||
|
Ui::AddSkip(advancedWrap, st::settingsCheckboxesSkip);
|
||||||
|
Ui::AddSubsectionTitle(advancedWrap, tr::lng_settings_notifications_count());
|
||||||
|
|
||||||
|
const auto countSlider = advancedWrap->add(
|
||||||
|
object_ptr<Ui::SettingsSlider>(advancedWrap, st::settingsSlider),
|
||||||
|
st::settingsBigScalePadding);
|
||||||
|
for (int i = 0; i != kMaxNotificationsCount; ++i) {
|
||||||
|
countSlider->addSection(QString::number(i + 1));
|
||||||
|
}
|
||||||
|
countSlider->setActiveSectionFast(CurrentNotificationsCount() - 1);
|
||||||
|
countSlider->sectionActivated(
|
||||||
|
) | rpl::on_next([=](int section) {
|
||||||
|
position->setCount(section + 1);
|
||||||
|
}, countSlider->lifetime());
|
||||||
|
Ui::AddSkip(advancedWrap, st::settingsCheckboxesSkip);
|
||||||
|
|
||||||
|
if (Core::App().settings().nativeNotifications()) {
|
||||||
|
advancedSlide->hide(anim::type::instant);
|
||||||
|
}
|
||||||
|
|
||||||
|
Core::App().notifications().settingsChanged(
|
||||||
|
) | rpl::on_next([=](ChangeType change) {
|
||||||
|
if (change == ChangeType::DesktopEnabled) {
|
||||||
|
const auto native = Core::App().settings().nativeNotifications();
|
||||||
|
advancedSlide->toggle(!native, anim::type::normal);
|
||||||
|
}
|
||||||
|
}, advancedSlide->lifetime());
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildNotificationsSectionContent(
|
||||||
|
SectionBuilder &builder,
|
||||||
|
Window::SessionController *controller) {
|
||||||
|
const auto container = builder.container();
|
||||||
|
|
||||||
|
builder.addSkip(st::settingsPrivacySkip);
|
||||||
|
|
||||||
|
BuildMultiAccountSection(builder, controller);
|
||||||
|
BuildGlobalNotificationsSection(builder, controller);
|
||||||
|
|
||||||
|
if (container && controller) {
|
||||||
|
BuildNotifyViewSection(builder, controller, container->lifetime());
|
||||||
|
}
|
||||||
|
|
||||||
|
BuildNotifyTypeSection(builder, controller);
|
||||||
|
BuildEventNotificationsSection(builder, controller);
|
||||||
|
BuildCallNotificationsSection(builder, controller);
|
||||||
|
BuildBadgeCounterSection(builder, controller);
|
||||||
|
BuildSystemIntegrationAndAdvancedSection(builder, controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void BuildNotificationsSection(
|
||||||
|
not_null<Ui::VerticalLayout*> container,
|
||||||
|
not_null<Window::SessionController*> controller,
|
||||||
|
Fn<void(Type)> showOther) {
|
||||||
|
const auto isPaused = Window::PausedIn(
|
||||||
|
controller,
|
||||||
|
Window::GifPauseReason::Layer);
|
||||||
|
auto builder = SectionBuilder(WidgetContext{
|
||||||
|
.container = container,
|
||||||
|
.controller = controller,
|
||||||
|
.showOther = std::move(showOther),
|
||||||
|
.isPaused = isPaused,
|
||||||
|
});
|
||||||
|
BuildNotificationsSectionContent(builder, controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<SearchEntry> BuildNotificationsSectionForSearch() {
|
||||||
|
auto entries = std::vector<SearchEntry>();
|
||||||
|
auto builder = SectionBuilder(SearchContext{
|
||||||
|
.entries = &entries,
|
||||||
|
});
|
||||||
|
BuildNotificationsSectionContent(builder, nullptr);
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Settings::Builder
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
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 "settings/builder/settings_builder.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class VerticalLayout;
|
||||||
|
} // namespace Ui
|
||||||
|
|
||||||
|
namespace Window {
|
||||||
|
class SessionController;
|
||||||
|
} // namespace Window
|
||||||
|
|
||||||
|
namespace Settings::Builder {
|
||||||
|
|
||||||
|
void BuildNotificationsSection(
|
||||||
|
not_null<Ui::VerticalLayout*> container,
|
||||||
|
not_null<Window::SessionController*> controller,
|
||||||
|
Fn<void(Type)> showOther);
|
||||||
|
|
||||||
|
[[nodiscard]] std::vector<SearchEntry> BuildNotificationsSectionForSearch();
|
||||||
|
|
||||||
|
} // namespace Settings::Builder
|
||||||
@@ -7,124 +7,50 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
*/
|
*/
|
||||||
#include "settings/settings_notifications.h"
|
#include "settings/settings_notifications.h"
|
||||||
|
|
||||||
#include "ui/widgets/continuous_sliders.h"
|
#include "settings/builder/settings_notifications_builder.h"
|
||||||
|
#include "settings/settings_notifications_common.h"
|
||||||
#include "settings/settings_notifications_type.h"
|
#include "settings/settings_notifications_type.h"
|
||||||
#include "ui/boxes/confirm_box.h"
|
#include "ui/boxes/confirm_box.h"
|
||||||
|
#include "ui/chat/chat_theme.h"
|
||||||
#include "ui/controls/chat_service_checkbox.h"
|
#include "ui/controls/chat_service_checkbox.h"
|
||||||
#include "ui/effects/animations.h"
|
#include "ui/effects/animations.h"
|
||||||
#include "data/notify/data_peer_notify_volume.h"
|
|
||||||
#include "ui/chat/chat_theme.h"
|
|
||||||
#include "ui/text/text_utilities.h"
|
|
||||||
#include "ui/wrap/vertical_layout.h"
|
|
||||||
#include "ui/wrap/slide_wrap.h"
|
|
||||||
#include "ui/widgets/box_content_divider.h"
|
|
||||||
#include "ui/widgets/checkbox.h"
|
|
||||||
#include "ui/widgets/buttons.h"
|
|
||||||
#include "ui/widgets/discrete_sliders.h"
|
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
#include "ui/vertical_list.h"
|
|
||||||
#include "ui/ui_utility.h"
|
#include "ui/ui_utility.h"
|
||||||
|
#include "ui/widgets/buttons.h"
|
||||||
|
#include "ui/widgets/checkbox.h"
|
||||||
|
#include "ui/wrap/slide_wrap.h"
|
||||||
|
#include "ui/wrap/vertical_layout.h"
|
||||||
|
#include "core/application.h"
|
||||||
|
#include "data/data_session.h"
|
||||||
|
#include "data/notify/data_notify_settings.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
|
#include "main/main_session.h"
|
||||||
|
#include "mainwindow.h"
|
||||||
#include "window/notifications_manager.h"
|
#include "window/notifications_manager.h"
|
||||||
#include "window/section_widget.h"
|
#include "window/section_widget.h"
|
||||||
#include "window/themes/window_theme.h"
|
#include "window/themes/window_theme.h"
|
||||||
#include "window/window_session_controller.h"
|
#include "window/window_session_controller.h"
|
||||||
#include "platform/platform_specific.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 "api/api_authorizations.h"
|
|
||||||
#include "api/api_ringtones.h"
|
|
||||||
#include "data/data_chat_filters.h"
|
|
||||||
#include "data/data_session.h"
|
|
||||||
#include "data/data_document.h"
|
|
||||||
#include "data/notify/data_notify_settings.h"
|
|
||||||
#include "boxes/ringtones_box.h"
|
|
||||||
#include "apiwrap.h"
|
|
||||||
#include "styles/style_settings.h"
|
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
|
#include "styles/style_chat.h"
|
||||||
|
#include "styles/style_dialogs.h"
|
||||||
#include "styles/style_layers.h"
|
#include "styles/style_layers.h"
|
||||||
#include "styles/style_menu_icons.h"
|
#include "styles/style_menu_icons.h"
|
||||||
#include "styles/style_chat.h"
|
#include "styles/style_settings.h"
|
||||||
#include "styles/style_window.h"
|
#include "styles/style_window.h"
|
||||||
#include "styles/style_dialogs.h"
|
|
||||||
|
|
||||||
#include <QSvgRenderer>
|
#include <QSvgRenderer>
|
||||||
#include <QtGui/QGuiApplication>
|
|
||||||
#include <QtGui/QScreen>
|
|
||||||
|
|
||||||
namespace Settings {
|
namespace Settings {
|
||||||
namespace {
|
|
||||||
|
|
||||||
constexpr auto kMaxNotificationsCount = 5;
|
using ChangeType = Window::Notifications::ChangeType;
|
||||||
constexpr auto kDefaultDisplayIndex = -1;
|
|
||||||
|
|
||||||
[[nodiscard]] int CurrentCount() {
|
int CurrentNotificationsCount() {
|
||||||
return std::clamp(
|
return std::clamp(
|
||||||
Core::App().settings().notificationsCount(),
|
Core::App().settings().notificationsCount(),
|
||||||
1,
|
1,
|
||||||
kMaxNotificationsCount);
|
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;
|
|
||||||
|
|
||||||
std::vector<SampleWidget*> _cornerSamples[4];
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class NotificationsCount::SampleWidget : public QWidget {
|
class NotificationsCount::SampleWidget : public QWidget {
|
||||||
public:
|
public:
|
||||||
SampleWidget(NotificationsCount *owner, const QPixmap &cache);
|
SampleWidget(NotificationsCount *owner, const QPixmap &cache);
|
||||||
@@ -306,7 +232,7 @@ NotificationsCount::NotificationsCount(
|
|||||||
not_null<Window::SessionController*> controller)
|
not_null<Window::SessionController*> controller)
|
||||||
: _controller(controller)
|
: _controller(controller)
|
||||||
, _chosenCorner(Core::App().settings().notificationsCorner())
|
, _chosenCorner(Core::App().settings().notificationsCorner())
|
||||||
, _oldCount(CurrentCount()) {
|
, _oldCount(CurrentNotificationsCount()) {
|
||||||
setMouseTracking(true);
|
setMouseTracking(true);
|
||||||
|
|
||||||
_sampleOpacities.resize(kMaxNotificationsCount);
|
_sampleOpacities.resize(kMaxNotificationsCount);
|
||||||
@@ -780,12 +706,6 @@ void NotifyPreview::paint(Painter &p, int x, int y) {
|
|||||||
2);
|
2);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct NotifyViewCheckboxes {
|
|
||||||
not_null<Ui::SlideWrap<>*> wrap;
|
|
||||||
not_null<Ui::Checkbox*> name;
|
|
||||||
not_null<Ui::Checkbox*> preview;
|
|
||||||
};
|
|
||||||
|
|
||||||
NotifyViewCheckboxes SetupNotifyViewOptions(
|
NotifyViewCheckboxes SetupNotifyViewOptions(
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
not_null<Ui::VerticalLayout*> container,
|
not_null<Ui::VerticalLayout*> container,
|
||||||
@@ -873,539 +793,6 @@ NotifyViewCheckboxes SetupNotifyViewOptions(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetupAdvancedNotifications(
|
|
||||||
not_null<Window::SessionController*> controller,
|
|
||||||
not_null<Ui::VerticalLayout*> container) {
|
|
||||||
if (Platform::IsWindows()) {
|
|
||||||
const auto skipInFocus = container->add(object_ptr<Button>(
|
|
||||||
container,
|
|
||||||
tr::lng_settings_skip_in_focus(),
|
|
||||||
st::settingsButtonNoIcon
|
|
||||||
))->toggleOn(rpl::single(Core::App().settings().skipToastsInFocus()));
|
|
||||||
|
|
||||||
skipInFocus->toggledChanges(
|
|
||||||
) | rpl::filter([](bool checked) {
|
|
||||||
return (checked != Core::App().settings().skipToastsInFocus());
|
|
||||||
}) | rpl::on_next([=](bool checked) {
|
|
||||||
Core::App().settings().setSkipToastsInFocus(checked);
|
|
||||||
Core::App().saveSettingsDelayed();
|
|
||||||
if (checked && Platform::Notifications::SkipToastForCustom()) {
|
|
||||||
using Change = Window::Notifications::ChangeType;
|
|
||||||
Core::App().notifications().notifySettingsChanged(
|
|
||||||
Change::DesktopEnabled);
|
|
||||||
}
|
|
||||||
}, skipInFocus->lifetime());
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto screens = QGuiApplication::screens();
|
|
||||||
if (screens.size() > 1) {
|
|
||||||
Ui::AddSkip(container, st::settingsCheckboxesSkip);
|
|
||||||
Ui::AddDivider(container);
|
|
||||||
Ui::AddSkip(container, st::settingsCheckboxesSkip);
|
|
||||||
Ui::AddSubsectionTitle(
|
|
||||||
container,
|
|
||||||
tr::lng_settings_notifications_display());
|
|
||||||
|
|
||||||
const auto currentChecksum
|
|
||||||
= Core::App().settings().notificationsDisplayChecksum();
|
|
||||||
auto currentIndex = (currentChecksum == 0)
|
|
||||||
? kDefaultDisplayIndex
|
|
||||||
: 0;
|
|
||||||
for (auto i = 0; i < screens.size(); ++i) {
|
|
||||||
if (Platform::ScreenNameChecksum(screens[i]) == currentChecksum) {
|
|
||||||
currentIndex = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto group = std::make_shared<Ui::RadiobuttonGroup>(
|
|
||||||
currentIndex);
|
|
||||||
|
|
||||||
container->add(
|
|
||||||
object_ptr<Ui::Radiobutton>(
|
|
||||||
container,
|
|
||||||
group,
|
|
||||||
kDefaultDisplayIndex,
|
|
||||||
tr::lng_settings_notifications_display_default(tr::now),
|
|
||||||
st::settingsSendType),
|
|
||||||
st::settingsSendTypePadding);
|
|
||||||
|
|
||||||
for (auto i = 0; i < screens.size(); ++i) {
|
|
||||||
const auto &screen = screens[i];
|
|
||||||
const auto name = Platform::ScreenDisplayLabel(screen);
|
|
||||||
const auto geometry = screen->geometry();
|
|
||||||
const auto resolution = QString::number(geometry.width())
|
|
||||||
+ QChar(0x00D7)
|
|
||||||
+ QString::number(geometry.height());
|
|
||||||
const auto label = name.isEmpty()
|
|
||||||
? QString("Display (%1)").arg(resolution)
|
|
||||||
: QString("%1 (%2)").arg(name).arg(resolution);
|
|
||||||
container->add(
|
|
||||||
object_ptr<Ui::Radiobutton>(
|
|
||||||
container,
|
|
||||||
group,
|
|
||||||
i,
|
|
||||||
label,
|
|
||||||
st::settingsSendType),
|
|
||||||
st::settingsSendTypePadding);
|
|
||||||
}
|
|
||||||
group->setChangedCallback([=](int selectedIndex) {
|
|
||||||
if (selectedIndex == kDefaultDisplayIndex) {
|
|
||||||
Core::App().settings().setNotificationsDisplayChecksum(0);
|
|
||||||
Core::App().saveSettings();
|
|
||||||
Core::App().notifications().notifySettingsChanged(
|
|
||||||
ChangeType::Corner);
|
|
||||||
} else {
|
|
||||||
const auto screens = QGuiApplication::screens();
|
|
||||||
if (selectedIndex >= 0 && selectedIndex < screens.size()) {
|
|
||||||
const auto checksum = Platform::ScreenNameChecksum(
|
|
||||||
screens[selectedIndex]);
|
|
||||||
Core::App().settings().setNotificationsDisplayChecksum(
|
|
||||||
checksum);
|
|
||||||
Core::App().saveSettings();
|
|
||||||
Core::App().notifications().notifySettingsChanged(
|
|
||||||
ChangeType::Corner);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Ui::AddSkip(container, st::settingsCheckboxesSkip);
|
|
||||||
Ui::AddDivider(container);
|
|
||||||
Ui::AddSkip(container, st::settingsCheckboxesSkip);
|
|
||||||
Ui::AddSubsectionTitle(
|
|
||||||
container,
|
|
||||||
tr::lng_settings_notifications_position());
|
|
||||||
Ui::AddSkip(container, st::settingsCheckboxesSkip);
|
|
||||||
|
|
||||||
const auto position = container->add(
|
|
||||||
object_ptr<NotificationsCount>(container, controller));
|
|
||||||
|
|
||||||
Ui::AddSkip(container, st::settingsCheckboxesSkip);
|
|
||||||
Ui::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::on_next([=](int section) {
|
|
||||||
position->setCount(section + 1);
|
|
||||||
}, count->lifetime());
|
|
||||||
Ui::AddSkip(container, st::settingsCheckboxesSkip);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetupMultiAccountNotifications(
|
|
||||||
not_null<Window::SessionController*> controller,
|
|
||||||
not_null<Ui::VerticalLayout*> container) {
|
|
||||||
if (Core::App().domain().accounts().size() < 2) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Ui::AddSubsectionTitle(container, tr::lng_settings_show_from());
|
|
||||||
|
|
||||||
const auto fromAll = container->add(object_ptr<Button>(
|
|
||||||
container,
|
|
||||||
tr::lng_settings_notify_all(),
|
|
||||||
st::settingsButtonNoIcon
|
|
||||||
))->toggleOn(rpl::single(Core::App().settings().notifyFromAll()));
|
|
||||||
fromAll->toggledChanges(
|
|
||||||
) | rpl::filter([](bool checked) {
|
|
||||||
return (checked != Core::App().settings().notifyFromAll());
|
|
||||||
}) | rpl::on_next([=](bool checked) {
|
|
||||||
Core::App().settings().setNotifyFromAll(checked);
|
|
||||||
Core::App().saveSettingsDelayed();
|
|
||||||
if (!checked) {
|
|
||||||
auto ¬ifications = 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());
|
|
||||||
|
|
||||||
Ui::AddSkip(container);
|
|
||||||
Ui::AddDividerText(container, tr::lng_settings_notify_all_about());
|
|
||||||
Ui::AddSkip(container);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetupNotificationsContent(
|
|
||||||
not_null<Window::SessionController*> controller,
|
|
||||||
not_null<Ui::VerticalLayout*> container,
|
|
||||||
Fn<void(Type)> showOther) {
|
|
||||||
using namespace rpl::mappers;
|
|
||||||
|
|
||||||
Ui::AddSkip(container, st::settingsPrivacySkip);
|
|
||||||
|
|
||||||
using NotifyView = Core::Settings::NotifyView;
|
|
||||||
SetupMultiAccountNotifications(controller, container);
|
|
||||||
|
|
||||||
AddSubsectionTitle(container, tr::lng_settings_notify_global());
|
|
||||||
|
|
||||||
const auto session = &controller->session();
|
|
||||||
const auto checkbox = [&](
|
|
||||||
rpl::producer<QString> label,
|
|
||||||
IconDescriptor &&descriptor,
|
|
||||||
rpl::producer<bool> checked) {
|
|
||||||
auto result = CreateButtonWithIcon(
|
|
||||||
container,
|
|
||||||
std::move(label),
|
|
||||||
st::settingsButton,
|
|
||||||
std::move(descriptor)
|
|
||||||
);
|
|
||||||
result->toggleOn(std::move(checked));
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
const auto addCheckbox = [&](
|
|
||||||
rpl::producer<QString> label,
|
|
||||||
IconDescriptor &&descriptor,
|
|
||||||
rpl::producer<bool> checked) {
|
|
||||||
return container->add(
|
|
||||||
checkbox(
|
|
||||||
std::move(label),
|
|
||||||
std::move(descriptor),
|
|
||||||
std::move(checked)));
|
|
||||||
};
|
|
||||||
const auto &settings = Core::App().settings();
|
|
||||||
const auto desktopToggles = container->lifetime(
|
|
||||||
).make_state<rpl::event_stream<bool>>();
|
|
||||||
const auto desktop = addCheckbox(
|
|
||||||
tr::lng_settings_desktop_notify(),
|
|
||||||
{ &st::menuIconNotifications },
|
|
||||||
desktopToggles->events_starting_with(settings.desktopNotify()));
|
|
||||||
|
|
||||||
const auto flashbounceToggles = container->lifetime(
|
|
||||||
).make_state<rpl::event_stream<bool>>();
|
|
||||||
const auto flashbounce = addCheckbox(
|
|
||||||
(Platform::IsWindows()
|
|
||||||
? tr::lng_settings_alert_windows
|
|
||||||
: Platform::IsMac()
|
|
||||||
? tr::lng_settings_alert_mac
|
|
||||||
: tr::lng_settings_alert_linux)(),
|
|
||||||
{ &st::menuIconDockBounce },
|
|
||||||
flashbounceToggles->events_starting_with(
|
|
||||||
settings.flashBounceNotify()));
|
|
||||||
|
|
||||||
const auto soundAllowed = container->lifetime(
|
|
||||||
).make_state<rpl::event_stream<bool>>();
|
|
||||||
const auto allowed = [=] {
|
|
||||||
return Core::App().settings().soundNotify();
|
|
||||||
};
|
|
||||||
const auto sound = addCheckbox(
|
|
||||||
tr::lng_settings_sound_allowed(),
|
|
||||||
{ &st::menuIconUnmute },
|
|
||||||
soundAllowed->events_starting_with(allowed()));
|
|
||||||
|
|
||||||
Ui::AddRingtonesVolumeSlider(
|
|
||||||
container,
|
|
||||||
rpl::single(true),
|
|
||||||
tr::lng_settings_master_volume_notifications(),
|
|
||||||
Data::VolumeController{
|
|
||||||
.volume = []() -> ushort {
|
|
||||||
const auto volume
|
|
||||||
= Core::App().settings().notificationsVolume();
|
|
||||||
return volume ? volume : 100;
|
|
||||||
},
|
|
||||||
.saveVolume = [=](ushort volume) {
|
|
||||||
Core::App().notifications().playSound(
|
|
||||||
session,
|
|
||||||
0,
|
|
||||||
volume / 100.);
|
|
||||||
Core::App().settings().setNotificationsVolume(volume);
|
|
||||||
Core::App().saveSettingsDelayed();
|
|
||||||
}});
|
|
||||||
|
|
||||||
Ui::AddSkip(container);
|
|
||||||
|
|
||||||
const auto checkboxes = SetupNotifyViewOptions(
|
|
||||||
controller,
|
|
||||||
container,
|
|
||||||
(settings.notifyView() <= NotifyView::ShowName),
|
|
||||||
(settings.notifyView() <= NotifyView::ShowPreview));
|
|
||||||
const auto name = checkboxes.name;
|
|
||||||
const auto preview = checkboxes.preview;
|
|
||||||
const auto previewWrap = checkboxes.wrap;
|
|
||||||
const auto previewDivider = container->add(
|
|
||||||
object_ptr<Ui::SlideWrap<Ui::BoxContentDivider>>(
|
|
||||||
container,
|
|
||||||
object_ptr<Ui::BoxContentDivider>(container)));
|
|
||||||
previewWrap->toggle(settings.desktopNotify(), anim::type::instant);
|
|
||||||
previewDivider->toggle(!settings.desktopNotify(), anim::type::instant);
|
|
||||||
|
|
||||||
controller->session().data().notifySettings().loadExceptions();
|
|
||||||
|
|
||||||
Ui::AddSkip(container, st::notifyPreviewBottomSkip);
|
|
||||||
Ui::AddSubsectionTitle(container, tr::lng_settings_notify_title());
|
|
||||||
const auto addType = [&](Data::DefaultNotify type) {
|
|
||||||
AddTypeButton(container, controller, type, showOther);
|
|
||||||
};
|
|
||||||
addType(Data::DefaultNotify::User);
|
|
||||||
addType(Data::DefaultNotify::Group);
|
|
||||||
addType(Data::DefaultNotify::Broadcast);
|
|
||||||
|
|
||||||
Ui::AddSkip(container, st::settingsCheckboxesSkip);
|
|
||||||
Ui::AddDivider(container);
|
|
||||||
Ui::AddSkip(container, st::settingsCheckboxesSkip);
|
|
||||||
Ui::AddSubsectionTitle(container, tr::lng_settings_events_title());
|
|
||||||
|
|
||||||
auto joinSilent = rpl::single(
|
|
||||||
session->api().contactSignupSilentCurrent().value_or(false)
|
|
||||||
) | rpl::then(session->api().contactSignupSilent());
|
|
||||||
const auto joined = addCheckbox(
|
|
||||||
tr::lng_settings_events_joined(),
|
|
||||||
{ &st::menuIconInvite },
|
|
||||||
std::move(joinSilent) | rpl::map(!_1));
|
|
||||||
joined->toggledChanges(
|
|
||||||
) | rpl::filter([=](bool enabled) {
|
|
||||||
const auto silent = session->api().contactSignupSilentCurrent();
|
|
||||||
return (enabled == silent.value_or(false));
|
|
||||||
}) | rpl::on_next([=](bool enabled) {
|
|
||||||
session->api().saveContactSignupSilent(!enabled);
|
|
||||||
}, joined->lifetime());
|
|
||||||
|
|
||||||
const auto pinned = addCheckbox(
|
|
||||||
tr::lng_settings_events_pinned(),
|
|
||||||
{ &st::menuIconPin },
|
|
||||||
rpl::single(
|
|
||||||
settings.notifyAboutPinned()
|
|
||||||
) | rpl::then(settings.notifyAboutPinnedChanges()));
|
|
||||||
pinned->toggledChanges(
|
|
||||||
) | rpl::filter([=](bool notify) {
|
|
||||||
return (notify != Core::App().settings().notifyAboutPinned());
|
|
||||||
}) | rpl::on_next([=](bool notify) {
|
|
||||||
Core::App().settings().setNotifyAboutPinned(notify);
|
|
||||||
Core::App().saveSettingsDelayed();
|
|
||||||
}, joined->lifetime());
|
|
||||||
|
|
||||||
Ui::AddSkip(container, st::settingsCheckboxesSkip);
|
|
||||||
Ui::AddDivider(container);
|
|
||||||
Ui::AddSkip(container, st::settingsCheckboxesSkip);
|
|
||||||
Ui::AddSubsectionTitle(
|
|
||||||
container,
|
|
||||||
tr::lng_settings_notifications_calls_title());
|
|
||||||
const auto authorizations = &session->api().authorizations();
|
|
||||||
// Request valid value of calls disabled flag.
|
|
||||||
authorizations->reload();
|
|
||||||
const auto acceptCalls = addCheckbox(
|
|
||||||
tr::lng_settings_call_accept_calls(),
|
|
||||||
{ &st::menuIconCallsReceive },
|
|
||||||
authorizations->callsDisabledHereValue() | rpl::map(!_1));
|
|
||||||
acceptCalls->toggledChanges(
|
|
||||||
) | rpl::filter([=](bool toggled) {
|
|
||||||
return (toggled == authorizations->callsDisabledHere());
|
|
||||||
}) | rpl::on_next([=](bool toggled) {
|
|
||||||
authorizations->toggleCallsDisabledHere(!toggled);
|
|
||||||
}, container->lifetime());
|
|
||||||
|
|
||||||
Ui::AddSkip(container, st::settingsCheckboxesSkip);
|
|
||||||
Ui::AddDivider(container);
|
|
||||||
Ui::AddSkip(container, st::settingsCheckboxesSkip);
|
|
||||||
Ui::AddSubsectionTitle(container, tr::lng_settings_badge_title());
|
|
||||||
|
|
||||||
const auto muted = container->add(object_ptr<Button>(
|
|
||||||
container,
|
|
||||||
tr::lng_settings_include_muted(),
|
|
||||||
st::settingsButtonNoIcon));
|
|
||||||
muted->toggleOn(rpl::single(settings.includeMutedCounter()));
|
|
||||||
const auto mutedFolders = session->data().chatsFilters().has()
|
|
||||||
? container->add(object_ptr<Button>(
|
|
||||||
container,
|
|
||||||
tr::lng_settings_include_muted_folders(),
|
|
||||||
st::settingsButtonNoIcon))
|
|
||||||
: nullptr;
|
|
||||||
if (mutedFolders) {
|
|
||||||
mutedFolders->toggleOn(
|
|
||||||
rpl::single(settings.includeMutedCounterFolders()));
|
|
||||||
}
|
|
||||||
const auto count = container->add(object_ptr<Button>(
|
|
||||||
container,
|
|
||||||
tr::lng_settings_count_unread(),
|
|
||||||
st::settingsButtonNoIcon));
|
|
||||||
count->toggleOn(rpl::single(settings.countUnreadMessages()));
|
|
||||||
|
|
||||||
auto nativeText = [&] {
|
|
||||||
if (!Platform::Notifications::Supported()
|
|
||||||
|| Core::App().notifications().nativeEnforced()) {
|
|
||||||
return rpl::producer<QString>();
|
|
||||||
} else if (Platform::IsWindows()) {
|
|
||||||
return tr::lng_settings_use_windows();
|
|
||||||
}
|
|
||||||
return tr::lng_settings_use_native_notifications();
|
|
||||||
}();
|
|
||||||
const auto native = [&]() -> Ui::SettingsButton* {
|
|
||||||
if (!nativeText) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ui::AddSkip(container, st::settingsCheckboxesSkip);
|
|
||||||
Ui::AddDivider(container);
|
|
||||||
Ui::AddSkip(container, st::settingsCheckboxesSkip);
|
|
||||||
Ui::AddSubsectionTitle(container, tr::lng_settings_native_title());
|
|
||||||
return container->add(object_ptr<Button>(
|
|
||||||
container,
|
|
||||||
std::move(nativeText),
|
|
||||||
st::settingsButtonNoIcon
|
|
||||||
))->toggleOn(rpl::single(settings.nativeNotifications()));
|
|
||||||
}();
|
|
||||||
|
|
||||||
const auto advancedSlide = !Core::App().notifications().nativeEnforced()
|
|
||||||
? 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 (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().notifySettingsChanged(change);
|
|
||||||
};
|
|
||||||
desktop->toggledChanges(
|
|
||||||
) | rpl::filter([](bool checked) {
|
|
||||||
return (checked != Core::App().settings().desktopNotify());
|
|
||||||
}) | rpl::on_next([=](bool checked) {
|
|
||||||
Core::App().settings().setDesktopNotify(checked);
|
|
||||||
changed(Change::DesktopEnabled);
|
|
||||||
}, desktop->lifetime());
|
|
||||||
|
|
||||||
sound->toggledChanges(
|
|
||||||
) | rpl::filter([](bool checked) {
|
|
||||||
return (checked != Core::App().settings().soundNotify());
|
|
||||||
}) | rpl::on_next([=](bool checked) {
|
|
||||||
Core::App().settings().setSoundNotify(checked);
|
|
||||||
changed(Change::SoundEnabled);
|
|
||||||
}, sound->lifetime());
|
|
||||||
|
|
||||||
name->checkedChanges(
|
|
||||||
) | rpl::map([=](bool checked) {
|
|
||||||
if (!checked) {
|
|
||||||
preview->setChecked(false);
|
|
||||||
return NotifyView::ShowNothing;
|
|
||||||
} else if (!preview->checked()) {
|
|
||||||
return NotifyView::ShowName;
|
|
||||||
}
|
|
||||||
return NotifyView::ShowPreview;
|
|
||||||
}) | rpl::filter([=](NotifyView value) {
|
|
||||||
return (value != Core::App().settings().notifyView());
|
|
||||||
}) | rpl::on_next([=](NotifyView value) {
|
|
||||||
Core::App().settings().setNotifyView(value);
|
|
||||||
changed(Change::ViewParams);
|
|
||||||
}, name->lifetime());
|
|
||||||
|
|
||||||
preview->checkedChanges(
|
|
||||||
) | rpl::map([=](bool checked) {
|
|
||||||
if (checked) {
|
|
||||||
name->setChecked(true);
|
|
||||||
return NotifyView::ShowPreview;
|
|
||||||
} else if (name->checked()) {
|
|
||||||
return NotifyView::ShowName;
|
|
||||||
}
|
|
||||||
return NotifyView::ShowNothing;
|
|
||||||
}) | rpl::filter([=](NotifyView value) {
|
|
||||||
return (value != Core::App().settings().notifyView());
|
|
||||||
}) | rpl::on_next([=](NotifyView value) {
|
|
||||||
Core::App().settings().setNotifyView(value);
|
|
||||||
changed(Change::ViewParams);
|
|
||||||
}, preview->lifetime());
|
|
||||||
|
|
||||||
flashbounce->toggledChanges(
|
|
||||||
) | rpl::filter([](bool checked) {
|
|
||||||
return (checked != Core::App().settings().flashBounceNotify());
|
|
||||||
}) | rpl::on_next([=](bool checked) {
|
|
||||||
Core::App().settings().setFlashBounceNotify(checked);
|
|
||||||
changed(Change::FlashBounceEnabled);
|
|
||||||
}, flashbounce->lifetime());
|
|
||||||
|
|
||||||
muted->toggledChanges(
|
|
||||||
) | rpl::filter([=](bool checked) {
|
|
||||||
return (checked != Core::App().settings().includeMutedCounter());
|
|
||||||
}) | rpl::on_next([=](bool checked) {
|
|
||||||
Core::App().settings().setIncludeMutedCounter(checked);
|
|
||||||
changed(Change::IncludeMuted);
|
|
||||||
}, muted->lifetime());
|
|
||||||
|
|
||||||
if (mutedFolders) {
|
|
||||||
mutedFolders->toggledChanges(
|
|
||||||
) | rpl::filter([=](bool checked) {
|
|
||||||
return (checked
|
|
||||||
!= Core::App().settings().includeMutedCounterFolders());
|
|
||||||
}) | rpl::on_next([=](bool checked) {
|
|
||||||
Core::App().settings().setIncludeMutedCounterFolders(checked);
|
|
||||||
changed(Change::IncludeMuted);
|
|
||||||
}, mutedFolders->lifetime());
|
|
||||||
}
|
|
||||||
|
|
||||||
count->toggledChanges(
|
|
||||||
) | rpl::filter([=](bool checked) {
|
|
||||||
return (checked != Core::App().settings().countUnreadMessages());
|
|
||||||
}) | rpl::on_next([=](bool checked) {
|
|
||||||
Core::App().settings().setCountUnreadMessages(checked);
|
|
||||||
changed(Change::CountMessages);
|
|
||||||
}, count->lifetime());
|
|
||||||
|
|
||||||
Core::App().notifications().settingsChanged(
|
|
||||||
) | rpl::on_next([=](Change change) {
|
|
||||||
if (change == Change::DesktopEnabled) {
|
|
||||||
desktopToggles->fire(Core::App().settings().desktopNotify());
|
|
||||||
previewWrap->toggle(
|
|
||||||
Core::App().settings().desktopNotify(),
|
|
||||||
anim::type::normal);
|
|
||||||
previewDivider->toggle(
|
|
||||||
!Core::App().settings().desktopNotify(),
|
|
||||||
anim::type::normal);
|
|
||||||
} else if (change == Change::ViewParams) {
|
|
||||||
//
|
|
||||||
} else if (change == Change::SoundEnabled) {
|
|
||||||
soundAllowed->fire(allowed());
|
|
||||||
} else if (change == Change::FlashBounceEnabled) {
|
|
||||||
flashbounceToggles->fire(
|
|
||||||
Core::App().settings().flashBounceNotify());
|
|
||||||
}
|
|
||||||
}, desktop->lifetime());
|
|
||||||
|
|
||||||
if (native) {
|
|
||||||
native->toggledChanges(
|
|
||||||
) | rpl::filter([](bool checked) {
|
|
||||||
return (checked != Core::App().settings().nativeNotifications());
|
|
||||||
}) | rpl::on_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,
|
|
||||||
Fn<void(Type)> showOther) {
|
|
||||||
SetupNotificationsContent(controller, container, std::move(showOther));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
Notifications::Notifications(
|
Notifications::Notifications(
|
||||||
QWidget *parent,
|
QWidget *parent,
|
||||||
not_null<Window::SessionController*> controller)
|
not_null<Window::SessionController*> controller)
|
||||||
@@ -1421,7 +808,10 @@ void Notifications::setupContent(
|
|||||||
not_null<Window::SessionController*> controller) {
|
not_null<Window::SessionController*> controller) {
|
||||||
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
|
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
|
||||||
|
|
||||||
SetupNotifications(controller, content, showOtherMethod());
|
Builder::BuildNotificationsSection(
|
||||||
|
content,
|
||||||
|
controller,
|
||||||
|
showOtherMethod());
|
||||||
|
|
||||||
Ui::ResizeFitChild(this, content);
|
Ui::ResizeFitChild(this, content);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
|
|
||||||
#include "settings/settings_common_session.h"
|
#include "settings/settings_common_session.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class VerticalLayout;
|
||||||
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Settings {
|
namespace Settings {
|
||||||
|
|
||||||
class Notifications : public Section<Notifications> {
|
class Notifications : public Section<Notifications> {
|
||||||
|
|||||||
@@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
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 <cstdint>
|
||||||
|
|
||||||
|
#include "base/object_ptr.h"
|
||||||
|
#include "core/core_settings.h"
|
||||||
|
#include "settings/settings_type.h"
|
||||||
|
#include "ui/effects/animations.h"
|
||||||
|
#include "ui/rp_widget.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class Checkbox;
|
||||||
|
class VerticalLayout;
|
||||||
|
template <typename Widget>
|
||||||
|
class SlideWrap;
|
||||||
|
} // namespace Ui
|
||||||
|
|
||||||
|
namespace Window {
|
||||||
|
class SessionController;
|
||||||
|
} // namespace Window
|
||||||
|
|
||||||
|
namespace Data {
|
||||||
|
enum class DefaultNotify : uint8_t;
|
||||||
|
} // namespace Data
|
||||||
|
|
||||||
|
namespace Settings {
|
||||||
|
|
||||||
|
constexpr auto kMaxNotificationsCount = 5;
|
||||||
|
|
||||||
|
[[nodiscard]] int CurrentNotificationsCount();
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
std::vector<SampleWidget*> _cornerSamples[4];
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NotifyViewCheckboxes {
|
||||||
|
not_null<Ui::SlideWrap<Ui::RpWidget>*> wrap;
|
||||||
|
not_null<Ui::Checkbox*> name;
|
||||||
|
not_null<Ui::Checkbox*> preview;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] NotifyViewCheckboxes SetupNotifyViewOptions(
|
||||||
|
not_null<Window::SessionController*> controller,
|
||||||
|
not_null<Ui::VerticalLayout*> container,
|
||||||
|
bool nameShown,
|
||||||
|
bool previewShown);
|
||||||
|
|
||||||
|
void AddTypeButton(
|
||||||
|
not_null<Ui::VerticalLayout*> container,
|
||||||
|
not_null<Window::SessionController*> controller,
|
||||||
|
Data::DefaultNotify type,
|
||||||
|
Fn<void(Type)> showOther);
|
||||||
|
|
||||||
|
} // namespace Settings
|
||||||
Reference in New Issue
Block a user