diff --git a/discover/assets.qrc b/discover/assets.qrc --- a/discover/assets.qrc +++ b/discover/assets.qrc @@ -2,6 +2,5 @@ banners/banner.svg - banners/coffee.jpg diff --git a/discover/autotests/updateandinstall.qml b/discover/autotests/updateandinstall.qml --- a/discover/autotests/updateandinstall.qml +++ b/discover/autotests/updateandinstall.qml @@ -32,6 +32,7 @@ { var updatePage = appRoot.stack.currentItem; compare(typeName(updatePage), "UpdatesPage") + verify(waitForSignal(updatePage, "stateChanged")) compare(updatePage.state, "has-updates", "to update") var button = findChild(updatePage, "Button") verify(!button.isActive) diff --git a/discover/qml/ApplicationPage.qml b/discover/qml/ApplicationPage.qml --- a/discover/qml/ApplicationPage.qml +++ b/discover/qml/ApplicationPage.qml @@ -242,6 +242,20 @@ Layout.bottomMargin: Kirigami.Units.largeSpacing } + Repeater { + model: application.objects + delegate: Loader { + property QtObject resource: appInfo.application + source: modelData + } + } + + Item { + height: addonsButton.height + width: 5 + } + + // Details/metadata Rectangle { color: Kirigami.Theme.linkColor Layout.fillWidth: true diff --git a/libdiscover/backends/CMakeLists.txt b/libdiscover/backends/CMakeLists.txt --- a/libdiscover/backends/CMakeLists.txt +++ b/libdiscover/backends/CMakeLists.txt @@ -28,7 +28,7 @@ message(WARNING "BUILD_FlatpakBackend enabled but Flatpak=${FLATPAK_FOUND} or AppStreamQt=${AppStreamQt_FOUND} not found") endif() -option(BUILD_SnapBackend "Build Snap support. Still a proof of concept" "OFF") +option(BUILD_SnapBackend "Build Snap support." "ON") if(BUILD_SnapBackend) find_package(Snapd) set_package_properties(Snapd PROPERTIES diff --git a/libdiscover/backends/SnapBackend/CMakeLists.txt b/libdiscover/backends/SnapBackend/CMakeLists.txt --- a/libdiscover/backends/SnapBackend/CMakeLists.txt +++ b/libdiscover/backends/SnapBackend/CMakeLists.txt @@ -1,6 +1,6 @@ add_subdirectory(libsnapclient) -add_library(snap-backend MODULE SnapResource.cpp SnapBackend.cpp SnapReviewsBackend.cpp SnapTransaction.cpp) +add_library(snap-backend MODULE SnapResource.cpp SnapBackend.cpp SnapReviewsBackend.cpp SnapTransaction.cpp snapui.qrc) target_link_libraries(snap-backend Qt5::Core KF5::CoreAddons KF5::ConfigCore Discover::Common Snapd::Core) install(TARGETS snap-backend DESTINATION ${PLUGIN_INSTALL_DIR}/discover) diff --git a/libdiscover/backends/SnapBackend/SnapResource.h b/libdiscover/backends/SnapBackend/SnapResource.h --- a/libdiscover/backends/SnapBackend/SnapResource.h +++ b/libdiscover/backends/SnapBackend/SnapResource.h @@ -27,10 +27,12 @@ #include class SnapBackend; +class QAbstractItemModel; class SnapResource : public AbstractResource { Q_OBJECT +Q_PROPERTY(QStringList objects MEMBER m_objects CONSTANT) public: explicit SnapResource(QSharedPointer snap, AbstractResource::State state, SnapBackend* parent); ~SnapResource() override = default; @@ -62,12 +64,15 @@ QDate releaseDate() const override; + Q_SCRIPTABLE QAbstractItemModel* plugs(QObject* parents); + public: void gotIcon(); AbstractResource::State m_state; QSharedPointer m_snap; mutable QVariant m_icon; + const QStringList m_objects; }; #endif // SNAPRESOURCE_H diff --git a/libdiscover/backends/SnapBackend/SnapResource.cpp b/libdiscover/backends/SnapBackend/SnapResource.cpp --- a/libdiscover/backends/SnapBackend/SnapResource.cpp +++ b/libdiscover/backends/SnapBackend/SnapResource.cpp @@ -24,11 +24,40 @@ #include #include #include +#include +#include +#include +#include -SnapResource::SnapResource(QSharedPointer snap, AbstractResource::State state, SnapBackend* parent) - : AbstractResource(parent) +QDebug operator<<(QDebug debug, const QSnapdPlug& plug) +{ + QDebugStateSaver saver(debug); + debug.nospace() << "QSnapdPlug("; + debug.nospace() << "name:" << plug.name() << ','; + debug.nospace() << "snap:" << plug.snap() << ','; + debug.nospace() << "interface:" << plug.interface() << ','; + debug.nospace() << "connectionCount:" << plug.connectionCount(); + debug.nospace() << ')'; + return debug; +} + +QDebug operator<<(QDebug debug, const QSnapdSlot& slot) +{ + QDebugStateSaver saver(debug); + debug.nospace() << "QSnapdSlot("; + debug.nospace() << "name:" << slot.name() << ','; + debug.nospace() << "snap:" << slot.snap() << ','; + debug.nospace() << "interface:" << slot.interface() << ','; + debug.nospace() << "connectionCount:" << slot.connectionCount(); + debug.nospace() << ')'; + return debug; +} + +SnapResource::SnapResource(QSharedPointer snap, AbstractResource::State state, SnapBackend* backend) + : AbstractResource(backend) , m_state(state) , m_snap(snap) + , m_objects({ QStringLiteral("qrc:/snapui/PermissionsButton.qml") }) { setObjectName(snap->name()); } @@ -192,3 +221,48 @@ { return {}; } + +QAbstractItemModel* SnapResource::plugs(QObject* p) +{ + QStandardItemModel* model = new QStandardItemModel(p); + if (!isInstalled()) + return model; + + model->setItemRoleNames(model->roleNames().unite( + { {Qt::CheckStateRole, "checked"} } + )); + connect(model, &QStandardItemModel::itemChanged, this, [this](QStandardItem* item){ + auto backend = qobject_cast(parent()); + const QString name = item->data().toString(); + + //TODO: look up for which package offers the slot instead of core? + if (item->checkState() == Qt::Checked) { + auto req = backend->client()->connectInterface(m_snap->name(), name, QStringLiteral("core"), name); + req->runAsync(); + } else { + auto req = backend->client()->disconnectInterface(m_snap->name(), name, QStringLiteral("core"), name); + req->runAsync(); + } + }); + + auto backend = qobject_cast(parent()); + auto req = backend->client()->getInterfaces(); + req->runSync(); + + for (int i = 0; iplugCount(); ++i) { + const QScopedPointer plug(req->plug(i)); + if (plug->snap() == m_snap->name()) { + auto item = new QStandardItem; + if (plug->label().isEmpty()) + item->setText(plug->name()); + else + item->setText(i18n("%1 - %2", plug->name(), plug->label())); + + item->setCheckable(true); + item->setCheckState(plug->connectionCount()>0 ? Qt::Checked : Qt::Unchecked); + item->setData(plug->name()); + model->appendRow(item); + } + } + return model; +}