Remove the protocol for SpaceServiceRoom given its a struct type. (#5000)

* Remove the protocol for SpaceServiceRoom given its a struct type.

* Fix a few missed mocks in the unit tests.
This commit is contained in:
Doug
2026-01-26 09:45:46 +00:00
committed by GitHub
parent 3b231339cd
commit 06f37dacae
46 changed files with 459 additions and 545 deletions
@@ -18,7 +18,7 @@ enum SpaceFlowCoordinatorAction {
enum SpaceFlowCoordinatorEntryPoint {
case space(SpaceRoomListProxyProtocol)
case joinSpace(SpaceServiceRoomProtocol)
case joinSpace(SpaceServiceRoom)
var spaceID: String {
switch self {
@@ -301,7 +301,7 @@ class SpaceFlowCoordinator: FlowCoordinatorProtocol {
guard event == .startCreateChildRoomFlow, case .space = fromState else { return nil }
return .createChildRoomFlow
} handler: { [weak self] context in
guard let space = context.userInfo as? SpaceServiceRoomProtocol else { fatalError("The space is missing") }
guard let space = context.userInfo as? SpaceServiceRoom else { fatalError("The space is missing") }
self?.startCreateChildFlow(space: space)
}
@@ -561,7 +561,7 @@ class SpaceFlowCoordinator: FlowCoordinatorProtocol {
flowCoordinator.start()
}
private func startCreateChildFlow(space: SpaceServiceRoomProtocol) {
private func startCreateChildFlow(space: SpaceServiceRoom) {
let stackCoordinator = NavigationStackCoordinator()
let flowCoordinator = StartChatFlowCoordinator(entryPoint: .createRoomInSpace(space),
userDiscoveryService: UserDiscoveryService(clientProxy: flowParameters.userSession.clientProxy),
@@ -25,7 +25,7 @@ enum StartChatFlowCoordinatorAction {
enum StartChatFlowCoordinatorEntryPoint {
case startChat
case createSpace
case createRoomInSpace(SpaceServiceRoomProtocol)
case createRoomInSpace(SpaceServiceRoom)
}
class StartChatFlowCoordinator: FlowCoordinatorProtocol {
@@ -141,7 +141,7 @@ class StartChatFlowCoordinator: FlowCoordinatorProtocol {
}
stateMachine.addRoutes(event: .createRoom(isSpace: false), transitions: [.initial => .createRoom]) { [weak self] context in
guard context.fromState == .initial else { return } // Required check because the event is used in another route.
guard let space = context.userInfo as? SpaceServiceRoomProtocol else {
guard let space = context.userInfo as? SpaceServiceRoom else {
fatalError("This transition only supports creating a room in a pre-selected space.")
}
self?.presentCreateRoomScreen(isSpace: false, spaceSelectionMode: .preSelected(space), isRoot: true)
@@ -16721,16 +16721,16 @@ class SpaceRoomListProxyMock: SpaceRoomListProxyProtocol, @unchecked Sendable {
set(value) { underlyingId = value }
}
var underlyingId: String!
var spaceServiceRoomPublisher: CurrentValuePublisher<SpaceServiceRoomProtocol, Never> {
var spaceServiceRoomPublisher: CurrentValuePublisher<SpaceServiceRoom, Never> {
get { return underlyingSpaceServiceRoomPublisher }
set(value) { underlyingSpaceServiceRoomPublisher = value }
}
var underlyingSpaceServiceRoomPublisher: CurrentValuePublisher<SpaceServiceRoomProtocol, Never>!
var spaceRoomsPublisher: CurrentValuePublisher<[SpaceServiceRoomProtocol], Never> {
var underlyingSpaceServiceRoomPublisher: CurrentValuePublisher<SpaceServiceRoom, Never>!
var spaceRoomsPublisher: CurrentValuePublisher<[SpaceServiceRoom], Never> {
get { return underlyingSpaceRoomsPublisher }
set(value) { underlyingSpaceRoomsPublisher = value }
}
var underlyingSpaceRoomsPublisher: CurrentValuePublisher<[SpaceServiceRoomProtocol], Never>!
var underlyingSpaceRoomsPublisher: CurrentValuePublisher<[SpaceServiceRoom], Never>!
var paginationStatePublisher: CurrentValuePublisher<SpaceRoomListPaginationState, Never> {
get { return underlyingPaginationStatePublisher }
set(value) { underlyingPaginationStatePublisher = value }
@@ -16809,11 +16809,11 @@ class SpaceRoomListProxyMock: SpaceRoomListProxyProtocol, @unchecked Sendable {
}
}
class SpaceServiceProxyMock: SpaceServiceProxyProtocol, @unchecked Sendable {
var topLevelSpacesPublisher: CurrentValuePublisher<[SpaceServiceRoomProtocol], Never> {
var topLevelSpacesPublisher: CurrentValuePublisher<[SpaceServiceRoom], Never> {
get { return underlyingTopLevelSpacesPublisher }
set(value) { underlyingTopLevelSpacesPublisher = value }
}
var underlyingTopLevelSpacesPublisher: CurrentValuePublisher<[SpaceServiceRoomProtocol], Never>!
var underlyingTopLevelSpacesPublisher: CurrentValuePublisher<[SpaceServiceRoom], Never>!
var spaceFilterPublisher: CurrentValuePublisher<[SpaceServiceFilter], Never> {
get { return underlyingSpaceFilterPublisher }
set(value) { underlyingSpaceFilterPublisher = value }
@@ -16922,13 +16922,13 @@ class SpaceServiceProxyMock: SpaceServiceProxyProtocol, @unchecked Sendable {
var spaceForIdentifierSpaceIDReceivedSpaceID: String?
var spaceForIdentifierSpaceIDReceivedInvocations: [String] = []
var spaceForIdentifierSpaceIDUnderlyingReturnValue: Result<SpaceServiceRoomProtocol?, SpaceServiceProxyError>!
var spaceForIdentifierSpaceIDReturnValue: Result<SpaceServiceRoomProtocol?, SpaceServiceProxyError>! {
var spaceForIdentifierSpaceIDUnderlyingReturnValue: Result<SpaceServiceRoom?, SpaceServiceProxyError>!
var spaceForIdentifierSpaceIDReturnValue: Result<SpaceServiceRoom?, SpaceServiceProxyError>! {
get {
if Thread.isMainThread {
return spaceForIdentifierSpaceIDUnderlyingReturnValue
} else {
var returnValue: Result<SpaceServiceRoomProtocol?, SpaceServiceProxyError>? = nil
var returnValue: Result<SpaceServiceRoom?, SpaceServiceProxyError>? = nil
DispatchQueue.main.sync {
returnValue = spaceForIdentifierSpaceIDUnderlyingReturnValue
}
@@ -16946,9 +16946,9 @@ class SpaceServiceProxyMock: SpaceServiceProxyProtocol, @unchecked Sendable {
}
}
}
var spaceForIdentifierSpaceIDClosure: ((String) async -> Result<SpaceServiceRoomProtocol?, SpaceServiceProxyError>)?
var spaceForIdentifierSpaceIDClosure: ((String) async -> Result<SpaceServiceRoom?, SpaceServiceProxyError>)?
func spaceForIdentifier(spaceID: String) async -> Result<SpaceServiceRoomProtocol?, SpaceServiceProxyError> {
func spaceForIdentifier(spaceID: String) async -> Result<SpaceServiceRoom?, SpaceServiceProxyError> {
spaceForIdentifierSpaceIDCallsCount += 1
spaceForIdentifierSpaceIDReceivedSpaceID = spaceID
DispatchQueue.main.async {
@@ -17062,13 +17062,13 @@ class SpaceServiceProxyMock: SpaceServiceProxyProtocol, @unchecked Sendable {
var joinedParentsChildIDReceivedChildID: String?
var joinedParentsChildIDReceivedInvocations: [String] = []
var joinedParentsChildIDUnderlyingReturnValue: Result<[SpaceServiceRoomProtocol], SpaceServiceProxyError>!
var joinedParentsChildIDReturnValue: Result<[SpaceServiceRoomProtocol], SpaceServiceProxyError>! {
var joinedParentsChildIDUnderlyingReturnValue: Result<[SpaceServiceRoom], SpaceServiceProxyError>!
var joinedParentsChildIDReturnValue: Result<[SpaceServiceRoom], SpaceServiceProxyError>! {
get {
if Thread.isMainThread {
return joinedParentsChildIDUnderlyingReturnValue
} else {
var returnValue: Result<[SpaceServiceRoomProtocol], SpaceServiceProxyError>? = nil
var returnValue: Result<[SpaceServiceRoom], SpaceServiceProxyError>? = nil
DispatchQueue.main.sync {
returnValue = joinedParentsChildIDUnderlyingReturnValue
}
@@ -17086,9 +17086,9 @@ class SpaceServiceProxyMock: SpaceServiceProxyProtocol, @unchecked Sendable {
}
}
}
var joinedParentsChildIDClosure: ((String) async -> Result<[SpaceServiceRoomProtocol], SpaceServiceProxyError>)?
var joinedParentsChildIDClosure: ((String) async -> Result<[SpaceServiceRoom], SpaceServiceProxyError>)?
func joinedParents(childID: String) async -> Result<[SpaceServiceRoomProtocol], SpaceServiceProxyError> {
func joinedParents(childID: String) async -> Result<[SpaceServiceRoom], SpaceServiceProxyError> {
joinedParentsChildIDCallsCount += 1
joinedParentsChildIDReceivedChildID = childID
DispatchQueue.main.async {
@@ -17130,13 +17130,13 @@ class SpaceServiceProxyMock: SpaceServiceProxyProtocol, @unchecked Sendable {
return editableSpacesCallsCount > 0
}
var editableSpacesUnderlyingReturnValue: [SpaceServiceRoomProtocol]!
var editableSpacesReturnValue: [SpaceServiceRoomProtocol]! {
var editableSpacesUnderlyingReturnValue: [SpaceServiceRoom]!
var editableSpacesReturnValue: [SpaceServiceRoom]! {
get {
if Thread.isMainThread {
return editableSpacesUnderlyingReturnValue
} else {
var returnValue: [SpaceServiceRoomProtocol]? = nil
var returnValue: [SpaceServiceRoom]? = nil
DispatchQueue.main.sync {
returnValue = editableSpacesUnderlyingReturnValue
}
@@ -17154,9 +17154,9 @@ class SpaceServiceProxyMock: SpaceServiceProxyProtocol, @unchecked Sendable {
}
}
}
var editableSpacesClosure: (() async -> [SpaceServiceRoomProtocol])?
var editableSpacesClosure: (() async -> [SpaceServiceRoom])?
func editableSpaces() async -> [SpaceServiceRoomProtocol] {
func editableSpaces() async -> [SpaceServiceRoom] {
editableSpacesCallsCount += 1
if let editableSpacesClosure = editableSpacesClosure {
return await editableSpacesClosure()
@@ -17305,49 +17305,6 @@ class SpaceServiceProxyMock: SpaceServiceProxyProtocol, @unchecked Sendable {
}
}
}
class SpaceServiceRoomMock: SpaceServiceRoomProtocol, @unchecked Sendable {
var id: String {
get { return underlyingId }
set(value) { underlyingId = value }
}
var underlyingId: String!
var name: String {
get { return underlyingName }
set(value) { underlyingName = value }
}
var underlyingName: String!
var rawName: String?
var avatarURL: URL?
var isSpace: Bool {
get { return underlyingIsSpace }
set(value) { underlyingIsSpace = value }
}
var underlyingIsSpace: Bool!
var isDirect: Bool?
var childrenCount: Int {
get { return underlyingChildrenCount }
set(value) { underlyingChildrenCount = value }
}
var underlyingChildrenCount: Int!
var joinedMembersCount: Int {
get { return underlyingJoinedMembersCount }
set(value) { underlyingJoinedMembersCount = value }
}
var underlyingJoinedMembersCount: Int!
var heroes: [UserProfileProxy] = []
var topic: String?
var canonicalAlias: String?
var joinRule: JoinRule?
var worldReadable: Bool?
var guestCanJoin: Bool {
get { return underlyingGuestCanJoin }
set(value) { underlyingGuestCanJoin = value }
}
var underlyingGuestCanJoin: Bool!
var state: Membership?
var via: [String] = []
}
class StaticRoomSummaryProviderMock: StaticRoomSummaryProviderProtocol, @unchecked Sendable {
var statePublisher: CurrentValuePublisher<RoomSummaryProviderState, Never> {
get { return underlyingStatePublisher }
@@ -98,7 +98,7 @@ extension RoomPreviewProxyMock {
underlyingOwnMembershipDetails = roomMembershipDetails
}
convenience init(spaceServiceRoom: SpaceServiceRoomProtocol) {
convenience init(spaceServiceRoom: SpaceServiceRoom) {
self.init(Configuration(roomID: spaceServiceRoom.id,
canonicalAlias: spaceServiceRoom.canonicalAlias ?? "",
name: spaceServiceRoom.name,
@@ -23,11 +23,11 @@ extension LeaveSpaceHandleSDKMock {
}
extension [LeaveSpaceRoom] {
static func mockRoomsWithSpace(spaceServiceRoom: SpaceServiceRoomProtocol, isLastOwner: Bool) -> [LeaveSpaceRoom] {
static func mockRoomsWithSpace(spaceServiceRoom: SpaceServiceRoom, isLastOwner: Bool) -> [LeaveSpaceRoom] {
mockRooms + mockSingleSpace(spaceServiceRoom: spaceServiceRoom, isLastOwner: isLastOwner)
}
static func mockSingleSpace(spaceServiceRoom: SpaceServiceRoomProtocol, isLastOwner: Bool) -> [LeaveSpaceRoom] {
static func mockSingleSpace(spaceServiceRoom: SpaceServiceRoom, isLastOwner: Bool) -> [LeaveSpaceRoom] {
[LeaveSpaceRoom(spaceRoom: SpaceRoom(id: spaceServiceRoom.id,
name: spaceServiceRoom.name,
avatarURL: spaceServiceRoom.avatarURL,
@@ -1,208 +0,0 @@
//
// Copyright 2025 Element Creations Ltd.
// Copyright 2025 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
// Please see LICENSE files in the repository root for full details.
//
import Foundation
import MatrixRustSDK
extension SpaceServiceRoomMock {
struct Configuration {
var id: String = UUID().uuidString
var name: String?
var rawName: String?
var avatarURL: URL?
var isSpace: Bool
var isDirect: Bool?
var childrenCount = 0
var joinedMembersCount = 0
var heroes: [UserProfileProxy] = []
var topic: String?
var canonicalAlias: String?
var joinRule: JoinRule?
var worldReadable: Bool?
var guestCanJoin = true
var state: Membership?
}
convenience init(_ configuration: Configuration) {
self.init()
id = configuration.id
name = configuration.name ?? configuration.id
rawName = configuration.rawName
avatarURL = configuration.avatarURL
isSpace = configuration.isSpace
isDirect = configuration.isDirect
childrenCount = configuration.childrenCount
joinedMembersCount = configuration.joinedMembersCount
heroes = configuration.heroes
topic = configuration.topic
canonicalAlias = configuration.canonicalAlias
joinRule = configuration.joinRule
worldReadable = configuration.worldReadable
guestCanJoin = configuration.guestCanJoin
state = configuration.state
}
}
extension [SpaceServiceRoomProtocol] {
static var mockJoinedSpaces: [SpaceServiceRoomMock] {
[
SpaceServiceRoomMock(.init(id: "space1",
name: "The Foundation",
isSpace: true,
childrenCount: 1,
joinedMembersCount: 500,
canonicalAlias: "#the-foundation:matrix.org",
state: .joined)),
SpaceServiceRoomMock(.init(id: "space2",
name: "The Second Foundation",
isSpace: true,
childrenCount: 1,
joinedMembersCount: 100,
state: .joined)),
SpaceServiceRoomMock(.init(id: "space3",
name: "The Galactic Empire",
isSpace: true,
childrenCount: 25000,
joinedMembersCount: 1_000_000_000,
canonicalAlias: "#the-galactic-empire:matrix.org",
state: .joined)),
SpaceServiceRoomMock(.init(id: "space4",
name: "The Korellians",
isSpace: true,
childrenCount: 27,
joinedMembersCount: 2_000_000,
state: .joined)),
SpaceServiceRoomMock(.init(id: "space5",
name: "The Luminists",
isSpace: true,
childrenCount: 1,
joinedMembersCount: 100_000,
state: .joined)),
SpaceServiceRoomMock(.init(id: "space6",
name: "The Anacreons",
isSpace: true,
childrenCount: 25,
joinedMembersCount: 400_000,
state: .joined)),
SpaceServiceRoomMock(.init(id: "space7",
name: "The Thespians",
isSpace: true,
childrenCount: 15,
joinedMembersCount: 300_000,
state: .joined))
]
}
static var mockJoinedSpaces2: [SpaceServiceRoomMock] {
[
SpaceServiceRoomMock(.init(id: "space1",
name: "The Foundation",
avatarURL: .mockMXCAvatar,
isSpace: true,
childrenCount: 1,
joinedMembersCount: 500,
canonicalAlias: "#the-foundation:matrix.org",
joinRule: .private,
state: .joined)),
SpaceServiceRoomMock(.init(id: "space2",
name: "The Second Foundation",
isSpace: true,
childrenCount: 1,
joinedMembersCount: 100,
state: .joined)),
SpaceServiceRoomMock(.init(id: "space3",
name: "The Galactic Empire",
isSpace: true,
childrenCount: 25000,
joinedMembersCount: 1_000_000_000,
canonicalAlias: "#the-galactic-empire:matrix.org",
state: .joined))
]
}
static var mockSpaceList: [SpaceServiceRoomProtocol] {
makeSpaceRooms(isSpace: true) + makeSpaceRooms(isSpace: false)
}
static var mockSingleRoom: [SpaceServiceRoomProtocol] {
[SpaceServiceRoomMock(.init(id: "!spaceroom:matrix.org",
name: "Management",
isSpace: false,
joinedMembersCount: 12,
topic: "This is where everything gets organised 📋.",
state: .joined))]
}
private static func makeSpaceRooms(isSpace: Bool) -> [SpaceServiceRoomMock] {
let typeName = isSpace ? "Space" : "Room"
return [
SpaceServiceRoomMock(.init(id: "!\(typeName.lowercased())1:matrix.org",
name: "Company \(typeName)",
isSpace: isSpace)),
SpaceServiceRoomMock(.init(id: "!\(typeName.lowercased())2:matrix.org",
name: "Public \(typeName)",
avatarURL: .mockMXCAvatar,
isSpace: isSpace,
joinedMembersCount: 78,
topic: "Discussion on specific topic goes here.",
joinRule: .public)),
SpaceServiceRoomMock(.init(id: "!\(typeName.lowercased())3:matrix.org",
name: "Joined \(typeName)",
isSpace: isSpace,
joinedMembersCount: 123,
topic: "Discussion on specific topic goes here.",
joinRule: .restricted(rules: []),
state: .joined))
]
}
}
extension SpaceServiceRoomMock {
convenience init(mode: JoinRoomScreenMode) {
var state: Membership?
var joinRule: JoinRule?
switch mode {
case .joinable:
joinRule = .public
case .restricted:
joinRule = .restricted(rules: [])
case .inviteRequired:
joinRule = .private
case .invited:
state = .invited
joinRule = .private
case .knockable:
joinRule = .knock
case .knocked:
state = .knocked
joinRule = .knock
case .banned:
state = .banned
case .loading, .unknown, .forbidden:
break
}
self.init(.init(id: "1",
name: "The Three-Body Problem",
avatarURL: .mockMXCAvatar,
isSpace: true,
childrenCount: 100,
joinedMembersCount: 123,
heroes: [.mockAlice, .mockBob, .mockCharlie],
topic: "“Science and technology were the only keys to opening the door to the future, and people approached science with the faith and sincerity of elementary school students.”",
canonicalAlias: "#3-body-problem:matrix.org",
joinRule: joinRule,
state: state))
}
}
@@ -12,15 +12,15 @@ import MatrixRustSDK
extension SpaceRoomListProxyMock {
class Configuration {
var spaceServiceRoom: SpaceServiceRoomProtocol
var initialSpaceRooms: [SpaceServiceRoomProtocol]
var spaceServiceRoom: SpaceServiceRoom
var initialSpaceRooms: [SpaceServiceRoom]
var paginationStateSubject: CurrentValueSubject<SpaceRoomListPaginationState, Never>
var paginationResponses: [[SpaceServiceRoomProtocol]]
var paginationResponses: [[SpaceServiceRoom]]
init(spaceServiceRoom: SpaceServiceRoomProtocol,
initialSpaceRooms: [SpaceServiceRoomProtocol] = [],
init(spaceServiceRoom: SpaceServiceRoom,
initialSpaceRooms: [SpaceServiceRoom] = [],
paginationStateSubject: CurrentValueSubject<SpaceRoomListPaginationState, Never> = .init(.idle(endReached: true)),
paginationResponses: [[SpaceServiceRoomProtocol]] = []) {
paginationResponses: [[SpaceServiceRoom]] = []) {
self.spaceServiceRoom = spaceServiceRoom
self.initialSpaceRooms = initialSpaceRooms
self.paginationStateSubject = paginationStateSubject
@@ -31,7 +31,7 @@ extension SpaceRoomListProxyMock {
convenience init(_ configuration: Configuration) {
self.init()
let spaceRoomsSubject: CurrentValueSubject<[SpaceServiceRoomProtocol], Never> = .init(configuration.initialSpaceRooms)
let spaceRoomsSubject: CurrentValueSubject<[SpaceServiceRoom], Never> = .init(configuration.initialSpaceRooms)
id = configuration.spaceServiceRoom.id
spaceServiceRoomPublisher = .init(configuration.spaceServiceRoom)
@@ -17,10 +17,10 @@ enum SpaceServiceProxyMockError: Error {
extension SpaceServiceProxyMock {
struct Configuration {
var topLevelSpaces: [SpaceServiceRoomProtocol] = []
var topLevelSpaces: [SpaceServiceRoom] = []
var spaceFilters: [SpaceServiceFilter] = []
var joinedParentSpaces: [SpaceServiceRoomProtocol] = []
var editableSpaces: [SpaceServiceRoomProtocol] = []
var joinedParentSpaces: [SpaceServiceRoom] = []
var editableSpaces: [SpaceServiceRoom] = []
var spaceRoomLists: [String: SpaceRoomListProxyMock] = [:]
var leaveSpaceRooms: [LeaveSpaceRoom] = []
}
@@ -55,16 +55,16 @@ extension SpaceServiceProxyMock {
extension SpaceServiceProxyMock.Configuration {
static var populated: SpaceServiceProxyMock.Configuration {
let spaceFilters = [SpaceServiceRoomProtocol].mockJoinedSpaces.reduce(into: [SpaceServiceFilter]()) { partialResult, spaceRoom in
let spaceFilters = [SpaceServiceRoom].mockJoinedSpaces.reduce(into: [SpaceServiceFilter]()) { partialResult, spaceRoom in
partialResult.append(SpaceServiceFilter(room: spaceRoom, level: 0, descendants: .init()))
partialResult.append(SpaceServiceFilter(room: spaceRoom, level: 1, descendants: .init()))
}
let spaceRoomLists = [SpaceServiceRoomProtocol].mockJoinedSpaces.map {
let spaceRoomLists = [SpaceServiceRoom].mockJoinedSpaces.map {
($0.id, SpaceRoomListProxyMock(.init(spaceServiceRoom: $0, initialSpaceRooms: .mockSpaceList)))
}
let subSpaceRoomLists = [SpaceServiceRoomProtocol].mockSpaceList.map {
let subSpaceRoomLists = [SpaceServiceRoom].mockSpaceList.map {
($0.id, SpaceRoomListProxyMock(.init(spaceServiceRoom: $0, initialSpaceRooms: .mockSingleRoom)))
}
@@ -89,7 +89,7 @@ struct ChatsSpaceFilterCell: View {
struct ChatsSpaceFilterCell_Previews: PreviewProvider, TestablePreview {
static let mediaProvider = MediaProviderMock(configuration: .init())
static let spaces = [SpaceServiceRoomProtocol].mockJoinedSpaces2
static let spaces = [SpaceServiceRoom].mockJoinedSpaces2
static var previews: some View {
VStack(spacing: 0) {
@@ -31,7 +31,7 @@ struct CreateRoomScreenViewState: BindableState {
let isKnockingFeatureEnabled: Bool
let canSelectSpace: Bool
var aliasLocalPart: String
var editableSpaces: [SpaceServiceRoomProtocol] = []
var editableSpaces: [SpaceServiceRoom] = []
var bindings: CreateRoomScreenViewStateBindings
var avatarMediaInfo: MediaInfo? {
didSet {
@@ -99,7 +99,7 @@ struct CreateRoomScreenViewState: BindableState {
struct CreateRoomScreenViewStateBindings {
var roomTopic: String
var selectedAccessType: CreateRoomScreenAccessType
var selectedSpace: SpaceServiceRoomProtocol?
var selectedSpace: SpaceServiceRoom?
var showAttachmentConfirmationDialog = false
var showSpaceSelectionSheet = false
@@ -144,5 +144,5 @@ enum CreateRoomScreenAccessType {
enum CreateRoomScreenSpaceSelectionMode {
case editableSpacesList
case preSelected(SpaceServiceRoomProtocol)
case preSelected(SpaceServiceRoom)
}
@@ -39,7 +39,7 @@ class CreateRoomScreenViewModel: CreateRoomScreenViewModelType, CreateRoomScreen
self.analytics = analytics
self.userIndicatorController = userIndicatorController
var selectedSpace: SpaceServiceRoomProtocol?
var selectedSpace: SpaceServiceRoom?
var canSelectSpace = false
switch spaceSelectionMode {
case .editableSpacesList:
@@ -378,21 +378,21 @@ struct CreateRoom_Previews: PreviewProvider, TestablePreview {
return viewModel
}()
static let selectedSpaceViewModel = makeViewModel(selectionMode: .preSelected(SpaceServiceRoomMock(.init(name: "Awesome Space",
isSpace: true,
joinRule: .private))))
static let selectedSpaceViewModel = makeViewModel(selectionMode: .preSelected(SpaceServiceRoom.mock(name: "Awesome Space",
isSpace: true,
joinRule: .private)))
static let selectedSpaceWithListViewModel = {
let viewModel = makeViewModel()
viewModel.context.selectedSpace = [SpaceServiceRoomProtocol].mockJoinedSpaces2.first
viewModel.context.selectedSpace = [SpaceServiceRoom].mockJoinedSpaces2.first
return viewModel
}()
static let selectedSpaceWithAskToJoinViewModel = {
let viewModel = makeViewModel(isKnockingEnabled: true,
selectionMode: .preSelected(SpaceServiceRoomMock(.init(name: "Awesome Space",
isSpace: true,
joinRule: .private))))
selectionMode: .preSelected(SpaceServiceRoom.mock(name: "Awesome Space",
isSpace: true,
joinRule: .private)))
viewModel.context.selectedAccessType = .askToJoinWithSpaceMembers
return viewModel
}()
@@ -469,7 +469,7 @@ struct CreateRoom_Previews: PreviewProvider, TestablePreview {
let clientProxy = ClientProxyMock(.init(userIDServerName: "example.org",
userID: "@userid:example.com"))
clientProxy.isAliasAvailableReturnValue = .success(isAliasAvailable)
let spaces = [SpaceServiceRoomProtocol].mockJoinedSpaces2
let spaces = [SpaceServiceRoom].mockJoinedSpaces2
clientProxy.spaceService = SpaceServiceProxyMock(.init(editableSpaces: spaces))
let userSession = UserSessionMock(.init(clientProxy: clientProxy))
@@ -18,7 +18,7 @@ struct JoinRoomScreenCoordinatorParameters {
enum JoinRoomScreenSource {
case generic(roomID: String, via: [String])
case space(SpaceServiceRoomProtocol)
case space(SpaceServiceRoom)
func roomIDAndVia() -> (roomID: String, via: [String]) {
switch self {
@@ -200,7 +200,7 @@ class JoinRoomScreenViewModel: JoinRoomScreenViewModelType, JoinRoomScreenViewMo
spaceVisibility: nil)
}
private func updateSpaceRoomDetails(spaceServiceRoom: SpaceServiceRoomProtocol, inviter: RoomInviterDetails?) async {
private func updateSpaceRoomDetails(spaceServiceRoom: SpaceServiceRoom, inviter: RoomInviterDetails?) async {
state.roomDetails = JoinRoomScreenRoomDetails(name: spaceServiceRoom.name,
topic: spaceServiceRoom.topic,
canonicalAlias: spaceServiceRoom.canonicalAlias,
@@ -447,7 +447,7 @@ struct JoinRoomScreenPreviewWrapper: Identifiable {
}
let source: JoinRoomScreenSource = if isSpace {
.space(SpaceServiceRoomMock(mode: mode))
.space(SpaceServiceRoom.mock(joinRoomScreenMode: mode))
} else {
.generic(roomID: "1", via: [])
}
@@ -37,7 +37,7 @@ enum ManageAuthorizedSpacesScreenViewAction {
}
struct AuthorizedSpacesSelection {
let joinedSpaces: [SpaceServiceRoomProtocol]
let joinedSpaces: [SpaceServiceRoom]
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: SpaceServiceRoomProtocol) -> some View {
private func avatar(space: SpaceServiceRoom) -> 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: [SpaceServiceRoomProtocol] = []
var selectableJoinedSpaces: [SpaceServiceRoom] = []
/// 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(SpaceServiceRoomProtocol)
case singleJoined(SpaceServiceRoom)
/// 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: [SpaceServiceRoomProtocol] = []
var joinedParentSpaces: [SpaceServiceRoom] = []
switch await clientProxy.spaceService.joinedParents(childID: roomProxy.id) {
case .success(let value):
joinedParentSpaces = value
@@ -313,7 +313,7 @@ class SecurityAndPrivacyScreenViewModel: SecurityAndPrivacyScreenViewModelType,
break
}
var nonParentJoinedSpaces: [SpaceServiceRoomProtocol] = []
var nonParentJoinedSpaces: [SpaceServiceRoom] = []
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 = [SpaceServiceRoomProtocol].mockSingleRoom[0]
let space = [SpaceServiceRoom].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 = [SpaceServiceRoomProtocol].mockJoinedSpaces
let spaces = [SpaceServiceRoom].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 = [SpaceServiceRoomProtocol].mockSingleRoom[0]
let space = [SpaceServiceRoom].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 = [SpaceServiceRoomProtocol].mockJoinedSpaces
let spaces = [SpaceServiceRoom].mockJoinedSpaces
return SecurityAndPrivacyScreenViewModel(roomProxy: JoinedRoomProxyMock(.init(isEncrypted: false,
canonicalAlias: "#room:matrix.org",
@@ -10,7 +10,7 @@ import Compound
import SwiftUI
struct SpaceHeaderView: View {
let spaceServiceRoom: SpaceServiceRoomProtocol
let spaceServiceRoom: SpaceServiceRoom
let mediaProvider: MediaProviderProtocol?
@State private var isPresentingTopic = false
@@ -112,36 +112,36 @@ struct SpaceHeaderView_Previews: PreviewProvider, TestablePreview {
}
}
static func makeSpaceRooms() -> [SpaceServiceRoomMock] {
static func makeSpaceRooms() -> [SpaceServiceRoom] {
[
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: "")])))
SpaceServiceRoom.mock(id: "!space1:matrix.org",
name: "Company Space",
isSpace: true,
childrenCount: 10,
joinedMembersCount: 50),
SpaceServiceRoom.mock(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),
SpaceServiceRoom.mock(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: "")]))
]
}
}
@@ -14,12 +14,12 @@ struct SpaceRoomCell: View {
@Environment(\.dynamicTypeSize) private var dynamicTypeSize
@Environment(\.editMode) private var editMode
let spaceServiceRoom: SpaceServiceRoomProtocol
let spaceServiceRoom: SpaceServiceRoom
let isSelected: Bool
var isJoining = false
let mediaProvider: MediaProviderProtocol!
enum Action { case select(SpaceServiceRoomProtocol), join(SpaceServiceRoomProtocol) }
enum Action { case select(SpaceServiceRoom), join(SpaceServiceRoom) }
let action: (Action) -> Void
private let verticalInsets = 12.0
@@ -179,7 +179,7 @@ struct SpaceRoomCellButtonStyle: ButtonStyle {
struct SpaceRoomCell_Previews: PreviewProvider, TestablePreview {
static let mediaProvider = MediaProviderMock(configuration: .init())
static let spaces = [SpaceServiceRoomProtocol].mockSpaceList
static let spaces = [SpaceServiceRoom].mockSpaceList
static var previews: some View {
ScrollView {
@@ -190,21 +190,21 @@ struct SpaceRoomCell_Previews: PreviewProvider, TestablePreview {
mediaProvider: mediaProvider) { _ in }
}
SpaceRoomCell(spaceServiceRoom: SpaceServiceRoomMock(.init(id: "Space being joined", isSpace: true)),
SpaceRoomCell(spaceServiceRoom: SpaceServiceRoom.mock(id: "Space being joined", isSpace: true),
isSelected: false,
isJoining: true,
mediaProvider: mediaProvider) { _ in }
SpaceRoomCell(spaceServiceRoom: SpaceServiceRoomMock(.init(id: "Room being joined", isSpace: false)),
SpaceRoomCell(spaceServiceRoom: SpaceServiceRoom.mock(id: "Room being joined", isSpace: false),
isSelected: false,
isJoining: true,
mediaProvider: mediaProvider) { _ in }
SpaceRoomCell(spaceServiceRoom: SpaceServiceRoomMock(.init(id: "Selected", isSpace: false, state: .joined)),
SpaceRoomCell(spaceServiceRoom: SpaceServiceRoom.mock(id: "Selected", isSpace: false, state: .joined),
isSelected: true,
isJoining: false,
mediaProvider: mediaProvider) { _ in }
.environment(\.editMode, .constant(.active))
SpaceRoomCell(spaceServiceRoom: SpaceServiceRoomMock(.init(id: "Unselected", isSpace: false, state: .joined)),
SpaceRoomCell(spaceServiceRoom: SpaceServiceRoom.mock(id: "Unselected", isSpace: false, state: .joined),
isSelected: false,
isJoining: false,
mediaProvider: mediaProvider) { _ in }
@@ -91,45 +91,45 @@ struct LeaveSpaceRoomDetailsCell: View {
struct LeaveSpaceRoomDetailsCell_Previews: PreviewProvider, TestablePreview {
static var previews: some View {
VStack(spacing: 0) {
LeaveSpaceRoomDetailsCell(room: .init(spaceServiceRoom: SpaceServiceRoomMock(.init(id: "1",
name: "Space",
isSpace: true)),
LeaveSpaceRoomDetailsCell(room: .init(spaceServiceRoom: SpaceServiceRoom.mock(id: "1",
name: "Space",
isSpace: true),
isLastOwner: false,
areCreatorsPrivileged: false,
isSelected: true),
mediaProvider: MediaProviderMock(configuration: .init())) { }
LeaveSpaceRoomDetailsCell(room: .init(spaceServiceRoom: SpaceServiceRoomMock(.init(id: "2",
name: "My Space",
isSpace: true)),
LeaveSpaceRoomDetailsCell(room: .init(spaceServiceRoom: SpaceServiceRoom.mock(id: "2",
name: "My Space",
isSpace: true),
isLastOwner: true,
areCreatorsPrivileged: false,
isSelected: false),
mediaProvider: MediaProviderMock(configuration: .init())) { }
LeaveSpaceRoomDetailsCell(room: .init(spaceServiceRoom: SpaceServiceRoomMock(.init(id: "2",
name: "My Space",
isSpace: true)),
LeaveSpaceRoomDetailsCell(room: .init(spaceServiceRoom: SpaceServiceRoom.mock(id: "2",
name: "My Space",
isSpace: true),
isLastOwner: true,
areCreatorsPrivileged: false,
isSelected: false),
hideSelection: true,
mediaProvider: MediaProviderMock(configuration: .init())) { }
LeaveSpaceRoomDetailsCell(room: .init(spaceServiceRoom: SpaceServiceRoomMock(.init(id: "3",
name: "Room",
isSpace: false)),
LeaveSpaceRoomDetailsCell(room: .init(spaceServiceRoom: SpaceServiceRoom.mock(id: "3",
name: "Room",
isSpace: false),
isLastOwner: false,
areCreatorsPrivileged: false,
isSelected: true),
mediaProvider: MediaProviderMock(configuration: .init())) { }
LeaveSpaceRoomDetailsCell(room: .init(spaceServiceRoom: SpaceServiceRoomMock(.init(id: "4",
name: "My Room",
isSpace: false)),
LeaveSpaceRoomDetailsCell(room: .init(spaceServiceRoom: SpaceServiceRoom.mock(id: "4",
name: "My Room",
isSpace: false),
isLastOwner: true,
areCreatorsPrivileged: false,
isSelected: false),
mediaProvider: MediaProviderMock(configuration: .init())) { }
LeaveSpaceRoomDetailsCell(room: .init(spaceServiceRoom: SpaceServiceRoomMock(.init(id: "4",
name: "My Room",
isSpace: false)),
LeaveSpaceRoomDetailsCell(room: .init(spaceServiceRoom: SpaceServiceRoom.mock(id: "4",
name: "My Room",
isSpace: false),
isLastOwner: true,
areCreatorsPrivileged: false,
isSelected: false),
@@ -136,14 +136,14 @@ struct LeaveSpaceView_Previews: PreviewProvider, TestablePreview {
.previewDisplayName("Last Space Admin")
}
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 let spaceServiceRoom = SpaceServiceRoom.mock(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 {
@@ -184,7 +184,7 @@ struct SpaceAddRoomsScreen_Previews: PreviewProvider, TestablePreview {
}
static func makeViewModel(searchQuery: String? = nil, hasSelection: Bool = false) -> SpaceAddRoomsScreenViewModel {
let spaceRoomListProxy = SpaceRoomListProxyMock(.init(spaceServiceRoom: SpaceServiceRoomMock(.init(isSpace: true))))
let spaceRoomListProxy = SpaceRoomListProxyMock(.init(spaceServiceRoom: SpaceServiceRoom.mock(isSpace: true)))
let clientProxy = ClientProxyMock(.init())
clientProxy.recentlyVisitedRoomsFilterReturnValue = .mockRooms
@@ -22,14 +22,14 @@ struct SpaceScreenCoordinatorParameters {
enum SpaceScreenCoordinatorAction {
case selectSpace(SpaceRoomListProxyProtocol)
case selectUnjoinedSpace(SpaceServiceRoomProtocol)
case selectUnjoinedSpace(SpaceServiceRoom)
case selectRoom(roomID: String)
case leftSpace
case displayMembers(roomProxy: JoinedRoomProxyProtocol)
case displaySpaceSettings(roomProxy: JoinedRoomProxyProtocol)
case displayRolesAndPermissions(roomProxy: JoinedRoomProxyProtocol)
case addExistingChildren
case displayCreateChildRoomFlow(space: SpaceServiceRoomProtocol)
case displayCreateChildRoomFlow(space: SpaceServiceRoom)
}
final class SpaceScreenCoordinator: CoordinatorProtocol {
@@ -10,24 +10,24 @@ import SwiftUI
enum SpaceScreenViewModelAction {
case selectSpace(SpaceRoomListProxyProtocol)
case selectUnjoinedSpace(SpaceServiceRoomProtocol)
case selectUnjoinedSpace(SpaceServiceRoom)
case selectRoom(roomID: String)
case leftSpace
case presentRolesAndPermissions(roomProxy: JoinedRoomProxyProtocol)
case displayMembers(roomProxy: JoinedRoomProxyProtocol)
case displaySpaceSettings(roomProxy: JoinedRoomProxyProtocol)
case addExistingChildren
case displayCreateChildRoomFlow(space: SpaceServiceRoomProtocol)
case displayCreateChildRoomFlow(space: SpaceServiceRoom)
}
struct SpaceScreenViewState: BindableState {
var space: SpaceServiceRoomProtocol
var space: SpaceServiceRoom
var permalink: URL?
var roomProxy: JoinedRoomProxyProtocol?
var paginationState: PaginationState = .idle
var rooms: [SpaceServiceRoomProtocol]
var rooms: [SpaceServiceRoom]
var selectedSpaceRoomID: String?
var joiningRoomIDs: Set<String> = []
@@ -47,7 +47,7 @@ struct SpaceScreenViewState: BindableState {
rooms.isEmpty && paginationState == .endReached && canEditChildren
}
var visibleRooms: [SpaceServiceRoomProtocol] {
var visibleRooms: [SpaceServiceRoom] {
if editMode == .inactive {
rooms
} else {
@@ -182,7 +182,7 @@ class SpaceScreenViewModel: SpaceScreenViewModelType, SpaceScreenViewModelProtoc
}
}
private func join(_ spaceServiceRoom: SpaceServiceRoomProtocol) async {
private func join(_ spaceServiceRoom: SpaceServiceRoom) async {
state.joiningRoomIDs.insert(spaceServiceRoom.id)
defer { state.joiningRoomIDs.remove(spaceServiceRoom.id) }
@@ -194,7 +194,7 @@ class SpaceScreenViewModel: SpaceScreenViewModelType, SpaceScreenViewModelProtoc
// We don't want to show the space room after joining it this way 🤷‍♂️
}
private func selectSpace(_ spaceServiceRoom: SpaceServiceRoomProtocol) async {
private func selectSpace(_ spaceServiceRoom: SpaceServiceRoom) async {
switch await spaceServiceProxy.spaceRoomList(spaceID: spaceServiceRoom.id) {
case .success(let spaceRoomListProxy):
actionsSubject.send(.selectSpace(spaceRoomListProxy))
@@ -210,15 +210,15 @@ struct SpaceScreen_Previews: PreviewProvider, TestablePreview {
appSettings.spaceSettingsEnabled = true
appSettings.createSpaceEnabled = true
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 spaceServiceRoom = SpaceServiceRoom.mock(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: isNewSpace ? [] : .mockSpaceList))
@@ -19,7 +19,7 @@ struct SpacesScreenViewState: BindableState {
var userDisplayName: String?
var userAvatarURL: URL?
var topLevelSpaces: [SpaceServiceRoomProtocol]
var topLevelSpaces: [SpaceServiceRoom]
var selectedSpaceID: String?
var isCreateSpaceEnabled: Bool
@@ -85,7 +85,7 @@ class SpacesScreenViewModel: SpacesScreenViewModelType, SpacesScreenViewModelPro
// MARK: - Private
private func selectSpace(_ spaceServiceRoom: SpaceServiceRoomProtocol) async {
private func selectSpace(_ spaceServiceRoom: SpaceServiceRoom) async {
switch await spaceServiceProxy.spaceRoomList(spaceID: spaceServiceRoom.id) {
case .success(let spaceRoomListProxy):
actionsSubject.send(.selectSpace(spaceRoomListProxy))
@@ -87,12 +87,12 @@ final class LeaveSpaceHandleProxy {
}
@Observable class LeaveSpaceRoomDetails {
let spaceServiceRoom: SpaceServiceRoomProtocol
let spaceServiceRoom: SpaceServiceRoom
let canLeave: Bool
let areCreatorsPrivileged: Bool
var isSelected: Bool
init(spaceServiceRoom: SpaceServiceRoomProtocol, isLastOwner: Bool, areCreatorsPrivileged: Bool, isSelected: Bool) {
init(spaceServiceRoom: SpaceServiceRoom, isLastOwner: Bool, areCreatorsPrivileged: Bool, isSelected: Bool) {
self.spaceServiceRoom = spaceServiceRoom
canLeave = !isLastOwner || spaceServiceRoom.joinedMembersCount == 1
self.isSelected = isSelected
@@ -15,14 +15,14 @@ class SpaceRoomListProxy: SpaceRoomListProxyProtocol {
private let spaceRoomList: SpaceRoomListProtocol
private var spaceServiceRoomHandle: TaskHandle?
private let spaceServiceRoomSubject: CurrentValueSubject<SpaceServiceRoomProtocol, Never>
var spaceServiceRoomPublisher: CurrentValuePublisher<SpaceServiceRoomProtocol, Never> {
private let spaceServiceRoomSubject: CurrentValueSubject<SpaceServiceRoom, Never>
var spaceServiceRoomPublisher: CurrentValuePublisher<SpaceServiceRoom, Never> {
spaceServiceRoomSubject.asCurrentValuePublisher()
}
private var spaceRoomsHandle: TaskHandle?
private let spaceRoomsSubject = CurrentValueSubject<[SpaceServiceRoomProtocol], Never>([])
var spaceRoomsPublisher: CurrentValuePublisher<[SpaceServiceRoomProtocol], Never> {
private let spaceRoomsSubject = CurrentValueSubject<[SpaceServiceRoom], Never>([])
var spaceRoomsPublisher: CurrentValuePublisher<[SpaceServiceRoom], Never> {
spaceRoomsSubject.asCurrentValuePublisher()
}
@@ -17,8 +17,8 @@ enum SpaceRoomListProxyError: Error {
protocol SpaceRoomListProxyProtocol {
var id: String { get }
var spaceServiceRoomPublisher: CurrentValuePublisher<SpaceServiceRoomProtocol, Never> { get }
var spaceRoomsPublisher: CurrentValuePublisher<[SpaceServiceRoomProtocol], Never> { get }
var spaceServiceRoomPublisher: CurrentValuePublisher<SpaceServiceRoom, Never> { get }
var spaceRoomsPublisher: CurrentValuePublisher<[SpaceServiceRoom], Never> { get }
var paginationStatePublisher: CurrentValuePublisher<SpaceRoomListPaginationState, Never> { get }
func paginate() async
@@ -14,8 +14,8 @@ class SpaceServiceProxy: SpaceServiceProxyProtocol {
private let spaceService: SpaceServiceProtocol
private var topLevelSpacesHandle: TaskHandle?
private let spacesSubject = CurrentValueSubject<[SpaceServiceRoomProtocol], Never>([])
var topLevelSpacesPublisher: CurrentValuePublisher<[SpaceServiceRoomProtocol], Never> {
private let spacesSubject = CurrentValueSubject<[SpaceServiceRoom], Never>([])
var topLevelSpacesPublisher: CurrentValuePublisher<[SpaceServiceRoom], Never> {
spacesSubject.asCurrentValuePublisher()
}
@@ -50,7 +50,7 @@ class SpaceServiceProxy: SpaceServiceProxyProtocol {
}
}
func spaceForIdentifier(spaceID: String) async -> Result<SpaceServiceRoomProtocol?, SpaceServiceProxyError> {
func spaceForIdentifier(spaceID: String) async -> Result<SpaceServiceRoom?, SpaceServiceProxyError> {
do {
return try await .success(spaceService.getSpaceRoom(roomId: spaceID).map(SpaceServiceRoom.init))
} catch {
@@ -68,7 +68,7 @@ class SpaceServiceProxy: SpaceServiceProxyProtocol {
}
}
func joinedParents(childID: String) async -> Result<[SpaceServiceRoomProtocol], SpaceServiceProxyError> {
func joinedParents(childID: String) async -> Result<[SpaceServiceRoom], SpaceServiceProxyError> {
do {
return try await .success(spaceService.joinedParentsOfChild(childId: childID).map(SpaceServiceRoom.init))
} catch {
@@ -77,7 +77,7 @@ class SpaceServiceProxy: SpaceServiceProxyProtocol {
}
}
func editableSpaces() async -> [SpaceServiceRoomProtocol] {
func editableSpaces() async -> [SpaceServiceRoom] {
await spaceService.editableSpaces().map(SpaceServiceRoom.init)
}
@@ -15,11 +15,11 @@ enum SpaceServiceProxyError: Error {
}
struct SpaceServiceFilter: Identifiable, Equatable {
let room: SpaceServiceRoomProtocol
let room: SpaceServiceRoom
let level: UInt
let descendants: Set<String>
init(room: SpaceServiceRoomProtocol, level: UInt, descendants: Set<String>) {
init(room: SpaceServiceRoom, level: UInt, descendants: Set<String>) {
self.room = room
self.level = level
self.descendants = descendants
@@ -43,17 +43,17 @@ struct SpaceServiceFilter: Identifiable, Equatable {
// sourcery: AutoMockable
protocol SpaceServiceProxyProtocol {
var topLevelSpacesPublisher: CurrentValuePublisher<[SpaceServiceRoomProtocol], Never> { get }
var topLevelSpacesPublisher: CurrentValuePublisher<[SpaceServiceRoom], Never> { get }
var spaceFilterPublisher: CurrentValuePublisher<[SpaceServiceFilter], Never> { get }
func spaceRoomList(spaceID: String) async -> Result<SpaceRoomListProxyProtocol, SpaceServiceProxyError>
/// Returns a joined space given its identifier
func spaceForIdentifier(spaceID: String) async -> Result<SpaceServiceRoomProtocol?, SpaceServiceProxyError>
func spaceForIdentifier(spaceID: String) async -> Result<SpaceServiceRoom?, SpaceServiceProxyError>
func leaveSpace(spaceID: String) async -> Result<LeaveSpaceHandleProxy, SpaceServiceProxyError>
/// Returns all the parent spaces of a child that user has joined.
func joinedParents(childID: String) async -> Result<[SpaceServiceRoomProtocol], SpaceServiceProxyError>
func joinedParents(childID: String) async -> Result<[SpaceServiceRoom], SpaceServiceProxyError>
/// Returns all the joined spaces that can be edited by the user
func editableSpaces() async -> [SpaceServiceRoomProtocol]
func editableSpaces() async -> [SpaceServiceRoom]
/// Adds a room (or space) as a child of another space.
func addChild(_ childID: String, to spaceID: String) async -> Result<Void, SpaceServiceProxyError>
@@ -9,7 +9,14 @@
import Foundation
import MatrixRustSDK
struct SpaceServiceRoom: SpaceServiceRoomProtocol {
enum SpaceServiceRoomVisibility: Equatable {
case `public`
case `private`
case restricted
// We can add the external case in here eventually.
}
struct SpaceServiceRoom {
var id: String
var name: String
var rawName: String?
@@ -30,6 +37,31 @@ struct SpaceServiceRoom: SpaceServiceRoomProtocol {
var state: Membership?
var via: [String]
var avatar: RoomAvatar {
if isSpace {
.space(id: id, name: name, avatarURL: avatarURL)
} else if isDirect == true, avatarURL == nil, heroes.count == 1 {
.heroes(heroes)
} else {
.room(id: id, name: name, avatarURL: avatarURL)
}
}
var visibility: SpaceServiceRoomVisibility? {
switch joinRule {
case .public:
.public
case .restricted, .knockRestricted:
.restricted
case .invite, .knock, .private, .custom:
.private
case .none:
.none
}
}
}
extension SpaceServiceRoom {
init(spaceRoom: SpaceRoom) {
id = spaceRoom.roomId
name = spaceRoom.displayName
@@ -51,4 +83,193 @@ struct SpaceServiceRoom: SpaceServiceRoomProtocol {
state = spaceRoom.state
via = spaceRoom.via
}
// MARK: - Mocks
static func mock(id: String = UUID().uuidString,
name: String? = nil,
rawName: String? = nil,
avatarURL: URL? = nil,
isSpace: Bool,
isDirect: Bool? = nil,
childrenCount: Int = 0,
joinedMembersCount: Int = 0,
heroes: [UserProfileProxy] = [],
topic: String? = nil,
canonicalAlias: String? = nil,
joinRule: JoinRule? = nil,
worldReadable: Bool? = nil,
guestCanJoin: Bool = true,
state: Membership? = nil,
via: [String] = []) -> Self {
SpaceServiceRoom(id: id,
name: name ?? id,
rawName: rawName,
avatarURL: avatarURL,
isSpace: isSpace,
isDirect: isDirect,
childrenCount: childrenCount,
joinedMembersCount: joinedMembersCount,
heroes: heroes,
topic: topic,
canonicalAlias: canonicalAlias,
joinRule: joinRule,
worldReadable: worldReadable,
guestCanJoin: guestCanJoin,
state: state,
via: via)
}
static func mock(joinRoomScreenMode: JoinRoomScreenMode) -> Self {
var state: Membership?
var joinRule: JoinRule?
switch joinRoomScreenMode {
case .joinable:
joinRule = .public
case .restricted:
joinRule = .restricted(rules: [])
case .inviteRequired:
joinRule = .private
case .invited:
state = .invited
joinRule = .private
case .knockable:
joinRule = .knock
case .knocked:
state = .knocked
joinRule = .knock
case .banned:
state = .banned
case .loading, .unknown, .forbidden:
break
}
return SpaceServiceRoom.mock(id: "1",
name: "The Three-Body Problem",
avatarURL: .mockMXCAvatar,
isSpace: true,
childrenCount: 100,
joinedMembersCount: 123,
heroes: [.mockAlice, .mockBob, .mockCharlie],
topic: "“Science and technology were the only keys to opening the door to the future, and people approached science with the faith and sincerity of elementary school students.”",
canonicalAlias: "#3-body-problem:matrix.org",
joinRule: joinRule,
state: state)
}
}
extension [SpaceServiceRoom] {
static var mockJoinedSpaces: [SpaceServiceRoom] {
[
SpaceServiceRoom.mock(id: "space1",
name: "The Foundation",
isSpace: true,
childrenCount: 1,
joinedMembersCount: 500,
canonicalAlias: "#the-foundation:matrix.org",
state: .joined),
SpaceServiceRoom.mock(id: "space2",
name: "The Second Foundation",
isSpace: true,
childrenCount: 1,
joinedMembersCount: 100,
state: .joined),
SpaceServiceRoom.mock(id: "space3",
name: "The Galactic Empire",
isSpace: true,
childrenCount: 25000,
joinedMembersCount: 1_000_000_000,
canonicalAlias: "#the-galactic-empire:matrix.org",
state: .joined),
SpaceServiceRoom.mock(id: "space4",
name: "The Korellians",
isSpace: true,
childrenCount: 27,
joinedMembersCount: 2_000_000,
state: .joined),
SpaceServiceRoom.mock(id: "space5",
name: "The Luminists",
isSpace: true,
childrenCount: 1,
joinedMembersCount: 100_000,
state: .joined),
SpaceServiceRoom.mock(id: "space6",
name: "The Anacreons",
isSpace: true,
childrenCount: 25,
joinedMembersCount: 400_000,
state: .joined),
SpaceServiceRoom.mock(id: "space7",
name: "The Thespians",
isSpace: true,
childrenCount: 15,
joinedMembersCount: 300_000,
state: .joined)
]
}
static var mockJoinedSpaces2: [SpaceServiceRoom] {
[
SpaceServiceRoom.mock(id: "space1",
name: "The Foundation",
avatarURL: .mockMXCAvatar,
isSpace: true,
childrenCount: 1,
joinedMembersCount: 500,
canonicalAlias: "#the-foundation:matrix.org",
joinRule: .private,
state: .joined),
SpaceServiceRoom.mock(id: "space2",
name: "The Second Foundation",
isSpace: true,
childrenCount: 1,
joinedMembersCount: 100,
state: .joined),
SpaceServiceRoom.mock(id: "space3",
name: "The Galactic Empire",
isSpace: true,
childrenCount: 25000,
joinedMembersCount: 1_000_000_000,
canonicalAlias: "#the-galactic-empire:matrix.org",
state: .joined)
]
}
static var mockSpaceList: [SpaceServiceRoom] {
makeSpaceRooms(isSpace: true) + makeSpaceRooms(isSpace: false)
}
static var mockSingleRoom: [SpaceServiceRoom] {
[SpaceServiceRoom.mock(id: "!spaceroom:matrix.org",
name: "Management",
isSpace: false,
joinedMembersCount: 12,
topic: "This is where everything gets organised 📋.",
state: .joined)]
}
private static func makeSpaceRooms(isSpace: Bool) -> [SpaceServiceRoom] {
let typeName = isSpace ? "Space" : "Room"
return [
SpaceServiceRoom.mock(id: "!\(typeName.lowercased())1:matrix.org",
name: "Company \(typeName)",
isSpace: isSpace),
SpaceServiceRoom.mock(id: "!\(typeName.lowercased())2:matrix.org",
name: "Public \(typeName)",
avatarURL: .mockMXCAvatar,
isSpace: isSpace,
joinedMembersCount: 78,
topic: "Discussion on specific topic goes here.",
joinRule: .public),
SpaceServiceRoom.mock(id: "!\(typeName.lowercased())3:matrix.org",
name: "Joined \(typeName)",
isSpace: isSpace,
joinedMembersCount: 123,
topic: "Discussion on specific topic goes here.",
joinRule: .restricted(rules: []),
state: .joined)
]
}
}
@@ -1,65 +0,0 @@
//
// Copyright 2025 Element Creations Ltd.
// Copyright 2025 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
// Please see LICENSE files in the repository root for full details.
//
import Foundation
import MatrixRustSDK
enum SpaceServiceRoomVisibility: Equatable {
case `public`
case `private`
case restricted
// We can add the external case in here eventually.
}
// sourcery: AutoMockable
protocol SpaceServiceRoomProtocol {
var id: String { get }
var name: String { get }
var rawName: String? { get }
var avatarURL: URL? { get }
var isSpace: Bool { get }
var isDirect: Bool? { get }
var childrenCount: Int { get }
var joinedMembersCount: Int { get }
var heroes: [UserProfileProxy] { get }
var topic: String? { get }
var canonicalAlias: String? { get }
var joinRule: JoinRule? { get }
var worldReadable: Bool? { get }
var guestCanJoin: Bool { get }
var state: Membership? { get }
var via: [String] { get }
}
extension SpaceServiceRoomProtocol {
var avatar: RoomAvatar {
if isSpace {
.space(id: id, name: name, avatarURL: avatarURL)
} else if isDirect == true, avatarURL == nil, heroes.count == 1 {
.heroes(heroes)
} else {
.room(id: id, name: name, avatarURL: avatarURL)
}
}
var visibility: SpaceServiceRoomVisibility? {
switch joinRule {
case .public:
.public
case .restricted, .knockRestricted:
.restricted
case .invite, .knock, .private, .custom:
.private
case .none:
.none
}
}
}
@@ -598,7 +598,7 @@ class MockScreen: Identifiable {
deviceID: "MOCKCLIENT",
roomSummaryProvider: RoomSummaryProviderMock(.init(state: .loaded(roomSummaries))),
spaceServiceConfiguration: .init(topLevelSpaces: .mockSpaceList.filter(\.isSpace) + .mockSingleRoom),
roomPreviews: [SpaceServiceRoomProtocol].mockSpaceList.map(RoomPreviewProxyMock.init),
roomPreviews: [SpaceServiceRoom].mockSpaceList.map(RoomPreviewProxyMock.init),
defaultRoomMembers: .allMembersAsAdmin))
clientProxy.recentlyVisitedRoomsFilterReturnValue = .mockRooms