mirror of
https://github.com/zoriya/noctalia-shell.git
synced 2025-12-06 06:36:15 +00:00
- All cards now live in Modules/Cards - CalendarPanel is now called ClockPanel - Added a way to ease settings migration in separate QML files
199 lines
6.5 KiB
QML
199 lines
6.5 KiB
QML
import QtQuick
|
|
import QtQuick.Effects
|
|
import QtQuick.Layouts
|
|
import Quickshell
|
|
import qs.Commons
|
|
import qs.Services.Location
|
|
import qs.Widgets
|
|
|
|
// Weather overview card (placeholder data)
|
|
NBox {
|
|
id: root
|
|
|
|
property int forecastDays: 6
|
|
property bool showLocation: true
|
|
property bool showEffects: Settings.data.location.weatherShowEffects
|
|
readonly property bool weatherReady: Settings.data.location.weatherEnabled && (LocationService.data.weather !== null)
|
|
|
|
// Test mode: set to "rain" or "snow"
|
|
property string testEffects: ""
|
|
|
|
// Weather condition detection
|
|
readonly property int currentWeatherCode: weatherReady ? LocationService.data.weather.current_weather.weathercode : 0
|
|
readonly property bool isRaining: testEffects === "rain" || (testEffects === "" && ((currentWeatherCode >= 51 && currentWeatherCode <= 67) || (currentWeatherCode >= 80 && currentWeatherCode <= 82)))
|
|
readonly property bool isSnowing: testEffects === "snow" || (testEffects === "" && ((currentWeatherCode >= 71 && currentWeatherCode <= 77) || (currentWeatherCode >= 85 && currentWeatherCode <= 86)))
|
|
|
|
visible: Settings.data.location.weatherEnabled
|
|
implicitHeight: Math.max(100 * Style.uiScaleRatio, content.implicitHeight + (Style.marginXL * 2))
|
|
|
|
// Weather effect layer (rain/snow)
|
|
Loader {
|
|
id: weatherEffectLoader
|
|
anchors.fill: parent
|
|
active: root.showEffects && (root.isRaining || root.isSnowing)
|
|
|
|
sourceComponent: Item {
|
|
anchors.fill: parent
|
|
|
|
// Animated time for shaders
|
|
property real shaderTime: 0
|
|
NumberAnimation on shaderTime {
|
|
loops: Animation.Infinite
|
|
from: 0
|
|
to: 1000
|
|
duration: 100000
|
|
}
|
|
|
|
ShaderEffect {
|
|
id: weatherEffect
|
|
anchors.fill: parent
|
|
// Snow fills the box, rain matches content margins
|
|
anchors.margins: root.isSnowing ? root.border.width : Style.marginXL
|
|
|
|
property var source: ShaderEffectSource {
|
|
sourceItem: content
|
|
hideSource: root.isRaining // Only hide for rain (distortion), show for snow
|
|
}
|
|
|
|
property real time: parent.shaderTime
|
|
property real itemWidth: weatherEffect.width
|
|
property real itemHeight: weatherEffect.height
|
|
property color bgColor: root.color
|
|
property real cornerRadius: root.isSnowing ? (root.radius - root.border.width) : 0
|
|
|
|
fragmentShader: root.isSnowing ? Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/weather_snow.frag.qsb") : Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/weather_rain.frag.qsb")
|
|
}
|
|
}
|
|
}
|
|
|
|
ColumnLayout {
|
|
id: content
|
|
anchors.fill: parent
|
|
anchors.margins: Style.marginXL
|
|
spacing: Style.marginM
|
|
clip: true
|
|
|
|
RowLayout {
|
|
Layout.fillWidth: true
|
|
spacing: Style.marginS
|
|
|
|
Item {
|
|
Layout.preferredWidth: Style.marginXXS
|
|
}
|
|
|
|
RowLayout {
|
|
spacing: Style.marginL
|
|
Layout.fillWidth: true
|
|
|
|
NIcon {
|
|
Layout.alignment: Qt.AlignVCenter
|
|
icon: weatherReady ? LocationService.weatherSymbolFromCode(LocationService.data.weather.current_weather.weathercode) : ""
|
|
pointSize: Style.fontSizeXXXL * 1.75
|
|
color: Color.mPrimary
|
|
}
|
|
|
|
ColumnLayout {
|
|
spacing: Style.marginXXS
|
|
NText {
|
|
text: {
|
|
// Ensure the name is not too long if one had to specify the country
|
|
const chunks = Settings.data.location.name.split(",");
|
|
return chunks[0];
|
|
}
|
|
pointSize: Style.fontSizeL
|
|
font.weight: Style.fontWeightBold
|
|
visible: showLocation
|
|
}
|
|
|
|
RowLayout {
|
|
NText {
|
|
visible: weatherReady
|
|
text: {
|
|
if (!weatherReady) {
|
|
return "";
|
|
}
|
|
var temp = LocationService.data.weather.current_weather.temperature;
|
|
var suffix = "C";
|
|
if (Settings.data.location.useFahrenheit) {
|
|
temp = LocationService.celsiusToFahrenheit(temp);
|
|
var suffix = "F";
|
|
}
|
|
temp = Math.round(temp);
|
|
return `${temp}°${suffix}`;
|
|
}
|
|
pointSize: showLocation ? Style.fontSizeXL : Style.fontSizeXL * 1.6
|
|
font.weight: Style.fontWeightBold
|
|
}
|
|
|
|
NText {
|
|
text: weatherReady ? `(${LocationService.data.weather.timezone_abbreviation})` : ""
|
|
pointSize: Style.fontSizeXS
|
|
color: Color.mOnSurfaceVariant
|
|
visible: LocationService.data.weather && showLocation
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
NDivider {
|
|
visible: weatherReady
|
|
Layout.fillWidth: true
|
|
}
|
|
|
|
RowLayout {
|
|
visible: weatherReady
|
|
Layout.fillWidth: true
|
|
Layout.alignment: Qt.AlignVCenter
|
|
spacing: Style.marginM
|
|
|
|
Repeater {
|
|
model: weatherReady ? Math.min(root.forecastDays, LocationService.data.weather.daily.time.length) : 0
|
|
delegate: ColumnLayout {
|
|
Layout.fillWidth: true
|
|
spacing: Style.marginXS
|
|
Item {
|
|
Layout.fillWidth: true
|
|
}
|
|
NText {
|
|
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
|
text: {
|
|
var weatherDate = new Date(LocationService.data.weather.daily.time[index].replace(/-/g, "/"));
|
|
return I18n.locale.toString(weatherDate, "ddd");
|
|
}
|
|
color: Color.mOnSurface
|
|
}
|
|
NIcon {
|
|
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
|
icon: LocationService.weatherSymbolFromCode(LocationService.data.weather.daily.weathercode[index])
|
|
pointSize: Style.fontSizeXXL * 1.6
|
|
color: Color.mPrimary
|
|
}
|
|
NText {
|
|
Layout.alignment: Qt.AlignHCenter
|
|
text: {
|
|
var max = LocationService.data.weather.daily.temperature_2m_max[index];
|
|
var min = LocationService.data.weather.daily.temperature_2m_min[index];
|
|
if (Settings.data.location.useFahrenheit) {
|
|
max = LocationService.celsiusToFahrenheit(max);
|
|
min = LocationService.celsiusToFahrenheit(min);
|
|
}
|
|
max = Math.round(max);
|
|
min = Math.round(min);
|
|
return `${max}°/${min}°`;
|
|
}
|
|
pointSize: Style.fontSizeXS
|
|
color: Color.mOnSurfaceVariant
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Loader {
|
|
active: !weatherReady
|
|
Layout.alignment: Qt.AlignCenter
|
|
sourceComponent: NBusyIndicator {}
|
|
}
|
|
}
|
|
}
|