slint/demos/weather-demo/ui/forecast_with_graph.slint
2024-10-26 09:39:52 +02:00

128 lines
4.1 KiB
Text

// Copyright © SixtyFPS GmbH <info@slint.dev>
// 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 <string> day-name;
in property <WeatherInfo> day-weather;
in property <bool> 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 <bool> show-animations: true;
property <length> 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 <int> max-days-count: 0;
property <int> days-count: Math.min(root.forecast-weather.length, root.max-days-count);
property <length> 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 <float> 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 <WeatherForecastInfo> day-forecast-weather: root.forecast-weather[index];
property <duration> 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;
}
}
}
}