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