// Copyright © SixtyFPS GmbH // SPDX-License-Identifier: MIT import { VerticalBox } from "std-widgets.slint"; import { AppPalette } from "./style/styles.slint"; import { AppText } from "./controls/generic.slint"; import { WeatherIcon, RainInfo, UvInfo } from "./controls/weather.slint"; import { WeatherInfo, WeatherForecastInfo, CityWeather } from "./weather_datatypes.slint"; component ForecastGraphText inherits AppText { horizontal-alignment: center; vertical-alignment: center; font-size: 0.85rem; } component DayForecastGraphEntry inherits VerticalLayout { in property day-name; in property day-weather; in property detailed: true; spacing: 5px; ForecastGraphText { font-size: 1.2rem; text: day-name; } WeatherIcon { icon-type: day-weather.icon-type; font-size: 1.6rem; } VerticalLayout { spacing: 5px; ForecastGraphText { text: Math.round(day-weather.detailed_temp.max) + "° / " + Math.round(day-weather.detailed_temp.min) + "°"; } RainInfo { precipitation-probability: root.day-weather.precipitation_prob; rain-volume: root.day-weather.rain; snow-volume: root.day-weather.snow; minimal: true; } UvInfo { uv-index: root.day-weather.uv; minimal: true; } } } export component DayForecastGraph inherits Rectangle { in property <[WeatherForecastInfo]> forecast-weather; in property show-animations: true; property preferred-day-width: 85px; // max-days-count is not directly as a binding here, only when the value is actually changed. // This is to avoid reevaluation of the conditional components that rely on it for every window size change. // see: https://github.com/slint-ui/slint/issues/5209 property max-days-count: 0; property days-count: Math.min(root.forecast-weather.length, root.max-days-count); property day-width: root.width / root.days-count; function update-max-days-count() { if (Math.floor(root.width / root.preferred-day-width) != root.max-days-count) { root.max-days-count = Math.floor(root.width / root.preferred-day-width); } } init => { root.update-max-days-count(); } changed width => { root.update-max-days-count(); } preferred-height: layout.preferred-height; Path { property visible-part: 0%; y: 0; height: 50%; stroke-width: 2px; commands: CityWeather.get_forecast_graph_command( root.forecast-weather, root.days-count, self.width, self.height); stroke: @linear-gradient(90deg, AppPalette.foreground.with-alpha(25%) 0%, AppPalette.foreground.with-alpha(25%) self.visible-part, transparent self.visible-part, transparent 100%); opacity: 0.0; animate opacity { duration: root.show-animations ? 1200ms : 0ms; easing: ease-in; } animate visible-part { duration: root.show-animations ? 900ms : 0ms; easing: ease-in; } init => { self.opacity = 1.0; self.visible-part = 100%; } } layout := HorizontalLayout { for index in root.days-count: DayForecastGraphEntry { property day-forecast-weather: root.forecast-weather[index]; property animation-duration: 0ms; width: root.day-width; day-name: day-forecast-weather.day-name; day-weather: day-forecast-weather.weather-info; opacity: 0.0; animate opacity { duration: self.animation-duration; easing: ease-in-out-quad; } init => { if (root.show-animations) { self.animation-duration = 600ms + (500ms - index * 50ms) * index; } self.opacity = 1.0; } } } }