From 6947fbc12a7fbc42bed6a016333ba0d4cda70ad5 Mon Sep 17 00:00:00 2001 From: Tobias Fella Date: Sat, 10 Feb 2024 00:14:56 +0100 Subject: [PATCH] Add purpose plugin Implements #182 --- .reuse/dep5 | 4 +++ CMakeLists.txt | 4 +++ src/CMakeLists.txt | 6 ++++ src/main.cpp | 50 ++++++++++++++++++++----------- src/purpose/CMakeLists.txt | 9 ++++++ src/purpose/purposeplugin.cpp | 55 ++++++++++++++++++++++++++++++++++ src/purpose/purposeplugin.json | 18 +++++++++++ src/qml/ChatBar.qml | 20 ++++++++++++- src/qml/main.qml | 27 +++++++++++++++++ src/sharehandler.cpp | 37 +++++++++++++++++++++++ src/sharehandler.h | 46 ++++++++++++++++++++++++++++ 11 files changed, 257 insertions(+), 19 deletions(-) create mode 100644 src/purpose/CMakeLists.txt create mode 100644 src/purpose/purposeplugin.cpp create mode 100644 src/purpose/purposeplugin.json create mode 100644 src/sharehandler.cpp create mode 100644 src/sharehandler.h diff --git a/.reuse/dep5 b/.reuse/dep5 index 2e7e8af2b..ce7d8a2c4 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -49,3 +49,7 @@ License: CC0-1.0 Files: appiumtests/data/* Copyright: 2023 Tobias Fella License: CC0-1.0 + +Files: src/purpose/purposeplugin.json +Copyright: 2023 Tobias Fella +License: BSD-2-Clause diff --git a/CMakeLists.txt b/CMakeLists.txt index 655e8c656..fd9398361 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,6 +72,10 @@ set_package_properties(KF6Kirigami PROPERTIES ) find_package(KF6KirigamiAddons 0.7.2 REQUIRED) +if (UNIX AND NOT APPLE AND NOT ANDROID AND NOT NEOCHAT_FLATPAK AND NOT NEOCHAT_APPIMAGE) + find_package(KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS Purpose) +endif () + if(ANDROID) find_package(OpenSSL) set_package_properties(OpenSSL PROPERTIES diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 28fc93dd9..861c57196 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,6 +3,10 @@ # SPDX-FileCopyrightText: 2020-2021 Tobias Fella # SPDX-License-Identifier: BSD-2-Clause +if (NOT ANDROID AND NOT WIN32 AND NOT APPLE AND NOT NEOCHAT_FLATPAK AND NOT NEOCHAT_APPIMAGE) + add_subdirectory(purpose) +endif() + add_library(neochat STATIC controller.cpp controller.h @@ -165,6 +169,8 @@ add_library(neochat STATIC mediamanager.h models/statekeysmodel.cpp models/statekeysmodel.h + sharehandler.cpp + sharehandler.h ) qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN diff --git a/src/main.cpp b/src/main.cpp index 7884d3f37..193132dbc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -44,6 +44,7 @@ #include "neochatconfig.h" #include "roommanager.h" #include "windowcontroller.h" +#include "sharehandler.h" #ifdef HAVE_RUNNER #include "runner.h" @@ -186,6 +187,9 @@ int main(int argc, char *argv[]) parser.addOption(dbusActivatedOption); #endif + QCommandLineOption shareOption(QStringLiteral("share"), i18n("Share a URL to Matrix"), QStringLiteral("text")); + parser.addOption(shareOption); + about.setupCommandLine(&parser); parser.process(app); about.processCommandLine(&parser); @@ -215,26 +219,32 @@ int main(int argc, char *argv[]) #ifdef HAVE_KDBUSADDONS service.connect(&service, - &KDBusService::activateRequested, - &RoomManager::instance(), - [&engine](const QStringList &arguments, const QString &workingDirectory) { - Q_UNUSED(workingDirectory); + &KDBusService::activateRequested, + &RoomManager::instance(), + [&engine](const QStringList &arguments, const QString &workingDirectory) { + Q_UNUSED(workingDirectory); - QWindow *window = windowFromEngine(&engine); - KWindowSystem::updateStartupId(window); + QWindow *window = windowFromEngine(&engine); + KWindowSystem::updateStartupId(window); - WindowController::instance().showAndRaiseWindow(QString()); + WindowController::instance().showAndRaiseWindow(QString()); - // Open matrix uri - if (arguments.isEmpty()) { - return; - } - auto args = arguments; - args.removeFirst(); - for (const auto &arg : args) { - RoomManager::instance().resolveResource(arg); - } - }); + // Open matrix uri + if (arguments.isEmpty()) { + return; + } + + auto args = arguments; + args.removeFirst(); + if (args.length() == 2 && args[0] == "--share"_ls) { + ShareHandler::instance().setText(args[1]); + return; + } + + for (const auto &arg : args) { + RoomManager::instance().resolveResource(arg); + } + }); #endif engine.rootContext()->setContextObject(new KLocalizedContext(&engine)); @@ -247,6 +257,10 @@ int main(int argc, char *argv[]) }); } + if (parser.isSet("share"_ls)) { + ShareHandler::instance().setText(parser.value(shareOption)); + } + engine.addImageProvider(QLatin1String("mxc"), MatrixImageProvider::create(&engine, &engine)); engine.addImageProvider(QLatin1String("blurhash"), new BlurhashImageProvider); @@ -255,7 +269,7 @@ int main(int argc, char *argv[]) return -1; } - if (!parser.positionalArguments().isEmpty()) { + if (!parser.positionalArguments().isEmpty() && !parser.isSet("share"_ls)) { RoomManager::instance().setUrlArgument(parser.positionalArguments()[0]); } diff --git a/src/purpose/CMakeLists.txt b/src/purpose/CMakeLists.txt new file mode 100644 index 000000000..d501be811 --- /dev/null +++ b/src/purpose/CMakeLists.txt @@ -0,0 +1,9 @@ +# SPDX-FileCopyrightText: 2024 Tobias Fella +# SPDX-License-Identifier: BSD-2-Clause + +kcoreaddons_add_plugin(neochatplugin SOURCES purposeplugin.cpp INSTALL_NAMESPACE "kf6/purpose") +target_link_libraries(neochatplugin + Qt::DBus + KF6::Purpose + KF6::KIOGui +) diff --git a/src/purpose/purposeplugin.cpp b/src/purpose/purposeplugin.cpp new file mode 100644 index 000000000..8a949500a --- /dev/null +++ b/src/purpose/purposeplugin.cpp @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: 2024 Tobias Fella +// SPDX-License-Identifier: LGPL-2.1-or-later + +#include +#include +#include + +class NeoChatJob : public Purpose::Job +{ + Q_OBJECT +public: + explicit NeoChatJob(QObject *parent) + : Purpose::Job(parent) + { + } + + QStringList arrayToList(const QJsonArray &array) + { + QStringList ret; + for (const auto &val : array) { + ret += val.toString(); + } + return ret; + } + + void start() override + { + const QJsonArray urlsJson = data().value(QStringLiteral("urls")).toArray(); + const QString title = data().value(QStringLiteral("title")).toString(); + const QString message = QStringLiteral("%1 - %2").arg(title, arrayToList(urlsJson).join(QLatin1Char(' '))); + + auto *job = new KIO::CommandLauncherJob(QStringLiteral("neochat"), {QStringLiteral("--share"), message}); + connect(job, &KJob::finished, this, &NeoChatJob::emitResult); + job->start(); + } +}; + +class Q_DECL_EXPORT PurposePlugin : public Purpose::PluginBase +{ + Q_OBJECT +public: + PurposePlugin(QObject *p, const QVariantList &) + : Purpose::PluginBase(p) + { + } + + Purpose::Job *createJob() const override + { + return new NeoChatJob(nullptr); + } +}; + +K_PLUGIN_CLASS_WITH_JSON(PurposePlugin, "purposeplugin.json") + +#include "purposeplugin.moc" diff --git a/src/purpose/purposeplugin.json b/src/purpose/purposeplugin.json new file mode 100644 index 000000000..559133411 --- /dev/null +++ b/src/purpose/purposeplugin.json @@ -0,0 +1,18 @@ +{ + "KPlugin": { + "Authors": [ + { + "Name": "Tobias Fella" + } + ], + "Category": "Utilities", + "Description": "Share via NeoChat", + "Icon": "org.kde.neochat", + "License": "GPL", + "Name": "NeoChat", + "X-Purpose-ActionDisplay": "NeoChat" + }, + "X-Purpose-PluginTypes": [ + "ShareUrl" + ] +} diff --git a/src/qml/ChatBar.qml b/src/qml/ChatBar.qml index d07883646..8cc6f3e0d 100644 --- a/src/qml/ChatBar.qml +++ b/src/qml/ChatBar.qml @@ -34,7 +34,25 @@ QQC2.Control { onActiveFocusChanged: textField.forceActiveFocus() - onCurrentRoomChanged: _private.chatBarCache = currentRoom.mainCache + onCurrentRoomChanged: { + _private.chatBarCache = currentRoom.mainCache + if (ShareHandler.text.length > 0 && ShareHandler.room === root.currentRoom.id) { + textField.text = ShareHandler.text; + ShareHandler.text = ""; + ShareHandler.room = ""; + } + } + + Connections { + target: ShareHandler + function onRoomChanged(): void { + if (ShareHandler.text.length > 0 && ShareHandler.room === root.currentRoom.id) { + textField.text = ShareHandler.text; + ShareHandler.text = ""; + ShareHandler.room = ""; + } + } + } /** * @brief The ActionsHandler object to use. diff --git a/src/qml/main.qml b/src/qml/main.qml index 52615b814..5eadbf9c4 100644 --- a/src/qml/main.qml +++ b/src/qml/main.qml @@ -53,6 +53,9 @@ Kirigami.ApplicationWindow { MatrixImageProvider.connection = root.connection; RoomManager.connection = root.connection; SpaceHierarchyCache.connection = root.connection; + if (ShareHandler.text && root.connection) { + root.handleShare(); + } } Connections { @@ -236,6 +239,9 @@ Kirigami.ApplicationWindow { RoomManager.connection = root.connection; SpaceHierarchyCache.connection = root.connection; WindowController.setBlur(pageStack, Config.blur && !Config.compactLayout); + if (ShareHandler.text && root.connection) { + root.handleShare() + } if (Config.minimizeToSystemTrayOnStartup && !Kirigami.Settings.isMobile && Controller.supportSystemTray && Config.systemTray) { restoreWindowGeometryConnections.enabled = true; // To restore window size and position } else { @@ -450,4 +456,25 @@ Kirigami.ApplicationWindow { }); } } + Connections { + target: ShareHandler + function onTextChanged(): void { + if (root.connection && ShareHandler.text.length > 0) { + handleShare(); + } + } + } + function handleShare(): void { + const dialog = applicationWindow().pageStack.pushDialogLayer("qrc:/org/kde/neochat/qml/ChooseRoomDialog.qml", { + connection: root.connection + }, { + title: i18nc("@title", "Share"), + width: Kirigami.Units.gridUnit * 25 + }) + dialog.chosen.connect(function(targetRoomId) { + RoomManager.resolveResource(targetRoomId) + ShareHandler.room = targetRoomId + dialog.closeDialog() + }) + } } diff --git a/src/sharehandler.cpp b/src/sharehandler.cpp new file mode 100644 index 000000000..31526b881 --- /dev/null +++ b/src/sharehandler.cpp @@ -0,0 +1,37 @@ +// SPDX-FileCopyrightText: 2023 Tobias Fella +// SPDX-License-Identifier: LGPL-2.0-or-later + +#include "sharehandler.h" + +ShareHandler::ShareHandler(QObject *parent) + : QObject(parent) +{} + +QString ShareHandler::text() const +{ + return m_text; +} + +void ShareHandler::setText(const QString &text) +{ + if (text == m_text) { + return; + } + m_text = text; + Q_EMIT textChanged(); +} + +QString ShareHandler::room() const +{ + return m_room; +} + +void ShareHandler::setRoom(const QString &roomId) +{ + if (roomId == m_room) { + return; + } + m_room = roomId; + Q_EMIT roomChanged(); +} + diff --git a/src/sharehandler.h b/src/sharehandler.h new file mode 100644 index 000000000..1cfec2af0 --- /dev/null +++ b/src/sharehandler.h @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2023 Tobias Fella +// SPDX-License-Identifier: LGPL-2.0-or-later + +#pragma once + +#include +#include + +class ShareHandler : public QObject +{ + Q_OBJECT + QML_ELEMENT + QML_SINGLETON + + Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) + Q_PROPERTY(QString room READ room WRITE setRoom NOTIFY roomChanged) + +public: + static ShareHandler &instance() + { + static ShareHandler _instance; + return _instance; + } + + static ShareHandler *create(QQmlEngine *, QJSEngine *) + { + QQmlEngine::setObjectOwnership(&instance(), QQmlEngine::CppOwnership); + return &instance(); + } + + QString text() const; + void setText(const QString &url); + + QString room() const; + void setRoom(const QString &roomId); + +Q_SIGNALS: + void textChanged(); + void roomChanged(); + +private: + explicit ShareHandler(QObject *parent = nullptr); + + QString m_text; + QString m_room; +};