diff --git a/nymea-app/stylecontroller.cpp b/nymea-app/stylecontroller.cpp index 7c64363d..eac65c3d 100644 --- a/nymea-app/stylecontroller.cpp +++ b/nymea-app/stylecontroller.cpp @@ -43,3 +43,25 @@ QStringList StyleController::allStyles() const // qDebug() << "styles:" << dir.entryList(); return dir.entryList(QDir::Dirs); } + +QString StyleController::currentExperience() const +{ + QSettings settings; + return settings.value("experience", "Default").toString(); +} + +void StyleController::setCurrentExperience(const QString ¤tExperience) +{ + QSettings settings; + if (settings.value("experience").toString() != currentExperience) { + settings.setValue("experience", currentExperience); + emit currentExperienceChanged(); + } +} + +QStringList StyleController::allExperiences() const +{ + QDir dir(":/ui/experiences"); + qDebug() << "experiences:" << dir.entryList(); + return QStringList() << "Default" << dir.entryList(); +} diff --git a/nymea-app/stylecontroller.h b/nymea-app/stylecontroller.h index 4c34ae36..524b59b0 100644 --- a/nymea-app/stylecontroller.h +++ b/nymea-app/stylecontroller.h @@ -9,6 +9,9 @@ class StyleController : public QObject Q_PROPERTY(QString currentStyle READ currentStyle WRITE setCurrentStyle NOTIFY currentStyleChanged) Q_PROPERTY(QStringList allStyles READ allStyles CONSTANT) + Q_PROPERTY(QString currentExperience READ currentExperience WRITE setCurrentExperience NOTIFY currentExperienceChanged) + Q_PROPERTY(QStringList allExperiences READ allExperiences CONSTANT) + public: explicit StyleController(QObject *parent = nullptr); @@ -17,8 +20,14 @@ public: QStringList allStyles() const; + QString currentExperience() const; + void setCurrentExperience(const QString ¤tExperience); + + QStringList allExperiences() const; + signals: void currentStyleChanged(); + void currentExperienceChanged(); }; diff --git a/nymea-app/ui/MainPage.qml b/nymea-app/ui/MainPage.qml index 67ac3851..2a626d12 100644 --- a/nymea-app/ui/MainPage.qml +++ b/nymea-app/ui/MainPage.qml @@ -31,6 +31,34 @@ Page { property bool swipeViewReady: false property bool tabsReady: false + // FIXME: All this can go away when we require Controls 2.3 (Qt 5.10) or greater as TabBar got a major rework there. + // Ideally we'd just list the 3 items and set visible to false if the server version isn't good enough but TabBar + // has troubles dealing with that. For now, let's manually fill it and use a timer to initialize the currentIndex. + Component.onCompleted: { + // Fill SwipeView (The 2 static views things and scenes will already be there). + if (engine.jsonRpcClient.ensureServerVersion(1.6)) { + swipeView.insertItem(0, favoritesViewComponent.createObject(swipeView)) + } + var experienceView = null; + if (styleController.currentExperience != "Default") { + experienceView = experienceViewComponent.createObject(swipeView, {source: "experiences/" + styleController.currentExperience + "/Main.qml" }); + swipeView.insertItem(0, experienceView) + } + root.swipeViewReady = true; + + + var pi = 0; + if (experienceView) { + tabEntryComponent.createObject(tabBar, {text: experienceView.title, iconSource: experienceView.icon, pageIndex: pi++}) + } + if (engine.jsonRpcClient.ensureServerVersion(1.6)) { + tabEntryComponent.createObject(tabBar, {text: qsTr("Favorites"), iconSource: "../images/starred.svg", pageIndex: pi++}) + } + tabEntryComponent.createObject(tabBar, {text: qsTr("Things"), iconSource: "../images/share.svg", pageIndex: pi++}) + tabEntryComponent.createObject(tabBar, {text: qsTr("Scenes"), iconSource: "../images/slideshow.svg", pageIndex: pi++}) + root.tabsReady = true + } + readonly property bool viewReady: swipeViewReady && tabsReady onViewReadyChanged: { if (tabSettings.currentMainViewIndex > swipeView.count) { @@ -90,13 +118,6 @@ Page { anchors.rightMargin: anchors.leftMargin currentIndex: root.currentViewIndex - Component.onCompleted: { - if (engine.jsonRpcClient.ensureServerVersion(1.6)) { - swipeView.insertItem(0, favoritesViewComponent.createObject(swipeView)) - } - swipeView.insertItem(0, experienceViewComponent.createObject(swipeView)) - root.swipeViewReady = true; - } onCurrentIndexChanged: { root.currentViewIndex = currentIndex } @@ -106,8 +127,9 @@ Page { Loader { width: swipeView.width height: swipeView.height - source: "experiences/garagegates/Main.qml" clip: true + readonly property string title: item ? item.title : "" + readonly property string icon: item ? item.icon : "" } } @@ -217,21 +239,6 @@ Page { ((systemProductType === "ios" && Screen.height === 375) ? -10 : -20) : (systemProductType === "ios" && Screen.height === 812) ? 14 : 0) - - // FIXME: All this can go away when we require Controls 2.3 (Qt 5.10) or greater as TabBar got a major rework there. - // Ideally we'd just list the 3 items and set visible to false if the server version isn't good enough but TabBar - // has troubles dealing with that. For now, let's manually fill it and use a timer to initialize the currentIndex. - Component.onCompleted: { - var pi = 0; - tabEntryComponent.createObject(tabBar, {text: qsTr("UX"), iconSource: "../images/starred.svg", pageIndex: pi++}) - if (engine.jsonRpcClient.ensureServerVersion(1.6)) { - tabEntryComponent.createObject(tabBar, {text: qsTr("Favorites"), iconSource: "../images/starred.svg", pageIndex: pi++}) - } - tabEntryComponent.createObject(tabBar, {text: qsTr("Things"), iconSource: "../images/share.svg", pageIndex: pi++}) - tabEntryComponent.createObject(tabBar, {text: qsTr("Scenes"), iconSource: "../images/slideshow.svg", pageIndex: pi++}) - root.tabsReady = true - } - Component { id: tabEntryComponent MainPageTabButton { diff --git a/nymea-app/ui/appsettings/DeveloperOptionsPage.qml b/nymea-app/ui/appsettings/DeveloperOptionsPage.qml index 0c5eb735..a4d5bb2b 100644 --- a/nymea-app/ui/appsettings/DeveloperOptionsPage.qml +++ b/nymea-app/ui/appsettings/DeveloperOptionsPage.qml @@ -46,6 +46,23 @@ Page { onClicked: pageStack.push(appLogComponent) enabled: AppLogController.enabled } + + RowLayout { + Layout.leftMargin: app.margins; Layout.rightMargin: app.margins + + Label { + Layout.fillWidth: true + text: qsTr("Experience mode") + } + + ComboBox { + currentIndex: model.indexOf(styleController.currentExperience) + model: styleController.allExperiences + onActivated: { + styleController.currentExperience = model[index] + } + } + } } Component { diff --git a/nymea-app/ui/components/ShutterControls.qml b/nymea-app/ui/components/ShutterControls.qml index c6410597..bb62ac7d 100644 --- a/nymea-app/ui/components/ShutterControls.qml +++ b/nymea-app/ui/components/ShutterControls.qml @@ -6,7 +6,7 @@ import Nymea 1.0 RowLayout { id: root - spacing: (parent.width - app.iconSize*2*children.length) / children.length + spacing: (parent.width - app.iconSize*2*children.length) / (children.length - 1) // implicitWidth: app.iconSize * 2 * children.length + spacing * (children.length - 1) implicitWidth: childrenRect.width diff --git a/nymea-app/ui/experiences/garagegates/Main.qml b/nymea-app/ui/experiences/garagegates/Main.qml index 5527106f..73b62137 100644 --- a/nymea-app/ui/experiences/garagegates/Main.qml +++ b/nymea-app/ui/experiences/garagegates/Main.qml @@ -5,6 +5,9 @@ import "qrc:/ui/components" import Nymea 1.0 Item { + id: root + readonly property string title: qsTr("Garage gates") + readonly property string icon: Qt.resolvedUrl("qrc:/ui/images/shutter/shutter-050.svg") DevicesProxy { id: garagesFilterModel @@ -12,6 +15,15 @@ Item { shownInterfaces: ["garagegate"] } + EmptyViewPlaceholder { + anchors.centerIn: parent + width: parent.width - app.margins * 2 + text: qsTr("There are no garage gates set up yet.") + imageSource: "qrc:/ui/images/shutter/shutter-050.svg" + buttonText: qsTr("Set up now") + visible: garagesFilterModel.count === 0 + } + SwipeView { id: swipeView anchors.fill: parent @@ -32,35 +44,54 @@ Item { readonly property StateType intermediatePositionStateType: device.deviceClass.stateTypes.findByName("intermediatePosition") readonly property State intermediatePositionState: intermediatePositionStateType ? device.states.getState(intermediatePositionStateType.id) : null - ColumnLayout { + GridLayout { + id: layout anchors.fill: parent anchors.margins: app.margins + columns: app.landscape ? 2 : 1 Label { + id: label text: garageGateView.device.name font.pixelSize: app.largeFont - Layout.fillWidth: true + Layout.preferredWidth: layout.width + Layout.columnSpan: parent.columns horizontalAlignment: Text.AlignHCenter } - ColorIcon { - name: "qrc:/ui/images/shutter/shutter-" + currentImage + ".svg" + Item { + Layout.fillHeight: true Layout.fillWidth: true - Layout.preferredHeight: width - - property string currentImage: garageGateView.openState.value === "closed" ? "100" : - garageGateView.openState.value === "open" && garageGateView.intermediatePositionState.value === false ? "000" : "050" + Layout.minimumWidth: app.landscape ? layout.width / 2 : layout.width + ColorIcon { + height: Math.min(parent.height, parent.width) + width: height + anchors.centerIn: parent + name: "qrc:/ui/images/shutter/shutter-" + currentImage + ".svg" + property string currentImage: garageGateView.openState.value === "closed" ? "100" : + garageGateView.openState.value === "open" && garageGateView.intermediatePositionState.value === false ? "000" : "050" + } } - ShutterControls { - id: controls + Item { Layout.fillWidth: true - anchors.horizontalCenter: parent.horizontalCenter - device: garageGateView.device + Layout.preferredHeight: controls.implicitHeight + Layout.minimumWidth: app.landscape ? layout.width / 2 : layout.width + + ShutterControls { + id: controls + device: garageGateView.device + } } } } } } + + PageIndicator { + anchors { bottom: parent.bottom; horizontalCenter: parent.horizontalCenter } + count: garagesFilterModel.count + currentIndex: swipeView.currentIndex + } }