File indexing completed on 2024-05-05 17:41:33

0001 /*
0002     SPDX-FileCopyrightText: 2018 David Edmundson <davidedmundson@kde.org>
0003     SPDX-FileCopyrightText: 2018 Eike Hein <hein@kde.org>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "browserintegrationreminder.h"
0009 
0010 #include <QAction>
0011 #include <QDBusConnection>
0012 #include <QDBusConnectionInterface>
0013 #include <QDBusMessage>
0014 #include <QDBusServiceWatcher>
0015 #include <QDebug>
0016 #include <QDesktopServices>
0017 #include <QMenu>
0018 #include <QTimer>
0019 
0020 #include <KActivities/ResourceInstance>
0021 #include <KConfig>
0022 #include <KConfigGroup>
0023 #include <KIO/ApplicationLauncherJob>
0024 #include <KLocalizedString>
0025 #include <KNotificationJobUiDelegate>
0026 #include <KService>
0027 #include <KSharedConfig>
0028 #include <KStatusNotifierItem>
0029 #include <kpluginfactory.h>
0030 
0031 K_PLUGIN_FACTORY_WITH_JSON(BrowserIntegrationReminderFactory, "browserintegrationreminder.json", registerPlugin<BrowserIntegrationReminder>();)
0032 
0033 static const QString s_dbusServiceName = QStringLiteral("org.kde.plasma.browser_integration");
0034 
0035 #define MAX_SHOW_COUNT 3
0036 
0037 BrowserIntegrationReminder::BrowserIntegrationReminder(QObject *parent, const QList<QVariant> &)
0038     : KDEDModule(parent)
0039 {
0040     m_debug = qEnvironmentVariableIsSet("PLASMA_BROWSE_REMIND_FORCE");
0041     auto config = KSharedConfig::openConfig()->group("PlasmaBrowserIntegration");
0042     m_shownCount = config.readEntry("shownCount", 0);
0043 
0044     if (m_shownCount > MAX_SHOW_COUNT && !m_debug) {
0045         disableAutoload(); // safer than it looks it won't be processed till we hit the event loop
0046         return;
0047     }
0048 
0049     QUrl firefox(QStringLiteral("https://addons.mozilla.org/en-US/firefox/addon/plasma-integration/"));
0050     m_browsers[QStringLiteral("firefox.desktop")] = firefox;
0051     m_browsers[QStringLiteral("nightly.desktop")] = firefox;
0052 
0053     QUrl chrome(QStringLiteral("https://chrome.google.com/webstore/detail/plasma-integration/cimiefiiaegbelhefglklhhakcgmhkai"));
0054     m_browsers[QStringLiteral("google-chrome.desktop")] = chrome;
0055     m_browsers[QStringLiteral("google-chrome-beta.desktop")] = chrome;
0056     m_browsers[QStringLiteral("google-chrome-unstable.desktop")] = chrome;
0057     m_browsers[QStringLiteral("chromium-browser.desktop")] = chrome;
0058     m_browsers[QStringLiteral("vivaldi-stable.desktop")] = chrome;
0059     m_browsers[QStringLiteral("brave-browser.desktop")] = chrome;
0060 
0061     QUrl edge(QStringLiteral("https://microsoftedge.microsoft.com/addons/detail/plasma-integration/dnnckbejblnejeabhcmhklcaljjpdjeh"));
0062     m_browsers[QStringLiteral("microsoft-edge.desktop")] = edge;
0063     m_browsers[QStringLiteral("microsoft-edge-beta.desktop")] = edge;
0064     m_browsers[QStringLiteral("microsoft-edge-dev.desktop")] = edge;
0065 
0066     setModuleName(QStringLiteral("BrowserIntegrationReminder"));
0067     QDBusConnection dbus = QDBusConnection::sessionBus();
0068     dbus.connect(QStringLiteral("org.kde.ActivityManager"),
0069                  QStringLiteral("/ActivityManager/Resources/Scoring"),
0070                  QStringLiteral("org.kde.ActivityManager.ResourcesScoring"),
0071                  QStringLiteral("ResourceScoreUpdated"),
0072                  this,
0073                  SLOT(onResourceScoresChanged(QString, QString, QString, double, unsigned int, unsigned int)));
0074 }
0075 
0076 BrowserIntegrationReminder::~BrowserIntegrationReminder()
0077 {
0078 }
0079 
0080 void BrowserIntegrationReminder::onResourceScoresChanged(const QString &activity,
0081                                                          const QString &client,
0082                                                          const QString &resource,
0083                                                          double score,
0084                                                          unsigned int lastUpdate,
0085                                                          unsigned int firstUpdate)
0086 {
0087     Q_UNUSED(activity);
0088     Q_UNUSED(score);
0089     Q_UNUSED(lastUpdate);
0090     Q_UNUSED(firstUpdate);
0091     Q_UNUSED(client)
0092 
0093     if (!resource.startsWith(QStringLiteral("applications:"))) {
0094         return;
0095     }
0096     const QString desktopFile = resource.mid(strlen("applications:"));
0097     if (!m_browsers.contains(desktopFile)) {
0098         return;
0099     }
0100     // wait a few seconds and then query if the extension is active
0101     QTimer::singleShot(10 * 1000, this, [this, desktopFile]() {
0102         onBrowserStarted(desktopFile);
0103     });
0104 }
0105 
0106 void BrowserIntegrationReminder::onBrowserStarted(const QString &browser)
0107 {
0108     QDBusConnection bus = QDBusConnection::sessionBus();
0109     if (m_sni) {
0110         return;
0111     }
0112 
0113     if (!KService::serviceByStorageId(browser)) {
0114         return;
0115     }
0116 
0117     if (!m_watcher) {
0118         m_watcher = new QDBusServiceWatcher(s_dbusServiceName, bus, QDBusServiceWatcher::WatchForRegistration, this);
0119         connect(m_watcher, &QDBusServiceWatcher::serviceRegistered, this, [this](const QString &service) {
0120             Q_UNUSED(service);
0121             if (m_sni) {
0122                 m_sni->deleteLater();
0123                 disableAutoload();
0124             }
0125         });
0126     }
0127 
0128     if (!m_debug && bus.interface()->isServiceRegistered(s_dbusServiceName)) {
0129         // the user has the extension installed, we don't need to keep checking
0130         // env var exists for easier testing
0131         disableAutoload();
0132         return;
0133     }
0134 
0135     m_sni = new KStatusNotifierItem(this);
0136     m_shownCount++;
0137     auto config = KSharedConfig::openConfig()->group("PlasmaBrowserIntegration");
0138     config.writeEntry("shownCount", m_shownCount);
0139 
0140     m_sni->setTitle(i18n("Get Plasma Browser Integration"));
0141     m_sni->setIconByName(QStringLiteral("plasma-browser-integration"));
0142     m_sni->setStandardActionsEnabled(false);
0143     m_sni->setStatus(KStatusNotifierItem::Active);
0144 
0145     connect(m_sni, &KStatusNotifierItem::activateRequested, this, [this, browser]() {
0146         const KService::Ptr service = KService::serviceByStorageId(browser);
0147 
0148         if (!service) {
0149             unload();
0150             return;
0151         }
0152 
0153         KIO::ApplicationLauncherJob *job = new KIO::ApplicationLauncherJob(service);
0154         job->setUrls({m_browsers[browser]});
0155         job->setUiDelegate(new KNotificationJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled));
0156         job->start();
0157 
0158         KActivities::ResourceInstance::notifyAccessed(QUrl(QStringLiteral("applications:") + browser),
0159                                                       QStringLiteral("org.kde.plasma.browserintegrationreminder"));
0160         // remove for this session.
0161         // If the user installed it successfully we won't show anything next session
0162         // If they didn't they'll get the link next login
0163         unload();
0164     });
0165 
0166     auto *menu = new QMenu;
0167     auto *action = new QAction(QIcon::fromTheme(QStringLiteral("view-hidden")), i18n("Do not show again"));
0168     menu->addAction(action);
0169     connect(action, &QAction::triggered, this, [this]() {
0170         auto config = KSharedConfig::openConfig()->group("PlasmaBrowserIntegration");
0171         config.writeEntry("shownCount", 100);
0172         disableAutoload();
0173     });
0174 
0175     m_sni->setContextMenu(menu);
0176 }
0177 
0178 void BrowserIntegrationReminder::unload()
0179 {
0180     QDBusConnection dbus = QDBusConnection::sessionBus();
0181     QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("org.kde.kded5"),
0182                                                       QStringLiteral("/kded"),
0183                                                       QStringLiteral("org.kde.kded5"),
0184                                                       QStringLiteral("unloadModule"));
0185     msg.setArguments({QVariant(QStringLiteral("browserintegrationreminder"))});
0186     dbus.call(msg, QDBus::NoBlock);
0187 }
0188 
0189 void BrowserIntegrationReminder::disableAutoload()
0190 {
0191     QDBusConnection dbus = QDBusConnection::sessionBus();
0192     QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("org.kde.kded5"),
0193                                                       QStringLiteral("/kded"),
0194                                                       QStringLiteral("org.kde.kded5"),
0195                                                       QStringLiteral("setModuleAutoloading"));
0196     msg.setArguments({QVariant(QStringLiteral("browserintegrationreminder")), QVariant(false)});
0197     dbus.call(msg, QDBus::NoBlock);
0198     unload();
0199 }
0200 
0201 #include "browserintegrationreminder.moc"