metatext-app-ios-iphone-ipad/ViewModels/Sources/ViewModels/AddIdentityViewModel.swift

103 lines
3.3 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-08-31 20:57:02 +02:00
import ServiceLayer
2020-09-10 02:52:46 +02:00
public enum AddIdentityError: Error {
case unableToConnectToInstance
}
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
public let addedIdentityID: AnyPublisher<UUID, Never>
2020-08-26 23:35:06 +02:00
private let allIdentitiesService: AllIdentitiesService
2020-09-09 08:17:35 +02:00
private let instanceFilterService: InstanceFilterService
2020-09-09 03:02:55 +02:00
private let addedIdentityIDSubject = PassthroughSubject<UUID, Never>()
2020-08-03 17:20:51 +02:00
private var cancellables = Set<AnyCancellable>()
2020-09-09 08:17:35 +02:00
init(allIdentitiesService: AllIdentitiesService, instanceFilterService: InstanceFilterService) {
2020-08-26 23:35:06 +02:00
self.allIdentitiesService = allIdentitiesService
2020-09-09 08:17:35 +02:00
self.instanceFilterService = instanceFilterService
2020-09-09 03:02:55 +02:00
addedIdentityID = addedIdentityIDSubject.eraseToAnyPublisher()
}
2020-09-01 09:33:49 +02:00
}
2020-09-01 09:33:49 +02:00
public extension AddIdentityViewModel {
func logInTapped() {
2020-09-10 02:52:46 +02:00
addIdentity(authenticated: true)
}
func browseAnonymouslyTapped() {
2020-09-10 02:52:46 +02:00
addIdentity(authenticated: false)
}
2020-09-07 06:56:18 +02:00
func refreshFilter() {
2020-09-09 08:17:35 +02:00
instanceFilterService.updateFilter()
2020-09-07 06:56:18 +02:00
.sink { _ in }
.store(in: &cancellables)
}
}
private extension AddIdentityViewModel {
private static let filteredURL = URL(string: "https://filtered")!
private static let HTTPSPrefix = "https://"
2020-09-10 02:52:46 +02:00
func addIdentity(authenticated: Bool) {
let identityID = UUID()
2020-09-07 06:56:18 +02:00
let url: URL
if urlFieldText.hasPrefix(Self.HTTPSPrefix), let prefixedURL = URL(string: urlFieldText) {
url = prefixedURL
} else if let unprefixedURL = URL(string: Self.HTTPSPrefix + urlFieldText) {
url = unprefixedURL
} else {
2020-09-10 02:52:46 +02:00
alertItem = AlertItem(error: AddIdentityError.unableToConnectToInstance)
return
2020-09-07 06:56:18 +02:00
}
2020-09-09 08:17:35 +02:00
if instanceFilterService.isFiltered(url: url) {
2020-09-10 02:52:46 +02:00
loading = true
DispatchQueue.main.asyncAfter(deadline: .now() + .random(in: 0.01...0.1)) {
self.alertItem = AlertItem(error: AddIdentityError.unableToConnectToInstance)
self.loading = false
}
return
2020-09-07 06:56:18 +02:00
}
2020-09-10 02:52:46 +02:00
allIdentitiesService.createIdentity(
id: identityID,
url: url,
authenticated: authenticated)
.receive(on: DispatchQueue.main)
.catch { [weak self] error -> Empty<Never, Never> in
if case AuthenticationError.canceled = error {
// no-op
} else {
let displayedError = error is URLError ? AddIdentityError.unableToConnectToInstance : error
self?.alertItem = AlertItem(error: displayedError)
}
return Empty()
}
.handleEvents(receiveSubscription: { [weak self] _ in self?.loading = true })
.sink { [weak self] in
guard let self = self else { return }
self.loading = false
if case .finished = $0 {
self.addedIdentityIDSubject.send(identityID)
}
} receiveValue: { _ in }
.store(in: &cancellables)
2020-09-07 06:56:18 +02:00
}
}