feat(communities/portal): add tags filtering
This commit is contained in:
parent
534a0d0f45
commit
27a9133882
|
@ -68,7 +68,7 @@ Item {
|
||||||
|
|
||||||
StatusCommunityTags {
|
StatusCommunityTags {
|
||||||
model: tagsModel
|
model: tagsModel
|
||||||
showOnlySelected: true
|
mode: StatusCommunityTags.ShowSelectedOnly
|
||||||
onClicked: {
|
onClicked: {
|
||||||
cntSelectedTags--;
|
cntSelectedTags--;
|
||||||
item.selected = false;
|
item.selected = false;
|
||||||
|
|
|
@ -3,14 +3,22 @@ import QtQuick 2.14
|
||||||
import StatusQ.Core 0.1
|
import StatusQ.Core 0.1
|
||||||
import StatusQ.Controls 0.1
|
import StatusQ.Controls 0.1
|
||||||
|
|
||||||
|
import SortFilterProxyModel 0.2
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property string filterString
|
property string filterString
|
||||||
property bool showOnlySelected: false
|
|
||||||
property bool active: true
|
property bool active: true
|
||||||
|
|
||||||
property alias model: repeater.model
|
enum Mode {
|
||||||
|
ShowUnselectedOnly,
|
||||||
|
ShowSelectedOnly,
|
||||||
|
Highlight
|
||||||
|
}
|
||||||
|
property int mode: StatusCommunityTags.ShowUnselectedOnly
|
||||||
|
|
||||||
|
property var model
|
||||||
property alias contentWidth: flow.width
|
property alias contentWidth: flow.width
|
||||||
|
|
||||||
readonly property int itemsWidth: {
|
readonly property int itemsWidth: {
|
||||||
|
@ -35,14 +43,39 @@ Item {
|
||||||
Repeater {
|
Repeater {
|
||||||
id: repeater
|
id: repeater
|
||||||
|
|
||||||
|
model: SortFilterProxyModel {
|
||||||
|
id: filterModel
|
||||||
|
|
||||||
|
sourceModel: root.model
|
||||||
|
|
||||||
|
function selectionPredicate(selected) {
|
||||||
|
return root.mode === StatusCommunityTags.ShowSelectedOnly ? selected : !selected
|
||||||
|
}
|
||||||
|
|
||||||
|
filters: [
|
||||||
|
ExpressionFilter {
|
||||||
|
enabled: root.filterString !== ""
|
||||||
|
expression: {
|
||||||
|
root.filterString
|
||||||
|
return model.name.toUpperCase().indexOf(root.filterString.toUpperCase()) !== -1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ExpressionFilter {
|
||||||
|
enabled: root.mode !== StatusCommunityTags.Highlight
|
||||||
|
expression: {
|
||||||
|
root.mode
|
||||||
|
return filterModel.selectionPredicate(model.selected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
delegate: StatusCommunityTag {
|
delegate: StatusCommunityTag {
|
||||||
emoji: model.emoji
|
emoji: model.emoji
|
||||||
name: model.name
|
name: model.name
|
||||||
visible: (root.showOnlySelected ? model.selected : !model.selected) &&
|
removable: root.mode === StatusCommunityTags.ShowSelectedOnly && root.active
|
||||||
(filterString == 0 || name.toUpperCase().indexOf(filterString.toUpperCase()) !== -1)
|
highlighted: root.mode === StatusCommunityTags.Highlight && model.selected
|
||||||
width: visible ? implicitWidth : -flow.spacing
|
|
||||||
height: visible ? implicitHeight : 0
|
|
||||||
removable: root.showOnlySelected && root.active
|
|
||||||
onClicked: root.clicked(model)
|
onClicked: root.clicked(model)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ Rectangle {
|
||||||
property string emoji
|
property string emoji
|
||||||
property string name
|
property string name
|
||||||
property bool removable: false
|
property bool removable: false
|
||||||
|
property bool highlighted: false
|
||||||
|
|
||||||
signal clicked()
|
signal clicked()
|
||||||
|
|
||||||
|
@ -18,7 +19,7 @@ Rectangle {
|
||||||
radius: height / 2
|
radius: height / 2
|
||||||
border.color: Theme.palette.baseColor2
|
border.color: Theme.palette.baseColor2
|
||||||
border.width: 1
|
border.width: 1
|
||||||
color: mouseArea.containsMouse ? Theme.palette.primaryColor2 : "transparent"
|
color: root.highlighted || mouseArea.containsMouse ? Theme.palette.primaryColor2 : "transparent"
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: mouseArea
|
id: mouseArea
|
||||||
|
|
|
@ -59,18 +59,33 @@ StatusSectionLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
SortFilterProxyModel {
|
SortFilterProxyModel {
|
||||||
id: searchModel
|
id: filteredCommunitiesModel
|
||||||
|
|
||||||
|
function selectedTagsPredicate(selectedTagsNames, tagsJSON) {
|
||||||
|
const tags = JSON.parse(tagsJSON)
|
||||||
|
for (const i in tags) {
|
||||||
|
selectedTagsNames = selectedTagsNames.filter(name => name !== tags[i].name)
|
||||||
|
}
|
||||||
|
return selectedTagsNames.length === 0
|
||||||
|
}
|
||||||
|
|
||||||
sourceModel: root.communitiesStore.curatedCommunitiesModel
|
sourceModel: root.communitiesStore.curatedCommunitiesModel
|
||||||
|
|
||||||
filters: ExpressionFilter {
|
filters: [
|
||||||
|
ExpressionFilter {
|
||||||
enabled: d.searchMode
|
enabled: d.searchMode
|
||||||
expression: {
|
expression: {
|
||||||
searcher.text
|
searcher.text
|
||||||
return name.toLowerCase().includes(searcher.text.toLowerCase())
|
return name.toLowerCase().includes(searcher.text.toLowerCase())
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
ExpressionFilter {
|
||||||
|
expression: {
|
||||||
|
return filteredCommunitiesModel.selectedTagsPredicate(communityTags.selectedTagsNames, model.tags)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
centerPanel: Item {
|
centerPanel: Item {
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
|
@ -137,8 +152,10 @@ StatusSectionLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
CommunityTagsRow {
|
CommunityTagsRow {
|
||||||
tags: root.communitiesStore.communityTags
|
id: communityTags
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
tags: root.communitiesStore.communityTags
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
@ -158,7 +175,7 @@ StatusSectionLayout {
|
||||||
bottomPadding: d.layoutBottomMargin
|
bottomPadding: d.layoutBottomMargin
|
||||||
|
|
||||||
locale: communitiesStore.locale
|
locale: communitiesStore.locale
|
||||||
model: searchModel
|
model: filteredCommunitiesModel
|
||||||
searchLayout: d.searchMode
|
searchLayout: d.searchMode
|
||||||
|
|
||||||
onCardClicked: d.navigateToCommunity(communityId)
|
onCardClicked: d.navigateToCommunity(communityId)
|
||||||
|
@ -168,7 +185,7 @@ StatusSectionLayout {
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
anchors.topMargin: parent.height / 3.1
|
anchors.topMargin: parent.height / 3.1
|
||||||
visible: d.searchMode && searchModel.count === 0
|
visible: d.searchMode && filteredCommunitiesModel.count === 0
|
||||||
text: qsTr("No communities found")
|
text: qsTr("No communities found")
|
||||||
color: Theme.palette.baseColor1
|
color: Theme.palette.baseColor1
|
||||||
font.pixelSize: 15
|
font.pixelSize: 15
|
||||||
|
|
|
@ -11,6 +11,7 @@ StatusRollArea {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property string tags
|
property string tags
|
||||||
|
property var selectedTagsNames: []
|
||||||
|
|
||||||
onTagsChanged: {
|
onTagsChanged: {
|
||||||
var obj = JSON.parse(tags);
|
var obj = JSON.parse(tags);
|
||||||
|
@ -19,16 +20,33 @@ StatusRollArea {
|
||||||
for (const key of Object.keys(obj)) {
|
for (const key of Object.keys(obj)) {
|
||||||
d.tagsModel.append({ name: key, emoji: obj[key], selected: false });
|
d.tagsModel.append({ name: key, emoji: obj[key], selected: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
d.evaluateSelectedTags()
|
||||||
}
|
}
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
id: d
|
id: d
|
||||||
|
|
||||||
property ListModel tagsModel: ListModel {}
|
property ListModel tagsModel: ListModel {}
|
||||||
|
|
||||||
|
function evaluateSelectedTags() {
|
||||||
|
let selectedTagsNames = []
|
||||||
|
for(let i = 0; i < tagsModel.count; i++) {
|
||||||
|
let tag = tagsModel.get(i)
|
||||||
|
if (tag.selected) selectedTagsNames.push(tag.name)
|
||||||
|
}
|
||||||
|
root.selectedTagsNames = selectedTagsNames
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
content: StatusCommunityTags {
|
content: StatusCommunityTags {
|
||||||
id: tagsFlow
|
id: tagsFlow
|
||||||
model: d.tagsModel
|
model: d.tagsModel
|
||||||
|
mode: StatusCommunityTags.Highlight
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
item.selected = !item.selected
|
||||||
|
d.evaluateSelectedTags()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,7 +126,7 @@ StatusScrollView {
|
||||||
|
|
||||||
StatusCommunityTags {
|
StatusCommunityTags {
|
||||||
model: d.tagsModel
|
model: d.tagsModel
|
||||||
showOnlySelected: true
|
mode: StatusCommunityTags.ShowSelectedOnly
|
||||||
onClicked: {
|
onClicked: {
|
||||||
d.cntSelectedTags--;
|
d.cntSelectedTags--;
|
||||||
item.selected = false;
|
item.selected = false;
|
||||||
|
|
Loading…
Reference in New Issue