feat: introduce first JoinCommunityView for token-gated communities

This does a few things:

- It integrates with the latest `CommunityTokensMetadata` to access
  community specific ERC721 token
- It changes `ChatLayout` such that it conditionally loads either
  `ChatView` or `JoinCommunityView`. `JoinCommunityView` has been
  specifically designed for token-gated communities

Here's what works (in terms of token permissions):

1. If a community has token permissions and the the current users is not
   a member of that community, we show `JoinCommunityView` instead of
   `ChatView`
2. Any community token permissions of type "Become member" are listed in
   the `JoinCommunityView`
3. There are different types of token critera a permission can have:
   ERC20 token, ERC721 token, or ENS (which is also ERC721 but we have
   a type for that nonetheless)

   Only ERC20 token balances are checked for the known wallet accounts.
   This happens every time the known token list has been updated (every
   10 min atm).

   We still need to add balance checks for any ERC721 tokens and ENS.
4. If token permissions are created, updated or deleted by the community
   owner, the `JoinCommunityView` will update in real-time.

You'll also notice that the `Reveal my address and request access`
button will be enabled if any of the token permissions are fulfilled
(only ERC20 at the time being). Clicking that button will not yet send
a request.

This will be done in the next step as part of https://github.com/status-im/status-desktop/issues/9761
This commit is contained in:
Pascal Precht 2023-03-07 17:51:06 +01:00 committed by r4bbit
parent 8f3a965a49
commit 25b0641cc2
14 changed files with 241 additions and 80 deletions

View File

@ -244,6 +244,12 @@ proc init*(self: Controller) =
if (args.communityId == self.sectionId): if (args.communityId == self.sectionId):
self.delegate.onCommunityTokenPermissionDeletionFailed(args.communityId) self.delegate.onCommunityTokenPermissionDeletionFailed(args.communityId)
self.events.on(SIGNAL_COMMUNITY_TOKEN_METADATA_ADDED) do(e: Args):
let args = CommunityTokenMetadataArgs(e)
if (args.communityId == self.sectionId):
self.delegate.onCommunityTokenMetadataAdded(args.communityId, args.tokenMetadata)
self.events.on(SIGNAL_WALLET_ACCOUNT_TOKENS_REBUILT) do(e: Args): self.events.on(SIGNAL_WALLET_ACCOUNT_TOKENS_REBUILT) do(e: Args):
self.delegate.onWalletAccountTokensRebuilt() self.delegate.onWalletAccountTokensRebuilt()

View File

@ -353,5 +353,8 @@ method onCommunityTokenPermissionDeleted*(self: AccessInterface, communityId: st
method onCommunityTokenPermissionDeletionFailed*(self: AccessInterface, communityId: string) = method onCommunityTokenPermissionDeletionFailed*(self: AccessInterface, communityId: string) =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method onCommunityTokenMetadataAdded*(self: AccessInterface, communityId: string, tokenMetadata: CommunityTokensMetadataDto) =
raise newException(ValueError, "No implementation available")
method onWalletAccountTokensRebuilt*(self: AccessInterface) = method onWalletAccountTokensRebuilt*(self: AccessInterface) =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")

View File

@ -12,6 +12,7 @@ import ../../shared_models/token_permission_item
import ../../shared_models/token_criteria_item import ../../shared_models/token_criteria_item
import ../../shared_models/token_criteria_model import ../../shared_models/token_criteria_model
import ../../shared_models/token_list_item import ../../shared_models/token_list_item
import ../../shared_models/token_list_model
import chat_content/module as chat_content_module import chat_content/module as chat_content_module
import chat_content/users/module as users_module import chat_content/users/module as users_module
@ -66,6 +67,8 @@ proc buildChatSectionUI(self: Module,
proc buildTokenPermissionItem*(self: Module, tokenPermission: CommunityTokenPermissionDto): TokenPermissionItem proc buildTokenPermissionItem*(self: Module, tokenPermission: CommunityTokenPermissionDto): TokenPermissionItem
proc buildTokenList*(self: Module)
proc newModule*( proc newModule*(
delegate: delegate_interface.AccessInterface, delegate: delegate_interface.AccessInterface,
events: EventEmitter, events: EventEmitter,
@ -303,6 +306,8 @@ proc initContactRequestsModel(self: Module) =
self.view.contactRequestsModel().addItems(contactsWhoAddedMe) self.view.contactRequestsModel().addItems(contactsWhoAddedMe)
proc rebuildCommunityTokenPermissionsModel(self: Module) = proc rebuildCommunityTokenPermissionsModel(self: Module) =
self.buildTokenList()
let community = self.controller.getMyCommunity() let community = self.controller.getMyCommunity()
var tokenPermissionsItems: seq[TokenPermissionItem] = @[] var tokenPermissionsItems: seq[TokenPermissionItem] = @[]
var allTokenRequirementsMet = false var allTokenRequirementsMet = false
@ -322,17 +327,17 @@ proc rebuildCommunityTokenPermissionsModel(self: Module) =
self.view.tokenPermissionsModel().setItems(tokenPermissionsItems) self.view.tokenPermissionsModel().setItems(tokenPermissionsItems)
self.view.setAllTokenRequirementsMet(allTokenRequirementsMet) self.view.setAllTokenRequirementsMet(allTokenRequirementsMet)
self.view.setRequiresTokenPermissionToJoin(tokenPermissionsItems.len > 0)
proc initCommunityTokenPermissionsModel(self: Module) = proc initCommunityTokenPermissionsModel(self: Module) =
self.rebuildCommunityTokenPermissionsModel() self.rebuildCommunityTokenPermissionsModel()
proc buildTokenList(self: Module) = proc buildTokenList(self: Module) =
var tokenListItems: seq[TokenListItem] var tokenListItems: seq[TokenListItem]
var collectiblesListItems: seq[TokenListItem] var collectiblesListItems: seq[TokenListItem]
let community = self.controller.getMyCommunity()
let erc20Tokens = self.controller.getTokenList() let erc20Tokens = self.controller.getTokenList()
let communityTokens = self.controller.getCommunityTokenList()
for token in erc20Tokens: for token in erc20Tokens:
let tokenListItem = initTokenListItem( let tokenListItem = initTokenListItem(
@ -346,7 +351,7 @@ proc buildTokenList(self: Module) =
tokenListItems.add(tokenListItem) tokenListItems.add(tokenListItem)
for token in communityTokens: for token in community.communityTokensMetadata:
let tokenListItem = initTokenListItem( let tokenListItem = initTokenListItem(
key = token.symbol, key = token.symbol,
name = token.name, name = token.name,
@ -402,8 +407,9 @@ method load*(
self.initContactRequestsModel() self.initContactRequestsModel()
else: else:
self.usersModule.load() self.usersModule.load()
let community = self.controller.getMyCommunity()
self.view.setAmIMember(community.joined)
self.initCommunityTokenPermissionsModel() self.initCommunityTokenPermissionsModel()
self.buildTokenList()
let activeChatId = self.controller.getActiveChatId() let activeChatId = self.controller.getActiveChatId()
let isCurrentSectionActive = self.controller.getIsCurrentSectionActive() let isCurrentSectionActive = self.controller.getIsCurrentSectionActive()
@ -743,14 +749,18 @@ method onChatUnmuted*(self: Module, chatId: string) =
method onCommunityTokenPermissionDeleted*(self: Module, communityId: string, permissionId: string) = method onCommunityTokenPermissionDeleted*(self: Module, communityId: string, permissionId: string) =
self.view.tokenPermissionsModel().removeItemWithId(permissionId) self.view.tokenPermissionsModel().removeItemWithId(permissionId)
self.view.setRequiresTokenPermissionToJoin(self.view.tokenPermissionsModel().getCount() > 0)
singletonInstance.globalEvents.showCommunityTokenPermissionDeletedNotification(communityId, "Community permission deleted", "A token permission has been removed") singletonInstance.globalEvents.showCommunityTokenPermissionDeletedNotification(communityId, "Community permission deleted", "A token permission has been removed")
method onCommunityTokenPermissionCreated*(self: Module, communityId: string, tokenPermission: CommunityTokenPermissionDto) = method onCommunityTokenPermissionCreated*(self: Module, communityId: string, tokenPermission: CommunityTokenPermissionDto) =
if tokenPermission.`type` == TokenPermissionType.BecomeMember: if tokenPermission.`type` == TokenPermissionType.BecomeMember:
let tokenPermissionItem = self.buildTokenPermissionItem(tokenPermission) let tokenPermissionItem = self.buildTokenPermissionItem(tokenPermission)
self.view.tokenPermissionsModel.addItem(tokenPermissionItem)
if tokenPermissionItem.tokenCriteriaMet: if tokenPermissionItem.tokenCriteriaMet:
self.view.setAllTokenRequirementsMet(true) self.view.setAllTokenRequirementsMet(true)
self.view.tokenPermissionsModel.addItem(tokenPermissionItem)
self.view.setRequiresTokenPermissionToJoin(true)
singletonInstance.globalEvents.showCommunityTokenPermissionCreatedNotification(communityId, "Community permission created", "A token permission has been added") singletonInstance.globalEvents.showCommunityTokenPermissionCreatedNotification(communityId, "Community permission created", "A token permission has been added")
method onCommunityTokenPermissionUpdated*(self: Module, communityId: string, tokenPermission: CommunityTokenPermissionDto) = method onCommunityTokenPermissionUpdated*(self: Module, communityId: string, tokenPermission: CommunityTokenPermissionDto) =
@ -784,6 +794,23 @@ method onCommunityTokenPermissionUpdateFailed*(self: Module, communityId: string
method onCommunityTokenPermissionDeletionFailed*(self: Module, communityId: string) = method onCommunityTokenPermissionDeletionFailed*(self: Module, communityId: string) =
singletonInstance.globalEvents.showCommunityTokenPermissionDeletionFailedNotification(communityId, "Failed to delete community permission", "Something went wrong") singletonInstance.globalEvents.showCommunityTokenPermissionDeletionFailedNotification(communityId, "Failed to delete community permission", "Something went wrong")
method onCommunityTokenMetadataAdded*(self: Module, communityId: string, tokenMetadata: CommunityTokensMetadataDto) =
let tokenListItem = initTokenListItem(
key = tokenMetadata.symbol,
name = tokenMetadata.name,
symbol = tokenMetadata.symbol,
color = "", # tokenMetadata doesn't provide a color
image = tokenMetadata.image,
category = ord(TokenListItemCategory.Community)
)
if tokenMetadata.tokenType == community_dto.TokenType.ERC721 and not self.view.collectiblesListModel().hasItem(tokenMetadata.symbol):
self.view.collectiblesListModel.addItems(@[tokenListItem])
return
if tokenMetadata.tokenType == community_dto.TokenType.ERC20 and not self.view.tokenListModel().hasItem(tokenMetadata.symbol):
self.view.tokenListModel.addItems(@[tokenListItem])
method onMarkAllMessagesRead*(self: Module, chatId: string) = method onMarkAllMessagesRead*(self: Module, chatId: string) =
self.updateBadgeNotifications(chatId, hasUnreadMessages=false, unviewedMentionsCount=0) self.updateBadgeNotifications(chatId, hasUnreadMessages=false, unviewedMentionsCount=0)
let chatDetails = self.controller.getChatDetails(chatId) let chatDetails = self.controller.getChatDetails(chatId)

View File

@ -32,6 +32,8 @@ QtObject:
collectiblesListModel: TokenListModel collectiblesListModel: TokenListModel
collectiblesListModelVariant: QVariant collectiblesListModelVariant: QVariant
allTokenRequirementsMet: bool allTokenRequirementsMet: bool
requiresTokenPermissionToJoin: bool
amIMember: bool
proc delete*(self: View) = proc delete*(self: View) =
self.model.delete self.model.delete
@ -74,6 +76,8 @@ QtObject:
result.tokenListModelVariant = newQVariant(result.tokenListModel) result.tokenListModelVariant = newQVariant(result.tokenListModel)
result.collectiblesListModel = newTokenListModel() result.collectiblesListModel = newTokenListModel()
result.collectiblesListModelVariant = newQVariant(result.collectiblesListModel) result.collectiblesListModelVariant = newQVariant(result.collectiblesListModel)
result.amIMember = false
result.requiresTokenPermissionToJoin = false
proc load*(self: View) = proc load*(self: View) =
self.delegate.viewDidLoad() self.delegate.viewDidLoad()
@ -381,6 +385,36 @@ QtObject:
proc deleteCommunityTokenPermission*(self: View, communityId: string, permissionId: string) {.slot.} = proc deleteCommunityTokenPermission*(self: View, communityId: string, permissionId: string) {.slot.} =
self.delegate.deleteCommunityTokenPermission(communityId, permissionId) self.delegate.deleteCommunityTokenPermission(communityId, permissionId)
proc requiresTokenPermissionToJoinChanged*(self: View) {.signal.}
proc getRequiresTokenPermissionToJoin(self: View): bool {.slot.} =
return self.requiresTokenPermissionToJoin
proc setRequiresTokenPermissionToJoin*(self: View, value: bool) =
if (value == self.requiresTokenPermissionToJoin):
return
self.requiresTokenPermissionToJoin = value
self.requiresTokenPermissionToJoinChanged()
QtProperty[bool] requiresTokenPermissionToJoin:
read = getRequiresTokenPermissionToJoin
notify = requiresTokenPermissionToJoinChanged
proc getAmIMember*(self: View): bool {.slot.} =
return self.amIMember
proc amIMemberChanged*(self: View) {.signal.}
proc setAmIMember*(self: View, value: bool) =
if (value == self.amIMember):
return
self.amIMember = value
self.amIMemberChanged()
QtProperty[bool] amIMember:
read = getAmIMember
notify = amIMemberChanged
proc getAllTokenRequirementsMet*(self: View): bool {.slot.} = proc getAllTokenRequirementsMet*(self: View): bool {.slot.} =
return self.allTokenRequirementsMet return self.allTokenRequirementsMet

View File

@ -78,6 +78,12 @@ QtObject:
proc getItems*(self: TokenCriteriaModel): seq[TokenCriteriaItem] = proc getItems*(self: TokenCriteriaModel): seq[TokenCriteriaItem] =
return self.items return self.items
proc setItems*(self: TokenCriteriaModel, items: seq[TokenCriteriaItem]) =
self.beginResetModel()
self.items = items
self.endResetModel()
self.countChanged()
proc addItem*(self: TokenCriteriaModel, item: TokenCriteriaItem) = proc addItem*(self: TokenCriteriaModel, item: TokenCriteriaItem) =
let parentModelIndex = newQModelIndex() let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete defer: parentModelIndex.delete

View File

@ -35,13 +35,24 @@ QtObject:
read = getCount read = getCount
notify = countChanged notify = countChanged
proc setItems*(self: TokenlistModel, items: seq[TokenListItem]) = proc setItems*(self: TokenListModel, items: seq[TokenListItem]) =
self.beginResetModel() self.beginResetModel()
self.items = items self.items = items
self.endResetModel() self.endResetModel()
self.countChanged() self.countChanged()
proc addItems*(self: TokenlistModel, items: seq[TokenListItem]) = proc hasItem*(self: TokenListModel, symbol: string): bool =
for item in self.items:
if item.getSymbol() == symbol:
return true
return false
proc getItem*(self: TokenListModel, symbol: string): TokenListItem =
for item in self.items:
if item.getSymbol() == symbol:
return item
proc addItems*(self: TokenListModel, items: seq[TokenListItem]) =
if(items.len == 0): if(items.len == 0):
return return

View File

@ -1,5 +1,6 @@
import NimQml, Tables import NimQml, Tables
import token_permission_item import token_permission_item
import token_criteria_model
type type
ModelRole {.pure.} = enum ModelRole {.pure.} = enum
@ -36,7 +37,7 @@ QtObject:
}.toTable }.toTable
proc countChanged(self: TokenPermissionsModel) {.signal.} proc countChanged(self: TokenPermissionsModel) {.signal.}
proc getCount(self: TokenPermissionsModel): int {.slot.} = proc getCount*(self: TokenPermissionsModel): int {.slot.} =
self.items.len self.items.len
QtProperty[int] count: QtProperty[int] count:
read = getCount read = getCount
@ -107,9 +108,8 @@ QtObject:
if(idx == -1): if(idx == -1):
return return
self.items[idx].id = permissionId
self.items[idx].`type` = item.`type` self.items[idx].`type` = item.`type`
self.items[idx].tokenCriteria = item.tokenCriteria self.items[idx].tokenCriteria.setItems(item.tokenCriteria.getItems())
self.items[idx].isPrivate = item.isPrivate self.items[idx].isPrivate = item.isPrivate
let index = self.createIndex(idx, 0, nil) let index = self.createIndex(idx, 0, nil)

View File

@ -64,6 +64,7 @@ type CommunityTokensMetadataDto* = object
description*: string description*: string
image*: string image*: string
symbol*: string symbol*: string
name*: string
tokenType*: TokenType tokenType*: TokenType
type CommunityDto* = object type CommunityDto* = object
@ -165,6 +166,7 @@ proc toCommunityTokensMetadataDto*(jsonObj: JsonNode): CommunityTokensMetadataDt
discard jsonObj.getProp("description", result.description) discard jsonObj.getProp("description", result.description)
discard jsonObj.getProp("image", result.image) discard jsonObj.getProp("image", result.image)
discard jsonObj.getProp("symbol", result.symbol) discard jsonObj.getProp("symbol", result.symbol)
discard jsonObj.getProp("name", result.name)
var tokenTypeInt: int var tokenTypeInt: int
discard jsonObj.getProp("tokenType", tokenTypeInt) discard jsonObj.getProp("tokenType", tokenTypeInt)
result.tokenType = intToEnum(tokenTypeInt, TokenType.ERC721) result.tokenType = intToEnum(tokenTypeInt, TokenType.ERC721)

View File

@ -21,8 +21,6 @@ export community_dto
logScope: logScope:
topics = "community-service" topics = "community-service"
include ../../common/json_utils
type type
CommunityArgs* = ref object of Args CommunityArgs* = ref object of Args
community*: CommunityDto community*: CommunityDto
@ -90,6 +88,10 @@ type
tokenPermission*: CommunityTokenPermissionDto tokenPermission*: CommunityTokenPermissionDto
error*: string error*: string
CommunityTokenMetadataArgs* = ref object of Args
communityId*: string
tokenMetadata*: CommunityTokensMetadataDto
CommunityTokenPermissionRemovedArgs* = ref object of Args CommunityTokenPermissionRemovedArgs* = ref object of Args
communityId*: string communityId*: string
permissionId*: string permissionId*: string
@ -156,6 +158,7 @@ const SIGNAL_COMMUNITY_TOKEN_PERMISSION_UPDATED* = "communityTokenPermissionUpda
const SIGNAL_COMMUNITY_TOKEN_PERMISSION_UPDATE_FAILED* = "communityTokenPermissionUpdateFailed" const SIGNAL_COMMUNITY_TOKEN_PERMISSION_UPDATE_FAILED* = "communityTokenPermissionUpdateFailed"
const SIGNAL_COMMUNITY_TOKEN_PERMISSION_DELETED* = "communityTokenPermissionDeleted" const SIGNAL_COMMUNITY_TOKEN_PERMISSION_DELETED* = "communityTokenPermissionDeleted"
const SIGNAL_COMMUNITY_TOKEN_PERMISSION_DELETION_FAILED* = "communityTokenPermissionDeletionFailed" const SIGNAL_COMMUNITY_TOKEN_PERMISSION_DELETION_FAILED* = "communityTokenPermissionDeletionFailed"
const SIGNAL_COMMUNITY_TOKEN_METADATA_ADDED* = "communityTokenMetadataAdded"
const SIGNAL_CURATED_COMMUNITIES_LOADING* = "curatedCommunitiesLoading" const SIGNAL_CURATED_COMMUNITIES_LOADING* = "curatedCommunitiesLoading"
const SIGNAL_CURATED_COMMUNITIES_LOADED* = "curatedCommunitiesLoaded" const SIGNAL_CURATED_COMMUNITIES_LOADED* = "curatedCommunitiesLoaded"
@ -357,6 +360,14 @@ QtObject:
return idx return idx
return -1 return -1
proc findIndexBySymbol(symbol: string, tokens: seq[CommunityTokensMetadataDto]): int =
var idx = -1
for token in tokens:
inc idx
if(token.symbol == symbol):
return idx
return -1
proc saveUpdatedCommunity(self: Service, community: var CommunityDto) = proc saveUpdatedCommunity(self: Service, community: var CommunityDto) =
# Community data we get from the signals and responses don't contgain the pending requests # Community data we get from the signals and responses don't contgain the pending requests
# therefore, we must keep the old one # therefore, we must keep the old one
@ -512,6 +523,15 @@ QtObject:
self.events.emit(SIGNAL_COMMUNITY_MEMBERS_CHANGED, self.events.emit(SIGNAL_COMMUNITY_MEMBERS_CHANGED,
CommunityMembersArgs(communityId: community.id, members: community.members)) CommunityMembersArgs(communityId: community.id, members: community.members))
# token metadata was added
if community.communityTokensMetadata.len > prev_community.communityTokensMetadata.len:
for tokenMetadata in community.communityTokensMetadata:
if findIndexBySymbol(tokenMetadata.symbol, prev_community.communityTokensMetadata) == -1:
self.communities[community.id].communityTokensMetadata.add(tokenMetadata)
self.events.emit(SIGNAL_COMMUNITY_TOKEN_METADATA_ADDED,
CommunityTokenMetadataArgs(communityId: community.id,
tokenMetadata: tokenMetadata))
# tokenPermission was added # tokenPermission was added
if community.tokenPermissions.len > prev_community.tokenPermissions.len: if community.tokenPermissions.len > prev_community.tokenPermissions.len:
for id, tokenPermission in community.tokenPermissions: for id, tokenPermission in community.tokenPermissions:

View File

@ -5,14 +5,18 @@ import QtQuick.Layouts 1.14
import utils 1.0 import utils 1.0
import "views" import "views"
import "views/communities"
import "stores" import "stores"
import "popups/community" import "popups/community"
import AppLayouts.Chat.stores 1.0
StackLayout { StackLayout {
id: root id: root
property RootStore rootStore property RootStore rootStore
readonly property var contactsStore: rootStore.contactsStore readonly property var contactsStore: rootStore.contactsStore
readonly property var permissionsStore: rootStore.permissionsStore
property var emojiPopup property var emojiPopup
property var stickersPopup property var stickersPopup
@ -37,6 +41,46 @@ StackLayout {
} }
} }
Loader {
readonly property var chatItem: root.rootStore.chatCommunitySectionModule
sourceComponent: chatItem.isCommunity() && chatItem.requiresTokenPermissionToJoin && !chatItem.amIMember ? joinCommunityViewComponent : chatViewComponent
}
Component {
id: joinCommunityViewComponent
JoinCommunityView {
id: joinCommunityView
readonly property var communityData: root.rootStore.mainModuleInst ? root.rootStore.mainModuleInst.activeSection || {} : {}
name: communityData.name
communityDesc: communityData.description
color: communityData.color
image: communityData.image
membersCount: communityData.members.count
accessType: communityData.access
joinCommunity: true
amISectionAdmin: communityData.amISectionAdmin
communityItemsModel: root.rootStore.communityItemsModel
requirementsMet: root.permissionsStore.allTokenRequirementsMet
communityHoldingsModel: root.permissionsStore.permissionsModel
assetsModel: root.rootStore.assetsModel
collectiblesModel: root.rootStore.collectiblesModel
isInvitationPending: root.rootStore.isCommunityRequestPending(communityData.id)
Connections {
target: root.rootStore.communitiesModuleInst
function onCommunityAccessRequested(communityId: string) {
if (communityId === joinCommunityView.communityData.id) {
joinCommunityView.isInvitationPending = root.rootStore.isCommunityRequestPending(communityData.id)
}
}
}
}
}
Component {
id: chatViewComponent
ChatView { ChatView {
id: chatView id: chatView
emojiPopup: root.emojiPopup emojiPopup: root.emojiPopup
@ -61,6 +105,7 @@ StackLayout {
root.openAppSearch() root.openAppSearch()
} }
} }
}
Loader { Loader {
active: root.rootStore.chatCommunitySectionModule.isCommunity() active: root.rootStore.chatCommunitySectionModule.isCommunity()

View File

@ -11,6 +11,8 @@ QtObject {
readonly property bool isOwner: false readonly property bool isOwner: false
readonly property bool allTokenRequirementsMet: chatCommunitySectionModuleInst.allTokenRequirementsMet
readonly property QtObject _d: QtObject { readonly property QtObject _d: QtObject {
id: d id: d

View File

@ -1,6 +1,7 @@
import QtQuick 2.13 import QtQuick 2.13
import utils 1.0 import utils 1.0
import SortFilterProxyModel 0.2
import StatusQ.Core.Utils 0.1 as StatusQUtils import StatusQ.Core.Utils 0.1 as StatusQUtils
import shared.stores 1.0 import shared.stores 1.0
@ -30,6 +31,57 @@ QtObject {
// Each `ChatLayout` has its own chatCommunitySectionModule // Each `ChatLayout` has its own chatCommunitySectionModule
// (on the backend chat and community sections share the same module since they are actually the same) // (on the backend chat and community sections share the same module since they are actually the same)
property var chatCommunitySectionModule property var chatCommunitySectionModule
property var communityItemsModel: chatCommunitySectionModule.model
property var assetsModel: SortFilterProxyModel {
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")
}
name: "iconSource"
expression: !!model.icon ? model.icon : icon(model.symbol)
}
}
property var collectiblesModel: chatCommunitySectionModule.collectiblesModel
// Since qml component doesn't follow encaptulation from the backend side, we're introducing // Since qml component doesn't follow encaptulation from the backend side, we're introducing
// a method which will return appropriate chat content module for selected chat/channel // a method which will return appropriate chat content module for selected chat/channel
function currentChatContentModule(){ function currentChatContentModule(){
@ -170,9 +222,6 @@ QtObject {
stickersModule: stickersModuleInst stickersModule: stickersModuleInst
} }
property var assetsModel: chatCommunitySectionModule.tokenList
property var collectiblesModel: chatCommunitySectionModule.collectiblesModel
function sendSticker(channelId, hash, replyTo, pack, url) { function sendSticker(channelId, hash, replyTo, pack, url) {
stickersModuleInst.send(channelId, hash, replyTo, pack, url) stickersModuleInst.send(channelId, hash, replyTo, pack, url)
} }

View File

@ -257,52 +257,8 @@ StatusSectionLayout {
// method is used in wallet (constructing filename from asset's // method is used in wallet (constructing filename from asset's
// symbol) and is intended to be replaced by more robust // symbol) and is intended to be replaced by more robust
// solution soon. // solution soon.
assetsModel: SortFilterProxyModel {
sourceModel: rootStore.assetsModel
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")
}
name: "iconSource"
expression: !!model.icon ? model.icon : icon(model.symbol)
}
}
assetsModel: rootStore.assetsModel
collectiblesModel: rootStore.collectiblesModel collectiblesModel: rootStore.collectiblesModel
channelsModel: rootStore.chatCommunitySectionModule.model channelsModel: rootStore.chatCommunitySectionModule.model

2
vendor/status-go vendored

@ -1 +1 @@
Subproject commit 3f3e8f8894dfd5c8a6124bce805d0bd708fb6433 Subproject commit f60716412259aece88d899d09fc71de4c4ba5d2e