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

179 lines
5.5 KiB
Text

// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
import { Palette } from "std-widgets.slint";
import { WindowInfo, WindowInfoHelper } from "./ui_utils.slint";
import { StackView, StackPage } from "./controls/stackview.slint";
import { CityListView } from "./city_weather.slint";
import { CityWeather } from "./weather_datatypes.slint";
import { LocationSearchView } from "./location_search.slint";
import { GeoLocation } from "./location_datatypes.slint";
import { AppPalette, AppFonts, AppImages } from "./style/styles.slint";
import { FloatingTextButton } from "./controls/generic.slint";
import { BusyLayerController, BusyLayer } from "./controls/busy-layer.slint";
// Re export for native rust
export { WindowInfo, AppPalette, BusyLayerController, CityWeather, GeoLocation }
component EdgeFloatingTextButton inherits FloatingTextButton {
out property<length> edge-spacing: 15px;
}
component AnimatedStackPage inherits StackPage {
// is-active and is-opened are not set as a binding here, only when the value is actually changed.
// This is to avoid redundant reevaluation of dependent properties and conditional elements.
// see: https://github.com/slint-ui/slint/issues/5209
out property<bool> is-active: false;
out property<bool> is-opened: false;
// using a helper int property to be able to use animate
property<int> is-active-value: 0;
property<duration> animation-duration: 250ms;
visible: root.is-active;
init => { root.is-active = (self.is-active_value == 1); }
changed is-active-value => { root.is-active = (self.is-active_value == 1); }
states [
active when self.is-current: {
is-active-value: 1;
out {
animate is-active-value { delay: root.animation-duration; }
}
}
]
content := Rectangle {
changed y => {
// First open animation is not working properly without the line below. (A bug?)
// Seems the animation in transition is using old values,
// and accessing the property somehow forces the update.
self.y;
if (root.is-opened != (self.y == 0)) {
root.is-opened = (self.y == 0);
}
}
y: root.is-current ? 0px : root.height;
animate y { duration: root.animation-duration; easing: ease-in-out-quad; }
@children
}
}
enum PageType {
Main,
AddLocation,
}
export component AppWindow inherits Window {
background: AppPalette.background;
default-font-size: AppFonts.default-font-size;
preferred-width: 900px;
preferred-height: 600px;
WindowInfoHelper {
init => {
// no support for the different modes currently
// this is to display slint badge in proper colors
Palette.color-scheme = ColorScheme.dark;
}
}
stack := StackView {
function show-page(pageType : PageType) {
if (pageType == PageType.Main) {
self.current-index = 0;
}
else if (pageType == PageType.AddLocation) {
self.current-index = 1;
}
}
function back-to-main() {
self.show-page(PageType.Main);
}
current-index: 0;
min-index: 0;
StackPage {
is-current: self.check-is-current(stack.current-index);
init => { self.page-index = stack.insert-page(); }
visible: self.page-index <= stack.current-index;
CityListView {}
// right (refresh) button
EdgeFloatingTextButton {
x: parent.width - self.width - self.edge-spacing;
y: parent.height - self.height - self.edge-spacing;
icon-source: AppImages.refresh;
clicked => {
BusyLayerController.set-busy();
CityWeather.refresh-all();
}
}
// left (add) button
EdgeFloatingTextButton {
x: self.edge-spacing;
y: parent.height - self.height - self.edge-spacing;
visible: CityWeather.can-add-city;
icon-source: AppImages.plus;
clicked => {
stack.show-page(PageType.AddLocation);
}
}
}
AnimatedStackPage {
is-current: self.check-is-current(stack.current-index);
init => { self.page-index = stack.insert-page(); }
location-search-view := LocationSearchView {
property<bool> is-active: parent.is-active;
property<bool> is-opened: parent.is-opened;
changed is-active => {
if (self.is-active) {
self.clear();
}
}
changed is-opened => {
if (self.is-opened) {
self.focus();
}
}
close-request => {
self.clear-focus();
stack.back-to-main();
}
EdgeFloatingTextButton {
x: parent.width - self.width - self.edge-spacing;
y: parent.height - self.height - self.edge-spacing;
icon-source: AppImages.xmark;
clicked => { location-search-view.close-request(); }
}
}
}
}
if BusyLayerController.is-busy: BusyLayer {}
}