Files
DankMaterialShell/quickshell/Modules/DankDash/Overview/WeatherOverviewCard.qml
T

296 lines
10 KiB
QML

import QtQuick
import qs.Common
import qs.Services
import qs.Widgets
import qs.Modules.DankDash
import qs.Modules.DankDash.Weather
import "../Weather/WeatherVisuals.js" as Visuals
Card {
id: root
property bool live: Window.window?.visible ?? false
property bool weatherRefHeld: false
readonly property bool available: WeatherService.weather.available
readonly property bool tall: height > width
readonly property bool narrow: width < DashMetrics.gridRowUnit * 2
readonly property bool compact: narrow && !tall
readonly property bool wide: width >= DashMetrics.gridRowUnit * 3
readonly property bool roomy: !narrow && height >= DashMetrics.gridRowUnit * 2
readonly property bool stacked: tall || narrow || roomy
readonly property bool heroLayout: available && roomy && wide
readonly property bool showReadings: options.readings !== false
readonly property bool showCity: options.city === true && available && !!WeatherService.weather.city
readonly property string cityText: WeatherService.weather.city ?? ""
readonly property string rowTitle: showCity && wide ? cityText + " · " + conditionText : conditionText
readonly property string rowSubtitle: {
if (showReadings)
return wide ? readingsText : feelsLikeText;
return showCity && !wide ? cityText : "";
}
readonly property string iconName: available ? WeatherService.getWeatherIcon(WeatherService.weather.wCode, WeatherService.weather.isDay) : "cloud_off"
readonly property string tempText: available ? WeatherService.currentTempText(false) : I18n.tr("No Weather")
readonly property string conditionText: available ? WeatherService.getWeatherCondition(WeatherService.weather.wCode) : ""
readonly property string feelsLikeText: {
if (!available)
return "";
const feelsLike = SettingsData.useFahrenheit ? (WeatherService.weather.feelsLikeF ?? WeatherService.weather.tempF) : (WeatherService.weather.feelsLike ?? WeatherService.weather.temp);
return I18n.tr("Feels Like %1°", "weather feels like temperature").arg(feelsLike);
}
readonly property string readingsText: {
if (!available)
return "";
const parts = [feelsLikeText];
const humidity = WeatherService.formatPercent(WeatherService.weather.humidity);
if (humidity)
parts.push(humidity);
const wind = WeatherService.formatSpeed(WeatherService.weather.wind);
if (wind)
parts.push(wind);
return parts.join(" · ");
}
entryId: "weather"
tone: options.tone ?? ""
clickable: true
pad: compact ? Theme.spacingS : Theme.spacingM
function syncWeatherRef(wanted) {
if (wanted === weatherRefHeld)
return;
weatherRefHeld = wanted;
if (wanted) {
WeatherService.addRef();
return;
}
WeatherService.removeRef();
}
onLiveChanged: syncWeatherRef(live)
Component.onCompleted: syncWeatherRef(live)
Component.onDestruction: syncWeatherRef(false)
Column {
anchors.fill: parent
spacing: Theme.spacingXS
visible: root.compact
Row {
width: parent.width
height: parent.height - compactCondition.height - parent.spacing
spacing: Theme.spacingXS
Item {
id: compactIcon
anchors.verticalCenter: parent.verticalCenter
width: Math.min(parent.height, parent.width * DashMetrics.weatherCompactIconRatio)
height: width
DankIcon {
anchors.centerIn: parent
name: root.iconName
size: parent.width
color: root.accentColor
visible: root.available || !WeatherService.weather.loading
}
DankSpinner {
anchors.centerIn: parent
size: parent.width
color: root.contentColor
visible: !root.available && WeatherService.weather.loading
}
}
StyledText {
anchors.verticalCenter: parent.verticalCenter
width: parent.width - compactIcon.width - parent.spacing
height: parent.height
text: root.available ? root.tempText : ""
font.pixelSize: Theme.fontSizeXXLarge
minimumPixelSize: Theme.fontSizeLarge
fontSizeMode: Text.HorizontalFit
font.weight: Theme.fontWeightMedium
color: root.contentColor
horizontalAlignment: Text.AlignRight
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
}
}
StyledText {
id: compactCondition
width: parent.width
text: root.available ? (root.showCity ? root.cityText : root.conditionText) : root.tempText
font.pixelSize: Theme.fontSizeSmall
font.weight: Theme.fontWeightMedium
color: root.mutedColor
elide: Text.ElideRight
}
}
Item {
id: stackedLayout
anchors.fill: parent
visible: root.stacked && !root.compact && !root.heroLayout
DankMaterialShape {
id: stackedChip
width: Math.min(parent.width * 0.5, parent.height * 0.42)
height: width
shape: Visuals.conditionShape(WeatherService.weather.wCode, WeatherService.weather.isDay)
color: root.chipColor
DankIcon {
anchors.centerIn: parent
name: root.iconName
size: parent.width * 0.55
color: root.accentColor
visible: root.available || !WeatherService.weather.loading
}
DankSpinner {
anchors.centerIn: parent
size: parent.width * 0.55
color: root.contentColor
visible: !root.available && WeatherService.weather.loading
}
}
StyledText {
anchors.top: parent.top
anchors.right: parent.right
anchors.left: stackedChip.right
anchors.leftMargin: Theme.spacingS
text: root.cityText
font.pixelSize: Theme.fontSizeSmall
font.weight: Theme.fontWeightMedium
color: root.mutedColor
horizontalAlignment: Text.AlignRight
elide: Text.ElideRight
visible: root.showCity && !root.narrow
}
Column {
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
spacing: 0
StyledText {
width: parent.width
text: root.tempText
font.pixelSize: root.available ? Math.min(Theme.fontSizeDisplay * 1.5, stackedLayout.height * 0.32) : Theme.fontSizeMedium
font.weight: Theme.fontWeightMedium
font.features: ({
"tnum": 1
})
minimumPixelSize: Theme.fontSizeXLarge
fontSizeMode: Text.HorizontalFit
color: root.contentColor
elide: Text.ElideRight
}
StyledText {
width: parent.width
text: root.conditionText
font.pixelSize: root.narrow ? Theme.fontSizeSmall : Theme.fontSizeMedium
font.weight: Theme.fontWeightMedium
color: root.mutedColor
elide: Text.ElideRight
maximumLineCount: 1
visible: text !== ""
}
StyledText {
width: parent.width
text: root.narrow ? root.feelsLikeText : root.readingsText
font.pixelSize: Theme.fontSizeSmall
color: root.mutedColor
elide: Text.ElideRight
visible: root.showReadings && text !== ""
}
StyledText {
width: parent.width
text: root.cityText
font.pixelSize: Theme.fontSizeSmall
font.weight: Theme.fontWeightMedium
color: root.mutedColor
elide: Text.ElideRight
visible: root.showCity && root.narrow
}
}
}
WeatherHero {
anchors.fill: parent
visible: root.heroLayout
showCity: root.showCity
showSunTimes: root.showReadings
tone: root.tone
flat: true
}
Row {
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingM
visible: !root.stacked
DankMaterialShape {
id: iconChip
anchors.verticalCenter: parent.verticalCenter
width: Math.min(DashMetrics.weatherChipSize, root.height - root.pad * 2)
height: width
shape: Visuals.conditionShape(WeatherService.weather.wCode, WeatherService.weather.isDay)
color: root.chipColor
DankIcon {
anchors.centerIn: parent
name: root.iconName
size: Theme.iconSize
color: root.accentColor
}
}
Column {
anchors.verticalCenter: parent.verticalCenter
width: parent.width - iconChip.width - tempLabel.width - parent.spacing * 2
spacing: 0
StyledText {
width: parent.width
text: root.available ? root.rowTitle : root.tempText
wrapMode: Text.NoWrap
font.pixelSize: Theme.fontSizeMedium
font.weight: Theme.fontWeightMedium
color: root.contentColor
elide: Text.ElideRight
}
StyledText {
width: parent.width
text: root.rowSubtitle
wrapMode: Text.NoWrap
font.pixelSize: Theme.fontSizeSmall
font.weight: Theme.fontWeightMedium
color: root.mutedColor
elide: Text.ElideRight
visible: text !== ""
}
}
StyledText {
id: tempLabel
anchors.verticalCenter: parent.verticalCenter
text: root.available ? root.tempText : ""
font.pixelSize: DashMetrics.weatherTempSize
font.weight: Theme.fontWeightMedium
color: root.contentColor
}
}
}