File indexing completed on 2024-04-21 05:32:52

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 <PlasmaActivities/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(QStringLiteral("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     m_browsers[QStringLiteral("librewolf.desktop")] = firefox;
0053 
0054     QUrl chrome(QStringLiteral("https://chrome.google.com/webstore/detail/plasma-integration/cimiefiiaegbelhefglklhhakcgmhkai"));
0055     m_browsers[QStringLiteral("google-chrome.desktop")] = chrome;
0056     m_browsers[QStringLiteral("google-chrome-beta.desktop")] = chrome;
0057     m_browsers[QStringLiteral("google-chrome-unstable.desktop")] = chrome;
0058     m_browsers[QStringLiteral("chromium-browser.desktop")] = chrome;
0059     m_browsers[QStringLiteral("vivaldi-stable.desktop")] = chrome;
0060     m_browsers[QStringLiteral("brave-browser.desktop")] = chrome;
0061 
0062     QUrl edge(QStringLiteral("https://microsoftedge.microsoft.com/addons/detail/plasma-integration/dnnckbejblnejeabhcmhklcaljjpdjeh"));
0063     m_browsers[QStringLiteral("microsoft-edge.desktop")] = edge;
0064     m_browsers[QStringLiteral("microsoft-edge-beta.desktop")] = edge;
0065     m_browsers[QStringLiteral("microsoft-edge-dev.desktop")] = edge;
0066 
0067     setModuleName(QStringLiteral("BrowserIntegrationReminder"));
0068     QDBusConnection dbus = QDBusConnection::sessionBus();
0069     dbus.connect(QStringLiteral("org.kde.ActivityManager"),
0070                  QStringLiteral("/ActivityManager/Resources/Scoring"),
0071                  QStringLiteral("org.kde.ActivityManager.ResourcesScoring"),
0072                  QStringLiteral("ResourceScoreUpdated"),
0073                  this,
0074                  SLOT(onResourceScoresChanged(QString, QString, QString, double, unsigned int, unsigned int)));
0075 }
0076 
0077 BrowserIntegrationReminder::~BrowserIntegrationReminder()
0078 {
0079 }
0080 
0081 void BrowserIntegrationReminder::onResourceScoresChanged(const QString &activity,
0082                                                          const QString &client,
0083                                                          const QString &resource,
0084                                                          double score,
0085                                                          unsigned int lastUpdate,
0086                                                          unsigned int firstUpdate)
0087 {
0088     Q_UNUSED(activity);
0089     Q_UNUSED(score);
0090     Q_UNUSED(lastUpdate);
0091     Q_UNUSED(firstUpdate);
0092     Q_UNUSED(client)
0093 
0094     if (!resource.startsWith(QStringLiteral("applications:"))) {
0095         return;
0096     }
0097     const QString desktopFile = resource.mid(strlen("applications:"));
0098     if (!m_browsers.contains(desktopFile)) {
0099         return;
0100     }
0101     // wait a few seconds and then query if the extension is active
0102     QTimer::singleShot(10 * 1000, this, [this, desktopFile]() {
0103         onBrowserStarted(desktopFile);
0104     });
0105 }
0106 
0107 void BrowserIntegrationReminder::onBrowserStarted(const QString &browser)
0108 {
0109     QDBusConnection bus = QDBusConnection::sessionBus();
0110     if (m_sni) {
0111         return;
0112     }
0113 
0114     if (!KService::serviceByStorageId(browser)) {
0115         return;
0116     }
0117 
0118     if (!m_watcher) {
0119         m_watcher = new QDBusServiceWatcher(s_dbusServiceName, bus, QDBusServiceWatcher::WatchForRegistration, this);
0120         connect(m_watcher, &QDBusServiceWatcher::serviceRegistered, this, [this](const QString &service) {
0121             Q_UNUSED(service);
0122             if (m_sni) {
0123                 m_sni->deleteLater();
0124                 disableAutoload();
0125             }
0126         });
0127     }
0128 
0129     if (!m_debug && bus.interface()->isServiceRegistered(s_dbusServiceName)) {
0130         // the user has the extension installed, we don't need to keep checking
0131         // env var exists for easier testing
0132         disableAutoload();
0133         return;
0134     }
0135 
0136     m_sni = new KStatusNotifierItem(this);
0137     m_shownCount++;
0138     auto config = KSharedConfig::openConfig()->group(QStringLiteral("PlasmaBrowserIntegration"));
0139     config.writeEntry("shownCount", m_shownCount);
0140 
0141     m_sni->setTitle(i18n("Get Plasma Browser Integration"));
0142     m_sni->setIconByName(QStringLiteral("plasma-browser-integration"));
0143     m_sni->setStandardActionsEnabled(false);
0144     m_sni->setStatus(KStatusNotifierItem::Active);
0145 
0146     connect(m_sni, &KStatusNotifierItem::activateRequested, this, [this, browser]() {
0147         const KService::Ptr service = KService::serviceByStorageId(browser);
0148 
0149         if (!service) {
0150             unload();
0151             return;
0152         }
0153 
0154         KIO::ApplicationLauncherJob *job = new KIO::ApplicationLauncherJob(service);
0155         job->setUrls({m_browsers[browser]});
0156         job->setUiDelegate(new KNotificationJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled));
0157         job->start();
0158 
0159         KActivities::ResourceInstance::notifyAccessed(QUrl(QStringLiteral("applications:") + browser),
0160                                                       QStringLiteral("org.kde.plasma.browserintegrationreminder"));
0161         // remove for this session.
0162         // If the user installed it successfully we won't show anything next session
0163         // If they didn't they'll get the link next login
0164         unload();
0165     });
0166 
0167     auto *menu = new QMenu;
0168     auto *action = new QAction(QIcon::fromTheme(QStringLiteral("view-hidden")), i18n("Do not show again"));
0169     menu->addAction(action);
0170     connect(action, &QAction::triggered, this, [this]() {
0171         auto config = KSharedConfig::openConfig()->group(QStringLiteral("PlasmaBrowserIntegration"));
0172         config.writeEntry("shownCount", 100);
0173         disableAutoload();
0174     });
0175 
0176     m_sni->setContextMenu(menu);
0177 }
0178 
0179 void BrowserIntegrationReminder::unload()
0180 {
0181     QDBusConnection dbus = QDBusConnection::sessionBus();
0182     QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("org.kde.kded6"),
0183                                                       QStringLiteral("/kded"),
0184                                                       QStringLiteral("org.kde.kded6"),
0185                                                       QStringLiteral("unloadModule"));
0186     msg.setArguments({QVariant(QStringLiteral("browserintegrationreminder"))});
0187     dbus.call(msg, QDBus::NoBlock);
0188 }
0189 
0190 void BrowserIntegrationReminder::disableAutoload()
0191 {
0192     QDBusConnection dbus = QDBusConnection::sessionBus();
0193     QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("org.kde.kded6"),
0194                                                       QStringLiteral("/kded"),
0195                                                       QStringLiteral("org.kde.kded6"),
0196                                                       QStringLiteral("setModuleAutoloading"));
0197     msg.setArguments({QVariant(QStringLiteral("browserintegrationreminder")), QVariant(false)});
0198     dbus.call(msg, QDBus::NoBlock);
0199     unload();
0200 }
0201 
0202 #include "browserintegrationreminder.moc"
0203 
0204 #include "moc_browserintegrationreminder.cpp"