From 6fc8c31449453477b9e213c893b3dddacca092dc Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Mon, 24 Jul 2023 10:42:14 +0200 Subject: [PATCH] Reduce boilerplate in Developer Options Screen (#1378) * Reduce developer options boilerplate * Add protocol DeveloperOptions * Delete timelineDiffableAnimationsEnabled * Refactor DeveloperOptions -> DeveloperOptionsProtocol --- .../xcshareddata/swiftpm/Package.resolved | 4 +-- .../DeveloperOptionsScreenCoordinator.swift | 2 +- .../DeveloperOptionsScreenModels.swift | 31 +++++++++++++------ .../DeveloperOptionsScreenViewModel.swift | 26 ++-------------- .../View/DeveloperOptionsScreen.swift | 17 +--------- 5 files changed, 27 insertions(+), 53 deletions(-) diff --git a/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 19a5f5283..ed6f30854 100644 --- a/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -228,8 +228,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/xctest-dynamic-overlay", "state" : { - "revision" : "4af50b38daf0037cfbab15514a241224c3f62f98", - "version" : "0.8.5" + "revision" : "245d527002f29c5a616c5b7131f6a50ac7f41cbf", + "version" : "0.8.6" } } ], diff --git a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenCoordinator.swift b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenCoordinator.swift index 38a008194..49fd7bd54 100644 --- a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenCoordinator.swift +++ b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenCoordinator.swift @@ -26,7 +26,7 @@ final class DeveloperOptionsScreenCoordinator: CoordinatorProtocol { var callback: ((DeveloperOptionsScreenCoordinatorAction) -> Void)? init() { - viewModel = DeveloperOptionsScreenViewModel(appSettings: ServiceLocator.shared.settings) + viewModel = DeveloperOptionsScreenViewModel(developerOptions: ServiceLocator.shared.settings) viewModel.callback = { [weak self] action in switch action { case .clearCache: diff --git a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenModels.swift b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenModels.swift index abea557e1..316625301 100644 --- a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenModels.swift +++ b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenModels.swift @@ -24,19 +24,30 @@ struct DeveloperOptionsScreenViewState: BindableState { var bindings: DeveloperOptionsScreenViewStateBindings } +@dynamicMemberLookup struct DeveloperOptionsScreenViewStateBindings { - var shouldCollapseRoomStateEvents: Bool - var userSuggestionsEnabled: Bool - var readReceiptsEnabled: Bool - var isEncryptionSyncEnabled: Bool - var notificationSettingsEnabled: Bool + private let developerOptions: DeveloperOptionsProtocol + + init(developerOptions: DeveloperOptionsProtocol) { + self.developerOptions = developerOptions + } + + subscript(dynamicMember keyPath: ReferenceWritableKeyPath) -> Setting { + get { developerOptions[keyPath: keyPath] } + set { developerOptions[keyPath: keyPath] = newValue } + } } enum DeveloperOptionsScreenViewAction { - case changedShouldCollapseRoomStateEvents - case changedUserSuggestionsEnabled - case changedReadReceiptsEnabled - case changedIsEncryptionSyncEnabled - case changedNotificationSettingsEnabled case clearCache } + +protocol DeveloperOptionsProtocol: AnyObject { + var shouldCollapseRoomStateEvents: Bool { get set } + var userSuggestionsEnabled: Bool { get set } + var readReceiptsEnabled: Bool { get set } + var isEncryptionSyncEnabled: Bool { get set } + var notificationSettingsEnabled: Bool { get set } +} + +extension AppSettings: DeveloperOptionsProtocol { } diff --git a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenViewModel.swift b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenViewModel.swift index f07434ea4..2923a4ea3 100644 --- a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenViewModel.swift +++ b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenViewModel.swift @@ -19,39 +19,17 @@ import SwiftUI typealias DeveloperOptionsScreenViewModelType = StateStoreViewModel class DeveloperOptionsScreenViewModel: DeveloperOptionsScreenViewModelType, DeveloperOptionsScreenViewModelProtocol { - private let appSettings: AppSettings - var callback: ((DeveloperOptionsScreenViewModelAction) -> Void)? - init(appSettings: AppSettings) { - self.appSettings = appSettings - - let bindings = DeveloperOptionsScreenViewStateBindings(shouldCollapseRoomStateEvents: appSettings.shouldCollapseRoomStateEvents, - userSuggestionsEnabled: appSettings.userSuggestionsEnabled, - readReceiptsEnabled: appSettings.readReceiptsEnabled, - isEncryptionSyncEnabled: appSettings.isEncryptionSyncEnabled, - notificationSettingsEnabled: appSettings.notificationSettingsEnabled) + init(developerOptions: DeveloperOptionsProtocol) { + let bindings = DeveloperOptionsScreenViewStateBindings(developerOptions: developerOptions) let state = DeveloperOptionsScreenViewState(bindings: bindings) super.init(initialViewState: state) - - appSettings.$shouldCollapseRoomStateEvents - .weakAssign(to: \.state.bindings.shouldCollapseRoomStateEvents, on: self) - .store(in: &cancellables) } override func process(viewAction: DeveloperOptionsScreenViewAction) { switch viewAction { - case .changedShouldCollapseRoomStateEvents: - appSettings.shouldCollapseRoomStateEvents = state.bindings.shouldCollapseRoomStateEvents - case .changedUserSuggestionsEnabled: - appSettings.userSuggestionsEnabled = state.bindings.userSuggestionsEnabled - case .changedReadReceiptsEnabled: - appSettings.readReceiptsEnabled = state.bindings.readReceiptsEnabled - case .changedIsEncryptionSyncEnabled: - appSettings.isEncryptionSyncEnabled = state.bindings.isEncryptionSyncEnabled - case .changedNotificationSettingsEnabled: - appSettings.notificationSettingsEnabled = state.bindings.notificationSettingsEnabled case .clearCache: callback?(.clearCache) } diff --git a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift index b254ece40..e231be92b 100644 --- a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift +++ b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift @@ -26,17 +26,11 @@ struct DeveloperOptionsScreen: View { Toggle(isOn: $context.shouldCollapseRoomStateEvents) { Text("Collapse room state events") } - .onChange(of: context.shouldCollapseRoomStateEvents) { _ in - context.send(viewAction: .changedShouldCollapseRoomStateEvents) - } Toggle(isOn: $context.readReceiptsEnabled) { Text("Show read receipts") Text("Requires app reboot") } - .onChange(of: context.readReceiptsEnabled) { _ in - context.send(viewAction: .changedReadReceiptsEnabled) - } } Section("Notifications") { @@ -44,25 +38,16 @@ struct DeveloperOptionsScreen: View { Text("Use notification encryption sync") Text("Requires app reboot") } - .onChange(of: context.isEncryptionSyncEnabled) { _ in - context.send(viewAction: .changedIsEncryptionSyncEnabled) - } Toggle(isOn: $context.notificationSettingsEnabled) { Text("Show notification settings") } - .onChange(of: context.notificationSettingsEnabled) { _ in - context.send(viewAction: .changedNotificationSettingsEnabled) - } } Section("Room creation") { Toggle(isOn: $context.userSuggestionsEnabled) { Text("User suggestions") } - .onChange(of: context.userSuggestionsEnabled) { _ in - context.send(viewAction: .changedUserSuggestionsEnabled) - } } Section { @@ -116,7 +101,7 @@ struct DeveloperOptionsScreen: View { // MARK: - Previews struct DeveloperOptionsScreen_Previews: PreviewProvider { - static let viewModel = DeveloperOptionsScreenViewModel(appSettings: ServiceLocator.shared.settings) + static let viewModel = DeveloperOptionsScreenViewModel(developerOptions: ServiceLocator.shared.settings) static var previews: some View { NavigationStack { DeveloperOptionsScreen(context: viewModel.context)