chore(StatusItemSelector): Use StatusFlowSelector as a base component

Closes: #9851
This commit is contained in:
Michał Cieślak 2023-03-13 11:02:41 +01:00 committed by Michał
parent 7df80bfa1c
commit bef14365aa
4 changed files with 97 additions and 123 deletions

View File

@ -14,11 +14,11 @@ ColumnLayout {
id: selector id: selector
icon: Style.png("tokens/SNT") icon: Style.png("tokens/SNT")
iconSize: 24
title: "Item Selector Title" title: "Item Selector Title"
defaultItemText: "Example: Empty items"
itemsModel: ListModel { placeholderText: "Example: Empty items"
model: ListModel {
id: model id: model
} }
@ -65,6 +65,6 @@ ColumnLayout {
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
text: "Clear list" text: "Clear list"
onClicked: { selector.itemsModel.clear() } onClicked: model.clear()
} }
} }

View File

@ -3,17 +3,19 @@ import QtQuick.Layouts 1.14
import StatusQ.Core 0.1 import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1 import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Core.Utils 0.1 import StatusQ.Core.Utils 0.1
/*! /*!
\qmltype StatusItemSelector \qmltype StatusItemSelector
\inherits Rectangle \inherits StatusFlowSelector
\inqmlmodule StatusQ.Components \inqmlmodule StatusQ.Components
\since StatusQ.Components 0.1 \since StatusQ.Components 0.1
\brief It allows to add items and display them as a tag item with an image and text. It also allows to store and display logical `and` / `or` operators into the list. Inherits \l{https://doc.qt.io/qt-6/qml-qtquick-rectangle.html}{Item}. \brief It allows to add items and display them as a tag item with an image
and text. It also allows to store and display logical `and` / `or` operators
into the list.
The \c StatusItemSelector is populated with a data model. The data model is commonly a JavaScript array or a ListModel object with specific expected roles. The \c StatusItemSelector is populated with a data model. The data model is
commonly a JavaScript array or a ListModel object with specific expected roles.
Example of how the component looks like: Example of how the component looks like:
\image status_item_selector.png \image status_item_selector.png
@ -40,45 +42,41 @@ import StatusQ.Core.Utils 0.1
\endqml \endqml
For a list of components available see StatusQ. For a list of components available see StatusQ.
*/ */
StatusGroupBox { StatusFlowSelector {
id: root id: root
/*! /*!
\qmlproperty string StatusItemSelector::defaultItemText \qmlproperty ListModel StatusItemSelector::model
This property holds the default item text shown when the list of items is empty.
*/
property string defaultItemText
/*!
\qmlproperty url StatusItemSelector::defaultItemImageSource
This property holds the default item icon shown when the list of items is empty.
*/
property url defaultItemImageSource: ""
/*!
\qmlproperty StatusRoundButton StatusItemSelector::addButton
This property holds an alias to the `add` button.
*/
readonly property alias addButton: addItemButton
/*!
\qmlproperty ListModel StatusItemSelector::itemsModel
This property holds the data that will be populated in the items selector. This property holds the data that will be populated in the items selector.
Here an example of the model roles expected: Here an example of the model roles expected:
\qml \qml
itemsModel: ListModel { model: ListModel {
ListElement { ListElement {
text: "Socks" text: "Socks"
imageSource: "qrc:imports/assets/png/tokens/SOCKS.png" imageSource: "qrc:imports/assets/png/tokens/SOCKS.png"
color: ""
emoji: ""
operator: Utils.Operator.None operator: Utils.Operator.None
} }
ListElement { ListElement {
text: "ZRX" text: "ZRX"
imageSource: "qrc:imports/assets/png/tokens/ZRX.png" imageSource: "qrc:imports/assets/png/tokens/ZRX.png"
color: ""
emoji: ""
operator: Utils.Operator.Or
}
ListElement {
text: "Custom Token"
imageSource: ""
color: "red"
emoji: "⚽"
operator: Utils.Operator.Or operator: Utils.Operator.Or
} }
} }
\endqml \endqml
*/ */
property var itemsModel: ListModel { } property alias model: repeater.model
/*! /*!
\qmlproperty bool StatusItemSelector::useIcons \qmlproperty bool StatusItemSelector::useIcons
This property determines if the imageSource role from the model will be handled as This property determines if the imageSource role from the model will be handled as
@ -115,84 +113,58 @@ StatusGroupBox {
*/ */
signal itemClicked(var item, int index, var mouse) signal itemClicked(var item, int index, var mouse)
placeholderItem.visible: repeater.count === 0
implicitWidth: 560 implicitWidth: 560
clip: true
Flow { Repeater {
id: flow id: repeater
clip: true RowLayout {
width: root.availableWidth spacing: flowSpacing
spacing: 6
StatusListItemTag { StatusBaseText {
bgColor: Theme.palette.baseColor2 visible: model.operator !== OperatorsUtils.Operators.None
visible: !itemsModel || itemsModel.count === 0 Layout.alignment: Qt.AlignVCenter
title: root.defaultItemText text: OperatorsUtils.setOperatorTextFormat(model.operator)
asset.name: root.defaultItemImageSource color: Theme.palette.primaryColor1
asset.isImage: true font.pixelSize: 17
closeButtonVisible: false MouseArea {
titleText.color: Theme.palette.baseColor1 anchors.fill: parent
titleText.font.pixelSize: 15 cursorShape: Qt.PointingHandCursor
} onClicked: {
Repeater { // Switch operator
model: itemsModel if(model.operator === OperatorsUtils.Operators.And)
model.operator = OperatorsUtils.Operators.Or
RowLayout { else
spacing: flow.spacing model.operator = OperatorsUtils.Operators.And
StatusBaseText {
visible: model.operator !== OperatorsUtils.Operators.None
Layout.alignment: Qt.AlignVCenter
text: OperatorsUtils.setOperatorTextFormat(model.operator)
color: Theme.palette.primaryColor1
font.pixelSize: 17
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
// Switch operator
if(model.operator === OperatorsUtils.Operators.And)
model.operator = OperatorsUtils.Operators.Or
else
model.operator = OperatorsUtils.Operators.And
}
}
}
StatusListItemTag {
title: model.text
asset.height: root.asset.height
asset.width: root.asset.width
asset.name: root.useLetterIdenticons ? model.text : (model.imageSource ?? "")
asset.isImage: root.asset.isImage
asset.bgColor: root.asset.bgColor
asset.emoji: model.emoji ? model.emoji : ""
asset.color: model.color ? model.color : ""
asset.isLetterIdenticon: root.useLetterIdenticons
//color: Theme.palette.primaryColor3
closeButtonVisible: false
titleText.color: Theme.palette.primaryColor1
titleText.font.pixelSize: 15
leftPadding: root.tagLeftPadding
MouseArea {
anchors.fill: parent
enabled: root.itemsClickable
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: root.itemClicked(parent, model.index, mouse)
} }
} }
} }
} StatusListItemTag {
StatusRoundButton { title: model.text
id: addItemButton
implicitHeight: 32 asset.height: root.asset.height
implicitWidth: implicitHeight asset.width: root.asset.width
height: width asset.name: root.useLetterIdenticons ? model.text : (model.imageSource ?? "")
type: StatusRoundButton.Type.Secondary asset.isImage: root.asset.isImage
icon.name: "add" asset.bgColor: root.asset.bgColor
asset.emoji: model.emoji ? model.emoji : ""
asset.color: model.color ? model.color : ""
asset.isLetterIdenticon: root.useLetterIdenticons
closeButtonVisible: false
titleText.color: Theme.palette.primaryColor1
titleText.font.pixelSize: 15
leftPadding: root.tagLeftPadding
MouseArea {
anchors.fill: parent
enabled: root.itemsClickable
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: root.itemClicked(parent, model.index, mouse)
}
}
} }
} }
} }

View File

@ -29,7 +29,7 @@ StatusScrollView {
property var selectedHoldingsModel: ListModel {} property var selectedHoldingsModel: ListModel {}
readonly property bool isFullyFilled: selectedHoldingsModel.count > 0 && readonly property bool isFullyFilled: selectedHoldingsModel.count > 0 &&
addressess.itemsModel.count > 0 addressess.model.count > 0
signal airdropClicked(var airdropTokens, string address) signal airdropClicked(var airdropTokens, string address)
@ -57,13 +57,13 @@ StatusScrollView {
Layout.fillWidth: true Layout.fillWidth: true
icon: Style.svg("token") icon: Style.svg("token")
title: qsTr("What") title: qsTr("What")
defaultItemText: qsTr("Example: 1 SOCK") placeholderText: qsTr("Example: 1 SOCK")
tagLeftPadding: 2 tagLeftPadding: 2
asset.height: 28 asset.height: 28
asset.width: asset.height asset.width: asset.height
addButton.visible: itemsModel.count < d.maxAirdropTokens addButton.visible: model.count < d.maxAirdropTokens
itemsModel: HoldingsSelectionModel { model: HoldingsSelectionModel {
sourceModel: root.selectedHoldingsModel sourceModel: root.selectedHoldingsModel
assetsModel: root.assetsModel assetsModel: root.assetsModel
@ -163,7 +163,7 @@ StatusScrollView {
dropdown.x = mouse.x + d.dropdownHorizontalOffset dropdown.x = mouse.x + d.dropdownHorizontalOffset
dropdown.y = d.dropdownVerticalOffset dropdown.y = d.dropdownVerticalOffset
const modelItem = tokensSelector.itemsModel.get(index) const modelItem = tokensSelector.model.get(index)
switch(modelItem.type) { switch(modelItem.type) {
case HoldingTypes.Type.Asset: case HoldingTypes.Type.Asset:
@ -213,17 +213,19 @@ StatusScrollView {
Layout.fillWidth: true Layout.fillWidth: true
icon: Style.svg("member") icon: Style.svg("member")
title: qsTr("To") title: qsTr("To")
defaultItemText: qsTr("Example: 12 addresses and 3 members") placeholderText: qsTr("Example: 12 addresses and 3 members")
tagLeftPadding: 2 tagLeftPadding: 2
asset.height: 28 asset.height: 28
asset.width: asset.height asset.width: asset.height
model: ListModel {}
addButton.onClicked: { addButton.onClicked: {
if(addressInput.text.length > 0) if(addressInput.text.length > 0)
itemsModel.append({text: addressInput.text}) model.append({text: addressInput.text})
} }
onItemClicked: addressess.itemsModel.remove(index) onItemClicked: addressess.model.remove(index)
} }
StatusButton { StatusButton {
@ -239,7 +241,7 @@ StatusScrollView {
root.selectedHoldingsModel, root.selectedHoldingsModel,
["key", "type", "amount"]) ["key", "type", "amount"])
root.airdropClicked(airdropTokens, addressess.itemsModel) root.airdropClicked(airdropTokens, addressess.model)
} }
} }
} }

View File

@ -96,11 +96,11 @@ StatusScrollView {
if (isCommunityPermission) { if (isCommunityPermission) {
d.dirtyValues.selectedChannelsModel.clear() d.dirtyValues.selectedChannelsModel.clear()
inSelector.wholeCommunitySelected = true inSelector.wholeCommunitySelected = true
inSelector.itemsModel = inModelCommunity inSelector.model = inModelCommunity
} else { } else {
inSelector.itemsModel = 0 inSelector.model = 0
inSelector.wholeCommunitySelected = false inSelector.wholeCommunitySelected = false
inSelector.itemsModel = channelsSelectionModel inSelector.model = channelsSelectionModel
} }
} }
@ -152,10 +152,10 @@ StatusScrollView {
(root.selectedChannelsModel.rowCount() (root.selectedChannelsModel.rowCount()
|| d.dirtyValues.permissionType === PermissionTypes.Type.None)) { || d.dirtyValues.permissionType === PermissionTypes.Type.None)) {
inSelector.wholeCommunitySelected = false inSelector.wholeCommunitySelected = false
inSelector.itemsModel = channelsSelectionModel inSelector.model = channelsSelectionModel
} else { } else {
inSelector.wholeCommunitySelected = true inSelector.wholeCommunitySelected = true
inSelector.itemsModel = inModelCommunity inSelector.model = inModelCommunity
} }
// Is private permission // Is private permission
@ -187,13 +187,13 @@ StatusScrollView {
Layout.fillWidth: true Layout.fillWidth: true
icon: Style.svg("contact_verified") icon: Style.svg("contact_verified")
title: qsTr("Who holds") title: qsTr("Who holds")
defaultItemText: qsTr("Example: 10 SNT") placeholderText: qsTr("Example: 10 SNT")
tagLeftPadding: 2 tagLeftPadding: 2
asset.height: 28 asset.height: 28
asset.width: asset.height asset.width: asset.height
addButton.visible: itemsModel.count < d.maxHoldingsItems addButton.visible: model.count < d.maxHoldingsItems
itemsModel: HoldingsSelectionModel { model: HoldingsSelectionModel {
sourceModel: d.dirtyValues.selectedHoldingsModel sourceModel: d.dirtyValues.selectedHoldingsModel
assetsModel: root.assetsModel assetsModel: root.assetsModel
@ -305,7 +305,7 @@ StatusScrollView {
dropdown.x = mouse.x + d.dropdownHorizontalOffset dropdown.x = mouse.x + d.dropdownHorizontalOffset
dropdown.y = d.dropdownVerticalOffset dropdown.y = d.dropdownVerticalOffset
const modelItem = tokensSelector.itemsModel.get(index) const modelItem = tokensSelector.model.get(index)
switch(modelItem.type) { switch(modelItem.type) {
case HoldingTypes.Type.Asset: case HoldingTypes.Type.Asset:
@ -343,7 +343,7 @@ StatusScrollView {
iconSize: 24 iconSize: 24
useIcons: true useIcons: true
title: qsTr("Is allowed to") title: qsTr("Is allowed to")
defaultItemText: qsTr("Example: View and post") placeholderText: qsTr("Example: View and post")
QtObject { QtObject {
id: permissionItemModelData id: permissionItemModelData
@ -353,8 +353,8 @@ StatusScrollView {
readonly property string imageSource: PermissionTypes.getIcon(key) readonly property string imageSource: PermissionTypes.getIcon(key)
} }
itemsModel: d.dirtyValues.permissionType !== PermissionTypes.Type.None model: d.dirtyValues.permissionType !== PermissionTypes.Type.None
? permissionItemModelData : null ? permissionItemModelData : null
addButton.visible: d.dirtyValues.permissionType === PermissionTypes.Type.None addButton.visible: d.dirtyValues.permissionType === PermissionTypes.Type.None
@ -413,7 +413,7 @@ StatusScrollView {
icon: d.isCommunityPermission ? Style.svg("communities") : Style.svg("create-category") icon: d.isCommunityPermission ? Style.svg("communities") : Style.svg("create-category")
iconSize: 24 iconSize: 24
title: qsTr("In") title: qsTr("In")
defaultItemText: qsTr("Example: `#general` channel") placeholderText: qsTr("Example: `#general` channel")
useLetterIdenticons: !wholeCommunitySelected || !inDropdown.communityImage useLetterIdenticons: !wholeCommunitySelected || !inDropdown.communityImage
@ -474,20 +474,20 @@ StatusScrollView {
onChannelsSelected: { onChannelsSelected: {
d.dirtyValues.selectedChannelsModel.clear() d.dirtyValues.selectedChannelsModel.clear()
inSelector.itemsModel = 0 inSelector.model = 0
inSelector.wholeCommunitySelected = false inSelector.wholeCommunitySelected = false
const modelData = channels.map(key => ({ key })) const modelData = channels.map(key => ({ key }))
d.dirtyValues.selectedChannelsModel.append(modelData) d.dirtyValues.selectedChannelsModel.append(modelData)
inSelector.itemsModel = channelsSelectionModel inSelector.model = channelsSelectionModel
close() close()
} }
onCommunitySelected: { onCommunitySelected: {
d.dirtyValues.selectedChannelsModel.clear() d.dirtyValues.selectedChannelsModel.clear()
inSelector.wholeCommunitySelected = true inSelector.wholeCommunitySelected = true
inSelector.itemsModel = inModelCommunity inSelector.model = inModelCommunity
close() close()
} }
} }