Skip to content

Commit

Permalink
Rename completion to callback and simplify actor usage.
Browse files Browse the repository at this point in the history
  • Loading branch information
pixlwave committed May 10, 2022
1 parent 4a9ace0 commit 18c3744
Show file tree
Hide file tree
Showing 11 changed files with 110 additions and 95 deletions.
6 changes: 2 additions & 4 deletions Riot/Modules/Onboarding/AuthenticationCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ final class AuthenticationCoordinator: NSObject, AuthenticationCoordinatorProtoc
let parameters = AuthenticationServerSelectionCoordinatorParameters(authenticationService: authenticationService,
hasModalPresentation: false)
let coordinator = AuthenticationServerSelectionCoordinator(parameters: parameters)
coordinator.completion = { [weak self, weak coordinator] result in
coordinator.callback = { [weak self, weak coordinator] result in
guard let self = self, let coordinator = coordinator else { return }
self.serverSelectionCoordinator(coordinator, didCompleteWith: result)
}
Expand Down Expand Up @@ -171,7 +171,7 @@ final class AuthenticationCoordinator: NSObject, AuthenticationCoordinatorProtoc
registrationFlow: homeserver.registrationFlow,
loginMode: homeserver.preferredLoginMode)
let coordinator = AuthenticationRegistrationCoordinator(parameters: parameters)
coordinator.completion = { [weak self, weak coordinator] result in
coordinator.callback = { [weak self, weak coordinator] result in
guard let self = self, let coordinator = coordinator else { return }
self.registrationCoordinator(coordinator, didCompleteWith: result)
}
Expand All @@ -193,8 +193,6 @@ final class AuthenticationCoordinator: NSObject, AuthenticationCoordinatorProtoc
@MainActor private func registrationCoordinator(_ coordinator: AuthenticationRegistrationCoordinator,
didCompleteWith result: AuthenticationRegistrationCoordinatorResult) {
switch result {
case .selectServer:
showServerSelectionScreen()
case .completed(let result):
handleRegistrationResult(result)
}
Expand Down
2 changes: 1 addition & 1 deletion Riot/Modules/Onboarding/OnboardingCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ final class OnboardingCoordinator: NSObject, OnboardingCoordinatorProtocol {
let parameters = OnboardingAvatarCoordinatorParameters(userSession: userSession, avatar: selectedAvatar)
let coordinator = OnboardingAvatarCoordinator(parameters: parameters)

coordinator.completion = { [weak self, weak coordinator] result in
coordinator.callback = { [weak self, weak coordinator] result in
guard let self = self, let coordinator = coordinator else { return }

switch result {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class AuthenticationRegistrationViewModel: AuthenticationRegistrationViewModelTy

// MARK: Public

@MainActor var completion: ((AuthenticationRegistrationViewModelResult) -> Void)?
@MainActor var callback: ((AuthenticationRegistrationViewModelResult) -> Void)?

// MARK: - Setup

Expand All @@ -47,25 +47,19 @@ class AuthenticationRegistrationViewModel: AuthenticationRegistrationViewModelTy
// MARK: - Public

override func process(viewAction: AuthenticationRegistrationViewAction) {
Task {
await MainActor.run {
switch viewAction {
case .selectServer:
completion?(.selectServer)
case .validateUsername:
state.hasEditedUsername = true
completion?(.validateUsername(state.bindings.username))
case .enablePasswordValidation:
state.hasEditedPassword = true
case .clearUsernameError:
guard state.usernameErrorMessage != nil else { return }
state.usernameErrorMessage = nil
case .next:
completion?(.createAccount(username: state.bindings.username, password: state.bindings.password))
case .continueWithSSO(let id):
break
}
}
switch viewAction {
case .selectServer:
Task { await callback?(.selectServer) }
case .validateUsername:
Task { await clearUsernameError() }
case .enablePasswordValidation:
Task { await enablePasswordValidation() }
case .clearUsernameError:
Task { await clearUsernameError() }
case .next:
Task { await callback?(.createAccount(username: state.bindings.username, password: state.bindings.password)) }
case .continueWithSSO(let id):
break
}
}

Expand Down Expand Up @@ -95,4 +89,27 @@ class AuthenticationRegistrationViewModel: AuthenticationRegistrationViewModelTy
state.bindings.alertInfo = AlertInfo(id: type)
}
}

// MARK: - Private

/// Checks the entered username is valid for use on the current homeserver.
@MainActor private func validateUsername() {
if !state.hasEditedUsername {
state.hasEditedUsername = true
}

callback?(.validateUsername(state.bindings.username))
}

/// Allow password validation to begin taking place.
@MainActor private func enablePasswordValidation() {
guard !state.hasEditedPassword else { return }
state.hasEditedPassword = true
}

/// Clear the error message currently shown in the username footer.
@MainActor private func clearUsernameError() {
guard state.usernameErrorMessage != nil else { return }
state.usernameErrorMessage = nil
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import Foundation

protocol AuthenticationRegistrationViewModelProtocol {

@MainActor var completion: ((AuthenticationRegistrationViewModelResult) -> Void)? { get set }
@MainActor var callback: ((AuthenticationRegistrationViewModelResult) -> Void)? { get set }
@available(iOS 14, *)
var context: AuthenticationRegistrationViewModelType.Context { get }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ struct AuthenticationRegistrationCoordinatorParameters {
}

enum AuthenticationRegistrationCoordinatorResult {
/// The user would like to select another server.
case selectServer
/// The screen completed with the associated registration result.
case completed(RegistrationResult)
}
Expand Down Expand Up @@ -65,7 +63,7 @@ final class AuthenticationRegistrationCoordinator: Coordinator, Presentable {

// Must be used only internally
var childCoordinators: [Coordinator] = []
@MainActor var completion: ((AuthenticationRegistrationCoordinatorResult) -> Void)?
@MainActor var callback: ((AuthenticationRegistrationCoordinatorResult) -> Void)?

// MARK: - Setup

Expand All @@ -89,23 +87,8 @@ final class AuthenticationRegistrationCoordinator: Coordinator, Presentable {

// MARK: - Public
func start() {
Task {
await MainActor.run {
MXLog.debug("[AuthenticationRegistrationCoordinator] did start.")
authenticationRegistrationViewModel.completion = { [weak self] result in
guard let self = self else { return }
MXLog.debug("[AuthenticationRegistrationCoordinator] AuthenticationRegistrationViewModel did complete with result: \(result).")
switch result {
case .selectServer:
self.presentServerSelectionScreen()
case.validateUsername(let username):
self.validateUsername(username)
case .createAccount(let username, let password):
self.createAccount(username: username, password: password)
}
}
}
}
MXLog.debug("[AuthenticationRegistrationCoordinator] did start.")
Task { await setupViewModel() }
}

func toPresentable() -> UIViewController {
Expand All @@ -114,6 +97,22 @@ final class AuthenticationRegistrationCoordinator: Coordinator, Presentable {

// MARK: - Private

/// Set up the view model. This method is extracted from `start()` so it can run on the `MainActor`.
@MainActor private func setupViewModel() {
authenticationRegistrationViewModel.callback = { [weak self] result in
guard let self = self else { return }
MXLog.debug("[AuthenticationRegistrationCoordinator] AuthenticationRegistrationViewModel did complete with result: \(result).")
switch result {
case .selectServer:
self.presentServerSelectionScreen()
case.validateUsername(let username):
self.validateUsername(username)
case .createAccount(let username, let password):
self.createAccount(username: username, password: password)
}
}
}

/// Show a blocking activity indicator whilst saving.
@MainActor private func startLoading(label: String? = nil) {
waitingIndicator = indicatorPresenter.present(.loading(label: label ?? VectorL10n.loading, isInteractionBlocking: true))
Expand Down Expand Up @@ -162,7 +161,7 @@ final class AuthenticationRegistrationCoordinator: Coordinator, Presentable {
let result = try await registrationWizard.createAccount(username: username, password: password, initialDeviceDisplayName: deviceDisplayName)

guard !Task.isCancelled else { return }
completion?(.completed(result))
callback?(.completed(result))

self?.stopLoading()
} catch {
Expand Down Expand Up @@ -213,7 +212,7 @@ final class AuthenticationRegistrationCoordinator: Coordinator, Presentable {
let parameters = AuthenticationServerSelectionCoordinatorParameters(authenticationService: authenticationService,
hasModalPresentation: true)
let coordinator = AuthenticationServerSelectionCoordinator(parameters: parameters)
coordinator.completion = { [weak self, weak coordinator] result in
coordinator.callback = { [weak self, weak coordinator] result in
guard let self = self, let coordinator = coordinator else { return }
self.serverSelectionCoordinator(coordinator, didCompleteWith: result)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class AuthenticationServerSelectionViewModel: AuthenticationServerSelectionViewM

// MARK: Public

var completion: ((AuthenticationServerSelectionViewModelResult) -> Void)?
@MainActor var callback: ((AuthenticationServerSelectionViewModelResult) -> Void)?

// MARK: - Setup

Expand All @@ -42,20 +42,15 @@ class AuthenticationServerSelectionViewModel: AuthenticationServerSelectionViewM
// MARK: - Public

override func process(viewAction: AuthenticationServerSelectionViewAction) {
Task {
await MainActor.run {
switch viewAction {
case .confirm:
completion?(.confirm(homeserverAddress: state.bindings.homeserverAddress))
case .dismiss:
completion?(.dismiss)
case .getInTouch:
getInTouch()
case .clearFooterError:
guard state.footerErrorMessage != nil else { return }
withAnimation { state.footerErrorMessage = nil }
}
}
switch viewAction {
case .confirm:
Task { await callback?(.confirm(homeserverAddress: state.bindings.homeserverAddress)) }
case .dismiss:
Task { await callback?(.dismiss) }
case .getInTouch:
Task { await getInTouch() }
case .clearFooterError:
Task { await clearFooterError() }
}
}

Expand All @@ -72,6 +67,11 @@ class AuthenticationServerSelectionViewModel: AuthenticationServerSelectionViewM

// MARK: - Private

@MainActor private func clearFooterError() {
guard state.footerErrorMessage != nil else { return }
withAnimation { state.footerErrorMessage = nil }
}

/// Opens the EMS link in the user's browser.
@MainActor private func getInTouch() {
let url = BuildSettings.onboardingHostYourOwnServerLink
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import Foundation

protocol AuthenticationServerSelectionViewModelProtocol {

@MainActor var completion: ((AuthenticationServerSelectionViewModelResult) -> Void)? { get set }
@MainActor var callback: ((AuthenticationServerSelectionViewModelResult) -> Void)? { get set }
@available(iOS 14, *)
var context: AuthenticationServerSelectionViewModelType.Context { get }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ final class AuthenticationServerSelectionCoordinator: Coordinator, Presentable {

// Must be used only internally
var childCoordinators: [Coordinator] = []
@MainActor var completion: ((AuthenticationServerSelectionCoordinatorResult) -> Void)?
@MainActor var callback: ((AuthenticationServerSelectionCoordinatorResult) -> Void)?

// MARK: - Setup

Expand All @@ -72,22 +72,8 @@ final class AuthenticationServerSelectionCoordinator: Coordinator, Presentable {
// MARK: - Public

func start() {
Task {
await MainActor.run {
MXLog.debug("[AuthenticationServerSelectionCoordinator] did start.")
authenticationServerSelectionViewModel.completion = { [weak self] result in
guard let self = self else { return }
MXLog.debug("[AuthenticationServerSelectionCoordinator] AuthenticationServerSelectionViewModel did complete with result: \(result).")

switch result {
case .confirm(let homeserverAddress):
self.useHomeserver(homeserverAddress)
case .dismiss:
self.completion?(.dismiss)
}
}
}
}
MXLog.debug("[AuthenticationServerSelectionCoordinator] did start.")
Task { await setupViewModel() }
}

func toPresentable() -> UIViewController {
Expand All @@ -96,6 +82,21 @@ final class AuthenticationServerSelectionCoordinator: Coordinator, Presentable {

// MARK: - Private

/// Set up the view model. This method is extracted from `start()` so it can run on the `MainActor`.
@MainActor private func setupViewModel() {
authenticationServerSelectionViewModel.callback = { [weak self] result in
guard let self = self else { return }
MXLog.debug("[AuthenticationServerSelectionCoordinator] AuthenticationServerSelectionViewModel did complete with result: \(result).")

switch result {
case .confirm(let homeserverAddress):
self.useHomeserver(homeserverAddress)
case .dismiss:
self.callback?(.dismiss)
}
}
}

/// Show an activity indicator whilst loading.
/// - Parameters:
/// - label: The label to show on the indicator.
Expand All @@ -122,7 +123,7 @@ final class AuthenticationServerSelectionCoordinator: Coordinator, Presentable {
try await authenticationService.startFlow(.register, for: homeserverAddress)
stopLoading()

completion?(.updated)
callback?(.updated)
} catch {
stopLoading()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ struct OnboardingAvatarCoordinatorParameters {
}

enum OnboardingAvatarCoordinatorResult {
/// The user has chosen an image (but hasn't yet saved it).
/// The user has chosen an image (but it isn't saved until `.complete` is sent).
case selectedAvatar(UIImage?)
/// The screen is finished and the next one can be shown.
case complete(UserSession)
Expand Down Expand Up @@ -64,7 +64,7 @@ final class OnboardingAvatarCoordinator: Coordinator, Presentable {

// Must be used only internally
var childCoordinators: [Coordinator] = []
var completion: ((OnboardingAvatarCoordinatorResult) -> Void)?
var callback: ((OnboardingAvatarCoordinatorResult) -> Void)?

// MARK: - Setup

Expand All @@ -89,7 +89,7 @@ final class OnboardingAvatarCoordinator: Coordinator, Presentable {

func start() {
MXLog.debug("[OnboardingAvatarCoordinator] did start.")
onboardingAvatarViewModel.completion = { [weak self] result in
onboardingAvatarViewModel.callback = { [weak self] result in
guard let self = self else { return }
MXLog.debug("[OnboardingAvatarCoordinator] OnboardingAvatarViewModel did complete with result: \(result).")
switch result {
Expand All @@ -100,7 +100,7 @@ final class OnboardingAvatarCoordinator: Coordinator, Presentable {
case .save(let avatar):
self.setAvatar(avatar)
case .skip:
self.completion?(.complete(self.parameters.userSession))
self.callback?(.complete(self.parameters.userSession))
}
}
}
Expand Down Expand Up @@ -162,7 +162,7 @@ final class OnboardingAvatarCoordinator: Coordinator, Presentable {
self.parameters.userSession.account.setUserAvatarUrl(urlString) { [weak self] in
guard let self = self else { return }
self.stopWaiting()
self.completion?(.complete(self.parameters.userSession))
self.callback?(.complete(self.parameters.userSession))
} failure: { [weak self] error in
guard let self = self else { return }
self.stopWaiting()
Expand All @@ -184,7 +184,7 @@ extension OnboardingAvatarCoordinator: MediaPickerPresenterDelegate {
/// so whilst this method may not appear to be called, everything works fine when run on a device.
func mediaPickerPresenter(_ presenter: MediaPickerPresenter, didPickImage image: UIImage) {
onboardingAvatarViewModel.updateAvatarImage(with: image)
completion?(.selectedAvatar(image))
callback?(.selectedAvatar(image))
presenter.dismiss(animated: true, completion: nil)
}

Expand All @@ -199,7 +199,7 @@ extension OnboardingAvatarCoordinator: MediaPickerPresenterDelegate {
extension OnboardingAvatarCoordinator: CameraPresenterDelegate {
func cameraPresenter(_ presenter: CameraPresenter, didSelectImage image: UIImage) {
onboardingAvatarViewModel.updateAvatarImage(with: image)
completion?(.selectedAvatar(image))
callback?(.selectedAvatar(image))
presenter.dismiss(animated: true, completion: nil)
}

Expand Down
Loading

0 comments on commit 18c3744

Please sign in to comment.