feat: implement ProfileShowcase settings

Implement the UI part of Profile/Settings/Showcase:

- Communities/Accounts/Collectibles/Assets tabs
- drag and drop of items between "hidden" and "in showcase" sections
- ability to set individual items' visibility
- persistency (showcase saved across restarts), not exposed yet due to
  missing backend API

Closes #9936
This commit is contained in:
Lukáš Tinkl 2023-03-20 13:29:05 +01:00 committed by Lukáš Tinkl
parent d180001f84
commit a8eed304c0
43 changed files with 1398 additions and 175 deletions

View File

@ -101,6 +101,26 @@ ListModel {
title: "TokenHoldersPanel"
section: "Panels"
}
ListElement {
title: "ProfileSocialLinksPanel"
section: "Panels"
}
ListElement {
title: "ProfileShowcaseCommunitiesPanel"
section: "Panels"
}
ListElement {
title: "ProfileShowcaseAccountsPanel"
section: "Panels"
}
ListElement {
title: "ProfileShowcaseCollectiblesPanel"
section: "Panels"
}
ListElement {
title: "ProfileShowcaseAssetsPanel"
section: "Panels"
}
ListElement {
title: "InviteFriendsToCommunityPopup"
section: "Popups"
@ -213,8 +233,4 @@ ListModel {
title: "LanguageCurrencySettings"
section: "Settings"
}
ListElement {
title: "ProfileSocialLinksPanel"
section: "Panels"
}
}

View File

@ -138,6 +138,27 @@
"https://www.figma.com/file/ibJOTPlNtIxESwS96vJb06/%F0%9F%91%A4-Profile-%7C-Desktop?node-id=6%3A16845&t=h8DUW6Eysawqe5u0-0",
"https://www.figma.com/file/ibJOTPlNtIxESwS96vJb06/%F0%9F%91%A4-Profile-%7C-Desktop?node-id=4%3A25437&t=h8DUW6Eysawqe5u0-0"
],
"ProfileShowcaseAccountsPanel": [
"https://www.figma.com/file/idUoxN7OIW2Jpp3PMJ1Rl8/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop?node-id=14580-339549&t=RkXAEv3G6mp3EUvl-0",
"https://www.figma.com/file/idUoxN7OIW2Jpp3PMJ1Rl8/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop?node-id=14729-233846&t=RkXAEv3G6mp3EUvl-0",
"https://www.figma.com/file/idUoxN7OIW2Jpp3PMJ1Rl8/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop?node-id=14609-237740&t=RkXAEv3G6mp3EUvl-0"
],
"ProfileShowcaseAssetsPanel": [
"https://www.figma.com/file/idUoxN7OIW2Jpp3PMJ1Rl8/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop?node-id=14588-319260&t=RkXAEv3G6mp3EUvl-0",
"https://www.figma.com/file/idUoxN7OIW2Jpp3PMJ1Rl8/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop?node-id=14609-238808&t=RkXAEv3G6mp3EUvl-0",
"https://www.figma.com/file/idUoxN7OIW2Jpp3PMJ1Rl8/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop?node-id=14609-239912&t=RkXAEv3G6mp3EUvl-0",
"https://www.figma.com/file/idUoxN7OIW2Jpp3PMJ1Rl8/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop?node-id=14609-240991&t=RkXAEv3G6mp3EUvl-0"
],
"ProfileShowcaseCollectiblesPanel": [
"https://www.figma.com/file/idUoxN7OIW2Jpp3PMJ1Rl8/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop?node-id=14609-235560&t=RkXAEv3G6mp3EUvl-0",
"https://www.figma.com/file/idUoxN7OIW2Jpp3PMJ1Rl8/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop?node-id=14729-235696&t=RkXAEv3G6mp3EUvl-0",
"https://www.figma.com/file/idUoxN7OIW2Jpp3PMJ1Rl8/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop?node-id=14729-237604&t=RkXAEv3G6mp3EUvl-0"
],
"ProfileShowcaseCommunitiesPanel": [
"https://www.figma.com/file/idUoxN7OIW2Jpp3PMJ1Rl8/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop?node-id=14580-339532&t=RkXAEv3G6mp3EUvl-0",
"https://www.figma.com/file/idUoxN7OIW2Jpp3PMJ1Rl8/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop?node-id=14729-231402&t=RkXAEv3G6mp3EUvl-0",
"https://www.figma.com/file/idUoxN7OIW2Jpp3PMJ1Rl8/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop?node-id=14609-236656&t=RkXAEv3G6mp3EUvl-0"
],
"ProfileSocialLinksPanel": [
"https://www.figma.com/file/idUoxN7OIW2Jpp3PMJ1Rl8/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop?node-id=14588%3A308727&t=cwFGbBHsAGOP0T5R-0"
],

View File

@ -16,6 +16,10 @@ ApplicationWindow {
property string currentPage
palette.window: Theme.palette.statusAppLayout.backgroundColor
palette.text: Theme.palette.directColor1
palette.windowText: Theme.palette.directColor1
palette.base: Theme.palette.indirectColor1
font.pixelSize: 13
PagesModel {

View File

@ -338,7 +338,8 @@ SplitView {
description: "Super Crypto Kitty",
backgroundColor: "",
imageUrl: ModelsData.collectibles.cryptoKitties,
permalink: ""
permalink: "",
isLoading: false
},
{
id: 34545656768,
@ -346,7 +347,8 @@ SplitView {
description: "",
backgroundColor: "green",
imageUrl: ModelsData.collectibles.kitty1Big,
permalink: ""
permalink: "",
isLoading: false
},
{
id: 123456,
@ -354,7 +356,8 @@ SplitView {
description: "",
backgroundColor: "",
imageUrl: ModelsData.collectibles.kitty2Big,
permalink: ""
permalink: "",
isLoading: false
},
{
id: 12345645459537432,
@ -362,7 +365,8 @@ SplitView {
description: "Kitty 3 description",
backgroundColor: "oink",
imageUrl: ModelsData.collectibles.kitty3Big,
permalink: ""
permalink: "",
isLoading: false
},
{
id: 691,
@ -370,7 +374,8 @@ SplitView {
description: "Please note that weapons are not yet reflected in the rarity stats.",
backgroundColor: "#807c56",
imageUrl: "https://assets.killabears.com/content/killabears/img/691-e81f892696a8ae700e0dbc62eb072060679a2046d1ef5eb2671bdb1fad1f68e3.png",
permalink: "https://opensea.io/assets/ethereum/0xc99c679c50033bbc5321eb88752e89a93e9e83c5/691"
permalink: "https://opensea.io/assets/ethereum/0xc99c679c50033bbc5321eb88752e89a93e9e83c5/691",
isLoading: true
}
]
Component.onCompleted: append(data)

View File

@ -0,0 +1,85 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import StatusQ.Core 0.1
import StatusQ.Core.Utils 0.1 as CoreUtils
import mainui 1.0
import AppLayouts.Profile.panels 1.0
import utils 1.0
import Storybook 1.0
import Models 1.0
SplitView {
id: root
Logs { id: logs }
orientation: Qt.Vertical
Popups {
popupParent: root
rootStore: QtObject {}
}
readonly property string currentWallet: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7420"
ListModel {
id: accountsModel
ListElement {
name: "My Status Account"
address: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7420"
color: "lightcoral"
emoji: "🇨🇿"
walletType: ""
}
ListElement {
name: "testing (no emoji, colored, seed)"
address: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7000"
color: "indigo"
emoji: ""
walletType: "seed"
}
ListElement {
name: "My Bro's Account"
address: "0xcdc2ea3b6ba8fed3a3402f8db8b2fab53e7b7421"
color: ""
emoji: "🇸🇰"
walletType: "watch"
}
ListElement {
name: "Keycard"
address: "0xdeadbeef"
color: "red"
emoji: ""
walletType: "key"
}
}
StatusScrollView { // wrapped in a ScrollView on purpose; to simulate SettingsContentBase.qml
SplitView.fillWidth: true
SplitView.preferredHeight: 500
ProfileShowcaseAccountsPanel {
id: showcasePanel
width: 500
baseModel: accountsModel
currentWallet: root.currentWallet
}
}
LogsAndControlsPanel {
id: logsAndControlsPanel
SplitView.minimumHeight: 100
SplitView.preferredHeight: 200
logsView.logText: logs.logText
Button {
text: "Reset (clear settings)"
onClicked: showcasePanel.settings.reset()
}
}
}

View File

@ -0,0 +1,114 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import StatusQ.Core 0.1
import StatusQ.Core.Utils 0.1 as CoreUtils
import mainui 1.0
import AppLayouts.Profile.panels 1.0
import utils 1.0
import Storybook 1.0
import Models 1.0
SplitView {
id: root
Logs { id: logs }
orientation: Qt.Vertical
Popups {
popupParent: root
rootStore: QtObject {}
}
ListModel {
id: assetsModel
readonly property var data: [
{
name: "Decentraland",
symbol: "MANA",
enabledNetworkBalance: {
amount: 301,
symbol: "MANA"
},
changePct24hour: -2.1,
visibleForNetworkWithPositiveBalance: true
},
{
name: "Ave Maria",
symbol: "AAVE",
enabledNetworkBalance: {
amount: 23.3,
symbol: "AAVE"
},
changePct24hour: 4.56,
visibleForNetworkWithPositiveBalance: true
},
{
name: "Polymorphism",
symbol: "POLY",
enabledNetworkBalance: {
amount: 3590,
symbol: "POLY"
},
changePct24hour: -11.6789,
visibleForNetworkWithPositiveBalance: true
},
{
name: "Common DDT",
symbol: "CDT",
enabledNetworkBalance: {
amount: 1000,
symbol: "CDT"
},
changePct24hour: 0,
visibleForNetworkWithPositiveBalance: true
},
{
name: "Makers' choice",
symbol: "MKR",
enabledNetworkBalance: {
amount: 1.3,
symbol: "MKR"
},
changePct24hour: -1,
visibleForNetworkWithPositiveBalance: true
},
{
name: "GetOuttaHere",
symbol: "InvisibleHere",
enabledNetworkBalance: {},
changePct24hour: 0,
visibleForNetworkWithPositiveBalance: false
}
]
Component.onCompleted: append(data)
}
StatusScrollView { // wrapped in a ScrollView on purpose; to simulate SettingsContentBase.qml
SplitView.fillWidth: true
SplitView.preferredHeight: 500
ProfileShowcaseAssetsPanel {
id: showcasePanel
width: 500
baseModel: assetsModel
}
}
LogsAndControlsPanel {
id: logsAndControlsPanel
SplitView.minimumHeight: 100
SplitView.preferredHeight: 200
logsView.logText: logs.logText
Button {
text: "Reset (clear settings)"
onClicked: showcasePanel.settings.reset()
}
}
}

View File

@ -0,0 +1,117 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import StatusQ.Core 0.1
import StatusQ.Core.Utils 0.1 as CoreUtils
import mainui 1.0
import AppLayouts.Profile.panels 1.0
import utils 1.0
import Storybook 1.0
import Models 1.0
SplitView {
id: root
Logs { id: logs }
orientation: Qt.Vertical
Popups {
popupParent: root
rootStore: QtObject {}
}
ListModel {
id: collectiblesModel
readonly property var data: [
{
id: 123,
name: "SNT",
description: "",
collectionName: "Super Nitro Toluen (with pink bg)",
backgroundColor: "pink",
imageUrl: ModelsData.collectibles.custom,
permalink: "green",
isLoading: false
},
{
id: 34545656768,
name: "Kitty 1",
description: "",
collectionName: "Kitties",
backgroundColor: "",
imageUrl: ModelsData.collectibles.kitty1Big,
permalink: "",
isLoading: false
},
{
id: 123456,
name: "Kitty 2",
description: "",
collectionName: "",
backgroundColor: "",
imageUrl: ModelsData.collectibles.kitty2Big,
permalink: "",
isLoading: false
},
{
id: 12345645459537432,
name: "",
description: "Kitty 3 description",
collectionName: "Super Kitties",
backgroundColor: "oink",
imageUrl: ModelsData.collectibles.kitty3Big,
permalink: "",
isLoading: false
},
{
id: 691,
name: "KILLABEAR",
description: "Please note that weapons are not yet reflected in the rarity stats.",
collectionName: "KILLABEARS",
backgroundColor: "#807c56",
imageUrl: "https://assets.killabears.com/content/killabears/img/691-e81f892696a8ae700e0dbc62eb072060679a2046d1ef5eb2671bdb1fad1f68e3.png",
permalink: "https://opensea.io/assets/ethereum/0xc99c679c50033bbc5321eb88752e89a93e9e83c5/691",
isLoading: true
},
{
id: 8876,
name: "AIORBIT",
description: "",
collectionName: "AIORBIT (Animated SVG)",
backgroundColor: "",
imageUrl: "https://dl.openseauserdata.com/cache/originImage/files/8b14ef530b28853445c27d6693c4e805.svg",
permalink: "https://opensea.io/assets/ethereum/0xba66a7c5e1f89a542e3108e3df155a9bf41ac824/8876",
isLoading: false
}
]
Component.onCompleted: append(data)
}
StatusScrollView { // wrapped in a ScrollView on purpose; to simulate SettingsContentBase.qml
SplitView.fillWidth: true
SplitView.preferredHeight: 500
ProfileShowcaseCollectiblesPanel {
id: showcasePanel
width: 500
baseModel: collectiblesModel
}
}
LogsAndControlsPanel {
id: logsAndControlsPanel
SplitView.minimumHeight: 100
SplitView.preferredHeight: 200
logsView.logText: logs.logText
Button {
text: "Reset (clear settings)"
onClicked: showcasePanel.settings.reset()
}
}
}

View File

@ -0,0 +1,96 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import StatusQ.Core 0.1
import StatusQ.Core.Utils 0.1 as CoreUtils
import mainui 1.0
import AppLayouts.Profile.panels 1.0
import utils 1.0
import Storybook 1.0
import Models 1.0
SplitView {
id: root
Logs { id: logs }
orientation: Qt.Vertical
Popups {
popupParent: root
rootStore: QtObject {}
}
ListModel {
id: communitiesModel
Component.onCompleted:
append([{
id: "0x0001",
name: "Test community",
joined: true,
amISectionAdmin: true,
image: ModelsData.icons.dribble,
color: "yellow"
},
{
id: "0x0002",
name: "Test community 2",
joined: true,
amISectionAdmin: false,
image: ModelsData.collectibles.custom,
color: "peach"
},
{
id: "0x0003",
name: "Test community invisible",
joined: false,
amISectionAdmin: false,
image: "",
color: "red"
},
{
id: "0x0004",
name: "Test community 3",
joined: true,
amISectionAdmin: false,
image: "",
color: "whitesmoke"
},
{
id: "0x0005",
name: "Test community 4",
joined: true,
amISectionAdmin: true,
image: ModelsData.icons.spotify,
color: "green"
},
])
}
StatusScrollView { // wrapped in a ScrollView on purpose; to simulate SettingsContentBase.qml
SplitView.fillWidth: true
SplitView.preferredHeight: 500
ProfileShowcaseCommunitiesPanel {
id: showcasePanel
width: 500
baseModel: communitiesModel
}
}
LogsAndControlsPanel {
id: logsAndControlsPanel
SplitView.minimumHeight: 100
SplitView.preferredHeight: 200
logsView.logText: logs.logText
Button {
text: "Reset (clear settings)"
onClicked: showcasePanel.settings.reset()
}
}
}

View File

@ -12,7 +12,7 @@ import StatusQ.Core.Theme 0.1
\since StatusQ.Components 0.1
\brief It is a list item with the ability to be dragged and dropped to reorder within a list view. Inherits from \c QtQuickControls::ItemDelegate.
The \c StatusDraggableListItem is a list item with an icon, title and a subtitle on the left side, and optional actions on the right.
The \c StatusDraggableListItem is a list item with a (smartident)icon, title and a subtitle on the left side, and optional actions on the right.
It displays a drag handle on its left side
@ -145,9 +145,49 @@ ItemDelegate {
*/
property bool draggable
/*!
\qmlproperty int StatusDraggableListItem::dragAxis
This property holds whether this item can be dragged along the x-axis (Drag.XAxis), y-axis (Drag.YAxis),
or both (Drag.XAndYAxis). Defaults to Drag.YAxis
*/
property int dragAxis: Drag.YAxis
/*!
\qmlproperty bool StatusDraggableListItem::hasIcon
This property holds whether this item wants to display an icon (using a StatusIcon); use `icon.name`
Defaults to false
*/
property bool hasIcon: false
/*!
\qmlproperty bool StatusDraggableListItem::hasImage
This property holds whether this item wants to display an image (using a StatusRoundedImage); use `icon.source`
Specifying `icon.name` adds a fallback to a letter identicon (using StatusLetterIdenticon).
Defaults to false
*/
property bool hasImage: false
/*!
\qmlproperty bool StatusDraggableListItem::hasEmoji
This property holds whether this item wants to display an emoji (using a StatusLetterIdenticon); use `icon.name`
Defaults to false
*/
property bool hasEmoji: false
/*!
\qmlproperty int StatusDraggableListItem::bgRadius
This property holds the background corner radius in pixels (if the background is visible)
Defaults to "rounded", half of the icon width or height
*/
property int bgRadius: icon.height/2
/*!
\qmlproperty color StatusDraggableListItem::bgColor
This property holds background color, if any
Defaults to "transparent" (ie no background)
*/
property color bgColor: "transparent"
Drag.dragType: Drag.Automatic
Drag.hotSpot.x: root.width/2
Drag.hotSpot.y: root.height/2
Drag.hotSpot.x: dragHandler.mouseX
Drag.hotSpot.y: dragHandler.mouseY
Drag.keys: ["x-status-draggable-list-item-internal"]
/*!
@ -179,7 +219,7 @@ ItemDelegate {
]
background: Rectangle {
color: "transparent"
color: root.dragActive ? Theme.palette.indirectColor2 : "transparent"
border.width: 1
border.color: Theme.palette.baseColor2
radius: 8
@ -188,10 +228,10 @@ ItemDelegate {
id: dragHandler
anchors.fill: parent
drag.target: root
drag.axis: Drag.YAxis
drag.axis: root.dragAxis
preventStealing: true // otherwise DND is broken inside a Flickable/ScrollView
hoverEnabled: true
cursorShape: root.dragActive ? Qt.ClosedHandCursor : Qt.PointingHandCursor
cursorShape: root.dragActive ? Qt.ClosedHandCursor : Qt.OpenHandCursor
}
}
@ -210,26 +250,42 @@ ItemDelegate {
spacing: root.spacing
StatusIcon {
Layout.preferredWidth: 20
Layout.preferredHeight: 20
icon: "justify"
visible: root.draggable
}
StatusIcon {
Layout.preferredWidth: root.icon.width
Layout.preferredHeight: root.icon.height
Loader {
Layout.leftMargin: root.spacing/2
icon: root.icon.name
color: root.icon.color
asynchronous: true
active: !!root.icon.name || !!root.icon.source
visible: active
sourceComponent: root.hasIcon ? iconComponent : root.hasImage ? imageComponent : letterIdenticonComponent
}
StatusBaseText {
ColumnLayout {
Layout.fillWidth: true
text: root.title
elide: Text.ElideRight
maximumLineCount: 1
}
Layout.leftMargin: root.secondaryTitle ? 4 : 0
// TODO secondaryTitle
StatusBaseText {
Layout.fillWidth: true
text: root.title
visible: text
elide: Text.ElideRight
maximumLineCount: 1
font.weight: root.highlighted ? Font.Medium : Font.Normal
}
StatusBaseText {
Layout.fillWidth: true
text: root.secondaryTitle
visible: text
color: Theme.palette.baseColor1
elide: Text.ElideRight
maximumLineCount: 1
}
}
RowLayout {
id: actionsRow
@ -237,4 +293,43 @@ ItemDelegate {
spacing: 12
}
}
Component {
id: iconComponent
StatusIcon {
width: root.icon.width
height: root.icon.height
icon: root.icon.name
color: root.icon.color
source: root.icon.source
}
}
Component {
id: imageComponent
StatusRoundedImage {
radius: root.bgRadius
color: root.bgColor
width: root.icon.width
height: root.icon.height
image.source: root.icon.source
image.sourceSize: Qt.size(width, height)
image.smooth: false
image.mipmap: true
showLoadingIndicator: true
image.fillMode: Image.PreserveAspectCrop
}
}
Component {
id: letterIdenticonComponent
StatusLetterIdenticon {
letterSize: 14
width: root.icon.width
height: root.icon.height
emoji: root.hasEmoji ? root.icon.name : ""
name: !root.hasEmoji ? root.icon.name : ""
color: root.icon.color
}
}
}

View File

@ -38,7 +38,7 @@ Rectangle {
font.weight: Font.Bold
font.pixelSize: root.letterSize
color: d.luminance(root.color) > 0.5 ? Qt.rgba(0, 0, 0, 0.5) : Qt.rgba(255, 255, 255, 0.7)
color: d.luminance(root.color) > 0.5 ? Qt.rgba(0, 0, 0, 0.5) : Qt.rgba(1, 1, 1, 0.7)
text: {
const shift = (root.name.charAt(0) === "#") ||

View File

@ -1,7 +1,4 @@
import QtQuick 2.13
import QtGraphicalEffects 1.0
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
/*!
\qmltype StatusRoundedImage

View File

@ -345,12 +345,12 @@ Item {
implicitHeight: edit.implicitHeight
boundsBehavior: Flickable.StopAtBounds
QC.ScrollBar.vertical: QC.ScrollBar {
QC.ScrollBar.vertical: StatusScrollBar {
interactive: multiline
enabled: multiline
}
clip: true
interactive: multiline
interactive: multiline && edit.activeFocus
TextEdit {
id: edit

View File

@ -124,7 +124,7 @@ Item {
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
y: comboBox.height + 8
width: comboBox.width
implicitWidth: comboBox.width
height: Math.min(implicitContentHeight + topPadding + bottomPadding,
comboBox.Window.height - topMargin - bottomMargin)
margins: 8

View File

@ -1,6 +1,6 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import QtGraphicalEffects 1.13
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Components 0.1
@ -24,8 +24,7 @@ TabButton {
anchors.fill: parent
StatusSmartIdenticon {
id: identicon
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
anchors.centerIn: parent
asset.isImage: (statusIconTabButton.icon.source.toString() !== "")
asset.name: asset.isImage ?
statusIconTabButton.icon.source : statusIconTabButton.icon.name
@ -47,7 +46,7 @@ TabButton {
MouseArea {
cursorShape: Qt.PointingHandCursor
anchors.fill: parent
onPressed: mouse.accepted = false
acceptedButtons: Qt.NoButton
}
}

View File

@ -82,6 +82,8 @@ QtObject {
console.trace()
return "N/A"
}
if (typeof currencyAmount.amount === "undefined")
return "N/A"
// Parse options
var optShowOnlyAmount = false

View File

@ -250,7 +250,7 @@ QtObject {
property QtObject statusSelect: QtObject {
property color menuItemBackgroundColor
property color menuItemHoeverBackgroundColor
property color menuItemHoverBackgroundColor
}
property QtObject statusMessage: QtObject {

View File

@ -41,45 +41,11 @@ QtObject {
sourceModel: chatCommunitySectionModule.tokenList
proxyRoles: ExpressionRole {
// list of symbols for which pngs are stored to avoid
// accessing not existing resources and providing
// default icon
readonly property var pngs: [
"aKNC", "AST", "BLT", "CND", "DNT", "EQUAD", "HEZ", "LOOM", "MTH",
"PAY", "RCN", "SALT", "STRK", "TRST", "WBTC", "AKRO", "aSUSD", "BLZ",
"COB", "DPY", "ETH2x-FLI", "HST", "LPT", "MTL", "PBTC", "RDN", "SAN",
"STT", "TRX", "WETH", "0-native", "aLEND", "ATMChain", "BNB", "COMP",
"DRT", "ETHOS", "HT", "LRC", "MYB", "PLR", "renBCH", "SNGLS", "STX",
"TUSD", "WINGS", "0XBTC", "aLINK", "aTUSD", "BNT", "CUSTOM-TOKEN",
"DTA", "ETH", "ICN", "MANA", "NEXO", "POE", "renBTC", "SNM", "SUB",
"UBT", "WTC", "1ST", "aMANA", "aUSDC", "BQX", "CVC", "EDG", "EVX",
"ICOS", "MCO", "NEXXO", "POLY", "REN", "SNT", "SUPR", "UKG", "XAUR",
"aBAT", "AMB", "aUSDT", "BRLN", "DAI", "EDO", "FUEL", "IOST", "MDA",
"NMR", "POWR", "renZEC", "SNX", "SUSD", "UNI", "XPA", "ABT", "aMKR",
"aWBTC", "BTM", "DATA", "EKG", "FUN", "KDO", "MET", "NPXS", "PPP",
"REP", "SOCKS", "TAAS", "UPP", "XRL", "aBUSD", "AMPL", "aYFI", "BTU",
"DAT", "EKO", "FXC", "KIN", "MFG", "OGN", "PPT", "REQ", "SPANK",
"TAUD", "USDC", "XUC", "ABYSS", "ANT", "aZRX", "CDAI", "DCN", "ELF",
"GDC", "KNC", "MGO", "OMG", "PT", "RHOC", "SPIKE", "TCAD", "USDS",
"ZRX", "aDAI", "APPC", "BAL", "CDT", "DEFAULT-TOKEN", "EMONA", "GEN",
"Kudos", "MKR", "OST", "QKC", "RLC", "SPN", "TGBP", "USDT", "ZSC",
"aENJ", "aREN", "BAM", "Centra", "DGD", "ENG", "GNO", "LEND", "MLN",
"OTN", "QRL", "ROL", "STORJ", "TKN", "VERI", "AE", "aREP", "BAND",
"CFI", "DGX", "ENJ", "GNT", "LINK", "MOC", "PAXG", "QSP", "R",
"STORM", "TKX", "VIB", "aETH", "aSNX", "BAT", "CK", "DLT", "EOS",
"GRID", "LISK", "MOD", "PAX", "RAE", "SAI", "ST", "TNT", "WABI"
]
function icon(symbol) {
if (pngs.indexOf(symbol) !== -1)
return Style.png("tokens/" + symbol)
return Style.png("tokens/DEFAULT-TOKEN")
function tokenIcon(symbol) {
return Constants.tokenIcon(symbol)
}
name: "iconSource"
expression: !!model.icon ? model.icon : icon(model.symbol)
expression: !!model.icon ? model.icon : tokenIcon(model.symbol)
}
}

View File

@ -50,9 +50,7 @@ StatusSectionLayout {
QtObject {
id: d
readonly property int bottomMargin: 56
readonly property int leftMargin: 64
readonly property int rightMargin: 64
readonly property int contentWidth: 560
}
@ -74,9 +72,7 @@ StatusSectionLayout {
readonly property var currentItem: (currentIndex >= 0 && currentIndex < children.length) ? children[currentIndex].item : null
anchors.fill: parent
anchors.bottomMargin: d.bottomMargin
anchors.leftMargin: d.leftMargin
anchors.rightMargin: d.rightMargin
currentIndex: Global.settingsSubsection

View File

@ -0,0 +1,12 @@
import QtQuick 2.15
import StatusQ.Core.Theme 0.1
ShowcaseDelegate {
title: !!showcaseObj && !!showcaseObj.name ? showcaseObj.name : ""
secondaryTitle: !!showcaseObj && !!showcaseObj.address ? showcaseObj.address : ""
hasEmoji: !!showcaseObj && !!showcaseObj.emoji
hasIcon: !hasEmoji
icon.name: hasEmoji ? showcaseObj.emoji : "filled-account"
icon.color: !!showcaseObj && showcaseObj.color ? showcaseObj.color : Theme.palette.primaryColor3
}

View File

@ -0,0 +1,12 @@
import QtQuick 2.15
import StatusQ.Core 0.1
import utils 1.0
ShowcaseDelegate {
title: !!showcaseObj && !!showcaseObj.name ? showcaseObj.name : ""
secondaryTitle: !!showcaseObj ? LocaleUtils.currencyAmountToLocaleString(showcaseObj.enabledNetworkBalance) : "0"
hasImage: true
icon.source: !!showcaseObj ? Constants.tokenIcon(showcaseObj.symbol) : ""
}

View File

@ -0,0 +1,13 @@
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
bgColor: !!showcaseObj && !!showcaseObj.backgroundColor ? showcaseObj.backgroundColor : "transparent"
}

View File

@ -1,14 +0,0 @@
import StatusQ.Components 0.1
StatusListItem {
property var community
title: community.name
subTitle: community.amISectionAdmin ? qsTr("Admin") : qsTr("Member")
asset.name: !!community.image ? community.image : community.name
asset.isImage: asset.name.includes("data")
asset.isLetterIdenticon: !community.image
asset.color: community.color
asset.width: 40
asset.height: 40
}

View File

@ -0,0 +1,11 @@
import QtQuick 2.15
ShowcaseDelegate {
title: !!showcaseObj && !!showcaseObj.name ? showcaseObj.name : ""
secondaryTitle: !!showcaseObj && !!showcaseObj.amISectionAdmin ? qsTr("Admin") : qsTr("Member")
hasImage: !!showcaseObj ? showcaseObj.image : false
icon.name: !!showcaseObj ? showcaseObj.name : ""
icon.source: !!showcaseObj ? showcaseObj.image : ""
icon.color: !!showcaseObj ? showcaseObj.color : ""
}

View File

@ -0,0 +1,96 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import StatusQ.Controls 0.1
import StatusQ.Components 0.1
import StatusQ.Popups 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import utils 1.0
StatusDraggableListItem {
id: root
property var showcaseObj
property int showcaseVisibility: Constants.ShowcaseVisibility.NoOne
signal showcaseVisibilityRequested(int value)
component ShowcaseVisibilityAction: StatusMenuItem {
property int showcaseVisibility: Constants.ShowcaseVisibility.NoOne
icon.name: ProfileUtils.visibilityIcon(showcaseVisibility)
icon.color: Theme.palette.primaryColor1
}
icon.width: 40
icon.height: 40
draggable: true
dragAxis: Drag.XAndYAxis
actions: [
StatusRoundButton {
icon.name: ProfileUtils.visibilityIcon(root.showcaseVisibility)
Layout.preferredWidth: 58
Layout.preferredHeight: 28
border.width: 1
border.color: Theme.palette.directColor7
radius: 14
highlighted: menuLoader.item && menuLoader.item.opened
onClicked: {
menuLoader.active = true
menuLoader.item.popup(width - menuLoader.item.width, height)
}
ButtonGroup {
id: showcaseVisibilityGroup
exclusive: true
onClicked: function(button) {
const newVisibility = (button as ShowcaseVisibilityAction).showcaseVisibility
if (newVisibility !== root.showcaseVisibility)
root.showcaseVisibilityRequested(newVisibility)
}
}
Loader {
id: menuLoader
active: false
sourceComponent: StatusMenu {
onClosed: menuLoader.active = false
StatusMenuHeadline { text: qsTr("Show to") }
ShowcaseVisibilityAction {
ButtonGroup.group: showcaseVisibilityGroup
showcaseVisibility: Constants.ShowcaseVisibility.Everyone
text: qsTr("Everyone")
checked: root.showcaseVisibility === showcaseVisibility
}
ShowcaseVisibilityAction {
ButtonGroup.group: showcaseVisibilityGroup
showcaseVisibility: Constants.ShowcaseVisibility.Contacts
text: qsTr("Contacts")
checked: root.showcaseVisibility === showcaseVisibility
}
ShowcaseVisibilityAction {
ButtonGroup.group: showcaseVisibilityGroup
showcaseVisibility: Constants.ShowcaseVisibility.IdVerifiedContacts
text: qsTr("ID verified contacts")
checked: root.showcaseVisibility === showcaseVisibility
}
StatusMenuSeparator {}
ShowcaseVisibilityAction {
ButtonGroup.group: showcaseVisibilityGroup
showcaseVisibility: Constants.ShowcaseVisibility.NoOne
text: qsTr("No one")
checked: root.showcaseVisibility === showcaseVisibility
}
}
}
}
]
}

View File

@ -1,3 +1,6 @@
CommunityDelegate 1.0 CommunityDelegate.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
StaticSocialLinkInput 1.0 StaticSocialLinkInput.qml

View File

@ -0,0 +1,49 @@
import QtQuick 2.15
import utils 1.0
import AppLayouts.Profile.controls 1.0
ProfileShowcasePanel {
id: root
property string currentWallet
settingsKey: "accounts"
keyRole: "address"
roleNames: ["name", "address", "walletType", "emoji", "color"]
filterFunc: (modelData) => modelData.walletType !== Constants.keyWalletType && !showcaseModel.hasItem(modelData.address)
hiddenPlaceholderBanner: qsTr("Accounts here will show on your profile")
showcasePlaceholderBanner: qsTr("Accounts here will be hidden from your profile")
draggableDelegateComponent: 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.append(tmpObj)
showcaseVisibility = Constants.ShowcaseVisibility.NoOne // reset
}
}
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: {
if (value === Constants.ShowcaseVisibility.NoOne) {
showcaseModel.remove(visualIndex)
} else {
showcaseModel.setProperty(visualIndex, "showcaseVisibility", value)
}
}
}
}

View File

@ -0,0 +1,45 @@
import QtQuick 2.15
import utils 1.0
import AppLayouts.Profile.controls 1.0
ProfileShowcasePanel {
id: root
settingsKey: "assets"
keyRole: "symbol"
roleNames: ["symbol", "name", "visibleForNetworkWithPositiveBalance", "enabledNetworkBalance"]
filterFunc: (modelData) => modelData.visibleForNetworkWithPositiveBalance && !showcaseModel.hasItem(modelData.symbol)
hiddenPlaceholderBanner: qsTr("Assets here will show on your profile")
showcasePlaceholderBanner: qsTr("Assets here will be hidden from your profile")
draggableDelegateComponent: AssetShowcaseDelegate {
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.append(tmpObj)
showcaseVisibility = Constants.ShowcaseVisibility.NoOne // reset
}
}
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: {
if (value === Constants.ShowcaseVisibility.NoOne) {
showcaseModel.remove(visualIndex)
} else {
showcaseModel.setProperty(visualIndex, "showcaseVisibility", value)
}
}
}
}

View File

@ -0,0 +1,45 @@
import QtQuick 2.15
import utils 1.0
import AppLayouts.Profile.controls 1.0
ProfileShowcasePanel {
id: root
settingsKey: "collectibles"
keyRole: "id"
roleNames: ["id", "name", "description", "collectionName", "backgroundColor", "imageUrl"]
filterFunc: (modelData) => !showcaseModel.hasItem(modelData.id)
hiddenPlaceholderBanner: qsTr("Collectibles here will show on your profile")
showcasePlaceholderBanner: qsTr("Collectibles here will be hidden from your profile")
draggableDelegateComponent: 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.append(tmpObj)
showcaseVisibility = Constants.ShowcaseVisibility.NoOne // reset
}
}
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: {
if (value === Constants.ShowcaseVisibility.NoOne) {
showcaseModel.remove(visualIndex)
} else {
showcaseModel.setProperty(visualIndex, "showcaseVisibility", value)
}
}
}
}

View File

@ -0,0 +1,45 @@
import QtQuick 2.15
import utils 1.0
import AppLayouts.Profile.controls 1.0
ProfileShowcasePanel {
id: root
settingsKey: "communities"
keyRole: "id"
roleNames: ["id", "name", "amISectionAdmin", "image", "color"]
filterFunc: (modelData) => modelData.joined && !showcaseModel.hasItem(modelData.id)
hiddenPlaceholderBanner: qsTr("Communities here will show on your profile")
showcasePlaceholderBanner: qsTr("Communities here will be hidden from your profile")
draggableDelegateComponent: 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
showcaseModel.append(tmpObj)
showcaseVisibility = Constants.ShowcaseVisibility.NoOne // reset
}
}
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: {
if (value === Constants.ShowcaseVisibility.NoOne) {
showcaseModel.remove(visualIndex)
} else {
showcaseModel.setProperty(visualIndex, "showcaseVisibility", value)
}
}
}
}

View File

@ -0,0 +1,352 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import Qt.labs.settings 1.0
import StatusQ.Core 0.1
import StatusQ.Controls 0.1
import StatusQ.Components 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Popups 0.1
import utils 1.0
import AppLayouts.Profile.controls 1.0
Control {
id: root
property var baseModel
readonly property alias settings: settings
readonly property alias showcaseModel: showcaseModel
// to override
property string settingsKey
property string keyRole
property var roleNames: []
property var filterFunc: (modelData) => true
property string hiddenPlaceholderBanner
property string showcasePlaceholderBanner
property Component draggableDelegateComponent
property Component showcaseDraggableDelegateComponent
background: null
component VisibilityDropArea: AbstractButton {
id: visibilityDropAreaLocal
property int showcaseVisibility: Constants.ShowcaseVisibility.NoOne
readonly property alias containsDrag: dropArea.containsDrag
padding: Style.current.halfPadding
spacing: padding/2
icon.color: Theme.palette.primaryColor1
background: ShapeRectangle {
path.strokeColor: dropArea.containsDrag ? "transparent" : Theme.palette.directColor7
path.fillColor: dropArea.containsDrag ? Theme.palette.white : "transparent"
DropArea {
id: dropArea
anchors.fill: parent
keys: ["x-status-draggable-showcase-item-hidden"]
onEntered: function(drag) {
drag.accept()
}
onDropped: function(drop) {
var showcaseObj = drop.source.showcaseObj
var tmpObj = Object()
root.roleNames.forEach(role => tmpObj[role] = showcaseObj[role])
tmpObj.showcaseVisibility = visibilityDropAreaLocal.showcaseVisibility
showcaseModel.append(tmpObj)
}
}
}
contentItem: Item {
RowLayout {
width: Math.min(parent.width, implicitWidth)
anchors.centerIn: parent
spacing: visibilityDropAreaLocal.spacing
StatusIcon {
width: 20
height: 20
icon: ProfileUtils.visibilityIcon(visibilityDropAreaLocal.showcaseVisibility)
color: visibilityDropAreaLocal.icon.color
}
StatusBaseText {
Layout.fillWidth: true
font.pixelSize: 13
font.weight: Font.Medium
elide: Text.ElideRight
color: visibilityDropAreaLocal.icon.color
text: visibilityDropAreaLocal.text
}
}
}
}
Component.onCompleted: showcaseModel.load()
Component.onDestruction: showcaseModel.save()
// NB temporary model until the backend knows the extra roles: "showcaseVisibility" and "order"
ListModel {
id: showcaseModel
function hasItem(itemId) {
for (let i = 0; i < count; i++) {
let item = get(i)
if (!!item && item[root.keyRole] === itemId)
return true
}
return false
}
function save() {
var result = []
for (let i = 0; i < count; i++) {
let item = get(i)
result.push(item)
}
settings.setValue(root.settingsKey, JSON.stringify(result))
}
function load() {
const data = settings.value(root.settingsKey)
try {
const arr = JSON.parse(data)
for (const i in arr)
showcaseModel.append(arr[i])
} catch (e) {
console.warn(e)
}
}
}
Settings {
id: settings
category: "Showcase"
function reset() {
showcaseModel.clear()
settings.setValue(root.settingsKey, "")
settings.sync()
}
}
QtObject {
id: d
readonly property int defaultDelegateHeight: 60
readonly property int contentSpacing: 12
readonly property int strokeMargin: 2
}
contentItem: ColumnLayout {
spacing: d.contentSpacing
StatusBaseText {
Layout.fillWidth: true
text: qsTr("In showcase")
color: Theme.palette.baseColor1
font.pixelSize: 13
font.weight: Font.Medium
}
StatusListView {
id: showcaseItemsListView
Layout.fillWidth: true
Layout.minimumHeight: Math.floor(targetDropArea.height + targetDropArea.anchors.bottomMargin)
model: showcaseModel
implicitHeight: contentHeight
interactive: false
displaced: Transition {
NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad }
}
delegate: DropArea {
id: showcaseDelegateRoot
property int visualIndex: index
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: ["x-status-draggable-showcase-item"]
onEntered: function(drag) {
const from = drag.source.visualIndex
const to = showcaseDraggableDelegateLoader.item.visualIndex
if (to === from)
return
showcaseModel.move(from, to, 1)
drag.accept()
}
Loader {
id: showcaseDraggableDelegateLoader
width: parent.width
sourceComponent: root.showcaseDraggableDelegateComponent
property var modelData: model
property var dragParentData: root
property int visualIndexData: index
}
}
// overlaid at the bottom of the listview
DropArea {
id: targetDropArea
width: parent.width
height: d.defaultDelegateHeight
anchors.bottom: parent.bottom
anchors.bottomMargin: showcaseModel.count ? Style.current.halfPadding : 0
keys: ["x-status-draggable-showcase-item-hidden"]
ShapeRectangle {
anchors.fill: parent
anchors.margins: d.strokeMargin
visible: !showcaseModel.count && !showcaseCombinedDropArea.visible
text: root.hiddenPlaceholderBanner
}
Rectangle {
id: showcaseCombinedDropArea
width: parent.width
height: parent.height + d.strokeMargin
anchors.centerIn: parent
color: Theme.palette.baseColor5
radius: Style.current.radius
visible: parent.containsDrag || dropAreaEveryone.containsDrag || dropAreaContacts.containsDrag || dropAreaVerified.containsDrag
RowLayout {
width: parent.width - spacing*2
anchors.centerIn: parent
spacing: d.contentSpacing
VisibilityDropArea {
id: dropAreaEveryone
Layout.fillWidth: true
showcaseVisibility: Constants.ShowcaseVisibility.Everyone
text: qsTr("Everyone")
}
VisibilityDropArea {
id: dropAreaContacts
Layout.fillWidth: true
showcaseVisibility: Constants.ShowcaseVisibility.Contacts
text: qsTr("Contacts")
}
VisibilityDropArea {
id: dropAreaVerified
Layout.fillWidth: true
showcaseVisibility: Constants.ShowcaseVisibility.IdVerifiedContacts
text: qsTr("Verified")
}
}
}
}
}
StatusBaseText {
Layout.fillWidth: true
Layout.topMargin: Style.current.halfPadding
text: qsTr("Hidden")
color: Theme.palette.baseColor1
font.pixelSize: 13
font.weight: Font.Medium
}
StatusListView {
id: hiddenItemsListView
Layout.fillWidth: true
Layout.minimumHeight: empty ? Math.floor(hiddenTargetDropArea.height + hiddenTargetDropArea.anchors.topMargin)
: d.defaultDelegateHeight * Math.min(count, 4)
model: root.baseModel
readonly property bool empty: !contentHeight
displaced: Transition {
NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad }
}
delegate: DropArea {
id: delegateRoot
property int visualIndex: index
visible: root.filterFunc(model)
width: ListView.view.width
height: visible && draggableDelegateLoader.item ? draggableDelegateLoader.item.height : 0
keys: ["x-status-draggable-showcase-item"]
onEntered: function(drag) {
drag.accept()
}
onDropped: function(drop) {
showcaseModel.remove(drop.source.visualIndex)
}
Rectangle {
width: parent.width
height: d.defaultDelegateHeight
anchors.centerIn: parent
color: Theme.palette.baseColor5
radius: Style.current.radius
visible: draggableDelegateLoader.item && draggableDelegateLoader.item.dragActive
}
Loader {
id: draggableDelegateLoader
width: parent.width
sourceComponent: root.draggableDelegateComponent
property var modelData: model
property var dragParentData: root
property int visualIndexData: delegateRoot.visualIndex
}
}
// overlaid at the top of the listview
DropArea {
id: hiddenTargetDropArea
width: parent.width
height: d.defaultDelegateHeight
anchors.top: parent.top
anchors.topMargin: !hiddenItemsListView.empty ? Style.current.halfPadding : 0
keys: ["x-status-draggable-showcase-item"]
ShapeRectangle {
readonly property bool stroked: hiddenItemsListView.empty && !parent.containsDrag
anchors.fill: parent
anchors.margins: d.strokeMargin
visible: hiddenItemsListView.empty || parent.containsDrag
path.fillColor: stroked ? "transparent" : Theme.palette.baseColor5
path.strokeColor: stroked ? Theme.palette.baseColor2 : "transparent"
text: root.showcasePlaceholderBanner
}
onEntered: function(drag) {
drag.accept()
}
onDropped: function(drop) {
showcaseModel.remove(drop.source.visualIndex)
}
}
}
}
}

View File

@ -1,7 +1,6 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQuick.Shapes 1.15
import StatusQ.Core 0.1
import StatusQ.Controls 0.1
@ -22,8 +21,6 @@ Control {
background: null
implicitHeight: layout.implicitHeight + linksView.contentHeight
Component {
id: addSocialLinkModalComponent
AddSocialLinkModal {
@ -80,8 +77,9 @@ Control {
StatusListView {
id: linksView
Layout.fillWidth: true
Layout.fillHeight: true
Layout.preferredHeight: contentHeight
model: root.socialLinksModel
interactive: false
displaced: Transition {
NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad }
@ -128,11 +126,13 @@ Control {
visualIndex: delegateRoot.visualIndex
draggable: linksView.count > 1
title: ProfileUtils.linkTypeToText(model.linkType) || model.text
hasIcon: true
icon.name: model.icon
icon.color: ProfileUtils.linkTypeColor(model.linkType)
actions: [
StatusLinkText {
Layout.fillWidth: true
Layout.maximumWidth: Math.ceil(implicitWidth)
Layout.alignment: Qt.AlignRight
horizontalAlignment: Text.AlignRight
font.pixelSize: Theme.primaryTextFontSize

View File

@ -31,7 +31,7 @@ Shape {
property string text
readonly property int radius: Style.current.radius
property int radius: Style.current.radius
readonly property alias path: path
asynchronous: true
@ -44,6 +44,8 @@ Shape {
anchors.centerIn: parent
color: Theme.palette.baseColor1
text: root.text
font.pixelSize: 13
visible: text
}
ShapePath {

View File

@ -1 +1,5 @@
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

View File

@ -21,6 +21,8 @@ QtObject {
property var importedAccounts: Global.appIsReady? walletSectionAccounts.imported : null
property var generatedAccounts: Global.appIsReady? walletSectionAccounts.generated : null
property var watchOnlyAccounts: Global.appIsReady? walletSectionAccounts.watchOnly : null
property var flatCollectibles: Global.appIsReady ? walletSectionCollectibles.model : null
property var currentAccount: Global.appIsReady? walletSectionCurrent : null

View File

@ -28,11 +28,9 @@ Item {
StatusScrollView {
contentWidth: availableWidth
contentHeight: profileMenu.height + 24
contentHeight: profileMenu.height + Style.current.bigPadding
anchors.right: parent.right
anchors.rightMargin: Style.current.smallPadding
anchors.left: parent.left
anchors.leftMargin: 0
anchors.top: title.bottom
anchors.topMargin: Style.current.halfPadding
anchors.bottom: parent.bottom

View File

@ -90,9 +90,9 @@ Item {
anchors.bottom: parent.bottom
anchors.topMargin: Style.current.padding
padding: 0
width: root.contentWidth
contentWidth: availableWidth
contentHeight: contentLayout.implicitHeight
width: root.width
contentWidth: root.contentWidth
contentHeight: contentLayout.implicitHeight + Style.current.bigPadding
Column {
id: contentLayout

View File

@ -76,7 +76,7 @@ ColumnLayout {
}
Connections {
target: Qt.platform.os === Constants.mac? root.privacyStore.privacyModule : null
target: Qt.platform.os === Constants.mac ? root.privacyStore.privacyModule : null
function onStoreToKeychainError(errorDescription: string) {
root.reset()
@ -126,8 +126,6 @@ ColumnLayout {
}
ProfileSocialLinksPanel {
id: socialLinksPanel
Layout.fillWidth: true
profileStore: root.profileStore
socialLinksModel: root.profileStore.temporarySocialLinksModel
@ -137,6 +135,12 @@ ColumnLayout {
Layout.fillWidth: true
}
StatusBaseText {
visible: Qt.platform.os === Constants.mac
text: qsTr("Security")
color: Theme.palette.baseColor1
}
StatusListItem {
Layout.fillWidth: true
visible: Qt.platform.os === Constants.mac
@ -156,85 +160,64 @@ ColumnLayout {
visible: Qt.platform.os === Constants.mac
}
StatusBaseText {
text: qsTr("Showcase (demo only)")
color: Theme.palette.baseColor1
}
StatusTabBar {
id: showcaseTabBar
Layout.fillWidth: true
function validateCurrentIndex() {
let processedButtons = 0;
while (!itemAt(currentIndex).enabled) {
if (++processedButtons === count) {
currentIndex = -1;
break;
}
currentIndex = (currentIndex + 1) % count;
}
}
StatusTabButton {
width: enabled ? implicitWidth : 0
width: implicitWidth
leftPadding: 0
text: qsTr("Communities")
onEnabledChanged: showcaseTabBar.validateCurrentIndex()
}
StatusTabButton {
enabled: root.profileStore.isWalletEnabled
width: enabled ? implicitWidth : 0
width: implicitWidth
text: qsTr("Accounts")
onEnabledChanged: showcaseTabBar.validateCurrentIndex()
}
StatusTabButton {
width: implicitWidth
text: qsTr("Collectibles")
}
StatusTabButton {
width: implicitWidth
text: qsTr("Assets")
}
}
StackLayout {
id: showcaseStack
Layout.fillWidth: true
currentIndex: showcaseTabBar.currentIndex
Column {
Layout.fillWidth: true
StatusBaseText {
visible: communitiesRepeater.count == 0
width: parent.width
horizontalAlignment: Text.AlignHCenter
color: Theme.palette.directColor1
text: qsTr("You haven't joined any communities yet")
}
Repeater {
id: communitiesRepeater
model: root.communitiesModel
CommunityDelegate {
width: parent.width
visible: joined
community: model
sensor.enabled: false
}
}
ProfileShowcaseCommunitiesPanel {
Layout.minimumHeight: implicitHeight
Layout.maximumHeight: implicitHeight
baseModel: root.communitiesModel
}
Column {
StatusBaseText {
visible: accountsRepeater.count == 0
width: parent.width
horizontalAlignment: Text.AlignHCenter
color: Theme.palette.directColor1
text: qsTr("You don't have any wallet accounts yet")
}
ProfileShowcaseAccountsPanel {
Layout.minimumHeight: implicitHeight
Layout.maximumHeight: implicitHeight
baseModel: root.walletStore.accounts
currentWallet: root.walletStore.currentAccount.address
}
Repeater {
id: accountsRepeater
model: root.walletStore.accounts
ProfileShowcaseCollectiblesPanel {
Layout.minimumHeight: implicitHeight
Layout.maximumHeight: implicitHeight
baseModel: root.walletStore.flatCollectibles
}
WalletAccountDelegate {
width: parent.width
account: model
showShevronIcon: false
sensor.enabled: false
}
}
ProfileShowcaseAssetsPanel {
Layout.minimumHeight: implicitHeight
Layout.maximumHeight: implicitHeight
baseModel: root.walletStore.currentAccount.assets
}
}
}

View File

@ -12,7 +12,6 @@ Rectangle {
property string text
property string url
property int linkType: 1
property string icon
implicitWidth: layout.implicitWidth + 16

View File

@ -155,6 +155,7 @@ Item {
Item {
Layout.fillWidth: true
implicitHeight: displayNameLabel.implicitHeight
visible: root.displayNameVisible
StyledText {
id: displayNameLabel

View File

@ -113,7 +113,6 @@ Control {
height: 32
text: model.text
url: model.url
linkType: model.linkType
icon: model.icon
}
}

View File

@ -375,12 +375,7 @@ Control {
width: 40
height: 40
anchors.verticalCenter: parent.verticalCenter
source: Style.png("tokens/" + model.symbol)
onStatusChanged: {
if (status === Image.Error) {
source = Style.png("tokens/DEFAULT-TOKEN")
}
}
source: Constants.tokenIcon(model.symbol)
}
]
onClicked: {

View File

@ -874,10 +874,53 @@ QtObject {
Other
}
enum ShowcaseVisibility {
NoOne = 0,
IdVerifiedContacts = 1,
Contacts = 2,
Everyone = 4
}
readonly property QtObject walletSection: QtObject {
readonly property string cancelledMessage: "cancelled"
}
// list of symbols for which pngs are stored to avoid
// accessing not existing resources and providing
// default icon
readonly property var knownTokenPNGs: [
"aKNC", "AST", "BLT", "CND", "DNT", "EQUAD", "HEZ", "LOOM", "MTH",
"PAY", "RCN", "SALT", "STRK", "TRST", "WBTC", "AKRO", "aSUSD", "BLZ",
"COB", "DPY", "ETH2x-FLI", "HST", "LPT", "MTL", "PBTC", "RDN", "SAN",
"STT", "TRX", "WETH", "0-native", "aLEND", "ATMChain", "BNB", "COMP",
"DRT", "ETHOS", "HT", "LRC", "MYB", "PLR", "renBCH", "SNGLS", "STX",
"TUSD", "WINGS", "0XBTC", "aLINK", "aTUSD", "BNT", "CUSTOM-TOKEN",
"DTA", "ETH", "ICN", "MANA", "NEXO", "POE", "renBTC", "SNM", "SUB",
"UBT", "WTC", "1ST", "aMANA", "aUSDC", "BQX", "CVC", "EDG", "EVX",
"ICOS", "MCO", "NEXXO", "POLY", "REN", "SNT", "SUPR", "UKG", "XAUR",
"aBAT", "AMB", "aUSDT", "BRLN", "DAI", "EDO", "FUEL", "IOST", "MDA",
"NMR", "POWR", "renZEC", "SNX", "SUSD", "UNI", "XPA", "ABT", "aMKR",
"aWBTC", "BTM", "DATA", "EKG", "FUN", "KDO", "MET", "NPXS", "PPP",
"REP", "SOCKS", "TAAS", "UPP", "XRL", "aBUSD", "AMPL", "aYFI", "BTU",
"DAT", "EKO", "FXC", "KIN", "MFG", "OGN", "PPT", "REQ", "SPANK",
"TAUD", "USDC", "XUC", "ABYSS", "ANT", "aZRX", "CDAI", "DCN", "ELF",
"GDC", "KNC", "MGO", "OMG", "PT", "RHOC", "SPIKE", "TCAD", "USDS",
"ZRX", "aDAI", "APPC", "BAL", "CDT", "DEFAULT-TOKEN", "EMONA", "GEN",
"Kudos", "MKR", "OST", "QKC", "RLC", "SPN", "TGBP", "USDT", "ZSC",
"aENJ", "aREN", "BAM", "Centra", "DGD", "ENG", "GNO", "LEND", "MLN",
"OTN", "QRL", "ROL", "STORJ", "TKN", "VERI", "AE", "aREP", "BAND",
"CFI", "DGX", "ENJ", "GNT", "LINK", "MOC", "PAXG", "QSP", "R",
"STORM", "TKX", "VIB", "aETH", "aSNX", "BAT", "CK", "DLT", "EOS",
"GRID", "LISK", "MOD", "PAX", "RAE", "SAI", "ST", "TNT", "WABI"
]
function tokenIcon(symbol) {
if (!!symbol && knownTokenPNGs.indexOf(symbol) !== -1)
return Style.png("tokens/" + symbol)
return Style.png("tokens/DEFAULT-TOKEN")
}
// Message outgoing status
readonly property string sending: "sending"
readonly property string sent: "sent"

View File

@ -60,4 +60,19 @@ QtObject {
if (text === "__telegram") return Constants.socialLinkType.telegram
return Constants.socialLinkType.custom
}
// showcase
function visibilityIcon(showcaseVisibility) {
switch (showcaseVisibility) {
case Constants.ShowcaseVisibility.IdVerifiedContacts:
return "checkmark-circle"
case Constants.ShowcaseVisibility.Contacts:
return "profile"
case Constants.ShowcaseVisibility.Everyone:
return "language"
case Constants.ShowcaseVisibility.NoOne:
default:
return "hide"
}
}
}