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:
Alfonso Grillo
2023-05-22 16:03:07 +02:00
committed by GitHub
parent 8ed8cf6f0c
commit d9e0f36aeb
58 changed files with 708 additions and 172 deletions
@@ -44,7 +44,8 @@ enum FormRowAccessory: View {
/// to change the background colour depending on whether the button is currently pressed or not.
struct FormButtonStyle: PrimitiveButtonStyle {
var iconAlignment: VerticalAlignment = .firstTextBaseline
/// Disables the button while providing an entry point for UI customizations
var isDisabled = false
/// An accessory to be added on the trailing side of the row.
var accessory: FormRowAccessory?
@@ -54,12 +55,14 @@ struct FormButtonStyle: PrimitiveButtonStyle {
.labelStyle(FormRowLabelStyle(alignment: iconAlignment, role: configuration.role))
.frame(maxHeight: .infinity) // Make sure the label fills the cell vertically.
}
.buttonStyle(Style(accessory: accessory))
.buttonStyle(Style(isDisabled: isDisabled, accessory: accessory))
.listRowInsets(EdgeInsets()) // Remove insets so the background fills the cell.
.disabled(isDisabled)
}
/// Inner style used to set the pressed background colour.
struct Style: ButtonStyle {
var isDisabled: Bool
var accessory: FormRowAccessory?
func makeBody(configuration: Configuration) -> some View {
@@ -70,6 +73,7 @@ struct FormButtonStyle: PrimitiveButtonStyle {
.frame(maxWidth: .infinity, alignment: .leading)
accessory
.opacity(isDisabled ? 0.54 : 1)
}
.contentShape(Rectangle())
.padding(FormRow.insets) // Re-apply the normal insets using padding.
@@ -132,7 +136,15 @@ struct FormButtonStyles_Previews: PreviewProvider {
}
.buttonStyle(FormButtonStyle())
Button { } label: {
Text("Selection")
Text("Selected")
}
.buttonStyle(FormButtonStyle(accessory: .selection(isSelected: true)))
Button { } label: {
Text("Selected (disabled)")
}
.buttonStyle(FormButtonStyle(isDisabled: true, accessory: .selection(isSelected: true)))
Button { } label: {
Text("Unselected")
}
.buttonStyle(FormButtonStyle(accessory: .selection(isSelected: false)))
}
@@ -14,10 +14,12 @@
// limitations under the License.
//
import MatrixRustSDK
import SwiftUI
struct UserProfileCell: View {
let user: UserProfile
let membership: MembershipState?
let imageProvider: ImageProviderProtocol?
var body: some View {
@@ -35,25 +37,92 @@ struct UserProfileCell: View {
.font(.compound.headingSM)
.foregroundColor(.element.primaryContent)
if user.displayName != nil {
Text(user.userID)
.font(.compound.bodyMD)
.foregroundColor(.element.tertiaryContent)
}
subtitleContent
if !user.isVerified {
HStack(alignment: .firstTextBaseline, spacing: 4) {
Text(Image(systemName: "exclamationmark.circle.fill"))
.foregroundColor(.compound.textCriticalPrimary)
Text(L10n.screenStartChatUnknownProfile)
.foregroundColor(.secondary)
}
.font(.compound.bodyXS)
.padding(.top, 4)
}
warningContent
}
.accessibilityElement(children: .combine)
}
}
// MARK: - Private
@ViewBuilder
private var subtitleContent: some View {
if let membershipText = membership?.localizedDescription {
Text(membershipText)
.font(.compound.bodyMD)
.foregroundColor(.element.tertiaryContent)
} else if user.displayName != nil {
Text(user.userID)
.font(.compound.bodyMD)
.foregroundColor(.element.tertiaryContent)
}
}
@ViewBuilder
private var warningContent: some View {
if !user.isVerified, membership == nil {
HStack(alignment: .firstTextBaseline, spacing: 4) {
Text(Image(systemName: "exclamationmark.circle.fill"))
.foregroundColor(.compound.textCriticalPrimary)
Text(L10n.screenStartChatUnknownProfile)
.foregroundColor(.secondary)
}
.font(.compound.bodyXS)
.padding(.top, 4)
}
}
}
private extension MembershipState {
var localizedDescription: String? {
switch self {
case .join:
return L10n.screenRoomDetailsAlreadyAMember
case .invite:
return L10n.screenRoomDetailsAlreadyInvited
default:
return nil
}
}
}
struct UserProfileCell_Previews: PreviewProvider {
static let action: () -> Void = { }
static var previews: some View {
Form {
Button(action: action) {
UserProfileCell(user: .mockAlice, membership: nil, imageProvider: MockMediaProvider())
}
.buttonStyle(FormButtonStyle(accessory: .selection(isSelected: true)))
.previewDisplayName("Selected user")
Button(action: action) {
UserProfileCell(user: .mockBob, membership: nil, imageProvider: MockMediaProvider())
}
.buttonStyle(FormButtonStyle(accessory: .selection(isSelected: false)))
.previewDisplayName("Unselected user")
Button(action: action) {
UserProfileCell(user: .mockCharlie, membership: .join, imageProvider: MockMediaProvider())
}
.buttonStyle(FormButtonStyle(isDisabled: true, accessory: .selection(isSelected: true)))
.previewDisplayName("Selected disabled user")
Button(action: action) {
UserProfileCell(user: .init(userID: "@someone:matrix.org"), membership: .join, imageProvider: MockMediaProvider())
}
.buttonStyle(FormButtonStyle(isDisabled: true, accessory: .selection(isSelected: true)))
.previewDisplayName("Unverified joined user")
Button(action: action) {
UserProfileCell(user: .init(userID: "@someone:matrix.org"), membership: nil, imageProvider: MockMediaProvider())
}
.buttonStyle(FormButtonStyle(accessory: .selection(isSelected: false)))
.previewDisplayName("Unverified user")
}
}
}