status-desktop/ui/app/AppLayouts/Chat/stores/RootStore.qml

746 lines
27 KiB
QML
Raw Normal View History

import QtQuick 2.15
import QtQml 2.15
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
2023-03-07 16:51:06 +00:00
import SortFilterProxyModel 0.2
import StatusQ 0.1
import StatusQ.Core.Utils 0.1 as StatusQUtils
import AppLayouts.Profile.stores 1.0
import AppLayouts.Wallet.stores 1.0 as WalletStore
import shared.stores 1.0
import utils 1.0
QtObject {
id: root
property ContactsStore contactsStore
property CommunityTokensStore communityTokensStore
property WalletStore.RootStore walletStore
property NetworkConnectionStore networkConnectionStore
readonly property PermissionsStore permissionsStore: PermissionsStore {
activeSectionId: mainModuleInst.activeSection.id
activeChannelId: root.currentChatContentModule().chatDetails.id
chatCommunitySectionModuleInst: chatCommunitySectionModule
}
property bool openCreateChat: false
property var contactsModel: root.contactsStore.myContactsModel
// Important:
// Each `ChatLayout` has its own chatCommunitySectionModule
// (on the backend chat and community sections share the same module since they are actually the same)
property var chatCommunitySectionModule
readonly property var sectionDetails: _d.sectionDetailsInstantiator.count ? _d.sectionDetailsInstantiator.objectAt(0) : null
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
2023-03-07 16:51:06 +00:00
property var communityItemsModel: chatCommunitySectionModule.model
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
2023-03-07 16:51:06 +00:00
property var assetsModel: SortFilterProxyModel {
sourceModel: communitiesModuleInst.tokenList
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
2023-03-07 16:51:06 +00:00
proxyRoles: ExpressionRole {
function tokenIcon(symbol) {
return Constants.tokenIcon(symbol)
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
2023-03-07 16:51:06 +00:00
}
name: "iconSource"
expression: !!model.icon ? model.icon : tokenIcon(model.symbol)
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
2023-03-07 16:51:06 +00:00
}
}
readonly property var communityCollectiblesModelWithCollectionRoles: SortFilterProxyModel {
sourceModel: communitiesModuleInst.collectiblesModel
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
2023-03-07 16:51:06 +00:00
proxyRoles: [
ExpressionRole {
function collectibleIcon(icon) {
return !!icon ? icon : Style.png("tokens/DEFAULT-TOKEN")
}
name: "iconSource"
expression: collectibleIcon(model.icon)
},
ExpressionRole {
name: "collectionUid"
expression: model.key
},
ExpressionRole {
function collectibleIcon(icon) {
return !!icon ? icon : Style.png("tokens/DEFAULT-TOKEN")
}
name: "collectionImageUrl"
expression: collectibleIcon(model.icon)
}
]
}
readonly property var walletCollectiblesModel: ObjectProxyModel {
sourceModel: WalletStore.RootStore.collectiblesStore.allCollectiblesModel
delegate: QtObject {
readonly property string key: model.symbol ?? ""
readonly property string shortName: model.collectionName ? model.collectionName : model.collectionUid ? model.collectionUid : ""
readonly property string symbol: shortName
readonly property string name: shortName
readonly property int category: 1 // Own
}
exposedRoles: ["key", "symbol", "shortName", "name", "category"]
expectedRoles: ["symbol", "collectionName", "collectionUid"]
}
readonly property var walletCollectiblesGroupingModel: GroupingModel {
sourceModel: walletCollectiblesModel
groupingRoleName: "collectionUid"
submodelRoleName: "subnames"
}
readonly property var walletNonCommunityCollectiblesModel: SortFilterProxyModel {
sourceModel: walletCollectiblesGroupingModel
filters: ValueFilter {
roleName: "communityId"
value: ""
}
}
property var walletCollectiblesWithIconSourceModel: RolesRenamingModel {
sourceModel: walletNonCommunityCollectiblesModel
mapping: RoleRename {
from: "mediaUrl"
to: "iconSource"
}
}
property var collectiblesModel: ConcatModel {
sources: [
SourceModel {
model: communityCollectiblesModelWithCollectionRoles
},
SourceModel {
model: walletCollectiblesWithIconSourceModel
}
]
}
function prepareTokenModelForCommunity(publicKey) {
root.communitiesModuleInst.prepareTokenModelForCommunity(publicKey)
}
function prepareTokenModelForCommunityChat(publicKey, chatId) {
root.communitiesModuleInst.prepareTokenModelForCommunityChat(publicKey, chatId)
}
2024-03-25 22:46:58 +00:00
readonly property bool allChannelsAreHiddenBecauseNotPermitted: root.chatCommunitySectionModule.allChannelsAreHiddenBecauseNotPermitted &&
!root.chatCommunitySectionModule.requiresTokenPermissionToJoin
readonly property int communityMemberReevaluationStatus: root.chatCommunitySectionModule && root.chatCommunitySectionModule.communityMemberReevaluationStatus
readonly property bool requirementsCheckPending: root.communitiesModuleInst.requirementsCheckPending
readonly property var permissionsModel: !!root.communitiesModuleInst.spectatedCommunityPermissionModel ?
root.communitiesModuleInst.spectatedCommunityPermissionModel : null
readonly property string overviewChartData: chatCommunitySectionModule.overviewChartData
readonly property bool isUserAllowedToSendMessage: _d.isUserAllowedToSendMessage
readonly property string chatInputPlaceHolderText: _d.chatInputPlaceHolderText
readonly property var oneToOneChatContact: _d.oneToOneChatContact
// 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
function currentChatContentModule() {
// When we decide to have the same struct as it's on the backend we will remove this function.
// So far this is a way to deal with refactored backend from the current qml structure.
chatCommunitySectionModule.prepareChatContentModuleForChatId(chatCommunitySectionModule.activeItem.id)
return chatCommunitySectionModule.getChatContentModule()
}
// Contact requests related part
property var contactRequestsModel: chatCommunitySectionModule.contactRequestsModel
property bool loadingHistoryMessagesInProgress: chatCommunitySectionModule.loadingHistoryMessagesInProgress
property var advancedModule: profileSectionModule.advancedModule
property var privacyModule: profileSectionModule.privacyModule
readonly property bool permissionsCheckOngoing: chatCommunitySectionModule.permissionsCheckOngoing
readonly property bool ensCommunityPermissionsEnabled: localAccountSensitiveSettings.ensCommunityPermissionsEnabled
signal importingCommunityStateChanged(string communityId, int state, string errorMsg)
signal communityAdded(string communityId)
signal communityAccessRequested(string communityId)
signal goToMembershipRequestsPage()
function setActiveCommunity(communityId) {
mainModule.setActiveSectionById(communityId);
}
function activateStatusDeepLink(link) {
mainModuleInst.activateStatusDeepLink(link)
}
function setObservedCommunity(communityId) {
communitiesModuleInst.setObservedCommunity(communityId);
}
function getMySectionId() {
return chatCommunitySectionModule.getMySectionId()
}
function amIChatAdmin() {
return currentChatContentModule().amIChatAdmin()
}
function acceptContactRequest(pubKey, contactRequestId) {
chatCommunitySectionModule.acceptContactRequest(pubKey, contactRequestId)
}
function acceptAllContactRequests() {
chatCommunitySectionModule.acceptAllContactRequests()
}
function dismissContactRequest(pubKey, contactRequestId) {
chatCommunitySectionModule.dismissContactRequest(pubKey, contactRequestId)
}
function dismissAllContactRequests() {
chatCommunitySectionModule.dismissAllContactRequests()
}
function blockContact(pubKey) {
chatCommunitySectionModule.blockContact(pubKey)
}
function interpretMessage(msg) {
if (msg.startsWith("/shrug")) {
return msg.replace("/shrug", "") + " ¯\\\\\\_(ツ)\\_/¯"
}
if (msg.startsWith("/tableflip")) {
return msg.replace("/tableflip", "") + " (╯°□°)╯︵ ┻━┻"
}
return msg
}
function cleanMessageText(formattedMessage) {
const text = globalUtilsInst.plainText(StatusQUtils.Emoji.deparse(formattedMessage))
return interpretMessage(text)
}
function sendMessage(chatId, event, text, replyMessageId, fileUrlsAndSources) {
chatCommunitySectionModule.prepareChatContentModuleForChatId(chatId)
const chatContentModule = chatCommunitySectionModule.getChatContentModule()
var result = false
const textMsg = cleanMessageText(text)
if (textMsg.trim() !== "") {
if (event)
event.accepted = true
}
if (fileUrlsAndSources.length > 0) {
chatContentModule.inputAreaModule.sendImages(JSON.stringify(fileUrlsAndSources), textMsg.trim(), replyMessageId)
result = true
} else {
if (textMsg.trim() !== "") {
chatContentModule.inputAreaModule.sendMessage(
textMsg,
replyMessageId,
Utils.isOnlyEmoji(textMsg) ? Constants.messageContentType.emojiType : Constants.messageContentType.messageType,
false)
result = true
}
}
return result
}
function openCloseCreateChatView() {
if (root.openCreateChat) {
Global.closeCreateChatView()
} else {
Global.openCreateChatView()
}
}
property MessageStore messageStore: MessageStore { }
property var emojiReactionsModel
property var globalUtilsInst: globalUtils
property var mainModuleInst: mainModule
property var communitiesModuleInst: communitiesModule
property var communitiesList: communitiesModuleInst.model
property var userProfileInst: userProfile
property string signingPhrase: walletSection.signingPhrase
property string channelEmoji: chatCommunitySectionModule && chatCommunitySectionModule.emoji ? chatCommunitySectionModule.emoji : ""
property ListModel addToGroupContacts: ListModel {}
property var walletSectionSendInst: walletSectionSend
property string communityTags: communitiesModule.tags
property var stickersModuleInst: stickersModule
property bool isDebugEnabled: advancedModule ? advancedModule.isDebugEnabled : false
readonly property int loginType: getLoginType()
property StickersStore stickersStore: StickersStore {
stickersModule: stickersModuleInst
}
function sendSticker(channelId, hash, replyTo, pack, url) {
stickersModuleInst.send(channelId, hash, replyTo, pack, url)
}
function isCurrentUser(pubkey) {
return userProfileInst.pubKey === pubkey
}
function displayName(name, pubkey) {
return isCurrentUser(pubkey) ? qsTr("You") : name
}
function myPublicKey() {
return userProfileInst.pubKey
}
function createCommunity(args = {
name: "",
description: "",
introMessage: "",
outroMessage: "",
color: "",
tags: "",
image: {
src: "",
AX: 0,
AY: 0,
BX: 0,
BY: 0,
},
options: {
historyArchiveSupportEnabled: false,
checkedMembership: false,
2022-10-07 16:33:23 +00:00
pinMessagesAllowedForMembers: false,
encrypted: false
},
bannerJsonStr: ""
}) {
return communitiesModuleInst.createCommunity(
args.name, args.description, args.introMessage, args.outroMessage,
args.options.checkedMembership, args.color, args.tags,
args.image.src, args.image.AX, args.image.AY, args.image.BX, args.image.BY,
2022-10-07 16:33:23 +00:00
args.options.historyArchiveSupportEnabled, args.options.pinMessagesAllowedForMembers,
args.bannerJsonStr, args.options.encrypted);
}
2022-01-25 20:39:20 +00:00
function createCommunityCategory(categoryName, channels) {
chatCommunitySectionModule.createCommunityCategory(categoryName, channels)
}
2022-02-01 15:31:05 +00:00
function editCommunityCategory(categoryId, categoryName, channels) {
chatCommunitySectionModule.editCommunityCategory(categoryId, categoryName, channels);
}
function deleteCommunityCategory(categoryId) {
chatCommunitySectionModule.deleteCommunityCategory(categoryId);
}
2022-02-01 15:31:05 +00:00
function prepareEditCategoryModel(categoryId) {
chatCommunitySectionModule.prepareEditCategoryModel(categoryId);
2022-02-09 09:43:23 +00:00
}
2022-02-01 15:31:05 +00:00
function leaveCommunity() {
chatCommunitySectionModule.leaveCommunity();
}
function removeUserFromCommunity(pubKey) {
chatCommunitySectionModule.removeUserFromCommunity(pubKey);
}
function loadCommunityMemberMessages(communityId, pubKey) {
chatCommunitySectionModule.loadCommunityMemberMessages(communityId, pubKey);
}
function banUserFromCommunity(pubKey, deleteAllMessages) {
chatCommunitySectionModule.banUserFromCommunity(pubKey, deleteAllMessages);
}
function unbanUserFromCommunity(pubKey) {
chatCommunitySectionModule.unbanUserFromCommunity(pubKey);
}
function createCommunityChannel(channelName, channelDescription, channelEmoji, channelColor,
categoryId, viewersCanPostReactions, hideIfPermissionsNotMet) {
chatCommunitySectionModule.createCommunityChannel(channelName, channelDescription,
channelEmoji.trim(), channelColor, categoryId, viewersCanPostReactions, hideIfPermissionsNotMet);
}
function editCommunityChannel(chatId, newName, newDescription, newEmoji, newColor,
newCategory, channelPosition, viewOnlyCanAddReaction, hideIfPermissionsNotMet) {
chatCommunitySectionModule.editCommunityChannel(
chatId,
newName,
newDescription,
newEmoji,
newColor,
newCategory,
channelPosition,
viewOnlyCanAddReaction,
hideIfPermissionsNotMet
)
}
function acceptRequestToJoinCommunity(requestId, communityId) {
chatCommunitySectionModule.acceptRequestToJoinCommunity(requestId, communityId)
}
function declineRequestToJoinCommunity(requestId, communityId) {
chatCommunitySectionModule.declineRequestToJoinCommunity(requestId, communityId)
}
function generateAlias(pk) {
return globalUtilsInst.generateAlias(pk);
}
function plainText(text) {
return globalUtilsInst.plainText(text)
}
function removeCommunityChat(chatId) {
chatCommunitySectionModule.removeCommunityChat(chatId)
}
2022-01-25 14:51:38 +00:00
function reorderCommunityCategories(categoryId, to) {
2022-01-25 14:51:38 +00:00
chatCommunitySectionModule.reorderCommunityCategories(categoryId, to)
}
function toggleCollapsedCommunityCategory(categoryId, collapsed) {
chatCommunitySectionModule.toggleCollapsedCommunityCategory(categoryId, collapsed)
}
function reorderCommunityChat(categoryId, chatId, to) {
2022-01-25 14:51:38 +00:00
chatCommunitySectionModule.reorderCommunityChat(categoryId, chatId, to)
}
function spectateCommunity(id, ensName) {
return communitiesModuleInst.spectateCommunity(id, ensName)
}
function prepareKeypairsForSigning(communityId, ensName, addressesToShare = [], airdropAddress = "", editMode = false) {
communitiesModuleInst.prepareKeypairsForSigning(communityId, ensName, JSON.stringify(addressesToShare), airdropAddress, editMode)
}
function signProfileKeypairAndAllNonKeycardKeypairs() {
communitiesModuleInst.signProfileKeypairAndAllNonKeycardKeypairs()
}
function signSharedAddressesForKeypair(keyUid) {
communitiesModuleInst.signSharedAddressesForKeypair(keyUid)
}
function joinCommunityOrEditSharedAddresses() {
communitiesModuleInst.joinCommunityOrEditSharedAddresses()
}
function cleanJoinEditCommunityData() {
communitiesModuleInst.cleanJoinEditCommunityData()
}
function userCanJoin(id) {
return communitiesModuleInst.userCanJoin(id)
}
function isUserMemberOfCommunity(id) {
return communitiesModuleInst.isUserMemberOfCommunity(id)
}
function isMyCommunityRequestPending(id) {
return communitiesModuleInst.isMyCommunityRequestPending(id)
}
function cancelPendingRequest(id: string) {
communitiesModuleInst.cancelRequestToJoinCommunity(id)
}
function getSectionNameById(id) {
return communitiesList.getSectionNameById(id)
}
function getSectionByIdJson(id) {
return communitiesList.getSectionByIdJson(id)
}
// intervals is a string containing json array [{startTimestamp: 1690548852, startTimestamp: 1690547684}, {...}]
function collectCommunityMetricsMessagesTimestamps(intervals) {
chatCommunitySectionModule.collectCommunityMetricsMessagesTimestamps(intervals)
}
function collectCommunityMetricsMessagesCount(intervals) {
chatCommunitySectionModule.collectCommunityMetricsMessagesCount(intervals)
}
function requestCommunityInfo(id, shardCluster, shardIndex, importing = false) {
communitiesModuleInst.requestCommunityInfo(id, shardCluster, shardIndex, importing)
}
function getCommunityDetailsAsJson(id) {
const jsonObj = communitiesModuleInst.getCommunityDetails(id)
try {
return JSON.parse(jsonObj)
}
catch (e) {
console.warn("error parsing community by id: ", id, " error: ", e.message)
return {}
}
}
function getChatDetails(id) {
const jsonObj = activityCenterModule.getChatDetailsAsJson(id)
try {
return JSON.parse(jsonObj)
}
catch (e) {
console.warn("error parsing chat by id: ", id, " error: ", e.message)
return {}
}
}
function getPubkey() {
return userProfile.getPubKey()
}
// Needed for TX in chat for stickers and via contact
readonly property var accounts: walletSectionAccounts.accounts
property string currentCurrency: walletSection.currentCurrency
property CurrenciesStore currencyStore: CurrenciesStore {}
property var savedAddressesModel: walletSectionSavedAddresses.model
property var disabledChainIdsFromList: []
property var disabledChainIdsToList: []
function addRemoveDisabledFromChain(chainID, isDisabled) {
if(isDisabled) {
disabledChainIdsFromList.push(chainID)
}
else {
for(var i = 0; i < disabledChainIdsFromList.length;i++) {
if(disabledChainIdsFromList[i] === chainID) {
disabledChainIdsFromList.splice(i, 1)
}
}
}
}
function addRemoveDisabledToChain(chainID, isDisabled) {
if(isDisabled) {
disabledChainIdsToList.push(chainID)
}
else {
for(var i = 0; i < disabledChainIdsToList.length;i++) {
if(disabledChainIdsToList[i] === chainID) {
disabledChainIdsToList.splice(i, 1)
}
}
}
}
function getFiatValue(balance, cryptoSymbol, fiatSymbol) {
return profileSectionModule.ensUsernamesModule.getFiatValue(balance, cryptoSymbol, fiatSymbol)
}
function acceptRequestTransaction(transactionHash, messageId, signature) {
return currentChatContentModule().inputAreaModule.acceptRequestTransaction(transactionHash, messageId, signature)
}
function acceptAddressRequest(messageId, address) {
currentChatContentModule().inputAreaModule.acceptAddressRequest(messageId, address)
}
function declineAddressRequest(messageId) {
currentChatContentModule().inputAreaModule.declineAddressRequest(messageId)
}
function declineRequest(messageId) {
currentChatContentModule().inputAreaModule.declineRequest(messageId)
}
function getGasEthValue(gweiValue, gasLimit) {
return profileSectionModule.ensUsernamesModule.getGasEthValue(gweiValue, gasLimit)
}
function resolveENS(value) {
mainModuleInst.resolveENS(value, "")
}
function getWei2Eth(wei) {
return globalUtilsInst.wei2Eth(wei,18)
}
function getEtherscanLink() {
return profileSectionModule.ensUsernamesModule.getEtherscanLink()
}
function getLoginType() {
if(!userProfileInst)
return Constants.LoginType.Password
if(userProfileInst.usingBiometricLogin)
return Constants.LoginType.Biometrics
if(userProfileInst.isKeycardUser)
return Constants.LoginType.Keycard
return Constants.LoginType.Password
}
readonly property Connections communitiesModuleConnections: Connections {
target: communitiesModuleInst
function onImportingCommunityStateChanged(communityId, state, errorMsg) {
root.importingCommunityStateChanged(communityId, state, errorMsg)
}
function onCommunityAccessRequested(communityId) {
root.communityAccessRequested(communityId)
}
function onCommunityAdded(communityId) {
root.communityAdded(communityId)
}
}
readonly property Connections mainModuleInstConnections: Connections {
target: mainModuleInst
enabled: !!chatCommunitySectionModule
function onOpenCommunityMembershipRequestsView(sectionId: string) {
if(root.getMySectionId() !== sectionId)
return
root.goToMembershipRequestsPage()
}
}
readonly property QtObject _d: QtObject {
id: _d
readonly property var sectionDetailsInstantiator: Instantiator {
model: SortFilterProxyModel {
sourceModel: mainModuleInst.sectionsModel
filters: ValueFilter {
roleName: "id"
value: chatCommunitySectionModule.getMySectionId()
}
}
delegate: QtObject {
readonly property string id: model.id
readonly property int sectionType: model.sectionType
readonly property string name: model.name
readonly property string image: model.image
readonly property bool joined: model.joined
readonly property bool amIBanned: model.amIBanned
readonly property string introMessage: model.introMessage
// add others when needed..
}
}
readonly property string activeChatId: chatCommunitySectionModule && chatCommunitySectionModule.activeItem ? chatCommunitySectionModule.activeItem.id : ""
readonly property int activeChatType: chatCommunitySectionModule && chatCommunitySectionModule.activeItem ? chatCommunitySectionModule.activeItem.type : -1
readonly property bool amIMember: chatCommunitySectionModule ? chatCommunitySectionModule.amIMember : false
property var oneToOneChatContact: undefined
readonly property string oneToOneChatContactName: !!_d.oneToOneChatContact ? ProfileUtils.displayName(_d.oneToOneChatContact.localNickname,
_d.oneToOneChatContact.name,
_d.oneToOneChatContact.displayName,
_d.oneToOneChatContact.alias) : ""
//Update oneToOneChatContact when the contact is updated
readonly property var myContactsModelConnection: Connections {
target: root.contactsStore.myContactsModel ?? null
enabled: _d.activeChatType === Constants.chatType.oneToOne
function onItemChanged(pubKey) {
if (pubKey === _d.activeChatId) {
_d.oneToOneChatContact = Utils.getContactDetailsAsJson(pubKey, false)
}
}
}
readonly property var receivedContactsReqModelConnection: Connections {
target: root.contactsStore.receivedContactRequestsModel ?? null
enabled: _d.activeChatType === Constants.chatType.oneToOne
function onItemChanged(pubKey) {
if (pubKey === _d.activeChatId) {
_d.oneToOneChatContact = Utils.getContactDetailsAsJson(pubKey, false)
}
}
}
readonly property var sentContactReqModelConnection: Connections {
target: root.contactsStore.sentContactRequestsModel ?? null
enabled: _d.activeChatType === Constants.chatType.oneToOne
function onItemChanged(pubKey) {
if (pubKey === _d.activeChatId) {
_d.oneToOneChatContact = Utils.getContactDetailsAsJson(pubKey, false)
}
}
}
readonly property bool isUserAllowedToSendMessage: {
if (_d.activeChatType === Constants.chatType.oneToOne && _d.oneToOneChatContact) {
return _d.oneToOneChatContact.contactRequestState === Constants.ContactRequestState.Mutual
} else if (_d.activeChatType === Constants.chatType.privateGroupChat) {
return _d.amIMember
} else if (_d.activeChatType === Constants.chatType.communityChat) {
return currentChatContentModule().chatDetails.canPost
}
return true
}
readonly property string chatInputPlaceHolderText: {
if(!_d.isUserAllowedToSendMessage && _d.activeChatType === Constants.chatType.privateGroupChat) {
return qsTr("You need to be a member of this group to send messages")
} else if(!_d.isUserAllowedToSendMessage && _d.activeChatType === Constants.chatType.oneToOne) {
return qsTr("Add %1 as a contact to send a message").arg(_d.oneToOneChatContactName)
}
return qsTr("Message")
}
//Update oneToOneChatContact when activeChat id changes
Binding on oneToOneChatContact {
when: _d.activeChatId && _d.activeChatType === Constants.chatType.oneToOne
value: Utils.getContactDetailsAsJson(_d.activeChatId, false)
restoreMode: Binding.RestoreBindingOrValue
}
}
function updatePermissionsModel(communityId, sharedAddresses) {
communitiesModuleInst.checkPermissions(communityId, JSON.stringify(sharedAddresses))
}
feature: add remove from group option to group chats feature: add remove from group option to group chats refactor ProfileContextMenu to make it a functional component refactor ProfileContextMenu to make it a functional component This refactor ProfileContextMenu to make it a functional component by: refactored out direct calls to backend, and passing backend data structures and moved this logic to the callers, also refactored common calls between the callers common types of context menus have been extracted to their sub components which removes a lot of logic too and makes the behaviour very clear user verification workflow (which was already disabled) has been removed refactor: use signals and call singletons on the parent instead remove unused code for now from profile context menu refactor profile context menu into two components; add property to storybook extract blocked profile context menu and self profile context menu use profileType instead of individual bools refactor to pass trustStatus as an argument make contact type a parameter remove unnecessary method from RegularProfileContextMenu add ensVerified property to ProfileContextMenu components add onlineStatus property to ProfileContextMenu components move ProfileContextMenu storybook controls to the right sidebar move contactDetails logic up from the view add local nickname property to ProfileContextMenu components fix issue with missing signal; fix logs in storybook use constant for profileType instead of string refactor common code into a single method refactor getProfileContext remove references to contactDetails which are not longer needed remove unnecessary comments fix bridged constant refactor into a single ProfileContextMenu component refactor into a single ProfileContextMenu component refactor into a single ProfileContextMenu component simplify imports remove unused store field move methods from utils to contacts store remove onClosed signal remove unused param feature: add remove from group option to group chats feature: add remove from group option to group chats add isAdmin property move removeMemberFromGroupChat to root store hide remove from group option from message context menu
2024-09-06 15:55:44 +00:00
function removeMemberFromGroupChat(publicKey) {
const chatId = chatCommunitySectionModule.activeItem.id
chatCommunitySectionModule.removeMemberFromGroupChat("", chatId, publicKey)
}
}