mirror of
https://git.jami.net/savoirfairelinux/jami-client-qt.git
synced 2025-03-28 14:56:19 +01:00
PluginStore: add view for plugin store
Gitlab: #1163 Change-Id: If9d9a27a296c5810b9f99126bed6453cc6ab6852
This commit is contained in:
parent
7581f9397a
commit
5530649f07
30 changed files with 1066 additions and 605 deletions
35
resources/icons/plugins_default_icon.svg
Normal file
35
resources/icons/plugins_default_icon.svg
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 428 428" style="enable-background:new 0 0 428 428;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill-rule:evenodd;clip-rule:evenodd;fill:url(#SVGID_1_);}
|
||||
.st1{fill-rule:evenodd;clip-rule:evenodd;fill:url(#SVGID_2_);}
|
||||
.st2{fill:url(#SVGID_3_);}
|
||||
.st3{fill:url(#SVGID_4_);}
|
||||
</style>
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="-12.6549" y1="165.4979" x2="165.4206" y2="343.5734">
|
||||
<stop offset="0" style="stop-color:#3A3A3A"/>
|
||||
<stop offset="1" style="stop-color:#818181"/>
|
||||
</linearGradient>
|
||||
<path class="st0" d="M1.6,154v21.5v1.4c0.2,0,0.4,0,0.6,0c21.8,0,39.5,17.7,39.5,39.5c0,21.8-17.7,39.5-39.5,39.5
|
||||
c-0.2,0-0.4,0-0.6,0V408H101V152c0.2,0.1,0.3,0.1,0.5,0.2V51.4L1.6,154z"/>
|
||||
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="227.3426" y1="84.8295" x2="405.4313" y2="262.9182">
|
||||
<stop offset="0" style="stop-color:#3A3A3A"/>
|
||||
<stop offset="1" style="stop-color:#717171"/>
|
||||
</linearGradient>
|
||||
<path class="st1" d="M386.9,176.8L386.9,176.8l0-157.8h-93.7v256c-0.1-0.1-0.3-0.1-0.4-0.2v100.8l94.2-96.7v-23.2h0
|
||||
c21.8,0,39.5-17.7,39.5-39.5C426.4,194.5,408.7,176.8,386.9,176.8z"/>
|
||||
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="1.6097" y1="86.4966" x2="395.2845" y2="86.4966">
|
||||
<stop offset="0" style="stop-color:#818181"/>
|
||||
<stop offset="1" style="stop-color:#3A3A3A"/>
|
||||
</linearGradient>
|
||||
<path class="st2" d="M181.3,19C126.4,19,1.6,31.5,1.6,154c0,0,49.3-42.7,136.9-25s160.9-0.7,207.6-49.1
|
||||
c18.6-19.3,32.4-39.6,40.2-60.9H181.3z"/>
|
||||
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="-553.2536" y1="-1072.2665" x2="-159.5788" y2="-1072.2665" gradientTransform="matrix(-1 0 0 -1 -166.3346 -728.8083)">
|
||||
<stop offset="0" style="stop-color:#818181"/>
|
||||
<stop offset="1" style="stop-color:#3A3A3A"/>
|
||||
</linearGradient>
|
||||
<path class="st3" d="M207.2,408c54.9,0,179.7-11.9,179.7-129.1c0,0-49.3,40.8-136.9,23.9c-87.6-16.9-160.9,0.7-207.6,47
|
||||
C23.8,368.3,10.1,387.6,2.2,408H207.2z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 2.2 KiB |
75
src/app/commoncomponents/HeaderToggleSwitch.qml
Normal file
75
src/app/commoncomponents/HeaderToggleSwitch.qml
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (C) 2022-2023 Savoir-faire Linux Inc.
|
||||
* Author: Xavier Jouslin <xavier.jouslindenoray@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
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Qt.labs.platform
|
||||
import net.jami.Models 1.1
|
||||
import net.jami.Adapters 1.1
|
||||
import net.jami.Constants 1.1
|
||||
|
||||
RowLayout {
|
||||
id: root
|
||||
property string labelText: ""
|
||||
property int widthOfSwitch: 50
|
||||
property int heightOfSwitch: 10
|
||||
|
||||
property string tooltipText: ""
|
||||
|
||||
property alias toggleSwitch: autoupdate
|
||||
property alias checked: autoupdate.checked
|
||||
|
||||
signal switchToggled
|
||||
Layout.alignment: Qt.AlignRight
|
||||
JamiSwitch {
|
||||
id: autoupdate
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
|
||||
Layout.preferredWidth: widthOfSwitch
|
||||
|
||||
hoverEnabled: true
|
||||
toolTipText: tooltipText
|
||||
|
||||
Accessible.role: Accessible.Button
|
||||
Accessible.name: JamiStrings.autoUpdate
|
||||
Accessible.description: root.tooltipText
|
||||
|
||||
onToggled: switchToggled()
|
||||
}
|
||||
Text {
|
||||
id: description
|
||||
Layout.rightMargin: JamiTheme.preferredMarginSize
|
||||
text: JamiStrings.autoUpdate
|
||||
font.pixelSize: JamiTheme.wizardViewButtonFontPixelSize
|
||||
visible: labelText !== ""
|
||||
font.kerning: true
|
||||
wrapMode: Text.WordWrap
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
||||
color: JamiTheme.textColor
|
||||
}
|
||||
TapHandler {
|
||||
target: parent
|
||||
enabled: parent.visible
|
||||
onTapped: function onTapped(eventPoint) {
|
||||
// switchToggled should be emitted as onToggled is not called (because it's only called if the user click on the switch)
|
||||
autoupdate.toggle();
|
||||
switchToggled();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -68,6 +68,7 @@ Item {
|
|||
antialiasing: true
|
||||
asynchronous: true
|
||||
visible: false
|
||||
mipmap: true
|
||||
|
||||
function setSourceSize() {
|
||||
sourceSize = undefined;
|
||||
|
|
|
@ -32,9 +32,8 @@ Item {
|
|||
property int spinningAnimationWidth: 4
|
||||
property real outerCutRadius: root.height / 2
|
||||
property int spinningAnimationDuration: 1000
|
||||
|
||||
property color color: "white"
|
||||
visible: mode !== SpinningAnimation.Mode.Disabled
|
||||
|
||||
ConicalGradient {
|
||||
id: conicalGradientOne
|
||||
|
||||
|
@ -48,7 +47,7 @@ Item {
|
|||
}
|
||||
GradientStop {
|
||||
position: 1.0
|
||||
color: "white"
|
||||
color: mode === SpinningAnimation.Mode.Disabled ? "transparent" : root.color
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,7 +89,7 @@ Item {
|
|||
}
|
||||
GradientStop {
|
||||
position: 1.0
|
||||
color: "white"
|
||||
color: mode === SpinningAnimation.Mode.Disabled ? "transparent" : root.color
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -166,7 +166,7 @@ Item {
|
|||
property string back: qsTr("Back")
|
||||
property string accountSettingsMenuTitle: qsTr("Account")
|
||||
property string generalSettingsTitle: qsTr("General")
|
||||
property string pluginSettingsTitle: qsTr("Plugins")
|
||||
property string pluginSettingsTitle: qsTr("Extensions")
|
||||
property string enableAccountSettingsTitle: qsTr("Enable account")
|
||||
property string manageAccountSettingsTitle: qsTr("Manage account")
|
||||
property string linkedDevicesSettingsTitle: qsTr("Linked devices")
|
||||
|
@ -659,9 +659,19 @@ Item {
|
|||
|
||||
// Plugins
|
||||
property string enable: qsTr("Enable")
|
||||
property string pluginPreferences: qsTr("Preferences")
|
||||
property string reset: qsTr("Reset")
|
||||
property string autoUpdate: qsTr("Auto update")
|
||||
property string disableAll: qsTr("Disable all")
|
||||
property string installed: qsTr("Installed")
|
||||
property string install: qsTr("Install")
|
||||
property string installing: qsTr("Installing")
|
||||
property string installManually: qsTr("Install manually")
|
||||
property string installMannuallyDescription: qsTr("Install an extension directly from your device.")
|
||||
property string pluginStoreTitle: qsTr("Available")
|
||||
property string pluginStoreNotAvailable: qsTr("Plugins store is not available")
|
||||
property string pluginPreferences: qsTr("Preferences")
|
||||
property string installationFailed: qsTr("Installation failed")
|
||||
property string pluginInstallationFailed: qsTr("The installation of the plugin failed")
|
||||
property string reset: qsTr("Reset")
|
||||
property string uninstall: qsTr("Uninstall")
|
||||
property string resetPreferences: qsTr("Reset Preferences")
|
||||
property string selectPluginInstall: qsTr("Select a plugin to install")
|
||||
|
@ -677,7 +687,6 @@ Item {
|
|||
property string chooseImageFile: qsTr("Choose image file")
|
||||
property string tipGeneralPluginSettingsDisplay: qsTr("Display or hide General plugin settings")
|
||||
property string tipAccountPluginSettingsDisplay: qsTr("Display or hide Account plugin settings")
|
||||
property string installedPlugins: qsTr("Installed plugins")
|
||||
property string pluginFiles: qsTr("Plugin Files (*.jpl)")
|
||||
property string loadUnload: qsTr("Load/Unload")
|
||||
property string selectAnImage: qsTr("Select An Image to %1")
|
||||
|
|
|
@ -383,6 +383,10 @@ Item {
|
|||
property real minimumMapWidth: 250
|
||||
property real pluginHandlersPopupViewHeight: 200
|
||||
property real pluginHandlersPopupViewDelegateHeight: 50
|
||||
property color pluginDefaultBackgroundColor: "#666666"
|
||||
property real remotePluginWidthDelegate: 350
|
||||
property real remotePluginHeightDelegate: 400
|
||||
property color pluginViewBackgroundColor: darkTheme ? "#000000" : "#F0EFEF"
|
||||
property real secondaryDialogDimension: 500
|
||||
|
||||
property real lineEditContextMenuItemsHeight: 15
|
||||
|
|
|
@ -42,15 +42,11 @@ Item {
|
|||
antialiasing: true
|
||||
property bool isGif: getIsGif(this)
|
||||
|
||||
Image {
|
||||
id: default_img
|
||||
objectName: "default_img"
|
||||
anchors.fill: parent
|
||||
source: defaultImage
|
||||
visible: image.status != Image.Ready
|
||||
smooth: true
|
||||
antialiasing: true
|
||||
property bool isGif: getIsGif(this)
|
||||
source: defaultImage
|
||||
onStatusChanged: {
|
||||
if (status === Image.Error) {
|
||||
source = defaultImage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,13 +66,6 @@ Item {
|
|||
function onDownloadImageSuccessful(localPath) {
|
||||
if (localPath === cachedImage.localPath) {
|
||||
image.source = "file://" + localPath;
|
||||
print("onDownloadImageSuccessful", localPath);
|
||||
}
|
||||
}
|
||||
function onDownloadImageFailed(localPath) {
|
||||
if (localPath === cachedImage.localPath) {
|
||||
print("Failed to download image: " + downloadUrl);
|
||||
image.source = defaultImage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -99,7 +88,6 @@ Item {
|
|||
}
|
||||
if (downloadUrl && downloadUrl !== "" && localPath !== "") {
|
||||
if (!UtilsAdapter.fileExists(localPath)) {
|
||||
print("ImageDownloader.downloadImage", downloadUrl, localPath);
|
||||
ImageDownloader.downloadImage(downloadUrl, localPath);
|
||||
} else {
|
||||
image.source = "file://" + localPath;
|
||||
|
|
|
@ -18,9 +18,13 @@
|
|||
|
||||
#include "pluginadapter.h"
|
||||
|
||||
#include "pluginversionmanager.h"
|
||||
#include "pluginlistmodel.h"
|
||||
#include "pluginstorelistmodel.h"
|
||||
#include "networkmanager.h"
|
||||
#include "lrcinstance.h"
|
||||
#include "utilsadapter.h"
|
||||
#include "qmlregister.h"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
|
@ -30,14 +34,16 @@
|
|||
|
||||
PluginAdapter::PluginAdapter(LRCInstance* instance, QObject* parent, QString baseUrl)
|
||||
: QmlAdapterBase(instance, parent)
|
||||
, pluginStoreListModel_(new PluginStoreListModel(this))
|
||||
, pluginStoreListModel_(new PluginStoreListModel(instance, this))
|
||||
, pluginVersionManager_(new PluginVersionManager(instance, baseUrl, this))
|
||||
, pluginListModel_(new PluginListModel(this))
|
||||
, pluginListModel_(new PluginListModel(instance, this))
|
||||
, lrcInstance_(instance)
|
||||
, tempPath_(QDir::tempPath())
|
||||
, baseUrl_(baseUrl)
|
||||
|
||||
{
|
||||
QML_REGISTERSINGLETONTYPE_POBJECT(NS_MODELS, pluginStoreListModel_, "PluginStoreListModel");
|
||||
QML_REGISTERSINGLETONTYPE_POBJECT(NS_MODELS, pluginListModel_, "PluginListModel")
|
||||
set_isEnabled(lrcInstance_->pluginModel().getPluginsEnabled());
|
||||
updateHandlersListCount();
|
||||
connect(&lrcInstance_->pluginModel(),
|
||||
|
@ -75,24 +81,34 @@ PluginAdapter::PluginAdapter(LRCInstance* instance, QObject* parent, QString bas
|
|||
void
|
||||
PluginAdapter::getPluginsFromStore()
|
||||
{
|
||||
pluginVersionManager_->sendGetRequest(QUrl(baseUrl_), [this](const QByteArray& data) {
|
||||
auto result = QJsonDocument::fromJson(data).array();
|
||||
auto pluginsInstalled = lrcInstance_->pluginModel().getPluginsId();
|
||||
QList<QVariantMap> plugins;
|
||||
for (const auto& plugin : result) {
|
||||
auto qPlugin = plugin.toVariant().toMap();
|
||||
if (!pluginsInstalled.contains(qPlugin["id"].toString())) {
|
||||
plugins.append(qPlugin);
|
||||
}
|
||||
}
|
||||
pluginStoreListModel_->setPlugins(plugins);
|
||||
});
|
||||
const auto& errorHandler = connect(pluginVersionManager_,
|
||||
&PluginVersionManager::errorOccurred,
|
||||
this,
|
||||
[this](NetworkManager::GetError error, const QString& msg) {
|
||||
Q_EMIT storeNotAvailable();
|
||||
});
|
||||
pluginVersionManager_
|
||||
->sendGetRequest(QUrl(baseUrl_ + "?arch=" + Utils::getPlatformString()),
|
||||
[this, errorHandler](const QByteArray& data) {
|
||||
auto result = QJsonDocument::fromJson(data).array();
|
||||
auto pluginsInstalled = lrcInstance_->pluginModel().getPluginsId();
|
||||
QList<QVariantMap> plugins;
|
||||
for (const auto& plugin : result) {
|
||||
auto qPlugin = plugin.toVariant().toMap();
|
||||
if (!pluginsInstalled.contains(qPlugin["name"].toString())) {
|
||||
plugins.append(qPlugin);
|
||||
}
|
||||
}
|
||||
pluginStoreListModel_->setPlugins(plugins);
|
||||
disconnect(errorHandler);
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
PluginAdapter::getPluginDetails(const QString& pluginId)
|
||||
{
|
||||
pluginVersionManager_->sendGetRequest(QUrl(baseUrl_ + "/details/" + pluginId),
|
||||
pluginVersionManager_->sendGetRequest(QUrl(baseUrl_ + "/details/" + pluginId
|
||||
+ "?arch=" + Utils::getPlatformString()),
|
||||
[this](const QByteArray& data) {
|
||||
auto result = QJsonDocument::fromJson(data).object();
|
||||
// my response is a json object and I want to convert
|
||||
|
@ -114,6 +130,18 @@ PluginAdapter::isAutoUpdaterEnabled()
|
|||
return pluginVersionManager_->isAutoUpdaterEnabled();
|
||||
}
|
||||
|
||||
void
|
||||
PluginAdapter::setAutoUpdate(bool state)
|
||||
{
|
||||
pluginVersionManager_->setAutoUpdate(state);
|
||||
}
|
||||
|
||||
void
|
||||
PluginAdapter::cancelDownload(const QString& pluginId)
|
||||
{
|
||||
pluginVersionManager_->cancelUpdate(pluginId);
|
||||
}
|
||||
|
||||
QVariant
|
||||
PluginAdapter::getMediaHandlerSelectableModel(const QString& callId)
|
||||
{
|
||||
|
@ -169,3 +197,9 @@ PluginAdapter::baseUrl() const
|
|||
{
|
||||
return baseUrl_;
|
||||
}
|
||||
|
||||
QString
|
||||
PluginAdapter::getIconUrl(const QString& pluginId) const
|
||||
{
|
||||
return baseUrl_ + "/icons/" + pluginId + "?arch=" + Utils::getPlatformString();
|
||||
}
|
||||
|
|
|
@ -30,6 +30,9 @@
|
|||
#include <QSortFilterProxyModel>
|
||||
#include <QString>
|
||||
|
||||
class PluginVersionManager;
|
||||
class PluginStoreListModel;
|
||||
|
||||
class PluginAdapter final : public QmlAdapterBase
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -49,6 +52,9 @@ public:
|
|||
Q_INVOKABLE QString baseUrl() const;
|
||||
Q_INVOKABLE void checkVersionStatus(const QString& pluginId);
|
||||
Q_INVOKABLE bool isAutoUpdaterEnabled();
|
||||
Q_INVOKABLE void cancelDownload(const QString& pluginId);
|
||||
Q_INVOKABLE void setAutoUpdate(bool state);
|
||||
Q_INVOKABLE QString getIconUrl(const QString& pluginId) const;
|
||||
|
||||
protected:
|
||||
Q_INVOKABLE QVariant getMediaHandlerSelectableModel(const QString& callId);
|
||||
|
@ -57,14 +63,18 @@ protected:
|
|||
Q_INVOKABLE QVariant getPluginPreferencesCategories(const QString& pluginId,
|
||||
const QString& accountId,
|
||||
bool removeLast = false);
|
||||
Q_SIGNALS:
|
||||
void storeNotAvailable();
|
||||
|
||||
private:
|
||||
void updateHandlersListCount();
|
||||
|
||||
std::unique_ptr<PluginHandlerListModel> pluginHandlerListModel_;
|
||||
PluginStoreListModel* pluginStoreListModel_;
|
||||
PluginVersionManager* pluginVersionManager_;
|
||||
PluginListModel* pluginListModel_;
|
||||
|
||||
std::unique_ptr<PluginHandlerListModel> pluginHandlerListModel_;
|
||||
|
||||
LRCInstance* lrcInstance_;
|
||||
std::mutex mtx_;
|
||||
QString tempPath_;
|
||||
|
|
|
@ -22,9 +22,12 @@
|
|||
|
||||
#include "api/pluginmodel.h"
|
||||
|
||||
PluginListModel::PluginListModel(QObject* parent)
|
||||
PluginListModel::PluginListModel(LRCInstance* lrcInstance, QObject* parent)
|
||||
: AbstractListModelBase(parent)
|
||||
{}
|
||||
, lrcInstance_(lrcInstance)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
PluginListModel::~PluginListModel() {}
|
||||
|
||||
|
@ -55,16 +58,20 @@ PluginListModel::data(const QModelIndex& index, int role) const
|
|||
}
|
||||
|
||||
auto details = lrcInstance_->pluginModel().getPluginDetails(installedPlugins_.at(index.row()));
|
||||
|
||||
installedPlugins_.at(index.row());
|
||||
switch (role) {
|
||||
case Role::PluginName:
|
||||
return QVariant(details.name);
|
||||
case Role::PluginDescription:
|
||||
return QVariant(details.description);
|
||||
case Role::PluginId:
|
||||
return QVariant(installedPlugins_.at(index.row()));
|
||||
case Role::PluginIcon:
|
||||
return QVariant(details.iconPath);
|
||||
case Role::IsLoaded:
|
||||
return QVariant(details.loaded);
|
||||
case Role::Status:
|
||||
return QVariant(pluginStatus_.value(installedPlugins_.at(index.row())));
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
@ -77,7 +84,8 @@ PluginListModel::roleNames() const
|
|||
roles[PluginId] = "PluginId";
|
||||
roles[PluginIcon] = "PluginIcon";
|
||||
roles[IsLoaded] = "IsLoaded";
|
||||
|
||||
roles[Status] = "Status";
|
||||
roles[PluginDescription] = "PluginDescription";
|
||||
return roles;
|
||||
}
|
||||
|
||||
|
@ -87,6 +95,9 @@ PluginListModel::reset()
|
|||
beginResetModel();
|
||||
installedPlugins_.clear();
|
||||
installedPlugins_ = lrcInstance_->pluginModel().getInstalledPlugins();
|
||||
for (auto plugin : installedPlugins_) {
|
||||
pluginStatus_[plugin] = PluginStatus::INSTALLED;
|
||||
}
|
||||
filterPlugins(installedPlugins_);
|
||||
endResetModel();
|
||||
}
|
||||
|
@ -97,6 +108,7 @@ PluginListModel::removePlugin(int index)
|
|||
beginRemoveRows(QModelIndex(), index, index);
|
||||
installedPlugins_.removeAt(index);
|
||||
endRemoveRows();
|
||||
reset();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -120,9 +132,18 @@ PluginListModel::addPlugin()
|
|||
index++;
|
||||
}
|
||||
|
||||
beginInsertRows(QModelIndex(), index, index);
|
||||
installedPlugins_ = newList;
|
||||
endInsertRows();
|
||||
reset();
|
||||
}
|
||||
|
||||
void
|
||||
PluginListModel::disableAllPlugins()
|
||||
{
|
||||
for (auto& plugin : installedPlugins_) {
|
||||
auto& pluginModel = lrcInstance_->pluginModel();
|
||||
const auto& details = pluginModel.getPluginDetails(plugin);
|
||||
pluginModel.unloadPlugin(details.path);
|
||||
disabled(details.path);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -165,14 +186,11 @@ PluginListModel::onVersionStatusChanged(const QString& pluginId, PluginStatus::R
|
|||
if (pluginIndex == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
pluginStatus_[pluginId] = status;
|
||||
switch (status) {
|
||||
case PluginStatus::INSTALLABLE:
|
||||
removePlugin(pluginIndex);
|
||||
break;
|
||||
case PluginStatus::FAILED:
|
||||
qWarning() << "Failed to install plugin" << pluginId;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -28,10 +28,17 @@ class PluginListModel : public AbstractListModelBase
|
|||
Q_OBJECT
|
||||
QML_PROPERTY(bool, filterAccount)
|
||||
public:
|
||||
enum Role { PluginName = Qt::UserRole + 1, PluginId, PluginIcon, IsLoaded };
|
||||
enum Role {
|
||||
PluginName = Qt::UserRole + 1,
|
||||
PluginDescription,
|
||||
PluginId,
|
||||
PluginIcon,
|
||||
IsLoaded,
|
||||
Status
|
||||
};
|
||||
Q_ENUM(Role)
|
||||
|
||||
explicit PluginListModel(QObject* parent = nullptr);
|
||||
explicit PluginListModel(LRCInstance* lrcInstance, QObject* parent = nullptr);
|
||||
~PluginListModel();
|
||||
|
||||
/*
|
||||
|
@ -52,16 +59,19 @@ public:
|
|||
Q_INVOKABLE void removePlugin(int index);
|
||||
Q_INVOKABLE void pluginChanged(int index);
|
||||
Q_INVOKABLE void addPlugin();
|
||||
Q_INVOKABLE void disableAllPlugins();
|
||||
|
||||
Q_SIGNALS:
|
||||
void versionCheckRequested(const QString& pluginId);
|
||||
void setVersionStatus(const QString& pluginId, PluginStatus::Role status);
|
||||
void autoUpdateChanged(bool state);
|
||||
|
||||
void disabled(const QString& pluginId);
|
||||
public Q_SLOTS:
|
||||
void onVersionStatusChanged(const QString& pluginId, PluginStatus::Role status);
|
||||
|
||||
private:
|
||||
LRCInstance* lrcInstance_ = nullptr;
|
||||
void filterPlugins(VectorString& list) const;
|
||||
VectorString installedPlugins_ {};
|
||||
QMap<QString, PluginStatus::Role> pluginStatus_ {};
|
||||
};
|
||||
|
|
|
@ -17,10 +17,17 @@
|
|||
|
||||
#include "pluginstorelistmodel.h"
|
||||
|
||||
#include "lrcinstance.h"
|
||||
|
||||
#include "api/pluginmodel.h"
|
||||
|
||||
#include <QUrl>
|
||||
|
||||
PluginStoreListModel::PluginStoreListModel(QObject* parent)
|
||||
#include <algorithm>
|
||||
|
||||
PluginStoreListModel::PluginStoreListModel(LRCInstance* lrcInstance, QObject* parent)
|
||||
: AbstractListModelBase(parent)
|
||||
, lrcInstance_(lrcInstance)
|
||||
{}
|
||||
|
||||
int
|
||||
|
@ -41,20 +48,16 @@ PluginStoreListModel::data(const QModelIndex& index, int role) const
|
|||
}
|
||||
auto plugin = plugins_.at(index.row());
|
||||
switch (role) {
|
||||
case Role::Id:
|
||||
return QVariant(plugin["id"].toString());
|
||||
case Role::Title:
|
||||
case Role::Name:
|
||||
return QVariant(plugin["name"].toString());
|
||||
case Role::IconPath:
|
||||
return QVariant(plugin["iconPath"].toString());
|
||||
case Role::Background:
|
||||
return QVariant(plugin["background"].toString());
|
||||
case Role::Description:
|
||||
return QVariant(plugin["description"].toString());
|
||||
case Role::Author:
|
||||
return QVariant(plugin["author"].toString());
|
||||
case Role::Status:
|
||||
return QVariant(plugin.value("status", PluginStatus::INSTALLABLE).toString());
|
||||
return QVariant(plugin.value("status", PluginStatus::INSTALLABLE));
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
@ -84,14 +87,16 @@ PluginStoreListModel::addPlugin(const QVariantMap& plugin)
|
|||
beginInsertRows(QModelIndex(), plugins_.size(), plugins_.size());
|
||||
plugins_.append(plugin);
|
||||
endInsertRows();
|
||||
sort();
|
||||
}
|
||||
|
||||
void
|
||||
PluginStoreListModel::setPlugins(const QList<QVariantMap>& plugins)
|
||||
{
|
||||
beginResetModel();
|
||||
plugins_ = plugins;
|
||||
plugins_ = filterPlugins(plugins);
|
||||
endResetModel();
|
||||
sort();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -99,7 +104,7 @@ PluginStoreListModel::removePlugin(const QString& pluginId)
|
|||
{
|
||||
auto index = 0;
|
||||
for (auto& plugin : plugins_) {
|
||||
if (plugin["id"].toString() == pluginId) {
|
||||
if (plugin["name"].toString() == pluginId) {
|
||||
beginRemoveRows(QModelIndex(), index, index);
|
||||
plugins_.removeAt(index);
|
||||
endRemoveRows();
|
||||
|
@ -107,6 +112,7 @@ PluginStoreListModel::removePlugin(const QString& pluginId)
|
|||
}
|
||||
index++;
|
||||
}
|
||||
sort();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -114,13 +120,14 @@ PluginStoreListModel::updatePlugin(const QVariantMap& plugin)
|
|||
{
|
||||
auto index = 0;
|
||||
for (auto& p : plugins_) {
|
||||
if (p["id"].toString() == plugin["id"].toString()) {
|
||||
if (p["name"].toString() == plugin["name"].toString()) {
|
||||
p = plugin;
|
||||
Q_EMIT dataChanged(createIndex(index, 0), createIndex(index, 0));
|
||||
return;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
sort();
|
||||
}
|
||||
|
||||
QColor
|
||||
|
@ -151,7 +158,7 @@ PluginStoreListModel::computeAverageColorOfImage(const QString& file)
|
|||
blue += pixelColor.blue();
|
||||
}
|
||||
}
|
||||
return QColor(red / nPixels, green / nPixels, blue / nPixels, 70);
|
||||
return QColor(red / nPixels, green / nPixels, blue / nPixels);
|
||||
} else {
|
||||
// Return an invalid color.
|
||||
return QColor();
|
||||
|
@ -161,36 +168,80 @@ PluginStoreListModel::computeAverageColorOfImage(const QString& file)
|
|||
void
|
||||
PluginStoreListModel::onVersionStatusChanged(const QString& pluginId, PluginStatus::Role status)
|
||||
{
|
||||
auto plugin = QVariantMap();
|
||||
for (auto& p : plugins_) {
|
||||
if (p["id"].toString() == pluginId) {
|
||||
plugin = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
auto it = std::find_if(plugins_.begin(), plugins_.end(), [&pluginId](const QVariantMap& p) {
|
||||
return p["name"].toString() == pluginId;
|
||||
});
|
||||
|
||||
switch (status) {
|
||||
case PluginStatus::INSTALLABLE:
|
||||
if (!plugin.isEmpty())
|
||||
if (it != plugins_.end()) {
|
||||
break;
|
||||
}
|
||||
pluginAdded(pluginId);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (plugin.isEmpty()) {
|
||||
|
||||
if (it == plugins_.end()) {
|
||||
return;
|
||||
}
|
||||
plugin["status"] = status;
|
||||
auto& plugin = *it;
|
||||
|
||||
plugin["status"] = status;
|
||||
auto index = createIndex(rowFromPluginId(pluginId), 0);
|
||||
if (index.isValid()) {
|
||||
Q_EMIT dataChanged(index, index, {PluginStoreList::Role::Status});
|
||||
}
|
||||
switch (status) {
|
||||
case PluginStatus::INSTALLED:
|
||||
removePlugin(pluginId);
|
||||
break;
|
||||
case PluginStatus::FAILED:
|
||||
qWarning() << "Failed to install plugin" << pluginId;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
PluginStoreListModel::rowFromPluginId(const QString& pluginId) const
|
||||
{
|
||||
const auto it = std::find_if(plugins_.begin(),
|
||||
plugins_.end(),
|
||||
[&pluginId](const QVariantMap& p) {
|
||||
return p["name"].toString() == pluginId;
|
||||
});
|
||||
if (it != plugins_.end()) {
|
||||
return std::distance(plugins_.begin(), it);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
PluginStoreListModel::sort()
|
||||
{
|
||||
beginResetModel();
|
||||
std::sort(plugins_.begin(), plugins_.end(), [](const QVariantMap& a, const QVariantMap& b) {
|
||||
return a["timestamp"].toString() < b["timestamp"].toString();
|
||||
});
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
QList<QVariantMap>
|
||||
PluginStoreListModel::filterPlugins(const QList<QVariantMap>& plugins)
|
||||
{
|
||||
auto& pluginModel = lrcInstance_->pluginModel();
|
||||
auto installedPlugins = pluginModel.getInstalledPlugins();
|
||||
QList<QVariantMap> filterPluginsNotInstalled;
|
||||
for (auto& remotePlugin : plugins) {
|
||||
if (std::find_if(installedPlugins.begin(),
|
||||
installedPlugins.end(),
|
||||
[remotePlugin, &pluginModel, this](const QString& installedPlugin) {
|
||||
const auto& details = pluginModel.getPluginDetails(installedPlugin);
|
||||
return remotePlugin["name"].toString() == details.name;
|
||||
})
|
||||
== installedPlugins.end()) {
|
||||
filterPluginsNotInstalled.append(remotePlugin);
|
||||
}
|
||||
}
|
||||
return filterPluginsNotInstalled;
|
||||
}
|
||||
|
|
|
@ -24,8 +24,7 @@ class QColor;
|
|||
class QString;
|
||||
|
||||
#define PLUGINSTORE_ROLES \
|
||||
X(Id) \
|
||||
X(Title) \
|
||||
X(Name) \
|
||||
X(IconPath) \
|
||||
X(Background) \
|
||||
X(Description) \
|
||||
|
@ -48,7 +47,7 @@ class PluginStoreListModel : public AbstractListModelBase
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PluginStoreListModel(QObject* parent = nullptr);
|
||||
explicit PluginStoreListModel(LRCInstance* lrcInstance, QObject* parent = nullptr);
|
||||
|
||||
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||
|
@ -69,6 +68,10 @@ public Q_SLOTS:
|
|||
void onVersionStatusChanged(const QString& pluginId, PluginStatus::Role status);
|
||||
|
||||
private:
|
||||
QList<QVariantMap> filterPlugins(const QList<QVariantMap>& plugins);
|
||||
int rowFromPluginId(const QString& pluginId) const;
|
||||
void sort();
|
||||
using Role = PluginStoreList::Role;
|
||||
QList<QVariantMap> plugins_;
|
||||
LRCInstance* lrcInstance_ {};
|
||||
};
|
||||
|
|
|
@ -45,7 +45,6 @@ public:
|
|||
return;
|
||||
}
|
||||
for (const auto& pluginId : qAsConst(pluginsId)) {
|
||||
Q_EMIT parent_.versionStatusChanged(pluginId, PluginStatus::Role::INSTALLING);
|
||||
parent_.pluginRepliesId.remove(pluginId);
|
||||
}
|
||||
});
|
||||
|
@ -74,6 +73,7 @@ public:
|
|||
return;
|
||||
}
|
||||
parent_.cancelDownload(parent_.pluginRepliesId[pluginId]);
|
||||
parent_.versionStatusChanged(pluginId, PluginStatus::Role::INSTALLABLE);
|
||||
};
|
||||
|
||||
bool isAutoUpdaterEnabled()
|
||||
|
@ -103,7 +103,8 @@ public:
|
|||
return;
|
||||
}
|
||||
|
||||
parent_.sendGetRequest(QUrl(parent_.baseUrl + "/versions/" + plugin.id),
|
||||
parent_.sendGetRequest(QUrl(parent_.baseUrl + "/versions/" + plugin.id
|
||||
+ "?arch=" + Utils::getPlatformString()),
|
||||
[this, plugin](const QByteArray& data) {
|
||||
// `data` represents the version in this case.
|
||||
if (plugin.version < data) {
|
||||
|
@ -120,7 +121,7 @@ public:
|
|||
void installRemotePlugin(const QString& pluginId)
|
||||
{
|
||||
parent_.downloadFile(
|
||||
QUrl(parent_.baseUrl + "/download/" + pluginId),
|
||||
QUrl(parent_.baseUrl + "/download/" + Utils::getPlatformString() + "/" + pluginId),
|
||||
pluginId,
|
||||
0,
|
||||
[this, pluginId](bool success, const QString& error) {
|
||||
|
@ -129,14 +130,17 @@ public:
|
|||
parent_.versionStatusChanged(pluginId, PluginStatus::Role::FAILED);
|
||||
return;
|
||||
}
|
||||
auto res = lrcInstance_->pluginModel().installPlugin(QDir(tempPath_).filePath(
|
||||
pluginId + ".jpl"),
|
||||
true);
|
||||
if (res) {
|
||||
parent_.versionStatusChanged(pluginId, PluginStatus::Role::INSTALLED);
|
||||
} else {
|
||||
parent_.versionStatusChanged(pluginId, PluginStatus::Role::FAILED);
|
||||
}
|
||||
QThreadPool::globalInstance()->start([this, pluginId] {
|
||||
auto res = lrcInstance_->pluginModel().installPlugin(QDir(tempPath_).filePath(
|
||||
pluginId + ".jpl"),
|
||||
true);
|
||||
if (res) {
|
||||
parent_.versionStatusChanged(pluginId, PluginStatus::Role::INSTALLED);
|
||||
} else {
|
||||
parent_.versionStatusChanged(pluginId, PluginStatus::Role::FAILED);
|
||||
}
|
||||
});
|
||||
parent_.versionStatusChanged(pluginId, PluginStatus::Role::INSTALLING);
|
||||
},
|
||||
tempPath_ + '/');
|
||||
Q_EMIT parent_.versionStatusChanged(pluginId, PluginStatus::Role::DOWNLOADING);
|
||||
|
@ -167,7 +171,7 @@ PluginVersionManager::PluginVersionManager(LRCInstance* instance, QString& baseU
|
|||
|
||||
PluginVersionManager::~PluginVersionManager()
|
||||
{
|
||||
for (const auto& pluginReplyId : qAsConst(pluginRepliesId)) {
|
||||
for (const auto& pluginReplyId : pluginRepliesId.values()) {
|
||||
cancelDownload(pluginReplyId);
|
||||
}
|
||||
pluginRepliesId.clear();
|
||||
|
|
|
@ -72,7 +72,7 @@ Q_SIGNALS:
|
|||
private:
|
||||
QString baseUrl;
|
||||
bool autoUpdateCheck = false;
|
||||
QMap<QString, unsigned int> pluginRepliesId {};
|
||||
QMap<QString, int> pluginRepliesId {};
|
||||
struct Impl;
|
||||
friend struct Impl;
|
||||
std::unique_ptr<Impl> pimpl_;
|
||||
|
|
|
@ -174,7 +174,6 @@ registerTypes(QQmlEngine* engine,
|
|||
QML_REGISTERTYPE(NS_MODELS, MediaCodecListModel);
|
||||
QML_REGISTERTYPE(NS_MODELS, AudioDeviceModel);
|
||||
QML_REGISTERTYPE(NS_MODELS, AudioManagerListModel);
|
||||
QML_REGISTERTYPE(NS_MODELS, PluginListModel);
|
||||
QML_REGISTERTYPE(NS_MODELS, PreferenceItemListModel);
|
||||
QML_REGISTERTYPE(NS_MODELS, PluginListPreferenceModel);
|
||||
QML_REGISTERTYPE(NS_MODELS, FilesToSendListModel);
|
||||
|
|
|
@ -59,14 +59,14 @@ ListSelectionView {
|
|||
leftPaneItem: viewCoordinator.getView("SettingsSidePanel")
|
||||
|
||||
Component.onCompleted: {
|
||||
leftPaneItem.updateModel()
|
||||
leftPaneItem.updateModel();
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: viewNode
|
||||
|
||||
function onIsSinglePaneChanged() {
|
||||
leftPaneItem.isSinglePane = viewNode.isSinglePane
|
||||
leftPaneItem.isSinglePane = viewNode.isSinglePane;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
78
src/app/settingsview/components/InstallManuallyView.qml
Normal file
78
src/app/settingsview/components/InstallManuallyView.qml
Normal file
|
@ -0,0 +1,78 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Qt.labs.platform
|
||||
import net.jami.Models 1.1
|
||||
import net.jami.Adapters 1.1
|
||||
import net.jami.Constants 1.1
|
||||
import "../../commoncomponents"
|
||||
|
||||
ColumnLayout {
|
||||
function installPlugin() {
|
||||
var dlg = viewCoordinator.presentDialog(appWindow, "commoncomponents/JamiFileDialog.qml", {
|
||||
"title": JamiStrings.selectPluginInstall,
|
||||
"fileMode": JamiFileDialog.OpenFile,
|
||||
"folder": StandardPaths.writableLocation(StandardPaths.DownloadLocation),
|
||||
"nameFilters": [JamiStrings.pluginFiles, JamiStrings.allFiles]
|
||||
});
|
||||
dlg.fileAccepted.connect(function (file) {
|
||||
var url = UtilsAdapter.getAbsPath(file.toString());
|
||||
var isInstall = PluginModel.installPlugin(url, true);
|
||||
if (isInstall) {
|
||||
PluginListModel.addPlugin();
|
||||
} else {
|
||||
presentErrorMessage();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function presentErrorMessage() {
|
||||
viewCoordinator.presentDialog(appWindow, "commoncomponents/SimpleMessageDialog.qml", {
|
||||
"title": JamiStrings.installationFailed,
|
||||
"infoText": JamiStrings.pluginInstallationFailed,
|
||||
"buttonStyles": [SimpleMessageDialog.ButtonStyle.TintedBlue],
|
||||
"buttonTitles": [JamiStrings.optionOk],
|
||||
"buttonCallBacks": []
|
||||
});
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: 20
|
||||
|
||||
text: JamiStrings.installManually
|
||||
font.pixelSize: JamiTheme.settingsTitlePixelSize
|
||||
font.kerning: true
|
||||
color: JamiTheme.textColor
|
||||
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
Text {
|
||||
id: descriptionInstallManually
|
||||
Layout.fillWidth: true
|
||||
font.pixelSize: JamiTheme.popuptextSize
|
||||
color: JamiTheme.textColor
|
||||
text: JamiStrings.installMannuallyDescription
|
||||
wrapMode: Text.WordWrap
|
||||
horizontalAlignment: Qt.AlignLeft
|
||||
lineHeight: 1.5
|
||||
textFormat: Text.PlainText
|
||||
}
|
||||
MaterialButton {
|
||||
id: installManually
|
||||
radius: JamiTheme.chatViewHeaderButtonRadius
|
||||
TextMetrics {
|
||||
id: textSize
|
||||
font.weight: Font.Black
|
||||
font.pixelSize: JamiTheme.wizardViewButtonFontPixelSize
|
||||
font.capitalization: Font.AllUppercase
|
||||
text: installManually.text
|
||||
}
|
||||
primary: true
|
||||
preferredWidth: textSize.width + 2 * JamiTheme.buttontextWizzardPadding
|
||||
text: JamiStrings.install
|
||||
fontSize: JamiTheme.popuptextSize
|
||||
onClicked: installPlugin()
|
||||
}
|
||||
}
|
|
@ -27,114 +27,195 @@ import "../../mainview/components"
|
|||
|
||||
ItemDelegate {
|
||||
id: root
|
||||
property string pluginId
|
||||
property string pluginTitle
|
||||
property string pluginName
|
||||
property string pluginIcon
|
||||
property string pluginBackground
|
||||
property string pluginBackground: JamiTheme.pluginDefaultBackgroundColor
|
||||
property string pluginDescription
|
||||
property string pluginAuthor
|
||||
property string pluginShortDescription
|
||||
property int pluginStatus
|
||||
property string installButtonStatus: {
|
||||
switch (pluginStatus) {
|
||||
case PluginStatus.DOWNLOADING:
|
||||
return JamiStrings.cancel;
|
||||
case PluginStatus.INSTALLABLE:
|
||||
return JamiStrings.install;
|
||||
case PluginStatus.INSTALLING:
|
||||
return JamiStrings.installing;
|
||||
default:
|
||||
return JamiStrings.install;
|
||||
}
|
||||
}
|
||||
onPluginStatusChanged: {
|
||||
if (pluginStatus === PluginStatus.FAILED) {
|
||||
presentErrorMessage();
|
||||
}
|
||||
}
|
||||
|
||||
background: null
|
||||
|
||||
function presentErrorMessage() {
|
||||
viewCoordinator.presentDialog(appWindow, "commoncomponents/SimpleMessageDialog.qml", {
|
||||
"title": JamiStrings.installationFailed,
|
||||
"infoText": JamiStrings.pluginInstallationFailed,
|
||||
"buttonStyles": [SimpleMessageDialog.ButtonStyle.TintedBlue],
|
||||
"buttonTitles": [JamiStrings.optionOk],
|
||||
"buttonCallBacks": []
|
||||
});
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: rect
|
||||
Scaffold {
|
||||
}
|
||||
color: Qt.rgba(0, 0, 0, 1)
|
||||
id: mask
|
||||
anchors.fill: parent
|
||||
radius: 15
|
||||
radius: 5
|
||||
}
|
||||
Page {
|
||||
id: plugin
|
||||
anchors.fill: parent
|
||||
layer {
|
||||
enabled: true
|
||||
effect: OpacityMask {
|
||||
maskSource: mask
|
||||
}
|
||||
}
|
||||
header: Control {
|
||||
padding: 10
|
||||
leftPadding: 20
|
||||
rightPadding: 5
|
||||
bottomPadding: 20
|
||||
topPadding: 5
|
||||
background: Rectangle {
|
||||
color: pluginBackground
|
||||
id: headerBackground
|
||||
color: hovered ? Qt.lighter(pluginBackground, 1.9) : Qt.lighter(pluginBackground, 2)
|
||||
}
|
||||
contentItem: ColumnLayout {
|
||||
RowLayout {
|
||||
SpinningAnimation {
|
||||
id: buttonContainer
|
||||
visible: true
|
||||
Layout.alignment: Qt.AlignTop | Qt.AlignRight
|
||||
Layout.rightMargin: 8
|
||||
Layout.topMargin: 2
|
||||
Layout.preferredHeight: install.height
|
||||
Layout.preferredWidth: install.width
|
||||
color: "black"
|
||||
outerCutRadius: install.radius
|
||||
spinningAnimationDuration: 5000
|
||||
mode: {
|
||||
if (pluginStatus === PluginStatus.INSTALLABLE || pluginStatus === PluginStatus.FAILED) {
|
||||
SpinningAnimation.Mode.Disabled;
|
||||
} else {
|
||||
SpinningAnimation.Mode.Radial;
|
||||
}
|
||||
}
|
||||
|
||||
MaterialButton {
|
||||
id: install
|
||||
Layout.alignment: Qt.AlignRight
|
||||
Layout.rightMargin: 8
|
||||
Layout.topMargin: 8
|
||||
Layout.preferredHeight: 20
|
||||
hoverEnabled: pluginStatus !== PluginStatus.INSTALLING
|
||||
secHoveredColor: Qt.darker(headerBackground.color, 1.1)
|
||||
buttontextHeightMargin: 10.0
|
||||
radius: JamiTheme.chatViewHeaderButtonRadius
|
||||
TextMetrics {
|
||||
id: installTextSize
|
||||
font.weight: Font.Black
|
||||
font.pixelSize: JamiTheme.wizardViewButtonFontPixelSize
|
||||
font.capitalization: Font.Medium
|
||||
text: isDownloading() ? JamiStrings.cancel : JamiStrings.install
|
||||
text: install.text
|
||||
}
|
||||
contentColorProvider: "black"
|
||||
onClicked: installPlugin()
|
||||
secondary: true
|
||||
preferredWidth: installTextSize.width + JamiTheme.buttontextWizzardPadding
|
||||
text: isDownloading() ? JamiStrings.cancel : JamiStrings.install
|
||||
fontSize: 15
|
||||
text: {
|
||||
switch (pluginStatus) {
|
||||
case PluginStatus.DOWNLOADING:
|
||||
return JamiStrings.cancel;
|
||||
case PluginStatus.INSTALLABLE:
|
||||
return JamiStrings.install;
|
||||
case PluginStatus.INSTALLING:
|
||||
return JamiStrings.installing;
|
||||
default:
|
||||
return JamiStrings.install;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
spacing: 10
|
||||
|
||||
CachedImage {
|
||||
id: icon
|
||||
Component.onCompleted: {
|
||||
pluginBackground = PluginStoreListModel.computeAverageColorOfImage("file://" + UtilsAdapter.getCachePath() + '/plugins/' + pluginId + '.svg');
|
||||
defaultImage: JamiResources.plugins_default_icon_svg
|
||||
onSourceChanged: {
|
||||
if (source == defaultImage) {
|
||||
pluginBackground = JamiTheme.pluginDefaultBackgroundColor;
|
||||
return;
|
||||
}
|
||||
pluginBackground = PluginStoreListModel.computeAverageColorOfImage(source);
|
||||
}
|
||||
width: 50
|
||||
height: 50
|
||||
downloadUrl: PluginAdapter.baseUrl + "/icons/" + pluginId
|
||||
width: 55
|
||||
height: 55
|
||||
downloadUrl: PluginAdapter.getIconUrl(pluginName)
|
||||
fileExtension: '.svg'
|
||||
localPath: UtilsAdapter.getCachePath() + '/plugins/' + pluginId + '.svg'
|
||||
localPath: UtilsAdapter.getCachePath() + '/plugins/' + pluginName + '.svg'
|
||||
}
|
||||
ColumnLayout {
|
||||
width: parent.width
|
||||
Label {
|
||||
text: pluginTitle
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
text: pluginName
|
||||
font.kerning: true
|
||||
color: JamiTheme.textColor
|
||||
font.pointSize: JamiTheme.settingsFontSize
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
Label {
|
||||
color: JamiTheme.textColor
|
||||
text: pluginShortDescription
|
||||
font.kerning: true
|
||||
font.pointSize: JamiTheme.settingsFontSize
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
color: "black"
|
||||
font.pointSize: JamiTheme.tinyCreditsTextSize
|
||||
textFormat: Text.PlainText
|
||||
wrapMode: Text.WrapAnywhere
|
||||
}
|
||||
// Label {
|
||||
// Layout.fillWidth: true
|
||||
// color: "black"
|
||||
// text: pluginShortDescription
|
||||
// font.pointSize: JamiTheme.settingsFontSize
|
||||
// textFormat: Text.PlainText
|
||||
// wrapMode: Text.WordWrap
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
id: contentContainer
|
||||
anchors.fill: parent
|
||||
color: JamiTheme.pluginViewBackgroundColor
|
||||
color: hovered ? JamiTheme.smartListHoveredColor : JamiTheme.pluginViewBackgroundColor
|
||||
}
|
||||
Flickable {
|
||||
JamiFlickable {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 10
|
||||
contentWidth: description.width
|
||||
anchors.margins: 20
|
||||
contentHeight: description.height
|
||||
clip: true
|
||||
flickableDirection: Flickable.VerticalFlick
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
ScrollBar.vertical: JamiScrollBar {
|
||||
id: scrollBar
|
||||
policy: ScrollBar.AsNeeded
|
||||
}
|
||||
Text {
|
||||
id: description
|
||||
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
||||
ColumnLayout {
|
||||
width: parent.width
|
||||
color: JamiTheme.textColor
|
||||
text: pluginDescription
|
||||
wrapMode: Text.WordWrap
|
||||
Text {
|
||||
id: description
|
||||
Layout.preferredWidth: contentContainer.width
|
||||
font.pixelSize: JamiTheme.popuptextSize
|
||||
color: JamiTheme.textColor
|
||||
text: pluginDescription
|
||||
wrapMode: Text.WordWrap
|
||||
horizontalAlignment: Qt.AlignLeft
|
||||
lineHeight: 1.5
|
||||
textFormat: Text.MarkdownText
|
||||
rightPadding: 40
|
||||
}
|
||||
}
|
||||
}
|
||||
footer: Control {
|
||||
padding: 10
|
||||
padding: 20
|
||||
background: Rectangle {
|
||||
color: JamiTheme.pluginViewBackgroundColor
|
||||
color: hovered ? JamiTheme.smartListHoveredColor : JamiTheme.pluginViewBackgroundColor
|
||||
}
|
||||
contentItem: Text {
|
||||
Layout.fillWidth: true
|
||||
|
@ -145,32 +226,26 @@ ItemDelegate {
|
|||
|
||||
font.pointSize: JamiTheme.settingsFontSize
|
||||
font.kerning: true
|
||||
font.italic: true
|
||||
text: "By " + pluginAuthor
|
||||
wrapMode: Text.WordWrap
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
}
|
||||
|
||||
DropShadow {
|
||||
z: 2
|
||||
visible: hovered
|
||||
width: root.width
|
||||
height: root.height
|
||||
radius: 16
|
||||
color: Qt.rgba(0, 0.34, 0.6, 0.16)
|
||||
source: root
|
||||
transparentBorder: true
|
||||
samples: radius + 1
|
||||
cached: true
|
||||
}
|
||||
}
|
||||
function installPlugin() {
|
||||
if (isDownloading()) {
|
||||
return;
|
||||
switch (pluginStatus) {
|
||||
case PluginStatus.DOWNLOADING:
|
||||
PluginAdapter.cancelDownload(pluginName);
|
||||
break;
|
||||
case PluginStatus.INSTALLABLE:
|
||||
PluginAdapter.installRemotePlugin(pluginName);
|
||||
break;
|
||||
case PluginStatus.FAILED:
|
||||
PluginAdapter.installRemotePlugin(pluginName);
|
||||
break;
|
||||
case PluginStatus.INSTALLING:
|
||||
break;
|
||||
}
|
||||
PluginAdapter.installRemotePlugin(pluginId);
|
||||
}
|
||||
|
||||
function isDownloading() {
|
||||
return pluginStatus === PluginStatus.DOWNLOADING;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,109 +20,133 @@ import QtQuick.Controls
|
|||
import QtQuick.Layouts
|
||||
import net.jami.Models 1.1
|
||||
import net.jami.Adapters 1.1
|
||||
import Qt5Compat.GraphicalEffects
|
||||
import net.jami.Constants 1.1
|
||||
import "../../commoncomponents"
|
||||
|
||||
ItemDelegate {
|
||||
id: root
|
||||
|
||||
property string pluginName: ""
|
||||
property string pluginId: ""
|
||||
property string pluginIcon: ""
|
||||
property int pluginStatus
|
||||
property bool isLoaded: false
|
||||
property string activeId: ""
|
||||
height: pluginPreferencesView.visible ? implicitHeight + pluginPreferencesView.childrenRect.height : implicitHeight
|
||||
height: implicitHeight
|
||||
Connections {
|
||||
target: PluginListModel
|
||||
function onDisabled(id) {
|
||||
if (root.pluginId === id) {
|
||||
isLoaded = false;
|
||||
loadSwitch.checked = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
signal settingsClicked
|
||||
onClicked: {
|
||||
pluginListView.currentIndex = index;
|
||||
}
|
||||
|
||||
onActiveIdChanged: pluginPreferencesView.visible = activeId != pluginId ? false : !pluginPreferencesView.visible
|
||||
Rectangle {
|
||||
id: mask
|
||||
anchors.fill: parent
|
||||
color: {
|
||||
if (pluginHover.hovered && pluginListView.currentIndex !== index) {
|
||||
return JamiTheme.smartListHoveredColor;
|
||||
} else {
|
||||
return JamiTheme.pluginViewBackgroundColor;
|
||||
}
|
||||
}
|
||||
border.width: 2
|
||||
border.color: {
|
||||
if (pluginListView.currentIndex === index) {
|
||||
return JamiTheme.switchHandleCheckedBorderColor;
|
||||
}
|
||||
return "transparent";
|
||||
}
|
||||
radius: 5
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
width: parent.width
|
||||
|
||||
RowLayout {
|
||||
width: parent.width - 20
|
||||
height: parent.height
|
||||
anchors.centerIn: parent
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: implicitHeight
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.preferredHeight: childrenRect.height
|
||||
|
||||
Label {
|
||||
id: pluginImage
|
||||
Layout.leftMargin: 8
|
||||
Layout.topMargin: 8
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlingVCenter
|
||||
anchors.left: parent.left
|
||||
width: JamiTheme.preferredFieldHeight
|
||||
Layout.fillHeight: true
|
||||
height: parent.height
|
||||
|
||||
background: Rectangle {
|
||||
color: "transparent"
|
||||
Image {
|
||||
ResponsiveImage {
|
||||
anchors.centerIn: parent
|
||||
source: "file:" + pluginIcon
|
||||
sourceSize: Qt.size(256, 256)
|
||||
mipmap: true
|
||||
width: JamiTheme.preferredFieldHeight
|
||||
height: JamiTheme.preferredFieldHeight
|
||||
containerWidth: JamiTheme.preferredFieldHeight
|
||||
containerHeight: JamiTheme.preferredFieldHeight
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 8
|
||||
Layout.leftMargin: 8
|
||||
width: contentWidth
|
||||
height: parent.height
|
||||
anchors.left: pluginImage.right
|
||||
anchors.leftMargin: 8
|
||||
color: JamiTheme.textColor
|
||||
|
||||
font.pointSize: JamiTheme.settingsFontSize
|
||||
font.pointSize: JamiTheme.tinyCreditsTextSize
|
||||
font.kerning: true
|
||||
text: pluginName === "" ? pluginId : pluginName
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
ToggleSwitch {
|
||||
id: loadSwitch
|
||||
Layout.fillHeight: true
|
||||
property bool isHovering: false
|
||||
Layout.topMargin: 8
|
||||
Layout.rightMargin: 8
|
||||
width: 20
|
||||
MaterialButton {
|
||||
id: update
|
||||
anchors.right: itemSwitch.left
|
||||
buttontextHeightMargin: 10.0
|
||||
TextMetrics {
|
||||
id: updateTextSize
|
||||
font.weight: Font.Bold
|
||||
font.pixelSize: JamiTheme.wizardViewButtonFontPixelSize
|
||||
font.capitalization: Font.AllUppercase
|
||||
text: JamiStrings.updateDialogTitle
|
||||
}
|
||||
visible: pluginStatus === PluginStatus.UPDATABLE
|
||||
secondary: true
|
||||
preferredWidth: updateTextSize.width
|
||||
text: JamiStrings.updateDialogTitle
|
||||
fontSize: 15
|
||||
}
|
||||
Item {
|
||||
id: itemSwitch
|
||||
height: parent.height
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 78
|
||||
ToggleSwitch {
|
||||
id: loadSwitch
|
||||
anchors.topMargin: parent.height / 2
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
property bool isHovering: false
|
||||
|
||||
tooltipText: JamiStrings.loadUnload
|
||||
tooltipText: JamiStrings.loadUnload
|
||||
|
||||
checked: isLoaded
|
||||
onSwitchToggled: {
|
||||
if (isLoaded)
|
||||
PluginModel.unloadPlugin(pluginId);
|
||||
else
|
||||
PluginModel.loadPlugin(pluginId);
|
||||
installedPluginsModel.pluginChanged(index);
|
||||
checked: isLoaded
|
||||
onSwitchToggled: {
|
||||
if (isLoaded)
|
||||
PluginModel.unloadPlugin(pluginId);
|
||||
else
|
||||
PluginModel.loadPlugin(pluginId);
|
||||
PluginListModel.pluginChanged(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PushButton {
|
||||
id: btnPreferencesPlugin
|
||||
|
||||
Layout.alignment: Qt.AlingVCenter | Qt.AlignRight
|
||||
Layout.topMargin: 8
|
||||
Layout.rightMargin: 8
|
||||
|
||||
source: JamiResources.round_settings_24dp_svg
|
||||
normalColor: JamiTheme.primaryBackgroundColor
|
||||
imageColor: JamiTheme.textColor
|
||||
toolTipText: JamiStrings.showHidePrefs
|
||||
|
||||
onClicked: settingsClicked()
|
||||
}
|
||||
}
|
||||
|
||||
PluginPreferencesView {
|
||||
id: pluginPreferencesView
|
||||
|
||||
pluginId: root.pluginId
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: JamiTheme.preferredMarginSize
|
||||
Layout.rightMargin: JamiTheme.preferredMarginSize
|
||||
Layout.preferredHeight: pluginPreferencesView.childrenRect.height
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,114 +26,105 @@ import "../../commoncomponents"
|
|||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property string activePlugin: ""
|
||||
|
||||
property int count: pluginLoader.item !== undefined ? pluginLoader.item.count : 0
|
||||
property bool isAutoUpdate: PluginAdapter.isAutoUpdaterEnabled()
|
||||
property int currentIndex: {
|
||||
if (pluginLoader.item !== undefined) {
|
||||
return -1;
|
||||
} else {
|
||||
if (pluginListView.currentIndex === null) {
|
||||
return -1;
|
||||
}
|
||||
return pluginListView.currentIndex;
|
||||
}
|
||||
}
|
||||
visible: PluginAdapter.isEnabled && count
|
||||
color: JamiTheme.secondaryBackgroundColor
|
||||
|
||||
ColumnLayout {
|
||||
anchors.left: root.left
|
||||
anchors.right: root.right
|
||||
anchors.bottomMargin: 20
|
||||
|
||||
Label {
|
||||
RowLayout {
|
||||
Layout.preferredHeight: JamiTheme.settingsHeaderpreferredHeight
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 25
|
||||
Layout.bottomMargin: 20
|
||||
Layout.alignment: Qt.AlignRight
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: JamiStrings.installed
|
||||
font.pixelSize: JamiTheme.settingsTitlePixelSize
|
||||
font.kerning: true
|
||||
color: JamiTheme.textColor
|
||||
|
||||
text: JamiStrings.installedPlugins
|
||||
font.pointSize: JamiTheme.headerFontSize
|
||||
font.kerning: true
|
||||
color: JamiTheme.textColor
|
||||
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
MaterialButton {
|
||||
id: disableAll
|
||||
TextMetrics {
|
||||
id: disableTextSize
|
||||
font.weight: Font.Bold
|
||||
font.pixelSize: JamiTheme.wizardViewButtonFontPixelSize
|
||||
font.capitalization: Font.AllUppercase
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
HeaderToggleSwitch {
|
||||
labelText: "auto update"
|
||||
tooltipText: "auto update"
|
||||
checked: isAutoUpdate
|
||||
onSwitchToggled: {
|
||||
isAutoUpdate = !isAutoUpdate;
|
||||
PluginAdapter.setAutoUpdate(isAutoUpdate);
|
||||
}
|
||||
}
|
||||
MaterialButton {
|
||||
id: disableAll
|
||||
radius: JamiTheme.chatViewHeaderButtonRadius
|
||||
buttontextHeightMargin: 10.0
|
||||
TextMetrics {
|
||||
id: disableTextSize
|
||||
font.weight: Font.Bold
|
||||
font.pixelSize: JamiTheme.wizardViewButtonFontPixelSize
|
||||
font.capitalization: Font.AllUppercase
|
||||
text: JamiStrings.disableAll
|
||||
}
|
||||
secondary: true
|
||||
preferredWidth: disableTextSize.width + 2
|
||||
text: JamiStrings.disableAll
|
||||
}
|
||||
secondary: true
|
||||
preferredWidth: disableTextSize.width
|
||||
text: JamiStrings.disableAll
|
||||
fontSize: 15
|
||||
}
|
||||
|
||||
MaterialButton {
|
||||
id: installButton
|
||||
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.topMargin: JamiTheme.preferredMarginSize / 2
|
||||
|
||||
preferredWidth: JamiTheme.preferredFieldWidth
|
||||
buttontextHeightMargin: JamiTheme.buttontextHeightMargin
|
||||
|
||||
color: JamiTheme.buttonTintedBlack
|
||||
hoveredColor: JamiTheme.buttonTintedBlackHovered
|
||||
pressedColor: JamiTheme.buttonTintedBlackPressed
|
||||
secondary: true
|
||||
toolTipText: JamiStrings.addNewPlugin
|
||||
|
||||
iconSource: JamiResources.round_add_24dp_svg
|
||||
|
||||
text: JamiStrings.installPlugin
|
||||
|
||||
onClicked: {
|
||||
var dlg = viewCoordinator.presentDialog(appWindow, "commoncomponents/JamiFileDialog.qml", {
|
||||
"title": JamiStrings.selectPluginInstall,
|
||||
"fileMode": JamiFileDialog.OpenFile,
|
||||
"folder": StandardPaths.writableLocation(StandardPaths.DownloadLocation),
|
||||
"nameFilters": [JamiStrings.pluginFiles, JamiStrings.allFiles]
|
||||
});
|
||||
dlg.fileAccepted.connect(function (file) {
|
||||
var url = UtilsAdapter.getAbsPath(file.toString());
|
||||
PluginModel.installPlugin(url, true);
|
||||
installedPluginsModel.addPlugin();
|
||||
});
|
||||
fontSize: JamiTheme.wizardViewButtonFontPixelSize
|
||||
onClicked: PluginListModel.disableAllPlugins()
|
||||
}
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: pluginList
|
||||
|
||||
Loader {
|
||||
id: pluginLoader
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: 10
|
||||
Layout.preferredHeight: childrenRect.height
|
||||
clip: true
|
||||
Layout.preferredHeight: pluginLoader.item.contentHeight
|
||||
Layout.topMargin: 10
|
||||
active: true
|
||||
asynchronous: true
|
||||
|
||||
model: PluginListModel {
|
||||
id: installedPluginsModel
|
||||
|
||||
lrcInstance: LRCInstance
|
||||
onLrcInstanceChanged: {
|
||||
this.reset();
|
||||
sourceComponent: ListView {
|
||||
id: pluginListView
|
||||
clip: true
|
||||
model: PluginListModel
|
||||
spacing: 10
|
||||
currentIndex: -1
|
||||
onCurrentIndexChanged: {
|
||||
root.currentIndex = currentIndex;
|
||||
}
|
||||
}
|
||||
delegate: PluginItemDelegate {
|
||||
id: pluginItemDelegate
|
||||
width: pluginLoader.width
|
||||
implicitHeight: 50
|
||||
|
||||
delegate: PluginItemDelegate {
|
||||
id: pluginItemDelegate
|
||||
|
||||
width: pluginList.width
|
||||
implicitHeight: 50
|
||||
|
||||
pluginName: PluginName
|
||||
pluginId: PluginId
|
||||
pluginIcon: PluginIcon
|
||||
isLoaded: IsLoaded
|
||||
activeId: root.activePlugin
|
||||
|
||||
background: Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "transparent"
|
||||
pluginName: PluginName
|
||||
pluginId: PluginId
|
||||
pluginIcon: PluginIcon
|
||||
pluginStatus: Status
|
||||
isLoaded: IsLoaded
|
||||
HoverHandler {
|
||||
id: pluginHover
|
||||
target: parent
|
||||
enabled: true
|
||||
}
|
||||
}
|
||||
|
||||
onSettingsClicked: {
|
||||
root.activePlugin = root.activePlugin === pluginId ? "" : pluginId;
|
||||
Connections {
|
||||
target: pluginPreferencesView
|
||||
function onClosed() {
|
||||
pluginListView.currentIndex = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,9 +25,9 @@ import "../../commoncomponents"
|
|||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property string accountId: ""
|
||||
required property string pluginId
|
||||
width: parent.width
|
||||
|
||||
property int count: pluginPreferenceView.count + pluginPreferenceViewCategory.count
|
||||
|
||||
|
@ -40,7 +40,6 @@ Rectangle {
|
|||
}
|
||||
|
||||
color: "transparent"
|
||||
|
||||
Connections {
|
||||
target: LRCInstance
|
||||
|
||||
|
@ -56,8 +55,6 @@ Rectangle {
|
|||
property var categories: PluginAdapter.getPluginPreferencesCategories(pluginId, accountId)
|
||||
property string generalCategory: categories.length <= 1 ? "all" : ""
|
||||
|
||||
visible: false
|
||||
|
||||
function setPreference(pluginId, preferenceKey, preferenceNewValue) {
|
||||
PluginModel.setPluginPreference(pluginId, accountId, preferenceKey, preferenceNewValue);
|
||||
}
|
||||
|
@ -66,7 +63,7 @@ Rectangle {
|
|||
anchors.left: root.left
|
||||
anchors.right: root.right
|
||||
|
||||
Rectangle {
|
||||
Item {
|
||||
id: prefsByCategory
|
||||
|
||||
visible: categories.length > 1
|
||||
|
@ -74,7 +71,6 @@ Rectangle {
|
|||
Layout.topMargin: 24
|
||||
Layout.fillWidth: true
|
||||
implicitHeight: childrenRect.height
|
||||
color: JamiTheme.backgroundColor
|
||||
|
||||
ColumnLayout {
|
||||
anchors.left: parent.left
|
||||
|
@ -263,7 +259,7 @@ Rectangle {
|
|||
|
||||
MaterialButton {
|
||||
id: resetButton
|
||||
|
||||
visible: count > 0
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
|
||||
preferredWidth: JamiTheme.preferredFieldWidth
|
||||
|
@ -274,8 +270,6 @@ Rectangle {
|
|||
pressedColor: JamiTheme.buttonTintedBlackPressed
|
||||
secondary: true
|
||||
|
||||
iconSource: JamiResources.settings_backup_restore_24dp_svg
|
||||
|
||||
text: JamiStrings.reset
|
||||
|
||||
onClicked: viewCoordinator.presentDialog(appWindow, "commoncomponents/SimpleMessageDialog.qml", {
|
||||
|
|
|
@ -19,179 +19,181 @@ import QtQuick
|
|||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import net.jami.Adapters 1.1
|
||||
import SortFilterProxyModel 0.2
|
||||
import net.jami.Models 1.1
|
||||
import net.jami.Constants 1.1
|
||||
import "../../commoncomponents"
|
||||
|
||||
Rectangle {
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property string pluginId
|
||||
|
||||
color: "transparent"
|
||||
|
||||
visible: false
|
||||
|
||||
ColumnLayout {
|
||||
anchors.left: root.left
|
||||
anchors.right: root.right
|
||||
anchors.bottomMargin: 10
|
||||
|
||||
Label {
|
||||
Layout.topMargin: 34
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
height: 64
|
||||
required property int currentIndex
|
||||
signal closed
|
||||
ListView {
|
||||
id: pluginPreferenceListView
|
||||
height: parent.height
|
||||
width: parent.width
|
||||
model: SortFilterProxyModel {
|
||||
sourceModel: PluginListModel
|
||||
filters: [
|
||||
ExpressionFilter {
|
||||
expression: index === currentIndex
|
||||
enabled: true
|
||||
}
|
||||
]
|
||||
}
|
||||
delegate: Page {
|
||||
id: settings
|
||||
width: root.width
|
||||
height: root.height
|
||||
background: Rectangle {
|
||||
Image {
|
||||
anchors.centerIn: parent
|
||||
source: pluginIcon === "" ? JamiResources.plugins_24dp_svg : "file:" + pluginIcon
|
||||
sourceSize: Qt.size(256, 256)
|
||||
height: 64
|
||||
width: 64
|
||||
mipmap: true
|
||||
color: JamiTheme.pluginViewBackgroundColor
|
||||
}
|
||||
header: Control {
|
||||
padding: 10
|
||||
background: Rectangle {
|
||||
color: JamiTheme.pluginViewBackgroundColor
|
||||
}
|
||||
contentItem: ColumnLayout {
|
||||
width: parent.width
|
||||
PushButton {
|
||||
id: closeButton
|
||||
normalColor: "transparent"
|
||||
hoveredColor: JamiTheme.smartListHoveredColor
|
||||
Layout.alignment: Qt.AlignRight
|
||||
Layout.preferredWidth: JamiTheme.preferredFieldHeight
|
||||
Layout.preferredHeight: childrenRect.height
|
||||
|
||||
imageColor: JamiTheme.textColor
|
||||
toolTipText: JamiStrings.closeSettings
|
||||
|
||||
preferredSize: 32
|
||||
source: JamiResources.round_close_24dp_svg
|
||||
onClicked: {
|
||||
closed();
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.preferredWidth: parent.width
|
||||
ResponsiveImage {
|
||||
Layout.bottomMargin: 10
|
||||
Layout.rightMargin: 10
|
||||
containerWidth: 64
|
||||
containerHeight: 64
|
||||
source: PluginIcon === "" ? JamiResources.plugins_default_icon_svg : "file:" + PluginIcon
|
||||
}
|
||||
Label {
|
||||
text: PluginName
|
||||
font.pixelSize: JamiTheme.settingsTitlePixelSize
|
||||
font.kerning: true
|
||||
color: JamiTheme.textColor
|
||||
textFormat: Text.PlainText
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
MaterialButton {
|
||||
id: update
|
||||
anchors.right: parent.right
|
||||
buttontextHeightMargin: 0.0
|
||||
TextMetrics {
|
||||
id: updateTextSize
|
||||
font.weight: Font.Bold
|
||||
font.pixelSize: JamiTheme.wizardViewButtonFontPixelSize
|
||||
font.capitalization: Font.AllUppercase
|
||||
text: JamiStrings.updateDialogTitle
|
||||
}
|
||||
visible: Status === PluginStatus.UPDATABLE
|
||||
secondary: true
|
||||
preferredWidth: updateTextSize.width
|
||||
text: JamiStrings.updateDialogTitle
|
||||
fontSize: 15
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JamiFlickable {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: childrenRect.height
|
||||
Layout.minimumHeight: childrenRect.height
|
||||
Layout.maximumHeight: 88
|
||||
contentWidth: description.width
|
||||
contentHeight: description.height
|
||||
clip: true
|
||||
flickableDirection: Flickable.VerticalFlick
|
||||
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
id: scrollBar
|
||||
policy: ScrollBar.AsNeeded
|
||||
}
|
||||
Text {
|
||||
id: description
|
||||
width: settings.width - 2 * scrollBar.width
|
||||
text: PluginDescription
|
||||
font.pixelSize: JamiTheme.popuptextSize
|
||||
color: JamiTheme.textColor
|
||||
wrapMode: Text.WordWrap
|
||||
textFormat: Text.PlainText
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.topMargin: 24
|
||||
height: JamiTheme.preferredFieldHeight
|
||||
|
||||
text: "%1\n%2".arg(pluginName).arg(JamiStrings.pluginPreferences)
|
||||
font.pointSize: JamiTheme.headerFontSize
|
||||
font.kerning: true
|
||||
color: JamiTheme.textColor
|
||||
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
Text {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: JamiTheme.preferredFieldHeight
|
||||
|
||||
font.pointSize: JamiTheme.headerFontSize
|
||||
font.kerning: true
|
||||
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
color: JamiTheme.textColor
|
||||
|
||||
text: JamiStrings.generalSettingsTitle
|
||||
elide: Text.ElideRight
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: JamiTheme.primaryBackgroundColor
|
||||
}
|
||||
JamiFlickable {
|
||||
anchors.fill: parent
|
||||
contentHeight: contentItem.childrenRect.height
|
||||
topMargin: JamiTheme.preferredSettingsBottomMarginSize
|
||||
bottomMargin: JamiTheme.preferredSettingsBottomMarginSize
|
||||
ScrollBar.horizontal.visible: false
|
||||
contentItem.children: ColumnLayout {
|
||||
width: root.width
|
||||
PluginPreferencesListView {
|
||||
id: pluginGeneralSettingsView
|
||||
Layout.fillWidth: true
|
||||
pluginId: PluginId
|
||||
}
|
||||
PluginPreferencesListView {
|
||||
id: pluginAccountSettingsView
|
||||
Layout.fillWidth: true
|
||||
accountId: LRCInstance.currentAccountId
|
||||
pluginId: PluginId
|
||||
}
|
||||
MaterialButton {
|
||||
id: uninstallButton
|
||||
|
||||
PushButton {
|
||||
Layout.preferredWidth: JamiTheme.preferredFieldHeight
|
||||
Layout.preferredHeight: JamiTheme.preferredFieldHeight
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
|
||||
imageColor: JamiTheme.textColor
|
||||
toolTipText: JamiStrings.tipGeneralPluginSettingsDisplay
|
||||
preferredWidth: JamiTheme.preferredFieldWidth
|
||||
buttontextHeightMargin: JamiTheme.buttontextHeightMargin
|
||||
contentColorProvider: JamiTheme.buttonTintedRed
|
||||
color: JamiTheme.buttonTintedBlack
|
||||
hoveredColor: JamiTheme.buttonTintedBlackHovered
|
||||
pressedColor: JamiTheme.buttonTintedBlackPressed
|
||||
tertiary: true
|
||||
toolTipText: JamiStrings.pluginUninstallConfirmation.arg(PluginId)
|
||||
|
||||
preferredSize: 32
|
||||
source: pluginGeneralSettingsView.visible ? JamiResources.expand_less_24dp_svg : JamiResources.expand_more_24dp_svg
|
||||
text: JamiStrings.uninstall
|
||||
|
||||
onClicked: {
|
||||
pluginGeneralSettingsView.visible = !pluginGeneralSettingsView.visible;
|
||||
onClicked: viewCoordinator.presentDialog(appWindow, "commoncomponents/SimpleMessageDialog.qml", {
|
||||
"title": JamiStrings.uninstallPlugin,
|
||||
"infoText": JamiStrings.pluginUninstallConfirmation.arg(PluginName),
|
||||
"buttonTitles": [JamiStrings.optionOk, JamiStrings.optionCancel],
|
||||
"buttonStyles": [SimpleMessageDialog.ButtonStyle.TintedBlue, SimpleMessageDialog.ButtonStyle.TintedBlack],
|
||||
"buttonCallBacks": [function () {
|
||||
PluginListModel.setVersionStatus(PluginName, PluginStatus.INSTALLABLE);
|
||||
PluginModel.uninstallPlugin(PluginId);
|
||||
PluginListModel.removePlugin(index);
|
||||
// could not call root from here
|
||||
settings.ListView.view.parent.closed();
|
||||
}]
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PluginPreferencesListView {
|
||||
id: pluginGeneralSettingsView
|
||||
visible: false
|
||||
Layout.fillWidth: true
|
||||
pluginId: root.pluginId
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
visible: pluginAccountSettingsView.count > 0
|
||||
|
||||
Text {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: JamiTheme.preferredFieldHeight
|
||||
|
||||
font.pointSize: JamiTheme.headerFontSize
|
||||
font.kerning: true
|
||||
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
color: JamiTheme.textColor
|
||||
|
||||
text: JamiStrings.accountSettingsMenuTitle
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
PushButton {
|
||||
Layout.preferredWidth: JamiTheme.preferredFieldHeight
|
||||
Layout.preferredHeight: JamiTheme.preferredFieldHeight
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
imageColor: JamiTheme.textColor
|
||||
toolTipText: JamiStrings.tipAccountPluginSettingsDisplay
|
||||
|
||||
preferredSize: 32
|
||||
source: pluginAccountSettingsView.visible ? JamiResources.expand_less_24dp_svg : JamiResources.expand_more_24dp_svg
|
||||
|
||||
onClicked: {
|
||||
pluginAccountSettingsView.visible = !pluginAccountSettingsView.visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PluginPreferencesListView {
|
||||
id: pluginAccountSettingsView
|
||||
visible: false
|
||||
Layout.fillWidth: true
|
||||
accountId: LRCInstance.currentAccountId
|
||||
pluginId: root.pluginId
|
||||
}
|
||||
|
||||
MaterialButton {
|
||||
id: uninstallButton
|
||||
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
|
||||
preferredWidth: JamiTheme.preferredFieldWidth
|
||||
buttontextHeightMargin: JamiTheme.buttontextHeightMargin
|
||||
|
||||
color: JamiTheme.buttonTintedBlack
|
||||
hoveredColor: JamiTheme.buttonTintedBlackHovered
|
||||
pressedColor: JamiTheme.buttonTintedBlackPressed
|
||||
secondary: true
|
||||
toolTipText: JamiStrings.pluginUninstallConfirmation.arg(pluginName)
|
||||
iconSource: JamiResources.delete_24dp_svg
|
||||
|
||||
text: JamiStrings.uninstall
|
||||
|
||||
onClicked: viewCoordinator.presentDialog(appWindow, "commoncomponents/SimpleMessageDialog.qml", {
|
||||
"title": JamiStrings.uninstallPlugin,
|
||||
"infoText": JamiStrings.pluginUninstallConfirmation.arg(pluginName),
|
||||
"buttonTitles": [JamiStrings.optionOk, JamiStrings.optionCancel],
|
||||
"buttonStyles": [SimpleMessageDialog.ButtonStyle.TintedBlue, SimpleMessageDialog.ButtonStyle.TintedBlack],
|
||||
"buttonCallBacks": [function () {
|
||||
pluginPreferencesView.visible = false;
|
||||
PluginModel.uninstallPlugin(pluginId);
|
||||
PluginListModel.removePlugin(index);
|
||||
var pluginPath = pluginId.split('/');
|
||||
PluginListModel.setVersionStatus(pluginPath[pluginPath.length - 1], PluginStatus.INSTALLABLE);
|
||||
}]
|
||||
})
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.bottomMargin: 10
|
||||
height: 2
|
||||
Layout.fillWidth: true
|
||||
color: "transparent"
|
||||
border.width: 1
|
||||
border.color: JamiTheme.separationLine
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,29 +25,84 @@ import "../../commoncomponents"
|
|||
|
||||
SettingsPageBase {
|
||||
id: root
|
||||
contentFlickableWidth: Math.min(root.width, root.width - 2 * JamiTheme.preferredSettingsMarginSize)
|
||||
title: JamiStrings.pluginSettingsTitle
|
||||
|
||||
flickableContent: ColumnLayout {
|
||||
id: pluginSettingsColumnLayout
|
||||
|
||||
width: contentFlickableWidth
|
||||
spacing: JamiTheme.settingsBlockSpacing
|
||||
onWidthChanged: resolvePanes()
|
||||
flickableContent: RowLayout {
|
||||
width: parent.width
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: JamiTheme.preferredSettingsMarginSize
|
||||
|
||||
ColumnLayout {
|
||||
id: generalSettings
|
||||
Layout.preferredWidth: root.width
|
||||
spacing: JamiTheme.settingsCategorySpacing
|
||||
}
|
||||
PluginListView {
|
||||
id: pluginListView
|
||||
|
||||
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
|
||||
Layout.maximumWidth: 3 * (JamiTheme.remotePluginWidthDelegate + 20)
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.minimumHeight: 0
|
||||
Layout.preferredHeight: childrenRect.height
|
||||
Layout.rightMargin: 80
|
||||
spacing: JamiTheme.settingsBlockSpacing
|
||||
// View of installed plugins
|
||||
PluginListView {
|
||||
id: pluginList
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 20
|
||||
Layout.preferredHeight: childrenRect.height
|
||||
Connections {
|
||||
target: pluginPreferencesView
|
||||
function onClosed() {
|
||||
pluginList.currentIndex = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// View of available plugins in the store
|
||||
PluginStoreListView {
|
||||
Layout.alignment: Qt.AlignBottom | Qt.AlignHCenter
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
InstallManuallyView {
|
||||
Layout.fillWidth: true
|
||||
spacing: 10
|
||||
}
|
||||
}
|
||||
}
|
||||
property real previousDetailsWidth: 500
|
||||
property real previousWidth: 500
|
||||
// This function governs the visibility of the plugin content and tracks the
|
||||
// the width of the SplitView and the details panel. This function should be
|
||||
// called when the width of the SplitView changes, when the SplitView is shown,
|
||||
// and when the details panel is shown. When called with force=true, it is being
|
||||
// called from a visibleChanged event, and we should not update the previous widths.
|
||||
function resolvePanes(force = false) {
|
||||
// If the details panel is not visible, then show the generalSettings.
|
||||
if (!pluginPreferencesView.visible) {
|
||||
pageContainer.visible = true;
|
||||
return;
|
||||
}
|
||||
// Next we compute whether the SplitView is expanding or shrinking.
|
||||
const isExpanding = width > previousWidth;
|
||||
// width has a first bad state
|
||||
const preferencePreferredWidth = pluginPreferencesView.width === 0 ? 500 : pluginPreferencesView.width;
|
||||
// If the SplitView is not wide enough to show both the generalSettings
|
||||
// and the details panel, then hide the generalSettings.
|
||||
if (width < 522 + preferencePreferredWidth && (!isExpanding || force) && pageContainer.visible) {
|
||||
if (!force)
|
||||
previousDetailsWidth = pluginPreferencesView.width;
|
||||
pageContainer.visible = false;
|
||||
} else if (width >= JamiTheme.mainViewPaneMinWidth + previousDetailsWidth && (isExpanding || force) && !pageContainer.visible) {
|
||||
pageContainer.visible = true;
|
||||
}
|
||||
if (!force)
|
||||
previousWidth = width;
|
||||
}
|
||||
|
||||
onResizingChanged: if (pageContainer.visible)
|
||||
pluginPreferencesView.previousWidth = pluginPreferencesView.width
|
||||
|
||||
PluginPreferencesView {
|
||||
id: pluginPreferencesView
|
||||
SplitView.maximumWidth: root.width
|
||||
SplitView.minimumWidth: 500
|
||||
SplitView.preferredWidth: 500
|
||||
SplitView.fillHeight: true
|
||||
property int previousWidth: 500
|
||||
currentIndex: pluginList.currentIndex
|
||||
visible: pluginList.currentIndex != -1
|
||||
onVisibleChanged: root.resolvePanes(true)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,80 +25,63 @@ import net.jami.Constants 1.1
|
|||
import "../../commoncomponents"
|
||||
|
||||
ColumnLayout {
|
||||
function installPlugin() {
|
||||
var dlg = viewCoordinator.presentDialog(appWindow, "commoncomponents/JamiFileDialog.qml", {
|
||||
"title": JamiStrings.selectPluginInstall,
|
||||
"fileMode": JamiFileDialog.OpenFile,
|
||||
"folder": StandardPaths.writableLocation(StandardPaths.DownloadLocation),
|
||||
"nameFilters": [JamiStrings.pluginFiles, JamiStrings.allFiles]
|
||||
});
|
||||
dlg.fileAccepted.connect(function (file) {
|
||||
var url = UtilsAdapter.getAbsPath(file.toString());
|
||||
PluginModel.installPlugin(url, true);
|
||||
PluginListModel.addPlugin();
|
||||
});
|
||||
property bool storeAvailable: true
|
||||
Component.onCompleted: {
|
||||
PluginAdapter.getPluginsFromStore();
|
||||
}
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 25
|
||||
|
||||
text: JamiStrings.pluginStoreTitle
|
||||
font.pointSize: JamiTheme.headerFontSize
|
||||
font.kerning: true
|
||||
color: JamiTheme.textColor
|
||||
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
Connections {
|
||||
target: PluginAdapter
|
||||
function onStoreNotAvailable() {
|
||||
storeAvailable = false;
|
||||
}
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignRight
|
||||
MaterialButton {
|
||||
id: installManually
|
||||
}
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: 20
|
||||
text: JamiStrings.pluginStoreTitle
|
||||
font.pixelSize: JamiTheme.settingsTitlePixelSize
|
||||
font.kerning: true
|
||||
color: JamiTheme.textColor
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
Loader {
|
||||
active: storeAvailable
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.preferredHeight: active ? item.height : 0
|
||||
sourceComponent: Flow {
|
||||
id: pluginStoreList
|
||||
height: childrenRect.height
|
||||
spacing: 20
|
||||
Repeater {
|
||||
model: PluginStoreListModel
|
||||
|
||||
TextMetrics {
|
||||
id: installManuallyTextSize
|
||||
font.weight: Font.Black
|
||||
font.pixelSize: JamiTheme.wizardViewButtonFontPixelSize
|
||||
font.capitalization: Font.Capitalize
|
||||
text: JamiStrings.installManually
|
||||
delegate: PluginAvailableDelagate {
|
||||
id: pluginItemDelegate
|
||||
width: JamiTheme.remotePluginWidthDelegate
|
||||
height: JamiTheme.remotePluginHeightDelegate
|
||||
pluginName: Name
|
||||
pluginIcon: IconPath
|
||||
pluginDescription: Description
|
||||
pluginAuthor: Author
|
||||
pluginShortDescription: ""
|
||||
pluginStatus: Status
|
||||
}
|
||||
secondary: true
|
||||
preferredWidth: installManuallyTextSize.width
|
||||
text: JamiStrings.installManually
|
||||
toolTipText: JamiStrings.installManually
|
||||
fontSize: 15
|
||||
onClicked: installPlugin()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Flow {
|
||||
id: pluginStoreList
|
||||
|
||||
Loader {
|
||||
Layout.fillWidth: true
|
||||
spacing: 20
|
||||
Layout.preferredHeight: childrenRect.height
|
||||
clip: true
|
||||
Repeater {
|
||||
model: PluginStoreListModel
|
||||
|
||||
delegate: PluginAvailableDelagate {
|
||||
id: pluginItemDelegate
|
||||
|
||||
width: 350
|
||||
height: 400
|
||||
pluginId: Id
|
||||
pluginTitle: Title
|
||||
pluginIcon: IconPath
|
||||
pluginBackground: Background === '' ? JamiTheme.backgroundColor : Background
|
||||
pluginDescription: Description
|
||||
pluginAuthor: Author
|
||||
pluginShortDescription: ""
|
||||
pluginStatus: Status
|
||||
}
|
||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
|
||||
Layout.preferredHeight: active ? JamiTheme.bigFontSize : 0
|
||||
active: !storeAvailable
|
||||
sourceComponent: Text {
|
||||
font.bold: true
|
||||
color: JamiTheme.textColor
|
||||
font.pixelSize: JamiTheme.bigFontSize
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: JamiStrings.pluginStoreNotAvailable
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,41 +23,44 @@ import net.jami.Enums 1.1
|
|||
import net.jami.Models 1.1
|
||||
import "../../commoncomponents"
|
||||
|
||||
Page {
|
||||
JamiSplitView {
|
||||
id: root
|
||||
|
||||
required property Item flickableContent
|
||||
|
||||
property real contentFlickableWidth: Math.min(JamiTheme.maximumWidthSettingsView, root.width - 2 * JamiTheme.preferredSettingsMarginSize)
|
||||
|
||||
property real contentFlickableWidth: Math.min(JamiTheme.maximumWidthSettingsView, settingsPage.width - 2 * JamiTheme.preferredSettingsMarginSize)
|
||||
property alias title: settingsPage.title
|
||||
property color backgroundColor: JamiTheme.secondaryBackgroundColor
|
||||
property alias pageContainer: settingsPage
|
||||
Page {
|
||||
id: settingsPage
|
||||
SplitView.maximumWidth: root.width
|
||||
SplitView.fillWidth: true
|
||||
SplitView.minimumWidth: 500
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
color: backgroundColor
|
||||
}
|
||||
header: Rectangle {
|
||||
height: JamiTheme.settingsHeaderpreferredHeight
|
||||
width: root.preferredWidth
|
||||
color: backgroundColor
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
color: backgroundColor
|
||||
}
|
||||
SettingsHeader {
|
||||
id: settingsHeader
|
||||
title: root.title
|
||||
anchors.fill: parent
|
||||
onBackArrowClicked: viewNode.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
header: Rectangle {
|
||||
height: JamiTheme.settingsHeaderpreferredHeight
|
||||
width: root.preferredWidth
|
||||
color: backgroundColor
|
||||
|
||||
SettingsHeader {
|
||||
id: settingsHeader
|
||||
title: root.title
|
||||
JamiFlickable {
|
||||
id: flickable
|
||||
anchors.fill: parent
|
||||
onBackArrowClicked: viewNode.dismiss()
|
||||
contentHeight: contentItem.childrenRect.height
|
||||
contentItem.children: [flickableContent]
|
||||
topMargin: JamiTheme.preferredSettingsBottomMarginSize
|
||||
bottomMargin: JamiTheme.preferredSettingsBottomMarginSize
|
||||
ScrollBar.horizontal.visible: false
|
||||
}
|
||||
}
|
||||
|
||||
JamiFlickable {
|
||||
id: flickable
|
||||
anchors.fill: parent
|
||||
contentHeight: contentItem.childrenRect.height
|
||||
contentItem.children: [flickableContent]
|
||||
topMargin: JamiTheme.preferredSettingsBottomMarginSize
|
||||
bottomMargin: JamiTheme.preferredSettingsBottomMarginSize
|
||||
ScrollBar.horizontal.visible: false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -933,3 +933,9 @@ Utils::generateUid()
|
|||
{
|
||||
return QUuid::createUuid().toString(QUuid::Id128);
|
||||
}
|
||||
|
||||
QString
|
||||
Utils::getPlatformString()
|
||||
{
|
||||
return "desktop";
|
||||
}
|
|
@ -127,4 +127,5 @@ QString generateUid();
|
|||
QString humanFileSize(qint64 fileSize);
|
||||
QString getDebugFilePath();
|
||||
|
||||
QString getPlatformString();
|
||||
} // namespace Utils
|
||||
|
|
|
@ -40,6 +40,7 @@ struct PluginDetails
|
|||
{
|
||||
QString id = "";
|
||||
QString name = "";
|
||||
QString description = "";
|
||||
QString path = "";
|
||||
QString version = "";
|
||||
QString iconPath = "";
|
||||
|
@ -201,7 +202,6 @@ public:
|
|||
* @return true if preference was succesfully reset
|
||||
*/
|
||||
Q_INVOKABLE bool resetPluginPreferencesValues(const QString& path, const QString& accountId);
|
||||
|
||||
Q_SIGNALS:
|
||||
void chatHandlerStatusUpdated(bool isVisible);
|
||||
void modelUpdated();
|
||||
|
|
|
@ -50,6 +50,15 @@ namespace lrc {
|
|||
|
||||
using namespace api;
|
||||
|
||||
enum pluginInstallResult {
|
||||
SUCCESS = 0,
|
||||
PLUGIN_ALREADY_INSTALLED = 100, /* Plugin already installed with the same version */
|
||||
PLUGIN_OLD_VERSION = 200, /* Plugin already installed with a newer version */
|
||||
SIGNATURE_VERIFICATION_FAILED = 300, /* Signature verification failed */
|
||||
CERTIFICATE_VERIFICATION_FAILED = 400,
|
||||
INVALID_PLUGIN = 500,
|
||||
};
|
||||
|
||||
PluginModel::PluginModel()
|
||||
: QObject()
|
||||
{
|
||||
|
@ -99,6 +108,7 @@ PluginModel::getPluginDetails(const QString& path)
|
|||
if (!details.empty()) {
|
||||
result.id = details["id"];
|
||||
result.name = details["name"];
|
||||
result.description = details["description"];
|
||||
result.path = path;
|
||||
result.iconPath = details["iconPath"];
|
||||
result.version = details["version"];
|
||||
|
@ -311,5 +321,4 @@ PluginModel::resetPluginPreferencesValues(const QString& path, const QString& ac
|
|||
Q_EMIT modelUpdated();
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace lrc
|
||||
|
|
Loading…
Add table
Reference in a new issue