SwiftUI NavigationController and UserNotificationControllers (#309)

* Fixes #286 - Adopted the new SwiftUI NavigationStack based NavigationController throughout the application
* Fixes #315 - Implemented new user notification components on top of SwiftUI and the new navigation flows
* Add home screen fade animation between skeletons and real rooms
* Bump the danger-swift version used on the CI and swiftlint with it
* Renamed Splash to Onboarding, Empty to Splash
This commit is contained in:
Stefan Ceriu
2022-11-16 15:37:34 +02:00
committed by GitHub
parent af85c770da
commit 2fd0491a18
108 changed files with 1627 additions and 3720 deletions
@@ -17,74 +17,58 @@
import SwiftUI
import UIKit
class UITestsAppCoordinator: Coordinator {
private let window: UIWindow
private let mainNavigationController: ElementNavigationController
private let navigationRouter: NavigationRouter
private var hostingController: UIViewController?
var childCoordinators: [Coordinator] = []
class UITestsAppCoordinator: CoordinatorProtocol {
private let navigationController: NavigationController
init() {
mainNavigationController = ElementNavigationController()
mainNavigationController.navigationBar.prefersLargeTitles = true
navigationRouter = NavigationRouter(navigationController: mainNavigationController)
window = UIWindow(frame: UIScreen.main.bounds)
window.rootViewController = mainNavigationController
window.tintColor = .element.accent
UIView.setAnimationsEnabled(false)
let screens = mockScreens()
let rootView = UITestsRootView(mockScreens: screens) { id in
guard let screen = screens.first(where: { $0.id == id }) else {
fatalError()
}
screen.coordinator.start()
self.navigationRouter.setRootModule(screen.coordinator)
}
let hostingController = UIHostingController(rootView: rootView)
self.hostingController = hostingController
mainNavigationController.setViewControllers([hostingController], animated: false)
navigationController = NavigationController()
}
func start() {
window.makeKeyAndVisible()
let screens = mockScreens()
let rootCoordinator = UITestsRootCoordinator(mockScreens: screens) { id in
guard let screen = screens.first(where: { $0.id == id }) else {
fatalError()
}
self.navigationController.setRootCoordinator(screen.coordinator)
}
navigationController.setRootCoordinator(rootCoordinator)
}
func toPresentable() -> AnyView {
navigationController.toPresentable()
}
private func mockScreens() -> [MockScreen] {
UITestScreenIdentifier.allCases.map { MockScreen(id: $0, navigationRouter: navigationRouter) }
UITestScreenIdentifier.allCases.map { MockScreen(id: $0, navigationController: navigationController) }
}
func stop() { }
}
@MainActor
class MockScreen: Identifiable {
let id: UITestScreenIdentifier
let navigationRouter: NavigationRouter
lazy var coordinator: Coordinator & Presentable = {
let navigationController: NavigationController
lazy var coordinator: CoordinatorProtocol = {
switch id {
case .login:
return LoginCoordinator(parameters: .init(authenticationService: MockAuthenticationServiceProxy(),
navigationRouter: navigationRouter))
navigationController: navigationController))
case .serverSelection:
return ServerSelectionCoordinator(parameters: .init(authenticationService: MockAuthenticationServiceProxy(),
hasModalPresentation: true))
userNotificationController: MockUserNotificationController(),
isModallyPresented: true))
case .serverSelectionNonModal:
return ServerSelectionCoordinator(parameters: .init(authenticationService: MockAuthenticationServiceProxy(),
hasModalPresentation: false))
userNotificationController: MockUserNotificationController(),
isModallyPresented: false))
case .analyticsPrompt:
return AnalyticsPromptCoordinator(parameters: .init(userSession: MockUserSession(clientProxy: MockClientProxy(userIdentifier: "@mock:client.com"),
mediaProvider: MockMediaProvider())))
case .authenticationFlow:
return AuthenticationCoordinator(authenticationService: MockAuthenticationServiceProxy(),
navigationRouter: navigationRouter)
navigationController: navigationController)
case .softLogout:
let credentials = SoftLogoutCredentials(userId: "@mock:matrix.org",
homeserverName: "matrix.org",
@@ -100,29 +84,37 @@ class MockScreen: Identifiable {
case .home:
let session = MockUserSession(clientProxy: MockClientProxy(userIdentifier: "@mock:matrix.org"),
mediaProvider: MockMediaProvider())
return HomeScreenCoordinator(parameters: .init(userSession: session, attributedStringBuilder: AttributedStringBuilder()))
return HomeScreenCoordinator(parameters: .init(userSession: session,
attributedStringBuilder: AttributedStringBuilder(),
bugReportService: MockBugReportService(),
navigationController: navigationController))
case .settings:
return SettingsCoordinator(parameters: .init(navigationRouter: navigationRouter,
return SettingsCoordinator(parameters: .init(navigationController: navigationController,
userNotificationController: MockUserNotificationController(),
userSession: MockUserSession(clientProxy: MockClientProxy(userIdentifier: "@mock:client.com"),
mediaProvider: MockMediaProvider()),
bugReportService: MockBugReportService()))
case .bugReport:
return BugReportCoordinator(parameters: .init(bugReportService: MockBugReportService(),
screenshot: nil))
userNotificationController: MockUserNotificationController(),
screenshot: nil,
isModallyPresented: false))
case .bugReportWithScreenshot:
return BugReportCoordinator(parameters: .init(bugReportService: MockBugReportService(),
screenshot: Asset.Images.appLogo.image))
userNotificationController: MockUserNotificationController(),
screenshot: Asset.Images.appLogo.image,
isModallyPresented: false))
case .splash:
return SplashScreenCoordinator()
return OnboardingCoordinator()
case .roomPlainNoAvatar:
let parameters = RoomScreenCoordinatorParameters(navigationRouter: navigationRouter,
let parameters = RoomScreenCoordinatorParameters(navigationController: navigationController,
timelineController: MockRoomTimelineController(),
mediaProvider: MockMediaProvider(),
roomName: "Some room name",
roomAvatarUrl: nil)
return RoomScreenCoordinator(parameters: parameters)
case .roomEncryptedWithAvatar:
let parameters = RoomScreenCoordinatorParameters(navigationRouter: navigationRouter,
let parameters = RoomScreenCoordinatorParameters(navigationController: navigationController,
timelineController: MockRoomTimelineController(),
mediaProvider: MockMediaProvider(),
roomName: "Some room name",
@@ -134,8 +126,8 @@ class MockScreen: Identifiable {
}
}()
init(id: UITestScreenIdentifier, navigationRouter: NavigationRouter) {
init(id: UITestScreenIdentifier, navigationController: NavigationController) {
self.id = id
self.navigationRouter = navigationRouter
self.navigationController = navigationController
}
}
@@ -16,20 +16,22 @@
import SwiftUI
struct UITestsRootView: View {
struct UITestsRootCoordinator: CoordinatorProtocol {
let mockScreens: [MockScreen]
var selectionCallback: ((UITestScreenIdentifier) -> Void)?
var body: some View {
NavigationView {
List(mockScreens) { coordinator in
Button(coordinator.id.description) {
selectionCallback?(coordinator.id)
}
.accessibilityIdentifier(coordinator.id.rawValue)
func toPresentable() -> AnyView {
AnyView(body)
}
private var body: some View {
List(mockScreens) { coordinator in
Button(coordinator.id.description) {
selectionCallback?(coordinator.id)
}
.listStyle(.plain)
.accessibilityIdentifier(coordinator.id.rawValue)
}
.listStyle(.plain)
.navigationTitle("Screens")
.navigationViewStyle(.stack)
}