blob: e2bd6eebb6782617e9068ef6ef3ec3e4c1aadb37 [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
Isa Nanic6e4a39a2018-12-04 14:26:02 -050067SettingsWidget::SettingsWidget(QWidget* parent)
68 : NavWidget(parent),
69 ui(new Ui::SettingsWidget),
Andreas Traczykb81281e2018-12-13 13:13:28 -050070 scrollArea_(new QScrollArea(this)),
Isa Nanic6e4a39a2018-12-04 14:26:02 -050071 deviceModel_(&Video::DeviceModel::instance()),
72 gif(new QMovie(":/images/ajax-loader.gif"))
73{
74 ui->setupUi(this);
75
76 ui->accountSettingsButton->setAutoFillBackground(true);
77 ui->generalSettingsButton->setAutoFillBackground(true);
78 ui->avSettingsButton->setAutoFillBackground(true);
79
80 ui->accountSettingsButton->setChecked(true);
81
82 ui->exitSettingsButton->setIconSize(QSize(24, 24));
83 ui->exitSettingsButton->setIcon(QPixmap(":/images/icons/round-close-24px.svg"));
84
85
86 // display name (aka alias)
87 ui->displayNameLineEdit->setAlignment(Qt::AlignHCenter);
88 ui->displayNameLineEdit->setPlaceholderText(tr("Enter the displayed name"));
89
90
91 setSelected(Button::accountSettingsButton);
92
93 ui->currentRegisteredID->setReadOnly(true);
94 ui->currentRegisteredID->setStyleSheet("border : 0px;");
95
96 ui->currentRingID->setReadOnly(true);
97
98 avatarSize_ = ui->currentAccountAvatar->width();
99
100 ui->currentAccountAvatar->setIconSize(QSize(avatarSize_, avatarSize_));
101
102 // create ellipse-selectable avatar image
103 QRegion avatarClickableRegion(-1, -1,
104 ui->currentAccountAvatar->width() + 2, ui->currentAccountAvatar->height() + 2, QRegion::Ellipse);
105 ui->currentAccountAvatar->setMask(avatarClickableRegion);
106
107 QString styleS(
108 "QPushButton{"
109 " background-color: rgb(245, 245, 245);"
110 " border: 0px;"
111 "}"
112 " QPushButton:hover{"
113 " background-color: rgb(250, 250, 250);"
114 " border: 0px;"
115 " }"
116
117 "QPushButton:checked{"
118 " background-color: white;"
119 " border: 0px;"
120 "}"
121 );
122
123 ui->accountSettingsButton->setStyleSheet(styleS);
124 ui->generalSettingsButton->setStyleSheet(styleS);
125 ui->avSettingsButton->setStyleSheet(styleS);
126
127 ui->advancedAccountSettingsPButton->setIcon(QPixmap(":/images/icons/round-arrow_drop_down-24px.svg"));
128 ui->linkDevPushButton->setIcon(QPixmap(":/images/icons/round-add-24px.svg"));
129 ui->blockedContactsBtn->setIcon(QPixmap(":/images/icons/round-arrow_drop_up-24px.svg"));
130
131 ui->advancedSettingsOffsetLabel->show();
132
Andreas Traczykfc33a492018-12-14 13:53:13 -0500133 auto accountList = LRCInstance::accountModel().getAccountList();
134 if (!accountList.size()) {
135 QMetaObject::Connection* toDisconnect = &accountAddedConnection_;
136 accountAddedConnection_ = connect(&LRCInstance::accountModel(),
137 &lrc::api::NewAccountModel::accountAdded,
138 [this, toDisconnect](const std::string& accountId) {
139 setConnections();
140 QObject::disconnect(*toDisconnect);
141 });
142 } else {
143 setConnections();
144 }
145
146 ui->containerWidget->setVisible(false);
147}
148
149void
150SettingsWidget::navigated(bool to)
151{
152 ui->containerWidget->setVisible(to);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500153}
154
155void
156SettingsWidget::leaveSettingsSlot()
157{
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500158 if (advancedSettingsDropped_) {
159 toggleAdvancedSettings();
160 }
161
Isa Nanic054ef9a2018-12-11 11:56:28 -0500162 Video::PreviewManager::instance().stopPreview();
163 saveSizeIndex();
164
165 emit NavigationRequested(ScreenEnum::CallScreen);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500166}
167
168SettingsWidget::~SettingsWidget()
169{
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500170 delete ui;
171}
172
173// called at every callwidget -> settingsWidget navigation
174void
175SettingsWidget::updateSettings(int size)
176{
177 setSelected(Button::accountSettingsButton);
178 resize(size);
179 updateAccountInfoDisplayed();
180}
181
182void
183SettingsWidget::resize(int size)
184{
185 ui->rightSettingsWidget->setGeometry(size, 0, this->width() - size, this->height());
186 ui->accountSettingsButton->setFixedWidth(size);
187}
188
189void
190SettingsWidget::setSelected(Button sel)
191{
Isa Nanic054ef9a2018-12-11 11:56:28 -0500192 saveSizeIndex();
193
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500194 switch (sel)
195 {
196 case Button::accountSettingsButton:
Isa Nanic054ef9a2018-12-11 11:56:28 -0500197 Video::PreviewManager::instance().stopPreview();
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500198
Isa Nanic054ef9a2018-12-11 11:56:28 -0500199 if (advancedSettingsDropped_) { toggleAdvancedSettings(); }
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500200 ui->stackedWidget->setCurrentWidget(ui->currentAccountSettingsScrollWidget);
201 if (pastButton_ == Button::generalSettingsButton) {
202 ui->accountSettingsButton->setChecked(true);
203 ui->generalSettingsButton->setChecked(false);
204 break;
205 }
206 else {
207 ui->accountSettingsButton->setChecked(true);
208 ui->avSettingsButton->setChecked(false);
209 break;
210 }
211 case Button::generalSettingsButton:
Isa Nanic054ef9a2018-12-11 11:56:28 -0500212 Video::PreviewManager::instance().stopPreview();
213
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500214 ui->stackedWidget->setCurrentWidget(ui->generalSettings);
215 populateGeneralSettings();
216 if (pastButton_ == Button::avSettingsButton) {
217 ui->generalSettingsButton->setChecked(true);
218 ui->avSettingsButton->setChecked(false);
219 break;
220 }
221 else {
222 ui->generalSettingsButton->setChecked(true);
223 ui->accountSettingsButton->setChecked(false);
224 break;
225 }
226 case Button::avSettingsButton:
227 ui->stackedWidget->setCurrentWidget(ui->avSettings);
Isa Nanic054ef9a2018-12-11 11:56:28 -0500228 populateAVSettings();
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500229 if (pastButton_ == Button::accountSettingsButton) {
230 ui->avSettingsButton->setChecked(true);
231 ui->accountSettingsButton->setChecked(false);
232 break;
233 }
234 else {
235 ui->avSettingsButton->setChecked(true);
236 ui->generalSettingsButton->setChecked(false);
237 break;
238 }
239 }
240 pastButton_ = sel;
241}
242
243// called to update current settings information when navigating to settingsWidget
244void
245SettingsWidget::updateAccountInfoDisplayed()
246{
247 ui->currentRegisteredID->setText(QString::fromStdString(LRCInstance::getCurrentAccountInfo().registeredName));
248 ui->currentRingID->setText(QString::fromStdString(LRCInstance::getCurrentAccountInfo().profileInfo.uri));
249
250 ui->currentRegisteredID->setReadOnly(true);
251
252// if no registered name is found for account
253 if (LRCInstance::getCurrentAccountInfo().registeredName.empty()) {
254 ui->currentRegisteredID->setReadOnly(false);
255 }
256 else {
257 ui->currentRegisteredID->setReadOnly(true);
258 setRegNameUi(RegName::BLANK);
259 }
260
261 ui->currentAccountAvatar->setIcon(LRCInstance::getCurrAccPixmap().
262 scaledToHeight(avatarSize_, Qt::SmoothTransformation));
263
264 ui->accountEnableCheckBox->setChecked(LRCInstance::getCurrentAccountInfo().enabled);
265
266 ui->displayNameLineEdit->setText(QString::fromStdString(LRCInstance::getCurrentAccountInfo().profileInfo.alias));
267
268 updateAndShowDevicesSlot();
Isa Nanic3a9c6e22018-12-11 17:07:20 -0500269 bannedContactsShown_ = false;
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500270 if (!LRCInstance::getCurrentAccountInfo().contactModel->getBannedContacts().size()){
271 ui->blockedContactsBtn->hide();
272 } else {
273 ui->blockedContactsBtn->show();
274 }
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500275}
276
277void
278SettingsWidget::passwordClicked()
279{
280 PasswordDialog passwdDialog(this);
281 passwdDialog.exec();
282}
283
284void
285SettingsWidget::toggleAdvancedSettings()
286{
287 if (advancedSettingsDropped_) {
288 ui->advancedAccountSettingsPButton->setIcon(QPixmap(":/images/icons/round-arrow_drop_down-24px.svg"));
289 ui->currentAccountSettingsScrollLayout->removeWidget(advancedSettingsWidget_);
290 ui->scrollBarLabel->show();
291 ui->advancedSettingsOffsetLabel->hide();
292 delete advancedSettingsWidget_;
293 }
294 else { // will show advanced settings next
295 ui->advancedAccountSettingsPButton->setIcon(QPixmap(":/images/icons/round-arrow_drop_up-24px.svg"));
Andreas Traczykb81281e2018-12-13 13:13:28 -0500296 advancedSettingsWidget_ = new AdvancedSettingsWidget(this);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500297 advancedSettingsWidget_->setMaximumWidth(ui->scrollAreaWidgetContents->width() - 10);
298 ui->currentAccountSettingsScrollLayout->addWidget(advancedSettingsWidget_);
299 ui->advancedSettingsOffsetLabel->show();
300 ui->scrollBarLabel->hide();
301 }
302 advancedSettingsDropped_ = !advancedSettingsDropped_;
303}
304
305void
306SettingsWidget::toggleBannedContacts()
307{
308 if (bannedContactsShown_) { // will show linked devices next
Isa Nanic3a9c6e22018-12-11 17:07:20 -0500309 bannedContactsShown_ = false;
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500310 updateAndShowDevicesSlot();
311 }
312 else { // will show banned contacts next
Isa Nanic3a9c6e22018-12-11 17:07:20 -0500313 bannedContactsShown_ = true;
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500314 updateAndShowBannedContactsSlot();
315 }
316}
317
318void
319SettingsWidget::resizeEvent(QResizeEvent* event)
320{
321 QWidget::resizeEvent(event);
322 scrollArea_->resize(ui->currentAccountSettingsScrollWidget->width(), this->height());
323}
324
325void
326SettingsWidget::avatarClicked()
327{
328 SetAvatarDialog avatarDialog(this);
329
330 // return new avatar pixmap from setAvatarDialog
331 connect(&avatarDialog, &SetAvatarDialog::pixmapSignal, [&](const std::string& pixString) {
332 if (!pixString.empty()) {
333 LRCInstance::setCurrAccAvatar(pixString);
334 updateAccountInfoDisplayed();
335 }
336 }
337 );
338 avatarDialog.exec();
339}
340
341void
342SettingsWidget::verifyRegisteredNameSlot()
343{
344 if (!LRCInstance::getCurrentAccountInfo().registeredName.empty()) {
345 setRegNameUi(RegName::BLANK);
346 }
347 else {
348 registeredName_ = ui->currentRegisteredID->text().simplified();
349
350 if (!registeredName_.isEmpty()) {
351 if (validateRegNameForm(registeredName_)) { // name has valid form
352 setRegNameUi(RegName::SEARCHING);
353 QTimer::singleShot(300, this, SLOT(beforeNameLookup()));
354 } else { // name does not have valid form
355 setRegNameUi(RegName::INVALIDFORM);
356 }
357 } else {
358 setRegNameUi(RegName::BLANK);
359 }
360 }
361}
362
363// returns true if name is valid registered name
364bool
365SettingsWidget::validateRegNameForm(const QString& regName)
366{
367 QRegularExpression regExp(" ");
368 if (regName.size() > 2 && !regName.contains(regExp)) {
369 return true;
370 }
371 else {
372 return false;
373 }
374}
375
376void
377SettingsWidget::receiveRegNameSlot(const std::string& accountID,
378 lrc::api::account::LookupStatus status, const std::string& address, const std::string& name)
379{
380 Q_UNUSED(accountID); Q_UNUSED(address);
381 afterNameLookup(status, name);
382}
383
384void
385SettingsWidget::beforeNameLookup()
386{
387 NameDirectory::instance().lookupName(nullptr, QString(), registeredName_);
388}
389
390void
391SettingsWidget::afterNameLookup(lrc::api::account::LookupStatus status, const std::string& regName)
392{
393 if (registeredName_.toStdString() == regName && regName.length() > 2) {
394 if (status == lrc::api::account::LookupStatus::NOT_FOUND) {
395 setRegNameUi(RegName::FREE);
396 }
397 else {
398 setRegNameUi(RegName::TAKEN);
399 }
400 }
401 else {
402 setRegNameUi(RegName::BLANK);
403 }
404}
405
406void SettingsWidget::setRegNameUi(RegName stat)
407{
408 disconnect(gif, SIGNAL(frameChanged(int)), this, SLOT(setButtonIconSlot(int)));
409 disconnect(ui->regNameButton, &QPushButton::clicked, this, &SettingsWidget::regNameRegisteredSlot);
410
411 switch (stat) {
412 case RegName::BLANK:
413 ui->currentRegisteredID->setStyleSheet("padding-left: 5px; border: 0px; border-radius: 3px; border: 1px solid rgb(245, 245, 245);");
414 regNameBtn_ = false;
415 ui->currentRegisteredID->setToolTip(tr(""));
416 ui->regNameButton->setIcon(QPixmap());
417 ui->regNameButton->setEnabled(false);
418 break;
419
420 case RegName::INVALIDFORM:
421 ui->currentRegisteredID->setStyleSheet("padding-left: 5px; border: 1px solid red; border-radius: 3px;");
422 regNameBtn_ = false;
423 ui->currentRegisteredID->setToolTip(tr("A registered name should not have any spaces and must be at least three letters long"));
424 ui->regNameButton->setIcon(QPixmap(":/images/icons/round-error-24px.svg"));
425 ui->regNameButton->setToolTip(tr("A registered name should not have any spaces and must be at least three letters long"));
426 ui->regNameButton->setEnabled(true);
427 break;
428
429 case RegName::TAKEN:
430 ui->currentRegisteredID->setStyleSheet("padding-left: 5px; border: 1px solid orange; border-radius: 3px;");
431 regNameBtn_ = false;
432 ui->currentRegisteredID->setToolTip(tr("This name is already taken"));
433 ui->regNameButton->setIcon(QPixmap(":/images/icons/round-error-24px.svg"));
434 ui->regNameButton->setToolTip(tr("This registered name is already taken"));
435 ui->regNameButton->setEnabled(true);
436 break;
437
438 case RegName::FREE:
439 ui->currentRegisteredID->setStyleSheet("padding-left: 5px; border: 1px solid green; border-radius: 3px;");
440 regNameBtn_ = true;
441 ui->currentRegisteredID->setToolTip(tr("This name is available"));
442 ui->regNameButton->setIcon(QPixmap(":/images/icons/round-check_circle-24px.svg"));
443 ui->regNameButton->setToolTip(tr("Register this name"));
444 ui->regNameButton->setEnabled(true);
445
446 connect(ui->regNameButton, &QPushButton::clicked, this, &SettingsWidget::regNameRegisteredSlot);
447
448 break;
449
450 case RegName::SEARCHING:
451 ui->currentRegisteredID->setStyleSheet("padding-left: 5px; border: 1px solid rgb(2, 187, 213); border-radius: 3px;");
452 regNameBtn_ = false;
453 ui->currentRegisteredID->setToolTip(tr(""));
454
455 connect(gif, SIGNAL(frameChanged(int)), this, SLOT(setButtonIconSlot(int)));
456 gif->start();
457 ui->regNameButton->setEnabled(false);
458
459 break;
460 }
461}
462void SettingsWidget::setButtonIconSlot(int frame)
463{
464 Q_UNUSED(frame);
465 ui->regNameButton->setIcon(QIcon(gif->currentPixmap()));
466}
467
468void
469SettingsWidget::regNameRegisteredSlot()
470{
471 if (!regNameBtn_) { return; }
472
473 RegNameDialog regNameDialog(registeredName_, this);
474 if (regNameDialog.exec() == QDialog::Accepted) { // if user confirms regName choice
475 ui->currentRegisteredID->setReadOnly(true);
476 }
477 else {
478 ui->currentRegisteredID->setText("");
479 registeredName_ = "";
480 }
481 setRegNameUi(RegName::BLANK);
482}
483
484void
485SettingsWidget::setAccEnableSlot(int state)
486{
487 LRCInstance::editableAccountModel()->enableAccount(LRCInstance::getCurrAccId(), (bool)state);
488
489 auto confProps = LRCInstance::accountModel().getAccountConfig(LRCInstance::getCurrAccId());
490 LRCInstance::editableAccountModel()->setAccountConfig(LRCInstance::getCurrAccId(), confProps);
491}
492
493void
494SettingsWidget::delAccountSlot()
495{
496 DeleteAccountDialog delDialog(this);
497 delDialog.exec();
498
499 if (!LRCInstance::accountModel().getAccountList().size()) {
Andreas Traczyk9b1b7d42018-12-13 14:44:24 -0500500 LRCInstance::setSelectedAccountId("");
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500501 emit NavigationRequested(ScreenEnum::WizardScreen);
502 }
503}
504
505void
506SettingsWidget::removeDeviceSlot(int index)
507{
508 if (!index) { return; }
509
510 auto deviceList = LRCInstance::getCurrentAccountInfo().deviceModel->getAllDevices();
511 auto it = deviceList.begin();
512
513 std::advance(it, index);
514 QString psswd;
515
516 bool ok = false;
517 if (LRCInstance::getCurrAccConfig().archiveHasPassword) {
518 psswd = QInputDialog::getText(this, tr("Remove Device"),
Isa Nanic100368f2018-12-11 16:43:01 -0500519 tr("Enter this account's password to confirm the removal of this device"), QLineEdit::Password,
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500520 QDir::home().dirName(), &ok);
521 }
522 else {
523 psswd = "";
524 QMessageBox devDel;
525 devDel.setText(tr("Please confirm that you wish to remove this device"));
526 devDel.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
527 devDel.setDefaultButton(QMessageBox::Cancel);
528 if (devDel.exec() == QMessageBox::Ok) { goto delete_; }
529 }
530
531 if (ok) {
532 delete_:
533 LRCInstance::getCurrentAccountInfo().deviceModel->revokeDevice(it->id, psswd.toStdString());
534 updateAndShowDevicesSlot();
535 }
536}
537
538void
539SettingsWidget::unban(int index)
540{
541 auto bannedContactList = LRCInstance::getCurrentAccountInfo().contactModel->getBannedContacts();
542 auto it = bannedContactList.begin();
543 std::advance(it, index);
544
545 auto contactInfo = LRCInstance::getCurrentAccountInfo().contactModel->getContact(*it);
546
547 LRCInstance::getCurrentAccountInfo().contactModel->addContact(contactInfo);
548 updateAndShowBannedContactsSlot();
549}
550
551void
552SettingsWidget::exportAccountSlot()
553{
554 QFileDialog dialog(this);
555 QString dir = QFileDialog::getExistingDirectory(this, tr("Export Account Here"),
556 QDir::homePath() + "/Desktop", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
557
558 if (!dir.isEmpty()) {
559 LRCInstance::accountModel().exportToFile(LRCInstance::getCurrAccId(), (dir + "/export.gz").toStdString());
560 }
561}
562
563void
564SettingsWidget::updateAndShowDevicesSlot()
565{
566 ui->settingsListWidget->clear();
567
568 ui->label->setText(tr("Linked Devices"));
569 ui->blockedContactsBtn->setText(tr("Blocked Contacts"));
570 ui->linkDevPushButton->show();
571
572 auto deviceList = LRCInstance::getCurrentAccountInfo().deviceModel->getAllDevices();
573
574 int i = 0;
575
576 for (auto it = deviceList.begin(); it != deviceList.end(); ++it, ++i) {
577 SettingsItemWidget* item = new SettingsItemWidget(itemHeight_, i, false, ui->settingsListWidget);
578 item->setSizeHint(QSize(ui->settingsListWidget->width(), itemHeight_));
579 ui->settingsListWidget->addItem(item);
580
581 if (i) {
582 connect(item->button_, &QPushButton::clicked, [this, i]() {
583 removeDeviceSlot(i);
584 }
585 );
586 }
587 }
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500588}
589
590void
591SettingsWidget::updateAndShowBannedContactsSlot()
592{
Isa Nanic3a9c6e22018-12-11 17:07:20 -0500593 if (bannedContactsShown_) {
594 ui->settingsListWidget->clear();
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500595
Isa Nanic3a9c6e22018-12-11 17:07:20 -0500596 ui->label->setText(tr("Blocked Contacts"));
597 ui->blockedContactsBtn->setText(tr("Linked Devices"));
598 ui->linkDevPushButton->hide();
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500599
Isa Nanic3a9c6e22018-12-11 17:07:20 -0500600 auto bannedContactList = LRCInstance::getCurrentAccountInfo().contactModel->getBannedContacts();
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500601
Isa Nanic3a9c6e22018-12-11 17:07:20 -0500602 int i = 0;
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500603
Isa Nanic3a9c6e22018-12-11 17:07:20 -0500604 for (auto it = bannedContactList.begin(); it != bannedContactList.end(); ++it, ++i) {
605 SettingsItemWidget* item = new SettingsItemWidget(itemHeight_, i, true, ui->settingsListWidget);
606 item->setSizeHint(QSize(ui->settingsListWidget->width(), itemHeight_));
607 ui->settingsListWidget->addItem(item);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500608
Isa Nanic3a9c6e22018-12-11 17:07:20 -0500609 connect(item->button_, &QPushButton::clicked, [this, i]() {
610 unban(i);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500611 }
Isa Nanic3a9c6e22018-12-11 17:07:20 -0500612 );
613 }
614 if (!bannedContactList.size()) { updateAndShowDevicesSlot(); ui->blockedContactsBtn->hide(); }
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500615 }
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500616}
617
618void
619SettingsWidget::showLinkDevSlot()
620{
621 if (!advancedSettingsWidget_) { delete advancedSettingsWidget_; }
622
623 linkDevWidget = new LinkDevWidget(ui->scrollAreaWidgetContents);
624 linkDevWidget->setMinimumWidth(600);
625
626 ui->accountHorLayout->insertWidget(1, linkDevWidget);
627
628 linkDevWidget->show();
629 ui->centralWidget->hide();
630
631 connect(linkDevWidget->cancelBtn(), &QPushButton::clicked, this, &SettingsWidget::showCurrentAccountSlot);
632 connect(linkDevWidget->endCancelBtn(), &QPushButton::clicked, this, &SettingsWidget::showCurrentAccountSlot);
633}
634
635void
636SettingsWidget::showCurrentAccountSlot()
637{
638 disconnect(linkDevWidget);
639
640 delete linkDevWidget;
641 ui->centralWidget->show();
642}
643
644void
645SettingsWidget::setConnections()
646{
647 // exitSettingsButton
648 connect(ui->exitSettingsButton, &QPushButton::clicked, this, &SettingsWidget::leaveSettingsSlot);
649
650 connect(ui->accountSettingsButton, &QPushButton::clicked, [this]() {
651 setSelected(Button::accountSettingsButton); }
652 );
653
654 connect(ui->generalSettingsButton, &QPushButton::clicked, [this]() {
655 setSelected(Button::generalSettingsButton); }
656 );
657
658 connect(ui->avSettingsButton, &QPushButton::clicked, [this]() {
659 setSelected(Button::avSettingsButton); }
660 );
661
662 connect(ui->passwdPushButton, &QPushButton::clicked, [this]() {
663 passwordClicked(); }
664 );
665
666 connect(ui->currentAccountAvatar, &QPushButton::clicked, [this]() {
667 avatarClicked(); }
668 );
669
670 connect(ui->advancedAccountSettingsPButton, &QPushButton::clicked, this, &SettingsWidget::toggleAdvancedSettings);
671
672 connect(ui->currentRegisteredID, &QLineEdit::textChanged, this, &SettingsWidget::verifyRegisteredNameSlot);
673
674 connect(&LRCInstance::accountModel(), &lrc::api::NewAccountModel::registeredNameFound,
675 this, &SettingsWidget::receiveRegNameSlot);
676
677 //connect "export account" button
678 connect(ui->btnExportAccount, &QPushButton::clicked, this, &SettingsWidget::exportAccountSlot);
679
680 // connect "delete account" button
681 connect(ui->btnDeletAccount, &QPushButton::clicked, this, &SettingsWidget::delAccountSlot);
682
683 // connect "banned contacts" button
684 connect(ui->blockedContactsBtn, &QPushButton::clicked, this, &SettingsWidget::toggleBannedContacts);
685
686 // connect "link device" button
687 connect(ui->linkDevPushButton, &QPushButton::clicked, this, &SettingsWidget::showLinkDevSlot);
688
689 // update banned accounts automatically
690 connect(LRCInstance::getCurrentAccountInfo().contactModel.get(), &lrc::api::ContactModel::modelUpdated,
691 this, &SettingsWidget::updateAndShowBannedContactsSlot);
692
693 // update linked devices automatically
694 QObject::connect(LRCInstance::getCurrentAccountInfo().deviceModel.get(), &lrc::api::NewDeviceModel::deviceUpdated,
695 this, &SettingsWidget::updateAndShowDevicesSlot);
696
697 // account settings setters {
Isa Nanic100368f2018-12-11 16:43:01 -0500698 connect(ui->accountEnableCheckBox, &QAbstractButton::clicked, this, &SettingsWidget::setAccEnableSlot);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500699
700 connect(ui->displayNameLineEdit, &QLineEdit::textChanged, [this](const QString& displayName) {
701 LRCInstance::setCurrAccDisplayName(displayName.toStdString());
702 }
703 );
704
705 // general settings
706
Isa Nanic100368f2018-12-11 16:43:01 -0500707 connect(ui->notificationCheckBox, &QAbstractButton::clicked, this, &SettingsWidget::setNotificationsSlot);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500708
Isa Nanic100368f2018-12-11 16:43:01 -0500709 connect(ui->closeOrMinCheckBox, &QAbstractButton::clicked, this, &SettingsWidget::setClosedOrMinSlot);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500710
Isa Nanic100368f2018-12-11 16:43:01 -0500711 connect(ui->downloadButton, &QAbstractButton::clicked, this, &SettingsWidget::openDownloadFolderSlot);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500712
Isa Nanic100368f2018-12-11 16:43:01 -0500713 connect(ui->alwaysRecordingCheckBox, &QAbstractButton::clicked, this, &SettingsWidget::setAlwaysRecordingSlot);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500714
Isa Nanic100368f2018-12-11 16:43:01 -0500715 connect(ui->checkUpdateButton, &QAbstractButton::clicked, this, &SettingsWidget::checkForUpdateSlot);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500716
717 connect(ui->intervalUpdateCheckSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), this, &SettingsWidget::setUpdateIntervalSlot);
718
Isa Nanic100368f2018-12-11 16:43:01 -0500719 connect(ui->autoUpdateCheckBox, &QAbstractButton::clicked, this, &SettingsWidget::setUpdateAutomaticSlot);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500720
721 // audio / visual settings
722
723 connect(ui->recordPathButton, &QPushButton::clicked, this, &SettingsWidget::openRecordFolderSlot);
724}
725
726
727// ************************* General Settings *************************
728
729void SettingsWidget::populateGeneralSettings()
730{
731 settings_ = new QSettings;
732
733 // settings
Isa Nanic7a3dfa42018-12-12 12:34:42 -0500734 ui->downloadButton->setText(settings_->value(SettingsKey::downloadPath).toString());
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500735 ui->closeOrMinCheckBox->setChecked(settings_->value(SettingsKey::closeOrMinimized).toBool());
736 ui->notificationCheckBox->setChecked(settings_->value(SettingsKey::enableNotifications).toBool());
737
738 //recordings
739 ui->alwaysRecordingCheckBox->setChecked(media::RecordingModel::instance().isAlwaysRecording());
740
741 if (media::RecordingModel::instance().recordPath().isEmpty()) {
742 QString recordPath = QDir::toNativeSeparators(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation));
743 media::RecordingModel::instance().setRecordPath(recordPath);
744 }
745 ui->recordPathButton->setText(media::RecordingModel::instance().recordPath());
746
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500747 ui->autoUpdateCheckBox->setChecked(win_sparkle_get_automatic_check_for_updates());
748 ui->intervalUpdateCheckSpinBox->setValue(win_sparkle_get_update_check_interval() / 86400);
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500749}
750
751void
752SettingsWidget::setNotificationsSlot(int state)
753{
754 if (state == Qt::CheckState::Unchecked) {
755 settings_->setValue(SettingsKey::enableNotifications, false);
756 } else {
757 settings_->setValue(SettingsKey::enableNotifications, true);
758 }
759}
760
761void
762SettingsWidget::setClosedOrMinSlot(int state)
763{
764 if (state == Qt::CheckState::Unchecked) {
765 settings_->setValue(SettingsKey::closeOrMinimized, false);
766 }
767 else {
768 settings_->setValue(SettingsKey::closeOrMinimized, true);
769 }
770}
771
772void
773SettingsWidget::checkForUpdateSlot()
774{
775 win_sparkle_check_update_with_ui();
776}
777
778void
779SettingsWidget::setUpdateIntervalSlot(int value)
780{
781 win_sparkle_set_update_check_interval(value * 86400);
782}
783
784void
785SettingsWidget::setUpdateAutomaticSlot(int state)
786{
787 if (state == Qt::CheckState::Unchecked) {
788 win_sparkle_set_automatic_check_for_updates(false);
789 ui->intervalUpdateCheckSpinBox->setEnabled(false);
790 } else {
791 win_sparkle_set_automatic_check_for_updates(true);
792 ui->intervalUpdateCheckSpinBox->setEnabled(true);
793 }
794}
795
796void
797SettingsWidget::openDownloadFolderSlot()
798{
799 QString dir = QFileDialog::getExistingDirectory(this, tr("Select A Folder For Your Downloads"),
800 QStandardPaths::writableLocation(QStandardPaths::DownloadLocation), QFileDialog::ShowDirsOnly
801 | QFileDialog::DontResolveSymlinks);
802
803 if (!dir.isEmpty()) {
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500804 ui->downloadButton->setText(dir);
Isa Nanic7a3dfa42018-12-12 12:34:42 -0500805 settings_->setValue(SettingsKey::downloadPath, dir);
806 LRCInstance::editableDataTransferModel()->downloadDirectory = dir.toStdString() + "/";
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500807 }
808}
809
810void
811SettingsWidget::setAlwaysRecordingSlot(int state)
812{
813 if (state == Qt::CheckState::Unchecked) {
814 media::RecordingModel::instance().setAlwaysRecording(false);
815 } else {
816 media::RecordingModel::instance().setAlwaysRecording(true);
817 }
818}
819
820void
821SettingsWidget::openRecordFolderSlot()
822{
823 QString dir = QFileDialog::getExistingDirectory(this, tr("Select A Folder For Your Recordings"),
824 media::RecordingModel::instance().recordPath(), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
825
826 if (!dir.isEmpty()) {
827 media::RecordingModel::instance().setRecordPath(dir);
828 ui->recordPathButton->setText(media::RecordingModel::instance().recordPath());
829 }
830}
831
832
833// ************************* Audio/Visual Settings *************************
834
835void
836SettingsWidget::populateAVSettings()
837{
838 ui->deviceBox->setModel(deviceModel_);
839 connect(deviceModel_, SIGNAL(currentIndexChanged(int)),
840 this, SLOT(deviceIndexChanged(int)));
841
842 if (ui->deviceBox->count() > 0) {
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500843 deviceBoxCurrentIndexChangedSlot(0);
844 }
845
Isa Nanic054ef9a2018-12-11 11:56:28 -0500846 if (currentResIndex >= 0) {
847 ui->sizeBox->setCurrentIndex(currentResIndex);
848 }
849
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500850 // Audio settings
851 auto inputModel = Audio::Settings::instance().inputDeviceModel();
852 auto outputModel = Audio::Settings::instance().outputDeviceModel();
853
854 ui->outputComboBox->setModel(outputModel);
855 ui->inputComboBox->setModel(inputModel);
856 if (ui->outputComboBox->count() > 0) {
857 ui->outputComboBox->setCurrentIndex(0);
858 }
859 if (ui->inputComboBox->count() > 0) {
860 ui->inputComboBox->setCurrentIndex(0);
861 }
862
Isa Nanic054ef9a2018-12-11 11:56:28 -0500863 isLoading_ = true;
864
865 showPreview();
866
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500867 connect(ui->outputComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
868 this, &SettingsWidget::outputDevIndexChangedSlot);
869 connect(ui->inputComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
870 this, &SettingsWidget::inputdevIndexChangedSlot);
871
872 connect(ui->deviceBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
873 &SettingsWidget::deviceBoxCurrentIndexChangedSlot);
874 connect(ui->sizeBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
875 &SettingsWidget::sizeBoxCurrentIndexChangedSlot);
Isa Nanic054ef9a2018-12-11 11:56:28 -0500876}
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500877
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500878
Isa Nanic054ef9a2018-12-11 11:56:28 -0500879void
880SettingsWidget::saveSizeIndex()
881{
882 currentResIndex = ui->sizeBox->currentIndex();
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500883}
884
885void
886SettingsWidget::showPreview()
887{
888 if (!CallModel::instance().getActiveCalls().size()) {
889 ui->previewUnavailableLabel->hide();
890 ui->videoWidget->show();
Isa Nanic054ef9a2018-12-11 11:56:28 -0500891 startVideo();
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500892 ui->videoWidget->setIsFullPreview(true);
893 } else {
894 ui->previewUnavailableLabel->show();
895 ui->videoWidget->hide();
896 }
897}
898
899void
900SettingsWidget::deviceBoxCurrentIndexChangedSlot(int index)
901{
902 if (index < 0) {
903 return;
904 }
905
906 if (!isLoading_)
907 deviceModel_->setActive(index);
908
909 auto device = deviceModel_->activeDevice();
910
911 ui->sizeBox->clear();
912
913 isLoading_ = true;
914 if (device->channelList().size() > 0) {
915 for (auto resolution : device->channelList()[0]->validResolutions()) {
916 ui->sizeBox->addItem(resolution->name());
917 }
918 }
919 ui->sizeBox->setCurrentIndex(
920 device->channelList()[0]->activeResolution()->relativeIndex());
921 isLoading_ = false;
922}
923
924void
925SettingsWidget::sizeBoxCurrentIndexChangedSlot(int index)
926{
927 auto device = deviceModel_->activeDevice();
928
929 if (index < 0) return;
930
931 device->channelList()[0]->setActiveResolution(device->channelList()[0]->validResolutions()[index]);
932}
933
934void
935SettingsWidget::deviceIndexChanged(int index)
936{
937 ui->deviceBox->setCurrentIndex(index);
938
939 ui->videoLayout->update();
940}
941
942void
943SettingsWidget::outputDevIndexChangedSlot(int index)
944{
945 auto outputModel = Audio::Settings::instance().outputDeviceModel();
946 outputModel->selectionModel()->setCurrentIndex(outputModel->index(index), QItemSelectionModel::ClearAndSelect);
947}
948
949void
950SettingsWidget::inputdevIndexChangedSlot(int index)
951{
952 auto inputModel = Audio::Settings::instance().inputDeviceModel();
953 inputModel->selectionModel()->setCurrentIndex(inputModel->index(index), QItemSelectionModel::ClearAndSelect);
Isa Nanic054ef9a2018-12-11 11:56:28 -0500954}
955
956void
957SettingsWidget::startVideo()
958{
959 Video::PreviewManager::instance().stopPreview();
960 Video::PreviewManager::instance().startPreview();
961}
962
963void
964SettingsWidget::stopVideo()
965{
966 Video::PreviewManager::instance().stopPreview();
Isa Nanic6e4a39a2018-12-04 14:26:02 -0500967}