From 823a824b5be6abb834df5e51d40486a096fc5c68 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Tue, 14 Feb 2023 11:09:55 +0100 Subject: [PATCH] 547 refactored userNotification into userIndicator --- .../Sources/Application/AppCoordinator.swift | 24 +++++------ .../Sources/Application/ServiceLocator.swift | 6 +-- .../MockUserIndicatorController.swift} | 8 ++-- .../UserIndicator.swift} | 10 ++--- .../UserIndicatorController.swift} | 40 +++++++++---------- .../UserIndicatorControllerProtocol.swift} | 8 ++-- .../UserIndicatorModalView.swift} | 28 ++++++------- .../UserIndicatorPresenter.swift} | 18 ++++----- .../UserIndicatorToastView.swift} | 18 ++++----- .../AuthenticationCoordinator.swift | 12 +++--- .../LoginScreen/LoginCoordinator.swift | 16 ++++---- .../ServerSelectionCoordinator.swift | 14 +++---- .../SoftLogout/SoftLogoutCoordinator.swift | 10 ++--- .../BugReport/BugReportCoordinator.swift | 18 ++++----- .../RoomDetails/RoomDetailsViewModel.swift | 4 +- .../RoomScreen/RoomScreenViewModel.swift | 8 ++-- .../Settings/SettingsScreenCoordinator.swift | 6 +-- .../UserSessionFlowCoordinator.swift | 12 +++--- .../UITests/UITestsAppCoordinator.swift | 12 +++--- .../UserNotificationControllerTests.swift | 24 +++++------ changelog.d/547.change | 1 + 21 files changed, 149 insertions(+), 148 deletions(-) rename ElementX/Sources/Other/{UserNotifications/MockUserNotificationController.swift => UserIndicator/MockUserIndicatorController.swift} (72%) rename ElementX/Sources/Other/{UserNotifications/UserNotification.swift => UserIndicator/UserIndicator.swift} (82%) rename ElementX/Sources/Other/{UserNotifications/UserNotificationController.swift => UserIndicator/UserIndicatorController.swift} (57%) rename ElementX/Sources/Other/{UserNotifications/UserNotificationControllerProtocol.swift => UserIndicator/UserIndicatorControllerProtocol.swift} (74%) rename ElementX/Sources/Other/{UserNotifications/UserNotificationModalView.swift => UserIndicator/UserIndicatorModalView.swift} (64%) rename ElementX/Sources/Other/{UserNotifications/UserNotificationPresenter.swift => UserIndicator/UserIndicatorPresenter.swift} (60%) rename ElementX/Sources/Other/{UserNotifications/UserNotificationToastView.swift => UserIndicator/UserIndicatorToastView.swift} (72%) create mode 100644 changelog.d/547.change diff --git a/ElementX/Sources/Application/AppCoordinator.swift b/ElementX/Sources/Application/AppCoordinator.swift index 2a2d34483..8575757da 100644 --- a/ElementX/Sources/Application/AppCoordinator.swift +++ b/ElementX/Sources/Application/AppCoordinator.swift @@ -101,13 +101,13 @@ class AppCoordinator: AppCoordinatorProtocol { } func toPresentable() -> AnyView { - ServiceLocator.shared.userNotificationController.toPresentable() + ServiceLocator.shared.userIndicatorController.toPresentable() } // MARK: - Private private static func setupServiceLocator(navigationRootCoordinator: NavigationRootCoordinator) { - ServiceLocator.shared.register(userNotificationController: UserNotificationController(rootCoordinator: navigationRootCoordinator)) + ServiceLocator.shared.register(userIndicatorController: UserIndicatorController(rootCoordinator: navigationRootCoordinator)) ServiceLocator.shared.register(appSettings: AppSettings()) ServiceLocator.shared.register(networkMonitor: NetworkMonitor()) } @@ -377,18 +377,18 @@ class AppCoordinator: AppCoordinatorProtocol { static let loadingIndicatorIdentifier = "AppCoordinatorLoading" private func showLoadingIndicator() { - ServiceLocator.shared.userNotificationController.submitNotification(UserNotification(id: Self.loadingIndicatorIdentifier, - type: .modal, - title: ElementL10n.loading, - persistent: true)) + ServiceLocator.shared.userIndicatorController.submitIndicator(UserIndicator(id: Self.loadingIndicatorIdentifier, + type: .modal, + title: ElementL10n.loading, + persistent: true)) } private func hideLoadingIndicator() { - ServiceLocator.shared.userNotificationController.retractNotificationWithId(Self.loadingIndicatorIdentifier) + ServiceLocator.shared.userIndicatorController.retractIndicatorWithId(Self.loadingIndicatorIdentifier) } private func showLoginErrorToast() { - ServiceLocator.shared.userNotificationController.submitNotification(UserNotification(title: "Failed logging in")) + ServiceLocator.shared.userIndicatorController.submitIndicator(UserIndicator(title: "Failed logging in")) } // MARK: - Application State @@ -447,11 +447,11 @@ class AppCoordinator: AppCoordinatorProtocol { MXLog.info("Reachability changed to \(reachable)") if reachable { - ServiceLocator.shared.userNotificationController.retractNotificationWithId(reachabilityNotificationIdentifier) + ServiceLocator.shared.userIndicatorController.retractIndicatorWithId(reachabilityNotificationIdentifier) } else { - ServiceLocator.shared.userNotificationController.submitNotification(.init(id: reachabilityNotificationIdentifier, - title: ElementL10n.a11yPresenceOffline, - persistent: true)) + ServiceLocator.shared.userIndicatorController.submitIndicator(.init(id: reachabilityNotificationIdentifier, + title: ElementL10n.a11yPresenceOffline, + persistent: true)) } }.store(in: &cancellables) } diff --git a/ElementX/Sources/Application/ServiceLocator.swift b/ElementX/Sources/Application/ServiceLocator.swift index 3e1927a45..2a674c62d 100644 --- a/ElementX/Sources/Application/ServiceLocator.swift +++ b/ElementX/Sources/Application/ServiceLocator.swift @@ -21,10 +21,10 @@ class ServiceLocator { private init() { } - private(set) var userNotificationController: UserNotificationControllerProtocol! + private(set) var userIndicatorController: UserIndicatorControllerProtocol! - func register(userNotificationController: UserNotificationControllerProtocol) { - self.userNotificationController = userNotificationController + func register(userIndicatorController: UserIndicatorControllerProtocol) { + self.userIndicatorController = userIndicatorController } private(set) var settings: AppSettings! diff --git a/ElementX/Sources/Other/UserNotifications/MockUserNotificationController.swift b/ElementX/Sources/Other/UserIndicator/MockUserIndicatorController.swift similarity index 72% rename from ElementX/Sources/Other/UserNotifications/MockUserNotificationController.swift rename to ElementX/Sources/Other/UserIndicator/MockUserIndicatorController.swift index 2b757aec7..607593de8 100644 --- a/ElementX/Sources/Other/UserNotifications/MockUserNotificationController.swift +++ b/ElementX/Sources/Other/UserIndicator/MockUserIndicatorController.swift @@ -16,10 +16,10 @@ import Foundation -class MockUserNotificationController: UserNotificationControllerProtocol { - func submitNotification(_ notification: UserNotification) { } +class MockUserIndicatorController: UserIndicatorControllerProtocol { + func submitIndicator(_ indicator: UserIndicator) { } - func retractNotificationWithId(_ id: String) { } + func retractIndicatorWithId(_ id: String) { } - func retractAllNotifications() { } + func retractAllIndicators() { } } diff --git a/ElementX/Sources/Other/UserNotifications/UserNotification.swift b/ElementX/Sources/Other/UserIndicator/UserIndicator.swift similarity index 82% rename from ElementX/Sources/Other/UserNotifications/UserNotification.swift rename to ElementX/Sources/Other/UserIndicator/UserIndicator.swift index 0b88637d4..b8a014c34 100644 --- a/ElementX/Sources/Other/UserNotifications/UserNotification.swift +++ b/ElementX/Sources/Other/UserIndicator/UserIndicator.swift @@ -14,15 +14,15 @@ // limitations under the License. // -import SwiftUI +import Foundation -enum UserNotificationType { +enum UserIndicatorType { case toast case modal } -struct UserNotification: Equatable, Identifiable { - static func == (lhs: UserNotification, rhs: UserNotification) -> Bool { +struct UserIndicator: Equatable, Identifiable { + static func == (lhs: UserIndicator, rhs: UserIndicator) -> Bool { lhs.id == rhs.id && lhs.type == rhs.type && lhs.title == rhs.title && @@ -31,7 +31,7 @@ struct UserNotification: Equatable, Identifiable { } var id: String = UUID().uuidString - var type = UserNotificationType.toast + var type = UserIndicatorType.toast var title: String var iconName: String? var persistent = false diff --git a/ElementX/Sources/Other/UserNotifications/UserNotificationController.swift b/ElementX/Sources/Other/UserIndicator/UserIndicatorController.swift similarity index 57% rename from ElementX/Sources/Other/UserNotifications/UserNotificationController.swift rename to ElementX/Sources/Other/UserIndicator/UserIndicatorController.swift index 9ff21ad36..813dfa846 100644 --- a/ElementX/Sources/Other/UserNotifications/UserNotificationController.swift +++ b/ElementX/Sources/Other/UserIndicator/UserIndicatorController.swift @@ -16,7 +16,7 @@ import SwiftUI -class UserNotificationController: ObservableObject, UserNotificationControllerProtocol, CustomStringConvertible { +class UserIndicatorController: ObservableObject, UserIndicatorControllerProtocol, CustomStringConvertible { private let rootCoordinator: CoordinatorProtocol private var dismisalTimer: Timer? @@ -25,15 +25,15 @@ class UserNotificationController: ObservableObject, UserNotificationControllerPr var nonPersistentDisplayDuration = 2.5 var minimumDisplayDuration = 0.5 - @Published private(set) var activeNotification: UserNotification? - private(set) var notificationQueue = [UserNotification]() { + @Published private(set) var activeIndicator: UserIndicator? + private(set) var indicatorQueue = [UserIndicator]() { didSet { - activeNotification = notificationQueue.last + activeIndicator = indicatorQueue.last - if let activeNotification, !activeNotification.persistent { + if let activeIndicator, !activeIndicator.persistent { dismisalTimer?.invalidate() dismisalTimer = Timer.scheduledTimer(withTimeInterval: nonPersistentDisplayDuration, repeats: false) { [weak self] _ in - self?.retractNotificationWithId(activeNotification.id) + self?.retractIndicatorWithId(activeIndicator.id) } } } @@ -45,35 +45,35 @@ class UserNotificationController: ObservableObject, UserNotificationControllerPr func toPresentable() -> AnyView { AnyView( - UserNotificationPresenter(userNotificationController: self, rootView: rootCoordinator.toPresentable()) + UserIndicatorPresenter(userIndicatorController: self, rootView: rootCoordinator.toPresentable()) ) } - func submitNotification(_ notification: UserNotification) { - if let index = notificationQueue.firstIndex(where: { $0.id == notification.id }) { - notificationQueue[index] = notification + func submitIndicator(_ indicator: UserIndicator) { + if let index = indicatorQueue.firstIndex(where: { $0.id == indicator.id }) { + indicatorQueue[index] = indicator } else { - retractNotificationWithId(notification.id) - notificationQueue.append(notification) + retractIndicatorWithId(indicator.id) + indicatorQueue.append(indicator) } - displayTimes[notification.id] = .now + displayTimes[indicator.id] = .now } - func retractAllNotifications() { - for notification in notificationQueue { - retractNotificationWithId(notification.id) + func retractAllIndicators() { + for indicator in indicatorQueue { + retractIndicatorWithId(indicator.id) } } - func retractNotificationWithId(_ id: String) { + func retractIndicatorWithId(_ id: String) { guard let displayTime = displayTimes[id], abs(displayTime.timeIntervalSinceNow) <= minimumDisplayDuration else { - notificationQueue.removeAll { $0.id == id } + indicatorQueue.removeAll { $0.id == id } return } Timer.scheduledTimer(withTimeInterval: minimumDisplayDuration, repeats: false) { [weak self] _ in - self?.notificationQueue.removeAll { $0.id == id } + self?.indicatorQueue.removeAll { $0.id == id } self?.displayTimes[id] = nil } } @@ -81,6 +81,6 @@ class UserNotificationController: ObservableObject, UserNotificationControllerPr // MARK: - CustomStringConvertible var description: String { - "UserNotificationController(\(String(describing: rootCoordinator)))" + "UserIndicatorController(\(String(describing: rootCoordinator)))" } } diff --git a/ElementX/Sources/Other/UserNotifications/UserNotificationControllerProtocol.swift b/ElementX/Sources/Other/UserIndicator/UserIndicatorControllerProtocol.swift similarity index 74% rename from ElementX/Sources/Other/UserNotifications/UserNotificationControllerProtocol.swift rename to ElementX/Sources/Other/UserIndicator/UserIndicatorControllerProtocol.swift index ba0ef6c1f..14537d671 100644 --- a/ElementX/Sources/Other/UserNotifications/UserNotificationControllerProtocol.swift +++ b/ElementX/Sources/Other/UserIndicator/UserIndicatorControllerProtocol.swift @@ -16,8 +16,8 @@ import Foundation -protocol UserNotificationControllerProtocol: CoordinatorProtocol { - func submitNotification(_ notification: UserNotification) - func retractNotificationWithId(_ id: String) - func retractAllNotifications() +protocol UserIndicatorControllerProtocol: CoordinatorProtocol { + func submitIndicator(_ indicator: UserIndicator) + func retractIndicatorWithId(_ id: String) + func retractAllIndicators() } diff --git a/ElementX/Sources/Other/UserNotifications/UserNotificationModalView.swift b/ElementX/Sources/Other/UserIndicator/UserIndicatorModalView.swift similarity index 64% rename from ElementX/Sources/Other/UserNotifications/UserNotificationModalView.swift rename to ElementX/Sources/Other/UserIndicator/UserIndicatorModalView.swift index 22eb9cb6e..3cc36f83b 100644 --- a/ElementX/Sources/Other/UserNotifications/UserNotificationModalView.swift +++ b/ElementX/Sources/Other/UserIndicator/UserIndicatorModalView.swift @@ -17,8 +17,8 @@ import Combine import SwiftUI -struct UserNotificationModalView: View { - let notification: UserNotification +struct UserIndicatorModalView: View { + let indicator: UserIndicator @State private var progressFraction: Double? var body: some View { @@ -31,10 +31,10 @@ struct UserNotificationModalView: View { } HStack { - if let iconName = notification.iconName { + if let iconName = indicator.iconName { Image(systemName: iconName) } - Text(notification.title) + Text(indicator.title) .font(.element.body) .foregroundColor(.element.primaryContent) } @@ -45,30 +45,30 @@ struct UserNotificationModalView: View { .background(Color.element.quinaryContent) .clipShape(RoundedCornerShape(radius: 12.0, corners: .allCorners)) .shadow(color: .black.opacity(0.1), radius: 10.0, y: 4.0) - .onReceive(notification.progressPublisher?.publisher ?? Empty().eraseToAnyPublisher()) { progress in + .onReceive(indicator.progressPublisher?.publisher ?? Empty().eraseToAnyPublisher()) { progress in progressFraction = progress } .transition(.opacity) } - .id(notification.id) + .id(indicator.id) .frame(maxWidth: .infinity, maxHeight: .infinity) .background(.black.opacity(0.1)) .ignoresSafeArea() } } -struct UserNotificationModalView_Previews: PreviewProvider { +struct UserIndicatorModalView_Previews: PreviewProvider { static var previews: some View { Group { - UserNotificationModalView(notification: UserNotification(type: .modal, - title: "Successfully logged in", - iconName: "checkmark") + UserIndicatorModalView(indicator: UserIndicator(type: .modal, + title: "Successfully logged in", + iconName: "checkmark") ) .previewDisplayName("Spinner") - UserNotificationModalView(notification: UserNotification(type: .modal, - title: "Successfully logged in", - iconName: "checkmark", - progressPublisher: ProgressTracker(initialValue: 0.5)) + UserIndicatorModalView(indicator: UserIndicator(type: .modal, + title: "Successfully logged in", + iconName: "checkmark", + progressPublisher: ProgressTracker(initialValue: 0.5)) ) .previewDisplayName("Progress Bar") } diff --git a/ElementX/Sources/Other/UserNotifications/UserNotificationPresenter.swift b/ElementX/Sources/Other/UserIndicator/UserIndicatorPresenter.swift similarity index 60% rename from ElementX/Sources/Other/UserNotifications/UserNotificationPresenter.swift rename to ElementX/Sources/Other/UserIndicator/UserIndicatorPresenter.swift index 5856ba918..56efc4bfb 100644 --- a/ElementX/Sources/Other/UserNotifications/UserNotificationPresenter.swift +++ b/ElementX/Sources/Other/UserIndicator/UserIndicatorPresenter.swift @@ -16,27 +16,27 @@ import SwiftUI -struct UserNotificationPresenter: View { - @ObservedObject var userNotificationController: UserNotificationController +struct UserIndicatorPresenter: View { + @ObservedObject var userIndicatorController: UserIndicatorController let rootView: AnyView var body: some View { ZStack(alignment: .top) { rootView - notificationViewFor(notification: userNotificationController.activeNotification) + indicatorViewFor(indicator: userIndicatorController.activeIndicator) } - .animation(.elementDefault, value: userNotificationController.activeNotification) + .animation(.elementDefault, value: userIndicatorController.activeIndicator) } @ViewBuilder - private func notificationViewFor(notification: UserNotification?) -> some View { + private func indicatorViewFor(indicator: UserIndicator?) -> some View { ZStack { // Need a container to properly animate transitions - if let notification { - switch notification.type { + if let indicator { + switch indicator.type { case .toast: - UserNotificationToastView(notification: notification) + UserIndicatorToastView(indicator: indicator) case .modal: - UserNotificationModalView(notification: notification) + UserIndicatorModalView(indicator: indicator) } } } diff --git a/ElementX/Sources/Other/UserNotifications/UserNotificationToastView.swift b/ElementX/Sources/Other/UserIndicator/UserIndicatorToastView.swift similarity index 72% rename from ElementX/Sources/Other/UserNotifications/UserNotificationToastView.swift rename to ElementX/Sources/Other/UserIndicator/UserIndicatorToastView.swift index 4c3814e2b..64a8ce8aa 100644 --- a/ElementX/Sources/Other/UserNotifications/UserNotificationToastView.swift +++ b/ElementX/Sources/Other/UserIndicator/UserIndicatorToastView.swift @@ -16,19 +16,19 @@ import SwiftUI -struct UserNotificationToastView: View { - let notification: UserNotification +struct UserIndicatorToastView: View { + let indicator: UserIndicator var body: some View { HStack { - if let iconName = notification.iconName { + if let iconName = indicator.iconName { Image(systemName: iconName) } - Text(notification.title) + Text(indicator.title) .font(.element.footnote) .foregroundColor(.element.primaryContent) } - .id(notification.id) + .id(indicator.id) .padding(.horizontal, 12.0) .padding(.vertical, 10.0) .frame(minWidth: 150.0) @@ -46,13 +46,13 @@ struct UserNotificationToastView: View { } } -struct UserNotificationToastView_Previews: PreviewProvider { +struct UserIndicatorToastView_Previews: PreviewProvider { static var previews: some View { VStack { - UserNotificationToastView(notification: UserNotification(title: "Successfully logged in", - iconName: "checkmark")) + UserIndicatorToastView(indicator: UserIndicator(title: "Successfully logged in", + iconName: "checkmark")) - UserNotificationToastView(notification: UserNotification(title: "Toast without icon")) + UserIndicatorToastView(indicator: UserIndicator(title: "Toast without icon")) } } } diff --git a/ElementX/Sources/Screens/Authentication/AuthenticationCoordinator.swift b/ElementX/Sources/Screens/Authentication/AuthenticationCoordinator.swift index 27e065146..10352a699 100644 --- a/ElementX/Sources/Screens/Authentication/AuthenticationCoordinator.swift +++ b/ElementX/Sources/Screens/Authentication/AuthenticationCoordinator.swift @@ -73,7 +73,7 @@ class AuthenticationCoordinator: CoordinatorProtocol { private func showServerSelectionScreen() { let parameters = ServerSelectionCoordinatorParameters(authenticationService: authenticationService, - userNotificationController: ServiceLocator.shared.userNotificationController, + userIndicatorController: ServiceLocator.shared.userIndicatorController, isModallyPresented: false) let coordinator = ServerSelectionCoordinator(parameters: parameters) @@ -123,13 +123,13 @@ class AuthenticationCoordinator: CoordinatorProtocol { static let loadingIndicatorIdentifier = "AuthenticationCoordinatorLoading" private func startLoading() { - ServiceLocator.shared.userNotificationController.submitNotification(UserNotification(id: Self.loadingIndicatorIdentifier, - type: .modal, - title: ElementL10n.loading, - persistent: true)) + ServiceLocator.shared.userIndicatorController.submitIndicator(UserIndicator(id: Self.loadingIndicatorIdentifier, + type: .modal, + title: ElementL10n.loading, + persistent: true)) } private func stopLoading() { - ServiceLocator.shared.userNotificationController.retractNotificationWithId(Self.loadingIndicatorIdentifier) + ServiceLocator.shared.userIndicatorController.retractIndicatorWithId(Self.loadingIndicatorIdentifier) } } diff --git a/ElementX/Sources/Screens/Authentication/LoginScreen/LoginCoordinator.swift b/ElementX/Sources/Screens/Authentication/LoginScreen/LoginCoordinator.swift index 501348879..2dff6267a 100644 --- a/ElementX/Sources/Screens/Authentication/LoginScreen/LoginCoordinator.swift +++ b/ElementX/Sources/Screens/Authentication/LoginScreen/LoginCoordinator.swift @@ -92,10 +92,10 @@ final class LoginCoordinator: CoordinatorProtocol { static let loadingIndicatorIdentifier = "LoginCoordinatorLoading" private func startLoading(isInteractionBlocking: Bool) { - ServiceLocator.shared.userNotificationController.submitNotification(UserNotification(id: Self.loadingIndicatorIdentifier, - type: .modal, - title: ElementL10n.loading, - persistent: true)) + ServiceLocator.shared.userIndicatorController.submitIndicator(UserIndicator(id: Self.loadingIndicatorIdentifier, + type: .modal, + title: ElementL10n.loading, + persistent: true)) if !isInteractionBlocking { viewModel.update(isLoading: true) @@ -104,15 +104,15 @@ final class LoginCoordinator: CoordinatorProtocol { private func stopLoading() { viewModel.update(isLoading: false) - ServiceLocator.shared.userNotificationController.retractNotificationWithId(Self.loadingIndicatorIdentifier) + ServiceLocator.shared.userIndicatorController.retractIndicatorWithId(Self.loadingIndicatorIdentifier) } private func indicateSuccess() { - ServiceLocator.shared.userNotificationController.submitNotification(UserNotification(title: ElementL10n.dialogTitleSuccess)) + ServiceLocator.shared.userIndicatorController.submitIndicator(UserIndicator(title: ElementL10n.dialogTitleSuccess)) } private func indicateFailure() { - ServiceLocator.shared.userNotificationController.submitNotification(UserNotification(title: ElementL10n.dialogTitleError)) + ServiceLocator.shared.userIndicatorController.submitIndicator(UserIndicator(title: ElementL10n.dialogTitleError)) } /// Processes an error to either update the flow or display it to the user. @@ -200,7 +200,7 @@ final class LoginCoordinator: CoordinatorProtocol { /// Presents the server selection screen as a modal. private func presentServerSelectionScreen() { let parameters = ServerSelectionCoordinatorParameters(authenticationService: authenticationService, - userNotificationController: ServiceLocator.shared.userNotificationController, + userIndicatorController: ServiceLocator.shared.userIndicatorController, isModallyPresented: false) let coordinator = ServerSelectionCoordinator(parameters: parameters) diff --git a/ElementX/Sources/Screens/Authentication/ServerSelection/ServerSelectionCoordinator.swift b/ElementX/Sources/Screens/Authentication/ServerSelection/ServerSelectionCoordinator.swift index 593de46dd..28d3c544d 100644 --- a/ElementX/Sources/Screens/Authentication/ServerSelection/ServerSelectionCoordinator.swift +++ b/ElementX/Sources/Screens/Authentication/ServerSelection/ServerSelectionCoordinator.swift @@ -19,7 +19,7 @@ import SwiftUI struct ServerSelectionCoordinatorParameters { /// The service used to authenticate the user. let authenticationService: AuthenticationServiceProxyProtocol - let userNotificationController: UserNotificationControllerProtocol + let userIndicatorController: UserIndicatorControllerProtocol /// Whether the screen is presented modally or within a navigation stack. let isModallyPresented: Bool } @@ -31,7 +31,7 @@ enum ServerSelectionCoordinatorAction { final class ServerSelectionCoordinator: CoordinatorProtocol { private let parameters: ServerSelectionCoordinatorParameters - private let userNotificationController: UserNotificationControllerProtocol + private let userIndicatorController: UserIndicatorControllerProtocol private var viewModel: ServerSelectionViewModelProtocol private var authenticationService: AuthenticationServiceProxyProtocol { parameters.authenticationService } @@ -41,7 +41,7 @@ final class ServerSelectionCoordinator: CoordinatorProtocol { self.parameters = parameters viewModel = ServerSelectionViewModel(homeserverAddress: parameters.authenticationService.homeserver.address, isModallyPresented: parameters.isModallyPresented) - userNotificationController = parameters.userNotificationController + userIndicatorController = parameters.userIndicatorController } // MARK: - Public @@ -70,13 +70,13 @@ final class ServerSelectionCoordinator: CoordinatorProtocol { // MARK: - Private private func startLoading(label: String = ElementL10n.loading) { - userNotificationController.submitNotification(UserNotification(type: .modal, - title: label, - persistent: true)) + userIndicatorController.submitIndicator(UserIndicator(type: .modal, + title: label, + persistent: true)) } private func stopLoading() { - userNotificationController.retractAllNotifications() + userIndicatorController.retractAllIndicators() } /// Updates the login flow using the supplied homeserver address, or shows an error when this isn't possible. diff --git a/ElementX/Sources/Screens/Authentication/SoftLogout/SoftLogoutCoordinator.swift b/ElementX/Sources/Screens/Authentication/SoftLogout/SoftLogoutCoordinator.swift index 86e491e9e..ba0c612fd 100644 --- a/ElementX/Sources/Screens/Authentication/SoftLogout/SoftLogoutCoordinator.swift +++ b/ElementX/Sources/Screens/Authentication/SoftLogout/SoftLogoutCoordinator.swift @@ -99,15 +99,15 @@ final class SoftLogoutCoordinator: CoordinatorProtocol { /// Show an activity indicator whilst loading. @MainActor private func startLoading() { - ServiceLocator.shared.userNotificationController.submitNotification(UserNotification(id: Self.loadingIndicatorIdentifier, - type: .modal, - title: ElementL10n.loading, - persistent: true)) + ServiceLocator.shared.userIndicatorController.submitIndicator(UserIndicator(id: Self.loadingIndicatorIdentifier, + type: .modal, + title: ElementL10n.loading, + persistent: true)) } /// Hide the currently displayed activity indicator. @MainActor private func stopLoading() { - ServiceLocator.shared.userNotificationController.retractNotificationWithId(Self.loadingIndicatorIdentifier) + ServiceLocator.shared.userIndicatorController.retractIndicatorWithId(Self.loadingIndicatorIdentifier) } /// Shows the forgot password screen. diff --git a/ElementX/Sources/Screens/BugReport/BugReportCoordinator.swift b/ElementX/Sources/Screens/BugReport/BugReportCoordinator.swift index fa35fb595..0b0d40497 100644 --- a/ElementX/Sources/Screens/BugReport/BugReportCoordinator.swift +++ b/ElementX/Sources/Screens/BugReport/BugReportCoordinator.swift @@ -23,7 +23,7 @@ enum BugReportCoordinatorResult { struct BugReportCoordinatorParameters { let bugReportService: BugReportServiceProtocol - weak var userNotificationController: UserNotificationControllerProtocol? + weak var userIndicatorController: UserIndicatorControllerProtocol? let screenshot: UIImage? let isModallyPresented: Bool } @@ -76,20 +76,20 @@ final class BugReportCoordinator: CoordinatorProtocol { static let loadingIndicatorIdentifier = "BugReportLoading" private func startLoading(label: String = ElementL10n.loading, progressPublisher: ProgressPublisher) { - parameters.userNotificationController?.submitNotification( - UserNotification(id: Self.loadingIndicatorIdentifier, - type: .modal, - title: label, - persistent: true, - progressPublisher: progressPublisher) + parameters.userIndicatorController?.submitIndicator( + UserIndicator(id: Self.loadingIndicatorIdentifier, + type: .modal, + title: label, + persistent: true, + progressPublisher: progressPublisher) ) } private func stopLoading() { - parameters.userNotificationController?.retractNotificationWithId(Self.loadingIndicatorIdentifier) + parameters.userIndicatorController?.retractIndicatorWithId(Self.loadingIndicatorIdentifier) } private func showError(label: String) { - parameters.userNotificationController?.submitNotification(UserNotification(title: label)) + parameters.userIndicatorController?.submitIndicator(UserIndicator(title: label)) } } diff --git a/ElementX/Sources/Screens/RoomDetails/RoomDetailsViewModel.swift b/ElementX/Sources/Screens/RoomDetails/RoomDetailsViewModel.swift index 949b4db91..0f23a7e2d 100644 --- a/ElementX/Sources/Screens/RoomDetails/RoomDetailsViewModel.swift +++ b/ElementX/Sources/Screens/RoomDetails/RoomDetailsViewModel.swift @@ -68,9 +68,9 @@ class RoomDetailsViewModel: RoomDetailsViewModelType, RoomDetailsViewModelProtoc private func copyRoomLink() { if let roomLink = state.permalink { UIPasteboard.general.url = roomLink - ServiceLocator.shared.userNotificationController.submitNotification(UserNotification(title: ElementL10n.linkCopiedToClipboard)) + ServiceLocator.shared.userIndicatorController.submitIndicator(UserIndicator(title: ElementL10n.linkCopiedToClipboard)) } else { - ServiceLocator.shared.userNotificationController.submitNotification(UserNotification(title: ElementL10n.unknownError)) + ServiceLocator.shared.userIndicatorController.submitIndicator(UserIndicator(title: ElementL10n.unknownError)) } } } diff --git a/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift b/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift index 42c2d8663..b5101951b 100644 --- a/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift +++ b/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift @@ -194,10 +194,10 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol title: ElementL10n.dialogTitleError, message: message) case .toast(let message): - ServiceLocator.shared.userNotificationController.submitNotification(UserNotification(id: Constants.toastErrorID, - type: .toast, - title: message, - iconName: "xmark")) + ServiceLocator.shared.userIndicatorController.submitIndicator(UserIndicator(id: Constants.toastErrorID, + type: .toast, + title: message, + iconName: "xmark")) } } diff --git a/ElementX/Sources/Screens/Settings/SettingsScreenCoordinator.swift b/ElementX/Sources/Screens/Settings/SettingsScreenCoordinator.swift index 27b783429..813aabc2c 100644 --- a/ElementX/Sources/Screens/Settings/SettingsScreenCoordinator.swift +++ b/ElementX/Sources/Screens/Settings/SettingsScreenCoordinator.swift @@ -18,7 +18,7 @@ import SwiftUI struct SettingsScreenCoordinatorParameters { weak var navigationStackCoordinator: NavigationStackCoordinator? - weak var userNotificationController: UserNotificationControllerProtocol? + weak var userIndicatorController: UserIndicatorControllerProtocol? let userSession: UserSessionProtocol let bugReportService: BugReportServiceProtocol } @@ -76,7 +76,7 @@ final class SettingsScreenCoordinator: CoordinatorProtocol { private func presentBugReportScreen() { let params = BugReportCoordinatorParameters(bugReportService: parameters.bugReportService, - userNotificationController: parameters.userNotificationController, + userIndicatorController: parameters.userIndicatorController, screenshot: nil, isModallyPresented: false) let coordinator = BugReportCoordinator(parameters: params) @@ -112,6 +112,6 @@ final class SettingsScreenCoordinator: CoordinatorProtocol { } private func showSuccess(label: String) { - parameters.userNotificationController?.submitNotification(UserNotification(title: label)) + parameters.userIndicatorController?.submitIndicator(UserIndicator(title: label)) } } diff --git a/ElementX/Sources/Services/UserSession/UserSessionFlowCoordinator.swift b/ElementX/Sources/Services/UserSession/UserSessionFlowCoordinator.swift index 964b8b8ae..4288cf3a4 100644 --- a/ElementX/Sources/Services/UserSession/UserSessionFlowCoordinator.swift +++ b/ElementX/Sources/Services/UserSession/UserSessionFlowCoordinator.swift @@ -188,10 +188,10 @@ class UserSessionFlowCoordinator: CoordinatorProtocol { private func presentSettingsScreen() { let settingsNavigationStackCoordinator = NavigationStackCoordinator() - let userNotificationController = UserNotificationController(rootCoordinator: settingsNavigationStackCoordinator) + let userIndicatorController = UserIndicatorController(rootCoordinator: settingsNavigationStackCoordinator) let parameters = SettingsScreenCoordinatorParameters(navigationStackCoordinator: settingsNavigationStackCoordinator, - userNotificationController: userNotificationController, + userIndicatorController: userIndicatorController, userSession: userSession, bugReportService: bugReportService) let settingsScreenCoordinator = SettingsScreenCoordinator(parameters: parameters) @@ -208,7 +208,7 @@ class UserSessionFlowCoordinator: CoordinatorProtocol { settingsNavigationStackCoordinator.setRootCoordinator(settingsScreenCoordinator) - navigationSplitCoordinator.setSheetCoordinator(userNotificationController) { [weak self] in + navigationSplitCoordinator.setSheetCoordinator(userIndicatorController) { [weak self] in self?.stateMachine.processEvent(.dismissedSettingsScreen) } } @@ -238,10 +238,10 @@ class UserSessionFlowCoordinator: CoordinatorProtocol { private func presentFeedbackScreen(for image: UIImage? = nil) { let feedbackNavigationStackCoordinator = NavigationStackCoordinator() - let userNotificationController = UserNotificationController(rootCoordinator: feedbackNavigationStackCoordinator) + let userIndicatorController = UserIndicatorController(rootCoordinator: feedbackNavigationStackCoordinator) let parameters = BugReportCoordinatorParameters(bugReportService: bugReportService, - userNotificationController: userNotificationController, + userIndicatorController: userIndicatorController, screenshot: image, isModallyPresented: true) let coordinator = BugReportCoordinator(parameters: parameters) @@ -251,7 +251,7 @@ class UserSessionFlowCoordinator: CoordinatorProtocol { feedbackNavigationStackCoordinator.setRootCoordinator(coordinator) - navigationSplitCoordinator.setSheetCoordinator(userNotificationController) { [weak self] in + navigationSplitCoordinator.setSheetCoordinator(userIndicatorController) { [weak self] in self?.stateMachine.processEvent(.dismissedFeedbackScreen) } } diff --git a/ElementX/Sources/UITests/UITestsAppCoordinator.swift b/ElementX/Sources/UITests/UITestsAppCoordinator.swift index 0cf6b191a..3fceacb74 100644 --- a/ElementX/Sources/UITests/UITestsAppCoordinator.swift +++ b/ElementX/Sources/UITests/UITestsAppCoordinator.swift @@ -27,7 +27,7 @@ class UITestsAppCoordinator: AppCoordinatorProtocol { navigationRootCoordinator = NavigationRootCoordinator() mockScreens = UITestScreenIdentifier.allCases.map { MockScreen(id: $0, navigationRootCoordinator: navigationRootCoordinator) } - ServiceLocator.shared.register(userNotificationController: MockUserNotificationController()) + ServiceLocator.shared.register(userIndicatorController: MockUserIndicatorController()) AppSettings.configureWithSuiteName("io.element.elementx.uitests") AppSettings.reset() @@ -76,13 +76,13 @@ class MockScreen: Identifiable { case .serverSelection: let navigationStackCoordinator = NavigationStackCoordinator() let coordinator = ServerSelectionCoordinator(parameters: .init(authenticationService: MockAuthenticationServiceProxy(), - userNotificationController: MockUserNotificationController(), + userIndicatorController: MockUserIndicatorController(), isModallyPresented: true)) navigationStackCoordinator.setRootCoordinator(coordinator) return navigationStackCoordinator case .serverSelectionNonModal: return ServerSelectionCoordinator(parameters: .init(authenticationService: MockAuthenticationServiceProxy(), - userNotificationController: MockUserNotificationController(), + userIndicatorController: MockUserIndicatorController(), isModallyPresented: false)) case .analyticsPrompt: return AnalyticsPromptCoordinator(parameters: .init(userSession: MockUserSession(clientProxy: MockClientProxy(userID: "@mock:client.com"), @@ -119,7 +119,7 @@ class MockScreen: Identifiable { case .settings: let navigationStackCoordinator = NavigationStackCoordinator() let coordinator = SettingsScreenCoordinator(parameters: .init(navigationStackCoordinator: navigationStackCoordinator, - userNotificationController: nil, + userIndicatorController: nil, userSession: MockUserSession(clientProxy: MockClientProxy(userID: "@mock:client.com"), mediaProvider: MockMediaProvider()), bugReportService: MockBugReportService())) @@ -128,7 +128,7 @@ class MockScreen: Identifiable { case .bugReport: let navigationStackCoordinator = NavigationStackCoordinator() let coordinator = BugReportCoordinator(parameters: .init(bugReportService: MockBugReportService(), - userNotificationController: nil, + userIndicatorController: nil, screenshot: nil, isModallyPresented: true)) navigationStackCoordinator.setRootCoordinator(coordinator) @@ -136,7 +136,7 @@ class MockScreen: Identifiable { case .bugReportWithScreenshot: let navigationStackCoordinator = NavigationStackCoordinator() let coordinator = BugReportCoordinator(parameters: .init(bugReportService: MockBugReportService(), - userNotificationController: nil, + userIndicatorController: nil, screenshot: Asset.Images.appLogo.image, isModallyPresented: false)) navigationStackCoordinator.setRootCoordinator(coordinator) diff --git a/UnitTests/Sources/UserNotificationControllerTests.swift b/UnitTests/Sources/UserNotificationControllerTests.swift index 3fecff831..9c93a022d 100644 --- a/UnitTests/Sources/UserNotificationControllerTests.swift +++ b/UnitTests/Sources/UserNotificationControllerTests.swift @@ -21,19 +21,19 @@ import XCTest @testable import ElementX @MainActor -class UserNotificationControllerTests: XCTestCase { - private var notificationController: UserNotificationController! +class UserIndicatorControllerTests: XCTestCase { + private var notificationController: UserIndicatorController! override func setUp() { - notificationController = UserNotificationController(rootCoordinator: SplashScreenCoordinator()) + notificationController = UserIndicatorController(rootCoordinator: SplashScreenCoordinator()) } func testNotificationQueueing() { notificationController.minimumDisplayDuration = 0.0 - notificationController.submitNotification(.init(id: "First", title: "")) - notificationController.submitNotification(.init(id: "Second", title: "")) - notificationController.submitNotification(.init(id: "Third", title: "")) + notificationController.submitIndicator(.init(id: "First", title: "")) + notificationController.submitIndicator(.init(id: "Second", title: "")) + notificationController.submitIndicator(.init(id: "Third", title: "")) XCTAssertEqual(notificationController.notificationQueue.count, 3) XCTAssertEqual(notificationController.notificationQueue[2].id, "Third") @@ -55,9 +55,9 @@ class UserNotificationControllerTests: XCTestCase { notificationController.minimumDisplayDuration = 0.25 notificationController.nonPersistentDisplayDuration = 2.5 - notificationController.submitNotification(.init(id: "First", title: "")) - notificationController.submitNotification(.init(id: "Second", title: "")) - notificationController.submitNotification(.init(id: "Third", title: "")) + notificationController.submitIndicator(.init(id: "First", title: "")) + notificationController.submitIndicator(.init(id: "Second", title: "")) + notificationController.submitIndicator(.init(id: "Third", title: "")) XCTAssertEqual(notificationController.activeNotification?.id, "Third") @@ -76,9 +76,9 @@ class UserNotificationControllerTests: XCTestCase { notificationController.minimumDisplayDuration = 0.25 notificationController.nonPersistentDisplayDuration = 2.5 - notificationController.submitNotification(.init(id: "First", title: "")) - notificationController.submitNotification(.init(id: "Second", title: "")) - notificationController.submitNotification(.init(id: "Third", title: "")) + notificationController.submitIndicator(.init(id: "First", title: "")) + notificationController.submitIndicator(.init(id: "Second", title: "")) + notificationController.submitIndicator(.init(id: "Third", title: "")) notificationController.retractNotificationWithId("Second") diff --git a/changelog.d/547.change b/changelog.d/547.change new file mode 100644 index 000000000..68102daa1 --- /dev/null +++ b/changelog.d/547.change @@ -0,0 +1 @@ +Refactored UserNotification into UserIndicator. \ No newline at end of file