blob: d6a0dea2ce951819bc131d9899aeddb7e60a8b3c [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>
Isa Nanic5bafcb92018-12-19 12:54:51 -050028#include <QSettings>
Isa Nanic6e4a39a2018-12-04 14:26:02 -050029
30// account settings
31#include "api/newdevicemodel.h"
32#include "settingsitemwidget.h"
33
34#include "settingswidget.h"
35#include "ui_settingswidget.h"
36
37#include "ui_advancedsettingswidget.h"
38
39#include "passworddialog.h"
40
41#include "regnamedialog.h"
42#include "ui_regnamedialog.h"
43
44#include "setavatardialog.h"
45#include "ui_setavatardialog.h"
46
47#include "deleteaccountdialog.h"
48#include "ui_deleteaccountdialog.h"
49
50
51// general Settings
52#include "winsparkle.h"
53#include "media/recordingmodel.h"
54
55// av setttings
56#include "audio/settings.h"
57#include "audio/outputdevicemodel.h"
58#include "audio/inputdevicemodel.h"
59
60#include "video/devicemodel.h"
61#include "video/channel.h"
62#include "video/resolution.h"
63#include "video/rate.h"
64#include "video/previewmanager.h"
65
66#include "callmodel.h"
67
Isa Nanic6e4a39a2018-12-04 14:26:02 -050068SettingsWidget::SettingsWidget(QWidget* parent)
69 : NavWidget(parent),
70 ui(new Ui::SettingsWidget),
Andreas Traczykb81281e2018-12-13 13:13:28 -050071 scrollArea_(new QScrollArea(this)),
Isa Nanic6e4a39a2018-12-04 14:26:02 -050072 deviceModel_(&Video::DeviceModel::instance()),
73 gif(new QMovie(":/images/ajax-loader.gif"))
74{
75 ui->setupUi(this);
76
77 ui->accountSettingsButton->setAutoFillBackground(true);
78 ui->generalSettingsButton->setAutoFillBackground(true);
79 ui->avSettingsButton->setAutoFillBackground(true);
80
81 ui->accountSettingsButton->setChecked(true);
82
83 ui->exitSettingsButton->setIconSize(QSize(24, 24));
84 ui->exitSettingsButton->setIcon(QPixmap(":/images/icons/round-close-24px.svg"));
85
86
87 // display name (aka alias)
88 ui->displayNameLineEdit->setAlignment(Qt::AlignHCenter);
89 ui->displayNameLineEdit->setPlaceholderText(tr("Enter the displayed name"));
90
91
92 setSelected(Button::accountSettingsButton);
93
94 ui->currentRegisteredID->setReadOnly(true);
95 ui->currentRegisteredID->setStyleSheet("border : 0px;");
96
97 ui->currentRingID->setReadOnly(true);
98
99 avatarSize_ = ui->currentAccountAvatar->width();
100
101 ui->currentAccountAvatar->setIconSize(QSize(avatarSize_, avatarSize_));
102
103 // create ellipse-selectable avatar image
104 QRegion avatarClickableRegion(-1, -1,
105 ui->currentAccountAvatar->width() + 2, ui->currentAccountAvatar->height() + 2, QRegion::Ellipse);
106 ui->currentAccountAvatar->setMask(avatarClickableRegion);
107
108 QString styleS(
109 "QPushButton{"
110 " background-color: rgb(245, 245, 245);"
111 " border: 0px;"
112 "}"
113 " QPushButton:hover{"
114 " background-color: rgb(250, 250, 250);"
115 " border: 0px;"
116 " }"
117
118 "QPushButton:checked{"
119 " background-color: white;"
120 " border: 0px;"
121 "}"
122 );
123
124 ui->accountSettingsButton->setStyleSheet(styleS);
125 ui->generalSettingsButton->setStyleSheet(styleS);
126 ui->avSettingsButton->setStyleSheet(styleS);
127
128 ui->advancedAccountSettingsPButton->setIcon(QPixmap(":/images/icons/round-arrow_drop_down-24px.svg"));
129 ui->linkDevPushButton->setIcon(QPixmap(":/images/icons/round-add-24px.svg"));
130 ui->blockedContactsBtn->setIcon(QPixmap(":/images/icons/round-arrow_drop_up-24px.svg"));
131
132 ui->advancedSettingsOffsetLabel->show();
133
Andreas Traczykfc33a492018-12-14 13:53:13 -0500134 auto accountList = LRCInstance::accountModel().getAccountList();
135 if (!accountList.size()) {
136 QMetaObject::Connection* toDisconnect = &accountAddedConnection_;
137 accountAddedConnection_ = connect(&LRCInstance::accountModel(),
138 &lrc::api::NewAccountModel::accountAdded,
139 [this, toDisconnect](const std::string& accountId) {
140 setConnections();
141 QObject::disconnect(*toDisconnect);
142 });
143 } else {
144 setConnections();
145 }
146
147 ui->containerWidget->setVisible(false);
148}
149
150void
151SettingsWidget::navigated(bool to)
152{
153 ui->containerWidget->setVisible(to);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500154}
155
156void
157SettingsWidget::leaveSettingsSlot()
158{
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500159 if (advancedSettingsDropped_) {
160 toggleAdvancedSettings();
161 }
162
Isa Nanic054ef9a2018-12-11 11:56:28 -0500163 Video::PreviewManager::instance().stopPreview();
164 saveSizeIndex();
165
166 emit NavigationRequested(ScreenEnum::CallScreen);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500167}
168
169SettingsWidget::~SettingsWidget()
170{
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500171 delete ui;
172}
173
174// called at every callwidget -> settingsWidget navigation
175void
176SettingsWidget::updateSettings(int size)
177{
178 setSelected(Button::accountSettingsButton);
179 resize(size);
180 updateAccountInfoDisplayed();
181}
182
183void
184SettingsWidget::resize(int size)
185{
186 ui->rightSettingsWidget->setGeometry(size, 0, this->width() - size, this->height());
187 ui->accountSettingsButton->setFixedWidth(size);
188}
189
190void
191SettingsWidget::setSelected(Button sel)
192{
Isa Nanic054ef9a2018-12-11 11:56:28 -0500193 saveSizeIndex();
194
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500195 switch (sel)
196 {
197 case Button::accountSettingsButton:
Isa Nanic054ef9a2018-12-11 11:56:28 -0500198 Video::PreviewManager::instance().stopPreview();
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500199
Isa Nanic054ef9a2018-12-11 11:56:28 -0500200 if (advancedSettingsDropped_) { toggleAdvancedSettings(); }
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500201 ui->stackedWidget->setCurrentWidget(ui->currentAccountSettingsScrollWidget);
202 if (pastButton_ == Button::generalSettingsButton) {
203 ui->accountSettingsButton->setChecked(true);
204 ui->generalSettingsButton->setChecked(false);
205 break;
206 }
207 else {
208 ui->accountSettingsButton->setChecked(true);
209 ui->avSettingsButton->setChecked(false);
210 break;
211 }
212 case Button::generalSettingsButton:
Isa Nanic054ef9a2018-12-11 11:56:28 -0500213 Video::PreviewManager::instance().stopPreview();
214
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500215 ui->stackedWidget->setCurrentWidget(ui->generalSettings);
216 populateGeneralSettings();
217 if (pastButton_ == Button::avSettingsButton) {
218 ui->generalSettingsButton->setChecked(true);
219 ui->avSettingsButton->setChecked(false);
220 break;
221 }
222 else {
223 ui->generalSettingsButton->setChecked(true);
224 ui->accountSettingsButton->setChecked(false);
225 break;
226 }
227 case Button::avSettingsButton:
228 ui->stackedWidget->setCurrentWidget(ui->avSettings);
Isa Nanic054ef9a2018-12-11 11:56:28 -0500229 populateAVSettings();
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500230 if (pastButton_ == Button::accountSettingsButton) {
231 ui->avSettingsButton->setChecked(true);
232 ui->accountSettingsButton->setChecked(false);
233 break;
234 }
235 else {
236 ui->avSettingsButton->setChecked(true);
237 ui->generalSettingsButton->setChecked(false);
238 break;
239 }
240 }
241 pastButton_ = sel;
242}
243
244// called to update current settings information when navigating to settingsWidget
245void
246SettingsWidget::updateAccountInfoDisplayed()
247{
248 ui->currentRegisteredID->setText(QString::fromStdString(LRCInstance::getCurrentAccountInfo().registeredName));
249 ui->currentRingID->setText(QString::fromStdString(LRCInstance::getCurrentAccountInfo().profileInfo.uri));
250
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500251// if no registered name is found for account
252 if (LRCInstance::getCurrentAccountInfo().registeredName.empty()) {
253 ui->currentRegisteredID->setReadOnly(false);
254 }
255 else {
256 ui->currentRegisteredID->setReadOnly(true);
257 setRegNameUi(RegName::BLANK);
258 }
259
260 ui->currentAccountAvatar->setIcon(LRCInstance::getCurrAccPixmap().
261 scaledToHeight(avatarSize_, Qt::SmoothTransformation));
262
263 ui->accountEnableCheckBox->setChecked(LRCInstance::getCurrentAccountInfo().enabled);
264
265 ui->displayNameLineEdit->setText(QString::fromStdString(LRCInstance::getCurrentAccountInfo().profileInfo.alias));
266
267 updateAndShowDevicesSlot();
Isa Nanic3a9c6e22018-12-11 17:07:20 -0500268 bannedContactsShown_ = false;
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500269 if (!LRCInstance::getCurrentAccountInfo().contactModel->getBannedContacts().size()){
270 ui->blockedContactsBtn->hide();
271 } else {
272 ui->blockedContactsBtn->show();
273 }
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500274}
275
276void
277SettingsWidget::passwordClicked()
278{
279 PasswordDialog passwdDialog(this);
280 passwdDialog.exec();
281}
282
283void
284SettingsWidget::toggleAdvancedSettings()
285{
286 if (advancedSettingsDropped_) {
287 ui->advancedAccountSettingsPButton->setIcon(QPixmap(":/images/icons/round-arrow_drop_down-24px.svg"));
288 ui->currentAccountSettingsScrollLayout->removeWidget(advancedSettingsWidget_);
289 ui->scrollBarLabel->show();
290 ui->advancedSettingsOffsetLabel->hide();
291 delete advancedSettingsWidget_;
292 }
293 else { // will show advanced settings next
294 ui->advancedAccountSettingsPButton->setIcon(QPixmap(":/images/icons/round-arrow_drop_up-24px.svg"));
Andreas Traczykb81281e2018-12-13 13:13:28 -0500295 advancedSettingsWidget_ = new AdvancedSettingsWidget(this);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500296 advancedSettingsWidget_->setMaximumWidth(ui->scrollAreaWidgetContents->width() - 10);
297 ui->currentAccountSettingsScrollLayout->addWidget(advancedSettingsWidget_);
298 ui->advancedSettingsOffsetLabel->show();
299 ui->scrollBarLabel->hide();
300 }
301 advancedSettingsDropped_ = !advancedSettingsDropped_;
302}
303
304void
305SettingsWidget::toggleBannedContacts()
306{
307 if (bannedContactsShown_) { // will show linked devices next
Isa Nanic3a9c6e22018-12-11 17:07:20 -0500308 bannedContactsShown_ = false;
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500309 updateAndShowDevicesSlot();
310 }
311 else { // will show banned contacts next
Isa Nanic3a9c6e22018-12-11 17:07:20 -0500312 bannedContactsShown_ = true;
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500313 updateAndShowBannedContactsSlot();
314 }
315}
316
317void
318SettingsWidget::resizeEvent(QResizeEvent* event)
319{
320 QWidget::resizeEvent(event);
321 scrollArea_->resize(ui->currentAccountSettingsScrollWidget->width(), this->height());
322}
323
324void
325SettingsWidget::avatarClicked()
326{
327 SetAvatarDialog avatarDialog(this);
328
329 // return new avatar pixmap from setAvatarDialog
330 connect(&avatarDialog, &SetAvatarDialog::pixmapSignal, [&](const std::string& pixString) {
331 if (!pixString.empty()) {
332 LRCInstance::setCurrAccAvatar(pixString);
333 updateAccountInfoDisplayed();
334 }
335 }
336 );
337 avatarDialog.exec();
338}
339
340void
341SettingsWidget::verifyRegisteredNameSlot()
342{
343 if (!LRCInstance::getCurrentAccountInfo().registeredName.empty()) {
344 setRegNameUi(RegName::BLANK);
345 }
346 else {
347 registeredName_ = ui->currentRegisteredID->text().simplified();
348
349 if (!registeredName_.isEmpty()) {
350 if (validateRegNameForm(registeredName_)) { // name has valid form
351 setRegNameUi(RegName::SEARCHING);
352 QTimer::singleShot(300, this, SLOT(beforeNameLookup()));
353 } else { // name does not have valid form
354 setRegNameUi(RegName::INVALIDFORM);
355 }
356 } else {
357 setRegNameUi(RegName::BLANK);
358 }
359 }
360}
361
362// returns true if name is valid registered name
363bool
364SettingsWidget::validateRegNameForm(const QString& regName)
365{
366 QRegularExpression regExp(" ");
367 if (regName.size() > 2 && !regName.contains(regExp)) {
368 return true;
Isa Nanic26c86612018-12-14 12:21:56 -0500369 } else {
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500370 return false;
371 }
372}
373
374void
375SettingsWidget::receiveRegNameSlot(const std::string& accountID,
376 lrc::api::account::LookupStatus status, const std::string& address, const std::string& name)
377{
378 Q_UNUSED(accountID); Q_UNUSED(address);
379 afterNameLookup(status, name);
380}
381
382void
383SettingsWidget::beforeNameLookup()
384{
385 NameDirectory::instance().lookupName(nullptr, QString(), registeredName_);
386}
387
388void
389SettingsWidget::afterNameLookup(lrc::api::account::LookupStatus status, const std::string& regName)
390{
391 if (registeredName_.toStdString() == regName && regName.length() > 2) {
392 if (status == lrc::api::account::LookupStatus::NOT_FOUND) {
393 setRegNameUi(RegName::FREE);
394 }
395 else {
396 setRegNameUi(RegName::TAKEN);
397 }
398 }
399 else {
400 setRegNameUi(RegName::BLANK);
401 }
402}
403
404void SettingsWidget::setRegNameUi(RegName stat)
405{
406 disconnect(gif, SIGNAL(frameChanged(int)), this, SLOT(setButtonIconSlot(int)));
407 disconnect(ui->regNameButton, &QPushButton::clicked, this, &SettingsWidget::regNameRegisteredSlot);
408
409 switch (stat) {
410 case RegName::BLANK:
411 ui->currentRegisteredID->setStyleSheet("padding-left: 5px; border: 0px; border-radius: 3px; border: 1px solid rgb(245, 245, 245);");
412 regNameBtn_ = false;
413 ui->currentRegisteredID->setToolTip(tr(""));
414 ui->regNameButton->setIcon(QPixmap());
415 ui->regNameButton->setEnabled(false);
416 break;
417
418 case RegName::INVALIDFORM:
419 ui->currentRegisteredID->setStyleSheet("padding-left: 5px; border: 1px solid red; border-radius: 3px;");
420 regNameBtn_ = false;
421 ui->currentRegisteredID->setToolTip(tr("A registered name should not have any spaces and must be at least three letters long"));
422 ui->regNameButton->setIcon(QPixmap(":/images/icons/round-error-24px.svg"));
423 ui->regNameButton->setToolTip(tr("A registered name should not have any spaces and must be at least three letters long"));
424 ui->regNameButton->setEnabled(true);
425 break;
426
427 case RegName::TAKEN:
428 ui->currentRegisteredID->setStyleSheet("padding-left: 5px; border: 1px solid orange; border-radius: 3px;");
429 regNameBtn_ = false;
430 ui->currentRegisteredID->setToolTip(tr("This name is already taken"));
431 ui->regNameButton->setIcon(QPixmap(":/images/icons/round-error-24px.svg"));
432 ui->regNameButton->setToolTip(tr("This registered name is already taken"));
433 ui->regNameButton->setEnabled(true);
434 break;
435
436 case RegName::FREE:
437 ui->currentRegisteredID->setStyleSheet("padding-left: 5px; border: 1px solid green; border-radius: 3px;");
438 regNameBtn_ = true;
439 ui->currentRegisteredID->setToolTip(tr("This name is available"));
440 ui->regNameButton->setIcon(QPixmap(":/images/icons/round-check_circle-24px.svg"));
441 ui->regNameButton->setToolTip(tr("Register this name"));
442 ui->regNameButton->setEnabled(true);
443
444 connect(ui->regNameButton, &QPushButton::clicked, this, &SettingsWidget::regNameRegisteredSlot);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500445 break;
446
447 case RegName::SEARCHING:
448 ui->currentRegisteredID->setStyleSheet("padding-left: 5px; border: 1px solid rgb(2, 187, 213); border-radius: 3px;");
449 regNameBtn_ = false;
450 ui->currentRegisteredID->setToolTip(tr(""));
451
452 connect(gif, SIGNAL(frameChanged(int)), this, SLOT(setButtonIconSlot(int)));
453 gif->start();
454 ui->regNameButton->setEnabled(false);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500455 break;
456 }
457}
Isa Nanic26c86612018-12-14 12:21:56 -0500458
459void
460SettingsWidget::setButtonIconSlot(int frame)
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500461{
462 Q_UNUSED(frame);
463 ui->regNameButton->setIcon(QIcon(gif->currentPixmap()));
464}
465
466void
467SettingsWidget::regNameRegisteredSlot()
468{
469 if (!regNameBtn_) { return; }
470
471 RegNameDialog regNameDialog(registeredName_, this);
Isa Nanic26c86612018-12-14 12:21:56 -0500472 if (regNameDialog.exec() == QDialog::Accepted) {
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500473 ui->currentRegisteredID->setReadOnly(true);
Isa Nanic26c86612018-12-14 12:21:56 -0500474 ui->currentRegisteredID->setText(registeredName_);
475
476 lrc::api::account::ConfProperties_t accountProperties = LRCInstance::accountModel().getAccountConfig(LRCInstance::getCurrAccId());
477 LRCInstance::accountModel().setAccountConfig(LRCInstance::getCurrAccId(), accountProperties);
478 } else {
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500479 ui->currentRegisteredID->setText("");
480 registeredName_ = "";
481 }
482 setRegNameUi(RegName::BLANK);
483}
484
485void
486SettingsWidget::setAccEnableSlot(int state)
487{
488 LRCInstance::editableAccountModel()->enableAccount(LRCInstance::getCurrAccId(), (bool)state);
489
490 auto confProps = LRCInstance::accountModel().getAccountConfig(LRCInstance::getCurrAccId());
491 LRCInstance::editableAccountModel()->setAccountConfig(LRCInstance::getCurrAccId(), confProps);
492}
493
494void
495SettingsWidget::delAccountSlot()
496{
497 DeleteAccountDialog delDialog(this);
498 delDialog.exec();
499
500 if (!LRCInstance::accountModel().getAccountList().size()) {
Andreas Traczyk9b1b7d42018-12-13 14:44:24 -0500501 LRCInstance::setSelectedAccountId("");
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500502 emit NavigationRequested(ScreenEnum::WizardScreen);
503 }
504}
505
506void
507SettingsWidget::removeDeviceSlot(int index)
508{
509 if (!index) { return; }
510
511 auto deviceList = LRCInstance::getCurrentAccountInfo().deviceModel->getAllDevices();
512 auto it = deviceList.begin();
513
514 std::advance(it, index);
515 QString psswd;
516
517 bool ok = false;
518 if (LRCInstance::getCurrAccConfig().archiveHasPassword) {
519 psswd = QInputDialog::getText(this, tr("Remove Device"),
Isa Nanic100368f2018-12-11 16:43:01 -0500520 tr("Enter this account's password to confirm the removal of this device"), QLineEdit::Password,
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500521 QDir::home().dirName(), &ok);
522 }
523 else {
524 psswd = "";
525 QMessageBox devDel;
526 devDel.setText(tr("Please confirm that you wish to remove this device"));
527 devDel.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
528 devDel.setDefaultButton(QMessageBox::Cancel);
529 if (devDel.exec() == QMessageBox::Ok) { goto delete_; }
530 }
531
532 if (ok) {
533 delete_:
534 LRCInstance::getCurrentAccountInfo().deviceModel->revokeDevice(it->id, psswd.toStdString());
535 updateAndShowDevicesSlot();
536 }
537}
538
539void
540SettingsWidget::unban(int index)
541{
542 auto bannedContactList = LRCInstance::getCurrentAccountInfo().contactModel->getBannedContacts();
543 auto it = bannedContactList.begin();
544 std::advance(it, index);
545
546 auto contactInfo = LRCInstance::getCurrentAccountInfo().contactModel->getContact(*it);
547
548 LRCInstance::getCurrentAccountInfo().contactModel->addContact(contactInfo);
549 updateAndShowBannedContactsSlot();
550}
551
552void
553SettingsWidget::exportAccountSlot()
554{
555 QFileDialog dialog(this);
556 QString dir = QFileDialog::getExistingDirectory(this, tr("Export Account Here"),
557 QDir::homePath() + "/Desktop", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
558
559 if (!dir.isEmpty()) {
560 LRCInstance::accountModel().exportToFile(LRCInstance::getCurrAccId(), (dir + "/export.gz").toStdString());
561 }
562}
563
564void
565SettingsWidget::updateAndShowDevicesSlot()
566{
567 ui->settingsListWidget->clear();
568
569 ui->label->setText(tr("Linked Devices"));
570 ui->blockedContactsBtn->setText(tr("Blocked Contacts"));
571 ui->linkDevPushButton->show();
572
573 auto deviceList = LRCInstance::getCurrentAccountInfo().deviceModel->getAllDevices();
574
575 int i = 0;
576
577 for (auto it = deviceList.begin(); it != deviceList.end(); ++it, ++i) {
578 SettingsItemWidget* item = new SettingsItemWidget(itemHeight_, i, false, ui->settingsListWidget);
579 item->setSizeHint(QSize(ui->settingsListWidget->width(), itemHeight_));
580 ui->settingsListWidget->addItem(item);
581
582 if (i) {
583 connect(item->button_, &QPushButton::clicked, [this, i]() {
584 removeDeviceSlot(i);
585 }
586 );
587 }
588 }
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500589}
590
591void
592SettingsWidget::updateAndShowBannedContactsSlot()
593{
Isa Nanic3a9c6e22018-12-11 17:07:20 -0500594 if (bannedContactsShown_) {
595 ui->settingsListWidget->clear();
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500596
Isa Nanic3a9c6e22018-12-11 17:07:20 -0500597 ui->label->setText(tr("Blocked Contacts"));
598 ui->blockedContactsBtn->setText(tr("Linked Devices"));
599 ui->linkDevPushButton->hide();
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500600
Isa Nanic3a9c6e22018-12-11 17:07:20 -0500601 auto bannedContactList = LRCInstance::getCurrentAccountInfo().contactModel->getBannedContacts();
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500602
Isa Nanic3a9c6e22018-12-11 17:07:20 -0500603 int i = 0;
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500604
Isa Nanic3a9c6e22018-12-11 17:07:20 -0500605 for (auto it = bannedContactList.begin(); it != bannedContactList.end(); ++it, ++i) {
606 SettingsItemWidget* item = new SettingsItemWidget(itemHeight_, i, true, ui->settingsListWidget);
607 item->setSizeHint(QSize(ui->settingsListWidget->width(), itemHeight_));
608 ui->settingsListWidget->addItem(item);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500609
Isa Nanic3a9c6e22018-12-11 17:07:20 -0500610 connect(item->button_, &QPushButton::clicked, [this, i]() {
611 unban(i);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500612 }
Isa Nanic3a9c6e22018-12-11 17:07:20 -0500613 );
614 }
615 if (!bannedContactList.size()) { updateAndShowDevicesSlot(); ui->blockedContactsBtn->hide(); }
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500616 }
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500617}
618
619void
620SettingsWidget::showLinkDevSlot()
621{
622 if (!advancedSettingsWidget_) { delete advancedSettingsWidget_; }
623
624 linkDevWidget = new LinkDevWidget(ui->scrollAreaWidgetContents);
625 linkDevWidget->setMinimumWidth(600);
626
627 ui->accountHorLayout->insertWidget(1, linkDevWidget);
628
629 linkDevWidget->show();
630 ui->centralWidget->hide();
631
632 connect(linkDevWidget->cancelBtn(), &QPushButton::clicked, this, &SettingsWidget::showCurrentAccountSlot);
633 connect(linkDevWidget->endCancelBtn(), &QPushButton::clicked, this, &SettingsWidget::showCurrentAccountSlot);
634}
635
636void
637SettingsWidget::showCurrentAccountSlot()
638{
639 disconnect(linkDevWidget);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500640 delete linkDevWidget;
Isa Nanic5bafcb92018-12-19 12:54:51 -0500641
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500642 ui->centralWidget->show();
Isa Nanic5bafcb92018-12-19 12:54:51 -0500643 updateAndShowDevicesSlot();
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500644}
645
646void
647SettingsWidget::setConnections()
648{
649 // exitSettingsButton
650 connect(ui->exitSettingsButton, &QPushButton::clicked, this, &SettingsWidget::leaveSettingsSlot);
651
652 connect(ui->accountSettingsButton, &QPushButton::clicked, [this]() {
653 setSelected(Button::accountSettingsButton); }
654 );
655
656 connect(ui->generalSettingsButton, &QPushButton::clicked, [this]() {
657 setSelected(Button::generalSettingsButton); }
658 );
659
660 connect(ui->avSettingsButton, &QPushButton::clicked, [this]() {
661 setSelected(Button::avSettingsButton); }
662 );
663
664 connect(ui->passwdPushButton, &QPushButton::clicked, [this]() {
665 passwordClicked(); }
666 );
667
668 connect(ui->currentAccountAvatar, &QPushButton::clicked, [this]() {
669 avatarClicked(); }
670 );
671
672 connect(ui->advancedAccountSettingsPButton, &QPushButton::clicked, this, &SettingsWidget::toggleAdvancedSettings);
673
674 connect(ui->currentRegisteredID, &QLineEdit::textChanged, this, &SettingsWidget::verifyRegisteredNameSlot);
675
676 connect(&LRCInstance::accountModel(), &lrc::api::NewAccountModel::registeredNameFound,
677 this, &SettingsWidget::receiveRegNameSlot);
678
679 //connect "export account" button
680 connect(ui->btnExportAccount, &QPushButton::clicked, this, &SettingsWidget::exportAccountSlot);
681
682 // connect "delete account" button
683 connect(ui->btnDeletAccount, &QPushButton::clicked, this, &SettingsWidget::delAccountSlot);
684
685 // connect "banned contacts" button
686 connect(ui->blockedContactsBtn, &QPushButton::clicked, this, &SettingsWidget::toggleBannedContacts);
687
688 // connect "link device" button
689 connect(ui->linkDevPushButton, &QPushButton::clicked, this, &SettingsWidget::showLinkDevSlot);
690
691 // update banned accounts automatically
692 connect(LRCInstance::getCurrentAccountInfo().contactModel.get(), &lrc::api::ContactModel::modelUpdated,
693 this, &SettingsWidget::updateAndShowBannedContactsSlot);
694
695 // update linked devices automatically
696 QObject::connect(LRCInstance::getCurrentAccountInfo().deviceModel.get(), &lrc::api::NewDeviceModel::deviceUpdated,
697 this, &SettingsWidget::updateAndShowDevicesSlot);
698
699 // account settings setters {
Isa Nanic26c86612018-12-14 12:21:56 -0500700 connect(ui->accountEnableCheckBox, &QCheckBox::clicked, this, &SettingsWidget::setAccEnableSlot);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500701
702 connect(ui->displayNameLineEdit, &QLineEdit::textChanged, [this](const QString& displayName) {
703 LRCInstance::setCurrAccDisplayName(displayName.toStdString());
704 }
705 );
706
707 // general settings
708
Isa Nanic100368f2018-12-11 16:43:01 -0500709 connect(ui->notificationCheckBox, &QAbstractButton::clicked, this, &SettingsWidget::setNotificationsSlot);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500710
Isa Nanic100368f2018-12-11 16:43:01 -0500711 connect(ui->closeOrMinCheckBox, &QAbstractButton::clicked, this, &SettingsWidget::setClosedOrMinSlot);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500712
Isa Nanic100368f2018-12-11 16:43:01 -0500713 connect(ui->downloadButton, &QAbstractButton::clicked, this, &SettingsWidget::openDownloadFolderSlot);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500714
Isa Nanic100368f2018-12-11 16:43:01 -0500715 connect(ui->alwaysRecordingCheckBox, &QAbstractButton::clicked, this, &SettingsWidget::setAlwaysRecordingSlot);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500716
Isa Nanic100368f2018-12-11 16:43:01 -0500717 connect(ui->checkUpdateButton, &QAbstractButton::clicked, this, &SettingsWidget::checkForUpdateSlot);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500718
719 connect(ui->intervalUpdateCheckSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), this, &SettingsWidget::setUpdateIntervalSlot);
720
Isa Nanic100368f2018-12-11 16:43:01 -0500721 connect(ui->autoUpdateCheckBox, &QAbstractButton::clicked, this, &SettingsWidget::setUpdateAutomaticSlot);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500722
723 // audio / visual settings
724
725 connect(ui->recordPathButton, &QPushButton::clicked, this, &SettingsWidget::openRecordFolderSlot);
726}
727
728
729// ************************* General Settings *************************
730
731void SettingsWidget::populateGeneralSettings()
732{
Isa Nanic5bafcb92018-12-19 12:54:51 -0500733 QSettings settings;
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500734
735 // settings
Isa Nanic5bafcb92018-12-19 12:54:51 -0500736 ui->downloadButton->setText(QString::fromStdString(LRCInstance::dataTransferModel().downloadDirectory));
737 ui->closeOrMinCheckBox->setChecked(settings.value(SettingsKey::closeOrMinimized).toBool());
738 ui->notificationCheckBox->setChecked(settings.value(SettingsKey::enableNotifications).toBool());
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500739
740 //recordings
741 ui->alwaysRecordingCheckBox->setChecked(media::RecordingModel::instance().isAlwaysRecording());
742
743 if (media::RecordingModel::instance().recordPath().isEmpty()) {
744 QString recordPath = QDir::toNativeSeparators(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation));
745 media::RecordingModel::instance().setRecordPath(recordPath);
746 }
747 ui->recordPathButton->setText(media::RecordingModel::instance().recordPath());
748
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500749 ui->autoUpdateCheckBox->setChecked(win_sparkle_get_automatic_check_for_updates());
750 ui->intervalUpdateCheckSpinBox->setValue(win_sparkle_get_update_check_interval() / 86400);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500751}
752
753void
754SettingsWidget::setNotificationsSlot(int state)
755{
Isa Nanic5bafcb92018-12-19 12:54:51 -0500756 QSettings settings;
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500757 if (state == Qt::CheckState::Unchecked) {
Isa Nanic5bafcb92018-12-19 12:54:51 -0500758 settings.setValue(SettingsKey::enableNotifications, false);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500759 } else {
Isa Nanic5bafcb92018-12-19 12:54:51 -0500760 settings.setValue(SettingsKey::enableNotifications, true);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500761 }
762}
763
764void
765SettingsWidget::setClosedOrMinSlot(int state)
766{
Isa Nanic5bafcb92018-12-19 12:54:51 -0500767 QSettings settings;
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500768 if (state == Qt::CheckState::Unchecked) {
Isa Nanic5bafcb92018-12-19 12:54:51 -0500769 settings.setValue(SettingsKey::closeOrMinimized, false);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500770 }
771 else {
Isa Nanic5bafcb92018-12-19 12:54:51 -0500772 settings.setValue(SettingsKey::closeOrMinimized, true);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500773 }
774}
775
776void
777SettingsWidget::checkForUpdateSlot()
778{
779 win_sparkle_check_update_with_ui();
780}
781
782void
783SettingsWidget::setUpdateIntervalSlot(int value)
784{
785 win_sparkle_set_update_check_interval(value * 86400);
786}
787
788void
789SettingsWidget::setUpdateAutomaticSlot(int state)
790{
791 if (state == Qt::CheckState::Unchecked) {
792 win_sparkle_set_automatic_check_for_updates(false);
793 ui->intervalUpdateCheckSpinBox->setEnabled(false);
794 } else {
795 win_sparkle_set_automatic_check_for_updates(true);
796 ui->intervalUpdateCheckSpinBox->setEnabled(true);
797 }
798}
799
800void
801SettingsWidget::openDownloadFolderSlot()
802{
Isa Nanic5bafcb92018-12-19 12:54:51 -0500803 QSettings settings;
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500804 QString dir = QFileDialog::getExistingDirectory(this, tr("Select A Folder For Your Downloads"),
805 QStandardPaths::writableLocation(QStandardPaths::DownloadLocation), QFileDialog::ShowDirsOnly
806 | QFileDialog::DontResolveSymlinks);
807
808 if (!dir.isEmpty()) {
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500809 ui->downloadButton->setText(dir);
Isa Nanic5bafcb92018-12-19 12:54:51 -0500810 settings.setValue(SettingsKey::downloadPath, dir);
Isa Nanic7a3dfa42018-12-12 12:34:42 -0500811 LRCInstance::editableDataTransferModel()->downloadDirectory = dir.toStdString() + "/";
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500812 }
813}
814
815void
816SettingsWidget::setAlwaysRecordingSlot(int state)
817{
818 if (state == Qt::CheckState::Unchecked) {
819 media::RecordingModel::instance().setAlwaysRecording(false);
820 } else {
821 media::RecordingModel::instance().setAlwaysRecording(true);
822 }
823}
824
825void
826SettingsWidget::openRecordFolderSlot()
827{
828 QString dir = QFileDialog::getExistingDirectory(this, tr("Select A Folder For Your Recordings"),
829 media::RecordingModel::instance().recordPath(), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
830
831 if (!dir.isEmpty()) {
832 media::RecordingModel::instance().setRecordPath(dir);
833 ui->recordPathButton->setText(media::RecordingModel::instance().recordPath());
834 }
835}
836
837
838// ************************* Audio/Visual Settings *************************
839
840void
841SettingsWidget::populateAVSettings()
842{
843 ui->deviceBox->setModel(deviceModel_);
844 connect(deviceModel_, SIGNAL(currentIndexChanged(int)),
845 this, SLOT(deviceIndexChanged(int)));
846
Isa Nanic9316d472018-12-18 16:27:13 -0500847 // Audio settings
848 auto inputModel = Audio::Settings::instance().inputDeviceModel();
849 auto outputModel = Audio::Settings::instance().outputDeviceModel();
850
851 ui->inputComboBox->setModel(inputModel);
852 ui->outputComboBox->setModel(outputModel);
853
854 auto inputIndex = inputModel->selectionModel()->currentIndex();
855 auto outputIndex = outputModel->selectionModel()->currentIndex();
856
857 ui->inputComboBox->setCurrentIndex(inputIndex.row());
858 ui->outputComboBox->setCurrentIndex(outputIndex.row());
859
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500860 if (ui->deviceBox->count() > 0) {
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500861 deviceBoxCurrentIndexChangedSlot(0);
862 }
863
Isa Nanic054ef9a2018-12-11 11:56:28 -0500864 if (currentResIndex >= 0) {
865 ui->sizeBox->setCurrentIndex(currentResIndex);
866 }
867
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500868 connect(ui->outputComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
869 this, &SettingsWidget::outputDevIndexChangedSlot);
870 connect(ui->inputComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
871 this, &SettingsWidget::inputdevIndexChangedSlot);
872
873 connect(ui->deviceBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
874 &SettingsWidget::deviceBoxCurrentIndexChangedSlot);
875 connect(ui->sizeBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
876 &SettingsWidget::sizeBoxCurrentIndexChangedSlot);
Isa Nanic9316d472018-12-18 16:27:13 -0500877
878 showPreview();
Isa Nanic054ef9a2018-12-11 11:56:28 -0500879}
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500880
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500881
Isa Nanic054ef9a2018-12-11 11:56:28 -0500882void
883SettingsWidget::saveSizeIndex()
884{
885 currentResIndex = ui->sizeBox->currentIndex();
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500886}
887
888void
889SettingsWidget::showPreview()
890{
891 if (!CallModel::instance().getActiveCalls().size()) {
892 ui->previewUnavailableLabel->hide();
893 ui->videoWidget->show();
Isa Nanic054ef9a2018-12-11 11:56:28 -0500894 startVideo();
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500895 ui->videoWidget->setIsFullPreview(true);
896 } else {
897 ui->previewUnavailableLabel->show();
898 ui->videoWidget->hide();
899 }
900}
901
902void
903SettingsWidget::deviceBoxCurrentIndexChangedSlot(int index)
904{
905 if (index < 0) {
906 return;
907 }
908
Isa Nanic9316d472018-12-18 16:27:13 -0500909 deviceModel_->setActive(index);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500910
911 auto device = deviceModel_->activeDevice();
912
913 ui->sizeBox->clear();
914
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500915 if (device->channelList().size() > 0) {
916 for (auto resolution : device->channelList()[0]->validResolutions()) {
917 ui->sizeBox->addItem(resolution->name());
918 }
919 }
920 ui->sizeBox->setCurrentIndex(
921 device->channelList()[0]->activeResolution()->relativeIndex());
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500922}
923
924void
925SettingsWidget::sizeBoxCurrentIndexChangedSlot(int index)
926{
Isa Nanic9316d472018-12-18 16:27:13 -0500927 if (index < 0) {
928 return;
929 }
930
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500931 auto device = deviceModel_->activeDevice();
932
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500933 device->channelList()[0]->setActiveResolution(device->channelList()[0]->validResolutions()[index]);
Isa Nanic9316d472018-12-18 16:27:13 -0500934
935 QTimer::singleShot(200, this, [this]() {
936 deviceModel_->setActive(ui->deviceBox->currentIndex());
937 });
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500938}
939
940void
941SettingsWidget::deviceIndexChanged(int index)
942{
943 ui->deviceBox->setCurrentIndex(index);
944
945 ui->videoLayout->update();
946}
947
948void
949SettingsWidget::outputDevIndexChangedSlot(int index)
950{
951 auto outputModel = Audio::Settings::instance().outputDeviceModel();
952 outputModel->selectionModel()->setCurrentIndex(outputModel->index(index), QItemSelectionModel::ClearAndSelect);
953}
954
955void
956SettingsWidget::inputdevIndexChangedSlot(int index)
957{
958 auto inputModel = Audio::Settings::instance().inputDeviceModel();
959 inputModel->selectionModel()->setCurrentIndex(inputModel->index(index), QItemSelectionModel::ClearAndSelect);
Isa Nanic054ef9a2018-12-11 11:56:28 -0500960}
961
962void
963SettingsWidget::startVideo()
964{
965 Video::PreviewManager::instance().stopPreview();
966 Video::PreviewManager::instance().startPreview();
967}
968
969void
970SettingsWidget::stopVideo()
971{
972 Video::PreviewManager::instance().stopPreview();
Isa Nanic26c86612018-12-14 12:21:56 -0500973}