diff --git a/src/accountadapter.cpp b/src/accountadapter.cpp index f8167597..42f93be9 100644 --- a/src/accountadapter.cpp +++ b/src/accountadapter.cpp @@ -54,12 +54,6 @@ AccountAdapter::getModel() return &(lrcInstance_->accountModel()); } -NewDeviceModel* -AccountAdapter::getDeviceModel() -{ - return lrcInstance_->getCurrentAccountInfo().deviceModel.get(); -} - void AccountAdapter::changeAccount(int row) { diff --git a/src/accountadapter.h b/src/accountadapter.h index c41dfc12..1096439b 100644 --- a/src/accountadapter.h +++ b/src/accountadapter.h @@ -34,15 +34,12 @@ class AccountAdapter final : public QmlAdapterBase Q_OBJECT Q_PROPERTY(lrc::api::NewAccountModel* model READ getModel NOTIFY modelChanged) - Q_PROPERTY(lrc::api::NewDeviceModel* deviceModel READ getDeviceModel NOTIFY deviceModelChanged) public: lrc::api::NewAccountModel* getModel(); - lrc::api::NewDeviceModel* getDeviceModel(); Q_SIGNALS: void modelChanged(); - void deviceModelChanged(); public: explicit AccountAdapter(AppSettingsManager* settingsManager, diff --git a/src/constant/JamiStrings.qml b/src/constant/JamiStrings.qml index d918879e..58553511 100644 --- a/src/constant/JamiStrings.qml +++ b/src/constant/JamiStrings.qml @@ -312,6 +312,9 @@ Item { // LinkedDevices property string tipLinkNewDevice: qsTr("Link a new device to this account") property string linkAnotherDevice: qsTr("Link another device") + property string removeDevice: qsTr("Remove Device") + property string sureToRemoveDevice: qsTr("Are you sure you wish to remove this device?") + property string linkedDevices: qsTr("Linked Devices") // BannedContacts property string tipBannedContacts: qsTr("Display or hide banned contacts") diff --git a/src/deviceitemlistmodel.cpp b/src/deviceitemlistmodel.cpp index fc2d3e41..105de958 100644 --- a/src/deviceitemlistmodel.cpp +++ b/src/deviceitemlistmodel.cpp @@ -1,6 +1,7 @@ /* - * Copyright (C) 2019-2020 by Savoir-faire Linux + * Copyright (C) 2021 by Savoir-faire Linux * Author: Yang Wang + * Author: Mingrui Zhang * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,7 +28,19 @@ DeviceItemListModel::DeviceItemListModel(QObject* parent) : AbstractListModelBase(parent) -{} +{ + connect(this, &AbstractListModelBase::lrcInstanceChanged, [this] { + if (lrcInstance_) { + if (!lrcInstance_->get_currentAccountId().isEmpty()) + onAccountChanged(); + connect(lrcInstance_, + &LRCInstance::currentAccountIdChanged, + this, + &DeviceItemListModel::onAccountChanged, + Qt::UniqueConnection); + } + }); +} DeviceItemListModel::~DeviceItemListModel() {} @@ -122,3 +135,35 @@ DeviceItemListModel::reset() beginResetModel(); endResetModel(); } + +void +DeviceItemListModel::revokeDevice(QString deviceId, QString password) +{ + lrcInstance_->getCurrentAccountInfo().deviceModel->revokeDevice(deviceId, password); +} + +void +DeviceItemListModel::onAccountChanged() +{ + reset(); + + auto* deviceModel = lrcInstance_->getCurrentAccountInfo().deviceModel.get(); + + connect(deviceModel, + &lrc::api::NewDeviceModel::deviceAdded, + this, + &DeviceItemListModel::reset, + Qt::UniqueConnection); + + connect(deviceModel, + &lrc::api::NewDeviceModel::deviceRevoked, + this, + &DeviceItemListModel::reset, + Qt::UniqueConnection); + + connect(deviceModel, + &lrc::api::NewDeviceModel::deviceUpdated, + this, + &DeviceItemListModel::reset, + Qt::UniqueConnection); +} diff --git a/src/deviceitemlistmodel.h b/src/deviceitemlistmodel.h index 93865700..96bb787f 100644 --- a/src/deviceitemlistmodel.h +++ b/src/deviceitemlistmodel.h @@ -1,6 +1,7 @@ /* - * Copyright (C) 2019-2020 by Savoir-faire Linux + * Copyright (C) 2021 by Savoir-faire Linux * Author: Yang Wang + * Author: Mingrui Zhang * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,6 +21,8 @@ #include "abstractlistmodelbase.h" +#include + class DeviceItemListModel : public AbstractListModelBase { Q_OBJECT @@ -31,22 +34,71 @@ public: explicit DeviceItemListModel(QObject* parent = nullptr); ~DeviceItemListModel(); - /* - * QAbstractListModel override. - */ + // QAbstractListModel override. int rowCount(const QModelIndex& parent = QModelIndex()) const override; int columnCount(const QModelIndex& parent) const override; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; - /* - * Override role name as access point in qml. - */ + + // Override role name as access point in qml. QHash roleNames() const override; QModelIndex index(int row, int column = 0, const QModelIndex& parent = QModelIndex()) const; QModelIndex parent(const QModelIndex& child) const; Qt::ItemFlags flags(const QModelIndex& index) const; - /* - * This function is to reset the model when there's new account added. - */ + // This function is to reset the model when there's new account added. Q_INVOKABLE void reset(); + + Q_INVOKABLE void revokeDevice(QString deviceId, QString password); + +public Q_SLOTS: + void onAccountChanged(); }; + +class DeviceItemProxyModel : public QSortFilterProxyModel +{ + Q_OBJECT + Q_PROPERTY(LRCInstance* lrcInstance READ getLrcInstance WRITE setLrcInstance) + +public: + explicit DeviceItemProxyModel(QObject* parent = nullptr) + : QSortFilterProxyModel(parent) + { + sourceModel_ = new DeviceItemListModel(this); + + setSourceModel(sourceModel_); + setSortRole(DeviceItemListModel::Role::IsCurrent); + sort(0, Qt::DescendingOrder); + setFilterCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive); + } + + bool lessThan(const QModelIndex& left, const QModelIndex& right) const override + { + QVariant leftIsCurrent = sourceModel()->data(left, DeviceItemListModel::Role::IsCurrent); + QVariant rightIsCurrent = sourceModel()->data(right, DeviceItemListModel::Role::IsCurrent); + + if (leftIsCurrent.toBool()) + return false; + if (rightIsCurrent.toBool()) + return true; + + QChar leftDeviceNameFirstChar + = sourceModel()->data(left, DeviceItemListModel::Role::DeviceName).toString().at(0); + QChar rightDeviceNameFirstChar + = sourceModel()->data(right, DeviceItemListModel::Role::DeviceName).toString().at(0); + + return leftDeviceNameFirstChar < rightDeviceNameFirstChar; + } + + LRCInstance* getLrcInstance() + { + return sourceModel_->property("lrcInstance").value(); + } + + void setLrcInstance(LRCInstance* instance) + { + sourceModel_->setProperty("lrcInstance", QVariant::fromValue(instance)); + } + +private: + DeviceItemListModel* sourceModel_; +}; \ No newline at end of file diff --git a/src/qmlregister.cpp b/src/qmlregister.cpp index dc6e6501..d9342d49 100644 --- a/src/qmlregister.cpp +++ b/src/qmlregister.cpp @@ -148,7 +148,7 @@ registerTypes(QQmlEngine* engine, QML_REGISTERNAMESPACE(NS_ENUMS, dummy::staticMetaObject, ""); // QAbstractListModels - QML_REGISTERTYPE(NS_MODELS, DeviceItemListModel); + QML_REGISTERTYPE(NS_MODELS, DeviceItemProxyModel); QML_REGISTERTYPE(NS_MODELS, BannedListModel); QML_REGISTERTYPE(NS_MODELS, ModeratorListModel); QML_REGISTERTYPE(NS_MODELS, MediaCodecListModel); @@ -215,9 +215,10 @@ registerTypes(QQmlEngine* engine, QML_REGISTERUNCREATABLE_IN_NAMESPACE(PeerDiscoveryModel, lrc::api); // Enums - QML_REGISTERUNCREATABLE(NS_ENUMS, Settings); - QML_REGISTERUNCREATABLE(NS_ENUMS, NetWorkManager); + QML_REGISTERUNCREATABLE(NS_ENUMS, Settings) + QML_REGISTERUNCREATABLE(NS_ENUMS, NetWorkManager) QML_REGISTERUNCREATABLE(NS_ENUMS, WizardViewStepModel) + QML_REGISTERUNCREATABLE(NS_ENUMS, DeviceItemListModel) engine->addImageProvider(QLatin1String("qrImage"), new QrImageProvider(lrcInstance)); engine->addImageProvider(QLatin1String("avatarImage"), diff --git a/src/settingsadapter.cpp b/src/settingsadapter.cpp index 7ec10f60..8b871a08 100644 --- a/src/settingsadapter.cpp +++ b/src/settingsadapter.cpp @@ -1017,10 +1017,7 @@ SettingsAdapter::tlsProtocolComboBoxIndexChanged(const int& index) void SettingsAdapter::setDeviceName(QString text) { - auto confProps = lrcInstance_->accountModel().getAccountConfig( - lrcInstance_->get_currentAccountId()); - confProps.deviceName = text; - lrcInstance_->accountModel().setAccountConfig(lrcInstance_->get_currentAccountId(), confProps); + lrcInstance_->getCurrentAccountInfo().deviceModel->setCurrentDeviceName(text); } void diff --git a/src/settingsview/SettingsView.qml b/src/settingsview/SettingsView.qml index 3462007e..176309a8 100644 --- a/src/settingsview/SettingsView.qml +++ b/src/settingsview/SettingsView.qml @@ -52,7 +52,6 @@ Rectangle { if(selectedMenu === sel && (!recovery)) { return } switch(sel) { case SettingsView.Account: - pageIdCurrentAccountSettings.connectCurrentAccount() AccountAdapter.stopPreviewing() selectedMenu = sel pageIdCurrentAccountSettings.updateAccountInfoDisplayed() @@ -97,7 +96,6 @@ Rectangle { var accountList = AccountAdapter.model.getAccountList() if(accountList.length === 0) return - pageIdCurrentAccountSettings.disconnectAccountConnections() var device = AVModel.getDefaultDevice() if(device.length === 0) { AVModel.setCurrentVideoCaptureDevice(device) diff --git a/src/settingsview/components/CurrentAccountSettings.qml b/src/settingsview/components/CurrentAccountSettings.qml index 23b65de7..bb73b747 100644 --- a/src/settingsview/components/CurrentAccountSettings.qml +++ b/src/settingsview/components/CurrentAccountSettings.qml @@ -44,7 +44,6 @@ Rectangle { accountEnableCheckBox.checked = SettingsAdapter.get_CurrentAccountInfo_Enabled() accountProfile.updateAccountInfo() userIdentity.updateAccountInfo() - linkedDevices.updateAndShowDevicesSlot() bannedContacts.updateAndShowBannedContactsSlot() advancedSettings.updateAdvancedAccountInfos() var isJams = !isSIP && SettingsAdapter.getAccountConfig_Manageruri() !== "" @@ -69,16 +68,6 @@ Rectangle { deleteAccountDialog.openDialog() } - function connectCurrentAccount() { - if (!isSIP) { - linkedDevices.connectCurrentAccount(true) - } - } - - function disconnectAccountConnections() { - linkedDevices.connectCurrentAccount(false) - } - function getAdvancedSettingsScrollPosition() { return advancedSettings.y } diff --git a/src/settingsview/components/DeviceItemDelegate.qml b/src/settingsview/components/DeviceItemDelegate.qml index fd54624f..fcb1337f 100644 --- a/src/settingsview/components/DeviceItemDelegate.qml +++ b/src/settingsview/components/DeviceItemDelegate.qml @@ -38,26 +38,11 @@ ItemDelegate { signal btnRemoveDeviceClicked - function toggleEditable() { - editable = !editable - if (!editable) { - SettingsAdapter.setDeviceName(elidedTextDeviceName.text) - } - } + highlighted: ListView.isCurrentItem background: Rectangle { color: highlighted? JamiTheme.selectedColor : JamiTheme.editBackgroundColor } - highlighted: ListView.isCurrentItem - - CustomBorder { - commonBorder: false - lBorderwidth: 0 - rBorderwidth: 0 - tBorderwidth: 0 - bBorderwidth: 2 - borderColor: JamiTheme.selectedColor - } RowLayout { anchors.fill: root @@ -80,6 +65,8 @@ ItemDelegate { } ColumnLayout { + id: deviceInfoColumnLayout + Layout.fillWidth: true Layout.fillHeight: true Layout.leftMargin: JamiTheme.preferredMarginSize @@ -91,32 +78,50 @@ ItemDelegate { Layout.fillWidth: true Layout.preferredHeight: 30 + padding: 8 font.pointSize: JamiTheme.textFontSize + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + wrapMode: Text.NoWrap readOnly: !editable + loseFocusWhenEnterPressed: true backgroundColor: JamiTheme.editBackgroundColor - text: elidedTextDeviceName.elidedText - padding: 8 + + onEditingFinished: { + SettingsAdapter.setDeviceName(editDeviceName.text) + editable = !editable + } + onReadOnlyChanged: { + if (readOnly) + editDeviceName.text = Qt.binding(function() { + return elidedTextDeviceName.elidedText + }) + else + editDeviceName.text = deviceName + } + + TextMetrics { + id: elidedTextDeviceName + + font: editDeviceName.font + elide: Text.ElideRight + elideWidth: editDeviceName.width - editDeviceName.leftPadding * 2 + text: deviceName + } } - TextMetrics { - id: elidedTextDeviceName - - elide: Text.ElideRight - elideWidth: root.width - btnEditDevice.width - deviceImage.width - - editDeviceName.leftPadding - text: deviceName - } - - ElidedTextLabel { + Text { id: labelDeviceId Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + Layout.fillWidth: true Layout.leftMargin: editDeviceName.leftPadding - maxWidth: root.width - btnEditDevice.width - deviceImage.width - eText: deviceId === "" ? qsTr("Device Id") : deviceId + elide: Text.ElideRight + color: JamiTheme.textColor + text: deviceId === "" ? qsTr("Device Id") : deviceId } } @@ -147,11 +152,23 @@ ItemDelegate { onClicked: { if (isCurrent) { - toggleEditable() + if (!editable) + editable = !editable + else + editDeviceName.focus = false } else { btnRemoveDeviceClicked() } } } } + + CustomBorder { + commonBorder: false + lBorderwidth: 0 + rBorderwidth: 0 + tBorderwidth: 0 + bBorderwidth: 2 + borderColor: JamiTheme.selectedColor + } } diff --git a/src/settingsview/components/LinkedDevices.qml b/src/settingsview/components/LinkedDevices.qml index 458c0461..a57e91f1 100644 --- a/src/settingsview/components/LinkedDevices.qml +++ b/src/settingsview/components/LinkedDevices.qml @@ -23,31 +23,13 @@ import QtQuick.Layouts 1.15 import net.jami.Models 1.1 import net.jami.Adapters 1.1 import net.jami.Constants 1.1 +import net.jami.Enums 1.1 import "../../commoncomponents" ColumnLayout { id:root - Connections { - id: accountConnections_DeviceModel - - target: AccountAdapter.deviceModel - enabled: root.visible - - function onDeviceAdded(id) { - updateAndShowDevicesSlot() - } - - function onDeviceRevoked(id, status) { - updateAndShowDevicesSlot() - } - - function onDeviceUpdated(id) { - updateAndShowDevicesSlot() - } - } - Connections { id: accountConnections @@ -61,24 +43,9 @@ ColumnLayout { } } - function connectCurrentAccount(status) { - accountConnections_DeviceModel.enabled = status - } - - function updateAndShowDevicesSlot() { - if (SettingsAdapter.getAccountConfig_Manageruri() === ""){ - linkDevPushButton.visible = SettingsAdapter.get_CurrentAccountInfo_Enabled() - } - settingsListView.model.reset() - } - - function revokeDeviceWithIDAndPassword(idDevice, password){ - AccountAdapter.deviceModel.revokeDevice(idDevice, password) - updateAndShowDevicesSlot() - } - function removeDeviceSlot(index){ - var idOfDevice = settingsListView.model.data(settingsListView.model.index(index,0), DeviceItemListModel.DeviceID) + var idOfDevice = settingsListView.model.data(settingsListView.model.index(index,0), + DeviceItemListModel.DeviceID) if(AccountAdapter.hasPassword()){ revokeDevicePasswordDialog.openRevokeDeviceDialog(idOfDevice) } else { @@ -89,14 +56,12 @@ ColumnLayout { LinkDeviceDialog { id: linkDeviceDialog - - onAccepted: updateAndShowDevicesSlot() } RevokeDevicePasswordDialog{ id: revokeDevicePasswordDialog - onRevokeDeviceWithPassword: revokeDeviceWithIDAndPassword(idOfDevice, password) + onRevokeDeviceWithPassword: deviceItemListModel.revokeDevice(idOfDevice, password) } SimpleMessageDialog { @@ -104,19 +69,19 @@ ColumnLayout { property string idOfDev: "" - title: qsTr("Remove Device") - infoText: qsTr("Are you sure you wish to remove this device?") + title: JamiStrings.removeDevice + infoText: JamiStrings.sureToRemoveDevice - buttonTitles: [qsTr("Ok"), qsTr("Cancel")] + buttonTitles: [JamiStrings.optionOk, JamiStrings.optionCancel] buttonStyles: [SimpleMessageDialog.ButtonStyle.TintedBlue, SimpleMessageDialog.ButtonStyle.TintedBlack] - buttonCallBacks: [function() {revokeDeviceWithIDAndPassword(idOfDev, "")}] + buttonCallBacks: [function() {deviceItemListModel.revokeDevice(idOfDev, "")}] } Label { Layout.preferredHeight: JamiTheme.preferredFieldHeight - text: qsTr("Linked Devices") + text: JamiStrings.linkedDevices color: JamiTheme.textColor font.pointSize: JamiTheme.headerFontSize @@ -129,7 +94,9 @@ ColumnLayout { Layout.fillWidth: true Layout.preferredHeight: 160 - model: DeviceItemListModel { + model: DeviceItemProxyModel { + id: deviceItemListModel + lrcInstance: LRCInstance }