diff --git a/apple/OmnivoreKit/Sources/App/Views/ApplyLabelsView.swift b/apple/OmnivoreKit/Sources/App/Views/Labels/ApplyLabelsView.swift similarity index 62% rename from apple/OmnivoreKit/Sources/App/Views/ApplyLabelsView.swift rename to apple/OmnivoreKit/Sources/App/Views/Labels/ApplyLabelsView.swift index 23e65a0b7..f49d8d582 100644 --- a/apple/OmnivoreKit/Sources/App/Views/ApplyLabelsView.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Labels/ApplyLabelsView.swift @@ -1,58 +1,15 @@ -import Combine import Models import Services import SwiftUI import Views -final class ApplyLabelsViewModel: ObservableObject { - private var hasLoadedInitialLabels = false - @Published var isLoading = true - @Published var selectedLabels = [FeedItemLabel]() - @Published var unselectedLabels = [FeedItemLabel]() - - var subscriptions = Set() - - func load(item: FeedItem, dataService: DataService) { - guard !hasLoadedInitialLabels else { return } - - dataService.labelsPublisher().sink( - receiveCompletion: { _ in }, - receiveValue: { [weak self] allLabels in - self?.isLoading = false - self?.hasLoadedInitialLabels = true - self?.selectedLabels = item.labels - self?.unselectedLabels = allLabels.filter { !item.labels.contains($0) } - } - ) - .store(in: &subscriptions) - } - - func saveChanges(itemID: String, dataService: DataService, onComplete: @escaping ([FeedItemLabel]) -> Void) { - dataService.updateArticleLabelsPublisher(itemID: itemID, labelIDs: selectedLabels.map(\.id)).sink( - receiveCompletion: { _ in }, - receiveValue: { onComplete($0) } - ) - .store(in: &subscriptions) - } - - func addLabel(_ label: FeedItemLabel) { - selectedLabels.insert(label, at: 0) - unselectedLabels.removeAll { $0.id == label.id } - } - - func removeLabel(_ label: FeedItemLabel) { - unselectedLabels.insert(label, at: 0) - selectedLabels.removeAll { $0.id == label.id } - } -} - struct ApplyLabelsView: View { let item: FeedItem let commitLabelChanges: ([FeedItemLabel]) -> Void @EnvironmentObject var dataService: DataService @Environment(\.presentationMode) private var presentationMode - @StateObject var viewModel = ApplyLabelsViewModel() + @StateObject var viewModel = LabelsViewModel() var body: some View { NavigationView { @@ -95,6 +52,19 @@ struct ApplyLabelsView: View { } } } + Section { + Button( + action: { viewModel.showCreateEmailModal = true }, + label: { + HStack { + Image(systemName: "plus.circle.fill").foregroundColor(.green) + Text("Create a new Label") + Spacer() + } + } + ) + .disabled(viewModel.isLoading) + } } .navigationTitle("Assign Labels") .navigationBarTitleDisplayMode(.inline) @@ -117,6 +87,9 @@ struct ApplyLabelsView: View { ) } } + .sheet(isPresented: $viewModel.showCreateEmailModal) { + CreateLabelView(viewModel: viewModel) + } } } .onAppear { diff --git a/apple/OmnivoreKit/Sources/App/Views/Profile/LabelsView.swift b/apple/OmnivoreKit/Sources/App/Views/Labels/LabelsView.swift similarity index 70% rename from apple/OmnivoreKit/Sources/App/Views/Profile/LabelsView.swift rename to apple/OmnivoreKit/Sources/App/Views/Labels/LabelsView.swift index 7161f67ad..5d535b0d8 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Profile/LabelsView.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Labels/LabelsView.swift @@ -4,65 +4,6 @@ import Services import SwiftUI import Views -final class LabelsViewModel: ObservableObject { - private var hasLoadedInitialLabels = false - @Published var isLoading = false - @Published var labels = [FeedItemLabel]() - @Published var showCreateEmailModal = false - - var subscriptions = Set() - - func loadLabels(dataService: DataService) { - guard !hasLoadedInitialLabels else { return } - isLoading = true - - dataService.labelsPublisher().sink( - receiveCompletion: { _ in }, - receiveValue: { [weak self] result in - self?.isLoading = false - self?.labels = result - self?.hasLoadedInitialLabels = true - } - ) - .store(in: &subscriptions) - } - - func createLabel(dataService: DataService, name: String, color: Color, description: String?) { - isLoading = true - - dataService.createLabelPublisher( - name: name, - color: color.hex ?? "", - description: description - ).sink( - receiveCompletion: { [weak self] _ in - self?.isLoading = false - }, - receiveValue: { [weak self] result in - self?.isLoading = false - self?.labels.insert(result, at: 0) - self?.showCreateEmailModal = false - } - ) - .store(in: &subscriptions) - } - - func deleteLabel(dataService: DataService, labelID: String) { - isLoading = true - - dataService.removeLabelPublisher(labelID: labelID).sink( - receiveCompletion: { [weak self] _ in - self?.isLoading = false - }, - receiveValue: { [weak self] _ in - self?.isLoading = false - self?.labels.removeAll { $0.id == labelID } - } - ) - .store(in: &subscriptions) - } -} - struct LabelsView: View { @EnvironmentObject var dataService: DataService @StateObject var viewModel = LabelsViewModel() diff --git a/apple/OmnivoreKit/Sources/App/Views/Labels/LabelsViewModel.swift b/apple/OmnivoreKit/Sources/App/Views/Labels/LabelsViewModel.swift new file mode 100644 index 000000000..4d06f287c --- /dev/null +++ b/apple/OmnivoreKit/Sources/App/Views/Labels/LabelsViewModel.swift @@ -0,0 +1,103 @@ +import Combine +import Models +import Services +import SwiftUI +import Views + +final class LabelsViewModel: ObservableObject { + private var hasLoadedInitialLabels = false + @Published var isLoading = false + @Published var selectedLabels = [FeedItemLabel]() + @Published var unselectedLabels = [FeedItemLabel]() + @Published var labels = [FeedItemLabel]() + @Published var showCreateEmailModal = false + + var subscriptions = Set() + + func loadLabels(dataService: DataService) { + guard !hasLoadedInitialLabels else { return } + isLoading = true + + dataService.labelsPublisher().sink( + receiveCompletion: { _ in }, + receiveValue: { [weak self] result in + self?.isLoading = false + self?.labels = result + self?.hasLoadedInitialLabels = true + } + ) + .store(in: &subscriptions) + } + + func load(item: FeedItem, dataService: DataService) { + guard !hasLoadedInitialLabels else { return } + + dataService.labelsPublisher().sink( + receiveCompletion: { _ in }, + receiveValue: { [weak self] allLabels in + self?.isLoading = false + self?.hasLoadedInitialLabels = true + self?.selectedLabels = item.labels + self?.unselectedLabels = allLabels.filter { !item.labels.contains($0) } + } + ) + .store(in: &subscriptions) + } + + func createLabel(dataService: DataService, name: String, color: Color, description: String?) { + isLoading = true + + dataService.createLabelPublisher( + name: name, + color: color.hex ?? "", + description: description + ).sink( + receiveCompletion: { [weak self] _ in + self?.isLoading = false + }, + receiveValue: { [weak self] result in + self?.isLoading = false + self?.labels.insert(result, at: 0) + self?.unselectedLabels.insert(result, at: 0) + self?.showCreateEmailModal = false + } + ) + .store(in: &subscriptions) + } + + func deleteLabel(dataService: DataService, labelID: String) { + isLoading = true + + dataService.removeLabelPublisher(labelID: labelID).sink( + receiveCompletion: { [weak self] _ in + self?.isLoading = false + }, + receiveValue: { [weak self] _ in + self?.isLoading = false + self?.labels.removeAll { $0.id == labelID } + } + ) + .store(in: &subscriptions) + } + + func saveChanges(itemID: String, dataService: DataService, onComplete: @escaping ([FeedItemLabel]) -> Void) { + isLoading = true + dataService.updateArticleLabelsPublisher(itemID: itemID, labelIDs: selectedLabels.map(\.id)).sink( + receiveCompletion: { [weak self] _ in + self?.isLoading = false + }, + receiveValue: { onComplete($0) } + ) + .store(in: &subscriptions) + } + + func addLabel(_ label: FeedItemLabel) { + selectedLabels.insert(label, at: 0) + unselectedLabels.removeAll { $0.id == label.id } + } + + func removeLabel(_ label: FeedItemLabel) { + unselectedLabels.insert(label, at: 0) + selectedLabels.removeAll { $0.id == label.id } + } +}