From b8d7f667782c66eb051104ca2fecb6442a84649c Mon Sep 17 00:00:00 2001 From: "kali kaneko (leap communications)" Date: Wed, 8 Dec 2021 22:23:46 +0100 Subject: [bug] alternative drawer implementation this is an attempt to solve the problem we're having with snaps, in which Overlays are not correctly displayed. --- gui/components/Footer.qml | 3 + gui/components/Header.qml | 2 +- gui/components/MainView.qml | 126 +++++++++++++------------- gui/components/NavigationDrawer.qml | 170 ++++++++++++++++++++++++++++++++++++ gui/components/StatusBox.qml | 8 +- gui/gui.qrc | 1 + gui/main.qml | 1 + 7 files changed, 244 insertions(+), 67 deletions(-) create mode 100644 gui/components/NavigationDrawer.qml diff --git a/gui/components/Footer.qml b/gui/components/Footer.qml index e6eb264..5e8335e 100644 --- a/gui/components/Footer.qml +++ b/gui/components/Footer.qml @@ -221,6 +221,9 @@ ToolBar { } function isFooterVisible() { + if (drawerOn) { + return false + } if (stackView.depth > 1) { return false } diff --git a/gui/components/Header.qml b/gui/components/Header.qml index ee2d886..6a1f6aa 100644 --- a/gui/components/Header.qml +++ b/gui/components/Header.qml @@ -29,7 +29,7 @@ ToolBar { if (stackView.depth > 1) { stackView.pop() } else { - settingsDrawer.open() + settingsDrawer.toggle() } } } diff --git a/gui/components/MainView.qml b/gui/components/MainView.qml index 0f5fb58..886e896 100644 --- a/gui/components/MainView.qml +++ b/gui/components/MainView.qml @@ -7,83 +7,80 @@ import QtQuick.Layouts 1.14 import "../themes/themes.js" as Theme Page { - StackView { id: stackView anchors.fill: parent initialItem: Home {} } - Drawer { + NavigationDrawer { id: settingsDrawer - - width: Math.min(root.width, root.height) / 3 * 2 - height: root.height - - ListView { - focus: true - currentIndex: -1 + Rectangle { anchors.fill: parent - - delegate: ItemDelegate { - width: parent.width - text: model.text - visible: { - if (isDonationService) {return true} - return model.text != qsTr("Donate") - } - highlighted: ListView.isCurrentItem - icon.color: "transparent" - icon.source: model.icon - onClicked: { - settingsDrawer.close() - model.triggered() - } - } - - model: ListModel { - ListElement { - text: qsTr("Preferences") - icon: "../resources/tools.svg" - triggered: function () { - stackView.push("Preferences.qml") - } - } - ListElement { - text: qsTr("Donate") - icon: "../resources/donate.svg" - triggered: function () { - Qt.openUrlExternally(ctx.donateURL) - } - } - ListElement { - text: qsTr("Help") - icon: "../resources/help.svg" - triggered: function () { - stackView.push("Help.qml") - settingsDrawer.close() - } - } // -> can link to another dialog with report bug / support / contribute / FAQ - ListElement { - text: qsTr("About") - icon: "../resources/about.svg" - triggered: function () { - stackView.push("About.qml") - settingsDrawer.close() + color: "white" + ListView { + focus: true + currentIndex: -1 + anchors.fill: parent + + model: navModel + delegate: ItemDelegate { + width: parent.width + text: model.text + visible: { + if (isDonationService) {return true} + return model.text != qsTr("Donate") } - } - ListElement { - text: qsTr("Quit") - icon: "../resources/quit.svg" - triggered: function () { - backend.quit() + highlighted: ListView.isCurrentItem + icon.color: "transparent" + icon.source: model.icon + onClicked: { + settingsDrawer.toggle() + model.triggered() } } } - - ScrollIndicator.vertical: ScrollIndicator {} } - } + } + + ListModel { + id: navModel + ListElement { + text: qsTr("Preferences") + icon: "../resources/tools.svg" + triggered: function () { + stackView.push("Preferences.qml") + } + } + ListElement { + text: qsTr("Donate") + icon: "../resources/donate.svg" + triggered: function () { + Qt.openUrlExternally(ctx.donateURL) + } + } + ListElement { + text: qsTr("Help") + icon: "../resources/help.svg" + triggered: function () { + stackView.push("Help.qml") + } + } // -> can link to another dialog with report bug / support / contribute / FAQ + ListElement { + text: qsTr("About") + icon: "../resources/about.svg" + triggered: function () { + stackView.push("About.qml") + } + } + ListElement { + text: qsTr("Quit") + icon: "../resources/quit.svg" + triggered: function () { + backend.quit() + } + } + } // end listmodel header: Header { id: header @@ -146,7 +143,6 @@ Page { horizontalCenter: parent.horizontalCenter } } - onYes: Qt.openUrlExternally(ctx.donateURL) } diff --git a/gui/components/NavigationDrawer.qml b/gui/components/NavigationDrawer.qml new file mode 100644 index 0000000..c0e467c --- /dev/null +++ b/gui/components/NavigationDrawer.qml @@ -0,0 +1,170 @@ +// (c) Evgenij Legotskoj https://evileg.com/en/post/192/ +// a reimplementation of Drawer to workaround a problem with overlays +// in the Qt version packaged with the snaps. +import QtQuick 2.5 +import QtQuick.Window 2.0 + +Rectangle { + id: panel + + function show() { open = true; } + function hide() { open = false; } + function toggle() { + open = open ? false : true; + drawerOn = open; + } + + property bool open: false + property int position: Qt.LeftEdge + + readonly property bool _rightEdge: position === Qt.RightEdge + readonly property int _closeX: _rightEdge ? _rootItem.width : - panel.width + readonly property int _openX: _rightEdge ? _rootItem.width - width : 0 + readonly property int _minimumX: _rightEdge ? _rootItem.width - panel.width : -panel.width + readonly property int _maximumX: _rightEdge ? _rootItem.width : 0 + readonly property int _pullThreshold: panel.width/2 + readonly property int _slideDuration: 260 + readonly property int _openMarginSize: 20 + + property real _velocity: 0 + property real _oldMouseX: -1 + + property Item _rootItem: parent + + on_RightEdgeChanged: _setupAnchors() + onOpenChanged: completeSlideDirection() + + width: Math.min(root.width, root.height) / 3 * 2 + height: root.height + x: _closeX + z: 10 + + function _setupAnchors() { + _rootItem = parent; + + shadow.anchors.right = undefined; + shadow.anchors.left = undefined; + + mouse.anchors.left = undefined; + mouse.anchors.right = undefined; + + if (_rightEdge) { + mouse.anchors.right = mouse.parent.right; + shadow.anchors.right = panel.left; + } else { + mouse.anchors.left = mouse.parent.left; + shadow.anchors.left = panel.right; + } + + slideAnimation.enabled = false; + panel.x = _rightEdge ? _rootItem.width : - panel.width; + slideAnimation.enabled = true; + } + + function completeSlideDirection() { + if (open) { + panel.x = _openX; + } else { + panel.x = _closeX; + Qt.inputMethod.hide(); + } + } + + function handleRelease() { + var velocityThreshold = 5 + if ((_rightEdge && _velocity > velocityThreshold) || + (!_rightEdge && _velocity < -velocityThreshold)) { + panel.open = false; + completeSlideDirection() + } else if ((_rightEdge && _velocity < -velocityThreshold) || + (!_rightEdge && _velocity > velocityThreshold)) { + panel.open = true; + completeSlideDirection() + } else if ((_rightEdge && panel.x < _openX + _pullThreshold) || + (!_rightEdge && panel.x > _openX - _pullThreshold) ) { + panel.open = true; + panel.x = _openX; + } else { + panel.open = false; + panel.x = _closeX; + } + } + + function handleClick(mouse) { + if ((_rightEdge && mouse.x < panel.x ) || mouse.x > panel.width) { + open = false; + } + } + + onPositionChanged: { + if (!(position === Qt.RightEdge || position === Qt.LeftEdge )) { + console.warn("SlidePanel: Unsupported position.") + } + } + + Behavior on x { + id: slideAnimation + enabled: !mouse.drag.active + NumberAnimation { + duration: _slideDuration + easing.type: Easing.OutCubic + } + } + + NumberAnimation on x { + id: holdAnimation + to: _closeX + (_openMarginSize * (_rightEdge ? -1 : 1)) + running : false + easing.type: Easing.OutCubic + duration: 200 + } + + MouseArea { + id: mouse + parent: _rootItem + + y: _rootItem.y + width: open ? _rootItem.width : _openMarginSize + height: _rootItem.height + onPressed: if (!open) holdAnimation.restart(); + onClicked: handleClick(mouse) + drag.target: panel + drag.minimumX: _minimumX + drag.maximumX: _maximumX + drag.axis: Qt.Horizontal + drag.onActiveChanged: if (active) holdAnimation.stop() + onReleased: handleRelease() + z: open ? 1 : 0 + onMouseXChanged: { + _velocity = (mouse.x - _oldMouseX); + _oldMouseX = mouse.x; + } + } + + Rectangle { + id: backgroundBlackout + parent: _rootItem + anchors.fill: parent + opacity: 0.5 * Math.min(1, Math.abs(panel.x - _closeX) / _rootItem.width/2) + color: "black" + } + + Item { + id: shadow + anchors.left: panel.right + anchors.leftMargin: _rightEdge ? 0 : 10 + height: parent.height + + Rectangle { + height: 10 + width: panel.height + rotation: 90 + opacity: Math.min(1, Math.abs(panel.x - _closeX)/ _openMarginSize) + transformOrigin: Item.TopLeft + gradient: Gradient{ + GradientStop { position: _rightEdge ? 1 : 0 ; color: "#00000000"} + GradientStop { position: _rightEdge ? 0 : 1 ; color: "#2c000000"} + } + } + } +} diff --git a/gui/components/StatusBox.qml b/gui/components/StatusBox.qml index 23fc271..bfcc175 100644 --- a/gui/components/StatusBox.qml +++ b/gui/components/StatusBox.qml @@ -55,11 +55,14 @@ Item { cursorShape: Qt.PointingHandCursor } onClicked: { + settingsDrawer.toggle() + /* if (stackView.depth > 1) { stackView.pop() } else { - settingsDrawer.open() + settingsDrawer.toggle() } + */ } Icon { @@ -67,8 +70,11 @@ Item { width: 16 height: 16 anchors.centerIn: settingsButton + source: "../resources/gear-fill.svg" + /* source: stackView.depth > 1 ? "../resources/arrow-left.svg" : "../resources/gear-fill.svg" + */ } } diff --git a/gui/gui.qrc b/gui/gui.qrc index 71a4422..9e357bf 100644 --- a/gui/gui.qrc +++ b/gui/gui.qrc @@ -41,6 +41,7 @@ components/InitErrors.qml components/ErrorBox.qml components/MotdBox.qml + components/NavigationDrawer.qml resources/icon-noshield.svg diff --git a/gui/main.qml b/gui/main.qml index 00a84fc..56220f5 100644 --- a/gui/main.qml +++ b/gui/main.qml @@ -14,6 +14,7 @@ ApplicationWindow { property int appHeight: 460 property int appWidth: 280 property alias customTheme: themeLoader.item + property bool drawerOn: false width: appWidth minimumWidth: appWidth -- cgit v1.2.3