diff --git a/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderViewModel.swift b/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderViewModel.swift index 3d92e3a0a..55d3d4cec 100644 --- a/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderViewModel.swift +++ b/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderViewModel.swift @@ -9,11 +9,6 @@ struct SafariWebLink: Identifiable { let url: URL } -func encodeHighlightResult(_ highlight: HighlightDep) -> [String: Any]? { - guard let data = try? JSONEncoder().encode(highlight) else { return nil } - return try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any] -} - final class WebReaderViewModel: ObservableObject { @Published var isLoading = false @Published var articleContent: ArticleContentDep? @@ -60,9 +55,9 @@ final class WebReaderViewModel: ObservableObject { .sink { completion in guard case .failure = completion else { return } replyHandler([], "createHighlight: Error encoding response") - } receiveValue: { highlight in - if let highlightValue = encodeHighlightResult(HighlightDep.make(from: highlight)) { - replyHandler(["result": highlightValue], nil) + } receiveValue: { result in + if let result = result { + replyHandler(["result": result], nil) } else { replyHandler([], "createHighlight: Error encoding response") } @@ -103,8 +98,8 @@ final class WebReaderViewModel: ObservableObject { .sink { completion in guard case .failure = completion else { return } replyHandler([], "mergeHighlight: Error encoding response") - } receiveValue: { highlight in - if let highlightValue = encodeHighlightResult(HighlightDep.make(from: highlight)) { + } receiveValue: { result in + if let highlightValue = result { replyHandler(["result": highlightValue], nil) } else { replyHandler([], "createHighlight: Error encoding response") @@ -126,9 +121,9 @@ final class WebReaderViewModel: ObservableObject { .sink { completion in guard case .failure = completion else { return } replyHandler([], "updateHighlight: Error encoding response") - } receiveValue: { highlight in + } receiveValue: { highlightID in // Update highlight JS code just expects the highlight ID back - replyHandler(["result": highlight.id], nil) + replyHandler(["result": highlightID], nil) } .store(in: &subscriptions) } diff --git a/apple/OmnivoreKit/Sources/Services/DataService/Mutations/CreateHighlight.swift b/apple/OmnivoreKit/Sources/Services/DataService/Mutations/CreateHighlight.swift index dc669f0df..bcad48562 100644 --- a/apple/OmnivoreKit/Sources/Services/DataService/Mutations/CreateHighlight.swift +++ b/apple/OmnivoreKit/Sources/Services/DataService/Mutations/CreateHighlight.swift @@ -11,9 +11,9 @@ public extension DataService { patch: String, articleId: String, annotation: String? = nil - ) -> AnyPublisher { + ) -> AnyPublisher<[String: Any]?, BasicError> { enum MutationResult { - case saved(highlight: HighlightDep) + case saved(highlight: InternalHighlight) case error(errorCode: Enums.CreateHighlightErrorCode) } @@ -54,14 +54,11 @@ public extension DataService { switch payload.data { case let .saved(highlight: highlight): - if let highlightObject = highlight.persist( + _ = highlight.persist( context: self.persistentContainer.viewContext, associatedItemID: articleId - ) { - promise(.success(highlightObject)) - } else { - promise(.failure(.message(messageText: "core data error"))) - } + ) + promise(.success(highlight.encoded())) case let .error(errorCode: errorCode): promise(.failure(.message(messageText: errorCode.rawValue))) } diff --git a/apple/OmnivoreKit/Sources/Services/DataService/Mutations/MergeHighlight.swift b/apple/OmnivoreKit/Sources/Services/DataService/Mutations/MergeHighlight.swift index 7a762c83d..272046f6c 100644 --- a/apple/OmnivoreKit/Sources/Services/DataService/Mutations/MergeHighlight.swift +++ b/apple/OmnivoreKit/Sources/Services/DataService/Mutations/MergeHighlight.swift @@ -12,9 +12,9 @@ public extension DataService { patch: String, articleId: String, overlapHighlightIdList: [String] - ) -> AnyPublisher { + ) -> AnyPublisher<[String: Any]?, BasicError> { enum MutationResult { - case saved(highlight: HighlightDep) + case saved(highlight: InternalHighlight) case error(errorCode: Enums.MergeHighlightErrorCode) } @@ -58,14 +58,11 @@ public extension DataService { switch payload.data { case let .saved(highlight: highlight): - if let highlightObject = highlight.persist( + _ = highlight.persist( context: self.persistentContainer.viewContext, associatedItemID: articleId - ) { - promise(.success(highlightObject)) - } else { - promise(.failure(.message(messageText: "core data error"))) - } + ) + promise(.success(highlight.encoded())) case let .error(errorCode: errorCode): promise(.failure(.message(messageText: errorCode.rawValue))) } diff --git a/apple/OmnivoreKit/Sources/Services/DataService/Mutations/UpdateHighlightAttributes.swift b/apple/OmnivoreKit/Sources/Services/DataService/Mutations/UpdateHighlightAttributes.swift index 8bfde44e0..b47768af2 100644 --- a/apple/OmnivoreKit/Sources/Services/DataService/Mutations/UpdateHighlightAttributes.swift +++ b/apple/OmnivoreKit/Sources/Services/DataService/Mutations/UpdateHighlightAttributes.swift @@ -8,9 +8,9 @@ public extension DataService { highlightID: String, annotation: String?, sharedAt: Date? - ) -> AnyPublisher { + ) -> AnyPublisher { enum MutationResult { - case saved(highlight: HighlightDep) + case saved(highlight: InternalHighlight) case error(errorCode: Enums.UpdateHighlightErrorCode) } @@ -48,7 +48,11 @@ public extension DataService { switch payload.data { case let .saved(highlight: highlight): - promise(.success(highlight)) + _ = highlight.persist( + context: self.persistentContainer.viewContext, + associatedItemID: "" // TODO: pass in articleID or just use update core data func + ) + promise(.success(highlight.id)) case let .error(errorCode: errorCode): promise(.failure(.message(messageText: errorCode.rawValue))) } diff --git a/apple/OmnivoreKit/Sources/Services/DataService/Queries/ArticleContentQuery.swift b/apple/OmnivoreKit/Sources/Services/DataService/Queries/ArticleContentQuery.swift index 703f8683b..13f29d163 100644 --- a/apple/OmnivoreKit/Sources/Services/DataService/Queries/ArticleContentQuery.swift +++ b/apple/OmnivoreKit/Sources/Services/DataService/Queries/ArticleContentQuery.swift @@ -13,7 +13,7 @@ public extension DataService { let articleSelection = Selection.Article { ArticleContentDep( htmlContent: try $0.content(), - highlights: try $0.highlights(selection: highlightSelection.list), + highlights: try $0.highlights(selection: highlightDepSelection.list), storedHighlightsJSONString: nil ) } diff --git a/apple/OmnivoreKit/Sources/Services/DataService/Queries/PDFHighlightsQuery.swift b/apple/OmnivoreKit/Sources/Services/DataService/Queries/PDFHighlightsQuery.swift index 7fe2ff470..4e7ee8331 100644 --- a/apple/OmnivoreKit/Sources/Services/DataService/Queries/PDFHighlightsQuery.swift +++ b/apple/OmnivoreKit/Sources/Services/DataService/Queries/PDFHighlightsQuery.swift @@ -10,21 +10,8 @@ public extension DataService { case error(error: String) } - let highlightSelection = Selection.Highlight { - HighlightDep( - id: try $0.id(), - shortId: try $0.shortId(), - quote: try $0.quote(), - prefix: try $0.prefix(), - suffix: try $0.suffix(), - patch: try $0.patch(), - annotation: try $0.annotation(), - createdByMe: try $0.createdByMe() - ) - } - let articleSelection = Selection.Article { - try $0.highlights(selection: highlightSelection.list) + try $0.highlights(selection: highlightDepSelection.list) } let selection = Selection { diff --git a/apple/OmnivoreKit/Sources/Services/DataService/Selections/HighlightSelection.swift b/apple/OmnivoreKit/Sources/Services/DataService/Selections/HighlightSelection.swift index 276078550..847eff213 100644 --- a/apple/OmnivoreKit/Sources/Services/DataService/Selections/HighlightSelection.swift +++ b/apple/OmnivoreKit/Sources/Services/DataService/Selections/HighlightSelection.swift @@ -2,6 +2,21 @@ import Models import SwiftGraphQL let highlightSelection = Selection.Highlight { + InternalHighlight( + id: try $0.id(), + shortId: try $0.shortId(), + quote: try $0.quote(), + prefix: try $0.prefix(), + suffix: try $0.suffix(), + patch: try $0.patch(), + annotation: try $0.annotation(), + createdAt: try $0.createdAt().value, + updatedAt: try $0.updatedAt().value, + createdByMe: try $0.createdByMe() + ) +} + +let highlightDepSelection = Selection.Highlight { HighlightDep( id: try $0.id(), shortId: try $0.shortId(), diff --git a/apple/OmnivoreKit/Sources/Services/InternalModels/InternalHighlight.swift b/apple/OmnivoreKit/Sources/Services/InternalModels/InternalHighlight.swift new file mode 100644 index 000000000..dd70d59d3 --- /dev/null +++ b/apple/OmnivoreKit/Sources/Services/InternalModels/InternalHighlight.swift @@ -0,0 +1,52 @@ +import CoreData +import Foundation +import Models + +struct InternalHighlight: Encodable { + let id: String + let shortId: String + let quote: String + let prefix: String? + let suffix: String? + let patch: String + let annotation: String? + let createdAt: Date? + let updatedAt: Date? + let createdByMe: Bool + + func asManagedObject(context: NSManagedObjectContext, associatedItemID: String) -> Highlight { + let highlight = Highlight(context: context) + highlight.linkedItemId = associatedItemID + highlight.markedForDeletion = false + highlight.id = id + highlight.shortId = shortId + highlight.quote = quote + highlight.prefix = prefix + highlight.suffix = suffix + highlight.patch = patch + highlight.annotation = annotation + highlight.createdAt = createdAt + highlight.updatedAt = updatedAt + highlight.createdByMe = createdByMe + return highlight + } + + func persist(context: NSManagedObjectContext, associatedItemID: String) -> Highlight? { + let highlight = asManagedObject(context: context, associatedItemID: associatedItemID) + + do { + try context.save() + print("Highlight saved succesfully") + return highlight + } catch { + context.rollback() + print("Failed to save Highlight: \(error.localizedDescription)") + return nil + } + } + + func encoded() -> [String: Any]? { + guard let data = try? JSONEncoder().encode(self) else { return nil } + return try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any] + } +}