mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-10-31 08:15:24 +00:00
Add hooks for room creation and privacy & security settings screen. (#6270)
Add hooks for the create room and security and privacy screens.
This commit is contained in:
@@ -48,6 +48,12 @@ final nonisolated class AppHooks: AppHooksProtocol {
|
||||
|
||||
@AppHook(default: DefaultRecoveryKeyScreenHook())
|
||||
var recoveryKeyScreenHook: RecoveryKeyScreenHookProtocol
|
||||
|
||||
@AppHook(default: DefaultCreateRoomScreenHook())
|
||||
var createRoomScreenHook: CreateRoomScreenHookProtocol
|
||||
|
||||
@AppHook(default: DefaultSecurityAndPrivacyScreenHook())
|
||||
var securityAndPrivacyScreenHook: SecurityAndPrivacyScreenHookProtocol
|
||||
#endif
|
||||
|
||||
@AppHook(default: DefaultTracingHook())
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// Copyright 2026 Element Creations 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
|
||||
|
||||
nonisolated protocol CreateRoomScreenHookProtocol: Sendable {
|
||||
@MainActor func update(_ viewState: CreateRoomScreenViewState, homeserver: String) -> CreateRoomScreenViewState
|
||||
}
|
||||
|
||||
struct DefaultCreateRoomScreenHook: CreateRoomScreenHookProtocol {
|
||||
func update(_ viewState: CreateRoomScreenViewState, homeserver: String) -> CreateRoomScreenViewState {
|
||||
viewState
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// Copyright 2026 Element Creations 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
|
||||
|
||||
nonisolated protocol SecurityAndPrivacyScreenHookProtocol: Sendable {
|
||||
@MainActor func update(_ viewState: SecurityAndPrivacyScreenViewState, homeserver: String) -> SecurityAndPrivacyScreenViewState
|
||||
}
|
||||
|
||||
struct DefaultSecurityAndPrivacyScreenHook: SecurityAndPrivacyScreenHookProtocol {
|
||||
func update(_ viewState: SecurityAndPrivacyScreenViewState, homeserver: String) -> SecurityAndPrivacyScreenViewState {
|
||||
viewState
|
||||
}
|
||||
}
|
||||
@@ -1420,7 +1420,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
let coordinator = SecurityAndPrivacyScreenCoordinator(parameters: .init(roomProxy: roomProxy,
|
||||
clientProxy: userSession.clientProxy,
|
||||
userIndicatorController: flowParameters.userIndicatorController,
|
||||
appSetting: flowParameters.userSettings))
|
||||
appSetting: flowParameters.userSettings,
|
||||
appHooks: flowParameters.appHooks))
|
||||
|
||||
coordinator.actionsPublisher.sink { [weak self] action in
|
||||
guard let self else { return }
|
||||
|
||||
@@ -278,7 +278,8 @@ final class SpaceSettingsFlowCoordinator: FlowCoordinatorProtocol {
|
||||
let coordinator = SecurityAndPrivacyScreenCoordinator(parameters: .init(roomProxy: roomProxy,
|
||||
clientProxy: flowParameters.userSession.clientProxy,
|
||||
userIndicatorController: flowParameters.userIndicatorController,
|
||||
appSetting: flowParameters.userSettings))
|
||||
appSetting: flowParameters.userSettings,
|
||||
appHooks: flowParameters.appHooks))
|
||||
|
||||
coordinator.actionsPublisher.sink { [weak self] action in
|
||||
guard let self else { return }
|
||||
|
||||
@@ -215,7 +215,8 @@ class StartChatFlowCoordinator: FlowCoordinatorProtocol {
|
||||
userSession: flowParameters.userSession,
|
||||
userIndicatorController: flowParameters.userIndicatorController,
|
||||
userSettings: flowParameters.userSettings,
|
||||
analytics: flowParameters.analytics)
|
||||
analytics: flowParameters.analytics,
|
||||
appHooks: flowParameters.appHooks)
|
||||
let coordinator = CreateRoomScreenCoordinator(parameters: createParameters)
|
||||
coordinator.actions.sink { [weak self] action in
|
||||
guard let self else { return }
|
||||
|
||||
@@ -17,6 +17,7 @@ struct CreateRoomScreenCoordinatorParameters {
|
||||
let userIndicatorController: UserIndicatorControllerProtocol
|
||||
let userSettings: UserSettings
|
||||
let analytics: AnalyticsServiceProtocol
|
||||
let appHooks: AppHooks
|
||||
}
|
||||
|
||||
enum CreateRoomScreenCoordinatorAction {
|
||||
@@ -41,7 +42,8 @@ final class CreateRoomScreenCoordinator: CoordinatorProtocol {
|
||||
userSession: parameters.userSession,
|
||||
analytics: parameters.analytics,
|
||||
userIndicatorController: parameters.userIndicatorController,
|
||||
userSettings: parameters.userSettings)
|
||||
userSettings: parameters.userSettings,
|
||||
appHooks: parameters.appHooks)
|
||||
}
|
||||
|
||||
func start() {
|
||||
|
||||
@@ -31,6 +31,7 @@ struct CreateRoomScreenViewState: BindableState {
|
||||
var roomName: String
|
||||
let serverName: String
|
||||
let isKnockingFeatureEnabled: Bool
|
||||
var isPublicAccessAllowed = true
|
||||
let canSelectSpace: Bool
|
||||
var aliasLocalPart: String
|
||||
var editableSpaces: [SpaceServiceRoom] = []
|
||||
@@ -69,6 +70,11 @@ struct CreateRoomScreenViewState: BindableState {
|
||||
}
|
||||
}
|
||||
availableAccessTypes.append(.private)
|
||||
|
||||
if !isPublicAccessAllowed {
|
||||
availableAccessTypes.removeAll { $0 == .public }
|
||||
}
|
||||
|
||||
return availableAccessTypes
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,8 @@ class CreateRoomScreenViewModel: CreateRoomScreenViewModelType, CreateRoomScreen
|
||||
userSession: UserSessionProtocol,
|
||||
analytics: AnalyticsServiceProtocol,
|
||||
userIndicatorController: UserIndicatorControllerProtocol,
|
||||
userSettings: UserSettings) {
|
||||
userSettings: UserSettings,
|
||||
appHooks: AppHooks) {
|
||||
self.userSession = userSession
|
||||
mediaUploadingPreprocessor = MediaUploadingPreprocessor(userSettings: userSettings)
|
||||
self.analytics = analytics
|
||||
@@ -59,14 +60,16 @@ class CreateRoomScreenViewModel: CreateRoomScreenViewModelType, CreateRoomScreen
|
||||
selectedAccessType: selectedAccessType,
|
||||
selectedSpace: selectedSpace)
|
||||
|
||||
super.init(initialViewState: CreateRoomScreenViewState(isSpace: isSpace,
|
||||
shouldShowCancelButton: shouldShowCancelButton,
|
||||
roomName: "",
|
||||
serverName: userSession.clientProxy.userIDServerName ?? "",
|
||||
isKnockingFeatureEnabled: userSettings.knockingEnabled,
|
||||
canSelectSpace: canSelectSpace,
|
||||
aliasLocalPart: roomAliasNameFromRoomDisplayName(roomName: ""),
|
||||
bindings: bindings),
|
||||
let viewState = CreateRoomScreenViewState(isSpace: isSpace,
|
||||
shouldShowCancelButton: shouldShowCancelButton,
|
||||
roomName: "",
|
||||
serverName: userSession.clientProxy.userIDServerName ?? "",
|
||||
isKnockingFeatureEnabled: userSettings.knockingEnabled,
|
||||
canSelectSpace: canSelectSpace,
|
||||
aliasLocalPart: roomAliasNameFromRoomDisplayName(roomName: ""),
|
||||
bindings: bindings)
|
||||
|
||||
super.init(initialViewState: appHooks.createRoomScreenHook.update(viewState, homeserver: userSession.clientProxy.homeserver),
|
||||
mediaProvider: userSession.mediaProvider)
|
||||
|
||||
setupBindings()
|
||||
|
||||
@@ -467,6 +467,7 @@ struct CreateRoom_Previews: PreviewProvider, TestablePreview {
|
||||
userSession: userSession,
|
||||
analytics: AnalyticsServiceMock(.init()),
|
||||
userIndicatorController: UserIndicatorControllerMock(),
|
||||
userSettings: userSettings)
|
||||
userSettings: userSettings,
|
||||
appHooks: AppHooks())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,8 @@ struct CreateRoomSpaceSelectionSheet_Previews: PreviewProvider, TestablePreview
|
||||
userSession: userSession,
|
||||
analytics: AnalyticsServiceMock(.init()),
|
||||
userIndicatorController: UserIndicatorControllerMock(),
|
||||
userSettings: userSettings)
|
||||
userSettings: userSettings,
|
||||
appHooks: AppHooks())
|
||||
}()
|
||||
|
||||
static var previews: some View {
|
||||
|
||||
+3
-1
@@ -14,6 +14,7 @@ struct SecurityAndPrivacyScreenCoordinatorParameters {
|
||||
let clientProxy: ClientProxyProtocol
|
||||
let userIndicatorController: UserIndicatorControllerProtocol
|
||||
let appSetting: UserSettings
|
||||
let appHooks: AppHooks
|
||||
}
|
||||
|
||||
enum SecurityAndPrivacyScreenCoordinatorAction {
|
||||
@@ -36,7 +37,8 @@ final class SecurityAndPrivacyScreenCoordinator: CoordinatorProtocol {
|
||||
viewModel = SecurityAndPrivacyScreenViewModel(roomProxy: parameters.roomProxy,
|
||||
clientProxy: parameters.clientProxy,
|
||||
userIndicatorController: parameters.userIndicatorController,
|
||||
userSettings: parameters.appSetting)
|
||||
userSettings: parameters.appSetting,
|
||||
appHooks: parameters.appHooks)
|
||||
}
|
||||
|
||||
func start() {
|
||||
|
||||
@@ -21,6 +21,7 @@ struct SecurityAndPrivacyScreenViewState: BindableState {
|
||||
|
||||
var canonicalAlias: String?
|
||||
var isKnockingEnabled: Bool
|
||||
var isPublicAccessAllowed = true
|
||||
var isSpace: Bool
|
||||
|
||||
var canEditAddress = false
|
||||
@@ -57,6 +58,11 @@ struct SecurityAndPrivacyScreenViewState: BindableState {
|
||||
return options.sorted()
|
||||
}
|
||||
|
||||
/// Keeps the option visible on rooms that are already public so the current state is shown.
|
||||
var isAnyoneOptionAvailable: Bool {
|
||||
currentSettings.accessType == .anyone || isPublicAccessAllowed
|
||||
}
|
||||
|
||||
var isSpaceMembersOptionAvailable: Bool {
|
||||
currentSettings.accessType.isSpaceMembers || isSpaceMembersOptionSelectable
|
||||
}
|
||||
|
||||
+10
-7
@@ -26,18 +26,21 @@ class SecurityAndPrivacyScreenViewModel: SecurityAndPrivacyScreenViewModelType,
|
||||
init(roomProxy: JoinedRoomProxyProtocol,
|
||||
clientProxy: ClientProxyProtocol,
|
||||
userIndicatorController: UserIndicatorControllerProtocol,
|
||||
userSettings: UserSettings) {
|
||||
userSettings: UserSettings,
|
||||
appHooks: AppHooks) {
|
||||
self.roomProxy = roomProxy
|
||||
self.clientProxy = clientProxy
|
||||
self.userIndicatorController = userIndicatorController
|
||||
self.userSettings = userSettings
|
||||
|
||||
super.init(initialViewState: SecurityAndPrivacyScreenViewState(accessType: roomProxy.infoPublisher.value.joinRule.toSecurityAndPrivacyRoomAccessType,
|
||||
isEncryptionEnabled: roomProxy.infoPublisher.value.isEncrypted,
|
||||
historyVisibility: roomProxy.infoPublisher.value.historyVisibility.toSecurityAndPrivacyHistoryVisibility,
|
||||
isSpace: roomProxy.infoPublisher.value.isSpace,
|
||||
isKnockingEnabled: userSettings.knockingEnabled,
|
||||
historySharingDetailsURL: userSettings.historySharingDetailsURL))
|
||||
let viewState = SecurityAndPrivacyScreenViewState(accessType: roomProxy.infoPublisher.value.joinRule.toSecurityAndPrivacyRoomAccessType,
|
||||
isEncryptionEnabled: roomProxy.infoPublisher.value.isEncrypted,
|
||||
historyVisibility: roomProxy.infoPublisher.value.historyVisibility.toSecurityAndPrivacyHistoryVisibility,
|
||||
isSpace: roomProxy.infoPublisher.value.isSpace,
|
||||
isKnockingEnabled: userSettings.knockingEnabled,
|
||||
historySharingDetailsURL: userSettings.historySharingDetailsURL)
|
||||
|
||||
super.init(initialViewState: appHooks.securityAndPrivacyScreenHook.update(viewState, homeserver: clientProxy.homeserver))
|
||||
|
||||
if let powerLevels = roomProxy.infoPublisher.value.powerLevels {
|
||||
setupPermissions(powerLevels: powerLevels)
|
||||
|
||||
+24
-13
@@ -46,10 +46,12 @@ struct SecurityAndPrivacyScreen: View {
|
||||
|
||||
private var roomAccessSection: some View {
|
||||
Section {
|
||||
ListRow(label: .default(title: L10n.screenSecurityAndPrivacyRoomAccessAnyoneOptionTitle,
|
||||
description: L10n.screenSecurityAndPrivacyRoomAccessAnyoneOptionDescription,
|
||||
icon: \.public),
|
||||
kind: .selection(isSelected: context.desiredSettings.accessType == .anyone) { context.desiredSettings.accessType = .anyone })
|
||||
if context.viewState.isAnyoneOptionAvailable {
|
||||
ListRow(label: .default(title: L10n.screenSecurityAndPrivacyRoomAccessAnyoneOptionTitle,
|
||||
description: L10n.screenSecurityAndPrivacyRoomAccessAnyoneOptionDescription,
|
||||
icon: \.public),
|
||||
kind: .selection(isSelected: context.desiredSettings.accessType == .anyone) { context.desiredSettings.accessType = .anyone })
|
||||
}
|
||||
|
||||
if context.viewState.isSpaceMembersOptionAvailable {
|
||||
ListRow(label: .default(title: L10n.screenSecurityAndPrivacyRoomAccessSpaceMembersOptionTitle,
|
||||
@@ -233,7 +235,8 @@ struct SecurityAndPrivacyScreen_Previews: PreviewProvider, TestablePreview {
|
||||
joinRule: .invite)),
|
||||
clientProxy: ClientProxyMock(.init()),
|
||||
userIndicatorController: UserIndicatorControllerMock(),
|
||||
userSettings: .volatile())
|
||||
userSettings: .volatile(),
|
||||
appHooks: AppHooks())
|
||||
|
||||
static let publicViewModel = SecurityAndPrivacyScreenViewModel(roomProxy: JoinedRoomProxyMock(.init(isEncrypted: false,
|
||||
canonicalAlias: "#room:matrix.org",
|
||||
@@ -242,14 +245,16 @@ struct SecurityAndPrivacyScreen_Previews: PreviewProvider, TestablePreview {
|
||||
isVisibleInPublicDirectory: true)),
|
||||
clientProxy: ClientProxyMock(.init(userIDServerName: "matrix.org")),
|
||||
userIndicatorController: UserIndicatorControllerMock(),
|
||||
userSettings: .volatile())
|
||||
userSettings: .volatile(),
|
||||
appHooks: AppHooks())
|
||||
|
||||
static let publicNoAddressViewModel = SecurityAndPrivacyScreenViewModel(roomProxy: JoinedRoomProxyMock(.init(isEncrypted: false,
|
||||
members: .allMembersAsCreator,
|
||||
joinRule: .public)),
|
||||
clientProxy: ClientProxyMock(.init(userIDServerName: "matrix.org")),
|
||||
userIndicatorController: UserIndicatorControllerMock(),
|
||||
userSettings: .volatile())
|
||||
userSettings: .volatile(),
|
||||
appHooks: AppHooks())
|
||||
|
||||
static let singleSpaceMembersViewModel = {
|
||||
let userSettings = UserSettings.volatile()
|
||||
@@ -264,7 +269,8 @@ struct SecurityAndPrivacyScreen_Previews: PreviewProvider, TestablePreview {
|
||||
clientProxy: ClientProxyMock(.init(userIDServerName: "matrix.org",
|
||||
spaceServiceConfiguration: .init(joinedParentSpaces: [space]))),
|
||||
userIndicatorController: UserIndicatorControllerMock(),
|
||||
userSettings: userSettings)
|
||||
userSettings: userSettings,
|
||||
appHooks: AppHooks())
|
||||
}()
|
||||
|
||||
static let multipleSpacesMembersViewModel = {
|
||||
@@ -280,7 +286,8 @@ struct SecurityAndPrivacyScreen_Previews: PreviewProvider, TestablePreview {
|
||||
clientProxy: ClientProxyMock(.init(userIDServerName: "matrix.org",
|
||||
spaceServiceConfiguration: .init(joinedParentSpaces: spaces))),
|
||||
userIndicatorController: UserIndicatorControllerMock(),
|
||||
userSettings: userSettings)
|
||||
userSettings: userSettings,
|
||||
appHooks: AppHooks())
|
||||
}()
|
||||
|
||||
static let askToJoinViewModel = {
|
||||
@@ -294,7 +301,8 @@ struct SecurityAndPrivacyScreen_Previews: PreviewProvider, TestablePreview {
|
||||
isVisibleInPublicDirectory: true)),
|
||||
clientProxy: ClientProxyMock(.init(userIDServerName: "matrix.org")),
|
||||
userIndicatorController: UserIndicatorControllerMock(),
|
||||
userSettings: userSettings)
|
||||
userSettings: userSettings,
|
||||
appHooks: AppHooks())
|
||||
}()
|
||||
|
||||
static let singleAskToJoinSpaceMembersViewModel = {
|
||||
@@ -311,7 +319,8 @@ struct SecurityAndPrivacyScreen_Previews: PreviewProvider, TestablePreview {
|
||||
clientProxy: ClientProxyMock(.init(userIDServerName: "matrix.org",
|
||||
spaceServiceConfiguration: .init(joinedParentSpaces: [space]))),
|
||||
userIndicatorController: UserIndicatorControllerMock(),
|
||||
userSettings: userSettings)
|
||||
userSettings: userSettings,
|
||||
appHooks: AppHooks())
|
||||
}()
|
||||
|
||||
static let multipleAskToJoinSpacesMembersViewModel = {
|
||||
@@ -328,7 +337,8 @@ struct SecurityAndPrivacyScreen_Previews: PreviewProvider, TestablePreview {
|
||||
clientProxy: ClientProxyMock(.init(userIDServerName: "matrix.org",
|
||||
spaceServiceConfiguration: .init(joinedParentSpaces: spaces))),
|
||||
userIndicatorController: UserIndicatorControllerMock(),
|
||||
userSettings: userSettings)
|
||||
userSettings: userSettings,
|
||||
appHooks: AppHooks())
|
||||
}()
|
||||
|
||||
static let publicSpaceViewModel = SecurityAndPrivacyScreenViewModel(roomProxy: JoinedRoomProxyMock(.init(isSpace: true,
|
||||
@@ -339,7 +349,8 @@ struct SecurityAndPrivacyScreen_Previews: PreviewProvider, TestablePreview {
|
||||
isVisibleInPublicDirectory: true)),
|
||||
clientProxy: ClientProxyMock(.init(userIDServerName: "matrix.org")),
|
||||
userIndicatorController: UserIndicatorControllerMock(),
|
||||
userSettings: .volatile())
|
||||
userSettings: .volatile(),
|
||||
appHooks: AppHooks())
|
||||
|
||||
static var previews: some View {
|
||||
ElementNavigationStack {
|
||||
|
||||
Reference in New Issue
Block a user