From 5f6eb2151b563e6b3209f3e8dc02e51f42c60bf8 Mon Sep 17 00:00:00 2001
From: agsantos <aline.gondimsantos@savoirfairelinux.com>
Date: Tue, 23 Mar 2021 17:46:13 -0400
Subject: [PATCH] settings: redesign plugin preferences view

GitLab: #341
Change-Id: Ibe7ad479845bf9390e8634c6b80cb0be79976143
---
 .../PreferenceItemDelegate.qml                |   7 +
 src/commoncomponents/SettingParaCombobox.qml  |   5 +-
 src/constant/JamiTheme.qml                    |   4 +
 .../components/PluginHandlerPicker.qml        |   7 +-
 src/pluginadapter.cpp                         |  27 +-
 src/pluginadapter.h                           |   6 +-
 src/pluginlistpreferencemodel.cpp             |   2 +
 src/preferenceitemlistmodel.cpp               |  44 ++-
 src/preferenceitemlistmodel.h                 |   6 +-
 .../components/PluginItemDelegate.qml         |  44 +--
 .../components/PluginListPreferencesView.qml  | 281 +++++++++++++++---
 .../components/PluginListSettingsView.qml     |   9 +-
 12 files changed, 363 insertions(+), 79 deletions(-)

diff --git a/src/commoncomponents/PreferenceItemDelegate.qml b/src/commoncomponents/PreferenceItemDelegate.qml
index 752d885bc..879906e3f 100644
--- a/src/commoncomponents/PreferenceItemDelegate.qml
+++ b/src/commoncomponents/PreferenceItemDelegate.qml
@@ -113,6 +113,7 @@ ItemDelegate {
             font.pointSize: JamiTheme.settingsFontSize
             ToolTip.visible: hovered
             ToolTip.text: preferenceSummary
+            opacity: enabled ? 1.0 : 0.5
         }
 
         PushButton {
@@ -130,6 +131,7 @@ ItemDelegate {
             source: "qrc:/images/icons/round-settings-24px.svg"
 
             toolTipText: qsTr("Edit preference")
+            opacity: enabled ? 1.0 : 0.5
         }
 
         Switch {
@@ -143,6 +145,7 @@ ItemDelegate {
             checked: preferenceCurrentValue === "1"
 
             onToggled: getNewPreferenceValueSlot(checked)
+            opacity: enabled ? 1.0 : 0.5
         }
 
         SettingParaCombobox {
@@ -161,6 +164,8 @@ ItemDelegate {
             textRole: "PreferenceValue"
             tooltipText: JamiStrings.select
             onActivated: getNewPreferenceValueSlot(index)
+            opacity: enabled ? 1.0 : 0.5
+            comboBoxBackgroundColor: JamiTheme.comboBoxBackgroundColor
         }
 
         MaterialButton {
@@ -181,6 +186,7 @@ ItemDelegate {
             pressedColor: JamiTheme.buttonTintedGreyPressed
 
             onClicked: getNewPreferenceValueSlot(0)
+            opacity: enabled ? 1.0 : 0.5
         }
 
         MaterialLineEdit {
@@ -201,6 +207,7 @@ ItemDelegate {
             wrapMode: Text.NoWrap
 
             onEditingFinished: getNewPreferenceValueSlot(0)
+            opacity: enabled ? 1.0 : 0.5
         }
     }
 }
diff --git a/src/commoncomponents/SettingParaCombobox.qml b/src/commoncomponents/SettingParaCombobox.qml
index 157e6d714..b0ab191ee 100644
--- a/src/commoncomponents/SettingParaCombobox.qml
+++ b/src/commoncomponents/SettingParaCombobox.qml
@@ -29,6 +29,7 @@ ComboBox {
     id: root
 
     property string tooltipText:""
+    property string comboBoxBackgroundColor: JamiTheme.editBackgroundColor
 
     ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval
     ToolTip.visible: hovered && (tooltipText.length > 0)
@@ -90,10 +91,10 @@ ComboBox {
     }
 
     background: Rectangle {
-        color: JamiTheme.editBackgroundColor
+        color: root.comboBoxBackgroundColor
         implicitWidth: 120
         implicitHeight: 40
-        border.color: JamiTheme.editBackgroundColor
+        border.color: root.comboBoxBackgroundColor
         border.width: root.visualFocus ? 2 : 1
         radius: 2
     }
diff --git a/src/constant/JamiTheme.qml b/src/constant/JamiTheme.qml
index 5552d29b4..23dab0c69 100644
--- a/src/constant/JamiTheme.qml
+++ b/src/constant/JamiTheme.qml
@@ -110,6 +110,10 @@ Item {
     property color successLabelColor: "#2b5084"
     property color rubberBandSelectionBlue: "steelblue"
     property color screenSelectionBorderGreen: "green"
+    property color separationLine: darkTheme ? selectedColor : backgroundColor
+
+    // Plugin Preferences View
+    property color comboBoxBackgroundColor: darkTheme ? editBackgroundColor : selectedColor
 
     // Chatview
     property color jamiLightBlue: darkTheme? "#003b4e" : Qt.rgba(59, 193, 211, 0.3)
diff --git a/src/mainview/components/PluginHandlerPicker.qml b/src/mainview/components/PluginHandlerPicker.qml
index 8ea38e208..c66603d47 100644
--- a/src/mainview/components/PluginHandlerPicker.qml
+++ b/src/mainview/components/PluginHandlerPicker.qml
@@ -188,7 +188,7 @@ Popup {
                 function onUpdateProperties() {
                     pluginhandlerPreferencePickerListView.pluginId = root.pluginId
                     pluginhandlerPreferencePickerListView.handlerName = root.handlerName
-                    pluginhandlerPreferencePickerListView.model = PluginAdapter.getPluginPreferencesModel(root.pluginId, root.handlerName)
+                    pluginhandlerPreferencePickerListView.model = PluginAdapter.getHandlerPreferencesModel(root.pluginId, root.handlerName)
                 }
             }
 
@@ -251,7 +251,7 @@ Popup {
                     property string pluginId: ""
                     property string handlerName: ""
 
-                    model: PluginAdapter.getPluginPreferencesModel(pluginId, handlerName)
+                    model: PluginAdapter.getHandlerPreferencesModel(pluginId, handlerName)
 
                     clip: true
 
@@ -269,6 +269,7 @@ Popup {
                         preferenceKey : PreferenceKey
                         fileFilters: FileFilters
                         isImage: IsImage
+                        enabled: Enabled
                         pluginListPreferenceModel: PluginListPreferenceModel {
                             id: handlerPickerPreferenceModel
 
@@ -282,7 +283,7 @@ Popup {
                         onBtnPreferenceClicked: {
                             PluginModel.setPluginPreference(pluginId, preferenceKey, preferenceNewValue)
                             PluginAdapter.preferenceChanged(pluginId)
-                            pluginhandlerPreferencePickerListView.model = PluginAdapter.getPluginPreferencesModel(pluginId, pluginhandlerPreferencePickerListView.handlerName)
+                            pluginhandlerPreferencePickerListView.model = PluginAdapter.getHandlerPreferencesModel(pluginId, pluginhandlerPreferencePickerListView.handlerName)
                         }
                     }
 
diff --git a/src/pluginadapter.cpp b/src/pluginadapter.cpp
index b025c7b98..87b28b692 100644
--- a/src/pluginadapter.cpp
+++ b/src/pluginadapter.cpp
@@ -48,7 +48,17 @@ PluginAdapter::getPluginSelectableModel()
 }
 
 QVariant
-PluginAdapter::getPluginPreferencesModel(const QString& pluginId, const QString& mediaHandlerName)
+PluginAdapter::getPluginPreferencesModel(const QString& pluginId, const QString& category)
+{
+    preferenceItemListModel_.reset(new PreferenceItemListModel(this, lrcInstance_));
+    preferenceItemListModel_->setCategory(category);
+    preferenceItemListModel_->setPluginId(pluginId);
+
+    return QVariant::fromValue(preferenceItemListModel_.get());
+}
+
+QVariant
+PluginAdapter::getHandlerPreferencesModel(const QString& pluginId, const QString& mediaHandlerName)
 {
     preferenceItemListModel_.reset(new PreferenceItemListModel(this, lrcInstance_));
     preferenceItemListModel_->setMediaHandlerName(mediaHandlerName);
@@ -56,3 +66,18 @@ PluginAdapter::getPluginPreferencesModel(const QString& pluginId, const QString&
 
     return QVariant::fromValue(preferenceItemListModel_.get());
 }
+
+QVariant
+PluginAdapter::getPluginPreferencesCategories(const QString& pluginId, bool removeLast)
+{
+    QStringList categories;
+    auto preferences = lrcInstance_->pluginModel().getPluginPreferences(pluginId);
+    for (auto& preference : preferences) {
+        if (!preference["category"].isEmpty())
+            categories.push_back(preference["category"]);
+    }
+    categories.removeDuplicates();
+    if (removeLast)
+        categories.pop_back();
+    return categories;
+}
diff --git a/src/pluginadapter.h b/src/pluginadapter.h
index b33569455..c902a804f 100644
--- a/src/pluginadapter.h
+++ b/src/pluginadapter.h
@@ -43,7 +43,11 @@ protected:
                                                        const QString& peerId);
     Q_INVOKABLE QVariant getPluginSelectableModel();
     Q_INVOKABLE QVariant getPluginPreferencesModel(const QString& pluginId,
-                                                   const QString& mediaHandlerName = "");
+                                                   const QString& category = "all");
+    Q_INVOKABLE QVariant getHandlerPreferencesModel(const QString& pluginId,
+                                                    const QString& mediaHandlerName = "");
+    Q_INVOKABLE QVariant getPluginPreferencesCategories(const QString& pluginId,
+                                                        bool removeLast = false);
 
 signals:
     void pluginHandlersUpdateStatus();
diff --git a/src/pluginlistpreferencemodel.cpp b/src/pluginlistpreferencemodel.cpp
index 2c6751760..db84e94ab 100644
--- a/src/pluginlistpreferencemodel.cpp
+++ b/src/pluginlistpreferencemodel.cpp
@@ -33,6 +33,8 @@ PluginListPreferenceModel::populateLists()
 {
     preferenceValuesList_.clear();
     preferenceList_.clear();
+    if (pluginId_.isEmpty())
+        return;
     const auto preferences = lrcInstance_->pluginModel().getPluginPreferences(pluginId_);
     for (const auto& preference : preferences) {
         if (preference["key"] == preferenceKey_) {
diff --git a/src/preferenceitemlistmodel.cpp b/src/preferenceitemlistmodel.cpp
index e325795c8..26eee8010 100644
--- a/src/preferenceitemlistmodel.cpp
+++ b/src/preferenceitemlistmodel.cpp
@@ -89,6 +89,26 @@ PreferenceItemListModel::data(const QModelIndex& index, int role) const
             acceptedFiles.append(QString("All (*.%1)").arg(mimeTypeList.join(" *.")));
         }
     }
+    const auto dependsOn = details["dependsOn"].split(",");
+    const auto preferences = lrcInstance_->pluginModel().getPluginPreferences(pluginId_);
+    const auto prefValues = lrcInstance_->pluginModel().getPluginPreferencesValues(pluginId_);
+    bool enabled = true;
+    for (auto& preference : preferences) {
+        auto key = preference["key"];
+        auto prefValue = prefValues[key];
+        for (auto& item : dependsOn) {
+            if (preference["type"] == "Switch" && item.endsWith(key)) {
+                if (!item.startsWith("!") && prefValue == "0") {
+                    enabled = false;
+                    break;
+                } else if (item.startsWith("!") && prefValue == "1") {
+                    enabled = false;
+                    break;
+                }
+            }
+        }
+    }
+
     switch (role) {
     case Role::PreferenceKey:
         return QVariant(details["key"]);
@@ -108,6 +128,8 @@ PreferenceItemListModel::data(const QModelIndex& index, int role) const
         return QVariant(acceptedFiles);
     case Role::IsImage:
         return QVariant(checkImage);
+    case Role::Enabled:
+        return QVariant(enabled);
     }
 
     return QVariant();
@@ -126,6 +148,7 @@ PreferenceItemListModel::roleNames() const
     roles[CurrentPath] = "CurrentPath";
     roles[FileFilters] = "FileFilters";
     roles[IsImage] = "IsImage";
+    roles[Enabled] = "Enabled";
     return roles;
 }
 
@@ -192,13 +215,32 @@ PreferenceItemListModel::setMediaHandlerName(const QString mediaHandlerName)
     mediaHandlerName_ = mediaHandlerName;
 }
 
+QString
+PreferenceItemListModel::category() const
+{
+    return category_;
+}
+
+void
+PreferenceItemListModel::setCategory(const QString category)
+{
+    category_ = category;
+}
+
 int
 PreferenceItemListModel::preferencesCount()
 {
     if (!preferenceList_.isEmpty())
         return preferenceList_.size();
     if (mediaHandlerName_.isEmpty()) {
-        preferenceList_ = lrcInstance_->pluginModel().getPluginPreferences(pluginId_);
+        auto preferences = lrcInstance_->pluginModel().getPluginPreferences(pluginId_);
+        if (category_ != "all")
+            for (auto& preference : preferences) {
+                if (preference["category"] == category_)
+                    preferenceList_.push_back(preference);
+            }
+        else
+            preferenceList_ = preferences;
         return preferenceList_.size();
     } else {
         auto preferences = lrcInstance_->pluginModel().getPluginPreferences(pluginId_);
diff --git a/src/preferenceitemlistmodel.h b/src/preferenceitemlistmodel.h
index 9a5f0fded..8c8f64fdc 100644
--- a/src/preferenceitemlistmodel.h
+++ b/src/preferenceitemlistmodel.h
@@ -39,7 +39,8 @@ public:
         PreferenceCurrentValue,
         CurrentPath,
         FileFilters,
-        IsImage
+        IsImage,
+        Enabled
     };
 
     typedef enum {
@@ -78,10 +79,13 @@ public:
     void setPluginId(const QString& pluginId);
     QString mediaHandlerName() const;
     void setMediaHandlerName(const QString mediaHandlerName);
+    QString category() const;
+    void setCategory(const QString category);
     int preferencesCount();
 
 private:
     QString pluginId_;
     QString mediaHandlerName_ = "";
     VectorMapStringString preferenceList_;
+    QString category_ = "all";
 };
diff --git a/src/settingsview/components/PluginItemDelegate.qml b/src/settingsview/components/PluginItemDelegate.qml
index 5c254fd8e..977e694d4 100644
--- a/src/settingsview/components/PluginItemDelegate.qml
+++ b/src/settingsview/components/PluginItemDelegate.qml
@@ -23,6 +23,7 @@ import QtQuick.Layouts 1.14
 import QtGraphicalEffects 1.14
 
 import net.jami.Models 1.0
+import net.jami.Adapters 1.0
 import net.jami.Constants 1.0
 
 import "../../commoncomponents"
@@ -34,45 +35,39 @@ ItemDelegate {
     property string pluginId: ""
     property string pluginIcon: ""
     property bool isLoaded: false
+    property int rowHeight: implicitHeight
 
     signal btnLoadPluginToggled
 
     function btnPreferencesPluginClicked() {
-        pluginListPreferencesView.pluginName = pluginName
-        pluginListPreferencesView.pluginIcon = pluginIcon
-        pluginListPreferencesView.pluginId = pluginId
-        pluginListPreferencesView.isLoaded = isLoaded
-        if (!pluginListPreferencesView.visible) {
-            pluginListPreferencesView.visible = !pluginListPreferencesView.visible
-            root.height += pluginListPreferencesView.childrenRect.height
-        } else {
-            root.height -= pluginListPreferencesView.childrenRect.height
-            pluginListPreferencesView.visible = !pluginListPreferencesView.visible
-        }
-        PluginAdapter.preferenceChanged(pluginId)
+        pluginListPreferencesView.visible = !pluginListPreferencesView.visible
+        pluginListPreferencesView.updateProperties(root.pluginName, root.pluginIcon, root.pluginId, root.isLoaded)
     }
 
     Connections {
         target: enabledplugin
 
         function onHidePreferences() {
-            root.height = 50
             pluginListPreferencesView.visible = false
+            pluginListPreferencesView.updatePluginPrefListView()
         }
     }
 
     ColumnLayout {
         anchors.fill: parent
-        Layout.preferredHeight: childrenRect.height
+        implicitHeight: childrenRect.height
 
         RowLayout {
             Layout.fillWidth: true
+            Layout.preferredHeight: root.rowHeight
 
             Label {
                 id: pluginImage
                 Layout.leftMargin: 8
+                Layout.topMargin: 8
                 Layout.alignment: Qt.AlignLeft | Qt.AlingVCenter
-                width: 30
+                width: JamiTheme.preferredFieldHeight
+                Layout.fillHeight: true
 
                 background: Rectangle {
                     color: "transparent"
@@ -81,26 +76,31 @@ ItemDelegate {
                         source: "file:" + pluginIcon
                         sourceSize: Qt.size(256, 256)
                         mipmap: true
-                        width: 32
-                        height: 32
+                        width: JamiTheme.preferredFieldHeight
+                        height: JamiTheme.preferredFieldHeight
                     }
                 }
             }
 
             Label {
                 id: labelDeviceId
+                Layout.fillHeight: true
                 Layout.fillWidth: true
+                Layout.topMargin: 8
                 Layout.leftMargin: 8
                 color: JamiTheme.textColor
 
                 font.pointSize: JamiTheme.settingsFontSize
                 font.kerning: true
                 text: pluginName === "" ? pluginId : pluginName
+                verticalAlignment: Text.AlignVCenter
             }
 
             Switch {
                 id: loadSwitch
+                Layout.fillHeight: true
                 property bool isHovering: false
+                Layout.topMargin: 8
                 Layout.rightMargin: 8
                 width: 20
 
@@ -137,6 +137,7 @@ ItemDelegate {
                 id: btnPreferencesPlugin
 
                 Layout.alignment: Qt.AlingVCenter | Qt.AlignRight
+                Layout.topMargin: 8
                 Layout.rightMargin: 8
 
                 source: "qrc:/images/icons/round-settings-24px.svg"
@@ -151,13 +152,18 @@ ItemDelegate {
         PluginListPreferencesView {
             id: pluginListPreferencesView
 
-            Layout.topMargin: 10
             Layout.fillWidth: true
             Layout.leftMargin: JamiTheme.preferredMarginSize
             Layout.rightMargin: JamiTheme.preferredMarginSize
-            Layout.bottomMargin: JamiTheme.preferredMarginSize
             Layout.minimumHeight: 1
             Layout.preferredHeight: childrenRect.height
+
+            onUpdatePluginPrefListView: {
+                if (pluginListPreferencesView.visible)
+                    root.implicitHeight = root.rowHeight + pluginListPreferencesView.childrenRect.height
+                else
+                    root.implicitHeight = root.rowHeight
+            }
         }
     }
 }
diff --git a/src/settingsview/components/PluginListPreferencesView.qml b/src/settingsview/components/PluginListPreferencesView.qml
index a7ee6f0fa..e22596ca3 100644
--- a/src/settingsview/components/PluginListPreferencesView.qml
+++ b/src/settingsview/components/PluginListPreferencesView.qml
@@ -44,18 +44,56 @@ Rectangle {
     property string pluginIcon: ""
     property string pluginId: ""
     property bool isLoaded: false
+    property string category: ""
+    property var categories: ["all"]
+    property string generalCategory: ""
 
     visible: false
     color: "transparent"
 
     signal uninstalled
+    signal updatePluginPrefListView
+
+    function updateProperties(name, icon, path, status) {
+        root.pluginName = name
+        root.pluginIcon = icon
+        root.pluginId = path
+        root.isLoaded = status
+        root.categories = PluginAdapter.getPluginPreferencesCategories(path)
+        if (root.category === "" && root.categories.length > 0)
+            root.category = root.categories[0]
+        resetModels()
+    }
+
+    function resetModels() {
+        updatePluginPrefListView()
+        root.categories = PluginAdapter.getPluginPreferencesCategories(root.pluginId)
+        if (root.categories.length <= 1) {
+            root.generalCategory = "all"
+            categoriesGrid.visible = false
+            prefsByCategory.visible = false
+        }
+        else {
+            gridModel.model = root.categories
+            if (root.categories.length % 2 == 1) {
+                gridModel.model = PluginAdapter.getPluginPreferencesCategories(pluginId, true)
+                oddCategoryButton.text = root.categories[root.categories.length - 1]
+                oddCategoryButton.highlighted = root.category == oddCategoryButton.text
+            }
+            oddCategoryButton.visible = root.categories.length % 2 == 1
+            root.generalCategory = ""
+        }
+        pluginPreferenceView.model = PluginAdapter.getPluginPreferencesModel(root.pluginId, root.generalCategory)
+        pluginPreferenceViewCategory.model = PluginAdapter.getPluginPreferencesModel(root.pluginId, root.category)
+        updatePluginPrefListView()
+    }
 
     Connections {
         target: PluginAdapter
 
         function onPreferenceChanged(pluginId) {
-            if (root.pluginId == pluginId)
-                pluginPreferenceView.model = PluginAdapter.getPluginPreferencesModel(pluginId)
+            if (root.pluginId === pluginId)
+                resetModels()
         }
     }
 
@@ -76,7 +114,8 @@ Rectangle {
         } else {
             PluginModel.resetPluginPreferencesValues(pluginId)
         }
-        pluginPreferenceView.model = PluginAdapter.getPluginPreferencesModel(pluginId)
+        pluginPreferenceView.model = PluginAdapter.getPluginPreferencesModel(root.pluginId, root.generalCategory)
+        pluginPreferenceViewCategory.model = PluginAdapter.getPluginPreferencesModel(root.pluginId, root.category)
         PluginAdapter.pluginHandlersUpdateStatus()
     }
 
@@ -89,7 +128,7 @@ Rectangle {
     }
 
     function uninstallPlugin() {
-        PluginModel.uninstallPlugin(pluginId)
+        PluginModel.uninstallPlugin(root.pluginId)
         PluginAdapter.pluginUninstalled()
         PluginAdapter.pluginHandlersUpdateStatus()
         root.visible = false
@@ -117,16 +156,19 @@ Rectangle {
     ColumnLayout {
         anchors.left: root.left
         anchors.right: root.right
+        anchors.bottomMargin: 10
 
         Label{
+            Layout.topMargin: 34
             Layout.alignment: Qt.AlignHCenter
+            height: 64
             background: Rectangle {
                 Image {
                     anchors.centerIn: parent
                     source: pluginIcon === "" ? "" : "file:" + pluginIcon
                     sourceSize: Qt.size(256, 256)
-                    height: 48
-                    width: 48
+                    height: 64
+                    width: 64
                     mipmap: true
                 }
             }
@@ -134,9 +176,10 @@ Rectangle {
 
         Label {
             Layout.alignment: Qt.AlignHCenter
-            Layout.topMargin: 16
+            Layout.topMargin: 24
+            height: JamiTheme.preferredFieldHeight
 
-            text: qsTr(pluginName + "\npreferences")
+            text: qsTr(pluginName + "\nPreferences")
             font.pointSize: JamiTheme.headerFontSize
             font.kerning: true
             color: JamiTheme.textColor
@@ -145,55 +188,142 @@ Rectangle {
             verticalAlignment: Text.AlignVCenter
         }
 
-        RowLayout {
-            Layout.topMargin: 10
-            height: 30
-
-            MaterialButton {
-                id: resetButton
-
-                Layout.fillWidth: true
-                Layout.preferredHeight: JamiTheme.preferredFieldHeight
-
-                color: JamiTheme.buttonTintedBlack
-                hoveredColor: JamiTheme.buttonTintedBlackHovered
-                pressedColor: JamiTheme.buttonTintedBlackPressed
-                outlined: true
-
-                source: "qrc:/images/icons/settings_backup_restore-24px.svg"
-
-                text: JamiStrings.reset
-
-                onClicked: resetPluginSlot()
-            }
-
-            MaterialButton {
-                id: uninstallButton
-
-                Layout.fillWidth: true
-                Layout.preferredHeight: JamiTheme.preferredFieldHeight
-
-                color: JamiTheme.buttonTintedBlack
-                hoveredColor: JamiTheme.buttonTintedBlackHovered
-                pressedColor: JamiTheme.buttonTintedBlackPressed
-                outlined: true
-
-                source: "qrc:/images/icons/delete-24px.svg"
+        Rectangle {
+            id: prefsByCategory
+            Layout.topMargin: 24
+            Layout.fillWidth: true
+            implicitHeight: childrenRect.height
+            color: JamiTheme.backgroundColor
+
+            ColumnLayout {
+                anchors.left: parent.left
+                anchors.right: parent.right
+
+                GridLayout {
+                    id: categoriesGrid
+                    Layout.fillWidth: true
+                    implicitHeight: childrenRect.height
+                    columns: 2
+                    columnSpacing: 0
+                    rowSpacing: 0
+
+                    Repeater {
+                        id: gridModel
+                        model: root.categories
+                        Button {
+                            id: repDelegate
+                            Layout.fillWidth: true
+                            Layout.preferredHeight: JamiTheme.preferredFieldHeight
+                            highlighted: root.category === modelData
+                            text: modelData
+                            flat: true
+                            onClicked: {
+                                root.category = modelData
+                                PluginAdapter.preferenceChanged(root.pluginId)
+                            }
+                            background: Rectangle {
+                                anchors.fill: parent
+                                color: repDelegate.highlighted ? JamiTheme.selectedColor : JamiTheme.primaryBackgroundColor
+                                border.color: JamiTheme.selectedColor
+                                border.width: 1
+                            }
+                            contentItem: Text {
+                                text: repDelegate.text
+                                font: repDelegate.font
+                                opacity: enabled ? 1.0 : 0.3
+                                color: JamiTheme.primaryForegroundColor
+                                horizontalAlignment: Text.AlignHCenter
+                                verticalAlignment: Text.AlignVCenter
+                                elide: Text.ElideRight
+                            }
+                        }
+                    }
+                }
 
-                text: qsTr("Uninstall")
+                Button {
+                    id: oddCategoryButton
+                    Layout.fillWidth: true
+                    Layout.preferredHeight: JamiTheme.preferredFieldHeight
+                    flat: true
+                    visible: false
+                    onClicked: {
+                        root.category = oddCategoryButton.text
+                        PluginAdapter.preferenceChanged(root.pluginId)
+                    }
+                    background: Rectangle {
+                        anchors.fill: parent
+                        color: oddCategoryButton.highlighted ? JamiTheme.selectedColor : JamiTheme.primaryBackgroundColor
+                        border.color: JamiTheme.selectedColor
+                        border.width: 1
+                    }
+                    contentItem: Text {
+                        text: oddCategoryButton.text
+                        font: oddCategoryButton.font
+                        opacity: enabled ? 1.0 : 0.3
+                        color: JamiTheme.primaryForegroundColor
+                        horizontalAlignment: Text.AlignHCenter
+                        verticalAlignment: Text.AlignVCenter
+                        elide: Text.ElideRight
+                    }
+                }
 
-                onClicked: uninstallPluginSlot()
+                ListView {
+                    id: pluginPreferenceViewCategory
+                    Layout.fillWidth: true
+                    Layout.minimumHeight: 1
+                    Layout.preferredHeight: childrenRect.height
+                    implicitHeight: childrenRect.height
+
+                    model: PluginAdapter.getPluginPreferencesModel(root.pluginId, root.category)
+                    interactive: false
+
+                    delegate: PreferenceItemDelegate {
+                        id: preferenceItemDelegateCategory
+
+                        width: pluginPreferenceViewCategory.width
+                        height: 50
+
+                        preferenceName: PreferenceName
+                        preferenceSummary: PreferenceSummary
+                        preferenceType: PreferenceType
+                        preferenceCurrentValue: PreferenceCurrentValue
+                        pluginId: PluginId
+                        currentPath: CurrentPath
+                        preferenceKey: PreferenceKey
+                        fileFilters: FileFilters
+                        isImage: IsImage
+                        enabled: Enabled
+                        pluginListPreferenceModel: PluginListPreferenceModel {
+                            id: pluginListPreferenceCategoryModel
+
+                            lrcInstance: LRCInstance
+                            preferenceKey : PreferenceKey
+                            pluginId: PluginId
+                        }
+
+                        onBtnPreferenceClicked: {
+                            setPreference(pluginId, preferenceKey, preferenceNewValue)
+                            pluginPreferenceViewCategory.model = PluginAdapter.getPluginPreferencesModel(pluginId, root.category)
+                        }
+
+                        background: Rectangle {
+                            anchors.fill: parent
+                            color: JamiTheme.backgroundColor
+                        }
+                    }
+                }
             }
         }
 
         ListView {
             id: pluginPreferenceView
-
             Layout.fillWidth: true
             Layout.minimumHeight: 1
-            Layout.preferredHeight: childrenRect.height + 30
 
-            model: PluginAdapter.getPluginPreferencesModel(pluginId)
+            implicitHeight: childrenRect.height
+            Layout.preferredHeight: childrenRect.height
+
+            model: PluginAdapter.getPluginPreferencesModel(root.pluginId)
             interactive: false
 
             delegate: PreferenceItemDelegate {
@@ -211,6 +341,7 @@ Rectangle {
                 preferenceKey: PreferenceKey
                 fileFilters: FileFilters
                 isImage: IsImage
+                enabled: Enabled
                 pluginListPreferenceModel: PluginListPreferenceModel {
                     id: pluginListPreferenceModel
 
@@ -221,14 +352,66 @@ Rectangle {
 
                 onBtnPreferenceClicked: {
                     setPreference(pluginId, preferenceKey, preferenceNewValue)
-                    pluginPreferenceView.model = PluginAdapter.getPluginPreferencesModel(pluginId)
+                    pluginPreferenceView.model = PluginAdapter.getPluginPreferencesModel(pluginId, generalCategory)
                 }
 
                 background: Rectangle {
                     anchors.fill: parent
-                    color: JamiTheme.secondaryBackgroundColor
+                    color: "transparent"
                 }
             }
         }
+
+        RowLayout {
+            Layout.topMargin: 10
+            Layout.bottomMargin: 10
+            height: 30
+
+            MaterialButton {
+                id: resetButton
+
+                Layout.fillWidth: true
+                Layout.preferredHeight: JamiTheme.preferredFieldHeight
+
+                color: JamiTheme.buttonTintedBlack
+                hoveredColor: JamiTheme.buttonTintedBlackHovered
+                pressedColor: JamiTheme.buttonTintedBlackPressed
+                outlined: true
+
+                source: "qrc:/images/icons/settings_backup_restore-24px.svg"
+
+                text: JamiStrings.reset
+
+                onClicked: resetPluginSlot()
+            }
+
+            MaterialButton {
+                id: uninstallButton
+
+                Layout.fillWidth: true
+                Layout.preferredHeight: JamiTheme.preferredFieldHeight
+
+                color: JamiTheme.buttonTintedBlack
+                hoveredColor: JamiTheme.buttonTintedBlackHovered
+                pressedColor: JamiTheme.buttonTintedBlackPressed
+                outlined: true
+
+                source: "qrc:/images/icons/delete-24px.svg"
+
+                text: qsTr("Uninstall")
+
+                onClicked: uninstallPluginSlot()
+            }
+        }
+
+        Rectangle {
+            id: endline
+            Layout.bottomMargin: 10
+            height: 2
+            Layout.fillWidth: true
+            color: "transparent"
+            border.width: 1
+            border.color: JamiTheme.separationLine
+        }
     }
 }
diff --git a/src/settingsview/components/PluginListSettingsView.qml b/src/settingsview/components/PluginListSettingsView.qml
index 9b3110856..95e303401 100644
--- a/src/settingsview/components/PluginListSettingsView.qml
+++ b/src/settingsview/components/PluginListSettingsView.qml
@@ -124,13 +124,13 @@ Rectangle {
             Layout.bottomMargin: 10
 
             model: PluginAdapter.getPluginSelectableModel()
-            interactive: false
 
             delegate: PluginItemDelegate {
                 id: pluginItemDelegate
 
                 width: pluginListView.width
-                implicitHeight: 50
+                rowHeight: 40
+                implicitHeight: 40
 
                 pluginName: PluginName
                 pluginId: PluginId
@@ -140,6 +140,11 @@ Rectangle {
                 onBtnLoadPluginToggled: {
                     isLoaded = loadPluginSlot(pluginId, isLoaded)
                 }
+
+                background: Rectangle {
+                    anchors.fill: parent
+                    color: "transparent"
+                }
             }
         }
     }
-- 
GitLab