From b2d678c2c4a8d97bd7f356f0160435f4b74c41ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Cie=C5=9Blak?= Date: Tue, 30 Aug 2022 18:27:00 +0200 Subject: [PATCH] chore(HoldingsDropdown): Component refactor and split into smaller files - decomposed into set of separate components - reduced number of magic numbers - minor adjustments with design --- .../controls/community/CollectiblesPanel.qml | 79 ++++ .../Chat/controls/community/EnsPanel.qml | 5 + .../community/ExtendedDropdownContent.qml | 237 ++++++------ .../controls/community/HoldingsDropdown.qml | 362 ++++++++---------- .../Chat/controls/community/HoldingsTabs.qml | 59 +++ .../community/ListDropdownContent.qml | 6 +- .../controls/community/OperatorsSelector.qml | 48 +++ .../Chat/controls/community/TokensPanel.qml | 59 +++ .../Chat/layouts/SettingsPageLayout.qml | 2 +- 9 files changed, 528 insertions(+), 329 deletions(-) create mode 100644 ui/app/AppLayouts/Chat/controls/community/CollectiblesPanel.qml create mode 100644 ui/app/AppLayouts/Chat/controls/community/EnsPanel.qml create mode 100644 ui/app/AppLayouts/Chat/controls/community/HoldingsTabs.qml create mode 100644 ui/app/AppLayouts/Chat/controls/community/OperatorsSelector.qml create mode 100644 ui/app/AppLayouts/Chat/controls/community/TokensPanel.qml diff --git a/ui/app/AppLayouts/Chat/controls/community/CollectiblesPanel.qml b/ui/app/AppLayouts/Chat/controls/community/CollectiblesPanel.qml new file mode 100644 index 0000000000..eca6a26846 --- /dev/null +++ b/ui/app/AppLayouts/Chat/controls/community/CollectiblesPanel.qml @@ -0,0 +1,79 @@ +import QtQuick 2.14 +import QtQuick.Layouts 1.14 + +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 +import StatusQ.Controls 0.1 +import StatusQ.Controls.Validators 0.1 + +ColumnLayout { + id: root + + property alias specificAmount: specificAmountSwitch.checked + property alias collectibleName: pickerButton.text + property url collectibleImage + + property alias amount: amountInput.text + + signal pickerClicked + + spacing: 0 + + StatusPickerButton { + id: pickerButton + + Layout.fillWidth: true + Layout.preferredHeight: 36 + bgColor: Theme.palette.baseColor5 + contentColor: Theme.palette.directColor1 + text: root.collectibleName + font.pixelSize: 13 + asset.name: root.collectibleImage + + onClicked: pickerClicked() + } + + RowLayout { + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter + Layout.leftMargin: 16 + Layout.rightMargin: 6 + Layout.topMargin: 8 + + StatusBaseText { + Layout.fillWidth: true + text: qsTr("Specific amount") + font.pixelSize: 13 + wrapMode: Text.WordWrap + elide: Text.ElideRight + } + StatusSwitch { id: specificAmountSwitch } + } + + StatusInput { + id: amountInput + + Layout.fillWidth: true + Layout.topMargin: 8 + visible: specificAmountSwitch.checked + minimumHeight: 36 + maximumHeight: 36 + topPadding: 0 + bottomPadding: 0 + font.pixelSize: 13 + rightPadding: amountText.implicitWidth + amountText.anchors.rightMargin + leftPadding + input.placeholderText: "0" + validationMode: StatusInput.ValidationMode.IgnoreInvalidInput + validators: StatusFloatValidator { bottom: 0 } + + StatusBaseText { + id: amountText + anchors.right: parent.right + anchors.rightMargin: 13 + anchors.verticalCenter: parent.verticalCenter + text: qsTr("Amount") + color: Theme.palette.baseColor1 + font.pixelSize: 13 + } + } +} diff --git a/ui/app/AppLayouts/Chat/controls/community/EnsPanel.qml b/ui/app/AppLayouts/Chat/controls/community/EnsPanel.qml new file mode 100644 index 0000000000..95b4ba9d27 --- /dev/null +++ b/ui/app/AppLayouts/Chat/controls/community/EnsPanel.qml @@ -0,0 +1,5 @@ +import QtQuick 2.14 + +Item { + +} diff --git a/ui/app/AppLayouts/Chat/controls/community/ExtendedDropdownContent.qml b/ui/app/AppLayouts/Chat/controls/community/ExtendedDropdownContent.qml index 1fa40bdc22..25661b376a 100644 --- a/ui/app/AppLayouts/Chat/controls/community/ExtendedDropdownContent.qml +++ b/ui/app/AppLayouts/Chat/controls/community/ExtendedDropdownContent.qml @@ -9,13 +9,14 @@ import StatusQ.Core 0.1 import shared.panels 1.0 -ColumnLayout { +Item { id: root property var store property int type: ExtendedDropdownContent.Type.Tokens - signal goBack() + readonly property bool canGoBack: root.state !== d.listView_depth1_State + signal itemClicked(string key, string name, url iconSource) enum Type{ @@ -23,6 +24,10 @@ ColumnLayout { Collectibles } + function goBack() { + root.state = d.listView_depth1_State + } + QtObject { id: d readonly property int filterItemsHeight: 36 @@ -48,7 +53,6 @@ ColumnLayout { } } - spacing: 0 state: d.listView_depth1_State states: [ State { @@ -71,138 +75,113 @@ ColumnLayout { } ] - // Header - RowLayout { - Layout.fillWidth: true - Layout.leftMargin: 16 - Layout.rightMargin: 8 - Layout.topMargin: 5 + StatusFlatRoundButton { + id: filterButton + implicitWidth: 32 + implicitHeight: 32 + visible: d.isFilterOptionVisible + type: StatusFlatRoundButton.Type.Secondary + icon.name: "filter" - StatusIconTextButton { - Layout.alignment: Qt.AlignVCenter - spacing: 0 - statusIcon: "next" - icon.width: 12 - icon.height: 12 - iconRotation: 180 - text: qsTr("Back") - onClicked: { - if(root.state == d.listView_depth1_State) { - root.goBack() - } - else { - root.state = d.listView_depth1_State - } - } + anchors.right: parent.right + anchors.bottom: parent.top + anchors.bottomMargin: 3 + + onClicked: { + filterOptionsPopup.x = filterButton.x + filterButton.width - filterOptionsPopup.width + filterOptionsPopup.y = filterButton.y + filterButton.height + 8 + filterOptionsPopup.open() } + } - // Just a filler to fit layout - Item { Layout.fillWidth: true; height: filterButton.implicitHeight } + // Filter options popup: + StatusDropdown { + id: filterOptionsPopup + width: d.filterPopupWidth + height: d.filterPopupHeight + contentItem: ColumnLayout { + anchors.fill: parent + anchors.topMargin: 8 + anchors.bottomMargin: 8 + ListView { + Layout.fillWidth: true + Layout.preferredHeight: model.count * d.filterItemsHeight + model: ListModel { + ListElement { text: qsTr("Most viewed"); selected: true } + ListElement { text: qsTr("Newest first"); selected: false } + ListElement { text: qsTr("Oldest first"); selected: false } + } + delegate: StatusItemPicker { + width: ListView.view.width + height: d.filterItemsHeight + color: sensor1.containsMouse ? Theme.palette.baseColor4 : "transparent" + name: model.text + namePixelSize: 13 + selectorType: StatusItemPicker.SelectorType.RadioButton + radioGroup: filterRadioBtnGroup + radioButtonSize: StatusRadioButton.Size.Small + selected: model.selected - StatusFlatRoundButton { - id: filterButton - implicitWidth: 32 - implicitHeight: 32 - visible: d.isFilterOptionVisible - type: StatusFlatRoundButton.Type.Secondary - icon.name: "filter" - - onClicked: { - filterOptionsPopup.x = filterButton.x + filterButton.width - filterOptionsPopup.width - filterOptionsPopup.y = filterButton.y + filterButton.height + 8 - filterOptionsPopup.open() - } - } - - // Filter options popup: - StatusDropdown { - id: filterOptionsPopup - width: d.filterPopupWidth - height: d.filterPopupHeight - contentItem: ColumnLayout { - anchors.fill: parent - anchors.topMargin: 8 - anchors.bottomMargin: 8 - ListView { - Layout.fillWidth: true - Layout.preferredHeight: model.count * d.filterItemsHeight - model: ListModel { - ListElement { text: qsTr("Most viewed"); selected: true } - ListElement { text: qsTr("Newest first"); selected: false } - ListElement { text: qsTr("Oldest first"); selected: false } - } - delegate: StatusItemPicker { - width: ListView.view.width - height: d.filterItemsHeight - color: sensor1.containsMouse ? Theme.palette.baseColor4 : "transparent" - name: model.text - namePixelSize: 13 - selectorType: StatusItemPicker.SelectorType.RadioButton - radioGroup: filterRadioBtnGroup - radioButtonSize: StatusRadioButton.Size.Small - selected: model.selected - - MouseArea { - id: sensor1 - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - hoverEnabled: true - onClicked: { - selected = !selected - console.log("TODO: Clicked filter option: " + model.text) - filterOptionsPopup.close() - } + MouseArea { + id: sensor1 + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + hoverEnabled: true + onClicked: { + selected = !selected + console.log("TODO: Clicked filter option: " + model.text) + filterOptionsPopup.close() } } + } - // Not visual element to control filter options - ButtonGroup { - id: filterRadioBtnGroup + // Not visual element to control filter options + ButtonGroup { + id: filterRadioBtnGroup + } + } + + Separator { Layout.fillWidth: true } + + ListView { + Layout.fillWidth: true + Layout.preferredHeight: model.count * d.filterItemsHeight + model: ListModel { + ListElement { key: "LIST"; text: qsTr("List"); selected: true } + ListElement { key: "THUMBNAILS"; text: qsTr("Thumbnails"); selected: false } + } + delegate: StatusItemPicker { + width: ListView.view.width + height: d.filterItemsHeight + color: sensor2.containsMouse ? Theme.palette.baseColor4 : "transparent" + name: model.text + namePixelSize: 13 + selectorType: StatusItemPicker.SelectorType.RadioButton + radioGroup: visualizationRadioBtnGroup + radioButtonSize: StatusRadioButton.Size.Small + selected: model.selected + + MouseArea { + id: sensor2 + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + hoverEnabled: true + onClicked: { + selected = !selected + if(model.key === "LIST") { + root.state = d.listView_depth2_State + } + else if(model.key === "THUMBNAILS") { + root.state = d.thumbnailsViewState + } + filterOptionsPopup.close() + } } } - Separator { Layout.fillWidth: true } - - ListView { - Layout.fillWidth: true - Layout.preferredHeight: model.count * d.filterItemsHeight - model: ListModel { - ListElement { key: "LIST"; text: qsTr("List"); selected: true } - ListElement { key: "THUMBNAILS"; text: qsTr("Thumbnails"); selected: false } - } - delegate: StatusItemPicker { - width: ListView.view.width - height: d.filterItemsHeight - color: sensor2.containsMouse ? Theme.palette.baseColor4 : "transparent" - name: model.text - namePixelSize: 13 - selectorType: StatusItemPicker.SelectorType.RadioButton - radioGroup: visualizationRadioBtnGroup - radioButtonSize: StatusRadioButton.Size.Small - selected: model.selected - - MouseArea { - id: sensor2 - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - hoverEnabled: true - onClicked: { - selected = !selected - if(model.key === "LIST") { - root.state = d.listView_depth2_State - } - else if(model.key === "THUMBNAILS") { - root.state = d.thumbnailsViewState - } - filterOptionsPopup.close() - } - } - } - - // Not visual element to control visualization options - ButtonGroup { - id: visualizationRadioBtnGroup - } + // Not visual element to control visualization options + ButtonGroup { + id: visualizationRadioBtnGroup } } } @@ -211,9 +190,8 @@ ColumnLayout { // List elements content Loader { id: contentLoader - Layout.preferredWidth: 289 // by design - Layout.bottomMargin: 5 - Layout.preferredHeight: (item != null && typeof(item) !== 'undefined') ? item.implicitHeight : 0 + + anchors.fill: parent } Component { @@ -267,6 +245,9 @@ ColumnLayout { ThumbnailsDropdownContent { title: d.currentItemName titleImage: d.currentItemSource + + padding: 0 + model: d.currentModel onItemClicked: { d.reset() diff --git a/ui/app/AppLayouts/Chat/controls/community/HoldingsDropdown.qml b/ui/app/AppLayouts/Chat/controls/community/HoldingsDropdown.qml index 33de2ca7f5..0205089979 100644 --- a/ui/app/AppLayouts/Chat/controls/community/HoldingsDropdown.qml +++ b/ui/app/AppLayouts/Chat/controls/community/HoldingsDropdown.qml @@ -1,17 +1,12 @@ -import QtQuick 2.13 +import QtQuick 2.14 import QtQuick.Layouts 1.14 -import QtQuick.Controls 2.13 -import QtGraphicalEffects 1.13 import StatusQ.Core 0.1 import StatusQ.Core.Theme 0.1 import StatusQ.Components 0.1 import StatusQ.Controls 0.1 -import StatusQ.Controls.Validators 0.1 import StatusQ.Core.Utils 0.1 as SQ -import utils 1.0 - StatusDropdown { id: root @@ -23,6 +18,8 @@ StatusDropdown { property url tokenImage: "" property real collectibleAmount: 1 property string collectibleName: d.defaultCollectibleNameText + property bool collectiblesSpecificAmount: false + property url collectibleImage: "" property int operator: SQ.Utils.Operators.None property bool withOperatorSelector: true @@ -38,107 +35,118 @@ StatusDropdown { root.collectibleAmount = 1 root.collectibleName = d.defaultCollectibleNameText root.collectibleImage = "" + root.collectiblesSpecificAmount = false root.operator = SQ.Utils.Operators.None } + padding: d.padding + + onOpened: d.selectInitState() + onClosed: root.reset() + onWithOperatorSelectorChanged: d.selectInitState() + QtObject { id: d // Internal management properties: readonly property bool tokensReady: root.tokenAmount > 0 && root.tokenName !== d.defaultTokenNameText readonly property bool collectiblesReady: root.collectibleAmount > 0 && root.collectibleName !== d.defaultCollectibleNameText + + readonly property string operatorsState: "OPERATORS" + readonly property string tabsState: "TABS" + readonly property string extendedState: "EXTENDED" + readonly property string tokensState: "TOKENS" readonly property string collectiblesState: "COLLECTIBLES" readonly property string ensState: "ENS" - property bool isTokensLayout: true + + property int extendedDropdownType: ExtendedDropdownContent.Type.Tokens property int currentTabIndex: 0 // By design values: - readonly property int initialHeight: 232 - readonly property int mainHeight: 256 - readonly property int mainExtendedHeight: 276 - readonly property int operatorsHeight: 96 - readonly property int extendedHeight: 417 - readonly property int defaultWidth: 289 + readonly property int padding: 8 + readonly property int topPaddingWithBack: 12 + readonly property int extendedTopPadding: 16 + readonly property int operatorsWidth: 159 + readonly property int operatorsHeight: 96 + + readonly property int defaultWidth: 289 + readonly property int defaultHeight: 232 + readonly property int enlargedHeight: 276 + readonly property int extendedHeight: 417 + + readonly property int backButtonExtraLeftMargin: 4 property string defaultTokenNameText: qsTr("Choose token") property string defaultCollectibleNameText: qsTr("Choose collectible") + signal addClicked + function selectInitState() { if(root.withOperatorSelector) - loader.sourceComponent = operatorsSelectorView + content.state = d.operatorsState else - loader.sourceComponent = tabsView + content.state = d.tabsState } } - implicitWidth: d.defaultWidth - implicitHeight: loader.implicitHeight + contentItem: ColumnLayout { + id: content - contentItem: Loader { - id: loader - anchors.top: parent.top - anchors.left: parent.left - width: parent.width - height: (item != null && typeof(item) !== 'undefined') ? item.implicitHeight : 0 - sourceComponent: root.withOperatorSelector ? operatorsSelectorView : tabsView - onSourceComponentChanged: { - if(sourceComponent == operatorsSelectorView) { - root.width = d.operatorsWidth - } - else { - root.width = d.defaultWidth - } + spacing: 10 + + StatusIconTextButton { + id: backButton + + Layout.leftMargin: d.backButtonExtraLeftMargin + spacing: 0 + statusIcon: "next" + icon.width: 12 + icon.height: 12 + iconRotation: 180 + text: qsTr("Back") } - } - onOpened: d.selectInitState() - onClosed: root.reset() - onWithOperatorSelectorChanged: d.selectInitState() + Loader { + id: loader + Layout.fillWidth: true + Layout.fillHeight: true + } + + states: [ + State { + name: d.operatorsState + PropertyChanges {target: loader; sourceComponent: operatorsSelectorView} + PropertyChanges {target: backButton; visible: false} + PropertyChanges {target: root; width: d.operatorsWidth; height: d.operatorsHeight } + }, + State { + name: d.tabsState + PropertyChanges {target: loader; sourceComponent: tabsView} + PropertyChanges {target: backButton; visible: root.withOperatorSelector} + PropertyChanges { + target: root; topPadding: root.withOperatorSelector ? d.topPaddingWithBack : d.extendedTopPadding + width: d.defaultWidth + height: (loader.item.state === d.collectiblesState && root.collectiblesSpecificAmount) ? d.enlargedHeight : d.defaultHeight + } + }, + State { + name: d.extendedState + PropertyChanges {target: loader; sourceComponent: extendedView} + PropertyChanges {target: backButton; visible: true} + PropertyChanges {target: root; topPadding: d.topPaddingWithBack; width: d.defaultWidth; height: d.extendedHeight} + } + ] + } Component { id: operatorsSelectorView - ColumnLayout { - StatusPickerButton { - Layout.margins: 8 - Layout.bottomMargin: 0 - Layout.preferredWidth: 143 // by design - Layout.preferredHeight: 36 - horizontalPadding: 12 - spacing: 10 - bgColor: Theme.palette.primaryColor3 - contentColor: Theme.palette.primaryColor1 - asset.name: Style.svg("add") - asset.isImage: true - text: qsTr("And...") - asset.height: 12 - asset.width: 12 - font.pixelSize: 13 - onClicked: { - root.operator = SQ.Utils.Operators.And - loader.sourceComponent = tabsView - } - } - StatusPickerButton { - Layout.margins: 8 - Layout.topMargin: 0 - Layout.fillWidth: true - Layout.preferredHeight: 36 - horizontalPadding: 12 - spacing: 10 - bgColor: Theme.palette.primaryColor3 - contentColor: Theme.palette.primaryColor1 - asset.name: Style.svg("condition-Or") - asset.isImage: true - asset.height: 12 - asset.width: 12 - text: qsTr("Or...") - font.pixelSize: 13 - onClicked: { - root.operator = SQ.Utils.Operators.Or - loader.sourceComponent = tabsView - } + + OperatorsSelector { + onOperatorSelected: { + root.operator = operator + content.state = d.tabsState } } } @@ -146,146 +154,92 @@ StatusDropdown { Component { id: tabsView - ColumnLayout { - spacing: 0 - state: d.currentTabIndex === 0 ? d.tokensState : (d.currentTabIndex === 1 ? d.collectiblesState : d.ensState) + HoldingsTabs { + id: holdingsTabs + states: [ State { name: d.tokensState - PropertyChanges {target: tabsLoader; sourceComponent: tokensCollectiblesLayout} - PropertyChanges {target: d; isTokensLayout: true} + PropertyChanges {target: holdingsTabs; sourceComponent: tokensLayout; addButtonEnabled: d.tokensReady} }, State { name: d.collectiblesState - PropertyChanges {target: tabsLoader; sourceComponent: tokensCollectiblesLayout} - PropertyChanges {target: d; isTokensLayout: false} + PropertyChanges {target: holdingsTabs; sourceComponent: collectiblesLayout; addButtonEnabled: d.collectiblesReady} }, State { name: d.ensState - PropertyChanges {target: tabsLoader; sourceComponent: ensLayout} + PropertyChanges {target: holdingsTabs; sourceComponent: ensLayout; addButtonEnabled: false} } ] - StatusIconTextButton { - visible: root.withOperatorSelector - Layout.leftMargin: 16 - Layout.topMargin: 12 - spacing: 0 - statusIcon: "next" - icon.width: 12 - icon.height: 12 - iconRotation: 180 - text: qsTr("Back") - onClicked: loader.sourceComponent = operatorsSelectorView - } - StatusSwitchTabBar { - id: tabBar - Layout.preferredWidth: 273 // by design - Layout.margins: 8 - Layout.topMargin: root.withOperatorSelector ? 12 : 16 - Layout.preferredHeight: 36 // by design - currentIndex: d.currentTabIndex - onCurrentIndexChanged: d.currentTabIndex = currentIndex - StatusSwitchTabButton { - text: qsTr("Token") - fontPixelSize: 13 + + tabLabels: [qsTr("Token"), qsTr("Collectible"), qsTr("ENS")] + state: [d.tokensState, d.collectiblesState, d.ensState][currentIndex] + + currentIndex: d.currentTabIndex + onCurrentIndexChanged: d.currentTabIndex = currentIndex + + onAddClicked: d.addClicked() + + Connections { + target: backButton + + function onClicked() { + content.state = d.operatorsState } - StatusSwitchTabButton { - text: qsTr("Collectible") - fontPixelSize: 13 - } - StatusSwitchTabButton { - text: qsTr("ENS") - fontPixelSize: 13 - enabled: false // TODO - } - } - Loader { - id: tabsLoader - Layout.fillWidth: true - Layout.margins: 8 } } } Component { - id: tokensCollectiblesLayout + id: tokensLayout - ColumnLayout { - spacing: 0 - StatusPickerButton { - Layout.fillWidth: true - Layout.preferredHeight: 36 - bgColor: Theme.palette.baseColor5 - contentColor: Theme.palette.directColor1 - text: d.isTokensLayout ? root.tokenName : root.collectibleName - font.pixelSize: 13 - asset.name: d.isTokensLayout ? root.tokenImage : root.collectibleImage - onClicked: loader.sourceComponent = extendedView + TokensPanel { + id: tokensPanel + + tokenName: root.tokenName + tokenImage: root.tokenImage + amount: root.tokenAmount === 0 ? "" : root.tokenAmount.toString() + onAmountChanged: root.tokenAmount = Number(amount) + + onPickerClicked: { + d.extendedDropdownType = ExtendedDropdownContent.Type.Tokens + content.state = d.extendedState } - RowLayout { - visible: !d.isTokensLayout - Layout.fillWidth: true - Layout.alignment: Qt.AlignVCenter - Layout.leftMargin: 16 - Layout.rightMargin: 6 - Layout.topMargin: 8 - StatusBaseText { - Layout.fillWidth: true - text: qsTr("Specific amount") - font.pixelSize: 13 - wrapMode: Text.WordWrap - elide: Text.ElideRight - clip: true - } - StatusSwitch { id: specificAmountSwitch } - } + Connections { + target: d - StatusInput { - Layout.fillWidth: true - Layout.topMargin: 8 - visible: d.isTokensLayout ? true : specificAmountSwitch.checked - minimumHeight: 36 - maximumHeight: 36 - topPadding: 0 - bottomPadding: 0 - text: d.isTokensLayout ? (root.tokenAmount === 0 ? "" : root.tokenAmount.toString()) : - (root.collectibleAmount === 0 ? "" : root.collectibleAmount.toString()) - font.pixelSize: 13 - rightPadding: amountText.implicitWidth + amountText.anchors.rightMargin + leftPadding - input.placeholderText: "0" - validationMode: StatusInput.ValidationMode.IgnoreInvalidInput - validators: StatusFloatValidator { bottom: 0 } - - StatusBaseText { - id: amountText - anchors.right: parent.right - anchors.rightMargin: 13 - anchors.verticalCenter: parent.verticalCenter - text: qsTr("Amount") - color: Theme.palette.baseColor1 - font.pixelSize: 13 - } - onTextChanged: { - if(d.isTokensLayout) - root.tokenAmount = Number(text) - else - root.collectibleAmount = Number(text) + function onAddClicked() { + root.addItem(root.itemKey, qsTr("%1 %2").arg(root.tokenAmount.toString()).arg(root.tokenName), + root.tokenImage, root.operator) } } + } + } - StatusButton { - enabled: d.isTokensLayout ? d.tokensReady : d.collectiblesReady - text: qsTr("Add") - height: 44 - Layout.alignment: Qt.AlignHCenter - Layout.fillWidth: true - Layout.topMargin: 32 - onClicked: { - if(d.isTokensLayout) - root.addItem(root.itemKey, root.tokenAmount.toString() + " " + root.tokenName, root.tokenImage, root.operator) - else - root.addItem(root.itemKey, root.collectibleAmount.toString() + " " + root.collectibleName, root.collectibleImage, root.operator) + Component { + id: collectiblesLayout + + CollectiblesPanel { + collectibleName: root.collectibleName + collectibleImage: root.collectibleImage + amount: root.collectibleAmount === 0 ? "" : root.collectibleAmount.toString() + onAmountChanged: root.collectibleAmount = Number(amount) + + specificAmount: root.collectiblesSpecificAmount + onSpecificAmountChanged: root.collectiblesSpecificAmount = specificAmount + + onPickerClicked: { + d.extendedDropdownType = ExtendedDropdownContent.Type.Collectibles + content.state = d.extendedState + } + + Connections { + target: d + + function onAddClicked() { + root.addItem(root.itemKey, qsTr("%1 %2").arg(root.collectibleAmount.toString()).arg(root.collectibleName), + root.tokenImage, root.operator) } } } @@ -294,21 +248,23 @@ StatusDropdown { // TODO Component { id: ensLayout - Item {} - } + EnsPanel {} + } Component { id: extendedView ExtendedDropdownContent { + id: extendedDropdown + store: root.store - type: d.isTokensLayout ? ExtendedDropdownContent.Type.Tokens : ExtendedDropdownContent.Type.Collectibles - onGoBack: loader.sourceComponent = tabsView + type: d.extendedDropdownType + onItemClicked: { // Go back - loader.sourceComponent = tabsView + content.state = d.tabsState - if(d.isTokensLayout) { + if(d.extendedDropdownType === ExtendedDropdownContent.Type.Tokens) { // Update new token item info root.tokenName = name root.tokenImage = iconSource @@ -318,8 +274,20 @@ StatusDropdown { root.collectibleName = name root.collectibleImage = iconSource } + root.itemKey = key } + + Connections { + target: backButton + + function onClicked() { + if (extendedDropdown.canGoBack) + extendedDropdown.goBack() + else + content.state = d.tabsState + } + } } } } diff --git a/ui/app/AppLayouts/Chat/controls/community/HoldingsTabs.qml b/ui/app/AppLayouts/Chat/controls/community/HoldingsTabs.qml new file mode 100644 index 0000000000..3a23912c9c --- /dev/null +++ b/ui/app/AppLayouts/Chat/controls/community/HoldingsTabs.qml @@ -0,0 +1,59 @@ +import QtQuick 2.14 + +import StatusQ.Core 0.1 +import StatusQ.Components 0.1 +import StatusQ.Controls 0.1 + + +Item { + property alias addButtonEnabled: addButton.enabled + property alias tabLabels: tabLabelsRepeater.model + + property alias currentIndex: tabBar.currentIndex + property alias sourceComponent: tabsLoader.sourceComponent + + readonly property alias item: tabsLoader.item + + signal addClicked + + StatusSwitchTabBar { + id: tabBar + + anchors.top: parent.top + anchors.right: parent.right + anchors.left: parent.left + + height: 36 // by design + + Repeater { + id: tabLabelsRepeater + + StatusSwitchTabButton { + text: modelData + fontPixelSize: 13 + } + } + } + + Loader { + id: tabsLoader + + anchors.top: tabBar.bottom + anchors.right: parent.right + anchors.left: parent.left + anchors.topMargin: 16 + } + + StatusButton { + id: addButton + + text: qsTr("Add") + height: 44 + + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.left: parent.left + + onClicked: addClicked() + } +} diff --git a/ui/app/AppLayouts/Chat/controls/community/ListDropdownContent.qml b/ui/app/AppLayouts/Chat/controls/community/ListDropdownContent.qml index 56790a7632..b38f3c5994 100644 --- a/ui/app/AppLayouts/Chat/controls/community/ListDropdownContent.qml +++ b/ui/app/AppLayouts/Chat/controls/community/ListDropdownContent.qml @@ -33,7 +33,7 @@ StatusListView { id: columnHeader anchors.top: parent.top anchors.left: parent.left - anchors.leftMargin: 16 + anchors.leftMargin: 6 anchors.rightMargin: anchors.leftMargin anchors.topMargin: 8 anchors.bottomMargin: 2 * anchors.topMargin @@ -59,7 +59,7 @@ StatusListView { color: mouseArea.containsMouse ? Theme.palette.baseColor4 : "transparent" RowLayout { anchors.fill: parent - anchors.leftMargin: 14 + anchors.leftMargin: 6 spacing: 8 StatusRoundedImage { Layout.alignment: Qt.AlignVCenter @@ -114,7 +114,7 @@ StatusListView { width: ListView.view.width height: 34 // by design StatusBaseText { - anchors.leftMargin: 18 + anchors.leftMargin: 8 anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter text: section diff --git a/ui/app/AppLayouts/Chat/controls/community/OperatorsSelector.qml b/ui/app/AppLayouts/Chat/controls/community/OperatorsSelector.qml new file mode 100644 index 0000000000..a65f26d3dd --- /dev/null +++ b/ui/app/AppLayouts/Chat/controls/community/OperatorsSelector.qml @@ -0,0 +1,48 @@ +import QtQuick.Layouts 1.14 +import QtQuick 2.14 + +import StatusQ.Controls 0.1 +import StatusQ.Core.Theme 0.1 +import StatusQ.Core.Utils 0.1 as SQ + +import utils 1.0 + +ColumnLayout { + id: root + + signal operatorSelected(int operator) + + spacing: 8 + + Repeater { + model: [ + { + icon: "add", + text: qsTr("And..."), + operator: SQ.Utils.Operators.And + }, + { + icon: "condition-Or", + text: qsTr("Or..."), + operator: SQ.Utils.Operators.Or + } + ] + + delegate: StatusPickerButton { + Layout.fillWidth: true + Layout.preferredHeight: 36 + horizontalPadding: 12 + spacing: 10 + bgColor: Theme.palette.primaryColor3 + contentColor: Theme.palette.primaryColor1 + asset.name: Style.svg(modelData.icon) + asset.isImage: true + asset.height: 12 + asset.width: 12 + text: modelData.text + font.pixelSize: 13 + + onClicked: root.operatorSelected(modelData.operator) + } + } +} diff --git a/ui/app/AppLayouts/Chat/controls/community/TokensPanel.qml b/ui/app/AppLayouts/Chat/controls/community/TokensPanel.qml new file mode 100644 index 0000000000..a46fade3a4 --- /dev/null +++ b/ui/app/AppLayouts/Chat/controls/community/TokensPanel.qml @@ -0,0 +1,59 @@ +import QtQuick 2.14 +import QtQuick.Layouts 1.14 + +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 +import StatusQ.Controls 0.1 +import StatusQ.Controls.Validators 0.1 + +ColumnLayout { + id: root + + property alias tokenName: pickerButton.text + property url tokenImage + property alias amount: amountInput.text + + signal pickerClicked + + spacing: 0 + + StatusPickerButton { + id: pickerButton + + Layout.fillWidth: true + Layout.preferredHeight: 36 + + bgColor: Theme.palette.baseColor5 + contentColor: Theme.palette.directColor1 + font.pixelSize: 13 + asset.name: root.tokenImage + + onClicked: pickerClicked() + } + + StatusInput { + id: amountInput + + Layout.fillWidth: true + Layout.topMargin: 8 + minimumHeight: 36 + maximumHeight: 36 + topPadding: 0 + bottomPadding: 0 + font.pixelSize: 13 + rightPadding: amountText.implicitWidth + amountText.anchors.rightMargin + leftPadding + input.placeholderText: "0" + validationMode: StatusInput.ValidationMode.IgnoreInvalidInput + validators: StatusFloatValidator { bottom: 0 } + + StatusBaseText { + id: amountText + anchors.right: parent.right + anchors.rightMargin: 13 + anchors.verticalCenter: parent.verticalCenter + text: qsTr("Amount") + color: Theme.palette.baseColor1 + font.pixelSize: 13 + } + } +} diff --git a/ui/app/AppLayouts/Chat/layouts/SettingsPageLayout.qml b/ui/app/AppLayouts/Chat/layouts/SettingsPageLayout.qml index 01fdab803d..1a07908d08 100644 --- a/ui/app/AppLayouts/Chat/layouts/SettingsPageLayout.qml +++ b/ui/app/AppLayouts/Chat/layouts/SettingsPageLayout.qml @@ -90,7 +90,7 @@ Item { } active: root.dirty flickable: root.contentItem - saveChangesButtonEnabled: root.contentItem && root.contentItem.saveChangesButtonEnabled + saveChangesButtonEnabled: !!root.contentItem && !!root.contentItem.saveChangesButtonEnabled onResetChangesClicked: root.resetChangesClicked() onSaveChangesClicked: root.saveChangesClicked() }