File indexing completed on 2024-06-23 05:45:43

0001 /*
0002     SPDX-FileCopyrightText: 2020 HanY <hanyoung@protonmail.com>
0003     SPDX-License-Identifier: LGPL-2.1-or-later
0004 */
0005 
0006 #include "kclock_kweather_3x3.h"
0007 
0008 #include <KLocalizedString>
0009 
0010 #include <QDBusConnection>
0011 #include <QDBusInterface>
0012 #include <QDBusReply>
0013 #include <QJsonArray>
0014 #include <QJsonDocument>
0015 #include <QProcess>
0016 #include <QTimer>
0017 #include <QXmlStreamReader>
0018 
0019 KClock_KWeather_3x3::KClock_KWeather_3x3(QObject *parent, const QVariantList &args)
0020     : Plasma::Applet(parent, args)
0021 {
0022     // KWeather
0023     auto system = QLocale::system().measurementSystem();
0024     if (system == QLocale::MetricSystem || system == QLocale::ImperialUKSystem)
0025         m_isCelsius = true;
0026     else
0027         m_isCelsius = false;
0028     QDBusConnection::sessionBus().connect(QStringLiteral("org.kde.kweather"),
0029                                           QStringLiteral("/"),
0030                                           QStringLiteral("org.kde.kweather.LocationModel"),
0031                                           QStringLiteral("removed"),
0032                                           this,
0033                                           SLOT(addCity(QString)));
0034     QDBusConnection::sessionBus().connect(QStringLiteral("org.kde.kweather"),
0035                                           QStringLiteral("/"),
0036                                           QStringLiteral("org.kde.kweather.LocationModel"),
0037                                           QStringLiteral("added"),
0038                                           this,
0039                                           SLOT(removeCity(QString)));
0040     QDBusInterface *interface = new QDBusInterface(QStringLiteral("org.kde.kweather"),
0041                                                    QStringLiteral("/locations"),
0042                                                    QStringLiteral("org.freedesktop.DBus.Introspectable"),
0043                                                    QDBusConnection::sessionBus(),
0044                                                    this);
0045     QDBusReply<QString> reply = interface->call(QStringLiteral("Introspect"));
0046     if (reply.isValid()) {
0047         auto xmlMsg = reply.value();
0048         QXmlStreamReader xml(xmlMsg);
0049         while (!xml.atEnd()) {
0050             xml.readNext();
0051             if (xml.name() == "node" && xml.attributes().hasAttribute("name")) {
0052                 m_location = xml.attributes().value("name").toString();
0053                 break;
0054             }
0055         }
0056     }
0057     delete interface;
0058     if (!m_location.isEmpty()) {
0059         m_KWeatherInterface = new QDBusInterface(QStringLiteral("org.kde.kweather"),
0060                                                  QStringLiteral("/locations/") + m_location,
0061                                                  QStringLiteral("org.kde.kweather.WeatherLocation"),
0062                                                  QDBusConnection::sessionBus(),
0063                                                  this);
0064         QDBusConnection::sessionBus().connect(QStringLiteral("org.kde.kweather"),
0065                                               QStringLiteral("/locations/") + m_location,
0066                                               QStringLiteral("org.kde.kweather.WeatherLocation"),
0067                                               QStringLiteral("currentForecastChange"),
0068                                               this,
0069                                               SLOT(update()));
0070 
0071         QDBusReply<QString> reply = m_KWeatherInterface->call("getWeatherData");
0072         this->parse(QJsonDocument::fromJson(reply.value().toUtf8()));
0073         this->m_cityName = m_KWeatherInterface->property("name").toString();
0074         Q_EMIT locationChanged();
0075     }
0076 
0077     // KClock
0078     m_timer = new QTimer(this);
0079     connect(m_timer, &QTimer::timeout, this, &KClock_KWeather_3x3::initialTimeUpdate);
0080     m_timer->setSingleShot(true);
0081 
0082     m_minutesCounter = QTime::currentTime().msecsSinceStartOfDay() / (1000 * 60); // seconds since start of the day
0083     // initial interval is milliseconds to next minute
0084     m_timer->start((60 - (QTime::currentTime().msecsSinceStartOfDay() / 1000) % 60) * 1000); // seconds to next minute
0085 
0086     if (!QDBusConnection::sessionBus().connect(QStringLiteral("org.kde.kclockd"),
0087                                                QStringLiteral("/Alarms"),
0088                                                QStringLiteral("org.kde.kclock.AlarmModel"),
0089                                                QStringLiteral("nextAlarm"),
0090                                                this,
0091                                                SLOT(updateAlarm(qulonglong))))
0092         m_string = QStringLiteral("connect failed");
0093 
0094     interface = new QDBusInterface(QStringLiteral("org.kde.kclockd"),
0095                                    QStringLiteral("/Alarms"),
0096                                    QStringLiteral("org.kde.kclock.AlarmModel"),
0097                                    QDBusConnection::sessionBus(),
0098                                    this);
0099     QDBusReply<quint64> KClock_reply = interface->call(QStringLiteral("getNextAlarm"));
0100     if (reply.isValid()) {
0101         auto alarmTime = KClock_reply.value();
0102         if (alarmTime > 0) {
0103             auto dateTime = QDateTime::fromSecsSinceEpoch(alarmTime).toLocalTime();
0104             m_string = QStringLiteral("%1 %2").arg(m_local.standaloneDayName(dateTime.date().dayOfWeek(), QLocale::ShortFormat),
0105                                                    m_local.toString(dateTime.time(), QStringLiteral("hh:mm")));
0106             m_hasAlarm = true;
0107         } else
0108             m_hasAlarm = false;
0109     }
0110     emit propertyChanged();
0111 }
0112 
0113 void KClock_KWeather_3x3::parse(QJsonDocument doc)
0114 {
0115     QJsonArray dailyArray = doc[QStringLiteral("dailyForecasts")].toArray();
0116     QJsonArray hourlyArray = doc[QStringLiteral("hourlyForecasts")].toArray();
0117     m_description = hourlyArray.at(0).toObject()[QStringLiteral("weatherDescription")].toString();
0118     m_weatherIcon = hourlyArray.at(0).toObject()[QStringLiteral("weatherIcon")].toString();
0119     if (m_isCelsius)
0120         m_tempNow = QString::number(hourlyArray.at(0).toObject()[QStringLiteral("temperature")].toDouble()) + QStringLiteral("°C");
0121     else
0122         m_tempNow = QString::number(hourlyArray.at(0).toObject()[QStringLiteral("temperature")].toDouble() * 1.8 + 32) + QStringLiteral("°");
0123 
0124     if (m_isCelsius) {
0125         m_maxTemp = static_cast<int>(dailyArray.first().toObject()[QStringLiteral("maxTemp")].toDouble());
0126         m_minTemp = static_cast<int>(dailyArray.first().toObject()[QStringLiteral("minTemp")].toDouble());
0127     } else {
0128         m_maxTemp = dailyArray.first().toObject()[QStringLiteral("maxTemp")].toDouble() * 1.8 + 32;
0129         m_minTemp = dailyArray.first().toObject()[QStringLiteral("minTemp")].toDouble() * 1.8 + 32;
0130     }
0131     Q_EMIT dataUpdated();
0132 }
0133 void KClock_KWeather_3x3::updateAlarm(qulonglong time)
0134 {
0135     auto dateTime = QDateTime::fromSecsSinceEpoch(time).toLocalTime();
0136     if (time > 0) {
0137         m_string = QStringLiteral("%1 %2").arg(m_local.standaloneDayName(dateTime.date().dayOfWeek(), QLocale::ShortFormat),
0138                                                m_local.toString(dateTime.time(), QStringLiteral("hh:mm")));
0139         m_hasAlarm = true;
0140     } else {
0141         m_hasAlarm = false;
0142     }
0143     emit propertyChanged();
0144 }
0145 void KClock_KWeather_3x3::openKClock()
0146 {
0147     m_process = new QProcess(this);
0148     m_process->start(QStringLiteral("kclock"), QStringList());
0149 }
0150 void KClock_KWeather_3x3::initialTimeUpdate()
0151 {
0152     emit timeChanged();
0153     disconnect(m_timer, &QTimer::timeout, this, &KClock_KWeather_3x3::initialTimeUpdate); // disconnect
0154     m_timer->setSingleShot(false);
0155     connect(m_timer, &QTimer::timeout, this, &KClock_KWeather_3x3::updateTime);
0156     m_timer->start(60000); // update every minute
0157 }
0158 
0159 void KClock_KWeather_3x3::updateTime()
0160 {
0161     Q_EMIT timeChanged();
0162     m_minutesCounter++;
0163     if (m_minutesCounter >= 60 * 24) {
0164         m_minutesCounter = 0;
0165         Q_EMIT dateChanged();
0166     }
0167 }
0168 QString KClock_KWeather_3x3::time()
0169 {
0170     return m_local.toString(QTime::currentTime(), QStringLiteral("hh:mm"));
0171 }
0172 QString KClock_KWeather_3x3::date()
0173 {
0174     return m_local.toString(QDate::currentDate(), QStringLiteral("ddd, MMMM d"));
0175 }
0176 KClock_KWeather_3x3::~KClock_KWeather_3x3()
0177 {
0178 }
0179 
0180 K_PLUGIN_CLASS(KClock_KWeather_3x3)
0181 
0182 #include "kclock_kweather_3x3.moc"