From db64033d56c07fcc4af6250828838708722f9011 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Wed, 22 Jun 2022 17:11:48 +0200 Subject: [PATCH] Rework bottom panel --- nymea-app/main.cpp | 1 + nymea-app/styles.qrc | 6 + nymea-app/styles/dark/Background.qml | 5 + nymea-app/styles/dark/Page.qml | 5 +- nymea-app/styles/energize/Background.qml | 8 + nymea-app/styles/energize/Page.qml | 8 +- nymea-app/styles/light/Background.qml | 5 + nymea-app/styles/light/Page.qml | 5 +- nymea-app/styles/lime/Background.qml | 5 + nymea-app/styles/lime/Page.qml | 5 +- nymea-app/styles/mellow/Background.qml | 5 + nymea-app/styles/mellow/Page.qml | 5 +- nymea-app/styles/noir/Background.qml | 5 + nymea-app/styles/noir/Page.qml | 4 +- nymea-app/ui/MainPage.qml | 573 ++++++++++++------ nymea-app/ui/components/MainPageTabButton.qml | 6 +- nymea-app/ui/components/MainViewBase.qml | 5 + nymea-app/ui/mainviews/EnergyView.qml | 1 + nymea-app/ui/mainviews/FavoritesView.qml | 2 + nymea-app/ui/mainviews/GaragesView.qml | 2 +- nymea-app/ui/mainviews/GroupsView.qml | 1 + nymea-app/ui/mainviews/MediaView.qml | 3 +- nymea-app/ui/mainviews/ScenesView.qml | 1 + nymea-app/ui/mainviews/ThingsView.qml | 1 + .../ui/mainviews/dashboard/Dashboard.qml | 5 +- 25 files changed, 439 insertions(+), 233 deletions(-) create mode 100644 nymea-app/styles/dark/Background.qml create mode 100644 nymea-app/styles/energize/Background.qml create mode 100644 nymea-app/styles/light/Background.qml create mode 100644 nymea-app/styles/lime/Background.qml create mode 100644 nymea-app/styles/mellow/Background.qml create mode 100644 nymea-app/styles/noir/Background.qml diff --git a/nymea-app/main.cpp b/nymea-app/main.cpp index 7e009a31..86f2b3c0 100644 --- a/nymea-app/main.cpp +++ b/nymea-app/main.cpp @@ -157,6 +157,7 @@ int main(int argc, char *argv[]) } qmlRegisterSingletonType(QUrl("qrc:///styles/" + styleController.currentStyle() + "/Style.qml"), "Nymea", 1, 0, "Style" ); + qmlRegisterType(QUrl("qrc:///styles/" + styleController.currentStyle() + "/Background.qml"), "Nymea", 1, 0, "Background" ); qmlRegisterSingletonType(QUrl("qrc:///ui/Configuration.qml"), "Nymea", 1, 0, "Configuration"); engine->rootContext()->setContextProperty("styleController", &styleController); diff --git a/nymea-app/styles.qrc b/nymea-app/styles.qrc index fa2a73c6..4fa9cbde 100644 --- a/nymea-app/styles.qrc +++ b/nymea-app/styles.qrc @@ -39,5 +39,11 @@ ui/Configuration.qml styles/dark/Dialog.qml styles/light/Dialog.qml + styles/dark/Background.qml + styles/light/Background.qml + styles/energize/Background.qml + styles/lime/Background.qml + styles/mellow/Background.qml + styles/noir/Background.qml diff --git a/nymea-app/styles/dark/Background.qml b/nymea-app/styles/dark/Background.qml new file mode 100644 index 00000000..64d39bee --- /dev/null +++ b/nymea-app/styles/dark/Background.qml @@ -0,0 +1,5 @@ +import QtQuick 2.0 + +Rectangle { + color: Style.backgroundColor +} diff --git a/nymea-app/styles/dark/Page.qml b/nymea-app/styles/dark/Page.qml index aa70bdf8..9255efa4 100644 --- a/nymea-app/styles/dark/Page.qml +++ b/nymea-app/styles/dark/Page.qml @@ -33,8 +33,5 @@ import QtQuick.Templates 2.2 import QtQuick.Controls.Material 2.2 Page { - - background: Rectangle { - color: Material.background - } + background: Background {} } diff --git a/nymea-app/styles/energize/Background.qml b/nymea-app/styles/energize/Background.qml new file mode 100644 index 00000000..ebe3d4fb --- /dev/null +++ b/nymea-app/styles/energize/Background.qml @@ -0,0 +1,8 @@ +import QtQuick 2.0 + +Rectangle { + gradient: Gradient { + GradientStop { position: 0.0; color: "#e3eae4" } + GradientStop { position: 1.0; color: "#cde2d8" } + } +} diff --git a/nymea-app/styles/energize/Page.qml b/nymea-app/styles/energize/Page.qml index 683758c2..9255efa4 100644 --- a/nymea-app/styles/energize/Page.qml +++ b/nymea-app/styles/energize/Page.qml @@ -33,11 +33,5 @@ import QtQuick.Templates 2.2 import QtQuick.Controls.Material 2.2 Page { - - background: Rectangle { - gradient: Gradient { - GradientStop { position: 0.0; color: "#e3eae4" } - GradientStop { position: 1.0; color: "#cde2d8" } - } - } + background: Background {} } diff --git a/nymea-app/styles/light/Background.qml b/nymea-app/styles/light/Background.qml new file mode 100644 index 00000000..64d39bee --- /dev/null +++ b/nymea-app/styles/light/Background.qml @@ -0,0 +1,5 @@ +import QtQuick 2.0 + +Rectangle { + color: Style.backgroundColor +} diff --git a/nymea-app/styles/light/Page.qml b/nymea-app/styles/light/Page.qml index aa70bdf8..9255efa4 100644 --- a/nymea-app/styles/light/Page.qml +++ b/nymea-app/styles/light/Page.qml @@ -33,8 +33,5 @@ import QtQuick.Templates 2.2 import QtQuick.Controls.Material 2.2 Page { - - background: Rectangle { - color: Material.background - } + background: Background {} } diff --git a/nymea-app/styles/lime/Background.qml b/nymea-app/styles/lime/Background.qml new file mode 100644 index 00000000..64d39bee --- /dev/null +++ b/nymea-app/styles/lime/Background.qml @@ -0,0 +1,5 @@ +import QtQuick 2.0 + +Rectangle { + color: Style.backgroundColor +} diff --git a/nymea-app/styles/lime/Page.qml b/nymea-app/styles/lime/Page.qml index aa70bdf8..9255efa4 100644 --- a/nymea-app/styles/lime/Page.qml +++ b/nymea-app/styles/lime/Page.qml @@ -33,8 +33,5 @@ import QtQuick.Templates 2.2 import QtQuick.Controls.Material 2.2 Page { - - background: Rectangle { - color: Material.background - } + background: Background {} } diff --git a/nymea-app/styles/mellow/Background.qml b/nymea-app/styles/mellow/Background.qml new file mode 100644 index 00000000..64d39bee --- /dev/null +++ b/nymea-app/styles/mellow/Background.qml @@ -0,0 +1,5 @@ +import QtQuick 2.0 + +Rectangle { + color: Style.backgroundColor +} diff --git a/nymea-app/styles/mellow/Page.qml b/nymea-app/styles/mellow/Page.qml index aa70bdf8..9255efa4 100644 --- a/nymea-app/styles/mellow/Page.qml +++ b/nymea-app/styles/mellow/Page.qml @@ -33,8 +33,5 @@ import QtQuick.Templates 2.2 import QtQuick.Controls.Material 2.2 Page { - - background: Rectangle { - color: Material.background - } + background: Background {} } diff --git a/nymea-app/styles/noir/Background.qml b/nymea-app/styles/noir/Background.qml new file mode 100644 index 00000000..64d39bee --- /dev/null +++ b/nymea-app/styles/noir/Background.qml @@ -0,0 +1,5 @@ +import QtQuick 2.0 + +Rectangle { + color: Style.backgroundColor +} diff --git a/nymea-app/styles/noir/Page.qml b/nymea-app/styles/noir/Page.qml index 7c8b3b33..db69bf21 100644 --- a/nymea-app/styles/noir/Page.qml +++ b/nymea-app/styles/noir/Page.qml @@ -34,7 +34,5 @@ import QtQuick.Controls.Material 2.2 import Nymea 1.0 Page { - background: Rectangle { - color: Style.backgroundColor - } + background: Background {} } diff --git a/nymea-app/ui/MainPage.qml b/nymea-app/ui/MainPage.qml index acd17b56..6042ec7a 100644 --- a/nymea-app/ui/MainPage.qml +++ b/nymea-app/ui/MainPage.qml @@ -54,6 +54,11 @@ Page { d.configOverlay = configComponent.createObject(contentContainer) } + // Removing the background from this page only because the MainViewBase adds it again in + // a deepter layer as we need to include it in the blurring of the header and footer. + // We don't want to paint the background on the entire screen twice (overdraw is costly) + background: null + header: Item { id: mainHeader height: 0 @@ -70,20 +75,6 @@ Page { } } - -// Label { -// anchors { left: parent.left; right: parent.right; verticalCenter: parent.verticalCenter } -// horizontalAlignment: Text.AlignHCenter -// leftPadding: Math.max(menuButton.width, additionalIcons.width) -// rightPadding: leftPadding -// elide: Text.ElideRight -// font: Style.bigFont -// text: d.configOverlay !== null ? -// qsTr("Configure main view") -// : swipeView.currentItem.item.title.length > 0 ? swipeView.currentItem.item.title : filteredContentModel.modelData(swipeView.currentIndex, "displayName") -// } - - Row { id: additionalIcons anchors { right: parent.right; top: parent.top } @@ -222,8 +213,7 @@ Page { } } - tabBar.currentIndex = Qt.binding(function() { return mainViewSettings.currentIndex; }) - swipeView.currentIndex = Qt.binding(function() { return tabBar.currentIndex; }) + swipeView.currentIndex = mainViewSettings.currentIndex mainViewSettings.currentIndex = Qt.binding(function() { return swipeView.currentIndex; }) } } @@ -242,16 +232,11 @@ Page { clip: true property int headerSize: 48 + property int footerSize: app.landscape ? 48 : 64 - readonly property int scrollOffset: swipeView.currentItem.item.contentY + readonly property int scrollOffset: swipeView.currentItem ? swipeView.currentItem.item.contentY : 0 readonly property int headerBlurSize: Math.min(headerSize, scrollOffset * 2) - Rectangle { - width: parent.width - height: contentContainer.headerBlurSize - color: Style.backgroundColor - } - SwipeView { id: swipeView anchors.fill: parent @@ -276,6 +261,12 @@ Page { value: swipeView.currentIndex == index } + Binding { + target: mainViewLoader.item + property: "bottomMargin" + value: footer.visible ? contentContainer.footerSize : 0 + } + Image { source: "qrc:/styles/%1/logo-wide.svg".arg(styleController.currentStyle) anchors { @@ -287,12 +278,13 @@ Page { height: 28 sourceSize.height: height antialiasing: true + z: 2 } - } } } + ColumnLayout { anchors { left: parent.left; right: parent.right; verticalCenter: parent.verticalCenter; margins: app.margins } spacing: app.margins @@ -314,9 +306,9 @@ Page { ShaderEffectSource { id: headerBlurSource width: contentContainer.width - height: contentContainer.headerBlurSize + height: d.configOverlay ? contentContainer.headerSize : contentContainer.headerBlurSize sourceItem: contentContainer - sourceRect: Qt.rect(0, 0, contentContainer.width, contentContainer.headerBlurSize) + sourceRect: Qt.rect(0, 0, contentContainer.width, d.configOverlay ? contentContainer.headerSize : contentContainer.headerBlurSize) visible: false } @@ -326,7 +318,7 @@ Page { top: parent.top; right: parent.right; } - height: contentContainer.headerBlurSize + height: d.configOverlay ? contentContainer.headerSize : contentContainer.headerBlurSize radius: 40 transparentBorder: true source: headerBlurSource @@ -339,7 +331,7 @@ Page { top: parent.top right: parent.right } - height: contentContainer.headerBlurSize + height: d.configOverlay ? contentContainer.headerSize : contentContainer.headerBlurSize gradient: Gradient { GradientStop { position: 0.1; color: Style.backgroundColor } @@ -348,17 +340,53 @@ Page { } } - footer: Item { - readonly property bool shown: tabsRepeater.count > 1 || d.configOverlay - implicitHeight: shown ? 64 + (app.landscape ? -20 : 0) : 0 - Behavior on implicitHeight { NumberAnimation { duration: 200; easing.type: Easing.InOutQuad }} + ShaderEffectSource { + id: footerBlurSource + width: contentContainer.width + height: contentContainer.footerSize + sourceItem: contentContainer + sourceRect: Qt.rect(0, contentContainer.height - height, contentContainer.width, contentContainer.footerSize) + visible: false + enabled: footer.shown + } - TabBar { - id: tabBar - anchors { left: parent.left; top: parent.top; right: parent.right } - height: 64 + (app.landscape ? -20 : 0) - Material.elevation: 3 - position: TabBar.Footer + FastBlur { + anchors { + left: parent.left; + bottom: parent.bottom; + right: parent.right; + } + height: contentContainer.footerSize + radius: 40 + transparentBorder: false + source: footerBlurSource + visible: footer.shown + } + + Rectangle { + id: footer + readonly property bool shown: tabsRepeater.count > 1 || d.configOverlay + visible: shown + anchors { + left: parent.left + bottom: parent.bottom + right: parent.right + } + height: contentContainer.footerSize + Behavior on height { NumberAnimation { duration: 200; easing.type: Easing.InOutQuad }} + +// color: "transparent" + + gradient: Gradient { + GradientStop { position: 0; color: "transparent" } + GradientStop { position: 0.4; color: Qt.rgba(Style.backgroundColor.r, Style.backgroundColor.g, Style.backgroundColor.b, 0.7) } + GradientStop { position: 1; color: Style.backgroundColor } + } + + RowLayout { + id: tabsLayout + anchors.fill: parent + spacing: 0 opacity: d.configOverlay ? 0 : 1 Behavior on opacity { NumberAnimation { duration: 200; easing.type: Easing.InOutQuad } } @@ -366,14 +394,18 @@ Page { Repeater { id: tabsRepeater model: d.configOverlay != null ? null : filteredContentModel - +// model: filteredContentModel delegate: MainPageTabButton { + Layout.fillWidth: true + Layout.fillHeight: true alignment: app.landscape ? Qt.Horizontal : Qt.Vertical + checked: index === swipeView.currentIndex height: tabBar.height - anchors.verticalCenter: parent.verticalCenter +// anchors.verticalCenter: parent.verticalCenter text: model.displayName iconSource: "../images/" + model.icon + ".svg" + onClicked: swipeView.currentIndex = index onPressAndHold: { root.configureViews(); } @@ -381,80 +413,83 @@ Page { } } - TabBar { - anchors.fill: tabBar - Material.elevation: 3 - position: TabBar.Footer + + MainPageTabButton { + anchors.fill: parent + alignment: app.landscape ? Qt.Horizontal : Qt.Vertical + text: d.configOverlay ? qsTr("Done") : qsTr("Configure") + iconSource: "../images/configure.svg" opacity: d.configOverlay ? 1 : 0 Behavior on opacity { NumberAnimation { duration: 200; easing.type: Easing.InOutQuad } } visible: opacity > 0 - MainPageTabButton { - height: tabBar.height - alignment: app.landscape ? Qt.Horizontal : Qt.Vertical - text: d.configOverlay ? qsTr("Done") : qsTr("Configure") - iconSource: "../images/configure.svg" - anchors.verticalCenter: parent.verticalCenter + checked: true - checked: false - checkable: false - - onClicked: { - if (d.configOverlay) { - d.configOverlay.destroy() - } else { - PlatformHelper.vibrate(PlatformHelper.HapticsFeedbackSelection) - d.configOverlay = configComponent.createObject(contentContainer) - } + onClicked: { + if (d.configOverlay) { + d.configOverlay.destroy() + } else { + PlatformHelper.vibrate(PlatformHelper.HapticsFeedbackSelection) + d.configOverlay = configComponent.createObject(contentContainer) } } } - } Component { id: configComponent - Item { + Background { id: configOverlay width: contentContainer.width height: contentContainer.height - NumberAnimation { - target: configOverlay - property: "scale" - duration: 200 - easing.type: Easing.InOutQuad - from: 2 - to: 1 - running: true - } - NumberAnimation { - target: configOverlay - property: "opacity" - duration: 200 - easing.type: Easing.InOutQuad - from: 0 - to: 1 - running: true - } - ListView { id: configListView + anchors.fill: parent model: mainMenuModel - width: parent.width - height: parent.height / 3 - anchors.centerIn: parent - orientation: ListView.Horizontal - moveDisplaced: Transition { - NumberAnimation { properties: "x,y"; duration: 200 } - } - - property int delegateWidth: width / 3 + topMargin: contentContainer.headerSize + bottomMargin: contentContainer.footerSize property bool dragging: draggingIndex >= 0 property int draggingIndex : -1 + moveDisplaced: Transition { NumberAnimation { properties: "y" } } + + delegate: NymeaItemDelegate { + id: viewConfigDelegate + width: parent.width + text: model.displayName + iconName: Qt.resolvedUrl("images/" + model.icon + ".svg") + progressive: false + checked: mainViewSettings.filterList.indexOf(model.name) >= 0 + visible: index !== configListView.draggingIndex + additionalItem: CheckBox { + checked: viewConfigDelegate.checked + anchors.verticalCenter: parent.verticalCenter + onClicked: { + var newList = [] + for (var i = 0; i < mainMenuModel.count; i++) { + var entry = mainMenuModel.get(i).name; + if (entry === model.name) { + if (!isEnabled) { + newList.push(model.name) + } + } else { + if (mainViewSettings.filterList.indexOf(entry) >= 0) { + newList.push(entry) + } + } + } + if (newList.length === 0) { + newList.push(Configuration.defaultMainView) + } + + mainViewSettings.filterList = newList + } + } + } + MouseArea { id: dndArea anchors.fill: parent @@ -463,22 +498,28 @@ Page { onPressAndHold: { mouse.accepted = true - var mouseXInListView = configListView.contentItem.mapFromItem(dndArea, mouseX, mouseY).x; - configListView.draggingIndex = configListView.indexAt(mouseXInListView, mouseY) + var mouseYInListView = configListView.contentItem.mapFromItem(dndArea, mouseX, mouseY).y; + configListView.draggingIndex = configListView.indexAt(mouseX, mouseYInListView) var item = mainMenuModel.get(configListView.draggingIndex) - dndItem.displayName = item.displayName - dndItem.icon = item.icon - var visualItem = configListView.itemAt(mouseXInListView, mouseY) - dndItem.isEnabled = visualItem.isEnabled - dndArea.dragOffset = configListView.mapToItem(visualItem, mouseX, mouseY).x + print("draggingIndex", configListView.draggingIndex) + dndItem.text = item.displayName + dndItem.iconName = item.icon + var visualItem = configListView.itemAt(mouseX, mouseYInListView) + dndItem.checked = visualItem.checked + dndArea.dragOffset = configListView.mapToItem(visualItem, mouseX, mouseY).y PlatformHelper.vibrate(PlatformHelper.HapticsFeedbackImpact) } onMouseYChanged: { if (configListView.dragging) { - var mouseXInListView = configListView.contentItem.mapFromItem(dndArea, mouseX, mouseY).x; - var indexUnderMouse = configListView.indexAt(mouseXInListView - dndArea.dragOffset / 2, mouseY) + var mouseYInListView = configListView.contentItem.mapFromItem(dndArea, mouseX, mouseY).y; + var indexUnderMouse = configListView.indexAt(mouseX, mouseYInListView - dndArea.dragOffset / 2) + if (indexUnderMouse < 0) { + return; + } + indexUnderMouse = Math.min(Math.max(0, indexUnderMouse), configListView.count - 1) if (configListView.draggingIndex !== indexUnderMouse) { + print("moving to", indexUnderMouse) PlatformHelper.vibrate(PlatformHelper.HapticsFeedbackSelection) mainMenuModel.move(configListView.draggingIndex, indexUnderMouse, 1) configListView.draggingIndex = indexUnderMouse; @@ -487,8 +528,8 @@ Page { } onReleased: { print("released!") - var mouseXInListView = configListView.contentItem.mapFromItem(dndArea, mouseX, mouseY).x; - var clickedIndex = configListView.indexAt(mouseXInListView, mouseY) + var mouseYInListView = configListView.contentItem.mapFromItem(dndArea, mouseX, mouseY).y; + var clickedIndex = configListView.indexAt(mouseX, mouseYInListView) var item = mainMenuModel.get(clickedIndex) var isEnabled = mainViewSettings.filterList.indexOf(item.name) >= 0; if (!configListView.dragging) { @@ -519,114 +560,244 @@ Page { } mainViewSettings.sortOrder = newSortOrder; } - Timer { - id: scroller - interval: 2 - repeat: true - running: direction != 0 - property int direction: { - if (!configListView.dragging) { - return 0; - } - return dndArea.mouseX < 50 ? -2 : dndArea.mouseX > dndArea.width - 50 ? 2 : 0 - } - onTriggered: { - configListView.contentX = Math.min(Math.max(0, configListView.contentX + direction), configListView.contentWidth - configListView.width) - } - } +// Timer { +// id: scroller +// interval: 2 +// repeat: true +// running: direction != 0 +// property int direction: { +// if (!configListView.dragging) { +// return 0; +// } +// return dndArea.mouseY < 50 ? -2 : dndArea.mouseY > dndArea.height - 50 ? 2 : 0 +// } +// onTriggered: { +// configListView.contentY = Math.min(Math.max(0, configListView.contentY + direction), configListView.contentHeight - configListView.height) +// } +// } } - delegate: BigTile { - id: configDelegate - width: configListView.delegateWidth - height: configListView.height - property bool isEnabled: mainViewSettings.filterList.indexOf(model.name) >= 0 - visible: configListView.draggingIndex !== index - - leftPadding: 0 - rightPadding: 0 - topPadding: 0 - bottomPadding: 0 - - header: RowLayout { - id: headerRow - width: parent.width - Label { - text: model.displayName - Layout.fillWidth: true - elide: Text.ElideRight - } - } - - contentItem: Item { - Layout.fillWidth: true - implicitHeight: configListView.height - headerRow.height - Style.margins * 2 - - ColorIcon { - anchors.centerIn: parent - width: Math.min(parent.width, parent.height) * .6 - height: width - name: Qt.resolvedUrl("images/" + model.icon + ".svg") - color: configDelegate.isEnabled ? Style.accentColor : Style.iconColor - } - } - } - Item { + NymeaItemDelegate { id: dndItem - width: configListView.delegateWidth - height: configListView.height - property bool isEnabled: false - property string displayName: "" - property string icon: "things" visible: configListView.dragging - x: dndArea.mouseX - dndArea.dragOffset - onVisibleChanged: { - if (visible) { - dragStartAnimation.start(); - } + y: dndArea.mouseY - dndArea.dragOffset + width: configListView.width + progressive: false + additionalItem: CheckBox { + checked: dndItem.checked + anchors.verticalCenter: parent.verticalCenter } - NumberAnimation { - id: dragStartAnimation - target: dndItem - property: "scale" - from: 1 - to: 0.95 - duration: 200 - } - - BigTile { - id: dndTile - anchors.fill: parent - // anchors.margins: app.margins / 2 - Material.elevation: 2 - - leftPadding: 0 - rightPadding: 0 - topPadding: 0 - bottomPadding: 0 - - header: RowLayout { - Label { - text: dndItem.displayName - } - } - - contentItem: Item { - Layout.fillWidth: true - implicitHeight: configListView.height - header.height - - ColorIcon { - anchors.centerIn: parent - width: Math.min(parent.width, parent.height) * .6 - height: width - name: Qt.resolvedUrl("images/" + dndItem.icon + ".svg") - color: dndItem.isEnabled ? Style.accentColor : Style.iconColor - } - } - } } } + +// NumberAnimation { +// target: configOverlay +// property: "scale" +// duration: 200 +// easing.type: Easing.InOutQuad +// from: 2 +// to: 1 +// running: true +// } +// NumberAnimation { +// target: configOverlay +// property: "opacity" +// duration: 200 +// easing.type: Easing.InOutQuad +// from: 0 +// to: 1 +// running: true +// } + +// ListView { +// id: configListView +// model: mainMenuModel +// width: parent.width +// height: parent.height / 3 +// anchors.centerIn: parent +// orientation: ListView.Horizontal +// moveDisplaced: Transition { +// NumberAnimation { properties: "x,y"; duration: 200 } +// } + +// property int delegateWidth: width / 3 + +// property bool dragging: draggingIndex >= 0 +// property int draggingIndex : -1 + +// MouseArea { +// id: dndArea +// anchors.fill: parent +// preventStealing: configListView.dragging +// property int dragOffset: 0 + +// onPressAndHold: { +// mouse.accepted = true +// var mouseXInListView = configListView.contentItem.mapFromItem(dndArea, mouseX, mouseY).x; +// configListView.draggingIndex = configListView.indexAt(mouseXInListView, mouseY) +// var item = mainMenuModel.get(configListView.draggingIndex) +// dndItem.displayName = item.displayName +// dndItem.icon = item.icon +// var visualItem = configListView.itemAt(mouseXInListView, mouseY) +// dndItem.isEnabled = visualItem.isEnabled +// dndArea.dragOffset = configListView.mapToItem(visualItem, mouseX, mouseY).x +// PlatformHelper.vibrate(PlatformHelper.HapticsFeedbackImpact) +// } +// onMouseYChanged: { +// if (configListView.dragging) { +// var mouseXInListView = configListView.contentItem.mapFromItem(dndArea, mouseX, mouseY).x; +// var indexUnderMouse = configListView.indexAt(mouseXInListView - dndArea.dragOffset / 2, mouseY) +// indexUnderMouse = Math.min(Math.max(0, indexUnderMouse), configListView.count - 1) +// if (configListView.draggingIndex !== indexUnderMouse) { +// PlatformHelper.vibrate(PlatformHelper.HapticsFeedbackSelection) +// mainMenuModel.move(configListView.draggingIndex, indexUnderMouse, 1) +// configListView.draggingIndex = indexUnderMouse; +// } +// } +// } +// onReleased: { +// print("released!") +// var mouseXInListView = configListView.contentItem.mapFromItem(dndArea, mouseX, mouseY).x; +// var clickedIndex = configListView.indexAt(mouseXInListView, mouseY) +// var item = mainMenuModel.get(clickedIndex) +// var isEnabled = mainViewSettings.filterList.indexOf(item.name) >= 0; +// if (!configListView.dragging) { +// var newList = [] +// for (var i = 0; i < mainMenuModel.count; i++) { +// var entry = mainMenuModel.get(i).name; +// if (entry === item.name) { +// if (!isEnabled) { +// newList.push(item.name) +// } +// } else { +// if (mainViewSettings.filterList.indexOf(entry) >= 0) { +// newList.push(entry) +// } +// } +// } +// if (newList.length === 0) { +// newList.push(Configuration.defaultMainView) +// } + +// mainViewSettings.filterList = newList +// } +// configListView.draggingIndex = -1; + +// var newSortOrder = [] +// for (var i = 0; i < mainMenuModel.count; i++) { +// newSortOrder.push(mainMenuModel.get(i).name) +// } +// mainViewSettings.sortOrder = newSortOrder; +// } +// Timer { +// id: scroller +// interval: 2 +// repeat: true +// running: direction != 0 +// property int direction: { +// if (!configListView.dragging) { +// return 0; +// } +// return dndArea.mouseX < 50 ? -2 : dndArea.mouseX > dndArea.width - 50 ? 2 : 0 +// } +// onTriggered: { +// configListView.contentX = Math.min(Math.max(0, configListView.contentX + direction), configListView.contentWidth - configListView.width) +// } +// } +// } + +// delegate: BigTile { +// id: configDelegate +// width: configListView.delegateWidth +// height: configListView.height +// property bool isEnabled: mainViewSettings.filterList.indexOf(model.name) >= 0 +// visible: configListView.draggingIndex !== index + +// leftPadding: 0 +// rightPadding: 0 +// topPadding: 0 +// bottomPadding: 0 + +// header: RowLayout { +// id: headerRow +// width: parent.width +// Label { +// text: model.displayName +// Layout.fillWidth: true +// elide: Text.ElideRight +// } +// } + +// contentItem: Item { +// Layout.fillWidth: true +// implicitHeight: configListView.height - headerRow.height - Style.margins * 2 + +// ColorIcon { +// anchors.centerIn: parent +// width: Math.min(parent.width, parent.height) * .6 +// height: width +// name: Qt.resolvedUrl("images/" + model.icon + ".svg") +// color: configDelegate.isEnabled ? Style.accentColor : Style.iconColor +// } +// } +// } +// Item { +// id: dndItem +// width: configListView.delegateWidth +// height: configListView.height +// property bool isEnabled: false +// property string displayName: "" +// property string icon: "things" +// visible: configListView.dragging +// x: dndArea.mouseX - dndArea.dragOffset +// onVisibleChanged: { +// if (visible) { +// dragStartAnimation.start(); +// } +// } + +// NumberAnimation { +// id: dragStartAnimation +// target: dndItem +// property: "scale" +// from: 1 +// to: 0.95 +// duration: 200 +// } + +// BigTile { +// id: dndTile +// anchors.fill: parent +// // anchors.margins: app.margins / 2 +// Material.elevation: 2 + +// leftPadding: 0 +// rightPadding: 0 +// topPadding: 0 +// bottomPadding: 0 + +// header: RowLayout { +// Label { +// text: dndItem.displayName +// } +// } + +// contentItem: Item { +// Layout.fillWidth: true +// implicitHeight: configListView.height - header.height + +// ColorIcon { +// anchors.centerIn: parent +// width: Math.min(parent.width, parent.height) * .6 +// height: width +// name: Qt.resolvedUrl("images/" + dndItem.icon + ".svg") +// color: dndItem.isEnabled ? Style.accentColor : Style.iconColor +// } +// } +// } +// } +// } } } diff --git a/nymea-app/ui/components/MainPageTabButton.qml b/nymea-app/ui/components/MainPageTabButton.qml index 55980f62..ca8d3523 100644 --- a/nymea-app/ui/components/MainPageTabButton.qml +++ b/nymea-app/ui/components/MainPageTabButton.qml @@ -47,18 +47,20 @@ TabButton { spacing: root.alignment == Qt.Horizontal ? app.margins : app.margins / 2 horizontalItemAlignment: Grid.AlignHCenter verticalItemAlignment: Grid.AlignVCenter + opacity: root.checked ? 1 : .4 + Behavior on opacity { NumberAnimation { duration: Style.animationDuration; easing.type: Easing.InOutQuad } } ColorIcon { width: Style.iconSize height: Style.iconSize name: root.iconSource - color: root.checked ? Style.accentColor : Style.iconColor + color: Style.foregroundColor } Label { id: textLabel text: root.text font.pixelSize: app.smallFont - color: root.checked ? Style.accentColor : Material.foreground + color: Style.foregroundColor } } } diff --git a/nymea-app/ui/components/MainViewBase.qml b/nymea-app/ui/components/MainViewBase.qml index 799b7d65..86845e10 100644 --- a/nymea-app/ui/components/MainViewBase.qml +++ b/nymea-app/ui/components/MainViewBase.qml @@ -44,10 +44,15 @@ Item { property bool isCurrentItem: false property int topMargin: 40 + property int bottomMargin: 64 property int contentY: 0 // Relative to topMargin property var headerButtons: [] + Background { + anchors.fill: parent + } + // Prevent scroll events to swipe left/right in case they fall through the grid MouseArea { anchors.fill: parent diff --git a/nymea-app/ui/mainviews/EnergyView.qml b/nymea-app/ui/mainviews/EnergyView.qml index e8251412..f14e925b 100644 --- a/nymea-app/ui/mainviews/EnergyView.qml +++ b/nymea-app/ui/mainviews/EnergyView.qml @@ -97,6 +97,7 @@ MainViewBase { contentHeight: energyGrid.childrenRect.height visible: !engine.thingManager.fetchingData && engine.jsonRpcClient.experiences.hasOwnProperty("Energy") && engine.jsonRpcClient.experiences["Energy"] >= "0.2" topMargin: root.topMargin + bottomMargin: root.bottomMargin // GridLayout directly in a flickable causes problems at initialisation Item { diff --git a/nymea-app/ui/mainviews/FavoritesView.qml b/nymea-app/ui/mainviews/FavoritesView.qml index c819349c..4b783d83 100644 --- a/nymea-app/ui/mainviews/FavoritesView.qml +++ b/nymea-app/ui/mainviews/FavoritesView.qml @@ -53,6 +53,8 @@ MainViewBase { anchors.fill: parent anchors.margins: app.margins / 2 topMargin: root.topMargin + bottomMargin: root.bottomMargin + readonly property int minTileWidth: 172 readonly property int tilesPerRow: root.width / minTileWidth diff --git a/nymea-app/ui/mainviews/GaragesView.qml b/nymea-app/ui/mainviews/GaragesView.qml index 7b6a3b5f..96bdb662 100644 --- a/nymea-app/ui/mainviews/GaragesView.qml +++ b/nymea-app/ui/mainviews/GaragesView.qml @@ -51,7 +51,7 @@ MainViewBase { id: swipeView anchors.fill: parent anchors.topMargin: root.topMargin - anchors.bottomMargin: pageIndicator.visible ? pageIndicator.height : 0 + anchors.bottomMargin: root.bottomMargin + (pageIndicator.visible ? pageIndicator.height : 0) Repeater { model: garagesFilterModel diff --git a/nymea-app/ui/mainviews/GroupsView.qml b/nymea-app/ui/mainviews/GroupsView.qml index bb0f280d..3c5bd888 100644 --- a/nymea-app/ui/mainviews/GroupsView.qml +++ b/nymea-app/ui/mainviews/GroupsView.qml @@ -44,6 +44,7 @@ MainViewBase { anchors.fill: parent anchors.margins: app.margins / 2 topMargin: root.topMargin + bottomMargin: root.bottomMargin readonly property int minTileWidth: 172 readonly property int tilesPerRow: root.width / minTileWidth diff --git a/nymea-app/ui/mainviews/MediaView.qml b/nymea-app/ui/mainviews/MediaView.qml index 6a295f2b..bd99bead 100644 --- a/nymea-app/ui/mainviews/MediaView.qml +++ b/nymea-app/ui/mainviews/MediaView.qml @@ -50,7 +50,7 @@ MainViewBase { SwipeView { id: swipeView - anchors { left: parent.left; top: parent.top; right: parent.right; bottom: parent.bottom } + anchors { left: parent.left; top: parent.top; right: parent.right; bottom: parent.bottom; bottomMargin: root.bottomMargin } currentIndex: pageIndicator.currentIndex Repeater { @@ -67,6 +67,7 @@ MainViewBase { currentIndex: swipeView.currentIndex interactive: true anchors.bottom: parent.bottom + anchors.bottomMargin: root.bottomMargin anchors.horizontalCenter: parent.horizontalCenter } diff --git a/nymea-app/ui/mainviews/ScenesView.qml b/nymea-app/ui/mainviews/ScenesView.qml index 7ed31e94..9cd6083a 100644 --- a/nymea-app/ui/mainviews/ScenesView.qml +++ b/nymea-app/ui/mainviews/ScenesView.qml @@ -45,6 +45,7 @@ MainViewBase { anchors.fill: parent anchors.margins: app.margins / 2 topMargin: root.topMargin + bottomMargin: root.bottomMargin readonly property int minTileWidth: 172 readonly property int tilesPerRow: root.width / minTileWidth diff --git a/nymea-app/ui/mainviews/ThingsView.qml b/nymea-app/ui/mainviews/ThingsView.qml index 15f122a4..e371ab26 100644 --- a/nymea-app/ui/mainviews/ThingsView.qml +++ b/nymea-app/ui/mainviews/ThingsView.qml @@ -57,6 +57,7 @@ MainViewBase { anchors.fill: parent anchors.margins: app.margins / 2 topMargin: root.topMargin + bottomMargin: root.bottomMargin model: mainModel readonly property int minTileWidth: 172 diff --git a/nymea-app/ui/mainviews/dashboard/Dashboard.qml b/nymea-app/ui/mainviews/dashboard/Dashboard.qml index e3e9a4e5..fdd92bfa 100644 --- a/nymea-app/ui/mainviews/dashboard/Dashboard.qml +++ b/nymea-app/ui/mainviews/dashboard/Dashboard.qml @@ -37,7 +37,7 @@ import Nymea 1.0 import "../../components" import "../../delegates" -Item { +MainViewBase { id: root property var model: null @@ -75,9 +75,10 @@ Item { Flickable { id: flickable anchors.fill: parent - anchors.margins: app.margins / 2 + anchors.margins: Style.smallMargins contentHeight: Math.max(layout.implicitHeight, height) contentWidth: width + bottomMargin: root.bottomMargin MouseArea { width: flickable.contentWidth