blob: 98a09c2600b3b49cdb450151432e4214a886ff3d [file] [log] [blame]
Isa Nanic6e4a39a2018-12-04 14:26:02 -05001/***************************************************************************
2 * Copyright (C) 2018 by Savoir-faire Linux *
3 * Author: Isa Nanic <isa.nanic@savoirfairelinux.com> *
4 * Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>*
5 * Author: Anthony LĂ©onard <anthony.leonard@savoirfairelinux.com> *
6 * Author: Olivier Soldano <olivier.soldano@savoirfairelinux.com> *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 3 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program. If not, see <https://www.gnu.org/licenses/>. *
20 **************************************************************************/
21#include <QPixmap>
22#include <QTimer>
23#include <QModelIndex>
24#include <QFileDialog>
25#include <QInputDialog>
26#include <QStandardPaths>
27#include <QMessageBox>
28
29// account settings
30#include "api/newdevicemodel.h"
31#include "settingsitemwidget.h"
32
33#include "settingswidget.h"
34#include "ui_settingswidget.h"
35
36#include "ui_advancedsettingswidget.h"
37
38#include "passworddialog.h"
39
40#include "regnamedialog.h"
41#include "ui_regnamedialog.h"
42
43#include "setavatardialog.h"
44#include "ui_setavatardialog.h"
45
46#include "deleteaccountdialog.h"
47#include "ui_deleteaccountdialog.h"
48
49
50// general Settings
51#include "winsparkle.h"
52#include "media/recordingmodel.h"
53
54// av setttings
55#include "audio/settings.h"
56#include "audio/outputdevicemodel.h"
57#include "audio/inputdevicemodel.h"
58
59#include "video/devicemodel.h"
60#include "video/channel.h"
61#include "video/resolution.h"
62#include "video/rate.h"
63#include "video/previewmanager.h"
64
65#include "callmodel.h"
66
67
68
69
70SettingsWidget::SettingsWidget(QWidget* parent)
71 : NavWidget(parent),
72 ui(new Ui::SettingsWidget),
73 scrollArea_(new QScrollArea),
74 deviceModel_(&Video::DeviceModel::instance()),
75 gif(new QMovie(":/images/ajax-loader.gif"))
76{
77 ui->setupUi(this);
78
79 ui->accountSettingsButton->setAutoFillBackground(true);
80 ui->generalSettingsButton->setAutoFillBackground(true);
81 ui->avSettingsButton->setAutoFillBackground(true);
82
83 ui->accountSettingsButton->setChecked(true);
84
85 ui->exitSettingsButton->setIconSize(QSize(24, 24));
86 ui->exitSettingsButton->setIcon(QPixmap(":/images/icons/round-close-24px.svg"));
87
88
89 // display name (aka alias)
90 ui->displayNameLineEdit->setAlignment(Qt::AlignHCenter);
91 ui->displayNameLineEdit->setPlaceholderText(tr("Enter the displayed name"));
92
93
94 setSelected(Button::accountSettingsButton);
95
96 ui->currentRegisteredID->setReadOnly(true);
97 ui->currentRegisteredID->setStyleSheet("border : 0px;");
98
99 ui->currentRingID->setReadOnly(true);
100
101 avatarSize_ = ui->currentAccountAvatar->width();
102
103 ui->currentAccountAvatar->setIconSize(QSize(avatarSize_, avatarSize_));
104
105 // create ellipse-selectable avatar image
106 QRegion avatarClickableRegion(-1, -1,
107 ui->currentAccountAvatar->width() + 2, ui->currentAccountAvatar->height() + 2, QRegion::Ellipse);
108 ui->currentAccountAvatar->setMask(avatarClickableRegion);
109
110 QString styleS(
111 "QPushButton{"
112 " background-color: rgb(245, 245, 245);"
113 " border: 0px;"
114 "}"
115 " QPushButton:hover{"
116 " background-color: rgb(250, 250, 250);"
117 " border: 0px;"
118 " }"
119
120 "QPushButton:checked{"
121 " background-color: white;"
122 " border: 0px;"
123 "}"
124 );
125
126 ui->accountSettingsButton->setStyleSheet(styleS);
127 ui->generalSettingsButton->setStyleSheet(styleS);
128 ui->avSettingsButton->setStyleSheet(styleS);
129
130 ui->advancedAccountSettingsPButton->setIcon(QPixmap(":/images/icons/round-arrow_drop_down-24px.svg"));
131 ui->linkDevPushButton->setIcon(QPixmap(":/images/icons/round-add-24px.svg"));
132 ui->blockedContactsBtn->setIcon(QPixmap(":/images/icons/round-arrow_drop_up-24px.svg"));
133
134 ui->advancedSettingsOffsetLabel->show();
135
Andreas Traczyk66e5a6d2018-12-10 14:27:34 -0500136 auto accountList = LRCInstance::accountModel().getAccountList();
137 if (accountList.empty()) {
138 connect(&LRCInstance::accountModel(),
139 &lrc::api::NewAccountModel::accountAdded,
140 [this](const std::string& accountId) {
141 setConnections();
142 });
143 } else {
144 setConnections();
145 }
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500146}
147
148void
149SettingsWidget::leaveSettingsSlot()
150{
151 emit NavigationRequested(ScreenEnum::CallScreen);
152 if (advancedSettingsDropped_) {
153 toggleAdvancedSettings();
154 }
155
156 if (avSettingsHaveAppeared) {
157 ui->videoWidget->previewStopped();
158 ui->videoWidget->renderingStopped();
159 avSettingsHaveAppeared = false;
160 }
161}
162
163SettingsWidget::~SettingsWidget()
164{
165 delete advancedSettingsWidget_;
166 delete scrollArea_;
167 delete ui;
168}
169
170// called at every callwidget -> settingsWidget navigation
171void
172SettingsWidget::updateSettings(int size)
173{
174 setSelected(Button::accountSettingsButton);
175 resize(size);
176 updateAccountInfoDisplayed();
177}
178
179void
180SettingsWidget::resize(int size)
181{
182 ui->rightSettingsWidget->setGeometry(size, 0, this->width() - size, this->height());
183 ui->accountSettingsButton->setFixedWidth(size);
184}
185
186void
187SettingsWidget::setSelected(Button sel)
188{
189 switch (sel)
190 {
191 case Button::accountSettingsButton:
192 if (advancedSettingsDropped_) { toggleAdvancedSettings(); }
193
194 ui->stackedWidget->setCurrentWidget(ui->currentAccountSettingsScrollWidget);
195 if (pastButton_ == Button::generalSettingsButton) {
196 ui->accountSettingsButton->setChecked(true);
197 ui->generalSettingsButton->setChecked(false);
198 break;
199 }
200 else {
201 ui->accountSettingsButton->setChecked(true);
202 ui->avSettingsButton->setChecked(false);
203 break;
204 }
205 case Button::generalSettingsButton:
206 ui->stackedWidget->setCurrentWidget(ui->generalSettings);
207 populateGeneralSettings();
208 if (pastButton_ == Button::avSettingsButton) {
209 ui->generalSettingsButton->setChecked(true);
210 ui->avSettingsButton->setChecked(false);
211 break;
212 }
213 else {
214 ui->generalSettingsButton->setChecked(true);
215 ui->accountSettingsButton->setChecked(false);
216 break;
217 }
218 case Button::avSettingsButton:
219 ui->stackedWidget->setCurrentWidget(ui->avSettings);
220 if (!avSettingsHaveAppeared) { populateAVSettings(); }
221 if (pastButton_ == Button::accountSettingsButton) {
222 ui->avSettingsButton->setChecked(true);
223 ui->accountSettingsButton->setChecked(false);
224 break;
225 }
226 else {
227 ui->avSettingsButton->setChecked(true);
228 ui->generalSettingsButton->setChecked(false);
229 break;
230 }
231 }
232 pastButton_ = sel;
233}
234
235// called to update current settings information when navigating to settingsWidget
236void
237SettingsWidget::updateAccountInfoDisplayed()
238{
239 ui->currentRegisteredID->setText(QString::fromStdString(LRCInstance::getCurrentAccountInfo().registeredName));
240 ui->currentRingID->setText(QString::fromStdString(LRCInstance::getCurrentAccountInfo().profileInfo.uri));
241
242 ui->currentRegisteredID->setReadOnly(true);
243
244// if no registered name is found for account
245 if (LRCInstance::getCurrentAccountInfo().registeredName.empty()) {
246 ui->currentRegisteredID->setReadOnly(false);
247 }
248 else {
249 ui->currentRegisteredID->setReadOnly(true);
250 setRegNameUi(RegName::BLANK);
251 }
252
253 ui->currentAccountAvatar->setIcon(LRCInstance::getCurrAccPixmap().
254 scaledToHeight(avatarSize_, Qt::SmoothTransformation));
255
256 ui->accountEnableCheckBox->setChecked(LRCInstance::getCurrentAccountInfo().enabled);
257
258 ui->displayNameLineEdit->setText(QString::fromStdString(LRCInstance::getCurrentAccountInfo().profileInfo.alias));
259
260 updateAndShowDevicesSlot();
261 if (!LRCInstance::getCurrentAccountInfo().contactModel->getBannedContacts().size()){
262 ui->blockedContactsBtn->hide();
263 } else {
264 ui->blockedContactsBtn->show();
265 }
266 bannedContactsShown_ = false;
267}
268
269void
270SettingsWidget::passwordClicked()
271{
272 PasswordDialog passwdDialog(this);
273 passwdDialog.exec();
274}
275
276void
277SettingsWidget::toggleAdvancedSettings()
278{
279 if (advancedSettingsDropped_) {
280 ui->advancedAccountSettingsPButton->setIcon(QPixmap(":/images/icons/round-arrow_drop_down-24px.svg"));
281 ui->currentAccountSettingsScrollLayout->removeWidget(advancedSettingsWidget_);
282 ui->scrollBarLabel->show();
283 ui->advancedSettingsOffsetLabel->hide();
284 delete advancedSettingsWidget_;
285 }
286 else { // will show advanced settings next
287 ui->advancedAccountSettingsPButton->setIcon(QPixmap(":/images/icons/round-arrow_drop_up-24px.svg"));
288 advancedSettingsWidget_ = new AdvancedSettingsWidget(ui->scrollAreaWidgetContents);
289 advancedSettingsWidget_->setMaximumWidth(ui->scrollAreaWidgetContents->width() - 10);
290 ui->currentAccountSettingsScrollLayout->addWidget(advancedSettingsWidget_);
291 ui->advancedSettingsOffsetLabel->show();
292 ui->scrollBarLabel->hide();
293 }
294 advancedSettingsDropped_ = !advancedSettingsDropped_;
295}
296
297void
298SettingsWidget::toggleBannedContacts()
299{
300 if (bannedContactsShown_) { // will show linked devices next
301 updateAndShowDevicesSlot();
302 }
303 else { // will show banned contacts next
304 updateAndShowBannedContactsSlot();
305 }
306}
307
308void
309SettingsWidget::resizeEvent(QResizeEvent* event)
310{
311 QWidget::resizeEvent(event);
312 scrollArea_->resize(ui->currentAccountSettingsScrollWidget->width(), this->height());
313}
314
315void
316SettingsWidget::avatarClicked()
317{
318 SetAvatarDialog avatarDialog(this);
319
320 // return new avatar pixmap from setAvatarDialog
321 connect(&avatarDialog, &SetAvatarDialog::pixmapSignal, [&](const std::string& pixString) {
322 if (!pixString.empty()) {
323 LRCInstance::setCurrAccAvatar(pixString);
324 updateAccountInfoDisplayed();
325 }
326 }
327 );
328 avatarDialog.exec();
329}
330
331void
332SettingsWidget::verifyRegisteredNameSlot()
333{
334 if (!LRCInstance::getCurrentAccountInfo().registeredName.empty()) {
335 setRegNameUi(RegName::BLANK);
336 }
337 else {
338 registeredName_ = ui->currentRegisteredID->text().simplified();
339
340 if (!registeredName_.isEmpty()) {
341 if (validateRegNameForm(registeredName_)) { // name has valid form
342 setRegNameUi(RegName::SEARCHING);
343 QTimer::singleShot(300, this, SLOT(beforeNameLookup()));
344 } else { // name does not have valid form
345 setRegNameUi(RegName::INVALIDFORM);
346 }
347 } else {
348 setRegNameUi(RegName::BLANK);
349 }
350 }
351}
352
353// returns true if name is valid registered name
354bool
355SettingsWidget::validateRegNameForm(const QString& regName)
356{
357 QRegularExpression regExp(" ");
358 if (regName.size() > 2 && !regName.contains(regExp)) {
359 return true;
360 }
361 else {
362 return false;
363 }
364}
365
366void
367SettingsWidget::receiveRegNameSlot(const std::string& accountID,
368 lrc::api::account::LookupStatus status, const std::string& address, const std::string& name)
369{
370 Q_UNUSED(accountID); Q_UNUSED(address);
371 afterNameLookup(status, name);
372}
373
374void
375SettingsWidget::beforeNameLookup()
376{
377 NameDirectory::instance().lookupName(nullptr, QString(), registeredName_);
378}
379
380void
381SettingsWidget::afterNameLookup(lrc::api::account::LookupStatus status, const std::string& regName)
382{
383 if (registeredName_.toStdString() == regName && regName.length() > 2) {
384 if (status == lrc::api::account::LookupStatus::NOT_FOUND) {
385 setRegNameUi(RegName::FREE);
386 }
387 else {
388 setRegNameUi(RegName::TAKEN);
389 }
390 }
391 else {
392 setRegNameUi(RegName::BLANK);
393 }
394}
395
396void SettingsWidget::setRegNameUi(RegName stat)
397{
398 disconnect(gif, SIGNAL(frameChanged(int)), this, SLOT(setButtonIconSlot(int)));
399 disconnect(ui->regNameButton, &QPushButton::clicked, this, &SettingsWidget::regNameRegisteredSlot);
400
401 switch (stat) {
402 case RegName::BLANK:
403 ui->currentRegisteredID->setStyleSheet("padding-left: 5px; border: 0px; border-radius: 3px; border: 1px solid rgb(245, 245, 245);");
404 regNameBtn_ = false;
405 ui->currentRegisteredID->setToolTip(tr(""));
406 ui->regNameButton->setIcon(QPixmap());
407 ui->regNameButton->setEnabled(false);
408 break;
409
410 case RegName::INVALIDFORM:
411 ui->currentRegisteredID->setStyleSheet("padding-left: 5px; border: 1px solid red; border-radius: 3px;");
412 regNameBtn_ = false;
413 ui->currentRegisteredID->setToolTip(tr("A registered name should not have any spaces and must be at least three letters long"));
414 ui->regNameButton->setIcon(QPixmap(":/images/icons/round-error-24px.svg"));
415 ui->regNameButton->setToolTip(tr("A registered name should not have any spaces and must be at least three letters long"));
416 ui->regNameButton->setEnabled(true);
417 break;
418
419 case RegName::TAKEN:
420 ui->currentRegisteredID->setStyleSheet("padding-left: 5px; border: 1px solid orange; border-radius: 3px;");
421 regNameBtn_ = false;
422 ui->currentRegisteredID->setToolTip(tr("This name is already taken"));
423 ui->regNameButton->setIcon(QPixmap(":/images/icons/round-error-24px.svg"));
424 ui->regNameButton->setToolTip(tr("This registered name is already taken"));
425 ui->regNameButton->setEnabled(true);
426 break;
427
428 case RegName::FREE:
429 ui->currentRegisteredID->setStyleSheet("padding-left: 5px; border: 1px solid green; border-radius: 3px;");
430 regNameBtn_ = true;
431 ui->currentRegisteredID->setToolTip(tr("This name is available"));
432 ui->regNameButton->setIcon(QPixmap(":/images/icons/round-check_circle-24px.svg"));
433 ui->regNameButton->setToolTip(tr("Register this name"));
434 ui->regNameButton->setEnabled(true);
435
436 connect(ui->regNameButton, &QPushButton::clicked, this, &SettingsWidget::regNameRegisteredSlot);
437
438 break;
439
440 case RegName::SEARCHING:
441 ui->currentRegisteredID->setStyleSheet("padding-left: 5px; border: 1px solid rgb(2, 187, 213); border-radius: 3px;");
442 regNameBtn_ = false;
443 ui->currentRegisteredID->setToolTip(tr(""));
444
445 connect(gif, SIGNAL(frameChanged(int)), this, SLOT(setButtonIconSlot(int)));
446 gif->start();
447 ui->regNameButton->setEnabled(false);
448
449 break;
450 }
451}
452void SettingsWidget::setButtonIconSlot(int frame)
453{
454 Q_UNUSED(frame);
455 ui->regNameButton->setIcon(QIcon(gif->currentPixmap()));
456}
457
458void
459SettingsWidget::regNameRegisteredSlot()
460{
461 if (!regNameBtn_) { return; }
462
463 RegNameDialog regNameDialog(registeredName_, this);
464 if (regNameDialog.exec() == QDialog::Accepted) { // if user confirms regName choice
465 ui->currentRegisteredID->setReadOnly(true);
466 }
467 else {
468 ui->currentRegisteredID->setText("");
469 registeredName_ = "";
470 }
471 setRegNameUi(RegName::BLANK);
472}
473
474void
475SettingsWidget::setAccEnableSlot(int state)
476{
477 LRCInstance::editableAccountModel()->enableAccount(LRCInstance::getCurrAccId(), (bool)state);
478
479 auto confProps = LRCInstance::accountModel().getAccountConfig(LRCInstance::getCurrAccId());
480 LRCInstance::editableAccountModel()->setAccountConfig(LRCInstance::getCurrAccId(), confProps);
481}
482
483void
484SettingsWidget::delAccountSlot()
485{
486 DeleteAccountDialog delDialog(this);
487 delDialog.exec();
488
489 if (!LRCInstance::accountModel().getAccountList().size()) {
490 emit NavigationRequested(ScreenEnum::WizardScreen);
491 }
492}
493
494void
495SettingsWidget::removeDeviceSlot(int index)
496{
497 if (!index) { return; }
498
499 auto deviceList = LRCInstance::getCurrentAccountInfo().deviceModel->getAllDevices();
500 auto it = deviceList.begin();
501
502 std::advance(it, index);
503 QString psswd;
504
505 bool ok = false;
506 if (LRCInstance::getCurrAccConfig().archiveHasPassword) {
507 psswd = QInputDialog::getText(this, tr("Remove Device"),
508 tr("Enter the password on this device to confirm the removal of this device"), QLineEdit::Password,
509 QDir::home().dirName(), &ok);
510 }
511 else {
512 psswd = "";
513 QMessageBox devDel;
514 devDel.setText(tr("Please confirm that you wish to remove this device"));
515 devDel.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
516 devDel.setDefaultButton(QMessageBox::Cancel);
517 if (devDel.exec() == QMessageBox::Ok) { goto delete_; }
518 }
519
520 if (ok) {
521 delete_:
522 LRCInstance::getCurrentAccountInfo().deviceModel->revokeDevice(it->id, psswd.toStdString());
523 updateAndShowDevicesSlot();
524 }
525}
526
527void
528SettingsWidget::unban(int index)
529{
530 auto bannedContactList = LRCInstance::getCurrentAccountInfo().contactModel->getBannedContacts();
531 auto it = bannedContactList.begin();
532 std::advance(it, index);
533
534 auto contactInfo = LRCInstance::getCurrentAccountInfo().contactModel->getContact(*it);
535
536 LRCInstance::getCurrentAccountInfo().contactModel->addContact(contactInfo);
537 updateAndShowBannedContactsSlot();
538}
539
540void
541SettingsWidget::exportAccountSlot()
542{
543 QFileDialog dialog(this);
544 QString dir = QFileDialog::getExistingDirectory(this, tr("Export Account Here"),
545 QDir::homePath() + "/Desktop", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
546
547 if (!dir.isEmpty()) {
548 LRCInstance::accountModel().exportToFile(LRCInstance::getCurrAccId(), (dir + "/export.gz").toStdString());
549 }
550}
551
552void
553SettingsWidget::updateAndShowDevicesSlot()
554{
555 ui->settingsListWidget->clear();
556
557 ui->label->setText(tr("Linked Devices"));
558 ui->blockedContactsBtn->setText(tr("Blocked Contacts"));
559 ui->linkDevPushButton->show();
560
561 auto deviceList = LRCInstance::getCurrentAccountInfo().deviceModel->getAllDevices();
562
563 int i = 0;
564
565 for (auto it = deviceList.begin(); it != deviceList.end(); ++it, ++i) {
566 SettingsItemWidget* item = new SettingsItemWidget(itemHeight_, i, false, ui->settingsListWidget);
567 item->setSizeHint(QSize(ui->settingsListWidget->width(), itemHeight_));
568 ui->settingsListWidget->addItem(item);
569
570 if (i) {
571 connect(item->button_, &QPushButton::clicked, [this, i]() {
572 removeDeviceSlot(i);
573 }
574 );
575 }
576 }
577 bannedContactsShown_ = false;
578}
579
580void
581SettingsWidget::updateAndShowBannedContactsSlot()
582{
583 ui->settingsListWidget->clear();
584
585 ui->label->setText(tr("Blocked Contacts"));
586 ui->blockedContactsBtn->setText(tr("Linked Devices"));
587 ui->linkDevPushButton->hide();
588
589 auto bannedContactList = LRCInstance::getCurrentAccountInfo().contactModel->getBannedContacts();
590
591 int i = 0;
592
593 for (auto it = bannedContactList.begin(); it != bannedContactList.end(); ++it, ++i) {
594 SettingsItemWidget* item = new SettingsItemWidget(itemHeight_, i, true, ui->settingsListWidget);
595 item->setSizeHint(QSize(ui->settingsListWidget->width(), itemHeight_));
596 ui->settingsListWidget->addItem(item);
597
598 connect(item->button_, &QPushButton::clicked, [this, i]() {
599 unban(i);
600 }
601 );
602 }
603 bannedContactsShown_ = true;
604 if (!bannedContactList.size()) { updateAndShowDevicesSlot(); ui->blockedContactsBtn->hide(); }
605}
606
607void
608SettingsWidget::showLinkDevSlot()
609{
610 if (!advancedSettingsWidget_) { delete advancedSettingsWidget_; }
611
612 linkDevWidget = new LinkDevWidget(ui->scrollAreaWidgetContents);
613 linkDevWidget->setMinimumWidth(600);
614
615 ui->accountHorLayout->insertWidget(1, linkDevWidget);
616
617 linkDevWidget->show();
618 ui->centralWidget->hide();
619
620 connect(linkDevWidget->cancelBtn(), &QPushButton::clicked, this, &SettingsWidget::showCurrentAccountSlot);
621 connect(linkDevWidget->endCancelBtn(), &QPushButton::clicked, this, &SettingsWidget::showCurrentAccountSlot);
622}
623
624void
625SettingsWidget::showCurrentAccountSlot()
626{
627 disconnect(linkDevWidget);
628
629 delete linkDevWidget;
630 ui->centralWidget->show();
631}
632
633void
634SettingsWidget::setConnections()
635{
636 // exitSettingsButton
637 connect(ui->exitSettingsButton, &QPushButton::clicked, this, &SettingsWidget::leaveSettingsSlot);
638
639 connect(ui->accountSettingsButton, &QPushButton::clicked, [this]() {
640 setSelected(Button::accountSettingsButton); }
641 );
642
643 connect(ui->generalSettingsButton, &QPushButton::clicked, [this]() {
644 setSelected(Button::generalSettingsButton); }
645 );
646
647 connect(ui->avSettingsButton, &QPushButton::clicked, [this]() {
648 setSelected(Button::avSettingsButton); }
649 );
650
651 connect(ui->passwdPushButton, &QPushButton::clicked, [this]() {
652 passwordClicked(); }
653 );
654
655 connect(ui->currentAccountAvatar, &QPushButton::clicked, [this]() {
656 avatarClicked(); }
657 );
658
659 connect(ui->advancedAccountSettingsPButton, &QPushButton::clicked, this, &SettingsWidget::toggleAdvancedSettings);
660
661 connect(ui->currentRegisteredID, &QLineEdit::textChanged, this, &SettingsWidget::verifyRegisteredNameSlot);
662
663 connect(&LRCInstance::accountModel(), &lrc::api::NewAccountModel::registeredNameFound,
664 this, &SettingsWidget::receiveRegNameSlot);
665
666 //connect "export account" button
667 connect(ui->btnExportAccount, &QPushButton::clicked, this, &SettingsWidget::exportAccountSlot);
668
669 // connect "delete account" button
670 connect(ui->btnDeletAccount, &QPushButton::clicked, this, &SettingsWidget::delAccountSlot);
671
672 // connect "banned contacts" button
673 connect(ui->blockedContactsBtn, &QPushButton::clicked, this, &SettingsWidget::toggleBannedContacts);
674
675 // connect "link device" button
676 connect(ui->linkDevPushButton, &QPushButton::clicked, this, &SettingsWidget::showLinkDevSlot);
677
678 // update banned accounts automatically
679 connect(LRCInstance::getCurrentAccountInfo().contactModel.get(), &lrc::api::ContactModel::modelUpdated,
680 this, &SettingsWidget::updateAndShowBannedContactsSlot);
681
682 // update linked devices automatically
683 QObject::connect(LRCInstance::getCurrentAccountInfo().deviceModel.get(), &lrc::api::NewDeviceModel::deviceUpdated,
684 this, &SettingsWidget::updateAndShowDevicesSlot);
685
686 // account settings setters {
687 connect(ui->accountEnableCheckBox, &QCheckBox::stateChanged, this, &SettingsWidget::setAccEnableSlot);
688
689 connect(ui->displayNameLineEdit, &QLineEdit::textChanged, [this](const QString& displayName) {
690 LRCInstance::setCurrAccDisplayName(displayName.toStdString());
691 }
692 );
693
694 // general settings
695
696 connect(ui->notificationCheckBox, &QCheckBox::stateChanged, this, &SettingsWidget::setNotificationsSlot);
697
698 connect(ui->closeOrMinCheckBox, &QCheckBox::stateChanged, this, &SettingsWidget::setClosedOrMinSlot);
699
700 connect(ui->downloadButton, &QPushButton::clicked, this, &SettingsWidget::openDownloadFolderSlot);
701
702 connect(ui->alwaysRecordingCheckBox, &QCheckBox::stateChanged, this, &SettingsWidget::setAlwaysRecordingSlot);
703
704 connect(ui->checkUpdateButton, &QPushButton::clicked, this, &SettingsWidget::checkForUpdateSlot);
705
706 connect(ui->intervalUpdateCheckSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), this, &SettingsWidget::setUpdateIntervalSlot);
707
708 connect(ui->autoUpdateCheckBox, &QCheckBox::stateChanged, this, &SettingsWidget::setUpdateAutomaticSlot);
709
710 // audio / visual settings
711
712 connect(ui->recordPathButton, &QPushButton::clicked, this, &SettingsWidget::openRecordFolderSlot);
713}
714
715
716// ************************* General Settings *************************
717
718void SettingsWidget::populateGeneralSettings()
719{
720 settings_ = new QSettings;
721
722 // settings
723 ui->downloadButton->setText(QStandardPaths::writableLocation(QStandardPaths::DownloadLocation));
724 ui->closeOrMinCheckBox->setChecked(settings_->value(SettingsKey::closeOrMinimized).toBool());
725 ui->notificationCheckBox->setChecked(settings_->value(SettingsKey::enableNotifications).toBool());
726
727 //recordings
728 ui->alwaysRecordingCheckBox->setChecked(media::RecordingModel::instance().isAlwaysRecording());
729
730 if (media::RecordingModel::instance().recordPath().isEmpty()) {
731 QString recordPath = QDir::toNativeSeparators(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation));
732 media::RecordingModel::instance().setRecordPath(recordPath);
733 }
734 ui->recordPathButton->setText(media::RecordingModel::instance().recordPath());
735
736
737 ui->autoUpdateCheckBox->setChecked(win_sparkle_get_automatic_check_for_updates());
738 ui->intervalUpdateCheckSpinBox->setValue(win_sparkle_get_update_check_interval() / 86400);
739
740}
741
742void
743SettingsWidget::setNotificationsSlot(int state)
744{
745 if (state == Qt::CheckState::Unchecked) {
746 settings_->setValue(SettingsKey::enableNotifications, false);
747 } else {
748 settings_->setValue(SettingsKey::enableNotifications, true);
749 }
750}
751
752void
753SettingsWidget::setClosedOrMinSlot(int state)
754{
755 if (state == Qt::CheckState::Unchecked) {
756 settings_->setValue(SettingsKey::closeOrMinimized, false);
757 }
758 else {
759 settings_->setValue(SettingsKey::closeOrMinimized, true);
760 }
761}
762
763void
764SettingsWidget::checkForUpdateSlot()
765{
766 win_sparkle_check_update_with_ui();
767}
768
769void
770SettingsWidget::setUpdateIntervalSlot(int value)
771{
772 win_sparkle_set_update_check_interval(value * 86400);
773}
774
775void
776SettingsWidget::setUpdateAutomaticSlot(int state)
777{
778 if (state == Qt::CheckState::Unchecked) {
779 win_sparkle_set_automatic_check_for_updates(false);
780 ui->intervalUpdateCheckSpinBox->setEnabled(false);
781 } else {
782 win_sparkle_set_automatic_check_for_updates(true);
783 ui->intervalUpdateCheckSpinBox->setEnabled(true);
784 }
785}
786
787void
788SettingsWidget::openDownloadFolderSlot()
789{
790 QString dir = QFileDialog::getExistingDirectory(this, tr("Select A Folder For Your Downloads"),
791 QStandardPaths::writableLocation(QStandardPaths::DownloadLocation), QFileDialog::ShowDirsOnly
792 | QFileDialog::DontResolveSymlinks);
793
794 if (!dir.isEmpty()) {
795 QStandardPaths::writableLocation(QStandardPaths::DownloadLocation) = dir;
796 ui->downloadButton->setText(dir);
797 }
798}
799
800void
801SettingsWidget::setAlwaysRecordingSlot(int state)
802{
803 if (state == Qt::CheckState::Unchecked) {
804 media::RecordingModel::instance().setAlwaysRecording(false);
805 } else {
806 media::RecordingModel::instance().setAlwaysRecording(true);
807 }
808}
809
810void
811SettingsWidget::openRecordFolderSlot()
812{
813 QString dir = QFileDialog::getExistingDirectory(this, tr("Select A Folder For Your Recordings"),
814 media::RecordingModel::instance().recordPath(), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
815
816 if (!dir.isEmpty()) {
817 media::RecordingModel::instance().setRecordPath(dir);
818 ui->recordPathButton->setText(media::RecordingModel::instance().recordPath());
819 }
820}
821
822
823// ************************* Audio/Visual Settings *************************
824
825void
826SettingsWidget::populateAVSettings()
827{
828 ui->deviceBox->setModel(deviceModel_);
829 connect(deviceModel_, SIGNAL(currentIndexChanged(int)),
830 this, SLOT(deviceIndexChanged(int)));
831
832 if (ui->deviceBox->count() > 0) {
833 ui->deviceBox->setCurrentIndex(0);
834 deviceBoxCurrentIndexChangedSlot(0);
835 }
836
837 // Audio settings
838 auto inputModel = Audio::Settings::instance().inputDeviceModel();
839 auto outputModel = Audio::Settings::instance().outputDeviceModel();
840
841 ui->outputComboBox->setModel(outputModel);
842 ui->inputComboBox->setModel(inputModel);
843 if (ui->outputComboBox->count() > 0) {
844 ui->outputComboBox->setCurrentIndex(0);
845 }
846 if (ui->inputComboBox->count() > 0) {
847 ui->inputComboBox->setCurrentIndex(0);
848 }
849
850 connect(ui->outputComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
851 this, &SettingsWidget::outputDevIndexChangedSlot);
852 connect(ui->inputComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
853 this, &SettingsWidget::inputdevIndexChangedSlot);
854
855 connect(ui->deviceBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
856 &SettingsWidget::deviceBoxCurrentIndexChangedSlot);
857 connect(ui->sizeBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
858 &SettingsWidget::sizeBoxCurrentIndexChangedSlot);
859
860 isLoading_ = true;
861 avSettingsHaveAppeared = true;
862
863 showPreview();
864}
865
866void
867SettingsWidget::showPreview()
868{
869 if (!CallModel::instance().getActiveCalls().size()) {
870 ui->previewUnavailableLabel->hide();
871 ui->videoWidget->show();
872 Video::PreviewManager::instance().startPreview();
873 ui->videoWidget->setIsFullPreview(true);
874 } else {
875 ui->previewUnavailableLabel->show();
876 ui->videoWidget->hide();
877 }
878}
879
880void
881SettingsWidget::deviceBoxCurrentIndexChangedSlot(int index)
882{
883 if (index < 0) {
884 return;
885 }
886
887 if (!isLoading_)
888 deviceModel_->setActive(index);
889
890 auto device = deviceModel_->activeDevice();
891
892 ui->sizeBox->clear();
893
894 isLoading_ = true;
895 if (device->channelList().size() > 0) {
896 for (auto resolution : device->channelList()[0]->validResolutions()) {
897 ui->sizeBox->addItem(resolution->name());
898 }
899 }
900 ui->sizeBox->setCurrentIndex(
901 device->channelList()[0]->activeResolution()->relativeIndex());
902 isLoading_ = false;
903}
904
905void
906SettingsWidget::sizeBoxCurrentIndexChangedSlot(int index)
907{
908 auto device = deviceModel_->activeDevice();
909
910 if (index < 0) return;
911
912 device->channelList()[0]->setActiveResolution(device->channelList()[0]->validResolutions()[index]);
913}
914
915void
916SettingsWidget::deviceIndexChanged(int index)
917{
918 ui->deviceBox->setCurrentIndex(index);
919
920 ui->videoLayout->update();
921}
922
923void
924SettingsWidget::outputDevIndexChangedSlot(int index)
925{
926 auto outputModel = Audio::Settings::instance().outputDeviceModel();
927 outputModel->selectionModel()->setCurrentIndex(outputModel->index(index), QItemSelectionModel::ClearAndSelect);
928}
929
930void
931SettingsWidget::inputdevIndexChangedSlot(int index)
932{
933 auto inputModel = Audio::Settings::instance().inputDeviceModel();
934 inputModel->selectionModel()->setCurrentIndex(inputModel->index(index), QItemSelectionModel::ClearAndSelect);
935}