[app] Add system volume control
Summary: Add a remote systemvolume plugin. Test Plan: Change volume via slider -> Volume on target changes Change volume on target -> Slider changes Mute via button -> Mute on target changes Mute on target -> Button changes icon Add/remove sink on host -> Sink is add/removed in list Reviewers: #kde_connect, apol Reviewed By: #kde_connect, apol Subscribers: apol, kdeconnect Tags: #kde_connect Differential Revision: https://phabricator.kde.org/D16667
This commit is contained in:
parent
061d415f83
commit
2f76d2143f
14 changed files with 562 additions and 2 deletions
|
@ -114,6 +114,12 @@ Kirigami.Page
|
||||||
shareIface.shareUrl(fileDialog.fileUrl)
|
shareIface.shareUrl(fileDialog.fileUrl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
PluginItem {
|
||||||
|
label: i18n("Volume control")
|
||||||
|
interfaceFactory: RemoteSystemVolumeDbusInterfaceFactory
|
||||||
|
component: "qrc:/qml/volume.qml"
|
||||||
|
pluginName: "remotesystemvolume"
|
||||||
|
}
|
||||||
|
|
||||||
Item { Layout.fillHeight: true }
|
Item { Layout.fillHeight: true }
|
||||||
}
|
}
|
||||||
|
|
68
app/qml/volume.qml
Normal file
68
app/qml/volume.qml
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Nicolas Fella <nicolas.fella@gmx.de>
|
||||||
|
*
|
||||||
|
* 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 2 of
|
||||||
|
* the License or (at your option) version 3 or any later version
|
||||||
|
* accepted by the membership of KDE e.V. (or its successor approved
|
||||||
|
* by the membership of KDE e.V.), which shall act as a proxy
|
||||||
|
* defined in Section 14 of version 3 of the license.
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.2
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
import QtQuick.Layouts 1.1
|
||||||
|
import org.kde.kirigami 2.0 as Kirigami
|
||||||
|
import org.kde.kdeconnect 1.0
|
||||||
|
|
||||||
|
Kirigami.Page
|
||||||
|
{
|
||||||
|
id: root
|
||||||
|
title: i18n("Volume control")
|
||||||
|
property QtObject pluginInterface
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: sinkList
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: Kirigami.Units.largeSpacing
|
||||||
|
|
||||||
|
model: RemoteSinksModel {
|
||||||
|
deviceId: pluginInterface.deviceId
|
||||||
|
}
|
||||||
|
delegate: ColumnLayout {
|
||||||
|
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: description
|
||||||
|
width: parent.width
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
|
||||||
|
Button {
|
||||||
|
icon.name: muted ? "player-volume-muted" : "player-volume"
|
||||||
|
onClicked: pluginInterface.sendMuted(name, !muted)
|
||||||
|
}
|
||||||
|
|
||||||
|
Slider {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
from: 0
|
||||||
|
value: volume
|
||||||
|
to: maxVolume
|
||||||
|
onMoved: pluginInterface.sendVolume(name, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,5 +9,6 @@
|
||||||
<file>qml/DevicePage.qml</file>
|
<file>qml/DevicePage.qml</file>
|
||||||
<file>qml/FindDevicesPage.qml</file>
|
<file>qml/FindDevicesPage.qml</file>
|
||||||
<file>qml/runcommand.qml</file>
|
<file>qml/runcommand.qml</file>
|
||||||
|
<file>qml/volume.qml</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include "interfaces/devicesmodel.h"
|
#include "interfaces/devicesmodel.h"
|
||||||
#include "interfaces/notificationsmodel.h"
|
#include "interfaces/notificationsmodel.h"
|
||||||
#include <remotecommandsmodel.h>
|
#include <remotecommandsmodel.h>
|
||||||
|
#include <remotesinksmodel.h>
|
||||||
|
|
||||||
QObject* createDeviceDbusInterface(const QVariant& deviceId)
|
QObject* createDeviceDbusInterface(const QVariant& deviceId)
|
||||||
{
|
{
|
||||||
|
@ -95,6 +96,12 @@ QObject* createShareInterface(const QVariant& deviceId)
|
||||||
return new ShareDbusInterface(deviceId.toString());
|
return new ShareDbusInterface(deviceId.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QObject* createRemoteSystemVolumeInterface(const QVariant& deviceId)
|
||||||
|
{
|
||||||
|
return new RemoteSystemVolumeDbusInterface(deviceId.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void KdeConnectDeclarativePlugin::registerTypes(const char* uri)
|
void KdeConnectDeclarativePlugin::registerTypes(const char* uri)
|
||||||
{
|
{
|
||||||
qmlRegisterType<DevicesModel>(uri, 1, 0, "DevicesModel");
|
qmlRegisterType<DevicesModel>(uri, 1, 0, "DevicesModel");
|
||||||
|
@ -102,13 +109,15 @@ void KdeConnectDeclarativePlugin::registerTypes(const char* uri)
|
||||||
qmlRegisterType<RemoteCommandsModel>(uri, 1, 0, "RemoteCommandsModel");
|
qmlRegisterType<RemoteCommandsModel>(uri, 1, 0, "RemoteCommandsModel");
|
||||||
qmlRegisterType<DBusAsyncResponse>(uri, 1, 0, "DBusAsyncResponse");
|
qmlRegisterType<DBusAsyncResponse>(uri, 1, 0, "DBusAsyncResponse");
|
||||||
qmlRegisterType<DevicesSortProxyModel>(uri, 1, 0, "DevicesSortProxyModel");
|
qmlRegisterType<DevicesSortProxyModel>(uri, 1, 0, "DevicesSortProxyModel");
|
||||||
|
qmlRegisterType<RemoteSinksModel>(uri, 1, 0, "RemoteSinksModel");
|
||||||
qmlRegisterUncreatableType<MprisDbusInterface>(uri, 1, 0, "MprisDbusInterface", QStringLiteral("You're not supposed to instantiate interfaces"));
|
qmlRegisterUncreatableType<MprisDbusInterface>(uri, 1, 0, "MprisDbusInterface", QStringLiteral("You're not supposed to instantiate interfaces"));
|
||||||
qmlRegisterUncreatableType<LockDeviceDbusInterface>(uri, 1, 0, "LockDeviceDbusInterface", QStringLiteral("You're not supposed to instantiate interfaces"));
|
qmlRegisterUncreatableType<LockDeviceDbusInterface>(uri, 1, 0, "LockDeviceDbusInterface", QStringLiteral("You're not supposed to instantiate interfaces"));
|
||||||
qmlRegisterUncreatableType<FindMyPhoneDeviceDbusInterface>(uri, 1, 0, "FindMyPhoneDbusInterface", QStringLiteral("You're not supposed to instantiate interfaces"));
|
qmlRegisterUncreatableType<FindMyPhoneDeviceDbusInterface>(uri, 1, 0, "FindMyPhoneDbusInterface", QStringLiteral("You're not supposed to instantiate interfaces"));
|
||||||
qmlRegisterUncreatableType<RemoteKeyboardDbusInterface>(uri, 1, 0, "RemoteKeyboardDbusInterface", QStringLiteral("You're not supposed to instantiate interfaces"));
|
qmlRegisterUncreatableType<RemoteKeyboardDbusInterface>(uri, 1, 0, "RemoteKeyboardDbusInterface", QStringLiteral("You're not supposed to instantiate interfaces"));
|
||||||
qmlRegisterUncreatableType<DeviceDbusInterface>(uri, 1, 0, "DeviceDbusInterface", QStringLiteral("You're not supposed to instantiate interfaces"));
|
qmlRegisterUncreatableType<DeviceDbusInterface>(uri, 1, 0, "DeviceDbusInterface", QStringLiteral("You're not supposed to instantiate interfaces"));
|
||||||
qmlRegisterUncreatableType<DeviceDbusInterface>(uri, 1, 0, "RemoteCommandsDbusInterface", QStringLiteral("You're not supposed to instantiate interfaces"));
|
qmlRegisterUncreatableType<RemoteCommandsDbusInterface>(uri, 1, 0, "RemoteCommandsDbusInterface", QStringLiteral("You're not supposed to instantiate interfaces"));
|
||||||
qmlRegisterUncreatableType<DeviceDbusInterface>(uri, 1, 0, "ShareDbusInterface", QStringLiteral("You're not supposed to instantiate interfaces"));
|
qmlRegisterUncreatableType<RemoteSystemVolumeDbusInterface>(uri, 1, 0, "RemoteSystemVolumeInterface", QStringLiteral("You're not supposed to instantiate interfaces"));
|
||||||
|
qmlRegisterUncreatableType<ShareDbusInterface>(uri, 1, 0, "ShareDbusInterface", QStringLiteral("You're not supposed to instantiate interfaces"));
|
||||||
qmlRegisterSingletonType<DaemonDbusInterface>(uri, 1, 0, "DaemonDbusInterface",
|
qmlRegisterSingletonType<DaemonDbusInterface>(uri, 1, 0, "DaemonDbusInterface",
|
||||||
[](QQmlEngine*, QJSEngine*) -> QObject* {
|
[](QQmlEngine*, QJSEngine*) -> QObject* {
|
||||||
return new DaemonDbusInterface;
|
return new DaemonDbusInterface;
|
||||||
|
@ -158,4 +167,8 @@ void KdeConnectDeclarativePlugin::initializeEngine(QQmlEngine* engine, const cha
|
||||||
|
|
||||||
engine->rootContext()->setContextProperty(QStringLiteral("ShareDbusInterfaceFactory")
|
engine->rootContext()->setContextProperty(QStringLiteral("ShareDbusInterfaceFactory")
|
||||||
, new ObjectFactory(engine, createShareInterface));
|
, new ObjectFactory(engine, createShareInterface));
|
||||||
|
|
||||||
|
engine->rootContext()->setContextProperty(QStringLiteral("RemoteSystemVolumeDbusInterfaceFactory")
|
||||||
|
, new ObjectFactory(engine, createRemoteSystemVolumeInterface));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ set(libkdeconnect_SRC
|
||||||
devicessortproxymodel.cpp
|
devicessortproxymodel.cpp
|
||||||
conversationmessage.cpp
|
conversationmessage.cpp
|
||||||
remotecommandsmodel.cpp
|
remotecommandsmodel.cpp
|
||||||
|
remotesinksmodel.cpp
|
||||||
# modeltest.cpp
|
# modeltest.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -51,6 +52,8 @@ geninterface(${CMAKE_SOURCE_DIR}/plugins/remotekeyboard/remotekeyboardplugin.h r
|
||||||
geninterface(${CMAKE_SOURCE_DIR}/plugins/sms/smsplugin.h smsinterface)
|
geninterface(${CMAKE_SOURCE_DIR}/plugins/sms/smsplugin.h smsinterface)
|
||||||
geninterface(${CMAKE_SOURCE_DIR}/plugins/sms/conversationsdbusinterface.h conversationsinterface)
|
geninterface(${CMAKE_SOURCE_DIR}/plugins/sms/conversationsdbusinterface.h conversationsinterface)
|
||||||
geninterface(${CMAKE_SOURCE_DIR}/plugins/share/shareplugin.h shareinterface)
|
geninterface(${CMAKE_SOURCE_DIR}/plugins/share/shareplugin.h shareinterface)
|
||||||
|
geninterface(${CMAKE_SOURCE_DIR}/plugins/remotesystemvolume/remotesystemvolumeplugin.h remotesystemvolumeinterface)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
add_library(kdeconnectinterfaces SHARED ${libkdeconnect_SRC})
|
add_library(kdeconnectinterfaces SHARED ${libkdeconnect_SRC})
|
||||||
|
|
|
@ -189,3 +189,8 @@ ShareDbusInterface::ShareDbusInterface(const QString& deviceId, QObject* parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
ShareDbusInterface::~ShareDbusInterface() = default;
|
ShareDbusInterface::~ShareDbusInterface() = default;
|
||||||
|
|
||||||
|
RemoteSystemVolumeDbusInterface::RemoteSystemVolumeDbusInterface(const QString& deviceId, QObject* parent):
|
||||||
|
OrgKdeKdeconnectDeviceRemotesystemvolumeInterface(DaemonDbusInterface::activatedService(), "/modules/kdeconnect/devices/" + deviceId + "/remotesystemvolume", QDBusConnection::sessionBus(), parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
#include "interfaces/smsinterface.h"
|
#include "interfaces/smsinterface.h"
|
||||||
#include "interfaces/conversationsinterface.h"
|
#include "interfaces/conversationsinterface.h"
|
||||||
#include "interfaces/shareinterface.h"
|
#include "interfaces/shareinterface.h"
|
||||||
|
#include "interfaces/remotesystemvolumeinterface.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Using these "proxy" classes just in case we need to rename the
|
* Using these "proxy" classes just in case we need to rename the
|
||||||
|
@ -229,6 +230,15 @@ public:
|
||||||
~ShareDbusInterface() override;
|
~ShareDbusInterface() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class KDECONNECTINTERFACES_EXPORT RemoteSystemVolumeDbusInterface
|
||||||
|
: public OrgKdeKdeconnectDeviceRemotesystemvolumeInterface
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit RemoteSystemVolumeDbusInterface(const QString& deviceId, QObject* parent = nullptr);
|
||||||
|
~RemoteSystemVolumeDbusInterface() = default;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T, typename W>
|
template <typename T, typename W>
|
||||||
static void setWhenAvailable(const QDBusPendingReply<T>& pending, W func, QObject* parent)
|
static void setWhenAvailable(const QDBusPendingReply<T>& pending, W func, QObject* parent)
|
||||||
{
|
{
|
||||||
|
|
173
interfaces/remotesinksmodel.cpp
Normal file
173
interfaces/remotesinksmodel.cpp
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2018 Nicolas Fella <nicolas.fella@gmx.de>
|
||||||
|
*
|
||||||
|
* 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 2 of
|
||||||
|
* the License or (at your option) version 3 or any later version
|
||||||
|
* accepted by the membership of KDE e.V. (or its successor approved
|
||||||
|
* by the membership of KDE e.V.), which shall act as a proxy
|
||||||
|
* defined in Section 14 of version 3 of the license.
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "remotesinksmodel.h"
|
||||||
|
#include "interfaces_debug.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QDBusInterface>
|
||||||
|
|
||||||
|
RemoteSinksModel::RemoteSinksModel(QObject* parent)
|
||||||
|
: QAbstractListModel(parent)
|
||||||
|
, m_dbusInterface(nullptr)
|
||||||
|
{
|
||||||
|
|
||||||
|
connect(this, &QAbstractItemModel::rowsInserted,
|
||||||
|
this, &RemoteSinksModel::rowsChanged);
|
||||||
|
connect(this, &QAbstractItemModel::rowsRemoved,
|
||||||
|
this, &RemoteSinksModel::rowsChanged);
|
||||||
|
|
||||||
|
QDBusServiceWatcher* watcher = new QDBusServiceWatcher(DaemonDbusInterface::activatedService(),
|
||||||
|
QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForOwnerChange, this);
|
||||||
|
connect(watcher, &QDBusServiceWatcher::serviceRegistered, this, &RemoteSinksModel::refreshSinkList);
|
||||||
|
connect(watcher, &QDBusServiceWatcher::serviceUnregistered, this, &RemoteSinksModel::refreshSinkList);
|
||||||
|
}
|
||||||
|
|
||||||
|
QHash<int, QByteArray> RemoteSinksModel::roleNames() const
|
||||||
|
{
|
||||||
|
//Role names for QML
|
||||||
|
QHash<int, QByteArray> names = QAbstractItemModel::roleNames();
|
||||||
|
names.insert(NameRole, "name");
|
||||||
|
names.insert(DescriptionRole, "description");
|
||||||
|
names.insert(MaxVolumeRole, "maxVolume");
|
||||||
|
names.insert(VolumeRole, "volume");
|
||||||
|
names.insert(MutedRole, "muted");
|
||||||
|
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoteSinksModel::~RemoteSinksModel()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QString RemoteSinksModel::deviceId() const
|
||||||
|
{
|
||||||
|
return m_deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoteSinksModel::setDeviceId(const QString& deviceId)
|
||||||
|
{
|
||||||
|
m_deviceId = deviceId;
|
||||||
|
|
||||||
|
if (m_dbusInterface) {
|
||||||
|
delete m_dbusInterface;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_dbusInterface = new RemoteSystemVolumeDbusInterface(deviceId, this);
|
||||||
|
|
||||||
|
connect(m_dbusInterface, &OrgKdeKdeconnectDeviceRemotesystemvolumeInterface::sinksChanged,
|
||||||
|
this, &RemoteSinksModel::refreshSinkList);
|
||||||
|
|
||||||
|
connect(m_dbusInterface, &OrgKdeKdeconnectDeviceRemotesystemvolumeInterface::volumeChanged, this, [this](const QString& name, int volume) {
|
||||||
|
for (Sink* s: m_sinkList) {
|
||||||
|
if (s->name == name) {
|
||||||
|
s->volume = volume;
|
||||||
|
Q_EMIT dataChanged(index(0,0), index(m_sinkList.size() - 1, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(m_dbusInterface, &OrgKdeKdeconnectDeviceRemotesystemvolumeInterface::mutedChanged, this, [this](const QString& name, bool muted) {
|
||||||
|
for (Sink* s: m_sinkList) {
|
||||||
|
if (s->name == name) {
|
||||||
|
s->muted = muted;
|
||||||
|
Q_EMIT dataChanged(index(0,0), index(m_sinkList.size() - 1, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
refreshSinkList();
|
||||||
|
|
||||||
|
Q_EMIT deviceIdChanged(deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoteSinksModel::refreshSinkList()
|
||||||
|
{
|
||||||
|
if (!m_dbusInterface) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_dbusInterface->isValid()) {
|
||||||
|
qCWarning(KDECONNECT_INTERFACES) << "dbus interface not valid";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto cmds = QJsonDocument::fromJson(m_dbusInterface->sinks()).array();
|
||||||
|
|
||||||
|
beginResetModel();
|
||||||
|
|
||||||
|
qDeleteAll(m_sinkList);
|
||||||
|
m_sinkList.clear();
|
||||||
|
|
||||||
|
for (auto it = cmds.constBegin(), itEnd = cmds.constEnd(); it!=itEnd; ++it) {
|
||||||
|
const QJsonObject cont = it->toObject();
|
||||||
|
Sink* sink = new Sink();
|
||||||
|
sink->name = cont.value(QStringLiteral("name")).toString();
|
||||||
|
sink->description = cont.value(QStringLiteral("description")).toString();
|
||||||
|
sink->maxVolume = cont.value(QStringLiteral("maxVolume")).toInt();
|
||||||
|
sink->volume = cont.value(QStringLiteral("volume")).toInt();
|
||||||
|
sink->muted = cont.value(QStringLiteral("muted")).toBool();
|
||||||
|
|
||||||
|
m_sinkList.append(sink);
|
||||||
|
}
|
||||||
|
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant RemoteSinksModel::data(const QModelIndex& index, int role) const
|
||||||
|
{
|
||||||
|
if (!index.isValid()
|
||||||
|
|| index.row() < 0
|
||||||
|
|| index.row() >= m_sinkList.count())
|
||||||
|
{
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_dbusInterface || !m_dbusInterface->isValid()) {
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
Sink* sink = m_sinkList[index.row()];
|
||||||
|
|
||||||
|
switch (role) {
|
||||||
|
case NameRole:
|
||||||
|
return sink->name;
|
||||||
|
case DescriptionRole:
|
||||||
|
return sink->description;
|
||||||
|
case MaxVolumeRole:
|
||||||
|
return sink->maxVolume;
|
||||||
|
case VolumeRole:
|
||||||
|
return sink->volume;
|
||||||
|
case MutedRole:
|
||||||
|
return sink->muted;
|
||||||
|
default:
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int RemoteSinksModel::rowCount(const QModelIndex& parent) const
|
||||||
|
{
|
||||||
|
if (parent.isValid()) {
|
||||||
|
//Return size 0 if we are a child because this is not a tree
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_sinkList.count();
|
||||||
|
}
|
75
interfaces/remotesinksmodel.h
Normal file
75
interfaces/remotesinksmodel.h
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2018 Nicolas Fella <nicolas.fella@gmx.de>
|
||||||
|
*
|
||||||
|
* 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 2 of
|
||||||
|
* the License or (at your option) version 3 or any later version
|
||||||
|
* accepted by the membership of KDE e.V. (or its successor approved
|
||||||
|
* by the membership of KDE e.V.), which shall act as a proxy
|
||||||
|
* defined in Section 14 of version 3 of the license.
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef REMOTESINKSMODEL_H
|
||||||
|
#define REMOTESINKSMODEL_H
|
||||||
|
|
||||||
|
#include <QAbstractListModel>
|
||||||
|
|
||||||
|
#include "interfaces/dbusinterfaces.h"
|
||||||
|
|
||||||
|
struct Sink {
|
||||||
|
QString name;
|
||||||
|
QString description;
|
||||||
|
int maxVolume;
|
||||||
|
int volume;
|
||||||
|
bool muted;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KDECONNECTINTERFACES_EXPORT RemoteSinksModel
|
||||||
|
: public QAbstractListModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(QString deviceId READ deviceId WRITE setDeviceId NOTIFY deviceIdChanged)
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum ModelRoles {
|
||||||
|
NameRole,
|
||||||
|
DescriptionRole,
|
||||||
|
MaxVolumeRole,
|
||||||
|
VolumeRole,
|
||||||
|
MutedRole
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit RemoteSinksModel(QObject* parent = nullptr);
|
||||||
|
~RemoteSinksModel() override;
|
||||||
|
|
||||||
|
QString deviceId() const;
|
||||||
|
void setDeviceId(const QString& deviceId);
|
||||||
|
|
||||||
|
QVariant data(const QModelIndex& index, int role) const override;
|
||||||
|
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||||
|
|
||||||
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void refreshSinkList();
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void deviceIdChanged(const QString& value);
|
||||||
|
void rowsChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
RemoteSystemVolumeDbusInterface* m_dbusInterface;
|
||||||
|
QVector<Sink*> m_sinkList;
|
||||||
|
QString m_deviceId;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DEVICESMODEL_H
|
|
@ -37,6 +37,7 @@ if(SAILFISHOS OR EXPERIMENTALAPP_ENABLED)
|
||||||
add_subdirectory(mprisremote)
|
add_subdirectory(mprisremote)
|
||||||
add_subdirectory(remotecontrol)
|
add_subdirectory(remotecontrol)
|
||||||
add_subdirectory(lockdevice)
|
add_subdirectory(lockdevice)
|
||||||
|
add_subdirectory(remotesystemvolume)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(KF5PulseAudioQt_FOUND)
|
if(KF5PulseAudioQt_FOUND)
|
||||||
|
|
11
plugins/remotesystemvolume/CMakeLists.txt
Normal file
11
plugins/remotesystemvolume/CMakeLists.txt
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
set(kdeconnect_remotesystemvolume_SRCS
|
||||||
|
remotesystemvolumeplugin.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
kdeconnect_add_plugin(kdeconnect_remotesystemvolume JSON kdeconnect_remotesystemvolume.json SOURCES ${kdeconnect_remotesystemvolume_SRCS})
|
||||||
|
|
||||||
|
target_link_libraries(kdeconnect_remotesystemvolume
|
||||||
|
kdeconnectcore
|
||||||
|
Qt5::DBus
|
||||||
|
KF5::I18n
|
||||||
|
)
|
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"KPlugin": {
|
||||||
|
"Authors": [
|
||||||
|
{
|
||||||
|
"Email": "nicolas.fella@gmx.de",
|
||||||
|
"Name": "Nicolas Fella"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Description": "Control the volume of the connected device",
|
||||||
|
"EnabledByDefault": true,
|
||||||
|
"Icon": "player-volume",
|
||||||
|
"Id": "kdeconnect_remotesystemvolume",
|
||||||
|
"License": "GPL",
|
||||||
|
"Name": "Remote system volume",
|
||||||
|
"ServiceTypes": [
|
||||||
|
"KdeConnect/Plugin"
|
||||||
|
],
|
||||||
|
"Version": "0.1",
|
||||||
|
"Website": "https://nicolasfella.wordpress.com"
|
||||||
|
},
|
||||||
|
"X-KdeConnect-OutgoingPacketType": [
|
||||||
|
"kdeconnect.systemvolume.request"
|
||||||
|
],
|
||||||
|
"X-KdeConnect-SupportedPacketType": [
|
||||||
|
"kdeconnect.systemvolume"
|
||||||
|
]
|
||||||
|
}
|
105
plugins/remotesystemvolume/remotesystemvolumeplugin.cpp
Normal file
105
plugins/remotesystemvolume/remotesystemvolumeplugin.cpp
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2018 Nicolas Fella <nicolas.fella@gmx.de>
|
||||||
|
*
|
||||||
|
* 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 2 of
|
||||||
|
* the License or (at your option) version 3 or any later version
|
||||||
|
* accepted by the membership of KDE e.V. (or its successor approved
|
||||||
|
* by the membership of KDE e.V.), which shall act as a proxy
|
||||||
|
* defined in Section 14 of version 3 of the license.
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "remotesystemvolumeplugin.h"
|
||||||
|
|
||||||
|
#include <KLocalizedString>
|
||||||
|
#include <KPluginFactory>
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QDBusConnection>
|
||||||
|
#include <QLoggingCategory>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
|
||||||
|
#include <core/device.h>
|
||||||
|
#include <core/daemon.h>
|
||||||
|
|
||||||
|
K_PLUGIN_FACTORY_WITH_JSON( KdeConnectPluginFactory, "kdeconnect_remotesystemvolume.json", registerPlugin< RemoteSystemVolumePlugin >(); )
|
||||||
|
|
||||||
|
Q_LOGGING_CATEGORY(KDECONNECT_PLUGIN_PING, "kdeconnect.plugin.remotesystemvolume")
|
||||||
|
|
||||||
|
RemoteSystemVolumePlugin::RemoteSystemVolumePlugin(QObject* parent, const QVariantList& args)
|
||||||
|
: KdeConnectPlugin(parent, args)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoteSystemVolumePlugin::~RemoteSystemVolumePlugin()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RemoteSystemVolumePlugin::receivePacket(const NetworkPacket& np)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (np.has(QStringLiteral("sinkList"))) {
|
||||||
|
QJsonDocument document(np.get<QJsonArray>(QStringLiteral("sinkList")));
|
||||||
|
m_sinks = document.toJson();
|
||||||
|
Q_EMIT sinksChanged();
|
||||||
|
} else {
|
||||||
|
|
||||||
|
QString name = np.get<QString>(QStringLiteral("name"));
|
||||||
|
|
||||||
|
if (np.has(QStringLiteral("volume"))) {
|
||||||
|
Q_EMIT volumeChanged(name, np.get<int>(QStringLiteral("volume")));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (np.has(QStringLiteral("muted"))) {
|
||||||
|
Q_EMIT mutedChanged(name, np.get<int>(QStringLiteral("muted")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoteSystemVolumePlugin::sendVolume(const QString& name, int volume)
|
||||||
|
{
|
||||||
|
NetworkPacket np(PACKET_TYPE_SYSTEMVOLUME_REQUEST);
|
||||||
|
np.set<QString>(QStringLiteral("name"), name);
|
||||||
|
np.set<int>(QStringLiteral("volume"), volume);
|
||||||
|
sendPacket(np);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoteSystemVolumePlugin::sendMuted(const QString& name, bool muted)
|
||||||
|
{
|
||||||
|
NetworkPacket np(PACKET_TYPE_SYSTEMVOLUME_REQUEST);
|
||||||
|
np.set<QString>(QStringLiteral("name"), name);
|
||||||
|
np.set<bool>(QStringLiteral("muted"), muted);
|
||||||
|
sendPacket(np);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoteSystemVolumePlugin::connected()
|
||||||
|
{
|
||||||
|
NetworkPacket np(PACKET_TYPE_SYSTEMVOLUME_REQUEST);
|
||||||
|
np.set<bool>(QStringLiteral("requestSinks"), true);
|
||||||
|
sendPacket(np);
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray RemoteSystemVolumePlugin::sinks()
|
||||||
|
{
|
||||||
|
return m_sinks;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString RemoteSystemVolumePlugin::dbusPath() const
|
||||||
|
{
|
||||||
|
return "/modules/kdeconnect/devices/" + device()->id() + "/remotesystemvolume";
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "remotesystemvolumeplugin.moc"
|
||||||
|
|
62
plugins/remotesystemvolume/remotesystemvolumeplugin.h
Normal file
62
plugins/remotesystemvolume/remotesystemvolumeplugin.h
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2018 Nicolas Fella <nicolas.fella@gmx.de>
|
||||||
|
*
|
||||||
|
* 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 2 of
|
||||||
|
* the License or (at your option) version 3 or any later version
|
||||||
|
* accepted by the membership of KDE e.V. (or its successor approved
|
||||||
|
* by the membership of KDE e.V.), which shall act as a proxy
|
||||||
|
* defined in Section 14 of version 3 of the license.
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef REMOTESYSTEMVOLUMEPLUGIN_H
|
||||||
|
#define REMOTESYSTEMVOLUMEPLUGIN_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include <core/kdeconnectplugin.h>
|
||||||
|
|
||||||
|
#define PACKET_TYPE_SYSTEMVOLUME QStringLiteral("kdeconnect.systemvolume")
|
||||||
|
#define PACKET_TYPE_SYSTEMVOLUME_REQUEST QStringLiteral("kdeconnect.systemvolume.request")
|
||||||
|
|
||||||
|
class Q_DECL_EXPORT RemoteSystemVolumePlugin
|
||||||
|
: public KdeConnectPlugin
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_CLASSINFO("D-Bus Interface", "org.kde.kdeconnect.device.remotesystemvolume")
|
||||||
|
Q_PROPERTY(QByteArray sinks READ sinks NOTIFY sinksChanged)
|
||||||
|
Q_PROPERTY(QString deviceId READ deviceId CONSTANT)
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit RemoteSystemVolumePlugin(QObject* parent, const QVariantList& args);
|
||||||
|
~RemoteSystemVolumePlugin() override;
|
||||||
|
|
||||||
|
bool receivePacket(const NetworkPacket& np) override;
|
||||||
|
void connected() override;
|
||||||
|
QString dbusPath() const override;
|
||||||
|
|
||||||
|
QString deviceId() const { return device()->id(); }
|
||||||
|
QByteArray sinks();
|
||||||
|
|
||||||
|
Q_SCRIPTABLE void sendVolume(const QString& name, int volume);
|
||||||
|
Q_SCRIPTABLE void sendMuted(const QString& name, bool muted);
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
Q_SCRIPTABLE void sinksChanged();
|
||||||
|
Q_SCRIPTABLE void volumeChanged(const QString& name, int volume);
|
||||||
|
Q_SCRIPTABLE void mutedChanged(const QString& name, bool muted);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QByteArray m_sinks;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // REMOTESYSTEMVOLUMEPLUGIN_H
|
Loading…
Reference in a new issue