feat(Community Permissions): Add search option in assets / collectibles dropdown
Closes: #9042
This commit is contained in:
parent
fc5dbf0d2c
commit
bd6dc02162
|
@ -44,6 +44,18 @@ ListModel {
|
||||||
iconSource: ModelsData.collectibles.kitty5,
|
iconSource: ModelsData.collectibles.kitty5,
|
||||||
imageSource: ModelsData.collectibles.kitty5Big,
|
imageSource: ModelsData.collectibles.kitty5Big,
|
||||||
name: "Magicat-3"
|
name: "Magicat-3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "Kitty5",
|
||||||
|
iconSource: ModelsData.collectibles.kitty4,
|
||||||
|
imageSource: ModelsData.collectibles.kitty4Big,
|
||||||
|
name: "Furbeard-3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "Kitty6",
|
||||||
|
iconSource: ModelsData.collectibles.kitty5,
|
||||||
|
imageSource: ModelsData.collectibles.kitty5Big,
|
||||||
|
name: "Magicat-4"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import QtQuick 2.13
|
import QtQuick 2.14
|
||||||
import QtQuick.Controls 2.13
|
import QtQuick.Controls 2.14
|
||||||
import QtQuick.Layouts 1.14
|
import QtQuick.Layouts 1.14
|
||||||
|
import QtQml 2.14
|
||||||
|
|
||||||
|
import Qt.labs.settings 1.0
|
||||||
|
|
||||||
import StatusQ.Controls 0.1
|
import StatusQ.Controls 0.1
|
||||||
import StatusQ.Core.Theme 0.1
|
import StatusQ.Core.Theme 0.1
|
||||||
|
@ -19,7 +22,7 @@ Item {
|
||||||
property var checkedKeys: []
|
property var checkedKeys: []
|
||||||
property int type: ExtendedDropdownContent.Type.Assets
|
property int type: ExtendedDropdownContent.Type.Assets
|
||||||
|
|
||||||
readonly property bool canGoBack: root.state !== d.listView_depth1_State
|
readonly property bool canGoBack: root.state !== d.depth1_ListState
|
||||||
|
|
||||||
signal itemClicked(string key, string name, url iconSource)
|
signal itemClicked(string key, string name, url iconSource)
|
||||||
signal navigateDeep(string key, var subItems)
|
signal navigateDeep(string key, var subItems)
|
||||||
|
@ -30,7 +33,7 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
function goBack() {
|
function goBack() {
|
||||||
root.state = d.listView_depth1_State
|
d.reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
function goForward(key, itemName, itemSource, subItems) {
|
function goForward(key, itemName, itemSource, subItems) {
|
||||||
|
@ -38,53 +41,81 @@ Item {
|
||||||
d.currentItemKey = key
|
d.currentItemKey = key
|
||||||
d.currentItemName = itemName
|
d.currentItemName = itemName
|
||||||
d.currentItemSource = itemSource
|
d.currentItemSource = itemSource
|
||||||
root.state = d.listView_depth2_State
|
root.state = d.useThumbnailsOnDepth2
|
||||||
|
? d.depth2_ThumbnailsState : d.depth2_ListState
|
||||||
|
}
|
||||||
|
|
||||||
|
Settings {
|
||||||
|
property alias useThumbnailsOnDepth2: d.useThumbnailsOnDepth2
|
||||||
}
|
}
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
id: d
|
id: d
|
||||||
|
|
||||||
readonly property int filterItemsHeight: 36
|
readonly property int filterItemsHeight: 36
|
||||||
readonly property int filterPopupWidth: 233
|
readonly property int filterPopupWidth: 233
|
||||||
readonly property int filterPopupHeight: 205
|
|
||||||
|
|
||||||
// Internal management properties
|
// Internal management properties
|
||||||
property bool isFilterOptionVisible: false
|
property bool isFilterOptionVisible: false
|
||||||
readonly property string thumbnailsViewState: "THUMBNAILS"
|
property bool useThumbnailsOnDepth2: false
|
||||||
readonly property string listView_depth1_State: "LIST-DEPTH1"
|
|
||||||
readonly property string listView_depth2_State: "LIST-DEPTH2"
|
readonly property string depth1_ListState: "DEPTH-1-LIST"
|
||||||
property var currentModel: root.store.collectiblesModel
|
readonly property string depth2_ListState: "DEPTH-2-LIST"
|
||||||
property var currentSubitems
|
readonly property string depth2_ThumbnailsState: "DEPTH-2-THUMBNAILS"
|
||||||
|
|
||||||
|
property var currentModel: null
|
||||||
|
property var currentSubitems: null
|
||||||
property string currentItemKey: ""
|
property string currentItemKey: ""
|
||||||
property string currentItemName: ""
|
property string currentItemName: ""
|
||||||
property url currentItemSource: ""
|
property url currentItemSource: ""
|
||||||
|
|
||||||
readonly property SortFilterProxyModel filtered: SortFilterProxyModel {
|
readonly property bool searchMode: searcher.text.length > 0
|
||||||
id: collectiblesFilteredModel
|
|
||||||
|
|
||||||
sourceModel: root.store.collectiblesModel
|
onCurrentModelChanged: {
|
||||||
|
// Workaround for a bug in SortFilterProxyModel causing that model
|
||||||
|
// is rendered incorrectly when sourceModel is changed to a model
|
||||||
|
// with different set of roles
|
||||||
|
filteredModel.active = false
|
||||||
|
filteredModel.active = true
|
||||||
|
|
||||||
filters: ExpressionFilter {
|
searcher.text = ""
|
||||||
expression: {
|
filteredModel.item.sourceModel = currentModel
|
||||||
searcher.text
|
contentLoader.item.model = filteredModel.item
|
||||||
return name.toLowerCase().includes(searcher.text.toLowerCase())
|
}
|
||||||
|
|
||||||
|
readonly property Loader loader_: Loader {
|
||||||
|
id: filteredModel
|
||||||
|
|
||||||
|
sourceComponent: SortFilterProxyModel {
|
||||||
|
filters: ExpressionFilter {
|
||||||
|
expression: {
|
||||||
|
searcher.text
|
||||||
|
|
||||||
|
if (model.shortName && model.shortName.toLowerCase()
|
||||||
|
.includes(searcher.text.toLowerCase()))
|
||||||
|
return true
|
||||||
|
|
||||||
|
return model.name.toLowerCase().includes(
|
||||||
|
searcher.text.toLowerCase())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function reset() {
|
function reset() {
|
||||||
|
searcher.text = ""
|
||||||
d.currentItemKey = ""
|
d.currentItemKey = ""
|
||||||
d.currentItemName = ""
|
d.currentItemName = ""
|
||||||
d.currentItemSource = ""
|
d.currentItemSource = ""
|
||||||
d.currentModel = root.store.collectiblesModel
|
d.currentSubitems = null
|
||||||
d.currentSubitems = undefined
|
root.state = d.depth1_ListState
|
||||||
root.state = d.listView_depth1_State
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
state: d.listView_depth1_State
|
state: d.depth1_ListState
|
||||||
states: [
|
states: [
|
||||||
State {
|
State {
|
||||||
name: d.listView_depth1_State
|
name: d.depth1_ListState
|
||||||
|
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: contentLoader
|
target: contentLoader
|
||||||
|
@ -94,20 +125,17 @@ Item {
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: d
|
target: d
|
||||||
currentModel: root.type === ExtendedDropdownContent.Type.Assets
|
currentModel: root.type === ExtendedDropdownContent.Type.Assets
|
||||||
? root.store.assetsModel : collectiblesFilteredModel//root.store.collectiblesModel
|
? root.store.assetsModel : root.store.collectiblesModel
|
||||||
isFilterOptionVisible: false
|
isFilterOptionVisible: false
|
||||||
}
|
}
|
||||||
|
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: tokenGroupItem
|
target: tokenGroupItem
|
||||||
visible: false
|
visible: false
|
||||||
}
|
}
|
||||||
PropertyChanges {
|
|
||||||
target: searcher
|
|
||||||
visible: type === ExtendedDropdownContent.Type.Collectibles
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
State {
|
State {
|
||||||
name: d.listView_depth2_State
|
name: d.depth2_ListState
|
||||||
|
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: contentLoader
|
target: contentLoader
|
||||||
|
@ -124,7 +152,7 @@ Item {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
State {
|
State {
|
||||||
name: d.thumbnailsViewState
|
name: d.depth2_ThumbnailsState
|
||||||
|
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
target: contentLoader
|
target: contentLoader
|
||||||
|
@ -164,23 +192,29 @@ Item {
|
||||||
// Filter options popup:
|
// Filter options popup:
|
||||||
StatusDropdown {
|
StatusDropdown {
|
||||||
id: filterOptionsPopup
|
id: filterOptionsPopup
|
||||||
|
|
||||||
width: d.filterPopupWidth
|
width: d.filterPopupWidth
|
||||||
height: d.filterPopupHeight
|
|
||||||
contentItem: ColumnLayout {
|
contentItem: ColumnLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.topMargin: 8
|
anchors.topMargin: 8
|
||||||
anchors.bottomMargin: 8
|
anchors.bottomMargin: 8
|
||||||
ListView {
|
|
||||||
Layout.fillWidth: true
|
spacing: 0
|
||||||
Layout.preferredHeight: model.count * d.filterItemsHeight
|
|
||||||
|
// TODO: it can be simplified by using inline components after
|
||||||
|
// migration to Qt 5.15 or higher
|
||||||
|
Repeater {
|
||||||
model: ListModel {
|
model: ListModel {
|
||||||
ListElement { text: qsTr("Most viewed"); selected: true }
|
ListElement { text: qsTr("Most viewed"); selected: true }
|
||||||
ListElement { text: qsTr("Newest first"); selected: false }
|
ListElement { text: qsTr("Newest first"); selected: false }
|
||||||
ListElement { text: qsTr("Oldest first"); selected: false }
|
ListElement { text: qsTr("Oldest first"); selected: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate: StatusItemPicker {
|
delegate: StatusItemPicker {
|
||||||
width: ListView.view.width
|
Layout.fillWidth: true
|
||||||
height: d.filterItemsHeight
|
Layout.preferredHeight: d.filterItemsHeight
|
||||||
|
|
||||||
color: sensor1.containsMouse ? Theme.palette.baseColor4 : "transparent"
|
color: sensor1.containsMouse ? Theme.palette.baseColor4 : "transparent"
|
||||||
name: model.text
|
name: model.text
|
||||||
namePixelSize: 13
|
namePixelSize: 13
|
||||||
|
@ -201,25 +235,28 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not visual element to control filter options
|
|
||||||
ButtonGroup {
|
|
||||||
id: filterRadioBtnGroup
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Separator { Layout.fillWidth: true }
|
ButtonGroup {
|
||||||
|
id: filterRadioBtnGroup
|
||||||
|
}
|
||||||
|
|
||||||
ListView {
|
Separator {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: model.count * d.filterItemsHeight
|
Layout.topMargin: 5
|
||||||
|
Layout.bottomMargin: 5
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater {
|
||||||
model: ListModel {
|
model: ListModel {
|
||||||
ListElement { key: "LIST"; text: qsTr("List"); selected: true }
|
ListElement { key: "LIST"; text: qsTr("List"); selected: true }
|
||||||
ListElement { key: "THUMBNAILS"; text: qsTr("Thumbnails"); selected: false }
|
ListElement { key: "THUMBNAILS"; text: qsTr("Thumbnails"); selected: false }
|
||||||
}
|
}
|
||||||
delegate: StatusItemPicker {
|
|
||||||
width: ListView.view.width
|
delegate: StatusItemPicker {
|
||||||
height: d.filterItemsHeight
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: d.filterItemsHeight
|
||||||
|
|
||||||
color: sensor2.containsMouse ? Theme.palette.baseColor4 : "transparent"
|
color: sensor2.containsMouse ? Theme.palette.baseColor4 : "transparent"
|
||||||
name: model.text
|
name: model.text
|
||||||
namePixelSize: 13
|
namePixelSize: 13
|
||||||
|
@ -236,21 +273,28 @@ Item {
|
||||||
onClicked: {
|
onClicked: {
|
||||||
selected = !selected
|
selected = !selected
|
||||||
if(model.key === "LIST") {
|
if(model.key === "LIST") {
|
||||||
root.state = d.listView_depth2_State
|
root.state = d.depth2_ListState
|
||||||
}
|
}
|
||||||
else if(model.key === "THUMBNAILS") {
|
else if(model.key === "THUMBNAILS") {
|
||||||
root.state = d.thumbnailsViewState
|
root.state = d.depth2_ThumbnailsState
|
||||||
}
|
}
|
||||||
filterOptionsPopup.close()
|
filterOptionsPopup.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Not visual element to control visualization options
|
Binding {
|
||||||
ButtonGroup {
|
target: d
|
||||||
id: visualizationRadioBtnGroup
|
when: model.key === "THUMBNAILS" && selected
|
||||||
|
property: "useThumbnailsOnDepth2"
|
||||||
|
value: true
|
||||||
|
restoreMode: Binding.RestoreBindingOrValue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ButtonGroup {
|
||||||
|
id: visualizationRadioBtnGroup
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,12 +307,20 @@ Item {
|
||||||
id: searcher
|
id: searcher
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: root.state === d.depth1_ListState ? 0 : 8
|
||||||
|
|
||||||
visible: false
|
|
||||||
topPadding: 0
|
topPadding: 0
|
||||||
bottomPadding: 0
|
bottomPadding: 0
|
||||||
minimumHeight: 36
|
minimumHeight: 36
|
||||||
maximumHeight: 36
|
maximumHeight: 36
|
||||||
|
|
||||||
|
placeholderText: root.type === ExtendedDropdownContent.Type.Assets ?
|
||||||
|
qsTr("Search assets") : qsTr("Search collectibles")
|
||||||
|
|
||||||
|
Binding on placeholderText{
|
||||||
|
when: d.currentItemName !== ""
|
||||||
|
value: qsTr("Search %1").arg(d.currentItemName)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TokenItem {
|
TokenItem {
|
||||||
|
@ -277,7 +329,7 @@ Item {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
key: d.currentItemKey
|
key: d.currentItemKey
|
||||||
name: d.currentItemName
|
name: qsTr("Any %1").arg(d.currentItemName)
|
||||||
iconSource: d.currentItemSource
|
iconSource: d.currentItemSource
|
||||||
|
|
||||||
selected: root.checkedKeys.includes(key)
|
selected: root.checkedKeys.includes(key)
|
||||||
|
@ -292,7 +344,6 @@ Item {
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,9 +355,9 @@ Item {
|
||||||
ListElement { key: "MINT"; icon: "add"; iconSize: 16; description: qsTr("Mint asset"); rotation: 0; spacing: 8 }
|
ListElement { key: "MINT"; icon: "add"; iconSize: 16; description: qsTr("Mint asset"); rotation: 0; spacing: 8 }
|
||||||
ListElement { key: "IMPORT"; icon: "invite-users"; iconSize: 16; description: qsTr("Import existing asset"); rotation: 180; spacing: 8 }
|
ListElement { key: "IMPORT"; icon: "invite-users"; iconSize: 16; description: qsTr("Import existing asset"); rotation: 180; spacing: 8 }
|
||||||
}
|
}
|
||||||
isHeaderVisible: false // TEMPORARILY hidden. These 2 header options will be implemented after MVP.
|
areHeaderButtonsVisible: false // TEMPORARILY hidden. These 2 header options will be implemented after MVP.
|
||||||
model: d.currentModel
|
|
||||||
checkedKeys: root.checkedKeys
|
checkedKeys: root.checkedKeys
|
||||||
|
searchMode: d.searchMode
|
||||||
|
|
||||||
onHeaderItemClicked: {
|
onHeaderItemClicked: {
|
||||||
if(key === "MINT") console.log("TODO: Mint asset")
|
if(key === "MINT") console.log("TODO: Mint asset")
|
||||||
|
@ -320,25 +371,26 @@ Item {
|
||||||
id: collectiblesListView
|
id: collectiblesListView
|
||||||
|
|
||||||
ListDropdownContent {
|
ListDropdownContent {
|
||||||
isHeaderVisible: root.state === d.listView_depth1_State
|
areHeaderButtonsVisible: root.state === d.depth1_ListState
|
||||||
headerModel: ListModel {
|
headerModel: ListModel {
|
||||||
ListElement { key: "MINT"; icon: "add"; iconSize: 16; description: qsTr("Mint collectible"); rotation: 0; spacing: 8 }
|
ListElement { key: "MINT"; icon: "add"; iconSize: 16; description: qsTr("Mint collectible"); rotation: 0; spacing: 8 }
|
||||||
}
|
}
|
||||||
|
|
||||||
model: d.currentModel
|
|
||||||
checkedKeys: root.checkedKeys
|
checkedKeys: root.checkedKeys
|
||||||
|
searchMode: d.searchMode
|
||||||
|
|
||||||
onHeaderItemClicked: {
|
onHeaderItemClicked: {
|
||||||
if(key === "MINT") console.log("TODO: Mint collectible")
|
if(key === "MINT") console.log("TODO: Mint collectible")
|
||||||
}
|
}
|
||||||
onItemClicked: {
|
onItemClicked: {
|
||||||
if(subItems && root.state === d.listView_depth1_State) {
|
if(subItems && root.state === d.depth1_ListState) {
|
||||||
// One deep navigation
|
// One deep navigation
|
||||||
d.currentSubitems = subItems
|
d.currentSubitems = subItems
|
||||||
d.currentItemKey = key
|
d.currentItemKey = key
|
||||||
d.currentItemName = name
|
d.currentItemName = name
|
||||||
d.currentItemSource = iconSource
|
d.currentItemSource = iconSource
|
||||||
root.state = d.listView_depth2_State
|
root.state = d.useThumbnailsOnDepth2
|
||||||
|
? d.depth2_ThumbnailsState : d.depth2_ListState
|
||||||
root.navigateDeep(key, subItems)
|
root.navigateDeep(key, subItems)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -355,12 +407,10 @@ Item {
|
||||||
ThumbnailsDropdownContent {
|
ThumbnailsDropdownContent {
|
||||||
title: d.currentItemName
|
title: d.currentItemName
|
||||||
titleImage: d.currentItemSource
|
titleImage: d.currentItemSource
|
||||||
|
checkedKeys: root.checkedKeys
|
||||||
|
|
||||||
padding: 0
|
padding: 0
|
||||||
|
|
||||||
model: d.currentModel
|
|
||||||
checkedKeys: root.checkedKeys
|
|
||||||
|
|
||||||
onItemClicked: {
|
onItemClicked: {
|
||||||
d.reset()
|
d.reset()
|
||||||
root.itemClicked(key, name, iconSource)
|
root.itemClicked(key, name, iconSource)
|
||||||
|
|
|
@ -204,7 +204,7 @@ StatusDropdown {
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
id: tabLabelsRepeater
|
id: tabLabelsRepeater
|
||||||
model: [qsTr("Asset"), qsTr("Collectible"), qsTr("ENS")]
|
model: [qsTr("Assets"), qsTr("Collectibles"), qsTr("ENS")]
|
||||||
|
|
||||||
StatusSwitchTabButton {
|
StatusSwitchTabButton {
|
||||||
text: modelData
|
text: modelData
|
||||||
|
|
|
@ -15,7 +15,9 @@ StatusListView {
|
||||||
property var checkedKeys: []
|
property var checkedKeys: []
|
||||||
|
|
||||||
property var headerModel
|
property var headerModel
|
||||||
property bool isHeaderVisible: true
|
property bool areHeaderButtonsVisible: true
|
||||||
|
property bool searchMode: false
|
||||||
|
|
||||||
property int maxHeight: 381 // default by design
|
property int maxHeight: 381 // default by design
|
||||||
|
|
||||||
signal headerItemClicked(string key)
|
signal headerItemClicked(string key)
|
||||||
|
@ -25,36 +27,56 @@ StatusListView {
|
||||||
implicitHeight: Math.min(contentHeight, root.maxHeight)
|
implicitHeight: Math.min(contentHeight, root.maxHeight)
|
||||||
currentIndex: -1
|
currentIndex: -1
|
||||||
clip: true
|
clip: true
|
||||||
header: Rectangle {
|
|
||||||
visible: root.isHeaderVisible
|
header: ColumnLayout {
|
||||||
z: 3 // Above delegate (z=1) and above section.delegate (z = 2)
|
|
||||||
color: Theme.palette.statusMenu.backgroundColor
|
|
||||||
width: root.width
|
width: root.width
|
||||||
height: root.isHeaderVisible ? columnHeader.implicitHeight + 2 * columnHeader.anchors.topMargin : 0
|
|
||||||
ColumnLayout {
|
spacing: 0
|
||||||
id: columnHeader
|
|
||||||
anchors.top: parent.top
|
Item {
|
||||||
anchors.left: parent.left
|
Layout.fillWidth: true
|
||||||
anchors.leftMargin: 6
|
Layout.preferredHeight: root.areHeaderButtonsVisible
|
||||||
anchors.rightMargin: anchors.leftMargin
|
? columnHeader.implicitHeight + 2 * columnHeader.anchors.topMargin
|
||||||
anchors.topMargin: 8
|
: 0
|
||||||
anchors.bottomMargin: 2 * anchors.topMargin
|
|
||||||
spacing: 20
|
visible: root.areHeaderButtonsVisible
|
||||||
Repeater {
|
z: 3 // Above delegate (z=1) and above section.delegate (z = 2)
|
||||||
model: root.headerModel
|
|
||||||
delegate: StatusIconTextButton {
|
ColumnLayout {
|
||||||
z: 3 // Above delegate (z=1) and above section.delegate (z = 2)
|
id: columnHeader
|
||||||
spacing: model.spacing
|
|
||||||
statusIcon: model.icon
|
anchors.top: parent.top
|
||||||
icon.width: model.iconSize
|
anchors.left: parent.left
|
||||||
icon.height: model.iconSize
|
anchors.leftMargin: 6
|
||||||
iconRotation: model.rotation
|
anchors.rightMargin: anchors.leftMargin
|
||||||
text: model.description
|
anchors.topMargin: 8
|
||||||
onClicked: root.headerItemClicked(model.index)
|
anchors.bottomMargin: 2 * anchors.topMargin
|
||||||
|
spacing: 20
|
||||||
|
Repeater {
|
||||||
|
model: root.headerModel
|
||||||
|
delegate: StatusIconTextButton {
|
||||||
|
z: 3 // Above delegate (z=1) and above section.delegate (z = 2)
|
||||||
|
spacing: model.spacing
|
||||||
|
statusIcon: model.icon
|
||||||
|
icon.width: model.iconSize
|
||||||
|
icon.height: model.iconSize
|
||||||
|
iconRotation: model.rotation
|
||||||
|
text: model.description
|
||||||
|
onClicked: root.headerItemClicked(model.index)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}// End of Header
|
|
||||||
|
Loader {
|
||||||
|
Layout.preferredHeight: visible ? d.sectionHeight : 0
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
visible: root.searchMode
|
||||||
|
sourceComponent: sectionComponent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
delegate: TokenItem {
|
delegate: TokenItem {
|
||||||
width: ListView.view.width
|
width: ListView.view.width
|
||||||
key: model.key
|
key: model.key
|
||||||
|
@ -70,19 +92,52 @@ StatusListView {
|
||||||
model.iconSource,
|
model.iconSource,
|
||||||
model.subItems)
|
model.subItems)
|
||||||
}
|
}
|
||||||
section.property: "category"
|
|
||||||
|
section.property: root.searchMode ? "" : "category"
|
||||||
section.criteria: ViewSection.FullString
|
section.criteria: ViewSection.FullString
|
||||||
|
|
||||||
section.delegate: Item {
|
section.delegate: Item {
|
||||||
width: ListView.view.width
|
width: ListView.view.width
|
||||||
height: 34 // by design
|
height: d.sectionHeight
|
||||||
StatusBaseText {
|
|
||||||
anchors.leftMargin: 8
|
Loader {
|
||||||
anchors.left: parent.left
|
id: loader
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.fill: parent
|
||||||
text: section
|
sourceComponent: sectionComponent
|
||||||
color: Theme.palette.baseColor1
|
|
||||||
font.pixelSize: 12
|
Binding {
|
||||||
elide: Text.ElideRight
|
target: loader.item
|
||||||
|
property: "section"
|
||||||
|
value: section
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}// End of Category item
|
}
|
||||||
}// End of Root
|
|
||||||
|
QtObject {
|
||||||
|
id: d
|
||||||
|
|
||||||
|
readonly property int sectionHeight: 34
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: sectionComponent
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: sectionDelegateRoot
|
||||||
|
|
||||||
|
property string section: root.model && root.model.count ?
|
||||||
|
qsTr("Search result") :
|
||||||
|
qsTr("No results")
|
||||||
|
|
||||||
|
StatusBaseText {
|
||||||
|
anchors.leftMargin: 8
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
text: sectionDelegateRoot.section
|
||||||
|
color: Theme.palette.baseColor1
|
||||||
|
font.pixelSize: 12
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ StatusScrollView {
|
||||||
property string title: ""
|
property string title: ""
|
||||||
property url titleImage: ""
|
property url titleImage: ""
|
||||||
property string subtitle: ""
|
property string subtitle: ""
|
||||||
property ListModel model
|
property var model
|
||||||
property var checkedKeys: []
|
property var checkedKeys: []
|
||||||
|
|
||||||
property int maxHeight: 381 // default by design
|
property int maxHeight: 381 // default by design
|
||||||
|
@ -30,64 +30,82 @@ StatusScrollView {
|
||||||
clip: true
|
clip: true
|
||||||
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
||||||
|
|
||||||
GridLayout {
|
ColumnLayout {
|
||||||
id: grid
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
columnSpacing: 8
|
|
||||||
rowSpacing: 12
|
|
||||||
columns: d.columns
|
|
||||||
|
|
||||||
Repeater {
|
StatusBaseText {
|
||||||
model: root.model
|
Layout.leftMargin: 8
|
||||||
delegate: ColumnLayout {
|
Layout.topMargin: 8
|
||||||
spacing: 4
|
|
||||||
Rectangle {
|
|
||||||
Layout.preferredWidth: 133
|
|
||||||
Layout.preferredHeight: 133
|
|
||||||
color: "transparent"
|
|
||||||
Image {
|
|
||||||
source: model.imageSource ? model.imageSource : ""
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
Rectangle {
|
visible: !!model ? model.count === 0 : false
|
||||||
width: 32
|
|
||||||
height: 32
|
|
||||||
|
|
||||||
anchors.bottom: parent.bottom
|
Layout.fillWidth: true
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.margins: 8
|
|
||||||
|
|
||||||
radius: width / 2
|
text: qsTr("No results")
|
||||||
visible: root.checkedKeys.includes(model.key)
|
color: Theme.palette.baseColor1
|
||||||
// TODO: use color from theme when defined properly in the design
|
font.pixelSize: 12
|
||||||
color: "#F5F6F8"
|
wrapMode: Text.Wrap
|
||||||
|
}
|
||||||
|
|
||||||
StatusIcon {
|
GridLayout {
|
||||||
anchors.centerIn: parent
|
id: grid
|
||||||
icon: "checkmark"
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
Layout.fillWidth: true
|
||||||
|
columnSpacing: 8
|
||||||
|
rowSpacing: 12
|
||||||
|
columns: d.columns
|
||||||
|
|
||||||
color: Theme.palette.baseColor1
|
Repeater {
|
||||||
width: 16
|
model: root.model
|
||||||
height: 16
|
delegate: ColumnLayout {
|
||||||
|
spacing: 4
|
||||||
|
Rectangle {
|
||||||
|
Layout.preferredWidth: 133
|
||||||
|
Layout.preferredHeight: 133
|
||||||
|
color: "transparent"
|
||||||
|
Image {
|
||||||
|
source: model.imageSource ? model.imageSource : ""
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: 32
|
||||||
|
height: 32
|
||||||
|
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.margins: 8
|
||||||
|
|
||||||
|
radius: width / 2
|
||||||
|
visible: root.checkedKeys.includes(model.key)
|
||||||
|
// TODO: use color from theme when defined properly in the design
|
||||||
|
color: "#F5F6F8"
|
||||||
|
|
||||||
|
StatusIcon {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
icon: "checkmark"
|
||||||
|
|
||||||
|
color: Theme.palette.baseColor1
|
||||||
|
width: 16
|
||||||
|
height: 16
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
hoverEnabled: true
|
||||||
|
onClicked: { root.itemClicked(model.key, model.name, model.iconSource) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
MouseArea {
|
StatusBaseText {
|
||||||
anchors.fill: parent
|
Layout.alignment: Qt.AlignLeft
|
||||||
cursorShape: Qt.PointingHandCursor
|
Layout.leftMargin: 8
|
||||||
hoverEnabled: true
|
text: model.name
|
||||||
onClicked: { root.itemClicked(model.key, model.name, model.iconSource) }
|
color: Theme.palette.directColor1
|
||||||
|
font.pixelSize: 13
|
||||||
|
elide: Text.ElideRight
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StatusBaseText {
|
|
||||||
Layout.alignment: Qt.AlignLeft
|
|
||||||
Layout.leftMargin: 8
|
|
||||||
text: model.name
|
|
||||||
color: Theme.palette.directColor1
|
|
||||||
font.pixelSize: 13
|
|
||||||
elide: Text.ElideRight
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue