blob: 2a149c2d66f36b392ea3510f0fed97ee2af0ec9d [file] [log] [blame]
Isa Nanic6e4a39a2018-12-04 14:26:02 -05001/***************************************************************************
Sébastien Blin68abac92019-01-02 17:41:31 -05002 * Copyright (C) 2019-2019 by Savoir-faire Linux *
Isa Nanic6e4a39a2018-12-04 14:26:02 -05003 * Author: Isa Nanic <isa.nanic@savoirfairelinux.com> *
4 * Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>*
Sébastien Blin68abac92019-01-02 17:41:31 -05005 * Author: Anthony L�onard <anthony.leonard@savoirfairelinux.com> *
Isa Nanic6e4a39a2018-12-04 14:26:02 -05006 * 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) {
Andreas Traczyk14c3e862018-12-26 14:02:30 -0500140 Q_UNUSED(accountId);
Andreas Traczykfc33a492018-12-14 13:53:13 -0500141 setConnections();
142 QObject::disconnect(*toDisconnect);
143 });
144 } else {
145 setConnections();
146 }
147
148 ui->containerWidget->setVisible(false);
149}
150
151void
152SettingsWidget::navigated(bool to)
153{
154 ui->containerWidget->setVisible(to);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500155}
156
Andreas Traczyk6ace34f2018-12-14 14:31:23 -0500157void SettingsWidget::updateCustomUI()
158{
159}
160
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500161void
162SettingsWidget::leaveSettingsSlot()
163{
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500164 if (advancedSettingsDropped_) {
165 toggleAdvancedSettings();
166 }
167
Isa Nanic054ef9a2018-12-11 11:56:28 -0500168 Video::PreviewManager::instance().stopPreview();
169 saveSizeIndex();
170
171 emit NavigationRequested(ScreenEnum::CallScreen);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500172}
173
174SettingsWidget::~SettingsWidget()
175{
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500176 delete ui;
177}
178
179// called at every callwidget -> settingsWidget navigation
180void
181SettingsWidget::updateSettings(int size)
182{
183 setSelected(Button::accountSettingsButton);
184 resize(size);
185 updateAccountInfoDisplayed();
186}
187
188void
189SettingsWidget::resize(int size)
190{
191 ui->rightSettingsWidget->setGeometry(size, 0, this->width() - size, this->height());
192 ui->accountSettingsButton->setFixedWidth(size);
193}
194
195void
196SettingsWidget::setSelected(Button sel)
197{
Isa Nanic054ef9a2018-12-11 11:56:28 -0500198 saveSizeIndex();
199
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500200 switch (sel)
201 {
202 case Button::accountSettingsButton:
Isa Nanic054ef9a2018-12-11 11:56:28 -0500203 Video::PreviewManager::instance().stopPreview();
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500204
Isa Nanic054ef9a2018-12-11 11:56:28 -0500205 if (advancedSettingsDropped_) { toggleAdvancedSettings(); }
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500206 ui->stackedWidget->setCurrentWidget(ui->currentAccountSettingsScrollWidget);
207 if (pastButton_ == Button::generalSettingsButton) {
208 ui->accountSettingsButton->setChecked(true);
209 ui->generalSettingsButton->setChecked(false);
210 break;
211 }
212 else {
213 ui->accountSettingsButton->setChecked(true);
214 ui->avSettingsButton->setChecked(false);
215 break;
216 }
217 case Button::generalSettingsButton:
Isa Nanic054ef9a2018-12-11 11:56:28 -0500218 Video::PreviewManager::instance().stopPreview();
219
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500220 ui->stackedWidget->setCurrentWidget(ui->generalSettings);
221 populateGeneralSettings();
222 if (pastButton_ == Button::avSettingsButton) {
223 ui->generalSettingsButton->setChecked(true);
224 ui->avSettingsButton->setChecked(false);
225 break;
226 }
227 else {
228 ui->generalSettingsButton->setChecked(true);
229 ui->accountSettingsButton->setChecked(false);
230 break;
231 }
232 case Button::avSettingsButton:
233 ui->stackedWidget->setCurrentWidget(ui->avSettings);
Isa Nanic054ef9a2018-12-11 11:56:28 -0500234 populateAVSettings();
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500235 if (pastButton_ == Button::accountSettingsButton) {
236 ui->avSettingsButton->setChecked(true);
237 ui->accountSettingsButton->setChecked(false);
238 break;
239 }
240 else {
241 ui->avSettingsButton->setChecked(true);
242 ui->generalSettingsButton->setChecked(false);
243 break;
244 }
245 }
246 pastButton_ = sel;
247}
248
249// called to update current settings information when navigating to settingsWidget
250void
251SettingsWidget::updateAccountInfoDisplayed()
252{
253 ui->currentRegisteredID->setText(QString::fromStdString(LRCInstance::getCurrentAccountInfo().registeredName));
254 ui->currentRingID->setText(QString::fromStdString(LRCInstance::getCurrentAccountInfo().profileInfo.uri));
255
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500256// if no registered name is found for account
257 if (LRCInstance::getCurrentAccountInfo().registeredName.empty()) {
258 ui->currentRegisteredID->setReadOnly(false);
259 }
260 else {
261 ui->currentRegisteredID->setReadOnly(true);
262 setRegNameUi(RegName::BLANK);
263 }
264
265 ui->currentAccountAvatar->setIcon(LRCInstance::getCurrAccPixmap().
266 scaledToHeight(avatarSize_, Qt::SmoothTransformation));
267
268 ui->accountEnableCheckBox->setChecked(LRCInstance::getCurrentAccountInfo().enabled);
269
270 ui->displayNameLineEdit->setText(QString::fromStdString(LRCInstance::getCurrentAccountInfo().profileInfo.alias));
271
272 updateAndShowDevicesSlot();
Isa Nanic3a9c6e22018-12-11 17:07:20 -0500273 bannedContactsShown_ = false;
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500274 if (!LRCInstance::getCurrentAccountInfo().contactModel->getBannedContacts().size()){
275 ui->blockedContactsBtn->hide();
276 } else {
277 ui->blockedContactsBtn->show();
278 }
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500279}
280
281void
282SettingsWidget::passwordClicked()
283{
284 PasswordDialog passwdDialog(this);
285 passwdDialog.exec();
286}
287
288void
289SettingsWidget::toggleAdvancedSettings()
290{
291 if (advancedSettingsDropped_) {
292 ui->advancedAccountSettingsPButton->setIcon(QPixmap(":/images/icons/round-arrow_drop_down-24px.svg"));
293 ui->currentAccountSettingsScrollLayout->removeWidget(advancedSettingsWidget_);
294 ui->scrollBarLabel->show();
295 ui->advancedSettingsOffsetLabel->hide();
296 delete advancedSettingsWidget_;
297 }
298 else { // will show advanced settings next
299 ui->advancedAccountSettingsPButton->setIcon(QPixmap(":/images/icons/round-arrow_drop_up-24px.svg"));
Andreas Traczykb81281e2018-12-13 13:13:28 -0500300 advancedSettingsWidget_ = new AdvancedSettingsWidget(this);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500301 advancedSettingsWidget_->setMaximumWidth(ui->scrollAreaWidgetContents->width() - 10);
302 ui->currentAccountSettingsScrollLayout->addWidget(advancedSettingsWidget_);
303 ui->advancedSettingsOffsetLabel->show();
304 ui->scrollBarLabel->hide();
305 }
306 advancedSettingsDropped_ = !advancedSettingsDropped_;
307}
308
309void
310SettingsWidget::toggleBannedContacts()
311{
312 if (bannedContactsShown_) { // will show linked devices next
Isa Nanic3a9c6e22018-12-11 17:07:20 -0500313 bannedContactsShown_ = false;
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500314 updateAndShowDevicesSlot();
315 }
316 else { // will show banned contacts next
Isa Nanic3a9c6e22018-12-11 17:07:20 -0500317 bannedContactsShown_ = true;
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500318 updateAndShowBannedContactsSlot();
319 }
320}
321
322void
323SettingsWidget::resizeEvent(QResizeEvent* event)
324{
325 QWidget::resizeEvent(event);
326 scrollArea_->resize(ui->currentAccountSettingsScrollWidget->width(), this->height());
327}
328
329void
330SettingsWidget::avatarClicked()
331{
332 SetAvatarDialog avatarDialog(this);
333
334 // return new avatar pixmap from setAvatarDialog
335 connect(&avatarDialog, &SetAvatarDialog::pixmapSignal, [&](const std::string& pixString) {
336 if (!pixString.empty()) {
337 LRCInstance::setCurrAccAvatar(pixString);
338 updateAccountInfoDisplayed();
339 }
340 }
341 );
342 avatarDialog.exec();
343}
344
345void
346SettingsWidget::verifyRegisteredNameSlot()
347{
348 if (!LRCInstance::getCurrentAccountInfo().registeredName.empty()) {
349 setRegNameUi(RegName::BLANK);
350 }
351 else {
352 registeredName_ = ui->currentRegisteredID->text().simplified();
353
354 if (!registeredName_.isEmpty()) {
355 if (validateRegNameForm(registeredName_)) { // name has valid form
356 setRegNameUi(RegName::SEARCHING);
357 QTimer::singleShot(300, this, SLOT(beforeNameLookup()));
358 } else { // name does not have valid form
359 setRegNameUi(RegName::INVALIDFORM);
360 }
361 } else {
362 setRegNameUi(RegName::BLANK);
363 }
364 }
365}
366
367// returns true if name is valid registered name
368bool
369SettingsWidget::validateRegNameForm(const QString& regName)
370{
371 QRegularExpression regExp(" ");
372 if (regName.size() > 2 && !regName.contains(regExp)) {
373 return true;
Isa Nanic26c86612018-12-14 12:21:56 -0500374 } else {
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500375 return false;
376 }
377}
378
379void
380SettingsWidget::receiveRegNameSlot(const std::string& accountID,
381 lrc::api::account::LookupStatus status, const std::string& address, const std::string& name)
382{
383 Q_UNUSED(accountID); Q_UNUSED(address);
384 afterNameLookup(status, name);
385}
386
387void
388SettingsWidget::beforeNameLookup()
389{
390 NameDirectory::instance().lookupName(nullptr, QString(), registeredName_);
391}
392
393void
394SettingsWidget::afterNameLookup(lrc::api::account::LookupStatus status, const std::string& regName)
395{
396 if (registeredName_.toStdString() == regName && regName.length() > 2) {
397 if (status == lrc::api::account::LookupStatus::NOT_FOUND) {
398 setRegNameUi(RegName::FREE);
399 }
400 else {
401 setRegNameUi(RegName::TAKEN);
402 }
403 }
404 else {
405 setRegNameUi(RegName::BLANK);
406 }
407}
408
409void SettingsWidget::setRegNameUi(RegName stat)
410{
411 disconnect(gif, SIGNAL(frameChanged(int)), this, SLOT(setButtonIconSlot(int)));
412 disconnect(ui->regNameButton, &QPushButton::clicked, this, &SettingsWidget::regNameRegisteredSlot);
413
414 switch (stat) {
415 case RegName::BLANK:
416 ui->currentRegisteredID->setStyleSheet("padding-left: 5px; border: 0px; border-radius: 3px; border: 1px solid rgb(245, 245, 245);");
417 regNameBtn_ = false;
418 ui->currentRegisteredID->setToolTip(tr(""));
419 ui->regNameButton->setIcon(QPixmap());
420 ui->regNameButton->setEnabled(false);
421 break;
422
423 case RegName::INVALIDFORM:
424 ui->currentRegisteredID->setStyleSheet("padding-left: 5px; border: 1px solid red; border-radius: 3px;");
425 regNameBtn_ = false;
426 ui->currentRegisteredID->setToolTip(tr("A registered name should not have any spaces and must be at least three letters long"));
427 ui->regNameButton->setIcon(QPixmap(":/images/icons/round-error-24px.svg"));
428 ui->regNameButton->setToolTip(tr("A registered name should not have any spaces and must be at least three letters long"));
429 ui->regNameButton->setEnabled(true);
430 break;
431
432 case RegName::TAKEN:
433 ui->currentRegisteredID->setStyleSheet("padding-left: 5px; border: 1px solid orange; border-radius: 3px;");
434 regNameBtn_ = false;
435 ui->currentRegisteredID->setToolTip(tr("This name is already taken"));
436 ui->regNameButton->setIcon(QPixmap(":/images/icons/round-error-24px.svg"));
437 ui->regNameButton->setToolTip(tr("This registered name is already taken"));
438 ui->regNameButton->setEnabled(true);
439 break;
440
441 case RegName::FREE:
442 ui->currentRegisteredID->setStyleSheet("padding-left: 5px; border: 1px solid green; border-radius: 3px;");
443 regNameBtn_ = true;
444 ui->currentRegisteredID->setToolTip(tr("This name is available"));
445 ui->regNameButton->setIcon(QPixmap(":/images/icons/round-check_circle-24px.svg"));
446 ui->regNameButton->setToolTip(tr("Register this name"));
447 ui->regNameButton->setEnabled(true);
448
449 connect(ui->regNameButton, &QPushButton::clicked, this, &SettingsWidget::regNameRegisteredSlot);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500450 break;
451
452 case RegName::SEARCHING:
453 ui->currentRegisteredID->setStyleSheet("padding-left: 5px; border: 1px solid rgb(2, 187, 213); border-radius: 3px;");
454 regNameBtn_ = false;
455 ui->currentRegisteredID->setToolTip(tr(""));
456
457 connect(gif, SIGNAL(frameChanged(int)), this, SLOT(setButtonIconSlot(int)));
458 gif->start();
459 ui->regNameButton->setEnabled(false);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500460 break;
461 }
462}
Isa Nanic26c86612018-12-14 12:21:56 -0500463
464void
465SettingsWidget::setButtonIconSlot(int frame)
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500466{
467 Q_UNUSED(frame);
468 ui->regNameButton->setIcon(QIcon(gif->currentPixmap()));
469}
470
471void
472SettingsWidget::regNameRegisteredSlot()
473{
474 if (!regNameBtn_) { return; }
475
476 RegNameDialog regNameDialog(registeredName_, this);
Isa Nanic26c86612018-12-14 12:21:56 -0500477 if (regNameDialog.exec() == QDialog::Accepted) {
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500478 ui->currentRegisteredID->setReadOnly(true);
Isa Nanic26c86612018-12-14 12:21:56 -0500479 ui->currentRegisteredID->setText(registeredName_);
480
481 lrc::api::account::ConfProperties_t accountProperties = LRCInstance::accountModel().getAccountConfig(LRCInstance::getCurrAccId());
482 LRCInstance::accountModel().setAccountConfig(LRCInstance::getCurrAccId(), accountProperties);
483 } else {
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500484 ui->currentRegisteredID->setText("");
485 registeredName_ = "";
486 }
487 setRegNameUi(RegName::BLANK);
488}
489
490void
491SettingsWidget::setAccEnableSlot(int state)
492{
493 LRCInstance::editableAccountModel()->enableAccount(LRCInstance::getCurrAccId(), (bool)state);
494
495 auto confProps = LRCInstance::accountModel().getAccountConfig(LRCInstance::getCurrAccId());
496 LRCInstance::editableAccountModel()->setAccountConfig(LRCInstance::getCurrAccId(), confProps);
497}
498
499void
500SettingsWidget::delAccountSlot()
501{
502 DeleteAccountDialog delDialog(this);
503 delDialog.exec();
504
Andreas Traczyk10523bf2018-12-31 16:49:03 -0500505 LRCInstance::setSelectedAccountId("");
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500506 if (!LRCInstance::accountModel().getAccountList().size()) {
507 emit NavigationRequested(ScreenEnum::WizardScreen);
Andreas Traczyk10523bf2018-12-31 16:49:03 -0500508 } else {
509 emit NavigationRequested(ScreenEnum::CallScreen);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500510 }
511}
512
513void
514SettingsWidget::removeDeviceSlot(int index)
515{
516 if (!index) { return; }
517
518 auto deviceList = LRCInstance::getCurrentAccountInfo().deviceModel->getAllDevices();
519 auto it = deviceList.begin();
520
521 std::advance(it, index);
522 QString psswd;
523
524 bool ok = false;
525 if (LRCInstance::getCurrAccConfig().archiveHasPassword) {
526 psswd = QInputDialog::getText(this, tr("Remove Device"),
Isa Nanic100368f2018-12-11 16:43:01 -0500527 tr("Enter this account's password to confirm the removal of this device"), QLineEdit::Password,
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500528 QDir::home().dirName(), &ok);
529 }
530 else {
531 psswd = "";
532 QMessageBox devDel;
533 devDel.setText(tr("Please confirm that you wish to remove this device"));
534 devDel.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
535 devDel.setDefaultButton(QMessageBox::Cancel);
536 if (devDel.exec() == QMessageBox::Ok) { goto delete_; }
537 }
538
539 if (ok) {
540 delete_:
541 LRCInstance::getCurrentAccountInfo().deviceModel->revokeDevice(it->id, psswd.toStdString());
542 updateAndShowDevicesSlot();
543 }
544}
545
546void
547SettingsWidget::unban(int index)
548{
549 auto bannedContactList = LRCInstance::getCurrentAccountInfo().contactModel->getBannedContacts();
550 auto it = bannedContactList.begin();
551 std::advance(it, index);
552
553 auto contactInfo = LRCInstance::getCurrentAccountInfo().contactModel->getContact(*it);
554
555 LRCInstance::getCurrentAccountInfo().contactModel->addContact(contactInfo);
556 updateAndShowBannedContactsSlot();
557}
558
559void
560SettingsWidget::exportAccountSlot()
561{
562 QFileDialog dialog(this);
563 QString dir = QFileDialog::getExistingDirectory(this, tr("Export Account Here"),
564 QDir::homePath() + "/Desktop", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
565
566 if (!dir.isEmpty()) {
567 LRCInstance::accountModel().exportToFile(LRCInstance::getCurrAccId(), (dir + "/export.gz").toStdString());
568 }
569}
570
571void
572SettingsWidget::updateAndShowDevicesSlot()
573{
574 ui->settingsListWidget->clear();
575
576 ui->label->setText(tr("Linked Devices"));
577 ui->blockedContactsBtn->setText(tr("Blocked Contacts"));
578 ui->linkDevPushButton->show();
579
580 auto deviceList = LRCInstance::getCurrentAccountInfo().deviceModel->getAllDevices();
581
582 int i = 0;
583
584 for (auto it = deviceList.begin(); it != deviceList.end(); ++it, ++i) {
585 SettingsItemWidget* item = new SettingsItemWidget(itemHeight_, i, false, ui->settingsListWidget);
586 item->setSizeHint(QSize(ui->settingsListWidget->width(), itemHeight_));
587 ui->settingsListWidget->addItem(item);
588
589 if (i) {
590 connect(item->button_, &QPushButton::clicked, [this, i]() {
591 removeDeviceSlot(i);
592 }
593 );
594 }
595 }
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500596}
597
598void
599SettingsWidget::updateAndShowBannedContactsSlot()
600{
Isa Nanic3a9c6e22018-12-11 17:07:20 -0500601 if (bannedContactsShown_) {
602 ui->settingsListWidget->clear();
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500603
Isa Nanic3a9c6e22018-12-11 17:07:20 -0500604 ui->label->setText(tr("Blocked Contacts"));
605 ui->blockedContactsBtn->setText(tr("Linked Devices"));
606 ui->linkDevPushButton->hide();
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500607
Isa Nanic3a9c6e22018-12-11 17:07:20 -0500608 auto bannedContactList = LRCInstance::getCurrentAccountInfo().contactModel->getBannedContacts();
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500609
Isa Nanic3a9c6e22018-12-11 17:07:20 -0500610 int i = 0;
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500611
Isa Nanic3a9c6e22018-12-11 17:07:20 -0500612 for (auto it = bannedContactList.begin(); it != bannedContactList.end(); ++it, ++i) {
613 SettingsItemWidget* item = new SettingsItemWidget(itemHeight_, i, true, ui->settingsListWidget);
614 item->setSizeHint(QSize(ui->settingsListWidget->width(), itemHeight_));
615 ui->settingsListWidget->addItem(item);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500616
Isa Nanic3a9c6e22018-12-11 17:07:20 -0500617 connect(item->button_, &QPushButton::clicked, [this, i]() {
618 unban(i);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500619 }
Isa Nanic3a9c6e22018-12-11 17:07:20 -0500620 );
621 }
622 if (!bannedContactList.size()) { updateAndShowDevicesSlot(); ui->blockedContactsBtn->hide(); }
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500623 }
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500624}
625
626void
627SettingsWidget::showLinkDevSlot()
628{
629 if (!advancedSettingsWidget_) { delete advancedSettingsWidget_; }
630
631 linkDevWidget = new LinkDevWidget(ui->scrollAreaWidgetContents);
632 linkDevWidget->setMinimumWidth(600);
633
634 ui->accountHorLayout->insertWidget(1, linkDevWidget);
635
636 linkDevWidget->show();
637 ui->centralWidget->hide();
638
639 connect(linkDevWidget->cancelBtn(), &QPushButton::clicked, this, &SettingsWidget::showCurrentAccountSlot);
640 connect(linkDevWidget->endCancelBtn(), &QPushButton::clicked, this, &SettingsWidget::showCurrentAccountSlot);
641}
642
643void
644SettingsWidget::showCurrentAccountSlot()
645{
646 disconnect(linkDevWidget);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500647 delete linkDevWidget;
Isa Nanic5bafcb92018-12-19 12:54:51 -0500648
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500649 ui->centralWidget->show();
Isa Nanic5bafcb92018-12-19 12:54:51 -0500650 updateAndShowDevicesSlot();
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500651}
652
653void
654SettingsWidget::setConnections()
655{
656 // exitSettingsButton
657 connect(ui->exitSettingsButton, &QPushButton::clicked, this, &SettingsWidget::leaveSettingsSlot);
658
659 connect(ui->accountSettingsButton, &QPushButton::clicked, [this]() {
660 setSelected(Button::accountSettingsButton); }
661 );
662
663 connect(ui->generalSettingsButton, &QPushButton::clicked, [this]() {
664 setSelected(Button::generalSettingsButton); }
665 );
666
667 connect(ui->avSettingsButton, &QPushButton::clicked, [this]() {
668 setSelected(Button::avSettingsButton); }
669 );
670
671 connect(ui->passwdPushButton, &QPushButton::clicked, [this]() {
672 passwordClicked(); }
673 );
674
675 connect(ui->currentAccountAvatar, &QPushButton::clicked, [this]() {
676 avatarClicked(); }
677 );
678
679 connect(ui->advancedAccountSettingsPButton, &QPushButton::clicked, this, &SettingsWidget::toggleAdvancedSettings);
680
681 connect(ui->currentRegisteredID, &QLineEdit::textChanged, this, &SettingsWidget::verifyRegisteredNameSlot);
682
683 connect(&LRCInstance::accountModel(), &lrc::api::NewAccountModel::registeredNameFound,
684 this, &SettingsWidget::receiveRegNameSlot);
685
686 //connect "export account" button
687 connect(ui->btnExportAccount, &QPushButton::clicked, this, &SettingsWidget::exportAccountSlot);
688
689 // connect "delete account" button
690 connect(ui->btnDeletAccount, &QPushButton::clicked, this, &SettingsWidget::delAccountSlot);
691
692 // connect "banned contacts" button
693 connect(ui->blockedContactsBtn, &QPushButton::clicked, this, &SettingsWidget::toggleBannedContacts);
694
695 // connect "link device" button
696 connect(ui->linkDevPushButton, &QPushButton::clicked, this, &SettingsWidget::showLinkDevSlot);
697
698 // update banned accounts automatically
699 connect(LRCInstance::getCurrentAccountInfo().contactModel.get(), &lrc::api::ContactModel::modelUpdated,
700 this, &SettingsWidget::updateAndShowBannedContactsSlot);
701
702 // update linked devices automatically
703 QObject::connect(LRCInstance::getCurrentAccountInfo().deviceModel.get(), &lrc::api::NewDeviceModel::deviceUpdated,
704 this, &SettingsWidget::updateAndShowDevicesSlot);
705
706 // account settings setters {
Isa Nanic26c86612018-12-14 12:21:56 -0500707 connect(ui->accountEnableCheckBox, &QCheckBox::clicked, this, &SettingsWidget::setAccEnableSlot);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500708
709 connect(ui->displayNameLineEdit, &QLineEdit::textChanged, [this](const QString& displayName) {
710 LRCInstance::setCurrAccDisplayName(displayName.toStdString());
711 }
712 );
713
714 // general settings
715
Isa Nanic100368f2018-12-11 16:43:01 -0500716 connect(ui->notificationCheckBox, &QAbstractButton::clicked, this, &SettingsWidget::setNotificationsSlot);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500717
Isa Nanic100368f2018-12-11 16:43:01 -0500718 connect(ui->closeOrMinCheckBox, &QAbstractButton::clicked, this, &SettingsWidget::setClosedOrMinSlot);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500719
Isa Nanic100368f2018-12-11 16:43:01 -0500720 connect(ui->downloadButton, &QAbstractButton::clicked, this, &SettingsWidget::openDownloadFolderSlot);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500721
Isa Nanic100368f2018-12-11 16:43:01 -0500722 connect(ui->alwaysRecordingCheckBox, &QAbstractButton::clicked, this, &SettingsWidget::setAlwaysRecordingSlot);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500723
Isa Nanic100368f2018-12-11 16:43:01 -0500724 connect(ui->checkUpdateButton, &QAbstractButton::clicked, this, &SettingsWidget::checkForUpdateSlot);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500725
726 connect(ui->intervalUpdateCheckSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), this, &SettingsWidget::setUpdateIntervalSlot);
727
Isa Nanic100368f2018-12-11 16:43:01 -0500728 connect(ui->autoUpdateCheckBox, &QAbstractButton::clicked, this, &SettingsWidget::setUpdateAutomaticSlot);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500729
730 // audio / visual settings
731
732 connect(ui->recordPathButton, &QPushButton::clicked, this, &SettingsWidget::openRecordFolderSlot);
733}
734
735
736// ************************* General Settings *************************
737
738void SettingsWidget::populateGeneralSettings()
739{
Isa Nanic5bafcb92018-12-19 12:54:51 -0500740 QSettings settings;
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500741
742 // settings
Isa Nanic5bafcb92018-12-19 12:54:51 -0500743 ui->downloadButton->setText(QString::fromStdString(LRCInstance::dataTransferModel().downloadDirectory));
744 ui->closeOrMinCheckBox->setChecked(settings.value(SettingsKey::closeOrMinimized).toBool());
745 ui->notificationCheckBox->setChecked(settings.value(SettingsKey::enableNotifications).toBool());
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500746
747 //recordings
748 ui->alwaysRecordingCheckBox->setChecked(media::RecordingModel::instance().isAlwaysRecording());
749
750 if (media::RecordingModel::instance().recordPath().isEmpty()) {
751 QString recordPath = QDir::toNativeSeparators(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation));
752 media::RecordingModel::instance().setRecordPath(recordPath);
753 }
754 ui->recordPathButton->setText(media::RecordingModel::instance().recordPath());
755
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500756 ui->autoUpdateCheckBox->setChecked(win_sparkle_get_automatic_check_for_updates());
757 ui->intervalUpdateCheckSpinBox->setValue(win_sparkle_get_update_check_interval() / 86400);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500758}
759
760void
761SettingsWidget::setNotificationsSlot(int state)
762{
Isa Nanic5bafcb92018-12-19 12:54:51 -0500763 QSettings settings;
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500764 if (state == Qt::CheckState::Unchecked) {
Isa Nanic5bafcb92018-12-19 12:54:51 -0500765 settings.setValue(SettingsKey::enableNotifications, false);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500766 } else {
Isa Nanic5bafcb92018-12-19 12:54:51 -0500767 settings.setValue(SettingsKey::enableNotifications, true);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500768 }
769}
770
771void
772SettingsWidget::setClosedOrMinSlot(int state)
773{
Isa Nanic5bafcb92018-12-19 12:54:51 -0500774 QSettings settings;
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500775 if (state == Qt::CheckState::Unchecked) {
Isa Nanic5bafcb92018-12-19 12:54:51 -0500776 settings.setValue(SettingsKey::closeOrMinimized, false);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500777 }
778 else {
Isa Nanic5bafcb92018-12-19 12:54:51 -0500779 settings.setValue(SettingsKey::closeOrMinimized, true);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500780 }
781}
782
783void
784SettingsWidget::checkForUpdateSlot()
785{
786 win_sparkle_check_update_with_ui();
787}
788
789void
790SettingsWidget::setUpdateIntervalSlot(int value)
791{
792 win_sparkle_set_update_check_interval(value * 86400);
793}
794
795void
796SettingsWidget::setUpdateAutomaticSlot(int state)
797{
798 if (state == Qt::CheckState::Unchecked) {
799 win_sparkle_set_automatic_check_for_updates(false);
800 ui->intervalUpdateCheckSpinBox->setEnabled(false);
801 } else {
802 win_sparkle_set_automatic_check_for_updates(true);
803 ui->intervalUpdateCheckSpinBox->setEnabled(true);
804 }
805}
806
807void
808SettingsWidget::openDownloadFolderSlot()
809{
Isa Nanic5bafcb92018-12-19 12:54:51 -0500810 QSettings settings;
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500811 QString dir = QFileDialog::getExistingDirectory(this, tr("Select A Folder For Your Downloads"),
812 QStandardPaths::writableLocation(QStandardPaths::DownloadLocation), QFileDialog::ShowDirsOnly
813 | QFileDialog::DontResolveSymlinks);
814
815 if (!dir.isEmpty()) {
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500816 ui->downloadButton->setText(dir);
Isa Nanic5bafcb92018-12-19 12:54:51 -0500817 settings.setValue(SettingsKey::downloadPath, dir);
Isa Nanic7a3dfa42018-12-12 12:34:42 -0500818 LRCInstance::editableDataTransferModel()->downloadDirectory = dir.toStdString() + "/";
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500819 }
820}
821
822void
823SettingsWidget::setAlwaysRecordingSlot(int state)
824{
825 if (state == Qt::CheckState::Unchecked) {
826 media::RecordingModel::instance().setAlwaysRecording(false);
827 } else {
828 media::RecordingModel::instance().setAlwaysRecording(true);
829 }
830}
831
832void
833SettingsWidget::openRecordFolderSlot()
834{
835 QString dir = QFileDialog::getExistingDirectory(this, tr("Select A Folder For Your Recordings"),
836 media::RecordingModel::instance().recordPath(), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
837
838 if (!dir.isEmpty()) {
839 media::RecordingModel::instance().setRecordPath(dir);
840 ui->recordPathButton->setText(media::RecordingModel::instance().recordPath());
841 }
842}
843
844
845// ************************* Audio/Visual Settings *************************
846
847void
848SettingsWidget::populateAVSettings()
849{
850 ui->deviceBox->setModel(deviceModel_);
851 connect(deviceModel_, SIGNAL(currentIndexChanged(int)),
852 this, SLOT(deviceIndexChanged(int)));
853
Isa Nanic9316d472018-12-18 16:27:13 -0500854 // Audio settings
855 auto inputModel = Audio::Settings::instance().inputDeviceModel();
856 auto outputModel = Audio::Settings::instance().outputDeviceModel();
857
858 ui->inputComboBox->setModel(inputModel);
859 ui->outputComboBox->setModel(outputModel);
860
861 auto inputIndex = inputModel->selectionModel()->currentIndex();
862 auto outputIndex = outputModel->selectionModel()->currentIndex();
863
864 ui->inputComboBox->setCurrentIndex(inputIndex.row());
865 ui->outputComboBox->setCurrentIndex(outputIndex.row());
866
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500867 if (ui->deviceBox->count() > 0) {
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500868 deviceBoxCurrentIndexChangedSlot(0);
869 }
870
Isa Nanic054ef9a2018-12-11 11:56:28 -0500871 if (currentResIndex >= 0) {
872 ui->sizeBox->setCurrentIndex(currentResIndex);
873 }
874
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500875 connect(ui->outputComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
876 this, &SettingsWidget::outputDevIndexChangedSlot);
877 connect(ui->inputComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
878 this, &SettingsWidget::inputdevIndexChangedSlot);
879
880 connect(ui->deviceBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
881 &SettingsWidget::deviceBoxCurrentIndexChangedSlot);
882 connect(ui->sizeBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
883 &SettingsWidget::sizeBoxCurrentIndexChangedSlot);
Isa Nanic9316d472018-12-18 16:27:13 -0500884
885 showPreview();
Isa Nanic054ef9a2018-12-11 11:56:28 -0500886}
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500887
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500888
Isa Nanic054ef9a2018-12-11 11:56:28 -0500889void
890SettingsWidget::saveSizeIndex()
891{
892 currentResIndex = ui->sizeBox->currentIndex();
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500893}
894
895void
896SettingsWidget::showPreview()
897{
898 if (!CallModel::instance().getActiveCalls().size()) {
899 ui->previewUnavailableLabel->hide();
900 ui->videoWidget->show();
Isa Nanic054ef9a2018-12-11 11:56:28 -0500901 startVideo();
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500902 ui->videoWidget->setIsFullPreview(true);
903 } else {
904 ui->previewUnavailableLabel->show();
905 ui->videoWidget->hide();
906 }
907}
908
909void
910SettingsWidget::deviceBoxCurrentIndexChangedSlot(int index)
911{
912 if (index < 0) {
913 return;
914 }
915
Isa Nanic9316d472018-12-18 16:27:13 -0500916 deviceModel_->setActive(index);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500917
918 auto device = deviceModel_->activeDevice();
919
920 ui->sizeBox->clear();
921
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500922 if (device->channelList().size() > 0) {
923 for (auto resolution : device->channelList()[0]->validResolutions()) {
924 ui->sizeBox->addItem(resolution->name());
925 }
926 }
927 ui->sizeBox->setCurrentIndex(
928 device->channelList()[0]->activeResolution()->relativeIndex());
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500929}
930
931void
932SettingsWidget::sizeBoxCurrentIndexChangedSlot(int index)
933{
Isa Nanic9316d472018-12-18 16:27:13 -0500934 if (index < 0) {
935 return;
936 }
937
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500938 auto device = deviceModel_->activeDevice();
939
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500940 device->channelList()[0]->setActiveResolution(device->channelList()[0]->validResolutions()[index]);
Isa Nanic9316d472018-12-18 16:27:13 -0500941
942 QTimer::singleShot(200, this, [this]() {
943 deviceModel_->setActive(ui->deviceBox->currentIndex());
944 });
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500945}
946
947void
948SettingsWidget::deviceIndexChanged(int index)
949{
950 ui->deviceBox->setCurrentIndex(index);
951
952 ui->videoLayout->update();
953}
954
955void
956SettingsWidget::outputDevIndexChangedSlot(int index)
957{
958 auto outputModel = Audio::Settings::instance().outputDeviceModel();
959 outputModel->selectionModel()->setCurrentIndex(outputModel->index(index), QItemSelectionModel::ClearAndSelect);
960}
961
962void
963SettingsWidget::inputdevIndexChangedSlot(int index)
964{
965 auto inputModel = Audio::Settings::instance().inputDeviceModel();
966 inputModel->selectionModel()->setCurrentIndex(inputModel->index(index), QItemSelectionModel::ClearAndSelect);
Isa Nanic054ef9a2018-12-11 11:56:28 -0500967}
968
969void
970SettingsWidget::startVideo()
971{
972 Video::PreviewManager::instance().stopPreview();
973 Video::PreviewManager::instance().startPreview();
974}
975
976void
977SettingsWidget::stopVideo()
978{
979 Video::PreviewManager::instance().stopPreview();
Isa Nanic26c86612018-12-14 12:21:56 -0500980}