From 4d8b006c348cbcd0787f312a199862d24d08a02f Mon Sep 17 00:00:00 2001 From: Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com> Date: Wed, 10 May 2023 16:17:48 -0300 Subject: [PATCH] settingssidepanel: use ListView Change-Id: I034edd72522badee2adb1ca558518854938b6deb --- src/app/ViewManager.qml | 48 +-- src/app/settingsview/SettingsSidePanel.qml | 372 ++++++++++----------- src/app/settingsview/SettingsView.qml | 20 +- 3 files changed, 216 insertions(+), 224 deletions(-) diff --git a/src/app/ViewManager.qml b/src/app/ViewManager.qml index b6ce50962..24cf22973 100644 --- a/src/app/ViewManager.qml +++ b/src/app/ViewManager.qml @@ -26,13 +26,13 @@ QtObject { // The number of views loaded (`views` is only resized). function viewCount() { - return Object.keys(views).length; + return Object.keys(views).length } // Destroy all views. function destroyAllViews() { for (var path in views) { - destroyView(path); + destroyView(path) } } @@ -40,50 +40,50 @@ QtObject { if (views.hasOwnProperty(path)) { // an instance of <path> already exists if (cb !== null) { - cb(views[path]); + cb(views[path]) } - return views[path]; + return views[path] } - const component = Qt.createComponent(Qt.resolvedUrl(path)); + const component = Qt.createComponent(Qt.resolvedUrl(path)) if (component.status === Component.Ready) { - const obj = component.createObject(parent, props); + const obj = component.createObject(parent, props) if (obj === null) { - print("error creating object"); - return null; + print("error creating object") + return null } - views[path] = obj; + views[path] = obj // Set the view name to the object name if it has one. - const viewName = obj.objectName.toString() !== '' ? obj.objectName : path.replace(/^.*[\\\/]/, '').replace(/\.[^/.]+$/, ""); - viewPaths[viewName] = path; + const viewName = obj.objectName.toString() !== '' ? obj.objectName : path.replace(/^.*[\\\/]/, '').replace(/\.[^/.]+$/, "") + viewPaths[viewName] = path if (cb !== null) { - cb(obj); + cb(obj) } - return views[path]; + return views[path] } - print("error creating component", path); - console.error(component.errorString()); - Qt.exit(1); - return null; + print("error creating component", path) + console.error(component.errorString()) + Qt.exit(1) + return null } function destroyView(path) { // The view may already have been destroyed. if (!views.hasOwnProperty(path)) { - return false; + return false } - views[path].destroy(); - delete views[path]; + views[path].destroy() + delete views[path] // Remove the view name from the viewPaths map. for (var viewName in viewPaths) { if (viewPaths[viewName] === path) { - delete viewPaths[viewName]; - break; + delete viewPaths[viewName] + break } } - return true; + return true } function getView(viewName) { - return views[viewPaths[viewName]] || null; + return views[viewPaths[viewName]] || null } } diff --git a/src/app/settingsview/SettingsSidePanel.qml b/src/app/settingsview/SettingsSidePanel.qml index 50b7ea167..b335f755d 100644 --- a/src/app/settingsview/SettingsSidePanel.qml +++ b/src/app/settingsview/SettingsSidePanel.qml @@ -32,12 +32,125 @@ SidePanelBase { color: JamiTheme.backgroundColor property int currentIndex + property bool isSinglePane - function createChild() { - if (page.menu === undefined) { - return; + function getHeaders() { + return [{ + "title": JamiStrings.accountSettingsMenuTitle, + "icon": JamiResources.account_24dp_svg, + "first": 0, + "last": 4, + "children": [{ + "id": 0, + "title": JamiStrings.manageAccountSettingsTitle + }, { + "id": 1, + "title": JamiStrings.customizeProfile + }, { + "id": 2, + "title": JamiStrings.linkedDevicesSettingsTitle, + "visible": CurrentAccount.type !== Profile.Type.SIP + }, { + "id": 3, + "title": JamiStrings.callSettingsTitle + }, { + "id": 4, + "title": JamiStrings.advancedSettingsTitle + }] + }, { + "title": JamiStrings.generalSettingsTitle, + "icon": JamiResources.gear_black_24dp_svg, + "first": 5, + "last": 11, + "children": [{ + "id": 5, + "title": JamiStrings.system + }, { + "id": 6, + "title": JamiStrings.appearence + }, { + "id": 7, + "title": JamiStrings.locationSharingLabel + }, { + "id": 8, + "title": JamiStrings.fileTransfer + }, { + "id": 9, + "title": JamiStrings.callRecording + }, { + "id": 10, + "title": JamiStrings.troubleshootTitle + }, { + "id": 11, + "title": JamiStrings.updatesTitle, + "visible": UpdateManager.isUpdaterEnabled() + }] + }, { + "title": JamiStrings.audioVideoSettingsTitle, + "icon": JamiResources.media_black_24dp_svg, + "first": 12, + "last": 14, + "children": [{ + "id": 12, + "title": JamiStrings.audio + }, { + "id": 13, + "title": JamiStrings.video + }, { + "id": 14, + "title": JamiStrings.screenSharing + }] + }, { + "title": JamiStrings.pluginSettingsTitle, + "icon": JamiResources.plugins_24dp_svg, + "first": 15, + "last": 15, + "children": [{ + "id": 15, + "title": JamiStrings.pluginSettingsTitle + }] + }]; + } + + function updateModel() { + if (visible) { + listView.model = {} + listView.model = getHeaders() + } + } + + Connections { + target: UtilsAdapter + + function onChangeLanguage() { + updateModel() + } + } + + // Bind to requests for a settings page to be selected via shorcut. + Connections { + target: JamiQmlUtils + function onSettingsPageRequested(index) { + viewCoordinator.present("SettingsView") + root.indexSelected(index) + root.currentIndex = index } - page.menu.createChild(); + } + + onIsSinglePaneChanged: { + if (visible && !isSinglePane) + select(root.currentIndex) + } + + function open(index) { + indexSelected(index) + root.currentIndex = index + } + + function select(index) { + if (!root.isSinglePane) + indexSelected(index) + root.currentIndex = index } Page { @@ -50,216 +163,87 @@ SidePanelBase { header: AccountComboBox { } - // Bind to requests for a settings page to be selected via shorcut. - Connections { - target: JamiQmlUtils - function onSettingsPageRequested(index) { - viewCoordinator.present("SettingsView"); - root.indexSelected(index); - root.currentIndex = index; - } - } - - property var menu: undefined - - Flickable { - id: flick - width: root.width - height: childrenRect.height + ListView { + id: listView + width: page.width + height: page.height clip: true - contentHeight: col.implicitHeight - - function getHeaders() { - return [{ - "title": JamiStrings.accountSettingsMenuTitle, - "icon": JamiResources.account_24dp_svg, - "children": [{ - "id": 0, - "title": JamiStrings.manageAccountSettingsTitle - }, { - "id": 1, - "title": JamiStrings.customizeProfile - }, { - "id": 2, - "title": JamiStrings.linkedDevicesSettingsTitle, - "visible": "isJamiAccount" - }, { - "id": 3, - "title": JamiStrings.callSettingsTitle - }, { - "id": 4, - "title": JamiStrings.advancedSettingsTitle - }] - }, { - "title": JamiStrings.generalSettingsTitle, - "icon": JamiResources.gear_black_24dp_svg, - "children": [{ - "id": 5, - "title": JamiStrings.system - }, { - "id": 6, - "title": JamiStrings.appearence - }, { - "id": 7, - "title": JamiStrings.locationSharingLabel - }, { - "id": 8, - "title": JamiStrings.fileTransfer - }, { - "id": 9, - "title": JamiStrings.callRecording - }, { - "id": 10, - "title": JamiStrings.troubleshootTitle - }, { - "id": 11, - "title": JamiStrings.updatesTitle, - "visible": "isUpdatable" - }] - }, { - "title": JamiStrings.audioVideoSettingsTitle, - "icon": JamiResources.media_black_24dp_svg, - "children": [{ - "id": 12, - "title": JamiStrings.audio - }, { - "id": 13, - "title": JamiStrings.video - }, { - "id": 14, - "title": JamiStrings.screenSharing - }] - }, { - "title": JamiStrings.pluginSettingsTitle, - "icon": JamiResources.plugins_24dp_svg, - "children": [{ - "id": 15, - "title": JamiStrings.pluginSettingsTitle - }] - }]; - } + contentHeight: contentItem.childrenRect.height - Column { + model: getHeaders() + delegate: ColumnLayout { id: col - anchors.left: parent.left - Component.onCompleted: { - page.menu = clv.createObject(this, { - "base": flick.getHeaders() - }); - } - } - Component { - id: clv + width: page.width + property bool isChildSelected: root.currentIndex >= modelData.first && root.currentIndex <= modelData.last - Repeater { - id: repeater + PushButton { + buttonText: modelData.title + circled: false + radius: 0 - property var base: ({}) - property var selected: null - model: Object.keys(base) - Layout.fillWidth: true - - function createChild() { - itemAt(0).children[0].createChild(); - root.currentIndex = 0; - } - - ColumnLayout { - id: clvButtons - spacing: 0 - Layout.fillWidth: true - - PushButton { - id: btn - property var sprite: null - property bool showFocusMargin: true - - property var isChildren: { - var ob = base[modelData]; - var c = ob["children"]; - return c === undefined; - } + alignement: Text.AlignLeft + Layout.preferredWidth: parent.width + Layout.leftMargin: 0 + preferredLeftMargin: 25 - function updateVisibility() { - var currentVisibility = visible; - var ob = base[modelData]; - var c = ob["visible"]; - if (c === undefined) - return true; - var res = false; - if (c === "isUpdatable") { - res = UpdateManager.isUpdaterEnabled(); - } else if (c === "isJamiAccount") { - res = CurrentAccount.type !== Profile.Type.SIP; - } else { - console.warn("Visibility condition not managed"); - } - if (currentVisibility !== res && root.currentIndex === ob["id"]) { - // If a menu disappears, go to the first index - root.currentIndex = 0; - root.indexSelected(0); - } - return res; - } + imageContainerWidth: 30 + height: JamiTheme.settingsMenuHeaderButtonHeight - function createChild() { - var ob = base[modelData]; - if (sprite === null) { - //deselect the current selection and collapse menu - if (repeater.selected) - repeater.selected.destroy(); - var c = ob["children"]; - if (c !== undefined) { - sprite = clv.createObject(parent, { - "base": c - }); - repeater.selected = sprite; - indexSelected(c[0]["id"]); - root.currentIndex = c[0]["id"]; - } else { - indexSelected(ob["id"]); - root.currentIndex = ob["id"]; - } - } - } + buttonTextFont.pixelSize: JamiTheme.settingsDescriptionPixelSize + buttonTextColor: isChildSelected ? JamiTheme.tintedBlue : JamiTheme.primaryForegroundColor + buttonTextFont.weight: isChildSelected ? Font.Medium : Font.Normal + buttonTextEnableElide: true - visible: updateVisibility() + normalColor: isChildSelected ? JamiTheme.smartListSelectedColor : "transparent" + hoveredColor: JamiTheme.smartListHoveredColor + imageColor: JamiTheme.tintedBlue - property bool isOpen: !isChildren && sprite != null - property bool isChildOpen: isChildren && (base[modelData]["id"] === root.currentIndex) + source: modelData.icon - alignement: Text.AlignLeft - Layout.preferredWidth: root.width - (isChildren ? 28 : 0) - Layout.leftMargin: isChildren ? 28 : 0 - preferredLeftMargin: isChildren ? 47 : 25 + onClicked: select(modelData.first) + Keys.onPressed: function (keyEvent) { + if (keyEvent.key === Qt.Key_Enter || keyEvent.key === Qt.Key_Return) { + clicked(); + keyEvent.accepted = true; + } + } + } - imageContainerWidth: !isChildren ? 30 : 0 - height: isChildren ? JamiTheme.settingsMenuChildrenButtonHeight : JamiTheme.settingsMenuHeaderButtonHeight + ListView { + id: childListView + width: parent.width + height: childrenRect.height + clip: true + visible: isChildSelected + model: modelData.children + delegate: ColumnLayout { + id: childCol + width: childListView.width + property bool isSelected: root.currentIndex == modelData.id + PushButton { + buttonText: modelData.title circled: false radius: 0 + visible: modelData.visible ? modelData.visible : true - buttonText: { - return base[modelData]["title"]; - } + alignement: Text.AlignLeft + Layout.preferredWidth: parent.width - 28 + Layout.leftMargin: 28 + preferredLeftMargin: 47 - buttonTextFont.pixelSize: !isChildren ? JamiTheme.settingsDescriptionPixelSize : JamiTheme.settingMenuPixelSize - buttonTextColor: isOpen || isChildOpen ? JamiTheme.tintedBlue : JamiTheme.primaryForegroundColor - buttonTextFont.weight: isOpen || isChildOpen ? Font.Medium : Font.Normal + imageContainerWidth: 0 + height: JamiTheme.settingsMenuChildrenButtonHeight + + buttonTextFont.pixelSize: JamiTheme.settingMenuPixelSize + buttonTextColor: isSelected ? JamiTheme.tintedBlue : JamiTheme.primaryForegroundColor + buttonTextFont.weight: isSelected ? Font.Medium : Font.Normal buttonTextEnableElide: true - normalColor: isOpen ? JamiTheme.smartListSelectedColor : "transparent" + normalColor: "transparent" hoveredColor: JamiTheme.smartListHoveredColor - imageColor: !isChildren ? JamiTheme.tintedBlue : null - - source: { - if (!isChildren) - return base[modelData]["icon"]; - else - return ""; - } - onClicked: createChild() + onClicked: open(modelData.id) Keys.onPressed: function (keyEvent) { if (keyEvent.key === Qt.Key_Enter || keyEvent.key === Qt.Key_Return) { diff --git a/src/app/settingsview/SettingsView.qml b/src/app/settingsview/SettingsView.qml index 43f3b0ac6..b9d8d378d 100644 --- a/src/app/settingsview/SettingsView.qml +++ b/src/app/settingsview/SettingsView.qml @@ -31,6 +31,7 @@ import "../mainview/js/contactpickercreation.js" as ContactPickerCreation ListSelectionView { id: viewNode objectName: "SettingsView" + selectionFallback: true // A map of view names to file paths for QML files that define each view. property variant resources: { @@ -57,6 +58,18 @@ ListSelectionView { leftPaneItem: viewCoordinator.getView("SettingsSidePanel") + Component.onCompleted: { + leftPaneItem.updateModel() + } + + Connections { + target: viewNode + + function onIsSinglePaneChanged() { + leftPaneItem.isSinglePane = viewNode.isSinglePane + } + } + onDismissed: { // Trigger an update to messages if needed. // Currently needed when changing the show link preview setting. @@ -68,10 +81,6 @@ ListSelectionView { } } - Component.onCompleted: { - leftPaneItem.createChild(); - } - property int selectedMenu: index rightPaneItem: StackView { @@ -83,8 +92,7 @@ ListSelectionView { signal stopBooth - initialItem: ManageAccountPage { - } + initialItem: ManageAccountPage {} onCurrentIndexChanged: { switch (currentIndex) { -- GitLab