From c83a2bd72931cf87a2f8e355877554241af6a751 Mon Sep 17 00:00:00 2001 From: Doug <6060466+pixlwave@users.noreply.github.com> Date: Tue, 18 Jul 2023 11:25:07 +0100 Subject: [PATCH] Tidy up Developer screen, add button to crash the app. (#1348) * ID all the things --- .../Sources/Application/AppCoordinator.swift | 8 +- .../UserSessionFlowCoordinator.swift | 14 +-- ...erSessionFlowCoordinatorStateMachine.swift | 97 ++++++++++--------- .../View/DeveloperOptionsScreen.swift | 54 +++++++---- .../Sources/Services/Client/ClientProxy.swift | 14 +-- 5 files changed, 104 insertions(+), 83 deletions(-) diff --git a/ElementX/Sources/Application/AppCoordinator.swift b/ElementX/Sources/Application/AppCoordinator.swift index 8b51ea37d..77b6cbd46 100644 --- a/ElementX/Sources/Application/AppCoordinator.swift +++ b/ElementX/Sources/Application/AppCoordinator.swift @@ -142,14 +142,14 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate, } func shouldDisplayInAppNotification(_ service: NotificationManagerProtocol, content: UNNotificationContent) -> Bool { - guard let roomId = content.roomID else { + guard let roomID = content.roomID else { return true } guard let userSessionFlowCoordinator else { // there is not a user session yet return false } - return !userSessionFlowCoordinator.isDisplayingRoomScreen(withRoomId: roomId) + return !userSessionFlowCoordinator.isDisplayingRoomScreen(withRoomID: roomID) } func notificationTapped(_ service: NotificationManagerProtocol, content: UNNotificationContent) async { @@ -179,10 +179,10 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate, MXLog.info("[AppCoordinator] handle notification reply") - guard let roomId = content.userInfo[NotificationConstants.UserInfoKey.roomIdentifier] as? String else { + guard let roomID = content.userInfo[NotificationConstants.UserInfoKey.roomIdentifier] as? String else { return } - let roomProxy = await userSession.clientProxy.roomForIdentifier(roomId) + let roomProxy = await userSession.clientProxy.roomForIdentifier(roomID) switch await roomProxy?.sendMessage(replyText) { case .success: break diff --git a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift index ec12aa5a9..bba7a879c 100644 --- a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift @@ -77,7 +77,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { switch action { case .presentedRoom(let roomID): self.analytics.signpost.beginRoomFlow(roomID) - self.stateMachine.processEvent(.selectRoom(roomId: roomID)) + self.stateMachine.processEvent(.selectRoom(roomID: roomID)) case .dismissedRoom: self.stateMachine.processEvent(.deselectRoom) self.analytics.signpost.endRoomFlow() @@ -100,8 +100,8 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { func stop() { } - func isDisplayingRoomScreen(withRoomId roomId: String) -> Bool { - stateMachine.isDisplayingRoomScreen(withRoomId: roomId) + func isDisplayingRoomScreen(withRoomID roomID: String) -> Bool { + stateMachine.isDisplayingRoomScreen(withRoomID: roomID) } // MARK: - FlowCoordinatorProtocol @@ -202,8 +202,8 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { stateMachine.addTransitionHandler { [weak self] context in switch context.toState { - case .roomList(let selectedRoomId): - self?.selectedRoomSubject.send(selectedRoomId) + case .roomList(let selectedRoomID): + self?.selectedRoomSubject.send(selectedRoomID) default: break } @@ -259,8 +259,8 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { case .presentRoomDetails(let roomID): self.roomFlowCoordinator.handleAppRoute(.roomDetails(roomID: roomID), animated: true) case .roomLeft(let roomID): - if case .roomList(selectedRoomId: let selectedRoomId) = stateMachine.state, - selectedRoomId == roomID { + if case .roomList(selectedRoomID: let selectedRoomID) = stateMachine.state, + selectedRoomID == roomID { self.roomFlowCoordinator.handleAppRoute(.roomList, animated: true) } case .presentSettingsScreen: diff --git a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinatorStateMachine.swift b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinatorStateMachine.swift index 11aec940d..b6c4bad47 100644 --- a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinatorStateMachine.swift +++ b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinatorStateMachine.swift @@ -29,23 +29,23 @@ class UserSessionFlowCoordinatorStateMachine { /// Showing the welcome screen. case welcomeScreen - /// Showing the home screen. The `selectedRoomId` represents the timeline shown on the detail panel (if any) - case roomList(selectedRoomId: String?) + /// Showing the home screen. The `selectedRoomID` represents the timeline shown on the detail panel (if any) + case roomList(selectedRoomID: String?) /// Showing the session verification flows - case sessionVerificationScreen(selectedRoomId: String?) + case sessionVerificationScreen(selectedRoomID: String?) /// Showing the session verification flows - case feedbackScreen(selectedRoomId: String?) + case feedbackScreen(selectedRoomID: String?) /// Showing the settings screen - case settingsScreen(selectedRoomId: String?) + case settingsScreen(selectedRoomID: String?) /// Showing the start chat screen - case startChatScreen(selectedRoomId: String?) + case startChatScreen(selectedRoomID: String?) /// Showing invites list screen - case invitesScreen(selectedRoomId: String?) + case invitesScreen(selectedRoomID: String?) } struct EventUserInfo { @@ -54,21 +54,26 @@ class UserSessionFlowCoordinatorStateMachine { /// Events that can be triggered on the AppCoordinator state machine enum Event: EventType { - /// Start the user session flows + /// Start the user session flows. case start - /// Starts the user session flows with the welcome screen + /// Starts the user session flows with the welcome screen. + /// **Note:** This is event is only for users who used the app before v1.1.8. + /// It can be removed once the older TestFlight builds have expired. case startWithWelcomeScreen /// Start the user session flows with a migration screen. case startWithMigration + /// Request to transition from the migration state to the home screen. case completeMigration - + + /// Request presentation of the welcome screen. case presentWelcomeScreen + /// The welcome screen has been dismissed. case dismissedWelcomeScreen /// Request presentation for a particular room - /// - Parameter roomId:the room identifier - case selectRoom(roomId: String) + /// - Parameter roomID:the room identifier + case selectRoom(roomID: String) /// The room screen has been dismissed case deselectRoom @@ -111,50 +116,50 @@ class UserSessionFlowCoordinatorStateMachine { // swiftlint:disable:next cyclomatic_complexity private func configure() { - stateMachine.addRoutes(event: .start, transitions: [.initial => .roomList(selectedRoomId: nil)]) + stateMachine.addRoutes(event: .start, transitions: [.initial => .roomList(selectedRoomID: nil)]) stateMachine.addRoutes(event: .startWithMigration, transitions: [.initial => .migration]) stateMachine.addRoutes(event: .startWithWelcomeScreen, transitions: [.initial => .welcomeScreen]) - stateMachine.addRoutes(event: .completeMigration, transitions: [.migration => .roomList(selectedRoomId: nil)]) - stateMachine.addRoutes(event: .dismissedWelcomeScreen, transitions: [.welcomeScreen => .roomList(selectedRoomId: nil)]) + stateMachine.addRoutes(event: .completeMigration, transitions: [.migration => .roomList(selectedRoomID: nil)]) + stateMachine.addRoutes(event: .dismissedWelcomeScreen, transitions: [.welcomeScreen => .roomList(selectedRoomID: nil)]) stateMachine.addRouteMapping { event, fromState, _ in switch (event, fromState) { - case (.selectRoom(let roomId), .roomList): - return .roomList(selectedRoomId: roomId) - case (.selectRoom(let roomId), .invitesScreen): - return .invitesScreen(selectedRoomId: roomId) + case (.selectRoom(let roomID), .roomList): + return .roomList(selectedRoomID: roomID) + case (.selectRoom(let roomID), .invitesScreen): + return .invitesScreen(selectedRoomID: roomID) case (.deselectRoom, .roomList): - return .roomList(selectedRoomId: nil) + return .roomList(selectedRoomID: nil) case (.deselectRoom, .invitesScreen): - return .invitesScreen(selectedRoomId: nil) + return .invitesScreen(selectedRoomID: nil) - case (.showSettingsScreen, .roomList(let selectedRoomId)): - return .settingsScreen(selectedRoomId: selectedRoomId) - case (.dismissedSettingsScreen, .settingsScreen(let selectedRoomId)): - return .roomList(selectedRoomId: selectedRoomId) + case (.showSettingsScreen, .roomList(let selectedRoomID)): + return .settingsScreen(selectedRoomID: selectedRoomID) + case (.dismissedSettingsScreen, .settingsScreen(let selectedRoomID)): + return .roomList(selectedRoomID: selectedRoomID) - case (.feedbackScreen, .roomList(let selectedRoomId)): - return .feedbackScreen(selectedRoomId: selectedRoomId) - case (.dismissedFeedbackScreen, .feedbackScreen(let selectedRoomId)): - return .roomList(selectedRoomId: selectedRoomId) + case (.feedbackScreen, .roomList(let selectedRoomID)): + return .feedbackScreen(selectedRoomID: selectedRoomID) + case (.dismissedFeedbackScreen, .feedbackScreen(let selectedRoomID)): + return .roomList(selectedRoomID: selectedRoomID) - case (.showSessionVerificationScreen, .roomList(let selectedRoomId)): - return .sessionVerificationScreen(selectedRoomId: selectedRoomId) - case (.dismissedSessionVerificationScreen, .sessionVerificationScreen(let selectedRoomId)): - return .roomList(selectedRoomId: selectedRoomId) + case (.showSessionVerificationScreen, .roomList(let selectedRoomID)): + return .sessionVerificationScreen(selectedRoomID: selectedRoomID) + case (.dismissedSessionVerificationScreen, .sessionVerificationScreen(let selectedRoomID)): + return .roomList(selectedRoomID: selectedRoomID) - case (.showStartChatScreen, .roomList(let selectedRoomId)): - return .startChatScreen(selectedRoomId: selectedRoomId) - case (.dismissedStartChatScreen, .startChatScreen(let selectedRoomId)): - return .roomList(selectedRoomId: selectedRoomId) + case (.showStartChatScreen, .roomList(let selectedRoomID)): + return .startChatScreen(selectedRoomID: selectedRoomID) + case (.dismissedStartChatScreen, .startChatScreen(let selectedRoomID)): + return .roomList(selectedRoomID: selectedRoomID) - case (.showInvitesScreen, .roomList(let selectedRoomId)): - return .invitesScreen(selectedRoomId: selectedRoomId) - case (.showInvitesScreen, .invitesScreen(let selectedRoomId)): - return .invitesScreen(selectedRoomId: selectedRoomId) + case (.showInvitesScreen, .roomList(let selectedRoomID)): + return .invitesScreen(selectedRoomID: selectedRoomID) + case (.showInvitesScreen, .invitesScreen(let selectedRoomID)): + return .invitesScreen(selectedRoomID: selectedRoomID) - case (.closedInvitesScreen, .invitesScreen(let selectedRoomId)): - return .roomList(selectedRoomId: selectedRoomId) + case (.closedInvitesScreen, .invitesScreen(let selectedRoomID)): + return .roomList(selectedRoomID: selectedRoomID) case (.presentWelcomeScreen, .roomList): return .welcomeScreen @@ -190,10 +195,10 @@ class UserSessionFlowCoordinatorStateMachine { } /// Flag indicating the machine is displaying room screen with given room identifier - func isDisplayingRoomScreen(withRoomId roomId: String) -> Bool { + func isDisplayingRoomScreen(withRoomID roomID: String) -> Bool { switch stateMachine.state { - case .roomList(let selectedRoomId): - return roomId == selectedRoomId + case .roomList(let selectedRoomID): + return roomID == selectedRoomID default: return false } diff --git a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift index b31bc45f1..82935f274 100644 --- a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift +++ b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift @@ -22,7 +22,7 @@ struct DeveloperOptionsScreen: View { var body: some View { Form { - Section { + Section("Timeline") { Toggle(isOn: $context.shouldCollapseRoomStateEvents) { Text("Collapse room state events") } @@ -30,29 +30,33 @@ struct DeveloperOptionsScreen: View { context.send(viewAction: .changedShouldCollapseRoomStateEvents) } - Toggle(isOn: $context.userSuggestionsEnabled) { - Text("User suggestions") - } - .onChange(of: context.userSuggestionsEnabled) { _ in - context.send(viewAction: .changedUserSuggestionsEnabled) - } - Toggle(isOn: $context.readReceiptsEnabled) { Text("Show read receipts") - Text("requires app reboot") + Text("Requires app reboot") } .onChange(of: context.readReceiptsEnabled) { _ in context.send(viewAction: .changedReadReceiptsEnabled) } - + } + + Section("Notifications") { Toggle(isOn: $context.isEncryptionSyncEnabled) { Text("Use notification encryption sync") - Text("requires app reboot") + 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("Location sharing") { Toggle(isOn: $context.locationEventsEnabled) { Text("Location events in timeline") } @@ -66,12 +70,14 @@ struct DeveloperOptionsScreen: View { .onChange(of: context.shareLocationEnabled) { _ in context.send(viewAction: .changedShareLocationEnabled) } - - Toggle(isOn: $context.notificationSettingsEnabled) { - Text("Show notification settings") + } + + Section("Room creation") { + Toggle(isOn: $context.userSuggestionsEnabled) { + Text("User suggestions") } - .onChange(of: context.notificationSettingsEnabled) { _ in - context.send(viewAction: .changedNotificationSettingsEnabled) + .onChange(of: context.userSuggestionsEnabled) { _ in + context.send(viewAction: .changedUserSuggestionsEnabled) } } @@ -81,6 +87,14 @@ struct DeveloperOptionsScreen: View { } label: { Text("🥳") .frame(maxWidth: .infinity) + .alignmentGuide(.listRowSeparatorLeading) { _ in 0 } // Fix separator alignment + } + + Button { + fatalError("This crash is a test.") + } label: { + Text("💥") + .frame(maxWidth: .infinity) } } @@ -118,8 +132,10 @@ struct DeveloperOptionsScreen: View { // MARK: - Previews struct DeveloperOptionsScreen_Previews: PreviewProvider { + static let viewModel = DeveloperOptionsScreenViewModel(appSettings: ServiceLocator.shared.settings) static var previews: some View { - let viewModel = DeveloperOptionsScreenViewModel(appSettings: ServiceLocator.shared.settings) - DeveloperOptionsScreen(context: viewModel.context) + NavigationStack { + DeveloperOptionsScreen(context: viewModel.context) + } } } diff --git a/ElementX/Sources/Services/Client/ClientProxy.swift b/ElementX/Sources/Services/Client/ClientProxy.swift index 15017093b..fa5d2cc52 100644 --- a/ElementX/Sources/Services/Client/ClientProxy.swift +++ b/ElementX/Sources/Services/Client/ClientProxy.swift @@ -149,8 +149,8 @@ class ClientProxy: ClientProxyProtocol { func directRoomForUserID(_ userID: String) async -> Result { await Task.dispatch(on: clientQueue) { do { - let roomId = try self.client.getDmRoom(userId: userID)?.id() - return .success(roomId) + let roomID = try self.client.getDmRoom(userId: userID)?.id() + return .success(roomID) } catch { return .failure(.failedRetrievingDirectRoom) } @@ -182,8 +182,8 @@ class ClientProxy: ClientProxyProtocol { preset: isRoomPrivate ? .privateChat : .publicChat, invite: userIDs, avatar: avatarURL?.absoluteString) - let roomId = try self.client.createRoom(request: parameters) - return .success(roomId) + let roomID = try self.client.createRoom(request: parameters) + return .success(roomID) } catch { return .failure(.failedCreatingRoom) } @@ -208,16 +208,16 @@ class ClientProxy: ClientProxyProtocol { } /// Await the room to be available in the room summary list - /// - Parameter result: the result of a room creation Task with the roomId + /// - Parameter result: the result of a room creation Task with the `roomID`. private func waitForRoomSummary(with result: Result, name: String?) async -> Result { - guard case .success(let roomId) = result else { return result } + guard case .success(let roomID) = result else { return result } let runner = ExpiringTaskRunner { [weak self] in guard let roomLists = self?.roomSummaryProvider?.roomListPublisher.values else { return } // for every list of summaries, we check if we have a room summary with matching ID and name (if present) for await roomList in roomLists { - guard let summary = roomList.first(where: { $0.id == roomId }) else { continue } + guard let summary = roomList.first(where: { $0.id == roomID }) else { continue } guard let name else { break } if summary.name == name { break