fix(@desktop/communities): request to join fixes (#14287)

This commit is contained in:
Mykhailo Prakhov 2024-04-04 18:03:10 +02:00 committed by GitHub
parent 6762630e51
commit 1e155046e7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 114 additions and 65 deletions

View File

@ -16,6 +16,7 @@ import ../../../../app_service/service/token/service as token_service
import ../../../../app_service/service/community_tokens/service as community_tokens_service
import ../../../../app_service/service/visual_identity/service as procs_from_visual_identity_service
import ../../../../app_service/service/shared_urls/service as shared_urls_service
import ../../../../app_service/common/types
import backend/collectibles as backend_collectibles
import ../../../core/signals/types
@ -411,6 +412,16 @@ proc init*(self: Controller) =
continue
self.delegate.onCommunityMemberMessagesDeleted(messagesIds)
self.events.on(SIGNAL_COMMUNITY_MY_REQUEST_ADDED) do(e:Args):
let args = CommunityRequestArgs(e)
if args.communityRequest.communityId == self.sectionId:
self.delegate.updateRequestToJoinState(RequestToJoinState.Requested)
self.events.on(SIGNAL_REQUEST_TO_JOIN_COMMUNITY_CANCELED) do(e:Args):
let args = community_service.CommunityIdArgs(e)
if args.communityId == self.sectionId:
self.delegate.updateRequestToJoinState(RequestToJoinState.None)
proc isCommunity*(self: Controller): bool =
return self.isCommunitySection
@ -750,3 +761,6 @@ proc getWalletAccounts*(self: Controller): seq[wallet_account_service.WalletAcco
proc deleteCommunityMemberMessages*(self: Controller, memberPubKey: string, messageId: string, chatId: string) =
self.messageService.deleteCommunityMemberMessages(self.getMySectionId(), memberPubKey, messageId, chatId)
proc isMyCommunityRequestPending*(self: Controller): bool =
return self.communityService.isMyCommunityRequestPending(self.sectionId)

View File

@ -9,6 +9,7 @@ import ../../../../app_service/service/message/service as message_service
import ../../../../app_service/service/gif/service as gif_service
import ../../../../app_service/service/mailservers/service as mailservers_service
import ../../../../app_service/service/shared_urls/service as shared_urls_service
import ../../../../app_service/common/types
import model as chats_model
import item as chat_item
@ -421,3 +422,6 @@ method communityContainsChat*(self: AccessInterface, chatId: string): bool {.bas
method openCommunityChatAndScrollToMessage*(self: AccessInterface, chatId: string, messageId: string) {.base.} =
raise newException(ValueError, "No implementation available")
method updateRequestToJoinState*(self: AccessInterface, state: RequestToJoinState) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -443,6 +443,11 @@ method onChatsLoaded*(
let community = self.controller.getMyCommunity()
self.view.setAmIMember(community.joined)
self.view.setWaitingOnNewCommunityOwnerToConfirmRequestToRejoin(self.controller.waitingOnNewCommunityOwnerToConfirmRequestToRejoin(community.id))
var requestToJoinState = RequestToJoinState.None
if self.controller.isMyCommunityRequestPending():
requestToJoinState = RequestToJoinState.Requested
self.view.setRequestToJoinState(requestToJoinState)
self.initCommunityTokenPermissionsModel(channelGroup)
self.onCommunityCheckAllChannelsPermissionsResponse(channelGroup.channelPermissions)
self.controller.asyncCheckPermissionsToJoin()
@ -1050,6 +1055,7 @@ method onJoinedCommunity*(self: Module) =
self.rebuildCommunityTokenPermissionsModel()
self.view.setAmIMember(true)
self.view.setWaitingOnNewCommunityOwnerToConfirmRequestToRejoin(false)
self.view.setRequestToJoinState(RequestToJoinState.None)
method onMarkAllMessagesRead*(self: Module, chat: ChatDto) =
self.updateBadgeNotifications(chat, hasUnreadMessages=false, unviewedMentionsCount=0)
@ -1555,3 +1561,6 @@ method openCommunityChatAndScrollToMessage*(self: Module, chatId: string, messag
if chatId in self.chatContentModules:
self.setActiveItem(chatId)
self.chatContentModules[chatId].scrollToMessage(messageId)
method updateRequestToJoinState*(self: Module, state: RequestToJoinState) =
self.view.setRequestToJoinState(state)

View File

@ -4,6 +4,7 @@ import item, active_item
import ../../shared_models/user_model as user_model
import ../../shared_models/message_model as member_msg_model
import ../../shared_models/token_permissions_model
import ../../../../app_service/common/types
import io_interface
QtObject:
@ -35,6 +36,7 @@ QtObject:
allChannelsAreHiddenBecauseNotPermitted: bool
memberMessagesModel: member_msg_model.Model
memberMessagesModelVariant: QVariant
requestToJoinState: RequestToJoinState
proc delete*(self: View) =
@ -79,6 +81,7 @@ QtObject:
result.isWaitingOnNewCommunityOwnerToConfirmRequestToRejoin = false
result.memberMessagesModel = member_msg_model.newModel()
result.memberMessagesModelVariant = newQVariant(result.memberMessagesModel)
result.requestToJoinState = RequestToJoinState.None
proc load*(self: View) =
self.delegate.viewDidLoad()
@ -534,3 +537,18 @@ QtObject:
proc openCommunityChatAndScrollToMessage*(self: View, chatId: string, messageId: string) {.slot.} =
self.delegate.openCommunityChatAndScrollToMessage(chatId, messageId)
proc requestToJoinStateChanged*(self: View) {.signal.}
proc getRequestToJoinState*(self: View): int {.slot.} =
return self.requestToJoinState.int
QtProperty[int] requestToJoinState:
read = getRequestToJoinState
notify = requestToJoinStateChanged
proc setRequestToJoinState*(self: View, requestToJoinState: RequestToJoinState) =
if self.requestToJoinState == requestToJoinState:
return
self.requestToJoinState = requestToJoinState
self.requestToJoinStateChanged()

View File

@ -357,6 +357,7 @@ method communityAccessRequested*(self: Module, communityId: string) =
method communityAccessFailed*(self: Module, communityId, err: string) =
error "communities: ", err
self.cleanJoinEditCommunityData()
self.delegate.updateRequestToJoinState(communityId, RequestToJoinState.None)
self.view.communityAccessFailed(communityId, err)
method communityEditSharedAddressesSucceeded*(self: Module, communityId: string) =
@ -843,6 +844,9 @@ method joinCommunityOrEditSharedAddresses*(self: Module) =
addressesToShare,
airdropAddress,
signatures)
self.delegate.updateRequestToJoinState(self.joiningCommunityDetails.communityId, RequestToJoinState.InProgress)
# The user reveals address after sending join coummunity request, before that he sees only the name of the wallet account, not the address.
self.events.emit(MARK_WALLET_ADDRESSES_AS_SHOWN, WalletAddressesArgs(addresses: addressesToShare))
return

View File

@ -16,7 +16,7 @@ import app_service/service/community_tokens/community_collectible_owner
import app_service/service/shared_urls/service as urls_service
import app_service/service/network/service as network_service
import app_service/service/network/network_item
from app_service/common/types import StatusType, ContractTransactionStatus, MembershipRequestState, Shard
from app_service/common/types import StatusType, ContractTransactionStatus, MembershipRequestState, Shard, RequestToJoinState
import app/global/app_signals
import app/core/eventemitter
@ -424,6 +424,9 @@ method checkIfAddressWasCopied*(self: AccessInterface, value: string) {.base.} =
method openSectionChatAndMessage*(self: AccessInterface, sectionId: string, chatId: string, messageId: string) {.base.} =
raise newException(ValueError, "No implementation available")
method updateRequestToJoinState*(self: AccessInterface, sectionId: string, requestToJoinState: RequestToJoinState) {.base.} =
raise newException(ValueError, "No implementation available")
# This way (using concepts) is used only for the modules managed by AppController
type
DelegateInterface* = concept c

View File

@ -351,7 +351,7 @@ proc createChannelGroupItem[T](self: Module[T], channelGroup: ChannelGroupDto):
let state = memberState.toMembershipRequestState()
case state:
of MembershipRequestState.Banned, MembershipRequestState.BannedWithAllMessagesDelete, MembershipRequestState.UnbannedPending:
bannedMembers.add(self.createMemberItem(memberId, state, MemberRole.None))
bannedMembers.add(self.createMemberItem(memberId, "", state, MemberRole.None))
else:
discard
@ -393,7 +393,7 @@ proc createChannelGroupItem[T](self: Module[T], channelGroup: ChannelGroupDto):
elif not member.joined:
state = MembershipRequestState.AwaitingAddress
result = self.createMemberItem(member.id, state, member.role)
result = self.createMemberItem(member.id, "", state, member.role)
),
# pendingRequestsToJoin
if (isCommunity): communityDetails.pendingRequestsToJoin.map(x => pending_request_item.initItem(
@ -409,11 +409,11 @@ proc createChannelGroupItem[T](self: Module[T], channelGroup: ChannelGroupDto):
bannedMembers,
# pendingMemberRequests
if (isCommunity): communityDetails.pendingRequestsToJoin.map(proc(requestDto: CommunityMembershipRequestDto): MemberItem =
result = self.createMemberItem(requestDto.publicKey, MembershipRequestState(requestDto.state), MemberRole.None)
result = self.createMemberItem(requestDto.publicKey, requestDto.id, MembershipRequestState(requestDto.state), MemberRole.None)
) else: @[],
# declinedMemberRequests
if (isCommunity): communityDetails.declinedRequestsToJoin.map(proc(requestDto: CommunityMembershipRequestDto): MemberItem =
result = self.createMemberItem(requestDto.publicKey, MembershipRequestState(requestDto.state), MemberRole.None)
result = self.createMemberItem(requestDto.publicKey, requestDto.id, MembershipRequestState(requestDto.state), MemberRole.None)
) else: @[],
channelGroup.encrypted,
communityTokensItems,
@ -1393,8 +1393,7 @@ method ephemeralNotificationClicked*[T](self: Module[T], id: int64) =
self.osNotificationClicked(item.details)
method onMyRequestAdded*[T](self: Module[T]) =
self.displayEphemeralNotification("Your Request has been submitted", "" , "checkmark-circle", false, EphemeralNotificationType.Success.int, "")
self.displayEphemeralNotification("Your Request has been submitted", "" , "checkmark-circle", false, EphemeralNotificationType.Success.int, "")
proc switchToContactOrDisplayUserProfile[T](self: Module[T], publicKey: string) =
let contact = self.controller.getContact(publicKey)
@ -1645,7 +1644,11 @@ method openSectionChatAndMessage*[T](self: Module[T], sectionId: string, chatId:
if sectionId in self.channelGroupModules:
self.channelGroupModules[sectionId].openCommunityChatAndScrollToMessage(chatId, messageId)
proc createMemberItem*[T](self: Module[T], memberId: string, state: MembershipRequestState, role: MemberRole): MemberItem =
method updateRequestToJoinState*[T](self: Module[T], sectionId: string, requestToJoinState: RequestToJoinState) =
if sectionId in self.channelGroupModules:
self.channelGroupModules[sectionId].updateRequestToJoinState(requestToJoinState)
proc createMemberItem*[T](self: Module[T], memberId: string, requestId: string, state: MembershipRequestState, role: MemberRole): MemberItem =
let contactDetails = self.controller.getContactDetails(memberId)
let status = self.controller.getStatusForContactWithId(memberId)
return initMemberItem(
@ -1663,6 +1666,7 @@ proc createMemberItem*[T](self: Module[T], memberId: string, state: MembershipRe
isVerified = contactDetails.dto.isContactVerified(),
memberRole = role,
membershipRequestState = state,
requestToJoinId = requestId
)
{.pop.}

View File

@ -91,3 +91,8 @@ type TokenType* {.pure.} = enum
ERC1155 = 3,
Unknown = 4,
ENS = 5
type RequestToJoinState* {.pure.} = enum
None = 0
InProgress
Requested

View File

@ -2055,7 +2055,7 @@ QtObject:
community.pendingRequestsToJoin.delete(i)
self.communities[communityId] = community
self.events.emit(SIGNAL_REQUEST_TO_JOIN_COMMUNITY_CANCELED, Args())
self.events.emit(SIGNAL_REQUEST_TO_JOIN_COMMUNITY_CANCELED, CommunityIdArgs(communityId: communityId))
checkAndEmitACNotificationsFromResponse(self.events, response.result{"activityCenterNotifications"})
return

View File

@ -38,7 +38,9 @@ Nemo enim 😋 ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
// Overlay component:
property bool requirementsMet: true
property bool isInvitationPending: true
property int requestToJoinState: Constants.RequestToJoinState.None
property bool isInvitationPending: requestToJoinState !== Constants.RequestToJoinState.None
property bool isJoinRequestRejected: false
property bool requiresRequest: false
@ -115,7 +117,7 @@ Nemo enim 😋 ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
channelDesc: d.channelDesc
joinCommunity: d.joinCommunity
accessType: d.accessType
isInvitationPending: d.isInvitationPending
requestToJoinState: d.requestToJoinState
// Blur background properties:
membersCount: d.membersCount
@ -226,12 +228,15 @@ Nemo enim 😋 ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
CheckBox {
checked: d.isInvitationPending
onCheckedChanged: d.isInvitationPending = checked
onCheckedChanged: {
d.isInvitationPending = checked
d.requestToJoinState = d.isInvitationPending ? Constants.RequestToJoinState.Requested : Constants.RequestToJoinState.None
}
}
}
ColumnLayout {
visible: !d.isInvitationPending
visible: d.requestToJoinState === Constants.RequestToJoinState.None
Label {
Layout.fillWidth: true
text: "Access type:"
@ -260,7 +265,7 @@ Nemo enim 😋 ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
channelName: d.chanelName
joinCommunity: d.joinCommunity
requirementsMet: d.requirementsMet
isInvitationPending: d.isInvitationPending
isInvitationPending: d.requestToJoinState !== Constants.RequestToJoinState.None
isJoinRequestRejected: d.isJoinRequestRejected
requiresRequest: d.requiresRequest

View File

@ -40,6 +40,7 @@ StackLayout {
readonly property bool isTokenMasterOwner: sectionItemModel.memberRole === Constants.memberRole.tokenMaster
readonly property bool isControlNode: sectionItemModel.isControlNode
readonly property bool isPrivilegedUser: isControlNode || isOwner || isAdmin || isTokenMasterOwner
readonly property int isInvitationPending: root.rootStore.chatCommunitySectionModule.requestToJoinState !== Constants.RequestToJoinState.None
property bool communitySettingsDisabled
@ -113,29 +114,20 @@ StackLayout {
viewAndPostHoldingsModel: root.permissionsStore.viewAndPostPermissionsModel
assetsModel: root.rootStore.assetsModel
collectiblesModel: root.rootStore.collectiblesModel
isInvitationPending: root.rootStore.isMyCommunityRequestPending(communityId)
requestToJoinState: root.rootStore.chatCommunitySectionModule.requestToJoinState
notificationCount: activityCenterStore.unreadNotificationsCount
hasUnseenNotifications: activityCenterStore.hasUnseenNotifications
openCreateChat: rootStore.openCreateChat
onNotificationButtonClicked: Global.openActivityCenterPopup()
onAdHocChatButtonClicked: rootStore.openCloseCreateChatView()
onRequestToJoinClicked: {
Global.communityIntroPopupRequested(joinCommunityView.communityId, communityData.name, communityData.introMessage,
communityData.image, root.rootStore.isMyCommunityRequestPending(communityId))
Global.communityIntroPopupRequested(joinCommunityView.communityId, communityData.name,
communityData.introMessage, communityData.image,
root.isInvitationPending)
}
onInvitationPendingClicked: {
Global.communityIntroPopupRequested(joinCommunityView.communityId, communityData.name, communityData.introMessage,
communityData.image, root.rootStore.isMyCommunityRequestPending(communityId))
joinCommunityView.isInvitationPending = root.rootStore.isMyCommunityRequestPending(communityId)
}
Connections {
target: root.rootStore.communitiesModuleInst
function onCommunityAccessRequested(communityId: string) {
if (communityId === joinCommunityView.communityId) {
joinCommunityView.isInvitationPending = root.rootStore.isMyCommunityRequestPending(communityId)
}
}
communityData.image, root.isInvitationPending)
}
}
}
@ -168,7 +160,7 @@ StackLayout {
viewAndPostPermissionsModel: root.permissionsStore.viewAndPostPermissionsModel
assetsModel: root.rootStore.assetsModel
collectiblesModel: root.rootStore.collectiblesModel
isInvitationPending: root.rootStore.isMyCommunityRequestPending(chatView.communityId)
requestToJoinState: sectionItem.requestToJoinState
isPendingOwnershipRequest: root.isPendingOwnershipRequest
@ -184,12 +176,11 @@ StackLayout {
}
onRequestToJoinClicked: {
Global.communityIntroPopupRequested(communityId, root.sectionItemModel.name, root.sectionItemModel.introMessage,
root.sectionItemModel.image, root.rootStore.isMyCommunityRequestPending(chatView.communityId))
root.sectionItemModel.image, root.isInvitationPending)
}
onInvitationPendingClicked: {
Global.communityIntroPopupRequested(communityId, root.sectionItemModel.name, root.sectionItemModel.introMessage,
root.sectionItemModel.image, root.rootStore.isMyCommunityRequestPending(chatView.communityId))
chatView.isInvitationPending = root.rootStore.isMyCommunityRequestPending(dialogRoot.communityId)
root.sectionItemModel.image, root.isInvitationPending)
}
}
}
@ -255,14 +246,4 @@ StackLayout {
onAdHocChatButtonClicked: rootStore.openCloseCreateChatView()
}
}
Connections {
target: root.rootStore
enabled: mainViewLoader.item
function onCommunityAccessRequested(communityId: string) {
if (communityId === mainViewLoader.item.communityId) {
mainViewLoader.item.isInvitationPending = root.rootStore.isMyCommunityRequestPending(communityId)
}
}
}
}

View File

@ -57,7 +57,7 @@ StatusSectionLayout {
property bool amISectionAdmin: false
readonly property bool allChannelsAreHiddenBecauseNotPermitted: rootStore.allChannelsAreHiddenBecauseNotPermitted
property bool isInvitationPending: false
property int requestToJoinState: Constants.RequestToJoinState.None
property var viewOnlyPermissionsModel
property var viewAndPostPermissionsModel
@ -258,7 +258,7 @@ StatusSectionLayout {
viewAndPostHoldingsModel: root.viewAndPostPermissionsModel
assetsModel: root.assetsModel
collectiblesModel: root.collectiblesModel
isInvitationPending: root.isInvitationPending
requestToJoinState: root.requestToJoinState
requiresRequest: !root.amIMember
requirementsMet: (viewOnlyPermissionsSatisfied && viewOnlyPermissionsModel.count > 0) ||
(viewAndPostPermissionsSatisfied && viewAndPostPermissionsModel.count > 0)

View File

@ -8,6 +8,8 @@ import StatusQ.Components 0.1
import StatusQ.Controls 0.1
import StatusQ.Layout 0.1
import utils 1.0
ColumnLayout {
id: root
@ -17,7 +19,7 @@ ColumnLayout {
property string name
property string channelName
property bool isInvitationPending: false
property int requestToJoinState: Constants.RequestToJoinState.None
property bool isJoinRequestRejected: false
property bool requiresRequest: false
@ -143,7 +145,7 @@ ColumnLayout {
allChannelsAreHiddenBecauseNotPermitted: root.allChannelsAreHiddenBecauseNotPermitted
requirementsMet: root.requirementsMet
requirementsCheckPending: root.requirementsCheckPending
isInvitationPending: root.isInvitationPending
requestToJoinState: root.requestToJoinState
isJoinRequestRejected: root.isJoinRequestRejected
requiresRequest: root.requiresRequest
communityName: root.name

View File

@ -23,7 +23,9 @@ Control {
property bool requirementsMet: false
property bool requirementsCheckPending: false
property bool requiresRequest: false
property bool isInvitationPending: false
property int requestToJoinState: Constants.RequestToJoinState.None
property bool isInvitationPending: root.requestToJoinState !== Constants.RequestToJoinState.None
property bool isJoinRequestRejected: false
property string communityName
property var communityHoldingsModel
@ -160,6 +162,7 @@ Control {
&& root.requiresRequest
&& !d.onlyPrivateNotMetPermissions
&& !root.allChannelsAreHiddenBecauseNotPermitted
loading: root.requestToJoinState === Constants.RequestToJoinState.InProgress
text: root.isInvitationPending ? (root.joinCommunity ? d.communityMembershipRequestPendingText : d.channelMembershipRequestPendingText)
: d.communityRequestToJoinText
font.pixelSize: 13

View File

@ -44,6 +44,8 @@ Item {
property var communityData
property alias createChannelPopup: createChannelPopup
property int requestToJoinState: Constants.RequestToJoinState.None
// Community transfer ownership related props:
required property bool isPendingOwnershipRequest
signal finaliseOwnershipClicked
@ -69,11 +71,8 @@ Item {
readonly property bool discordImportInProgress: (root.communitiesStore.discordImportProgress > 0 && root.communitiesStore.discordImportProgress < 100)
|| root.communitiesStore.discordImportInProgress
property bool invitationPending: root.store.isMyCommunityRequestPending(communityData.id)
property bool joiningCommunityInProgress: false
onShowJoinButtonChanged: invitationPending = root.store.isMyCommunityRequestPending(communityData.id)
readonly property int requestToJoinState: root.communitySectionModule.requestToJoinState
readonly property bool invitationPending: d.requestToJoinState !== Constants.RequestToJoinState.None
}
ColumnHeaderPanel {
@ -491,11 +490,11 @@ Item {
anchors.bottomMargin: Style.current.halfPadding
anchors.horizontalCenter: parent.horizontalCenter
enabled: !root.communityData.amIBanned
loading: d.joiningCommunityInProgress
loading: d.requestToJoinState === Constants.RequestToJoinState.InProgress
text: {
if (root.communityData.amIBanned) return qsTr("You were banned from community")
if (d.invitationPending) return qsTr("Membership request pending...")
if (d.requestToJoinState === Constants.RequestToJoinState.Requested) return qsTr("Membership request pending...")
return root.communityData.access === Constants.communityChatOnRequestAccess ?
qsTr("Request to join") : qsTr("Join Community")
@ -507,19 +506,11 @@ Item {
}
Connections {
enabled: d.joiningCommunityInProgress
enabled: d.showJoinButton
target: root.store.communitiesModuleInst
function onCommunityAccessRequested(communityId: string) {
if (communityId === root.communityData.id) {
d.invitationPending = root.store.isMyCommunityRequestPending(communityId)
d.joiningCommunityInProgress = false
}
}
function onCommunityAccessFailed(communityId: string, error: string) {
if (communityId === root.communityData.id) {
d.invitationPending = false
d.joiningCommunityInProgress = false
Global.displayToastMessage(qsTr("Request to join failed"),
qsTr("Please try again later"),
"",

View File

@ -30,7 +30,7 @@ StatusSectionLayout {
property string channelDesc
property bool joinCommunity: true // Otherwise it means join channel action
property int accessType
property bool isInvitationPending: false
property int requestToJoinState: Constants.RequestToJoinState.None
// Permission overlay view properties:
property bool requirementsMet: true
@ -128,7 +128,7 @@ StatusSectionLayout {
name: root.name
channelName: root.channelName
isInvitationPending: root.isInvitationPending
requestToJoinState: root.requestToJoinState
isJoinRequestRejected: root.isJoinRequestRejected
requiresRequest: root.requiresRequest
requirementsMet: root.requirementsMet

View File

@ -1300,4 +1300,10 @@ QtObject {
Collection = 2,
Community = 3
}
enum RequestToJoinState {
None = 0,
InProgress = 1,
Requested = 2
}
}