Commit f7afdaa4 authored by Han Young's avatar Han Young
Browse files

add detailed mode and delete LocationModel

parent ea900547
Pipeline #68391 failed with stage
in 22 seconds
......@@ -9,7 +9,6 @@ add_definitions(-DTRANSLATION_DOMAIN=\"plasma_applet_org.kde.plasma.kweather_1x4
set(kweather_1x4_SRCS
kweather_1x4.cpp
locationmodel.cpp
hourlymodel.cpp
)
add_library(plasma_applet_kweather_1x4 MODULE ${kweather_1x4_SRCS})
......
......@@ -38,11 +38,10 @@ QHash<int, QByteArray> HourlyModel::roleNames() const
return {{Time, "time"}, {Icon, "weatherIcon"}, {Description, "description"},
{Temperature, "temperature"}, {Precipitation, "precipitation"}};
}
void HourlyModel::loadForecast(QExplicitlySharedDataPointer<KWeatherCore::WeatherForecast> forecast, int index)
void HourlyModel::loadForecast(QExplicitlySharedDataPointer<KWeatherCore::WeatherForecast> forecast)
{
beginResetModel();
m_location = forecast;
m_index = index;
endResetModel();
Q_EMIT reseted();
}
......@@ -63,10 +62,6 @@ const KWeatherCore::HourlyWeatherForecast &HourlyModel::getNthHour(int index) co
return m_location->dailyWeatherForecast().at(dayIndex).hourlyWeatherForecast().at(hourIndex);
}
const QString &HourlyModel::location() const
{
return m_locationModel->getLocation(m_index);
}
const QString &HourlyModel::currentIcon() const
{
return getNthHour(0).weatherIcon();
......
......@@ -7,11 +7,9 @@
#include <QAbstractListModel>
#include <KWeatherCore/WeatherForecast>
class LocationModel;
class HourlyModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(QString location READ location NOTIFY reseted)
Q_PROPERTY(QString currentIcon READ currentIcon NOTIFY reseted)
Q_PROPERTY(QString currentTemperature READ currentTemperature NOTIFY reseted)
Q_PROPERTY(QString currentDescription READ currentDescription NOTIFY reseted)
......@@ -20,24 +18,17 @@ public:
virtual QVariant data(const QModelIndex &index, int role) const override;
virtual int rowCount(const QModelIndex &index) const override;
virtual QHash<int, QByteArray> roleNames() const override;
void loadForecast(QExplicitlySharedDataPointer<KWeatherCore::WeatherForecast>, int);
const QString &location() const;
const QString &currentIcon() const;
QString currentTemperature() const;
const QString &currentDescription() const;
Q_INVOKABLE void openKWeather();
public Q_SLOTS:
void loadForecast(QExplicitlySharedDataPointer<KWeatherCore::WeatherForecast>);
Q_SIGNALS:
void reseted();
protected:
friend class KWeather_1x4;
void setLocationModel(LocationModel *locationModel) {
m_locationModel = locationModel;
}
private:
const KWeatherCore::HourlyWeatherForecast &getNthHour(int index) const;
QExplicitlySharedDataPointer<KWeatherCore::WeatherForecast> m_location;
LocationModel *m_locationModel;
int m_index = 0;
};
#endif // HOURLYNMODEL_H
......@@ -2,14 +2,17 @@
SPDX-FileCopyrightText: 2020 HanY <hanyoung@protonmail.com>
SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include <QQmlApplicationEngine>
#include "kweather_1x4.h"
#include "kweathersettings.h"
#include "hourlymodel.h"
#include <KWeatherCore/WeatherForecastSource>
#include <KSharedConfig>
KWeather_1x4::KWeather_1x4(QObject *parent, const QVariantList &args)
: Plasma::Applet(parent, args)
, m_hourlyModel(new HourlyModel())
{
qmlRegisterAnonymousType<HourlyModel>("HourlyModel", 1);
auto config = KSharedConfig::openConfig(QStringLiteral("kweather/plasmoid"));
auto group = config->group("general");
QString locationID = group.readEntry("locationID");
......@@ -30,11 +33,13 @@ void KWeather_1x4::update()
if (pendingForecast->isFinished()) {
m_forecast = pendingForecast->value();
pendingForecast->deleteLater();
m_hourlyModel->loadForecast(m_forecast);
Q_EMIT updated();
} else {
connect(pendingForecast, &KWeatherCore::PendingWeatherForecast::finished, [this, pendingForecast] {
m_forecast = pendingForecast->value();
pendingForecast->deleteLater();
m_hourlyModel->loadForecast(m_forecast);
Q_EMIT updated();
});
}
......@@ -65,6 +70,7 @@ void KWeather_1x4::setLocation(const QString &location)
update();
m_needLocation = false;
Q_EMIT needLocationChanged();
Q_EMIT locationChanged();
group.sync();
break;
......
......@@ -7,6 +7,7 @@
#define KWEATHER_1X4_H
#include <KWeatherCore/WeatherForecast>
#include <Plasma/Applet>
class HourlyModel;
class KWeather_1x4 : public Plasma::Applet
{
Q_OBJECT
......@@ -17,6 +18,7 @@ class KWeather_1x4 : public Plasma::Applet
Q_PROPERTY(QString weatherIcon READ weatherIcon NOTIFY updated)
Q_PROPERTY(qreal humidity READ humidity NOTIFY updated)
Q_PROPERTY(qreal precipitation READ precipitation NOTIFY updated)
Q_PROPERTY(HourlyModel* hourlyModel READ hourlyModel NOTIFY hourlyModelChanged)
public:
KWeather_1x4(QObject *parent, const QVariantList &args);
QString location() const;
......@@ -28,6 +30,9 @@ public:
bool needLocation() const {
return m_needLocation;
}
HourlyModel *hourlyModel() const {
return m_hourlyModel;
}
Q_INVOKABLE QStringList locationsInSystem();
Q_INVOKABLE void setLocation(const QString &location);
......@@ -35,6 +40,7 @@ signals:
void locationChanged();
void updated();
void needLocationChanged();
void hourlyModelChanged();
private:
void update();
bool hasForecast() const;
......@@ -44,6 +50,8 @@ private:
QString m_location;
double m_latitude, m_longitude;
QExplicitlySharedDataPointer<KWeatherCore::WeatherForecast> m_forecast;
HourlyModel *m_hourlyModel;
};
#endif
/*
SPDX-FileCopyrightText: 2021 HanYoung <hanyoung@protonmail.com>
SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include <KSharedConfig>
#include <KConfigGroup>
#include <KWeatherCore/WeatherForecastSource>
#include <QTimer>
#include <QLocale>
#include "kweathersettings.h"
#include "locationmodel.h"
const QString WEATHER_LOCATIONS_CFG_GROUP = QStringLiteral("WeatherLocations");
class LocationModel::Location : public QObject
{
Q_OBJECT
public:
Location(QObject *parent = nullptr)
: QObject(parent)
{}
QString name;
double latitude, longitude;
int index = 0;
QExplicitlySharedDataPointer<KWeatherCore::WeatherForecast> forecast;
void update(QExplicitlySharedDataPointer<KWeatherCore::WeatherForecast> forecast) {
this->forecast = forecast;
}
KWeatherCore::PendingWeatherForecast *reply = nullptr;
Q_SIGNALS:
void updated(int index);
public Q_SLOT:
void updateFromConnection() {
if (reply) {
update(reply->value());
reply->deleteLater();
Q_EMIT updated(index);
}
}
};
LocationModel::LocationModel()
: m_timer(new QTimer(this))
{
// load locations from kconfig
auto config = KWeatherSettings().config()->group(WEATHER_LOCATIONS_CFG_GROUP);
auto i {0};
for (const auto &location : config.groupList()) {
auto locationSubGroup = config.group(location);
if (locationSubGroup.isValid()) {
auto locationFromConfig = new Location(this);
locationFromConfig->name = locationSubGroup.readEntry("locationName");
locationFromConfig->latitude = locationSubGroup.readEntry("latitude").toDouble();
locationFromConfig->longitude = locationSubGroup.readEntry("longitude").toDouble();
m_locations.push_back(locationFromConfig);
connect(locationFromConfig, &LocationModel::Location::updated, this,
[this](int index){
Q_EMIT dataChanged(this->index(index), this->index(index));});
locationFromConfig->index = i;
i++;
}
}
connect(m_timer, &QTimer::timeout, this, &LocationModel::update);
m_timer->setInterval(1000 * 60 * 60); // one hour
m_timer->start();
update();
}
void LocationModel::update()
{
KWeatherCore::WeatherForecastSource source;
auto index {0};
for (auto location : m_locations) {
auto reply = source.requestData(location->latitude, location->longitude);
if (reply->isFinished()) {
beginResetModel();
location->update(reply->value());
endResetModel();
reply->deleteLater();
Q_EMIT dataChanged(this->index(location->index), this->index(location->index));
} else {
qDebug() << "unfinished";
location->reply = reply;
connect(reply, &KWeatherCore::PendingWeatherForecast::finished, location, &LocationModel::Location::updateFromConnection);
}
index++;
}
}
QHash<int, QByteArray> LocationModel::roleNames() const
{
static QHash<int, QByteArray> hash = {{LocationName, "locationName"}, {Temperature, "temperature"}, {Icon, "icon"}, {Description, "description"}, {Precipitation, "precipitation"}, {Humidity, "humidity"}, {Date, "date"}};
return hash;
}
QVariant LocationModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() < 0 || index.row() > (int)m_locations.size())
return {};
auto row = index.row();
KWeatherCore::HourlyWeatherForecast const *currentWeather = nullptr;
if (m_locations.at(row)->forecast && !m_locations.at(row)->forecast->dailyWeatherForecast().empty()) {
const auto &daily = m_locations.at(row)->forecast->dailyWeatherForecast();
if (!daily.front().hourlyWeatherForecast().empty()) {
currentWeather = &daily.front().hourlyWeatherForecast().front();
}
}
if (!currentWeather) {
return {};
}
switch (role) {
case LocationName:
return m_locations.at(row)->name;
case Temperature:
return currentWeather->temperature();
case Icon:
return currentWeather->weatherIcon();
case Description:
return currentWeather->weatherDescription();
case Precipitation:
return currentWeather->precipitationAmount();
case Humidity:
return currentWeather->humidity();
case Date:
return QLocale::system().toString(currentWeather->date().date(), QStringLiteral("ddd, dd"));
default:
return QVariant();
}
}
int LocationModel::rowCount(const QModelIndex &index) const
{
Q_UNUSED(index)
return m_locations.size();
}
QExplicitlySharedDataPointer<KWeatherCore::WeatherForecast> LocationModel::getData(int index) const
{
if (index >= 0 && index < (int)m_locations.size())
return m_locations.at(index)->forecast;
else
return {};
}
const QString &LocationModel::getLocation(int index) const
{
return m_locations.at(index)->name;
}
Q_DECLARE_INTERFACE(LocationModel, "org.kde.LocationModel")
#include "locationmodel.moc"
/*
SPDX-FileCopyrightText: 2021 HanYoung <hanyoung@protonmail.com>
SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef LOCATIONMODEL_H
#define LOCATIONMODEL_H
#include <QAbstractListModel>
#include <KWeatherCore/WeatherForecast>
class QTimer;
class LocationModel : public QAbstractListModel
{
Q_OBJECT
public:
enum LocationRole {LocationName = Qt::UserRole + 1, Temperature, Icon, Description, Precipitation, Humidity, Date};
LocationModel();
virtual QVariant data(const QModelIndex &index, int role) const override;
virtual int rowCount(const QModelIndex &index) const override;
virtual QHash<int, QByteArray> roleNames() const override;
const QString &getLocation(int index) const;
private Q_SLOTS:
void update();
protected:
friend class KWeather_1x4;
QExplicitlySharedDataPointer<KWeatherCore::WeatherForecast> getData(int index) const;
private:
class Location;
QTimer *m_timer = nullptr;
std::vector<Location *> m_locations;
};
#endif // LOCATIONMODEL_H
......@@ -4,6 +4,7 @@ import QtQuick.Controls 2.4
import org.kde.plasma.plasmoid 2.0
import org.kde.kirigami 2.11 as Kirigami
Rectangle {
signal selected()
id: container
Layout.preferredWidth: Kirigami.Units.gridUnit * 12
Layout.preferredHeight: Kirigami.Units.gridUnit * 12
......@@ -16,7 +17,10 @@ Rectangle {
model: plasmoid.nativeInterface.locationsInSystem()
delegate: Kirigami.BasicListItem {
text: modelData
onClicked: plasmoid.nativeInterface.setLocation(modelData)
onClicked: {
selected()
plasmoid.nativeInterface.setLocation(modelData)
}
}
Label {
anchors.bottom: parent.bottom
......
......@@ -10,6 +10,11 @@ Rectangle {
color: Kirigami.Theme.backgroundColor
radius: 8
MouseArea {
anchors.fill: parent
onDoubleClicked: window.showMaximized()
}
ColumnLayout {
anchors.fill: parent
RowLayout {
......@@ -64,4 +69,102 @@ Rectangle {
}
}
}
Kirigami.AbstractApplicationWindow {
id: window
visible: false
flags: Qt.FramelessWindowHint
modality: Qt.WindowModal
color: "transparent"
MouseArea {
anchors.fill: parent
onClicked: window.close()
}
// TODO: content here
Loader {
active: window.active
anchors.fill: parent
sourceComponent: Item {
id: detailedItem
anchors.fill: parent
Rectangle {
width: Kirigami.Units.gridUnit * 21
height: Kirigami.Units.gridUnit * 22
radius: Kirigami.Units.gridUnit
anchors.centerIn: parent
RowLayout {
anchors.fill: parent
RowLayout {
Layout.alignment: Qt.AlignHCenter
ColumnLayout {
Label {
Layout.alignment: Qt.AlignHCenter
font.pointSize: Kirigami.Theme.defaultFont.pointSize * 2
font.weight: Font.Light
text: plasmoid.nativeInterface.location
}
Kirigami.Icon {
source: plasmoid.nativeInterface.hourlyModel.currentIcon
Layout.preferredHeight: width
Layout.preferredWidth: detailedItem.width * 0.8 - headerText.width
Layout.maximumHeight: Kirigami.Theme.defaultFont.pointSize * 15
Layout.maximumWidth: Kirigami.Theme.defaultFont.pointSize * 15
Layout.minimumHeight: Kirigami.Theme.defaultFont.pointSize * 5
Layout.minimumWidth: Kirigami.Theme.defaultFont.pointSize * 5
smooth: true
}
Button {
Layout.alignment: Qt.AlignHCenter
text: i18n("Select Location")
onClicked: locationSelectDialog.open()
}
Button {
Layout.alignment: Qt.AlignHCenter
text: i18n("Open KWeather")
onClicked: plasmoid.nativeInterface.hourlyModel.openKWeather()
}
}
// weather header
ColumnLayout {
id: headerText
Label {
font.pointSize: Kirigami.Theme.defaultFont.pointSize * 3
font.weight: Font.Light
text: plasmoid.nativeInterface.hourlyModel.currentTemperature + "°"
}
Label {
font.pointSize: Kirigami.Theme.defaultFont.pointSize * 1.3
font.weight: Font.Bold
text: plasmoid.nativeInterface.hourlyModel.currentDescription
}
}
}
ListView {
Layout.preferredHeight: Kirigami.Units.gridUnit * 16
Layout.fillWidth: true
model: plasmoid.nativeInterface.hourlyModel
delegate: Kirigami.BasicListItem {
label: time
subtitle: temperature + "°"
icon: weatherIcon
}
}
}
}
Dialog {
id: locationSelectDialog
standardButtons: Dialog.Close
title: i18n("Select Location")
anchors.centerIn: parent
width: Kirigami.Units.gridUnit * 12
height: Kirigami.Units.gridUnit * 12
LocationSelector {
anchors.fill: parent
onSelected: locationSelectDialog.close()
}
}
}
}
}
}
......@@ -14,88 +14,4 @@ Item {
active: true
source: plasmoid.nativeInterface.needLocation ? "LocationSelector.qml" : "WeatherContainer.qml"
}
/*
Kirigami.AbstractApplicationWindow {
id: window
visible: false
flags: Qt.FramelessWindowHint
modality: Qt.WindowModal
color: "transparent"
MouseArea {
anchors.fill: parent
onClicked: window.close()
}
// TODO: content here
Loader {
active: window.visible
anchors.fill: parent
sourceComponent: Item {
id: detailedItem
anchors.fill: parent
Rectangle {
width: Kirigami.Units.gridUnit * 20
height: Kirigami.Units.gridUnit * 21
radius: Kirigami.Units.gridUnit
anchors.centerIn: parent
RowLayout {
anchors.fill: parent
RowLayout {
Layout.alignment: Qt.AlignHCenter
ColumnLayout {
Label {
Layout.alignment: Qt.AlignHCenter
font.pointSize: Kirigami.Theme.defaultFont.pointSize * 2
font.weight: Font.Light
text: plasmoid.nativeInterface.hourlyModel.location
}
Kirigami.Icon {
source: plasmoid.nativeInterface.hourlyModel.currentIcon
Layout.preferredHeight: width
Layout.preferredWidth: detailedItem.width * 0.8 - headerText.width
Layout.maximumHeight: Kirigami.Theme.defaultFont.pointSize * 15
Layout.maximumWidth: Kirigami.Theme.defaultFont.pointSize * 15
Layout.minimumHeight: Kirigami.Theme.defaultFont.pointSize * 5
Layout.minimumWidth: Kirigami.Theme.defaultFont.pointSize * 5
smooth: true
}
Button {
Layout.alignment: Qt.AlignHCenter
text: i18n("Open KWeather")
onClicked: plasmoid.nativeInterface.hourlyModel.openKWeather()
}
}
// weather header
ColumnLayout {
id: headerText
Label {
font.pointSize: Kirigami.Theme.defaultFont.pointSize * 3
font.weight: Font.Light
text: plasmoid.nativeInterface.hourlyModel.currentTemperature + "°"
}
Label {
font.pointSize: Kirigami.Theme.defaultFont.pointSize * 1.3
font.weight: Font.Bold
text: plasmoid.nativeInterface.hourlyModel.currentDescription
}
}
}
ListView {
Layout.preferredHeight: Kirigami.Units.gridUnit * 16
Layout.preferredWidth: Kirigami.Units.gridUnit * 5
model: plasmoid.nativeInterface.hourlyModel
delegate: Kirigami.BasicListItem {
label: time
subtitle: temperature + "°"
icon: weatherIcon
//backgroundColor: Kirigami.Theme.backgroundColor
}
}
}
}
}
}
}
*/
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment