Compare commits

...

27 commits

Author SHA1 Message Date
Carl Schwan
e62e31ec09
Modernize code 2024-11-03 22:27:45 +01:00
Carl Schwan
976c400489
Listen to providersChanged in the KCM ui 2024-11-03 22:26:10 +01:00
Carl Schwan
821534271a
Remove all the non relevant change to the UI file 2024-11-03 22:26:10 +01:00
Carl Schwan
b2d0d5fa48
Provide a QML UI to the new functionality 2024-11-03 22:26:10 +01:00
Carl Schwan
5b10d9632c
Simplify backend by only storing the list of disabled link providers
Previously the list of enabled and disabled providers was too easy to
get out of sync. Only having one list simplify the code and avoids issue
with for example the default state which should contains no disabled
backends.
2024-11-03 22:26:09 +01:00
Rob Emery
e2e36e698c
Refactoring 2024-11-03 22:26:09 +01:00
Rob Emery
e82d2e5e4a
Not sure why the display has changed so much, but switching things to minimum
rather than expanding seems to make it look more like it used to
2024-11-03 22:26:09 +01:00
Rob Emery
5895daf612
Adding dedicated button for backend saving 2024-11-03 22:26:09 +01:00
Rob Emery
27f5882dc1
By ref 2024-11-03 22:26:09 +01:00
Rob Emery
b5bf26c919
Refactoring 2024-11-03 22:26:09 +01:00
Rob Emery
fd07c7bea6
Injecting disabled status from the very start 2024-11-03 22:26:08 +01:00
Rob Emery
9800664360
These all need to be near-idempotent 2024-11-03 22:26:08 +01:00
Rob Emery
732bf0636f
Fixing rebase mangle 2024-11-03 22:26:08 +01:00
Rob Emery
97841c8634
Rough enable/disable for lanlink 2024-11-03 22:26:08 +01:00
Rob Emery
bc48c5e9f8
Hacking in a very rough enable/disable (untested) implementation 2024-11-03 22:26:08 +01:00
Rob Emery
21b081ad14
Wiring up config and forcing implementation of enable/disable per
provider
2024-11-03 22:26:07 +01:00
Rob Emery
44e85d73df
Fixed marshalling of the message so we now pass the status back 2024-11-03 22:26:07 +01:00
Rob Emery
355c2e1ff8
Wiring this up to send through, looks like the array is empty for some
reason that I'm not seeing at a glance at current
2024-11-03 22:26:07 +01:00
Rob Emery
e97461937c
Using string serialisation to workaround the weird build failure if
I make the return type anything more complex
2024-11-03 22:26:07 +01:00
Rob Emery
cc2dc39f92
OK this only works with QString and QStringList for some reason;
so I'll hack some substringing stuff together for now
2024-11-03 22:26:07 +01:00
Rob Emery
5b5fac2d5d
So this doesn't seem to work, if the return type is anything other than
QString or QStringList then it blows up with:
/home/rob/kde/src/kdeconnect-kde/kcm/kcm.cpp: In constructor ‘KdeConnectKcm::KdeConnectKcm(QObject*, const KPluginMetaData&, const QVariantList&)’:
/home/rob/kde/src/kdeconnect-kde/kcm/kcm.cpp:82:17: error: ‘class DaemonDbusInterface’ has no member named ‘linkProviders’
   82 |         daemon->linkProviders(),

even though the signatures are correct etc. No idea, I'll have
to fix this ultimately but I'll workaround it for now
2024-11-03 22:26:07 +01:00
Rob Emery
0bb9c8e294
OK, so this builds; but doesn't return the right type now. Untested if
the UI does what we want
2024-11-03 22:26:06 +01:00
Rob Emery
837c2af9bf
This now works at least 2024-11-03 22:26:06 +01:00
Rob Emery
e1ce928d01
This at least compiles 2024-11-03 22:26:06 +01:00
Rob Emery
0856afe216
New tact, lets create a new endpoint entirely based on "devices" 2024-11-03 22:26:06 +01:00
Rob Emery
811542cf84
This thows an error in kdeconnectd
qt.dbus.integration: QDBusConnection: couldn't handle call to getLinkProviders, no slot matched

but we are getting nearer
2024-11-03 22:26:06 +01:00
Rob Emery
01897942a0
Trying to get end-to-end of the link providers out so we can pass back
lists
2024-11-03 22:26:05 +01:00
15 changed files with 315 additions and 20 deletions

View file

@ -29,6 +29,44 @@ FormCard.FormCardPage {
}
}
FormCard.FormHeader {
title: i18nc("@title:group", "Backends")
}
FormCard.FormCard {
DBusProperty {
id: linkProvidersProperty
object: DaemonDbusInterface
read: "linkProviders"
defaultValue: []
}
Repeater {
model: linkProvidersProperty.value
FormCard.FormCheckDelegate {
required property string modelData
readonly property string linkProviderId: modelData.split('|')[0]
readonly property string displayName: switch (linkProviderId) {
case 'BluetoothLinkProvider':
return i18nc("@info KDE Connect provider name", "Bluetooth")
case 'LoopbackLinkProvider':
return i18nc("@info KDE Connect provider name", "Loopback")
case 'LanLinkProvider':
return i18nc("@info KDE Connect provider name", "WiFi Network")
}
checked: modelData.split('|')[1] === 'enabled'
text: displayName
onCheckedChanged: {
DaemonDbusInterface.setLinkProviderState(linkProviderId, checked);
}
}
}
}
FormCard.FormCard {
Layout.topMargin: Kirigami.Units.gridUnit

View file

@ -13,11 +13,12 @@
#include <QBluetoothServiceInfo>
BluetoothLinkProvider::BluetoothLinkProvider()
BluetoothLinkProvider::BluetoothLinkProvider(bool isDisabled)
: mServiceUuid(QBluetoothUuid(QStringLiteral("185f3df4-3268-4e3f-9fca-d4d5059915bd")))
, mServiceDiscoveryAgent(new QBluetoothServiceDiscoveryAgent(this))
, connectTimer(new QTimer(this))
{
this->mDisabled = isDisabled;
connectTimer->setInterval(30000);
connectTimer->setSingleShot(false);
@ -32,8 +33,10 @@ BluetoothLinkProvider::BluetoothLinkProvider()
void BluetoothLinkProvider::onStart()
{
qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::onStart executed";
if (!mDisabled) {
tryToInitialise();
}
}
void BluetoothLinkProvider::tryToInitialise()
{
@ -57,6 +60,7 @@ void BluetoothLinkProvider::tryToInitialise()
void BluetoothLinkProvider::onStop()
{
if (!mDisabled) {
qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::onStop executed";
if (!mBluetoothServer) {
return;
@ -68,12 +72,34 @@ void BluetoothLinkProvider::onStop()
mBluetoothServer->close();
mBluetoothServer->deleteLater();
}
}
void BluetoothLinkProvider::enable()
{
if (mDisabled) {
mDisabled = false;
tryToInitialise();
}
}
void BluetoothLinkProvider::disable()
{
if (!mDisabled) {
mDisabled = true;
onStop();
mBluetoothServer = nullptr;
mServiceDiscoveryAgent = nullptr;
}
}
void BluetoothLinkProvider::onNetworkChange()
{
qCDebug(KDECONNECT_CORE) << "BluetoothLinkProvider::onNetworkChange executed";
if (!mDisabled) {
tryToInitialise();
}
}
void BluetoothLinkProvider::connectError()
{

View file

@ -29,7 +29,8 @@ class KDECONNECTCORE_EXPORT BluetoothLinkProvider : public LinkProvider
Q_OBJECT
public:
BluetoothLinkProvider();
BluetoothLinkProvider(bool disabled = false);
virtual ~BluetoothLinkProvider();
QString name() override
@ -42,6 +43,10 @@ public:
return 10;
}
void enable() override;
void disable() override;
public Q_SLOTS:
virtual void onNetworkChange() override;
virtual void onStart() override;
@ -69,6 +74,7 @@ private:
QBluetoothServiceInfo mKdeconnectService;
QBluetoothServiceDiscoveryAgent *mServiceDiscoveryAgent;
QTimer *connectTimer;
bool mDisabled;
QMap<QString, DeviceLink *> mLinks;

View file

@ -42,12 +42,13 @@ static const int MAX_REMEMBERED_IDENTITY_PACKETS = 42;
static const long MILLIS_DELAY_BETWEEN_CONNECTIONS_TO_SAME_DEVICE = 500;
LanLinkProvider::LanLinkProvider(bool testMode)
LanLinkProvider::LanLinkProvider(bool testMode, bool isDisabled)
: m_server(new Server(this))
, m_udpSocket(this)
, m_tcpPort(0)
, m_testMode(testMode)
, m_combineNetworkChangeTimer(this)
, m_disabled(isDisabled)
#ifdef KDECONNECT_MDNS
, m_mdnsDiscovery(this)
#endif
@ -84,8 +85,27 @@ LanLinkProvider::~LanLinkProvider()
{
}
void LanLinkProvider::enable()
{
if (m_disabled == true) {
m_disabled = false;
onStart();
}
}
void LanLinkProvider::disable()
{
if (m_disabled == false) {
onStop();
m_disabled = true;
}
}
void LanLinkProvider::onStart()
{
if (m_disabled) {
return;
}
const QHostAddress bindAddress = m_testMode ? QHostAddress::LocalHost : QHostAddress::Any;
bool success = m_udpSocket.bind(bindAddress, UDP_PORT, QUdpSocket::ShareAddress);
@ -118,6 +138,9 @@ void LanLinkProvider::onStart()
void LanLinkProvider::onStop()
{
if (m_disabled) {
return;
}
#ifdef KDECONNECT_MDNS
m_mdnsDiscovery.onStop();
#endif
@ -128,6 +151,9 @@ void LanLinkProvider::onStop()
void LanLinkProvider::onNetworkChange()
{
if (m_disabled) {
return;
}
if (m_combineNetworkChangeTimer.isActive()) {
qCDebug(KDECONNECT_CORE) << "Device discovery triggered too fast, ignoring";
return;
@ -138,6 +164,9 @@ void LanLinkProvider::onNetworkChange()
// I'm in a new network, let's be polite and introduce myself
void LanLinkProvider::combinedOnNetworkChange()
{
if (m_disabled) {
return;
}
if (!m_server->isListening()) {
qWarning() << "TCP server not listening, not broadcasting";
return;

View file

@ -30,7 +30,7 @@ public:
/**
* @param testMode Some special overrides needed while testing
*/
LanLinkProvider(bool testMode = false);
LanLinkProvider(bool testMode = false, bool disabled = false);
~LanLinkProvider() override;
QString name() override
@ -43,6 +43,9 @@ public:
return 20;
}
void enable() override;
void disable() override;
void sendUdpIdentityPacket(const QList<QHostAddress> &addresses);
static void configureSslSocket(QSslSocket *socket, const QString &deviceId, bool isDeviceTrusted);
@ -92,6 +95,8 @@ private:
const bool m_testMode;
QTimer m_combineNetworkChangeTimer;
bool m_disabled;
#ifdef KDECONNECT_MDNS
MdnsDiscovery m_mdnsDiscovery;
#endif

View file

@ -24,6 +24,9 @@ public:
virtual QString name() = 0;
virtual int priority() = 0;
virtual void enable() = 0;
virtual void disable() = 0;
public Q_SLOTS:
virtual void onStart() = 0;
virtual void onStop() = 0;

View file

@ -27,6 +27,14 @@ public:
return 0;
}
void enable() override
{
}
void disable() override
{
}
void onStart() override;
void onStop() override;
void onNetworkChange() override;

View file

@ -72,18 +72,22 @@ void Daemon::init()
qCDebug(KDECONNECT_CORE) << "DBus registration complete";
auto configInstance = KdeConnectConfig::instance();
const auto disabledLinkProviders = configInstance.disabledLinkProviders();
// Load backends
if (d->m_testMode)
if (d->m_testMode) {
d->m_linkProviders.insert(new LoopbackLinkProvider());
else {
d->m_linkProviders.insert(new LanLinkProvider());
} else {
d->m_linkProviders.insert(new LanLinkProvider(false, disabledLinkProviders.contains(QStringLiteral("LanLinkProvider"))));
#ifdef KDECONNECT_BLUETOOTH
d->m_linkProviders.insert(new BluetoothLinkProvider());
d->m_linkProviders.insert(new BluetoothLinkProvider(disabledLinkProviders.contains(QStringLiteral("BluetoothLinkProvider"))));
#endif
#ifdef KDECONNECT_LOOPBACK
d->m_linkProviders.insert(new LoopbackLinkProvider());
#endif
}
Q_EMIT linkProvidersChanged(linkProviders());
qCDebug(KDECONNECT_CORE) << "Backends loaded";
@ -147,6 +151,55 @@ QSet<LinkProvider *> Daemon::getLinkProviders() const
return d->m_linkProviders;
}
QStringList Daemon::linkProviders() const
{
auto configInstance = KdeConnectConfig::instance();
const auto disabledLinkProviders = configInstance.disabledLinkProviders();
QStringList returnValue;
for (LinkProvider *a : std::as_const(d->m_linkProviders)) {
QString line(a->name());
if (disabledLinkProviders.contains(a->name())) {
line += QStringLiteral("|disabled");
} else {
line += QStringLiteral("|enabled");
}
returnValue.append(line);
}
return returnValue;
}
void Daemon::setDisabledLinkProviders(const QStringList &disabledLinkProviders)
{
qCDebug(KDECONNECT_CORE) << "setDisabledLinkProviders called" << disabledLinkProviders;
KdeConnectConfig configInstance = KdeConnectConfig::instance();
configInstance.setDisabledLinkProviders(disabledLinkProviders);
Q_EMIT linkProvidersChanged(linkProviders());
}
void Daemon::setLinkProviderState(const QString &linkProvider, bool state)
{
qCDebug(KDECONNECT_CORE) << "setLinkProviderState called" << linkProvider << state;
KdeConnectConfig configInstance = KdeConnectConfig::instance();
auto disabledLinkProviders = configInstance.disabledLinkProviders();
if (!state && !disabledLinkProviders.contains(linkProvider)) {
disabledLinkProviders.append(linkProvider);
} else if (state && disabledLinkProviders.contains(linkProvider)) {
disabledLinkProviders.removeAll(linkProvider);
} else {
return; // no change
}
configInstance.setDisabledLinkProviders(disabledLinkProviders);
Q_EMIT linkProvidersChanged(linkProviders());
}
QStringList Daemon::devices(bool onlyReachable, bool onlyTrusted) const
{
QStringList ret;

View file

@ -61,11 +61,19 @@ public Q_SLOTS:
// Returns a list of ids. The respective devices can be manipulated using the dbus path: "/modules/kdeconnect/Devices/"+id
Q_SCRIPTABLE QStringList devices(bool onlyReachable = false, bool onlyPaired = false) const;
Q_SCRIPTABLE QMap<QString, QString> deviceNames(bool onlyReachable = false, bool onlyPaired = false) const;
Q_SCRIPTABLE QString deviceIdByName(const QString &name) const;
/// Return the list of link providers with their state e.g. "BluetoothLinkProvider|enabled"
Q_SCRIPTABLE QStringList linkProviders() const;
/// Set the list of disabled link providers.
Q_SCRIPTABLE void setDisabledLinkProviders(const QStringList &disabledLinkProviders);
/// Set the state of a link provider.
Q_SCRIPTABLE void setLinkProviderState(const QString &linkProvider, bool state);
Q_SCRIPTABLE virtual void sendSimpleNotification(const QString &eventId, const QString &title, const QString &text, const QString &iconName) = 0;
Q_SIGNALS:
@ -75,6 +83,7 @@ Q_SIGNALS:
Q_SCRIPTABLE void deviceListChanged(); // Emitted when any of deviceAdded, deviceRemoved or deviceVisibilityChanged is emitted
Q_SCRIPTABLE void announcedNameChanged(const QString &announcedName);
Q_SCRIPTABLE void pairingRequestsChanged();
Q_SCRIPTABLE void linkProvidersChanged(const QStringList &linkProviders);
Q_SCRIPTABLE void customDevicesChanged(const QStringList &customDevices);
private Q_SLOTS:

View file

@ -76,6 +76,17 @@ void KdeConnectConfig::setName(const QString &name)
d->m_config->sync();
}
void KdeConnectConfig::setDisabledLinkProviders(const QStringList disabledProviders)
{
d->m_config->setValue(QStringLiteral("disabled_providers"), disabledProviders);
d->m_config->sync();
}
QStringList KdeConnectConfig::disabledLinkProviders() const
{
return d->m_config->value(QStringLiteral("disabled_providers")).toStringList();
}
DeviceType KdeConnectConfig::deviceType()
{
const QByteArrayList platforms = qgetenv("PLASMA_PLATFORM").split(':');

View file

@ -35,6 +35,8 @@ public:
QString certificatePath();
void setName(const QString &name);
void setDisabledLinkProviders(const QStringList disabledProviders);
QStringList disabledLinkProviders() const;
/*
* Trusted devices

View file

@ -33,7 +33,8 @@ DBusResponseWaiter::DBusResponseWaiter()
m_registered << qRegisterMetaType<QDBusPendingReply<>>("QDBusPendingReply<>")
<< qRegisterMetaType<QDBusPendingReply<QVariant>>("QDBusPendingReply<QVariant>")
<< qRegisterMetaType<QDBusPendingReply<bool>>("QDBusPendingReply<bool>") << qRegisterMetaType<QDBusPendingReply<int>>("QDBusPendingReply<int>")
<< qRegisterMetaType<QDBusPendingReply<QString>>("QDBusPendingReply<QString>");
<< qRegisterMetaType<QDBusPendingReply<QString>>("QDBusPendingReply<QString>")
<< qRegisterMetaType<QDBusPendingReply<QStringList>>("QDBusPendingReply<QStringList>");
}
QVariant DBusResponseWaiter::waitForReply(QVariant variant) const
@ -73,6 +74,8 @@ void DBusAsyncResponse::setPendingCall(QVariant variant)
connect(watcher, &QDBusPendingCallWatcher::finished, watcher, &QObject::deleteLater);
connect(&m_timeout, &QTimer::timeout, watcher, &QObject::deleteLater);
m_timeout.start();
} else {
qWarning() << "error: extractPendingCall didn't work";
}
}

View file

@ -12,11 +12,14 @@
#include <KLocalizedString>
#include <KPluginFactory>
#include <KPluginMetaData>
#include <QMessageBox>
#include <QtWidgets/QListView>
#include <kcmutils_version.h>
#include <QQmlContext>
#include <QQuickItem>
#include <QQuickStyle>
#include <qassert.h>
#include "dbushelpers.h"
#include "dbusinterfaces.h"
@ -92,8 +95,68 @@ KdeConnectKcm::KdeConnectKcm(QObject *parent, const KPluginMetaData &md, const Q
}
},
this);
setWhenAvailable(
daemon->linkProviders(),
[this](bool error, const QStringList &linkProviders) {
kcmUi.linkProviders_list->clear();
for (int i = 0; i < linkProviders.size(); ++i) {
const QStringList linkProvider = linkProviders.at(i).split(QStringLiteral("|"));
const QString providerId = linkProvider.at(0);
QString displayName;
if (providerId == QLatin1StringView("BluetoothLinkProvider")) {
displayName = i18nc("@info KDE Connect provider name", "Bluetooth");
} else if (providerId == QLatin1StringView("LoopbackLinkProvider")) {
displayName = i18nc("@info KDE Connect provider name", "Loopback");
} else if (providerId == QLatin1StringView("LanLinkProvider")) {
displayName = i18nc("@info KDE Connect provider name", "WiFi Network");
} else {
Q_ASSERT_X(false, Q_FUNC_INFO, "Unknow provider given");
displayName = i18nc("@info KDE Connect provider name", "Unknown");
}
QString providerStatus = linkProvider.at(1);
QListWidgetItem *linkProviderItem = new QListWidgetItem(displayName, kcmUi.linkProviders_list);
linkProviderItem->setData(Qt::UserRole, providerId);
if (providerStatus.compare(QStringLiteral("enabled")) == 0) {
linkProviderItem->setCheckState(Qt::Checked);
} else {
linkProviderItem->setCheckState(Qt::Unchecked);
}
kcmUi.linkProviders_list->addItem(linkProviderItem);
}
},
this);
connect(daemon, &DaemonDbusInterface::announcedNameChanged, kcmUi.rename_edit, &QLineEdit::setText);
connect(daemon, &DaemonDbusInterface::announcedNameChanged, kcmUi.rename_label, &QLabel::setText);
connect(daemon, &DaemonDbusInterface::linkProvidersChanged, this, [this](const QStringList &providers) {
if (kcmUi.linkProviders_list->count() == 0) {
return; // not yet setup
}
for (auto i = 0, count = kcmUi.linkProviders_list->count(); i < count; i++) {
const auto item = kcmUi.linkProviders_list->item(i);
const auto id = item->data(Qt::UserRole).toString();
bool found = false;
for (const auto &provider : providers) {
if (provider.startsWith(id)) {
const auto status = provider.split(QStringLiteral("|")).at(1);
if (status.compare(QStringLiteral("enabled")) == 0) {
item->setCheckState(Qt::Checked);
} else {
item->setCheckState(Qt::Unchecked);
}
found = true;
break;
}
}
Q_ASSERT_X(found, Q_FUNC_INFO, "A new backend appeared, this should not happen as the list of backends is static");
}
});
setRenameMode(false);
setButtons(KCModule::Help | KCModule::NoAdditionalButton);
@ -109,6 +172,7 @@ KdeConnectKcm::KdeConnectKcm(QObject *parent, const KPluginMetaData &md, const Q
connect(kcmUi.renameDone_button, &QAbstractButton::clicked, this, &KdeConnectKcm::renameDone);
connect(kcmUi.renameShow_button, &QAbstractButton::clicked, this, &KdeConnectKcm::renameShow);
connect(kcmUi.pluginSelector, &KPluginWidget::changed, this, &KdeConnectKcm::pluginsConfigChanged);
connect(kcmUi.backend_apply_button, &QAbstractButton::clicked, this, &KdeConnectKcm::saveBackends);
if (!args.isEmpty() && !args.first().isNull() && args.first().canConvert<QString>()) {
const QString input = args.first().toString();
@ -162,6 +226,19 @@ void KdeConnectKcm::refresh()
daemon->forceOnNetworkChange();
}
void KdeConnectKcm::saveBackends()
{
QStringList disabledLinkProviders;
for (int i = 0; i < kcmUi.linkProviders_list->count(); ++i) {
QListWidgetItem *item = kcmUi.linkProviders_list->item(i);
if (item->checkState() == Qt::Unchecked) {
disabledLinkProviders << item->data(Qt::UserRole).toString();
}
}
daemon->setDisabledLinkProviders(disabledLinkProviders);
}
void KdeConnectKcm::deviceSelected(const QString &deviceId)
{
if (currentDevice) {

View file

@ -36,6 +36,7 @@ private Q_SLOTS:
void sendPing();
void pairingFailed(const QString &error);
void refresh();
void saveBackends();
void renameShow();
void renameDone();
void setRenameMode(bool b);

View file

@ -128,6 +128,30 @@
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Backends:</string>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="linkProviders_list">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="backend_apply_button">
<property name="text">
<string>Apply</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>