feat(ProfileShowcase): Simplify ProfileShowcasePanel API and connect to the new models

1. Fix `EmptyShapeRectangleFooterListView` visibility and positioning after ListView items are animated out of view
2. Update `ShowcaseDelegate` to remove modelObject dependency. The UI properties needed will be received from parent
3. Update `ProfileShowcasePanel` to remove the previous logic involving rows move and visibility change. There is no need now for two specialised delegate components (one for in showcase and one for hidden). The delegate is still configured outside of this component because the model rolenames need to be mapped to the delegate properties. The common delegate logic is implemented in the `ProfileShowcasePanel` and only the model mapping is needed from parent component.
3. Update all `ProfileShowcase*Panel` to impement the new API
4. Remove all `*ShowcaseDelegate`. The delegate is simple enough to be configured at once in the Panel
This commit is contained in:
Alex Jbanca 2024-02-28 14:19:14 +02:00 committed by Alex Jbanca
parent fbcd90ef3b
commit 07484cb15c
20 changed files with 775 additions and 712 deletions

View File

@ -5,7 +5,6 @@ import QtQuick.Layouts 1.15
import StatusQ.Core 0.1 import StatusQ.Core 0.1
import StatusQ.Core.Utils 0.1 as CoreUtils import StatusQ.Core.Utils 0.1 as CoreUtils
import mainui 1.0
import AppLayouts.Profile.panels 1.0 import AppLayouts.Profile.panels 1.0
import shared.stores 1.0 import shared.stores 1.0
@ -21,91 +20,76 @@ SplitView {
orientation: Qt.Vertical orientation: Qt.Vertical
Popups { readonly property string currentWallet: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7420"
popupParent: root
rootStore: QtObject {} ListModel {
communityTokensStore: CommunityTokensStore {} id: hiddenModelItem
ListElement {
name: "My Status Account"
key: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7420"
colorId: "primary"
emoji: "🇨🇿"
walletType: ""
visibility: 0
}
ListElement {
name: "testing (no emoji, colored, seed)"
key: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7000"
colorId: ""
emoji: ""
walletType: "seed"
visibility: 0
}
ListElement {
name: "My Bro's Account"
key: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7421"
colorId: "orange"
emoji: "🇸🇰"
walletType: "watch"
visibility: 0
}
} }
readonly property string currentWallet: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7420" ListModel {
id: inShowcaseModelItem
ListElement {
name: "My Status Account"
key: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7420"
colorId: "primary"
emoji: "🇨🇿"
walletType: ""
visibility: 1
}
ListElement {
name: "testing (no emoji, colored, seed)"
key: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7000"
colorId: ""
emoji: ""
walletType: "seed"
visibility: 1
}
ListElement {
name: "My Bro's Account"
key: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7421"
colorId: "orange"
emoji: "🇸🇰"
walletType: "watch"
visibility: 1
}
}
ListModel { ListModel {
id: emptyModel id: emptyModel
} }
ListModel { ProfileShowcaseAccountsPanel {
id: accountsModel id: showcasePanel
ListElement {
name: "My Status Account"
address: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7420"
colorId: "primary"
emoji: "🇨🇿"
walletType: ""
}
ListElement {
name: "testing (no emoji, colored, seed)"
address: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7000"
colorId: ""
emoji: ""
walletType: "seed"
}
ListElement {
name: "My Bro's Account"
address: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7421"
colorId: "orange"
emoji: "🇸🇰"
walletType: "watch"
}
}
ListModel {
id: inShowcaseAccountsModel
property int hiddenCount: emptyModelChecker.checked ? 0 : accountsModel.count - count
signal baseModelFilterConditionsMayHaveChanged()
function setVisibilityByIndex(index, visibility) {
if (visibility === Constants.ShowcaseVisibility.NoOne) {
remove(index)
} else {
get(index).showcaseVisibility = visibility
}
}
function setVisibility(address, visibility) {
for (let i = 0; i < count; ++i) {
if (get(i).address === address) {
setVisibilityByIndex(i, visibility)
}
}
}
function hasItemInShowcase(address) {
for (let i = 0; i < count; ++i) {
if (get(i).address === address) {
return true
}
}
return false
}
function upsertItemJson(item) {
append(JSON.parse(item))
}
}
StatusScrollView { // wrapped in a ScrollView on purpose; to simulate SettingsContentBase.qml
SplitView.fillWidth: true SplitView.fillWidth: true
SplitView.preferredHeight: 500 SplitView.preferredHeight: 500
ProfileShowcaseAccountsPanel { inShowcaseModel: emptyModelChecker.checked ? emptyModel : inShowcaseModelItem
id: showcasePanel hiddenModel: emptyModelChecker.checked ? emptyModel : hiddenModelItem
width: 500 currentWallet: root.currentWallet
baseModel: emptyModelChecker.checked ? emptyModel : accountsModel
showcaseModel: inShowcaseAccountsModel
currentWallet: root.currentWallet
}
} }
LogsAndControlsPanel { LogsAndControlsPanel {
@ -117,9 +101,8 @@ SplitView {
logsView.logText: logs.logText logsView.logText: logs.logText
ColumnLayout { ColumnLayout {
Button { Label {
text: "Reset (clear settings)" text: "ⓘ Shwcase interaction implemented in ProfileShowcasePanelPage"
onClicked: showcasePanel.reset()
} }
CheckBox { CheckBox {
@ -127,8 +110,6 @@ SplitView {
text: "Empty model" text: "Empty model"
checked: false checked: false
onClicked: showcasePanel.reset()
} }
} }
} }

View File

@ -2,9 +2,12 @@ import QtQuick 2.14
import QtQuick.Controls 2.14 import QtQuick.Controls 2.14
import QtQuick.Layouts 1.15 import QtQuick.Layouts 1.15
import StatusQ 0.1
import StatusQ.Core 0.1 import StatusQ.Core 0.1
import StatusQ.Core.Utils 0.1 as CoreUtils import StatusQ.Core.Utils 0.1 as CoreUtils
import SortFilterProxyModel 0.2
import mainui 1.0 import mainui 1.0
import AppLayouts.Profile.panels 1.0 import AppLayouts.Profile.panels 1.0
import shared.stores 1.0 import shared.stores 1.0
@ -23,77 +26,58 @@ SplitView {
orientation: Qt.Vertical orientation: Qt.Vertical
Popups {
popupParent: root
rootStore: QtObject {}
communityTokensStore: CommunityTokensStore {}
}
readonly property WalletAssetsStore walletAssetStore: WalletAssetsStore { readonly property WalletAssetsStore walletAssetStore: WalletAssetsStore {
assetsWithFilteredBalances: walletAssetStore.groupedAccountsAssetsModel assetsWithFilteredBalances: walletAssetStore.groupedAccountsAssetsModel
} }
ListModel { SortFilterProxyModel {
id: emptyModel id: inShowcaseModelItem
sourceModel: !emptyModelChecker.checked ? walletAssetStore.groupedAccountAssetsModel : null
proxyRoles: [
FastExpressionRole {
name: "key"
expression: "Asset 1" + index
},
FastExpressionRole {
name: "visibility"
expression: 1
}
]
} }
ListModel { SortFilterProxyModel {
id: inShowcaseAssetsModel id: hiddenShowcaseModelItem
sourceModel: !emptyModelChecker.checked ? walletAssetStore.groupedAccountAssetsModel : null
property int hiddenCount: emptyModelChecker.checked ? 0 : walletAssetStore.groupedAccountsAssetsModel.count - count proxyRoles: [
FastExpressionRole {
signal baseModelFilterConditionsMayHaveChanged() name: "key"
expression: "Asset 2" + index
function setVisibilityByIndex(index, visibility) { },
if (visibility === Constants.ShowcaseVisibility.NoOne) { FastExpressionRole {
remove(index) name: "visibility"
} else { expression: 0
get(index).showcaseVisibility = visibility
} }
} ]
function setVisibility(symbol, visibility) {
for (let i = 0; i < count; ++i) {
if (get(i).symbol === symbol) {
setVisibilityByIndex(i, visibility)
}
}
}
function hasItemInShowcase(symbol) {
for (let i = 0; i < count; ++i) {
if (get(i).symbol === symbol) {
return true
}
}
return false
}
function upsertItemJson(item) {
append(JSON.parse(item))
}
} }
StatusScrollView { // wrapped in a ScrollView on purpose; to simulate SettingsContentBase.qml ProfileShowcaseAssetsPanel {
id: showcasePanel
SplitView.fillWidth: true SplitView.fillWidth: true
SplitView.preferredHeight: 500 SplitView.preferredHeight: 500
inShowcaseModel: inShowcaseModelItem
hiddenModel: hiddenShowcaseModelItem
ProfileShowcaseAssetsPanel { addAccountsButtonVisible: !hasAllAccountsChecker.checked
id: showcasePanel
width: 500
baseModel: emptyModelChecker.checked ? emptyModel : walletAssetStore.groupedAccountAssetsModel
showcaseModel: inShowcaseAssetsModel
addAccountsButtonVisible: !hasAllAccountsChecker.checked
formatCurrencyAmount: function (amount, symbol) { formatCurrencyAmount: function (amount, symbol) {
return ({amount: amount, const currencyAmount = ({amount: amount,
symbol: symbol.toUpperCase(), symbol: symbol.toUpperCase(),
displayDecimals: 4, displayDecimals: 4,
stripTrailingZeroes: false}) stripTrailingZeroes: false})
} return LocaleUtils.currencyAmountToLocaleString(currencyAmount)
onNavigateToAccountsTab: logs.logEvent("ProfileShowcaseAssetsPanel::onNavigateToAccountsTab")
} }
onNavigateToAccountsTab: logs.logEvent("ProfileShowcaseAssetsPanel::onNavigateToAccountsTab")
} }
LogsAndControlsPanel { LogsAndControlsPanel {
@ -123,8 +107,6 @@ SplitView {
text: "Empty model" text: "Empty model"
checked: false checked: false
onClicked: showcasePanel.reset()
} }
} }
} }

View File

@ -23,71 +23,132 @@ SplitView {
orientation: Qt.Vertical orientation: Qt.Vertical
Popups {
popupParent: root
rootStore: QtObject {}
communityTokensStore: CommunityTokensStore {}
}
ListModel { ListModel {
id: emptyModel id: hiddenModelItem
}
ListModel {
id: collectiblesModel
readonly property var data: [ readonly property var data: [
{ {
uid: "123", key: "1234",
name: "SNT", name: "SNTT",
collectionName: "Super Nitro Toluen (with pink bg)", collectionName: "Super Nitro Toluen (with pink bg)",
backgroundColor: "pink", backgroundColor: "pink",
imageUrl: ModelsData.collectibles.custom, imageUrl: ModelsData.collectibles.custom,
isLoading: false, isLoading: false,
communityId: "ddls" communityId: "ddls",
visibility: Constants.ShowcaseVisibility.NoOne
}, },
{ {
uid: "34545656768", key: "3454565676",
name: "Kitty 1", name: "Kitty 3",
collectionName: "Kitties", collectionName: "Kitties",
backgroundColor: "", backgroundColor: "",
imageUrl: ModelsData.collectibles.kitty1Big, imageUrl: ModelsData.collectibles.kitty1Big,
isLoading: false isLoading: false,
visibility: Constants.ShowcaseVisibility.NoOne
}, },
{ {
uid: "123456", key: "12345",
name: "Kitty 2", name: "Kitty 4",
collectionName: "", collectionName: "",
backgroundColor: "", backgroundColor: "",
imageUrl: ModelsData.collectibles.kitty2Big, imageUrl: ModelsData.collectibles.kitty2Big,
isLoading: false, isLoading: false,
communityId: "sox" communityId: "sox",
visibility: Constants.ShowcaseVisibility.NoOne
}, },
{ {
uid: "12345645459537432", key: "123456454595374",
name: "", name: "",
collectionName: "Super Kitties", collectionName: "Super Kitties",
backgroundColor: "oink", backgroundColor: "oink",
imageUrl: ModelsData.collectibles.kitty3Big, imageUrl: ModelsData.collectibles.kitty3Big,
isLoading: false, isLoading: false,
communityId: "ast" communityId: "ast",
visibility: Constants.ShowcaseVisibility.NoOne
}, },
{ {
uid: "691", key: "6912",
name: "KILLABEAR", name: "KILLABEAR",
collectionName: "KILLABEARS", collectionName: "KILLABEARS",
backgroundColor: "#807c56", backgroundColor: "#807c56",
imageUrl: "https://assets.killabears.com/content/killabears/img/691-e81f892696a8ae700e0dbc62eb072060679a2046d1ef5eb2671bdb1fad1f68e3.png", imageUrl: "https://assets.killabears.com/content/killabears/img/691-e81f892696a8ae700e0dbc62eb072060679a2046d1ef5eb2671bdb1fad1f68e3.png",
isLoading: true isLoading: true,
visibility: Constants.ShowcaseVisibility.NoOne
}, },
{ {
uid: "8876", key: "8876",
name: "AIORBIT", name: "AIORBIT",
description: "", description: "",
collectionName: "AIORBIT (Animated SVG)", collectionName: "AIORBIT (Animated SVG)",
backgroundColor: "", backgroundColor: "",
imageUrl: "https://dl.openseauserdata.com/cache/originImage/files/8b14ef530b28853445c27d6693c4e805.svg", imageUrl: "https://dl.openseauserdata.com/cache/originImage/files/8b14ef530b28853445c27d6693c4e805.svg",
isLoading: false isLoading: false,
visibility: Constants.ShowcaseVisibility.NoOne
}
]
Component.onCompleted: append(data)
}
ListModel {
id: inShowcaseModelItem
readonly property var data: [
{
key: "123",
name: "SNT",
collectionName: "Super Nitro Toluen (with pink bg)",
backgroundColor: "pink",
imageUrl: ModelsData.collectibles.custom,
isLoading: false,
communityId: "ddls",
visibility: Constants.ShowcaseVisibility.Everyone
},
{
key: "34545656768",
name: "Kitty 1",
collectionName: "Kitties",
backgroundColor: "",
imageUrl: ModelsData.collectibles.kitty1Big,
isLoading: false,
visibility: Constants.ShowcaseVisibility.Everyone
},
{
key: "123456",
name: "Kitty 2",
collectionName: "",
backgroundColor: "",
imageUrl: ModelsData.collectibles.kitty2Big,
isLoading: false,
communityId: "sox",
visibility: Constants.ShowcaseVisibility.Everyone
},
{
key: "12345645459537432",
name: "",
collectionName: "Super Kitties",
backgroundColor: "oink",
imageUrl: ModelsData.collectibles.kitty3Big,
isLoading: false,
communityId: "ast",
visibility: Constants.ShowcaseVisibility.Everyone
},
{
key: "691",
name: "KILLABEAR",
collectionName: "KILLABEARS",
backgroundColor: "#807c56",
imageUrl: "https://assets.killabears.com/content/killabears/img/691-e81f892696a8ae700e0dbc62eb072060679a2046d1ef5eb2671bdb1fad1f68e3.png",
isLoading: true,
visibility: Constants.ShowcaseVisibility.Everyone
},
{
key: "8876",
name: "AIORBIT",
description: "",
collectionName: "AIORBIT (Animated SVG)",
backgroundColor: "",
imageUrl: "https://dl.openseauserdata.com/cache/originImage/files/8b14ef530b28853445c27d6693c4e805.svg",
isLoading: false,
visibility: Constants.ShowcaseVisibility.Everyone
} }
] ]
Component.onCompleted: append(data) Component.onCompleted: append(data)
@ -117,63 +178,37 @@ SplitView {
} }
LeftJoinModel { LeftJoinModel {
id: leftJoinModel id: joinedInShowcase
leftModel: collectiblesModel leftModel: inShowcaseModelItem
rightModel: communityModel rightModel: communityModel
joinRole: "communityId" joinRole: "communityId"
} }
ListModel { ListModel {
id: inShowcaseCollectiblesModel id: emptyModelItem
property int hiddenCount: emptyModelChecker.checked ? 0 : collectiblesModel.count - count
signal baseModelFilterConditionsMayHaveChanged()
function setVisibilityByIndex(index, visibility) {
if (visibility === Constants.ShowcaseVisibility.NoOne) {
remove(index)
} else {
get(index).showcaseVisibility = visibility
}
}
function setVisibility(uid, visibility) {
for (let i = 0; i < count; ++i) {
if (get(i).uid === uid) {
setVisibilityByIndex(i, visibility)
}
}
}
function hasItemInShowcase(uid) {
for (let i = 0; i < count; ++i) {
if (get(i).uid === uid) {
return true
}
}
return false
}
function upsertItemJson(item) {
append(JSON.parse(item))
}
} }
StatusScrollView { // wrapped in a ScrollView on purpose; to simulate SettingsContentBase.qml LeftJoinModel {
id: joinedHiddenModel
leftModel: hiddenModelItem
rightModel: communityModel
joinRole: "communityId"
}
ProfileShowcaseCollectiblesPanel {
id: showcasePanel
SplitView.fillWidth: true SplitView.fillWidth: true
SplitView.preferredHeight: 500 SplitView.preferredHeight: 500
ProfileShowcaseCollectiblesPanel { inShowcaseModel: emptyModelChecker.checked ? emptyModelItem : joinedInShowcase
id: showcasePanel hiddenModel: emptyModelChecker.checked ? emptyModelItem : joinedHiddenModel
width: 500
baseModel: emptyModelChecker.checked ? emptyModel : leftJoinModel
showcaseModel: inShowcaseCollectiblesModel
addAccountsButtonVisible: !hasAllAccountsChecker.checked
onNavigateToAccountsTab: logs.logEvent("ProfileShowcaseCollectiblesPanel::onNavigateToAccountsTab") addAccountsButtonVisible: !hasAllAccountsChecker.checked
}
onNavigateToAccountsTab: logs.logEvent("ProfileShowcaseCollectiblesPanel::onNavigateToAccountsTab")
} }
LogsAndControlsPanel { LogsAndControlsPanel {
@ -185,12 +220,10 @@ SplitView {
logsView.logText: logs.logText logsView.logText: logs.logText
ColumnLayout { ColumnLayout {
Button { Label {
text: "Reset (clear settings)" text: "ⓘ Shwcase interaction implemented in ProfileShowcasePanelPage"
onClicked: showcasePanel.settings.reset()
} }
CheckBox { CheckBox {
id: hasAllAccountsChecker id: hasAllAccountsChecker
@ -203,10 +236,7 @@ SplitView {
text: "Empty model" text: "Empty model"
checked: false checked: false
onClicked: showcasePanel.reset()
} }
} }
} }
} }

View File

@ -5,7 +5,6 @@ import QtQuick.Layouts 1.15
import StatusQ.Core 0.1 import StatusQ.Core 0.1
import StatusQ.Core.Utils 0.1 as CoreUtils import StatusQ.Core.Utils 0.1 as CoreUtils
import mainui 1.0
import AppLayouts.Profile.panels 1.0 import AppLayouts.Profile.panels 1.0
import AppLayouts.Profile.controls 1.0 import AppLayouts.Profile.controls 1.0
import shared.stores 1.0 import shared.stores 1.0
@ -22,106 +21,110 @@ SplitView {
orientation: Qt.Vertical orientation: Qt.Vertical
Popups { ListModel {
popupParent: root id: hiddenModelItem
rootStore: QtObject {} Component.onCompleted:
communityTokensStore: CommunityTokensStore {} append([{
key: "0x0006",
name: "Test community 6",
joined: true,
memberRole: Constants.memberRole.owner,
isControlNode: true,
image: ModelsData.icons.dribble,
color: "yellow",
visibility: Constants.ShowcaseVisibility.NoOne
},
{
key: "0x0007",
name: "Test community 7",
joined: true,
memberRole: Constants.memberRole.none,
isControlNode: false,
image: ModelsData.collectibles.custom,
color: "peach",
visibility: Constants.ShowcaseVisibility.NoOne
},
{
key: "0x0008",
name: "Test community 8",
joined: true,
memberRole: Constants.memberRole.none,
isControlNode: false,
image: "",
color: "whitesmoke",
visibility: Constants.ShowcaseVisibility.NoOne
},
{
key: "0x0009",
name: "Test community 9",
joined: true,
memberRole: Constants.memberRole.admin,
isControlNode: false,
image: ModelsData.icons.spotify,
color: "green",
visibility: Constants.ShowcaseVisibility.NoOne
},
])
}
ListModel {
id: inShowcaseModelItem
Component.onCompleted:
append([{
key: "0x0001",
name: "Test community",
joined: true,
memberRole: Constants.memberRole.owner,
isControlNode: true,
image: ModelsData.icons.dribble,
color: "yellow",
visibility: Constants.ShowcaseVisibility.Everyone
},
{
key: "0x0002",
name: "Test community 2",
joined: true,
memberRole: Constants.memberRole.none,
isControlNode: false,
image: ModelsData.collectibles.custom,
color: "peach",
visibility: Constants.ShowcaseVisibility.Everyone
},
{
key: "0x0004",
name: "Test community 3",
joined: true,
memberRole: Constants.memberRole.none,
isControlNode: false,
image: "",
color: "whitesmoke",
visibility: Constants.ShowcaseVisibility.Everyone
},
{
key: "0x0005",
name: "Test community 4",
joined: true,
memberRole: Constants.memberRole.admin,
isControlNode: false,
image: ModelsData.icons.spotify,
color: "green",
visibility: Constants.ShowcaseVisibility.Everyone
},
])
} }
ListModel { ListModel {
id: emptyModel id: emptyModel
} }
ListModel { ProfileShowcaseCommunitiesPanel {
id: communitiesModel id: showcasePanel
Component.onCompleted:
append([{
id: "0x0001",
name: "Test community",
joined: true,
memberRole: Constants.memberRole.owner,
isControlNode: true,
image: ModelsData.icons.dribble,
color: "yellow"
},
{
id: "0x0002",
name: "Test community 2",
joined: true,
memberRole: Constants.memberRole.none,
isControlNode: false,
image: ModelsData.collectibles.custom,
color: "peach"
},
{
id: "0x0004",
name: "Test community 3",
joined: true,
memberRole: Constants.memberRole.none,
isControlNode: false,
image: "",
color: "whitesmoke"
},
{
id: "0x0005",
name: "Test community 4",
joined: true,
memberRole: Constants.memberRole.admin,
isControlNode: false,
image: ModelsData.icons.spotify,
color: "green"
},
])
}
ListModel {
id: inShowcaseCommunitiesModel
property int hiddenCount: emptyModelChecker.checked ? 0 : communitiesModel.count - count
signal baseModelFilterConditionsMayHaveChanged()
function setVisibilityByIndex(index, visibility) {
if (visibility === Constants.ShowcaseVisibility.NoOne) {
remove(index)
} else {
get(index).showcaseVisibility = visibility
}
}
function setVisibility(id, visibility) {
for (let i = 0; i < count; ++i) {
if (get(i).id === id) {
setVisibilityByIndex(i, visibility)
}
}
}
function hasItemInShowcase(id) {
for (let i = 0; i < count; ++i) {
if (get(i).id === id) {
return true
}
}
return false
}
function upsertItemJson(item) {
append(JSON.parse(item))
}
}
StatusScrollView { // wrapped in a ScrollView on purpose; to simulate SettingsContentBase.qml
SplitView.fillWidth: true SplitView.fillWidth: true
SplitView.preferredHeight: 500 SplitView.preferredHeight: 500
ProfileShowcaseCommunitiesPanel { inShowcaseModel: emptyModelChecker.checked ? emptyModel : inShowcaseModelItem
id: showcasePanel hiddenModel: emptyModelChecker.checked ? emptyModel : hiddenModelItem
width: 500
baseModel: emptyModelChecker.checked ? emptyModel : communitiesModel
showcaseModel: inShowcaseCommunitiesModel
}
} }
LogsAndControlsPanel { LogsAndControlsPanel {
@ -133,9 +136,8 @@ SplitView {
logsView.logText: logs.logText logsView.logText: logs.logText
ColumnLayout { ColumnLayout {
Button { Label {
text: "Reset (clear settings)" text: "ⓘ Shwcase interaction implemented in ProfileShowcasePanelPage"
onClicked: showcasePanel.reset()
} }
CheckBox { CheckBox {
@ -143,11 +145,10 @@ SplitView {
text: "Empty model" text: "Empty model"
checked: false checked: false
onClicked: showcasePanel.reset()
} }
} }
} }
} }
// category: Panels // category: Panels

View File

@ -0,0 +1,222 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import AppLayouts.Profile.panels 1.0
import AppLayouts.Profile.controls 1.0
import StatusQ.Components 0.1
import utils 1.0
import Storybook 1.0
SplitView {
//id: root
property int inShowcaseModelCount: inShowcaseCounter.value
property int hiddenModelCount: hiddenCounter.value
orientation: Qt.Vertical
Logs { id: logs }
ListModel {
id: inShowcaseModelItem
ListElement {
key: 1
title: "Item 1"
secondaryTitle: "Description 1"
hasImage: true
image: "https://picsum.photos/200/300?random=1"
iconName: "https://picsum.photos/40/40?random=1"
visibility: 1
name: "Test community"
joined: true
isControlNode: true
color: "yellow"
hasTag: true
tagText: "New"
tagAsset: "https://picsum.photos/40/40?random=1"
tagLoading: true
}
}
ListModel {
id: hiddenModelItem
ListElement {
key: 2
title: "Item 1"
secondaryTitle: "Description 1"
hasImage: true
image: "https://picsum.photos/200/300?random=1"
iconName: "https://picsum.photos/40/40?random=1"
visibility: 0
name: "Test community"
joined: true
isControlNode: true
color: "yellow"
tagVisible: true
tagText: "New"
tagAsset: "https://picsum.photos/40/40?random=1"
tagLoading: true
}
}
ProfileShowcasePanel {
id: root
inShowcaseModel: inShowcaseModelItem
hiddenModel: hiddenModelItem
SplitView.fillWidth: true
SplitView.fillHeight: true
emptyInShowcasePlaceholderText: "No items in showcase"
emptyHiddenPlaceholderText: "No hidden items"
onChangePositionRequested: function (key, to) {
for (var i = 0; i < inShowcaseModelItem.count; i++) {
if (inShowcaseModelItem.get(i).key === key) {
inShowcaseModelItem.move(i, to, 1)
break
}
}
for (var i = 0; i < hiddenModelItem.count; i++) {
if (hiddenModelItem.get(i).key === key) {
hiddenModelItem.move(from, to, 1)
break
}
}
}
onSetVisibilityRequested: function (key, toVisibility) {
for (var i = 0; i < inShowcaseModelItem.count; i++) {
if (inShowcaseModelItem.get(i).key === key) {
inShowcaseModelItem.setProperty(i, "visibility", toVisibility)
if(toVisibility === 0) {
let item = inShowcaseModelItem.get(i)
hiddenModelItem.append(item)
inShowcaseModelItem.remove(i, 1)
}
return
}
}
for (var i = 0; i < hiddenModelItem.count; i++) {
if (hiddenModelItem.get(i).key === key) {
hiddenModelItem.setProperty(i, "visibility", toVisibility)
if(toVisibility !== 0) {
let item = hiddenModelItem.get(i)
inShowcaseModelItem.append(item)
hiddenModelItem.remove(i, 1)
}
return
}
}
}
delegate: ProfileShowcasePanel.Delegate {
title: model ? model.title : ""
secondaryTitle: model ? model.secondaryTitle : ""
hasImage: model ? model.hasImage : false
icon.name: model ? model.iconName : ""
icon.source: model ? model.image : ""
icon.color: model ? model.color : ""
tag.visible: model ? model.hasTag : false
tag.text: model ? model.tagText : ""
tag.asset.name: model ? model.tagAsset : ""
tag.loading: model ? model.tagLoading : false
}
}
LogsAndControlsPanel {
id: logsAndControlsPanel
SplitView.fillWidth: true
SplitView.preferredHeight: 200
RowLayout {
anchors.fill: parent
spacing: 10
ColumnLayout {
Label {
text: "In showcase: " + inShowcaseCounter.value
}
Slider {
id: inShowcaseCounter
from: 0
to: 200
stepSize: 1
value: 25
}
Label {
text: "Hidden: " + hiddenCounter.value
}
Slider {
id: hiddenCounter
from: 0
to: 200
stepSize: 1
value: 25
}
}
}
}
onInShowcaseModelCountChanged: {
let count = inShowcaseModelCount - inShowcaseModelItem.count;
let operation = count > 0 ? (i) =>{
inShowcaseModelItem.append({
key: Math.random() * Math.random() * Math.random() * 1000,
title: "Item " + i,
secondaryTitle: "Description " + i,
hasImage: true,
image: "https://picsum.photos/200/300?random=" + i,
iconName: "https://picsum.photos/40/40?random=" + i,
visibility: Math.ceil(Math.random() * 3),
name: "Test community",
joined: true,
isControlNode: true,
color: "yellow",
hasTag: Math.random() > 0.5,
tagText: "New " + 1,
tagAsset: "https://picsum.photos/40/40?random=" + i,
tagLoading: Math.random() > 0.5
})} : (i) => {
inShowcaseModelItem.remove(inShowcaseModelItem.count - 1);
}
for (var i = 0; i < Math.abs(count); i++) {
operation(i)
}
}
onHiddenModelCountChanged: {
let count = hiddenModelCount - hiddenModelItem.count;
let operation = count > 0 ? (i) =>{
hiddenModelItem.append({
key: Math.random() * Math.random() * Math.random() * 1000,
title: "Item " + i,
secondaryTitle: "Description " + i,
hasImage: true,
image: "https://picsum.photos/200/300?random=" + i,
iconName: "https://picsum.photos/40/40?random=" + i,
visibility: 0,
name: "Test community",
joined: true,
memberRole: Constants.memberRole.owner,
isControlNode: true,
color: "yellow",
hasTag: Math.random() > 0.5,
tagText: "New " + i,
tagAsset: "https://picsum.photos/40/40?random=" + i,
tagLoading: Math.random() > 0.8
})} : (i) => {
hiddenModelItem.remove(hiddenModelItem.count - 1);
}
for (var i = 0; i < Math.abs(count); i++) {
operation(i)
}
}
}
// category: Panels

View File

@ -191,6 +191,7 @@
<file>StatusQ/Core/Utils/ModelUtils.qml</file> <file>StatusQ/Core/Utils/ModelUtils.qml</file>
<file>StatusQ/Core/Utils/ModelsComparator.qml</file> <file>StatusQ/Core/Utils/ModelsComparator.qml</file>
<file>StatusQ/Core/Utils/OperatorsUtils.qml</file> <file>StatusQ/Core/Utils/OperatorsUtils.qml</file>
<file>StatusQ/Core/Utils/QObject.qml</file>
<file>StatusQ/Core/Utils/StackViewStates.qml</file> <file>StatusQ/Core/Utils/StackViewStates.qml</file>
<file>StatusQ/Core/Utils/StatesStack.qml</file> <file>StatusQ/Core/Utils/StatesStack.qml</file>
<file>StatusQ/Core/Utils/StringUtils.qml</file> <file>StatusQ/Core/Utils/StringUtils.qml</file>

View File

@ -1,16 +0,0 @@
import QtQuick 2.15
import StatusQ.Core.Theme 0.1
import AppLayouts.Wallet 1.0
import utils 1.0
ShowcaseDelegate {
title: !!showcaseObj && !!showcaseObj.name ? showcaseObj.name : ""
secondaryTitle: WalletUtils.addressToDisplay(!!showcaseObj && !!showcaseObj.address ? showcaseObj.address : "", "", true, containsMouse)
hasEmoji: !!showcaseObj && !!showcaseObj.emoji
hasIcon: !hasEmoji
icon.name: hasEmoji ? showcaseObj.emoji : "filled-account"
icon.color: !!showcaseObj && showcaseObj.colorId ? Utils.getColorForId(showcaseObj.colorId) : Theme.palette.primaryColor3
}

View File

@ -1,26 +0,0 @@
import QtQuick 2.15
import StatusQ 0.1
import StatusQ.Core 0.1
import utils 1.0
ShowcaseDelegate {
id: root
property var formatCurrencyAmount: function(amount, symbol){}
property double totalValue: !!showcaseObj && !!showcaseObj.decimals ? balancesAggregator.value/(10 ** showcaseObj.decimals): 0
title: !!showcaseObj && !!showcaseObj.name ? showcaseObj.name : ""
secondaryTitle: !!showcaseObj && !!showcaseObj.enabledNetworkBalance ?
LocaleUtils.currencyAmountToLocaleString(showcaseObj.enabledNetworkBalance) :
!!showcaseObj && !!showcaseObj.symbol ? formatCurrencyAmount(totalValue, showcaseObj.symbol): Qt.locale().zeroDigit
hasImage: true
icon.source: !!showcaseObj ? Constants.tokenIcon(showcaseObj.symbol) : ""
SumAggregator {
id: balancesAggregator
model: !!showcaseObj && !!showcaseObj.balances ? showcaseObj.balances: null
roleName: "balance"
}
}

View File

@ -1,13 +0,0 @@
import QtQuick 2.15
import utils 1.0
ShowcaseDelegate {
title: !!showcaseObj ? `${showcaseObj.name}` || `#${showcaseObj.id}` : ""
secondaryTitle: !!showcaseObj && !!showcaseObj.collectionName ? showcaseObj.collectionName : ""
hasImage: !!showcaseObj && !!showcaseObj.imageUrl
icon.source: hasImage ? showcaseObj.imageUrl : ""
bgRadius: Style.current.radius
assetBgColor: !!showcaseObj && !!showcaseObj.backgroundColor ? showcaseObj.backgroundColor : "transparent"
}

View File

@ -1,15 +0,0 @@
import QtQuick 2.15
import utils 1.0
ShowcaseDelegate {
title: !!showcaseObj && !!showcaseObj.name ? showcaseObj.name : ""
secondaryTitle: !!showcaseObj && (showcaseObj.memberRole === Constants.memberRole.owner ||
showcaseObj.memberRole === Constants.memberRole.admin ||
showcaseObj.memberRole === Constants.memberRole.tokenMaster) ? qsTr("Admin") : qsTr("Member")
hasImage: !!showcaseObj && !!showcaseObj.image
icon.name: !!showcaseObj ? showcaseObj.name : ""
icon.source: !!showcaseObj ? showcaseObj.image : ""
icon.color: !!showcaseObj ? showcaseObj.color : "transparent"
}

View File

@ -17,7 +17,7 @@ import utils 1.0
StatusDraggableListItem { StatusDraggableListItem {
id: root id: root
property var showcaseObj property alias tag: tagItem
property int showcaseVisibility: Constants.ShowcaseVisibility.NoOne property int showcaseVisibility: Constants.ShowcaseVisibility.NoOne
property bool blurState: false property bool blurState: false
@ -46,10 +46,9 @@ StatusDraggableListItem {
actions: [ actions: [
ManageTokensCommunityTag { ManageTokensCommunityTag {
id: tagItem
Layout.maximumWidth: root.width *.4 Layout.maximumWidth: root.width *.4
visible: showcaseObj && !!showcaseObj.communityId visible: false
text: showcaseObj && !! showcaseObj.communityName ? showcaseObj.communityName : ""
asset.name: showcaseObj && !!showcaseObj.communityImage ? showcaseObj.communityImage : ""
}, },
StatusRoundButton { StatusRoundButton {
icon.name: ProfileUtils.visibilityIcon(root.showcaseVisibility) icon.name: ProfileUtils.visibilityIcon(root.showcaseVisibility)

View File

@ -1,8 +1,5 @@
AddMoreAccountsLink 1.0 AddMoreAccountsLink.qml AddMoreAccountsLink 1.0 AddMoreAccountsLink.qml
CommunityShowcaseDelegate 1.0 CommunityShowcaseDelegate.qml
CollectibleShowcaseDelegate 1.0 CollectibleShowcaseDelegate.qml
AccountShowcaseDelegate 1.0 AccountShowcaseDelegate.qml
AssetShowcaseDelegate 1.0 AssetShowcaseDelegate.qml
WalletAccountDelegate 1.0 WalletAccountDelegate.qml WalletAccountDelegate 1.0 WalletAccountDelegate.qml
ShowcaseDelegate 1.0 ShowcaseDelegate.qml
StaticSocialLinkInput 1.0 StaticSocialLinkInput.qml StaticSocialLinkInput 1.0 StaticSocialLinkInput.qml
WalletKeyPairDelegate 1.0 WalletKeyPairDelegate.qml WalletKeyPairDelegate 1.0 WalletKeyPairDelegate.qml

View File

@ -3,43 +3,25 @@ import QtQuick 2.15
import utils 1.0 import utils 1.0
import AppLayouts.Profile.controls 1.0 import AppLayouts.Profile.controls 1.0
import AppLayouts.Wallet 1.0
import StatusQ.Core.Theme 0.1
ProfileShowcasePanel { ProfileShowcasePanel {
id: root id: root
property string currentWallet property string currentWallet
keyRole: "address"
roleNames: ["address", "name", "walletType", "emoji", "colorId"].concat(showcaseRoles)
filterFunc: (modelData) => modelData.walletType !== Constants.keyWalletType && !showcaseModel.hasItemInShowcase(modelData.address)
emptyInShowcasePlaceholderText: qsTr("Accounts here will show on your profile") emptyInShowcasePlaceholderText: qsTr("Accounts here will show on your profile")
emptyHiddenPlaceholderText: qsTr("Accounts here will be hidden from your profile") emptyHiddenPlaceholderText: qsTr("Accounts here will be hidden from your profile")
hiddenDraggableDelegateComponent: AccountShowcaseDelegate { delegate: ProfileShowcasePanel.Delegate {
Drag.keys: ["x-status-draggable-showcase-item-hidden"] title: model ? model.name : ""
showcaseObj: modelData secondaryTitle: WalletUtils.addressToDisplay(model ? model.key : "", "", true, containsMouse)
dragParent: dragParentData hasEmoji: model && !!model.emoji
visualIndex: visualIndexData hasIcon: !hasEmoji
highlighted: !!modelData && modelData.address === root.currentWallet icon.name: hasEmoji ? model.emoji : "filled-account"
onShowcaseVisibilityRequested: { icon.color: model && model.colorId ? Utils.getColorForId(model.colorId) : Theme.palette.primaryColor3
var tmpObj = Object() highlighted: model ? model.key === root.currentWallet : false
root.roleNames.forEach(role => tmpObj[role] = showcaseObj[role])
tmpObj.showcaseVisibility = value
showcaseModel.upsertItemJson(JSON.stringify(tmpObj))
root.showcaseEntryChanged()
}
}
showcaseDraggableDelegateComponent: AccountShowcaseDelegate {
Drag.keys: ["x-status-draggable-showcase-item"]
showcaseObj: modelData
dragParent: dragParentData
visualIndex: visualIndexData
highlighted: !!modelData && modelData.address === root.currentWallet
dragAxis: Drag.YAxis
showcaseVisibility: !!modelData ? modelData.showcaseVisibility : Constants.ShowcaseVisibility.NoOne
onShowcaseVisibilityRequested: {
showcaseModel.setVisibility(showcaseObj.address, value)
root.showcaseEntryChanged()
}
} }
} }

View File

@ -1,6 +1,7 @@
import QtQuick 2.15 import QtQuick 2.15
import QtQuick.Layouts 1.15 import QtQuick.Layouts 1.15
import StatusQ 0.1
import StatusQ.Core 0.1 import StatusQ.Core 0.1
import StatusQ.Controls 0.1 import StatusQ.Controls 0.1
@ -18,40 +19,28 @@ ProfileShowcasePanel {
signal navigateToAccountsTab() signal navigateToAccountsTab()
keyRole: "symbol"
roleNames: ["symbol", "name", "address", "communityId", "enabledNetworkBalance", "decimals"].concat(showcaseRoles)
filterFunc: (modelData) => modelData.symbol !== "" && !showcaseModel.hasItemInShowcase(modelData.symbol)
emptyInShowcasePlaceholderText: qsTr("Assets here will show on your profile") emptyInShowcasePlaceholderText: qsTr("Assets here will show on your profile")
emptyHiddenPlaceholderText: qsTr("Assets here will be hidden from your profile") emptyHiddenPlaceholderText: qsTr("Assets here will be hidden from your profile")
hiddenDraggableDelegateComponent: AssetShowcaseDelegate { delegate: ProfileShowcasePanel.Delegate {
Drag.keys: ["x-status-draggable-showcase-item-hidden"]
showcaseObj: modelData property double totalValue: !!model && !!model.decimals ? balancesAggregator.value/(10 ** model.decimals): 0
dragParent: dragParentData
visualIndex: visualIndexData title: !!model && !!model.name ? model.name : ""
formatCurrencyAmount: function(amount, symbol) { secondaryTitle: !!model && !!model.enabledNetworkBalance ?
return root.formatCurrencyAmount(amount, symbol) LocaleUtils.currencyAmountToLocaleString(model.enabledNetworkBalance) :
} !!model && !!model.symbol ? root.formatCurrencyAmount(totalValue, model.symbol) : Qt.locale().zeroDigit
onShowcaseVisibilityRequested: {
var tmpObj = Object() hasImage: true
root.roleNames.forEach(role => tmpObj[role] = showcaseObj[role]) icon.source: !!model ? Constants.tokenIcon(model.symbol) : ""
tmpObj.showcaseVisibility = value
showcaseModel.upsertItemJson(JSON.stringify(tmpObj)) SumAggregator {
root.showcaseEntryChanged() id: balancesAggregator
} model: !!model && !!model.balances ? model.balances: null
} roleName: "balance"
showcaseDraggableDelegateComponent: AssetShowcaseDelegate {
Drag.keys: ["x-status-draggable-showcase-item"]
showcaseObj: modelData
dragParent: dragParentData
visualIndex: visualIndexData
dragAxis: Drag.YAxis
showcaseVisibility: !!modelData ? modelData.showcaseVisibility : Constants.ShowcaseVisibility.NoOne
onShowcaseVisibilityRequested: {
showcaseModel.setVisibility(showcaseObj.symbol, value)
root.showcaseEntryChanged()
} }
} }
additionalFooterComponent: root.addAccountsButtonVisible ? addMoreAccountsComponent : null additionalFooterComponent: root.addAccountsButtonVisible ? addMoreAccountsComponent : null
Component { Component {

View File

@ -16,39 +16,26 @@ ProfileShowcasePanel {
signal navigateToAccountsTab() signal navigateToAccountsTab()
keyRole: "uid"
roleNames: ["uid", "chainId", "tokenId", "contractAddress", "communityId", "name", "collectionName", "backgroundColor", "imageUrl"].concat(showcaseRoles)
filterFunc: (modelData) => !showcaseModel.hasItemInShowcase(modelData.uid)
emptyInShowcasePlaceholderText: qsTr("Collectibles here will show on your profile") emptyInShowcasePlaceholderText: qsTr("Collectibles here will show on your profile")
emptyHiddenPlaceholderText: qsTr("Collectibles here will be hidden from your profile") emptyHiddenPlaceholderText: qsTr("Collectibles here will be hidden from your profile")
hiddenDraggableDelegateComponent: CollectibleShowcaseDelegate {
Drag.keys: ["x-status-draggable-showcase-item-hidden"]
showcaseObj: modelData
dragParent: dragParentData
visualIndex: visualIndexData
onShowcaseVisibilityRequested: {
var tmpObj = Object()
root.roleNames.forEach(role => tmpObj[role] = showcaseObj[role])
tmpObj.showcaseVisibility = value
showcaseModel.upsertItemJson(JSON.stringify(tmpObj))
root.showcaseEntryChanged()
}
}
showcaseDraggableDelegateComponent: CollectibleShowcaseDelegate {
Drag.keys: ["x-status-draggable-showcase-item"]
showcaseObj: modelData
dragParent: dragParentData
visualIndex: visualIndexData
dragAxis: Drag.YAxis
showcaseVisibility: !!modelData ? modelData.showcaseVisibility : Constants.ShowcaseVisibility.NoOne
onShowcaseVisibilityRequested: {
showcaseModel.setVisibility(showcaseObj.uid, value)
root.showcaseEntryChanged()
}
}
additionalFooterComponent: root.addAccountsButtonVisible ? addMoreAccountsComponent : null additionalFooterComponent: root.addAccountsButtonVisible ? addMoreAccountsComponent : null
delegate: ProfileShowcasePanel.Delegate {
title: !!model ? `${model.name}` || `#${model.id}` : ""
secondaryTitle: !!model && !!model.collectionName ? model.collectionName : ""
hasImage: !!model && !!model.imageUrl
icon.source: hasImage ? model.imageUrl : ""
bgRadius: Style.current.radius
assetBgColor: !!model && !!model.backgroundColor ? model.backgroundColor : "transparent"
tag.visible: model && !!model.communityId
tag.text: model && !!model.communityName ? model.communityName : ""
tag.asset.name: model && !!model.communityImage ? model.communityImage : ""
tag.loading: model && !!model.communityImageLoading ? model.communityImageLoading : false
}
Component { Component {
id: addMoreAccountsComponent id: addMoreAccountsComponent

View File

@ -7,35 +7,18 @@ import AppLayouts.Profile.controls 1.0
ProfileShowcasePanel { ProfileShowcasePanel {
id: root id: root
keyRole: "id"
roleNames: ["id", "name", "memberRole", "image", "color"].concat(showcaseRoles)
filterFunc: (modelData) => modelData.joined && !root.showcaseModel.hasItemInShowcase(modelData.id)
emptyInShowcasePlaceholderText: qsTr("Drag communities here to display in showcase") emptyInShowcasePlaceholderText: qsTr("Drag communities here to display in showcase")
emptyHiddenPlaceholderText: qsTr("Communities here will be hidden from your Profile") emptyHiddenPlaceholderText: qsTr("Communities here will be hidden from your Profile")
hiddenDraggableDelegateComponent: CommunityShowcaseDelegate { delegate: ProfileShowcasePanel.Delegate {
Drag.keys: ["x-status-draggable-showcase-item-hidden"] title: model ? model.name : ""
showcaseObj: modelData secondaryTitle: model && (model.memberRole === Constants.memberRole.owner ||
dragParent: dragParentData model.memberRole === Constants.memberRole.admin ||
visualIndex: visualIndexData model.memberRole === Constants.memberRole.tokenMaster) ? qsTr("Admin") : qsTr("Member")
onShowcaseVisibilityRequested: { hasImage: model && !!model.image
var tmpObj = Object()
root.roleNames.forEach(role => tmpObj[role] = showcaseObj[role]) icon.name: model ? model.name : ""
tmpObj.showcaseVisibility = value icon.source: model ? model.image : ""
root.showcaseModel.upsertItemJson(JSON.stringify(tmpObj)) icon.color: model ? model.color : ""
root.showcaseEntryChanged()
}
}
showcaseDraggableDelegateComponent: CommunityShowcaseDelegate {
Drag.keys: ["x-status-draggable-showcase-item"]
showcaseObj: modelData
dragParent: dragParentData
visualIndex: visualIndexData
dragAxis: Drag.YAxis
showcaseVisibility: !!modelData ? modelData.showcaseVisibility : Constants.ShowcaseVisibility.NoOne
onShowcaseVisibilityRequested: {
root.showcaseModel.setVisibility(showcaseObj.id, value)
root.showcaseEntryChanged()
}
} }
} }

View File

@ -2,6 +2,7 @@ import QtQuick 2.15
import QtQuick.Controls 2.15 import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15 import QtQuick.Layouts 1.15
import QtQml 2.15 import QtQml 2.15
import QtQml.Models 2.15
import StatusQ.Controls 0.1 import StatusQ.Controls 0.1
import StatusQ.Core 0.1 import StatusQ.Core 0.1
@ -16,44 +17,51 @@ import AppLayouts.Profile.controls 1.0
DoubleFlickableWithFolding { DoubleFlickableWithFolding {
id: root id: root
readonly property var showcaseRoles: ["showcaseVisibility", "order"] property Component delegate: Delegate {}
required property string keyRole // Expected roles:
required property var roleNames // - visibility: int
required property var filterFunc property var inShowcaseModel
property var hiddenModel
property var baseModel
property var showcaseModel
property Component showcaseDraggableDelegateComponent
property Component hiddenDraggableDelegateComponent
property Component additionalFooterComponent property Component additionalFooterComponent
// Placeholder text to be shown when the list is empty
property string emptyInShowcasePlaceholderText property string emptyInShowcasePlaceholderText
property string emptyHiddenPlaceholderText property string emptyHiddenPlaceholderText
readonly property Connections showcaseUpdateConnections: Connections { // Signal to requst position change of the visible items
target: root.showcaseModel signal changePositionRequested(var key, int to)
// Signal to request visibility change of the items
signal setVisibilityRequested(var key, int toVisibility)
function onBaseModelFilterConditionsMayHaveChanged() { // Public delegate component. Implements the minimal ShowcaseDelegate interface needed for DND
root.updateBaseModelFilters() component Delegate: ShowcaseDelegate {
id: showcaseDelegate
property var model: modelData
property var dragKeys: dragKeysData
readonly property var key: model ? model.key : null
Drag.keys: dragKeys
dragParent: root
visualIndex: visualIndexData
dragAxis: Drag.YAxis
showcaseVisibility: model ? model.visibility ?? Constants.ShowcaseVisibility.NoOne :
Constants.ShowcaseVisibility.NoOne
onShowcaseVisibilityRequested: function (toVisibility){
root.setVisibilityRequested(key, toVisibility)
} }
} }
function reset() { ScrollBar.vertical: StatusScrollBar {
root.showcaseModel.clear() policy: ScrollBar.AsNeeded
updateBaseModelFilters() visible: resolveVisibility(policy, root.height, root.contentHeight)
} }
function updateBaseModelFilters() {
// Reset base model to update filter conditions
hiddenListView.model = null
hiddenListView.model = root.baseModel
}
signal showcaseEntryChanged()
QtObject { QtObject {
id: d id: d
@ -69,20 +77,16 @@ DoubleFlickableWithFolding {
clip: true clip: true
ScrollBar.vertical: StatusScrollBar {
policy: ScrollBar.AsNeeded
visible: resolveVisibility(policy, root.height, root.contentHeight)
}
flickable1: EmptyShapeRectangleFooterListView { flickable1: EmptyShapeRectangleFooterListView {
id: inShowcaseListView id: inShowcaseListView
model: root.showcaseModel
width: root.width width: root.width
placeholderText: root.emptyInShowcasePlaceholderText placeholderText: root.emptyInShowcasePlaceholderText
footerHeight: ProfileUtils.defaultDelegateHeight footerHeight: ProfileUtils.defaultDelegateHeight
footerContentVisible: !dropAreaRow.visible footerContentVisible: !dropAreaRow.visible
spacing: Style.current.halfPadding spacing: Style.current.halfPadding
delegate: delegateWrapper
model: root.inShowcaseModel
header: FoldableHeader { header: FoldableHeader {
width: ListView.view.width width: ListView.view.width
@ -101,66 +105,7 @@ DoubleFlickableWithFolding {
} }
onToggleFolding: root.flip1Folding() onToggleFolding: root.flip1Folding()
} }
delegate: DropArea {
id: showcaseDelegateRoot
property int visualIndex: index
width: ListView.view.width
height: visible && showcaseDraggableDelegateLoader.item ? showcaseDraggableDelegateLoader.item.height : 0
keys: d.dragShowcaseItemKey
visible: model.showcaseVisibility !== Constants.ShowcaseVisibility.NoOne
onEntered: function(drag) {
const from = drag.source.visualIndex
const to = showcaseDraggableDelegateLoader.item.visualIndex
if (to === from)
return
root.showcaseEntryChanged()
root.showcaseModel.move(from, to, 1)
drag.accept()
}
// TODO:
// This animation is causing issues when there are no elements in the showcase list.
// Reenable it once the refactor of the models and delegates is done (simplified): #13498
// ListView.onRemove: SequentialAnimation {
// PropertyAction { target: showcaseDelegateRoot; property: "ListView.delayRemove"; value: true }
// NumberAnimation { target: showcaseDelegateRoot; property: "scale"; to: 0; easing.type: Easing.InOutQuad }
// PropertyAction { target: showcaseDelegateRoot; property: "ListView.delayRemove"; value: false }
// }
// In showcase delegate item container:
Loader {
id: showcaseDraggableDelegateLoader
property var modelData: model
property var dragParentData: root
property int visualIndexData: index
width: parent.width
sourceComponent: root.showcaseDraggableDelegateComponent
}
// Delegate shadow background when dragging:
ShadowDelegate {
id: showcaseShadow
visible: showcaseDraggableDelegateLoader.item && showcaseDraggableDelegateLoader.item.dragActive
onVisibleChanged: d.isAnyShowcaseDragActive = visible
}
Binding {
when: dropAreaRow.visible
target: showcaseDraggableDelegateLoader.item
property: "blurState"
value: true
restoreMode: Binding.RestoreBindingOrValue
}
}
// Overlaid showcase listview content drop area: // Overlaid showcase listview content drop area:
DropArea { DropArea {
@ -188,14 +133,14 @@ DoubleFlickableWithFolding {
flickable2: EmptyShapeRectangleFooterListView { flickable2: EmptyShapeRectangleFooterListView {
id: hiddenListView id: hiddenListView
model: root.baseModel
width: root.width width: root.width
placeholderText: root.emptyHiddenPlaceholderText placeholderText: root.emptyHiddenPlaceholderText
footerHeight: ProfileUtils.defaultDelegateHeight footerHeight: ProfileUtils.defaultDelegateHeight
footerContentVisible: !hiddenDropAreaButton.visible footerContentVisible: !hiddenDropAreaButton.visible
empty: root.showcaseModel.hiddenCount === 0 && !root.flickable2Folded // TO BE REMOVE: #13498
additionalFooterComponent: root.additionalFooterComponent additionalFooterComponent: root.additionalFooterComponent
spacing: Style.current.halfPadding spacing: Style.current.halfPadding
delegate: delegateWrapper
model: root.hiddenModel
header: FoldableHeader { header: FoldableHeader {
width: ListView.view.width width: ListView.view.width
@ -209,64 +154,12 @@ DoubleFlickableWithFolding {
text: qsTr("Hide") text: qsTr("Hide")
dropAreaKeys: d.dragShowcaseItemKey dropAreaKeys: d.dragShowcaseItemKey
onDropped: { onDropped: root.setVisibilityRequested(drop.source.key, visibility)
root.showcaseModel.setVisibilityByIndex(drop.source.visualIndex, visibility)
root.showcaseEntryChanged()
}
} }
onToggleFolding: root.flip2Folding() onToggleFolding: root.flip2Folding()
} }
delegate: DropArea {
id: hiddenDelegateRoot
property int visualIndex: index
visible: root.filterFunc(model)
width: ListView.view.width
height: visible && hiddenDraggableDelegateLoader.item ? hiddenDraggableDelegateLoader.item.height : 0
keys: d.dragShowcaseItemKey
onEntered: function(drag) {
drag.accept()
}
onDropped: function(drop) {
root.showcaseModel.setVisibilityByIndex(drop.source.visualIndex, Constants.ShowcaseVisibility.NoOne)
root.showcaseEntryChanged()
}
// Hidden delegate item container:
Loader {
id: hiddenDraggableDelegateLoader
property var modelData: model
property var dragParentData: root
property int visualIndexData: hiddenDelegateRoot.visualIndex
width: parent.width
sourceComponent: root.hiddenDraggableDelegateComponent
}
// Delegate shadow background when dragging:
ShadowDelegate {
id: hiddenShadow
visible: hiddenDraggableDelegateLoader.item && hiddenDraggableDelegateLoader.item.dragActive
onVisibleChanged: d.isAnyHiddenDragActive = visible
}
Binding {
when: hiddenDropAreaButton.visible
target: hiddenDraggableDelegateLoader.item
property: "blurState"
value: true
restoreMode: Binding.RestoreBindingOrValue
}
}
// Overlaid hidden listview content drop area: // Overlaid hidden listview content drop area:
DropArea { DropArea {
anchors.top: parent.top anchors.top: parent.top
@ -288,11 +181,7 @@ DoubleFlickableWithFolding {
text: qsTr("Hide") text: qsTr("Hide")
dropAreaKeys: d.dragShowcaseItemKey dropAreaKeys: d.dragShowcaseItemKey
onDropped: { onDropped: root.setVisibilityRequested(drop.source.key, visibility)
root.showcaseModel.setVisibilityByIndex(drop.source.visualIndex, visibility)
root.showcaseEntryChanged()
root.updateBaseModelFilters()
}
} }
} }
} }
@ -366,18 +255,7 @@ DoubleFlickableWithFolding {
property int margins: Style.current.halfPadding property int margins: Style.current.halfPadding
function dropped(drop, visibility) { function dropped(drop, visibility) {
var showcaseObj = drop.source.showcaseObj root.setVisibilityRequested(drop.source.key, visibility)
// need to set total balance for an asset
if (drop.source.totalValue !== undefined) {
showcaseObj.enabledNetworkBalance = drop.source.totalValue
}
var tmpObj = Object()
root.roleNames.forEach(role => tmpObj[role] = showcaseObj[role])
tmpObj.showcaseVisibility = visibility
root.showcaseModel.upsertItemJson(JSON.stringify(tmpObj))
root.showcaseEntryChanged()
} }
RowLayout { RowLayout {
@ -427,4 +305,92 @@ DoubleFlickableWithFolding {
color: Theme.palette.baseColor5 color: Theme.palette.baseColor5
radius: Style.current.radius radius: Style.current.radius
} }
Component {
id: delegateWrapper
DropArea {
id: showcaseDelegateRoot
required property var model
required property int index
readonly property int visualIndex: index
readonly property bool isHiddenShowcaseItem: !model.visibility || model.visibility === Constants.ShowcaseVisibility.NoOne
function handleEntered(drag) {
if (!showcaseDelegateRoot.isHiddenShowcaseItem) {
var from = drag.source.visualIndex
var to = visualIndex
if (to === from)
return
root.changePositionRequested(drag.source.key, to)
}
drag.accept()
}
function handleDropped(drop) {
if (showcaseDelegateRoot.isHiddenShowcaseItem) {
root.setVisibilityRequested(drop.source.key, Constants.ShowcaseVisibility.NoOne)
}
}
ListView.onRemove: SequentialAnimation {
PropertyAction { target: showcaseDelegateRoot; property: "ListView.delayRemove"; value: true }
NumberAnimation { target: showcaseDelegateRoot; property: "scale"; to: 0; easing.type: Easing.InOutQuad }
PropertyAction { target: showcaseDelegateRoot; property: "ListView.delayRemove"; value: false }
}
width: ListView.view.width
height: showcaseDraggableDelegateLoader.item ? showcaseDraggableDelegateLoader.item.height : 0
keys: d.dragShowcaseItemKey
onEntered: handleEntered(drag)
onDropped: handleDropped(drop)
// In showcase delegate item container:
Loader {
id: showcaseDraggableDelegateLoader
property var modelData: showcaseDelegateRoot.model
property var dragParentData: root
property int visualIndexData: showcaseDelegateRoot.index
property var dragKeysData: showcaseDelegateRoot.isHiddenShowcaseItem ?
d.dragHiddenItemKey : d.dragShowcaseItemKey
width: parent.width
sourceComponent: root.delegate
}
Binding {
when: showcaseDelegateRoot.isHiddenShowcaseItem ? d.isAnyShowcaseDragActive : d.isAnyHiddenDragActive
target: showcaseDraggableDelegateLoader.item
property: "blurState"
value: true
restoreMode: Binding.RestoreBindingOrValue
}
Binding {
when: showcaseShadow.visible
target: d
property: showcaseDelegateRoot.isHiddenShowcaseItem ? "isAnyHiddenDragActive" : "isAnyShowcaseDragActive"
value: true
restoreMode: Binding.RestoreBindingOrValue
}
// Delegate shadow background when dragging:
ShadowDelegate {
id: showcaseShadow
visible: showcaseDraggableDelegateLoader.item && showcaseDraggableDelegateLoader.item.dragActive
}
// Delegate shadow background when dragging:
Rectangle {
width: parent.width
height: d.defaultDelegateHeight
anchors.centerIn: parent
color: Theme.palette.baseColor5
radius: Style.current.radius
visible: showcaseShadow.visible
}
}
}
} }

View File

@ -1,7 +1,8 @@
ProfileDescriptionPanel 1.0 ProfileDescriptionPanel.qml ProfileDescriptionPanel 1.0 ProfileDescriptionPanel.qml
ProfileSocialLinksPanel 1.0 ProfileSocialLinksPanel.qml
ProfileShowcaseCommunitiesPanel 1.0 ProfileShowcaseCommunitiesPanel.qml
ProfileShowcaseCollectiblesPanel 1.0 ProfileShowcaseCollectiblesPanel.qml
ProfileShowcaseAccountsPanel 1.0 ProfileShowcaseAccountsPanel.qml ProfileShowcaseAccountsPanel 1.0 ProfileShowcaseAccountsPanel.qml
ProfileShowcaseAssetsPanel 1.0 ProfileShowcaseAssetsPanel.qml ProfileShowcaseAssetsPanel 1.0 ProfileShowcaseAssetsPanel.qml
ProfileShowcaseCollectiblesPanel 1.0 ProfileShowcaseCollectiblesPanel.qml
ProfileShowcaseCommunitiesPanel 1.0 ProfileShowcaseCommunitiesPanel.qml
ProfileShowcasePanel 1.0 ProfileShowcasePanel.qml
ProfileSocialLinksPanel 1.0 ProfileSocialLinksPanel.qml
SupportedTokenListsPanel 1.0 SupportedTokenListsPanel.qml SupportedTokenListsPanel 1.0 SupportedTokenListsPanel.qml

View File

@ -16,9 +16,11 @@ import "./profile"
import StatusQ.Core 0.1 import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1 import StatusQ.Core.Theme 0.1
import StatusQ.Core.Utils 0.1
import StatusQ.Components 0.1 import StatusQ.Components 0.1
import StatusQ.Controls 0.1 import StatusQ.Controls 0.1
import AppLayouts.Profile.helpers 1.0
import AppLayouts.Profile.panels 1.0 import AppLayouts.Profile.panels 1.0
import AppLayouts.Wallet.stores 1.0 import AppLayouts.Wallet.stores 1.0
@ -113,7 +115,18 @@ SettingsContentBase {
readonly property var priv: QtObject { readonly property var priv: QtObject {
id: priv id: priv
property bool hasAnyProfileShowcaseChanges: false property bool hasAnyProfileShowcaseChanges: showcaseModels.dirty
property ProfileShowcaseModels showcaseModels: ProfileShowcaseModels {
communitiesSourceModel: root.communitiesModel
communitiesShowcaseModel: root.profileStore.profileShowcaseCommunitiesModel
accountsSourceModel: root.walletStore.accounts
accountsShowcaseModel: root.profileStore.profileShowcaseAccountsModel
collectiblesSourceModel: root.profileStore.collectiblesModel
collectiblesShowcaseModel: root.profileStore.profileShowcaseCollectiblesModel
}
function reset() { function reset() {
descriptionPanel.displayName.text = Qt.binding(() => { return profileStore.displayName }) descriptionPanel.displayName.text = Qt.binding(() => { return profileStore.displayName })
@ -121,33 +134,15 @@ SettingsContentBase {
profileStore.resetSocialLinks() profileStore.resetSocialLinks()
profileHeader.icon = Qt.binding(() => { return profileStore.profileLargeImage }) profileHeader.icon = Qt.binding(() => { return profileStore.profileLargeImage })
profileShowcaseCommunitiesPanel.reset() priv.showcaseModels.revert()
profileShowcaseAccountsPanel.reset()
profileShowcaseCollectiblesPanel.reset()
profileShowcaseAssetsPanel.reset()
root.profileStore.requestProfileShowcasePreferences() root.profileStore.requestProfileShowcasePreferences()
hasAnyProfileShowcaseChanges = false
} }
function save() { function save() {
if (hasAnyProfileShowcaseChanges) if (hasAnyProfileShowcaseChanges)
profileStore.storeProfileShowcasePreferences() print ("Profile showcase changes detected: SAVING")
//TODO: implement save as deschibed here
if (!descriptionPanel.isEnsName) // https://github.com/status-im/status-desktop/pull/13708
profileStore.setDisplayName(descriptionPanel.displayName.text)
profileStore.setBio(descriptionPanel.bio.text.trim())
profileStore.saveSocialLinks()
if (profileHeader.icon === "") {
root.profileStore.removeImage()
} else {
profileStore.uploadImage(profileHeader.icon,
profileHeader.cropRect.x.toFixed(),
profileHeader.cropRect.y.toFixed(),
(profileHeader.cropRect.x + profileHeader.cropRect.width).toFixed(),
(profileHeader.cropRect.y + profileHeader.cropRect.height).toFixed());
}
reset()
} }
} }
@ -206,32 +201,50 @@ SettingsContentBase {
// communities // communities
ProfileShowcaseCommunitiesPanel { ProfileShowcaseCommunitiesPanel {
id: profileShowcaseCommunitiesPanel id: profileShowcaseCommunitiesPanel
baseModel: root.communitiesModel inShowcaseModel: priv.showcaseModels.communitiesVisibleModel
showcaseModel: root.profileStore.profileShowcaseCommunitiesModel hiddenModel: priv.showcaseModels.communitiesHiddenModel
onShowcaseEntryChanged: priv.hasAnyProfileShowcaseChanges = true
onChangePositionRequested: function (key, to) {
priv.showcaseModels.changeCommunityPosition(key, to)
}
onSetVisibilityRequested: function (key, toVisibility) {
priv.showcaseModels.setCommunityVisibility(key, toVisibility)
}
} }
// accounts // accounts
ProfileShowcaseAccountsPanel { ProfileShowcaseAccountsPanel {
id: profileShowcaseAccountsPanel id: profileShowcaseAccountsPanel
baseModel: root.walletStore.accounts inShowcaseModel: priv.showcaseModels.accountsVisibleModel
showcaseModel: root.profileStore.profileShowcaseAccountsModel hiddenModel: priv.showcaseModels.accountsHiddenModel
currentWallet: root.walletStore.overview.mixedcaseAddress currentWallet: root.walletStore.overview.mixedcaseAddress
onShowcaseEntryChanged: priv.hasAnyProfileShowcaseChanges = true
onChangePositionRequested: function (key, to) {
priv.showcaseModels.changeAccountPosition(key, to)
}
onSetVisibilityRequested: function (key, toVisibility) {
priv.showcaseModels.setAccountVisibility(key, toVisibility)
}
} }
// collectibles // collectibles
ProfileShowcaseCollectiblesPanel { ProfileShowcaseCollectiblesPanel {
id: profileShowcaseCollectiblesPanel id: profileShowcaseCollectiblesPanel
baseModel: root.profileStore.collectiblesModel
showcaseModel: root.profileStore.profileShowcaseCollectiblesModel
addAccountsButtonVisible: root.profileStore.profileShowcaseAccountsModel.hiddenCount > 0
onShowcaseEntryChanged: priv.hasAnyProfileShowcaseChanges = true addAccountsButtonVisible: priv.showcaseModels.accountsHiddenModel > 0
onNavigateToAccountsTab: profileTabBar.currentIndex = MyProfileView.TabIndex.Accounts onNavigateToAccountsTab: profileTabBar.currentIndex = MyProfileView.TabIndex.Accounts
inShowcaseModel: priv.showcaseModels.collectiblesVisibleModel
hiddenModel: priv.showcaseModels.collectiblesHiddenModel
onChangePositionRequested: function (key, to) {
priv.showcaseModels.changeCollectiblePosition(key, to)
}
onSetVisibilityRequested: function (key, toVisibility) {
priv.showcaseModels.setCollectibleVisibility(key, toVisibility)
}
} }
// web // web

View File

@ -15,10 +15,9 @@ StatusListView {
property bool footerContentVisible: true property bool footerContentVisible: true
property Component additionalFooterComponent property Component additionalFooterComponent
// TO BE REMOVE: #13498
property bool empty: root.model && root.count === 0
ScrollBar.vertical: null ScrollBar.vertical: null
footerPositioning: ListView.PullBackFooter
footer: ColumnLayout { footer: ColumnLayout {
width: root.width width: root.width
@ -27,7 +26,7 @@ StatusListView {
Layout.preferredHeight: root.footerHeight Layout.preferredHeight: root.footerHeight
Layout.fillWidth: true Layout.fillWidth: true
visible: root.empty// TO BE REPLACE root.empty in (#13498): root.empty = root.model && root.count === 0 visible: root.model && root.count === 0
ShapeRectangle { ShapeRectangle {
id: shapeRectangle id: shapeRectangle