Refactoring
This commit is contained in:
parent
a6185c9cf4
commit
62ddaac083
|
@ -13,6 +13,7 @@ public struct AppEnvironment {
|
|||
let keychain: Keychain.Type
|
||||
let userDefaults: UserDefaults
|
||||
let userNotificationClient: UserNotificationClient
|
||||
let uuid: () -> UUID
|
||||
let inMemoryContent: Bool
|
||||
let fixtureDatabase: IdentityDatabase?
|
||||
|
||||
|
@ -21,6 +22,7 @@ public struct AppEnvironment {
|
|||
keychain: Keychain.Type,
|
||||
userDefaults: UserDefaults,
|
||||
userNotificationClient: UserNotificationClient,
|
||||
uuid: @escaping () -> UUID,
|
||||
inMemoryContent: Bool,
|
||||
fixtureDatabase: IdentityDatabase?) {
|
||||
self.session = session
|
||||
|
@ -28,6 +30,7 @@ public struct AppEnvironment {
|
|||
self.keychain = keychain
|
||||
self.userDefaults = userDefaults
|
||||
self.userNotificationClient = userNotificationClient
|
||||
self.uuid = uuid
|
||||
self.inMemoryContent = inMemoryContent
|
||||
self.fixtureDatabase = fixtureDatabase
|
||||
}
|
||||
|
@ -41,6 +44,7 @@ public extension AppEnvironment {
|
|||
keychain: LiveKeychain.self,
|
||||
userDefaults: .standard,
|
||||
userNotificationClient: .live(userNotificationCenter),
|
||||
uuid: UUID.init,
|
||||
inMemoryContent: false,
|
||||
fixtureDatabase: nil)
|
||||
}
|
||||
|
|
|
@ -8,14 +8,18 @@ import MastodonAPI
|
|||
import Secrets
|
||||
|
||||
public struct AllIdentitiesService {
|
||||
public let identitiesCreated: AnyPublisher<UUID, Never>
|
||||
|
||||
private let environment: AppEnvironment
|
||||
private let database: IdentityDatabase
|
||||
private let identitiesCreatedSubject = PassthroughSubject<UUID, Never>()
|
||||
|
||||
public init(environment: AppEnvironment) throws {
|
||||
self.environment = environment
|
||||
self.database = try environment.fixtureDatabase ?? IdentityDatabase(
|
||||
inMemory: environment.inMemoryContent,
|
||||
keychain: environment.keychain)
|
||||
identitiesCreated = identitiesCreatedSubject.eraseToAnyPublisher()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,18 +32,16 @@ public extension AllIdentitiesService {
|
|||
database.immediateMostRecentlyUsedIdentityIDObservation()
|
||||
}
|
||||
|
||||
func createIdentity(id: UUID, url: URL, authenticated: Bool) -> AnyPublisher<Never, Error> {
|
||||
func createIdentity(url: URL, authenticated: Bool) -> AnyPublisher<Never, Error> {
|
||||
createIdentity(
|
||||
id: id,
|
||||
url: url,
|
||||
authenticationPublisher: authenticated
|
||||
? AuthenticationService(url: url, environment: environment).authenticate()
|
||||
: nil)
|
||||
}
|
||||
|
||||
func createIdentity(id: UUID, url: URL, registration: Registration) -> AnyPublisher<Never, Error> {
|
||||
func createIdentity(url: URL, registration: Registration) -> AnyPublisher<Never, Error> {
|
||||
createIdentity(
|
||||
id: id,
|
||||
url: url,
|
||||
authenticationPublisher: AuthenticationService(url: url, environment: environment)
|
||||
.register(registration))
|
||||
|
@ -91,9 +93,9 @@ public extension AllIdentitiesService {
|
|||
|
||||
private extension AllIdentitiesService {
|
||||
func createIdentity(
|
||||
id: UUID,
|
||||
url: URL,
|
||||
authenticationPublisher: AnyPublisher<(AppAuthorization, AccessToken), Error>?) -> AnyPublisher<Never, Error> {
|
||||
let id = environment.uuid()
|
||||
let secrets = Secrets(identityID: id, keychain: environment.keychain)
|
||||
|
||||
do {
|
||||
|
@ -107,6 +109,11 @@ private extension AllIdentitiesService {
|
|||
url: url,
|
||||
authenticated: authenticationPublisher != nil)
|
||||
.ignoreOutput()
|
||||
.handleEvents(receiveCompletion: {
|
||||
if case .finished = $0 {
|
||||
identitiesCreatedSubject.send(id)
|
||||
}
|
||||
})
|
||||
.eraseToAnyPublisher()
|
||||
|
||||
if let authenticationPublisher = authenticationPublisher {
|
||||
|
|
|
@ -14,6 +14,7 @@ public extension AppEnvironment {
|
|||
keychain: Keychain.Type = MockKeychain.self,
|
||||
userDefaults: UserDefaults = MockUserDefaults(),
|
||||
userNotificationClient: UserNotificationClient = .mock,
|
||||
uuid: @escaping () -> UUID = UUID.init,
|
||||
inMemoryContent: Bool = true,
|
||||
fixtureDatabase: IdentityDatabase? = nil) -> Self {
|
||||
AppEnvironment(
|
||||
|
@ -22,6 +23,7 @@ public extension AppEnvironment {
|
|||
keychain: keychain,
|
||||
userDefaults: userDefaults,
|
||||
userNotificationClient: userNotificationClient,
|
||||
uuid: uuid,
|
||||
inMemoryContent: inMemoryContent,
|
||||
fixtureDatabase: fixtureDatabase)
|
||||
}
|
||||
|
|
|
@ -16,17 +16,14 @@ public final class AddIdentityViewModel: ObservableObject {
|
|||
@Published public private(set) var url: URL?
|
||||
@Published public private(set) var instance: Instance?
|
||||
@Published public private(set) var isPublicTimelineAvailable = false
|
||||
public let addedIdentityID: AnyPublisher<UUID, Never>
|
||||
|
||||
private let allIdentitiesService: AllIdentitiesService
|
||||
private let instanceURLService: InstanceURLService
|
||||
private let addedIdentityIDSubject = PassthroughSubject<UUID, Never>()
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
|
||||
init(allIdentitiesService: AllIdentitiesService, instanceURLService: InstanceURLService) {
|
||||
self.allIdentitiesService = allIdentitiesService
|
||||
self.instanceURLService = instanceURLService
|
||||
addedIdentityID = addedIdentityIDSubject.eraseToAnyPublisher()
|
||||
setupURLObservation()
|
||||
}
|
||||
}
|
||||
|
@ -88,18 +85,13 @@ private extension AddIdentityViewModel {
|
|||
}
|
||||
|
||||
func addIdentity(authenticated: Bool) {
|
||||
let identityID = UUID()
|
||||
|
||||
guard let url = instanceURLService.url(text: urlFieldText) else {
|
||||
alertItem = AlertItem(error: AddIdentityError.unableToConnectToInstance)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
allIdentitiesService.createIdentity(
|
||||
id: identityID,
|
||||
url: url,
|
||||
authenticated: authenticated)
|
||||
allIdentitiesService.createIdentity(url: url, authenticated: authenticated)
|
||||
.receive(on: DispatchQueue.main)
|
||||
.handleEvents(receiveSubscription: { [weak self] _ in self?.loading = true })
|
||||
.sink { [weak self] in
|
||||
|
@ -107,10 +99,7 @@ private extension AddIdentityViewModel {
|
|||
|
||||
self.loading = false
|
||||
|
||||
switch $0 {
|
||||
case .finished:
|
||||
self.addedIdentityIDSubject.send(identityID)
|
||||
case let .failure(error):
|
||||
if case let .failure(error) = $0 {
|
||||
if case AuthenticationError.canceled = error {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ public extension RegistrationViewModel {
|
|||
return
|
||||
}
|
||||
|
||||
allIdentitiesService.createIdentity(id: UUID(), url: url, registration: registration)
|
||||
allIdentitiesService.createIdentity(url: url, registration: registration)
|
||||
.handleEvents(receiveSubscription: { [weak self] _ in self?.registering = true })
|
||||
.mapError { error -> Error in
|
||||
if error is URLError {
|
||||
|
|
|
@ -27,6 +27,10 @@ public final class RootViewModel: ObservableObject {
|
|||
|
||||
identitySelected(id: mostRecentlyUsedIdentityID, immediate: true)
|
||||
|
||||
allIdentitiesService.identitiesCreated
|
||||
.sink { [weak self] in self?.identitySelected(id: $0) }
|
||||
.store(in: &cancellables)
|
||||
|
||||
userNotificationService.isAuthorized()
|
||||
.filter { $0 }
|
||||
.zip(registerForRemoteNotifications())
|
||||
|
|
|
@ -12,11 +12,13 @@ import XCTest
|
|||
|
||||
class AddIdentityViewModelTests: XCTestCase {
|
||||
func testAddIdentity() throws {
|
||||
let environment = AppEnvironment.mock()
|
||||
let uuid = UUID(uuidString: "E621E1F8-C36C-495A-93FC-0C247A3E6E5F")!
|
||||
let environment = AppEnvironment.mock(uuid: { uuid })
|
||||
let allIdentitiesService = try AllIdentitiesService(environment: environment)
|
||||
let sut = AddIdentityViewModel(
|
||||
allIdentitiesService: try AllIdentitiesService(environment: environment),
|
||||
allIdentitiesService: allIdentitiesService,
|
||||
instanceURLService: InstanceURLService(environment: environment))
|
||||
let addedIDRecorder = sut.addedIdentityID.record()
|
||||
let addedIDRecorder = allIdentitiesService.identitiesCreated.record()
|
||||
|
||||
sut.urlFieldText = "https://mastodon.social"
|
||||
sut.logInTapped()
|
||||
|
@ -25,11 +27,13 @@ class AddIdentityViewModelTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testAddIdentityWithoutScheme() throws {
|
||||
let environment = AppEnvironment.mock()
|
||||
let uuid = UUID(uuidString: "E621E1F8-C36C-495A-93FC-0C247A3E6E5F")!
|
||||
let environment = AppEnvironment.mock(uuid: { uuid })
|
||||
let allIdentitiesService = try AllIdentitiesService(environment: environment)
|
||||
let sut = AddIdentityViewModel(
|
||||
allIdentitiesService: try AllIdentitiesService(environment: environment),
|
||||
allIdentitiesService: allIdentitiesService,
|
||||
instanceURLService: InstanceURLService(environment: environment))
|
||||
let addedIDRecorder = sut.addedIdentityID.record()
|
||||
let addedIDRecorder = allIdentitiesService.identitiesCreated.record()
|
||||
|
||||
sut.urlFieldText = "mastodon.social"
|
||||
sut.logInTapped()
|
||||
|
|
|
@ -11,8 +11,9 @@ class RootViewModelTests: XCTestCase {
|
|||
var cancellables = Set<AnyCancellable>()
|
||||
|
||||
func testAddIdentity() throws {
|
||||
let uuid = UUID(uuidString: "E621E1F8-C36C-495A-93FC-0C247A3E6E5F")!
|
||||
let sut = try RootViewModel(
|
||||
environment: .mock(),
|
||||
environment: .mock(uuid: { uuid }),
|
||||
registerForRemoteNotifications: { Empty().setFailureType(to: Error.self).eraseToAnyPublisher() })
|
||||
let recorder = sut.$navigationViewModel.record()
|
||||
|
||||
|
@ -20,10 +21,6 @@ class RootViewModelTests: XCTestCase {
|
|||
|
||||
let addIdentityViewModel = sut.addIdentityViewModel()
|
||||
|
||||
addIdentityViewModel.addedIdentityID
|
||||
.sink(receiveValue: sut.identitySelected(id:))
|
||||
.store(in: &cancellables)
|
||||
|
||||
addIdentityViewModel.urlFieldText = "https://mastodon.social"
|
||||
addIdentityViewModel.logInTapped()
|
||||
|
||||
|
|
|
@ -74,11 +74,6 @@ struct AddIdentityView: View {
|
|||
}
|
||||
.animation(.default, if: !accessibilityReduceMotion)
|
||||
.alertItem($viewModel.alertItem)
|
||||
.onReceive(viewModel.addedIdentityID) { id in
|
||||
withAnimation {
|
||||
rootViewModel.identitySelected(id: id)
|
||||
}
|
||||
}
|
||||
.onAppear(perform: viewModel.refreshFilter)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue