diff --git a/ui/StatusQ/sandbox/pages/StatusCommunityTagsPage.qml b/ui/StatusQ/sandbox/pages/StatusCommunityTagsPage.qml index 13d702565d..4367b8c1db 100644 --- a/ui/StatusQ/sandbox/pages/StatusCommunityTagsPage.qml +++ b/ui/StatusQ/sandbox/pages/StatusCommunityTagsPage.qml @@ -68,7 +68,7 @@ Item { StatusCommunityTags { model: tagsModel - showOnlySelected: true + mode: StatusCommunityTags.ShowSelectedOnly onClicked: { cntSelectedTags--; item.selected = false; diff --git a/ui/StatusQ/src/StatusQ/Components/StatusCommunityTags.qml b/ui/StatusQ/src/StatusQ/Components/StatusCommunityTags.qml index bfd060aaf0..d9dc319040 100644 --- a/ui/StatusQ/src/StatusQ/Components/StatusCommunityTags.qml +++ b/ui/StatusQ/src/StatusQ/Components/StatusCommunityTags.qml @@ -3,14 +3,22 @@ import QtQuick 2.14 import StatusQ.Core 0.1 import StatusQ.Controls 0.1 +import SortFilterProxyModel 0.2 + Item { id: root property string filterString - property bool showOnlySelected: false 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 readonly property int itemsWidth: { @@ -35,16 +43,41 @@ Item { 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 { emoji: model.emoji name: model.name - visible: (root.showOnlySelected ? model.selected : !model.selected) && - (filterString == 0 || name.toUpperCase().indexOf(filterString.toUpperCase()) !== -1) - width: visible ? implicitWidth : -flow.spacing - height: visible ? implicitHeight : 0 - removable: root.showOnlySelected && root.active + removable: root.mode === StatusCommunityTags.ShowSelectedOnly && root.active + highlighted: root.mode === StatusCommunityTags.Highlight && model.selected + onClicked: root.clicked(model) } } } -} \ No newline at end of file +} diff --git a/ui/StatusQ/src/StatusQ/Controls/StatusCommunityTag.qml b/ui/StatusQ/src/StatusQ/Controls/StatusCommunityTag.qml index ef2624515b..5e06706fb2 100644 --- a/ui/StatusQ/src/StatusQ/Controls/StatusCommunityTag.qml +++ b/ui/StatusQ/src/StatusQ/Controls/StatusCommunityTag.qml @@ -10,6 +10,7 @@ Rectangle { property string emoji property string name property bool removable: false + property bool highlighted: false signal clicked() @@ -18,7 +19,7 @@ Rectangle { radius: height / 2 border.color: Theme.palette.baseColor2 border.width: 1 - color: mouseArea.containsMouse ? Theme.palette.primaryColor2 : "transparent" + color: root.highlighted || mouseArea.containsMouse ? Theme.palette.primaryColor2 : "transparent" MouseArea { id: mouseArea diff --git a/ui/app/AppLayouts/CommunitiesPortal/CommunitiesPortalLayout.qml b/ui/app/AppLayouts/CommunitiesPortal/CommunitiesPortalLayout.qml index 32f4397e5d..00847cdecd 100644 --- a/ui/app/AppLayouts/CommunitiesPortal/CommunitiesPortalLayout.qml +++ b/ui/app/AppLayouts/CommunitiesPortal/CommunitiesPortalLayout.qml @@ -59,17 +59,32 @@ StatusSectionLayout { } 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 - filters: ExpressionFilter { - enabled: d.searchMode - expression: { - searcher.text - return name.toLowerCase().includes(searcher.text.toLowerCase()) + filters: [ + ExpressionFilter { + enabled: d.searchMode + expression: { + searcher.text + return name.toLowerCase().includes(searcher.text.toLowerCase()) + } + }, + ExpressionFilter { + expression: { + return filteredCommunitiesModel.selectedTagsPredicate(communityTags.selectedTagsNames, model.tags) + } } - } + ] } centerPanel: Item { @@ -137,8 +152,10 @@ StatusSectionLayout { } CommunityTagsRow { - tags: root.communitiesStore.communityTags + id: communityTags Layout.fillWidth: true + + tags: root.communitiesStore.communityTags } Item { @@ -158,7 +175,7 @@ StatusSectionLayout { bottomPadding: d.layoutBottomMargin locale: communitiesStore.locale - model: searchModel + model: filteredCommunitiesModel searchLayout: d.searchMode onCardClicked: d.navigateToCommunity(communityId) @@ -168,7 +185,7 @@ StatusSectionLayout { anchors.top: parent.top anchors.horizontalCenter: parent.horizontalCenter anchors.topMargin: parent.height / 3.1 - visible: d.searchMode && searchModel.count === 0 + visible: d.searchMode && filteredCommunitiesModel.count === 0 text: qsTr("No communities found") color: Theme.palette.baseColor1 font.pixelSize: 15 @@ -223,7 +240,7 @@ StatusSectionLayout { CommunityBanner { property bool importInProgress: root.communitiesStore.discordImportInProgress && !root.communitiesStore.discordImportCancelled text: importInProgress ? - qsTr("'%1' import in progress...").arg(root.communitiesStore.discordImportCommunityName) : + qsTr("'%1' import in progress...").arg(root.communitiesStore.discordImportCommunityName) : qsTr("Import existing Discord community into Status") buttonText: qsTr("Import existing") icon.name: "download" diff --git a/ui/app/AppLayouts/CommunitiesPortal/controls/CommunityTagsRow.qml b/ui/app/AppLayouts/CommunitiesPortal/controls/CommunityTagsRow.qml index efa4a79270..f049aaf6d9 100644 --- a/ui/app/AppLayouts/CommunitiesPortal/controls/CommunityTagsRow.qml +++ b/ui/app/AppLayouts/CommunitiesPortal/controls/CommunityTagsRow.qml @@ -11,6 +11,7 @@ StatusRollArea { id: root property string tags + property var selectedTagsNames: [] onTagsChanged: { var obj = JSON.parse(tags); @@ -19,16 +20,33 @@ StatusRollArea { for (const key of Object.keys(obj)) { d.tagsModel.append({ name: key, emoji: obj[key], selected: false }); } + + d.evaluateSelectedTags() } QtObject { id: d 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 { id: tagsFlow model: d.tagsModel + mode: StatusCommunityTags.Highlight + + onClicked: { + item.selected = !item.selected + d.evaluateSelectedTags() + } } } diff --git a/ui/app/AppLayouts/CommunitiesPortal/panels/CommunityTagsPanel.qml b/ui/app/AppLayouts/CommunitiesPortal/panels/CommunityTagsPanel.qml index c5ec532f36..b0cac02f34 100644 --- a/ui/app/AppLayouts/CommunitiesPortal/panels/CommunityTagsPanel.qml +++ b/ui/app/AppLayouts/CommunitiesPortal/panels/CommunityTagsPanel.qml @@ -126,7 +126,7 @@ StatusScrollView { StatusCommunityTags { model: d.tagsModel - showOnlySelected: true + mode: StatusCommunityTags.ShowSelectedOnly onClicked: { d.cntSelectedTags--; item.selected = false;