mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 21:33:26 +00:00
Invite people in an existing room (#915)
* Handle power levels * Add “invite” button in RoomMembersListScreen * Refactor DI in RoomDetailsScreenCoordinator * Add navigation to “select people” coordinator * Add InviteUsersScreenRoomContext * Add invite user by id api * Updare InviteUsersScreenRoomContext * Support disabled state on FormButtonStyles * Handle membership in UserProfileCell * Fix conflicts * Refactor RoomContext -> RoomType * Refactor UserProfileCell * Add invite action * Setup navigation to user flow coordinator * Add invite logic * Fix test build errors * Address comments * Fix localisations * Update required state * Handle error * Move invite logic in RoomDetailsScreenCoordinator * Add navigation from room’s members list * Fix UTs * Fix missing display name in RoomMemberDetails * Add user indicator * Add feature flag * Add RoomDetailsViewModel UTs * Add room details ui tests * Add InviteUsersViewModelTests UTs * Add UI tests * Update UI tests * Empty commit
This commit is contained in:
+5
-1
@@ -22,7 +22,9 @@ struct RoomMembersListScreenCoordinatorParameters {
|
||||
let members: [RoomMemberProxyProtocol]
|
||||
}
|
||||
|
||||
enum RoomMembersListScreenCoordinatorAction { }
|
||||
enum RoomMembersListScreenCoordinatorAction {
|
||||
case invite
|
||||
}
|
||||
|
||||
final class RoomMembersListScreenCoordinator: CoordinatorProtocol {
|
||||
private let parameters: RoomMembersListScreenCoordinatorParameters
|
||||
@@ -45,6 +47,8 @@ final class RoomMembersListScreenCoordinator: CoordinatorProtocol {
|
||||
switch action {
|
||||
case let .selectMember(member):
|
||||
self.selectMember(member)
|
||||
case .invite:
|
||||
callback?(.invite)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,11 +18,13 @@ import Foundation
|
||||
|
||||
enum RoomMembersListScreenViewModelAction {
|
||||
case selectMember(_ member: RoomMemberProxyProtocol)
|
||||
case invite
|
||||
}
|
||||
|
||||
struct RoomMembersListScreenViewState: BindableState {
|
||||
private var joinedMembers: [RoomMemberDetails]
|
||||
private var invitedMembers: [RoomMemberDetails]
|
||||
var canInviteUsers = false
|
||||
var bindings: RoomMembersListScreenViewStateBindings
|
||||
|
||||
init(joinedMembers: [RoomMemberDetails] = [], invitedMembers: [RoomMemberDetails] = [], bindings: RoomMembersListScreenViewStateBindings = .init()) {
|
||||
@@ -59,6 +61,7 @@ struct RoomMembersListScreenViewStateBindings {
|
||||
|
||||
enum RoomMembersListScreenViewAction {
|
||||
case selectMember(id: String)
|
||||
case invite
|
||||
}
|
||||
|
||||
private extension RoomMemberDetails {
|
||||
|
||||
+32
-12
@@ -29,7 +29,7 @@ class RoomMembersListScreenViewModel: RoomMembersListScreenViewModelType, RoomMe
|
||||
self.members = members
|
||||
super.init(initialViewState: .init(), imageProvider: mediaProvider)
|
||||
|
||||
buildMembersDetails(members: members)
|
||||
setupState(members: members)
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
@@ -42,12 +42,14 @@ class RoomMembersListScreenViewModel: RoomMembersListScreenViewModelType, RoomMe
|
||||
return
|
||||
}
|
||||
callback?(.selectMember(member))
|
||||
case .invite:
|
||||
callback?(.invite)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
func buildMembersDetails(members: [RoomMemberProxyProtocol]) {
|
||||
private func setupState(members: [RoomMemberProxyProtocol]) {
|
||||
Task {
|
||||
let indicatorId = UUID().uuidString
|
||||
defer {
|
||||
@@ -55,24 +57,42 @@ class RoomMembersListScreenViewModel: RoomMembersListScreenViewModelType, RoomMe
|
||||
}
|
||||
ServiceLocator.shared.userIndicatorController.submitIndicator(UserIndicator(id: indicatorId, type: .modal, title: L10n.commonLoading, persistent: true))
|
||||
|
||||
let (invitedMembers, joinedMembers) = await split(members: members)
|
||||
self.state = .init(joinedMembers: joinedMembers, invitedMembers: invitedMembers)
|
||||
let roomMembersDetails = await buildMembersDetails(members: members)
|
||||
self.state = .init(joinedMembers: roomMembersDetails.joinedMembers, invitedMembers: roomMembersDetails.invitedMembers)
|
||||
self.state.canInviteUsers = roomMembersDetails.accountOwner?.canInviteUsers ?? false
|
||||
}
|
||||
}
|
||||
|
||||
func split(members: [RoomMemberProxyProtocol]) async -> (invited: [RoomMemberDetails], joined: [RoomMemberDetails]) {
|
||||
private func buildMembersDetails(members: [RoomMemberProxyProtocol]) async -> RoomMembersDetails {
|
||||
await Task.detached {
|
||||
// accessing RoomMember's properties is very slow. We need to do it in a background thread.
|
||||
let invitedMembers = members
|
||||
.filter { $0.membership == .invite }
|
||||
.map(RoomMemberDetails.init(withProxy:))
|
||||
var invitedMembers: [RoomMemberDetails] = .init()
|
||||
var joinedMembers: [RoomMemberDetails] = .init()
|
||||
var accountOwner: RoomMemberProxyProtocol?
|
||||
|
||||
let joinedMembers = members
|
||||
.filter { $0.membership == .join }
|
||||
.map(RoomMemberDetails.init(withProxy:))
|
||||
for member in members {
|
||||
if accountOwner == nil, member.isAccountOwner {
|
||||
accountOwner = member
|
||||
}
|
||||
|
||||
switch member.membership {
|
||||
case .invite:
|
||||
invitedMembers.append(.init(withProxy: member))
|
||||
case .join:
|
||||
joinedMembers.append(.init(withProxy: member))
|
||||
default:
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return (invitedMembers, joinedMembers)
|
||||
return .init(invitedMembers: invitedMembers, joinedMembers: joinedMembers, accountOwner: accountOwner)
|
||||
}
|
||||
.value
|
||||
}
|
||||
}
|
||||
|
||||
private struct RoomMembersDetails {
|
||||
var invitedMembers: [RoomMemberDetails]
|
||||
var joinedMembers: [RoomMemberDetails]
|
||||
var accountOwner: RoomMemberProxyProtocol?
|
||||
}
|
||||
|
||||
@@ -34,6 +34,11 @@ struct RoomMembersListScreen: View {
|
||||
.background(Color.element.background.ignoresSafeArea())
|
||||
.navigationTitle(L10n.commonPeople)
|
||||
.alert(item: $context.alertInfo) { $0.alert }
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .confirmationAction) {
|
||||
inviteButton
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
@@ -53,6 +58,17 @@ struct RoomMembersListScreen: View {
|
||||
}
|
||||
.padding(.horizontal)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var inviteButton: some View {
|
||||
if context.viewState.canInviteUsers, ServiceLocator.shared.settings.inviteMorePeopleFlowEnabled {
|
||||
Button {
|
||||
context.send(viewAction: .invite)
|
||||
} label: {
|
||||
Text(L10n.actionInvite)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Previews
|
||||
|
||||
Reference in New Issue
Block a user