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.Utils 0.1 as CoreUtils
import mainui 1.0
import AppLayouts.Profile.panels 1.0
import shared.stores 1.0
@ -21,91 +20,76 @@ SplitView {
orientation: Qt.Vertical
Popups {
popupParent: root
rootStore: QtObject {}
communityTokensStore: CommunityTokensStore {}
readonly property string currentWallet: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7420"
ListModel {
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 {
id: emptyModel
}
ListModel {
id: accountsModel
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
ProfileShowcaseAccountsPanel {
id: showcasePanel
SplitView.fillWidth: true
SplitView.preferredHeight: 500
ProfileShowcaseAccountsPanel {
id: showcasePanel
width: 500
baseModel: emptyModelChecker.checked ? emptyModel : accountsModel
showcaseModel: inShowcaseAccountsModel
currentWallet: root.currentWallet
}
inShowcaseModel: emptyModelChecker.checked ? emptyModel : inShowcaseModelItem
hiddenModel: emptyModelChecker.checked ? emptyModel : hiddenModelItem
currentWallet: root.currentWallet
}
LogsAndControlsPanel {
@ -117,9 +101,8 @@ SplitView {
logsView.logText: logs.logText
ColumnLayout {
Button {
text: "Reset (clear settings)"
onClicked: showcasePanel.reset()
Label {
text: "ⓘ Shwcase interaction implemented in ProfileShowcasePanelPage"
}
CheckBox {
@ -127,8 +110,6 @@ SplitView {
text: "Empty model"
checked: false
onClicked: showcasePanel.reset()
}
}
}

View File

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

View File

@ -23,71 +23,132 @@ SplitView {
orientation: Qt.Vertical
Popups {
popupParent: root
rootStore: QtObject {}
communityTokensStore: CommunityTokensStore {}
}
ListModel {
id: emptyModel
}
ListModel {
id: collectiblesModel
id: hiddenModelItem
readonly property var data: [
{
uid: "123",
name: "SNT",
key: "1234",
name: "SNTT",
collectionName: "Super Nitro Toluen (with pink bg)",
backgroundColor: "pink",
imageUrl: ModelsData.collectibles.custom,
isLoading: false,
communityId: "ddls"
communityId: "ddls",
visibility: Constants.ShowcaseVisibility.NoOne
},
{
uid: "34545656768",
name: "Kitty 1",
key: "3454565676",
name: "Kitty 3",
collectionName: "Kitties",
backgroundColor: "",
imageUrl: ModelsData.collectibles.kitty1Big,
isLoading: false
isLoading: false,
visibility: Constants.ShowcaseVisibility.NoOne
},
{
uid: "123456",
name: "Kitty 2",
key: "12345",
name: "Kitty 4",
collectionName: "",
backgroundColor: "",
imageUrl: ModelsData.collectibles.kitty2Big,
isLoading: false,
communityId: "sox"
communityId: "sox",
visibility: Constants.ShowcaseVisibility.NoOne
},
{
uid: "12345645459537432",
key: "123456454595374",
name: "",
collectionName: "Super Kitties",
backgroundColor: "oink",
imageUrl: ModelsData.collectibles.kitty3Big,
isLoading: false,
communityId: "ast"
communityId: "ast",
visibility: Constants.ShowcaseVisibility.NoOne
},
{
uid: "691",
key: "6912",
name: "KILLABEAR",
collectionName: "KILLABEARS",
backgroundColor: "#807c56",
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",
description: "",
collectionName: "AIORBIT (Animated SVG)",
backgroundColor: "",
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)
@ -117,63 +178,37 @@ SplitView {
}
LeftJoinModel {
id: leftJoinModel
id: joinedInShowcase
leftModel: collectiblesModel
leftModel: inShowcaseModelItem
rightModel: communityModel
joinRole: "communityId"
}
ListModel {
id: inShowcaseCollectiblesModel
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))
}
id: emptyModelItem
}
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.preferredHeight: 500
ProfileShowcaseCollectiblesPanel {
id: showcasePanel
width: 500
baseModel: emptyModelChecker.checked ? emptyModel : leftJoinModel
showcaseModel: inShowcaseCollectiblesModel
addAccountsButtonVisible: !hasAllAccountsChecker.checked
inShowcaseModel: emptyModelChecker.checked ? emptyModelItem : joinedInShowcase
hiddenModel: emptyModelChecker.checked ? emptyModelItem : joinedHiddenModel
onNavigateToAccountsTab: logs.logEvent("ProfileShowcaseCollectiblesPanel::onNavigateToAccountsTab")
}
addAccountsButtonVisible: !hasAllAccountsChecker.checked
onNavigateToAccountsTab: logs.logEvent("ProfileShowcaseCollectiblesPanel::onNavigateToAccountsTab")
}
LogsAndControlsPanel {
@ -185,12 +220,10 @@ SplitView {
logsView.logText: logs.logText
ColumnLayout {
Button {
text: "Reset (clear settings)"
onClicked: showcasePanel.settings.reset()
Label {
text: "ⓘ Shwcase interaction implemented in ProfileShowcasePanelPage"
}
CheckBox {
id: hasAllAccountsChecker
@ -203,10 +236,7 @@ SplitView {
text: "Empty model"
checked: false
onClicked: showcasePanel.reset()
}
}
}
}

View File

@ -5,7 +5,6 @@ import QtQuick.Layouts 1.15
import StatusQ.Core 0.1
import StatusQ.Core.Utils 0.1 as CoreUtils
import mainui 1.0
import AppLayouts.Profile.panels 1.0
import AppLayouts.Profile.controls 1.0
import shared.stores 1.0
@ -22,106 +21,110 @@ SplitView {
orientation: Qt.Vertical
Popups {
popupParent: root
rootStore: QtObject {}
communityTokensStore: CommunityTokensStore {}
ListModel {
id: hiddenModelItem
Component.onCompleted:
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 {
id: emptyModel
}
ListModel {
id: communitiesModel
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
ProfileShowcaseCommunitiesPanel {
id: showcasePanel
SplitView.fillWidth: true
SplitView.preferredHeight: 500
ProfileShowcaseCommunitiesPanel {
id: showcasePanel
width: 500
baseModel: emptyModelChecker.checked ? emptyModel : communitiesModel
showcaseModel: inShowcaseCommunitiesModel
}
inShowcaseModel: emptyModelChecker.checked ? emptyModel : inShowcaseModelItem
hiddenModel: emptyModelChecker.checked ? emptyModel : hiddenModelItem
}
LogsAndControlsPanel {
@ -133,9 +136,8 @@ SplitView {
logsView.logText: logs.logText
ColumnLayout {
Button {
text: "Reset (clear settings)"
onClicked: showcasePanel.reset()
Label {
text: "ⓘ Shwcase interaction implemented in ProfileShowcasePanelPage"
}
CheckBox {
@ -143,11 +145,10 @@ SplitView {
text: "Empty model"
checked: false
onClicked: showcasePanel.reset()
}
}
}
}
// 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/ModelsComparator.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/StatesStack.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 {
id: root
property var showcaseObj
property alias tag: tagItem
property int showcaseVisibility: Constants.ShowcaseVisibility.NoOne
property bool blurState: false
@ -46,10 +46,9 @@ StatusDraggableListItem {
actions: [
ManageTokensCommunityTag {
id: tagItem
Layout.maximumWidth: root.width *.4
visible: showcaseObj && !!showcaseObj.communityId
text: showcaseObj && !! showcaseObj.communityName ? showcaseObj.communityName : ""
asset.name: showcaseObj && !!showcaseObj.communityImage ? showcaseObj.communityImage : ""
visible: false
},
StatusRoundButton {
icon.name: ProfileUtils.visibilityIcon(root.showcaseVisibility)

View File

@ -1,8 +1,5 @@
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
ShowcaseDelegate 1.0 ShowcaseDelegate.qml
StaticSocialLinkInput 1.0 StaticSocialLinkInput.qml
WalletKeyPairDelegate 1.0 WalletKeyPairDelegate.qml

View File

@ -3,43 +3,25 @@ import QtQuick 2.15
import utils 1.0
import AppLayouts.Profile.controls 1.0
import AppLayouts.Wallet 1.0
import StatusQ.Core.Theme 0.1
ProfileShowcasePanel {
id: root
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")
emptyHiddenPlaceholderText: qsTr("Accounts here will be hidden from your profile")
hiddenDraggableDelegateComponent: AccountShowcaseDelegate {
Drag.keys: ["x-status-draggable-showcase-item-hidden"]
showcaseObj: modelData
dragParent: dragParentData
visualIndex: visualIndexData
highlighted: !!modelData && modelData.address === root.currentWallet
onShowcaseVisibilityRequested: {
var tmpObj = Object()
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()
}
delegate: ProfileShowcasePanel.Delegate {
title: model ? model.name : ""
secondaryTitle: WalletUtils.addressToDisplay(model ? model.key : "", "", true, containsMouse)
hasEmoji: model && !!model.emoji
hasIcon: !hasEmoji
icon.name: hasEmoji ? model.emoji : "filled-account"
icon.color: model && model.colorId ? Utils.getColorForId(model.colorId) : Theme.palette.primaryColor3
highlighted: model ? model.key === root.currentWallet : false
}
}

View File

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

View File

@ -16,39 +16,26 @@ ProfileShowcasePanel {
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")
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
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 {
id: addMoreAccountsComponent

View File

@ -7,35 +7,18 @@ import AppLayouts.Profile.controls 1.0
ProfileShowcasePanel {
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")
emptyHiddenPlaceholderText: qsTr("Communities here will be hidden from your Profile")
hiddenDraggableDelegateComponent: CommunityShowcaseDelegate {
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
root.showcaseModel.upsertItemJson(JSON.stringify(tmpObj))
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()
}
delegate: ProfileShowcasePanel.Delegate {
title: model ? model.name : ""
secondaryTitle: model && (model.memberRole === Constants.memberRole.owner ||
model.memberRole === Constants.memberRole.admin ||
model.memberRole === Constants.memberRole.tokenMaster) ? qsTr("Admin") : qsTr("Member")
hasImage: model && !!model.image
icon.name: model ? model.name : ""
icon.source: model ? model.image : ""
icon.color: model ? model.color : ""
}
}

View File

@ -2,6 +2,7 @@ import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQml 2.15
import QtQml.Models 2.15
import StatusQ.Controls 0.1
import StatusQ.Core 0.1
@ -16,44 +17,51 @@ import AppLayouts.Profile.controls 1.0
DoubleFlickableWithFolding {
id: root
readonly property var showcaseRoles: ["showcaseVisibility", "order"]
property Component delegate: Delegate {}
required property string keyRole
required property var roleNames
required property var filterFunc
property var baseModel
property var showcaseModel
property Component showcaseDraggableDelegateComponent
property Component hiddenDraggableDelegateComponent
// Expected roles:
// - visibility: int
property var inShowcaseModel
property var hiddenModel
property Component additionalFooterComponent
// Placeholder text to be shown when the list is empty
property string emptyInShowcasePlaceholderText
property string emptyHiddenPlaceholderText
readonly property Connections showcaseUpdateConnections: Connections {
target: root.showcaseModel
// Signal to requst position change of the visible items
signal changePositionRequested(var key, int to)
// Signal to request visibility change of the items
signal setVisibilityRequested(var key, int toVisibility)
function onBaseModelFilterConditionsMayHaveChanged() {
root.updateBaseModelFilters()
// Public delegate component. Implements the minimal ShowcaseDelegate interface needed for DND
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() {
root.showcaseModel.clear()
updateBaseModelFilters()
ScrollBar.vertical: StatusScrollBar {
policy: ScrollBar.AsNeeded
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 {
id: d
@ -69,20 +77,16 @@ DoubleFlickableWithFolding {
clip: true
ScrollBar.vertical: StatusScrollBar {
policy: ScrollBar.AsNeeded
visible: resolveVisibility(policy, root.height, root.contentHeight)
}
flickable1: EmptyShapeRectangleFooterListView {
id: inShowcaseListView
model: root.showcaseModel
width: root.width
placeholderText: root.emptyInShowcasePlaceholderText
footerHeight: ProfileUtils.defaultDelegateHeight
footerContentVisible: !dropAreaRow.visible
spacing: Style.current.halfPadding
delegate: delegateWrapper
model: root.inShowcaseModel
header: FoldableHeader {
width: ListView.view.width
@ -101,66 +105,7 @@ DoubleFlickableWithFolding {
}
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:
DropArea {
@ -188,14 +133,14 @@ DoubleFlickableWithFolding {
flickable2: EmptyShapeRectangleFooterListView {
id: hiddenListView
model: root.baseModel
width: root.width
placeholderText: root.emptyHiddenPlaceholderText
footerHeight: ProfileUtils.defaultDelegateHeight
footerContentVisible: !hiddenDropAreaButton.visible
empty: root.showcaseModel.hiddenCount === 0 && !root.flickable2Folded // TO BE REMOVE: #13498
additionalFooterComponent: root.additionalFooterComponent
spacing: Style.current.halfPadding
delegate: delegateWrapper
model: root.hiddenModel
header: FoldableHeader {
width: ListView.view.width
@ -209,64 +154,12 @@ DoubleFlickableWithFolding {
text: qsTr("Hide")
dropAreaKeys: d.dragShowcaseItemKey
onDropped: {
root.showcaseModel.setVisibilityByIndex(drop.source.visualIndex, visibility)
root.showcaseEntryChanged()
}
onDropped: root.setVisibilityRequested(drop.source.key, visibility)
}
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:
DropArea {
anchors.top: parent.top
@ -288,11 +181,7 @@ DoubleFlickableWithFolding {
text: qsTr("Hide")
dropAreaKeys: d.dragShowcaseItemKey
onDropped: {
root.showcaseModel.setVisibilityByIndex(drop.source.visualIndex, visibility)
root.showcaseEntryChanged()
root.updateBaseModelFilters()
}
onDropped: root.setVisibilityRequested(drop.source.key, visibility)
}
}
}
@ -366,18 +255,7 @@ DoubleFlickableWithFolding {
property int margins: Style.current.halfPadding
function dropped(drop, visibility) {
var showcaseObj = drop.source.showcaseObj
// 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()
root.setVisibilityRequested(drop.source.key, visibility)
}
RowLayout {
@ -427,4 +305,92 @@ DoubleFlickableWithFolding {
color: Theme.palette.baseColor5
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
ProfileSocialLinksPanel 1.0 ProfileSocialLinksPanel.qml
ProfileShowcaseCommunitiesPanel 1.0 ProfileShowcaseCommunitiesPanel.qml
ProfileShowcaseCollectiblesPanel 1.0 ProfileShowcaseCollectiblesPanel.qml
ProfileShowcaseAccountsPanel 1.0 ProfileShowcaseAccountsPanel.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

View File

@ -16,9 +16,11 @@ import "./profile"
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Core.Utils 0.1
import StatusQ.Components 0.1
import StatusQ.Controls 0.1
import AppLayouts.Profile.helpers 1.0
import AppLayouts.Profile.panels 1.0
import AppLayouts.Wallet.stores 1.0
@ -113,7 +115,18 @@ SettingsContentBase {
readonly property var priv: QtObject {
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() {
descriptionPanel.displayName.text = Qt.binding(() => { return profileStore.displayName })
@ -121,33 +134,15 @@ SettingsContentBase {
profileStore.resetSocialLinks()
profileHeader.icon = Qt.binding(() => { return profileStore.profileLargeImage })
profileShowcaseCommunitiesPanel.reset()
profileShowcaseAccountsPanel.reset()
profileShowcaseCollectiblesPanel.reset()
profileShowcaseAssetsPanel.reset()
priv.showcaseModels.revert()
root.profileStore.requestProfileShowcasePreferences()
hasAnyProfileShowcaseChanges = false
}
function save() {
if (hasAnyProfileShowcaseChanges)
profileStore.storeProfileShowcasePreferences()
if (!descriptionPanel.isEnsName)
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()
print ("Profile showcase changes detected: SAVING")
//TODO: implement save as deschibed here
// https://github.com/status-im/status-desktop/pull/13708
}
}
@ -206,32 +201,50 @@ SettingsContentBase {
// communities
ProfileShowcaseCommunitiesPanel {
id: profileShowcaseCommunitiesPanel
baseModel: root.communitiesModel
showcaseModel: root.profileStore.profileShowcaseCommunitiesModel
onShowcaseEntryChanged: priv.hasAnyProfileShowcaseChanges = true
inShowcaseModel: priv.showcaseModels.communitiesVisibleModel
hiddenModel: priv.showcaseModels.communitiesHiddenModel
onChangePositionRequested: function (key, to) {
priv.showcaseModels.changeCommunityPosition(key, to)
}
onSetVisibilityRequested: function (key, toVisibility) {
priv.showcaseModels.setCommunityVisibility(key, toVisibility)
}
}
// accounts
ProfileShowcaseAccountsPanel {
id: profileShowcaseAccountsPanel
baseModel: root.walletStore.accounts
showcaseModel: root.profileStore.profileShowcaseAccountsModel
inShowcaseModel: priv.showcaseModels.accountsVisibleModel
hiddenModel: priv.showcaseModels.accountsHiddenModel
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
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
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

View File

@ -15,10 +15,9 @@ StatusListView {
property bool footerContentVisible: true
property Component additionalFooterComponent
// TO BE REMOVE: #13498
property bool empty: root.model && root.count === 0
ScrollBar.vertical: null
footerPositioning: ListView.PullBackFooter
footer: ColumnLayout {
width: root.width
@ -27,7 +26,7 @@ StatusListView {
Layout.preferredHeight: root.footerHeight
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 {
id: shapeRectangle