1
0
Fork 0
mirror of https://git.jami.net/savoirfairelinux/jami-client-qt.git synced 2025-08-11 02:05:40 +02:00

settingsview: LinkedDevices view refactor

1. Remove deviceModel from AccountAdapter
2. Use QSortFilterProxyModel to make sure that
   current device is always on top and the rest are
   in alphabetical order
3. Elide device name properly in DeviceItemDelegate

Change-Id: Ic66a11fb4a4a8cca65916653e0981b15c939bce6
This commit is contained in:
Ming Rui Zhang 2021-08-11 14:08:34 -04:00
parent 95315ce608
commit 66edc82b82
11 changed files with 177 additions and 117 deletions

View file

@ -54,12 +54,6 @@ AccountAdapter::getModel()
return &(lrcInstance_->accountModel()); return &(lrcInstance_->accountModel());
} }
NewDeviceModel*
AccountAdapter::getDeviceModel()
{
return lrcInstance_->getCurrentAccountInfo().deviceModel.get();
}
void void
AccountAdapter::changeAccount(int row) AccountAdapter::changeAccount(int row)
{ {

View file

@ -34,15 +34,12 @@ class AccountAdapter final : public QmlAdapterBase
Q_OBJECT Q_OBJECT
Q_PROPERTY(lrc::api::NewAccountModel* model READ getModel NOTIFY modelChanged) Q_PROPERTY(lrc::api::NewAccountModel* model READ getModel NOTIFY modelChanged)
Q_PROPERTY(lrc::api::NewDeviceModel* deviceModel READ getDeviceModel NOTIFY deviceModelChanged)
public: public:
lrc::api::NewAccountModel* getModel(); lrc::api::NewAccountModel* getModel();
lrc::api::NewDeviceModel* getDeviceModel();
Q_SIGNALS: Q_SIGNALS:
void modelChanged(); void modelChanged();
void deviceModelChanged();
public: public:
explicit AccountAdapter(AppSettingsManager* settingsManager, explicit AccountAdapter(AppSettingsManager* settingsManager,

View file

@ -312,6 +312,9 @@ Item {
// LinkedDevices // LinkedDevices
property string tipLinkNewDevice: qsTr("Link a new device to this account") property string tipLinkNewDevice: qsTr("Link a new device to this account")
property string linkAnotherDevice: qsTr("Link another device") 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 // BannedContacts
property string tipBannedContacts: qsTr("Display or hide banned contacts") property string tipBannedContacts: qsTr("Display or hide banned contacts")

View file

@ -1,6 +1,7 @@
/* /*
* Copyright (C) 2019-2020 by Savoir-faire Linux * Copyright (C) 2021 by Savoir-faire Linux
* Author: Yang Wang <yang.wang@savoirfairelinux.com> * Author: Yang Wang <yang.wang@savoirfairelinux.com>
* Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -27,7 +28,19 @@
DeviceItemListModel::DeviceItemListModel(QObject* parent) DeviceItemListModel::DeviceItemListModel(QObject* parent)
: AbstractListModelBase(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() {} DeviceItemListModel::~DeviceItemListModel() {}
@ -122,3 +135,35 @@ DeviceItemListModel::reset()
beginResetModel(); beginResetModel();
endResetModel(); 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);
}

View file

@ -1,6 +1,7 @@
/* /*
* Copyright (C) 2019-2020 by Savoir-faire Linux * Copyright (C) 2021 by Savoir-faire Linux
* Author: Yang Wang <yang.wang@savoirfairelinux.com> * Author: Yang Wang <yang.wang@savoirfairelinux.com>
* Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -20,6 +21,8 @@
#include "abstractlistmodelbase.h" #include "abstractlistmodelbase.h"
#include <QSortFilterProxyModel>
class DeviceItemListModel : public AbstractListModelBase class DeviceItemListModel : public AbstractListModelBase
{ {
Q_OBJECT Q_OBJECT
@ -31,22 +34,71 @@ public:
explicit DeviceItemListModel(QObject* parent = nullptr); explicit DeviceItemListModel(QObject* parent = nullptr);
~DeviceItemListModel(); ~DeviceItemListModel();
/* // QAbstractListModel override.
* QAbstractListModel override.
*/
int rowCount(const QModelIndex& parent = QModelIndex()) const override; int rowCount(const QModelIndex& parent = QModelIndex()) const override;
int columnCount(const QModelIndex& parent) const override; int columnCount(const QModelIndex& parent) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) 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<int, QByteArray> roleNames() const override; QHash<int, QByteArray> roleNames() const override;
QModelIndex index(int row, int column = 0, const QModelIndex& parent = QModelIndex()) const; QModelIndex index(int row, int column = 0, const QModelIndex& parent = QModelIndex()) const;
QModelIndex parent(const QModelIndex& child) const; QModelIndex parent(const QModelIndex& child) const;
Qt::ItemFlags flags(const QModelIndex& index) 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 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<LRCInstance*>();
}
void setLrcInstance(LRCInstance* instance)
{
sourceModel_->setProperty("lrcInstance", QVariant::fromValue(instance));
}
private:
DeviceItemListModel* sourceModel_;
}; };

View file

@ -148,7 +148,7 @@ registerTypes(QQmlEngine* engine,
QML_REGISTERNAMESPACE(NS_ENUMS, dummy::staticMetaObject, ""); QML_REGISTERNAMESPACE(NS_ENUMS, dummy::staticMetaObject, "");
// QAbstractListModels // QAbstractListModels
QML_REGISTERTYPE(NS_MODELS, DeviceItemListModel); QML_REGISTERTYPE(NS_MODELS, DeviceItemProxyModel);
QML_REGISTERTYPE(NS_MODELS, BannedListModel); QML_REGISTERTYPE(NS_MODELS, BannedListModel);
QML_REGISTERTYPE(NS_MODELS, ModeratorListModel); QML_REGISTERTYPE(NS_MODELS, ModeratorListModel);
QML_REGISTERTYPE(NS_MODELS, MediaCodecListModel); QML_REGISTERTYPE(NS_MODELS, MediaCodecListModel);
@ -215,9 +215,10 @@ registerTypes(QQmlEngine* engine,
QML_REGISTERUNCREATABLE_IN_NAMESPACE(PeerDiscoveryModel, lrc::api); QML_REGISTERUNCREATABLE_IN_NAMESPACE(PeerDiscoveryModel, lrc::api);
// Enums // Enums
QML_REGISTERUNCREATABLE(NS_ENUMS, Settings); QML_REGISTERUNCREATABLE(NS_ENUMS, Settings)
QML_REGISTERUNCREATABLE(NS_ENUMS, NetWorkManager); QML_REGISTERUNCREATABLE(NS_ENUMS, NetWorkManager)
QML_REGISTERUNCREATABLE(NS_ENUMS, WizardViewStepModel) QML_REGISTERUNCREATABLE(NS_ENUMS, WizardViewStepModel)
QML_REGISTERUNCREATABLE(NS_ENUMS, DeviceItemListModel)
engine->addImageProvider(QLatin1String("qrImage"), new QrImageProvider(lrcInstance)); engine->addImageProvider(QLatin1String("qrImage"), new QrImageProvider(lrcInstance));
engine->addImageProvider(QLatin1String("avatarImage"), engine->addImageProvider(QLatin1String("avatarImage"),

View file

@ -1017,10 +1017,7 @@ SettingsAdapter::tlsProtocolComboBoxIndexChanged(const int& index)
void void
SettingsAdapter::setDeviceName(QString text) SettingsAdapter::setDeviceName(QString text)
{ {
auto confProps = lrcInstance_->accountModel().getAccountConfig( lrcInstance_->getCurrentAccountInfo().deviceModel->setCurrentDeviceName(text);
lrcInstance_->get_currentAccountId());
confProps.deviceName = text;
lrcInstance_->accountModel().setAccountConfig(lrcInstance_->get_currentAccountId(), confProps);
} }
void void

View file

@ -52,7 +52,6 @@ Rectangle {
if(selectedMenu === sel && (!recovery)) { return } if(selectedMenu === sel && (!recovery)) { return }
switch(sel) { switch(sel) {
case SettingsView.Account: case SettingsView.Account:
pageIdCurrentAccountSettings.connectCurrentAccount()
AccountAdapter.stopPreviewing() AccountAdapter.stopPreviewing()
selectedMenu = sel selectedMenu = sel
pageIdCurrentAccountSettings.updateAccountInfoDisplayed() pageIdCurrentAccountSettings.updateAccountInfoDisplayed()
@ -97,7 +96,6 @@ Rectangle {
var accountList = AccountAdapter.model.getAccountList() var accountList = AccountAdapter.model.getAccountList()
if(accountList.length === 0) if(accountList.length === 0)
return return
pageIdCurrentAccountSettings.disconnectAccountConnections()
var device = AVModel.getDefaultDevice() var device = AVModel.getDefaultDevice()
if(device.length === 0) { if(device.length === 0) {
AVModel.setCurrentVideoCaptureDevice(device) AVModel.setCurrentVideoCaptureDevice(device)

View file

@ -44,7 +44,6 @@ Rectangle {
accountEnableCheckBox.checked = SettingsAdapter.get_CurrentAccountInfo_Enabled() accountEnableCheckBox.checked = SettingsAdapter.get_CurrentAccountInfo_Enabled()
accountProfile.updateAccountInfo() accountProfile.updateAccountInfo()
userIdentity.updateAccountInfo() userIdentity.updateAccountInfo()
linkedDevices.updateAndShowDevicesSlot()
bannedContacts.updateAndShowBannedContactsSlot() bannedContacts.updateAndShowBannedContactsSlot()
advancedSettings.updateAdvancedAccountInfos() advancedSettings.updateAdvancedAccountInfos()
var isJams = !isSIP && SettingsAdapter.getAccountConfig_Manageruri() !== "" var isJams = !isSIP && SettingsAdapter.getAccountConfig_Manageruri() !== ""
@ -69,16 +68,6 @@ Rectangle {
deleteAccountDialog.openDialog() deleteAccountDialog.openDialog()
} }
function connectCurrentAccount() {
if (!isSIP) {
linkedDevices.connectCurrentAccount(true)
}
}
function disconnectAccountConnections() {
linkedDevices.connectCurrentAccount(false)
}
function getAdvancedSettingsScrollPosition() { function getAdvancedSettingsScrollPosition() {
return advancedSettings.y return advancedSettings.y
} }

View file

@ -38,26 +38,11 @@ ItemDelegate {
signal btnRemoveDeviceClicked signal btnRemoveDeviceClicked
function toggleEditable() { highlighted: ListView.isCurrentItem
editable = !editable
if (!editable) {
SettingsAdapter.setDeviceName(elidedTextDeviceName.text)
}
}
background: Rectangle { background: Rectangle {
color: highlighted? JamiTheme.selectedColor : JamiTheme.editBackgroundColor color: highlighted? JamiTheme.selectedColor : JamiTheme.editBackgroundColor
} }
highlighted: ListView.isCurrentItem
CustomBorder {
commonBorder: false
lBorderwidth: 0
rBorderwidth: 0
tBorderwidth: 0
bBorderwidth: 2
borderColor: JamiTheme.selectedColor
}
RowLayout { RowLayout {
anchors.fill: root anchors.fill: root
@ -80,6 +65,8 @@ ItemDelegate {
} }
ColumnLayout { ColumnLayout {
id: deviceInfoColumnLayout
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
Layout.leftMargin: JamiTheme.preferredMarginSize Layout.leftMargin: JamiTheme.preferredMarginSize
@ -91,32 +78,50 @@ ItemDelegate {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 30 Layout.preferredHeight: 30
padding: 8
font.pointSize: JamiTheme.textFontSize font.pointSize: JamiTheme.textFontSize
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
wrapMode: Text.NoWrap wrapMode: Text.NoWrap
readOnly: !editable readOnly: !editable
loseFocusWhenEnterPressed: true
backgroundColor: JamiTheme.editBackgroundColor 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 { TextMetrics {
id: elidedTextDeviceName id: elidedTextDeviceName
font: editDeviceName.font
elide: Text.ElideRight elide: Text.ElideRight
elideWidth: root.width - btnEditDevice.width - deviceImage.width elideWidth: editDeviceName.width - editDeviceName.leftPadding * 2
- editDeviceName.leftPadding
text: deviceName text: deviceName
} }
}
ElidedTextLabel { Text {
id: labelDeviceId id: labelDeviceId
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
Layout.fillWidth: true
Layout.leftMargin: editDeviceName.leftPadding Layout.leftMargin: editDeviceName.leftPadding
maxWidth: root.width - btnEditDevice.width - deviceImage.width elide: Text.ElideRight
eText: deviceId === "" ? qsTr("Device Id") : deviceId color: JamiTheme.textColor
text: deviceId === "" ? qsTr("Device Id") : deviceId
} }
} }
@ -147,11 +152,23 @@ ItemDelegate {
onClicked: { onClicked: {
if (isCurrent) { if (isCurrent) {
toggleEditable() if (!editable)
editable = !editable
else
editDeviceName.focus = false
} else { } else {
btnRemoveDeviceClicked() btnRemoveDeviceClicked()
} }
} }
} }
} }
CustomBorder {
commonBorder: false
lBorderwidth: 0
rBorderwidth: 0
tBorderwidth: 0
bBorderwidth: 2
borderColor: JamiTheme.selectedColor
}
} }

View file

@ -23,31 +23,13 @@ import QtQuick.Layouts 1.15
import net.jami.Models 1.1 import net.jami.Models 1.1
import net.jami.Adapters 1.1 import net.jami.Adapters 1.1
import net.jami.Constants 1.1 import net.jami.Constants 1.1
import net.jami.Enums 1.1
import "../../commoncomponents" import "../../commoncomponents"
ColumnLayout { ColumnLayout {
id:root 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 { Connections {
id: accountConnections 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){ 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()){ if(AccountAdapter.hasPassword()){
revokeDevicePasswordDialog.openRevokeDeviceDialog(idOfDevice) revokeDevicePasswordDialog.openRevokeDeviceDialog(idOfDevice)
} else { } else {
@ -89,14 +56,12 @@ ColumnLayout {
LinkDeviceDialog { LinkDeviceDialog {
id: linkDeviceDialog id: linkDeviceDialog
onAccepted: updateAndShowDevicesSlot()
} }
RevokeDevicePasswordDialog{ RevokeDevicePasswordDialog{
id: revokeDevicePasswordDialog id: revokeDevicePasswordDialog
onRevokeDeviceWithPassword: revokeDeviceWithIDAndPassword(idOfDevice, password) onRevokeDeviceWithPassword: deviceItemListModel.revokeDevice(idOfDevice, password)
} }
SimpleMessageDialog { SimpleMessageDialog {
@ -104,19 +69,19 @@ ColumnLayout {
property string idOfDev: "" property string idOfDev: ""
title: qsTr("Remove Device") title: JamiStrings.removeDevice
infoText: qsTr("Are you sure you wish to remove this device?") infoText: JamiStrings.sureToRemoveDevice
buttonTitles: [qsTr("Ok"), qsTr("Cancel")] buttonTitles: [JamiStrings.optionOk, JamiStrings.optionCancel]
buttonStyles: [SimpleMessageDialog.ButtonStyle.TintedBlue, buttonStyles: [SimpleMessageDialog.ButtonStyle.TintedBlue,
SimpleMessageDialog.ButtonStyle.TintedBlack] SimpleMessageDialog.ButtonStyle.TintedBlack]
buttonCallBacks: [function() {revokeDeviceWithIDAndPassword(idOfDev, "")}] buttonCallBacks: [function() {deviceItemListModel.revokeDevice(idOfDev, "")}]
} }
Label { Label {
Layout.preferredHeight: JamiTheme.preferredFieldHeight Layout.preferredHeight: JamiTheme.preferredFieldHeight
text: qsTr("Linked Devices") text: JamiStrings.linkedDevices
color: JamiTheme.textColor color: JamiTheme.textColor
font.pointSize: JamiTheme.headerFontSize font.pointSize: JamiTheme.headerFontSize
@ -129,7 +94,9 @@ ColumnLayout {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 160 Layout.preferredHeight: 160
model: DeviceItemListModel { model: DeviceItemProxyModel {
id: deviceItemListModel
lrcInstance: LRCInstance lrcInstance: LRCInstance
} }