metatext/ViewModels/Sources/ViewModels/View Models/AddIdentityViewModel.swift

116 lines
4.1 KiB
Swift
Raw Normal View History

// Copyright © 2020 Metabolist. All rights reserved.
import Combine
2020-09-05 02:31:43 +00:00
import Foundation
2020-09-10 09:38:21 +00:00
import Mastodon
2020-08-31 18:57:02 +00:00
import ServiceLayer
2020-09-10 00:52:46 +00:00
public enum AddIdentityError: Error {
case unableToConnectToInstance
2021-01-17 20:24:50 +00:00
case instanceNotSupported
2020-09-10 00:52:46 +00:00
}
2020-09-08 02:35:28 +00:00
public final class AddIdentityViewModel: ObservableObject {
2020-09-01 07:33:49 +00:00
@Published public var urlFieldText = ""
@Published public var alertItem: AlertItem?
@Published public private(set) var loading = false
2020-09-12 19:09:54 +00:00
@Published public private(set) var url: URL?
@Published public private(set) var instance: Instance?
2020-09-10 09:38:21 +00:00
@Published public private(set) var isPublicTimelineAvailable = false
2020-08-26 21:35:06 +00:00
private let allIdentitiesService: AllIdentitiesService
2020-09-10 04:51:31 +00:00
private let instanceURLService: InstanceURLService
2020-08-03 15:20:51 +00:00
private var cancellables = Set<AnyCancellable>()
2020-09-10 04:51:31 +00:00
init(allIdentitiesService: AllIdentitiesService, instanceURLService: InstanceURLService) {
2020-08-26 21:35:06 +00:00
self.allIdentitiesService = allIdentitiesService
2020-09-10 04:51:31 +00:00
self.instanceURLService = instanceURLService
2020-09-07 04:56:18 +00:00
2020-09-12 19:09:54 +00:00
let url = $urlFieldText
2021-01-27 20:31:32 +00:00
.throttle(for: .seconds(Self.textFieldThrottleInterval), scheduler: DispatchQueue.global(), latest: true)
2020-09-12 19:09:54 +00:00
.removeDuplicates()
2020-09-14 01:36:03 +00:00
.flatMap {
2021-03-19 00:51:19 +00:00
instanceURLService.url(text: $0.trimmingCharacters(in: .whitespacesAndNewlines)).publisher
2020-09-13 01:12:33 +00:00
.map { $0 as URL? }
.replaceError(with: nil)
}
2020-09-12 19:09:54 +00:00
.share()
url.receive(on: DispatchQueue.main).assign(to: &$url)
2020-09-14 01:36:03 +00:00
url.flatMap { url -> AnyPublisher<Instance?, Never> in
guard let url = url else {
2020-09-12 19:09:54 +00:00
return Just(nil).eraseToAnyPublisher()
}
2020-09-14 01:36:03 +00:00
return instanceURLService.instance(url: url)
2020-09-12 19:09:54 +00:00
.map { $0 as Instance? }
.replaceError(with: nil)
.eraseToAnyPublisher()
}
.receive(on: DispatchQueue.main)
.assign(to: &$instance)
2020-09-12 19:58:23 +00:00
2020-09-14 01:36:03 +00:00
url.flatMap { url -> AnyPublisher<Bool, Never> in
guard let url = url else {
2020-09-12 19:58:23 +00:00
return Just(false).eraseToAnyPublisher()
}
2020-09-14 01:36:03 +00:00
return instanceURLService.isPublicTimelineAvailable(url: url)
2020-09-12 19:58:23 +00:00
.replaceError(with: false)
.eraseToAnyPublisher()
}
.receive(on: DispatchQueue.main)
.assign(to: &$isPublicTimelineAvailable)
2020-09-12 19:09:54 +00:00
}
2020-09-14 01:36:03 +00:00
}
public extension AddIdentityViewModel {
func logInTapped() {
addIdentity(kind: .authentication)
}
func browseTapped() {
addIdentity(kind: .browsing)
}
2020-09-12 19:09:54 +00:00
2020-09-14 01:36:03 +00:00
func registrationViewModel(instance: Instance, url: URL) -> RegistrationViewModel {
RegistrationViewModel(instance: instance, url: url, allIdentitiesService: allIdentitiesService)
}
}
private extension AddIdentityViewModel {
2021-01-27 20:31:32 +00:00
private static let textFieldThrottleInterval: TimeInterval = 0.5
2020-09-13 08:03:08 +00:00
func addIdentity(kind: AllIdentitiesService.IdentityCreation) {
2021-03-19 00:51:19 +00:00
instanceURLService.url(text: urlFieldText.trimmingCharacters(in: .whitespacesAndNewlines)).publisher
2020-09-13 08:03:08 +00:00
.map { ($0, kind) }
.flatMap(allIdentitiesService.createIdentity(url:kind:))
2020-09-10 00:52:46 +00:00
.receive(on: DispatchQueue.main)
.handleEvents(receiveSubscription: { [weak self] _ in self?.loading = true })
.sink { [weak self] in
guard let self = self else { return }
self.loading = false
2020-09-13 00:50:22 +00:00
if case let .failure(error) = $0 {
2020-09-10 09:38:21 +00:00
if case AuthenticationError.canceled = error {
return
}
2021-01-17 20:24:50 +00:00
let displayedError: Error
if case InstanceURLError.instanceNotSupported = error {
displayedError = AddIdentityError.instanceNotSupported
} else if error is URLError {
displayedError = AddIdentityError.unableToConnectToInstance
} else {
displayedError = error
}
2020-09-10 09:38:21 +00:00
self.alertItem = AlertItem(error: displayedError)
2020-09-10 00:52:46 +00:00
}
} receiveValue: { _ in }
.store(in: &cancellables)
2020-09-07 04:56:18 +00:00
}
}