feat(Wallet/Toasts): Updated / added toasts related to community tokens received
- Added new role into ephemeral_notification_model: image. - Added new view API to display ephemeral notifications with image and action. - Added support to display asset or collectible image in a toast with different shape (circle or square). - Default values assigned to the new parameters added in `CommunityTokensStore` meanwhile backend is not ready. - Created page for `StatusToastMessage` in `storybook`. Closes #13039
This commit is contained in:
parent
09629985f7
commit
21a33cabd9
|
@ -13,6 +13,7 @@ type
|
||||||
title: string
|
title: string
|
||||||
durationInMs: int
|
durationInMs: int
|
||||||
subTitle: string
|
subTitle: string
|
||||||
|
image: string
|
||||||
icon: string
|
icon: string
|
||||||
iconColor: string
|
iconColor: string
|
||||||
loading: bool
|
loading: bool
|
||||||
|
@ -26,6 +27,7 @@ proc initItem*(id: int64,
|
||||||
title: string,
|
title: string,
|
||||||
durationInMs = 0,
|
durationInMs = 0,
|
||||||
subTitle = "",
|
subTitle = "",
|
||||||
|
image = "",
|
||||||
icon = "",
|
icon = "",
|
||||||
iconColor = "",
|
iconColor = "",
|
||||||
loading = false,
|
loading = false,
|
||||||
|
@ -40,6 +42,7 @@ proc initItem*(id: int64,
|
||||||
result.durationInMs = durationInMs
|
result.durationInMs = durationInMs
|
||||||
result.title = title
|
result.title = title
|
||||||
result.subTitle = subTitle
|
result.subTitle = subTitle
|
||||||
|
result.image = image
|
||||||
result.icon = icon
|
result.icon = icon
|
||||||
result.iconColor = iconColor
|
result.iconColor = iconColor
|
||||||
result.loading = loading
|
result.loading = loading
|
||||||
|
@ -64,6 +67,9 @@ proc durationInMs*(self: Item): int =
|
||||||
proc subTitle*(self: Item): string =
|
proc subTitle*(self: Item): string =
|
||||||
self.subTitle
|
self.subTitle
|
||||||
|
|
||||||
|
proc image*(self: Item): string =
|
||||||
|
self.image
|
||||||
|
|
||||||
proc icon*(self: Item): string =
|
proc icon*(self: Item): string =
|
||||||
self.icon
|
self.icon
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ type
|
||||||
DurationInMs
|
DurationInMs
|
||||||
Title
|
Title
|
||||||
SubTitle
|
SubTitle
|
||||||
|
Image
|
||||||
Icon
|
Icon
|
||||||
IconColor
|
IconColor
|
||||||
Loading
|
Loading
|
||||||
|
@ -41,6 +42,7 @@ QtObject:
|
||||||
ModelRole.DurationInMs.int:"durationInMs",
|
ModelRole.DurationInMs.int:"durationInMs",
|
||||||
ModelRole.Title.int:"title",
|
ModelRole.Title.int:"title",
|
||||||
ModelRole.SubTitle.int:"subTitle",
|
ModelRole.SubTitle.int:"subTitle",
|
||||||
|
ModelRole.Image.int:"image",
|
||||||
ModelRole.Icon.int:"icon",
|
ModelRole.Icon.int:"icon",
|
||||||
ModelRole.IconColor.int:"iconColor",
|
ModelRole.IconColor.int:"iconColor",
|
||||||
ModelRole.Loading.int:"loading",
|
ModelRole.Loading.int:"loading",
|
||||||
|
@ -69,6 +71,8 @@ QtObject:
|
||||||
result = newQVariant(item.title)
|
result = newQVariant(item.title)
|
||||||
of ModelRole.SubTitle:
|
of ModelRole.SubTitle:
|
||||||
result = newQVariant(item.subTitle)
|
result = newQVariant(item.subTitle)
|
||||||
|
of ModelRole.Image:
|
||||||
|
result = newQVariant(item.image)
|
||||||
of ModelRole.Icon:
|
of ModelRole.Icon:
|
||||||
result = newQVariant(item.icon)
|
result = newQVariant(item.icon)
|
||||||
of ModelRole.IconColor:
|
of ModelRole.IconColor:
|
||||||
|
|
|
@ -204,6 +204,10 @@ method displayEphemeralWithActionNotification*(self: AccessInterface, title: str
|
||||||
ephNotifType: int, actionType: int, actionData: string, details = NotificationDetails()) {.base.} =
|
ephNotifType: int, actionType: int, actionData: string, details = NotificationDetails()) {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method displayEphemeralImageWithActionNotification*(self: AccessInterface, title: string, subTitle: string, image: string,
|
||||||
|
ephNotifType: int, actionType: int, actionData: string, details = NotificationDetails()) {.base.} =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
method removeEphemeralNotification*(self: AccessInterface, id: int64) {.base.} =
|
method removeEphemeralNotification*(self: AccessInterface, id: int64) {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
|
|
@ -1312,7 +1312,7 @@ method displayEphemeralNotification*[T](self: Module[T], title: string, subTitle
|
||||||
elif(ephNotifType == EphemeralNotificationType.Danger.int):
|
elif(ephNotifType == EphemeralNotificationType.Danger.int):
|
||||||
finalEphNotifType = EphemeralNotificationType.Danger
|
finalEphNotifType = EphemeralNotificationType.Danger
|
||||||
|
|
||||||
let item = ephemeral_notification_item.initItem(id, title, TOAST_MESSAGE_VISIBILITY_DURATION_IN_MS, subTitle, icon, "",
|
let item = ephemeral_notification_item.initItem(id, title, TOAST_MESSAGE_VISIBILITY_DURATION_IN_MS, subTitle, "", icon, "",
|
||||||
loading, finalEphNotifType, url, 0, "", details)
|
loading, finalEphNotifType, url, 0, "", details)
|
||||||
self.view.ephemeralNotificationModel().addItem(item)
|
self.view.ephemeralNotificationModel().addItem(item)
|
||||||
|
|
||||||
|
@ -1328,10 +1328,27 @@ method displayEphemeralWithActionNotification*[T](self: Module[T], title: string
|
||||||
elif(ephNotifType == EphemeralNotificationType.Danger.int):
|
elif(ephNotifType == EphemeralNotificationType.Danger.int):
|
||||||
finalEphNotifType = EphemeralNotificationType.Danger
|
finalEphNotifType = EphemeralNotificationType.Danger
|
||||||
|
|
||||||
let item = ephemeral_notification_item.initItem(id, title, TOAST_MESSAGE_VISIBILITY_DURATION_IN_MS, subTitle, icon, iconColor,
|
let item = ephemeral_notification_item.initItem(id, title, TOAST_MESSAGE_VISIBILITY_DURATION_IN_MS, subTitle, "", icon, iconColor,
|
||||||
loading, finalEphNotifType, "", actionType, actionData, details)
|
loading, finalEphNotifType, "", actionType, actionData, details)
|
||||||
self.view.ephemeralNotificationModel().addItem(item)
|
self.view.ephemeralNotificationModel().addItem(item)
|
||||||
|
|
||||||
|
# TO UNIFY with the one above.
|
||||||
|
# Further refactor will be done in a next step
|
||||||
|
method displayEphemeralImageWithActionNotification*[T](self: Module[T], title: string, subTitle: string, image: string, ephNotifType: int,
|
||||||
|
actionType: int, actionData: string, details = NotificationDetails()) =
|
||||||
|
let now = getTime()
|
||||||
|
let id = now.toUnix * 1000000000 + now.nanosecond
|
||||||
|
var finalEphNotifType = EphemeralNotificationType.Default
|
||||||
|
if(ephNotifType == EphemeralNotificationType.Success.int):
|
||||||
|
finalEphNotifType = EphemeralNotificationType.Success
|
||||||
|
elif(ephNotifType == EphemeralNotificationType.Danger.int):
|
||||||
|
finalEphNotifType = EphemeralNotificationType.Danger
|
||||||
|
|
||||||
|
|
||||||
|
let item = ephemeral_notification_item.initItem(id, title, TOAST_MESSAGE_VISIBILITY_DURATION_IN_MS, subTitle, image, "", "", false,
|
||||||
|
finalEphNotifType, "", actionType, actionData, details)
|
||||||
|
self.view.ephemeralNotificationModel().addItem(item)
|
||||||
|
|
||||||
method displayEphemeralNotification*[T](self: Module[T], title: string, subTitle: string, details: NotificationDetails) =
|
method displayEphemeralNotification*[T](self: Module[T], title: string, subTitle: string, details: NotificationDetails) =
|
||||||
if(details.notificationType == NotificationType.NewMessage or
|
if(details.notificationType == NotificationType.NewMessage or
|
||||||
details.notificationType == NotificationType.NewMessageWithPersonalMention or
|
details.notificationType == NotificationType.NewMessageWithPersonalMention or
|
||||||
|
|
|
@ -124,6 +124,12 @@ QtObject:
|
||||||
ephNotifType: int, actionType: int, actionData: string) {.slot.} =
|
ephNotifType: int, actionType: int, actionData: string) {.slot.} =
|
||||||
self.delegate.displayEphemeralWithActionNotification(title, subTitle, icon, iconColor, loading, ephNotifType, actionType, actionData)
|
self.delegate.displayEphemeralWithActionNotification(title, subTitle, icon, iconColor, loading, ephNotifType, actionType, actionData)
|
||||||
|
|
||||||
|
# TO UNIFY with the one above.
|
||||||
|
# Further refactor will be done in a next step
|
||||||
|
proc displayEphemeralImageWithActionNotification*(self: View, title: string, subTitle: string, image: string, ephNotifType: int,
|
||||||
|
actionType: int, actionData: string) {.slot.} =
|
||||||
|
self.delegate.displayEphemeralImageWithActionNotification(title, subTitle, image, ephNotifType, actionType, actionData)
|
||||||
|
|
||||||
proc removeEphemeralNotification*(self: View, id: string) {.slot.} =
|
proc removeEphemeralNotification*(self: View, id: string) {.slot.} =
|
||||||
self.delegate.removeEphemeralNotification(id.parseInt)
|
self.delegate.removeEphemeralNotification(id.parseInt)
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1636,10 +1636,25 @@ Item {
|
||||||
clip: false
|
clip: false
|
||||||
|
|
||||||
delegate: StatusToastMessage {
|
delegate: StatusToastMessage {
|
||||||
|
property bool isSquare : isSquareShape(model.actionData)
|
||||||
|
|
||||||
|
// Specific method to calculate image radius depending on if the toast represents some info about a collectible or an asset
|
||||||
|
function isSquareShape(data) {
|
||||||
|
// It expects the data is a JSON file containing `tokenType`
|
||||||
|
if(data) {
|
||||||
|
var parsedData = JSON.parse(data)
|
||||||
|
var tokenType = parsedData.tokenType
|
||||||
|
return tokenType === Constants.TokenType.ERC721
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
objectName: "statusToastMessage"
|
objectName: "statusToastMessage"
|
||||||
width: ListView.view.width
|
width: ListView.view.width
|
||||||
primaryText: model.title
|
primaryText: model.title
|
||||||
secondaryText: model.subTitle
|
secondaryText: model.subTitle
|
||||||
|
image: model.image
|
||||||
|
imageRadius: model.image && isSquare ? 8 : imageSize / 2
|
||||||
icon.name: model.icon
|
icon.name: model.icon
|
||||||
iconColor: model.iconColor
|
iconColor: model.iconColor
|
||||||
loading: model.loading
|
loading: model.loading
|
||||||
|
|
|
@ -2,6 +2,8 @@ import QtQuick 2.15
|
||||||
|
|
||||||
import utils 1.0
|
import utils 1.0
|
||||||
|
|
||||||
|
import AppLayouts.Wallet 1.0
|
||||||
|
|
||||||
import AppLayouts.stores 1.0
|
import AppLayouts.stores 1.0
|
||||||
import AppLayouts.Chat.stores 1.0 as ChatStores
|
import AppLayouts.Chat.stores 1.0 as ChatStores
|
||||||
|
|
||||||
|
@ -21,7 +23,8 @@ QtObject {
|
||||||
NavigateToCommunityAdmin = 1,
|
NavigateToCommunityAdmin = 1,
|
||||||
OpenFinaliseOwnershipPopup = 2,
|
OpenFinaliseOwnershipPopup = 2,
|
||||||
OpenSendModalPopup = 3,
|
OpenSendModalPopup = 3,
|
||||||
ViewTransactionDetails = 4
|
ViewTransactionDetails = 4,
|
||||||
|
OpenFirstCommunityTokenPopup = 5
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stores:
|
// Stores:
|
||||||
|
@ -54,22 +57,6 @@ QtObject {
|
||||||
communityId)
|
communityId)
|
||||||
}
|
}
|
||||||
|
|
||||||
function onCommunityTokenReceived(name, image, communityId, communityName, communityColor, balance, chainId, txHash) {
|
|
||||||
var data = {
|
|
||||||
communityId: communityId,
|
|
||||||
chainId: chainId,
|
|
||||||
txHash: txHash
|
|
||||||
}
|
|
||||||
Global.displayToastWithActionMessage(qsTr("You were airdropped %1 %2 asset from %3").arg(balance).arg(name).arg(communityName),
|
|
||||||
qsTr("View transaction details"),
|
|
||||||
image,
|
|
||||||
communityColor,
|
|
||||||
false,
|
|
||||||
Constants.ephemeralNotificationType.normal,
|
|
||||||
ToastsManager.ActionType.ViewTransactionDetails,
|
|
||||||
JSON.stringify(data))
|
|
||||||
}
|
|
||||||
|
|
||||||
function onSetSignerStateChanged(communityId, communityName, status, url) {
|
function onSetSignerStateChanged(communityId, communityName, status, url) {
|
||||||
if (status === Constants.ContractTransactionStatus.Completed) {
|
if (status === Constants.ContractTransactionStatus.Completed) {
|
||||||
Global.displayToastMessage(qsTr("%1 smart contract amended").arg(communityName),
|
Global.displayToastMessage(qsTr("%1 smart contract amended").arg(communityName),
|
||||||
|
@ -140,6 +127,48 @@ QtObject {
|
||||||
Constants.ephemeralNotificationType.danger,
|
Constants.ephemeralNotificationType.danger,
|
||||||
"")
|
"")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Community token received in the user wallet:
|
||||||
|
function onCommunityTokenReceived(name, image, communityId, communityName, balance, chainId, txHash, isFirst, tokenType, walletAccountName) {
|
||||||
|
|
||||||
|
// Some error control:
|
||||||
|
if(tokenType !== Constants.TokenType.ERC20 && tokenType !== Constants.TokenType.ERC721) {
|
||||||
|
console.warn("Community token Received: Unexpected token type while creating a toast message: " + tokenType)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var data = {
|
||||||
|
communityId: communityId,
|
||||||
|
chainId: chainId,
|
||||||
|
txHash: txHash,
|
||||||
|
tokenType: tokenType
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isFirst) {
|
||||||
|
var tokenTypeText = ""
|
||||||
|
if(tokenType === Constants.TokenType.ERC20) {
|
||||||
|
tokenTypeText = qsTr("You received your first community asset")
|
||||||
|
} else if(tokenType === Constants.TokenType.ERC721) {
|
||||||
|
tokenTypeText = qsTr("You received your first community collectible")
|
||||||
|
}
|
||||||
|
|
||||||
|
// First community token received toast:
|
||||||
|
Global.displayImageToastWithActionMessage(qsTr("%1: %2 %3").arg(tokenTypeText).arg(balance).arg(name),
|
||||||
|
qsTr("Learn more"),
|
||||||
|
image,
|
||||||
|
Constants.ephemeralNotificationType.normal,
|
||||||
|
ToastsManager.ActionType.OpenFirstCommunityTokenPopup,
|
||||||
|
JSON.stringify(data))
|
||||||
|
} else {
|
||||||
|
// Generic community token received toast:
|
||||||
|
Global.displayImageToastWithActionMessage(qsTr("You were airdropped %1 %2 from %3 to %4").arg(balance).arg(name).arg(communityName).arg(walletAccountName),
|
||||||
|
qsTr("View transaction details"),
|
||||||
|
image,
|
||||||
|
Constants.ephemeralNotificationType.normal,
|
||||||
|
ToastsManager.ActionType.ViewTransactionDetails,
|
||||||
|
JSON.stringify(data))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connections to global. These will lead the backend integration:
|
// Connections to global. These will lead the backend integration:
|
||||||
|
@ -155,6 +184,10 @@ QtObject {
|
||||||
function onDisplayToastWithActionMessage(title: string, subTitle: string, icon: string, iconColor: string, loading: bool, ephNotifType: int, actionType: int, actionData: string) {
|
function onDisplayToastWithActionMessage(title: string, subTitle: string, icon: string, iconColor: string, loading: bool, ephNotifType: int, actionType: int, actionData: string) {
|
||||||
root.rootStore.mainModuleInst.displayEphemeralWithActionNotification(title, subTitle, icon, iconColor, loading, ephNotifType, actionType, actionData)
|
root.rootStore.mainModuleInst.displayEphemeralWithActionNotification(title, subTitle, icon, iconColor, loading, ephNotifType, actionType, actionData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onDisplayImageToastWithActionMessage(title: string, subTitle: string, image: string, ephNotifType: int, actionType: int, actionData: string) {
|
||||||
|
root.rootStore.mainModuleInst.displayEphemeralImageWithActionNotification(title, subTitle, image, ephNotifType, actionType, actionData)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// It will cover all specific actions (different than open external links) that can be done after clicking toast link text
|
// It will cover all specific actions (different than open external links) that can be done after clicking toast link text
|
||||||
|
@ -169,6 +202,22 @@ QtObject {
|
||||||
case ToastsManager.ActionType.OpenSendModalPopup:
|
case ToastsManager.ActionType.OpenSendModalPopup:
|
||||||
root.sendModalPopup.open()
|
root.sendModalPopup.open()
|
||||||
return
|
return
|
||||||
|
case ToastsManager.ActionType.ViewTransactionDetails:
|
||||||
|
var txHash = ""
|
||||||
|
if(actionData) {
|
||||||
|
var parsedData = JSON.parse(actionData)
|
||||||
|
txHash = parsedData.txHash
|
||||||
|
Global.changeAppSectionBySectionType(Constants.appSection.wallet,
|
||||||
|
WalletLayout.LeftPanelSelection.AllAddresses,
|
||||||
|
WalletLayout.RightPanelSelection.Activity)
|
||||||
|
// TODO: Final navigation to the specific transaction entry --> {transaction: txHash}) --> Issue #13249
|
||||||
|
return
|
||||||
|
}
|
||||||
|
console.warn("Unexpected transaction hash while trying to navigate to the details page: " + txHash)
|
||||||
|
return
|
||||||
|
case ToastsManager.ActionType.OpenFirstCommunityTokenPopup:
|
||||||
|
console.warn("TODO: #12366")
|
||||||
|
return
|
||||||
default:
|
default:
|
||||||
console.warn("ToastsManager: Action type is not defined")
|
console.warn("ToastsManager: Action type is not defined")
|
||||||
return
|
return
|
||||||
|
|
|
@ -34,7 +34,11 @@ QtObject {
|
||||||
signal communityOwnershipDeclined(string communityName)
|
signal communityOwnershipDeclined(string communityName)
|
||||||
signal sendOwnerTokenStateChanged(string tokenName, int status, string url)
|
signal sendOwnerTokenStateChanged(string tokenName, int status, string url)
|
||||||
signal ownerTokenReceived(string communityId, string communityName)
|
signal ownerTokenReceived(string communityId, string communityName)
|
||||||
signal communityTokenReceived(string name, string image, string communityId, string communityName, string communityColor, string balance, int chainId, string txHash)
|
signal communityTokenReceived(string name, string image,
|
||||||
|
string communityId, string communityName,
|
||||||
|
string balance, int chainId,
|
||||||
|
string txHash, bool isFirst,
|
||||||
|
int tokenType, string walletAccountName)
|
||||||
|
|
||||||
// Minting tokens:
|
// Minting tokens:
|
||||||
function deployCollectible(communityId, collectibleItem)
|
function deployCollectible(communityId, collectibleItem)
|
||||||
|
@ -132,8 +136,16 @@ QtObject {
|
||||||
root.ownerTokenReceived(communityId, communityName)
|
root.ownerTokenReceived(communityId, communityName)
|
||||||
}
|
}
|
||||||
|
|
||||||
function onCommunityTokenReceived(name, image, communityId, communityName, communityColor, balance, chainId, txHash) {
|
function onCommunityTokenReceived(name, image, communityId, communityName, communityColor /*Unused, can be removed*/, balance, chainId, txHash/*, isFirst, tokenType, walletAccountName*/) {
|
||||||
root.communityTokenReceived(name, image, communityId, communityName, communityColor, balance, chainId, txHash)
|
// TODO BACKEND: #13250
|
||||||
|
// ** `isFirst` property will be true if it's the first time the user receives a community asset and a community collectible
|
||||||
|
// ** `tokenType` property will determine if the received minted token is an ERC20 or an ERC720
|
||||||
|
// ** `walletAccountName` property will provide the wallet account name where the token was received
|
||||||
|
|
||||||
|
var isFirst = false
|
||||||
|
var tokenType = Constants.TokenType.ERC20
|
||||||
|
var walletAccountName = "Status account"
|
||||||
|
root.communityTokenReceived(name, image, communityId, communityName, balance, chainId, txHash, isFirst, tokenType, walletAccountName)
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSetSignerStateChanged(communityId, communityName, status, url) {
|
function onSetSignerStateChanged(communityId, communityName, status, url) {
|
||||||
|
|
|
@ -27,6 +27,7 @@ QtObject {
|
||||||
|
|
||||||
signal displayToastMessage(string title, string subTitle, string icon, bool loading, int ephNotifType, string url)
|
signal displayToastMessage(string title, string subTitle, string icon, bool loading, int ephNotifType, string url)
|
||||||
signal displayToastWithActionMessage(string title, string subTitle, string icon, string iconColor, bool loading, int ephNotifType, int actionType, string data)
|
signal displayToastWithActionMessage(string title, string subTitle, string icon, string iconColor, bool loading, int ephNotifType, int actionType, string data)
|
||||||
|
signal displayImageToastWithActionMessage(string title, string subTitle, string image, int ephNotifType, int actionType, string data)
|
||||||
|
|
||||||
signal openPopupRequested(var popupComponent, var params)
|
signal openPopupRequested(var popupComponent, var params)
|
||||||
signal closePopupRequested()
|
signal closePopupRequested()
|
||||||
|
|
Loading…
Reference in New Issue