File indexing completed on 2024-05-19 05:55:49
0001 /* 0002 * SPDX-FileCopyrightText: 2020 Han Young <hanyoung@protonmail.com> 0003 * SPDX-FileCopyrightText: 2020 Devin Lin <espidev@gmail.com> 0004 * SPDX-FileCopyrightText: 2021 Nicolas Fella <nicolas.fella@gmx.de> 0005 * 0006 * SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "weatherlocation.h" 0010 0011 #include <QDir> 0012 #include <QFile> 0013 #include <QJsonArray> 0014 #include <QQmlEngine> 0015 #include <QTimeZone> 0016 #include <QTimer> 0017 0018 #include <utility> 0019 0020 #include "global.h" 0021 #include "kweathersettings.h" 0022 #include "locationquerymodel.h" 0023 0024 WeatherLocation::WeatherLocation(QString locationId, 0025 QString locationName, 0026 QString timeZone, 0027 float latitude, 0028 float longitude, 0029 KWeatherCore::WeatherForecast forecast) 0030 : m_forecast(forecast) 0031 , m_locationName(std::move(locationName)) 0032 , m_locationId(std::move(locationId)) 0033 , m_timeZone(std::move(timeZone)) 0034 , m_latitude(latitude) 0035 , m_longitude(longitude) 0036 { 0037 this->m_timer = new QTimer(this); 0038 connect(m_timer, &QTimer::timeout, this, &WeatherLocation::updateCurrentDateTime); 0039 this->m_timer->start(60 - QDateTime::currentDateTime().currentMSecsSinceEpoch() % 60); 0040 0041 m_lastUpdated = forecast.createdTime(); 0042 Q_EMIT lastUpdatedChanged(); 0043 0044 update(); 0045 0046 determineCurrentForecast(); 0047 0048 connect(this, &WeatherLocation::selectedDayChanged, this, [this] { 0049 m_hourForecasts.clear(); 0050 if (!m_forecast.dailyWeatherForecast().empty()) { 0051 const auto hourForecasts = m_forecast.dailyWeatherForecast()[m_selectedDay].hourlyWeatherForecast(); 0052 for (const KWeatherCore::HourlyWeatherForecast &hour : hourForecasts) { 0053 m_hourForecasts << QVariant::fromValue(hour); 0054 } 0055 } 0056 Q_EMIT hourForecastsChanged(); 0057 }); 0058 } 0059 0060 WeatherLocation::WeatherLocation() 0061 { 0062 } 0063 0064 WeatherLocation *WeatherLocation::load(const QString &groupName) 0065 { 0066 auto config = KWeatherSettings::self()->config()->group(KWeather::WEATHER_LOCATIONS_CFG_GROUP).group(groupName); 0067 if (config.isValid()) { 0068 return new WeatherLocation(groupName, 0069 config.readEntry("locationName"), 0070 config.readEntry("timezone"), 0071 config.readEntry("latitude").toFloat(), 0072 config.readEntry("longitude").toFloat()); 0073 } else { 0074 return nullptr; 0075 } 0076 } 0077 0078 void WeatherLocation::save() 0079 { 0080 auto config = KWeatherSettings::self()->config()->group(KWeather::WEATHER_LOCATIONS_CFG_GROUP).group(locationId()); 0081 config.writeEntry("locationName", locationName()); 0082 config.writeEntry("latitude", latitude()); 0083 config.writeEntry("longitude", longitude()); 0084 config.writeEntry("timezone", m_timeZone); 0085 config.sync(); 0086 } 0087 0088 void WeatherLocation::saveOrder(int index) 0089 { 0090 auto config = KWeatherSettings::self()->config()->group(KWeather::WEATHER_LOCATIONS_CFG_GROUP).group(locationId()); 0091 config.writeEntry("index", index); 0092 config.sync(); 0093 } 0094 0095 int WeatherLocation::index() 0096 { 0097 auto config = KWeatherSettings::self()->config()->group(KWeather::WEATHER_LOCATIONS_CFG_GROUP).group(locationId()); 0098 auto res = config.readEntry("index"); 0099 if (res.isEmpty()) { 0100 return -1; 0101 } else { 0102 return res.toInt(); 0103 } 0104 } 0105 0106 void WeatherLocation::deleteConfig() 0107 { 0108 auto config = KWeatherSettings::self()->config()->group(KWeather::WEATHER_LOCATIONS_CFG_GROUP); 0109 config.deleteGroup(locationId()); 0110 config.sync(); 0111 } 0112 0113 const QString &WeatherLocation::locationId() const 0114 { 0115 return m_locationId; 0116 } 0117 0118 const QString &WeatherLocation::locationName() const 0119 { 0120 return m_locationName; 0121 } 0122 0123 const QString &WeatherLocation::timeZone() const 0124 { 0125 return m_timeZone; 0126 } 0127 0128 float WeatherLocation::latitude() const 0129 { 0130 return m_latitude; 0131 } 0132 0133 float WeatherLocation::longitude() const 0134 { 0135 return m_longitude; 0136 } 0137 0138 QString WeatherLocation::lastUpdatedFormatted() const 0139 { 0140 return QLocale().toString(lastUpdated().time(), QLocale::ShortFormat).toLower(); 0141 } 0142 0143 const QDateTime &WeatherLocation::lastUpdated() const 0144 { 0145 return m_lastUpdated; 0146 } 0147 0148 QString WeatherLocation::currentTimeFormatted() const 0149 { 0150 return QLocale().toString(currentDateTime().time(), QLocale::ShortFormat).toLower(); 0151 } 0152 0153 QString WeatherLocation::currentDateFormatted() const 0154 { 0155 return QLocale().toString(currentDateTime().toLocalTime().date(), QLocale::LongFormat); 0156 } 0157 0158 QDateTime WeatherLocation::currentDateTime() const 0159 { 0160 return QDateTime::currentDateTime().toTimeZone(QTimeZone(m_timeZone.toUtf8())); 0161 } 0162 0163 const QString &WeatherLocation::backgroundComponent() const 0164 { 0165 return m_backgroundComponent; 0166 } 0167 0168 const QColor &WeatherLocation::backgroundColor() const 0169 { 0170 return m_backgroundColor; 0171 } 0172 0173 const QColor &WeatherLocation::textColor() const 0174 { 0175 return m_textColor; 0176 } 0177 0178 const QColor &WeatherLocation::cardBackgroundColor() const 0179 { 0180 return m_cardBackgroundColor; 0181 } 0182 0183 const QColor &WeatherLocation::cardTextColor() const 0184 { 0185 return m_cardTextColor; 0186 } 0187 0188 const QColor &WeatherLocation::cardSecondaryTextColor() const 0189 { 0190 return m_cardSecondaryTextColor; 0191 } 0192 0193 const QColor &WeatherLocation::iconColor() const 0194 { 0195 return m_iconColor; 0196 } 0197 0198 bool WeatherLocation::darkTheme() const 0199 { 0200 return m_isDarkTheme; 0201 } 0202 0203 QVariantList WeatherLocation::dayForecasts() const 0204 { 0205 return m_dayForecasts; 0206 } 0207 0208 QVariantList WeatherLocation::hourForecasts() const 0209 { 0210 return m_hourForecasts; 0211 } 0212 0213 int WeatherLocation::selectedDay() const 0214 { 0215 return m_selectedDay; 0216 } 0217 0218 void WeatherLocation::setSelectedDay(int selectedDay) 0219 { 0220 if (selectedDay != m_selectedDay) { 0221 m_selectedDay = selectedDay; 0222 Q_EMIT selectedDayChanged(); 0223 } 0224 } 0225 0226 QVariant WeatherLocation::currentHourForecast() 0227 { 0228 if (!m_forecast.dailyWeatherForecast().empty() && !m_forecast.dailyWeatherForecast()[0].hourlyWeatherForecast().empty()) { 0229 return QVariant::fromValue(m_forecast.dailyWeatherForecast().begin()->hourlyWeatherForecast()[0]); 0230 } 0231 return {}; 0232 } 0233 0234 void WeatherLocation::updateData(KWeatherCore::WeatherForecast forecasts) 0235 { 0236 m_forecast = forecasts; 0237 0238 // first time the timezone is empty 0239 if (m_timeZone.isEmpty()) { 0240 m_timeZone = forecasts.timezone(); 0241 Q_EMIT timeZoneChanged(); 0242 save(); 0243 } 0244 0245 determineCurrentForecast(); 0246 m_lastUpdated = forecasts.createdTime(); 0247 Q_EMIT lastUpdatedChanged(); 0248 0249 m_hourForecasts.clear(); 0250 if (!m_forecast.dailyWeatherForecast().empty() && m_forecast.dailyWeatherForecast().size() > m_selectedDay) { 0251 const auto hourForecasts = m_forecast.dailyWeatherForecast()[m_selectedDay].hourlyWeatherForecast(); 0252 for (const KWeatherCore::HourlyWeatherForecast &hour : hourForecasts) { 0253 m_hourForecasts << QVariant::fromValue(hour); 0254 } 0255 } 0256 Q_EMIT hourForecastsChanged(); 0257 0258 m_dayForecasts.clear(); 0259 for (const KWeatherCore::DailyWeatherForecast &day : m_forecast.dailyWeatherForecast()) { 0260 m_dayForecasts << QVariant::fromValue(day); 0261 } 0262 Q_EMIT dayForecastsChanged(); 0263 0264 Q_EMIT weatherRefresh(m_forecast); 0265 Q_EMIT stopLoadingIndicator(); 0266 0267 updateCurrentDateTime(); 0268 } 0269 0270 void WeatherLocation::determineCurrentForecast() 0271 { 0272 if (m_forecast.dailyWeatherForecast().empty()) 0273 return; 0274 0275 auto currentWeather = m_forecast.dailyWeatherForecast().begin()->hourlyWeatherForecast().begin(); 0276 m_backgroundComponent = QStringLiteral("qrc:/qt/qml/org/kde/kweather/backgrounds/qml/backgrounds/ClearDay.qml"); 0277 0278 bool isDayStyle = false; // make sure that if the background is definitively day, the colours match that 0279 m_sun = false; 0280 m_rain = false; 0281 m_cloud = false; 0282 m_snow = false; 0283 m_star = false; 0284 if (currentWeather->weatherIcon() == QStringLiteral("weather-clear")) { 0285 m_backgroundComponent = QStringLiteral("qrc:/qt/qml/org/kde/kweather/backgrounds/qml/backgrounds/ClearDay.qml"); 0286 isDayStyle = true; 0287 m_topColor = {255, 193, 7}; //"#ffc107" 0288 m_bottomColor = {255, 193, 7}; 0289 m_sun = true; 0290 } else if (currentWeather->weatherIcon() == QStringLiteral("weather-clear-night")) { 0291 m_backgroundComponent = QStringLiteral("qrc:/qt/qml/org/kde/kweather/backgrounds/qml/backgrounds/ClearNight.qml"); 0292 m_topColor = {69, 90, 100}; // "#455a64" 0293 m_bottomColor = {38, 50, 56}; // "#263238" 0294 m_star = true; 0295 } else if (currentWeather->weatherIcon() == QStringLiteral("weather-clouds")) { 0296 m_backgroundComponent = QStringLiteral("qrc:/qt/qml/org/kde/kweather/backgrounds/qml/backgrounds/CloudyDay.qml"); 0297 isDayStyle = true; 0298 m_topColor = {0, 188, 212}; // #00bcd4 0299 m_bottomColor = {36, 163, 222}; // #24a3de 0300 m_cloudColor = {224, 247, 250}; // #e0f7fa 0301 m_cloud = true; 0302 } else if (currentWeather->weatherIcon() == QStringLiteral("weather-clouds-night") || currentWeather->weatherIcon() == QStringLiteral("weather-overcast")) { 0303 m_backgroundComponent = QStringLiteral("qrc:/qt/qml/org/kde/kweather/backgrounds/qml/backgrounds/CloudyNight.qml"); 0304 m_topColor = {69, 90, 100}; // #455a64 0305 m_bottomColor = {38, 50, 56}; // #263238 0306 m_cloudColor = {176, 190, 197}; // #b0bec5 0307 m_star = true; 0308 m_cloud = true; 0309 } else if (currentWeather->weatherIcon() == QStringLiteral("weather-few-clouds")) { 0310 m_backgroundComponent = QStringLiteral("qrc:/qt/qml/org/kde/kweather/backgrounds/qml/backgrounds/PartlyCloudyDay.qml"); 0311 isDayStyle = true; 0312 m_topColor = {0, 188, 212}; // #00bcd4 0313 m_bottomColor = {36, 163, 222}; // #24a3de 0314 m_cloudColor = {224, 247, 250}; // #e0f7fa 0315 m_cloud = true; 0316 } else if (currentWeather->weatherIcon() == QStringLiteral("weather-few-clouds-night")) { 0317 m_backgroundComponent = QStringLiteral("qrc:/qt/qml/org/kde/kweather/backgrounds/qml/backgrounds/PartlyCloudyNight.qml"); 0318 m_topColor = {69, 90, 100}; // "#455a64" 0319 m_bottomColor = {38, 50, 56}; // "#263238" 0320 m_cloudColor = {176, 190, 197}; // #b0bec5 0321 m_star = true; 0322 m_cloud = true; 0323 } else if (currentWeather->weatherIcon() == QStringLiteral("weather-fog") || currentWeather->weatherIcon() == QStringLiteral("weather-mist")) { 0324 m_backgroundComponent = QStringLiteral("qrc:/qt/qml/org/kde/kweather/backgrounds/qml/backgrounds/Misty.qml"); 0325 isDayStyle = true; 0326 m_topColor = {194, 197, 203}; // #c2c5cb 0327 m_bottomColor = {91, 96, 107}; // #5b606b 0328 m_cloudColor = {218, 224, 236}; // #dae0ec 0329 m_cloud = true; 0330 0331 } else if (currentWeather->weatherIcon() == QStringLiteral("weather-freezing-rain") || currentWeather->weatherIcon() == QStringLiteral("weather-snow-hail") 0332 || currentWeather->weatherIcon() == QStringLiteral("weather-showers") || currentWeather->weatherIcon() == QStringLiteral("weather-showers-day") 0333 || currentWeather->weatherIcon() == QStringLiteral("weather-showers-scattered") 0334 || currentWeather->weatherIcon() == QStringLiteral("weather-showers-scattered-day") 0335 || currentWeather->weatherIcon() == QStringLiteral("weather-storm") || currentWeather->weatherIcon() == QStringLiteral("weather-storm-day")) { 0336 m_backgroundComponent = QStringLiteral("qrc:/qt/qml/org/kde/kweather/backgrounds/qml/backgrounds/RainyDay.qml"); 0337 isDayStyle = true; 0338 m_topColor = {54, 156, 203}; // #369ccb 0339 m_bottomColor = {26, 131, 179}; // #1A83B3 0340 m_cloudColor = {255, 255, 255}; // white 0341 m_cloud = true; 0342 m_rain = true; 0343 } else if (currentWeather->weatherIcon() == QStringLiteral("weather-showers-night") 0344 || currentWeather->weatherIcon() == QStringLiteral("weather-showers-scattered-night") 0345 || currentWeather->weatherIcon() == QStringLiteral("weather-storm-night")) { 0346 m_backgroundComponent = QStringLiteral("qrc:/qt/qml/org/kde/kweather/backgrounds/qml/backgrounds/RainyNight.qml"); 0347 m_backgroundComponent = QStringLiteral("qrc:/qt/qml/org/kde/kweather/backgrounds/qml/backgrounds/CloudyNight.qml"); 0348 m_topColor = {69, 90, 100}; // #455a64 0349 m_bottomColor = {38, 50, 56}; // #263238 0350 m_cloudColor = {176, 190, 197}; // #b0bec5 0351 m_cloud = true; 0352 m_rain = true; 0353 } else if (currentWeather->weatherIcon() == QStringLiteral("weather-hail") || currentWeather->weatherIcon() == QStringLiteral("weather-snow-scattered") 0354 || currentWeather->weatherIcon() == QStringLiteral("weather-snow")) { 0355 m_backgroundComponent = QStringLiteral("qrc:/qt/qml/org/kde/kweather/backgrounds/qml/backgrounds/SnowyDay.qml"); 0356 isDayStyle = true; 0357 m_topColor = {53, 217, 237}; // #35d9ed 0358 m_bottomColor = {36, 163, 222}; // #24a3de 0359 m_snow = true; 0360 } else if (currentWeather->weatherIcon() == QStringLiteral("weather-snow-scattered-night")) { 0361 m_backgroundComponent = QStringLiteral("qrc:/qt/qml/org/kde/kweather/backgrounds/qml/backgrounds/SnowyNight.qml"); 0362 m_topColor = {69, 90, 100}; // #455a64 0363 m_bottomColor = {38, 50, 56}; // #263238 0364 m_snow = true; 0365 } 0366 0367 if (isDayStyle) { 0368 m_cardBackgroundColor = QStringLiteral("#fefefe"); 0369 m_cardTextColor = QStringLiteral("black"); 0370 m_cardSecondaryTextColor = QStringLiteral("#404040"); 0371 m_backgroundColor = QStringLiteral("#3daee2"); 0372 m_textColor = m_cardTextColor; 0373 m_iconColor = QStringLiteral("#4d4d4d"); 0374 m_isDarkTheme = false; 0375 } else { 0376 m_cardBackgroundColor = QStringLiteral("#333333"); 0377 m_cardTextColor = QStringLiteral("#eeeeee"); 0378 m_cardSecondaryTextColor = QStringLiteral("#C2C2C2"); 0379 m_backgroundColor = QStringLiteral("#222222"); 0380 m_textColor = m_cardTextColor; 0381 m_iconColor = QStringLiteral("white"); 0382 m_isDarkTheme = true; 0383 } 0384 0385 Q_EMIT currentForecastChanged(); 0386 } 0387 0388 void WeatherLocation::update() 0389 { 0390 auto pendingForecast = m_source.requestData(latitude(), longitude()); 0391 connect(pendingForecast, &KWeatherCore::PendingWeatherForecast::finished, [this, pendingForecast] { 0392 this->updateData(pendingForecast->value()); 0393 pendingForecast->deleteLater(); 0394 }); 0395 } 0396 0397 void WeatherLocation::updateCurrentDateTime() 0398 { 0399 m_timer->setInterval(60000); 0400 Q_EMIT currentTimeChanged(); 0401 Q_EMIT currentDateChanged(); 0402 } 0403 0404 const QColor &WeatherLocation::topColor() const 0405 { 0406 return m_topColor; 0407 } 0408 const QColor &WeatherLocation::bottomColor() const 0409 { 0410 return m_bottomColor; 0411 } 0412 const QColor &WeatherLocation::cloudColor() const 0413 { 0414 return m_cloudColor; 0415 } 0416 bool WeatherLocation::rain() const 0417 { 0418 return m_rain; 0419 } 0420 bool WeatherLocation::cloud() const 0421 { 0422 return m_cloud; 0423 } 0424 bool WeatherLocation::star() const 0425 { 0426 return m_star; 0427 } 0428 bool WeatherLocation::sun() const 0429 { 0430 return m_sun; 0431 } 0432 bool WeatherLocation::snow() const 0433 { 0434 return m_snow; 0435 } 0436 0437 #include "moc_weatherlocation.cpp"