feat: improve lock weather
This commit is contained in:
parent
20be5ac9cb
commit
f5692c485c
3 changed files with 72 additions and 176 deletions
|
|
@ -15,20 +15,10 @@ RowLayout {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
spacing: Tokens.spacing.medium
|
spacing: Tokens.spacing.medium
|
||||||
|
|
||||||
StyledRect {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
implicitHeight: weather.implicitHeight
|
|
||||||
|
|
||||||
topLeftRadius: Tokens.rounding.extraLarge
|
|
||||||
radius: Tokens.rounding.medium
|
|
||||||
color: Colours.tPalette.m3surfaceContainer
|
|
||||||
|
|
||||||
WeatherInfo {
|
WeatherInfo {
|
||||||
id: weather
|
Layout.fillWidth: true
|
||||||
|
|
||||||
rootHeight: root.height
|
rootHeight: root.height
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
StyledRect {
|
StyledRect {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
|
||||||
|
|
@ -6,163 +6,14 @@ import Caelestia.Config
|
||||||
import qs.components
|
import qs.components
|
||||||
import qs.services
|
import qs.services
|
||||||
|
|
||||||
ColumnLayout {
|
StyledRect {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property int rootHeight
|
required property int rootHeight // TODO: add forecast when large height
|
||||||
|
|
||||||
anchors.left: parent.left
|
implicitHeight: layout.implicitHeight + Tokens.padding.extraLarge * 2
|
||||||
anchors.right: parent.right
|
radius: Tokens.rounding.extraExtraLarge
|
||||||
anchors.margins: Tokens.padding.extraLargeIncreased
|
color: Colours.tPalette.m3surfaceContainer
|
||||||
|
|
||||||
spacing: Tokens.spacing.small
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
asynchronous: true
|
|
||||||
Layout.topMargin: Tokens.padding.extraLargeIncreased
|
|
||||||
Layout.bottomMargin: -Tokens.padding.large
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
|
|
||||||
active: root.rootHeight > 610
|
|
||||||
visible: active
|
|
||||||
|
|
||||||
sourceComponent: StyledText {
|
|
||||||
text: qsTr("Weather")
|
|
||||||
color: Colours.palette.m3primary
|
|
||||||
font: Tokens.font.body.builders.large.size(28).weight(Font.Medium).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
spacing: Tokens.spacing.largeIncreased
|
|
||||||
|
|
||||||
MaterialIcon {
|
|
||||||
animate: true
|
|
||||||
text: Weather.icon
|
|
||||||
color: Colours.palette.m3secondary
|
|
||||||
fontStyle: Tokens.font.icon.builders.extraLarge.scale(2.5).build()
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
spacing: Tokens.spacing.small
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
animate: true
|
|
||||||
text: Weather.description
|
|
||||||
color: Colours.palette.m3secondary
|
|
||||||
font: Tokens.font.body.builders.large.weight(Font.Medium).build()
|
|
||||||
elide: Text.ElideRight
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
animate: true
|
|
||||||
text: qsTr("Humidity: %1%").arg(Weather.humidity)
|
|
||||||
color: Colours.palette.m3onSurfaceVariant
|
|
||||||
font: Tokens.font.body.medium
|
|
||||||
elide: Text.ElideRight
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
asynchronous: true
|
|
||||||
Layout.rightMargin: Tokens.padding.small
|
|
||||||
active: root.width > 400
|
|
||||||
visible: active
|
|
||||||
|
|
||||||
sourceComponent: ColumnLayout {
|
|
||||||
spacing: Tokens.spacing.small
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
animate: true
|
|
||||||
text: Weather.temp
|
|
||||||
color: Colours.palette.m3primary
|
|
||||||
horizontalAlignment: Text.AlignRight
|
|
||||||
font: Tokens.font.body.builders.large.size(28).weight(Font.Medium).build()
|
|
||||||
elide: Text.ElideLeft
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
animate: true
|
|
||||||
text: qsTr("Feels like: %1").arg(Weather.feelsLike)
|
|
||||||
color: Colours.palette.m3outline
|
|
||||||
horizontalAlignment: Text.AlignRight
|
|
||||||
font: Tokens.font.body.small
|
|
||||||
elide: Text.ElideLeft
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: forecastLoader
|
|
||||||
|
|
||||||
asynchronous: true
|
|
||||||
Layout.topMargin: Tokens.spacing.medium
|
|
||||||
Layout.bottomMargin: Tokens.padding.extraLargeIncreased
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
active: root.rootHeight > 820
|
|
||||||
visible: active
|
|
||||||
|
|
||||||
sourceComponent: RowLayout {
|
|
||||||
spacing: Tokens.spacing.largeIncreased
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: {
|
|
||||||
const forecast = Weather.hourlyForecast;
|
|
||||||
const count = root.width < 320 ? 3 : root.width < 400 ? 4 : 5;
|
|
||||||
if (!forecast)
|
|
||||||
return Array.from({
|
|
||||||
length: count
|
|
||||||
}, () => null);
|
|
||||||
|
|
||||||
return forecast.slice(0, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
id: forecastHour
|
|
||||||
|
|
||||||
required property var modelData
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
spacing: Tokens.spacing.small
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
text: {
|
|
||||||
const hour = forecastHour.modelData?.hour ?? 0;
|
|
||||||
return hour > 12 ? `${(hour - 12).toString().padStart(2, "0")} PM` : `${hour.toString().padStart(2, "0")} AM`;
|
|
||||||
}
|
|
||||||
color: Colours.palette.m3outline
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
font: Tokens.font.body.large
|
|
||||||
}
|
|
||||||
|
|
||||||
MaterialIcon {
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
text: forecastHour.modelData?.icon ?? "cloud_alert"
|
|
||||||
fontStyle: Tokens.font.icon.builders.extraLarge.scale(1.5).weight(Font.Medium).build()
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
text: GlobalConfig.services.useFahrenheit ? `${forecastHour.modelData?.tempF ?? 0}°F` : `${forecastHour.modelData?.tempC ?? 0}°C`
|
|
||||||
color: Colours.palette.m3secondary
|
|
||||||
font: Tokens.font.body.large
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
running: true
|
running: true
|
||||||
|
|
@ -171,4 +22,59 @@ ColumnLayout {
|
||||||
interval: 900000 // 15 minutes
|
interval: 900000 // 15 minutes
|
||||||
onTriggered: Weather.reload()
|
onTriggered: Weather.reload()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: layout
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: Tokens.spacing.extraSmall
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
animate: true
|
||||||
|
text: Weather.description
|
||||||
|
color: Colours.palette.m3onSurfaceVariant
|
||||||
|
font: Tokens.font.body.large
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
spacing: Tokens.spacing.medium
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
id: temp
|
||||||
|
|
||||||
|
animate: true
|
||||||
|
text: Weather.temp
|
||||||
|
color: Colours.palette.m3primary
|
||||||
|
font: Tokens.font.headline.builders.large.scale(1.5).weight(Font.DemiBold).width(80).build()
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
animate: true
|
||||||
|
text: Weather.icon
|
||||||
|
color: Colours.palette.m3tertiary
|
||||||
|
fontStyle: Tokens.font.headline.builders.large.scale(1.5).build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
animate: true
|
||||||
|
text: qsTr("Feels like %1").arg(Weather.temp)
|
||||||
|
color: Colours.palette.m3onSurfaceVariant
|
||||||
|
font: Tokens.font.body.large
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
animate: true
|
||||||
|
text: {
|
||||||
|
const today = Weather.forecast[0];
|
||||||
|
return qsTr("High %1 • Low %2").arg(Weather.formatTemp(today?.maxTempC)).arg(Weather.formatTemp(today?.minTempC));
|
||||||
|
}
|
||||||
|
color: Colours.palette.m3onSurfaceVariant
|
||||||
|
font: Tokens.font.body.medium
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@ Singleton {
|
||||||
|
|
||||||
readonly property string icon: cc ? Icons.getWeatherIcon(cc.weatherCode) : "cloud_alert"
|
readonly property string icon: cc ? Icons.getWeatherIcon(cc.weatherCode) : "cloud_alert"
|
||||||
readonly property string description: cc?.weatherDesc ?? qsTr("No weather")
|
readonly property string description: cc?.weatherDesc ?? qsTr("No weather")
|
||||||
readonly property string temp: GlobalConfig.services.useFahrenheit ? `${cc?.tempF ?? 0}°F` : `${cc?.tempC ?? 0}°C`
|
readonly property string temp: formatTemp(cc?.tempC)
|
||||||
readonly property string feelsLike: GlobalConfig.services.useFahrenheit ? `${cc?.feelsLikeF ?? 0}°F` : `${cc?.feelsLikeC ?? 0}°C`
|
readonly property string feelsLike: formatTemp(cc?.feelsLikeC)
|
||||||
readonly property int humidity: cc?.humidity ?? 0
|
readonly property int humidity: cc?.humidity ?? 0
|
||||||
readonly property real windSpeed: cc?.windSpeed ?? 0
|
readonly property real windSpeed: cc?.windSpeed ?? 0
|
||||||
readonly property string sunrise: cc ? Qt.formatDateTime(new Date(cc.sunrise), GlobalConfig.services.useTwelveHourClock ? "h:mm A" : "h:mm") : "--:--"
|
readonly property string sunrise: cc ? Qt.formatDateTime(new Date(cc.sunrise), GlobalConfig.services.useTwelveHourClock ? "h:mm A" : "h:mm") : "--:--"
|
||||||
|
|
@ -26,6 +26,10 @@ Singleton {
|
||||||
|
|
||||||
readonly property var cachedCities: new Map()
|
readonly property var cachedCities: new Map()
|
||||||
|
|
||||||
|
function formatTemp(temp: var): string {
|
||||||
|
return GlobalConfig.services.useFahrenheit ? `${temp !== undefined ? Math.round(toFahrenheit(temp)) : "--"}°F` : `${temp !== undefined ? Math.round(temp) : "--"}°C`;
|
||||||
|
}
|
||||||
|
|
||||||
function reload(): void {
|
function reload(): void {
|
||||||
const configLocation = GlobalConfig.services.weatherLocation;
|
const configLocation = GlobalConfig.services.weatherLocation;
|
||||||
|
|
||||||
|
|
@ -114,10 +118,8 @@ Singleton {
|
||||||
cc = {
|
cc = {
|
||||||
weatherCode: json.current.weather_code,
|
weatherCode: json.current.weather_code,
|
||||||
weatherDesc: getWeatherCondition(json.current.weather_code),
|
weatherDesc: getWeatherCondition(json.current.weather_code),
|
||||||
tempC: Math.round(json.current.temperature_2m),
|
tempC: json.current.temperature_2m,
|
||||||
tempF: Math.round(toFahrenheit(json.current.temperature_2m)),
|
feelsLikeC: json.current.apparent_temperature,
|
||||||
feelsLikeC: Math.round(json.current.apparent_temperature),
|
|
||||||
feelsLikeF: Math.round(toFahrenheit(json.current.apparent_temperature)),
|
|
||||||
humidity: json.current.relative_humidity_2m,
|
humidity: json.current.relative_humidity_2m,
|
||||||
windSpeed: json.current.wind_speed_10m,
|
windSpeed: json.current.wind_speed_10m,
|
||||||
isDay: json.current.is_day,
|
isDay: json.current.is_day,
|
||||||
|
|
@ -129,10 +131,8 @@ Singleton {
|
||||||
for (let i = 0; i < json.daily.time.length; i++)
|
for (let i = 0; i < json.daily.time.length; i++)
|
||||||
forecastList.push({
|
forecastList.push({
|
||||||
date: json.daily.time[i].replace(/-/g, "/"),
|
date: json.daily.time[i].replace(/-/g, "/"),
|
||||||
maxTempC: Math.round(json.daily.temperature_2m_max[i]),
|
maxTempC: json.daily.temperature_2m_max[i],
|
||||||
maxTempF: Math.round(toFahrenheit(json.daily.temperature_2m_max[i])),
|
minTempC: json.daily.temperature_2m_min[i],
|
||||||
minTempC: Math.round(json.daily.temperature_2m_min[i]),
|
|
||||||
minTempF: Math.round(toFahrenheit(json.daily.temperature_2m_min[i])),
|
|
||||||
weatherCode: json.daily.weather_code[i],
|
weatherCode: json.daily.weather_code[i],
|
||||||
icon: Icons.getWeatherIcon(json.daily.weather_code[i])
|
icon: Icons.getWeatherIcon(json.daily.weather_code[i])
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue