Commit 67293df0 authored by Aleix Pol Gonzalez's avatar Aleix Pol Gonzalez 🐧

Snap: Support configuring used snap channels

Adds a dialog that allows to choose the channel in use for a snap.

BUG: 389012
parent 17ef1f54
......@@ -69,7 +69,7 @@ QDebug operator<<(QDebug debug, const QSnapdSlot* slot)
return debug;
}
const QStringList SnapResource::m_objects({ QStringLiteral("qrc:/qml/PermissionsButton.qml") });
const QStringList SnapResource::m_objects({ QStringLiteral("qrc:/qml/PermissionsButton.qml"), QStringLiteral("qrc:/qml/ChannelsButton.qml") });
SnapResource::SnapResource(QSharedPointer<QSnapdSnap> snap, AbstractResource::State state, SnapBackend* backend)
: AbstractResource(backend)
......@@ -79,6 +79,12 @@ SnapResource::SnapResource(QSharedPointer<QSnapdSnap> snap, AbstractResource::St
setObjectName(snap->name());
}
QSnapdClient * SnapResource::client() const
{
auto backend = qobject_cast<SnapBackend*>(parent());
return backend->client();
}
QString SnapResource::availableVersion() const
{
return installedVersion();
......@@ -111,8 +117,7 @@ QVariant SnapResource::icon() const
if (!iconPath.startsWith(QLatin1Char('/')))
return QUrl(iconPath);
auto backend = qobject_cast<SnapBackend*>(parent());
auto req = backend->client()->getIcon(packageName());
auto req = client()->getIcon(packageName());
connect(req, &QSnapdGetIconRequest::complete, this, &SnapResource::gotIcon);
req->runAsync();
return {};
......@@ -226,6 +231,8 @@ void SnapResource::setSnap(const QSharedPointer<QSnapdSnap>& snap)
m_snap = snap;
if (newSize)
Q_EMIT sizeChanged();
Q_EMIT newSnap();
}
QDate SnapResource::releaseDate() const
......@@ -330,3 +337,90 @@ QString SnapResource::appstreamId() const
;
return ids.isEmpty() ? QLatin1String("com.snap.") + m_snap->name() : ids.first();
}
QString SnapResource::channel() const
{
auto req = client()->getSnap(packageName());
req->runSync();
return req->error() ? QString() : req->snap()->trackingChannel();
}
void SnapResource::setChannel(const QString& channelName)
{
Q_ASSERT(isInstalled());
auto request = client()->switchChannel(m_snap->name(), channelName);
const auto currentChannel = channel();
auto dest = new CallOnDestroy([this, currentChannel]() {
const auto newChannel = channel();
if (newChannel != currentChannel) {
Q_EMIT channelChanged(newChannel);
}
});
request->runAsync();
connect(request, &QSnapdRequest::complete, dest, &QObject::deleteLater);
}
void SnapResource::refreshSnap()
{
auto request = client()->find(QSnapdClient::FindFlag::MatchName, m_snap->name());
connect(request, &QSnapdRequest::complete, this, [this, request](){
if (request->error()) {
qWarning() << "error" << request->error() << ": " << request->errorString();
return;
}
Q_ASSERT(request->snapCount() == 1);
setSnap(QSharedPointer<QSnapdSnap>(request->snap(0)));
});
request->runAsync();
}
class Channels : public QObject
{
Q_OBJECT
Q_PROPERTY(QList<QObject *> channels READ channels NOTIFY channelsChanged)
public:
Channels(SnapResource* res, QObject* parent) : QObject(parent), m_res(res) {
if (res->snap()->channelCount() == 0)
res->refreshSnap();
else
refreshChannels();
connect(res, &SnapResource::newSnap, this, &Channels::refreshChannels);
}
void refreshChannels()
{
qDeleteAll(m_channels);
auto s = m_res->snap();
for(int i=0, c=s->channelCount(); i<c; ++i) {
auto channel = s->channel(i);
channel->setParent(this);
m_channels << channel;
}
Q_EMIT channelsChanged();
}
QList<QObject *> channels() const
{
return m_channels;
}
Q_SIGNALS:
void channelsChanged();
private:
QList<QObject*> m_channels;
SnapResource* const m_res;
};
QObject * SnapResource::channels(QObject* parent)
{
return new Channels(this, parent);
}
#include "SnapResource.moc"
......@@ -28,11 +28,14 @@
class SnapBackend;
class QAbstractItemModel;
class QSnapdClient;
class QSnapdChannel;
class SnapResource : public AbstractResource
{
Q_OBJECT
Q_PROPERTY(QStringList objects MEMBER m_objects CONSTANT)
Q_PROPERTY(QString channel READ channel WRITE setChannel NOTIFY channelChanged)
public:
explicit SnapResource(QSharedPointer<QSnapdSnap> snap, AbstractResource::State state, SnapBackend* parent);
~SnapResource() override = default;
......@@ -63,10 +66,22 @@ public:
QDate releaseDate() const override;
Q_SCRIPTABLE QAbstractItemModel* plugs(QObject* parents);
Q_SCRIPTABLE QAbstractItemModel* plugs(QObject* parentC);
Q_SCRIPTABLE QObject* channels(QObject* parent);
QString appstreamId() const override;
QString channel() const;
void setChannel(const QString &channel);
QSharedPointer<QSnapdSnap> snap() const { return m_snap; }
Q_SIGNALS:
void channelChanged(const QString &channel);
void newSnap();
public:
QSnapdClient* client() const;
void refreshSnap();
void gotIcon();
AbstractResource::State m_state;
......
/*
* Copyright (C) 2018 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library/Lesser General Public License
* version 2, or (at your option) any later version, as published by the
* Free Software Foundation
*
* 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 Library/Lesser General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import QtQuick 2.1
import QtQuick.Layouts 1.1
import QtQuick.Controls 2.1
import org.kde.kirigami 2.1 as Kirigami
Button
{
id: root
text: i18n("Channels...")
onClicked: overlay.open()
visible: resource.isInstalled /*&& view.count > 0*/
DiscoverPopup {
id: overlay
ListView {
id: view
anchors.fill: parent
header: Kirigami.ItemViewHeader {
title: i18n ("%1 channels", resource.name)
}
model: resource.channels(root).channels
delegate: RowLayout {
width: parent.width
readonly property bool current: resource.channel === modelData.name
Label {
Layout.fillWidth: true
text: i18n("%1 - %2", modelData.name, modelData.track)
}
Button {
text: i18n("Switch")
enabled: !parent.current
onClicked: resource.channel = modelData.name
}
}
}
}
}
......@@ -2,5 +2,6 @@
<RCC version="1.0">
<qresource>
<file>qml/PermissionsButton.qml</file>
<file>qml/ChannelsButton.qml</file>
</qresource>
</RCC>
......@@ -83,4 +83,14 @@ public:
QString m_name;
};
class CallOnDestroy : public QObject
{
public:
CallOnDestroy(std::function<void()> f) : m_func(std::move(f)) {}
~CallOnDestroy() { m_func(); }
private:
std::function<void()> m_func;
};
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment