feat(ProfileShowcase): Component managing all models required by Profile Showcase settings UI

Closes: #13435
Closes: #13490
Closes: #13494
This commit is contained in:
Michał Cieślak 2024-02-16 13:08:45 +01:00 committed by Michał
parent 809af0ac90
commit ac266bb997
3 changed files with 488 additions and 0 deletions

View File

@ -0,0 +1,324 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQml 2.15
import StatusQ 0.1
import StatusQ.Core.Utils 0.1
import Storybook 1.0
import utils 1.0
import AppLayouts.Profile.helpers 1.0
ColumnLayout {
ListModel {
id: accountsModel
ListElement { key: "1"; name: "Crypto Kitties" }
ListElement { key: "2"; name: "Status" }
ListElement { key: "3"; name: "Fun Stuff" }
ListElement { key: "4"; name: "Other Stuff" }
}
ListModel {
id: accountsShowcaseModel
ListElement { key: "1"; visibility: 1; position: 0 }
ListElement { key: "3"; visibility: 2; position: 9 }
}
ListModel {
id: collectiblesModel
ListElement { key: "1"; name: "Collectible 1"; accounts: "1:3" }
ListElement { key: "2"; name: "Collectible 2"; accounts: "3" }
ListElement { key: "3"; name: "Collectible 3"; accounts: "1:2:3" }
ListElement { key: "4"; name: "Collectible 4"; accounts: "1:4" }
}
ListModel {
id: collectiblesShowcaseModel
ListElement { key: "1"; visibility: 1; position: 0 }
ListElement { key: "2"; visibility: 2; position: 2 }
ListElement { key: "3"; visibility: 2; position: 1 }
}
ProfileShowcaseModels {
id: showcaseModels
accountsSourceModel: accountsModel
accountsShowcaseModel: accountsShowcaseModel
collectiblesSourceModel: collectiblesModel
collectiblesShowcaseModel: collectiblesShowcaseModel
}
MovableModel {
id: accountsMovableModel
sourceModel: showcaseModels.accountsVisibleModel
}
MovableModel {
id: collectiblesMovableModel
sourceModel: showcaseModels.collectiblesVisibleModel
}
component VisibilityComboBox: ComboBox {
model: ListModel {
ListElement { text: "contacts"; value: 1 }
ListElement { text: "verified"; value: 2 }
ListElement { text: "all"; value: 3 }
}
textRole: "text"
valueRole: "value"
}
Flickable {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.margins: 10
contentWidth: grid.width
contentHeight: grid.height
clip: true
Grid {
id: grid
rows: 3
columns: 4
spacing: 10
flow: Grid.TopToBottom
Label {
text: "Backend models"
font.pixelSize: 22
padding: 10
}
GenericListView {
width: 200
height: 300
model: accountsModel
label: "ACCOUNTS MODEL"
}
GenericListView {
width: 200
height: 300
model: accountsShowcaseModel
label: "SHOWCASE MODEL"
roles: ["key", "visibility", "position"]
}
Label {
text: "Display models"
font.pixelSize: 22
padding: 10
}
GenericListView {
width: 420
height: 300
model: accountsMovableModel
label: "IN SHOWCASE"
movable: true
roles: ["key", "visibility", "position"]
onMoveRequested: {
accountsMovableModel.move(from, to)
const key = ModelUtils.get(accountsMovableModel, to, "key")
showcaseModels.changeAccountPosition(key, to);
}
insetComponent: RowLayout {
readonly property var topModel: model
RoundButton {
text: "❌"
onClicked: showcaseModels.setAccountVisibility(
model.key, 0)
}
VisibilityComboBox {
property bool completed: false
onCurrentValueChanged: {
if (!completed || topModel.index < 0)
return
showcaseModels.setAccountVisibility(
topModel.key, currentValue)
}
Component.onCompleted: {
currentIndex = indexOfValue(topModel.visibility)
completed = true
}
}
}
}
GenericListView {
width: 420
height: 300
model: showcaseModels.accountsHiddenModel
label: "HIDDEN"
roles: ["key", "visibility", "position"]
insetComponent: Button {
text: "unhide"
onClicked: showcaseModels.setAccountVisibility(
model.key, 1)
}
}
Label {
text: "Backend models"
font.pixelSize: 22
padding: 10
}
GenericListView {
width: 270
height: 300
model: collectiblesModel
label: "COLLECTIBLES MODEL"
roles: ["key", "name", "accounts"]
}
GenericListView {
width: 270
height: 300
model: collectiblesShowcaseModel
label: "SHOWCASE MODEL"
roles: ["key", "visibility", "position"]
}
Label {
text: "Display models"
font.pixelSize: 22
padding: 10
}
GenericListView {
width: 610
height: 300
model: collectiblesMovableModel
label: "IN SHOWCASE"
movable: true
roles: ["key", "visibility", "position", "accounts", "maxVisibility"]
onMoveRequested: {
collectiblesMovableModel.move(from, to)
const key = ModelUtils.get(collectiblesMovableModel, to, "key")
showcaseModels.changeCollectiblePosition(key, to);
}
insetComponent: RowLayout {
readonly property var topModel: model
RoundButton {
text: "❌"
onClicked: showcaseModels.setCollectibleVisibility(
model.key, 0)
}
VisibilityComboBox {
property bool completed: false
onCurrentValueChanged: {
if (!completed || topModel.index < 0)
return
showcaseModels.setCollectibleVisibility(
topModel.key, currentValue)
}
Component.onCompleted: {
currentIndex = indexOfValue(topModel.visibility)
completed = true
}
}
}
}
GenericListView {
width: 610
height: 300
model: showcaseModels.collectiblesHiddenModel
label: "HIDDEN"
roles: ["key", "visibility", "position",
"accounts", "maxVisibility"]
insetComponent: Button {
text: "unhide"
onClicked: showcaseModels.setCollectibleVisibility(
model.key, 1)
}
}
}
}
Label {
text: `accounts in showcase: [${showcaseModels.visibleAccountsList}]`
Layout.alignment: Qt.AlignHCenter
}
Label {
readonly property string visibilities:
JSON.stringify(showcaseModels.accountsVisibilityMap)
text: `accounts visibilities: [${visibilities}]`
Layout.alignment: Qt.AlignHCenter
}
Button {
text: "SAVE"
onClicked: {
const accountsToBeSaved = showcaseModels.accountsCurrentState()
const collectiblesToBeSaved = showcaseModels.collectiblesCurrentState()
accountsMovableModel.syncOrder()
collectiblesMovableModel.syncOrder()
accountsShowcaseModel.clear()
accountsShowcaseModel.append(accountsToBeSaved)
collectiblesShowcaseModel.clear()
collectiblesShowcaseModel.append(collectiblesToBeSaved)
}
Layout.alignment: Qt.AlignHCenter
Layout.margins: 10
}
}
// category: Models

View File

@ -0,0 +1,163 @@
import QtQml 2.15
import StatusQ 0.1
import StatusQ.Core.Utils 0.1
import SortFilterProxyModel 0.2
QObject {
id: root
// COMMUNITIES
// Input models
property alias communitiesSourceModel: communities.sourceModel
property alias communitiesShowcaseModel: communities.showcaseModel
// Output models
readonly property alias communitiesVisibleModel: communities.visibleModel
readonly property alias communitiesHiddenModel: communities.hiddenModel
// Methods
function communitiesCurrentState() {
return communities.currentState()
}
function setCommunityVisibility(key, visibility) {
communities.setVisibility(key, visibility)
}
function changeCommunityPosition(key, to) {
communities.changePosition(key, to)
}
// ACCOUNTS
// Input models
property alias accountsSourceModel: accounts.sourceModel
property alias accountsShowcaseModel: accounts.showcaseModel
// Output models
readonly property alias accountsVisibleModel: accounts.visibleModel
readonly property alias accountsHiddenModel: accounts.hiddenModel
// Methods
function accountsCurrentState() {
return accounts.currentState()
}
function setAccountVisibility(key, visibility) {
accounts.setVisibility(key, visibility)
}
function changeAccountPosition(key, to) {
accounts.changePosition(key, to)
}
// Other
readonly property alias visibleAccountsList:
visibleAccountsConnections.visibleAccountsList
readonly property alias accountsVisibilityMap:
visibleAccountsConnections.accountsVisibilityMap
// COLLECTIBLES
// Input models
property alias collectiblesSourceModel: collectiblesFilter.sourceModel
property alias collectiblesShowcaseModel: collectibles.showcaseModel
// Output models
readonly property alias collectiblesVisibleModel: collectibles.visibleModel
readonly property alias collectiblesHiddenModel: collectibles.hiddenModel
// Methods
function collectiblesCurrentState() {
return collectibles.currentState()
}
function setCollectibleVisibility(key, visibility) {
collectibles.setVisibility(key, visibility)
}
function changeCollectiblePosition(key, to) {
collectibles.changePosition(key, to)
}
ProfileShowcaseDirtyState {
id: communities
}
ProfileShowcaseDirtyState {
id: accounts
}
ProfileShowcaseDirtyState {
id: collectibles
sourceModel: collectiblesFilter
}
SortFilterProxyModel {
id: collectiblesFilter
delayed: true
proxyRoles: FastExpressionRole {
name: "maxVisibility"
expression: {
const m = root.accountsVisibilityMap
const accounts = model.accounts.split(":")
const visibilities = accounts.map(e => m[e]).filter(e => e)
return visibilities.length ? Math.min(...visibilities) : 0
}
expectedRoles: ["accounts"]
}
filters: RangeFilter {
roleName: "maxVisibility"
minimumValue: 1
}
}
Connections {
id: visibleAccountsConnections
target: accounts.visibleModel
property var visibleAccountsList: []
property var accountsVisibilityMap: ({})
function updateAccountsList() {
const keysAndVisibility = ModelUtils.modelToArray(
accounts.visibleModel, ["key", "visibility"])
visibleAccountsList = keysAndVisibility.map(e => e.key)
accountsVisibilityMap = keysAndVisibility.reduce(
(acc, val) => Object.assign(
acc, {[val.key]: val.visibility}), {})
}
function onDataChanged() {
updateAccountsList()
}
function onRowsInserted() {
updateAccountsList()
}
function onRowsRemoved() {
updateAccountsList()
}
function onModelReset() {
updateAccountsList()
}
Component.onCompleted: updateAccountsList()
}
}

View File

@ -1,2 +1,3 @@
ProfileShowcaseDirtyState 1.0 ProfileShowcaseDirtyState.qml
ProfileShowcaseModels 1.0 ProfileShowcaseModels.qml
VisibilityAndPositionDirtyStateModel 1.0 VisibilityAndPositionDirtyStateModel.qml