From 55a63898a51b2b87bf01f80731654f28534938a9 Mon Sep 17 00:00:00 2001 From: Pascal Precht Date: Wed, 2 Jun 2021 12:41:31 +0200 Subject: [PATCH] feat(StatusQ.Popups): introduce StatusPopupMenu component Usage: ```qml import StatusQ.Popups 0.1 Button { onClicked: simpleMenu.popup() } StatusPopupMenu { id: simpleMenu StatusMenuItem { text: "One" } StatusMenuItem { text: "Two" } StatusMenuItem { text: "Three" } } ``` Closes #96 #74 --- README.md | 1 + sandbox/DemoApp.qml | 31 +++- sandbox/StatusPopupMenuPage.qml | 72 ++++++++++ sandbox/main.qml | 11 ++ src/StatusQ/Core/Theme/StatusDarkTheme.qml | 6 + src/StatusQ/Core/Theme/StatusLightTheme.qml | 6 + src/StatusQ/Core/Theme/ThemePalette.qml | 7 + src/StatusQ/Popups/StatusMenuItem.qml | 15 ++ src/StatusQ/Popups/StatusMenuSeparator.qml | 12 ++ src/StatusQ/Popups/StatusPopupMenu.qml | 148 ++++++++++++++++++++ src/StatusQ/Popups/qmldir | 5 + 11 files changed, 313 insertions(+), 1 deletion(-) create mode 100644 sandbox/StatusPopupMenuPage.qml create mode 100644 src/StatusQ/Popups/StatusMenuItem.qml create mode 100644 src/StatusQ/Popups/StatusMenuSeparator.qml create mode 100644 src/StatusQ/Popups/StatusPopupMenu.qml create mode 100644 src/StatusQ/Popups/qmldir diff --git a/README.md b/README.md index 9675fbf3..60eb3ab6 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ These modules are: - [StatusQ.Components](https://github.com/status-im/StatusQ/blob/master/src/StatusQ/Controls/qmldir) - [StatusQ.Controls](https://github.com/status-im/StatusQ/blob/master/src/StatusQ/Components/qmldir) - [StatusQ.Layout](https://github.com/status-im/StatusQ/blob/master/src/StatusQ/Layout/qmldir) +- [StatusQ.Popups](https://github.com/status-im/StatusQ/blob/master/src/StatusQ/Popups/qmldir) Provided components can be viewed and tested in the [sandbox application](#viewing-and-testing-components) that comes with this repository. Other than that, modules and components can be used as expected. diff --git a/sandbox/DemoApp.qml b/sandbox/DemoApp.qml index c799e200..802735a5 100644 --- a/sandbox/DemoApp.qml +++ b/sandbox/DemoApp.qml @@ -6,6 +6,7 @@ import StatusQ.Core.Theme 0.1 import StatusQ.Controls 0.1 import StatusQ.Components 0.1 import StatusQ.Layout 0.1 +import StatusQ.Popups 0.1 Rectangle { id: demoApp @@ -180,9 +181,37 @@ Rectangle { notificationCount: 1 - onMenuButtonClicked: notificationCount += 1 + onMenuButtonClicked: contextMenu.popup() onNotificationButtonClicked: notificationCount = 0 + + StatusPopupMenu { + id: contextMenu + + StatusMenuItem { + text: "Mute Chat" + icon.name: "notification" + } + StatusMenuItem { + text: "Mark as Read" + icon.name: "checkmark-circle" + } + StatusMenuItem { + text: "Clear History" + icon.name: "close-circle" + } + + StatusMenuSeparator {} + + StatusMenuItem { + text: "Leave Chat" + icon.name: "arrow-right" + icon.width: 14 + iconRotation: 180 + type: StatusMenuItem.Type.Danger + } + } } + } } } diff --git a/sandbox/StatusPopupMenuPage.qml b/sandbox/StatusPopupMenuPage.qml new file mode 100644 index 00000000..db6d50b5 --- /dev/null +++ b/sandbox/StatusPopupMenuPage.qml @@ -0,0 +1,72 @@ +import QtQuick 2.14 +import QtQuick.Layouts 1.14 +import QtQuick.Controls 2.13 + +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 +import StatusQ.Controls 0.1 +import StatusQ.Popups 0.1 + +GridLayout { + columns: 1 + columnSpacing: 5 + rowSpacing: 5 + + StatusButton { + text: "Simple" + onClicked: simpleMenu.popup() + } + + StatusButton { + text: "Complex" + onClicked: complexMenu.popup() + } + + StatusPopupMenu { + id: simpleMenu + StatusMenuItem { + text: "One" + } + + StatusMenuItem { + text: "Two" + } + + StatusMenuItem { + text: "Three" + } + } + + StatusPopupMenu { + id: complexMenu + subMenuItemIcons: ['info'] + StatusMenuItem { + text: "One" + icon.name: "info" + } + + StatusMenuSeparator {} + + StatusMenuItem { + text: "Two" + icon.name: "info" + } + + StatusMenuItem { + text: "Three" + icon.name: "info" + } + + StatusPopupMenu { + title: "Four" + StatusMenuItem { + text: "One" + icon.name: "info" + } + StatusMenuItem { + text: "Three" + icon.name: "info" + } + } + } +} diff --git a/sandbox/main.qml b/sandbox/main.qml index c473530f..65e65ff3 100644 --- a/sandbox/main.qml +++ b/sandbox/main.qml @@ -142,6 +142,12 @@ StatusWindow { selected: page.sourceComponent == othersComponent onClicked: page.sourceComponent = othersComponent } + NavigationHeader { text: "StatusQ.Popup" } + StatusNavigationListItem { + title: "StatusPopupMenu" + selected: page.sourceComponent == popupMenuComponent + onClicked: page.sourceComponent = popupMenuComponent + } } } } @@ -229,6 +235,11 @@ StatusWindow { Buttons {} } + Component { + id: popupMenuComponent + StatusPopupMenuPage {} + } + Component { id: demoAppCmp diff --git a/src/StatusQ/Core/Theme/StatusDarkTheme.qml b/src/StatusQ/Core/Theme/StatusDarkTheme.qml index c52ed9a8..c9c2ecb9 100644 --- a/src/StatusQ/Core/Theme/StatusDarkTheme.qml +++ b/src/StatusQ/Core/Theme/StatusDarkTheme.qml @@ -153,5 +153,11 @@ ThemePalette { property QtObject statusChatInfoButton: QtObject { property color backgroundColor: baseColor3 } + + property QtObject statusPopupMenu: QtObject { + property color backgroundColor: baseColor2 + property color hoverBackgroundColor: directColor7 + property color separatorColor: directColor7 + } } diff --git a/src/StatusQ/Core/Theme/StatusLightTheme.qml b/src/StatusQ/Core/Theme/StatusLightTheme.qml index 655ff0b6..6311107d 100644 --- a/src/StatusQ/Core/Theme/StatusLightTheme.qml +++ b/src/StatusQ/Core/Theme/StatusLightTheme.qml @@ -151,5 +151,11 @@ ThemePalette { property QtObject statusChatInfoButton: QtObject { property color backgroundColor: white } + + property QtObject statusPopupMenu: QtObject { + property color backgroundColor: white + property color hoverBackgroundColor: baseColor2 + property color separatorColor: baseColor2 + } } diff --git a/src/StatusQ/Core/Theme/ThemePalette.qml b/src/StatusQ/Core/Theme/ThemePalette.qml index 5c598bd6..f3dbd48c 100644 --- a/src/StatusQ/Core/Theme/ThemePalette.qml +++ b/src/StatusQ/Core/Theme/ThemePalette.qml @@ -111,6 +111,13 @@ QtObject { property QtObject statusChatInfoButton: QtObject { property color backgroundColor + property color hoverBackgroundColor + } + + property QtObject statusPopupMenu: QtObject { + property color backgroundColor + property color hoverBackgroundColor + property color separatorColor } function alphaColor(color, alpha) { diff --git a/src/StatusQ/Popups/StatusMenuItem.qml b/src/StatusQ/Popups/StatusMenuItem.qml new file mode 100644 index 00000000..256906ae --- /dev/null +++ b/src/StatusQ/Popups/StatusMenuItem.qml @@ -0,0 +1,15 @@ +import QtQuick 2.13 +import QtQuick.Controls 2.13 +import StatusQ.Core 0.1 + +Action { + id: statusMenuItem + + enum Type { + Normal, + Danger + } + + property int type: StatusMenuItem.Type.Normal + property real iconRotation: 0 +} diff --git a/src/StatusQ/Popups/StatusMenuSeparator.qml b/src/StatusQ/Popups/StatusMenuSeparator.qml new file mode 100644 index 00000000..29fbb471 --- /dev/null +++ b/src/StatusQ/Popups/StatusMenuSeparator.qml @@ -0,0 +1,12 @@ +import QtQuick 2.13 +import QtQuick.Controls 2.13 + +import StatusQ.Core.Theme 0.1 + +MenuSeparator { + contentItem: Rectangle { + implicitWidth: 176 + implicitHeight: 1 + color: Theme.palette.statusPopupMenu.separatorColor + } +} diff --git a/src/StatusQ/Popups/StatusPopupMenu.qml b/src/StatusQ/Popups/StatusPopupMenu.qml new file mode 100644 index 00000000..349a259e --- /dev/null +++ b/src/StatusQ/Popups/StatusPopupMenu.qml @@ -0,0 +1,148 @@ +import QtQuick 2.13 +import QtQuick.Controls 2.13 +import QtGraphicalEffects 1.13 + +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 +import StatusQ.Popups 0.1 + + +Menu { + id: statusPopupMenu + + closePolicy: Popup.CloseOnReleaseOutside | Popup.CloseOnEscape + topPadding: 8 + bottomPadding: 8 + + property int menuItemCount: 0 + property var subMenuItemIcons: [] + + delegate: MenuItem { + id: statusPopupMenuItem + + implicitHeight: 38 + + property int subMenuIndex + + Component.onCompleted: { + if (subMenu) { + subMenuIndex = statusPopupMenu.menuItemCount + statusPopupMenu.menuItemCount += 1 + } + } + + action: StatusMenuItem {} + + Component { + id: indicatorComponent + Item { + implicitWidth: 24 + implicitHeight: 24 + StatusIcon { + anchors.centerIn: parent + width: !!statusPopupMenuItem.action.icon.width ? + statusPopupMenuItem.action.icon.width : 18 + rotation: statusPopupMenuItem.action.iconRotation + icon: statusPopupMenuItem.subMenu ? + statusPopupMenu.subMenuItemIcons[statusPopupMenuItem.subMenuIndex] : + statusPopupMenuItem.action.icon.name + color: { + switch (statusPopupMenuItem.action.type) { + case StatusMenuItem.Type.Danger: + return Theme.palette.dangerColor1 + break; + default: + return Theme.palette.primaryColor1 + } + } + } + } + } + + indicator: Loader { + sourceComponent: indicatorComponent + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: 8 + active: parent.subMenu && !!statusPopupMenu.subMenuItemIcons[parent.subMenuIndex] || + !!statusPopupMenuItem.action.icon.name + } + + contentItem: StatusBaseText { + anchors.left: statusPopupMenuItem.indicator.right + anchors.leftMargin: 4 + + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + + text: statusPopupMenuItem.text + color: { + switch (statusPopupMenuItem.action.type) { + case StatusMenuItem.Type.Danger: + return Theme.palette.dangerColor1 + break; + default: + return Theme.palette.directColor1 + } + } + font.pixelSize: 13 + elide: Text.ElideRight + } + + arrow: StatusIcon { + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.rightMargin: 8 + height: 16 + visible: statusPopupMenuItem.subMenu + icon: "next" + color: Theme.palette.directColor1 + } + + background: Rectangle { + color: { + if (hovered) { + return statusPopupMenuItem.action.type === StatusMenuItem.Type.Danger ? Theme.palette.dangerColor3 : Theme.palette.statusPopupMenu.hoverBackgroundColor + } + return "transparent" + } + } + + MouseArea { + id: sensor + + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + hoverEnabled: true + onPressed: mouse.accepted = false + } + } + + background: Item { + id: statusPopupMenuBackground + implicitWidth: 176 + + Rectangle { + id: statusPopupMenuBackgroundContent + implicitWidth: statusPopupMenuBackground.width + implicitHeight: statusPopupMenuBackground.height + color: Theme.palette.statusPopupMenu.backgroundColor + radius: 8 + layer.enabled: true + layer.effect: DropShadow { + width: statusPopupMenuBackgroundContent.width + height: statusPopupMenuBackgroundContent.height + x: statusPopupMenuBackgroundContent.x + visible: statusPopupMenuBackgroundContent.visible + source: statusPopupMenuBackgroundContent + horizontalOffset: 0 + verticalOffset: 4 + radius: 12 + samples: 25 + spread: 0.2 + color: Theme.palette.dropShadow + } + } + } + +} diff --git a/src/StatusQ/Popups/qmldir b/src/StatusQ/Popups/qmldir new file mode 100644 index 00000000..629ee314 --- /dev/null +++ b/src/StatusQ/Popups/qmldir @@ -0,0 +1,5 @@ +module StatusQ.Popups + +StatusMenuSeparator 0.1 StatusMenuSeparator.qml +StatusPopupMenu 0.1 StatusPopupMenu.qml +StatusMenuItem 0.1 StatusMenuItem.qml