blob: 5137b1923502ecaaf582a8f37bae688a39aecbeb [file] [log] [blame]
Edric Milaret627500d2015-03-27 16:41:40 -04001/***************************************************************************
Anthony Léonard2fde81d2017-04-17 10:06:55 -04002 * Copyright (C) 2015-2017 by Savoir-faire Linux *
Edric Milaret627500d2015-03-27 16:41:40 -04003 * Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>*
Olivier SOLDANO47aa97f2017-04-04 10:40:00 -04004 * Author: Anthony Léonard <anthony.leonard@savoirfairelinux.com> *
5 * Author: Olivier Soldano <olivier.soldano@savoirfairelinux.com> *
Edric Milaret627500d2015-03-27 16:41:40 -04006 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 3 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
19 **************************************************************************/
20
21#include "configurationwidget.h"
22#include "ui_configurationwidget.h"
23
Edric Milaret1eece872015-06-10 13:37:51 -040024#include <QMessageBox>
Edric Milaretfd5a1f22016-02-05 15:30:00 -050025#include <QDir>
26#include <QStandardPaths>
27#include <QFileDialog>
Nicolas Jager74fe46f2016-02-29 14:55:09 -050028#include <QPropertyAnimation>
Edric Milaretce0ea472016-04-12 10:16:56 -040029#include <QtConcurrent/QtConcurrent>
Edric Milaret1eece872015-06-10 13:37:51 -040030
Edric Milaret627500d2015-03-27 16:41:40 -040031#include "video/devicemodel.h"
32#include "video/channel.h"
33#include "video/resolution.h"
34#include "video/rate.h"
Edric Milaret4bba46d2015-04-29 16:33:38 -040035#include "video/previewmanager.h"
Edric Milaret627500d2015-03-27 16:41:40 -040036
Edric Milaret47c40eb2016-03-14 15:06:22 -040037#include "audio/settings.h"
38#include "audio/outputdevicemodel.h"
39#include "audio/inputdevicemodel.h"
40
Edric Milaretfd5a1f22016-02-05 15:30:00 -050041#include "media/recordingmodel.h"
42
Edric Milaret3e6aefe2015-06-05 16:07:26 -040043#include "accountserializationadapter.h"
Edric Milaretb25af972015-06-17 16:55:45 -040044#include "accountstatedelegate.h"
45#include "settingskey.h"
Edric Milaret79d3f682015-12-09 12:32:52 -050046#include "utils.h"
Edric Milaretce0ea472016-04-12 10:16:56 -040047#include "pathpassworddialog.h"
Edric Milaret25236d92016-03-28 09:40:58 -040048#include "photoboothdialog.h"
Edric Milaret57467842016-08-30 13:06:11 -040049#include "wizarddialog.h"
Edric Milaret3e6aefe2015-06-05 16:07:26 -040050
Edric Milaret627500d2015-03-27 16:41:40 -040051#include "accountmodel.h"
52#include "protocolmodel.h"
53#include "accountdetails.h"
Edric Milaret3aeae3a2015-06-01 17:31:54 -040054#include "callmodel.h"
Edric Milaret1eece872015-06-10 13:37:51 -040055#include "ringtonemodel.h"
56#include "categorizedhistorymodel.h"
Edric Milaret25236d92016-03-28 09:40:58 -040057#include "profilemodel.h"
58#include "profile.h"
59#include "person.h"
Edric Milaret627500d2015-03-27 16:41:40 -040060
Edric Milaret79d3f682015-12-09 12:32:52 -050061#include "winsparkle.h"
Edric Milaret627500d2015-03-27 16:41:40 -040062
63ConfigurationWidget::ConfigurationWidget(QWidget *parent) :
Nicolas Jager74fe46f2016-02-29 14:55:09 -050064 NavWidget(parent),
Edric Milaret627500d2015-03-27 16:41:40 -040065 ui(new Ui::ConfigurationWidget),
Edric Milareta3e47282015-10-23 15:20:30 -040066 accountModel_(&AccountModel::instance()),
67 deviceModel_(&Video::DeviceModel::instance()),
Edric Milaret627500d2015-03-27 16:41:40 -040068 accountDetails_(new AccountDetails())
69{
70 ui->setupUi(this);
71
Nicolas Jager74fe46f2016-02-29 14:55:09 -050072 connect(ui->exitSettingsButton, &QPushButton::clicked, this, [=]() {
73 if (CallModel::instance().getActiveCalls().size() == 0
74 && Video::PreviewManager::instance().isPreviewing()) {
75 Video::PreviewManager::instance().stopPreview();
76 }
77 accountModel_->save();
78 accountDetails_->save();
79 });
80
81 connect(accountDetails_->getDeleteAccountButton(), &QPushButton::clicked, this, [=]() {
82 auto account = accountModel_->getAccountByModelIndex(
83 ui->accountView->currentIndex());
Edric Milaretce0ea472016-04-12 10:16:56 -040084 accountModel_->remove(account);
85 accountModel_->save();
Nicolas Jager74fe46f2016-02-29 14:55:09 -050086 });
87
88 connect(ui->exitSettingsButton, &QPushButton::clicked, this, [=]() {
89 emit NavigationRequested(ScreenEnum::CallScreen);
90 });
91
Edric Milaret627500d2015-03-27 16:41:40 -040092 ui->accountView->setModel(accountModel_);
Edric Milaret01f23842015-06-22 14:46:01 -040093 accountStateDelegate_ = new AccountStateDelegate();
94 ui->accountView->setItemDelegate(accountStateDelegate_);
Edric Milaret627500d2015-03-27 16:41:40 -040095
Edric Milaret627500d2015-03-27 16:41:40 -040096 isLoading_ = true;
97 ui->deviceBox->setModel(deviceModel_);
Edric Milaret94b4aab2015-05-08 12:10:44 -040098 connect(deviceModel_, SIGNAL(currentIndexChanged(int)),
99 this, SLOT(deviceIndexChanged(int)));
Edric Milaret627500d2015-03-27 16:41:40 -0400100
Edric Milaretf8048cf2016-05-13 10:21:08 -0400101 AccountModel::instance().selectionModel()->clear();
Edric Milaretce0ea472016-04-12 10:16:56 -0400102 ui->accountView->setSelectionModel(AccountModel::instance().selectionModel());
Edric Milaret627500d2015-03-27 16:41:40 -0400103 connect(ui->accountView->selectionModel(),
Edric Milaret3aeae3a2015-06-01 17:31:54 -0400104 SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
105 this, SLOT(accountSelected(QItemSelection)));
Edric Milaret627500d2015-03-27 16:41:40 -0400106
107 ui->accountView->setCurrentIndex(accountModel_->index(0));
108 ui->accountDetailLayout->addWidget(accountDetails_);
Edric Milaret627500d2015-03-27 16:41:40 -0400109 ui->accountTypeBox->setModel(accountModel_->protocolModel());
Olivier SOLDANOadc81f02016-11-07 15:22:34 -0500110 ui->accountTypeBox->setCurrentIndex(ui->accountTypeBox->findText("RING"));
Edric Milaret4bba46d2015-04-29 16:33:38 -0400111 ui->startupBox->setChecked(Utils::CheckStartupLink());
Edric Milaret1eece872015-06-10 13:37:51 -0400112
Edric Milaretb25af972015-06-17 16:55:45 -0400113 ui->historyDaySettingsSpinBox->setValue(
Edric Milareta3e47282015-10-23 15:20:30 -0400114 CategorizedHistoryModel::instance().historyLimit());
Edric Milaretb25af972015-06-17 16:55:45 -0400115 ui->closeOrMinCheckBox->setChecked(settings_.value(
116 SettingsKey::closeOrMinimized).toBool());
Edric Milaret568a0e52016-09-02 16:26:58 -0400117 ui->notificationCheckBox->setChecked(settings_.value(
118 SettingsKey::enableNotifications).toBool());
Nicolas Jager74fe46f2016-02-29 14:55:09 -0500119 connect(ui->stackedWidget, &QStackedWidget::currentChanged, [](int index) {
Edric Milaretfb5fc5c2015-09-24 14:32:49 -0400120 if (index == 1
Edric Milareta3e47282015-10-23 15:20:30 -0400121 && CallModel::instance().getActiveCalls().size() == 0) {
122 Video::PreviewManager::instance().startPreview();
Edric Milaretfb5fc5c2015-09-24 14:32:49 -0400123 } else {
Edric Milareta3e47282015-10-23 15:20:30 -0400124 if (CallModel::instance().getActiveCalls().size() == 0
125 && Video::PreviewManager::instance().isPreviewing()) {
126 Video::PreviewManager::instance().stopPreview();
Edric Milaretfb5fc5c2015-09-24 14:32:49 -0400127 }
128 }
129 });
Edric Milaret0b7fe5d2016-01-27 11:12:43 -0500130
131 ui->videoView->setIsFullPreview(true);
Edric Milaretfd5a1f22016-02-05 15:30:00 -0500132
133 auto recordPath = Media::RecordingModel::instance().recordPath();
134 if (recordPath.isEmpty()) {
135 recordPath = QDir::toNativeSeparators(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation));
136 Media::RecordingModel::instance().setRecordPath(recordPath);
137 }
138 ui->recordPath->setText(Media::RecordingModel::instance().recordPath());
139
140 ui->alwaysRecordCheckBox->setChecked(Media::RecordingModel::instance().isAlwaysRecording());
141 connect(ui->alwaysRecordCheckBox, &QCheckBox::clicked, [](bool checked){
142 Media::RecordingModel::instance().setAlwaysRecording(checked);
143 });
144
Nicolas Jager74fe46f2016-02-29 14:55:09 -0500145 connect(ui->generalTabButton, &QPushButton::toggled, [=] (bool toggled) {
146 if (toggled) {
147 ui->stackedWidget->setCurrentWidget(ui->generalPage);
148 ui->videoTabButton->setChecked(false);
149 ui->accountTabButton->setChecked(false);
150 }
151 });
152
153 connect(ui->videoTabButton, &QPushButton::toggled, [=] (bool toggled) {
154 if (toggled) {
155 ui->stackedWidget->setCurrentWidget(ui->videoPage);
156 ui->accountTabButton->setChecked(false);
157 ui->generalTabButton->setChecked(false);
158 }
159 });
160
161 connect(ui->accountTabButton, &QPushButton::toggled, [=] (bool toggled) {
162 if (toggled) {
163 ui->stackedWidget->setCurrentWidget(ui->accountPage);
164 ui->videoTabButton->setChecked(false);
165 ui->generalTabButton->setChecked(false);
166 }
167 });
168
169 ui->generalTabButton->setChecked(true);
170
Edric Milaret47c40eb2016-03-14 15:06:22 -0400171 auto inputModel = Audio::Settings::instance().inputDeviceModel();
172 auto outputModel = Audio::Settings::instance().outputDeviceModel();
173
174 ui->outputComboBox->setModel(outputModel);
175 ui->inputComboBox->setModel(inputModel);
176 ui->outputComboBox->setCurrentIndex(outputModel->selectionModel()->currentIndex().row());
177 ui->inputComboBox->setCurrentIndex(inputModel->selectionModel()->currentIndex().row());
178 connect(ui->outputComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(outputIndexChanged(int)));
179 connect(ui->inputComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(inputIndexChanged(int)));
180
Edric Milaret25236d92016-03-28 09:40:58 -0400181 auto profile = ProfileModel::instance().selectedProfile();
182 ui->avatarButton->setIcon(QPixmap::fromImage(Utils::getCirclePhoto(profile->person()->photo().value<QImage>(), ui->avatarButton->width())));
183 ui->profileNameEdit->setText(profile->person()->formattedName());
Olivier SOLDANO16c11f32016-10-28 11:57:48 -0400184
185 //temporary fix hiding imports buttons
186 ui->exportButton->hide();
187 ui->importButton->hide();
Olivier SOLDANO257e0682016-11-09 13:59:04 -0500188
189 ui->intervalUpdateCheckSpinBox->setEnabled(true);
Edric Milaret627500d2015-03-27 16:41:40 -0400190}
191
Edric Milaretef9b85b2016-02-05 11:47:10 -0500192void ConfigurationWidget::showPreview()
193{
Nicolas Jager74fe46f2016-02-29 14:55:09 -0500194 if (ui->stackedWidget->currentIndex() == 1
Edric Milaretef9b85b2016-02-05 11:47:10 -0500195 && CallModel::instance().getActiveCalls().size() == 0) {
196 ui->previewUnavailable->hide();
197 ui->videoView->show();
198 Video::PreviewManager::instance().startPreview();
199 } else {
200 ui->previewUnavailable->show();
201 ui->videoView->hide();
202 }
203}
204
Edric Milaretfb5fc5c2015-09-24 14:32:49 -0400205void
Edric Milaretf8048cf2016-05-13 10:21:08 -0400206ConfigurationWidget::showEvent(QShowEvent *event)
207{
Edric Milaret79d3f682015-12-09 12:32:52 -0500208 if (win_sparkle_get_automatic_check_for_updates()) {
209 ui->autoUpdateCheckBox->setChecked(true);
210 }
211 ui->intervalUpdateCheckSpinBox->setValue(win_sparkle_get_update_check_interval() / 86400);
Edric Milaretfb5fc5c2015-09-24 14:32:49 -0400212 QWidget::showEvent(event);
Edric Milaretef9b85b2016-02-05 11:47:10 -0500213 showPreview();
Edric Milaretfb5fc5c2015-09-24 14:32:49 -0400214}
215
Edric Milaret627500d2015-03-27 16:41:40 -0400216ConfigurationWidget::~ConfigurationWidget()
217{
218 delete ui;
Edric Milaret01f23842015-06-22 14:46:01 -0400219 delete accountStateDelegate_;
Edric Milaret627500d2015-03-27 16:41:40 -0400220}
221
222void
Edric Milaretf8048cf2016-05-13 10:21:08 -0400223ConfigurationWidget::deviceIndexChanged(int index)
224{
Edric Milaret94b4aab2015-05-08 12:10:44 -0400225 ui->deviceBox->setCurrentIndex(index);
226}
227
228void
Edric Milaret627500d2015-03-27 16:41:40 -0400229ConfigurationWidget::on_deviceBox_currentIndexChanged(int index)
230{
231 if (index < 0)
232 return;
233
234 if (!isLoading_)
235 deviceModel_->setActive(index);
236
237 auto device = deviceModel_->activeDevice();
238
239 ui->sizeBox->clear();
240
241 isLoading_ = true;
242 if (device->channelList().size() > 0) {
243 for (auto resolution : device->channelList()[0]->validResolutions()) {
244 ui->sizeBox->addItem(resolution->name());
245 }
246 }
247 ui->sizeBox->setCurrentIndex(
248 device->channelList()[0]->activeResolution()->relativeIndex());
249 isLoading_ = false;
250}
251
252void
253ConfigurationWidget::on_sizeBox_currentIndexChanged(int index)
254{
255 auto device = deviceModel_->activeDevice();
256
Edric Milaret627500d2015-03-27 16:41:40 -0400257 if (index < 0)
258 return;
259 if (!isLoading_)
260 device->channelList()[0]->setActiveResolution(
261 device->channelList()[0]->validResolutions()[index]);
Edric Milaret627500d2015-03-27 16:41:40 -0400262}
263
264void
Edric Milaretf8048cf2016-05-13 10:21:08 -0400265ConfigurationWidget::accountSelected(QItemSelection itemSel)
266{
267 if (itemSel.size())
268 accountDetails_->show();
269 else
270 accountDetails_->hide();
Edric Milaret3e6aefe2015-06-05 16:07:26 -0400271
Edric Milaretf8048cf2016-05-13 10:21:08 -0400272 if (accountConnection_)
273 disconnect(accountConnection_);
274
Edric Milaret3e6aefe2015-06-05 16:07:26 -0400275 auto account = accountModel_->getAccountByModelIndex(
276 ui->accountView->currentIndex());
277 accountDetails_->setAccount(account);
Edric Milaretf8048cf2016-05-13 10:21:08 -0400278 if (account) {
Edric Milaretce0ea472016-04-12 10:16:56 -0400279 AccountSerializationAdapter adapter(account, accountDetails_);
Edric Milaretf8048cf2016-05-13 10:21:08 -0400280 accountConnection_= connect(account,
281 SIGNAL(propertyChanged(Account*,QString,QString,QString)),
282 this,
283 SLOT(accountPropertyChanged(Account*,QString,QString,QString)));
284 }
285}
286
287void
288ConfigurationWidget::accountPropertyChanged(Account* a,
289 const QString& name,
290 const QString& newVal,
291 const QString& oldVal)
292{
293 Q_UNUSED(name)
294 Q_UNUSED(newVal)
295 Q_UNUSED(oldVal)
296 accountDetails_->setAccount(a);
297 AccountSerializationAdapter adapter(a, accountDetails_);
Edric Milaret627500d2015-03-27 16:41:40 -0400298}
299
300void
Edric Milaret627500d2015-03-27 16:41:40 -0400301ConfigurationWidget::on_addAccountButton_clicked()
302{
Edric Milaret57467842016-08-30 13:06:11 -0400303 auto type = ui->accountTypeBox->model()->index(ui->accountTypeBox->currentIndex(), 0);
304 if (type.data() == "RING") {
305 WizardDialog dlg(WizardDialog::NEW_ACCOUNT);
306 dlg.exec();
307 } else {
308 auto account = accountModel_->add(tr("New Account"), type);
309 account->setRingtonePath(Utils::GetRingtonePath());
310 accountModel_->save();
311 }
Edric Milaret627500d2015-03-27 16:41:40 -0400312}
Edric Milaret4bba46d2015-04-29 16:33:38 -0400313
Edric Milaret3aeae3a2015-06-01 17:31:54 -0400314void
315ConfigurationWidget::on_startupBox_toggled(bool checked)
Edric Milaret4bba46d2015-04-29 16:33:38 -0400316{
317 if (checked)
318 Utils::CreateStartupLink();
319 else
320 Utils::DeleteStartupLink();
321}
Edric Milaret3aeae3a2015-06-01 17:31:54 -0400322
323void
Edric Milaret1eece872015-06-10 13:37:51 -0400324ConfigurationWidget::on_clearHistoryButton_clicked()
325{
326 QMessageBox confirmationDialog;
327
Edric Milaret53ac6e52015-09-14 13:37:06 -0400328 confirmationDialog.setText(tr("Are you sure you want to clear all your history?"));
Edric Milaret1eece872015-06-10 13:37:51 -0400329 confirmationDialog.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
330 auto ret = confirmationDialog.exec();
331
332 if (ret == QMessageBox::Ok)
Edric Milareta3e47282015-10-23 15:20:30 -0400333 CategorizedHistoryModel::instance().clearAllCollections();
Edric Milaret1eece872015-06-10 13:37:51 -0400334}
335
336void
337ConfigurationWidget::on_historyDaySettingsSpinBox_valueChanged(int limit)
338{
Edric Milareta3e47282015-10-23 15:20:30 -0400339 if (CategorizedHistoryModel::instance().historyLimit() != limit)
340 CategorizedHistoryModel::instance().setHistoryLimit(limit);
Edric Milaret1eece872015-06-10 13:37:51 -0400341}
Edric Milaretb25af972015-06-17 16:55:45 -0400342
343void
344ConfigurationWidget::on_closeOrMinCheckBox_toggled(bool checked)
345{
346 settings_.setValue(SettingsKey::closeOrMinimized, checked);
347}
Edric Milaret79d3f682015-12-09 12:32:52 -0500348
349void
350ConfigurationWidget::on_checkUpdateButton_clicked()
351{
Edric Milaret79d3f682015-12-09 12:32:52 -0500352 win_sparkle_check_update_with_ui();
Edric Milaret79d3f682015-12-09 12:32:52 -0500353}
354
355void
356ConfigurationWidget::on_autoUpdateCheckBox_toggled(bool checked)
357{
Edric Milaret79d3f682015-12-09 12:32:52 -0500358 win_sparkle_set_automatic_check_for_updates(checked);
Edric Milaret79d3f682015-12-09 12:32:52 -0500359}
360
361void
362ConfigurationWidget::on_intervalUpdateCheckSpinBox_valueChanged(int arg1)
363{
Edric Milaret79d3f682015-12-09 12:32:52 -0500364 win_sparkle_set_update_check_interval(arg1 * 86400);
Edric Milaret79d3f682015-12-09 12:32:52 -0500365}
Edric Milaretef9b85b2016-02-05 11:47:10 -0500366
367void
Nicolas Jager74fe46f2016-02-29 14:55:09 -0500368ConfigurationWidget::on_stackedWidget_currentChanged(int index)
Edric Milaretef9b85b2016-02-05 11:47:10 -0500369{
370 Q_UNUSED(index)
371 showPreview();
372}
Edric Milaretfd5a1f22016-02-05 15:30:00 -0500373
374void
375ConfigurationWidget::on_recordPath_clicked()
376{
377 QString dir = QFileDialog::getExistingDirectory(this, tr("Choose Directory"),
378 Media::RecordingModel::instance().recordPath(),
379 QFileDialog::ShowDirsOnly
380 | QFileDialog::DontResolveSymlinks);
381 if (not dir.isEmpty()) {
382 Media::RecordingModel::instance().setRecordPath(dir);
383 ui->recordPath->setText(dir);
384 }
385}
Edric Milaret47c40eb2016-03-14 15:06:22 -0400386
387void
388ConfigurationWidget::outputIndexChanged(int index)
389{
390 auto outputModel = Audio::Settings::instance().outputDeviceModel();
391 outputModel->selectionModel()->setCurrentIndex(outputModel->index(index), QItemSelectionModel::ClearAndSelect);
392}
393
394void
395ConfigurationWidget::inputIndexChanged(int index)
396{
397 auto inputModel = Audio::Settings::instance().inputDeviceModel();
398 inputModel->selectionModel()->setCurrentIndex(inputModel->index(index), QItemSelectionModel::ClearAndSelect);
399}
Edric Milaretce0ea472016-04-12 10:16:56 -0400400
401void
402ConfigurationWidget::on_importButton_clicked()
403{
404 PathPasswordDialog dlg;
405 if (dlg.exec() == QDialog::Accepted)
406 if (AccountModel::instance().importAccounts(dlg.path_, dlg.password_) > 0)
407 errorDlg_.showMessage(tr("An error occured while importing account."));
408}
409
410void
411ConfigurationWidget::on_exportButton_clicked()
412{
413 PathPasswordDialog dlg;
414 dlg.exportMode = true;
415 if (dlg.exec() == QDialog::Accepted) {
416 auto func = [](QString path, QString password)
417 {
418 AccountModel::instance().exportAccounts(
419 {AccountModel::instance().selectedAccount()->id()},
420 path,
421 password);
422 };
423 QtConcurrent::run(func, dlg.path_, dlg.password_);
424 }
425}
Edric Milaret25236d92016-03-28 09:40:58 -0400426
427void
428ConfigurationWidget::on_avatarButton_clicked()
429{
430 PhotoBoothDialog dlg;
431 dlg.exec();
432 if (dlg.result() == QDialog::Accepted) {
433 auto image = QImage(dlg.fileName_);
434 auto avatar = image.scaled(100, 100, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
435 ProfileModel::instance().selectedProfile()->person()->setPhoto(avatar);
436 ProfileModel::instance().selectedProfile()->save();
437 ui->avatarButton->setIcon(QPixmap::fromImage(Utils::getCirclePhoto(avatar, ui->avatarButton->width())));
438 }
439}
440
441void
442ConfigurationWidget::on_profileNameEdit_textEdited(const QString& name)
443{
444 ProfileModel::instance().selectedProfile()->person()->setFormattedName(name);
445 ProfileModel::instance().selectedProfile()->save();
446}
Edric Milaret568a0e52016-09-02 16:26:58 -0400447
448void
449ConfigurationWidget::on_notificationCheckBox_toggled(bool checked)
450{
451 settings_.setValue(SettingsKey::enableNotifications, checked);
452}