diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index 8ebfce325..322ec9f11 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -603,6 +603,7 @@ 6B61F5B27412ED4BC2F9769C /* test_audio.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 66B96842BF5F8ACA1AC84C55 /* test_audio.mp3 */; }; 6B80C24A52411EAF10E06E96 /* SecurityAndPrivacyScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BBADF8010C813D905C172CE /* SecurityAndPrivacyScreenModels.swift */; }; 6BAD956B909A6E29F6CC6E7C /* ButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CC23C63849452BC86EA2852 /* ButtonStyle.swift */; }; + 6BAE34CFA9821709CFE61E50 /* DeveloperOptionsScreenHook.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F60FDB3AEFC60830BD289FE /* DeveloperOptionsScreenHook.swift */; }; 6C34237AFB808E38FC8776B9 /* RoomStateEventStringBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D55702474F279D910D2D162 /* RoomStateEventStringBuilder.swift */; }; 6C98153D60FF9B648C166C27 /* TimelineItemMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91FFE1F410969ECB23FE9BB2 /* TimelineItemMenu.swift */; }; 6CAADDC6318E41C7D7AA9526 /* SpaceScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 646B50583A2CE6DA67F7739A /* SpaceScreen.swift */; }; @@ -1585,6 +1586,7 @@ 0E95B3BDB80531C85CD50AE6 /* InvitedRoomProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvitedRoomProxy.swift; sourceTree = ""; }; 0EE9EAF0309A2A1D67D8FAF5 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = sv; path = sv.lproj/Localizable.stringsdict; sourceTree = ""; }; 0F5567A7EF6F2AB9473236F6 /* DocumentPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DocumentPicker.swift; sourceTree = ""; }; + 0F60FDB3AEFC60830BD289FE /* DeveloperOptionsScreenHook.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeveloperOptionsScreenHook.swift; sourceTree = ""; }; 0F64447FF544298A6A3BEF85 /* NotificationSettingsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsScreenModels.swift; sourceTree = ""; }; 0F71A54CB96DAA1E72C6541D /* AuthenticationStartScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationStartScreenViewModel.swift; sourceTree = ""; }; 0F793C422BDACE0C60C774F4 /* UserIdentityProxyProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserIdentityProxyProtocol.swift; sourceTree = ""; }; @@ -3475,6 +3477,7 @@ 3865AD7B7249C939D7C69C33 /* CertificateValidatorHook.swift */, 7AC0CD1CAFD3F8B057F9AEA5 /* ClientBuilderHook.swift */, 8B89D6C760E8CAE29CA28FB1 /* CompoundHook.swift */, + 0F60FDB3AEFC60830BD289FE /* DeveloperOptionsScreenHook.swift */, D5D186A6DB8FAC5C9D0E4D61 /* RemoteSettingsHook.swift */, B343C5255FB408DDE853CFDF /* RoomScreenHook.swift */, 2A95C9B8299A36A6495DECA6 /* TracingHook.swift */, @@ -5337,7 +5340,6 @@ children = ( BDDD421CD80AD0BCBA035076 /* Common */, EEFCB022372FE5F306ED9199 /* LeaveSpace */, - ADA672F2647D05F087305B21 /* LeaveSpaceSheet */, FCF165F4DDB83F3DECFEB57A /* SpaceListScreen */, C360FCF7418FE3593D5A0CBF /* SpaceScreen */, 55312ACF4155CC5B2054AD75 /* SpaceSettingsScreen */, @@ -5633,13 +5635,6 @@ path = View; sourceTree = ""; }; - ADA672F2647D05F087305B21 /* LeaveSpaceSheet */ = { - isa = PBXGroup; - children = ( - ); - path = LeaveSpaceSheet; - sourceTree = ""; - }; B04B538A859CD012755DC19C /* NSE */ = { isa = PBXGroup; children = ( @@ -5869,13 +5864,6 @@ path = MapLibre; sourceTree = ""; }; - C18958141C8ED6D778F779A4 /* CreateRoom */ = { - isa = PBXGroup; - children = ( - ); - path = CreateRoom; - sourceTree = ""; - }; C1CD278862878F9545608040 /* SessionVerificationScreen */ = { isa = PBXGroup; children = ( @@ -6258,7 +6246,6 @@ 53FB148CD26AFB6A5B9E20B3 /* BugReportScreen */, 1185EECDD07495D65AC84AFC /* CallScreen */, 90DC2E28718955ED87AD1456 /* CreatePollScreen */, - C18958141C8ED6D778F779A4 /* CreateRoom */, 821EB0D1C0019E3C7BBAEDBB /* CreateRoomScreen */, 3E1CCC4B607946CE90B4A827 /* DeclineAndBlockScreen */, 45F2BCFD6E9A6F040CC20582 /* EditRoomAddressScreen */, @@ -7783,6 +7770,7 @@ EE8491AD81F47DF3C192497B /* DecorationTimelineItemProtocol.swift in Sources */, 5780E444F405AA1304E1C23E /* DeveloperOptionsScreen.swift in Sources */, 5DD85A0FE3D85AEC3C7EFE36 /* DeveloperOptionsScreenCoordinator.swift in Sources */, + 6BAE34CFA9821709CFE61E50 /* DeveloperOptionsScreenHook.swift in Sources */, 784592335560C2E91D32D177 /* DeveloperOptionsScreenModels.swift in Sources */, B3D652AA1654270742072FB3 /* DeveloperOptionsScreenViewModel.swift in Sources */, B9CB30FED3E29D2036EA3FCC /* DeveloperOptionsScreenViewModelProtocol.swift in Sources */, diff --git a/ElementX/Sources/AppHooks/AppHooks.swift b/ElementX/Sources/AppHooks/AppHooks.swift index b916242be..c35cf63c4 100644 --- a/ElementX/Sources/AppHooks/AppHooks.swift +++ b/ElementX/Sources/AppHooks/AppHooks.swift @@ -38,6 +38,11 @@ class AppHooks: AppHooksProtocol { func registerRoomScreenHook(_ hook: RoomScreenHookProtocol) { roomScreenHook = hook } + + private(set) var developerOptionsScreenHook: DeveloperOptionsScreenHookProtocol = DefaultDeveloperOptionsScreenHook() + func registerDeveloperOptionsScreenHook(_ hook: DeveloperOptionsScreenHookProtocol) { + developerOptionsScreenHook = hook + } #endif private(set) var tracingHook: TracingHookProtocol = DefaultTracingHook() diff --git a/ElementX/Sources/AppHooks/Hooks/DeveloperOptionsScreenHook.swift b/ElementX/Sources/AppHooks/Hooks/DeveloperOptionsScreenHook.swift new file mode 100644 index 000000000..e31b390b4 --- /dev/null +++ b/ElementX/Sources/AppHooks/Hooks/DeveloperOptionsScreenHook.swift @@ -0,0 +1,16 @@ +// +// Copyright 2025 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 SwiftUI + +protocol DeveloperOptionsScreenHookProtocol { + func generalSectionRows() -> AnyView? +} + +struct DefaultDeveloperOptionsScreenHook: DeveloperOptionsScreenHookProtocol { + func generalSectionRows() -> AnyView? { nil } +} diff --git a/ElementX/Sources/FlowCoordinators/SettingsFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/SettingsFlowCoordinator.swift index 434436eab..b23d354cd 100644 --- a/ElementX/Sources/FlowCoordinators/SettingsFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/SettingsFlowCoordinator.swift @@ -215,7 +215,7 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol { } private func presentDeveloperOptions() { - let coordinator = DeveloperOptionsScreenCoordinator(appSettings: flowParameters.appSettings) + let coordinator = DeveloperOptionsScreenCoordinator(appSettings: flowParameters.appSettings, appHooks: flowParameters.appHooks) coordinator.actions .sink { [weak self] action in diff --git a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenCoordinator.swift b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenCoordinator.swift index 874ad1be3..981daadbc 100644 --- a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenCoordinator.swift +++ b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenCoordinator.swift @@ -23,9 +23,10 @@ final class DeveloperOptionsScreenCoordinator: CoordinatorProtocol { actionsSubject.eraseToAnyPublisher() } - init(appSettings: AppSettings) { + init(appSettings: AppSettings, appHooks: AppHooks) { viewModel = DeveloperOptionsScreenViewModel(developerOptions: appSettings, - elementCallBaseURL: appSettings.elementCallBaseURL) + elementCallBaseURL: appSettings.elementCallBaseURL, + appHooks: appHooks) viewModel.actions .sink { [weak self] action in diff --git a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenModels.swift b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenModels.swift index f48cae097..a242707c0 100644 --- a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenModels.swift +++ b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenModels.swift @@ -14,6 +14,7 @@ enum DeveloperOptionsScreenViewModelAction { struct DeveloperOptionsScreenViewState: BindableState { let elementCallBaseURL: URL + let appHooks: AppHooks var bindings: DeveloperOptionsScreenViewStateBindings } diff --git a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenViewModel.swift b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenViewModel.swift index 86e7d0c91..ee70b54a1 100644 --- a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenViewModel.swift +++ b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenViewModel.swift @@ -18,9 +18,9 @@ class DeveloperOptionsScreenViewModel: DeveloperOptionsScreenViewModelType, Deve actionsSubject.eraseToAnyPublisher() } - init(developerOptions: DeveloperOptionsProtocol, elementCallBaseURL: URL) { + init(developerOptions: DeveloperOptionsProtocol, elementCallBaseURL: URL, appHooks: AppHooks) { let bindings = DeveloperOptionsScreenViewStateBindings(developerOptions: developerOptions) - let state = DeveloperOptionsScreenViewState(elementCallBaseURL: elementCallBaseURL, bindings: bindings) + let state = DeveloperOptionsScreenViewState(elementCallBaseURL: elementCallBaseURL, appHooks: appHooks, bindings: bindings) super.init(initialViewState: state) } diff --git a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift index 534c5c1b6..023a73c53 100644 --- a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift +++ b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift @@ -33,10 +33,14 @@ struct DeveloperOptionsScreen: View { } } - Section("Spaces") { + Section("General") { Toggle(isOn: $context.spaceSettingsEnabled) { Text("Space settings") } + + context.viewState.appHooks + .developerOptionsScreenHook + .generalSectionRows() } Section("Room List") { @@ -146,7 +150,6 @@ struct DeveloperOptionsScreen: View { } } .overlay(effectsView) - .compoundList() .navigationTitle(L10n.commonDeveloperOptions) .navigationBarTitleDisplayMode(.inline) } @@ -205,7 +208,8 @@ private extension Set { struct DeveloperOptionsScreen_Previews: PreviewProvider { static let viewModel = DeveloperOptionsScreenViewModel(developerOptions: ServiceLocator.shared.settings, - elementCallBaseURL: ServiceLocator.shared.settings.elementCallBaseURL) + elementCallBaseURL: ServiceLocator.shared.settings.elementCallBaseURL, + appHooks: AppHooks()) static var previews: some View { NavigationStack { DeveloperOptionsScreen(context: viewModel.context) diff --git a/compound-ios/Sources/Compound/Colors/CompoundColors.swift b/compound-ios/Sources/Compound/Colors/CompoundColors.swift index 5881ae4fb..f44a8a9b2 100644 --- a/compound-ios/Sources/Compound/Colors/CompoundColors.swift +++ b/compound-ios/Sources/Compound/Colors/CompoundColors.swift @@ -21,6 +21,7 @@ public extension ShapeStyle where Self == Color { /// The colours used by Element as defined in Compound Design Tokens. /// This struct contains only the colour tokens in a more usable form. +@Observable @dynamicMemberLookup public class CompoundColors { /// The base colour tokens that form the palette of available colours. diff --git a/compound-ios/Sources/Compound/Colors/CompoundUIColors.swift b/compound-ios/Sources/Compound/Colors/CompoundUIColors.swift index 3635812a8..5d8564db1 100644 --- a/compound-ios/Sources/Compound/Colors/CompoundUIColors.swift +++ b/compound-ios/Sources/Compound/Colors/CompoundUIColors.swift @@ -16,6 +16,7 @@ public extension UIColor { /// The colours used by Element as defined in Compound Design Tokens. /// This struct contains only the colour tokens in a more usable form. +@Observable @dynamicMemberLookup public class CompoundUIColors { /// The base colour tokens that form the palette of available colours.