File indexing completed on 2024-04-14 05:39:35

0001 // SPDX-License-Identifier: GPL-3.0-or-later
0002 /*
0003   Copyright 2017 - 2023 Martin Koller, kollix@aon.at
0004 
0005   This file is part of liquidshell.
0006 
0007   liquidshell is free software: you can redistribute it and/or modify
0008   it under the terms of the GNU General Public License as published by
0009   the Free Software Foundation, either version 3 of the License, or
0010   (at your option) any later version.
0011 
0012   liquidshell is distributed in the hope that it will be useful,
0013   but WITHOUT ANY WARRANTY; without even the implied warranty of
0014   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0015   GNU General Public License for more details.
0016 
0017   You should have received a copy of the GNU General Public License
0018   along with liquidshell.  If not, see <http://www.gnu.org/licenses/>.
0019 */
0020 
0021 #include <KdeConnect.hxx>
0022 #include <Battery.hxx>
0023 
0024 #include <QDBusConnection>
0025 #include <QDBusConnectionInterface>
0026 #include <QDBusServiceWatcher>
0027 #include <QDBusMessage>
0028 #include <QDebug>
0029 
0030 #include <KLocalizedString>
0031 
0032 //--------------------------------------------------------------------------------
0033 
0034 KdeConnect::KdeConnect()
0035 {
0036   getDevices();
0037 
0038   QDBusConnection::sessionBus().connect("org.kde.kdeconnect", "/modules/kdeconnect",
0039                                         "org.kde.kdeconnect.daemon", "deviceAdded",
0040                                         this, SLOT(deviceAddedSlot(QString)));
0041 
0042   QDBusConnection::sessionBus().connect("org.kde.kdeconnect", "/modules/kdeconnect",
0043                                         "org.kde.kdeconnect.daemon", "deviceRemoved",
0044                                         this, SLOT(deviceRemovedSlot(QString)));
0045 
0046   QDBusConnection::sessionBus().connect("org.kde.kdeconnect", "/modules/kdeconnect",
0047                                         "org.kde.kdeconnect.daemon", "deviceVisibilityChanged",
0048                                         this, SLOT(deviceVisibilityChanged(QString, bool)));
0049 }
0050 
0051 //--------------------------------------------------------------------------------
0052 
0053 void KdeConnect::getDevices()
0054 {
0055   QDBusMessage msg =
0056     QDBusMessage::createMethodCall("org.kde.kdeconnect", "/modules/kdeconnect",
0057                                    "org.kde.kdeconnect.daemon", "devices");
0058   msg << true << true;  // onlyReachable, onlyPaired
0059   QDBusConnection::sessionBus().callWithCallback(msg, this, SLOT(gotDevices(QDBusMessage)));
0060 }
0061 
0062 //--------------------------------------------------------------------------------
0063 
0064 void KdeConnect::gotDevices(const QDBusMessage &msg)
0065 {
0066   QStringList deviceList = msg.arguments()[0].toStringList();
0067 
0068   //qDebug() << __FUNCTION__ << deviceList;
0069   for (const QString &device : deviceList)
0070     deviceAddedSlot(device);
0071 }
0072 
0073 //--------------------------------------------------------------------------------
0074 
0075 void KdeConnect::deviceVisibilityChanged(const QString &dev, bool visible)
0076 {
0077   //qDebug() << __FUNCTION__ << dev << visible;
0078   if ( visible )
0079     deviceAddedSlot(dev);
0080   else
0081     deviceRemovedSlot(dev);
0082 }
0083 
0084 //--------------------------------------------------------------------------------
0085 
0086 void KdeConnect::deviceAddedSlot(const QString &dev)
0087 {
0088   //qDebug() << __FUNCTION__ << dev;
0089   if ( devices.contains(dev) )
0090     return;
0091 
0092   const QString devicePath = "/modules/kdeconnect/devices/" + dev;
0093 
0094   QDBusInterface interface("org.kde.kdeconnect", devicePath, "org.kde.kdeconnect.device");
0095 
0096   if ( !interface.property("isTrusted").toBool() ||
0097        !interface.property("isReachable").toBool() )
0098     return;  // only show paired, reachable devices
0099 
0100   Device device;
0101   device->id = dev;
0102 
0103   device->name = interface.property("name").toString();
0104 
0105   QDBusConnection::sessionBus().connect("org.kde.kdeconnect", devicePath,
0106                                         "org.kde.kdeconnect.device", "nameChanged",
0107                                         device.data(), SLOT(nameChangedSlot(const QString &)));
0108 
0109   QDBusConnection::sessionBus().connect("org.kde.kdeconnect", devicePath,
0110                                         "org.kde.kdeconnect.device", "pluginsChanged",
0111                                         device.data(), SLOT(updatePlugins()));
0112 
0113   QString type = interface.property("type").toString();
0114 
0115   if ( type == "smartphone" )
0116     device->icon = QIcon::fromTheme("smartphone");
0117   else if ( type == "tablet" )
0118     device->icon = QIcon::fromTheme("tablet");
0119   else
0120     device->icon = QIcon::fromTheme(interface.property("statusIconName").toString());
0121 
0122   device->updatePlugins();
0123 
0124   devices.insert(dev, device);
0125 
0126   emit deviceAdded(device);
0127 }
0128 
0129 //--------------------------------------------------------------------------------
0130 
0131 void KdeConnect::deviceRemovedSlot(const QString &dev)
0132 {
0133   if ( !devices.contains(dev) )
0134     return;
0135 
0136   devices.remove(dev);
0137   emit deviceRemoved(dev);
0138 }
0139 
0140 //--------------------------------------------------------------------------------
0141 //--------------------------------------------------------------------------------
0142 //--------------------------------------------------------------------------------
0143 
0144 void KdeConnectDevice::ringPhone()
0145 {
0146   QDBusMessage msg =
0147     QDBusMessage::createMethodCall("org.kde.kdeconnect", "/modules/kdeconnect/devices/" + id + "/findmyphone",
0148                                    "org.kde.kdeconnect.device.findmyphone", "ring");
0149   QDBusConnection::sessionBus().call(msg);
0150 }
0151 
0152 //--------------------------------------------------------------------------------
0153 
0154 void KdeConnectDevice::chargeChangedSlot()
0155 {
0156   charge = batteryInterface->property("charge").toInt();
0157   isCharging = batteryInterface->property("isCharging").toBool();
0158 
0159   //qDebug() << __FUNCTION__ << name << charge << isCharging;
0160 
0161   if ( charge < 0 )
0162     return;
0163 
0164   chargeIcon = Battery::getStatusIcon(charge, isCharging);
0165   emit changed();
0166 
0167   if ( isCharging )
0168   {
0169     if ( notif ) notif->close();
0170     return;
0171   }
0172 
0173   const int LIMIT = 40;
0174 
0175   if ( charge < LIMIT )  // I want to keep charge above 40%
0176   {
0177     if ( !warned )
0178     {
0179       warned = true;
0180       notif = new KNotification("device needs charging", KNotification::Persistent);
0181       notif->setTitle(i18n("Device needs charging"));
0182       notif->setText(i18n("Device charge of '%1' is at %2%.\nYou should charge it.", name, charge));
0183       notif->setIconName("battery-040");
0184       notif->sendEvent();
0185     }
0186   }
0187   else
0188   {
0189     warned = false;
0190     if ( notif ) notif->close();
0191   }
0192 }
0193 
0194 //--------------------------------------------------------------------------------
0195 
0196 void KdeConnectDevice::nameChangedSlot(const QString &newName)
0197 {
0198   //qDebug() << __FUNCTION__ << newName;
0199   name = newName;
0200   emit changed();
0201 }
0202 
0203 //--------------------------------------------------------------------------------
0204 
0205 void KdeConnectDevice::updatePlugins()
0206 {
0207   const QString devicePath = "/modules/kdeconnect/devices/" + id;
0208   QDBusInterface interface("org.kde.kdeconnect", devicePath, "org.kde.kdeconnect.device");
0209 
0210   QDBusReply<QStringList> strings = interface.call("loadedPlugins");
0211   plugins = strings.value();
0212 
0213   if ( plugins.contains("kdeconnect_battery") )
0214   {
0215     if ( !batteryInterface )
0216     {
0217       batteryInterface = new QDBusInterface("org.kde.kdeconnect", devicePath + "/battery",
0218                              "org.kde.kdeconnect.device.battery", QDBusConnection::sessionBus(),
0219                              this);
0220 
0221       chargeChangedSlot();
0222 
0223       connect(batteryInterface, SIGNAL(refreshed(bool, int)), this, SLOT(chargeChangedSlot()));
0224     }
0225   }
0226   else
0227   {
0228     delete batteryInterface;
0229     batteryInterface = nullptr;
0230     charge = -1;
0231   }
0232 
0233   emit changed();
0234 }
0235 
0236 //--------------------------------------------------------------------------------