Merge branch 'langleyd/4781_swiftui_template_examples' of https://github.com/vector-im/element-ios into langleyd/4781_swiftui_template_example2

This commit is contained in:
David Langley
2021-09-15 17:32:19 +01:00
91 changed files with 3348 additions and 354 deletions

View File

@@ -17,14 +17,17 @@
import UIKit
@objcMembers
final class FlowTemplateCoordinator: FlowTemplateCoordinatorType {
final class FlowTemplateCoordinator: FlowTemplateCoordinatorProtocol {
// MARK: - Properties
// MARK: Private
private let parameters: FlowTemplateCoordinatorParameters
private let navigationRouter: NavigationRouterType
private let session: MXSession
private var navigationRouter: NavigationRouterType {
return self.parameters.navigationRouter
}
// MARK: Public
@@ -35,32 +38,40 @@ final class FlowTemplateCoordinator: FlowTemplateCoordinatorType {
// MARK: - Setup
init(session: MXSession) {
self.navigationRouter = NavigationRouter(navigationController: RiotNavigationController())
self.session = session
init(parameters: FlowTemplateCoordinatorParameters) {
self.parameters = parameters
}
// MARK: - Public methods
// MARK: - Public
func start() {
let rootCoordinator = self.createTemplateScreenCoordinator()
rootCoordinator.start()
self.add(childCoordinator: rootCoordinator)
self.navigationRouter.setRootModule(rootCoordinator)
if self.navigationRouter.modules.isEmpty == false {
self.navigationRouter.push(rootCoordinator, animated: true, popCompletion: { [weak self] in
self?.remove(childCoordinator: rootCoordinator)
})
} else {
self.navigationRouter.setRootModule(rootCoordinator) { [weak self] in
self?.remove(childCoordinator: rootCoordinator)
}
}
}
func toPresentable() -> UIViewController {
return self.navigationRouter.toPresentable()
}
// MARK: - Private methods
// MARK: - Private
private func createTemplateScreenCoordinator() -> TemplateScreenCoordinator {
let coordinator = TemplateScreenCoordinator(session: self.session)
let coordinatorParameters = TemplateScreenCoordinatorParameters(session: self.parameters.session)
let coordinator = TemplateScreenCoordinator(parameters: coordinatorParameters)
coordinator.delegate = self
return coordinator
}
@@ -68,11 +79,11 @@ final class FlowTemplateCoordinator: FlowTemplateCoordinatorType {
// MARK: - TemplateScreenCoordinatorDelegate
extension FlowTemplateCoordinator: TemplateScreenCoordinatorDelegate {
func templateScreenCoordinator(_ coordinator: TemplateScreenCoordinatorType, didCompleteWithUserDisplayName userDisplayName: String?) {
func templateScreenCoordinator(_ coordinator: TemplateScreenCoordinatorProtocol, didCompleteWithUserDisplayName userDisplayName: String?) {
self.delegate?.flowTemplateCoordinatorDidComplete(self)
}
func templateScreenCoordinatorDidCancel(_ coordinator: TemplateScreenCoordinatorType) {
func templateScreenCoordinatorDidCancel(_ coordinator: TemplateScreenCoordinatorProtocol) {
self.delegate?.flowTemplateCoordinatorDidComplete(self)
}
}

View File

@@ -22,15 +22,23 @@ import Foundation
/// FlowTemplateCoordinatorBridgePresenter enables to start FlowTemplateCoordinator from a view controller.
/// This bridge is used while waiting for global usage of coordinator pattern.
/// It breaks the Coordinator abstraction and it has been introduced for Objective-C compatibility (mainly for integration in legacy view controllers). Each bridge should be removed once the underlying Coordinator has been integrated by another Coordinator.
/// **WARNING**: This class breaks the Coordinator abstraction and it has been introduced for **Objective-C compatibility only** (mainly for integration in legacy view controllers). Each bridge should be removed once the underlying Coordinator has been integrated by another Coordinator.
@objcMembers
final class FlowTemplateCoordinatorBridgePresenter: NSObject {
// MARK: - Constants
private enum NavigationType {
case present
case push
}
// MARK: - Properties
// MARK: Private
private let session: MXSession
private var navigationType: NavigationType = .present
private var coordinator: FlowTemplateCoordinator?
// MARK: Public
@@ -52,7 +60,10 @@ final class FlowTemplateCoordinatorBridgePresenter: NSObject {
// }
func present(from viewController: UIViewController, animated: Bool) {
let flowTemplateCoordinator = FlowTemplateCoordinator(session: self.session)
let flowTemplateCoordinatorParameters = FlowTemplateCoordinatorParameters(session: self.session)
let flowTemplateCoordinator = FlowTemplateCoordinator(parameters: flowTemplateCoordinatorParameters)
flowTemplateCoordinator.delegate = self
let presentable = flowTemplateCoordinator.toPresentable()
presentable.presentationController?.delegate = self
@@ -60,13 +71,44 @@ final class FlowTemplateCoordinatorBridgePresenter: NSObject {
flowTemplateCoordinator.start()
self.coordinator = flowTemplateCoordinator
self.navigationType = .present
}
func push(from navigationController: UINavigationController, animated: Bool) {
let navigationRouter = NavigationRouter(navigationController: navigationController)
let flowTemplateCoordinatorParameters = FlowTemplateCoordinatorParameters(session: self.session, navigationRouter: navigationRouter)
let flowTemplateCoordinator = FlowTemplateCoordinator(parameters: flowTemplateCoordinatorParameters)
flowTemplateCoordinator.delegate = self
flowTemplateCoordinator.start() // Will trigger the view controller push
self.coordinator = flowTemplateCoordinator
self.navigationType = .push
}
func dismiss(animated: Bool, completion: (() -> Void)?) {
guard let coordinator = self.coordinator else {
return
}
coordinator.toPresentable().dismiss(animated: animated) {
switch navigationType {
case .present:
// Dismiss modal
coordinator.toPresentable().dismiss(animated: animated) {
self.coordinator = nil
if let completion = completion {
completion()
}
}
case .push:
// Pop view controller from UINavigationController
guard let navigationController = coordinator.toPresentable() as? UINavigationController else {
return
}
navigationController.popViewController(animated: animated)
self.coordinator = nil
if let completion = completion {
@@ -78,7 +120,7 @@ final class FlowTemplateCoordinatorBridgePresenter: NSObject {
// MARK: - FlowTemplateCoordinatorDelegate
extension FlowTemplateCoordinatorBridgePresenter: FlowTemplateCoordinatorDelegate {
func flowTemplateCoordinatorDidComplete(_ coordinator: FlowTemplateCoordinatorType) {
func flowTemplateCoordinatorDidComplete(_ coordinator: FlowTemplateCoordinatorProtocol) {
self.delegate?.flowTemplateCoordinatorBridgePresenterDelegateDidComplete(self)
}
}

View File

@@ -0,0 +1,33 @@
/*
Copyright 2021 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import Foundation
/// FlowTemplateCoordinator input parameters
struct FlowTemplateCoordinatorParameters {
/// The Matrix session
let session: MXSession
/// The navigation router that manage physical navigation
let navigationRouter: NavigationRouterType
init(session: MXSession,
navigationRouter: NavigationRouterType? = nil) {
self.session = session
self.navigationRouter = navigationRouter ?? NavigationRouter(navigationController: RiotNavigationController())
}
}

View File

@@ -17,10 +17,10 @@
import Foundation
protocol FlowTemplateCoordinatorDelegate: AnyObject {
func flowTemplateCoordinatorDidComplete(_ coordinator: FlowTemplateCoordinatorType)
func flowTemplateCoordinatorDidComplete(_ coordinator: FlowTemplateCoordinatorProtocol)
}
/// `FlowTemplateCoordinatorType` is a protocol describing a Coordinator that handle keybackup setup navigation flow.
protocol FlowTemplateCoordinatorType: Coordinator, Presentable {
/// `FlowTemplateCoordinatorProtocol` is a protocol describing a Coordinator that handle xxxxxxx navigation flow.
protocol FlowTemplateCoordinatorProtocol: Coordinator, Presentable {
var delegate: FlowTemplateCoordinatorDelegate? { get }
}

View File

@@ -17,14 +17,14 @@
import Foundation
import UIKit
final class TemplateScreenCoordinator: TemplateScreenCoordinatorType {
final class TemplateScreenCoordinator: TemplateScreenCoordinatorProtocol {
// MARK: - Properties
// MARK: Private
private let session: MXSession
private var templateScreenViewModel: TemplateScreenViewModelType
private let parameters: TemplateScreenCoordinatorParameters
private var templateScreenViewModel: TemplateScreenViewModelProtocol
private let templateScreenViewController: TemplateScreenViewController
// MARK: Public
@@ -36,16 +36,15 @@ final class TemplateScreenCoordinator: TemplateScreenCoordinatorType {
// MARK: - Setup
init(session: MXSession) {
self.session = session
let templateScreenViewModel = TemplateScreenViewModel(session: self.session)
init(parameters: TemplateScreenCoordinatorParameters) {
self.parameters = parameters
let templateScreenViewModel = TemplateScreenViewModel(session: self.parameters.session)
let templateScreenViewController = TemplateScreenViewController.instantiate(with: templateScreenViewModel)
self.templateScreenViewModel = templateScreenViewModel
self.templateScreenViewController = templateScreenViewController
}
// MARK: - Public methods
// MARK: - Public
func start() {
self.templateScreenViewModel.coordinatorDelegate = self
@@ -59,11 +58,11 @@ final class TemplateScreenCoordinator: TemplateScreenCoordinatorType {
// MARK: - TemplateScreenViewModelCoordinatorDelegate
extension TemplateScreenCoordinator: TemplateScreenViewModelCoordinatorDelegate {
func templateScreenViewModel(_ viewModel: TemplateScreenViewModelType, didCompleteWithUserDisplayName userDisplayName: String?) {
func templateScreenViewModel(_ viewModel: TemplateScreenViewModelProtocol, didCompleteWithUserDisplayName userDisplayName: String?) {
self.delegate?.templateScreenCoordinator(self, didCompleteWithUserDisplayName: userDisplayName)
}
func templateScreenViewModelDidCancel(_ viewModel: TemplateScreenViewModelType) {
func templateScreenViewModelDidCancel(_ viewModel: TemplateScreenViewModelProtocol) {
self.delegate?.templateScreenCoordinatorDidCancel(self)
}
}

View File

@@ -0,0 +1,24 @@
/*
Copyright 2021 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import Foundation
/// TemplateScreenCoordinator input parameters
struct TemplateScreenCoordinatorParameters {
/// The Matrix session
let session: MXSession
}

View File

@@ -17,11 +17,11 @@
import Foundation
protocol TemplateScreenCoordinatorDelegate: AnyObject {
func templateScreenCoordinator(_ coordinator: TemplateScreenCoordinatorType, didCompleteWithUserDisplayName userDisplayName: String?)
func templateScreenCoordinatorDidCancel(_ coordinator: TemplateScreenCoordinatorType)
func templateScreenCoordinator(_ coordinator: TemplateScreenCoordinatorProtocol, didCompleteWithUserDisplayName userDisplayName: String?)
func templateScreenCoordinatorDidCancel(_ coordinator: TemplateScreenCoordinatorProtocol)
}
/// `TemplateScreenCoordinatorType` is a protocol describing a Coordinator that handle key backup setup passphrase navigation flow.
protocol TemplateScreenCoordinatorType: Coordinator, Presentable {
/// `TemplateScreenCoordinatorProtocol` is a protocol describing a Coordinator that handle xxxxxxx navigation flow.
protocol TemplateScreenCoordinatorProtocol: Coordinator, Presentable {
var delegate: TemplateScreenCoordinatorDelegate? { get }
}

View File

@@ -35,7 +35,7 @@ final class TemplateScreenViewController: UIViewController {
// MARK: Private
private var viewModel: TemplateScreenViewModelType!
private var viewModel: TemplateScreenViewModelProtocol!
private var theme: Theme!
private var keyboardAvoider: KeyboardAvoider?
private var errorPresenter: MXKErrorPresentation!
@@ -43,7 +43,7 @@ final class TemplateScreenViewController: UIViewController {
// MARK: - Setup
class func instantiate(with viewModel: TemplateScreenViewModelType) -> TemplateScreenViewController {
class func instantiate(with viewModel: TemplateScreenViewModelProtocol) -> TemplateScreenViewController {
let viewController = StoryboardScene.TemplateScreenViewController.initialScene.instantiate()
viewController.viewModel = viewModel
viewController.theme = ThemeService.shared().theme
@@ -172,7 +172,7 @@ final class TemplateScreenViewController: UIViewController {
// MARK: - TemplateScreenViewModelViewDelegate
extension TemplateScreenViewController: TemplateScreenViewModelViewDelegate {
func templateScreenViewModel(_ viewModel: TemplateScreenViewModelType, didUpdateViewState viewSate: TemplateScreenViewState) {
func templateScreenViewModel(_ viewModel: TemplateScreenViewModelProtocol, didUpdateViewState viewSate: TemplateScreenViewState) {
self.render(viewState: viewSate)
}
}

View File

@@ -16,7 +16,7 @@
import Foundation
final class TemplateScreenViewModel: TemplateScreenViewModelType {
final class TemplateScreenViewModel: TemplateScreenViewModelProtocol {
// MARK: - Properties

View File

@@ -17,16 +17,16 @@
import Foundation
protocol TemplateScreenViewModelViewDelegate: AnyObject {
func templateScreenViewModel(_ viewModel: TemplateScreenViewModelType, didUpdateViewState viewSate: TemplateScreenViewState)
func templateScreenViewModel(_ viewModel: TemplateScreenViewModelProtocol, didUpdateViewState viewSate: TemplateScreenViewState)
}
protocol TemplateScreenViewModelCoordinatorDelegate: AnyObject {
func templateScreenViewModel(_ viewModel: TemplateScreenViewModelType, didCompleteWithUserDisplayName userDisplayName: String?)
func templateScreenViewModelDidCancel(_ viewModel: TemplateScreenViewModelType)
func templateScreenViewModel(_ viewModel: TemplateScreenViewModelProtocol, didCompleteWithUserDisplayName userDisplayName: String?)
func templateScreenViewModelDidCancel(_ viewModel: TemplateScreenViewModelProtocol)
}
/// Protocol describing the view model used by `TemplateScreenViewController`
protocol TemplateScreenViewModelType {
protocol TemplateScreenViewModelProtocol {
var viewDelegate: TemplateScreenViewModelViewDelegate? { get set }
var coordinatorDelegate: TemplateScreenViewModelCoordinatorDelegate? { get set }