From ff98144a56506fd6c73b311f1230fde39eb34835 Mon Sep 17 00:00:00 2001 From: Khushboo Mehta Date: Fri, 2 Jun 2023 20:00:31 +0200 Subject: [PATCH] feat(@desktop/wallet): Part implementation of the filter activity UI --- storybook/PagesModel.qml | 4 + storybook/pages/ActivityFilterMenuPage.qml | 171 ++++++++++++++++++ .../controls/ActivityFilterMenuItem.qml | 17 ++ .../Wallet/controls/ActivityTypeCheckBox.qml | 41 +++++ .../Wallet/controls/MenuBackButton.qml | 21 +++ .../controls/StatusWalletMenuRadioButton.qml | 34 ++++ .../Wallet/popups/ActivityFilterMenu.qml | 61 +++++++ .../ActivityPeriodFilterSubMenu.qml | 74 ++++++++ .../ActivityTypeFilterSubMenu.qml | 86 +++++++++ ui/app/AppLayouts/Wallet/popups/qmldir | 5 +- ui/imports/shared/views/HistoryView.qml | 46 +++++ 11 files changed, 559 insertions(+), 1 deletion(-) create mode 100644 storybook/pages/ActivityFilterMenuPage.qml create mode 100644 ui/app/AppLayouts/Wallet/controls/ActivityFilterMenuItem.qml create mode 100644 ui/app/AppLayouts/Wallet/controls/ActivityTypeCheckBox.qml create mode 100644 ui/app/AppLayouts/Wallet/controls/MenuBackButton.qml create mode 100644 ui/app/AppLayouts/Wallet/controls/StatusWalletMenuRadioButton.qml create mode 100644 ui/app/AppLayouts/Wallet/popups/ActivityFilterMenu.qml create mode 100644 ui/app/AppLayouts/Wallet/popups/filterSubMenus/ActivityPeriodFilterSubMenu.qml create mode 100644 ui/app/AppLayouts/Wallet/popups/filterSubMenus/ActivityTypeFilterSubMenu.qml diff --git a/storybook/PagesModel.qml b/storybook/PagesModel.qml index 8c135cbc83..a360b18fd7 100644 --- a/storybook/PagesModel.qml +++ b/storybook/PagesModel.qml @@ -349,4 +349,8 @@ ListModel { title: "StatusTxProgressBar" section: "Wallet" } + ListElement { + title: "ActivityFilterMenu" + section: "Wallet" + } } diff --git a/storybook/pages/ActivityFilterMenuPage.qml b/storybook/pages/ActivityFilterMenuPage.qml new file mode 100644 index 0000000000..38a10cac1d --- /dev/null +++ b/storybook/pages/ActivityFilterMenuPage.qml @@ -0,0 +1,171 @@ +import QtQuick 2.14 +import QtQuick.Controls 2.14 + +import AppLayouts.Wallet.controls 1.0 +import AppLayouts.Wallet.popups 1.0 + +import StatusQ.Core.Theme 0.1 +import StatusQ.Controls 0.1 +import StatusQ.Popups 0.1 + +import Storybook 1.0 + +import Models 1.0 + +SplitView { + id: root + + Logs { id: logs } + + orientation: Qt.Vertical + + QtObject { + id: d + property int selectedTime: ActivityPeriodFilterSubMenu.All + function changeSelectedTime(newTime) { + selectedTime = newTime + } + function setCustomTimeRange(fromTimestamp , toTimestamp) { + dialog.fromTimestamp = fromTimestamp + dialog.toTimestamp = toTimestamp + } + property var typeFilters: [ + ActivityTypeFilterSubMenu.Send, + ActivityTypeFilterSubMenu.Receive, + ActivityTypeFilterSubMenu.Buy, + ActivityTypeFilterSubMenu.Swap, + ActivityTypeFilterSubMenu.Bridge] + } + + Item { + SplitView.fillWidth: true + SplitView.fillHeight: true + + StatusRoundButton { + id: filterButton + anchors.top: parent.top + anchors.topMargin: 100 + anchors.horizontalCenter: parent.horizontalCenter + width: 32 + height: 32 + border.width: 1 + border.color: Theme.palette.directColor8 + type: StatusRoundButton.Type.Tertiary + icon.name: "filter" + onClicked: { + activityFilterMenu.popup(filterButton.x, filterButton.y + filterButton.height + 4) + } + } + ActivityFilterMenu { + id: activityFilterMenu + + selectedTime: d.selectedTime + onSetSelectedTime: { + if(selectedTime === ActivityPeriodFilterSubMenu.Custom) { + dialog.open() + } + d.changeSelectedTime(selectedTime) + } + + typeFilters: d.typeFilters + onUpdateTypeFilter: console.warn("onUpdateTypeFilter:: type :: ", type, " checked ::", checked) + } + + + StatusDateRangePicker { + id: dialog + anchors.centerIn: parent + destroyOnClose: false + fromTimestamp: new Date().setDate(new Date().getDate() - 7) // 7 days ago + onNewRangeSet: { + d.setCustomTimeRange(fromTimestamp, toTimestamp) + } + } + } + + LogsAndControlsPanel { + id: logsAndControlsPanel + + SplitView.minimumHeight: 100 + SplitView.preferredHeight: 200 + + logsView.logText: logs.logText + + ButtonGroup { + buttons: periodRow.children + } + + Column { + spacing: 20 + + Row { + id: periodRow + spacing: 20 + + RadioButton { + checked: true + text: "All" + onCheckedChanged: if(checked) { d.selectedTime = ActivityPeriodFilterSubMenu.All} + } + RadioButton { + text: "Today" + onCheckedChanged: if(checked) { d.selectedTime = ActivityPeriodFilterSubMenu.Today} + } + RadioButton { + text: "Yesterday" + onCheckedChanged: if(checked) { d.selectedTime = ActivityPeriodFilterSubMenu.Yesterday} + } + RadioButton { + text: "ThisWeek" + onCheckedChanged: if(checked) { d.selectedTime = ActivityPeriodFilterSubMenu.ThisWeek} + } + RadioButton { + text: "LastWeek" + onCheckedChanged: if(checked) { d.selectedTime = ActivityPeriodFilterSubMenu.LastWeek} + } + RadioButton { + text: "ThisMonth" + onCheckedChanged: if(checked) { d.selectedTime = ActivityPeriodFilterSubMenu.ThisMonth} + } + RadioButton { + text: "LastMonth" + onCheckedChanged: if(checked) { d.selectedTime = ActivityPeriodFilterSubMenu.LastMonth} + } + RadioButton { + text: "Custom" + onCheckedChanged: if(checked) { d.selectedTime = ActivityPeriodFilterSubMenu.Custom} + } + } + + Row { + spacing: 20 + CheckBox { + id: sendCheckbox + text: "Send" + checked: true + } + CheckBox { + id: receiveCheckbox + text: "Receive" + checked: true + } + CheckBox { + id: buyCheckbox + text: "Buy" + checked: true + } + CheckBox { + id: swapCheckbox + text: "Swap" + checked: true + } + CheckBox { + id: bridgeCheckbox + text: "Bridge" + checked: true + } + } + + } + } +} diff --git a/ui/app/AppLayouts/Wallet/controls/ActivityFilterMenuItem.qml b/ui/app/AppLayouts/Wallet/controls/ActivityFilterMenuItem.qml new file mode 100644 index 0000000000..81dead43ab --- /dev/null +++ b/ui/app/AppLayouts/Wallet/controls/ActivityFilterMenuItem.qml @@ -0,0 +1,17 @@ +import QtQuick 2.15 + +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 +import StatusQ.Popups 0.1 + +StatusMenuItem { + arrow: StatusIcon { + anchors.right: parent.right + anchors.rightMargin: 12 + anchors.verticalCenter: parent.verticalCenter + width: 16 + height: 16 + icon: "next" + color: Theme.palette.directColor1 + } +} diff --git a/ui/app/AppLayouts/Wallet/controls/ActivityTypeCheckBox.qml b/ui/app/AppLayouts/Wallet/controls/ActivityTypeCheckBox.qml new file mode 100644 index 0000000000..8b2c14ece9 --- /dev/null +++ b/ui/app/AppLayouts/Wallet/controls/ActivityTypeCheckBox.qml @@ -0,0 +1,41 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 + +import StatusQ.Components 0.1 +import StatusQ.Controls 0.1 + +StatusListItem { + id: root + + property bool checked: true + property bool allChecked : false + property ButtonGroup buttonGroup + + signal actionTriggered(bool checked) + + height: 44 + radius: 0 + leftPadding: 21 + rightPadding: 21 + asset.width: 24 + asset.height: 24 + asset.bgWidth: 0 + asset.bgHeight: 0 + statusListItemTitle.font.pixelSize: 13 + ButtonGroup.group: buttonGroup + onClicked: checkBox.nextCheckState() + components: [ + StatusCheckBox { + id: checkBox + tristate: true + spacing: 0 + leftPadding: 0 + rightPadding: 0 + checkState: allChecked ? Qt.PartiallyChecked : root.checked ? Qt.Checked : Qt.Unchecked + nextCheckState: function() { + root.actionTriggered(checkBox.checked) + return Qt.PartiallyChecked + } + } + ] +} diff --git a/ui/app/AppLayouts/Wallet/controls/MenuBackButton.qml b/ui/app/AppLayouts/Wallet/controls/MenuBackButton.qml new file mode 100644 index 0000000000..5d7ff0d7c0 --- /dev/null +++ b/ui/app/AppLayouts/Wallet/controls/MenuBackButton.qml @@ -0,0 +1,21 @@ +import QtQuick 2.13 +import QtQuick.Controls 2.13 + +import StatusQ.Controls 0.1 +import StatusQ.Core.Theme 0.1 + +StatusIconTextButton { + id: root + implicitHeight: 34 + spacing: 2 + leftPadding: 10 + statusIcon: "tiny/chevron-left" + icon.width: 18 + icon.height: 18 + font.pixelSize: 13 + text: qsTr("Back") + background: Rectangle { + anchors.fill: parent + color: root.hovered ? Theme.palette.baseColor2 : Theme.palette.statusModal.backgroundColor + } +} diff --git a/ui/app/AppLayouts/Wallet/controls/StatusWalletMenuRadioButton.qml b/ui/app/AppLayouts/Wallet/controls/StatusWalletMenuRadioButton.qml new file mode 100644 index 0000000000..49c92d421e --- /dev/null +++ b/ui/app/AppLayouts/Wallet/controls/StatusWalletMenuRadioButton.qml @@ -0,0 +1,34 @@ +import QtQuick 2.14 +import QtQuick.Layouts 1.12 + +import StatusQ.Core.Theme 0.1 +import StatusQ.Core 0.1 +import StatusQ.Controls 0.1 + +StatusRadioButton { + id: root + implicitHeight: 34 + contentItem: StatusBaseText { + width: parent.width + font.pixelSize: 13 + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + color: Theme.palette.directColor1 + leftPadding: 14 + rightPadding: 24 + text: root.text + } + indicator: StatusIcon { + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.rightMargin: 10 + icon: "checkbox" + width: 12 + height: 12 + color: Theme.palette.primaryColor1 + visible: root.checked + } + background: Rectangle { + color: root.hovered ? Theme.palette.baseColor2 : Theme.palette.statusModal.backgroundColor + } +} diff --git a/ui/app/AppLayouts/Wallet/popups/ActivityFilterMenu.qml b/ui/app/AppLayouts/Wallet/popups/ActivityFilterMenu.qml new file mode 100644 index 0000000000..9c5c1f5ec9 --- /dev/null +++ b/ui/app/AppLayouts/Wallet/popups/ActivityFilterMenu.qml @@ -0,0 +1,61 @@ +import QtQuick 2.15 + +import StatusQ.Popups 0.1 + +import "../controls" +import "./filterSubMenus" + +StatusMenu { + id: root + + // Time filter + property int selectedTime: ActivityFilterMenu.All + signal setSelectedTime(int selectedTime) + + // Type filter + property var typeFilters: [] + signal updateTypeFilter(int type, bool checked) + + implicitWidth: 176 + + // Filter By Period + ActivityFilterMenuItem { + text: qsTr("Period") + onTriggered: timeMenu.popup(Qt.point(0, -8)) + + // just to be able to place the submenus within an Item + ActivityPeriodFilterSubMenu { + id: timeMenu + onBack: root.open() + onActionTriggered: { + timeMenu.close() + setSelectedTime(action) + } + selectedTime: root.selectedTime + } + ActivityTypeFilterSubMenu { + id: typeMenu + onBack: root.open() + typeFilters: root.typeFilters + onActionTriggered: updateTypeFilter(action, checked) + } + } + + ActivityFilterMenuItem { + text: qsTr("Type") + onTriggered: typeMenu.popup(Qt.point(0, -8)) + } + + ActivityFilterMenuItem { + text: qsTr("Status") + } + + ActivityFilterMenuItem { + text: qsTr("Tokens") + } + + ActivityFilterMenuItem { + text: qsTr("Counterparty") + } +} + diff --git a/ui/app/AppLayouts/Wallet/popups/filterSubMenus/ActivityPeriodFilterSubMenu.qml b/ui/app/AppLayouts/Wallet/popups/filterSubMenus/ActivityPeriodFilterSubMenu.qml new file mode 100644 index 0000000000..9ea069ac22 --- /dev/null +++ b/ui/app/AppLayouts/Wallet/popups/filterSubMenus/ActivityPeriodFilterSubMenu.qml @@ -0,0 +1,74 @@ +import QtQuick 2.15 + +import StatusQ.Popups 0.1 + +import "../../controls" + +StatusMenu { + id: root + + property int selectedTime: ActivityFilterMenu.All + + signal back() + signal actionTriggered(int action) + + enum TimePeriod { + All, + Today, + Yesterday, + ThisWeek, + LastWeek, + ThisMonth, + LastMonth, + Custom + } + + MenuBackButton { + width: parent.width + onClicked: { + close() + back() + } + } + StatusWalletMenuRadioButton { + checked: root.selectedTime === ActivityPeriodFilterSubMenu.All + text: qsTr("All time") + onClicked: actionTriggered(ActivityPeriodFilterSubMenu.All) + } + StatusWalletMenuRadioButton { + checked: root.selectedTime === ActivityPeriodFilterSubMenu.Today + text: qsTr("Today") + onClicked: actionTriggered(ActivityPeriodFilterSubMenu.Today) + } + StatusWalletMenuRadioButton { + checked: root.selectedTime === ActivityPeriodFilterSubMenu.Yesterday + text: qsTr("Yesterday") + onClicked: actionTriggered(ActivityPeriodFilterSubMenu.Yesterday) + } + StatusWalletMenuRadioButton { + checked: root.selectedTime === ActivityPeriodFilterSubMenu.ThisWeek + text: qsTr("This week") + onClicked: actionTriggered(ActivityPeriodFilterSubMenu.ThisWeek) + } + StatusWalletMenuRadioButton { + checked: root.selectedTime === ActivityPeriodFilterSubMenu.LastWeek + text: qsTr("Last week") + onClicked: actionTriggered(ActivityPeriodFilterSubMenu.LastWeek) + } + StatusWalletMenuRadioButton { + checked: root.selectedTime === ActivityPeriodFilterSubMenu.ThisMonth + text: qsTr("This month") + onClicked: actionTriggered(ActivityPeriodFilterSubMenu.ThisMonth) + } + StatusWalletMenuRadioButton { + checked: root.selectedTime === ActivityPeriodFilterSubMenu.LastMonth + text: qsTr("Last month") + onClicked: actionTriggered(ActivityPeriodFilterSubMenu.LastMonth) + } + StatusMenuSeparator {} + StatusWalletMenuRadioButton { + checked: root.selectedTime === ActivityPeriodFilterSubMenu.Custom + text: qsTr("Custom range") + onClicked: actionTriggered(ActivityPeriodFilterSubMenu.Custom) + } +} diff --git a/ui/app/AppLayouts/Wallet/popups/filterSubMenus/ActivityTypeFilterSubMenu.qml b/ui/app/AppLayouts/Wallet/popups/filterSubMenus/ActivityTypeFilterSubMenu.qml new file mode 100644 index 0000000000..ee327956d0 --- /dev/null +++ b/ui/app/AppLayouts/Wallet/popups/filterSubMenus/ActivityTypeFilterSubMenu.qml @@ -0,0 +1,86 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 + +import StatusQ.Popups 0.1 + +import "../../controls" + +StatusMenu { + id: root + + property var typeFilters:[] + + signal back() + signal actionTriggered(int action, bool checked) + + property bool allChecked: { + let allCheckedIs = true + for(var i=0;i< root.contentChildren.length;i++) { + if(root.contentChildren[i].checkState === Qt.Unchecked) + allCheckedIs = false + } + return allCheckedIs + } + + enum TxType { + Send, + Receive, + Buy, + Swap, + Bridge + } + + MenuBackButton { + width: parent.width + onClicked: { + close() + back() + } + } + + ButtonGroup { + id: typeButtonGroup + exclusive: false + } + + ActivityTypeCheckBox { + title: qsTr("Send") + asset.name: "send" + checked: typeFilters.includes(ActivityTypeFilterSubMenu.Send) + buttonGroup: typeButtonGroup + onActionTriggered: root.actionTriggered(ActivityTypeFilterSubMenu.Send, checked) + allChecked: root.allChecked + } + ActivityTypeCheckBox { + title: qsTr("Receive") + asset.name: "receive" + buttonGroup: typeButtonGroup + checked: typeFilters.includes(ActivityTypeFilterSubMenu.Receive) + onActionTriggered: root.actionTriggered(ActivityTypeFilterSubMenu.Receive, checked) + allChecked: root.allChecked + } + ActivityTypeCheckBox { + title: qsTr("Buy") + asset.name: "token" + buttonGroup: typeButtonGroup + checked: typeFilters.includes(ActivityTypeFilterSubMenu.Buy) + onActionTriggered: root.actionTriggered(ActivityTypeFilterSubMenu.Buy, checked) + allChecked: root.allChecked + } + ActivityTypeCheckBox { + title: qsTr("Swap") + asset.name: "swap" + buttonGroup: typeButtonGroup + checked: typeFilters.includes(ActivityTypeFilterSubMenu.Swap) + onActionTriggered: root.actionTriggered(ActivityTypeFilterSubMenu.Swap, checked) + allChecked: root.allChecked + } + ActivityTypeCheckBox { + title: qsTr("Bridge") + asset.name: "bridge" + buttonGroup: typeButtonGroup + checked: typeFilters.includes(ActivityTypeFilterSubMenu.Bridge) + onActionTriggered: root.actionTriggered(ActivityTypeFilterSubMenu.Bridge, checked) + allChecked: root.allChecked + } +} diff --git a/ui/app/AppLayouts/Wallet/popups/qmldir b/ui/app/AppLayouts/Wallet/popups/qmldir index 62cd384798..39b4aef3d3 100644 --- a/ui/app/AppLayouts/Wallet/popups/qmldir +++ b/ui/app/AppLayouts/Wallet/popups/qmldir @@ -1 +1,4 @@ -NetworkSelectPopup 1.0 NetworkSelectPopup.qml \ No newline at end of file +NetworkSelectPopup 1.0 NetworkSelectPopup.qml +ActivityFilterMenu 1.0 ActivityFilterMenu.qml +ActivityPeriodFilterSubMenu 1.0 filterSubMenus/ActivityPeriodFilterSubMenu.qml +ActivityTypeFilterSubMenu 1.0 filterSubMenus/ActivityTypeFilterSubMenu.qml diff --git a/ui/imports/shared/views/HistoryView.qml b/ui/imports/shared/views/HistoryView.qml index befddda2b0..24bc3b2698 100644 --- a/ui/imports/shared/views/HistoryView.qml +++ b/ui/imports/shared/views/HistoryView.qml @@ -19,6 +19,8 @@ import "../stores" import "../controls" import AppLayouts.Wallet.stores 1.0 as WalletStores +import AppLayouts.Wallet.popups 1.0 +import AppLayouts.Wallet.controls 1.0 ColumnLayout { id: root @@ -68,6 +70,30 @@ ColumnLayout { text: qsTr("Activity for this account will appear here") } + Rectangle { + id: filterComponent + visible: !d.isLoading && transactionListRoot.count !== 0 + Layout.fillWidth: true + Layout.preferredHeight: 50 + color: Theme.palette.transparent + StatusRoundButton { + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + width: 32 + height: 32 + border.width: 1 + border.color: Theme.palette.directColor8 + icon.name: "filter" + onClicked: activityFilter.popup(x, y + height + 4) + type: StatusRoundButton.Type.Tertiary + } + } + + Separator { + Layout.fillWidth: true + visible: filterComponent.visible + } + StatusListView { id: transactionListRoot objectName: "walletAccountTransactionList" @@ -161,6 +187,7 @@ ColumnLayout { Layout.fillWidth: true Layout.topMargin: 20 implicitHeight: 1 + visible: !sectionDelegate.isFirstSection } StatusTextWithLoadingState { @@ -312,4 +339,23 @@ ColumnLayout { } } } + + ActivityFilterMenu { + id: activityFilter + selectedTime: ActivityPeriodFilterSubMenu.All + onSetSelectedTime: { + // To do connect with n=backend to set time range + if(selectedTime === ActivityPeriodFilterSubMenu.Custom) { + customDateRangePicker.open() + } + } + } + + // To-do update once https://github.com/status-im/status-desktop/pull/10916 is updated and connect with backend values + StatusDateRangePicker { + id: customDateRangePicker + destroyOnClose: false + fromTimestamp: new Date().setDate(new Date().getDate() - 7) +// onNewRangeSet: d.setCustomTimeRange(fromTimestamp, toTimestamp) + } }