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:
parent
95315ce608
commit
66edc82b82
11 changed files with 177 additions and 117 deletions
|
@ -54,12 +54,6 @@ AccountAdapter::getModel()
|
|||
return &(lrcInstance_->accountModel());
|
||||
}
|
||||
|
||||
NewDeviceModel*
|
||||
AccountAdapter::getDeviceModel()
|
||||
{
|
||||
return lrcInstance_->getCurrentAccountInfo().deviceModel.get();
|
||||
}
|
||||
|
||||
void
|
||||
AccountAdapter::changeAccount(int row)
|
||||
{
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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_;
|
||||
};
|
|
@ -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"),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue