diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,12 @@ OPTIONAL_COMPONENTS DocTools ) find_package(Qca-qt5 2.1.0 REQUIRED) +find_package(Phonon4Qt5 4.9.0 NO_MODULE) +set_package_properties(Phonon4Qt5 PROPERTIES + DESCRIPTION "Qt-based audio library" + TYPE OPTIONAL + PURPOSE "Required for Find My Device plugin" +) include_directories(${CMAKE_SOURCE_DIR}) diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -10,6 +10,9 @@ add_subdirectory(notifications) add_subdirectory(battery) add_subdirectory(findmyphone) +if(Phonon4Qt5_FOUND) + add_subdirectory(findthisdevice) +endif() add_subdirectory(remotekeyboard) add_subdirectory(mousepad) if(NOT WIN32) diff --git a/plugins/findthisdevice/CMakeLists.txt b/plugins/findthisdevice/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/plugins/findthisdevice/CMakeLists.txt @@ -0,0 +1,33 @@ +include_directories(${PHONON_INCLUDE_DIR}) + +set(kdeconnect_findthisdevice_SRCS + findthisdeviceplugin.cpp +) + +kdeconnect_add_plugin(kdeconnect_findthisdevice + JSON kdeconnect_findthisdevice.json + SOURCES ${kdeconnect_findthisdevice_SRCS}) + +target_link_libraries(kdeconnect_findthisdevice + kdeconnectcore + ${PHONON_LIBRARIES} + Qt5::Core + Qt5::DBus +) + + +set(kdeconnect_findthisdevice_config_SRCS findthisdevice_config.cpp) +ki18n_wrap_ui(kdeconnect_findthisdevice_config_SRCS findthisdevice_config.ui) + +add_library(kdeconnect_findthisdevice_config MODULE ${kdeconnect_findthisdevice_config_SRCS}) +target_link_libraries(kdeconnect_findthisdevice_config + kdeconnectpluginkcm + ${PHONON_LIBRARIES} + KF5::I18n + KF5::CoreAddons + KF5::ConfigWidgets + KF5::KIOWidgets # KUrlRequester +) + +install(TARGETS kdeconnect_findthisdevice_config DESTINATION ${KDE_INSTALL_PLUGINDIR}) +install(FILES kdeconnect_findthisdevice_config.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}) diff --git a/plugins/findthisdevice/findthisdevice_config.h b/plugins/findthisdevice/findthisdevice_config.h new file mode 100644 --- /dev/null +++ b/plugins/findthisdevice/findthisdevice_config.h @@ -0,0 +1,50 @@ +/** + * Copyright 2018 Friedrich W. H. Kossebau + * + * 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 . + */ + +#ifndef FINDTHISDEVICE_CONFIG_H +#define FINDTHISDEVICE_CONFIG_H + +#include + +namespace Ui { +class FindThisDeviceConfigUi; +} + +class FindThisDeviceConfig + : public KdeConnectPluginKcm +{ + Q_OBJECT +public: + FindThisDeviceConfig(QWidget* parent, const QVariantList&); + ~FindThisDeviceConfig() override; + +public Q_SLOTS: + void save() override; + void load() override; + void defaults() override; + +private Q_SLOTS: + void playSound(); + +private: + Ui::FindThisDeviceConfigUi* m_ui; +}; + +#endif diff --git a/plugins/findthisdevice/findthisdevice_config.cpp b/plugins/findthisdevice/findthisdevice_config.cpp new file mode 100644 --- /dev/null +++ b/plugins/findthisdevice/findthisdevice_config.cpp @@ -0,0 +1,123 @@ +/** + * Copyright 2018 Friedrich W. H. Kossebau + * + * 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 . + */ + +#include "findthisdevice_config.h" + +#include "ui_findthisdevice_config.h" +// Phonon +#include +// KF +#include +#include +// Qt +#include + + +K_PLUGIN_FACTORY(FindThisDeviceConfigFactory, registerPlugin();) + + +namespace { +namespace Strings { +inline QString defaultSound() { return QStringLiteral("Oxygen-Im-Phone-Ring.ogg"); } +} +} + +FindThisDeviceConfig::FindThisDeviceConfig(QWidget* parent, const QVariantList& args) + : KdeConnectPluginKcm(parent, args, QStringLiteral("kdeconnect_findthisdevice_config")) + , m_ui(new Ui::FindThisDeviceConfigUi()) +{ + m_ui->setupUi(this); + + const QStringList soundDirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, + QStringLiteral("sounds"), + QStandardPaths::LocateDirectory); + if (!soundDirs.isEmpty()) { + m_ui->soundFileRequester->setStartDir(QUrl::fromLocalFile(soundDirs.last())); + } + + connect(m_ui->playSoundButton, &QToolButton::clicked, + this, &FindThisDeviceConfig::playSound); + connect(m_ui->soundFileRequester, &KUrlRequester::textChanged, + this, QOverload<>::of(&FindThisDeviceConfig::changed)); +} + +FindThisDeviceConfig::~FindThisDeviceConfig() +{ + delete m_ui; +} + + +void FindThisDeviceConfig::defaults() +{ + KCModule::defaults(); + + m_ui->soundFileRequester->setText(Strings::defaultSound()); + + Q_EMIT changed(true); +} + +void FindThisDeviceConfig::load() +{ + KCModule::load(); + + const QString ringTone = config()->get(QStringLiteral("ringtone"), Strings::defaultSound()); + m_ui->soundFileRequester->setText(ringTone); + + Q_EMIT changed(false); +} + +void FindThisDeviceConfig::save() +{ + config()->set(QStringLiteral("ringtone"), m_ui->soundFileRequester->text()); + + KCModule::save(); + + Q_EMIT changed(false); +} + +void FindThisDeviceConfig::playSound() +{ + const QString soundFilename = m_ui->soundFileRequester->text(); + + QUrl soundURL; + const auto dataLocations = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation); + for (const QString &dataLocation : dataLocations) { + soundURL = QUrl::fromUserInput(soundFilename, + dataLocation + QStringLiteral("/sounds"), + QUrl::AssumeLocalFile); + if (soundURL.isLocalFile()) { + if (QFile::exists(soundURL.toLocalFile())) { + break; + } + } else { + if (soundURL.isValid()) { + break; + } + } + soundURL.clear(); + } + + Phonon::MediaObject *media = Phonon::createPlayer(Phonon::NotificationCategory, soundURL); + media->play(); + connect(media, SIGNAL(finished()), media, SLOT(deleteLater())); +} + + +#include "findthisdevice_config.moc" diff --git a/plugins/findthisdevice/findthisdevice_config.ui b/plugins/findthisdevice/findthisdevice_config.ui new file mode 100644 --- /dev/null +++ b/plugins/findthisdevice/findthisdevice_config.ui @@ -0,0 +1,72 @@ + + + FindThisDeviceConfigUi + + + + 0 + 0 + 569 + 140 + + + + + + + Discovery Utilities + + + + + + + + Sound to play: + + + + + + + + + + + + + + Select the sound to play + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + KUrlRequester + QWidget +
kurlrequester.h
+
+
+ + +
diff --git a/plugins/findthisdevice/findthisdeviceplugin.h b/plugins/findthisdevice/findthisdeviceplugin.h new file mode 100644 --- /dev/null +++ b/plugins/findthisdevice/findthisdeviceplugin.h @@ -0,0 +1,47 @@ +/** + * Copyright 2018 Friedrich W. H. Kossebau + * + * 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 . + */ + +#ifndef FINDTHISDEVICEPLUGIN_H +#define FINDTHISDEVICEPLUGIN_H + +#include +// Qt +#include + +#define PACKET_TYPE_FINDMYPHONE_REQUEST QStringLiteral("kdeconnect.findmyphone.request") + +Q_DECLARE_LOGGING_CATEGORY(KDECONNECT_PLUGIN_FINDTHISDEVICE) + +class FindThisDevicePlugin + : public KdeConnectPlugin +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.kde.kdeconnect.device.findthisdevice") + +public: + explicit FindThisDevicePlugin(QObject* parent, const QVariantList& args); + ~FindThisDevicePlugin() override; + + QString dbusPath() const override; + void connected() override; + bool receivePacket(const NetworkPacket& np) override; +}; + +#endif diff --git a/plugins/findthisdevice/findthisdeviceplugin.cpp b/plugins/findthisdevice/findthisdeviceplugin.cpp new file mode 100644 --- /dev/null +++ b/plugins/findthisdevice/findthisdeviceplugin.cpp @@ -0,0 +1,100 @@ +/** + * Copyright 2018 Friedrich W. H. Kossebau + * + * 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 . + */ + +#include "findthisdeviceplugin.h" + +// Phonon +#include +// KF +#include +// Qt +#include +#include +#include +#include + + +K_PLUGIN_FACTORY_WITH_JSON(KdeConnectPluginFactory, "kdeconnect_findthisdevice.json", + registerPlugin();) + +Q_LOGGING_CATEGORY(KDECONNECT_PLUGIN_FINDTHISDEVICE, "kdeconnect.plugin.findthisdevice") + +namespace { +namespace Strings { +inline QString defaultSound() { return QStringLiteral("Oxygen-Im-Phone-Ring.ogg"); } +} +} + +FindThisDevicePlugin::FindThisDevicePlugin(QObject* parent, const QVariantList& args) + : KdeConnectPlugin(parent, args) +{ +} + +FindThisDevicePlugin::~FindThisDevicePlugin() = default; + +void FindThisDevicePlugin::connected() +{ +} + +bool FindThisDevicePlugin::receivePacket(const NetworkPacket& np) +{ + Q_UNUSED(np); + + const QString soundFilename = config()->get(QStringLiteral("ringtone"), Strings::defaultSound()); + + QUrl soundURL; + const auto dataLocations = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation); + for (const QString &dataLocation : dataLocations) { + soundURL = QUrl::fromUserInput(soundFilename, + dataLocation + QStringLiteral("/sounds"), + QUrl::AssumeLocalFile); + if (soundURL.isLocalFile()) { + if (QFile::exists(soundURL.toLocalFile())) { + break; + } + } else { + if (soundURL.isValid()) { + break; + } + } + soundURL.clear(); + } + if (soundURL.isEmpty()) { + qCWarning(KDECONNECT_PLUGIN_FINDTHISDEVICE) << "Not playing sounds, could not find ring tone" << soundFilename; + return true; + } + + Phonon::MediaObject *media = Phonon::createPlayer(Phonon::NotificationCategory, soundURL); // or CommunicationCategory? + media->play(); + connect(media, &Phonon::MediaObject::finished, media, &QObject::deleteLater); + + // TODO: by-pass volume settings in case it is muted + // TODO: ensure to use built-in loudspeakers + + return true; +} + +QString FindThisDevicePlugin::dbusPath() const +{ + return "/modules/kdeconnect/devices/" + device()->id() + "/findthisdevice"; +} + +#include "findthisdeviceplugin.moc" + diff --git a/plugins/findthisdevice/kdeconnect_findthisdevice.json b/plugins/findthisdevice/kdeconnect_findthisdevice.json new file mode 100644 --- /dev/null +++ b/plugins/findthisdevice/kdeconnect_findthisdevice.json @@ -0,0 +1,24 @@ +{ + "KPlugin": { + "Authors": [ + { + "Email": "kossebau@kde.org", + "Name": "Friedrich W. H. Kossebau" + } + ], + "Description": "Find this device by making it play an alarm sound", + "EnabledByDefault": true, + "Icon": "edit-find", + "Id": "kdeconnect_findthisdevice", + "License": "GPL", + "Name": "Find this device", + "ServiceTypes": [ + "KdeConnect/Plugin" + ], + "Version": "0.1", + "Website": "https://kde.org" + }, + "X-KdeConnect-SupportedPacketType": [ + "kdeconnect.findmyphone.request" + ] +} diff --git a/plugins/findthisdevice/kdeconnect_findthisdevice_config.desktop b/plugins/findthisdevice/kdeconnect_findthisdevice_config.desktop new file mode 100644 --- /dev/null +++ b/plugins/findthisdevice/kdeconnect_findthisdevice_config.desktop @@ -0,0 +1,10 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=KCModule + +X-KDE-Library=kdeconnect_findthisdevice_config +X-KDE-ParentComponents=kdeconnect_findthisdevice + +Name=Find This Device plugin settings + +Categories=Qt;KDE;X-KDE-settings-kdeconnect;