Rename SpaceRoomProxy to SpaceServiceRoom and stop proxying the struct. (#4952)

* Rename SpaceRoomProxy to SpaceServiceRoom.

The underlying type is a struct, we don't need to proxy it.

* Actually stop proxying the SpaceRoom.
This commit is contained in:
Doug
2026-01-13 12:00:20 +00:00
committed by GitHub
parent de1753a766
commit 334df3f5cd
43 changed files with 620 additions and 604 deletions
@@ -18,14 +18,14 @@ struct JoinRoomScreenCoordinatorParameters {
enum JoinRoomScreenSource {
case generic(roomID: String, via: [String])
case space(SpaceRoomProxyProtocol)
case space(SpaceServiceRoomProtocol)
func roomIDAndVia() -> (roomID: String, via: [String]) {
switch self {
case let .generic(roomID: roomID, via: via):
return (roomID: roomID, via: via)
case let .space(spaceRoomProxy):
return (roomID: spaceRoomProxy.id, via: spaceRoomProxy.via)
case let .space(spaceServiceRoom):
return (roomID: spaceServiceRoom.id, via: spaceServiceRoom.via)
}
}
}
@@ -49,7 +49,7 @@ struct JoinRoomScreenRoomDetails {
let isSpace: Bool?
let childrenCount: Int?
let spaceVisibility: SpaceRoomProxyVisibility?
let spaceVisibility: SpaceServiceRoomVisibility?
}
struct JoinRoomScreenViewState: BindableState {
@@ -172,8 +172,8 @@ class JoinRoomScreenViewModel: JoinRoomScreenViewModelType, JoinRoomScreenViewMo
switch source {
case .generic(let roomID, _):
await updateGenericRoomDetails(roomID: roomID, roomInfo: roomInfo, inviter: inviter)
case .space(let spaceRoomProxy):
await updateSpaceRoomDetails(spaceRoomProxy: spaceRoomProxy, inviter: inviter)
case .space(let spaceServiceRoom):
await updateSpaceRoomDetails(spaceServiceRoom: spaceServiceRoom, inviter: inviter)
}
await updateMode()
}
@@ -200,18 +200,18 @@ class JoinRoomScreenViewModel: JoinRoomScreenViewModelType, JoinRoomScreenViewMo
spaceVisibility: nil)
}
private func updateSpaceRoomDetails(spaceRoomProxy: SpaceRoomProxyProtocol, inviter: RoomInviterDetails?) async {
state.roomDetails = JoinRoomScreenRoomDetails(name: spaceRoomProxy.name,
topic: spaceRoomProxy.topic,
canonicalAlias: spaceRoomProxy.canonicalAlias,
avatar: spaceRoomProxy.avatar,
memberCount: spaceRoomProxy.joinedMembersCount,
heroes: spaceRoomProxy.heroes,
private func updateSpaceRoomDetails(spaceServiceRoom: SpaceServiceRoomProtocol, inviter: RoomInviterDetails?) async {
state.roomDetails = JoinRoomScreenRoomDetails(name: spaceServiceRoom.name,
topic: spaceServiceRoom.topic,
canonicalAlias: spaceServiceRoom.canonicalAlias,
avatar: spaceServiceRoom.avatar,
memberCount: spaceServiceRoom.joinedMembersCount,
heroes: spaceServiceRoom.heroes,
inviter: inviter,
isDirect: spaceRoomProxy.isDirect,
isSpace: spaceRoomProxy.isSpace,
childrenCount: spaceRoomProxy.childrenCount,
spaceVisibility: spaceRoomProxy.visibility)
isDirect: spaceServiceRoom.isDirect,
isSpace: spaceServiceRoom.isSpace,
childrenCount: spaceServiceRoom.childrenCount,
spaceVisibility: spaceServiceRoom.visibility)
}
private func updateMode() async {
@@ -225,16 +225,16 @@ class JoinRoomScreenViewModel: JoinRoomScreenViewModelType, JoinRoomScreenViewMo
return
}
if case .space(let spaceRoomProxy) = source {
switch spaceRoomProxy.state {
if case .space(let spaceServiceRoom) = source {
switch spaceServiceRoom.state {
case .invited:
state.mode = .invited(isDM: spaceRoomProxy.isDirect == true && spaceRoomProxy.joinedMembersCount == 1)
state.mode = .invited(isDM: spaceServiceRoom.isDirect == true && spaceServiceRoom.joinedMembersCount == 1)
case .knocked:
state.mode = .knocked
case .banned:
state.mode = .banned(sender: nil, reason: nil)
default:
switch spaceRoomProxy.joinRule {
switch spaceServiceRoom.joinRule {
case .private, .invite:
state.mode = .inviteRequired
case .knock, .knockRestricted:
@@ -445,7 +445,7 @@ struct JoinRoomScreenPreviewWrapper: Identifiable {
}
let source: JoinRoomScreenSource = if isSpace {
.space(SpaceRoomProxyMock(mode: mode))
.space(SpaceServiceRoomMock(mode: mode))
} else {
.generic(roomID: "1", via: [])
}
@@ -37,7 +37,7 @@ enum ManageAuthorizedSpacesScreenViewAction {
}
struct AuthorizedSpacesSelection {
let joinedSpaces: [SpaceRoomProxyProtocol]
let joinedSpaces: [SpaceServiceRoomProtocol]
let unknownSpacesIDs: [String]
let initialSelectedIDs: Set<String>
let selectedIDs: PassthroughSubject<Set<String>, Never> = .init()
@@ -77,7 +77,7 @@ struct ManageAuthorizedSpacesScreen: View {
}
}
private func avatar(space: SpaceRoomProxyProtocol) -> some View {
private func avatar(space: SpaceServiceRoomProtocol) -> some View {
RoomAvatarImage(avatar: space.avatar,
avatarSize: .room(on: .authorizedSpaces),
mediaProvider: context.mediaProvider)
@@ -32,7 +32,7 @@ struct SecurityAndPrivacyScreenViewState: BindableState {
var canEditHistoryVisibility = false
/// The union of joined parent spaces and the joined spaces in the current access type
var selectableJoinedSpaces: [SpaceRoomProxyProtocol] = []
var selectableJoinedSpaces: [SpaceServiceRoomProtocol] = []
/// The count of the intersection between the set of joined parent spaces and the set of spaces in the current access type
var selectableSpacesCount: Int {
@@ -118,7 +118,7 @@ struct SecurityAndPrivacyScreenViewState: BindableState {
enum SpaceSelection {
/// There is only one available parent space for selection and is joined by the user
case singleJoined(SpaceRoomProxyProtocol)
case singleJoined(SpaceServiceRoomProtocol)
/// There is only one available space for selection and is unknown to the user
case singleUnknown(id: String)
/// Multiple spaces are available for selection
@@ -305,7 +305,7 @@ class SecurityAndPrivacyScreenViewModel: SecurityAndPrivacyScreenViewModelType,
}
private func setupSelectableJoinedSpaces() async {
var joinedParentSpaces: [SpaceRoomProxyProtocol] = []
var joinedParentSpaces: [SpaceServiceRoomProtocol] = []
switch await clientProxy.spaceService.joinedParents(childID: roomProxy.id) {
case .success(let value):
joinedParentSpaces = value
@@ -313,7 +313,7 @@ class SecurityAndPrivacyScreenViewModel: SecurityAndPrivacyScreenViewModelType,
break
}
var nonParentJoinedSpaces: [SpaceRoomProxyProtocol] = []
var nonParentJoinedSpaces: [SpaceServiceRoomProtocol] = []
for spaceID in state.currentSettings.accessType.spaceIDs where !joinedParentSpaces.contains(where: { $0.id == spaceID }) {
if case let .success(.some(space)) = await clientProxy.spaceService.spaceForIdentifier(spaceID: spaceID) {
nonParentJoinedSpaces.append(space)
@@ -269,7 +269,7 @@ struct SecurityAndPrivacyScreen_Previews: PreviewProvider, TestablePreview {
AppSettings.resetAllSettings()
let appSettings = AppSettings()
appSettings.spaceSettingsEnabled = true
let space = [SpaceRoomProxyProtocol].mockSingleRoom[0]
let space = [SpaceServiceRoomProtocol].mockSingleRoom[0]
return SecurityAndPrivacyScreenViewModel(roomProxy: JoinedRoomProxyMock(.init(isEncrypted: false,
canonicalAlias: "#room:matrix.org",
@@ -286,7 +286,7 @@ struct SecurityAndPrivacyScreen_Previews: PreviewProvider, TestablePreview {
AppSettings.resetAllSettings()
let appSettings = AppSettings()
appSettings.spaceSettingsEnabled = true
let spaces = [SpaceRoomProxyProtocol].mockJoinedSpaces
let spaces = [SpaceServiceRoomProtocol].mockJoinedSpaces
return SecurityAndPrivacyScreenViewModel(roomProxy: JoinedRoomProxyMock(.init(isEncrypted: false,
canonicalAlias: "#room:matrix.org",
@@ -319,7 +319,7 @@ struct SecurityAndPrivacyScreen_Previews: PreviewProvider, TestablePreview {
let appSettings = AppSettings()
appSettings.spaceSettingsEnabled = true
appSettings.knockingEnabled = true
let space = [SpaceRoomProxyProtocol].mockSingleRoom[0]
let space = [SpaceServiceRoomProtocol].mockSingleRoom[0]
return SecurityAndPrivacyScreenViewModel(roomProxy: JoinedRoomProxyMock(.init(isEncrypted: false,
canonicalAlias: "#room:matrix.org",
@@ -337,7 +337,7 @@ struct SecurityAndPrivacyScreen_Previews: PreviewProvider, TestablePreview {
let appSettings = AppSettings()
appSettings.spaceSettingsEnabled = true
appSettings.knockingEnabled = true
let spaces = [SpaceRoomProxyProtocol].mockJoinedSpaces
let spaces = [SpaceServiceRoomProtocol].mockJoinedSpaces
return SecurityAndPrivacyScreenViewModel(roomProxy: JoinedRoomProxyMock(.init(isEncrypted: false,
canonicalAlias: "#room:matrix.org",
@@ -10,36 +10,36 @@ import Compound
import SwiftUI
struct SpaceHeaderView: View {
let spaceRoomProxy: SpaceRoomProxyProtocol
let spaceServiceRoom: SpaceServiceRoomProtocol
let mediaProvider: MediaProviderProtocol?
@State private var isPresentingTopic = false
var body: some View {
VStack(spacing: 16) {
RoomAvatarImage(avatar: spaceRoomProxy.avatar,
RoomAvatarImage(avatar: spaceServiceRoom.avatar,
avatarSize: .room(on: .spaceHeader),
mediaProvider: mediaProvider)
.accessibilityHidden(true)
VStack(spacing: 8) {
Text(spaceRoomProxy.name)
Text(spaceServiceRoom.name)
.font(.compound.headingLGBold)
.foregroundStyle(.compound.textPrimary)
.multilineTextAlignment(.center)
if let alias = spaceRoomProxy.canonicalAlias {
if let alias = spaceServiceRoom.canonicalAlias {
CopyTextButton(content: alias)
}
spaceDetails
JoinedMembersBadgeView(heroes: spaceRoomProxy.heroes,
joinedCount: spaceRoomProxy.joinedMembersCount,
JoinedMembersBadgeView(heroes: spaceServiceRoom.heroes,
joinedCount: spaceServiceRoom.joinedMembersCount,
mediaProvider: mediaProvider)
}
if let topic = spaceRoomProxy.topic {
if let topic = spaceServiceRoom.topic {
Button { isPresentingTopic = true } label: {
Text(topic)
.font(.compound.bodyMD)
@@ -60,7 +60,7 @@ struct SpaceHeaderView: View {
.frame(height: 1 / UIScreen.main.scale)
}
.sheet(isPresented: $isPresentingTopic) {
if let topic = spaceRoomProxy.topic {
if let topic = spaceServiceRoom.topic {
SpaceHeaderTopicSheetView(topic: topic)
}
}
@@ -79,7 +79,7 @@ struct SpaceHeaderView: View {
}
private var spaceDetailsVisibilityTitle: String {
switch spaceRoomProxy.visibility {
switch spaceServiceRoom.visibility {
case .public: L10n.commonPublicSpace
case .private: L10n.commonPrivateSpace
case .restricted: L10n.commonSharedSpace
@@ -88,7 +88,7 @@ struct SpaceHeaderView: View {
}
private var spaceDetailsVisibilityIcon: KeyPath<CompoundIcons, Image> {
switch spaceRoomProxy.visibility {
switch spaceServiceRoom.visibility {
case .public: \.public
case .private: \.lock
case .restricted: \.space
@@ -107,41 +107,41 @@ struct SpaceHeaderView_Previews: PreviewProvider, TestablePreview {
static var previews: some View {
VStack(spacing: 0) {
ForEach(spaces, id: \.id) { space in
SpaceHeaderView(spaceRoomProxy: space, mediaProvider: mediaProvider)
SpaceHeaderView(spaceServiceRoom: space, mediaProvider: mediaProvider)
}
}
}
static func makeSpaceRooms() -> [SpaceRoomProxyMock] {
static func makeSpaceRooms() -> [SpaceServiceRoomMock] {
[
SpaceRoomProxyMock(.init(id: "!space1:matrix.org",
name: "Company Space",
isSpace: true,
childrenCount: 10,
joinedMembersCount: 50)),
SpaceRoomProxyMock(.init(id: "!space2:matrix.org",
name: "Community Space",
avatarURL: .mockMXCAvatar,
isSpace: true,
childrenCount: 20,
joinedMembersCount: 78,
topic: "Description of the space goes right here.",
canonicalAlias: "#space:matrix.org",
joinRule: .public)),
SpaceRoomProxyMock(.init(id: "!space3:matrix.org",
name: "Subspace",
isSpace: true,
childrenCount: 30,
joinedMembersCount: 123,
heroes: [.mockDan, .mockBob, .mockCharlie, .mockVerbose],
topic: ["Description of the space goes right here.",
"Lorem ipsum dolor sit amet consectetur.",
"Leo viverra morbi habitant in.",
"Sem amet enim habitant nibh augue mauris.",
"Interdum mauris ultrices tincidunt proin morbi erat aenean risus nibh.",
"Diam amet sit fermentum vulputate faucibus."].joined(separator: " "),
canonicalAlias: "#subspace:matrix.org",
joinRule: .knockRestricted(rules: [.roomMembership(roomId: "")])))
SpaceServiceRoomMock(.init(id: "!space1:matrix.org",
name: "Company Space",
isSpace: true,
childrenCount: 10,
joinedMembersCount: 50)),
SpaceServiceRoomMock(.init(id: "!space2:matrix.org",
name: "Community Space",
avatarURL: .mockMXCAvatar,
isSpace: true,
childrenCount: 20,
joinedMembersCount: 78,
topic: "Description of the space goes right here.",
canonicalAlias: "#space:matrix.org",
joinRule: .public)),
SpaceServiceRoomMock(.init(id: "!space3:matrix.org",
name: "Subspace",
isSpace: true,
childrenCount: 30,
joinedMembersCount: 123,
heroes: [.mockDan, .mockBob, .mockCharlie, .mockVerbose],
topic: ["Description of the space goes right here.",
"Lorem ipsum dolor sit amet consectetur.",
"Leo viverra morbi habitant in.",
"Sem amet enim habitant nibh augue mauris.",
"Interdum mauris ultrices tincidunt proin morbi erat aenean risus nibh.",
"Diam amet sit fermentum vulputate faucibus."].joined(separator: " "),
canonicalAlias: "#subspace:matrix.org",
joinRule: .knockRestricted(rules: [.roomMembership(roomId: "")])))
]
}
}
@@ -13,32 +13,32 @@ import SwiftUI
struct SpaceRoomCell: View {
@Environment(\.dynamicTypeSize) var dynamicTypeSize
let spaceRoomProxy: SpaceRoomProxyProtocol
let spaceServiceRoom: SpaceServiceRoomProtocol
let isSelected: Bool
var isJoining = false
let mediaProvider: MediaProviderProtocol!
enum Action { case select(SpaceRoomProxyProtocol), join(SpaceRoomProxyProtocol) }
enum Action { case select(SpaceServiceRoomProtocol), join(SpaceServiceRoomProtocol) }
let action: (Action) -> Void
private let verticalInsets = 12.0
private let horizontalInsets = 16.0
private var subtitle: String {
if spaceRoomProxy.isSpace {
switch spaceRoomProxy.visibility {
if spaceServiceRoom.isSpace {
switch spaceServiceRoom.visibility {
case .public: L10n.commonPublicSpace
case .private: L10n.commonPrivateSpace
case .restricted: L10n.commonSharedSpace
case .none: L10n.commonPrivateSpace
}
} else {
L10n.commonMemberCount(spaceRoomProxy.joinedMembersCount)
L10n.commonMemberCount(spaceServiceRoom.joinedMembersCount)
}
}
var visibilityIcon: KeyPath<CompoundIcons, Image>? {
switch spaceRoomProxy.visibility {
switch spaceServiceRoom.visibility {
case .public: \.public
case .private: \.lockSolid
case .restricted: nil
@@ -47,16 +47,16 @@ struct SpaceRoomCell: View {
}
private var details: String {
if spaceRoomProxy.isSpace {
L10n.commonMemberCount(spaceRoomProxy.joinedMembersCount)
if spaceServiceRoom.isSpace {
L10n.commonMemberCount(spaceServiceRoom.joinedMembersCount)
} else {
spaceRoomProxy.topic ?? " " // Use a single space to reserve a consistent amount of space.
spaceServiceRoom.topic ?? " " // Use a single space to reserve a consistent amount of space.
}
}
var body: some View {
Button {
action(.select(spaceRoomProxy))
action(.select(spaceServiceRoom))
} label: {
HStack(spacing: 16.0) {
avatar
@@ -74,13 +74,13 @@ struct SpaceRoomCell: View {
.accessibilityElement(children: .combine)
}
.buttonStyle(SpaceRoomCellButtonStyle(isSelected: isSelected))
.accessibilityIdentifier(A11yIdentifiers.spaceListScreen.spaceRoomName(spaceRoomProxy.name))
.accessibilityIdentifier(A11yIdentifiers.spaceListScreen.spaceRoomName(spaceServiceRoom.name))
}
@ViewBuilder @MainActor
private var avatar: some View {
if dynamicTypeSize < .accessibility3 {
RoomAvatarImage(avatar: spaceRoomProxy.avatar,
RoomAvatarImage(avatar: spaceServiceRoom.avatar,
avatarSize: .room(on: .spaces),
mediaProvider: mediaProvider)
.dynamicTypeSize(dynamicTypeSize < .accessibility1 ? dynamicTypeSize : .accessibility1)
@@ -91,7 +91,7 @@ struct SpaceRoomCell: View {
private var content: some View {
HStack(spacing: 16) {
VStack(alignment: .leading, spacing: 2) {
Text(spaceRoomProxy.name)
Text(spaceServiceRoom.name)
.font(.compound.bodyLGSemibold)
.foregroundColor(.compound.textPrimary)
.lineLimit(1)
@@ -128,9 +128,9 @@ struct SpaceRoomCell: View {
@ViewBuilder
private var accessory: some View {
switch spaceRoomProxy.state {
switch spaceServiceRoom.state {
case .none, .left, .invited:
Button(L10n.actionJoin) { action(.join(spaceRoomProxy)) }
Button(L10n.actionJoin) { action(.join(spaceServiceRoom)) }
.font(.compound.bodyLG)
.foregroundStyle(.compound.textActionAccent)
.opacity(isJoining ? 0 : 1)
@@ -159,21 +159,21 @@ struct SpaceRoomCellButtonStyle: ButtonStyle {
struct SpaceRoomCell_Previews: PreviewProvider, TestablePreview {
static let mediaProvider = MediaProviderMock(configuration: .init())
static let spaces = [SpaceRoomProxyProtocol].mockSpaceList
static let spaces = [SpaceServiceRoomProtocol].mockSpaceList
static var previews: some View {
VStack(spacing: 0) {
ForEach(spaces, id: \.id) { space in
SpaceRoomCell(spaceRoomProxy: space,
SpaceRoomCell(spaceServiceRoom: space,
isSelected: false,
mediaProvider: mediaProvider) { _ in }
}
SpaceRoomCell(spaceRoomProxy: SpaceRoomProxyMock(.init(id: "Space being joined", isSpace: true)),
SpaceRoomCell(spaceServiceRoom: SpaceServiceRoomMock(.init(id: "Space being joined", isSpace: true)),
isSelected: false,
isJoining: true,
mediaProvider: mediaProvider) { _ in }
SpaceRoomCell(spaceRoomProxy: SpaceRoomProxyMock(.init(id: "Room being joined", isSpace: false)),
SpaceRoomCell(spaceServiceRoom: SpaceServiceRoomMock(.init(id: "Room being joined", isSpace: false)),
isSelected: false,
isJoining: true,
mediaProvider: mediaProvider) { _ in }
@@ -19,13 +19,13 @@ struct LeaveSpaceRoomDetailsCell: View {
let action: () -> Void
private var subtitle: String? {
guard !room.spaceRoomProxy.isSpace else { return nil }
let memberCount = L10n.commonMemberCount(room.spaceRoomProxy.joinedMembersCount)
guard !room.spaceServiceRoom.isSpace else { return nil }
let memberCount = L10n.commonMemberCount(room.spaceServiceRoom.joinedMembersCount)
return room.isLastAdmin ? L10n.screenLeaveSpaceLastAdminInfo(memberCount) : memberCount
}
var visibilityIcon: KeyPath<CompoundIcons, Image>? {
switch room.spaceRoomProxy.visibility {
switch room.spaceServiceRoom.visibility {
case .public: \.public
case .private: \.lockSolid
case .restricted: nil
@@ -37,13 +37,13 @@ struct LeaveSpaceRoomDetailsCell: View {
Button(action: action) {
HStack(spacing: 16) {
if dynamicTypeSize < .accessibility3 {
RoomAvatarImage(avatar: room.spaceRoomProxy.avatar,
RoomAvatarImage(avatar: room.spaceServiceRoom.avatar,
avatarSize: .room(on: .leaveSpace),
mediaProvider: mediaProvider)
}
VStack(alignment: .leading, spacing: 0) {
Text(room.spaceRoomProxy.name)
Text(room.spaceServiceRoom.name)
.font(.compound.bodyLGSemibold)
.foregroundStyle(.compound.textPrimary)
.lineLimit(1)
@@ -91,40 +91,40 @@ struct LeaveSpaceRoomDetailsCell: View {
struct LeaveSpaceRoomDetailsCell_Previews: PreviewProvider, TestablePreview {
static var previews: some View {
VStack(spacing: 0) {
LeaveSpaceRoomDetailsCell(room: .init(spaceRoomProxy: SpaceRoomProxyMock(.init(id: "1",
name: "Space",
isSpace: true)),
LeaveSpaceRoomDetailsCell(room: .init(spaceServiceRoom: SpaceServiceRoomMock(.init(id: "1",
name: "Space",
isSpace: true)),
isLastAdmin: false,
isSelected: true),
mediaProvider: MediaProviderMock(configuration: .init())) { }
LeaveSpaceRoomDetailsCell(room: .init(spaceRoomProxy: SpaceRoomProxyMock(.init(id: "2",
name: "My Space",
isSpace: true)),
LeaveSpaceRoomDetailsCell(room: .init(spaceServiceRoom: SpaceServiceRoomMock(.init(id: "2",
name: "My Space",
isSpace: true)),
isLastAdmin: true,
isSelected: false),
mediaProvider: MediaProviderMock(configuration: .init())) { }
LeaveSpaceRoomDetailsCell(room: .init(spaceRoomProxy: SpaceRoomProxyMock(.init(id: "2",
name: "My Space",
isSpace: true)),
LeaveSpaceRoomDetailsCell(room: .init(spaceServiceRoom: SpaceServiceRoomMock(.init(id: "2",
name: "My Space",
isSpace: true)),
isLastAdmin: true,
isSelected: false),
hideSelection: true,
mediaProvider: MediaProviderMock(configuration: .init())) { }
LeaveSpaceRoomDetailsCell(room: .init(spaceRoomProxy: SpaceRoomProxyMock(.init(id: "3",
name: "Room",
isSpace: false)),
LeaveSpaceRoomDetailsCell(room: .init(spaceServiceRoom: SpaceServiceRoomMock(.init(id: "3",
name: "Room",
isSpace: false)),
isLastAdmin: false,
isSelected: true),
mediaProvider: MediaProviderMock(configuration: .init())) { }
LeaveSpaceRoomDetailsCell(room: .init(spaceRoomProxy: SpaceRoomProxyMock(.init(id: "4",
name: "My Room",
isSpace: false)),
LeaveSpaceRoomDetailsCell(room: .init(spaceServiceRoom: SpaceServiceRoomMock(.init(id: "4",
name: "My Room",
isSpace: false)),
isLastAdmin: true,
isSelected: false),
mediaProvider: MediaProviderMock(configuration: .init())) { }
LeaveSpaceRoomDetailsCell(room: .init(spaceRoomProxy: SpaceRoomProxyMock(.init(id: "4",
name: "My Room",
isSpace: false)),
LeaveSpaceRoomDetailsCell(room: .init(spaceServiceRoom: SpaceServiceRoomMock(.init(id: "4",
name: "My Room",
isSpace: false)),
isLastAdmin: true,
isSelected: false),
hideSelection: true,
@@ -64,11 +64,11 @@ struct LeaveSpaceView: View {
context.viewState.leaveHandle.canLeave {
LazyVStack(spacing: 0, pinnedViews: .sectionHeaders) {
Section {
ForEach(context.viewState.leaveHandle.rooms, id: \.spaceRoomProxy.id) { room in
ForEach(context.viewState.leaveHandle.rooms, id: \.spaceServiceRoom.id) { room in
LeaveSpaceRoomDetailsCell(room: room,
hideSelection: context.viewState.leaveHandle.mode == .onlyAdminRooms,
mediaProvider: context.mediaProvider) {
context.send(viewAction: .toggleRoom(roomID: room.spaceRoomProxy.id))
context.send(viewAction: .toggleRoom(roomID: room.spaceServiceRoom.id))
}
.disabled(room.isLastAdmin)
}
@@ -136,27 +136,27 @@ struct LeaveSpaceView_Previews: PreviewProvider, TestablePreview {
.previewDisplayName("Last Space Admin")
}
static let spaceRoomProxy = SpaceRoomProxyMock(.init(id: "!eng-space:matrix.org",
name: "Engineering Team",
isSpace: true,
childrenCount: 30,
joinedMembersCount: 76,
heroes: [.mockDan, .mockBob, .mockCharlie, .mockVerbose],
topic: "Description of the space goes right here. Lorem ipsum dolor sit amet consectetur. Leo viverra morbi habitant in.",
joinRule: .knockRestricted(rules: [.roomMembership(roomId: "")])))
static let spaceServiceRoom = SpaceServiceRoomMock(.init(id: "!eng-space:matrix.org",
name: "Engineering Team",
isSpace: true,
childrenCount: 30,
joinedMembersCount: 76,
heroes: [.mockDan, .mockBob, .mockCharlie, .mockVerbose],
topic: "Description of the space goes right here. Lorem ipsum dolor sit amet consectetur. Leo viverra morbi habitant in.",
joinRule: .knockRestricted(rules: [.roomMembership(roomId: "")])))
static func makeViewModel(mode: LeaveSpaceHandleProxy.Mode) -> LeaveSpaceViewModel {
let rooms: [LeaveSpaceRoom] = switch mode {
case .manyRooms: .mockRooms
case .onlyAdminRooms: .mockAdminRooms
case .noRooms: .mockSingleSpace(spaceRoomProxy: spaceRoomProxy, isLastAdmin: false)
case .lastSpaceAdmin: .mockRoomsWithSpace(spaceRoomProxy: spaceRoomProxy, isLastAdmin: true)
case .noRooms: .mockSingleSpace(spaceServiceRoom: spaceServiceRoom, isLastAdmin: false)
case .lastSpaceAdmin: .mockRoomsWithSpace(spaceServiceRoom: spaceServiceRoom, isLastAdmin: true)
}
let leaveHandle = LeaveSpaceHandleProxy(spaceID: spaceRoomProxy.id,
let leaveHandle = LeaveSpaceHandleProxy(spaceID: spaceServiceRoom.id,
leaveHandle: LeaveSpaceHandleSDKMock(.init(rooms: rooms)))
return LeaveSpaceViewModel(spaceName: spaceRoomProxy.name,
return LeaveSpaceViewModel(spaceName: spaceServiceRoom.name,
canEditRolesAndPermissions: true,
leaveHandle: leaveHandle,
userIndicatorController: UserIndicatorControllerMock(),
@@ -18,7 +18,7 @@ struct SpaceListScreenViewState: BindableState {
var userDisplayName: String?
var userAvatarURL: URL?
var topLevelSpaces: [SpaceRoomProxyProtocol]
var topLevelSpaces: [SpaceServiceRoomProtocol]
var selectedSpaceID: String?
var isCreateSpaceEnabled: Bool
@@ -65,8 +65,8 @@ class SpaceListScreenViewModel: SpaceListScreenViewModelType, SpaceListScreenVie
MXLog.info("View model: received view action: \(viewAction)")
switch viewAction {
case .spaceAction(.select(let spaceRoomProxy)):
Task { await selectSpace(spaceRoomProxy) }
case .spaceAction(.select(let spaceServiceRoom)):
Task { await selectSpace(spaceServiceRoom) }
case .spaceAction(.join):
fatalError("There shouldn't be any unjoined spaces in the joined spaces list.")
case .showSettings:
@@ -86,8 +86,8 @@ class SpaceListScreenViewModel: SpaceListScreenViewModelType, SpaceListScreenVie
// MARK: - Private
private func selectSpace(_ spaceRoomProxy: SpaceRoomProxyProtocol) async {
switch await spaceServiceProxy.spaceRoomList(spaceID: spaceRoomProxy.id) {
private func selectSpace(_ spaceServiceRoom: SpaceServiceRoomProtocol) async {
switch await spaceServiceProxy.spaceRoomList(spaceID: spaceServiceRoom.id) {
case .success(let spaceRoomListProxy):
actionsSubject.send(.selectSpace(spaceRoomListProxy))
case .failure(let error):
@@ -85,9 +85,9 @@ struct SpaceListScreen: View {
}
private var spaces: some View {
ForEach(context.viewState.topLevelSpaces, id: \.id) { spaceRoomProxy in
SpaceRoomCell(spaceRoomProxy: spaceRoomProxy,
isSelected: spaceRoomProxy.id == context.viewState.selectedSpaceID,
ForEach(context.viewState.topLevelSpaces, id: \.id) { spaceServiceRoom in
SpaceRoomCell(spaceServiceRoom: spaceServiceRoom,
isSelected: spaceServiceRoom.id == context.viewState.selectedSpaceID,
mediaProvider: context.mediaProvider) { action in
context.send(viewAction: .spaceAction(action))
}
@@ -22,7 +22,7 @@ struct SpaceScreenCoordinatorParameters {
enum SpaceScreenCoordinatorAction {
case selectSpace(SpaceRoomListProxyProtocol)
case selectUnjoinedSpace(SpaceRoomProxyProtocol)
case selectUnjoinedSpace(SpaceServiceRoomProtocol)
case selectRoom(roomID: String)
case leftSpace
case displayMembers(roomProxy: JoinedRoomProxyProtocol)
@@ -60,8 +60,8 @@ final class SpaceScreenCoordinator: CoordinatorProtocol {
switch action {
case .selectSpace(let spaceRoomListProxy):
actionsSubject.send(.selectSpace(spaceRoomListProxy))
case .selectUnjoinedSpace(let spaceRoomProxy):
actionsSubject.send(.selectUnjoinedSpace(spaceRoomProxy))
case .selectUnjoinedSpace(let spaceServiceRoom):
actionsSubject.send(.selectUnjoinedSpace(spaceServiceRoom))
case .selectRoom(let roomID):
actionsSubject.send(.selectRoom(roomID: roomID))
case .leftSpace:
@@ -10,7 +10,7 @@ import Foundation
enum SpaceScreenViewModelAction {
case selectSpace(SpaceRoomListProxyProtocol)
case selectUnjoinedSpace(SpaceRoomProxyProtocol)
case selectUnjoinedSpace(SpaceServiceRoomProtocol)
case selectRoom(roomID: String)
case leftSpace
case presentRolesAndPermissions(roomProxy: JoinedRoomProxyProtocol)
@@ -19,13 +19,13 @@ enum SpaceScreenViewModelAction {
}
struct SpaceScreenViewState: BindableState {
var space: SpaceRoomProxyProtocol
var space: SpaceServiceRoomProtocol
var permalink: URL?
var roomProxy: JoinedRoomProxyProtocol?
var isPaginating = false
var rooms: [SpaceRoomProxyProtocol]
var rooms: [SpaceServiceRoomProtocol]
var selectedSpaceRoomID: String?
var joiningRoomIDs: Set<String> = []
@@ -37,12 +37,12 @@ class SpaceScreenViewModel: SpaceScreenViewModelType, SpaceScreenViewModelProtoc
self.userIndicatorController = userIndicatorController
self.appSettings = appSettings
super.init(initialViewState: SpaceScreenViewState(space: spaceRoomListProxy.spaceRoomProxyPublisher.value,
super.init(initialViewState: SpaceScreenViewState(space: spaceRoomListProxy.spaceServiceRoomPublisher.value,
rooms: spaceRoomListProxy.spaceRoomsPublisher.value,
selectedSpaceRoomID: selectedSpaceRoomPublisher.value),
mediaProvider: userSession.mediaProvider)
spaceRoomListProxy.spaceRoomProxyPublisher
spaceRoomListProxy.spaceServiceRoomPublisher
.receive(on: DispatchQueue.main)
.weakAssign(to: \.state.space, on: self)
.store(in: &cancellables)
@@ -107,19 +107,19 @@ class SpaceScreenViewModel: SpaceScreenViewModelType, SpaceScreenViewModelProtoc
MXLog.info("View model: received view action: \(viewAction)")
switch viewAction {
case .spaceAction(.select(let spaceRoomProxy)):
if spaceRoomProxy.isSpace {
if spaceRoomProxy.state != .joined {
actionsSubject.send(.selectUnjoinedSpace(spaceRoomProxy))
case .spaceAction(.select(let spaceServiceRoom)):
if spaceServiceRoom.isSpace {
if spaceServiceRoom.state != .joined {
actionsSubject.send(.selectUnjoinedSpace(spaceServiceRoom))
} else {
Task { await selectSpace(spaceRoomProxy) }
Task { await selectSpace(spaceServiceRoom) }
}
} else {
// No need to check the join state, the room flow will show an appropriately configured join screen if needed.
actionsSubject.send(.selectRoom(roomID: spaceRoomProxy.id))
actionsSubject.send(.selectRoom(roomID: spaceServiceRoom.id))
}
case .spaceAction(.join(let spaceRoomProxy)):
Task { await join(spaceRoomProxy) }
case .spaceAction(.join(let spaceServiceRoom)):
Task { await join(spaceServiceRoom) }
case .leaveSpace:
Task { await showLeaveSpaceConfirmation() }
case .displayMembers(let roomProxy):
@@ -136,11 +136,11 @@ class SpaceScreenViewModel: SpaceScreenViewModelType, SpaceScreenViewModelProtoc
// MARK: - Private
private func join(_ spaceRoomProxy: SpaceRoomProxyProtocol) async {
state.joiningRoomIDs.insert(spaceRoomProxy.id)
defer { state.joiningRoomIDs.remove(spaceRoomProxy.id) }
private func join(_ spaceServiceRoom: SpaceServiceRoomProtocol) async {
state.joiningRoomIDs.insert(spaceServiceRoom.id)
defer { state.joiningRoomIDs.remove(spaceServiceRoom.id) }
guard case .success = await clientProxy.joinRoom(spaceRoomProxy.id, via: spaceRoomProxy.via) else {
guard case .success = await clientProxy.joinRoom(spaceServiceRoom.id, via: spaceServiceRoom.via) else {
showFailureIndicator()
return
}
@@ -148,8 +148,8 @@ class SpaceScreenViewModel: SpaceScreenViewModelType, SpaceScreenViewModelProtoc
// We don't want to show the space room after joining it this way 🤷‍♂️
}
private func selectSpace(_ spaceRoomProxy: SpaceRoomProxyProtocol) async {
switch await spaceServiceProxy.spaceRoomList(spaceID: spaceRoomProxy.id) {
private func selectSpace(_ spaceServiceRoom: SpaceServiceRoomProtocol) async {
switch await spaceServiceProxy.spaceRoomList(spaceID: spaceServiceRoom.id) {
case .success(let spaceRoomListProxy):
actionsSubject.send(.selectSpace(spaceRoomListProxy))
case .failure(let error):
@@ -15,7 +15,7 @@ struct SpaceScreen: View {
var body: some View {
ScrollView {
LazyVStack(spacing: 0) {
SpaceHeaderView(spaceRoomProxy: context.viewState.space,
SpaceHeaderView(spaceServiceRoom: context.viewState.space,
mediaProvider: context.mediaProvider)
rooms
}
@@ -32,10 +32,10 @@ struct SpaceScreen: View {
@ViewBuilder
var rooms: some View {
ForEach(context.viewState.rooms, id: \.id) { spaceRoomProxy in
SpaceRoomCell(spaceRoomProxy: spaceRoomProxy,
isSelected: spaceRoomProxy.id == context.viewState.selectedSpaceRoomID,
isJoining: context.viewState.joiningRoomIDs.contains(spaceRoomProxy.id),
ForEach(context.viewState.rooms, id: \.id) { spaceServiceRoom in
SpaceRoomCell(spaceServiceRoom: spaceServiceRoom,
isSelected: spaceServiceRoom.id == context.viewState.selectedSpaceRoomID,
isJoining: context.viewState.joiningRoomIDs.contains(spaceServiceRoom.id),
mediaProvider: context.mediaProvider) { action in
context.send(viewAction: .spaceAction(action))
}
@@ -114,16 +114,16 @@ struct SpaceScreen_Previews: PreviewProvider, TestablePreview {
}
static func makeViewModel() -> SpaceScreenViewModel {
let spaceRoomProxy = SpaceRoomProxyMock(.init(id: "!eng-space:matrix.org",
name: "Engineering Team",
isSpace: true,
childrenCount: 30,
joinedMembersCount: 76,
heroes: [.mockDan, .mockBob, .mockCharlie, .mockVerbose],
topic: "Description of the space goes right here. Lorem ipsum dolor sit amet consectetur. Leo viverra morbi habitant in.",
canonicalAlias: "#engineering-team:element.io",
joinRule: .knockRestricted(rules: [.roomMembership(roomId: "")])))
let spaceRoomListProxy = SpaceRoomListProxyMock(.init(spaceRoomProxy: spaceRoomProxy,
let spaceServiceRoom = SpaceServiceRoomMock(.init(id: "!eng-space:matrix.org",
name: "Engineering Team",
isSpace: true,
childrenCount: 30,
joinedMembersCount: 76,
heroes: [.mockDan, .mockBob, .mockCharlie, .mockVerbose],
topic: "Description of the space goes right here. Lorem ipsum dolor sit amet consectetur. Leo viverra morbi habitant in.",
canonicalAlias: "#engineering-team:element.io",
joinRule: .knockRestricted(rules: [.roomMembership(roomId: "")])))
let spaceRoomListProxy = SpaceRoomListProxyMock(.init(spaceServiceRoom: spaceServiceRoom,
initialSpaceRooms: .mockSpaceList))
let clientProxy = ClientProxyMock(.init())