1
0
Fork 0
mirror of https://git.jami.net/savoirfairelinux/jami-client-qt.git synced 2025-08-04 06:45:45 +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());
}
NewDeviceModel*
AccountAdapter::getDeviceModel()
{
return lrcInstance_->getCurrentAccountInfo().deviceModel.get();
}
void
AccountAdapter::changeAccount(int row)
{

View file

@ -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,

View file

@ -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")

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: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
*
* 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);
}

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: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
*
* 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 <QSortFilterProxyModel>
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<int, QByteArray> 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<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, "");
// 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"),

View file

@ -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

View file

@ -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)

View file

@ -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
}

View file

@ -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
}
}

View file

@ -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
}