summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKamil Hajdukiewicz <kaj@spyro-soft.com>2023-06-20 08:03:50 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2023-06-20 12:30:32 +0000
commitd134e41edc366cb9989d6d0410054a44b3a01f07 (patch)
tree1390b024f965eb9ad9baa3013e89ee686c95a752
parentf6d2c09907a0a0d3c1737d56cc86c968e4afe1bd (diff)
Revamp Thermostat example 2
The new responsive design of Thermostat Example is implemented. The application is prepared to look good on desktop, mobile and small displays. In the current state only part of the application is prepared. Schedule View is not ready. What is done: 1. Rooms View 2. Thermostat Control View 3. Statistics View 4. Dark/Light mode Change-Id: I52d07b7001b1f78025d74ab827e58b5d23b2dedb Reviewed-by: <kaj@spyro-soft.com> Reviewed-by: Kimmo Leppälä <kimmo.leppala@qt.io> Reviewed-by: Jani Heikkinen <jani.heikkinen@qt.io> (cherry picked from commit 3f9c25bdb70e984e2bda6ea27121ff0a12a332f6) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--examples/demos/CMakeLists.txt4
-rw-r--r--examples/demos/thermostat/CMakeLists.txt43
-rw-r--r--examples/demos/thermostat/Main.qml8
-rw-r--r--examples/demos/thermostat/Thermostat.qmlproject96
-rw-r--r--examples/demos/thermostat/content/App.qml38
-rw-r--r--examples/demos/thermostat/content/BottomBar.qml8
-rw-r--r--examples/demos/thermostat/content/BottomBarForm.ui.qml62
-rw-r--r--examples/demos/thermostat/content/CMakeLists.txt98
-rw-r--r--examples/demos/thermostat/content/EnergyInfo.qml12
-rw-r--r--examples/demos/thermostat/content/EnergyInfoForm.ui.qml24
-rw-r--r--examples/demos/thermostat/content/HomePage.qml8
-rw-r--r--examples/demos/thermostat/content/HomePageForm.ui.qml234
-rw-r--r--examples/demos/thermostat/content/HumidityInfo.qml21
-rw-r--r--examples/demos/thermostat/content/HumidityInfoForm.ui.qml26
-rw-r--r--examples/demos/thermostat/content/RoomItem.qml8
-rw-r--r--examples/demos/thermostat/content/RoomItemForm.ui.qml308
-rw-r--r--examples/demos/thermostat/content/RoomOption.qml8
-rw-r--r--examples/demos/thermostat/content/RoomOptionForm.ui.qml56
-rw-r--r--examples/demos/thermostat/content/RoomsScrollView.qml8
-rw-r--r--examples/demos/thermostat/content/RoomsScrollViewForm.ui.qml47
-rw-r--r--examples/demos/thermostat/content/RoomsSwipeView.qml10
-rw-r--r--examples/demos/thermostat/content/RoomsSwipeViewForm.ui.qml107
-rw-r--r--examples/demos/thermostat/content/RoomsView.qml8
-rw-r--r--examples/demos/thermostat/content/RoomsViewForm.ui.qml193
-rw-r--r--examples/demos/thermostat/content/ScheduleScrollView.qml8
-rw-r--r--examples/demos/thermostat/content/ScheduleScrollViewForm.ui.qml78
-rw-r--r--examples/demos/thermostat/content/ScheduleSwipeView.qml8
-rw-r--r--examples/demos/thermostat/content/ScheduleSwipeViewForm.ui.qml77
-rw-r--r--examples/demos/thermostat/content/ScheduleView.qml8
-rw-r--r--examples/demos/thermostat/content/ScheduleViewForm.ui.qml176
-rw-r--r--examples/demos/thermostat/content/SideBar.qml8
-rw-r--r--examples/demos/thermostat/content/SideBarForm.ui.qml220
-rw-r--r--examples/demos/thermostat/content/StatisticsScrollView.qml8
-rw-r--r--examples/demos/thermostat/content/StatisticsScrollViewForm.ui.qml169
-rw-r--r--examples/demos/thermostat/content/StatisticsStackView.qml8
-rw-r--r--examples/demos/thermostat/content/StatisticsStackViewForm.ui.qml39
-rw-r--r--examples/demos/thermostat/content/StatisticsSwipeView.qml8
-rw-r--r--examples/demos/thermostat/content/StatisticsSwipeViewForm.ui.qml79
-rw-r--r--examples/demos/thermostat/content/StatisticsView.qml8
-rw-r--r--examples/demos/thermostat/content/StatisticsViewForm.ui.qml188
-rw-r--r--examples/demos/thermostat/content/TemperatureInfo.qml8
-rw-r--r--examples/demos/thermostat/content/TemperatureInfoForm.ui.qml26
-rw-r--r--examples/demos/thermostat/content/TemperatureSetter.qml8
-rw-r--r--examples/demos/thermostat/content/TemperatureSetterDesktopView.qml8
-rw-r--r--examples/demos/thermostat/content/TemperatureSetterDesktopViewForm.ui.qml156
-rw-r--r--examples/demos/thermostat/content/TemperatureSetterForm.ui.qml91
-rw-r--r--examples/demos/thermostat/content/TemperatureSetterMobileView.qml8
-rw-r--r--examples/demos/thermostat/content/TemperatureSetterMobileViewForm.ui.qml154
-rw-r--r--examples/demos/thermostat/content/TemperatureSetterSmallView.qml8
-rw-r--r--examples/demos/thermostat/content/TemperatureSetterSmallViewForm.ui.qml189
-rw-r--r--examples/demos/thermostat/content/ThermostatInfo.qml8
-rw-r--r--examples/demos/thermostat/content/ThermostatInfoForm.ui.qml258
-rw-r--r--examples/demos/thermostat/content/ThermostatScrollView.qml8
-rw-r--r--examples/demos/thermostat/content/ThermostatScrollViewForm.ui.qml120
-rw-r--r--examples/demos/thermostat/content/ThermostatSettings.qml8
-rw-r--r--examples/demos/thermostat/content/ThermostatSettingsForm.ui.qml322
-rw-r--r--examples/demos/thermostat/content/ThermostatStackView.qml8
-rw-r--r--examples/demos/thermostat/content/ThermostatStackViewForm.ui.qml44
-rw-r--r--examples/demos/thermostat/content/ThermostatSwipeView.qml8
-rw-r--r--examples/demos/thermostat/content/ThermostatSwipeViewForm.ui.qml86
-rw-r--r--examples/demos/thermostat/content/ThermostatView.qml8
-rw-r--r--examples/demos/thermostat/content/ThermostatViewForm.ui.qml184
-rw-r--r--examples/demos/thermostat/content/TimeSchedule.qml8
-rw-r--r--examples/demos/thermostat/content/TimeScheduleForm.ui.qml104
-rw-r--r--examples/demos/thermostat/content/images/Auto.svg4
-rw-r--r--examples/demos/thermostat/content/images/Cool.svg3
-rw-r--r--examples/demos/thermostat/content/images/Dry.svg3
-rw-r--r--examples/demos/thermostat/content/images/Eco.svg3
-rw-r--r--examples/demos/thermostat/content/images/Fan.svg3
-rw-r--r--examples/demos/thermostat/content/images/Heat.svg3
-rw-r--r--examples/demos/thermostat/content/images/arrow.svg3
-rw-r--r--examples/demos/thermostat/content/images/bedroom.svg10
-rw-r--r--examples/demos/thermostat/content/images/circle.svg17
-rw-r--r--examples/demos/thermostat/content/images/down.svg3
-rw-r--r--examples/demos/thermostat/content/images/drop.svg3
-rw-r--r--examples/demos/thermostat/content/images/edit.svg3
-rw-r--r--examples/demos/thermostat/content/images/energy.svg3
-rw-r--r--examples/demos/thermostat/content/images/home.svg3
-rw-r--r--examples/demos/thermostat/content/images/kid_room.svg12
-rw-r--r--examples/demos/thermostat/content/images/kitchen.svg10
-rw-r--r--examples/demos/thermostat/content/images/living_room.svg10
-rw-r--r--examples/demos/thermostat/content/images/logo.pngbin0 -> 2479 bytes
-rw-r--r--examples/demos/thermostat/content/images/maxTemp.svg3
-rw-r--r--examples/demos/thermostat/content/images/minTemp.svg3
-rw-r--r--examples/demos/thermostat/content/images/more.svg5
-rw-r--r--examples/demos/thermostat/content/images/power.svg3
-rw-r--r--examples/demos/thermostat/content/images/schedule.svg3
-rw-r--r--examples/demos/thermostat/content/images/settings.svg3
-rw-r--r--examples/demos/thermostat/content/images/stats.svg3
-rw-r--r--examples/demos/thermostat/content/images/temperature.svg3
-rw-r--r--examples/demos/thermostat/content/images/theme.svg3
-rw-r--r--examples/demos/thermostat/content/images/thermostat.svg3
-rw-r--r--examples/demos/thermostat/content/images/up.svg3
-rw-r--r--examples/demos/thermostat/doc/images/desktop_dark.pngbin0 -> 46949 bytes
-rw-r--r--examples/demos/thermostat/doc/images/desktop_light.pngbin0 -> 45833 bytes
-rw-r--r--examples/demos/thermostat/doc/images/mobile_dark.pngbin0 -> 20606 bytes
-rw-r--r--examples/demos/thermostat/doc/images/mobile_light.pngbin0 -> 20842 bytes
-rw-r--r--examples/demos/thermostat/doc/images/small_dark.pngbin0 -> 9456 bytes
-rw-r--r--examples/demos/thermostat/doc/images/small_light.pngbin0 -> 10146 bytes
-rw-r--r--examples/demos/thermostat/doc/src/thermostat.qdoc52
-rw-r--r--examples/demos/thermostat/imports/CMakeLists.txt5
-rw-r--r--examples/demos/thermostat/imports/CustomControls/CMakeLists.txt24
-rw-r--r--examples/demos/thermostat/imports/CustomControls/CustomComboBox.qml109
-rw-r--r--examples/demos/thermostat/imports/CustomControls/CustomDial.qml86
-rw-r--r--examples/demos/thermostat/imports/CustomControls/CustomRadioButton.qml49
-rw-r--r--examples/demos/thermostat/imports/CustomControls/CustomRoundButton.qml36
-rw-r--r--examples/demos/thermostat/imports/CustomControls/CustomSlider.qml98
-rw-r--r--examples/demos/thermostat/imports/CustomControls/CustomSwitch.qml99
-rw-r--r--examples/demos/thermostat/imports/CustomControls/CustomTextField.qml49
-rw-r--r--examples/demos/thermostat/imports/CustomControls/StatisticsChart.qml198
-rw-r--r--examples/demos/thermostat/imports/CustomControls/TemperatureLabel.qml95
-rw-r--r--examples/demos/thermostat/imports/CustomControls/ThermostatControl.qml204
-rw-r--r--examples/demos/thermostat/imports/CustomControls/TimeSelector.qml151
-rw-r--r--examples/demos/thermostat/imports/CustomControls/images/keyboard.svg3
-rw-r--r--examples/demos/thermostat/imports/CustomControls/images/thermometer.svg3
-rw-r--r--examples/demos/thermostat/imports/CustomControls/images/tooltip.svg3
-rw-r--r--examples/demos/thermostat/imports/CustomControls/qmldir14
-rw-r--r--examples/demos/thermostat/imports/Thermostat/AppSettings.qml10
-rw-r--r--examples/demos/thermostat/imports/Thermostat/CMakeLists.txt22
-rw-r--r--examples/demos/thermostat/imports/Thermostat/Constants.qml47
-rw-r--r--examples/demos/thermostat/imports/Thermostat/RoomsModel.qml1497
-rw-r--r--examples/demos/thermostat/imports/Thermostat/qmldir8
-rw-r--r--examples/demos/thermostat/qmlcomponents33
-rw-r--r--examples/demos/thermostat/qmlmodules18
-rw-r--r--examples/demos/thermostat/qt_attribution.json55
-rw-r--r--examples/demos/thermostat/qtquickcontrols2.conf2
-rw-r--r--examples/demos/thermostat/src/app_environment.h11
-rw-r--r--examples/demos/thermostat/src/import_qml_components_plugins.h17
-rw-r--r--examples/demos/thermostat/src/import_qml_plugins.h9
-rw-r--r--examples/demos/thermostat/src/main.cpp24
130 files changed, 7516 insertions, 1 deletions
diff --git a/examples/demos/CMakeLists.txt b/examples/demos/CMakeLists.txt
index 313d6d7ac..05f1292dd 100644
--- a/examples/demos/CMakeLists.txt
+++ b/examples/demos/CMakeLists.txt
@@ -28,8 +28,10 @@ if(TARGET Qt6::Widgets AND TARGET Qt6::PdfWidgets)
endif()
if(TARGET Qt::Quick AND TARGET Qt::QuickControls2 AND TARGET Qt::Quick3D)
qt_internal_add_example(robotarm)
- qt_internal_add_example(FX_Material_Showroom)
endif()
if(TARGET Qt::Quick AND TARGET Qt::QuickControls2 AND TARGET Qt::Multimedia)
qt_internal_add_example(mediaplayer)
endif()
+if(TARGET Qt6::Quick AND TARGET Qt6::QuickControls2 AND TARGET Qt6::Charts)
+ qt_internal_add_example(thermostat)
+endif()
diff --git a/examples/demos/thermostat/CMakeLists.txt b/examples/demos/thermostat/CMakeLists.txt
new file mode 100644
index 000000000..a5d243ab0
--- /dev/null
+++ b/examples/demos/thermostat/CMakeLists.txt
@@ -0,0 +1,43 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+
+set(BUILD_QDS_COMPONENTS ON CACHE BOOL "Build design studio components")
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/demos/thermostat")
+
+project(ThermostatApp LANGUAGES CXX)
+
+find_package(Qt6 6.5 REQUIRED COMPONENTS Gui Qml Quick QuickControls2 Svg Charts)
+
+qt_standard_project_setup(REQUIRES 6.5)
+
+qt_add_executable(ThermostatApp src/main.cpp)
+
+qt_add_resources(ThermostatApp "configuration"
+ PREFIX "/"
+ FILES
+ qtquickcontrols2.conf
+)
+
+if (${BUILD_QDS_COMPONENTS})
+ include(qmlcomponents)
+endif ()
+
+include(qmlmodules)
+
+target_link_libraries(ThermostatApp PRIVATE
+ Qt6::Core
+ Qt6::Gui
+ Qt6::Quick
+ Qt6::Qml
+ Qt6::Svg
+ Qt6::Charts
+ Qt6::QuickControls2
+)
+
+install(TARGETS ThermostatApp
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/examples/demos/thermostat/Main.qml b/examples/demos/thermostat/Main.qml
new file mode 100644
index 000000000..bd50dcad1
--- /dev/null
+++ b/examples/demos/thermostat/Main.qml
@@ -0,0 +1,8 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import content
+
+App {
+}
diff --git a/examples/demos/thermostat/Thermostat.qmlproject b/examples/demos/thermostat/Thermostat.qmlproject
new file mode 100644
index 000000000..c7534c361
--- /dev/null
+++ b/examples/demos/thermostat/Thermostat.qmlproject
@@ -0,0 +1,96 @@
+import QmlProject
+
+Project {
+ mainFile: "content/App.qml"
+ mainUiFile: "content/HomePageForm.ui.qml"
+
+ /* Include .qml, .js, and image files from current directory and subdirectories */
+ QmlFiles {
+ directory: "content"
+ }
+
+ QmlFiles {
+ directory: "imports"
+ }
+
+ JavaScriptFiles {
+ directory: "content"
+ }
+
+ JavaScriptFiles {
+ directory: "imports"
+ }
+
+ ImageFiles {
+ directory: "content"
+ }
+
+ Files {
+ filter: "*.conf"
+ files: ["qtquickcontrols2.conf"]
+ }
+
+ Files {
+ filter: "qmldir"
+ directory: "."
+ }
+
+ Files {
+ filter: "qmldir"
+ directory: "imports/CustomControls"
+ }
+
+ Files {
+ filter: "*.ttf;*.otf"
+ }
+
+ Files {
+ filter: "*.wav;*.mp3"
+ }
+
+ Files {
+ filter: "*.mp4"
+ }
+
+ Files {
+ filter: "*.glsl;*.glslv;*.glslf;*.vsh;*.fsh;*.vert;*.frag"
+ }
+
+ Files {
+ filter: "*.qsb"
+ }
+
+ Environment {
+ QT_QUICK_CONTROLS_CONF: "qtquickcontrols2.conf"
+ QML_COMPAT_RESOLVE_URLS_ON_ASSIGNMENT: "1"
+ }
+
+ qt6Project: true
+
+ /* List of plugin directories passed to QML runtime */
+ importPaths: [ "imports" ]
+
+ /* Required for deployment */
+ targetDirectory: "/opt/thermostat"
+
+ qdsVersion: "4.1"
+
+ quickVersion: "6.5"
+
+ /* If any modules the project imports require widgets (e.g. QtCharts), widgetApp must be true */
+ widgetApp: true
+
+ /* args: Specifies command line arguments for qsb tool to generate shaders.
+ files: Specifies target files for qsb tool. If path is included, it must be relative to this file.
+ Wildcard '*' can be used in the file name part of the path.
+ e.g. files: [ "content/shaders/*.vert", "*.frag" ] */
+ ShaderTool {
+ args: "-s --glsl \"100 es,120,150\" --hlsl 50 --msl 12"
+ files: [ "content/shaders/*" ]
+ }
+
+ multilanguageSupport: true
+ supportedLanguages: ["en"]
+ primaryLanguage: "en"
+
+}
diff --git a/examples/demos/thermostat/content/App.qml b/examples/demos/thermostat/content/App.qml
new file mode 100644
index 000000000..c204029be
--- /dev/null
+++ b/examples/demos/thermostat/content/App.qml
@@ -0,0 +1,38 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import Thermostat
+
+Window {
+ id: window
+
+ width: Constants.width
+ height: Constants.height
+
+ minimumHeight: 272
+ minimumWidth: Qt.PrimaryOrientation === Qt.LandscapeOrientation ? 480 : 360
+
+ visible: true
+ title: "Thermostat"
+
+ HomePage {
+ id: mainScreen
+ anchors.fill: parent
+ }
+
+ Component.onCompleted: function() {
+ Constants.isBigDesktopLayout = Qt.binding( function(){
+ return window.width >= Constants.width && window.width >= window.height
+ })
+ Constants.isSmallDesktopLayout = Qt.binding( function(){
+ return window.width >= 647 && window.width < Constants.width && window.width >= window.height
+ })
+ Constants.isMobileLayout = Qt.binding( function(){
+ return window.width < window.height
+ })
+ Constants.isSmallLayout = Qt.binding( function(){
+ return window.width < 647 && window.width >= window.height
+ })
+ }
+}
diff --git a/examples/demos/thermostat/content/BottomBar.qml b/examples/demos/thermostat/content/BottomBar.qml
new file mode 100644
index 000000000..079159475
--- /dev/null
+++ b/examples/demos/thermostat/content/BottomBar.qml
@@ -0,0 +1,8 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+BottomBarForm {
+
+}
diff --git a/examples/demos/thermostat/content/BottomBarForm.ui.qml b/examples/demos/thermostat/content/BottomBarForm.ui.qml
new file mode 100644
index 000000000..8a9fb4a58
--- /dev/null
+++ b/examples/demos/thermostat/content/BottomBarForm.ui.qml
@@ -0,0 +1,62 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+
+/*
+This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
+It is supposed to be strictly declarative and only uses a subset of QML. If you edit
+this file manually, you might introduce QML code that is not supported by Qt Design Studio.
+Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
+*/
+import QtQuick
+import QtQuick.Controls
+import Thermostat
+
+TabBar {
+ id: root
+
+ required property var roomsList
+ property alias menuOptions: repeater.model
+
+ contentHeight: 56
+
+ background: Rectangle {
+ color: Constants.accentColor
+ border.color: Constants.accentTextColor
+ radius: 12
+ }
+
+ Repeater {
+ id: repeater
+
+ delegate: TabButton {
+ id: menuItem
+
+ required property string name
+ required property string view
+ required property string iconSource
+ readonly property bool active: Constants.currentView == menuItem.view
+
+ background: Rectangle {
+ color: "transparent"
+ }
+
+ icon.width: 24
+ icon.height: 24
+ icon.source: "images/" + menuItem.iconSource
+ icon.color: menuItem.active ? "#2CDE85" : Constants.accentTextColor
+
+ Connections {
+ function onClicked() {
+ if (menuItem.view != "SettingsView"
+ && menuItem.view != Constants.currentView) {
+ stackView.replace(menuItem.view + ".qml", {
+ "roomsList": roomsList
+ }, StackView.Immediate)
+ Constants.currentView = menuItem.view
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/examples/demos/thermostat/content/CMakeLists.txt b/examples/demos/thermostat/content/CMakeLists.txt
new file mode 100644
index 000000000..025b2b23a
--- /dev/null
+++ b/examples/demos/thermostat/content/CMakeLists.txt
@@ -0,0 +1,98 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+qt_add_library(content STATIC)
+qt_add_qml_module(content
+ URI "content"
+ VERSION 1.0
+ QML_FILES
+ App.qml
+ BottomBar.qml
+ BottomBarForm.ui.qml
+ EnergyInfo.qml
+ EnergyInfoForm.ui.qml
+ HomePage.qml
+ HomePageForm.ui.qml
+ HumidityInfo.qml
+ HumidityInfoForm.ui.qml
+ RoomItem.qml
+ RoomItemForm.ui.qml
+ RoomOption.qml
+ RoomOptionForm.ui.qml
+ RoomsScrollView.qml
+ RoomsScrollViewForm.ui.qml
+ RoomsSwipeView.qml
+ RoomsSwipeViewForm.ui.qml
+ RoomsView.qml
+ RoomsViewForm.ui.qml
+ ScheduleScrollView.qml
+ ScheduleScrollViewForm.ui.qml
+ ScheduleSwipeView.qml
+ ScheduleSwipeViewForm.ui.qml
+ ScheduleView.qml
+ ScheduleViewForm.ui.qml
+ SideBar.qml
+ SideBarForm.ui.qml
+ StatisticsScrollView.qml
+ StatisticsScrollViewForm.ui.qml
+ StatisticsStackView.qml
+ StatisticsStackViewForm.ui.qml
+ StatisticsSwipeView.qml
+ StatisticsSwipeViewForm.ui.qml
+ StatisticsView.qml
+ StatisticsViewForm.ui.qml
+ TemperatureInfo.qml
+ TemperatureInfoForm.ui.qml
+ TemperatureSetter.qml
+ TemperatureSetterDesktopView.qml
+ TemperatureSetterDesktopViewForm.ui.qml
+ TemperatureSetterForm.ui.qml
+ TemperatureSetterMobileView.qml
+ TemperatureSetterMobileViewForm.ui.qml
+ TemperatureSetterSmallView.qml
+ TemperatureSetterSmallViewForm.ui.qml
+ ThermostatInfo.qml
+ ThermostatInfoForm.ui.qml
+ ThermostatScrollView.qml
+ ThermostatScrollViewForm.ui.qml
+ ThermostatSettings.qml
+ ThermostatSettingsForm.ui.qml
+ ThermostatStackView.qml
+ ThermostatStackViewForm.ui.qml
+ ThermostatSwipeView.qml
+ ThermostatSwipeViewForm.ui.qml
+ ThermostatView.qml
+ ThermostatViewForm.ui.qml
+ TimeSchedule.qml
+ TimeScheduleForm.ui.qml
+ RESOURCES
+ images/arrow.svg
+ images/Auto.svg
+ images/bedroom.svg
+ images/circle.svg
+ images/Cool.svg
+ images/down.svg
+ images/drop.svg
+ images/Dry.svg
+ images/Eco.svg
+ images/edit.svg
+ images/energy.svg
+ images/Fan.svg
+ images/Heat.svg
+ images/home.svg
+ images/kid_room.svg
+ images/kitchen.svg
+ images/living_room.svg
+ images/logo.png
+ images/maxTemp.svg
+ images/minTemp.svg
+ images/more.svg
+ images/power.svg
+ images/schedule.svg
+ images/settings.svg
+ images/stats.svg
+ images/temperature.svg
+ images/theme.svg
+ images/thermostat.svg
+ images/up.svg
+)
diff --git a/examples/demos/thermostat/content/EnergyInfo.qml b/examples/demos/thermostat/content/EnergyInfo.qml
new file mode 100644
index 000000000..964424315
--- /dev/null
+++ b/examples/demos/thermostat/content/EnergyInfo.qml
@@ -0,0 +1,12 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+EnergyInfoForm {
+ Component.onCompleted: function() {
+ for (let i = 0; i < energyValuesModel.count; ++i) {
+ totalEnergy += energyValuesModel.get(i).enrg
+ }
+ }
+}
diff --git a/examples/demos/thermostat/content/EnergyInfoForm.ui.qml b/examples/demos/thermostat/content/EnergyInfoForm.ui.qml
new file mode 100644
index 000000000..0fd82d2d5
--- /dev/null
+++ b/examples/demos/thermostat/content/EnergyInfoForm.ui.qml
@@ -0,0 +1,24 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+
+/*
+This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
+It is supposed to be strictly declarative and only uses a subset of QML. If you edit
+this file manually, you might introduce QML code that is not supported by Qt Design Studio.
+Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
+*/
+import QtQuick
+
+ThermostatInfo {
+
+ required property var energyValuesModel
+
+ property int totalEnergy: 0
+ property real costOf1KWH: 0.23
+
+ title: qsTr("Energy Usage")
+ leftIcon: "images/energy.svg"
+ topLabel: qsTr("Total: %1 KWH".arg(totalEnergy))
+ bottomLeftLabel: qsTr("Estimeted Cost: $%1".arg(totalEnergy * costOf1KWH))
+}
diff --git a/examples/demos/thermostat/content/HomePage.qml b/examples/demos/thermostat/content/HomePage.qml
new file mode 100644
index 000000000..8122a2259
--- /dev/null
+++ b/examples/demos/thermostat/content/HomePage.qml
@@ -0,0 +1,8 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+HomePageForm {
+
+}
diff --git a/examples/demos/thermostat/content/HomePageForm.ui.qml b/examples/demos/thermostat/content/HomePageForm.ui.qml
new file mode 100644
index 000000000..366426306
--- /dev/null
+++ b/examples/demos/thermostat/content/HomePageForm.ui.qml
@@ -0,0 +1,234 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+
+/*
+This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
+It is supposed to be strictly declarative and only uses a subset of QML. If you edit
+this file manually, you might introduce QML code that is not supported by Qt Design Studio.
+Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
+*/
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import Thermostat
+
+Page {
+ id: root
+
+ header: ToolBar {
+ id: toolBar
+
+ background: Rectangle {
+ color: Constants.accentColor
+ }
+
+ RowLayout {
+ anchors.fill: parent
+ Image {
+ id: qtLogo
+
+ Layout.topMargin: 6
+ Layout.bottomMargin: 6
+ Layout.leftMargin: 38
+ source: "images/logo"
+ sourceSize.height: 50
+ }
+
+ Item {
+ Layout.fillWidth: true
+ }
+
+ Image {
+ id: themeTapButton
+
+ source: "images/theme.svg"
+ sourceSize.height: Constants.isSmallLayout ? 15 : 20
+ sourceSize.width: Constants.isSmallLayout ? 15 : 20
+ Layout.rightMargin: Constants.isSmallLayout ? 5 : 19
+ visible: Constants.isSmallLayout || Constants.isMobileLayout
+
+ TapHandler {
+ onTapped: AppSettings.isDarkTheme = !AppSettings.isDarkTheme
+ }
+ }
+ }
+ }
+
+ background: Rectangle {
+ color: Constants.accentColor
+ }
+
+ StackView {
+ id: stackView
+
+ anchors.left: sideMenu.right
+ anchors.right: parent.right
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+
+ initialItem: RoomsView {
+ roomsList: roomsList
+ }
+ }
+
+ SideBar {
+ id: sideMenu
+
+ anchors.left: parent.left
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ anchors.topMargin: 63
+ height: parent.height
+
+ menuOptions: menuItems
+ roomsList: roomsList
+ }
+
+ BottomBar {
+ id: bottomMenu
+
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ width: parent.width
+
+ visible: false
+ position: TabBar.Footer
+ menuOptions: menuItems
+ roomsList: roomsList
+ }
+
+ RoomsModel {
+ id: roomsList
+ }
+
+ ListModel {
+ id: menuItems
+
+ ListElement {
+ name: qsTr("Rooms")
+ view: "RoomsView"
+ iconSource: "home.svg"
+ }
+ ListElement {
+ name: qsTr("Thermostat Control")
+ view: "ThermostatView"
+ iconSource: "thermostat.svg"
+ }
+ ListElement {
+ name: qsTr("Stats")
+ view: "StatisticsView"
+ iconSource: "stats.svg"
+ }
+ ListElement {
+ name: qsTr("Settings")
+ view: "SettingsView"
+ iconSource: "settings.svg"
+ }
+ }
+
+ states: [
+ State {
+ name: "mobileLayout"
+ when: Constants.isMobileLayout
+
+ PropertyChanges {
+ target: sideMenu
+ visible: false
+ }
+ PropertyChanges {
+ target: bottomMenu
+ visible: true
+ }
+ PropertyChanges {
+ target: stackView
+ anchors.leftMargin: 0
+ }
+ PropertyChanges {
+ target: qtLogo
+ Layout.leftMargin: 19
+ sourceSize.height: 25
+ Layout.topMargin: 7
+ Layout.bottomMargin: 7
+ }
+ PropertyChanges {
+ target: toolBar
+ height: 39
+ }
+ AnchorChanges {
+ target: stackView
+ anchors.left: parent.left
+ anchors.bottom: bottomMenu.top
+ }
+ },
+ State {
+ name: "desktopLayout"
+ when: Constants.isBigDesktopLayout || Constants.isSmallDesktopLayout
+
+ PropertyChanges {
+ target: sideMenu
+ visible: true
+ anchors.topMargin: 63
+ }
+ PropertyChanges {
+ target: bottomMenu
+ visible: false
+ }
+ PropertyChanges {
+ target: stackView
+ anchors.leftMargin: 5
+ }
+ PropertyChanges {
+ target: qtLogo
+ Layout.leftMargin: 38
+ sourceSize.height: 50
+ Layout.topMargin: 6
+ Layout.bottomMargin: 6
+ }
+ PropertyChanges {
+ target: toolBar
+ height: 56
+ }
+ AnchorChanges {
+ target: stackView
+ anchors.left: sideMenu.right
+ anchors.bottom: parent.bottom
+ }
+ },
+ State {
+ name: "smallLayout"
+ when: Constants.isSmallLayout
+
+ PropertyChanges {
+ target: sideMenu
+ visible: true
+ anchors.topMargin: 24
+ }
+ PropertyChanges {
+ target: bottomMenu
+ visible: false
+ }
+ PropertyChanges {
+ target: stackView
+ anchors.leftMargin: 5
+ }
+ PropertyChanges {
+ target: qtLogo
+ Layout.leftMargin: 5
+ sourceSize.height: 18
+ Layout.topMargin: 5
+ Layout.bottomMargin: 0
+ }
+ PropertyChanges {
+ target: toolBar
+ height: 24
+ }
+ AnchorChanges {
+ target: stackView
+ anchors.left: sideMenu.right
+ anchors.bottom: parent.bottom
+ }
+ }
+ ]
+}
diff --git a/examples/demos/thermostat/content/HumidityInfo.qml b/examples/demos/thermostat/content/HumidityInfo.qml
new file mode 100644
index 000000000..62919e4f9
--- /dev/null
+++ b/examples/demos/thermostat/content/HumidityInfo.qml
@@ -0,0 +1,21 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+HumidityInfoForm {
+ Component.onCompleted: function() {
+ var hmd = []
+ var sum = 0
+ var count = humidityValuesModel.count
+ for (let i = 0; i < count; ++i) {
+ sum += humidityValuesModel.get(i).hmd
+ hmd.push(humidityValuesModel.get(i).hmd)
+ }
+ humidityAvg = sum / count
+ humidityDiff = 100 * ( humidityValuesModel.get(count-1).hmd /
+ humidityValuesModel.get(count-2).hmd - 1)
+ humidityValues = hmd
+ isMore = humidityDiff > 0
+ }
+}
diff --git a/examples/demos/thermostat/content/HumidityInfoForm.ui.qml b/examples/demos/thermostat/content/HumidityInfoForm.ui.qml
new file mode 100644
index 000000000..4b36ead1a
--- /dev/null
+++ b/examples/demos/thermostat/content/HumidityInfoForm.ui.qml
@@ -0,0 +1,26 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+/*
+This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
+It is supposed to be strictly declarative and only uses a subset of QML. If you edit
+this file manually, you might introduce QML code that is not supported by Qt Design Studio.
+Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
+*/
+import QtQuick
+
+ThermostatInfo {
+
+ required property var humidityValuesModel
+ property var humidityValues
+ property int humidityAvg
+ property int humidityDiff
+ property bool isMore
+
+ title: qsTr("Humidity")
+ leftIcon: "images/drop.svg"
+ topLabel: qsTr("Avarage: %1 %".arg(humidityAvg))
+ bottomLeftLabel: isMore ? qsTr("%1 % more than Last Month".arg(humidityDiff)) :
+ qsTr("%1 % less than Last Month".arg(Math.abs(humidityDiff)))
+ bottomLeftIcon: isMore ? "images/up" : "images/down"
+}
diff --git a/examples/demos/thermostat/content/RoomItem.qml b/examples/demos/thermostat/content/RoomItem.qml
new file mode 100644
index 000000000..b221b6319
--- /dev/null
+++ b/examples/demos/thermostat/content/RoomItem.qml
@@ -0,0 +1,8 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+RoomItemForm {
+
+}
diff --git a/examples/demos/thermostat/content/RoomItemForm.ui.qml b/examples/demos/thermostat/content/RoomItemForm.ui.qml
new file mode 100644
index 000000000..0f8de640e
--- /dev/null
+++ b/examples/demos/thermostat/content/RoomItemForm.ui.qml
@@ -0,0 +1,308 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+
+/*
+This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
+It is supposed to be strictly declarative and only uses a subset of QML. If you edit
+this file manually, you might introduce QML code that is not supported by Qt Design Studio.
+Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
+*/
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import QtQuick.Effects
+import CustomControls
+import Thermostat
+
+Pane {
+ id: root
+
+ property bool isSmallLayout: false
+
+ property alias isEnabled: toggle.checked
+ property alias toggle: toggle
+
+ required property string name
+ required property string floor
+ required property string iconName
+ required property int temp
+ required property int humidity
+ required property int energy
+ required property bool active
+ required property var model
+
+ width: internal.width
+ height: internal.height
+
+ topPadding: 12
+ leftPadding: internal.leftPadding
+ bottomPadding: 0
+ rightPadding: 16
+
+ background: Rectangle {
+ radius: 12
+ color: Constants.accentColor
+ }
+
+ RowLayout {
+ id: header
+
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.top: parent.top
+ anchors.rightMargin: internal.switchMargin
+ spacing: 16
+
+ Item {
+ Layout.preferredWidth: internal.iconSize
+ Layout.preferredHeight: internal.iconSize
+ Layout.alignment: Qt.AlignTop
+
+ Image {
+ id: icon
+
+ source: "images/" + root.iconName
+ sourceSize.width: internal.iconSize
+ sourceSize.height: internal.iconSize
+ }
+
+ MultiEffect {
+ anchors.fill: icon
+ source: icon
+ colorization: 1
+ colorizationColor: Constants.iconColor
+ }
+ }
+
+ Column {
+ id: title
+
+ Layout.fillWidth: true
+ spacing: internal.titleSpacing
+
+ Label {
+ text: root.name
+ font.pixelSize: !root.isSmallLayout ? 24 : 18
+ font.weight: 600
+ font.family: "Titillium Web"
+ color: Constants.primaryTextColor
+ }
+
+ Label {
+ text: root.floor
+ font.pixelSize: 10
+ font.weight: 400
+ font.family: "Titillium Web"
+ color: Constants.accentTextColor
+ }
+ }
+
+ CustomSwitch {
+ id: toggle
+ checked: root.active
+ onCheckedChanged: model.active = toggle.checked
+ }
+ }
+
+ Column {
+ id: column
+
+ spacing: internal.spacing
+ anchors.left: parent.left
+ anchors.leftMargin: internal.columnMargin
+ anchors.top: header.bottom
+ anchors.topMargin: !root.isSmallLayout ? 10 : 8
+
+ Repeater {
+ model: [qsTr("Humidity: %1%".arg(humidity)), qsTr(
+ "Energy Usage: %1 KM/H".arg(energy))]
+
+ Label {
+ text: modelData
+ font.pixelSize: !root.isSmallLayout ? 14 : 12
+ font.weight: 400
+ font.family: "Titillium Web"
+ color: toggle.checked ? Constants.primaryTextColor : "#898989"
+ }
+ }
+ }
+
+ TemperatureLabel {
+ id: temp
+
+ anchors.verticalCenter: column.verticalCenter
+ anchors.right: parent.right
+ anchors.rightMargin: internal.rightMargin
+ isEnabled: root.isEnabled
+ isHeating: root.model.thermostatTemp > root.model.temp
+ tempValue: root.temp
+ }
+
+ Rectangle {
+ id: separator
+
+ anchors.bottom: menu.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+ height: 1
+ color: "#DCDCDC"
+ }
+
+ ListModel {
+ id: roomOptions
+ ListElement {
+ name: "Cool"
+ }
+ ListElement {
+ name: "Heat"
+ }
+ ListElement {
+ name: "Dry"
+ }
+ ListElement {
+ name: "Fan"
+ }
+ ListElement {
+ name: "Eco"
+ }
+ ListElement {
+ name: "Auto"
+ }
+ }
+
+ RowLayout {
+ id: menu
+
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ anchors.rightMargin: !root.isSmallLayout ? 24 : 0
+
+ Repeater {
+ model: roomOptions
+
+ RoomOption {
+ id: roomOption
+
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ isEnabled: root.isEnabled
+ isSmallLayout: root.isSmallLayout
+ isActive: root.model.mode === roomOption.name
+
+ Connections {
+ function onClicked() {
+ root.model.mode = roomOption.name
+ }
+ }
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.preferredWidth: 30
+ }
+
+ Item {
+ Layout.preferredWidth: !root.isSmallLayout ? 24 : 20
+ Layout.preferredHeight: !root.isSmallLayout ? 24 : 20
+ Layout.alignment: Qt.AlignBottom
+ Layout.bottomMargin: !root.isSmallLayout ? 19 : 7
+
+ Image {
+ id: icon2
+
+ source: "images/more.svg"
+ sourceSize.width: !root.isSmallLayout ? 24 : 20
+ }
+
+ MultiEffect {
+ anchors.fill: icon2
+ source: icon2
+ colorization: 1
+ colorizationColor: root.isEnabled ? Constants.accentTextColor : "#898989"
+ }
+ }
+
+ }
+
+ QtObject {
+ id: internal
+
+ property int width: 530
+ property int height: 276
+ property int rightMargin: 60
+ property int leftPadding: 16
+ property int titleSpacing: 8
+ property int spacing: 16
+ property int columnMargin: 7
+ property int iconSize: 34
+ property int switchMargin: 9
+ }
+
+ states: [
+ State {
+ name: "desktopLayout"
+ when: Constants.isBigDesktopLayout || Constants.isSmallDesktopLayout
+ PropertyChanges {
+ target: root
+ isSmallLayout: false
+ }
+ PropertyChanges {
+ target: internal
+ width: 530
+ height: 276
+ rightMargin: 53
+ leftPadding: 16
+ spacing: 16
+ titleSpacing: 8
+ columnMargin: 7
+ iconSize: 34
+ switchMargin: 9
+ }
+ },
+ State {
+ name: "mobileLayout"
+ when: Constants.isMobileLayout
+ PropertyChanges {
+ target: internal
+ width: 306
+ height: 177
+ rightMargin: 12
+ leftPadding: 8
+ spacing: 6
+ titleSpacing: 4
+ columnMargin: 17
+ iconSize: 24
+ switchMargin: 2
+ }
+ PropertyChanges {
+ target: root
+ isSmallLayout: true
+ }
+ },
+ State {
+ name: "smallLayout"
+ when: Constants.isSmallLayout
+ PropertyChanges {
+ target: root
+ isSmallLayout: true
+ }
+ PropertyChanges {
+ target: internal
+ width: 340
+ height: 177
+ rightMargin: 34
+ leftPadding: 8
+ spacing: 3
+ titleSpacing: 2
+ columnMargin: 7
+ iconSize: 24
+ switchMargin: 9
+ }
+ }
+ ]
+}
diff --git a/examples/demos/thermostat/content/RoomOption.qml b/examples/demos/thermostat/content/RoomOption.qml
new file mode 100644
index 000000000..46239a7ca
--- /dev/null
+++ b/examples/demos/thermostat/content/RoomOption.qml
@@ -0,0 +1,8 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+RoomOptionForm {
+
+}
diff --git a/examples/demos/thermostat/content/RoomOptionForm.ui.qml b/examples/demos/thermostat/content/RoomOptionForm.ui.qml
new file mode 100644
index 000000000..a13446305
--- /dev/null
+++ b/examples/demos/thermostat/content/RoomOptionForm.ui.qml
@@ -0,0 +1,56 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+
+/*
+This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
+It is supposed to be strictly declarative and only uses a subset of QML. If you edit
+this file manually, you might introduce QML code that is not supported by Qt Design Studio.
+Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
+*/
+import QtQuick
+import QtQuick.Controls
+import Thermostat
+
+Button {
+ id: root
+
+ required property string name
+ required property bool isSmallLayout
+ required property bool isEnabled
+ required property bool isActive
+
+ leftPadding: 0
+ rightPadding: 0
+ topPadding: root.isSmallLayout ? 7 : 12
+ bottomPadding: root.isSmallLayout ? 7 : 20
+ spacing: root.isSmallLayout ? 5 : 10
+
+ enabled: root.isEnabled
+ checked: root.isActive && root.isEnabled
+ checkable: true
+ flat: true
+ autoExclusive: true
+ display: AbstractButton.TextUnderIcon
+
+ text: root.name
+ icon.source: "images/" + root.name + ".svg"
+ icon.width: root.isSmallLayout ? 20 : 32
+ icon.height: root.isSmallLayout ? 20 : 32
+
+ palette.brightText: "#2CDE85"
+ palette.dark: "transparent"
+ palette.windowText: root.isEnabled ? Constants.accentTextColor : "#898989"
+
+ font.family: "Titillium Web"
+ font.pixelSize: !root.isSmallLayout ? 12 : 10
+ font.weight: 600
+
+ Image {
+ anchors.topMargin: 2
+ anchors.top: root.top
+ anchors.horizontalCenter: root.horizontalCenter
+ source: "images/circle.svg"
+ visible: (root.down || root.checked) && !root.isSmallLayout
+ }
+}
diff --git a/examples/demos/thermostat/content/RoomsScrollView.qml b/examples/demos/thermostat/content/RoomsScrollView.qml
new file mode 100644
index 000000000..a21a72885
--- /dev/null
+++ b/examples/demos/thermostat/content/RoomsScrollView.qml
@@ -0,0 +1,8 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+RoomsScrollViewForm {
+
+}
diff --git a/examples/demos/thermostat/content/RoomsScrollViewForm.ui.qml b/examples/demos/thermostat/content/RoomsScrollViewForm.ui.qml
new file mode 100644
index 000000000..de46fa07d
--- /dev/null
+++ b/examples/demos/thermostat/content/RoomsScrollViewForm.ui.qml
@@ -0,0 +1,47 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+
+/*
+This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
+It is supposed to be strictly declarative and only uses a subset of QML. If you edit
+this file manually, you might introduce QML code that is not supported by Qt Design Studio.
+Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
+*/
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+ScrollView {
+ id: scrollView
+
+ clip: true
+ contentWidth: availableWidth
+
+ property alias model: repeater.model
+ property alias columns: gridLayout.columns
+ property alias gridWidth: gridLayout.width
+ property alias gridHeight: gridLayout.height
+
+ required property int delegatePreferredHeight
+ required property int delegatePreferredWidth
+
+ GridLayout {
+ id: gridLayout
+
+ columnSpacing: 24
+ rowSpacing: 25
+
+ Repeater {
+ id: repeater
+
+ RoomItem {
+ id: roomItem
+
+ Layout.preferredHeight: scrollView.delegatePreferredHeight
+ Layout.preferredWidth: scrollView.delegatePreferredWidth
+ Layout.alignment: Qt.AlignHCenter
+ }
+ }
+ }
+}
diff --git a/examples/demos/thermostat/content/RoomsSwipeView.qml b/examples/demos/thermostat/content/RoomsSwipeView.qml
new file mode 100644
index 000000000..5a35521ee
--- /dev/null
+++ b/examples/demos/thermostat/content/RoomsSwipeView.qml
@@ -0,0 +1,10 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+RoomsSwipeViewForm {
+
+ previousItem.onTapped: swipeView.decrementCurrentIndex()
+ nextItem.onTapped: swipeView.incrementCurrentIndex()
+}
diff --git a/examples/demos/thermostat/content/RoomsSwipeViewForm.ui.qml b/examples/demos/thermostat/content/RoomsSwipeViewForm.ui.qml
new file mode 100644
index 000000000..2eb331e27
--- /dev/null
+++ b/examples/demos/thermostat/content/RoomsSwipeViewForm.ui.qml
@@ -0,0 +1,107 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+
+/*
+This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
+It is supposed to be strictly declarative and only uses a subset of QML. If you edit
+this file manually, you might introduce QML code that is not supported by Qt Design Studio.
+Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
+*/
+import QtQuick
+import QtQuick.Controls
+
+Item {
+ id: root
+
+ property alias model: repeater.model
+ property alias swipeView: swipeView
+ property alias previousItem: previousItem
+ property alias nextItem: nextItem
+
+ required property int delegatePreferredHeight
+ required property int delegatePreferredWidth
+
+ ListView {
+ id: roomSelector
+
+ model: root.model
+ orientation: ListView.Horizontal
+ width: parent.width
+ height: 28
+ spacing: 26
+ delegate: Label {
+ id: labelDelegate
+
+ required property string name
+ required property int index
+
+ text: name
+ font.pixelSize: 12
+ font.family: "Titillium Web"
+ font.weight: 400
+ font.bold: swipeView.currentIndex === index
+ font.underline: swipeView.currentIndex === index
+ color: swipeView.currentIndex === index ? "#2CDE85" : "#898989"
+
+ MouseArea {
+ anchors.fill: parent
+ Connections {
+ function onClicked() {
+ swipeView.setCurrentIndex(labelDelegate.index)
+ }
+ }
+ }
+ }
+ }
+
+ Image {
+ source: "images/arrow.svg"
+ sourceSize.width: 35
+ sourceSize.height: 35
+ anchors.verticalCenter: swipeView.verticalCenter
+ anchors.right: swipeView.left
+ mirror: true
+
+ TapHandler {
+ id: previousItem
+ }
+ }
+
+ Image {
+ source: "images/arrow.svg"
+ anchors.verticalCenter: swipeView.verticalCenter
+ anchors.left: swipeView.right
+ sourceSize.width: 35
+ sourceSize.height: 35
+
+ TapHandler {
+ id: nextItem
+ }
+ }
+
+ SwipeView {
+ id: swipeView
+
+ height: root.delegatePreferredHeight
+ width: root.delegatePreferredWidth
+
+ anchors.top: roomSelector.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.topMargin: 4
+
+ spacing: 7
+ clip: true
+
+ Repeater {
+ id: repeater
+
+ RoomItem {
+ id: roomItem
+
+ height: root.delegatePreferredHeight
+ width: root.delegatePreferredWidth
+ }
+ }
+ }
+}
diff --git a/examples/demos/thermostat/content/RoomsView.qml b/examples/demos/thermostat/content/RoomsView.qml
new file mode 100644
index 000000000..ced439f03
--- /dev/null
+++ b/examples/demos/thermostat/content/RoomsView.qml
@@ -0,0 +1,8 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+RoomsViewForm {
+
+}
diff --git a/examples/demos/thermostat/content/RoomsViewForm.ui.qml b/examples/demos/thermostat/content/RoomsViewForm.ui.qml
new file mode 100644
index 000000000..22b6ff738
--- /dev/null
+++ b/examples/demos/thermostat/content/RoomsViewForm.ui.qml
@@ -0,0 +1,193 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+
+/*
+This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
+It is supposed to be strictly declarative and only uses a subset of QML. If you edit
+this file manually, you might introduce QML code that is not supported by Qt Design Studio.
+Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
+*/
+import QtQuick
+import QtQuick.Controls
+import Thermostat
+
+Pane {
+ id: root
+
+ topPadding: 4
+ leftPadding: 27
+ rightPadding: 27
+ bottomPadding: 13
+
+ required property var roomsList
+
+ background: Rectangle {
+ anchors.fill: parent
+ color: Constants.backgroundColor
+ }
+
+ Column {
+ id: title
+
+ width: internal.contentWidth
+
+ Label {
+ id: heading
+
+ text: qsTr("Welcome")
+ font: Constants.desktopTitleFont
+ color: Constants.primaryTextColor
+ elide: Text.ElideRight
+ }
+
+ Label {
+ id: heading2
+
+ text: qsTr("Here's the list of your Rooms at Home")
+ font.pixelSize: 24
+ font.weight: 600
+ font.family: "Titillium Web"
+ color: Constants.accentTextColor
+ elide: Text.ElideRight
+ }
+ }
+
+ RoomsScrollView {
+ id: scrollView
+
+ anchors.top: title.bottom
+ anchors.topMargin: 10
+
+ width: internal.contentWidth
+ height: internal.contentHeight
+ gridWidth: internal.contentWidth
+ gridHeight: internal.contentHeight
+
+ delegatePreferredWidth: internal.delegatePreferredWidth
+ delegatePreferredHeight: internal.delegatePreferredHeight
+
+ columns: root.width < 1140 ? 1 : 2
+ model: roomsList
+ }
+
+ RoomsSwipeView {
+ id: swipeView
+
+ anchors.top: title.bottom
+ anchors.topMargin: 5
+ anchors.left: parent.left
+ anchors.right: parent.right
+
+ width: internal.contentWidth
+ height: internal.contentHeight
+ delegatePreferredHeight: internal.delegatePreferredHeight
+ delegatePreferredWidth: internal.delegatePreferredWidth
+
+ model: roomsList
+ visible: false
+ }
+
+ QtObject {
+ id: internal
+
+ readonly property int contentHeight: root.height - title.height
+ - root.topPadding - root.bottomPadding
+ readonly property int contentWidth: root.width - root.rightPadding - root.leftPadding
+ property int delegatePreferredHeight: 276
+ property int delegatePreferredWidth: 530
+ }
+
+ states: [
+ State {
+ name: "desktopLayout"
+ when: Constants.isBigDesktopLayout || Constants.isSmallDesktopLayout
+ PropertyChanges {
+ target: heading
+ text: qsTr("Welcome")
+ font: Constants.desktopTitleFont
+ }
+ PropertyChanges {
+ target: heading2
+ visible: true
+ }
+ PropertyChanges {
+ target: scrollView
+ visible: true
+ }
+ PropertyChanges {
+ target: swipeView
+ visible: false
+ }
+ PropertyChanges {
+ target: internal
+ delegatePreferredHeight: 276
+ delegatePreferredWidth: 530
+ }
+ PropertyChanges {
+ target: root
+ leftPadding: 27
+ }
+ },
+ State {
+ name: "mobileLayout"
+ when: Constants.isMobileLayout
+ PropertyChanges {
+ target: heading
+ text: qsTr("Rooms")
+ font: Constants.mobileTitleFont
+ }
+ PropertyChanges {
+ target: heading2
+ visible: false
+ }
+ PropertyChanges {
+ target: scrollView
+ visible: true
+ }
+ PropertyChanges {
+ target: swipeView
+ visible: false
+ }
+ PropertyChanges {
+ target: internal
+ delegatePreferredHeight: 177
+ delegatePreferredWidth: 306
+ }
+ PropertyChanges {
+ target: root
+ leftPadding: 27
+ }
+ },
+ State {
+ name: "smallLayout"
+ when: Constants.isSmallLayout
+ PropertyChanges {
+ target: heading
+ text: qsTr("Rooms")
+ font: Constants.smallTitleFont
+ }
+ PropertyChanges {
+ target: heading2
+ visible: false
+ }
+ PropertyChanges {
+ target: scrollView
+ visible: false
+ }
+ PropertyChanges {
+ target: swipeView
+ visible: true
+ }
+ PropertyChanges {
+ target: internal
+ delegatePreferredHeight: 177
+ delegatePreferredWidth: 340
+ }
+ PropertyChanges {
+ target: root
+ leftPadding: 11
+ }
+ }
+ ]
+}
diff --git a/examples/demos/thermostat/content/ScheduleScrollView.qml b/examples/demos/thermostat/content/ScheduleScrollView.qml
new file mode 100644
index 000000000..6178821f6
--- /dev/null
+++ b/examples/demos/thermostat/content/ScheduleScrollView.qml
@@ -0,0 +1,8 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+ScheduleScrollViewForm {
+
+}
diff --git a/examples/demos/thermostat/content/ScheduleScrollViewForm.ui.qml b/examples/demos/thermostat/content/ScheduleScrollViewForm.ui.qml
new file mode 100644
index 000000000..e8754baeb
--- /dev/null
+++ b/examples/demos/thermostat/content/ScheduleScrollViewForm.ui.qml
@@ -0,0 +1,78 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+/*
+This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
+It is supposed to be strictly declarative and only uses a subset of QML. If you edit
+this file manually, you might introduce QML code that is not supported by Qt Design Studio.
+Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
+*/
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import Thermostat
+
+ScrollView {
+ id: scrollView
+
+ property int timeScheduleHeight: 361
+ property int timeScheduleWidth: 1087
+ property int tempSetterHeight: 427
+ property int tempSetterWidth: 1087
+
+ clip: true
+ padding: 0
+
+ ColumnLayout {
+ width: scrollView.width
+ height: scrollView.height
+
+ TimeSchedule {
+ Layout.preferredHeight: scrollView.timeScheduleHeight
+ Layout.preferredWidth: scrollView.timeScheduleWidth
+ Layout.alignment: Qt.AlignHCenter
+ }
+
+ TemperatureSetter {
+ Layout.preferredHeight: scrollView.tempSetterHeight
+ Layout.preferredWidth: scrollView.tempSetterWidth
+ Layout.alignment: Qt.AlignHCenter
+ }
+ }
+
+ states: [
+ State {
+ name: "desktopLayout"
+ when: Constants.isBigDesktopLayout || Constants.isSmallDesktopLayout
+ PropertyChanges {
+ target: scrollView
+ timeScheduleHeight: 361
+ timeScheduleWidth: 1087
+ tempSetterHeight: 427
+ tempSetterWidth: 1087
+ }
+ },
+ State {
+ name: "mobileLayout"
+ when: Constants.isMobileLayout
+ PropertyChanges {
+ target: scrollView
+ timeScheduleHeight: 314
+ timeScheduleWidth: 327
+ tempSetterHeight: 529
+ tempSetterWidth: 327
+ }
+ },
+ State {
+ name: "smallLayout"
+ when: Constants.isSmallLayout
+ PropertyChanges {
+ target: scrollView
+ timeScheduleHeight: 230
+ timeScheduleWidth: 400
+ tempSetterHeight: 370
+ tempSetterWidth: 400
+ }
+ }
+ ]
+}
diff --git a/examples/demos/thermostat/content/ScheduleSwipeView.qml b/examples/demos/thermostat/content/ScheduleSwipeView.qml
new file mode 100644
index 000000000..4a9504243
--- /dev/null
+++ b/examples/demos/thermostat/content/ScheduleSwipeView.qml
@@ -0,0 +1,8 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+ScheduleSwipeViewForm {
+
+}
diff --git a/examples/demos/thermostat/content/ScheduleSwipeViewForm.ui.qml b/examples/demos/thermostat/content/ScheduleSwipeViewForm.ui.qml
new file mode 100644
index 000000000..4ea49d9b5
--- /dev/null
+++ b/examples/demos/thermostat/content/ScheduleSwipeViewForm.ui.qml
@@ -0,0 +1,77 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+
+/*
+This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
+It is supposed to be strictly declarative and only uses a subset of QML. If you edit
+this file manually, you might introduce QML code that is not supported by Qt Design Studio.
+Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
+*/
+import QtQuick
+import QtQuick.Controls
+
+Item {
+ id: root
+
+ property alias model: repeater.model
+ property alias swipeView: swipeView
+ property alias currentRoomIndex: swipeView.currentIndex
+
+ property bool isOneColumn: false
+
+ ListView {
+ id: roomSelector
+
+ model: root.model
+ width: root.width
+ height: 28
+ spacing: 26
+ orientation: ListView.Horizontal
+ delegate: Label {
+ id: labelDelegate
+
+ required property string name
+ required property int index
+ readonly property bool isActive: swipeView.currentIndex === index
+
+ text: name
+ font.pixelSize: 12
+ font.family: "Titillium Web"
+ font.weight: 400
+ font.bold: isActive
+ font.underline: isActive
+ color: isActive ? "#2CDE85" : "#898989"
+
+ MouseArea {
+ anchors.fill: parent
+ Connections {
+ function onClicked() {
+ swipeView.setCurrentIndex(labelDelegate.index)
+ }
+ }
+ }
+ }
+ }
+
+ SwipeView {
+ id: swipeView
+
+ height: root.height - roomSelector.height + 13
+ width: root.width
+
+ anchors.top: roomSelector.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ spacing: 7
+ clip: true
+
+ Repeater {
+ id: repeater
+
+ ScheduleScrollView {
+ width: swipeView.width
+ height: swipeView.height
+ }
+ }
+ }
+}
diff --git a/examples/demos/thermostat/content/ScheduleView.qml b/examples/demos/thermostat/content/ScheduleView.qml
new file mode 100644
index 000000000..d706f1b69
--- /dev/null
+++ b/examples/demos/thermostat/content/ScheduleView.qml
@@ -0,0 +1,8 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+ScheduleViewForm {
+
+}
diff --git a/examples/demos/thermostat/content/ScheduleViewForm.ui.qml b/examples/demos/thermostat/content/ScheduleViewForm.ui.qml
new file mode 100644
index 000000000..c1a432a78
--- /dev/null
+++ b/examples/demos/thermostat/content/ScheduleViewForm.ui.qml
@@ -0,0 +1,176 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+
+/*
+This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
+It is supposed to be strictly declarative and only uses a subset of QML. If you edit
+this file manually, you might introduce QML code that is not supported by Qt Design Studio.
+Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
+*/
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import Thermostat
+import CustomControls
+
+Pane {
+ id: root
+
+ property int currentRoomIndex: 0
+ required property var roomsList
+
+ background: Rectangle {
+ anchors.fill: parent
+ color: Constants.backgroundColor
+ }
+
+ Column {
+ id: title
+
+ width: parent.width
+ Label {
+ id: header
+
+ text: qsTr("Time Schedule")
+ font.pixelSize: 48
+ font.weight: 600
+ font.family: "Titillium Web"
+ color: Constants.primaryTextColor
+ elide: Text.ElideRight
+ }
+
+ RowLayout {
+ id: label
+ width: parent.width
+ Label {
+ text: qsTr("Adjust a timer for specific room temperature")
+ font.pixelSize: 24
+ font.weight: 600
+ font.family: "Titillium Web"
+ color: Constants.accentTextColor
+ elide: Text.ElideRight
+ Layout.fillWidth: true
+ }
+
+ CustomComboBox {
+ model: roomsList
+ currentIndex: root.currentRoomIndex
+ onCurrentIndexChanged: root.currentRoomIndex = currentIndex
+ }
+ }
+ }
+
+ ScheduleScrollView {
+ id: scrollView
+ anchors.top: title.bottom
+ anchors.leftMargin: 28
+
+ width: internal.contentWidth
+ height: internal.contentHeight
+ }
+
+ ScheduleSwipeView {
+ id: swipeView
+ anchors.top: title.bottom
+
+ model: roomsList
+
+ width: internal.contentWidth
+ height: internal.contentHeight
+
+ visible: false
+ currentRoomIndex: root.currentRoomIndex
+ onCurrentRoomIndexChanged: root.currentRoomIndex = currentRoomIndex
+ }
+
+ QtObject {
+ id: internal
+ readonly property int contentHeight: root.height - title.height
+ - root.topPadding - root.bottomPadding
+ readonly property int contentWidth: root.width - root.rightPadding - root.leftPadding
+ }
+
+ states: [
+ State {
+ name: "desktopLayout"
+ when: Constants.isBigDesktopLayout || Constants.isSmallDesktopLayout
+ PropertyChanges {
+ target: root
+ leftPadding: 20
+ }
+ PropertyChanges {
+ target: header
+ font.pixelSize: 48
+ font.weight: 600
+ font.family: "Titillium Web"
+ visible: true
+ }
+ PropertyChanges {
+ target: label
+ visible: true
+ }
+ PropertyChanges {
+ target: scrollView
+ visible: true
+ }
+ PropertyChanges {
+ target: swipeView
+ visible: false
+ }
+ },
+ State {
+ name: "mobileLayout"
+ when: Constants.isMobileLayout
+ PropertyChanges {
+ target: root
+ leftPadding: 16
+ rightPadding: 16
+ }
+ PropertyChanges {
+ target: header
+ font.pixelSize: 24
+ font.weight: 600
+ font.family: "Titillium Web"
+ visible: true
+ }
+ PropertyChanges {
+ target: label
+ visible: false
+ }
+ PropertyChanges {
+ target: scrollView
+ visible: false
+ }
+ PropertyChanges {
+ target: swipeView
+ visible: true
+ }
+ },
+ State {
+ name: "smallLayout"
+ when: Constants.isSmallLayout
+ PropertyChanges {
+ target: root
+ leftPadding: 15
+ rightPadding: 15
+ }
+ PropertyChanges {
+ target: header
+ visible: false
+ }
+ PropertyChanges {
+ target: label
+ visible: false
+ }
+ PropertyChanges {
+ target: scrollView
+ visible: false
+ }
+ PropertyChanges {
+ target: swipeView
+ visible: true
+ }
+ }
+ ]
+}
diff --git a/examples/demos/thermostat/content/SideBar.qml b/examples/demos/thermostat/content/SideBar.qml
new file mode 100644
index 000000000..dd03d7241
--- /dev/null
+++ b/examples/demos/thermostat/content/SideBar.qml
@@ -0,0 +1,8 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+SideBarForm {
+
+}
diff --git a/examples/demos/thermostat/content/SideBarForm.ui.qml b/examples/demos/thermostat/content/SideBarForm.ui.qml
new file mode 100644
index 000000000..fe92063a1
--- /dev/null
+++ b/examples/demos/thermostat/content/SideBarForm.ui.qml
@@ -0,0 +1,220 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+
+/*
+This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
+It is supposed to be strictly declarative and only uses a subset of QML. If you edit
+this file manually, you might introduce QML code that is not supported by Qt Design Studio.
+Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
+*/
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import QtQuick.Effects
+import Thermostat
+import CustomControls
+
+Column {
+ id: root
+
+ property alias menuOptions: repeater.model
+ required property var roomsList
+
+ leftPadding: internal.leftPadding
+ spacing: internal.spacing
+
+ Repeater {
+ id: repeater
+ model: menuOptions
+
+ delegate: ItemDelegate {
+ id: columnItem
+
+ required property string name
+ required property string view
+ required property string iconSource
+
+ readonly property bool active: Constants.currentView === columnItem.view
+
+ width: column.width
+ height: column.height
+
+ background: Rectangle {
+ color: active ? "#2CDE85" : "transparent"
+ radius: 12
+ anchors.fill: parent
+ opacity: 0.1
+ }
+
+ Column {
+ id: column
+ padding: 0
+ Item {
+ id: menuItem
+
+ width: internal.delegateWidth
+ height: internal.delegateHeight
+
+ RowLayout {
+ anchors.fill: parent
+ anchors.leftMargin: internal.leftMargin
+ anchors.rightMargin: internal.rightMargin
+ spacing: 24
+
+ Item {
+ Layout.preferredWidth: internal.iconWidth
+ Layout.preferredHeight: internal.iconWidth
+ Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
+
+ Image {
+ id: icon
+
+ source: "images/" + columnItem.iconSource
+ sourceSize.width: internal.iconWidth
+ }
+
+ MultiEffect {
+ anchors.fill: icon
+ source: icon
+ colorization: 1
+ colorizationColor: Constants.iconColor
+ }
+ }
+
+ Label {
+ id: menuItemName
+ text: name
+ font.family: "Titillium Web"
+ font.pixelSize: 18
+ font.weight: 600
+ Layout.fillWidth: true
+ visible: internal.isNameVisible
+ color: Constants.primaryTextColor
+ }
+
+ Image {
+ source: "images/arrow.svg"
+ visible: !columnItem.active
+ && internal.isNameVisible
+ }
+ }
+ }
+
+ ListView {
+ model: [qsTr("Dark/Light")]
+ width: internal.delegateWidth
+ height: 44
+ visible: (Constants.isBigDesktopLayout
+ || Constants.isSmallDesktopLayout)
+ && columnItem.active
+ && columnItem.view == "SettingsView"
+ delegate: ItemDelegate {
+ id: item1
+ width: internal.delegateWidth
+ height: 44
+
+ RowLayout {
+ id: row
+
+ width: Constants.isBigDesktopLayout ? 190 : 18
+ spacing: 6
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ Image {
+ source: "images/theme.svg"
+ }
+
+ Label {
+ text: modelData
+ Layout.fillWidth: true
+ color: Constants.primaryTextColor
+ visible: internal.isNameVisible
+ }
+ }
+
+ Connections {
+ function onClicked() {
+ AppSettings.isDarkTheme = !AppSettings.isDarkTheme
+ }
+ }
+ }
+ }
+ }
+
+ Connections {
+ function onClicked() {
+ if (columnItem.view != "SettingsView"
+ && columnItem.view != Constants.currentView) {
+ stackView.replace(columnItem.view + ".qml", {
+ "roomsList": roomsList
+ }, StackView.Immediate)
+ }
+ Constants.currentView = columnItem.view
+ }
+ }
+ }
+ }
+
+ states: [
+ State {
+ name: "bigDesktop"
+ when: Constants.isBigDesktopLayout
+ PropertyChanges {
+ target: internal
+ delegateWidth: 290
+ delegateHeight: 60
+ iconWidth: 34
+ isNameVisible: true
+ leftMargin: 31
+ rightMargin: 13
+ leftPadding: 5
+ spacing: 5
+ }
+ },
+ State {
+ name: "smallDesktop"
+ when: Constants.isSmallDesktopLayout
+ PropertyChanges {
+ target: internal
+ delegateWidth: 56
+ delegateHeight: 56
+ iconWidth: 34
+ isNameVisible: false
+ leftMargin: 0
+ rightMargin: 0
+ leftPadding: 5
+ spacing: 5
+ }
+ },
+ State {
+ name: "small"
+ when: Constants.isSmallLayout
+ PropertyChanges {
+ target: internal
+ delegateWidth: 24
+ delegateHeight: 24
+ iconWidth: 24
+ isNameVisible: false
+ leftMargin: 0
+ rightMargin: 0
+ leftPadding: 6
+ spacing: 12
+ }
+ }
+ ]
+
+ QtObject {
+ id: internal
+
+ property int delegateWidth: 290
+ property int delegateHeight: 60
+ property int iconWidth: 34
+ property bool isNameVisible: true
+ property int leftMargin: 5
+ property int rightMargin: 13
+ property int leftPadding: 5
+ property int spacing: 5
+ }
+}
diff --git a/examples/demos/thermostat/content/StatisticsScrollView.qml b/examples/demos/thermostat/content/StatisticsScrollView.qml
new file mode 100644
index 000000000..4d44d0694
--- /dev/null
+++ b/examples/demos/thermostat/content/StatisticsScrollView.qml
@@ -0,0 +1,8 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+StatisticsScrollViewForm {
+
+}
diff --git a/examples/demos/thermostat/content/StatisticsScrollViewForm.ui.qml b/examples/demos/thermostat/content/StatisticsScrollViewForm.ui.qml
new file mode 100644
index 000000000..49b5ef15e
--- /dev/null
+++ b/examples/demos/thermostat/content/StatisticsScrollViewForm.ui.qml
@@ -0,0 +1,169 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+
+/*
+This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
+It is supposed to be strictly declarative and only uses a subset of QML. If you edit
+this file manually, you might introduce QML code that is not supported by Qt Design Studio.
+Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
+*/
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import CustomControls
+import Thermostat
+
+ScrollView {
+ id: scrollView
+
+ required property var model
+
+ property bool isOneColumn: false
+ property bool isBackgroundVisible: false
+ property int statisticsChartHeight: 647
+ property int statisticsChartWidth: 1098
+ property int delegateHeight: 182
+ property int delegateWidth: 350
+
+ clip: true
+ padding: 0
+ contentWidth: availableWidth
+
+ background: Rectangle {
+ color: Constants.accentColor
+ visible: scrollView.isBackgroundVisible
+ radius: 12
+ }
+
+ GridLayout {
+ id: grid
+
+ width: scrollView.width
+ height: scrollView.height
+
+ columns: scrollView.isOneColumn ? 1 : 3
+ rows: scrollView.isOneColumn ? 8 : 1
+
+ columnSpacing: 24
+ rowSpacing: scrollView.isOneColumn ? 12 : 24
+
+ Pane {
+ id: statistics
+
+ leftPadding: 53
+ rightPadding: 53
+ topPadding: 23
+ bottomPadding: 43
+
+ Layout.columnSpan: scrollView.isOneColumn ? 1 : 3
+ Layout.rowSpan: scrollView.isOneColumn ? 5 : 1
+
+ Layout.preferredHeight: scrollView.statisticsChartHeight
+ Layout.preferredWidth: scrollView.statisticsChartWidth
+ Layout.alignment: Qt.AlignHCenter
+
+ background: Rectangle {
+ radius: 12
+ color: Constants.accentColor
+ }
+
+ StatisticsChart {
+ id: statisticsChart
+
+ anchors.fill: parent
+ energyValuesModel: model.energyStats
+ tempValuesModel: model.tempStats
+ }
+ }
+
+ TemperatureInfo {
+ id: tempInfo
+
+ Layout.preferredHeight: scrollView.delegateHeight
+ Layout.preferredWidth: scrollView.delegateWidth
+ Layout.alignment: Qt.AlignHCenter
+ maxTempValue: statisticsChart.maxValue
+ minTempValue: statisticsChart.minValue
+ avgTempValue: statisticsChart.avgValue
+ }
+
+ HumidityInfo {
+ id: humidityInfo
+ Layout.preferredHeight: scrollView.delegateHeight
+ Layout.preferredWidth: scrollView.delegateWidth
+ Layout.alignment: Qt.AlignHCenter
+
+ humidityValuesModel: model.humidityStats
+ }
+
+ EnergyInfo {
+ id: energyInfo
+ Layout.preferredHeight: scrollView.delegateHeight
+ Layout.preferredWidth: scrollView.delegateWidth
+ Layout.alignment: Qt.AlignHCenter
+
+ energyValuesModel: model.energyStats
+ }
+ }
+
+ states: [
+ State {
+ name: "desktopLayout"
+ when: Constants.isBigDesktopLayout || Constants.isSmallDesktopLayout
+ PropertyChanges {
+ target: statistics
+ leftPadding: 53
+ rightPadding: 53
+ topPadding: 23
+ bottomPadding: 43
+ }
+ PropertyChanges {
+ target: scrollView
+ isBackgroundVisible: false
+ delegateWidth: 350
+ delegateHeight: 182
+ statisticsChartWidth: 1098
+ statisticsChartHeight: 647
+ }
+ },
+ State {
+ name: "mobileLayout"
+ when: Constants.isMobileLayout
+ PropertyChanges {
+ target: statistics
+ leftPadding: 0
+ rightPadding: 0
+ topPadding: 0
+ bottomPadding: 43
+ }
+ PropertyChanges {
+ target: scrollView
+ isBackgroundVisible: false
+ delegateWidth: 327
+ delegateHeight: 100
+ statisticsChartWidth: 327
+ statisticsChartHeight: 383
+ }
+ },
+ State {
+ name: "smallLayout"
+ when: Constants.isSmallLayout
+ PropertyChanges {
+ target: statistics
+ leftPadding: 0
+ rightPadding: 0
+ topPadding: 0
+ bottomPadding: 43
+ }
+ PropertyChanges {
+ target: scrollView
+ isBackgroundVisible: true
+ delegateWidth: 332
+ delegateHeight: 80
+ statisticsChartWidth: 401
+ statisticsChartHeight: 280
+ }
+ }
+ ]
+}
diff --git a/examples/demos/thermostat/content/StatisticsStackView.qml b/examples/demos/thermostat/content/StatisticsStackView.qml
new file mode 100644
index 000000000..4391787e0
--- /dev/null
+++ b/examples/demos/thermostat/content/StatisticsStackView.qml
@@ -0,0 +1,8 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+StatisticsStackViewForm {
+
+}
diff --git a/examples/demos/thermostat/content/StatisticsStackViewForm.ui.qml b/examples/demos/thermostat/content/StatisticsStackViewForm.ui.qml
new file mode 100644
index 000000000..98251f99d
--- /dev/null
+++ b/examples/demos/thermostat/content/StatisticsStackViewForm.ui.qml
@@ -0,0 +1,39 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+
+/*
+This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
+It is supposed to be strictly declarative and only uses a subset of QML. If you edit
+this file manually, you might introduce QML code that is not supported by Qt Design Studio.
+Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
+*/
+import QtQuick
+import QtQuick.Layouts
+
+Item {
+ id: root
+
+ property alias model: repeater.model
+
+ property bool isOneColumn: false
+ property int currentRoomIndex
+
+ StackLayout {
+ anchors.fill: parent
+ currentIndex: root.currentRoomIndex
+
+ Repeater {
+ id: repeater
+
+ StatisticsScrollView {
+ required property int index
+
+ width: root.width
+ height: root.height
+
+ isOneColumn: root.isOneColumn
+ }
+ }
+ }
+}
diff --git a/examples/demos/thermostat/content/StatisticsSwipeView.qml b/examples/demos/thermostat/content/StatisticsSwipeView.qml
new file mode 100644
index 000000000..dc590abe6
--- /dev/null
+++ b/examples/demos/thermostat/content/StatisticsSwipeView.qml
@@ -0,0 +1,8 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+StatisticsSwipeViewForm {
+
+}
diff --git a/examples/demos/thermostat/content/StatisticsSwipeViewForm.ui.qml b/examples/demos/thermostat/content/StatisticsSwipeViewForm.ui.qml
new file mode 100644
index 000000000..2e825fa35
--- /dev/null
+++ b/examples/demos/thermostat/content/StatisticsSwipeViewForm.ui.qml
@@ -0,0 +1,79 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+
+/*
+This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
+It is supposed to be strictly declarative and only uses a subset of QML. If you edit
+this file manually, you might introduce QML code that is not supported by Qt Design Studio.
+Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
+*/
+import QtQuick
+import QtQuick.Controls
+
+Item {
+ id: root
+
+ property alias model: repeater.model
+ property alias swipeView: swipeView
+ property alias currentRoomIndex: swipeView.currentIndex
+
+ property bool isOneColumn: false
+
+ ListView {
+ id: roomSelector
+
+ model: root.model
+ width: root.width
+ height: 28
+ spacing: 26
+ orientation: ListView.Horizontal
+ delegate: Label {
+ id: labelDelegate
+
+ required property string name
+ required property int index
+ readonly property bool isActive: swipeView.currentIndex === index
+
+ text: name
+ font.pixelSize: 12
+ font.family: "Titillium Web"
+ font.weight: 400
+ font.bold: isActive
+ font.underline: isActive
+ color: isActive ? "#2CDE85" : "#898989"
+
+ MouseArea {
+ anchors.fill: parent
+ Connections {
+ function onClicked() {
+ swipeView.setCurrentIndex(labelDelegate.index)
+ }
+ }
+ }
+ }
+ }
+
+ SwipeView {
+ id: swipeView
+
+ height: root.height - roomSelector.height + 13
+ width: root.width
+
+ anchors.top: roomSelector.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ spacing: 7
+ clip: true
+
+ Repeater {
+ id: repeater
+
+ StatisticsScrollView {
+ width: swipeView.width
+ height: swipeView.height
+
+ isOneColumn: root.isOneColumn
+ }
+ }
+ }
+}
diff --git a/examples/demos/thermostat/content/StatisticsView.qml b/examples/demos/thermostat/content/StatisticsView.qml
new file mode 100644
index 000000000..88a4f1511
--- /dev/null
+++ b/examples/demos/thermostat/content/StatisticsView.qml
@@ -0,0 +1,8 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+StatisticsViewForm {
+
+}
diff --git a/examples/demos/thermostat/content/StatisticsViewForm.ui.qml b/examples/demos/thermostat/content/StatisticsViewForm.ui.qml
new file mode 100644
index 000000000..265564b3a
--- /dev/null
+++ b/examples/demos/thermostat/content/StatisticsViewForm.ui.qml
@@ -0,0 +1,188 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+
+/*
+This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
+It is supposed to be strictly declarative and only uses a subset of QML. If you edit
+this file manually, you might introduce QML code that is not supported by Qt Design Studio.
+Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
+*/
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import Thermostat
+import CustomControls
+
+Pane {
+ id: root
+
+ leftPadding: 20
+ rightPadding: 20
+ bottomPadding: 15
+
+ property int currentRoomIndex: 0
+ required property var roomsList
+
+ background: Rectangle {
+ color: Constants.backgroundColor
+ }
+
+ Column {
+ id: title
+
+ width: parent.width
+
+ Label {
+ id: header
+
+ text: qsTr("Statistics")
+ font: Constants.desktopTitleFont
+ color: Constants.primaryTextColor
+ elide: Text.ElideRight
+ }
+
+ RowLayout {
+ id: label
+ width: parent.width
+
+ Label {
+ text: qsTr("Overview of your home's temperature and energy usage")
+ font: Constants.desktopSubtitleFont
+ color: Constants.accentTextColor
+ elide: Text.ElideRight
+ Layout.fillWidth: true
+ }
+
+ CustomComboBox {
+ id: comboBox
+ Layout.alignment: Qt.AlignLeft | Qt.AlignTop
+ model: roomsList
+ currentIndex: root.currentRoomIndex
+ onCurrentIndexChanged: root.currentRoomIndex = currentIndex
+ }
+ }
+ }
+
+ StatisticsStackView {
+ id: scrollView
+
+ anchors.top: title.bottom
+ anchors.topMargin: 12
+ anchors.leftMargin: 28
+
+ width: internal.contentWidth
+ height: internal.contentHeight
+ isOneColumn: internal.isOneColumn
+
+ model: roomsList
+ currentRoomIndex: root.currentRoomIndex
+ }
+
+ StatisticsSwipeView {
+ id: swipeView
+
+ anchors.top: title.bottom
+
+ model: roomsList
+
+ width: internal.contentWidth
+ height: internal.contentHeight
+ isOneColumn: internal.isOneColumn
+
+ currentRoomIndex: root.currentRoomIndex
+ onCurrentRoomIndexChanged: root.currentRoomIndex = currentRoomIndex
+ visible: false
+ }
+
+ QtObject {
+ id: internal
+
+ readonly property int contentHeight: root.height - title.height
+ - root.topPadding - root.bottomPadding
+ readonly property int contentWidth: root.width - root.rightPadding - root.leftPadding
+ readonly property bool isOneColumn: contentWidth < 900
+ }
+
+ states: [
+ State {
+ name: "desktopLayout"
+ when: Constants.isBigDesktopLayout || Constants.isSmallDesktopLayout
+ PropertyChanges {
+ target: header
+ font.pixelSize: 48
+ font.weight: 600
+ font.family: "Titillium Web"
+ }
+ PropertyChanges {
+ target: label
+ visible: true
+ }
+ PropertyChanges {
+ target: root
+ leftPadding: 20
+ }
+ PropertyChanges {
+ target: scrollView
+ visible: true
+ }
+ PropertyChanges {
+ target: swipeView
+ visible: false
+ }
+ },
+ State {
+ name: "mobileLayout"
+ when: Constants.isMobileLayout
+ PropertyChanges {
+ target: header
+ font.pixelSize: 24
+ font.weight: 600
+ font.family: "Titillium Web"
+ }
+ PropertyChanges {
+ target: label
+ visible: false
+ }
+ PropertyChanges {
+ target: root
+ leftPadding: 16
+ rightPadding: 16
+ }
+ PropertyChanges {
+ target: scrollView
+ visible: false
+ }
+ PropertyChanges {
+ target: swipeView
+ visible: true
+ }
+ },
+ State {
+ name: "smallLayout"
+ when: Constants.isSmallLayout
+ PropertyChanges {
+ target: header
+ visible: false
+ }
+ PropertyChanges {
+ target: label
+ visible: false
+ }
+ PropertyChanges {
+ target: root
+ leftPadding: 15
+ rightPadding: 15
+ topPadding: 3
+ }
+ PropertyChanges {
+ target: scrollView
+ visible: false
+ }
+ PropertyChanges {
+ target: swipeView
+ visible: true
+ }
+ }
+ ]
+}
diff --git a/examples/demos/thermostat/content/TemperatureInfo.qml b/examples/demos/thermostat/content/TemperatureInfo.qml
new file mode 100644
index 000000000..785755b7f
--- /dev/null
+++ b/examples/demos/thermostat/content/TemperatureInfo.qml
@@ -0,0 +1,8 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+TemperatureInfoForm {
+
+}
diff --git a/examples/demos/thermostat/content/TemperatureInfoForm.ui.qml b/examples/demos/thermostat/content/TemperatureInfoForm.ui.qml
new file mode 100644
index 000000000..9f561ba89
--- /dev/null
+++ b/examples/demos/thermostat/content/TemperatureInfoForm.ui.qml
@@ -0,0 +1,26 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+
+/*
+This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
+It is supposed to be strictly declarative and only uses a subset of QML. If you edit
+this file manually, you might introduce QML code that is not supported by Qt Design Studio.
+Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
+*/
+import QtQuick
+
+ThermostatInfo {
+
+ property real maxTempValue: 26
+ property real minTempValue: 18
+ property real avgTempValue: 22
+
+ title: qsTr("Temperature")
+ leftIcon: "images/temperature"
+ topLabel: qsTr("Avarage: %1°C".arg(avgTempValue))
+ bottomLeftLabel: qsTr("Minimum: %1°C".arg(minTempValue))
+ bottomLeftIcon: "images/minTemp.svg"
+ bottomRightLabel: qsTr("Maximum: %1°C".arg(maxTempValue))
+ bottomRightIcon: "images/maxTemp.svg"
+}
diff --git a/examples/demos/thermostat/content/TemperatureSetter.qml b/examples/demos/thermostat/content/TemperatureSetter.qml
new file mode 100644
index 000000000..570ac972d
--- /dev/null
+++ b/examples/demos/thermostat/content/TemperatureSetter.qml
@@ -0,0 +1,8 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+TemperatureSetterForm {
+
+}
diff --git a/examples/demos/thermostat/content/TemperatureSetterDesktopView.qml b/examples/demos/thermostat/content/TemperatureSetterDesktopView.qml
new file mode 100644
index 000000000..21bed94ca
--- /dev/null
+++ b/examples/demos/thermostat/content/TemperatureSetterDesktopView.qml
@@ -0,0 +1,8 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+TemperatureSetterDesktopViewForm {
+
+}
diff --git a/examples/demos/thermostat/content/TemperatureSetterDesktopViewForm.ui.qml b/examples/demos/thermostat/content/TemperatureSetterDesktopViewForm.ui.qml
new file mode 100644
index 000000000..7d5dd68a3
--- /dev/null
+++ b/examples/demos/thermostat/content/TemperatureSetterDesktopViewForm.ui.qml
@@ -0,0 +1,156 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+/*
+This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
+It is supposed to be strictly declarative and only uses a subset of QML. If you edit
+this file manually, you might introduce QML code that is not supported by Qt Design Studio.
+Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
+*/
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import QtQuick.Effects
+import Thermostat
+import CustomControls
+
+Pane {
+ width: 1087
+ height: 427
+
+ topPadding: 30
+ bottomPadding: 24
+ leftPadding: 16
+ rightPadding: 36
+
+ background: Rectangle {
+ color: Constants.accentColor
+ radius: 12
+ }
+
+ Row {
+ id: row1
+ width: parent.width
+ height: 70
+ spacing: 80
+
+ Row {
+ anchors.verticalCenter: parent.verticalCenter
+ spacing: 24
+
+ Item {
+ width: internal.iconSize
+ height: internal.iconSize
+
+ Image {
+ id: icon
+ source: "images/temperature.svg"
+ sourceSize.width: internal.iconSize
+ sourceSize.height: internal.iconSize
+ }
+
+ MultiEffect {
+ anchors.fill: icon
+ source: icon
+ colorization: 1
+ colorizationColor: Constants.iconColor
+ }
+ }
+
+ Label {
+ font.pixelSize: internal.fontSize
+ font.weight: 600
+ font.family: "Titillium Web"
+ text: qsTr("Set Temperature :")
+ color: Constants.primaryTextColor
+ }
+ }
+
+ CustomTextField {
+ anchors.verticalCenter: parent.verticalCenter
+ text: slider.value
+ onAccepted: slider.value = +text
+ }
+
+ CustomSlider {
+ id: slider
+ anchors.bottom: parent.bottom
+ }
+ }
+
+ Column {
+ anchors.verticalCenter: parent.verticalCenter
+ spacing: 50
+ Row {
+ id: row
+ spacing: 70
+ Label {
+ font.pixelSize: 24
+ font.weight: 600
+ font.family: "Titillium Web"
+ text: qsTr("Mode")
+ anchors.verticalCenter: parent.verticalCenter
+ color: Constants.primaryTextColor
+ }
+
+ Repeater {
+ model: [qsTr("Heating"), qsTr("Cooling"), qsTr("Auto")]
+ CustomRadioButton {
+ text: modelData
+ indicatorSize: 20
+ }
+ }
+ }
+
+ Row {
+ spacing: 24
+ Label {
+ font.pixelSize: 24
+ font.weight: 600
+ font.family: "Titillium Web"
+ text: qsTr("Repeat")
+ anchors.verticalCenter: parent.verticalCenter
+ color: Constants.primaryTextColor
+ }
+
+ Repeater {
+ model: [qsTr("Mon"), qsTr("Tue"), qsTr("Wed"), qsTr(
+ "Thu"), qsTr("Fri"), qsTr("Sat"), qsTr("Sun")]
+
+ CustomRoundButton {
+ text: modelData
+ width: 90
+ height: 50
+ radius: 12
+ font.pixelSize: 24
+ }
+ }
+ }
+ }
+
+ Row {
+ anchors.bottom: parent.bottom
+ anchors.right: parent.right
+ spacing: 24
+
+ Repeater {
+ model: [qsTr("Cancel"), qsTr("Save")]
+ CustomRoundButton {
+ width: 120
+ height: 48
+ text: modelData
+ radius: 12
+ contentColor: "#2CDE85"
+ checkable: false
+ font.pixelSize: 14
+ }
+ }
+ }
+
+ QtObject {
+ id: internal
+ property int fontSize: 24
+ property int topMargin: 67
+ property int iconSize: 34
+ }
+}
diff --git a/examples/demos/thermostat/content/TemperatureSetterForm.ui.qml b/examples/demos/thermostat/content/TemperatureSetterForm.ui.qml
new file mode 100644
index 000000000..53f670280
--- /dev/null
+++ b/examples/demos/thermostat/content/TemperatureSetterForm.ui.qml
@@ -0,0 +1,91 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+/*
+This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
+It is supposed to be strictly declarative and only uses a subset of QML. If you edit
+this file manually, you might introduce QML code that is not supported by Qt Design Studio.
+Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
+*/
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import Thermostat
+import CustomControls
+
+Pane {
+ width: 1087
+ height: 361
+
+ padding: 0
+
+ background: Rectangle {
+ color: Constants.accentColor
+ radius: 12
+ }
+
+ TemperatureSetterDesktopView {
+ id: desktopView
+ }
+
+ TemperatureSetterMobileView {
+ id: mobileView
+ visible: false
+ }
+
+ TemperatureSetterSmallView {
+ id: smallView
+ visible: false
+ }
+
+ states: [
+ State {
+ name: "desktopLayout"
+ when: Constants.isBigDesktopLayout || Constants.isSmallDesktopLayout
+ PropertyChanges {
+ target: desktopView
+ visible: true
+ }
+ PropertyChanges {
+ target: mobileView
+ visible: false
+ }
+ PropertyChanges {
+ target: smallView
+ visible: false
+ }
+ },
+ State {
+ name: "mobileLayout"
+ when: Constants.isMobileLayout
+ PropertyChanges {
+ target: desktopView
+ visible: false
+ }
+ PropertyChanges {
+ target: mobileView
+ visible: true
+ }
+ PropertyChanges {
+ target: smallView
+ visible: false
+ }
+ },
+ State {
+ name: "smallLayout"
+ when: Constants.isSmallLayout
+ PropertyChanges {
+ target: desktopView
+ visible: false
+ }
+ PropertyChanges {
+ target: mobileView
+ visible: false
+ }
+ PropertyChanges {
+ target: smallView
+ visible: true
+ }
+ }
+ ]
+}
diff --git a/examples/demos/thermostat/content/TemperatureSetterMobileView.qml b/examples/demos/thermostat/content/TemperatureSetterMobileView.qml
new file mode 100644
index 000000000..715dbfb74
--- /dev/null
+++ b/examples/demos/thermostat/content/TemperatureSetterMobileView.qml
@@ -0,0 +1,8 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+TemperatureSetterMobileViewForm {
+
+}
diff --git a/examples/demos/thermostat/content/TemperatureSetterMobileViewForm.ui.qml b/examples/demos/thermostat/content/TemperatureSetterMobileViewForm.ui.qml
new file mode 100644
index 000000000..f509061b9
--- /dev/null
+++ b/examples/demos/thermostat/content/TemperatureSetterMobileViewForm.ui.qml
@@ -0,0 +1,154 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+
+/*
+This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
+It is supposed to be strictly declarative and only uses a subset of QML. If you edit
+this file manually, you might introduce QML code that is not supported by Qt Design Studio.
+Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
+*/
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import QtQuick.Effects
+import Thermostat
+import CustomControls
+
+Pane {
+ width: 329
+ height: 527
+
+ topPadding: 16
+ bottomPadding: 19
+
+ background: Rectangle {
+ color: Constants.accentColor
+ radius: 12
+ }
+
+ ColumnLayout {
+ anchors.fill: parent
+ spacing: 15
+ Row {
+ spacing: 10
+
+ Item {
+ width: 24
+ height: 24
+ Image {
+ id: icon
+ source: "images/temperature.svg"
+ sourceSize.width: 24
+ sourceSize.height: 24
+ }
+ MultiEffect {
+ anchors.fill: icon
+ source: icon
+ colorization: 1
+ colorizationColor: Constants.iconColor
+ }
+ }
+
+ Label {
+ font.pixelSize: 18
+ font.weight: 600
+ font.family: "Titillium Web"
+ text: qsTr("Set Temperature :")
+ color: Constants.primaryTextColor
+ }
+ }
+
+ CustomTextField {
+ width: 102
+ height: 40
+ font.pixelSize: 14
+ text: slider.value
+ onAccepted: slider.value = +text
+ }
+
+ Item {
+ id: item1
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ CustomSlider {
+ id: slider
+ width: parent.width
+ anchors.bottom: parent.bottom
+ }
+ }
+
+ Column {
+ Label {
+ font.pixelSize: 18
+ font.weight: 600
+ font.family: "Titillium Web"
+ text: qsTr("Mode")
+ color: Constants.primaryTextColor
+ }
+
+ Repeater {
+ model: [qsTr("Heating"), qsTr("Cooling"), qsTr("Auto")]
+ CustomRadioButton {
+ text: modelData
+ font.pixelSize: 14
+ indicatorSize: 14
+ }
+ }
+ }
+
+ ColumnLayout {
+ spacing: 12
+ Label {
+ font.pixelSize: 18
+ font.weight: 600
+ font.family: "Titillium Web"
+ text: qsTr("Repeat")
+ color: Constants.primaryTextColor
+ }
+
+ RowLayout {
+ Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
+ Layout.fillWidth: true
+ spacing: 24
+ Repeater {
+ id: repeater
+ model: [qsTr("MO"), qsTr("TU"), qsTr("WE"), qsTr(
+ "TH"), qsTr("FR"), qsTr("SA"), qsTr("SU")]
+
+ Label {
+ property bool checked: false
+
+ text: modelData
+ Layout.fillWidth: true
+ height: 21
+ font.pixelSize: 14
+ horizontalAlignment: Text.AlignHCenter
+ color: checked ? "#2CDE85" : Constants.primaryTextColor
+ TapHandler {
+ onTapped: parent.checked = !parent.checked
+ }
+ }
+ }
+ }
+ }
+ ColumnLayout {
+ Layout.fillWidth: true
+ spacing: 8
+
+ Repeater {
+ model: [qsTr("Cancel"), qsTr("Save")]
+
+ CustomRoundButton {
+ height: 45
+ Layout.fillWidth: true
+ text: modelData
+ radius: 12
+ contentColor: "#2CDE85"
+ checkable: false
+ font.pixelSize: 14
+ }
+ }
+ }
+ }
+}
diff --git a/examples/demos/thermostat/content/TemperatureSetterSmallView.qml b/examples/demos/thermostat/content/TemperatureSetterSmallView.qml
new file mode 100644
index 000000000..131bffdc6
--- /dev/null
+++ b/examples/demos/thermostat/content/TemperatureSetterSmallView.qml
@@ -0,0 +1,8 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+TemperatureSetterSmallViewForm {
+
+}
diff --git a/examples/demos/thermostat/content/TemperatureSetterSmallViewForm.ui.qml b/examples/demos/thermostat/content/TemperatureSetterSmallViewForm.ui.qml
new file mode 100644
index 000000000..d0688361a
--- /dev/null
+++ b/examples/demos/thermostat/content/TemperatureSetterSmallViewForm.ui.qml
@@ -0,0 +1,189 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+
+/*
+This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
+It is supposed to be strictly declarative and only uses a subset of QML. If you edit
+this file manually, you might introduce QML code that is not supported by Qt Design Studio.
+Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
+*/
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import QtQuick.Effects
+import Thermostat
+import CustomControls
+
+Pane {
+ width: 400
+ height: 370
+
+ topPadding: 16
+ bottomPadding: 19
+
+ background: Rectangle {
+ color: Constants.accentColor
+ radius: 12
+ }
+
+ Frame {
+ id: frame
+ height: 260
+ width: 332
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ ColumnLayout {
+ anchors.fill: parent
+
+ RowLayout {
+ width: parent.width
+
+ Row {
+ id: row
+ Layout.alignment: Qt.AlignLeft | Qt.AlignBottom
+ Layout.fillWidth: true
+ spacing: 10
+
+ Item {
+ width: 15
+ height: 15
+ anchors.verticalCenter: parent.verticalCenter
+
+ Image {
+ id: icon
+
+ source: "images/temperature.svg"
+ sourceSize.width: 15
+ sourceSize.height: 15
+ }
+
+ MultiEffect {
+ anchors.fill: icon
+ source: icon
+ colorization: 1
+ colorizationColor: Constants.iconColor
+ }
+ }
+
+ Label {
+ font.pixelSize: 14
+ font.weight: 600
+ font.family: "Titillium Web"
+ text: qsTr("Set Temperature :")
+ color: Constants.primaryTextColor
+ }
+ }
+
+ CustomTextField {
+ width: 102
+ height: 40
+ font.pixelSize: 14
+ text: slider.value
+ onAccepted: slider.value = +text
+ }
+ }
+
+ Item {
+ id: item1
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ CustomSlider {
+ id: slider
+ width: parent.width
+ anchors.bottom: parent.bottom
+ }
+ }
+
+ ColumnLayout {
+ spacing: 0
+
+ Label {
+ font.pixelSize: 14
+ font.weight: 600
+ font.family: "Titillium Web"
+ text: qsTr("Mode")
+ color: Constants.primaryTextColor
+ }
+
+ RowLayout {
+ Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
+ Layout.fillWidth: true
+ Layout.leftMargin: 50
+ spacing: 16
+ Repeater {
+ model: [qsTr("Heating"), qsTr("Cooling"), qsTr("Auto")]
+ CustomRadioButton {
+ text: modelData
+ font.pixelSize: 14
+ indicatorSize: 14
+ topPadding: 0
+ bottomPadding: 0
+ }
+ }
+ }
+ }
+
+ ColumnLayout {
+ spacing: 0
+
+ Label {
+ font.pixelSize: 14
+ font.weight: 600
+ font.family: "Titillium Web"
+ text: qsTr("Repeat")
+ color: Constants.primaryTextColor
+ }
+
+ RowLayout {
+ Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
+ Layout.fillWidth: true
+ Layout.leftMargin: 50
+ spacing: 16
+
+ Repeater {
+ id: repeater
+ model: [qsTr("MO"), qsTr("TU"), qsTr("WE"), qsTr(
+ "TH"), qsTr("FR"), qsTr("SA"), qsTr("SU")]
+
+ Label {
+ property bool checked: false
+
+ text: modelData
+ Layout.fillWidth: true
+ height: 21
+ font.pixelSize: 14
+ horizontalAlignment: Text.AlignHCenter
+ color: checked ? "#2CDE85" : Constants.primaryTextColor
+ TapHandler {
+ onTapped: parent.checked = !parent.checked
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Row {
+ anchors.top: frame.bottom
+ anchors.right: frame.right
+ anchors.topMargin: 16
+ spacing: 17
+
+ Repeater {
+ model: [qsTr("Cancel"), qsTr("Save")]
+
+ CustomRoundButton {
+ width: 78
+ height: 38
+ text: modelData
+ radius: 8
+ contentColor: "#2CDE85"
+ checkable: false
+ font.pixelSize: 14
+ display: AbstractButton.TextOnly
+ }
+ }
+ }
+}
diff --git a/examples/demos/thermostat/content/ThermostatInfo.qml b/examples/demos/thermostat/content/ThermostatInfo.qml
new file mode 100644
index 000000000..0f87b2ebe
--- /dev/null
+++ b/examples/demos/thermostat/content/ThermostatInfo.qml
@@ -0,0 +1,8 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+ThermostatInfoForm {
+
+}
diff --git a/examples/demos/thermostat/content/ThermostatInfoForm.ui.qml b/examples/demos/thermostat/content/ThermostatInfoForm.ui.qml
new file mode 100644
index 000000000..515963289
--- /dev/null
+++ b/examples/demos/thermostat/content/ThermostatInfoForm.ui.qml
@@ -0,0 +1,258 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+
+/*
+This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
+It is supposed to be strictly declarative and only uses a subset of QML. If you edit
+this file manually, you might introduce QML code that is not supported by Qt Design Studio.
+Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
+*/
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import QtQuick.Effects
+import Thermostat
+import CustomControls
+
+Pane {
+ id: root
+
+ property alias title: title.text
+ property alias leftIcon: icon.source
+ property alias rightIcon: icon2.source
+ property alias topLabel: topLabel.text
+ property alias bottomLeftIcon: bottomLeftIcon.source
+ property alias bottomRightIcon: bottomRightIcon.source
+ property alias bottomLeftLabel: bottomLeftLabel.text
+ property alias bottomRightLabel: bottomRightLabel.text
+
+ topPadding: 20
+ leftPadding: 16
+ rightPadding: 16
+ bottomPadding: 14
+
+ width: 350
+ height: 182
+
+ background: Rectangle {
+ radius: 12
+ color: Constants.accentColor
+ border.color: Constants.isSmallLayout ? "#D9D9D9" : "transparent"
+ }
+
+ Column {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.top: parent.top
+ spacing: internal.columnSpacing
+
+ RowLayout {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ spacing: internal.rowSpacing
+
+ Item {
+ id: iconItem
+
+ Layout.preferredWidth: icon.sourceSize.width
+ Layout.preferredHeight: icon.sourceSize.height
+
+ Image {
+ id: icon
+
+ source: "images/schedule.svg"
+ }
+
+ MultiEffect {
+ anchors.fill: icon
+ source: icon
+ colorization: 1
+ colorizationColor: Constants.iconColor
+ }
+ }
+
+ Label {
+ id: title
+
+ text: qsTr("Room Schedule")
+ font.weight: 600
+ font.pixelSize: 24
+ font.family: "Titillium Web"
+ color: Constants.primaryTextColor
+ Layout.fillWidth: true
+ }
+
+ Image {
+ id: icon2
+ }
+ }
+
+ Column {
+ leftPadding: internal.infoLeftPadding
+ spacing: internal.infoSpacing
+ width: parent.width
+
+ Label {
+ id: topLabel
+
+ text: qsTr("Afternoon: 21°C (12pm-5pm)")
+ font.pixelSize: internal.infoFontSize
+ font.bold: true
+ font.family: "Titillium Web"
+ color: Constants.primaryTextColor
+ }
+
+ RowLayout {
+ spacing: 32
+
+ Row {
+ spacing: 10
+
+ Image {
+ id: bottomLeftIcon
+ }
+
+ Label {
+ id: bottomLeftLabel
+
+ text: qsTr("Night: 25°C (10pm-6am)")
+ font.pixelSize: internal.infoFontSize
+ font.weight: 600
+ font.family: "Titillium Web"
+ color: Constants.primaryTextColor
+ }
+ }
+
+ Row {
+ spacing: 10
+
+ Image {
+ id: bottomRightIcon
+ }
+
+ Label {
+ id: bottomRightLabel
+
+ font.pixelSize: internal.infoFontSize
+ font.weight: 600
+ font.family: "Titillium Web"
+ color: Constants.primaryTextColor
+ }
+ }
+ }
+ }
+ }
+
+ QtObject {
+ id: internal
+
+ property int rowSpacing: 24
+ property int columnSpacing: 24
+ property int infoSpacing: 8
+ property int infoFontSize: 14
+ property int infoLeftPadding: 14
+ }
+
+ states: [
+ State {
+ name: "desktopLayout"
+ when: Constants.isBigDesktopLayout || Constants.isSmallDesktopLayout
+ PropertyChanges {
+ target: internal
+ rowSpacing: 24
+ columnSpacing: 16
+ infoSpacing: 16
+ infoFontSize: 14
+ infoLeftPadding: 0
+ }
+ PropertyChanges {
+ target: icon
+ sourceSize.width: 34
+ sourceSize.height: 34
+ }
+ PropertyChanges {
+ target: icon2
+ sourceSize.width: 20
+ sourceSize.height: 20
+ }
+ PropertyChanges {
+ target: title
+ font.pixelSize: 24
+ }
+ PropertyChanges {
+ target: root
+ topPadding: 20
+ leftPadding: 16
+ rightPadding: 16
+ bottomPadding: 14
+ }
+ },
+ State {
+ name: "mobileLayout"
+ when: Constants.isMobileLayout
+ PropertyChanges {
+ target: internal
+ rowSpacing: 9
+ columnSpacing: 11
+ infoSpacing: 5
+ infoFontSize: 12
+ infoLeftPadding: 10
+ }
+ PropertyChanges {
+ target: icon
+ sourceSize.width: 20
+ sourceSize.height: 20
+ }
+ PropertyChanges {
+ target: icon2
+ sourceSize.width: 15
+ sourceSize.height: 15
+ }
+ PropertyChanges {
+ target: title
+ font.pixelSize: 14
+ }
+ PropertyChanges {
+ target: root
+ topPadding: 10
+ leftPadding: 7
+ rightPadding: 16
+ bottomPadding: 8
+ }
+ },
+ State {
+ name: "smallLayout"
+ when: Constants.isSmallLayout
+ PropertyChanges {
+ target: internal
+ rowSpacing: 5
+ infoFontSize: 12
+ columnSpacing: 3
+ infoSpacing: 4
+ infoLeftPadding: 13
+ }
+ PropertyChanges {
+ target: icon
+ sourceSize.width: 15
+ sourceSize.height: 15
+ }
+ PropertyChanges {
+ target: icon2
+ sourceSize.width: 15
+ sourceSize.height: 15
+ }
+ PropertyChanges {
+ target: title
+ font.pixelSize: 14
+ }
+ PropertyChanges {
+ target: root
+ topPadding: 4
+ leftPadding: 5
+ rightPadding: 10
+ bottomPadding: 14
+ }
+ }
+ ]
+}
diff --git a/examples/demos/thermostat/content/ThermostatScrollView.qml b/examples/demos/thermostat/content/ThermostatScrollView.qml
new file mode 100644
index 000000000..d0afa043c
--- /dev/null
+++ b/examples/demos/thermostat/content/ThermostatScrollView.qml
@@ -0,0 +1,8 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+ThermostatScrollViewForm {
+
+}
diff --git a/examples/demos/thermostat/content/ThermostatScrollViewForm.ui.qml b/examples/demos/thermostat/content/ThermostatScrollViewForm.ui.qml
new file mode 100644
index 000000000..16fb91ee3
--- /dev/null
+++ b/examples/demos/thermostat/content/ThermostatScrollViewForm.ui.qml
@@ -0,0 +1,120 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+
+/*
+This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
+It is supposed to be strictly declarative and only uses a subset of QML. If you edit
+this file manually, you might introduce QML code that is not supported by Qt Design Studio.
+Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
+*/
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import Thermostat
+
+ScrollView {
+ id: root
+
+ clip: true
+ contentWidth: availableWidth
+
+ property alias thermoSettings: thermoSettings
+ property alias roomName: thermoSettings.roomNameText
+ property alias roomIcon: thermoSettings.roomIconSource
+ property alias isActive: thermoSettings.isActive
+
+ property bool isOneColumn
+ property int thermostatControlHeight
+ property int thermostatControlWidth
+ property int delegateHeight
+ property int delegateWidth
+
+ background: Rectangle {
+ color: Constants.isSmallLayout ? Constants.accentColor : "transparent"
+ radius: 12
+ }
+
+ GridLayout {
+ id: grid
+
+ width: root.width
+ height: root.height
+ columns: root.isOneColumn ? 1 : 3
+ rows: root.isOneColumn ? 10 : 1
+ columnSpacing: 24
+ rowSpacing: root.isOneColumn ? 12 : 24
+
+ ThermostatSettings {
+ id: thermoSettings
+
+ Layout.columnSpan: root.isOneColumn ? 1 : 3
+ Layout.rowSpan: root.isOneColumn ? 7 : 1
+ Layout.preferredHeight: root.thermostatControlHeight
+ Layout.preferredWidth: root.thermostatControlWidth
+ Layout.alignment: Qt.AlignHCenter
+
+ model: root.model
+
+ onIsActiveChanged: root.model.active = isActive
+ }
+
+ ThermostatInfo {
+ Layout.preferredHeight: root.delegateHeight
+ Layout.preferredWidth: root.delegateWidth
+ Layout.alignment: Qt.AlignHCenter
+ }
+
+ HumidityInfo {
+ Layout.preferredHeight: root.delegateHeight
+ Layout.preferredWidth: root.delegateWidth
+ Layout.alignment: Qt.AlignHCenter
+
+ humidityValuesModel: root.model.humidityStats
+ }
+
+ EnergyInfo {
+ Layout.preferredHeight: root.delegateHeight
+ Layout.preferredWidth: root.delegateWidth
+ Layout.alignment: Qt.AlignHCenter
+
+ energyValuesModel: root.model.energyStats
+ }
+ }
+
+ states: [
+ State {
+ name: "desktopLayout"
+ when: Constants.isBigDesktopLayout || Constants.isSmallDesktopLayout
+ PropertyChanges {
+ target: root
+ thermostatControlHeight: 673
+ thermostatControlWidth: 1094
+ delegateHeight: 182
+ delegateWidth: 350
+ }
+ },
+ State {
+ name: "mobileLayout"
+ when: Constants.isMobileLayout
+ PropertyChanges {
+ target: root
+ delegateWidth: 327
+ delegateHeight: 100
+ thermostatControlHeight: 694
+ thermostatControlWidth: 327
+ }
+ },
+ State {
+ name: "smallLayout"
+ when: Constants.isSmallLayout
+ PropertyChanges {
+ target: root
+ delegateWidth: 332
+ delegateHeight: 80
+ thermostatControlHeight: 250
+ thermostatControlWidth: 400
+ }
+ }
+ ]
+}
diff --git a/examples/demos/thermostat/content/ThermostatSettings.qml b/examples/demos/thermostat/content/ThermostatSettings.qml
new file mode 100644
index 000000000..83feaaf4a
--- /dev/null
+++ b/examples/demos/thermostat/content/ThermostatSettings.qml
@@ -0,0 +1,8 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+ThermostatSettingsForm {
+ buttonGroup.onClicked: (button) => model.mode = button.text
+}
diff --git a/examples/demos/thermostat/content/ThermostatSettingsForm.ui.qml b/examples/demos/thermostat/content/ThermostatSettingsForm.ui.qml
new file mode 100644
index 000000000..8929785c8
--- /dev/null
+++ b/examples/demos/thermostat/content/ThermostatSettingsForm.ui.qml
@@ -0,0 +1,322 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+
+/*
+This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
+It is supposed to be strictly declarative and only uses a subset of QML. If you edit
+this file manually, you might introduce QML code that is not supported by Qt Design Studio.
+Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
+*/
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Effects
+import CustomControls
+import Thermostat
+
+Pane {
+ id: root
+
+ required property var model
+ property alias buttonGroup: buttonGroup
+ property alias powerButton: powerButton
+ property alias powerToggle: powerToggle
+ property alias roomIconSource: roomIcon.source
+ property alias roomNameText: roomName.text
+ property bool isActive: false
+
+ padding: 0
+
+ background: Rectangle {
+ color: Constants.accentColor
+ radius: 12
+ }
+
+ Row {
+ anchors.left: parent.left
+ anchors.top: parent.top
+ anchors.leftMargin: internal.leftMargin
+ anchors.topMargin: internal.topMargin
+ spacing: internal.headerSpacing
+
+ Item {
+ width: internal.iconSize
+ height: internal.iconSize
+
+ Image {
+ id: roomIcon
+
+ source: "images/living_room.svg"
+ sourceSize.width: internal.iconSize
+ sourceSize.height: internal.iconSize
+ }
+
+ MultiEffect {
+ anchors.fill: roomIcon
+ source: roomIcon
+ colorization: 1
+ colorizationColor: Constants.iconColor
+ }
+ }
+
+ Label {
+ id: roomName
+ text: qsTr("Living room")
+ font.pixelSize: internal.headerSize
+ font.weight: 600
+ font.family: "Titillium Web"
+ color: Constants.primaryTextColor
+ }
+ }
+
+ CustomSwitch {
+ id: powerToggle
+ anchors.right: parent.right
+ anchors.top: parent.top
+ anchors.topMargin: 12
+ anchors.rightMargin: 12
+ checked: root.isActive
+ Connections {
+ function onCheckedChanged() {
+ root.isActive = powerToggle.checked
+ }
+ }
+ }
+
+ ThermostatControl {
+ id: thermostat
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.top: parent.top
+ anchors.topMargin: internal.thermostatTopMargin
+ enabled: root.isActive
+
+ currentTemp: root.model.temp
+ targetTemp: root.model.thermostatTemp
+ onTargetTempChanged: root.model.thermostatTemp = targetTemp
+ }
+
+ ButtonGroup {
+ id: buttonGroup
+ }
+
+ Column {
+ id: leftButtons
+
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.left: parent.left
+ anchors.leftMargin: 100
+ spacing: 25
+
+ Repeater {
+ model: [qsTr("Cool"), qsTr("Fan"), qsTr("Auto")]
+
+ CustomRoundButton {
+ width: internal.buttonWidth
+ height: internal.buttonHeight
+ text: modelData
+ font.pixelSize: 18
+ icon.source: "images/" + modelData
+ icon.width: internal.optionIconSize
+ icon.height: internal.optionIconSize
+ LayoutMirroring.enabled: true
+ radius: internal.radius
+ ButtonGroup.group: buttonGroup
+ enabled: root.isActive
+ checked: enabled && root.model.mode == modelData
+ }
+ }
+ }
+
+ Column {
+ id: rightButtons
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.right: parent.right
+ anchors.rightMargin: 100
+ spacing: 25
+
+ Repeater {
+ model: [qsTr("Heat"), qsTr("Dry"), qsTr("Eco")]
+
+ CustomRoundButton {
+ width: internal.buttonWidth
+ height: internal.buttonHeight
+ text: modelData
+ font.pixelSize: 18
+ icon.source: "images/" + modelData
+ icon.width: internal.optionIconSize
+ icon.height: internal.optionIconSize
+ radius: internal.radius
+ ButtonGroup.group: buttonGroup
+ enabled: root.isActive
+ checked: enabled && root.model.mode == modelData
+ }
+ }
+ }
+
+ CustomRoundButton {
+ id: powerButton
+ height: 80
+ width: 80
+ radius: 65
+ text: qsTr("Power")
+ font.pixelSize: 18
+ icon.source: "images/power.svg"
+ icon.width: 40
+ icon.height: 40
+ display: AbstractButton.IconOnly
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: 50
+ checked: root.isActive
+ Connections {
+ function onCheckedChanged() {
+ root.isActive = powerButton.checked
+ }
+ }
+ }
+
+ QtObject {
+ id: internal
+
+ property int buttonWidth: 130
+ property int buttonHeight: 66
+ property int radius: 20
+ property int leftMargin: 20
+ property int topMargin: 16
+ property int iconSize: 34
+ property int optionIconSize: 42
+ property int headerSpacing: 24
+ property int headerSize: 24
+ property int thermostatTopMargin: 14
+ }
+
+ states: [
+ State {
+ name: "desktopLayout"
+ when: Constants.isBigDesktopLayout || Constants.isSmallDesktopLayout
+ PropertyChanges {
+ target: internal
+ buttonHeight: 66
+ buttonWidth: 130
+ radius: 20
+ leftMargin: 20
+ topMargin: 16
+ iconSize: 34
+ optionIconSize: 42
+ headerSpacing: 24
+ headerSize: 24
+ thermostatTopMargin: 14
+ }
+ PropertyChanges {
+ target: powerButton
+ width: 80
+ height: 80
+ radius: 40
+ visible: true
+ anchors.bottomMargin: 50
+ icon.width: 40
+ icon.height: 40
+ }
+ PropertyChanges {
+ target: powerToggle
+ visible: false
+ }
+ },
+ State {
+ name: "mobileLayout"
+ when: Constants.isMobileLayout
+ PropertyChanges {
+ target: internal
+ buttonHeight: 50
+ buttonWidth: 110
+ radius: 12
+ leftMargin: 16
+ topMargin: 16
+ iconSize: 24
+ optionIconSize: 30
+ headerSpacing: 16
+ headerSize: 18
+ thermostatTopMargin: 60
+ }
+ PropertyChanges {
+ target: leftButtons
+ anchors.leftMargin: 46 - root.leftPadding
+ spacing: 14
+ }
+ AnchorChanges {
+ target: leftButtons
+ anchors.verticalCenter: undefined
+ anchors.top: thermostat.bottom
+ }
+ PropertyChanges {
+ target: rightButtons
+ anchors.rightMargin: 46 - root.rightPadding
+ spacing: 14
+ }
+ AnchorChanges {
+ target: rightButtons
+ anchors.verticalCenter: undefined
+ anchors.top: thermostat.bottom
+ }
+ PropertyChanges {
+ target: powerButton
+ width: 60
+ height: 60
+ radius: 30
+ visible: true
+ anchors.bottomMargin: 32
+ icon.width: 30
+ icon.height: 30
+ }
+ PropertyChanges {
+ target: powerToggle
+ visible: false
+ }
+ },
+ State {
+ name: "smallLayout"
+ when: Constants.isSmallLayout
+ PropertyChanges {
+ target: internal
+ buttonHeight: 42
+ buttonWidth: 42
+ radius: 21
+ leftMargin: 14
+ topMargin: 11
+ iconSize: 24
+ optionIconSize: 24
+ headerSpacing: 12
+ headerSize: 18
+ thermostatTopMargin: 19
+ }
+ PropertyChanges {
+ target: powerButton
+ visible: false
+ }
+ PropertyChanges {
+ target: leftButtons
+ anchors.leftMargin: 14
+ spacing: 9
+ }
+ AnchorChanges {
+ target: leftButtons
+ anchors.verticalCenter: thermostat.verticalCenter
+ anchors.top: undefined
+ }
+ PropertyChanges {
+ target: rightButtons
+ anchors.rightMargin: 14
+ spacing: 9
+ }
+ AnchorChanges {
+ target: rightButtons
+ anchors.verticalCenter: thermostat.verticalCenter
+ anchors.top: undefined
+ }
+ PropertyChanges {
+ target: powerToggle
+ visible: true
+ }
+ }
+ ]
+}
diff --git a/examples/demos/thermostat/content/ThermostatStackView.qml b/examples/demos/thermostat/content/ThermostatStackView.qml
new file mode 100644
index 000000000..2309b1853
--- /dev/null
+++ b/examples/demos/thermostat/content/ThermostatStackView.qml
@@ -0,0 +1,8 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+ThermostatStackViewForm {
+
+}
diff --git a/examples/demos/thermostat/content/ThermostatStackViewForm.ui.qml b/examples/demos/thermostat/content/ThermostatStackViewForm.ui.qml
new file mode 100644
index 000000000..c8a31cea6
--- /dev/null
+++ b/examples/demos/thermostat/content/ThermostatStackViewForm.ui.qml
@@ -0,0 +1,44 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+
+/*
+This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
+It is supposed to be strictly declarative and only uses a subset of QML. If you edit
+this file manually, you might introduce QML code that is not supported by Qt Design Studio.
+Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
+*/
+import QtQuick
+import QtQuick.Layouts
+
+Item {
+ id: root
+
+ property bool isOneColumn: false
+ property var model
+ property int currentRoomIndex
+
+ StackLayout {
+ anchors.fill: parent
+ currentIndex: currentRoomIndex
+
+ Repeater {
+ id: repeater
+ model: root.model
+
+ ThermostatScrollView {
+ id: delegate
+
+ required property string name
+ required property var model
+
+ width: root.width
+ height: root.height
+ isOneColumn: root.isOneColumn
+
+ roomName: name
+ isActive: model.active
+ }
+ }
+ }
+}
diff --git a/examples/demos/thermostat/content/ThermostatSwipeView.qml b/examples/demos/thermostat/content/ThermostatSwipeView.qml
new file mode 100644
index 000000000..d76c64816
--- /dev/null
+++ b/examples/demos/thermostat/content/ThermostatSwipeView.qml
@@ -0,0 +1,8 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+ThermostatSwipeViewForm {
+
+}
diff --git a/examples/demos/thermostat/content/ThermostatSwipeViewForm.ui.qml b/examples/demos/thermostat/content/ThermostatSwipeViewForm.ui.qml
new file mode 100644
index 000000000..f53d63239
--- /dev/null
+++ b/examples/demos/thermostat/content/ThermostatSwipeViewForm.ui.qml
@@ -0,0 +1,86 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+/*
+This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
+It is supposed to be strictly declarative and only uses a subset of QML. If you edit
+this file manually, you might introduce QML code that is not supported by Qt Design Studio.
+Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
+*/
+import QtQuick
+import QtQuick.Controls
+
+Item {
+ id: root
+
+ property alias swipe: swipeView
+ property alias currentRoomIndex: swipeView.currentIndex
+
+ property var model
+ property bool isOneColumn: false
+
+ ListView {
+ id: roomSelector
+
+ model: root.model
+ orientation: ListView.Horizontal
+ width: root.width
+ height: 28
+ spacing: 26
+ delegate: Label {
+ id: labelDelegate
+
+ required property string name
+ required property int index
+
+ text: name
+ font.pixelSize: 12
+ font.family: "Titillium Web"
+ font.weight: 400
+ font.bold: swipeView.currentIndex === index
+ font.underline: swipeView.currentIndex === index
+ color: swipeView.currentIndex === index ? "#2CDE85" : "#898989"
+
+ MouseArea {
+ anchors.fill: parent
+ Connections {
+ function onClicked() {
+ swipeView.setCurrentIndex(labelDelegate.index)
+ }
+ }
+ }
+ }
+ }
+
+ SwipeView {
+ id: swipeView
+
+ height: root.height - roomSelector.height + 13
+ width: root.width
+
+ anchors.top: roomSelector.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ spacing: 7
+ clip: true
+
+ Repeater {
+ id: repeater
+ model: root.model
+
+ ThermostatScrollView {
+ id: delegate
+ required property int index
+ required property string name
+ required property bool active
+ required property var model
+
+ width: swipeView.width
+ height: swipeView.height
+ isOneColumn: root.isOneColumn
+
+ roomName: name
+ isActive: model.active
+ }
+ }
+ }
+}
diff --git a/examples/demos/thermostat/content/ThermostatView.qml b/examples/demos/thermostat/content/ThermostatView.qml
new file mode 100644
index 000000000..3b159871e
--- /dev/null
+++ b/examples/demos/thermostat/content/ThermostatView.qml
@@ -0,0 +1,8 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+ThermostatViewForm {
+
+}
diff --git a/examples/demos/thermostat/content/ThermostatViewForm.ui.qml b/examples/demos/thermostat/content/ThermostatViewForm.ui.qml
new file mode 100644
index 000000000..f27e00be5
--- /dev/null
+++ b/examples/demos/thermostat/content/ThermostatViewForm.ui.qml
@@ -0,0 +1,184 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+
+/*
+This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
+It is supposed to be strictly declarative and only uses a subset of QML. If you edit
+this file manually, you might introduce QML code that is not supported by Qt Design Studio.
+Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
+*/
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import Thermostat
+import CustomControls
+
+Pane {
+ id: root
+
+ leftPadding: 20
+ rightPadding: 20
+ bottomPadding: 15
+
+ property int currentRoomIndex: 0
+ required property var roomsList
+
+ background: Rectangle {
+ color: Constants.backgroundColor
+ }
+
+ QtObject {
+ id: internal
+
+ readonly property int contentHeight: root.height - title.height
+ - root.topPadding - root.bottomPadding
+ readonly property int contentWidth: root.width - root.rightPadding - root.leftPadding
+ readonly property bool isOneColumn: contentWidth < 900
+ }
+
+ Column {
+ id: title
+
+ width: parent.width
+ Label {
+ id: header
+
+ text: qsTr("Thermostat Control")
+ font.pixelSize: 48
+ font.weight: 600
+ font.family: "Titillium Web"
+ color: Constants.primaryTextColor
+ elide: Text.ElideRight
+ }
+
+ RowLayout {
+ id: label
+ width: parent.width
+ Label {
+ text: qsTr("Adjust your thermostat settings")
+ font.pixelSize: 24
+ font.weight: 600
+ font.family: "Titillium Web"
+ color: Constants.accentTextColor
+ elide: Text.ElideRight
+ Layout.fillWidth: true
+ }
+
+ CustomComboBox {
+ model: roomsList
+ currentIndex: root.currentRoomIndex
+ onCurrentIndexChanged: root.currentRoomIndex = currentIndex
+ }
+ }
+ }
+
+ ThermostatStackView {
+ id: scrollView
+ anchors.top: title.bottom
+ anchors.topMargin: 12
+ anchors.leftMargin: 28
+
+ width: internal.contentWidth
+ height: internal.contentHeight
+
+ isOneColumn: internal.isOneColumn
+ model: roomsList
+ currentRoomIndex: root.currentRoomIndex
+ }
+
+ ThermostatSwipeView {
+ id: swipeView
+ anchors.top: title.bottom
+ anchors.leftMargin: 28
+
+ width: internal.contentWidth
+ height: internal.contentHeight
+
+ isOneColumn: internal.isOneColumn
+ currentRoomIndex: root.currentRoomIndex
+ model: roomsList
+ swipe.onCurrentIndexChanged: root.currentRoomIndex = swipe.currentIndex
+ }
+
+ states: [
+ State {
+ name: "desktopLayout"
+ when: Constants.isBigDesktopLayout || Constants.isSmallDesktopLayout
+ PropertyChanges {
+ target: header
+ font.pixelSize: 48
+ font.weight: 600
+ font.family: "Titillium Web"
+ }
+ PropertyChanges {
+ target: label
+ visible: true
+ }
+ PropertyChanges {
+ target: root
+ leftPadding: 20
+ }
+ PropertyChanges {
+ target: scrollView
+ visible: true
+ }
+ PropertyChanges {
+ target: swipeView
+ visible: false
+ }
+ },
+ State {
+ name: "mobileLayout"
+ when: Constants.isMobileLayout
+ PropertyChanges {
+ target: header
+ font.pixelSize: 24
+ font.weight: 600
+ font.family: "Titillium Web"
+ }
+ PropertyChanges {
+ target: label
+ visible: false
+ }
+ PropertyChanges {
+ target: root
+ leftPadding: 16
+ rightPadding: 16
+ }
+ PropertyChanges {
+ target: scrollView
+ visible: false
+ }
+ PropertyChanges {
+ target: swipeView
+ visible: true
+ }
+ },
+ State {
+ name: "smallLayout"
+ when: Constants.isSmallLayout
+ PropertyChanges {
+ target: header
+ visible: false
+ }
+ PropertyChanges {
+ target: label
+ visible: false
+ }
+ PropertyChanges {
+ target: root
+ leftPadding: 15
+ rightPadding: 15
+ }
+ PropertyChanges {
+ target: scrollView
+ visible: false
+ }
+ PropertyChanges {
+ target: swipeView
+ visible: true
+ }
+ }
+ ]
+}
diff --git a/examples/demos/thermostat/content/TimeSchedule.qml b/examples/demos/thermostat/content/TimeSchedule.qml
new file mode 100644
index 000000000..e07522246
--- /dev/null
+++ b/examples/demos/thermostat/content/TimeSchedule.qml
@@ -0,0 +1,8 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+TimeScheduleForm {
+
+}
diff --git a/examples/demos/thermostat/content/TimeScheduleForm.ui.qml b/examples/demos/thermostat/content/TimeScheduleForm.ui.qml
new file mode 100644
index 000000000..b78b486d7
--- /dev/null
+++ b/examples/demos/thermostat/content/TimeScheduleForm.ui.qml
@@ -0,0 +1,104 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+
+/*
+This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
+It is supposed to be strictly declarative and only uses a subset of QML. If you edit
+this file manually, you might introduce QML code that is not supported by Qt Design Studio.
+Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
+*/
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import Thermostat
+import CustomControls
+
+Pane {
+ width: 1087
+ height: 361
+
+ topPadding: internal.topPadding
+
+ background: Rectangle {
+ color: Constants.accentColor
+ radius: 12
+ }
+
+ RowLayout {
+ width: parent.width
+ Label {
+ font.pixelSize: internal.fontSize
+ font.weight: 600
+ font.family: "Titillium Web"
+ text: qsTr("Set Time :")
+ Layout.fillWidth: true
+ color: Constants.primaryTextColor
+ }
+ Button {
+ text: "Select Date"
+ }
+ }
+
+ TimeSelector {
+ id: timeSelector
+ anchors.top: parent.top
+ anchors.topMargin: internal.topMargin
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+
+ Label {
+ anchors.top: timeSelector.bottom
+ anchors.left: timeSelector.left
+ anchors.topMargin: internal.labelMargin
+ color: Constants.accentTextColor
+ text: qsTr("Click on a block to set the whole hour")
+ font.pixelSize: 14
+ font.weight: 400
+ font.family: "Titillium Web"
+ }
+
+ QtObject {
+ id: internal
+ property int fontSize: 24
+ property int topMargin: 67
+ property int topPadding: 20
+ property int labelMargin: 12
+ }
+
+ states: [
+ State {
+ name: "desktopLayout"
+ when: Constants.isBigDesktopLayout || Constants.isSmallDesktopLayout
+ PropertyChanges {
+ target: internal
+ topMargin: 67
+ topPadding: 20
+ fontSize: 24
+ labelMargin: 12
+ }
+ },
+ State {
+ name: "mobileLayout"
+ when: Constants.isMobileLayout
+ PropertyChanges {
+ target: internal
+ topMargin: 85
+ topPadding: 16
+ fontSize: 18
+ labelMargin: 12
+ }
+ },
+ State {
+ name: "smallLayout"
+ when: Constants.isSmallLayout
+ PropertyChanges {
+ target: internal
+ topMargin: 54
+ topPadding: 10
+ fontSize: 14
+ labelMargin: -12
+ }
+ }
+ ]
+}
diff --git a/examples/demos/thermostat/content/images/Auto.svg b/examples/demos/thermostat/content/images/Auto.svg
new file mode 100644
index 000000000..4837b5941
--- /dev/null
+++ b/examples/demos/thermostat/content/images/Auto.svg
@@ -0,0 +1,4 @@
+<svg width="32" height="31" viewBox="0 0 32 31" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M28.5706 15.2518C28.5706 22.1913 22.9386 27.8233 15.9992 27.8233C9.05973 27.8233 4.82316 20.8336 4.82316 20.8336M4.82316 20.8336H10.5054M4.82316 20.8336V27.1193M3.42773 15.2518C3.42773 8.31242 9.00945 2.68042 15.9992 2.68042C24.3843 2.68042 28.5706 9.67013 28.5706 9.67013M28.5706 9.67013V3.38442M28.5706 9.67013H22.9889" stroke="#898989" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M15.9998 11.6768C15.2928 11.6768 14.6016 11.8864 14.0137 12.2793C13.4258 12.6721 12.9676 13.2304 12.697 13.8837C12.4264 14.5369 12.3556 15.2557 12.4935 15.9492C12.6315 16.6427 12.972 17.2797 13.4719 17.7797C13.9719 18.2797 14.6089 18.6201 15.3024 18.7581C15.9959 18.896 16.7147 18.8252 17.3679 18.5546C18.0212 18.2841 18.5795 17.8258 18.9723 17.2379C19.3652 16.65 19.5748 15.9588 19.5748 15.2518C19.5738 14.304 19.1968 13.3953 18.5265 12.7251C17.8563 12.0549 16.9477 11.6779 15.9998 11.6768ZM15.9998 17.1768C15.6191 17.1768 15.2469 17.0639 14.9304 16.8524C14.6138 16.6408 14.3671 16.3402 14.2214 15.9884C14.0757 15.6367 14.0376 15.2496 14.1118 14.8762C14.1861 14.5028 14.3694 14.1598 14.6387 13.8906C14.9079 13.6214 15.2509 13.438 15.6243 13.3638C15.9977 13.2895 16.3848 13.3276 16.7365 13.4733C17.0883 13.619 17.3889 13.8657 17.6004 14.1823C17.8119 14.4989 17.9248 14.871 17.9248 15.2518C17.9248 15.7623 17.722 16.252 17.361 16.613C17 16.974 16.5104 17.1768 15.9998 17.1768ZM22.3248 15.3061V15.1975L23.2873 13.9937C23.3681 13.8928 23.4241 13.7743 23.4507 13.6479C23.4774 13.5214 23.4739 13.3905 23.4407 13.2656C23.267 12.6105 23.0074 11.9812 22.6686 11.3942C22.6033 11.2823 22.5126 11.1873 22.4038 11.1169C22.295 11.0466 22.1711 11.0028 22.0423 10.9893L20.5105 10.8174L20.4342 10.7411L20.2623 9.20865C20.2487 9.07991 20.2049 8.9562 20.1345 8.84751C20.0642 8.73883 19.9693 8.64822 19.8574 8.58303C19.2704 8.24319 18.6409 7.98265 17.9853 7.80822C17.8604 7.77545 17.7294 7.7725 17.6031 7.79961C17.4767 7.82671 17.3585 7.88312 17.258 7.96428L16.0542 8.92678H15.9455L14.7417 7.96428C14.6409 7.88348 14.5224 7.82752 14.396 7.80089C14.2695 7.77426 14.1385 7.77771 14.0137 7.81097C13.3584 7.98574 12.7291 8.2465 12.1423 8.58647C12.0308 8.65139 11.9361 8.74157 11.8657 8.84974C11.7954 8.95792 11.7514 9.08108 11.7373 9.20934L11.5655 10.7411L11.4892 10.8174L9.95672 10.9893C9.82798 11.003 9.70426 11.0467 9.59558 11.1171C9.48689 11.1874 9.39629 11.2824 9.3311 11.3942C8.99221 11.9814 8.7326 12.6109 8.55903 13.2663C8.52589 13.3911 8.5225 13.5219 8.54912 13.6482C8.57575 13.7745 8.63166 13.8929 8.71235 13.9937L9.67485 15.1975V15.3061L8.71235 16.5099C8.63155 16.6108 8.57558 16.7292 8.54895 16.8557C8.52232 16.9821 8.52578 17.1131 8.55903 17.238C8.73402 17.8933 8.99502 18.5225 9.33522 19.1093C9.40008 19.2208 9.49014 19.3154 9.5982 19.3857C9.70625 19.4561 9.82927 19.5001 9.95741 19.5143L11.4892 19.6848L11.5655 19.7611L11.7373 21.2949C11.751 21.4236 11.7948 21.5474 11.8651 21.656C11.9355 21.7647 12.0304 21.8553 12.1423 21.9205C12.7293 22.2604 13.3588 22.5209 14.0143 22.6953C14.1393 22.7281 14.2703 22.7311 14.3966 22.7039C14.523 22.6768 14.6412 22.6204 14.7417 22.5393L15.9455 21.5768H16.0542L17.258 22.5393C17.3588 22.6201 17.4773 22.676 17.6037 22.7027C17.7302 22.7293 17.8611 22.7258 17.986 22.6926C18.6411 22.5189 19.2704 22.2593 19.8574 21.9205C19.9692 21.8558 20.0642 21.7657 20.1347 21.6575C20.2053 21.5493 20.2495 21.426 20.2637 21.2977L20.4342 19.7659L20.5105 19.6896L22.043 19.5143C22.1714 19.5 22.2946 19.4559 22.4028 19.3853C22.511 19.3147 22.6011 19.2197 22.6658 19.108C23.0057 18.5209 23.2662 17.8914 23.4407 17.2359C23.4736 17.1113 23.4769 16.9808 23.4502 16.8547C23.4236 16.7286 23.3678 16.6105 23.2873 16.5099L22.3248 15.3061ZM20.6666 14.9699C20.6776 15.1577 20.6776 15.3459 20.6666 15.5337C20.6543 15.7378 20.7183 15.9391 20.846 16.0988L21.7288 17.2022C21.6455 17.4489 21.546 17.6898 21.4311 17.9234L20.0265 18.0795C19.8232 18.1027 19.6357 18.2007 19.5006 18.3545C19.3757 18.4952 19.2426 18.6283 19.1018 18.7532C18.9481 18.8883 18.8501 19.0758 18.8268 19.2792L18.6715 20.683C18.4379 20.7984 18.197 20.8983 17.9503 20.9821L16.8468 20.0987C16.7004 19.9818 16.5186 19.9183 16.3312 19.9185C16.3147 19.9185 16.2982 19.9185 16.2817 19.9185C16.094 19.9295 15.9057 19.9295 15.718 19.9185C15.514 19.9064 15.3128 19.9701 15.1528 20.0973L14.0494 20.9807C13.8028 20.8974 13.5618 20.7979 13.3282 20.683L13.1722 19.2785C13.1489 19.0751 13.0509 18.8877 12.8972 18.7525C12.7565 18.6276 12.6233 18.4945 12.4984 18.3538C12.3633 18.2 12.1758 18.102 11.9725 18.0788L10.5686 17.9234C10.4532 17.6898 10.3533 17.4489 10.2695 17.2022L11.1523 16.0988C11.2801 15.9391 11.344 15.7378 11.3317 15.5337C11.3207 15.3459 11.3207 15.1577 11.3317 14.9699C11.344 14.7658 11.2801 14.5644 11.1523 14.4048L10.2709 13.3013C10.3542 13.0547 10.4537 12.8138 10.5686 12.5802L11.9732 12.4241C12.1765 12.4008 12.364 12.3028 12.4991 12.1491C12.624 12.0084 12.7571 11.8752 12.8978 11.7503C13.0516 11.6152 13.1496 11.4278 13.1728 11.2244L13.3282 9.82053C13.5618 9.70515 13.8027 9.60524 14.0494 9.52147L15.1528 10.4049C15.3128 10.5321 15.514 10.5957 15.718 10.5837C15.9057 10.5727 16.094 10.5727 16.2817 10.5837C16.4857 10.5961 16.6871 10.5324 16.8468 10.4049L17.9503 9.52147C18.197 9.60524 18.4379 9.70515 18.6715 9.82053L18.8275 11.2251C18.8508 11.4284 18.9488 11.6159 19.1025 11.751C19.2432 11.8759 19.3764 12.0091 19.5013 12.1498C19.6364 12.3035 19.8239 12.4015 20.0272 12.4248L21.4311 12.5802C21.5465 12.8137 21.6464 13.0547 21.7302 13.3013L20.8474 14.4048C20.7191 14.5642 20.6547 14.7656 20.6666 14.9699Z" fill="#898989"/>
+</svg>
diff --git a/examples/demos/thermostat/content/images/Cool.svg b/examples/demos/thermostat/content/images/Cool.svg
new file mode 100644
index 000000000..120ff8f6a
--- /dev/null
+++ b/examples/demos/thermostat/content/images/Cool.svg
@@ -0,0 +1,3 @@
+<svg width="22" height="21" viewBox="0 0 22 21" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M18.8288 11.9127C18.8883 12.1555 18.849 12.4119 18.7195 12.6257C18.59 12.8395 18.3809 12.9931 18.1382 13.0528L16.5141 13.4519L16.9384 15.0359C17.0032 15.2774 16.9694 15.5348 16.8445 15.7514C16.7195 15.968 16.5136 16.1261 16.2721 16.1909C16.0306 16.2557 15.7732 16.2219 15.5566 16.097C15.34 15.972 15.1819 15.7662 15.1171 15.5246L14.5443 13.3875L11.942 11.8844V14.8874L13.5512 16.4966C13.6389 16.5843 13.7085 16.6884 13.7559 16.803C13.8034 16.9176 13.8278 17.0404 13.8278 17.1644C13.8278 17.2885 13.8034 17.4113 13.7559 17.5259C13.7085 17.6405 13.6389 17.7446 13.5512 17.8323C13.4635 17.92 13.3594 17.9896 13.2448 18.037C13.1302 18.0845 13.0074 18.1089 12.8833 18.1089C12.7593 18.1089 12.6365 18.0845 12.5219 18.037C12.4073 17.9896 12.3032 17.92 12.2155 17.8323L10.9992 16.616L9.78054 17.8354C9.69284 17.9231 9.58872 17.9927 9.47412 18.0402C9.35953 18.0876 9.23672 18.1121 9.11268 18.1121C8.98865 18.1121 8.86583 18.0876 8.75124 18.0402C8.63665 17.9927 8.53253 17.9231 8.44483 17.8354C8.35712 17.7477 8.28755 17.6436 8.24009 17.529C8.19262 17.4144 8.16819 17.2916 8.16819 17.1676C8.16819 17.0435 8.19262 16.9207 8.24009 16.8061C8.28755 16.6915 8.35712 16.5874 8.44483 16.4997L10.0563 14.8874V11.8844L7.45404 13.3875L6.88125 15.5246C6.81645 15.7662 6.65835 15.972 6.44175 16.097C6.22514 16.2219 5.96777 16.2557 5.72625 16.1909C5.48474 16.1261 5.27886 15.968 5.1539 15.7514C5.02895 15.5348 4.99516 15.2774 5.05997 15.0359L5.48425 13.4519L3.86018 13.0528C3.73718 13.026 3.6208 12.9748 3.5179 12.9023C3.415 12.8298 3.32766 12.7374 3.26103 12.6306C3.19441 12.5237 3.14985 12.4047 3.12998 12.2804C3.11011 12.1561 3.11534 12.029 3.14535 11.9068C3.17537 11.7845 3.22956 11.6695 3.30473 11.5685C3.37991 11.4676 3.47454 11.3827 3.58305 11.3188C3.69157 11.255 3.81176 11.2136 3.93654 11.197C4.06133 11.1803 4.18818 11.1889 4.30961 11.2221L6.50097 11.7603L9.11347 10.2517L6.50097 8.74314L4.30961 9.28135C4.23611 9.29966 4.16064 9.3089 4.0849 9.30885C3.85474 9.30833 3.63271 9.22365 3.46067 9.07075C3.28864 8.91785 3.17847 8.70731 3.15093 8.4788C3.12339 8.25029 3.18039 8.0196 3.31118 7.83021C3.44197 7.64082 3.63752 7.50582 3.86097 7.45064L5.48504 7.05149L5.06075 5.46749C4.99595 5.22598 5.02974 4.96861 5.15469 4.752C5.27964 4.5354 5.48552 4.3773 5.72704 4.31249C5.96856 4.24769 6.22593 4.28147 6.44253 4.40643C6.65914 4.53138 6.81723 4.73726 6.88204 4.97878L7.45483 7.11592L10.0563 8.61821V5.61599L8.44718 4.00371C8.35948 3.916 8.28991 3.81188 8.24244 3.69729C8.19498 3.5827 8.17055 3.45988 8.17055 3.33585C8.17055 3.08536 8.27006 2.84512 8.44718 2.66799C8.62431 2.49087 8.86454 2.39136 9.11504 2.39136C9.23907 2.39136 9.36189 2.41579 9.47648 2.46325C9.59107 2.51072 9.69519 2.58029 9.7829 2.66799L10.9992 3.88742L12.2178 2.66799C12.3055 2.58029 12.4097 2.51072 12.5242 2.46325C12.6388 2.41579 12.7617 2.39136 12.8857 2.39136C13.0097 2.39136 13.1325 2.41579 13.2471 2.46325C13.3617 2.51072 13.4658 2.58029 13.5535 2.66799C13.6412 2.7557 13.7108 2.85982 13.7583 2.97441C13.8057 3.089 13.8302 3.21182 13.8302 3.33585C13.8302 3.45988 13.8057 3.5827 13.7583 3.69729C13.7108 3.81188 13.6412 3.916 13.5535 4.00371L11.942 5.61599V8.62056L14.5443 7.11828L15.1171 4.98114C15.1819 4.73962 15.34 4.53374 15.5566 4.40879C15.7732 4.28383 16.0306 4.25004 16.2721 4.31485C16.5136 4.37966 16.7195 4.53775 16.8445 4.75436C16.9694 4.97096 17.0032 5.22833 16.9384 5.46985L16.5141 7.05385L18.1382 7.45299C18.3596 7.51002 18.5527 7.64556 18.6817 7.83437C18.8106 8.02318 18.8665 8.25241 18.839 8.47939C18.8116 8.70636 18.7025 8.91562 18.5323 9.06821C18.362 9.2208 18.1421 9.30632 17.9135 9.30885C17.8375 9.30896 17.7617 9.29973 17.688 9.28135L15.4966 8.74314L12.8849 10.2517L15.4974 11.7603L17.6888 11.2221C17.9315 11.1626 18.188 11.2019 18.4018 11.3314C18.6155 11.4609 18.7692 11.67 18.8288 11.9127Z" fill="#323232"/>
+</svg>
diff --git a/examples/demos/thermostat/content/images/Dry.svg b/examples/demos/thermostat/content/images/Dry.svg
new file mode 100644
index 000000000..e0c3f2e77
--- /dev/null
+++ b/examples/demos/thermostat/content/images/Dry.svg
@@ -0,0 +1,3 @@
+<svg width="22" height="21" viewBox="0 0 22 21" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M11.5397 0.679387C11.3812 0.568505 11.1925 0.509033 10.9991 0.509033C10.8057 0.509033 10.617 0.568505 10.4585 0.679387C9.24358 1.57476 8.13203 2.60251 7.14437 3.74367C4.93729 6.27839 3.77051 8.96475 3.77051 11.5089C3.77051 13.426 4.53209 15.2646 5.88771 16.6203C7.24333 17.9759 9.08194 18.7375 10.9991 18.7375C12.9162 18.7375 14.7548 17.9759 16.1105 16.6203C17.4661 15.2646 18.2277 13.426 18.2277 11.5089C18.2277 5.4306 11.8131 0.870315 11.5397 0.679387ZM10.9991 16.8517C9.58251 16.8503 8.22438 16.2869 7.22272 15.2853C6.22105 14.2836 5.65768 12.9255 5.65622 11.5089C5.65622 8.89167 7.22765 6.52982 8.53979 5.01024C9.28895 4.14971 10.1118 3.35627 10.9991 2.63896C11.8863 3.35627 12.7092 4.14971 13.4584 5.01024C14.7705 6.52982 16.3419 8.89167 16.3419 11.5089C16.3405 12.9255 15.7771 14.2836 14.7754 15.2853C13.7738 16.2869 12.4156 16.8503 10.9991 16.8517ZM14.8978 12.7346C14.7004 13.362 14.3545 13.9325 13.8894 14.3976C13.4243 14.8627 12.8538 15.2087 12.2264 15.406C12.1348 15.4345 12.0394 15.4491 11.9435 15.4492C11.7181 15.4494 11.5001 15.3688 11.329 15.2221C11.158 15.0754 11.0451 14.8722 11.0109 14.6495C10.9767 14.4267 11.0234 14.199 11.1426 14.0077C11.2618 13.8165 11.4456 13.6742 11.6607 13.6067C11.9988 13.5005 12.3062 13.3142 12.5569 13.0635C12.8075 12.8129 12.9938 12.5055 13.1001 12.1673C13.1372 12.0492 13.1973 11.9395 13.2768 11.8446C13.3563 11.7496 13.4538 11.6713 13.5636 11.614C13.7854 11.4984 14.044 11.4755 14.2826 11.5505C14.4007 11.5877 14.5104 11.6477 14.6053 11.7273C14.7003 11.8068 14.7786 11.9042 14.8359 12.014C14.8932 12.1238 14.9282 12.2439 14.9391 12.3672C14.95 12.4906 14.9365 12.6149 14.8994 12.733L14.8978 12.7346Z" fill="#323232"/>
+</svg>
diff --git a/examples/demos/thermostat/content/images/Eco.svg b/examples/demos/thermostat/content/images/Eco.svg
new file mode 100644
index 000000000..7b19b526c
--- /dev/null
+++ b/examples/demos/thermostat/content/images/Eco.svg
@@ -0,0 +1,3 @@
+<svg width="22" height="21" viewBox="0 0 22 21" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M20.7127 3.30982C20.6991 3.07942 20.6014 2.86203 20.4382 2.69883C20.275 2.53563 20.0576 2.43796 19.8272 2.42432C15.641 2.1776 12.2687 3.47482 10.8041 5.89246C9.85024 7.46389 9.81724 9.36296 10.6894 11.1803C10.3164 11.6559 10.0185 12.1859 9.80624 12.7517L9.0441 11.9896C9.60903 10.672 9.54931 9.30953 8.85553 8.16396C7.7571 6.35132 5.25538 5.38018 2.16438 5.55932C1.93399 5.57296 1.71659 5.67063 1.55339 5.83383C1.39019 5.99703 1.29252 6.21442 1.27888 6.44482C1.09974 9.53582 2.07088 12.0375 3.8851 13.136C4.5004 13.511 5.20738 13.7087 5.92796 13.7072C6.5423 13.7021 7.14918 13.5719 7.71153 13.3245L9.42831 15.0445V17.1659C9.42831 17.416 9.52765 17.6558 9.70447 17.8326C9.88129 18.0094 10.1211 18.1087 10.3712 18.1087C10.6212 18.1087 10.8611 18.0094 11.0379 17.8326C11.2147 17.6558 11.314 17.416 11.314 17.1659V14.8488C11.3121 14.006 11.5727 13.1835 12.0597 12.4956C12.848 12.8705 13.7082 13.07 14.581 13.0802C15.5204 13.0824 16.4421 12.8252 17.2446 12.3369C19.6622 10.8684 20.9595 7.49532 20.7127 3.30982ZM4.86174 11.5229C3.82538 10.8943 3.1976 9.36532 3.14653 7.42696C5.08488 7.47803 6.61467 8.10661 7.24246 9.14218C7.48796 9.5415 7.58866 10.0131 7.52767 10.4779L6.63746 9.58453C6.46033 9.40741 6.22009 9.3079 5.9696 9.3079C5.7191 9.3079 5.47887 9.40741 5.30174 9.58453C5.12461 9.76166 5.02511 10.0019 5.02511 10.2524C5.02511 10.5029 5.12461 10.7431 5.30174 10.9202L6.19274 11.8112C5.72923 11.8685 5.26001 11.7668 4.86174 11.5229ZM16.268 10.723C15.4304 11.2298 14.4608 11.3257 13.4543 11.0185L16.3811 8.09246C16.5582 7.91534 16.6577 7.6751 16.6577 7.4246C16.6577 7.17411 16.5582 6.93387 16.3811 6.75675C16.204 6.57962 15.9637 6.48011 15.7132 6.48011C15.4627 6.48011 15.2225 6.57962 15.0454 6.75675L12.1186 9.68275C11.8145 8.68018 11.9104 7.70668 12.414 6.87303C13.4174 5.21596 15.7926 4.27468 18.8569 4.28018C18.8679 7.34446 17.925 9.71575 16.268 10.723Z" fill="#323232"/>
+</svg>
diff --git a/examples/demos/thermostat/content/images/Fan.svg b/examples/demos/thermostat/content/images/Fan.svg
new file mode 100644
index 000000000..13a59155a
--- /dev/null
+++ b/examples/demos/thermostat/content/images/Fan.svg
@@ -0,0 +1,3 @@
+<svg width="22" height="21" viewBox="0 0 22 21" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M19.5516 10.7232C19.3645 10.0239 19.0286 9.37319 18.5668 8.81564C18.105 8.25809 17.5283 7.80682 16.8761 7.49268C16.2238 7.17853 15.5115 7.00892 14.7876 6.99544C14.0638 6.98196 13.3456 7.12493 12.6821 7.41457L13.7994 2.95407C13.847 2.76271 13.8334 2.56125 13.7606 2.37803C13.6877 2.1948 13.5592 2.03904 13.3932 1.93264C12.2943 1.23612 10.9681 0.992653 9.69344 1.2534C8.41876 1.51415 7.29475 2.25881 6.5576 3.33092C5.82045 4.40304 5.52753 5.71913 5.74041 7.00268C5.95328 8.28623 6.65536 9.43731 7.69914 10.2141L3.27714 11.4767C3.0871 11.531 2.91894 11.6437 2.79642 11.7988C2.6739 11.9539 2.60321 12.1435 2.59435 12.341C2.52802 13.649 2.9746 14.9312 3.8391 15.915C4.7036 16.8988 5.91781 17.5065 7.22346 17.6089C8.52912 17.7112 9.82319 17.3002 10.8304 16.4631C11.8377 15.626 12.4786 14.429 12.6169 13.1267L15.9169 16.3246C16.0591 16.4615 16.2407 16.5503 16.4361 16.5785C16.6315 16.6067 16.8308 16.5728 17.0059 16.4817C18.0224 15.955 18.8287 15.0972 19.2915 14.0502C19.7544 13.0031 19.8462 11.8295 19.5516 10.7232ZM10.0563 10.2518C10.0563 10.0653 10.1116 9.88301 10.2152 9.72796C10.3188 9.57291 10.466 9.45206 10.6383 9.38069C10.8106 9.30933 11.0002 9.29066 11.1831 9.32704C11.366 9.36342 11.534 9.45322 11.6658 9.58508C11.7977 9.71694 11.8875 9.88494 11.9239 10.0678C11.9603 10.2507 11.9416 10.4403 11.8702 10.6126C11.7989 10.7849 11.678 10.9321 11.523 11.0357C11.3679 11.1393 11.1856 11.1946 10.9991 11.1946C10.7491 11.1946 10.5093 11.0953 10.3324 10.9185C10.1556 10.7417 10.0563 10.5018 10.0563 10.2518ZM10.6849 3.02321C11.0605 3.02321 11.433 3.09053 11.7849 3.22199L10.732 7.43657C10.3296 7.47498 9.94004 7.59922 9.58968 7.8009C9.23932 8.00257 8.93626 8.27701 8.70092 8.60571C8.19675 8.19625 7.83182 7.64065 7.65631 7.01531C7.48081 6.38998 7.50336 5.72563 7.72085 5.11363C7.93834 4.50163 8.3401 3.97205 8.87087 3.59771C9.40164 3.22337 10.0354 3.02267 10.6849 3.02321ZM9.19199 15.2882C8.75198 15.5428 8.25676 15.6869 7.74882 15.7081C7.24088 15.7293 6.73538 15.627 6.27568 15.4099C5.81598 15.1928 5.41581 14.8674 5.1095 14.4617C4.80318 14.0559 4.59987 13.5819 4.51699 13.0804L8.69542 11.8869C8.92939 12.2168 9.23142 12.4928 9.58111 12.6961C9.93081 12.8994 10.3201 13.0253 10.7226 13.0654C10.6494 13.5266 10.474 13.9656 10.2091 14.3502C9.94429 14.7348 9.59676 15.0553 9.19199 15.2882ZM17.4184 13.5942C17.2305 13.9206 16.9854 14.2104 16.6948 14.4499L13.5708 11.4304C13.7394 11.0628 13.827 10.6633 13.8277 10.2589C13.8284 9.8545 13.7421 9.45469 13.5747 9.08657C14.1814 8.85494 14.845 8.81695 15.4741 8.9778C16.1033 9.13865 16.6672 9.49045 17.0883 9.98484C17.5094 10.4792 17.767 11.0919 17.8257 11.7387C17.8844 12.3854 17.7413 13.0345 17.4161 13.5966L17.4184 13.5942Z" fill="#323232"/>
+</svg>
diff --git a/examples/demos/thermostat/content/images/Heat.svg b/examples/demos/thermostat/content/images/Heat.svg
new file mode 100644
index 000000000..7f7887961
--- /dev/null
+++ b/examples/demos/thermostat/content/images/Heat.svg
@@ -0,0 +1,3 @@
+<svg width="22" height="21" viewBox="0 0 22 21" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M10.0565 3.02326V2.70897C10.0565 2.45891 10.1559 2.21909 10.3327 2.04227C10.5095 1.86545 10.7493 1.76611 10.9994 1.76611C11.2494 1.76611 11.4893 1.86545 11.6661 2.04227C11.8429 2.21909 11.9422 2.45891 11.9422 2.70897V3.02326C11.9422 3.27332 11.8429 3.51314 11.6661 3.68996C11.4893 3.86678 11.2494 3.96611 10.9994 3.96611C10.7493 3.96611 10.5095 3.86678 10.3327 3.68996C10.1559 3.51314 10.0565 3.27332 10.0565 3.02326ZM16.3422 10.2518C16.3422 11.3085 16.0289 12.3415 15.4418 13.2202C14.8547 14.0988 14.0203 14.7836 13.044 15.188C12.0677 15.5924 10.9935 15.6982 9.95705 15.492C8.92063 15.2859 7.96863 14.777 7.22142 14.0298C6.4742 13.2826 5.96535 12.3306 5.75919 11.2942C5.55304 10.2578 5.65884 9.18349 6.06323 8.20721C6.46762 7.23093 7.15243 6.39649 8.03105 5.80941C8.90968 5.22232 9.94267 4.90897 10.9994 4.90897C12.416 4.91043 13.7741 5.4738 14.7758 6.47547C15.7774 7.47713 16.3408 8.83526 16.3422 10.2518ZM14.4565 10.2518C14.4565 9.56807 14.2538 8.89967 13.8739 8.33114C13.494 7.76262 12.9541 7.31951 12.3224 7.05785C11.6907 6.79618 10.9956 6.72772 10.3249 6.86111C9.65431 6.99451 9.03831 7.32377 8.55482 7.80726C8.07133 8.29075 7.74207 8.90675 7.60867 9.57737C7.47528 10.248 7.54374 10.9431 7.8054 11.5748C8.06707 12.2065 8.51018 12.7465 9.0787 13.1263C9.64723 13.5062 10.3156 13.709 10.9994 13.709C11.916 13.7079 12.7947 13.3434 13.4428 12.6953C14.0909 12.0471 14.4555 11.1684 14.4565 10.2518ZM4.98946 5.57604C5.07716 5.66375 5.18128 5.73332 5.29587 5.78078C5.41046 5.82825 5.53328 5.85268 5.65732 5.85268C5.78135 5.85268 5.90417 5.82825 6.01876 5.78078C6.13335 5.73332 6.23747 5.66375 6.32517 5.57604C6.41288 5.48834 6.48245 5.38422 6.52991 5.26963C6.57738 5.15504 6.60181 5.03222 6.60181 4.90819C6.60181 4.78415 6.57738 4.66133 6.52991 4.54674C6.48245 4.43215 6.41288 4.32803 6.32517 4.24033L6.01089 3.92604C5.83376 3.74892 5.59352 3.64941 5.34303 3.64941C5.09253 3.64941 4.8523 3.74892 4.67517 3.92604C4.49805 4.10317 4.39854 4.3434 4.39854 4.5939C4.39854 4.84439 4.49805 5.08463 4.67517 5.26176L4.98946 5.57604ZM4.98946 14.926L4.67517 15.2403C4.58747 15.328 4.5179 15.4322 4.47043 15.5467C4.42297 15.6613 4.39854 15.7842 4.39854 15.9082C4.39854 16.0322 4.42297 16.155 4.47043 16.2696C4.5179 16.3842 4.58747 16.4883 4.67517 16.576C4.8523 16.7532 5.09253 16.8527 5.34303 16.8527C5.46706 16.8527 5.58988 16.8282 5.70447 16.7808C5.81906 16.7333 5.92318 16.6637 6.01089 16.576L6.32517 16.2618C6.5023 16.0846 6.60181 15.8444 6.60181 15.5939C6.60181 15.3434 6.5023 15.1032 6.32517 14.926C6.14805 14.7489 5.90781 14.6494 5.65732 14.6494C5.40682 14.6494 5.16658 14.7489 4.98946 14.926ZM16.3422 5.85183C16.4661 5.85193 16.5888 5.82762 16.7032 5.7803C16.8177 5.73298 16.9217 5.66357 17.0093 5.57604L17.3236 5.26176C17.5007 5.08463 17.6002 4.84439 17.6002 4.5939C17.6002 4.3434 17.5007 4.10317 17.3236 3.92604C17.1465 3.74892 16.9062 3.64941 16.6557 3.64941C16.4053 3.64941 16.165 3.74892 15.9879 3.92604L15.6736 4.24033C15.541 4.3722 15.4505 4.54055 15.4138 4.72396C15.3771 4.90737 15.3958 5.09755 15.4675 5.27032C15.5392 5.44309 15.6606 5.59063 15.8164 5.69417C15.9722 5.79772 16.1552 5.8526 16.3422 5.85183ZM17.0093 14.9276C16.8322 14.7505 16.592 14.651 16.3415 14.651C16.091 14.651 15.8507 14.7505 15.6736 14.9276C15.4965 15.1047 15.397 15.345 15.397 15.5955C15.397 15.846 15.4965 16.0862 15.6736 16.2633L15.9879 16.5776C16.165 16.7547 16.4053 16.8543 16.6557 16.8543C16.9062 16.8543 17.1465 16.7547 17.3236 16.5776C17.5007 16.4005 17.6002 16.1603 17.6002 15.9098C17.6002 15.6593 17.5007 15.419 17.3236 15.2419L17.0093 14.9276ZM4.71367 10.2518C4.71367 10.0018 4.61434 9.76195 4.43752 9.58513C4.2607 9.40831 4.02088 9.30897 3.77082 9.30897H3.45653C3.20647 9.30897 2.96665 9.40831 2.78983 9.58513C2.61301 9.76195 2.51367 10.0018 2.51367 10.2518C2.51367 10.5019 2.61301 10.7417 2.78983 10.9185C2.96665 11.0954 3.20647 11.1947 3.45653 11.1947H3.77082C4.02088 11.1947 4.2607 11.0954 4.43752 10.9185C4.61434 10.7417 4.71367 10.5019 4.71367 10.2518ZM10.9994 16.5375C10.7493 16.5375 10.5095 16.6369 10.3327 16.8137C10.1559 16.9905 10.0565 17.2303 10.0565 17.4804V17.7947C10.0565 18.0448 10.1559 18.2846 10.3327 18.4614C10.5095 18.6382 10.7493 18.7375 10.9994 18.7375C11.2494 18.7375 11.4893 18.6382 11.6661 18.4614C11.8429 18.2846 11.9422 18.0448 11.9422 17.7947V17.4804C11.9422 17.2303 11.8429 16.9905 11.6661 16.8137C11.4893 16.6369 11.2494 16.5375 10.9994 16.5375ZM18.5422 9.30897H18.228C17.9779 9.30897 17.7381 9.40831 17.5613 9.58513C17.3844 9.76195 17.2851 10.0018 17.2851 10.2518C17.2851 10.5019 17.3844 10.7417 17.5613 10.9185C17.7381 11.0954 17.9779 11.1947 18.228 11.1947H18.5422C18.7923 11.1947 19.0321 11.0954 19.2089 10.9185C19.3858 10.7417 19.4851 10.5019 19.4851 10.2518C19.4851 10.0018 19.3858 9.76195 19.2089 9.58513C19.0321 9.40831 18.7923 9.30897 18.5422 9.30897Z" fill="#323232"/>
+</svg>
diff --git a/examples/demos/thermostat/content/images/arrow.svg b/examples/demos/thermostat/content/images/arrow.svg
new file mode 100644
index 000000000..b8d49dc28
--- /dev/null
+++ b/examples/demos/thermostat/content/images/arrow.svg
@@ -0,0 +1,3 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M14.1922 10.4422L7.94217 16.6922C7.8841 16.7502 7.81516 16.7963 7.73929 16.8277C7.66342 16.8592 7.5821 16.8753 7.49998 16.8753C7.41786 16.8753 7.33654 16.8592 7.26067 16.8277C7.1848 16.7963 7.11586 16.7502 7.05779 16.6922C6.99972 16.6341 6.95366 16.5652 6.92224 16.4893C6.89081 16.4134 6.87463 16.3321 6.87463 16.25C6.87463 16.1679 6.89081 16.0865 6.92224 16.0107C6.95366 15.9348 6.99972 15.8659 7.05779 15.8078L12.8664 9.99998L7.05779 4.19217C6.94052 4.07489 6.87463 3.91583 6.87463 3.74998C6.87463 3.58413 6.94052 3.42507 7.05779 3.30779C7.17507 3.19052 7.33413 3.12463 7.49998 3.12463C7.66583 3.12463 7.82489 3.19052 7.94217 3.30779L14.1922 9.55779C14.2503 9.61584 14.2964 9.68477 14.3278 9.76064C14.3593 9.83652 14.3755 9.91785 14.3755 9.99998C14.3755 10.0821 14.3593 10.1634 14.3278 10.2393C14.2964 10.3152 14.2503 10.3841 14.1922 10.4422Z" fill="#898989"/>
+</svg>
diff --git a/examples/demos/thermostat/content/images/bedroom.svg b/examples/demos/thermostat/content/images/bedroom.svg
new file mode 100644
index 000000000..e1b82bd62
--- /dev/null
+++ b/examples/demos/thermostat/content/images/bedroom.svg
@@ -0,0 +1,10 @@
+<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_836_38508)">
+<path d="M9.33398 18.6666C11.5473 18.6666 13.334 16.88 13.334 14.6666C13.334 12.4533 11.5473 10.6666 9.33398 10.6666C7.12065 10.6666 5.33398 12.4533 5.33398 14.6666C5.33398 16.88 7.12065 18.6666 9.33398 18.6666ZM9.33398 13.3333C10.0673 13.3333 10.6673 13.9333 10.6673 14.6666C10.6673 15.4 10.0673 16 9.33398 16C8.60065 16 8.00065 15.4 8.00065 14.6666C8.00065 13.9333 8.60065 13.3333 9.33398 13.3333ZM25.334 9.33329H14.6673V20H4.00065V6.66663H1.33398V26.6666H4.00065V22.6666H28.0006V26.6666H30.6673V14.6666C30.6673 11.72 28.2806 9.33329 25.334 9.33329ZM28.0006 20H17.334V12H25.334C26.8006 12 28.0006 13.2 28.0006 14.6666V20Z" fill="white"/>
+</g>
+<defs>
+<clipPath id="clip0_836_38508">
+<rect width="32" height="32" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/examples/demos/thermostat/content/images/circle.svg b/examples/demos/thermostat/content/images/circle.svg
new file mode 100644
index 000000000..68a8ecaeb
--- /dev/null
+++ b/examples/demos/thermostat/content/images/circle.svg
@@ -0,0 +1,17 @@
+<svg width="52" height="53" viewBox="0 0 52 53" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g filter="url(#filter0_d_608_9323)">
+<circle cx="26" cy="25.2517" r="21.5" stroke="#2CDE85" shape-rendering="crispEdges"/>
+</g>
+<defs>
+<filter id="filter0_d_608_9323" x="0" y="0.251709" width="52" height="52" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="2"/>
+<feComposite in2="hardAlpha" operator="out"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_608_9323"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_608_9323" result="shape"/>
+</filter>
+</defs>
+</svg>
diff --git a/examples/demos/thermostat/content/images/down.svg b/examples/demos/thermostat/content/images/down.svg
new file mode 100644
index 000000000..0c8c4268b
--- /dev/null
+++ b/examples/demos/thermostat/content/images/down.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M22.8759 12.7501V18.7501C22.8759 19.0484 22.7574 19.3346 22.5464 19.5456C22.3355 19.7565 22.0493 19.8751 21.7509 19.8751H15.7509C15.4526 19.8751 15.1664 19.7565 14.9554 19.5456C14.7445 19.3346 14.6259 19.0484 14.6259 18.7501C14.6259 18.4517 14.7445 18.1656 14.9554 17.9546C15.1664 17.7436 15.4526 17.6251 15.7509 17.6251H19.0322L12.7509 11.3438L9.79687 14.2988C9.69236 14.4037 9.56816 14.4869 9.43142 14.5437C9.29467 14.6005 9.14806 14.6297 9 14.6297C8.85193 14.6297 8.70532 14.6005 8.56858 14.5437C8.43183 14.4869 8.30764 14.4037 8.20312 14.2988L1.45312 7.54883C1.24178 7.33748 1.12305 7.05084 1.12305 6.75195C1.12305 6.60396 1.1522 6.45741 1.20883 6.32069C1.26547 6.18396 1.34848 6.05972 1.45312 5.95508C1.55777 5.85043 1.682 5.76742 1.81873 5.71078C1.95546 5.65415 2.102 5.625 2.25 5.625C2.54888 5.625 2.83553 5.74373 3.04687 5.95508L9.00094 11.9063L11.955 8.95133C12.0595 8.84645 12.1837 8.76323 12.3205 8.70645C12.4572 8.64967 12.6038 8.62044 12.7519 8.62044C12.8999 8.62044 13.0465 8.64967 13.1833 8.70645C13.32 8.76323 13.4442 8.84645 13.5487 8.95133L20.6259 16.0313V12.7501C20.6259 12.4517 20.7445 12.1656 20.9554 11.9546C21.1664 11.7436 21.4526 11.6251 21.7509 11.6251C22.0493 11.6251 22.3355 11.7436 22.5464 11.9546C22.7574 12.1656 22.8759 12.4517 22.8759 12.7501Z" fill="#2CDE85"/>
+</svg>
diff --git a/examples/demos/thermostat/content/images/drop.svg b/examples/demos/thermostat/content/images/drop.svg
new file mode 100644
index 000000000..69d31461e
--- /dev/null
+++ b/examples/demos/thermostat/content/images/drop.svg
@@ -0,0 +1,3 @@
+<svg width="34" height="34" viewBox="0 0 34 34" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M17.9138 0.819694C17.6459 0.632267 17.3269 0.531738 17 0.531738C16.6731 0.531738 16.3541 0.632267 16.0863 0.819694C14.0326 2.33318 12.1537 4.07043 10.4842 5.99938C6.75352 10.2839 4.78125 14.8248 4.78125 19.1252C4.78125 22.3659 6.06858 25.4737 8.36004 27.7652C10.6515 30.0567 13.7594 31.344 17 31.344C20.2406 31.344 23.3485 30.0567 25.64 27.7652C27.9314 25.4737 29.2188 22.3659 29.2188 19.1252C29.2188 8.85087 18.3759 1.14243 17.9138 0.819694ZM17 28.1565C14.6055 28.154 12.3098 27.2017 10.6167 25.5086C8.92351 23.8154 7.97121 21.5197 7.96875 19.1252C7.96875 14.7013 10.625 10.7089 12.843 8.14032C14.1093 6.68573 15.5003 5.34454 17 4.13204C18.4997 5.34454 19.8907 6.68573 21.157 8.14032C23.375 10.7089 26.0312 14.7013 26.0312 19.1252C26.0288 21.5197 25.0765 23.8154 23.3833 25.5086C21.6902 27.2017 19.3945 28.154 17 28.1565ZM23.5902 21.1971C23.2565 22.2577 22.6718 23.222 21.8856 24.0082C21.0995 24.7944 20.1351 25.3791 19.0745 25.7127C18.9197 25.7609 18.7585 25.7855 18.5964 25.7858C18.2154 25.7861 17.847 25.6499 17.5578 25.4018C17.2686 25.1538 17.0778 24.8104 17.02 24.4339C16.9621 24.0573 17.0411 23.6725 17.2426 23.3492C17.4441 23.0258 17.7548 22.7854 18.1183 22.6713C18.6898 22.4918 19.2096 22.1768 19.6332 21.7531C20.0568 21.3295 20.3718 20.8098 20.5514 20.2382C20.6142 20.0385 20.7157 19.8531 20.8501 19.6927C20.9846 19.5322 21.1493 19.3998 21.3349 19.3029C21.7097 19.1074 22.1469 19.0688 22.5502 19.1956C22.7499 19.2584 22.9353 19.3599 23.0958 19.4944C23.2563 19.6288 23.3887 19.7935 23.4855 19.9791C23.5823 20.1647 23.6416 20.3676 23.66 20.5761C23.6784 20.7846 23.6556 20.9948 23.5928 21.1945L23.5902 21.1971Z" fill="white"/>
+</svg>
diff --git a/examples/demos/thermostat/content/images/edit.svg b/examples/demos/thermostat/content/images/edit.svg
new file mode 100644
index 000000000..7d0c1d5e4
--- /dev/null
+++ b/examples/demos/thermostat/content/images/edit.svg
@@ -0,0 +1,3 @@
+<svg width="20" height="21" viewBox="0 0 20 21" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M19.4369 4.86074L15.1407 0.563543C14.9621 0.384883 14.7501 0.243157 14.5167 0.146463C14.2833 0.0497686 14.0332 0 13.7806 0C13.528 0 13.2778 0.0497686 13.0444 0.146463C12.8111 0.243157 12.599 0.384883 12.4205 0.563543L0.563481 12.4215C0.384249 12.5995 0.242149 12.8114 0.145424 13.0448C0.048698 13.2782 -0.000729156 13.5285 8.12823e-06 13.7811V18.0783C8.12823e-06 18.5884 0.202621 19.0775 0.563276 19.4382C0.92393 19.7988 1.41308 20.0014 1.92312 20.0014H6.22033C6.47296 20.0021 6.72322 19.9527 6.95661 19.8559C7.19 19.7592 7.40188 19.6171 7.57997 19.438L19.4369 7.58003C19.7975 7.21939 20 6.73033 20 6.22039C20 5.71045 19.7975 5.22138 19.4369 4.86074ZM6.05782 17.6937H2.30775V13.9436L10.3848 5.86653L14.1349 9.61661L6.05782 17.6937ZM15.7696 7.98196L12.0195 4.23189L13.783 2.46839L17.5331 6.21846L15.7696 7.98196Z" fill="#323232"/>
+</svg>
diff --git a/examples/demos/thermostat/content/images/energy.svg b/examples/demos/thermostat/content/images/energy.svg
new file mode 100644
index 000000000..9888fb5ae
--- /dev/null
+++ b/examples/demos/thermostat/content/images/energy.svg
@@ -0,0 +1,3 @@
+<svg width="34" height="34" viewBox="0 0 34 34" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M8.62708 18.8133H13.0046V29.0133C13.0046 31.3933 14.2937 31.8749 15.8662 30.0899L26.5904 17.9066C27.9079 16.4191 27.3554 15.1866 25.3579 15.1866H20.9804V4.9866C20.9804 2.6066 19.6912 2.12494 18.1187 3.90994L7.39457 16.0933C6.09124 17.5949 6.64374 18.8133 8.62708 18.8133Z" stroke="white" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>
diff --git a/examples/demos/thermostat/content/images/home.svg b/examples/demos/thermostat/content/images/home.svg
new file mode 100644
index 000000000..49fb4d07f
--- /dev/null
+++ b/examples/demos/thermostat/content/images/home.svg
@@ -0,0 +1,3 @@
+<svg width="34" height="34" viewBox="0 0 34 34" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M29.0634 13.782L18.4384 3.75727C18.4332 3.75273 18.4283 3.74785 18.4238 3.74266C18.0326 3.3869 17.5228 3.18976 16.994 3.18976C16.4653 3.18976 15.9555 3.3869 15.5643 3.74266L15.5497 3.75727L4.93664 13.782C4.72015 13.981 4.54735 14.2229 4.42915 14.4922C4.31096 14.7615 4.24996 15.0524 4.25 15.3465V27.625C4.25 28.1886 4.47388 28.7291 4.8724 29.1276C5.27091 29.5261 5.81141 29.75 6.375 29.75H12.75C13.3136 29.75 13.8541 29.5261 14.2526 29.1276C14.6511 28.7291 14.875 28.1886 14.875 27.625V21.25H19.125V27.625C19.125 28.1886 19.3489 28.7291 19.7474 29.1276C20.1459 29.5261 20.6864 29.75 21.25 29.75H27.625C28.1886 29.75 28.7291 29.5261 29.1276 29.1276C29.5261 28.7291 29.75 28.1886 29.75 27.625V15.3465C29.75 15.0524 29.689 14.7615 29.5708 14.4922C29.4527 14.2229 29.2798 13.981 29.0634 13.782ZM27.625 27.625H21.25V21.25C21.25 20.6864 21.0261 20.1459 20.6276 19.7474C20.2291 19.3489 19.6886 19.125 19.125 19.125H14.875C14.3114 19.125 13.7709 19.3489 13.3724 19.7474C12.9739 20.1459 12.75 20.6864 12.75 21.25V27.625H6.375V15.3465L6.38961 15.3332L17 5.3125L27.6117 15.3305L27.6263 15.3438L27.625 27.625Z" fill="white"/>
+</svg>
diff --git a/examples/demos/thermostat/content/images/kid_room.svg b/examples/demos/thermostat/content/images/kid_room.svg
new file mode 100644
index 000000000..771c0071f
--- /dev/null
+++ b/examples/demos/thermostat/content/images/kid_room.svg
@@ -0,0 +1,12 @@
+<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_836_38511)">
+<path d="M19.3327 15.6667C20.2532 15.6667 20.9993 14.9205 20.9993 14C20.9993 13.0796 20.2532 12.3334 19.3327 12.3334C18.4122 12.3334 17.666 13.0796 17.666 14C17.666 14.9205 18.4122 15.6667 19.3327 15.6667Z" fill="white"/>
+<path d="M12.6667 15.6667C13.5871 15.6667 14.3333 14.9205 14.3333 14C14.3333 13.0796 13.5871 12.3334 12.6667 12.3334C11.7462 12.3334 11 13.0796 11 14C11 14.9205 11.7462 15.6667 12.6667 15.6667Z" fill="white"/>
+<path d="M30.5873 15.12C30.254 13.1067 28.774 11.4667 26.8406 10.8933C26.134 9.4 25.134 8.09333 23.9207 7.01333C21.814 5.13333 19.0406 4 16.0007 4C12.9607 4 10.1873 5.13333 8.08065 7.01333C6.85398 8.09333 5.85398 9.41333 5.16065 10.8933C3.22732 11.4667 1.74732 13.0933 1.41398 15.12C1.36065 15.4 1.33398 15.6933 1.33398 16C1.33398 16.3067 1.36065 16.6 1.41398 16.88C1.74732 18.8933 3.22732 20.5333 5.16065 21.1067C5.85398 22.5867 6.85398 23.8933 8.05398 24.96C10.1607 26.8533 12.9473 28 16.0007 28C19.054 28 21.8406 26.8533 23.9606 24.96C25.1606 23.8933 26.1606 22.5733 26.854 21.1067C28.774 20.5333 30.254 18.9067 30.5873 16.88C30.6407 16.6 30.6673 16.3067 30.6673 16C30.6673 15.6933 30.6407 15.4 30.5873 15.12V15.12ZM25.334 18.6667C25.2006 18.6667 25.0806 18.64 24.9473 18.6267C24.6806 19.52 24.294 20.3467 23.8007 21.1067C22.134 23.6533 19.2673 25.3333 16.0007 25.3333C12.734 25.3333 9.86732 23.6533 8.20065 21.1067C7.70732 20.3467 7.32065 19.52 7.05398 18.6267C6.92065 18.64 6.80065 18.6667 6.66732 18.6667C5.20065 18.6667 4.00065 17.4667 4.00065 16C4.00065 14.5333 5.20065 13.3333 6.66732 13.3333C6.80065 13.3333 6.92065 13.36 7.05398 13.3733C7.32065 12.48 7.70732 11.6533 8.20065 10.8933C9.86732 8.34667 12.734 6.66667 16.0007 6.66667C19.2673 6.66667 22.134 8.34667 23.8007 10.8933C24.294 11.6533 24.6806 12.48 24.9473 13.3733C25.0806 13.36 25.2006 13.3333 25.334 13.3333C26.8006 13.3333 28.0006 14.5333 28.0006 16C28.0006 17.4667 26.8006 18.6667 25.334 18.6667ZM16.0007 22.6667C18.6806 22.6667 20.9873 21.0267 22.0006 18.6667H10.0007C11.014 21.0267 13.3207 22.6667 16.0007 22.6667Z" fill="white"/>
+</g>
+<defs>
+<clipPath id="clip0_836_38511">
+<rect width="32" height="32" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/examples/demos/thermostat/content/images/kitchen.svg b/examples/demos/thermostat/content/images/kitchen.svg
new file mode 100644
index 000000000..0831a5d0e
--- /dev/null
+++ b/examples/demos/thermostat/content/images/kitchen.svg
@@ -0,0 +1,10 @@
+<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_836_38516)">
+<path d="M21.3333 7.99996V18.6666H25.3333V29.3333H28V2.66663C24.32 2.66663 21.3333 5.65329 21.3333 7.99996ZM14.6667 12H12V2.66663H9.33333V12H6.66667V2.66663H4V12C4 14.9466 6.38667 17.3333 9.33333 17.3333V29.3333H12V17.3333C14.9467 17.3333 17.3333 14.9466 17.3333 12V2.66663H14.6667V12Z" fill="white"/>
+</g>
+<defs>
+<clipPath id="clip0_836_38516">
+<rect width="32" height="32" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/examples/demos/thermostat/content/images/living_room.svg b/examples/demos/thermostat/content/images/living_room.svg
new file mode 100644
index 000000000..22afa3b95
--- /dev/null
+++ b/examples/demos/thermostat/content/images/living_room.svg
@@ -0,0 +1,10 @@
+<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_836_38502)">
+<path d="M25.3333 4H6.66667C5.2 4 4 5.2 4 6.66667V25.3333C4 26.8 5.2 28 6.66667 28H25.3333C26.8 28 28 26.8 28 25.3333V6.66667C28 5.2 26.8 4 25.3333 4ZM25.3333 25.3333H6.66667V6.66667H25.3333V25.3333ZM11.4267 8H8V11.44C9.89333 11.44 11.4267 9.89333 11.4267 8ZM16 8H13.72C13.72 11.1467 11.16 13.72 8 13.72V16C12.4267 16 16 12.4133 16 8ZM18.8533 15.8133L14.8533 20.9733L12 17.5333L8 22.6667H24L18.8533 15.8133Z" fill="white"/>
+</g>
+<defs>
+<clipPath id="clip0_836_38502">
+<rect width="32" height="32" fill="white"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/examples/demos/thermostat/content/images/logo.png b/examples/demos/thermostat/content/images/logo.png
new file mode 100644
index 000000000..feb2eb20b
--- /dev/null
+++ b/examples/demos/thermostat/content/images/logo.png
Binary files differ
diff --git a/examples/demos/thermostat/content/images/maxTemp.svg b/examples/demos/thermostat/content/images/maxTemp.svg
new file mode 100644
index 000000000..c4248b3f8
--- /dev/null
+++ b/examples/demos/thermostat/content/images/maxTemp.svg
@@ -0,0 +1,3 @@
+<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M14.5589 5.67208C13.8298 4.94129 12.9632 4.36206 12.0091 3.96781C11.055 3.57356 10.0323 3.37207 9 3.37497H8.97187C4.64555 3.38974 1.125 6.96091 1.125 11.3294V12.9375C1.125 13.2358 1.24353 13.522 1.4545 13.733C1.66548 13.9439 1.95163 14.0625 2.25 14.0625H15.75C16.0484 14.0625 16.3345 13.9439 16.5455 13.733C16.7565 13.522 16.875 13.2358 16.875 12.9375V11.25C16.8779 10.2131 16.6746 9.18605 16.277 8.22848C15.8794 7.2709 15.2954 6.40192 14.5589 5.67208ZM15.75 12.9375H8.41711L12.2674 7.64294C12.3553 7.52229 12.3916 7.37168 12.3684 7.22426C12.3451 7.07684 12.2643 6.94468 12.1437 6.85684C12.023 6.76901 11.8724 6.73271 11.725 6.75591C11.5776 6.77912 11.4454 6.85994 11.3576 6.98059L7.02562 12.9375H2.25V11.3294C2.25 11.1129 2.26055 10.8991 2.28023 10.6875H3.9375C4.08668 10.6875 4.22976 10.6282 4.33525 10.5227C4.44074 10.4172 4.5 10.2742 4.5 10.125C4.5 9.97579 4.44074 9.83271 4.33525 9.72722C4.22976 9.62173 4.08668 9.56247 3.9375 9.56247H2.47992C3.20555 6.83013 5.57367 4.76434 8.4375 4.52388V6.18747C8.4375 6.33665 8.49676 6.47973 8.60225 6.58522C8.70774 6.69071 8.85082 6.74997 9 6.74997C9.14918 6.74997 9.29226 6.69071 9.39775 6.58522C9.50324 6.47973 9.5625 6.33665 9.5625 6.18747V4.52317C10.958 4.64061 12.2825 5.18854 13.3531 6.09125C14.4237 6.99397 15.1876 8.20691 15.5391 9.56247H14.0625C13.9133 9.56247 13.7702 9.62173 13.6648 9.72722C13.5593 9.83271 13.5 9.97579 13.5 10.125C13.5 10.2742 13.5593 10.4172 13.6648 10.5227C13.7702 10.6282 13.9133 10.6875 14.0625 10.6875H15.7268C15.7416 10.8738 15.75 11.0608 15.75 11.25V12.9375Z" fill="#FA0000"/>
+</svg>
diff --git a/examples/demos/thermostat/content/images/minTemp.svg b/examples/demos/thermostat/content/images/minTemp.svg
new file mode 100644
index 000000000..2a8ab0145
--- /dev/null
+++ b/examples/demos/thermostat/content/images/minTemp.svg
@@ -0,0 +1,3 @@
+<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M3.44109 5.67208C4.17023 4.94129 5.03683 4.36206 5.99091 3.96781C6.94499 3.57356 7.96768 3.37207 9 3.37497H9.02813C13.3545 3.38974 16.875 6.96091 16.875 11.3294V12.9375C16.875 13.2358 16.7565 13.522 16.5455 13.733C16.3345 13.9439 16.0484 14.0625 15.75 14.0625H2.25C1.95163 14.0625 1.66548 13.9439 1.45451 13.733C1.24353 13.522 1.125 13.2358 1.125 12.9375V11.25C1.12211 10.2131 1.32538 9.18605 1.723 8.22848C2.12061 7.2709 2.70463 6.40192 3.44109 5.67208ZM2.25 12.9375H9.58289L5.73258 7.64294C5.64475 7.52229 5.60844 7.37168 5.63165 7.22426C5.65486 7.07684 5.73567 6.94468 5.85633 6.85684C5.97698 6.76901 6.12758 6.73271 6.275 6.75591C6.42243 6.77912 6.55459 6.85994 6.64242 6.98059L10.9744 12.9375H15.75V11.3294C15.75 11.1129 15.7395 10.8991 15.7198 10.6875H14.0625C13.9133 10.6875 13.7702 10.6282 13.6648 10.5227C13.5593 10.4172 13.5 10.2742 13.5 10.125C13.5 9.97579 13.5593 9.83271 13.6648 9.72722C13.7702 9.62173 13.9133 9.56247 14.0625 9.56247H15.5201C14.7945 6.83013 12.4263 4.76434 9.5625 4.52388V6.18747C9.5625 6.33665 9.50324 6.47973 9.39775 6.58522C9.29226 6.69071 9.14918 6.74997 9 6.74997C8.85082 6.74997 8.70774 6.69071 8.60225 6.58522C8.49676 6.47973 8.4375 6.33665 8.4375 6.18747V4.52317C7.04204 4.64061 5.71749 5.18854 4.64688 6.09125C3.57627 6.99397 2.81244 8.20691 2.46094 9.56247H3.9375C4.08668 9.56247 4.22976 9.62173 4.33525 9.72722C4.44074 9.83271 4.5 9.97579 4.5 10.125C4.5 10.2742 4.44074 10.4172 4.33525 10.5227C4.22976 10.6282 4.08668 10.6875 3.9375 10.6875H2.2732C2.25844 10.8738 2.25 11.0608 2.25 11.25V12.9375Z" fill="#0064FA"/>
+</svg>
diff --git a/examples/demos/thermostat/content/images/more.svg b/examples/demos/thermostat/content/images/more.svg
new file mode 100644
index 000000000..9a50c3974
--- /dev/null
+++ b/examples/demos/thermostat/content/images/more.svg
@@ -0,0 +1,5 @@
+<svg width="24" height="25" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M5 10.1403C3.9 10.1403 3 11.0371 3 12.1331C3 13.2291 3.9 14.1259 5 14.1259C6.1 14.1259 7 13.2291 7 12.1331C7 11.0371 6.1 10.1403 5 10.1403Z" stroke="white" stroke-width="1.5"/>
+<path d="M19 10.1403C17.9 10.1403 17 11.0371 17 12.1331C17 13.2291 17.9 14.1259 19 14.1259C20.1 14.1259 21 13.2291 21 12.1331C21 11.0371 20.1 10.1403 19 10.1403Z" stroke="white" stroke-width="1.5"/>
+<path d="M12 10.1403C10.9 10.1403 10 11.0371 10 12.1331C10 13.2291 10.9 14.1259 12 14.1259C13.1 14.1259 14 13.2291 14 12.1331C14 11.0371 13.1 10.1403 12 10.1403Z" stroke="white" stroke-width="1.5"/>
+</svg>
diff --git a/examples/demos/thermostat/content/images/power.svg b/examples/demos/thermostat/content/images/power.svg
new file mode 100644
index 000000000..930382533
--- /dev/null
+++ b/examples/demos/thermostat/content/images/power.svg
@@ -0,0 +1,3 @@
+<svg width="32" height="31" viewBox="0 0 32 31" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M14.6875 15V1.875C14.6875 1.5269 14.8258 1.19306 15.0719 0.946923C15.3181 0.700781 15.6519 0.5625 16 0.5625C16.3481 0.5625 16.6819 0.700781 16.9281 0.946923C17.1742 1.19306 17.3125 1.5269 17.3125 1.875V15C17.3125 15.3481 17.1742 15.6819 16.9281 15.9281C16.6819 16.1742 16.3481 16.3125 16 16.3125C15.6519 16.3125 15.3181 16.1742 15.0719 15.9281C14.8258 15.6819 14.6875 15.3481 14.6875 15ZM24.592 2.08828C24.3004 1.90404 23.9482 1.84193 23.6112 1.91537C23.2743 1.9888 22.9798 2.1919 22.7914 2.48073C22.603 2.76957 22.5359 3.12094 22.6045 3.45889C22.6731 3.79684 22.8719 4.09422 23.158 4.28672C26.9495 6.75914 29.125 10.6638 29.125 15C29.125 18.481 27.7422 21.8194 25.2808 24.2808C22.8194 26.7422 19.481 28.125 16 28.125C12.519 28.125 9.18064 26.7422 6.71922 24.2808C4.25781 21.8194 2.875 18.481 2.875 15C2.875 10.6638 5.05047 6.75914 8.84195 4.28672C9.12807 4.09422 9.32692 3.79684 9.39553 3.45889C9.46414 3.12094 9.39699 2.76957 9.2086 2.48073C9.02021 2.1919 8.72572 1.9888 8.38878 1.91537C8.05185 1.84193 7.69955 1.90404 7.40805 2.08828C2.85859 5.05453 0.25 9.75984 0.25 15C0.25 19.1772 1.90937 23.1832 4.86307 26.1369C7.81677 29.0906 11.8228 30.75 16 30.75C20.1772 30.75 24.1832 29.0906 27.1369 26.1369C30.0906 23.1832 31.75 19.1772 31.75 15C31.75 9.75984 29.1414 5.05453 24.592 2.08828Z" fill="#898989"/>
+</svg>
diff --git a/examples/demos/thermostat/content/images/schedule.svg b/examples/demos/thermostat/content/images/schedule.svg
new file mode 100644
index 000000000..489b676f3
--- /dev/null
+++ b/examples/demos/thermostat/content/images/schedule.svg
@@ -0,0 +1,3 @@
+<svg width="34" height="34" viewBox="0 0 34 34" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M27.625 4.25H24.4375V3.1875C24.4375 2.90571 24.3256 2.63546 24.1263 2.4362C23.927 2.23694 23.6568 2.125 23.375 2.125C23.0932 2.125 22.823 2.23694 22.6237 2.4362C22.4244 2.63546 22.3125 2.90571 22.3125 3.1875V4.25H11.6875V3.1875C11.6875 2.90571 11.5756 2.63546 11.3763 2.4362C11.177 2.23694 10.9068 2.125 10.625 2.125C10.3432 2.125 10.073 2.23694 9.8737 2.4362C9.67444 2.63546 9.5625 2.90571 9.5625 3.1875V4.25H6.375C5.81141 4.25 5.27091 4.47388 4.8724 4.8724C4.47388 5.27091 4.25 5.81141 4.25 6.375V27.625C4.25 28.1886 4.47388 28.7291 4.8724 29.1276C5.27091 29.5261 5.81141 29.75 6.375 29.75H27.625C28.1886 29.75 28.7291 29.5261 29.1276 29.1276C29.5261 28.7291 29.75 28.1886 29.75 27.625V6.375C29.75 5.81141 29.5261 5.27091 29.1276 4.8724C28.7291 4.47388 28.1886 4.25 27.625 4.25ZM9.5625 6.375V7.4375C9.5625 7.71929 9.67444 7.98954 9.8737 8.1888C10.073 8.38806 10.3432 8.5 10.625 8.5C10.9068 8.5 11.177 8.38806 11.3763 8.1888C11.5756 7.98954 11.6875 7.71929 11.6875 7.4375V6.375H22.3125V7.4375C22.3125 7.71929 22.4244 7.98954 22.6237 8.1888C22.823 8.38806 23.0932 8.5 23.375 8.5C23.6568 8.5 23.927 8.38806 24.1263 8.1888C24.3256 7.98954 24.4375 7.71929 24.4375 7.4375V6.375H27.625V10.625H6.375V6.375H9.5625ZM27.625 27.625H6.375V12.75H27.625V27.625ZM14.875 15.9375V24.4375C14.875 24.7193 14.7631 24.9895 14.5638 25.1888C14.3645 25.3881 14.0943 25.5 13.8125 25.5C13.5307 25.5 13.2605 25.3881 13.0612 25.1888C12.8619 24.9895 12.75 24.7193 12.75 24.4375V17.6561L12.163 17.9509C11.9108 18.077 11.6188 18.0978 11.3513 18.0086C11.0838 17.9195 10.8627 17.7277 10.7366 17.4755C10.6105 17.2233 10.5897 16.9313 10.6789 16.6638C10.768 16.3963 10.9598 16.1752 11.212 16.0491L13.337 14.9866C13.4991 14.9055 13.6792 14.8672 13.8602 14.8753C14.0412 14.8834 14.2171 14.9377 14.3713 15.033C14.5254 15.1283 14.6526 15.2615 14.7407 15.4198C14.8289 15.5781 14.8751 15.7563 14.875 15.9375ZM22.7322 19.9816L20.1875 23.375H22.3125C22.5943 23.375 22.8645 23.4869 23.0638 23.6862C23.2631 23.8855 23.375 24.1557 23.375 24.4375C23.375 24.7193 23.2631 24.9895 23.0638 25.1888C22.8645 25.3881 22.5943 25.5 22.3125 25.5H18.0625C17.8652 25.5 17.6718 25.4451 17.5039 25.3413C17.3361 25.2376 17.2004 25.0892 17.1122 24.9127C17.0239 24.7362 16.9866 24.5386 17.0043 24.3421C17.022 24.1456 17.0941 23.9579 17.2125 23.8L21.0348 18.704C21.1218 18.5882 21.1842 18.4559 21.2181 18.3152C21.2521 18.1745 21.257 18.0283 21.2324 17.8857C21.2079 17.743 21.1544 17.6069 21.0754 17.4856C20.9963 17.3643 20.8933 17.2605 20.7727 17.1805C20.6521 17.1004 20.5163 17.0459 20.3739 17.0202C20.2314 16.9945 20.0852 16.9982 19.9442 17.0311C19.8032 17.0639 19.6705 17.1252 19.554 17.2112C19.4376 17.2972 19.3399 17.4061 19.2671 17.5312C19.1994 17.6559 19.1074 17.7658 18.9966 17.8544C18.8857 17.9429 18.7582 18.0084 18.6217 18.0469C18.4851 18.0854 18.3422 18.0961 18.2014 18.0785C18.0606 18.0609 17.9248 18.0152 17.802 17.9443C17.6791 17.8733 17.5717 17.7785 17.4861 17.6653C17.4005 17.5522 17.3384 17.423 17.3035 17.2855C17.2686 17.148 17.2616 17.0048 17.283 16.8646C17.3043 16.7243 17.3535 16.5897 17.4277 16.4688C17.7786 15.8614 18.3202 15.3868 18.9683 15.1184C19.6164 14.8501 20.335 14.8031 21.0126 14.9847C21.6901 15.1663 22.2889 15.5663 22.716 16.1227C23.1431 16.6792 23.3748 17.361 23.375 18.0625C23.3773 18.7554 23.1514 19.4299 22.7322 19.9816Z" fill="white"/>
+</svg>
diff --git a/examples/demos/thermostat/content/images/settings.svg b/examples/demos/thermostat/content/images/settings.svg
new file mode 100644
index 000000000..d6e31db53
--- /dev/null
+++ b/examples/demos/thermostat/content/images/settings.svg
@@ -0,0 +1,3 @@
+<svg width="34" height="34" viewBox="0 0 34 34" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M16.9992 10.6249C15.7383 10.6249 14.5058 10.9988 13.4574 11.6993C12.4091 12.3998 11.592 13.3955 11.1095 14.5603C10.627 15.7252 10.5007 17.007 10.7467 18.2436C10.9927 19.4803 11.5998 20.6162 12.4914 21.5077C13.383 22.3993 14.5189 23.0065 15.7555 23.2524C16.9921 23.4984 18.2739 23.3722 19.4388 22.8897C20.6037 22.4072 21.5993 21.5901 22.2998 20.5417C23.0003 19.4933 23.3742 18.2608 23.3742 16.9999C23.3724 15.3097 22.7002 13.6892 21.5051 12.4941C20.3099 11.2989 18.6894 10.6267 16.9992 10.6249ZM16.9992 21.2499C16.1586 21.2499 15.3369 21.0007 14.638 20.5337C13.9391 20.0667 13.3944 19.4029 13.0727 18.6263C12.751 17.8498 12.6669 16.9952 12.8309 16.1708C12.9949 15.3464 13.3996 14.5891 13.994 13.9947C14.5884 13.4004 15.3457 12.9956 16.1701 12.8316C16.9945 12.6676 17.849 12.7518 18.6256 13.0735C19.4022 13.3951 20.066 13.9399 20.533 14.6388C20.9999 15.3377 21.2492 16.1594 21.2492 16.9999C21.2492 18.1271 20.8014 19.2081 20.0044 20.0051C19.2074 20.8022 18.1264 21.2499 16.9992 21.2499ZM28.6867 17.2868C28.692 17.0956 28.692 16.9043 28.6867 16.7131L30.6683 14.2374C30.7722 14.1075 30.8441 13.9549 30.8782 13.792C30.9124 13.6292 30.9078 13.4605 30.8648 13.2998C30.54 12.0787 30.0541 10.9063 29.4198 9.81345C29.3368 9.67044 29.2215 9.54878 29.0832 9.45817C28.9448 9.36755 28.7872 9.31048 28.623 9.2915L25.4726 8.94088C25.3416 8.80275 25.2088 8.66994 25.0742 8.54244L24.7023 5.38416C24.6832 5.21975 24.6259 5.06209 24.5351 4.92374C24.4442 4.78539 24.3223 4.67017 24.1791 4.58728C23.0858 3.95423 21.9135 3.46878 20.6927 3.14361C20.5319 3.10084 20.3632 3.09647 20.2003 3.13084C20.0374 3.16521 19.8849 3.23737 19.7551 3.3415L17.2861 5.31244C17.0948 5.31244 16.9036 5.31244 16.7123 5.31244L14.2367 3.33486C14.1067 3.23096 13.9542 3.15904 13.7913 3.1249C13.6284 3.09076 13.4598 3.09535 13.2991 3.1383C12.0782 3.46372 10.9058 3.94963 9.81272 4.5833C9.66971 4.66634 9.54805 4.78162 9.45744 4.91996C9.36682 5.0583 9.30975 5.21589 9.29077 5.38017L8.94014 8.5358C8.80202 8.66772 8.66921 8.80054 8.54171 8.93424L5.38342 9.29681C5.21902 9.31594 5.06136 9.37321 4.923 9.46406C4.78465 9.55491 4.66944 9.67683 4.58655 9.8201C3.95349 10.9134 3.46805 12.0857 3.14288 13.3064C3.10011 13.4673 3.09573 13.636 3.13011 13.7988C3.16448 13.9617 3.23664 14.1142 3.34077 14.2441L5.31171 16.7131C5.31171 16.9043 5.31171 17.0956 5.31171 17.2868L3.33413 19.7624C3.23023 19.8924 3.15831 20.045 3.12417 20.2079C3.09002 20.3707 3.09461 20.5393 3.13757 20.7001C3.46241 21.9212 3.94834 23.0936 4.58257 24.1864C4.66561 24.3294 4.78089 24.4511 4.91923 24.5417C5.05757 24.6323 5.21516 24.6894 5.37944 24.7084L8.52975 25.059C8.66168 25.1971 8.79449 25.3299 8.92819 25.4574L9.29608 28.6157C9.31521 28.7801 9.37248 28.9378 9.46333 29.0761C9.55418 29.2145 9.6761 29.3297 9.81936 29.4126C10.9126 30.0457 12.0849 30.5311 13.3057 30.8563C13.4666 30.899 13.6352 30.9034 13.7981 30.869C13.961 30.8347 14.1135 30.7625 14.2433 30.6584L16.7123 28.6874C16.9036 28.6928 17.0948 28.6928 17.2861 28.6874L19.7617 30.669C19.8917 30.7729 20.0443 30.8448 20.2071 30.879C20.37 30.9131 20.5386 30.9085 20.6994 30.8656C21.9204 30.5407 23.0928 30.0548 24.1857 29.4206C24.3287 29.3375 24.4504 29.2222 24.541 29.0839C24.6316 28.9456 24.6887 28.788 24.7076 28.6237L25.0583 25.4734C25.1964 25.3423 25.3292 25.2095 25.4567 25.0749L28.615 24.7031C28.7794 24.6839 28.9371 24.6267 29.0754 24.5358C29.2138 24.445 29.329 24.323 29.4119 24.1798C30.0449 23.0865 30.5304 21.9142 30.8555 20.6935C30.8983 20.5326 30.9027 20.3639 30.8683 20.201C30.8339 20.0382 30.7618 19.8857 30.6576 19.7558L28.6867 17.2868ZM26.5484 16.4235C26.571 16.8075 26.571 17.1924 26.5484 17.5763C26.5326 17.8392 26.615 18.0986 26.7795 18.3042L28.6641 20.6589C28.4479 21.3462 28.171 22.0129 27.8367 22.6511L24.8351 22.9911C24.5737 23.0201 24.3324 23.1451 24.1578 23.3417C23.9021 23.6293 23.6299 23.9016 23.3423 24.1572C23.1457 24.3318 23.0207 24.5732 22.9917 24.8345L22.6583 27.8335C22.0202 28.1679 21.3535 28.4448 20.6662 28.6609L18.3101 26.7763C18.1215 26.6256 17.8873 26.5437 17.646 26.5438H17.5823C17.1983 26.5664 16.8134 26.5664 16.4294 26.5438C16.1666 26.528 15.9072 26.6104 15.7016 26.7749L13.3402 28.6609C12.653 28.4446 11.9863 28.1677 11.348 27.8335L11.008 24.8359C10.979 24.5745 10.8541 24.3331 10.6574 24.1585C10.3699 23.9029 10.0976 23.6306 9.84194 23.3431C9.66734 23.1464 9.42599 23.0215 9.1646 22.9924L6.16569 22.6578C5.83126 22.0196 5.55436 21.3529 5.33827 20.6656L7.22288 18.3095C7.38744 18.1039 7.46979 17.8445 7.45397 17.5817C7.43139 17.1977 7.43139 16.8128 7.45397 16.4288C7.46979 16.166 7.38744 15.9066 7.22288 15.701L5.33827 13.341C5.55452 12.6537 5.83142 11.987 6.16569 11.3488L9.16327 11.0088C9.42466 10.9798 9.66601 10.8548 9.84061 10.6581C10.0963 10.3706 10.3686 10.0983 10.6561 9.84267C10.8535 9.66795 10.979 9.42606 11.008 9.164L11.3414 6.16642C11.9796 5.83199 12.6463 5.55509 13.3336 5.339L15.6897 7.22361C15.8953 7.38817 16.1546 7.47053 16.4175 7.4547C16.8014 7.43213 17.1864 7.43213 17.5703 7.4547C17.8332 7.47053 18.0925 7.38817 18.2981 7.22361L20.6582 5.339C21.3455 5.55525 22.0121 5.83215 22.6504 6.16642L22.9904 9.164C23.0194 9.4254 23.1443 9.66674 23.341 9.84134C23.6285 10.097 23.9008 10.3693 24.1565 10.6568C24.3311 10.8535 24.5724 10.9784 24.8338 11.0074L27.8327 11.3408C28.1672 11.979 28.4441 12.6457 28.6601 13.333L26.7755 15.6891C26.6094 15.8964 26.5269 16.1584 26.5444 16.4235H26.5484Z" fill="#D9D9D9"/>
+</svg>
diff --git a/examples/demos/thermostat/content/images/stats.svg b/examples/demos/thermostat/content/images/stats.svg
new file mode 100644
index 000000000..92d4d5f1e
--- /dev/null
+++ b/examples/demos/thermostat/content/images/stats.svg
@@ -0,0 +1,3 @@
+<svg width="34" height="34" viewBox="0 0 34 34" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M29.75 26.5625H28.6875V5.3125C28.6875 5.03071 28.5756 4.76046 28.3763 4.5612C28.177 4.36194 27.9068 4.25 27.625 4.25H20.1875C19.9057 4.25 19.6355 4.36194 19.4362 4.5612C19.2369 4.76046 19.125 5.03071 19.125 5.3125V10.625H12.75C12.4682 10.625 12.198 10.7369 11.9987 10.9362C11.7994 11.1355 11.6875 11.4057 11.6875 11.6875V17H6.375C6.09321 17 5.82296 17.1119 5.6237 17.3112C5.42444 17.5105 5.3125 17.7807 5.3125 18.0625V26.5625H4.25C3.96821 26.5625 3.69796 26.6744 3.4987 26.8737C3.29944 27.073 3.1875 27.3432 3.1875 27.625C3.1875 27.9068 3.29944 28.177 3.4987 28.3763C3.69796 28.5756 3.96821 28.6875 4.25 28.6875H29.75C30.0318 28.6875 30.302 28.5756 30.5013 28.3763C30.7006 28.177 30.8125 27.9068 30.8125 27.625C30.8125 27.3432 30.7006 27.073 30.5013 26.8737C30.302 26.6744 30.0318 26.5625 29.75 26.5625ZM21.25 6.375H26.5625V26.5625H21.25V6.375ZM13.8125 12.75H19.125V26.5625H13.8125V12.75ZM7.4375 19.125H11.6875V26.5625H7.4375V19.125Z" fill="white"/>
+</svg>
diff --git a/examples/demos/thermostat/content/images/temperature.svg b/examples/demos/thermostat/content/images/temperature.svg
new file mode 100644
index 000000000..4712178e5
--- /dev/null
+++ b/examples/demos/thermostat/content/images/temperature.svg
@@ -0,0 +1,3 @@
+<svg width="34" height="35" viewBox="0 0 34 35" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M23.5623 11.1967C23.4027 10.9647 23.3417 10.6789 23.3928 10.4019C23.4438 10.125 23.6027 9.87969 23.8345 9.71984C25.2158 8.76625 27.378 8.76625 28.7592 9.71984C29.4233 10.1807 30.6027 10.1807 31.272 9.71984C31.504 9.57246 31.784 9.52069 32.0533 9.57539C32.3227 9.6301 32.5603 9.78703 32.7164 10.0132C32.8724 10.2394 32.9348 10.5173 32.8904 10.7885C32.8459 11.0597 32.6981 11.3031 32.478 11.4677C31.7415 11.9343 30.8875 12.1821 30.0156 12.1821C29.1437 12.1821 28.2898 11.9343 27.5533 11.4677C26.8892 11.0068 25.7098 11.0068 25.0405 11.4677C24.9256 11.5469 24.7963 11.6028 24.6598 11.6321C24.5234 11.6614 24.3825 11.6636 24.2452 11.6384C24.108 11.6132 23.977 11.5613 23.8598 11.4855C23.7426 11.4097 23.6415 11.3116 23.5623 11.1967ZM31.272 13.9698C30.608 14.4307 29.4286 14.4307 28.7592 13.9698C27.378 13.0162 25.2158 13.0162 23.8345 13.9698C23.7139 14.0465 23.61 14.1467 23.529 14.2644C23.448 14.3822 23.3916 14.5151 23.3631 14.6551C23.3347 14.7952 23.3348 14.9395 23.3634 15.0796C23.392 15.2196 23.4486 15.3524 23.5298 15.47C23.611 15.5877 23.715 15.6877 23.8358 15.7642C23.9565 15.8407 24.0914 15.892 24.2325 15.9151C24.3735 15.9383 24.5178 15.9327 24.6566 15.8987C24.7954 15.8648 24.926 15.8032 25.0405 15.7177C25.7045 15.2568 26.8839 15.2568 27.5533 15.7177C28.2898 16.1843 29.1437 16.4321 30.0156 16.4321C30.8875 16.4321 31.7415 16.1843 32.478 15.7177C32.6981 15.5531 32.8459 15.3097 32.8904 15.0385C32.9348 14.7673 32.8724 14.4894 32.7164 14.2632C32.5603 14.037 32.3227 13.8801 32.0533 13.8254C31.784 13.7707 31.504 13.8225 31.272 13.9698ZM20.1875 24.9375C20.1871 25.7323 19.9638 26.5111 19.5431 27.1853C19.1223 27.8596 18.5209 28.4024 17.8071 28.752C17.0933 29.1017 16.2958 29.2442 15.5051 29.1633C14.7145 29.0824 13.9623 28.7815 13.3341 28.2946C12.7058 27.8077 12.2267 27.1545 11.9512 26.409C11.6756 25.6635 11.6146 24.8556 11.775 24.0772C11.9355 23.2988 12.3111 22.5809 12.859 22.0052C13.407 21.4295 14.1054 21.019 14.875 20.8203V6.875C14.875 6.59321 14.9869 6.32296 15.1862 6.1237C15.3855 5.92444 15.6557 5.8125 15.9375 5.8125C16.2193 5.8125 16.4895 5.92444 16.6888 6.1237C16.8881 6.32296 17 6.59321 17 6.875V20.8203C17.912 21.0572 18.7196 21.5899 19.2964 22.3349C19.8732 23.08 20.1866 23.9953 20.1875 24.9375ZM18.0625 24.9375C18.0625 24.5172 17.9379 24.1064 17.7044 23.7569C17.4709 23.4075 17.139 23.1351 16.7507 22.9743C16.3624 22.8134 15.9351 22.7713 15.5229 22.8533C15.1107 22.9353 14.7321 23.1377 14.4349 23.4349C14.1377 23.7321 13.9353 24.1107 13.8533 24.5229C13.7713 24.9351 13.8134 25.3624 13.9743 25.7507C14.1351 26.139 14.4075 26.4709 14.7569 26.7044C15.1064 26.9379 15.5172 27.0625 15.9375 27.0625C16.5011 27.0625 17.0416 26.8386 17.4401 26.4401C17.8386 26.0416 18.0625 25.5011 18.0625 24.9375ZM24.4375 24.9375C24.4366 26.3748 24.0713 27.7883 23.3756 29.0461C22.68 30.3038 21.6768 31.3646 20.4599 32.1293C19.2429 32.894 17.8519 33.3376 16.4169 33.4187C14.982 33.4997 13.5498 33.2156 12.2545 32.5928C10.9592 31.9701 9.84288 31.029 9.01003 29.8576C8.17718 28.6863 7.65496 27.3228 7.49219 25.8948C7.32942 24.4668 7.53141 23.0208 8.07929 21.6921C8.62717 20.3633 9.50303 19.1952 10.625 18.2969V6.875C10.625 5.46604 11.1847 4.11478 12.181 3.1185C13.1773 2.12221 14.5285 1.5625 15.9375 1.5625C17.3465 1.5625 18.6977 2.12221 19.694 3.1185C20.6903 4.11478 21.25 5.46604 21.25 6.875V18.2969C22.2448 19.0943 23.0477 20.1051 23.5994 21.2545C24.1511 22.4039 24.4375 23.6625 24.4375 24.9375ZM22.3125 24.9375C22.3117 23.9097 22.0627 22.8973 21.5869 21.9863C21.111 21.0752 20.4223 20.2926 19.5792 19.7047C19.4382 19.6062 19.3232 19.475 19.2441 19.3224C19.165 19.1697 19.1241 19.0001 19.125 18.8281V6.875C19.125 6.02962 18.7892 5.21887 18.1914 4.6211C17.5936 4.02333 16.7829 3.6875 15.9375 3.6875C15.0921 3.6875 14.2814 4.02333 13.6836 4.6211C13.0858 5.21887 12.75 6.02962 12.75 6.875V18.8281C12.75 18.9992 12.7087 19.1677 12.6297 19.3194C12.5506 19.4711 12.436 19.6014 12.2958 19.6994C11.3962 20.3255 10.6733 21.1729 10.1967 22.1599C9.72014 23.1468 9.50608 24.24 9.57519 25.3338C9.6443 26.4276 9.99425 27.4852 10.5912 28.4043C11.1882 29.3234 12.0121 30.0731 12.9833 30.581C13.9545 31.0889 15.0403 31.3378 16.1358 31.3037C17.2312 31.2697 18.2994 30.9537 19.2372 30.3864C20.1749 29.8192 20.9506 29.0197 21.4893 28.0652C22.028 27.1107 22.3115 26.0335 22.3125 24.9375Z" fill="white"/>
+</svg>
diff --git a/examples/demos/thermostat/content/images/theme.svg b/examples/demos/thermostat/content/images/theme.svg
new file mode 100644
index 000000000..b22587ed5
--- /dev/null
+++ b/examples/demos/thermostat/content/images/theme.svg
@@ -0,0 +1,3 @@
+<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M9 0C7.21997 0 5.47991 0.527841 3.99987 1.51677C2.51983 2.50571 1.36628 3.91131 0.685088 5.55585C0.00389956 7.20038 -0.17433 9.00998 0.172937 10.7558C0.520203 12.5016 1.37737 14.1053 2.63604 15.364C3.89471 16.6226 5.49836 17.4798 7.24419 17.8271C8.99002 18.1743 10.7996 17.9961 12.4442 17.3149C14.0887 16.6337 15.4943 15.4802 16.4832 14.0001C17.4722 12.5201 18 10.78 18 9C17.9975 6.61382 17.0485 4.3261 15.3612 2.63882C13.6739 0.95154 11.3862 0.00251984 9 0ZM9.69231 1.41663C10.161 1.4594 10.6246 1.54633 11.0769 1.67625V16.3272C10.6246 16.4571 10.161 16.5441 9.69231 16.5868V1.41663ZM12.4615 2.21798C12.955 2.47061 13.4193 2.77646 13.8462 3.1301V14.8699C13.4193 15.2235 12.955 15.5294 12.4615 15.782V2.21798ZM1.38462 9C1.3869 7.10083 2.09785 5.27087 3.37832 3.86828C4.65878 2.46569 6.41659 1.59144 8.30769 1.41663V16.5834C6.41659 16.4086 4.65878 15.5343 3.37832 14.1317C2.09785 12.7291 1.3869 10.8992 1.38462 9ZM15.2308 13.3737V4.62635C16.1318 5.90679 16.6154 7.43429 16.6154 9C16.6154 10.5657 16.1318 12.0932 15.2308 13.3737Z" fill="#888888"/>
+</svg>
diff --git a/examples/demos/thermostat/content/images/thermostat.svg b/examples/demos/thermostat/content/images/thermostat.svg
new file mode 100644
index 000000000..694dc6785
--- /dev/null
+++ b/examples/demos/thermostat/content/images/thermostat.svg
@@ -0,0 +1,3 @@
+<svg width="34" height="34" viewBox="0 0 34 34" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M3.1875 12.75V22.3125C3.1875 22.5943 3.29944 22.8645 3.4987 23.0638C3.69796 23.2631 3.96821 23.375 4.25 23.375H14.875C15.1568 23.375 15.427 23.4869 15.6263 23.6862C15.8256 23.8855 15.9375 24.1557 15.9375 24.4375C15.9375 24.7193 15.8256 24.9895 15.6263 25.1888C15.427 25.3881 15.1568 25.5 14.875 25.5H12.75V27.625H14.875C15.1568 27.625 15.427 27.7369 15.6263 27.9362C15.8256 28.1355 15.9375 28.4057 15.9375 28.6875C15.9375 28.9693 15.8256 29.2395 15.6263 29.4388C15.427 29.6381 15.1568 29.75 14.875 29.75H8.5C8.21821 29.75 7.94796 29.6381 7.7487 29.4388C7.54944 29.2395 7.4375 28.9693 7.4375 28.6875C7.4375 28.4057 7.54944 28.1355 7.7487 27.9362C7.94796 27.7369 8.21821 27.625 8.5 27.625H10.625V25.5H4.25C3.40462 25.5 2.59387 25.1642 1.9961 24.5664C1.39832 23.9686 1.0625 23.1579 1.0625 22.3125V12.75C1.0625 11.9046 1.39832 11.0939 1.9961 10.4961C2.59387 9.89832 3.40462 9.5625 4.25 9.5625H14.875C15.1568 9.5625 15.427 9.67444 15.6263 9.8737C15.8256 10.073 15.9375 10.3432 15.9375 10.625C15.9375 10.9068 15.8256 11.177 15.6263 11.3763C15.427 11.5756 15.1568 11.6875 14.875 11.6875H4.25C3.96821 11.6875 3.69796 11.7994 3.4987 11.9987C3.29944 12.198 3.1875 12.4682 3.1875 12.75ZM27.625 8.5H23.375C23.0932 8.5 22.823 8.61194 22.6237 8.8112C22.4244 9.01046 22.3125 9.28071 22.3125 9.5625C22.3125 9.84429 22.4244 10.1145 22.6237 10.3138C22.823 10.5131 23.0932 10.625 23.375 10.625H27.625C27.9068 10.625 28.177 10.5131 28.3763 10.3138C28.5756 10.1145 28.6875 9.84429 28.6875 9.5625C28.6875 9.28071 28.5756 9.01046 28.3763 8.8112C28.177 8.61194 27.9068 8.5 27.625 8.5ZM27.625 12.75H23.375C23.0932 12.75 22.823 12.8619 22.6237 13.0612C22.4244 13.2605 22.3125 13.5307 22.3125 13.8125C22.3125 14.0943 22.4244 14.3645 22.6237 14.5638C22.823 14.7631 23.0932 14.875 23.375 14.875H27.625C27.9068 14.875 28.177 14.7631 28.3763 14.5638C28.5756 14.3645 28.6875 14.0943 28.6875 13.8125C28.6875 13.5307 28.5756 13.2605 28.3763 13.0612C28.177 12.8619 27.9068 12.75 27.625 12.75ZM32.9375 6.375V27.625C32.9375 28.1886 32.7136 28.7291 32.3151 29.1276C31.9166 29.5261 31.3761 29.75 30.8125 29.75H20.1875C19.6239 29.75 19.0834 29.5261 18.6849 29.1276C18.2864 28.7291 18.0625 28.1886 18.0625 27.625V6.375C18.0625 5.81141 18.2864 5.27091 18.6849 4.8724C19.0834 4.47388 19.6239 4.25 20.1875 4.25H30.8125C31.3761 4.25 31.9166 4.47388 32.3151 4.8724C32.7136 5.27091 32.9375 5.81141 32.9375 6.375ZM30.8125 27.625V6.375H20.1875V27.625H30.8125ZM25.5 22.3125C25.1848 22.3125 24.8767 22.406 24.6146 22.5811C24.3525 22.7562 24.1482 23.0051 24.0276 23.2963C23.9069 23.5876 23.8754 23.908 23.9369 24.2172C23.9984 24.5263 24.1502 24.8103 24.373 25.0332C24.5959 25.2561 24.8799 25.4079 25.1891 25.4694C25.4982 25.5309 25.8187 25.4993 26.1099 25.3787C26.4011 25.2581 26.65 25.0538 26.8252 24.7917C27.0003 24.5296 27.0938 24.2215 27.0938 23.9062C27.0938 23.4836 26.9258 23.0782 26.627 22.7793C26.3281 22.4804 25.9227 22.3125 25.5 22.3125Z" fill="white"/>
+</svg>
diff --git a/examples/demos/thermostat/content/images/up.svg b/examples/demos/thermostat/content/images/up.svg
new file mode 100644
index 000000000..69b44ffa6
--- /dev/null
+++ b/examples/demos/thermostat/content/images/up.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M22.875 5.25V11.25C22.875 11.5484 22.7564 11.8345 22.5455 12.0455C22.3345 12.2565 22.0483 12.375 21.75 12.375C21.4516 12.375 21.1654 12.2565 20.9545 12.0455C20.7435 11.8345 20.625 11.5484 20.625 11.25V7.96875L13.5459 15.0488C13.4414 15.1536 13.3172 15.2368 13.1804 15.2936C13.0437 15.3504 12.8971 15.3796 12.749 15.3796C12.601 15.3796 12.4543 15.3504 12.3176 15.2936C12.1809 15.2368 12.0567 15.1536 11.9521 15.0488L8.99996 12.0938L3.0459 18.0459C2.83455 18.2573 2.54791 18.376 2.24902 18.376C1.95014 18.376 1.66349 18.2573 1.45215 18.0459C1.2408 17.8346 1.12207 17.5479 1.12207 17.2491C1.12207 16.9502 1.2408 16.6635 1.45215 16.4522L8.20215 9.70219C8.30666 9.59731 8.43086 9.51409 8.5676 9.45731C8.70435 9.40053 8.85096 9.3713 8.99902 9.3713C9.14709 9.3713 9.2937 9.40053 9.43044 9.45731C9.56719 9.51409 9.69138 9.59731 9.7959 9.70219L12.75 12.6562L19.0312 6.375H15.75C15.4516 6.375 15.1654 6.25647 14.9545 6.0455C14.7435 5.83452 14.625 5.54837 14.625 5.25C14.625 4.95163 14.7435 4.66548 14.9545 4.4545C15.1654 4.24353 15.4516 4.125 15.75 4.125H21.75C22.0483 4.125 22.3345 4.24353 22.5455 4.4545C22.7564 4.66548 22.875 4.95163 22.875 5.25Z" fill="#CC0A0A"/>
+</svg>
diff --git a/examples/demos/thermostat/doc/images/desktop_dark.png b/examples/demos/thermostat/doc/images/desktop_dark.png
new file mode 100644
index 000000000..1c635ad1f
--- /dev/null
+++ b/examples/demos/thermostat/doc/images/desktop_dark.png
Binary files differ
diff --git a/examples/demos/thermostat/doc/images/desktop_light.png b/examples/demos/thermostat/doc/images/desktop_light.png
new file mode 100644
index 000000000..5c30acbbd
--- /dev/null
+++ b/examples/demos/thermostat/doc/images/desktop_light.png
Binary files differ
diff --git a/examples/demos/thermostat/doc/images/mobile_dark.png b/examples/demos/thermostat/doc/images/mobile_dark.png
new file mode 100644
index 000000000..9312432d9
--- /dev/null
+++ b/examples/demos/thermostat/doc/images/mobile_dark.png
Binary files differ
diff --git a/examples/demos/thermostat/doc/images/mobile_light.png b/examples/demos/thermostat/doc/images/mobile_light.png
new file mode 100644
index 000000000..3cf72730a
--- /dev/null
+++ b/examples/demos/thermostat/doc/images/mobile_light.png
Binary files differ
diff --git a/examples/demos/thermostat/doc/images/small_dark.png b/examples/demos/thermostat/doc/images/small_dark.png
new file mode 100644
index 000000000..2362cbfa5
--- /dev/null
+++ b/examples/demos/thermostat/doc/images/small_dark.png
Binary files differ
diff --git a/examples/demos/thermostat/doc/images/small_light.png b/examples/demos/thermostat/doc/images/small_light.png
new file mode 100644
index 000000000..2c84c2170
--- /dev/null
+++ b/examples/demos/thermostat/doc/images/small_light.png
Binary files differ
diff --git a/examples/demos/thermostat/doc/src/thermostat.qdoc b/examples/demos/thermostat/doc/src/thermostat.qdoc
new file mode 100644
index 000000000..87639bd36
--- /dev/null
+++ b/examples/demos/thermostat/doc/src/thermostat.qdoc
@@ -0,0 +1,52 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+/*!
+ \title Thermostat
+ \examplecategory {Application Examples}
+ \ingroup qtquickdemos
+ \example demos/thermostat
+ \brief A user interface for a home thermostat, implemented in Qt Quick. It demonstrates how to create responsive applications that scale from large desktop displays to mobile and small embedded displays.
+ \meta {tag} {demo,quick,charts}
+
+ \table
+ \header
+ \li Light theme
+ \li Dark theme
+ \row
+ \li \inlineimage small_light.png
+ \li \inlineimage small_dark.png
+ \row
+ \li \inlineimage mobile_light.png
+ \li \inlineimage mobile_dark.png
+ \row
+ \li \inlineimage desktop_light.png
+ \li \inlineimage desktop_dark.png
+ \endtable
+
+ \e{Thermostat} demonstrates a sample thermostat application that is fully responsive. The example can be run and edited in both \l{Qt Design Studio} and \l{Qt Creator}.
+ It shows how to implement different designs depending on the window size.
+
+ \section1 Responsive Design
+ As mentioned above, the application has support for a variety of display sizes.It can scale dynamically when the user changes the window size, or the application will select the correct sizes based on the available display on mobile targets.
+ Properties that specify the display size and control which layout is currently in use have been created in \c Constants.qml to achieve this behavior.
+
+ \quotefromfile demos/thermostat/imports/Thermostat/Constants.qml
+ \skipto isBigDesktopLayout
+ \printuntil isSmallLayout
+
+ In \c App.qml, the properties were bound to the window height and width at application startup.
+
+ \quotefromfile demos/thermostat/content/App.qml
+ \skipto Component.onCompleted
+ \printuntil Constants.isSmallLayout
+ \printuntil }
+ \printuntil }
+
+ The states are then used to control the properties of the component such as width, height, fontSize, position, layout (column or row), etc.
+
+ \quotefromfile demos/thermostat/content/StatisticsScrollViewForm.ui.qml
+ \skipto states
+ \printuntil ]
+
+*/
diff --git a/examples/demos/thermostat/imports/CMakeLists.txt b/examples/demos/thermostat/imports/CMakeLists.txt
new file mode 100644
index 000000000..42cff97be
--- /dev/null
+++ b/examples/demos/thermostat/imports/CMakeLists.txt
@@ -0,0 +1,5 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+add_subdirectory(CustomControls)
+add_subdirectory(Thermostat)
diff --git a/examples/demos/thermostat/imports/CustomControls/CMakeLists.txt b/examples/demos/thermostat/imports/CustomControls/CMakeLists.txt
new file mode 100644
index 000000000..4e16ec2d9
--- /dev/null
+++ b/examples/demos/thermostat/imports/CustomControls/CMakeLists.txt
@@ -0,0 +1,24 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+qt_add_library(CustomControls STATIC)
+qt_add_qml_module(CustomControls
+ URI "CustomControls"
+ VERSION 1.0
+ QML_FILES
+ CustomComboBox.qml
+ CustomDial.qml
+ CustomRadioButton.qml
+ CustomRoundButton.qml
+ CustomSlider.qml
+ CustomSwitch.qml
+ CustomTextField.qml
+ StatisticsChart.qml
+ TemperatureLabel.qml
+ ThermostatControl.qml
+ TimeSelector.qml
+ RESOURCES
+ images/keyboard.svg
+ images/thermometer.svg
+ images/tooltip.svg
+)
diff --git a/examples/demos/thermostat/imports/CustomControls/CustomComboBox.qml b/examples/demos/thermostat/imports/CustomControls/CustomComboBox.qml
new file mode 100644
index 000000000..f6b7de4f1
--- /dev/null
+++ b/examples/demos/thermostat/imports/CustomControls/CustomComboBox.qml
@@ -0,0 +1,109 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+pragma ComponentBehavior: Bound
+
+import QtQuick
+import QtQuick.Controls
+import Thermostat
+
+ComboBox {
+ id: control
+
+ font.family: "Titillium Web"
+ font.pixelSize: 14
+ font.weight: 400
+ textRole: "name"
+
+ background: Rectangle {
+ border.color: "#DCDCDC"
+ border.width: control.visualFocus ? 2 : 1
+ color: Constants.accentColor
+ implicitHeight: 40
+ implicitWidth: 120
+ radius: 8
+ }
+
+ contentItem: Text {
+ text: control.displayText
+ font: control.font
+ color: Constants.primaryTextColor
+ elide: Text.ElideRight
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ delegate: ItemDelegate {
+ id: comboBoxItem
+ required property int index
+ required property string name
+
+ highlighted: control.highlightedIndex === index
+ palette.light: AppSettings.isDarkTheme ? "#000000" : "#DCDCDC"
+ width: control.width
+
+ background: Rectangle {
+ color: Color.blend(comboBoxItem.down ? palette.midlight : palette.light, palette.highlight, comboBoxItem.visualFocus ? 0.15 : 0.0)
+ radius: 8
+ visible: comboBoxItem.down || comboBoxItem.highlighted || comboBoxItem.visualFocus
+ }
+ contentItem: Text {
+ color: Constants.primaryTextColor
+ elide: Text.ElideRight
+ font: control.font
+ text: comboBoxItem.name
+ verticalAlignment: Text.AlignVCenter
+ }
+ }
+
+ indicator: Canvas {
+ id: canvas
+
+ contextType: "2d"
+ height: 8
+ width: 12
+ x: control.width - width - control.rightPadding
+ y: control.topPadding + (control.availableHeight - height) / 2
+
+ onPaint: {
+ context.reset();
+ context.moveTo(0, 0);
+ context.lineTo(width, 0);
+ context.lineTo(width / 2, height);
+ context.closePath();
+ context.fillStyle = "#898989";
+ context.fill();
+ }
+
+ Connections {
+ function onPressedChanged() {
+ canvas.requestPaint();
+ }
+
+ target: control
+ }
+ }
+
+ popup: Popup {
+ implicitHeight: contentItem.implicitHeight
+ padding: 1
+ width: control.width
+ y: control.height - 1
+
+ background: Rectangle {
+ border.color: "#DCDCDC"
+ color: Constants.accentColor
+ radius: 8
+ }
+
+ contentItem: ListView {
+ clip: true
+ currentIndex: control.highlightedIndex
+ implicitHeight: contentHeight
+ model: control.popup.visible ? control.delegateModel : null
+
+ ScrollIndicator.vertical: ScrollIndicator {
+ }
+ }
+ }
+}
diff --git a/examples/demos/thermostat/imports/CustomControls/CustomDial.qml b/examples/demos/thermostat/imports/CustomControls/CustomDial.qml
new file mode 100644
index 000000000..b8c25e46f
--- /dev/null
+++ b/examples/demos/thermostat/imports/CustomControls/CustomDial.qml
@@ -0,0 +1,86 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Shapes
+import Thermostat
+
+Dial {
+ id: control
+
+ property alias handleHeight: handleItem.height
+ property alias handleWidth: handleItem.width
+ property int shapeRadius
+ property int shapeWidth
+
+ background: Rectangle {
+ border.color: "#2CDE85"
+ height: width
+ implicitHeight: 140
+ implicitWidth: 140
+ opacity: control.enabled ? 1 : 0.3
+ radius: width / 2
+ width: Math.max(64, Math.min(control.width, control.height))
+ x: control.width / 2 - width / 2
+ y: control.height / 2 - height / 2
+
+ gradient: Gradient {
+ GradientStop {
+ color: AppSettings.isDarkTheme ? "#558276" : "#EFFCF6"
+ position: 0.0
+ }
+ GradientStop {
+ color: Constants.accentColor
+ position: 1.0
+ }
+ }
+ }
+ handle: Rectangle {
+ id: handleItem
+
+ antialiasing: true
+ border.color: "#2CDE85"
+ border.width: 4
+ color: "#FFFFFF"
+ height: 30
+ opacity: control.enabled ? 1 : 0.3
+ radius: width / 2
+ width: 30
+ x: control.background.x + control.background.width / 2 - width / 2
+ y: control.background.y + control.background.height / 2 - height / 2
+ z: shape.z + 1
+
+ transform: [
+ Translate {
+ y: -Math.min(control.background.width, control.background.height) * 0.4 + handleItem.height / 2
+ },
+ Rotation {
+ angle: control.angle
+ origin.x: handleItem.width / 2
+ origin.y: handleItem.height / 2
+ }
+ ]
+ }
+
+ Shape {
+ id: shape
+
+ antialiasing: true
+
+ ShapePath {
+ fillColor: "transparent"
+ strokeColor: control.enabled ? "#2CDE85" : AppSettings.isDarkTheme ? "#125F46" : "#B8F6D5"
+ strokeWidth: control.shapeWidth
+
+ PathAngleArc {
+ centerX: control.width / 2
+ centerY: control.height / 2
+ radiusX: control.shapeRadius
+ radiusY: control.shapeRadius
+ startAngle: -242
+ sweepAngle: control.angle + 140
+ }
+ }
+ }
+}
diff --git a/examples/demos/thermostat/imports/CustomControls/CustomRadioButton.qml b/examples/demos/thermostat/imports/CustomControls/CustomRadioButton.qml
new file mode 100644
index 000000000..b5266aee3
--- /dev/null
+++ b/examples/demos/thermostat/imports/CustomControls/CustomRadioButton.qml
@@ -0,0 +1,49 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+import QtQuick
+import QtQuick.Controls
+import Thermostat
+
+RadioButton {
+ id: control
+
+ readonly property color indicatorColor: AppSettings.isDarkTheme ? "#D9D9D9" : "#202020"
+ property var indicatorSize
+
+ text: qsTr("Heating")
+ font.family: "Titillium Web"
+ font.pixelSize: 18
+ font.weight: 400
+
+ spacing: 11
+ topPadding: 6
+ bottomPadding: 6
+
+ contentItem: Text {
+ color: control.indicatorColor
+ font: control.font
+ leftPadding: control.indicator.width + control.spacing
+ text: control.text
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ indicator: Rectangle {
+ border.color: control.indicatorColor
+ color: "transparent"
+ implicitHeight: control.indicatorSize
+ implicitWidth: control.indicatorSize
+ radius: control.indicatorSize / 2
+ x: control.leftPadding
+ y: parent.height / 2 - height / 2
+
+ Rectangle {
+ color: control.indicatorColor
+ implicitHeight: parent.implicitHeight / 2
+ implicitWidth: parent.implicitWidth / 2
+ radius: parent.radius / 2
+ visible: control.checked
+ x: parent.implicitWidth / 4
+ y: parent.implicitHeight / 4
+ }
+ }
+}
diff --git a/examples/demos/thermostat/imports/CustomControls/CustomRoundButton.qml b/examples/demos/thermostat/imports/CustomControls/CustomRoundButton.qml
new file mode 100644
index 000000000..315787bce
--- /dev/null
+++ b/examples/demos/thermostat/imports/CustomControls/CustomRoundButton.qml
@@ -0,0 +1,36 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls
+import Thermostat
+
+RoundButton {
+ id: control
+
+ property color contentColor: AppSettings.isDarkTheme ? "#D9D9D9" : "#898989"
+ property color borderColor: AppSettings.isDarkTheme ? "#898989" : "#D9D9D9"
+
+ width: 130
+ height: 63
+ text: qsTr("Button")
+
+ font.pixelSize: 18
+ font.weight: 600
+ font.family: "Titillium Web"
+
+ icon.width: 42
+ icon.height: 42
+ icon.color: (control.checked || control.pressed) && control.enabled ? "#FFFFFF" : control.contentColor
+
+ palette.buttonText: control.pressed ? "#FFFFFF" : control.contentColor
+ display: Constants.isSmallLayout ? AbstractButton.IconOnly : AbstractButton.TextBesideIcon
+ checkable: true
+ radius: 20
+
+ background: Rectangle {
+ color: control.checked || control.down ? "#2CDE85" : "transparent"
+ border.color: control.enabled ? control.contentColor : control.borderColor
+ radius: control.radius
+ }
+}
diff --git a/examples/demos/thermostat/imports/CustomControls/CustomSlider.qml b/examples/demos/thermostat/imports/CustomControls/CustomSlider.qml
new file mode 100644
index 000000000..cad365416
--- /dev/null
+++ b/examples/demos/thermostat/imports/CustomControls/CustomSlider.qml
@@ -0,0 +1,98 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Effects
+import Thermostat
+
+Slider {
+ id: control
+
+ from: 10
+ value: 10
+ to: 30
+
+ snapMode: Slider.SnapAlways
+ stepSize: 1
+
+ readonly property color mainColor: AppSettings.isDarkTheme ? "#2CDE85" : "#00414A"
+ readonly property color backgroundColor: AppSettings.isDarkTheme ? "#D9D9D9" : "#2CDE85"
+
+ background: Rectangle {
+ x: control.leftPadding
+ y: control.topPadding + control.availableHeight / 2 - height / 2
+ implicitWidth: 250
+ implicitHeight: 4
+ width: control.availableWidth
+ height: implicitHeight
+ radius: 2
+ color: control.backgroundColor
+
+ Row {
+ anchors.verticalCenter: parent.verticalCenter
+ width: parent.width
+ height: 2
+ spacing: 24
+ Repeater {
+ model: control.background.implicitWidth / parent.spacing
+ Rectangle {
+ width: 2
+ height: 2
+ color: "#67AC94"
+ }
+ }
+ }
+
+ Rectangle {
+ x: control.handle.x - control.leftPadding - width / 4
+ y: control.handle.y + control.topPadding - height / 2 - height / 4
+ implicitWidth: 40
+ implicitHeight: 40
+ radius: 20
+ color: "#2CDE85"
+ opacity: 0.1
+ visible: control.hovered || control.pressed
+ }
+ }
+
+ handle: Rectangle {
+ x: control.leftPadding + control.visualPosition * (control.availableWidth - width)
+ y: control.topPadding + control.availableHeight / 2 - height / 2
+ implicitWidth: 20
+ implicitHeight: 20
+ radius: 10
+ color: control.mainColor
+ }
+
+ ToolTip {
+ id: toolTip
+
+ parent: control.handle
+ visible: control.pressed
+ width: 32
+ height: 34
+
+ background: Item {
+ width: icon.width
+ height: icon.height
+
+ Image {
+ id: icon
+ source: "images/tooltip.svg"
+ }
+ MultiEffect {
+ anchors.fill: icon
+ source: icon
+ colorization: 1
+ colorizationColor: control.mainColor
+ }
+ }
+
+ contentItem: Text {
+ text: control.value + "°C"
+ horizontalAlignment: Text.AlignHCenter
+ color: "#FFFFFF"
+ }
+ }
+}
diff --git a/examples/demos/thermostat/imports/CustomControls/CustomSwitch.qml b/examples/demos/thermostat/imports/CustomControls/CustomSwitch.qml
new file mode 100644
index 000000000..b5fcc8ae6
--- /dev/null
+++ b/examples/demos/thermostat/imports/CustomControls/CustomSwitch.qml
@@ -0,0 +1,99 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls
+import Thermostat
+
+Switch {
+ id: control
+
+ readonly property color gradientColor1: AppSettings.isDarkTheme ? "#FFFFFF" : "#898989"
+ readonly property color gradientColor2: AppSettings.isDarkTheme ? "#002125" : "#FFFFFF"
+
+ indicator: Rectangle {
+ anchors.right: parent.right
+ implicitWidth: internal.indicatorWidth
+ implicitHeight: internal.indicatorHeight
+ radius: 12
+ border.color: "#898989"
+
+ gradient: Gradient {
+ GradientStop {
+ position: 0.0
+ color: !control.checked ? control.gradientColor1 : "#2CDE85"
+ }
+ GradientStop {
+ position: 1.0
+ color: !control.checked ? control.gradientColor2 : "#2CDE85"
+ }
+ }
+
+ Rectangle {
+ width: 1
+ height: internal.separatorHeight
+ anchors.verticalCenter: parent.verticalCenter
+ x: control.checked ? internal.separatorStartPos : internal.separatorEndPos
+ color: "#898989"
+ }
+
+ Rectangle {
+ id: circle
+
+ anchors.verticalCenter: parent.verticalCenter
+ x: control.checked ? parent.width - width - 2 : 2
+ width: internal.circleSize
+ height: internal.circleSize
+ radius: 10
+ color: "#ffffff"
+ border.color: "#898989"
+
+ Behavior on x {
+ NumberAnimation {
+ duration: 250
+ easing.type: Easing.OutBack
+ }
+ }
+ }
+ }
+
+ QtObject {
+ id: internal
+
+ property int circleSize: 20
+ property int indicatorWidth: 55
+ property int indicatorHeight: 24
+ property int separatorHeight: 9
+ property int separatorStartPos: 20
+ property int separatorEndPos: 35
+ }
+
+ states: [
+ State {
+ name: "desktopLayout"
+ when: Constants.isBigDesktopLayout || Constants.isSmallDesktopLayout
+ PropertyChanges {
+ target: internal
+ circleSize: 20
+ indicatorWidth: 55
+ indicatorHeight: 24
+ separatorStartPos: 20
+ separatorEndPos: 35
+ separatorHeight: 9
+ }
+ },
+ State {
+ name: "smallLayout"
+ when: Constants.isSmallLayout || Constants.isMobileLayout
+ PropertyChanges {
+ target: internal
+ circleSize: 12
+ indicatorWidth: 35
+ indicatorHeight: 15
+ separatorStartPos: 12
+ separatorEndPos: 22
+ separatorHeight: 6
+ }
+ }
+ ]
+}
diff --git a/examples/demos/thermostat/imports/CustomControls/CustomTextField.qml b/examples/demos/thermostat/imports/CustomControls/CustomTextField.qml
new file mode 100644
index 000000000..9405192e2
--- /dev/null
+++ b/examples/demos/thermostat/imports/CustomControls/CustomTextField.qml
@@ -0,0 +1,49 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls
+import Thermostat
+
+TextField {
+ id: control
+
+ width: 135
+ height: 56
+
+ text: "10"
+ font.pixelSize: 24
+ font.weight: 400
+ font.family: "Titillium Web"
+ color: Constants.primaryTextColor
+
+ inputMethodHints: Qt.ImhDigitsOnly
+ validator: IntValidator {
+ bottom: 10
+ top: 30
+ }
+ leftPadding: 15
+
+ background: Rectangle {
+ implicitHeight: control.height
+ implicitWidth: control.width
+ border.color: control.acceptableInput ? Constants.accentTextColor : "red"
+ color: "transparent"
+ radius: 8
+
+ Label {
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.horizontalCenter: parent.horizontalCenter
+ text: "°C"
+ font.pixelSize: 14
+ color: "#898989"
+ }
+
+ Image {
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.right: parent.right
+ anchors.rightMargin: 15
+ source: "images/keyboard.svg"
+ }
+ }
+}
diff --git a/examples/demos/thermostat/imports/CustomControls/StatisticsChart.qml b/examples/demos/thermostat/imports/CustomControls/StatisticsChart.qml
new file mode 100644
index 000000000..7ffb2d44a
--- /dev/null
+++ b/examples/demos/thermostat/imports/CustomControls/StatisticsChart.qml
@@ -0,0 +1,198 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls
+import QtCharts
+import Thermostat
+
+Pane {
+ width: 900
+ height: 580
+
+ padding: 0
+
+ property var energyValuesModel
+ property var tempValuesModel
+
+ property var energyValues: {
+ var enrg = [];
+ for (let i = 0; i < energyValuesModel.count; ++i) {
+ enrg.push(energyValuesModel.get(i).enrg);
+ }
+ return enrg;
+ }
+
+ property var tempValues: {
+ var temp = [];
+ for (let i = 0; i < tempValuesModel.count; ++i) {
+ temp.push(tempValuesModel.get(i).tmp);
+ }
+ return temp;
+ }
+
+ property real maxValue
+ property real minValue
+ property real avgValue
+
+ background: Rectangle {
+ radius: 12
+ color: Constants.accentColor
+ }
+
+ ValuesAxis {
+ id: barChartAxisY
+
+ min: 0
+ max: 2000
+ labelsColor: internal.energyBarColor
+ labelsFont.family: "Titillium Web"
+ labelsFont.pixelSize: internal.axisFontSize
+ }
+
+ ValuesAxis {
+ id: splineChartAxisY
+
+ min: 0
+ max: 40
+ tickAnchor: 5
+ tickInterval: 10
+ tickType: ValuesAxis.TicksDynamic
+ labelsColor: internal.splineChartColor
+ labelsFont.family: "Titillium Web"
+ lineVisible: false
+ labelsFont.pixelSize: internal.axisFontSize
+ }
+
+ ValuesAxis {
+ id: splineChartAxisX
+
+ visible: false
+ min: 0
+ max: 365
+ }
+
+ BarCategoryAxis {
+ id: barChartAxisX
+
+ labelsColor: internal.energyBarColor
+ gridVisible: false
+ labelsFont.family: "Titillium Web"
+ labelsFont.pixelSize: internal.axisFontSize
+ truncateLabels: false
+ categories: [qsTr("Jan"), qsTr("Feb"), qsTr("Mar"), qsTr("Apr"), qsTr("May"), qsTr("Jun"), qsTr("Jul"), qsTr("Aug"), qsTr("Sep"), qsTr("Oct"), qsTr("Nov"), qsTr("Dec")]
+ }
+
+ ChartView {
+ id: chart
+
+ anchors.fill: parent
+ antialiasing: true
+
+ margins.left: 0
+ margins.right: 0
+ margins.top: 0
+ margins.bottom: 0
+
+ legend.alignment: Qt.AlignTop
+ legend.markerShape: Legend.MarkerShapeCircle
+ legend.font.family: "Titillium Web"
+ legend.font.weight: 400
+ legend.font.pixelSize: internal.fontSize
+ legend.labelColor: Constants.primaryTextColor
+
+ dropShadowEnabled: internal.dropShadowEnabled
+ backgroundColor: Constants.accentColor
+
+ BarSeries {
+ id: mySeries
+
+ axisX: barChartAxisX
+ axisY: barChartAxisY
+ barWidth: internal.barWidth
+
+ BarSet {
+ id: energySet
+
+ label: "Energy Usage [wh]"
+ color: internal.energyBarColor
+ borderWidth: 0
+ values: energyValues
+ }
+ }
+
+ SplineSeries {
+ id: spline
+
+ name: "Temperature [°C]"
+ color: internal.splineChartColor
+ width: internal.lineWidth
+
+ axisX: splineChartAxisX
+ axisYRight: splineChartAxisY
+
+ Component.onCompleted: function () {
+ for (var i = 0; i < tempValues.length; i++) {
+ spline.append(i * 7, tempValues[i]);
+ }
+ }
+ }
+ }
+
+ QtObject {
+ id: internal
+
+ property int fontSize: 14
+ property int axisFontSize: 14
+ property int lineWidth: 5
+ property real barWidth: 0.5
+ property bool dropShadowEnabled: true
+ readonly property color energyBarColor: AppSettings.isDarkTheme ? "#2CDE85" : "#00414A"
+ readonly property color splineChartColor: AppSettings.isDarkTheme ? "#D9D9D9" : "#2CDE85"
+ }
+
+ states: [
+ State {
+ name: "desktopLayout"
+ when: Constants.isSmallDesktopLayout || Constants.isBigDesktopLayout
+ PropertyChanges {
+ target: internal
+ fontSize: 14
+ axisFontSize: 14
+ lineWidth: 5
+ barWidth: 0.5
+ dropShadowEnabled: true
+ }
+ },
+ State {
+ name: "mobileLayout"
+ when: Constants.isMobileLayout
+ PropertyChanges {
+ target: internal
+ fontSize: 10
+ axisFontSize: 8
+ lineWidth: 2
+ barWidth: 0.7
+ dropShadowEnabled: false
+ }
+ },
+ State {
+ name: "smallLayout"
+ when: Constants.isSmallLayout
+ PropertyChanges {
+ target: internal
+ fontSize: 8
+ axisFontSize: 10
+ lineWidth: 2
+ barWidth: 0.6
+ dropShadowEnabled: false
+ }
+ }
+ ]
+
+ Component.onCompleted: function () {
+ maxValue = Math.max(...tempValues).toFixed(1);
+ minValue = Math.min(...tempValues).toFixed(1);
+ avgValue = (tempValues.reduce((a, b) => a + b, 0) / tempValues.length).toFixed(1);
+ }
+}
diff --git a/examples/demos/thermostat/imports/CustomControls/TemperatureLabel.qml b/examples/demos/thermostat/imports/CustomControls/TemperatureLabel.qml
new file mode 100644
index 000000000..d0da26b2f
--- /dev/null
+++ b/examples/demos/thermostat/imports/CustomControls/TemperatureLabel.qml
@@ -0,0 +1,95 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Effects
+import Thermostat
+
+Row {
+ id: root
+
+ required property bool isEnabled
+ required property bool isHeating
+
+ property alias tempValue: temp.text
+
+ spacing: internal.rowSpacing
+
+ Label {
+ id: temp
+ text: "24"
+ font.pixelSize: internal.fontSize
+ font.weight: 600
+ font.family: "Titillium Web"
+ color: internal.itemColor
+ }
+
+ Column {
+ anchors.verticalCenter: temp.verticalCenter
+ spacing: internal.columnSpacing
+
+ Label {
+ text: "oC"
+ font.pixelSize: internal.smallFontSize
+ font.weight: 600
+ font.family: "Titillium Web"
+ color: internal.itemColor
+ }
+
+ Item {
+ anchors.horizontalCenter: parent.horizontalCenter
+ height: internal.smallFontSize
+ width: internal.smallFontSize / 2
+
+ Image {
+ id: icon
+ sourceSize.height: internal.smallFontSize
+ source: "images/thermometer.svg"
+ }
+
+ MultiEffect {
+ anchors.fill: icon
+ source: icon
+ colorization: 1
+ colorizationColor: root.isEnabled ? internal.thermometerColor : "#898989"
+ }
+ }
+ }
+
+ QtObject {
+ id: internal
+ property int rowSpacing: 7
+ property int fontSize: 96
+ property int columnSpacing: 20
+ property int smallFontSize: 24
+
+ readonly property color thermometerColor: root.isHeating ? "#D21313" : "#131AD2"
+ readonly property color itemColor: root.isEnabled ? Constants.primaryTextColor : "#898989"
+ }
+
+ states: [
+ State {
+ name: "desktopLayout"
+ when: Constants.isBigDesktopLayout || Constants.isSmallDesktopLayout
+ PropertyChanges {
+ target: internal
+ rowSpacing: 7
+ fontSize: 96
+ columnSpacing: 20
+ smallFontSize: 24
+ }
+ },
+ State {
+ name: "mobileLayout"
+ when: Constants.isMobileLayout || Constants.isSmallLayout
+ PropertyChanges {
+ target: internal
+ rowSpacing: 0
+ fontSize: 56
+ columnSpacing: 12
+ smallFontSize: 14
+ }
+ }
+ ]
+}
diff --git a/examples/demos/thermostat/imports/CustomControls/ThermostatControl.qml b/examples/demos/thermostat/imports/CustomControls/ThermostatControl.qml
new file mode 100644
index 000000000..170f464f5
--- /dev/null
+++ b/examples/demos/thermostat/imports/CustomControls/ThermostatControl.qml
@@ -0,0 +1,204 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+pragma ComponentBehavior: Bound
+
+import QtQuick
+import QtQuick.Controls
+import Thermostat
+
+Pane {
+ id: root
+
+ property alias targetTemp: thermostat.value
+ property int currentTemp: 10
+
+ layer.enabled: true
+ layer.samples: 4
+
+ background: Rectangle {
+ color: "transparent"
+ }
+
+ CustomDial {
+ id: thermostat
+
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ width: internal.thermostatSize
+ height: internal.thermostatSize
+ handleWidth: internal.handleSize
+ handleHeight: internal.handleSize
+ shapeRadius: internal.shapeRadius
+ shapeWidth: internal.shapeWidth
+
+ from: 10
+ to: 30
+ stepSize: 1
+ }
+
+ TemperatureLabel {
+ anchors.centerIn: thermostat
+
+ isEnabled: root.enabled
+ isHeating: thermostat.value > root.currentTemp
+ tempValue: thermostat.value
+ }
+
+ PathView {
+ model: 11
+
+ delegate: Rectangle {
+ required property int index
+ readonly property color activeColor: root.enabled ? "#2CDE85" : "#B8F6D5"
+
+ width: internal.dotSize
+ height: internal.dotSize
+ radius: internal.dotSize / 2
+ color: thermostat.value - (index * 2) >= 10 ? activeColor : "#D9D9D9"
+ }
+
+ path: Path {
+ PathAngleArc {
+ centerX: thermostat.x + thermostat.width / 2
+ centerY: thermostat.y + thermostat.height / 2
+ radiusX: internal.dotsRadius
+ radiusY: internal.dotsRadius
+ startAngle: -240
+ sweepAngle: 330
+ }
+ }
+ }
+
+ PathView {
+ model: ["14°C", "20°C", "26°C"]
+
+ delegate: Label {
+ required property string modelData
+ text: modelData
+ color: AppSettings.isDarkTheme ? "#D9D9D9" : "#898989"
+ font.pixelSize: internal.fontSize
+ font.family: "Titillium Web"
+ }
+
+ path: Path {
+ PathAngleArc {
+ centerX: thermostat.x + thermostat.width / 2
+ centerY: thermostat.y + thermostat.height / 2
+ radiusX: internal.tempRadius
+ radiusY: internal.tempRadius
+ startAngle: -180
+ sweepAngle: 270
+ }
+ }
+ }
+
+ Row {
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.top: thermostat.bottom
+ spacing: internal.rowSpacing
+ palette.highlight: "#2CDE85"
+ palette.button: "#2CDE85"
+
+ RoundButton {
+ width: internal.buttonSize
+ height: internal.buttonSize
+ text: "-"
+
+ onClicked: thermostat.decrease()
+ }
+
+ RoundButton {
+ width: internal.buttonSize
+ height: internal.buttonSize
+ text: "+"
+
+ onClicked: thermostat.increase()
+ }
+ }
+
+ QtObject {
+ id: internal
+
+ property int thermostatSize: 300
+ property int dotsRadius: 172
+ property int shapeRadius: 100
+ property int tempRadius: 228
+ property int shapeWidth: 18
+ property int handleSize: 32
+ property int fontSize: 24
+ property int dotSize: 8
+ property int rowSpacing: 255
+ property int buttonSize: 32
+ }
+
+ states: [
+ State {
+ name: "desktopLayout"
+ when: Constants.isBigDesktopLayout || Constants.isSmallDesktopLayout
+ PropertyChanges {
+ target: root
+ width: 520
+ height: 472
+ }
+ PropertyChanges {
+ target: internal
+ thermostatSize: 300
+ dotsRadius: 172
+ shapeRadius: 103
+ tempRadius: 228
+ shapeWidth: 18
+ handleSize: 32
+ fontSize: 24
+ dotSize: 8
+ rowSpacing: 190
+ buttonSize: 32
+ }
+ },
+ State {
+ name: "mobileLayout"
+ when: Constants.isMobileLayout
+ PropertyChanges {
+ target: root
+ width: 327
+ height: 300
+ }
+ PropertyChanges {
+ target: internal
+ thermostatSize: 175
+ dotsRadius: 100
+ shapeRadius: 60
+ tempRadius: 128
+ shapeWidth: 10
+ handleSize: 18
+ fontSize: 14
+ dotSize: 6
+ rowSpacing: 120
+ buttonSize: 20
+ }
+ },
+ State {
+ name: "smallLayout"
+ when: Constants.isSmallLayout
+ PropertyChanges {
+ target: root
+ width: 250
+ height: 225
+ }
+ PropertyChanges {
+ target: internal
+ thermostatSize: 144
+ dotsRadius: 82
+ shapeRadius: 49
+ tempRadius: 105
+ shapeWidth: 8
+ handleSize: 14
+ fontSize: 10
+ dotSize: 4
+ rowSpacing: 110
+ buttonSize: 20
+ }
+ }
+ ]
+}
diff --git a/examples/demos/thermostat/imports/CustomControls/TimeSelector.qml b/examples/demos/thermostat/imports/CustomControls/TimeSelector.qml
new file mode 100644
index 000000000..5a50ac529
--- /dev/null
+++ b/examples/demos/thermostat/imports/CustomControls/TimeSelector.qml
@@ -0,0 +1,151 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+pragma ComponentBehavior: Bound
+
+import QtQuick
+import QtQuick.Controls
+import Thermostat
+
+Rectangle {
+ id: root
+
+ width: 1010
+ height: 200
+ radius: 12
+
+ gradient: Gradient {
+ GradientStop {
+ position: 0.0
+ color: Constants.backgroundColor
+ }
+ GradientStop {
+ position: 1.0
+ color: "transparent"
+ }
+ }
+
+ Row {
+ anchors.bottom: parent.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ spacing: 0
+
+ Repeater {
+ model: 24
+ Item {
+ id: column
+
+ height: root.height
+ width: internal.itemWidth
+
+ Label {
+ id: hour
+
+ text: index
+ font.pixelSize: internal.hourSize
+ horizontalAlignment: Text.AlignHCenter
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.top: parent.top
+ font.weight: 700
+ font.family: "Titillium Web"
+ color: "#2CDE85"
+ visible: index % 6 == 0 || index === 23
+ }
+
+ CustomRoundButton {
+ id: rec
+
+ height: internal.itemHeight
+ width: internal.itemWidth
+ contentColor: "#2CDE85"
+ text: ""
+ radius: 12
+ anchors.top: parent.top
+ anchors.topMargin: internal.itemTopMargin
+ }
+
+ Label {
+ id: bottomHour
+
+ text: index
+ font.pixelSize: 14
+ horizontalAlignment: Text.AlignHCenter
+ anchors.bottom: parent.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ font.weight: 600
+ font.family: "Titillium Web"
+ color: "#D9D9D9"
+ visible: internal.bottomHourVisibility
+ }
+ }
+ }
+ }
+
+ QtObject {
+ id: internal
+
+ property int hourSize: 24
+ property int itemWidth: 40
+ property int itemHeight: 120
+ property int itemTopMargin: 55
+ property int columnHeight: 165
+ property bool bottomHourVisibility: true
+ }
+
+ states: [
+ State {
+ name: "desktopLayout"
+ when: Constants.isBigDesktopLayout || Constants.isSmallDesktopLayout
+ PropertyChanges {
+ target: root
+ width: 1010
+ height: 200
+ }
+ PropertyChanges {
+ target: internal
+ hourSize: 24
+ itemWidth: 40
+ itemHeight: 120
+ columnHeight: 165
+ bottomHourVisibility: true
+ itemTopMargin: 55
+ }
+ },
+ State {
+ name: "mobileLayout"
+ when: Constants.isMobileLayout
+ PropertyChanges {
+ target: root
+ width: 326
+ height: 150
+ }
+ PropertyChanges {
+ target: internal
+ hourSize: 14
+ itemWidth: 13
+ itemHeight: 110
+ columnHeight: 110
+ bottomHourVisibility: false
+ itemTopMargin: 32
+ }
+ },
+ State {
+ name: "smallLayout"
+ when: Constants.isSmallLayout
+ PropertyChanges {
+ target: root
+ width: 388
+ height: 150
+ }
+ PropertyChanges {
+ target: internal
+ hourSize: 14
+ itemWidth: 16
+ itemHeight: 110
+ columnHeight: 110
+ bottomHourVisibility: false
+ itemTopMargin: 24
+ }
+ }
+ ]
+}
diff --git a/examples/demos/thermostat/imports/CustomControls/images/keyboard.svg b/examples/demos/thermostat/imports/CustomControls/images/keyboard.svg
new file mode 100644
index 000000000..fdc818fbc
--- /dev/null
+++ b/examples/demos/thermostat/imports/CustomControls/images/keyboard.svg
@@ -0,0 +1,3 @@
+<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M15 3.75H3C2.175 3.75 1.5075 4.425 1.5075 5.25L1.5 12.75C1.5 13.575 2.175 14.25 3 14.25H15C15.825 14.25 16.5 13.575 16.5 12.75V5.25C16.5 4.425 15.825 3.75 15 3.75ZM15 5.25V12.75H3V5.25H15ZM9.75 6H8.25V7.5H9.75V6ZM8.25 8.25H9.75V9.75H8.25V8.25ZM7.5 6H6V7.5H7.5V6ZM6 8.25H7.5V9.75H6V8.25ZM5.25 8.25H3.75V9.75H5.25V8.25ZM3.75 6H5.25V7.5H3.75V6ZM12 10.5H6V12H12V10.5ZM10.5 8.25H12V9.75H10.5V8.25ZM12 6H10.5V7.5H12V6ZM12.75 8.25H14.25V9.75H12.75V8.25ZM14.25 6H12.75V7.5H14.25V6Z" fill="#898989"/>
+</svg>
diff --git a/examples/demos/thermostat/imports/CustomControls/images/thermometer.svg b/examples/demos/thermostat/imports/CustomControls/images/thermometer.svg
new file mode 100644
index 000000000..6b36c5e75
--- /dev/null
+++ b/examples/demos/thermostat/imports/CustomControls/images/thermometer.svg
@@ -0,0 +1,3 @@
+<svg width="13" height="24" viewBox="0 0 13 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M11.2258 14.1958V5.03227C11.2258 3.69763 10.6956 2.41765 9.75191 1.47392C8.80818 0.530184 7.5282 0 6.19356 0C4.85892 0 3.57895 0.530184 2.63521 1.47392C1.69148 2.41765 1.1613 3.69763 1.1613 5.03227V14.1958C0.497243 15.1214 0.101292 16.2121 0.016988 17.3481C-0.0673164 18.484 0.163292 19.6213 0.68345 20.6347C1.20361 21.6481 1.99317 22.4984 2.9653 23.0921C3.93742 23.6859 5.05446 24 6.19356 24C7.33266 24 8.4497 23.6859 9.42183 23.0921C10.394 22.4984 11.1835 21.6481 11.7037 20.6347C12.2238 19.6213 12.4544 18.484 12.3701 17.3481C12.2858 16.2121 11.8899 15.1214 11.2258 14.1958ZM6.19356 21.6775C5.46013 21.6775 4.74178 21.4691 4.12218 21.0767C3.50257 20.6843 3.0072 20.1239 2.69376 19.4608C2.38032 18.7977 2.26171 18.0592 2.35173 17.3313C2.44176 16.6035 2.73672 15.9161 3.20227 15.3494C3.38386 15.1387 3.48379 14.8698 3.48388 14.5916V5.03227C3.48388 4.31362 3.76936 3.6244 4.27753 3.11623C4.78569 2.60807 5.47491 2.32259 6.19356 2.32259C6.91222 2.32259 7.60144 2.60807 8.1096 3.11623C8.61776 3.6244 8.90325 4.31362 8.90325 5.03227V14.5907C8.90299 14.8621 8.99784 15.1251 9.17131 15.3339C9.64084 15.8995 9.93963 16.5871 10.0327 17.3162C10.1258 18.0454 10.0094 18.786 9.69704 19.4514C9.38469 20.1168 8.88934 20.6795 8.26891 21.0737C7.64848 21.4679 6.92864 21.6773 6.19356 21.6775ZM8.51615 17.8065C8.51623 18.2142 8.40898 18.6148 8.20518 18.9679C8.00138 19.321 7.70821 19.6143 7.35515 19.8182C7.00208 20.0221 6.60156 20.1295 6.19384 20.1295C5.78612 20.1296 5.38558 20.0223 5.03246 19.8185C4.67935 19.6146 4.38611 19.3214 4.18223 18.9684C3.97834 18.6153 3.871 18.2148 3.87098 17.807C3.87096 17.3993 3.97827 16.9988 4.18212 16.6457C4.38597 16.2926 4.67918 15.9994 5.03227 15.7955V8.51615C5.03227 8.20815 5.15462 7.91277 5.37241 7.69499C5.59019 7.4772 5.88557 7.35485 6.19356 7.35485C6.50156 7.35485 6.79694 7.4772 7.01472 7.69499C7.23251 7.91277 7.35486 8.20815 7.35486 8.51615V15.7955C7.70787 15.9993 8.00102 16.2925 8.20487 16.6454C8.40872 16.9984 8.51607 17.3989 8.51615 17.8065Z" fill="white"/>
+</svg>
diff --git a/examples/demos/thermostat/imports/CustomControls/images/tooltip.svg b/examples/demos/thermostat/imports/CustomControls/images/tooltip.svg
new file mode 100644
index 000000000..6846231f2
--- /dev/null
+++ b/examples/demos/thermostat/imports/CustomControls/images/tooltip.svg
@@ -0,0 +1,3 @@
+<svg width="32" height="34" viewBox="0 0 32 34" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M16 34L4.68629 24.0416C-1.5621 18.5418 -1.5621 9.62475 4.68629 4.12489C10.9347 -1.37496 21.0653 -1.37496 27.3137 4.12489C33.5621 9.62475 33.5621 18.5418 27.3137 24.0416L16 34Z" fill="white"/>
+</svg>
diff --git a/examples/demos/thermostat/imports/CustomControls/qmldir b/examples/demos/thermostat/imports/CustomControls/qmldir
new file mode 100644
index 000000000..bc31f4f21
--- /dev/null
+++ b/examples/demos/thermostat/imports/CustomControls/qmldir
@@ -0,0 +1,14 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+module CustomControls
+CustomSwitch 1.0 CustomSwitch.qml
+CustomComboBox 1.0 CustomComboBox.qml
+StatisticsChart 1.0 StatisticsChart.qml
+ThermostatControl 1.0 ThermostatControl.qml
+TemperatureLabel 1.0 TemperatureLabel.qml
+CustomRoundButton 1.0 CustomRoundButton.qml
+CustomSlider 1.0 CustomSlider.qml
+CustomTextField 1.0 CustomTextField.qml
+TimeSelector 1.0 TimeSelector.qml
+CustomRadioButton 1.0 CustomRadioButton.qml
diff --git a/examples/demos/thermostat/imports/Thermostat/AppSettings.qml b/examples/demos/thermostat/imports/Thermostat/AppSettings.qml
new file mode 100644
index 000000000..83639e53b
--- /dev/null
+++ b/examples/demos/thermostat/imports/Thermostat/AppSettings.qml
@@ -0,0 +1,10 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+pragma Singleton
+import QtQuick
+import QtCore
+
+Settings {
+ property bool isDarkTheme: Qt.styleHints.colorScheme === Qt.Dark
+}
diff --git a/examples/demos/thermostat/imports/Thermostat/CMakeLists.txt b/examples/demos/thermostat/imports/Thermostat/CMakeLists.txt
new file mode 100644
index 000000000..14f2b7007
--- /dev/null
+++ b/examples/demos/thermostat/imports/Thermostat/CMakeLists.txt
@@ -0,0 +1,22 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+set_source_files_properties(Constants.qml
+ PROPERTIES
+ QT_QML_SINGLETON_TYPE true
+)
+
+set_source_files_properties(AppSettings.qml
+ PROPERTIES
+ QT_QML_SINGLETON_TYPE true
+)
+
+qt_add_library(Thermostat STATIC)
+qt_add_qml_module(Thermostat
+ URI "Thermostat"
+ VERSION 1.0
+ QML_FILES
+ AppSettings.qml
+ Constants.qml
+ RoomsModel.qml
+)
diff --git a/examples/demos/thermostat/imports/Thermostat/Constants.qml b/examples/demos/thermostat/imports/Thermostat/Constants.qml
new file mode 100644
index 000000000..658271d61
--- /dev/null
+++ b/examples/demos/thermostat/imports/Thermostat/Constants.qml
@@ -0,0 +1,47 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+pragma Singleton
+import QtQuick
+
+QtObject {
+ readonly property int width: 1440
+ readonly property int height: 1080
+
+ property string currentView: "RoomsView"
+
+ property bool isBigDesktopLayout: true
+ property bool isSmallDesktopLayout: false
+ property bool isMobileLayout: false
+ property bool isSmallLayout: false
+
+ readonly property font smallTitleFont: Qt.font({
+ "family": "Inter",
+ "pixelSize": 14,
+ "weight": 700
+ })
+
+ readonly property font mobileTitleFont: Qt.font({
+ "family": "Titillium Web",
+ "pixelSize": 24,
+ "weight": 600
+ })
+
+ readonly property font desktopTitleFont: Qt.font({
+ "family": "Titillium Web",
+ "pixelSize": 48,
+ "weight": 600
+ })
+
+ readonly property font desktopSubtitleFont: Qt.font({
+ "family": "Titillium Web",
+ "pixelSize": 24,
+ "weight": 600
+ })
+
+ readonly property color backgroundColor: AppSettings.isDarkTheme ? "#000000" : "#EFFCF6"
+ readonly property color accentColor: AppSettings.isDarkTheme ? "#002125" : "#FFFFFF"
+ readonly property color primaryTextColor: AppSettings.isDarkTheme ? "#FFFFFF" : "#000000"
+ readonly property color accentTextColor: AppSettings.isDarkTheme ? "#D9D9D9" : "#898989"
+ readonly property color iconColor: AppSettings.isDarkTheme ? "#D9D9D9" : "#00414A"
+}
diff --git a/examples/demos/thermostat/imports/Thermostat/RoomsModel.qml b/examples/demos/thermostat/imports/Thermostat/RoomsModel.qml
new file mode 100644
index 000000000..f721da4c0
--- /dev/null
+++ b/examples/demos/thermostat/imports/Thermostat/RoomsModel.qml
@@ -0,0 +1,1497 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+ListModel {
+ id: roomsList
+
+ ListElement {
+ name: qsTr("Living Room")
+ floor: qsTr("First floor")
+ iconName: "living_room.svg"
+ mode: "Auto"
+ active: false
+ temp: 24
+ thermostatTemp: 22
+ humidity: 32
+ energy: 12
+ humidityStats: [
+ ListElement {
+ hmd: 60
+ },
+ ListElement {
+ hmd: 55
+ },
+ ListElement {
+ hmd: 50
+ },
+ ListElement {
+ hmd: 40
+ },
+ ListElement {
+ hmd: 45
+ },
+ ListElement {
+ hmd: 35
+ },
+ ListElement {
+ hmd: 30
+ },
+ ListElement {
+ hmd: 50
+ },
+ ListElement {
+ hmd: 60
+ },
+ ListElement {
+ hmd: 50
+ },
+ ListElement {
+ hmd: 55
+ },
+ ListElement {
+ hmd: 60
+ }
+ ]
+ energyStats: [
+ ListElement {
+ enrg: 1200
+ },
+ ListElement {
+ enrg: 1400
+ },
+ ListElement {
+ enrg: 1000
+ },
+ ListElement {
+ enrg: 900
+ },
+ ListElement {
+ enrg: 800
+ },
+ ListElement {
+ enrg: 500
+ },
+ ListElement {
+ enrg: 600
+ },
+ ListElement {
+ enrg: 550
+ },
+ ListElement {
+ enrg: 1200
+ },
+ ListElement {
+ enrg: 1400
+ },
+ ListElement {
+ enrg: 1600
+ },
+ ListElement {
+ enrg: 1000
+ }
+ ]
+ tempStats: [
+ ListElement {
+ tmp: 21.2
+ },
+ ListElement {
+ tmp: 21.5
+ },
+ ListElement {
+ tmp: 21.0
+ },
+ ListElement {
+ tmp: 20.8
+ },
+ ListElement {
+ tmp: 20.5
+ },
+ ListElement {
+ tmp: 20.5
+ },
+ ListElement {
+ tmp: 20.0
+ },
+ ListElement {
+ tmp: 20.8
+ },
+ ListElement {
+ tmp: 21.2
+ },
+ ListElement {
+ tmp: 21.5
+ },
+ ListElement {
+ tmp: 21.9
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 22.2
+ },
+ ListElement {
+ tmp: 22.3
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.8
+ },
+ ListElement {
+ tmp: 23.0
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 22.2
+ },
+ ListElement {
+ tmp: 22.3
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.8
+ },
+ ListElement {
+ tmp: 23.0
+ },
+ ListElement {
+ tmp: 21.0
+ },
+ ListElement {
+ tmp: 21.2
+ },
+ ListElement {
+ tmp: 21.3
+ },
+ ListElement {
+ tmp: 21.5
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.8
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 21.0
+ },
+ ListElement {
+ tmp: 21.2
+ },
+ ListElement {
+ tmp: 21.3
+ },
+ ListElement {
+ tmp: 21.5
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.8
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 19.0
+ },
+ ListElement {
+ tmp: 18.7
+ },
+ ListElement {
+ tmp: 17.5
+ },
+ ListElement {
+ tmp: 20.5
+ },
+ ListElement {
+ tmp: 21.8
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 21.0
+ },
+ ListElement {
+ tmp: 20.5
+ },
+ ListElement {
+ tmp: 21.8
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 23.0
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 23.0
+ },
+ ListElement {
+ tmp: 23.0
+ }
+ ]
+ }
+ ListElement {
+ name: qsTr("Master")
+ floor: qsTr("First floor")
+ iconName: "bedroom.svg"
+ mode: "Auto"
+ active: true
+ temp: 14
+ thermostatTemp: 22
+ humidity: 32
+ energy: 12
+ humidityStats: [
+ ListElement {
+ hmd: 40
+ },
+ ListElement {
+ hmd: 45
+ },
+ ListElement {
+ hmd: 50
+ },
+ ListElement {
+ hmd: 40
+ },
+ ListElement {
+ hmd: 45
+ },
+ ListElement {
+ hmd: 35
+ },
+ ListElement {
+ hmd: 30
+ },
+ ListElement {
+ hmd: 50
+ },
+ ListElement {
+ hmd: 40
+ },
+ ListElement {
+ hmd: 50
+ },
+ ListElement {
+ hmd: 45
+ },
+ ListElement {
+ hmd: 40
+ }
+ ]
+ energyStats: [
+ ListElement {
+ enrg: 800
+ },
+ ListElement {
+ enrg: 1000
+ },
+ ListElement {
+ enrg: 1000
+ },
+ ListElement {
+ enrg: 900
+ },
+ ListElement {
+ enrg: 600
+ },
+ ListElement {
+ enrg: 300
+ },
+ ListElement {
+ enrg: 300
+ },
+ ListElement {
+ enrg: 450
+ },
+ ListElement {
+ enrg: 600
+ },
+ ListElement {
+ enrg: 1200
+ },
+ ListElement {
+ enrg: 1300
+ },
+ ListElement {
+ enrg: 1600
+ }
+ ]
+ tempStats: [
+ ListElement {
+ tmp: 20.0
+ },
+ ListElement {
+ tmp: 20.0
+ },
+ ListElement {
+ tmp: 21.0
+ },
+ ListElement {
+ tmp: 21.8
+ },
+ ListElement {
+ tmp: 21.5
+ },
+ ListElement {
+ tmp: 21.5
+ },
+ ListElement {
+ tmp: 21.0
+ },
+ ListElement {
+ tmp: 20.8
+ },
+ ListElement {
+ tmp: 21.2
+ },
+ ListElement {
+ tmp: 21.5
+ },
+ ListElement {
+ tmp: 21.9
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 22.2
+ },
+ ListElement {
+ tmp: 22.3
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.8
+ },
+ ListElement {
+ tmp: 23.0
+ },
+ ListElement {
+ tmp: 23.4
+ },
+ ListElement {
+ tmp: 24.2
+ },
+ ListElement {
+ tmp: 25.3
+ },
+ ListElement {
+ tmp: 25.5
+ },
+ ListElement {
+ tmp: 24.5
+ },
+ ListElement {
+ tmp: 23.8
+ },
+ ListElement {
+ tmp: 23.0
+ },
+ ListElement {
+ tmp: 20.0
+ },
+ ListElement {
+ tmp: 20.2
+ },
+ ListElement {
+ tmp: 20.3
+ },
+ ListElement {
+ tmp: 20.5
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.8
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 21.0
+ },
+ ListElement {
+ tmp: 21.2
+ },
+ ListElement {
+ tmp: 21.3
+ },
+ ListElement {
+ tmp: 21.5
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.8
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 21.0
+ },
+ ListElement {
+ tmp: 20.7
+ },
+ ListElement {
+ tmp: 17.5
+ },
+ ListElement {
+ tmp: 20.5
+ },
+ ListElement {
+ tmp: 21.8
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 21.0
+ },
+ ListElement {
+ tmp: 20.5
+ },
+ ListElement {
+ tmp: 21.8
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 23.0
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 23.0
+ },
+ ListElement {
+ tmp: 23.0
+ }
+ ]
+ }
+ ListElement {
+ name: qsTr("Kitchen")
+ floor: qsTr("First floor")
+ iconName: "kitchen.svg"
+ mode: "Auto"
+ active: false
+ temp: 24
+ thermostatTemp: 22
+ humidity: 32
+ energy: 12
+ humidityStats: [
+ ListElement {
+ hmd: 60
+ },
+ ListElement {
+ hmd: 55
+ },
+ ListElement {
+ hmd: 50
+ },
+ ListElement {
+ hmd: 40
+ },
+ ListElement {
+ hmd: 45
+ },
+ ListElement {
+ hmd: 35
+ },
+ ListElement {
+ hmd: 30
+ },
+ ListElement {
+ hmd: 50
+ },
+ ListElement {
+ hmd: 60
+ },
+ ListElement {
+ hmd: 50
+ },
+ ListElement {
+ hmd: 55
+ },
+ ListElement {
+ hmd: 60
+ }
+ ]
+ energyStats: [
+ ListElement {
+ enrg: 1700
+ },
+ ListElement {
+ enrg: 1600
+ },
+ ListElement {
+ enrg: 1600
+ },
+ ListElement {
+ enrg: 1400
+ },
+ ListElement {
+ enrg: 1800
+ },
+ ListElement {
+ enrg: 1900
+ },
+ ListElement {
+ enrg: 1300
+ },
+ ListElement {
+ enrg: 1000
+ },
+ ListElement {
+ enrg: 900
+ },
+ ListElement {
+ enrg: 1200
+ },
+ ListElement {
+ enrg: 1300
+ },
+ ListElement {
+ enrg: 1400
+ }
+ ]
+ tempStats: [
+ ListElement {
+ tmp: 21.2
+ },
+ ListElement {
+ tmp: 21.5
+ },
+ ListElement {
+ tmp: 21.0
+ },
+ ListElement {
+ tmp: 20.8
+ },
+ ListElement {
+ tmp: 20.5
+ },
+ ListElement {
+ tmp: 20.5
+ },
+ ListElement {
+ tmp: 20.0
+ },
+ ListElement {
+ tmp: 20.8
+ },
+ ListElement {
+ tmp: 21.2
+ },
+ ListElement {
+ tmp: 21.5
+ },
+ ListElement {
+ tmp: 21.9
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 22.2
+ },
+ ListElement {
+ tmp: 22.3
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.8
+ },
+ ListElement {
+ tmp: 23.0
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 22.2
+ },
+ ListElement {
+ tmp: 22.3
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.8
+ },
+ ListElement {
+ tmp: 23.0
+ },
+ ListElement {
+ tmp: 21.0
+ },
+ ListElement {
+ tmp: 21.2
+ },
+ ListElement {
+ tmp: 21.3
+ },
+ ListElement {
+ tmp: 21.5
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.8
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 21.0
+ },
+ ListElement {
+ tmp: 21.2
+ },
+ ListElement {
+ tmp: 21.3
+ },
+ ListElement {
+ tmp: 21.5
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.8
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 19.0
+ },
+ ListElement {
+ tmp: 18.7
+ },
+ ListElement {
+ tmp: 17.5
+ },
+ ListElement {
+ tmp: 20.5
+ },
+ ListElement {
+ tmp: 21.8
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 21.0
+ },
+ ListElement {
+ tmp: 20.5
+ },
+ ListElement {
+ tmp: 21.8
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 23.0
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 23.0
+ },
+ ListElement {
+ tmp: 23.0
+ }
+ ]
+ }
+ ListElement {
+ name: qsTr("Kid Room")
+ floor: qsTr("First floor")
+ iconName: "kid_room.svg"
+ mode: "Auto"
+ active: false
+ temp: 14
+ thermostatTemp: 22
+ humidity: 32
+ energy: 12
+ humidityStats: [
+ ListElement {
+ hmd: 60
+ },
+ ListElement {
+ hmd: 55
+ },
+ ListElement {
+ hmd: 50
+ },
+ ListElement {
+ hmd: 40
+ },
+ ListElement {
+ hmd: 45
+ },
+ ListElement {
+ hmd: 35
+ },
+ ListElement {
+ hmd: 30
+ },
+ ListElement {
+ hmd: 50
+ },
+ ListElement {
+ hmd: 60
+ },
+ ListElement {
+ hmd: 50
+ },
+ ListElement {
+ hmd: 55
+ },
+ ListElement {
+ hmd: 60
+ }
+ ]
+ energyStats: [
+ ListElement {
+ enrg: 1000
+ },
+ ListElement {
+ enrg: 1000
+ },
+ ListElement {
+ enrg: 1100
+ },
+ ListElement {
+ enrg: 920
+ },
+ ListElement {
+ enrg: 840
+ },
+ ListElement {
+ enrg: 800
+ },
+ ListElement {
+ enrg: 1000
+ },
+ ListElement {
+ enrg: 1100
+ },
+ ListElement {
+ enrg: 1000
+ },
+ ListElement {
+ enrg: 600
+ },
+ ListElement {
+ enrg: 590
+ },
+ ListElement {
+ enrg: 720
+ }
+ ]
+ tempStats: [
+ ListElement {
+ tmp: 21.2
+ },
+ ListElement {
+ tmp: 21.5
+ },
+ ListElement {
+ tmp: 21.0
+ },
+ ListElement {
+ tmp: 20.8
+ },
+ ListElement {
+ tmp: 20.5
+ },
+ ListElement {
+ tmp: 20.5
+ },
+ ListElement {
+ tmp: 20.0
+ },
+ ListElement {
+ tmp: 20.8
+ },
+ ListElement {
+ tmp: 21.2
+ },
+ ListElement {
+ tmp: 21.5
+ },
+ ListElement {
+ tmp: 21.9
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 22.2
+ },
+ ListElement {
+ tmp: 22.3
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.8
+ },
+ ListElement {
+ tmp: 23.0
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 22.2
+ },
+ ListElement {
+ tmp: 22.3
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.8
+ },
+ ListElement {
+ tmp: 23.0
+ },
+ ListElement {
+ tmp: 21.0
+ },
+ ListElement {
+ tmp: 21.2
+ },
+ ListElement {
+ tmp: 21.3
+ },
+ ListElement {
+ tmp: 21.5
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.8
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 21.0
+ },
+ ListElement {
+ tmp: 21.2
+ },
+ ListElement {
+ tmp: 21.3
+ },
+ ListElement {
+ tmp: 21.5
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.8
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 19.0
+ },
+ ListElement {
+ tmp: 18.7
+ },
+ ListElement {
+ tmp: 17.5
+ },
+ ListElement {
+ tmp: 20.5
+ },
+ ListElement {
+ tmp: 21.8
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 21.0
+ },
+ ListElement {
+ tmp: 20.5
+ },
+ ListElement {
+ tmp: 21.8
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 23.0
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 23.0
+ },
+ ListElement {
+ tmp: 23.0
+ }
+ ]
+ }
+ ListElement {
+ name: qsTr("Kid Room2")
+ floor: qsTr("First floor")
+ iconName: "kid_room.svg"
+ mode: "Auto"
+ active: false
+ temp: 22
+ thermostatTemp: 22
+ humidity: 32
+ energy: 12
+ humidityStats: [
+ ListElement {
+ hmd: 60
+ },
+ ListElement {
+ hmd: 55
+ },
+ ListElement {
+ hmd: 50
+ },
+ ListElement {
+ hmd: 40
+ },
+ ListElement {
+ hmd: 45
+ },
+ ListElement {
+ hmd: 35
+ },
+ ListElement {
+ hmd: 30
+ },
+ ListElement {
+ hmd: 50
+ },
+ ListElement {
+ hmd: 60
+ },
+ ListElement {
+ hmd: 50
+ },
+ ListElement {
+ hmd: 55
+ },
+ ListElement {
+ hmd: 60
+ }
+ ]
+ energyStats: [
+ ListElement {
+ enrg: 900
+ },
+ ListElement {
+ enrg: 800
+ },
+ ListElement {
+ enrg: 1000
+ },
+ ListElement {
+ enrg: 900
+ },
+ ListElement {
+ enrg: 900
+ },
+ ListElement {
+ enrg: 1000
+ },
+ ListElement {
+ enrg: 1100
+ },
+ ListElement {
+ enrg: 1200
+ },
+ ListElement {
+ enrg: 1300
+ },
+ ListElement {
+ enrg: 800
+ },
+ ListElement {
+ enrg: 700
+ },
+ ListElement {
+ enrg: 720
+ }
+ ]
+ tempStats: [
+ ListElement {
+ tmp: 21.2
+ },
+ ListElement {
+ tmp: 21.5
+ },
+ ListElement {
+ tmp: 21.0
+ },
+ ListElement {
+ tmp: 20.8
+ },
+ ListElement {
+ tmp: 20.5
+ },
+ ListElement {
+ tmp: 20.5
+ },
+ ListElement {
+ tmp: 20.0
+ },
+ ListElement {
+ tmp: 20.8
+ },
+ ListElement {
+ tmp: 21.2
+ },
+ ListElement {
+ tmp: 21.5
+ },
+ ListElement {
+ tmp: 21.9
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 22.2
+ },
+ ListElement {
+ tmp: 22.3
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.8
+ },
+ ListElement {
+ tmp: 23.0
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 22.2
+ },
+ ListElement {
+ tmp: 22.3
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.8
+ },
+ ListElement {
+ tmp: 23.0
+ },
+ ListElement {
+ tmp: 21.0
+ },
+ ListElement {
+ tmp: 21.2
+ },
+ ListElement {
+ tmp: 21.3
+ },
+ ListElement {
+ tmp: 21.5
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.8
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 21.0
+ },
+ ListElement {
+ tmp: 21.2
+ },
+ ListElement {
+ tmp: 21.3
+ },
+ ListElement {
+ tmp: 21.5
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.8
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 19.0
+ },
+ ListElement {
+ tmp: 18.7
+ },
+ ListElement {
+ tmp: 17.5
+ },
+ ListElement {
+ tmp: 20.5
+ },
+ ListElement {
+ tmp: 21.8
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 21.0
+ },
+ ListElement {
+ tmp: 20.5
+ },
+ ListElement {
+ tmp: 21.8
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 23.0
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 23.0
+ },
+ ListElement {
+ tmp: 23.0
+ }
+ ]
+ }
+ ListElement {
+ name: qsTr("Bedroom")
+ floor: qsTr("First floor")
+ iconName: "bedroom.svg"
+ mode: "Auto"
+ active: false
+ temp: 21
+ thermostatTemp: 22
+ humidity: 32
+ energy: 12
+ humidityStats: [
+ ListElement {
+ hmd: 60
+ },
+ ListElement {
+ hmd: 55
+ },
+ ListElement {
+ hmd: 50
+ },
+ ListElement {
+ hmd: 40
+ },
+ ListElement {
+ hmd: 45
+ },
+ ListElement {
+ hmd: 35
+ },
+ ListElement {
+ hmd: 30
+ },
+ ListElement {
+ hmd: 50
+ },
+ ListElement {
+ hmd: 60
+ },
+ ListElement {
+ hmd: 50
+ },
+ ListElement {
+ hmd: 55
+ },
+ ListElement {
+ hmd: 60
+ }
+ ]
+ energyStats: [
+ ListElement {
+ enrg: 400
+ },
+ ListElement {
+ enrg: 500
+ },
+ ListElement {
+ enrg: 400
+ },
+ ListElement {
+ enrg: 400
+ },
+ ListElement {
+ enrg: 450
+ },
+ ListElement {
+ enrg: 500
+ },
+ ListElement {
+ enrg: 600
+ },
+ ListElement {
+ enrg: 550
+ },
+ ListElement {
+ enrg: 700
+ },
+ ListElement {
+ enrg: 720
+ },
+ ListElement {
+ enrg: 780
+ },
+ ListElement {
+ enrg: 750
+ }
+ ]
+ tempStats: [
+ ListElement {
+ tmp: 21.2
+ },
+ ListElement {
+ tmp: 21.5
+ },
+ ListElement {
+ tmp: 21.0
+ },
+ ListElement {
+ tmp: 20.8
+ },
+ ListElement {
+ tmp: 20.5
+ },
+ ListElement {
+ tmp: 20.5
+ },
+ ListElement {
+ tmp: 20.0
+ },
+ ListElement {
+ tmp: 20.8
+ },
+ ListElement {
+ tmp: 21.2
+ },
+ ListElement {
+ tmp: 21.5
+ },
+ ListElement {
+ tmp: 21.9
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 22.2
+ },
+ ListElement {
+ tmp: 22.3
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.8
+ },
+ ListElement {
+ tmp: 23.0
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 22.2
+ },
+ ListElement {
+ tmp: 22.3
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.8
+ },
+ ListElement {
+ tmp: 23.0
+ },
+ ListElement {
+ tmp: 21.0
+ },
+ ListElement {
+ tmp: 21.2
+ },
+ ListElement {
+ tmp: 21.3
+ },
+ ListElement {
+ tmp: 21.5
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.8
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 21.0
+ },
+ ListElement {
+ tmp: 21.2
+ },
+ ListElement {
+ tmp: 21.3
+ },
+ ListElement {
+ tmp: 21.5
+ },
+ ListElement {
+ tmp: 22.5
+ },
+ ListElement {
+ tmp: 22.8
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 19.0
+ },
+ ListElement {
+ tmp: 18.7
+ },
+ ListElement {
+ tmp: 17.5
+ },
+ ListElement {
+ tmp: 20.5
+ },
+ ListElement {
+ tmp: 21.8
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 21.0
+ },
+ ListElement {
+ tmp: 20.5
+ },
+ ListElement {
+ tmp: 21.8
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 23.0
+ },
+ ListElement {
+ tmp: 22.0
+ },
+ ListElement {
+ tmp: 23.0
+ },
+ ListElement {
+ tmp: 23.0
+ }
+ ]
+ }
+}
diff --git a/examples/demos/thermostat/imports/Thermostat/qmldir b/examples/demos/thermostat/imports/Thermostat/qmldir
new file mode 100644
index 000000000..1bc7146af
--- /dev/null
+++ b/examples/demos/thermostat/imports/Thermostat/qmldir
@@ -0,0 +1,8 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+module Thermostat
+singleton Constants 1.0 Constants.qml
+singleton AppSettings 1.0 AppSettings.qml
+RoomsModel 1.0 RoomsModel.qml
+
diff --git a/examples/demos/thermostat/qmlcomponents b/examples/demos/thermostat/qmlcomponents
new file mode 100644
index 000000000..79b6b9ef2
--- /dev/null
+++ b/examples/demos/thermostat/qmlcomponents
@@ -0,0 +1,33 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+message("Building designer components.")
+
+set(QT_QML_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/qml")
+
+include(FetchContent)
+FetchContent_Declare(
+ ds
+ GIT_TAG qds-4.1
+ GIT_REPOSITORY https://code.qt.io/qt-labs/qtquickdesigner-components.git
+)
+
+FetchContent_GetProperties(ds)
+FetchContent_Populate(ds)
+
+target_link_libraries(ThermostatApp PRIVATE
+ QuickStudioComponentsplugin
+ QuickStudioEffectsplugin
+ QuickStudioApplicationplugin
+ FlowViewplugin
+ QuickStudioLogicHelperplugin
+ QuickStudioMultiTextplugin
+ QuickStudioEventSimulatorplugin
+ QuickStudioEventSystemplugin
+)
+
+add_subdirectory(${ds_SOURCE_DIR} ${ds_BINARY_DIR})
+
+target_compile_definitions(ThermostatApp PRIVATE
+ BULD_QDS_COMPONENTS=true
+)
diff --git a/examples/demos/thermostat/qmlmodules b/examples/demos/thermostat/qmlmodules
new file mode 100644
index 000000000..d9aa59bf2
--- /dev/null
+++ b/examples/demos/thermostat/qmlmodules
@@ -0,0 +1,18 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+qt_add_qml_module(ThermostatApp
+ URI "Main"
+ VERSION 1.0
+ NO_PLUGIN
+ QML_FILES Main.qml
+)
+
+add_subdirectory(content)
+add_subdirectory(imports)
+
+target_link_libraries(ThermostatApp PRIVATE
+ contentplugin
+ CustomControlsplugin
+ Thermostatplugin
+)
diff --git a/examples/demos/thermostat/qt_attribution.json b/examples/demos/thermostat/qt_attribution.json
new file mode 100644
index 000000000..10c4d6152
--- /dev/null
+++ b/examples/demos/thermostat/qt_attribution.json
@@ -0,0 +1,55 @@
+[{
+ "Id": "thermostatexample-phosphoricons",
+ "Name": "Phosphor Icons",
+ "QDocModule": "qtdoc",
+ "QtUsage": "Used in the Thermostat example.",
+ "QtParts": [ "examples" ],
+ "Files": [
+ "content/images/Auto.svg",
+ "content/images/stats.svg",
+ "content/images/settings.svg",
+ "content/images/schedule.svg",
+ "content/images/thermostat.svg",
+ "content/images/Cool.svg",
+ "content/images/Heat.svg",
+ "content/images/Dry.svg",
+ "content/images/Fan.svg",
+ "content/images/Eco.svg",
+ "content/images/energy.svg",
+ "content/images/drop.svg",
+ "content/images/power.svg",
+ "content/images/temperature.svg",
+ "content/images/up.svg",
+ "content/images/down.svg",
+ "content/images/edit.svg",
+ "content/images/minTemp.svg",
+ "content/images/maxTemp.svg",
+ "content/images/more.svg",
+ "imports/CustomControls/images/thermometer.svg"
+ ],
+ "Homepage": "https://phosphoricons.com",
+ "LicenseId": "CC-BY-4.0",
+ "License": "Creative Commons Attribution 4.0 International",
+ "Copyright": "© Phosphor Icons"
+},
+{
+ "Id": "thermostatexample-materialicons",
+ "Name": "Google Material Icons",
+ "QDocModule": "qtdoc",
+ "QtUsage": "Used in the Thermostat example.",
+ "QtParts": [ "examples" ],
+ "Files": [
+ "content/images/kitchen.svg",
+ "content/images/bedroom.svg",
+ "content/images/kid_room.svg",
+ "content/images/living_room.svg",
+ "content/images/home.svg",
+ "content/images/arrow.svg",
+ "content/images/theme.svg",
+ "imports/CustomControls/images/keyboard.svg"
+ ],
+ "Homepage": "https://fonts.google.com/icons",
+ "LicenseId": "Apache-2.0",
+ "License": "Apache License 2.0",
+ "Copyright": "© Google"
+}]
diff --git a/examples/demos/thermostat/qtquickcontrols2.conf b/examples/demos/thermostat/qtquickcontrols2.conf
new file mode 100644
index 000000000..db9486764
--- /dev/null
+++ b/examples/demos/thermostat/qtquickcontrols2.conf
@@ -0,0 +1,2 @@
+[Controls]
+Style=Basic
diff --git a/examples/demos/thermostat/src/app_environment.h b/examples/demos/thermostat/src/app_environment.h
new file mode 100644
index 000000000..a20d91907
--- /dev/null
+++ b/examples/demos/thermostat/src/app_environment.h
@@ -0,0 +1,11 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QGuiApplication>
+
+void set_qt_environment()
+{
+ qputenv("QML_COMPAT_RESOLVE_URLS_ON_ASSIGNMENT", "1");
+ qputenv("QT_QUICK_CONTROLS_CONF", ":/qtquickcontrols2.conf");
+
+}
diff --git a/examples/demos/thermostat/src/import_qml_components_plugins.h b/examples/demos/thermostat/src/import_qml_components_plugins.h
new file mode 100644
index 000000000..ada144aff
--- /dev/null
+++ b/examples/demos/thermostat/src/import_qml_components_plugins.h
@@ -0,0 +1,17 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "qqmlextensionplugin.h"
+
+#ifdef BULD_QDS_COMPONENTS
+
+Q_IMPORT_QML_PLUGIN(QtQuick_Studio_ComponentsPlugin)
+Q_IMPORT_QML_PLUGIN(QtQuick_Studio_EffectsPlugin)
+Q_IMPORT_QML_PLUGIN(QtQuick_Studio_ApplicationPlugin)
+Q_IMPORT_QML_PLUGIN(FlowViewPlugin)
+Q_IMPORT_QML_PLUGIN(QtQuick_Studio_LogicHelperPlugin)
+Q_IMPORT_QML_PLUGIN(QtQuick_Studio_MultiTextPlugin)
+Q_IMPORT_QML_PLUGIN(QtQuick_Studio_EventSimulatorPlugin)
+Q_IMPORT_QML_PLUGIN(QtQuick_Studio_EventSystemPlugin)
+
+#endif
diff --git a/examples/demos/thermostat/src/import_qml_plugins.h b/examples/demos/thermostat/src/import_qml_plugins.h
new file mode 100644
index 000000000..aa78e5e2f
--- /dev/null
+++ b/examples/demos/thermostat/src/import_qml_plugins.h
@@ -0,0 +1,9 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QtQml/qqmlextensionplugin.h>
+
+Q_IMPORT_QML_PLUGIN(contentPlugin)
+Q_IMPORT_QML_PLUGIN(CustomControlsPlugin)
+Q_IMPORT_QML_PLUGIN(ThermostatPlugin)
+
diff --git a/examples/demos/thermostat/src/main.cpp b/examples/demos/thermostat/src/main.cpp
new file mode 100644
index 000000000..680ec306b
--- /dev/null
+++ b/examples/demos/thermostat/src/main.cpp
@@ -0,0 +1,24 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QApplication>
+#include <QQmlApplicationEngine>
+#include <QSettings>
+
+#include "app_environment.h"
+#include "import_qml_plugins.h"
+
+int main(int argc, char *argv[])
+{
+ set_qt_environment();
+ QApplication app(argc, argv);
+ QApplication::setApplicationName("ThermostatApp");
+ QApplication::setOrganizationName("QtProject");
+ QSettings settings;
+
+ QQmlApplicationEngine engine;
+ QObject::connect(&engine, &QQmlApplicationEngine::quit, &app, &QGuiApplication::quit);
+ engine.loadFromModule("Main", "Main");
+
+ return app.exec();
+}