diff --git a/applets/CMakeLists.txt b/applets/CMakeLists.txt index 0486c8430..ead78b856 100644 --- a/applets/CMakeLists.txt +++ b/applets/CMakeLists.txt @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +# SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd. # # SPDX-License-Identifier: GPL-3.0-or-later @@ -7,3 +7,4 @@ add_subdirectory(dde-appearance) add_subdirectory(dde-apps) add_subdirectory(dde-key-notify) add_subdirectory(dde-shutdown) +add_subdirectory(dde-weather) diff --git a/applets/dde-weather/CMakeLists.txt b/applets/dde-weather/CMakeLists.txt new file mode 100644 index 000000000..ee3b62795 --- /dev/null +++ b/applets/dde-weather/CMakeLists.txt @@ -0,0 +1,27 @@ +# SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd. +# +# SPDX-License-Identifier: GPL-3.0-or-later + +find_package(Qt${QT_VERSION_MAJOR} ${REQUIRED_QT_VERSION} REQUIRED COMPONENTS Network) + +add_library(dde-weather SHARED + weatherapplet.h + weatherapplet.cpp + weathermodel.h + weathermodel.cpp + weatherhelper.h + weatherhelper.cpp +) + +target_link_libraries(dde-weather PRIVATE + dde-shell-frame + Qt${QT_VERSION_MAJOR}::Network +) + +find_package(Dtk${DTK_VERSION_MAJOR}DConfig REQUIRED) + +dtk_add_config_meta_files(APPID "org.deepin.dde.shell" FILES configs/org.deepin.ds.weather.json) + +ds_install_package(PACKAGE org.deepin.ds.weather TARGET dde-weather) + +ds_handle_package_translation(PACKAGE org.deepin.ds.weather) diff --git a/applets/dde-weather/configs/org.deepin.ds.weather.json b/applets/dde-weather/configs/org.deepin.ds.weather.json new file mode 100644 index 000000000..b5d0e316c --- /dev/null +++ b/applets/dde-weather/configs/org.deepin.ds.weather.json @@ -0,0 +1,42 @@ +{ + "magic": "dsg.config.meta", + "version": "1.0", + "contents": { + "city": { + "value": "auto", + "serial": 0, + "flags": [], + "name": "city name or 'auto' for auto detection", + "name[zh_CN]": "城市名称或'auto'自动检测", + "permissions": "readwrite", + "visibility": "public" + }, + "refreshInterval": { + "value": 30, + "serial": 0, + "flags": [], + "name": "weather refresh interval in minutes", + "name[zh_CN]": "天气刷新间隔(分钟)", + "permissions": "readwrite", + "visibility": "public" + }, + "temperatureUnit": { + "value": "celsius", + "serial": 0, + "flags": [], + "name": "temperature unit: celsius or fahrenheit", + "name[zh_CN]": "温度单位:摄氏度或华氏度", + "permissions": "readwrite", + "visibility": "public" + }, + "showInDock": { + "value": true, + "serial": 0, + "flags": [], + "name": "show weather widget in dock", + "name[zh_CN]": "在任务栏显示天气小组件", + "permissions": "readwrite", + "visibility": "public" + } + } +} diff --git a/applets/dde-weather/package/WeatherDetail.qml b/applets/dde-weather/package/WeatherDetail.qml new file mode 100644 index 000000000..344b760cc --- /dev/null +++ b/applets/dde-weather/package/WeatherDetail.qml @@ -0,0 +1,120 @@ +// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 + +import org.deepin.ds 1.0 + +Rectangle { + id: detail + color: Qt.rgba(0.15, 0.15, 0.15, 0.95) + radius: 12 + + ColumnLayout { + anchors.fill: parent + anchors.margins: 16 + spacing: 12 + + RowLayout { + Layout.fillWidth: true + spacing: 12 + + Text { + text: Applet.weatherIcon || "☀" + font.pixelSize: 48 + color: "white" + } + + ColumnLayout { + Layout.fillWidth: true + spacing: 4 + + Text { + text: Applet.currentCity || qsTr("Unknown") + font.pixelSize: 18 + font.bold: true + color: "white" + } + + Text { + text: Applet.temperature + "°C" + font.pixelSize: 28 + font.bold: true + color: "white" + } + + Text { + text: Applet.weatherDesc || "" + font.pixelSize: 14 + color: Qt.rgba(1, 1, 1, 0.7) + } + } + } + + Rectangle { + Layout.fillWidth: true + height: 1 + color: Qt.rgba(1, 1, 1, 0.1) + } + + ListView { + Layout.fillWidth: true + Layout.fillHeight: true + model: Applet.model + spacing: 8 + clip: true + + delegate: RowLayout { + width: ListView.view.width + spacing: 12 + + Text { + text: model.icon || "☀" + font.pixelSize: 20 + color: "white" + } + + Text { + text: model.city || "" + font.pixelSize: 14 + color: "white" + Layout.fillWidth: true + } + + Text { + text: model.temperature + "°C" + font.pixelSize: 14 + font.bold: true + color: "white" + } + + Text { + text: model.description || "" + font.pixelSize: 12 + color: Qt.rgba(1, 1, 1, 0.6) + } + } + } + + RowLayout { + Layout.fillWidth: true + spacing: 8 + + Button { + text: qsTr("Refresh") + onClicked: Applet.refresh() + } + + Item { Layout.fillWidth: true } + + Text { + text: qsTr("Last update: --:--") + font.pixelSize: 11 + color: Qt.rgba(1, 1, 1, 0.5) + } + } + } +} diff --git a/applets/dde-weather/package/main.qml b/applets/dde-weather/package/main.qml new file mode 100644 index 000000000..4aa1cee21 --- /dev/null +++ b/applets/dde-weather/package/main.qml @@ -0,0 +1,84 @@ +// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 + +import org.deepin.ds 1.0 + +AppletItem { + id: root + objectName: "weather-applet" + implicitWidth: 200 + implicitHeight: 100 + + property bool expanded: false + + Rectangle { + anchors.fill: parent + radius: 8 + color: Qt.rgba(1, 1, 1, 0.1) + + ColumnLayout { + anchors.centerIn: parent + spacing: 4 + + Text { + Layout.alignment: Qt.AlignHCenter + text: Applet.weatherIcon || "☀" + font.pixelSize: 32 + color: "white" + } + + Text { + Layout.alignment: Qt.AlignHCenter + text: Applet.temperature + "°C" + font.pixelSize: 16 + font.bold: true + color: "white" + } + + Text { + Layout.alignment: Qt.AlignHCenter + text: Applet.currentCity || qsTr("Loading...") + font.pixelSize: 11 + color: Qt.rgba(1, 1, 1, 0.7) + } + } + + MouseArea { + anchors.fill: parent + onClicked: { + if (popup.visible) { + popup.close() + } else { + popup.open() + } + } + } + } + + PanelPopup { + id: popup + x: -50 + y: -320 + width: 300 + height: 300 + + WeatherDetail { + anchors.fill: parent + } + } + + PanelToolTip { + id: toolTip + text: Applet.currentCity + " " + Applet.weatherDesc + " " + Applet.temperature + "°C" + visible: false + } + + Component.onCompleted: { + Applet.refresh() + } +} diff --git a/applets/dde-weather/package/metadata.json b/applets/dde-weather/package/metadata.json new file mode 100644 index 000000000..cd3887733 --- /dev/null +++ b/applets/dde-weather/package/metadata.json @@ -0,0 +1,8 @@ +{ + "Plugin": { + "Version": "1.0", + "Id": "org.deepin.ds.weather", + "Url": "main.qml", + "Category": "DDE" + } +} diff --git a/applets/dde-weather/translations/org.deepin.ds.weather.ts b/applets/dde-weather/translations/org.deepin.ds.weather.ts new file mode 100644 index 000000000..85e0d3992 --- /dev/null +++ b/applets/dde-weather/translations/org.deepin.ds.weather.ts @@ -0,0 +1,3 @@ + + + diff --git a/applets/dde-weather/translations/org.deepin.ds.weather_ar.ts b/applets/dde-weather/translations/org.deepin.ds.weather_ar.ts new file mode 100644 index 000000000..85e0d3992 --- /dev/null +++ b/applets/dde-weather/translations/org.deepin.ds.weather_ar.ts @@ -0,0 +1,3 @@ + + + diff --git a/applets/dde-weather/translations/org.deepin.ds.weather_az.ts b/applets/dde-weather/translations/org.deepin.ds.weather_az.ts new file mode 100644 index 000000000..85e0d3992 --- /dev/null +++ b/applets/dde-weather/translations/org.deepin.ds.weather_az.ts @@ -0,0 +1,3 @@ + + + diff --git a/applets/dde-weather/translations/org.deepin.ds.weather_bo.ts b/applets/dde-weather/translations/org.deepin.ds.weather_bo.ts new file mode 100644 index 000000000..85e0d3992 --- /dev/null +++ b/applets/dde-weather/translations/org.deepin.ds.weather_bo.ts @@ -0,0 +1,3 @@ + + + diff --git a/applets/dde-weather/translations/org.deepin.ds.weather_ca.ts b/applets/dde-weather/translations/org.deepin.ds.weather_ca.ts new file mode 100644 index 000000000..85e0d3992 --- /dev/null +++ b/applets/dde-weather/translations/org.deepin.ds.weather_ca.ts @@ -0,0 +1,3 @@ + + + diff --git a/applets/dde-weather/translations/org.deepin.ds.weather_de.ts b/applets/dde-weather/translations/org.deepin.ds.weather_de.ts new file mode 100644 index 000000000..85e0d3992 --- /dev/null +++ b/applets/dde-weather/translations/org.deepin.ds.weather_de.ts @@ -0,0 +1,3 @@ + + + diff --git a/applets/dde-weather/translations/org.deepin.ds.weather_es.ts b/applets/dde-weather/translations/org.deepin.ds.weather_es.ts new file mode 100644 index 000000000..85e0d3992 --- /dev/null +++ b/applets/dde-weather/translations/org.deepin.ds.weather_es.ts @@ -0,0 +1,3 @@ + + + diff --git a/applets/dde-weather/translations/org.deepin.ds.weather_fi.ts b/applets/dde-weather/translations/org.deepin.ds.weather_fi.ts new file mode 100644 index 000000000..85e0d3992 --- /dev/null +++ b/applets/dde-weather/translations/org.deepin.ds.weather_fi.ts @@ -0,0 +1,3 @@ + + + diff --git a/applets/dde-weather/translations/org.deepin.ds.weather_fr.ts b/applets/dde-weather/translations/org.deepin.ds.weather_fr.ts new file mode 100644 index 000000000..85e0d3992 --- /dev/null +++ b/applets/dde-weather/translations/org.deepin.ds.weather_fr.ts @@ -0,0 +1,3 @@ + + + diff --git a/applets/dde-weather/translations/org.deepin.ds.weather_hu.ts b/applets/dde-weather/translations/org.deepin.ds.weather_hu.ts new file mode 100644 index 000000000..85e0d3992 --- /dev/null +++ b/applets/dde-weather/translations/org.deepin.ds.weather_hu.ts @@ -0,0 +1,3 @@ + + + diff --git a/applets/dde-weather/translations/org.deepin.ds.weather_it.ts b/applets/dde-weather/translations/org.deepin.ds.weather_it.ts new file mode 100644 index 000000000..85e0d3992 --- /dev/null +++ b/applets/dde-weather/translations/org.deepin.ds.weather_it.ts @@ -0,0 +1,3 @@ + + + diff --git a/applets/dde-weather/translations/org.deepin.ds.weather_ja.ts b/applets/dde-weather/translations/org.deepin.ds.weather_ja.ts new file mode 100644 index 000000000..85e0d3992 --- /dev/null +++ b/applets/dde-weather/translations/org.deepin.ds.weather_ja.ts @@ -0,0 +1,3 @@ + + + diff --git a/applets/dde-weather/translations/org.deepin.ds.weather_ko.ts b/applets/dde-weather/translations/org.deepin.ds.weather_ko.ts new file mode 100644 index 000000000..85e0d3992 --- /dev/null +++ b/applets/dde-weather/translations/org.deepin.ds.weather_ko.ts @@ -0,0 +1,3 @@ + + + diff --git a/applets/dde-weather/translations/org.deepin.ds.weather_lo.ts b/applets/dde-weather/translations/org.deepin.ds.weather_lo.ts new file mode 100644 index 000000000..85e0d3992 --- /dev/null +++ b/applets/dde-weather/translations/org.deepin.ds.weather_lo.ts @@ -0,0 +1,3 @@ + + + diff --git a/applets/dde-weather/translations/org.deepin.ds.weather_nb_NO.ts b/applets/dde-weather/translations/org.deepin.ds.weather_nb_NO.ts new file mode 100644 index 000000000..85e0d3992 --- /dev/null +++ b/applets/dde-weather/translations/org.deepin.ds.weather_nb_NO.ts @@ -0,0 +1,3 @@ + + + diff --git a/applets/dde-weather/translations/org.deepin.ds.weather_pl.ts b/applets/dde-weather/translations/org.deepin.ds.weather_pl.ts new file mode 100644 index 000000000..85e0d3992 --- /dev/null +++ b/applets/dde-weather/translations/org.deepin.ds.weather_pl.ts @@ -0,0 +1,3 @@ + + + diff --git a/applets/dde-weather/translations/org.deepin.ds.weather_pt_BR.ts b/applets/dde-weather/translations/org.deepin.ds.weather_pt_BR.ts new file mode 100644 index 000000000..85e0d3992 --- /dev/null +++ b/applets/dde-weather/translations/org.deepin.ds.weather_pt_BR.ts @@ -0,0 +1,3 @@ + + + diff --git a/applets/dde-weather/translations/org.deepin.ds.weather_ru.ts b/applets/dde-weather/translations/org.deepin.ds.weather_ru.ts new file mode 100644 index 000000000..85e0d3992 --- /dev/null +++ b/applets/dde-weather/translations/org.deepin.ds.weather_ru.ts @@ -0,0 +1,3 @@ + + + diff --git a/applets/dde-weather/translations/org.deepin.ds.weather_sq.ts b/applets/dde-weather/translations/org.deepin.ds.weather_sq.ts new file mode 100644 index 000000000..85e0d3992 --- /dev/null +++ b/applets/dde-weather/translations/org.deepin.ds.weather_sq.ts @@ -0,0 +1,3 @@ + + + diff --git a/applets/dde-weather/translations/org.deepin.ds.weather_uk.ts b/applets/dde-weather/translations/org.deepin.ds.weather_uk.ts new file mode 100644 index 000000000..85e0d3992 --- /dev/null +++ b/applets/dde-weather/translations/org.deepin.ds.weather_uk.ts @@ -0,0 +1,3 @@ + + + diff --git a/applets/dde-weather/translations/org.deepin.ds.weather_zh_CN.ts b/applets/dde-weather/translations/org.deepin.ds.weather_zh_CN.ts new file mode 100644 index 000000000..85e0d3992 --- /dev/null +++ b/applets/dde-weather/translations/org.deepin.ds.weather_zh_CN.ts @@ -0,0 +1,3 @@ + + + diff --git a/applets/dde-weather/translations/org.deepin.ds.weather_zh_HK.ts b/applets/dde-weather/translations/org.deepin.ds.weather_zh_HK.ts new file mode 100644 index 000000000..85e0d3992 --- /dev/null +++ b/applets/dde-weather/translations/org.deepin.ds.weather_zh_HK.ts @@ -0,0 +1,3 @@ + + + diff --git a/applets/dde-weather/translations/org.deepin.ds.weather_zh_TW.ts b/applets/dde-weather/translations/org.deepin.ds.weather_zh_TW.ts new file mode 100644 index 000000000..85e0d3992 --- /dev/null +++ b/applets/dde-weather/translations/org.deepin.ds.weather_zh_TW.ts @@ -0,0 +1,3 @@ + + + diff --git a/applets/dde-weather/weatherapplet.cpp b/applets/dde-weather/weatherapplet.cpp new file mode 100644 index 000000000..a7cd49c35 --- /dev/null +++ b/applets/dde-weather/weatherapplet.cpp @@ -0,0 +1,94 @@ +// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "weatherapplet.h" +#include "weathermodel.h" +#include "weatherhelper.h" +#include "pluginfactory.h" + +#include + +WeatherApplet::WeatherApplet(QObject *parent) + : DApplet(parent) + , m_model(new WeatherModel(this)) + , m_helper(new WeatherHelper(this)) +{ + connect(m_helper, &WeatherHelper::weatherUpdated, this, [this](const QString &city, int temp, const QString &desc, const QString &icon) { + if (m_currentCity != city) { + m_currentCity = city; + Q_EMIT currentCityChanged(); + } + if (m_temperature != temp) { + m_temperature = temp; + Q_EMIT temperatureChanged(); + } + if (m_weatherDesc != desc) { + m_weatherDesc = desc; + Q_EMIT weatherDescChanged(); + } + if (m_weatherIcon != icon) { + m_weatherIcon = icon; + Q_EMIT weatherIconChanged(); + } + }); + + connect(m_helper, &WeatherHelper::forecastUpdated, m_model, &WeatherModel::updateData); +} + +WeatherApplet::~WeatherApplet() +{ +} + +bool WeatherApplet::load() +{ + DCORE_USE_NAMESPACE; + auto config = DConfig::create("org.deepin.dde.shell", "org.deepin.ds.weather"); + if (config) { + m_helper->setCity(config->value("city", "auto").toString()); + m_helper->setRefreshInterval(config->value("refreshInterval", 30).toInt()); + delete config; + } + return true; +} + +bool WeatherApplet::init() +{ + DApplet::init(); + m_helper->refresh(); + return true; +} + +WeatherModel *WeatherApplet::model() const +{ + return m_model; +} + +QString WeatherApplet::currentCity() const +{ + return m_currentCity; +} + +int WeatherApplet::temperature() const +{ + return m_temperature; +} + +QString WeatherApplet::weatherDesc() const +{ + return m_weatherDesc; +} + +QString WeatherApplet::weatherIcon() const +{ + return m_weatherIcon; +} + +void WeatherApplet::refresh() +{ + m_helper->refresh(); +} + +D_APPLET_CLASS(WeatherApplet) + +#include "weatherapplet.moc" diff --git a/applets/dde-weather/weatherapplet.h b/applets/dde-weather/weatherapplet.h new file mode 100644 index 000000000..b4eee6786 --- /dev/null +++ b/applets/dde-weather/weatherapplet.h @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "applet.h" +#include "dsglobal.h" +#include "weathermodel.h" + +DS_USE_NAMESPACE + +class WeatherHelper; + +class WeatherApplet : public DApplet +{ + Q_OBJECT + Q_PROPERTY(WeatherModel *model READ model CONSTANT FINAL) + Q_PROPERTY(QString currentCity READ currentCity NOTIFY currentCityChanged FINAL) + Q_PROPERTY(int temperature READ temperature NOTIFY temperatureChanged FINAL) + Q_PROPERTY(QString weatherDesc READ weatherDesc NOTIFY weatherDescChanged FINAL) + Q_PROPERTY(QString weatherIcon READ weatherIcon NOTIFY weatherIconChanged FINAL) + +public: + explicit WeatherApplet(QObject *parent = nullptr); + ~WeatherApplet(); + + bool load() override; + bool init() override; + + WeatherModel *model() const; + QString currentCity() const; + int temperature() const; + QString weatherDesc() const; + QString weatherIcon() const; + + Q_INVOKABLE void refresh(); + +Q_SIGNALS: + void currentCityChanged(); + void temperatureChanged(); + void weatherDescChanged(); + void weatherIconChanged(); + +private: + WeatherModel *m_model = nullptr; + WeatherHelper *m_helper = nullptr; + QString m_currentCity; + int m_temperature = 0; + QString m_weatherDesc; + QString m_weatherIcon; +}; diff --git a/applets/dde-weather/weatherhelper.cpp b/applets/dde-weather/weatherhelper.cpp new file mode 100644 index 000000000..c1ec90e3d --- /dev/null +++ b/applets/dde-weather/weatherhelper.cpp @@ -0,0 +1,117 @@ +// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "weatherhelper.h" + +#include +#include +#include +#include +#include + +static const char *WEATHER_API_URL = "https://api.openweathermap.org/data/2.5/weather"; +static const char *FORECAST_API_URL = "https://api.openweathermap.org/data/2.5/forecast"; + +WeatherHelper::WeatherHelper(QObject *parent) + : QObject(parent) + , m_nam(new QNetworkAccessManager(this)) + , m_timer(new QTimer(this)) +{ + connect(m_nam, &QNetworkAccessManager::finished, this, &WeatherHelper::onReplyFinished); + connect(m_timer, &QTimer::timeout, this, &WeatherHelper::refresh); +} + +void WeatherHelper::setCity(const QString &city) +{ + m_city = city; +} + +void WeatherHelper::setRefreshInterval(int minutes) +{ + m_refreshInterval = minutes; + m_timer->stop(); + if (minutes > 0) { + m_timer->start(minutes * 60 * 1000); + } +} + +void WeatherHelper::refresh() +{ + if (m_city == "auto" || m_city.isEmpty()) { + updateWithMockData(); + return; + } + + QUrl url(WEATHER_API_URL); + QUrlQuery query; + query.addQueryItem("q", m_city); + query.addQueryItem("appid", "demo"); + query.addQueryItem("units", "metric"); + query.addQueryItem("lang", "zh_cn"); + url.setQuery(query); + + QNetworkRequest request(url); + m_nam->get(request); +} + +void WeatherHelper::onReplyFinished(QNetworkReply *reply) +{ + if (reply->error() != QNetworkReply::NoError) { + updateWithMockData(); + reply->deleteLater(); + return; + } + + parseWeatherData(reply->readAll()); + reply->deleteLater(); +} + +void WeatherHelper::parseWeatherData(const QByteArray &data) +{ + QJsonDocument doc = QJsonDocument::fromJson(data); + if (!doc.isObject()) + return; + + QJsonObject obj = doc.object(); + + QString city = obj.value("name").toString(); + QJsonObject main = obj.value("main").toObject(); + int temp = static_cast(main.value("temp").toDouble()); + + QJsonArray weatherArray = obj.value("weather").toArray(); + QString desc; + QString icon; + if (!weatherArray.isEmpty()) { + QJsonObject weather = weatherArray.first().toObject(); + desc = weather.value("description").toString(); + icon = weatherCodeToIcon(weather.value("icon").toString()); + } + + Q_EMIT weatherUpdated(city, temp, desc, icon); +} + +void WeatherHelper::updateWithMockData() +{ + Q_EMIT weatherUpdated(tr("Demo City"), 26, tr("Partly cloudy"), "⛅"); + + QList forecast; + forecast.append({ tr("Demo City"), 26, tr("Partly cloudy"), "⛅" }); + forecast.append({ tr("Demo City"), 24, tr("Light rain"), "🌧" }); + forecast.append({ tr("Demo City"), 28, tr("Sunny"), "☀" }); + forecast.append({ tr("Demo City"), 22, tr("Overcast"), "☁" }); + forecast.append({ tr("Demo City"), 25, tr("Clear"), "🌙" }); + Q_EMIT forecastUpdated(forecast); +} + +QString WeatherHelper::weatherCodeToIcon(const QString &code) const +{ + if (code.startsWith("01")) return "☀"; + if (code.startsWith("02")) return "⛅"; + if (code.startsWith("03") || code.startsWith("04")) return "☁"; + if (code.startsWith("09") || code.startsWith("10")) return "🌧"; + if (code.startsWith("11")) return "⛈"; + if (code.startsWith("13")) return "❄"; + if (code.startsWith("50")) return "🌫"; + return "☀"; +} diff --git a/applets/dde-weather/weatherhelper.h b/applets/dde-weather/weatherhelper.h new file mode 100644 index 000000000..74652a94a --- /dev/null +++ b/applets/dde-weather/weatherhelper.h @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "weathermodel.h" + +#include +#include +#include + +class WeatherHelper : public QObject +{ + Q_OBJECT + +public: + explicit WeatherHelper(QObject *parent = nullptr); + + void setCity(const QString &city); + void setRefreshInterval(int minutes); + void refresh(); + +Q_SIGNALS: + void weatherUpdated(const QString &city, int temperature, const QString &description, const QString &icon); + void forecastUpdated(const QList &forecast); + +private Q_SLOTS: + void onReplyFinished(QNetworkReply *reply); + +private: + void parseWeatherData(const QByteArray &data); + void updateWithMockData(); + QString weatherCodeToIcon(const QString &code) const; + + QNetworkAccessManager *m_nam = nullptr; + QTimer *m_timer = nullptr; + QString m_city = "auto"; + int m_refreshInterval = 30; +}; diff --git a/applets/dde-weather/weathermodel.cpp b/applets/dde-weather/weathermodel.cpp new file mode 100644 index 000000000..8bedf7ff2 --- /dev/null +++ b/applets/dde-weather/weathermodel.cpp @@ -0,0 +1,61 @@ +// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "weathermodel.h" + +WeatherModel::WeatherModel(QObject *parent) + : QAbstractListModel(parent) +{ +} + +int WeatherModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return 0; + return m_data.count(); +} + +QVariant WeatherModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || index.row() >= m_data.count()) + return {}; + + const auto &item = m_data.at(index.row()); + switch (role) { + case CityRole: + return item.city; + case TemperatureRole: + return item.temperature; + case DescriptionRole: + return item.description; + case IconRole: + return item.icon; + default: + return {}; + } +} + +QHash WeatherModel::roleNames() const +{ + return { + { CityRole, "city" }, + { TemperatureRole, "temperature" }, + { DescriptionRole, "description" }, + { IconRole, "icon" }, + }; +} + +void WeatherModel::updateData(const QList &data) +{ + beginResetModel(); + m_data = data; + endResetModel(); +} + +void WeatherModel::clear() +{ + beginResetModel(); + m_data.clear(); + endResetModel(); +} diff --git a/applets/dde-weather/weathermodel.h b/applets/dde-weather/weathermodel.h new file mode 100644 index 000000000..1d44d4ab2 --- /dev/null +++ b/applets/dde-weather/weathermodel.h @@ -0,0 +1,39 @@ +// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include + +struct WeatherData { + QString city; + int temperature = 0; + QString description; + QString icon; +}; + +class WeatherModel : public QAbstractListModel +{ + Q_OBJECT + +public: + enum Roles { + CityRole = Qt::UserRole + 1, + TemperatureRole, + DescriptionRole, + IconRole, + }; + + explicit WeatherModel(QObject *parent = nullptr); + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QHash roleNames() const override; + + void updateData(const QList &data); + void clear(); + +private: + QList m_data; +}; diff --git a/panels/dock/taskmanager/package/TaskManager.qml b/panels/dock/taskmanager/package/TaskManager.qml index e143b060e..64c137821 100644 --- a/panels/dock/taskmanager/package/TaskManager.qml +++ b/panels/dock/taskmanager/package/TaskManager.qml @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2023-2026 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2023 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later