use core data to track reading progress

This commit is contained in:
Satindar Dhillon 2022-04-25 12:17:27 -07:00
parent 9c7a0d2ee9
commit 9828846222
4 changed files with 49 additions and 75 deletions

View file

@ -75,18 +75,11 @@ public final class PDFViewerViewModel: ObservableObject {
}
public func updateItemReadProgress(percent: Double, anchorIndex: Int) {
services.dataService
.updateArticleReadingProgressPublisher(
itemID: linkedItem.unwrappedID,
readingProgress: percent,
anchorIndex: anchorIndex
)
.sink { completion in
guard case let .failure(error) = completion else { return }
print(error)
} receiveValue: { _ in
}
.store(in: &subscriptions)
services.dataService.updateLinkReadingProgress(
itemID: linkedItem.unwrappedID,
readingProgress: percent,
anchorIndex: anchorIndex
)
}
public func highlightShareURL(shortId: String) -> URL? {

View file

@ -34,19 +34,11 @@ enum PDFProvider {
}
func updateItemReadStatus(dataService: DataService) {
dataService
.updateArticleReadingProgressPublisher(
itemID: item.unwrappedID,
readingProgress: item.isRead ? 0 : 100,
anchorIndex: 0
)
.sink { completion in
guard case let .failure(error) = completion else { return }
print(error)
} receiveValue: { [weak self] readingProgress in
self?.item.readingProgress = readingProgress
}
.store(in: &subscriptions)
dataService.updateLinkReadingProgress(
itemID: item.unwrappedID,
readingProgress: item.isRead ? 0 : 100,
anchorIndex: 0
)
}
func loadWebAppWrapper(dataService: DataService, rawAuthCookie: String?) async {

View file

@ -141,18 +141,8 @@ final class WebReaderViewModel: ObservableObject {
return
}
dataService.updateArticleReadingProgressPublisher(
itemID: itemID,
readingProgress: readingProgress,
anchorIndex: anchorIndex
)
.sink { completion in
guard case .failure = completion else { return }
replyHandler(["result": false], nil)
} receiveValue: { _ in
replyHandler(["result": true], nil)
}
.store(in: &subscriptions)
dataService.updateLinkReadingProgress(itemID: itemID, readingProgress: readingProgress, anchorIndex: anchorIndex)
replyHandler(["result": true], nil)
}
func webViewActionWithReplyHandler(

View file

@ -4,13 +4,29 @@ import Foundation
import Models
import SwiftGraphQL
public extension DataService {
// swiftlint:disable function_body_length
func updateArticleReadingProgressPublisher(
itemID: String,
readingProgress: Double,
anchorIndex: Int
) -> AnyPublisher<Double, SaveArticleError> {
extension DataService {
public func updateLinkReadingProgress(itemID: String, readingProgress: Double, anchorIndex: Int) {
backgroundContext.perform { [weak self] in
guard let self = self else { return }
guard let linkedItem = LinkedItem.lookup(byID: itemID, inContext: self.backgroundContext) else { return }
linkedItem.update(
inContext: self.backgroundContext,
newReadingProgress: readingProgress,
newAnchorIndex: anchorIndex
)
// Send update to server
self.syncLinkReadingProgress(
itemID: linkedItem.unwrappedID,
objectID: linkedItem.objectID,
readingProgress: readingProgress,
anchorIndex: anchorIndex
)
}
}
func syncLinkReadingProgress(itemID: String, objectID: NSManagedObjectID, readingProgress: Double, anchorIndex: Int) {
enum MutationResult {
case saved(readingProgress: Double)
case error(errorCode: Enums.SaveArticleReadingProgressErrorCode)
@ -40,41 +56,24 @@ public extension DataService {
let path = appEnvironment.graphqlPath
let headers = networker.defaultHeaders
let context = backgroundContext
return Deferred {
Future { promise in
send(mutation, to: path, headers: headers) { result in
switch result {
case let .success(payload):
if let graphqlError = payload.errors {
promise(.failure(.unknown(description: graphqlError.first.debugDescription)))
}
send(mutation, to: path, headers: headers) { result in
let data = try? result.get()
let syncStatus: ServerSyncStatus = data == nil ? .needsUpdate : .isNSync
switch payload.data {
case .saved:
if let linkedItem = LinkedItem.lookup(byID: itemID, inContext: self.backgroundContext) {
linkedItem.update(
inContext: self.backgroundContext,
newReadingProgress: readingProgress,
newAnchorIndex: anchorIndex
)
}
promise(.success(readingProgress))
case let .error(errorCode: errorCode):
switch errorCode {
case .unauthorized:
promise(.failure(.unauthorized))
case .badData, .notFound:
promise(.failure(.badData))
}
}
case .failure:
promise(.failure(.badData))
}
context.perform {
guard let linkedItem = context.object(with: objectID) as? LinkedItem else { return }
linkedItem.serverSyncStatus = Int64(syncStatus.rawValue)
do {
try context.save()
logger.debug("LinkedItem updated succesfully")
} catch {
context.rollback()
logger.debug("Failed to update LinkedItem: \(error.localizedDescription)")
}
}
}
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
}
}