mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
remove HighlightDep and pdf specific highlight functions
This commit is contained in:
parent
23edb9b99b
commit
25e237255c
10 changed files with 12 additions and 258 deletions
|
|
@ -1,4 +1,5 @@
|
|||
import Combine
|
||||
import CoreData
|
||||
import Foundation
|
||||
import Models
|
||||
import Services
|
||||
|
|
@ -17,52 +18,17 @@ public final class PDFViewerViewModel: ObservableObject {
|
|||
self.feedItem = feedItem
|
||||
}
|
||||
|
||||
public func loadHighlights(completion onComplete: @escaping ([HighlightDep]) -> Void) {
|
||||
guard let username = services.dataService.currentViewer?.username else { return }
|
||||
|
||||
services.dataService.pdfHighlightsPublisher(username: username, slug: feedItem.slug).sink(
|
||||
receiveCompletion: { [weak self] completion in
|
||||
guard case .failure = completion else { return }
|
||||
onComplete(self?.allHighlights(fetchedHighlights: []) ?? [])
|
||||
},
|
||||
receiveValue: { [weak self] highlights in
|
||||
onComplete(self?.allHighlights(fetchedHighlights: highlights) ?? [])
|
||||
}
|
||||
public func loadHighlights(completion onComplete: @escaping ([String]) -> Void) {
|
||||
let fetchRequest: NSFetchRequest<Models.Highlight> = Highlight.fetchRequest()
|
||||
fetchRequest.predicate = NSPredicate(
|
||||
format: "linkedItemId == %@", feedItem.id
|
||||
)
|
||||
.store(in: &subscriptions)
|
||||
}
|
||||
|
||||
// TODO: use core data instead
|
||||
private func allHighlights(fetchedHighlights: [HighlightDep]) -> [HighlightDep] {
|
||||
var resultSet = [String: HighlightDep]()
|
||||
|
||||
for highlight in services.dataService.cachedHighlights(pdfID: feedItem.id) {
|
||||
resultSet[highlight.id] = highlight
|
||||
}
|
||||
for highlight in fetchedHighlights {
|
||||
resultSet[highlight.id] = highlight
|
||||
}
|
||||
for highlightId in services.dataService.deletedHighlightsIDs {
|
||||
resultSet.removeValue(forKey: highlightId)
|
||||
}
|
||||
return Array(resultSet.values)
|
||||
let highlights = (try? services.dataService.viewContext.fetch(fetchRequest)) ?? []
|
||||
onComplete(highlights.map { $0.patch ?? "" })
|
||||
}
|
||||
|
||||
public func createHighlight(shortId: String, highlightID: String, quote: String, patch: String) {
|
||||
services.dataService.persistHighlight(
|
||||
pdfID: feedItem.id,
|
||||
highlight: HighlightDep(
|
||||
id: highlightID,
|
||||
shortId: shortId,
|
||||
quote: quote,
|
||||
prefix: nil,
|
||||
suffix: nil,
|
||||
patch: patch,
|
||||
annotation: nil,
|
||||
createdByMe: true
|
||||
)
|
||||
)
|
||||
|
||||
services.dataService
|
||||
.createHighlightPublisher(
|
||||
shortId: shortId,
|
||||
|
|
@ -78,7 +44,6 @@ public final class PDFViewerViewModel: ObservableObject {
|
|||
.store(in: &subscriptions)
|
||||
}
|
||||
|
||||
// TODO: able to delete this now?
|
||||
public func mergeHighlight(
|
||||
shortId: String,
|
||||
highlightID: String,
|
||||
|
|
@ -103,7 +68,6 @@ public final class PDFViewerViewModel: ObservableObject {
|
|||
}
|
||||
|
||||
public func removeHighlights(highlightIds: [String]) {
|
||||
// TODO: update function to take an array?
|
||||
highlightIds.forEach { highlightId in
|
||||
services.dataService.deleteHighlightPublisher(highlightId: highlightId)
|
||||
.sink { [weak self] completion in
|
||||
|
|
|
|||
|
|
@ -51,9 +51,6 @@ import Views
|
|||
}
|
||||
|
||||
func loadItems(dataService: DataService, isRefresh: Bool) {
|
||||
// Clear offline highlights since we'll be populating new FeedItems with the correct highlights set
|
||||
dataService.clearHighlights()
|
||||
|
||||
let thisSearchIdx = searchIdx
|
||||
searchIdx += 1
|
||||
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ public extension FeedItemDep {
|
|||
linkedItem.contentReader = contentReader
|
||||
|
||||
// for label in item.labels {
|
||||
// TODO: append labels
|
||||
// TODO: append labels...and highlights?
|
||||
// }
|
||||
|
||||
return linkedItem
|
||||
|
|
|
|||
|
|
@ -1,85 +0,0 @@
|
|||
import CoreData
|
||||
import Foundation
|
||||
|
||||
public struct HighlightDep: Identifiable, Hashable, Codable {
|
||||
public let id: String
|
||||
public let shortId: String
|
||||
public let quote: String
|
||||
public let prefix: String?
|
||||
public let suffix: String?
|
||||
public let patch: String
|
||||
public let annotation: String?
|
||||
public let createdAt: Date?
|
||||
public let updatedAt: Date?
|
||||
public let createdByMe: Bool
|
||||
|
||||
public init(
|
||||
id: String,
|
||||
shortId: String,
|
||||
quote: String,
|
||||
prefix: String?,
|
||||
suffix: String?,
|
||||
patch: String,
|
||||
annotation: String?,
|
||||
createdByMe: Bool,
|
||||
createdAt: Date? = nil,
|
||||
updatedAt: Date? = nil
|
||||
) {
|
||||
self.id = id
|
||||
self.shortId = shortId
|
||||
self.quote = quote
|
||||
self.prefix = prefix
|
||||
self.suffix = suffix
|
||||
self.patch = patch
|
||||
self.annotation = annotation
|
||||
self.createdAt = createdAt
|
||||
self.updatedAt = updatedAt
|
||||
self.createdByMe = createdByMe
|
||||
}
|
||||
|
||||
public func toManagedObject(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
|
||||
}
|
||||
|
||||
public func persist(context: NSManagedObjectContext, associatedItemID: String) -> Highlight? {
|
||||
let highlight = toManagedObject(context: context, associatedItemID: associatedItemID)
|
||||
|
||||
do {
|
||||
try context.save()
|
||||
logger.debug("Highlight saved succesfully")
|
||||
return highlight
|
||||
} catch {
|
||||
context.rollback()
|
||||
logger.debug("Failed to save Highlight: \(error.localizedDescription)")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
public static func make(from highlight: Highlight) -> HighlightDep {
|
||||
HighlightDep(
|
||||
id: highlight.id ?? "",
|
||||
shortId: highlight.shortId ?? "",
|
||||
quote: highlight.quote ?? "",
|
||||
prefix: highlight.prefix,
|
||||
suffix: highlight.suffix,
|
||||
patch: highlight.patch ?? "",
|
||||
annotation: highlight.annotation,
|
||||
createdByMe: highlight.createdByMe,
|
||||
createdAt: highlight.createdAt,
|
||||
updatedAt: highlight.updatedAt
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -21,8 +21,6 @@ public final class DataService: ObservableObject {
|
|||
persistentContainer.viewContext
|
||||
}
|
||||
|
||||
public var deletedHighlightsIDs = Set<String>()
|
||||
|
||||
public init(appEnvironment: AppEnvironment, networker: Networker) {
|
||||
self.appEnvironment = appEnvironment
|
||||
self.networker = networker
|
||||
|
|
@ -43,26 +41,6 @@ public final class DataService: ObservableObject {
|
|||
return try? persistentContainer.viewContext.fetch(fetchRequest).first
|
||||
}
|
||||
|
||||
public func clearHighlights() {
|
||||
backgroundContext.perform {
|
||||
self.deletedHighlightsIDs.removeAll()
|
||||
|
||||
let fetchRequest: NSFetchRequest<Models.Highlight> = Highlight.fetchRequest()
|
||||
|
||||
let highlights = (try? self.backgroundContext.fetch(fetchRequest)) ?? []
|
||||
|
||||
for highlight in highlights {
|
||||
self.backgroundContext.delete(highlight)
|
||||
}
|
||||
|
||||
do {
|
||||
try self.backgroundContext.save()
|
||||
} catch {
|
||||
logger.debug("failed to delete objects")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func switchAppEnvironment(appEnvironment: AppEnvironment) {
|
||||
do {
|
||||
try ValetKey.appEnvironmentString.setValue(appEnvironment.rawValue)
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ public extension DataService {
|
|||
|
||||
switch payload.data {
|
||||
case let .saved(highlight: highlight):
|
||||
_ = highlight.persist(
|
||||
highlight.persist(
|
||||
context: self.backgroundContext,
|
||||
associatedItemID: articleId
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,55 +0,0 @@
|
|||
import Combine
|
||||
import Foundation
|
||||
import Models
|
||||
import SwiftGraphQL
|
||||
|
||||
public extension DataService {
|
||||
func pdfHighlightsPublisher(username: String, slug: String) -> AnyPublisher<[HighlightDep], ServerError> {
|
||||
enum QueryResult {
|
||||
case success(result: [HighlightDep])
|
||||
case error(error: String)
|
||||
}
|
||||
|
||||
let articleSelection = Selection.Article {
|
||||
try $0.highlights(selection: highlightDepSelection.list)
|
||||
}
|
||||
|
||||
let selection = Selection<QueryResult, Unions.ArticleResult> {
|
||||
try $0.on(
|
||||
articleSuccess: .init {
|
||||
QueryResult.success(result: try $0.article(selection: articleSelection))
|
||||
},
|
||||
articleError: .init {
|
||||
QueryResult.error(error: try $0.errorCodes().description)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
let query = Selection.Query {
|
||||
try $0.article(username: username, slug: slug, selection: selection)
|
||||
}
|
||||
|
||||
let path = appEnvironment.graphqlPath
|
||||
let headers = networker.defaultHeaders
|
||||
|
||||
return Deferred {
|
||||
Future { promise in
|
||||
send(query, to: path, headers: headers) { result in
|
||||
switch result {
|
||||
case let .success(payload):
|
||||
switch payload.data {
|
||||
case let .success(result: result):
|
||||
promise(.success(result))
|
||||
case .error:
|
||||
promise(.failure(.unknown))
|
||||
}
|
||||
case .failure:
|
||||
promise(.failure(.unknown))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.receive(on: DispatchQueue.main)
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
}
|
||||
|
|
@ -15,16 +15,3 @@ let highlightSelection = Selection.Highlight {
|
|||
createdByMe: try $0.createdByMe()
|
||||
)
|
||||
}
|
||||
|
||||
let highlightDepSelection = 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()
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,32 +0,0 @@
|
|||
import Combine
|
||||
import CoreData
|
||||
import Foundation
|
||||
import Models
|
||||
|
||||
// TODO: possibly remove this file?
|
||||
public extension DataService {
|
||||
func cachedHighlights(pdfID: String) -> [HighlightDep] {
|
||||
let fetchRequest: NSFetchRequest<Models.Highlight> = Highlight.fetchRequest()
|
||||
fetchRequest.predicate = NSPredicate(
|
||||
format: "linkedItemId == %@ AND markedForDeletion == %@", pdfID, false
|
||||
)
|
||||
|
||||
let highlights = (try? persistentContainer.viewContext.fetch(fetchRequest)) ?? []
|
||||
return highlights.map { HighlightDep.make(from: $0) }
|
||||
}
|
||||
|
||||
func persistHighlight(pdfID: String, highlight: HighlightDep) {
|
||||
_ = highlight.toManagedObject(
|
||||
context: persistentContainer.viewContext,
|
||||
associatedItemID: pdfID
|
||||
)
|
||||
|
||||
do {
|
||||
try persistentContainer.viewContext.save()
|
||||
print("Highlight saved succesfully")
|
||||
} catch {
|
||||
persistentContainer.viewContext.rollback()
|
||||
print("Failed to save Highlight: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -301,10 +301,10 @@ import Utils
|
|||
}
|
||||
|
||||
private func applyHighlights(documentProvider: PDFDocumentProvider) {
|
||||
viewModel.loadHighlights { [weak self] highlights in
|
||||
viewModel.loadHighlights { [weak self] highlightPatches in
|
||||
var annnotations: [Annotation] = []
|
||||
for highlight in highlights {
|
||||
guard let data = highlight.patch.data(using: String.Encoding.utf8) else { continue }
|
||||
for patch in highlightPatches {
|
||||
guard let data = patch.data(using: String.Encoding.utf8) else { continue }
|
||||
let annotation = try? Annotation(fromInstantJSON: data, documentProvider: documentProvider)
|
||||
guard let annotation = annotation else { continue }
|
||||
annnotations.append(annotation)
|
||||
|
|
|
|||
Loading…
Reference in a new issue