From d4628edcaf758dfaf9f3302fd35274fa74c0267f Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Wed, 20 Dec 2023 14:20:40 +0800 Subject: [PATCH] Improve subscription labels rules --- .../App/Views/Profile/SubscriptionsView.swift | 89 ++++++++++++++----- .../Mutations/SetRuleMutation.swift | 6 +- 2 files changed, 70 insertions(+), 25 deletions(-) diff --git a/apple/OmnivoreKit/Sources/App/Views/Profile/SubscriptionsView.swift b/apple/OmnivoreKit/Sources/App/Views/Profile/SubscriptionsView.swift index 3983a592d..83cdd0752 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Profile/SubscriptionsView.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Profile/SubscriptionsView.swift @@ -24,8 +24,8 @@ typealias OperationStatusHandler = (_: OperationStatus) -> Void @Published var isLoading = true @Published var feeds = [Subscription]() @Published var newsletters = [Subscription]() - @Published var rules = [Rule]() - @Published var labels = [LinkedItemLabel]() + @Published var rules: [Rule]? + @Published var labels: [LinkedItemLabel]? @Published var hasNetworkError = false @Published var subscriptionNameToCancel: String? @@ -53,13 +53,19 @@ typealias OperationStatusHandler = (_: OperationStatus) -> Void rules = try await dataService.rules() } catch { print("error fetching rules and labels", error) + rules = [] } - await loadLabelsFromStore(dataService: dataService) + await loadLabels(dataService: dataService) isLoading = false } + func loadLabels(dataService: DataService) async { + _ = try? await dataService.labels() + await loadLabelsFromStore(dataService: dataService) + } + func loadLabelsFromStore(dataService: DataService) async { let fetchRequest: NSFetchRequest = LinkedItemLabel.fetchRequest() @@ -112,12 +118,30 @@ typealias OperationStatusHandler = (_: OperationStatus) -> Void } } - func setLabelsRule(dataService: DataService, ruleName: String, filter: String, labelIDs: [String]) async { - async { + func setLabelsRule(dataService: DataService, existingRule: Rule?, ruleName: String, filter: String, labelIDs: [String]) async { + Task { operationMessage = "Creating label rule..." operationStatus = .isPerforming do { - try await dataService.createAddLabelsRule(name: ruleName, filter: filter, labelIDs: labelIDs) + // Make sure the labels have been created + await loadLabels(dataService: dataService) + let existingLabelIDs = labels?.map(\.unwrappedID) ?? [] + if labelIDs.first(where: { !existingLabelIDs.contains($0) }) != nil { + throw BasicError.message(messageText: "Label not created") + } + + _ = try await dataService.createOrUpdateAddLabelsRule( + existingID: existingRule?.id, + name: ruleName, + filter: filter, + labelIDs: labelIDs + ) + if let newRules = try? await dataService.rules() { + if !newRules.contains(where: { $0.name == ruleName }) { + throw BasicError.message(messageText: "Rule not created") + } + rules = newRules + } operationMessage = "Rule created" operationStatus = .success } catch { @@ -398,10 +422,16 @@ struct SubscriptionSettingsView: View { @State var folderSelection: String = "" @State var showLabelsSelector = false + @State var isLoadingRule = false + let unsubscribe: (_: Subscription) -> Void @Environment(\.dismiss) private var dismiss + var existingRule: Rule? { + viewModel.rules?.first { $0.name == ruleName } + } + var ruleName: String { if let url = subscription.url, subscription.type == .newsletter { return "system.autoLabel.(\(url))" @@ -416,6 +446,15 @@ struct SubscriptionSettingsView: View { return "subscription:\"\(subscription.name)\"" } + var ruleLabels: [LinkedItemLabel]? { + if let labelIDs = existingRule?.actions.flatMap(\.params) { + return Array(labelIDs.compactMap { labelID in + viewModel.labels?.first(where: { $0.unwrappedID == labelID }) + }) + } + return nil + } + var folderRow: some View { HStack { Picker("Destination Folder", selection: $folderSelection) { @@ -435,10 +474,11 @@ struct SubscriptionSettingsView: View { .onChange(of: prefetchContent) { newValue in Task { viewModel.showOperationToast = true - await viewModel.updateSubscription(dataService: dataService, subscription: subscription, fetchContent: newValue) - DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(1500)) { - viewModel.showOperationToast = false - } + await viewModel.updateSubscription( + dataService: dataService, + subscription: subscription, + fetchContent: newValue + ) } } } @@ -448,18 +488,18 @@ struct SubscriptionSettingsView: View { HStack { Text("Add Labels") Spacer() - Button(action: { showLabelsSelector = true }, label: { - if let rule = viewModel.rules.first(where: { $0.name == ruleName }) { - let labelIDs = rule.actions.flatMap(\.params) - let labelNames = Array(labelIDs.compactMap { labelID in - viewModel.labels.first(where: { $0.unwrappedID == labelID })?.unwrappedName - }) - - Text("[\(labelNames.joined(separator: ","))]") - } else { - Text("[none]") - } - }) + if isLoadingRule || viewModel.rules != nil { + Button(action: { showLabelsSelector = true }, label: { + if let ruleLabels = ruleLabels { + let labelNames = ruleLabels.map(\.unwrappedName) + Text("[\(labelNames.joined(separator: ","))]") + } else { + Text("[none]") + } + }) + } else { + ProgressView() + } } } @@ -513,17 +553,20 @@ struct SubscriptionSettingsView: View { } } .sheet(isPresented: $showLabelsSelector) { - ApplyLabelsView(mode: .list([]), onSave: { labels in + ApplyLabelsView(mode: .list(ruleLabels ?? []), onSave: { labels in Task { + isLoadingRule = true viewModel.showOperationToast = true await viewModel.setLabelsRule( dataService: dataService, + existingRule: existingRule, ruleName: ruleName, filter: ruleFilter, labelIDs: labels.map(\.unwrappedID) ) DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(1500)) { viewModel.showOperationToast = false + isLoadingRule = true } } }) diff --git a/apple/OmnivoreKit/Sources/Services/DataService/Mutations/SetRuleMutation.swift b/apple/OmnivoreKit/Sources/Services/DataService/Mutations/SetRuleMutation.swift index 8228a4dcd..48dfc16f5 100644 --- a/apple/OmnivoreKit/Sources/Services/DataService/Mutations/SetRuleMutation.swift +++ b/apple/OmnivoreKit/Sources/Services/DataService/Mutations/SetRuleMutation.swift @@ -43,7 +43,7 @@ let ruleSelection = Selection.Rule { } public extension DataService { - func createAddLabelsRule(name: String, filter: String, labelIDs: [String]) async throws -> Rule { + func createOrUpdateAddLabelsRule(existingID: String?, name: String, filter: String, labelIDs: [String]) async throws -> Rule { enum MutationResult { case result(rule: Rule) case error(errorMessage: String) @@ -62,7 +62,9 @@ public extension DataService { actions: [InputObjects.RuleActionInput(params: labelIDs, type: .addLabel)], enabled: true, eventTypes: [.pageCreated], - filter: filter, name: name + filter: filter, + id: OptionalArgument(existingID), + name: name ), selection: selection )