feat: add hourly forecast to lock weather
Shows if screen is large
This commit is contained in:
parent
18af8ab4ac
commit
318d20fec2
4 changed files with 135 additions and 6 deletions
|
|
@ -7,9 +7,15 @@ import qs.services
|
||||||
StyledRect {
|
StyledRect {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property int rootHeight // TODO: add forecast when large height
|
required property int rootHeight
|
||||||
|
readonly property bool showForecast: rootHeight >= Tokens.sizes.lock.showForecastHeight
|
||||||
|
|
||||||
implicitHeight: layout.implicitHeight + Tokens.padding.extraLarge * 2
|
implicitHeight: {
|
||||||
|
const base = brief.implicitHeight + brief.anchors.topMargin;
|
||||||
|
if (showForecast)
|
||||||
|
return base + Tokens.spacing.largeIncreased + forecast.implicitHeight + forecast.anchors.margins;
|
||||||
|
return base + brief.anchors.topMargin;
|
||||||
|
}
|
||||||
radius: Tokens.rounding.extraExtraLarge
|
radius: Tokens.rounding.extraExtraLarge
|
||||||
color: Colours.tPalette.m3surfaceContainer
|
color: Colours.tPalette.m3surfaceContainer
|
||||||
|
|
||||||
|
|
@ -22,8 +28,24 @@ StyledRect {
|
||||||
}
|
}
|
||||||
|
|
||||||
BriefInfo {
|
BriefInfo {
|
||||||
id: layout
|
id: brief
|
||||||
|
|
||||||
anchors.centerIn: parent
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: Tokens.padding.extraLarge
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: forecast
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.margins: Tokens.padding.large
|
||||||
|
|
||||||
|
active: root.showForecast
|
||||||
|
asynchronous: true
|
||||||
|
|
||||||
|
sourceComponent: Forecast {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
105
modules/lock/weather/Forecast.qml
Normal file
105
modules/lock/weather/Forecast.qml
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import M3Shapes
|
||||||
|
import Caelestia
|
||||||
|
import Caelestia.Config
|
||||||
|
import qs.components
|
||||||
|
import qs.services
|
||||||
|
|
||||||
|
StyledRect {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
color: Colours.layer(Colours.palette.m3surfaceContainerHigh, 2)
|
||||||
|
radius: Tokens.rounding.extraLargeIncreased
|
||||||
|
implicitHeight: header.anchors.margins + header.implicitHeight + Tokens.spacing.medium + layout.implicitHeight + layout.anchors.bottomMargin
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: header
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.margins: Tokens.padding.largeIncreased
|
||||||
|
|
||||||
|
spacing: Tokens.spacing.small
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
Layout.topMargin: Math.round(fontInfo.pointSize * 0.12)
|
||||||
|
text: "schedule"
|
||||||
|
fontStyle: Tokens.font.icon.builders.medium.weight(title.font.weight).build()
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
id: title
|
||||||
|
|
||||||
|
text: qsTr("Hourly forecast")
|
||||||
|
font: Tokens.font.title.medium
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: layout
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.bottomMargin: Tokens.padding.largeIncreased
|
||||||
|
anchors.margins: Tokens.padding.large
|
||||||
|
|
||||||
|
spacing: Tokens.spacing.small
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: CUtils.clamp(Math.floor((layout.width + layout.spacing) / (Tokens.sizes.lock.forecastItemWidth + layout.spacing)), 0, Weather.hourlyForecast.length)
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: hour
|
||||||
|
|
||||||
|
required property int index
|
||||||
|
readonly property var cond: Weather.hourlyForecast[index]
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: Tokens.spacing.extraSmall
|
||||||
|
|
||||||
|
MaterialShape {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
implicitSize: temp.implicitHeight + Tokens.padding.medium * 2
|
||||||
|
shape: MaterialShape.Cookie4Sided
|
||||||
|
color: Qt.alpha(Colours.palette.m3primary, hour.index === 0 ? 1 : 0)
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
CAnim {}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
id: temp
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: Weather.formatTemp(hour.cond.tempC).slice(0, -1) // Remove C/F
|
||||||
|
color: hour.index === 0 ? Colours.palette.m3onPrimary : Colours.palette.m3onSurface
|
||||||
|
font: Tokens.font.title.medium
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
text: hour.cond.icon
|
||||||
|
color: Colours.palette.m3secondary
|
||||||
|
fontStyle: Tokens.font.icon.large
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
text: hour.cond.precipChance + "%"
|
||||||
|
color: Colours.palette.m3primary
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
Layout.topMargin: Tokens.spacing.extraSmall
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
text: hour.index === 0 ? qsTr("Now") : Qt.formatDateTime(new Date(hour.cond.timestamp.replace("T", " ")), GlobalConfig.services.useTwelveHourClock ? "ha" : "hh00")
|
||||||
|
color: Colours.palette.m3onSurfaceVariant
|
||||||
|
font: Tokens.font.body.medium
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -285,6 +285,8 @@ class LockTokens : public ConfigObject {
|
||||||
CONFIG_PROPERTY(qreal, heightMult, 0.7)
|
CONFIG_PROPERTY(qreal, heightMult, 0.7)
|
||||||
CONFIG_PROPERTY(qreal, ratio, 16.0 / 9.0)
|
CONFIG_PROPERTY(qreal, ratio, 16.0 / 9.0)
|
||||||
CONFIG_PROPERTY(int, centerWidth, 600)
|
CONFIG_PROPERTY(int, centerWidth, 600)
|
||||||
|
CONFIG_PROPERTY(int, showForecastHeight, 975)
|
||||||
|
CONFIG_PROPERTY(int, forecastItemWidth, 51)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit LockTokens(QObject* parent = nullptr)
|
explicit LockTokens(QObject* parent = nullptr)
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,7 @@ Singleton {
|
||||||
timestamp: json.hourly.time[i],
|
timestamp: json.hourly.time[i],
|
||||||
hour: time.getHours(),
|
hour: time.getHours(),
|
||||||
tempC: Math.round(json.hourly.temperature_2m[i]),
|
tempC: Math.round(json.hourly.temperature_2m[i]),
|
||||||
tempF: Math.round(toFahrenheit(json.hourly.temperature_2m[i])),
|
precipChance: json.hourly.precipitation_probability[i],
|
||||||
weatherCode: json.hourly.weather_code[i],
|
weatherCode: json.hourly.weather_code[i],
|
||||||
icon: Icons.getWeatherIcon(json.hourly.weather_code[i])
|
icon: Icons.getWeatherIcon(json.hourly.weather_code[i])
|
||||||
});
|
});
|
||||||
|
|
@ -169,7 +169,7 @@ Singleton {
|
||||||
|
|
||||||
const [lat, lon] = loc.split(",").map(s => s.trim());
|
const [lat, lon] = loc.split(",").map(s => s.trim());
|
||||||
const baseUrl = "https://api.open-meteo.com/v1/forecast";
|
const baseUrl = "https://api.open-meteo.com/v1/forecast";
|
||||||
const params = ["latitude=" + lat, "longitude=" + lon, "hourly=weather_code,temperature_2m", "daily=weather_code,temperature_2m_max,temperature_2m_min,sunrise,sunset", "current=temperature_2m,relative_humidity_2m,apparent_temperature,is_day,weather_code,wind_speed_10m", "timezone=auto", "forecast_days=7"];
|
const params = ["latitude=" + lat, "longitude=" + lon, "hourly=weather_code,temperature_2m,precipitation_probability", "daily=weather_code,temperature_2m_max,temperature_2m_min,sunrise,sunset", "current=temperature_2m,relative_humidity_2m,apparent_temperature,is_day,weather_code,wind_speed_10m", "timezone=auto", "forecast_days=7"];
|
||||||
|
|
||||||
return baseUrl + "?" + params.join("&");
|
return baseUrl + "?" + params.join("&");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue