2023-11-29 15:48:33 +00:00
import QtQuick 2.15
import QtQuick . Layouts 1.15
import QtQuick . Controls 2.15
2023-12-06 10:54:36 +00:00
import Qt . labs . settings 1.1
2024-01-24 12:36:23 +00:00
import QtQml 2.15
2021-09-28 15:04:06 +00:00
2023-11-29 15:48:33 +00:00
import StatusQ 0.1
2022-07-13 12:29:38 +00:00
import StatusQ . Components 0.1
2023-03-06 16:46:32 +00:00
import StatusQ . Controls 0.1
2024-01-24 12:36:23 +00:00
import StatusQ . Core 0.1
import StatusQ . Core . Theme 0.1
import StatusQ . Core . Utils 0.1
import StatusQ . Models 0.1
2023-11-29 15:48:33 +00:00
import StatusQ . Popups 0.1
import StatusQ . Popups . Dialog 0.1
2023-01-31 10:49:07 +00:00
2023-11-29 15:48:33 +00:00
import shared . controls 1.0
2021-10-27 21:27:49 +00:00
import shared . panels 1.0
2023-11-29 15:48:33 +00:00
import shared . popups 1.0
2023-01-31 10:49:07 +00:00
import utils 1.0
2021-10-21 08:22:05 +00:00
2023-11-29 15:48:33 +00:00
import AppLayouts . Wallet . views . collectibles 1.0
2023-12-06 10:54:36 +00:00
import AppLayouts . Wallet . controls 1.0
2023-11-29 15:48:33 +00:00
import SortFilterProxyModel 0.2
2021-10-21 08:22:05 +00:00
2023-12-06 10:54:36 +00:00
ColumnLayout {
2020-08-18 18:46:11 +00:00
id: root
2023-11-29 15:48:33 +00:00
2024-01-31 18:09:44 +00:00
required property var controller
2024-01-17 20:19:58 +00:00
required property string addressFilters
required property string networkFilters
2023-11-29 15:48:33 +00:00
property bool sendEnabled: true
2023-12-06 10:54:36 +00:00
property bool filterVisible
2024-02-07 22:58:56 +00:00
property bool isFetching: false // Indicates if a collectibles page is being loaded from the backend
property bool isUpdating: false // Indicates if the collectibles list is being updated
property bool isError: false // Indicates an error occurred while updating/fetching the collectibles list
2023-01-20 00:44:35 +00:00
2024-03-05 09:27:40 +00:00
signal collectibleClicked ( int chainId , string contractAddress , string tokenId , string uid , int tokenType )
signal sendRequested ( string symbol , int tokenType )
2023-11-29 15:48:33 +00:00
signal receiveRequested ( string symbol )
signal switchToCommunityRequested ( string communityId )
signal manageTokensRequested ( )
2023-12-06 10:54:36 +00:00
spacing: 0
2023-11-29 15:48:33 +00:00
QtObject {
id: d
readonly property int cellHeight: 225
readonly property int communityCellHeight: 242
readonly property int cellWidth: 176
2024-01-24 12:36:23 +00:00
readonly property int headerHeight: 56
2023-01-20 00:44:35 +00:00
2023-12-06 10:54:36 +00:00
readonly property bool isCustomView: cmbTokenOrder . currentValue === SortOrderComboBox . TokenOrderCustom
2023-11-29 15:48:33 +00:00
2024-02-07 22:58:56 +00:00
readonly property var sourceModel: root . controller . sourceModel
readonly property bool isLoading: root . isUpdating || root . isFetching
onIsLoadingChanged: {
d . loadingItemsModel . refresh ( )
}
readonly property var loadingItemsModel: ListModel {
Component.onCompleted: {
refresh ( )
}
function refresh ( ) {
clear ( )
if ( d . isLoading ) {
for ( let i = 0 ; i < 10 ; i ++ ) {
append ( { isLoading: true } )
}
}
}
}
readonly property var communityModel: CustomSFPM {
isCommunity: true
}
readonly property var communityModelWithLoadingItems: ConcatModel {
sources: [
SourceModel {
model: d . communityModel
markerRoleValue: "communityModel"
} ,
SourceModel {
model: d . loadingItemsModel
markerRoleValue: "loadingItemsModel"
}
]
markerRoleName: "sourceGroup"
}
readonly property var nonCommunityModel: CustomSFPM {
isCommunity: false
}
readonly property var nonCommunityModelWithLoadingItems: ConcatModel {
sources: [
SourceModel {
model: d . nonCommunityModel
markerRoleValue: "nonCommunityModel"
} ,
SourceModel {
model: d . loadingItemsModel
markerRoleValue: "loadingItemsModel"
}
]
markerRoleName: "sourceGroup"
}
2024-03-12 15:48:59 +00:00
readonly property bool hasRegularCollectibles: d . nonCommunityModel . count || d . loadingItemsModel . count
2024-02-07 22:58:56 +00:00
readonly property bool hasCommunityCollectibles: d . communityModel . count || d . loadingItemsModel . count
2024-03-12 15:48:59 +00:00
readonly property bool onlyRegularCollectiblesType: hasRegularCollectibles && ! hasCommunityCollectibles
2023-11-29 15:48:33 +00:00
2024-01-17 20:19:58 +00:00
readonly property var nwFilters: root . networkFilters . split ( ":" )
readonly property var addrFilters: root . addressFilters . split ( ":" ) . map ( ( addr ) = > addr . toLowerCase ( ) )
2024-03-05 20:16:37 +00:00
function getLatestTimestmap ( ownership , filterList ) {
let latest = 0
if ( ! ! ownership ) {
for ( let i = 0 ; i < ownership . count ; i ++ ) {
let accountAddress = ModelUtils . get ( ownership , i , "accountAddress" ) . toLowerCase ( )
if ( filterList . includes ( accountAddress ) ) {
let txTimestamp = ModelUtils . get ( ownership , i , "txTimestamp" )
latest = Math . max ( latest , txTimestamp )
}
2024-01-17 20:19:58 +00:00
}
}
2024-03-05 20:16:37 +00:00
return latest
2024-01-17 20:19:58 +00:00
}
2024-02-15 12:59:34 +00:00
2024-03-05 20:16:37 +00:00
function getBalance ( ownership , filterList ) {
// Balance is a Uint256, so we need to use AmountsArithmetic to handle it
let balance = AmountsArithmetic . fromNumber ( 0 )
if ( ! ! ownership ) {
for ( let i = 0 ; i < ownership . count ; i ++ ) {
let accountAddress = ModelUtils . get ( ownership , i , "accountAddress" ) . toLowerCase ( )
if ( filterList . includes ( accountAddress ) ) {
let tokenBalanceStr = ModelUtils . get ( ownership , i , "balance" ) + ""
if ( tokenBalanceStr !== "" ) {
let tokenBalance = AmountsArithmetic . fromString ( tokenBalanceStr )
balance = AmountsArithmetic . sum ( balance , tokenBalance )
}
}
}
// For simplicity, we limit the result to the maximum int manageable by QML
const maxInt = 2147483647
if ( AmountsArithmetic . cmp ( balance , AmountsArithmetic . fromNumber ( maxInt ) ) === 1 ) {
return maxInt
2024-02-15 12:59:34 +00:00
}
}
2024-03-05 20:16:37 +00:00
return AmountsArithmetic . toNumber ( balance )
2024-02-15 12:59:34 +00:00
}
2020-08-19 15:58:25 +00:00
}
2023-12-06 10:54:36 +00:00
component CustomSFPM: SortFilterProxyModel {
id: customFilter
property bool isCommunity
2023-11-29 15:48:33 +00:00
2024-02-07 22:58:56 +00:00
sourceModel: d . sourceModel
2024-02-15 12:59:34 +00:00
proxyRoles: [
JoinRole {
name: "groupName"
roleNames: [ "collectionName" , "communityName" ]
} ,
2024-03-05 20:16:37 +00:00
FastExpressionRole {
name: "balance"
expression: d . addrFilters , d . getBalance ( model . ownership , d . addrFilters )
expectedRoles: [ "ownership" ]
} ,
2024-02-15 12:59:34 +00:00
FastExpressionRole {
name: "lastTxTimestamp"
expression: d . addrFilters , d . getLatestTimestmap ( model . ownership , d . addrFilters )
expectedRoles: [ "ownership" ]
}
]
2023-12-06 10:54:36 +00:00
filters: [
2024-01-17 20:19:58 +00:00
FastExpressionFilter {
expression: {
2024-03-05 20:16:37 +00:00
return d . nwFilters . includes ( model . chainId + "" )
2024-01-17 20:19:58 +00:00
}
2024-03-05 20:16:37 +00:00
expectedRoles: [ "chainId" ]
} ,
ValueFilter {
roleName: "balance"
value: 0
inverted: true
2024-01-17 20:19:58 +00:00
} ,
2024-01-04 12:05:54 +00:00
FastExpressionFilter {
2023-12-06 10:54:36 +00:00
expression: {
2024-01-31 18:09:44 +00:00
root . controller . revision
return root . controller . filterAcceptsSymbol ( model . symbol ) && ( customFilter . isCommunity ? ! ! model.communityId : ! model . communityId )
2023-12-06 10:54:36 +00:00
}
2024-01-04 12:05:54 +00:00
expectedRoles: [ "symbol" , "communityId" ]
2023-12-18 10:12:57 +00:00
} ,
2024-01-04 12:05:54 +00:00
FastExpressionFilter {
2023-12-18 10:12:57 +00:00
enabled: customFilter . isCommunity && cmbFilter . hasEnabledFilters
expression: cmbFilter . selectedFilterGroupIds . includes ( model . communityId ) ||
( ! model . communityId && cmbFilter . selectedFilterGroupIds . includes ( "" ) )
2024-01-04 12:05:54 +00:00
expectedRoles: [ "communityId" ]
2023-12-18 10:12:57 +00:00
} ,
2024-01-04 12:05:54 +00:00
FastExpressionFilter {
2023-12-18 10:12:57 +00:00
enabled: ! customFilter . isCommunity && cmbFilter . hasEnabledFilters
expression: cmbFilter . selectedFilterGroupIds . includes ( model . collectionUid ) ||
( ! model . collectionUid && cmbFilter . selectedFilterGroupIds . includes ( "" ) )
2024-01-04 12:05:54 +00:00
expectedRoles: [ "collectionUid" ]
2023-12-06 10:54:36 +00:00
}
]
sorters: [
2024-01-04 12:05:54 +00:00
FastExpressionSorter {
2023-12-06 10:54:36 +00:00
expression: {
2024-01-31 18:09:44 +00:00
root . controller . revision
return root . controller . compareTokens ( modelLeft . symbol , modelRight . symbol )
2023-12-06 10:54:36 +00:00
}
enabled: d . isCustomView
2024-01-04 12:05:54 +00:00
expectedRoles: [ "symbol" ]
2023-12-06 10:54:36 +00:00
} ,
RoleSorter {
roleName: cmbTokenOrder . currentSortRoleName
sortOrder: cmbTokenOrder . currentSortOrder
enabled: ! d . isCustomView
}
]
}
2023-11-29 15:48:33 +00:00
2023-12-06 10:54:36 +00:00
Settings {
2024-01-24 12:02:03 +00:00
id: settings
2023-12-06 10:54:36 +00:00
category: "CollectiblesViewSortSettings"
2024-01-24 12:02:03 +00:00
property int currentSortValue: SortOrderComboBox . TokenOrderDateAdded
2023-12-06 10:54:36 +00:00
property alias currentSortOrder: cmbTokenOrder . currentSortOrder
2023-12-18 10:12:57 +00:00
property alias selectedFilterGroupIds: cmbFilter . selectedFilterGroupIds
2023-12-06 10:54:36 +00:00
}
2024-01-24 12:02:03 +00:00
Component.onCompleted: {
settings . sync ( )
cmbTokenOrder . currentIndex = cmbTokenOrder . indexOfValue ( settings . currentSortValue )
}
Component.onDestruction: {
settings . currentSortValue = cmbTokenOrder . currentValue
}
2023-12-06 10:54:36 +00:00
ColumnLayout {
Layout.fillWidth: true
2024-01-24 12:36:23 +00:00
Layout.fillHeight: false
2023-12-18 10:12:57 +00:00
Layout.preferredHeight: root . filterVisible ? implicitHeight : 0
2023-12-06 10:54:36 +00:00
spacing: 20
2023-12-18 10:12:57 +00:00
opacity: root . filterVisible ? 1 : 0
2023-12-06 10:54:36 +00:00
Behavior on Layout . preferredHeight { NumberAnimation { duration: 200 ; easing.type: Easing . InOutQuad } }
Behavior on opacity { NumberAnimation { duration: 200 ; easing.type: Easing . InOutQuad } }
2023-11-29 15:48:33 +00:00
StatusDialogDivider {
Layout.fillWidth: true
}
RowLayout {
Layout.fillWidth: true
2023-12-06 10:54:36 +00:00
spacing: Style . current . halfPadding
2023-12-18 10:12:57 +00:00
FilterComboBox {
id: cmbFilter
2024-01-31 18:09:44 +00:00
regularTokensModel: root . controller . regularTokensModel
collectionGroupsModel: root . controller . collectionGroupsModel
communityTokenGroupsModel: root . controller . communityTokenGroupsModel
2023-12-18 10:12:57 +00:00
hasCommunityGroups: d . hasCommunityCollectibles
}
Rectangle {
Layout.preferredHeight: 34
Layout.preferredWidth: 1
Layout.leftMargin: 12
Layout.rightMargin: 12
color: Theme . palette . baseColor2
}
2023-11-29 15:48:33 +00:00
StatusBaseText {
color: Theme . palette . baseColor1
2023-12-06 10:54:36 +00:00
font.pixelSize: Style . current . additionalTextSize
text: qsTr ( "Sort by:" )
2023-11-29 15:48:33 +00:00
}
2023-12-06 10:54:36 +00:00
SortOrderComboBox {
id: cmbTokenOrder
2024-01-31 18:09:44 +00:00
hasCustomOrderDefined: root . controller . hasSettings
2023-12-06 10:54:36 +00:00
model: [
2024-02-15 12:59:34 +00:00
{ value: SortOrderComboBox . TokenOrderDateAdded , text: qsTr ( "Date added" ) , icon: "calendar" , sortRoleName: "lastTxTimestamp" } , // Custom SFPM role
2023-12-06 10:54:36 +00:00
{ value: SortOrderComboBox . TokenOrderAlpha , text: qsTr ( "Collectible name" ) , icon: "bold" , sortRoleName: "name" } ,
{ value: SortOrderComboBox . TokenOrderGroupName , text: qsTr ( "Collection/community name" ) , icon: "group" , sortRoleName: "groupName" } , // Custom SFPM role communityName || collectionName
{ value: SortOrderComboBox . TokenOrderCustom , text: qsTr ( "Custom order" ) , icon: "exchange" , sortRoleName: "" } ,
{ value: SortOrderComboBox . TokenOrderNone , text: "---" , icon: "" , sortRoleName: "" } , // separator
{ value: SortOrderComboBox . TokenOrderCreateCustom , text: hasCustomOrderDefined ? qsTr ( "Edit custom order →" ) : qsTr ( "Create custom order →" ) ,
icon: "" , sortRoleName: "" }
]
onCreateOrEditRequested: {
root . manageTokensRequested ( )
}
2020-08-20 21:59:07 +00:00
}
2023-12-18 10:12:57 +00:00
Item { Layout.fillWidth: true }
StatusLinkText {
visible: cmbFilter . hasEnabledFilters
normalColor: Theme . palette . primaryColor1
text: qsTr ( "Clear filter" )
onClicked: cmbFilter . clearFilter ( )
}
2020-08-20 21:59:07 +00:00
}
2023-11-29 15:48:33 +00:00
2023-12-06 10:54:36 +00:00
StatusDialogDivider {
Layout.fillWidth: true
}
}
ShapeRectangle {
Layout.fillWidth: true
2023-12-18 10:12:57 +00:00
Layout.topMargin: Style . current . padding
2024-03-12 15:48:59 +00:00
visible: ! d . hasRegularCollectibles && ! d . hasCommunityCollectibles
2023-12-06 10:54:36 +00:00
text: qsTr ( "Collectibles will appear here" )
}
2024-01-24 12:36:23 +00:00
DoubleFlickableWithFolding {
id: doubleFlickable
2023-12-06 10:54:36 +00:00
Layout.fillWidth: true
Layout.fillHeight: true
2024-01-24 12:36:23 +00:00
clip: true
flickable1: CustomGridView {
id: communityCollectiblesView
2024-03-12 15:48:59 +00:00
header: d . hasCommunityCollectibles ? communityHeaderComponent : null
2024-01-24 12:36:23 +00:00
width: doubleFlickable . width
cellHeight: d . communityCellHeight
2024-02-07 22:58:56 +00:00
model: d . communityModelWithLoadingItems
2024-01-24 12:36:23 +00:00
2024-03-12 15:48:59 +00:00
Component {
id: communityHeaderComponent
2024-01-24 12:36:23 +00:00
2024-03-12 15:48:59 +00:00
FoldableHeader {
height: d . headerHeight
width: doubleFlickable . width
title: qsTr ( "Community minted" )
titleColor: Theme . palette . baseColor1
folded: doubleFlickable . flickable1Folded
rightAdditionalComponent: StatusFlatButton {
icon.name: "info"
textColor: Theme . palette . baseColor1
2024-01-24 12:36:23 +00:00
2024-03-12 15:48:59 +00:00
onClicked: Global . openPopup ( communityInfoPopupCmp )
}
onToggleFolding: doubleFlickable . flip1Folding ( )
}
2023-12-06 10:54:36 +00:00
}
2024-03-12 15:48:59 +00:00
}
2023-12-06 10:54:36 +00:00
2024-03-12 15:48:59 +00:00
flickable2: CustomGridView {
id: regularCollectiblesView
2024-01-24 12:36:23 +00:00
2024-03-12 15:48:59 +00:00
header: ! d . hasRegularCollectibles || d . onlyRegularCollectiblesType ? null : regularHeaderComponent
2024-01-24 12:36:23 +00:00
width: doubleFlickable . width
cellHeight: d . cellHeight
2024-02-07 22:58:56 +00:00
model: d . nonCommunityModelWithLoadingItems
2024-01-24 12:36:23 +00:00
2024-03-12 15:48:59 +00:00
Component {
id: regularHeaderComponent
2024-01-24 12:36:23 +00:00
2024-03-12 15:48:59 +00:00
FoldableHeader {
height: d . headerHeight
width: doubleFlickable . width
title: qsTr ( "Others" )
titleColor: Theme . palette . baseColor1
folded: doubleFlickable . flickable2Folded
2024-01-24 12:36:23 +00:00
2024-03-12 15:48:59 +00:00
onToggleFolding: doubleFlickable . flip2Folding ( )
}
2024-01-24 12:36:23 +00:00
}
}
2023-11-29 15:48:33 +00:00
}
component CustomGridView: StatusGridView {
id: gridView
interactive: false
cellWidth: d . cellWidth
delegate: collectibleDelegate
2020-08-20 21:59:07 +00:00
}
2020-08-18 18:46:11 +00:00
2021-10-21 08:22:05 +00:00
Component {
2023-11-29 15:48:33 +00:00
id: collectibleDelegate
CollectibleView {
width: d . cellWidth
height: isCommunityCollectible ? d.communityCellHeight : d . cellHeight
title: model . name ? model.name : "..."
2023-12-06 10:54:36 +00:00
subTitle: model . collectionName ? model.collectionName : model . collectionUid ? model.collectionUid : ""
2023-11-29 15:48:33 +00:00
mediaUrl: model . mediaUrl ? ? ""
2024-03-12 15:48:59 +00:00
mediaType: model . mediaType ? ? ""
fallbackImageUrl: model . imageUrl ? ? ""
backgroundColor: model . backgroundColor ? model.backgroundColor : "transparent"
2023-11-29 15:48:33 +00:00
isLoading: ! ! model . isLoading
privilegesLevel: model . communityPrivilegesLevel ? ? Constants . TokenPrivilegesLevel . Community
2024-03-12 15:48:59 +00:00
ornamentColor: model . communityColor ? ? "transparent"
communityId: model . communityId ? ? ""
communityName: model . communityName ? ? ""
communityImage: model . communityImage ? ? ""
balance: model . balance ? ? 1
2023-11-29 15:48:33 +00:00
2024-03-12 15:48:59 +00:00
onClicked: root . collectibleClicked ( model . chainId , model . contractAddress , model . tokenId , model . symbol , model . tokenType )
2023-11-29 15:48:33 +00:00
onRightClicked: {
Global . openMenu ( tokenContextMenu , this ,
{ symbol: model . symbol , tokenName: model . name , tokenImage: model . imageUrl ,
2024-03-05 09:27:40 +00:00
communityId: model . communityId , communityName: model . communityName ,
communityImage: model . communityImage , tokenType: model . tokenType } )
2020-08-19 15:58:25 +00:00
}
2023-11-29 15:48:33 +00:00
onSwitchToCommunityRequested: ( communityId ) = > root . switchToCommunityRequested ( communityId )
}
}
2023-03-06 16:46:32 +00:00
2023-11-29 15:48:33 +00:00
Component {
id: tokenContextMenu
StatusMenu {
onClosed: destroy ( )
2023-08-03 16:05:04 +00:00
2023-11-29 15:48:33 +00:00
property string symbol
property string tokenName
property string tokenImage
property string communityId
property string communityName
property string communityImage
2024-03-05 09:27:40 +00:00
property int tokenType
2023-08-03 16:05:04 +00:00
2023-11-29 15:48:33 +00:00
StatusAction {
enabled: root . sendEnabled
2024-02-02 09:55:56 +00:00
visibleOnDisabled: true
2023-11-29 15:48:33 +00:00
icon.name: "send"
text: qsTr ( "Send" )
2024-03-05 09:27:40 +00:00
onTriggered: root . sendRequested ( symbol , tokenType )
2023-11-29 15:48:33 +00:00
}
StatusAction {
icon.name: "receive"
text: qsTr ( "Receive" )
onTriggered: root . receiveRequested ( symbol )
}
StatusMenuSeparator { }
StatusAction {
icon.name: "settings"
text: qsTr ( "Manage tokens" )
onTriggered: root . manageTokensRequested ( )
2023-08-03 16:05:04 +00:00
}
2023-11-29 15:48:33 +00:00
StatusAction {
2024-03-05 17:15:08 +00:00
enabled: symbol !== Constants . ethToken
2023-11-29 15:48:33 +00:00
type: StatusAction . Type . Danger
icon.name: "hide"
text: qsTr ( "Hide collectible" )
2024-01-31 18:09:44 +00:00
onTriggered: Global . openConfirmHideCollectiblePopup ( symbol , tokenName , tokenImage , ! ! communityId )
2023-11-29 15:48:33 +00:00
}
StatusAction {
enabled: ! ! communityId
type: StatusAction . Type . Danger
icon.name: "hide"
text: qsTr ( "Hide all collectibles from this community" )
onTriggered: Global . openPopup ( confirmHideCommunityCollectiblesPopup , { communityId , communityName , communityImage } )
}
}
}
2023-08-03 16:05:04 +00:00
2023-11-29 15:48:33 +00:00
Component {
id: communityInfoPopupCmp
StatusDialog {
destroyOnClose: true
title: qsTr ( "What are community collectibles?" )
standardButtons: Dialog . Ok
width: 520
contentItem: StatusBaseText {
wrapMode: Text . Wrap
text: qsTr ( "Community collectibles are collectibles that have been minted by a community. As these collectibles cannot be verified, always double check their origin and validity before interacting with them. If in doubt, ask a trusted member or admin of the relevant community." )
}
}
}
Component {
id: confirmHideCommunityCollectiblesPopup
ConfirmationDialog {
property string communityId
property string communityName
property string communityImage
2023-08-03 16:05:04 +00:00
2023-11-29 15:48:33 +00:00
width: 520
destroyOnClose: true
2024-01-29 15:37:17 +00:00
confirmButtonLabel: qsTr ( "Hide '%1' collectibles" ) . arg ( communityName )
2023-11-29 15:48:33 +00:00
cancelBtnType: ""
showCancelButton: true
headerSettings.title: qsTr ( "Hide %1 community collectibles" ) . arg ( communityName )
headerSettings.asset.name: communityImage
confirmationText: qsTr ( "Are you sure you want to hide all community collectibles minted by %1? You will no longer see or be able to interact with these collectibles anywhere inside Status." ) . arg ( communityName )
onCancelButtonClicked: close ( )
onConfirmButtonClicked: {
2024-01-31 18:09:44 +00:00
root . controller . showHideGroup ( communityId , false )
2023-11-29 15:48:33 +00:00
close ( )
Global . displayToastMessage (
2024-03-12 15:48:59 +00:00
qsTr ( "%1 community collectibles were successfully hidden. You can toggle collectible visibility via %2." ) . arg ( communityName )
2023-12-06 10:54:36 +00:00
. arg ( ` < a style = "text-decoration:none" href = "#${Constants.appSection.profile}/${Constants.settingsSubsection.wallet}/${Constants.walletSettingsSubsection.manageCollectibles}" > ` + qsTr ( "Settings" , "Go to Settings" ) + "</a>" ) ,
2024-03-12 15:48:59 +00:00
"" ,
"checkmark-circle" ,
false ,
Constants . ephemeralNotificationType . success ,
""
)
2023-08-03 16:05:04 +00:00
}
2020-08-18 18:46:11 +00:00
}
2020-07-28 18:19:46 +00:00
}
2020-05-28 14:54:42 +00:00
}