1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: MIT
3
4import { Palette } from "std-widgets.slint";
5import { WindowInfo, WindowInfoHelper } from "./ui_utils.slint";
6import { StackView, StackPage } from "./controls/stackview.slint";
7import { CityListView } from "./city_weather.slint";
8import { CityWeather } from "./weather_datatypes.slint";
9import { LocationSearchView } from "./location_search.slint";
10import { GeoLocation } from "./location_datatypes.slint";
11import { AppPalette, AppFonts, AppImages } from "./style/styles.slint";
12import { FloatingTextButton } from "./controls/generic.slint";
13import { BusyLayerController, BusyLayer } from "./controls/busy-layer.slint";
14
15// Re export for native rust
16export { WindowInfo, AppPalette, BusyLayerController, CityWeather, GeoLocation }
17
18component EdgeFloatingTextButton inherits FloatingTextButton {
19 out property<length> edge-spacing: 15px;
20}
21
22component AnimatedStackPage inherits StackPage {
23 // is-active and is-opened are not set as a binding here, only when the value is actually changed.
24 // This is to avoid redundant reevaluation of dependent properties and conditional elements.
25 // see: https://github.com/slint-ui/slint/issues/5209
26 out property<bool> is-active: false;
27 out property<bool> is-opened: false;
28
29 // using a helper int property to be able to use animate
30 property<int> is-active-value: 0;
31
32 property<duration> animation-duration: 250ms;
33
34 visible: root.is-active;
35
36 init => { root.is-active = (self.is-active_value == 1); }
37 changed is-active-value => { root.is-active = (self.is-active_value == 1); }
38
39 states [
40 active when self.is-current: {
41 is-active-value: 1;
42
43 out {
44 animate is-active-value { delay: root.animation-duration; }
45 }
46 }
47 ]
48
49 content := Rectangle {
50 changed y => {
51 // First open animation is not working properly without the line below. (A bug?)
52 // Seems the animation in transition is using old values,
53 // and accessing the property somehow forces the update.
54 self.y;
55
56 if (root.is-opened != (self.y == 0)) {
57 root.is-opened = (self.y == 0);
58 }
59 }
60
61 y: root.is-current ? 0px : root.height;
62
63 animate y { duration: root.animation-duration; easing: ease-in-out-quad; }
64
65 @children
66 }
67}
68
69enum PageType {
70 Main,
71 AddLocation,
72}
73
74export component AppWindow inherits Window {
75 background: AppPalette.background;
76 default-font-size: AppFonts.default-font-size;
77
78 preferred-width: 900px;
79 preferred-height: 600px;
80
81 WindowInfoHelper {
82 init => {
83 // no support for the different modes currently
84 // this is to display slint badge in proper colors
85 Palette.color-scheme = ColorScheme.dark;
86 }
87 }
88
89 stack := StackView {
90 function show-page(pageType : PageType) {
91 if (pageType == PageType.Main) {
92 self.current-index = 0;
93 }
94 else if (pageType == PageType.AddLocation) {
95 self.current-index = 1;
96 }
97 }
98
99 function back-to-main() {
100 self.show-page(PageType.Main);
101 }
102
103 current-index: 0;
104 min-index: 0;
105
106 StackPage {
107 is-current: self.check-is-current(stack.current-index);
108 init => { self.page-index = stack.insert-page(); }
109 visible: self.page-index <= stack.current-index;
110
111 CityListView {}
112
113 // right (refresh) button
114 EdgeFloatingTextButton {
115 x: parent.width - self.width - self.edge-spacing;
116 y: parent.height - self.height - self.edge-spacing;
117
118 icon-source: AppImages.refresh;
119
120 clicked => {
121 BusyLayerController.set-busy();
122 CityWeather.refresh-all();
123 }
124 }
125
126 // left (add) button
127 EdgeFloatingTextButton {
128 x: self.edge-spacing;
129 y: parent.height - self.height - self.edge-spacing;
130
131 visible: CityWeather.can-add-city;
132
133 icon-source: AppImages.plus;
134
135 clicked => {
136 stack.show-page(PageType.AddLocation);
137 }
138 }
139 }
140
141 AnimatedStackPage {
142 is-current: self.check-is-current(stack.current-index);
143 init => { self.page-index = stack.insert-page(); }
144
145 location-search-view := LocationSearchView {
146 property<bool> is-active: parent.is-active;
147 property<bool> is-opened: parent.is-opened;
148
149 changed is-active => {
150 if (self.is-active) {
151 self.clear();
152 }
153 }
154
155 changed is-opened => {
156 if (self.is-opened) {
157 self.focus();
158 }
159 }
160
161 close-request => {
162 self.clear-focus();
163 stack.back-to-main();
164 }
165
166 EdgeFloatingTextButton {
167 x: parent.width - self.width - self.edge-spacing;
168 y: parent.height - self.height - self.edge-spacing;
169
170 icon-source: AppImages.xmark;
171
172 clicked => { location-search-view.close-request(); }
173 }
174 }
175 }
176 }
177
178 if BusyLayerController.is-busy: BusyLayer {}
179}
180