From 8d47b67e1508add7546048a18f343d0b1ae7a14c Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 19 Dec 2023 19:54:24 +0800 Subject: [PATCH] Start to add subscription rules --- .../App/Views/Profile/SubscriptionsView.swift | 82 ++++++++++++------- .../Mutations/SetRuleMutation.swift | 70 ++++++++++++++++ 2 files changed, 124 insertions(+), 28 deletions(-) create mode 100644 apple/OmnivoreKit/Sources/Services/DataService/Mutations/SetRuleMutation.swift diff --git a/apple/OmnivoreKit/Sources/App/Views/Profile/SubscriptionsView.swift b/apple/OmnivoreKit/Sources/App/Views/Profile/SubscriptionsView.swift index de092a50c..5a464b875 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Profile/SubscriptionsView.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Profile/SubscriptionsView.swift @@ -346,6 +346,7 @@ struct SubscriptionCell: View { } } +@MainActor struct SubscriptionSettingsView: View { let subscription: Subscription let viewModel: SubscriptionsViewModel @@ -355,12 +356,50 @@ struct SubscriptionSettingsView: View { @State var deleteConfirmationShown = false @State var showDeleteCompleted = false @State var folderSelection: String = "" + @State var showLabelsSelector = false - // let dismiss: () -> Void let unsubscribe: (_: Subscription) -> Void @Environment(\.dismiss) private var dismiss + var folderRow: some View { + HStack { + Picker("Destination Folder", selection: $folderSelection) { + Text("Inbox").tag("inbox") + Text("Following").tag("following") + } + .pickerStyle(MenuPickerStyle()) + .onChange(of: folderSelection) { newValue in + Task { + viewModel.showOperationToast = true + await viewModel.updateSubscription(dataService: dataService, subscription: subscription, folder: newValue) + DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(1500)) { + viewModel.showOperationToast = false + } + } + } + .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 + } + } + } + } + } + + var labelRuleRow: some View { + HStack { + Text("Add Labels") + Spacer() + Button(action: { showLabelsSelector = true }, label: { + Text("[none]") + }) + } + } + var body: some View { VStack { SubscriptionRow(subscription: subscription, useImageSpacer: false, trailingButton: { @@ -385,35 +424,14 @@ struct SubscriptionSettingsView: View { .padding(.horizontal, 15) List { - Toggle(isOn: $prefetchContent, label: { Text("Prefetch Content:") }) - .onAppear { - prefetchContent = subscription.fetchContent - } - HStack { - Picker("Destination Folder", selection: $folderSelection) { - Text("Inbox").tag("inbox") - Text("Following").tag("following") - } - .pickerStyle(MenuPickerStyle()) - .onChange(of: folderSelection) { newValue in - Task { - viewModel.showOperationToast = true - await viewModel.updateSubscription(dataService: dataService, subscription: subscription, folder: newValue) - DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(1500)) { - viewModel.showOperationToast = false - } + if subscription.type != .newsletter { + Toggle(isOn: $prefetchContent, label: { Text("Prefetch Content:") }) + .onAppear { + prefetchContent = subscription.fetchContent } - } - .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 - } - } - } } + folderRow + labelRuleRow }.listStyle(.insetGrouped) Spacer() @@ -431,5 +449,13 @@ struct SubscriptionSettingsView: View { viewModel.subscriptionNameToCancel = nil } } + .sheet(isPresented: $showLabelsSelector) { + ApplyLabelsView(mode: .list([]), onSave: { labels in + print("APPLIED LABELSL: ", labels) +// showLabelsModal = false +// item.labels = NSSet(array: labels) +// readerSettingsChangedTransactionID = UUID() + }) + } } } diff --git a/apple/OmnivoreKit/Sources/Services/DataService/Mutations/SetRuleMutation.swift b/apple/OmnivoreKit/Sources/Services/DataService/Mutations/SetRuleMutation.swift new file mode 100644 index 000000000..80a68d73d --- /dev/null +++ b/apple/OmnivoreKit/Sources/Services/DataService/Mutations/SetRuleMutation.swift @@ -0,0 +1,70 @@ +import CoreData +import Foundation +import Models +import SwiftGraphQL + +// input SetRuleInput { +// id: ID +// name: String! +// description: String +// filter: String! +// actions: [RuleActionInput!]! +// enabled: Boolean! +// eventTypes: [RuleEventType!]! +// } + +public struct Rule { + let id: String + let name: String +} + +let ruleSelection = Selection.Rule { + Rule(id: try $0.id(), name: try $0.name()) +} + +public extension DataService { + func createAddLabelsRule(name: String, filter: String, labelIDs: [String]) async throws -> Rule { + enum MutationResult { + case result(rule: Rule) + case error(errorMessage: String) + } + + let selection = Selection { + try $0.on( + setRuleError: .init { .error(errorMessage: try $0.errorCodes().first?.rawValue ?? "Unknown Error") }, + setRuleSuccess: .init { .result(rule: try $0.rule(selection: ruleSelection)) } + ) + } + + let mutation = Selection.Mutation { + try $0.setRule( + input: InputObjects.SetRuleInput( + actions: [InputObjects.RuleActionInput(params: labelIDs, type: .addLabel)], + enabled: true, + eventTypes: [.pageCreated], + filter: filter, name: name + ), + selection: selection + ) + } + + let path = appEnvironment.graphqlPath + let headers = networker.defaultHeaders + + return try await withCheckedThrowingContinuation { continuation in + send(mutation, to: path, headers: headers) { queryResult in + guard let payload = try? queryResult.get() else { + continuation.resume(throwing: BasicError.message(messageText: "network error")) + return + } + + switch payload.data { + case let .result(rule: rule): + continuation.resume(returning: rule) + case let .error(errorMessage: errorMessage): + continuation.resume(throwing: BasicError.message(messageText: errorMessage)) + } + } + } + } +}