diff --git a/Shared/Localizations/Localizable.strings b/Shared/Localizations/Localizable.strings index 35d8236..7705584 100644 --- a/Shared/Localizations/Localizable.strings +++ b/Shared/Localizations/Localizable.strings @@ -5,6 +5,7 @@ "oauth.error.code-not-found" = "OAuth error: code not found"; "secondary-navigation.accounts" = "Accounts"; "secondary-navigation.preferences" = "Preferences"; +"identities.add" = "Add"; "preferences" = "Preferences"; "preferences.posting-reading" = "Posting and Reading"; "preferences.posting" = "Posting"; diff --git a/Shared/Model/IdentityDatabase.swift b/Shared/Model/IdentityDatabase.swift index ae40750..30ef8ab 100644 --- a/Shared/Model/IdentityDatabase.swift +++ b/Shared/Model/IdentityDatabase.swift @@ -41,6 +41,12 @@ extension IdentityDatabase { .eraseToAnyPublisher() } + func deleteIdentity(id: UUID) -> AnyPublisher { + return databaseQueue.writePublisher(updates: StoredIdentity.filter(Column("id") == id).deleteAll) + .map { _ in () } + .eraseToAnyPublisher() + } + func updateLastUsedAt(identityID: UUID) -> AnyPublisher { databaseQueue.writePublisher { try StoredIdentity @@ -110,8 +116,8 @@ extension IdentityDatabase { .eraseToAnyPublisher() } - func identitiesObservation(excluding: UUID) -> AnyPublisher<[Identity], Error> { - ValueObservation.tracking(Self.identitiesRequest(excluding: excluding).fetchAll) + func identitiesObservation() -> AnyPublisher<[Identity], Error> { + ValueObservation.tracking(Self.identitiesRequest().fetchAll) .removeDuplicates() .publisher(in: databaseQueue, scheduling: .immediate) .map { $0.map(Identity.init(result:)) } @@ -119,7 +125,11 @@ extension IdentityDatabase { } func recentIdentitiesObservation(excluding: UUID) -> AnyPublisher<[Identity], Error> { - ValueObservation.tracking(Self.identitiesRequest(excluding: excluding).limit(9).fetchAll) + ValueObservation.tracking( + Self.identitiesRequest() + .filter(Column("id") != excluding) + .limit(9) + .fetchAll) .removeDuplicates() .publisher(in: databaseQueue, scheduling: .immediate) .map { $0.map(Identity.init(result:)) } @@ -132,9 +142,8 @@ extension IdentityDatabase { } private extension IdentityDatabase { - private static func identitiesRequest(excluding: UUID) -> QueryInterfaceRequest { + private static func identitiesRequest() -> QueryInterfaceRequest { StoredIdentity - .filter(Column("id") != excluding) .order(Column("lastUsedAt").desc) .including(optional: StoredIdentity.instance) .including(optional: StoredIdentity.account) diff --git a/Shared/Model/IdentityRepository.swift b/Shared/Model/IdentityRepository.swift index b6cf5f6..a0154e5 100644 --- a/Shared/Model/IdentityRepository.swift +++ b/Shared/Model/IdentityRepository.swift @@ -69,7 +69,7 @@ extension IdentityRepository { } func identitiesObservation() -> AnyPublisher<[Identity], Error> { - appEnvironment.identityDatabase.identitiesObservation(excluding: identity.id) + appEnvironment.identityDatabase.identitiesObservation() } func recentIdentitiesObservation() -> AnyPublisher<[Identity], Error> { diff --git a/Shared/View Models/RootViewModel.swift b/Shared/View Models/RootViewModel.swift index 5fa9e1c..d736de9 100644 --- a/Shared/View Models/RootViewModel.swift +++ b/Shared/View Models/RootViewModel.swift @@ -24,6 +24,12 @@ extension RootViewModel { .store(in: &cancellables) } + func deleteIdentity(id: UUID) { + environment.identityDatabase.deleteIdentity(id: id) + .sink(receiveCompletion: { _ in }, receiveValue: {}) + .store(in: &cancellables) + } + func addIdentityViewModel() -> AddIdentityViewModel { AddIdentityViewModel(environment: environment) } diff --git a/iOS/Views/IdentitiesView.swift b/iOS/Views/IdentitiesView.swift index a9f173e..9adea75 100644 --- a/iOS/Views/IdentitiesView.swift +++ b/iOS/Views/IdentitiesView.swift @@ -1,10 +1,12 @@ // Copyright © 2020 Metabolist. All rights reserved. import SwiftUI +import KingfisherSwiftUI struct IdentitiesView: View { @StateObject var viewModel: IdentitiesViewModel @EnvironmentObject var rootViewModel: RootViewModel + @Environment(\.displayScale) var displayScale: CGFloat var body: some View { Form { @@ -12,19 +14,43 @@ struct IdentitiesView: View { NavigationLink( destination: AddIdentityView(viewModel: rootViewModel.addIdentityViewModel()), label: { - Label("add new account", systemImage: "plus") + Label("identities.add", systemImage: "plus.circle") }) } Section { - List(viewModel.identities) { identity in - Button(identity.handle) { - withAnimation { - rootViewModel.newIdentitySelected(id: identity.id) + List { + ForEach(viewModel.identities) { identity in + Button { + withAnimation { + rootViewModel.newIdentitySelected(id: identity.id) + } + } label: { + HStack { + KFImage(identity.image, + options: .downsampled(dimension: 28, scaleFactor: displayScale)) + Text(identity.handle) + Spacer() + if identity.id == viewModel.identity.id { + Image(systemName: "checkmark.circle") + } + } } + .disabled(identity.id == viewModel.identity.id) + .buttonStyle(PlainButtonStyle()) + } + .onDelete { + guard let index = $0.first else { return } + + rootViewModel.deleteIdentity(id: viewModel.identities[index].id) } } } } + .toolbar { + ToolbarItem(placement: ToolbarItemPlacement.navigationBarTrailing) { + EditButton() + } + } } }