diff --git a/dashboard/src/home_assistant.rs b/dashboard/src/home_assistant.rs index cf6490f..6b8ad67 100644 --- a/dashboard/src/home_assistant.rs +++ b/dashboard/src/home_assistant.rs @@ -297,7 +297,7 @@ impl HaClient { } } upcoming.sort_by_key(|event| event.sort_epoch); - upcoming.truncate(7); + upcoming.truncate(6); Ok(upcoming) } } diff --git a/dashboard/ui/calendar.slint b/dashboard/ui/calendar.slint index c8f967a..2a20f29 100644 --- a/dashboard/ui/calendar.slint +++ b/dashboard/ui/calendar.slint @@ -9,44 +9,8 @@ import { } from "material/material.slint"; import { Icons } from "material/ui/icons/icons.slint"; -export struct CalendarEventData { - id: string, - date: string, - time: string, - summary: string, - calendar: string, -} export component Calendar inherits Rectangle { - in property <[CalendarEventData]> calendar-events; - VerticalLayout { - for event[index] in calendar-events: ListTile { - avatar_icon: Icons.calendar_today; - avatar_foreground: Palette.foreground; - text: event.date; - supporting-text: event.summary; - height: 72px; - VerticalLayout { - alignment: center; - horizontal_stretch: 1; - MaterialText { - text: event.time; - horizontal-alignment: right; - color: MaterialPalette.on_surface; - overflow: elide; - style: MaterialTypography.title_medium; - } - - MaterialText { - text: ""; - horizontal-alignment: right; - overflow: elide; - style: MaterialTypography.body_medium; - } - } - } - - Rectangle { } - } + Rectangle { } } diff --git a/dashboard/ui/climate.slint b/dashboard/ui/climate.slint deleted file mode 100644 index 702d4cc..0000000 --- a/dashboard/ui/climate.slint +++ /dev/null @@ -1,198 +0,0 @@ -import { Palette, HorizontalBox, VerticalBox } from "std-widgets.slint"; -import { Icons } from "material/ui/icons/icons.slint"; -import { - ListTile, - Vertical, - ElevatedButton, - SegmentedButton, - MaterialPalette, - FilledButton, - MaterialText, - MaterialTypography, - MaterialStyleMetrics, -} from "material/material.slint"; - -export struct WeatherData { - icon-index: int, - label: string, - temperature: float, - temperature_unit: string, -} - -export struct ThermostatData { - id: string, - name: string, - current: float, - temperature: float, - unit: string, - target: int, - remainder: int, - state: string, - available: bool, -} - -export component Climate inherits Rectangle { - in property weather; - in property <[ThermostatData]> thermostats; - in property is-night; - - in property next-event-date; - in property next-event-time; - in property next-event-summary; - - property icon-index: weather.icon-index == 1 && is-night ? 2 : weather.icon-index; - - callback set_temperature(string, float); - callback toggle_thermostat(string); - - property <[image]> icons: [ - @image-url("icons/sun.svg"), - @image-url("icons/cloud-sun.svg"), - @image-url("icons/cloud-moon.svg"), - @image-url("icons/cloud.svg"), - @image-url("icons/cloud-rain.svg"), - @image-url("icons/cloud-rain-wind.svg"), - @image-url("icons/cloud-lightning.svg"), - @image-url("icons/snowflake.svg"), - @image-url("icons/cloud-fog.svg"), - @image-url("icons/moon.svg"), - ]; - - VerticalLayout { - spacing: MaterialStyleMetrics.spacing_16; - HorizontalLayout { - Vertical { - ListTile { - avatar_icon: Icons.event_upcoming; - avatar_foreground: Palette.foreground; - text: next-event-date; - supporting-text: next-event-summary; - height: 72px; - enabled: false; - VerticalLayout { - alignment: center; - horizontal_stretch: 1; - MaterialText { - text: next-event-time; - color: MaterialPalette.on_surface; - overflow: elide; - horizontal-alignment: right; - style: MaterialTypography.title_medium; - } - - MaterialText { - text: ""; - overflow: elide; - horizontal-alignment: right; - style: MaterialTypography.body_medium; - } - } - } - } - - Vertical { - Text { - text: "\{weather.temperature}\{weather.temperature-unit}"; - font-size: 36px; - font-weight: 700; - vertical-alignment: center; - horizontal-alignment: right; - } - - Text { - text: weather.label; - font-size: 24px; - font-weight: 500; - vertical-alignment: center; - horizontal-alignment: right; - } - } - - Image { - colorize: Palette.foreground; - width: 120px; - height: 105px; - source: icons[icon-index]; - image-fit: contain; - } - } - - for thermostat[index] in thermostats: ListTile { - avatar_icon: Icons.thermostat; - avatar_foreground: Palette.foreground; - text: thermostat.name; - supporting-text: thermostat.available ? thermostat.state : "UNAVAILABLE"; - height: 72px; - enabled: false; - - ElevatedButton { - icon: Icons.remove; - clicked => { root.set_temperature(thermostat.id, thermostat.temperature - 0.5) } - } - - Rectangle { - width: 80px; - VerticalLayout { - HorizontalLayout { - Text { - text: thermostat.target; - font-size: 40px; - vertical-alignment: center; - horizontal-alignment: right; - font-weight: 700; - height: 40px; - } - - VerticalLayout { - padding-top: 2px; - Text { - text: thermostat.unit; - font-size: 14px; - horizontal-alignment: left; - vertical-alignment: top; - font-weight: 500; - height: 18px; - } - - Text { - text: ".\{thermostat.remainder}"; - // color: MaterialPalette.primary; - font-size: 14px; - horizontal-alignment: left; - vertical-alignment: bottom; - font-weight: 500; - height: 18px; - } - } - } - - Text { - text: "\{thermostat.current} \{thermostat.unit}"; - color: MaterialPalette.secondary; - font-size: 12px; - vertical-alignment: top; - horizontal-alignment: center; - font-weight: 500; - } - } - } - - ElevatedButton { - icon: Icons.add; - clicked => { root.set_temperature(thermostat.id, thermostat.temperature + 0.5) } - } - - if thermostat.state == "OFF": ElevatedButton { - icon: Icons.mode_heat_off; - clicked => { root.toggle_thermostat(thermostat.id) } - } - - if thermostat.state == "HEAT": FilledButton { - icon: Icons.mode_heat; - clicked => { root.toggle_thermostat(thermostat.id) } - } - } - - Rectangle { } - } -} diff --git a/dashboard/ui/main.slint b/dashboard/ui/main.slint index 57eea9e..52023e3 100644 --- a/dashboard/ui/main.slint +++ b/dashboard/ui/main.slint @@ -8,8 +8,14 @@ import { StandardTableView, } from "std-widgets.slint"; -import { Climate, WeatherData, ThermostatData } from "./climate.slint"; -import { CalendarEventData } from "./calendar.slint"; +import { + CalendarEventData, + MainPage, + WeatherData, + ThermostatData, +} from "./main_page.slint"; + +// import { } from "./calendar.slint"; import { Calendar } from "calendar.slint"; import { Energy } from "energy.slint"; @@ -181,10 +187,8 @@ export component AppWindow inherits Window { Rectangle { width: (root.width / 4) * 3; VerticalLayout { - if tab-bar.current-index == 0: Climate { - next-event-date: next-event-date; - next-event-time: next-event-time; - next-event-summary: next-event-summary; + MainPage { + calendar-events: calendar-events; thermostats: thermostats; is-night: is-night; @@ -193,24 +197,16 @@ export component AppWindow inherits Window { toggle_thermostat(entity_id) => { toggle_thermostat(entity_id) } } - if tab-bar.current-index == 1: Calendar { - calendar-events: calendar-events; - } - - if tab-bar.current-index == 2: Energy { - render-plot(iteration) => render-plot(iteration); - } - - Rectangle { - tab-bar := TabBar { - width: parent.width; - items: [ - { icon: Icons.wb_sunny, text: "Climate" }, - { icon: Icons.calendar_today, text: "Calendar" }, - { icon: Icons.energy_savings_leaf, text: "Energy" } - ]; - } - } + // Rectangle { + // tab-bar := TabBar { + // width: parent.width; + // items: [ + // { icon: Icons.wb_sunny, text: "Climate" }, + // { icon: Icons.calendar_today, text: "Calendar" }, + // { icon: Icons.energy_savings_leaf, text: "Energy" } + // ]; + // } + // } } } diff --git a/dashboard/ui/main_page.slint b/dashboard/ui/main_page.slint new file mode 100644 index 0000000..5c9bd12 --- /dev/null +++ b/dashboard/ui/main_page.slint @@ -0,0 +1,241 @@ +import { Palette, HorizontalBox, VerticalBox } from "std-widgets.slint"; +import { Icons } from "material/ui/icons/icons.slint"; +import { + ListTile, + Vertical, + ElevatedButton, + SegmentedButton, + MaterialPalette, + FilledButton, + MaterialText, + MaterialTypography, + MaterialStyleMetrics, +} from "material/material.slint"; + +export struct WeatherData { + icon-index: int, + label: string, + temperature: float, + temperature_unit: string, +} + +export struct ThermostatData { + id: string, + name: string, + current: float, + temperature: float, + unit: string, + target: int, + remainder: int, + state: string, + available: bool, +} + +export struct CalendarEventData { + id: string, + date: string, + time: string, + summary: string, + calendar: string, +} + +export component MainPage inherits Rectangle { + in property weather; + in property <[ThermostatData]> thermostats; + in property is-night; + + in property <[CalendarEventData]> calendar-events; + + // in property next-event-date; + // in property next-event-time; + // in property next-event-summary; + + property icon-index: weather.icon-index == 1 && is-night ? 2 : weather.icon-index; + + callback set_temperature(string, float); + callback toggle_thermostat(string); + + property <[image]> icons: [ + @image-url("icons/sun.svg"), + @image-url("icons/cloud-sun.svg"), + @image-url("icons/cloud-moon.svg"), + @image-url("icons/cloud.svg"), + @image-url("icons/cloud-rain.svg"), + @image-url("icons/cloud-rain-wind.svg"), + @image-url("icons/cloud-lightning.svg"), + @image-url("icons/snowflake.svg"), + @image-url("icons/cloud-fog.svg"), + @image-url("icons/moon.svg"), + ]; + + VerticalLayout { + spacing: MaterialStyleMetrics.spacing_16; + HorizontalLayout { + // Vertical { + // ListTile { + // avatar_icon: Icons.event_upcoming; + // avatar_foreground: Palette.foreground; + // text: next-event-date; + // supporting-text: next-event-summary; + // height: 72px; + // enabled: false; + // VerticalLayout { + // alignment: center; + // horizontal_stretch: 1; + // MaterialText { + // text: next-event-time; + // color: MaterialPalette.on_surface; + // overflow: elide; + // horizontal-alignment: right; + // style: MaterialTypography.title_medium; + // } + + // MaterialText { + // text: ""; + // overflow: elide; + // horizontal-alignment: right; + // style: MaterialTypography.body_medium; + // } + // } + // } + // } + + Vertical { + for thermostat[index] in thermostats: ListTile { + avatar_icon: Icons.thermostat; + avatar_foreground: Palette.foreground; + // text: thermostat.name; + // supporting-text: thermostat.available ? thermostat.state : "UNAVAILABLE"; + height: 72px; + enabled: false; + + ElevatedButton { + icon: Icons.remove; + enabled: thermostat.available; + clicked => { root.set_temperature(thermostat.id, thermostat.temperature - 0.5) } + } + + Rectangle { + width: 80px; + VerticalLayout { + HorizontalLayout { + Text { + text: thermostat.target; + font-size: 40px; + vertical-alignment: center; + horizontal-alignment: right; + font-weight: 700; + height: 40px; + } + + VerticalLayout { + padding-top: 2px; + Text { + text: thermostat.unit; + font-size: 14px; + horizontal-alignment: left; + vertical-alignment: top; + font-weight: 500; + height: 18px; + } + + Text { + text: ".\{thermostat.remainder}"; + // color: MaterialPalette.primary; + font-size: 14px; + horizontal-alignment: left; + vertical-alignment: bottom; + font-weight: 500; + height: 18px; + } + } + } + + Text { + text: "\{thermostat.current} \{thermostat.unit}"; + color: MaterialPalette.secondary; + font-size: 12px; + vertical-alignment: top; + horizontal-alignment: center; + font-weight: 500; + } + } + } + + ElevatedButton { + icon: Icons.add; + enabled: thermostat.available; + clicked => { root.set_temperature(thermostat.id, thermostat.temperature + 0.5) } + } + + if thermostat.state == "OFF": ElevatedButton { + icon: Icons.mode_heat_off; + enabled: thermostat.available; + clicked => { root.toggle_thermostat(thermostat.id) } + } + + if thermostat.state == "HEAT": FilledButton { + icon: Icons.mode_heat; + clicked => { root.toggle_thermostat(thermostat.id) } + } + } + } + + Vertical { + Text { + text: "\{weather.temperature}\{weather.temperature-unit}"; + font-size: 36px; + font-weight: 700; + vertical-alignment: center; + horizontal-alignment: right; + } + + Text { + text: weather.label; + font-size: 24px; + font-weight: 500; + vertical-alignment: center; + horizontal-alignment: right; + } + } + + Image { + colorize: Palette.foreground; + width: 120px; + height: 105px; + source: icons[icon-index]; + image-fit: contain; + } + } + + VerticalLayout { + for event[index] in calendar-events: ListTile { + avatar_icon: Icons.calendar_today; + avatar_foreground: Palette.foreground; + text: event.date; + supporting-text: event.summary; + height: 72px; + VerticalLayout { + alignment: center; + horizontal_stretch: 1; + MaterialText { + text: event.time; + horizontal-alignment: right; + color: MaterialPalette.on_surface; + overflow: elide; + style: MaterialTypography.title_medium; + } + + MaterialText { + text: ""; + horizontal-alignment: right; + overflow: elide; + style: MaterialTypography.body_medium; + } + } + } + + Rectangle { } + } + } +}