mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
Merge pull request #3009 from omnivore-app/fix/ios-force-pdf-reading-position
Force reading position to update on iOS in PDFs
This commit is contained in:
commit
6443da0afc
15 changed files with 757 additions and 712 deletions
|
|
@ -237,13 +237,12 @@ import Utils
|
|||
let pageIndex = Int(event.pageIndex)
|
||||
if let totalPageCount = controller.document?.pageCount {
|
||||
let percent = min(100, max(0, ((Double(pageIndex) + 1.0) / Double(totalPageCount)) * 100.0))
|
||||
if percent > self.viewModel.pdfItem.readingProgress {
|
||||
self.viewModel.updateItemReadProgress(
|
||||
dataService: dataService,
|
||||
percent: percent,
|
||||
anchorIndex: pageIndex
|
||||
)
|
||||
}
|
||||
self.viewModel.updateItemReadProgress(
|
||||
dataService: dataService,
|
||||
percent: percent,
|
||||
anchorIndex: pageIndex,
|
||||
force: true
|
||||
)
|
||||
}
|
||||
}
|
||||
}.store(in: &subscriptions)
|
||||
|
|
|
|||
|
|
@ -76,11 +76,12 @@ final class PDFViewerViewModel: ObservableObject {
|
|||
}
|
||||
}
|
||||
|
||||
func updateItemReadProgress(dataService: DataService, percent: Double, anchorIndex: Int) {
|
||||
func updateItemReadProgress(dataService: DataService, percent: Double, anchorIndex: Int, force: Bool = false) {
|
||||
dataService.updateLinkReadingProgress(
|
||||
itemID: pdfItem.itemID,
|
||||
readingProgress: percent,
|
||||
anchorIndex: anchorIndex
|
||||
anchorIndex: anchorIndex,
|
||||
force: force
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -356,34 +356,11 @@ import Views
|
|||
}
|
||||
|
||||
func markRead(dataService: DataService, item: LinkedItem) {
|
||||
dataService.updateLinkReadingProgress(itemID: item.unwrappedID, readingProgress: 100, anchorIndex: 0)
|
||||
dataService.updateLinkReadingProgress(itemID: item.unwrappedID, readingProgress: 100, anchorIndex: 0, force: true)
|
||||
}
|
||||
|
||||
func markUnread(dataService: DataService, item: LinkedItem) {
|
||||
dataService.updateLinkReadingProgress(itemID: item.unwrappedID, readingProgress: 0, anchorIndex: 0)
|
||||
}
|
||||
|
||||
func snoozeUntil(dataService: DataService, linkId: String, until: Date, successMessage: String?) async {
|
||||
isLoading = true
|
||||
|
||||
if let itemIndex = items.firstIndex(where: { $0.id == linkId }) {
|
||||
items.remove(at: itemIndex)
|
||||
}
|
||||
|
||||
do {
|
||||
try await dataService.createReminder(
|
||||
reminderItemId: .link(id: linkId),
|
||||
remindAt: until
|
||||
)
|
||||
|
||||
if let message = successMessage {
|
||||
snackbar(message)
|
||||
}
|
||||
} catch {
|
||||
NSNotification.operationFailed(message: "Failed to snooze")
|
||||
}
|
||||
|
||||
isLoading = false
|
||||
dataService.updateLinkReadingProgress(itemID: item.unwrappedID, readingProgress: 0, anchorIndex: 0, force: true)
|
||||
}
|
||||
|
||||
private var queryContainsFilter: Bool {
|
||||
|
|
|
|||
|
|
@ -39,7 +39,8 @@ import Views
|
|||
dataService.updateLinkReadingProgress(
|
||||
itemID: itemID,
|
||||
readingProgress: isItemRead ? 0 : 100,
|
||||
anchorIndex: 0
|
||||
anchorIndex: 0,
|
||||
force: false
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -233,7 +233,7 @@ struct WebReaderContainerView: View {
|
|||
)
|
||||
Button(
|
||||
action: {
|
||||
dataService.updateLinkReadingProgress(itemID: item.unwrappedID, readingProgress: 0, anchorIndex: 0)
|
||||
dataService.updateLinkReadingProgress(itemID: item.unwrappedID, readingProgress: 0, anchorIndex: 0, force: true)
|
||||
},
|
||||
label: { Label("Reset Read Location", systemImage: "arrow.counterclockwise.circle") }
|
||||
)
|
||||
|
|
@ -432,7 +432,7 @@ struct WebReaderContainerView: View {
|
|||
#endif
|
||||
.onAppear {
|
||||
if item.isUnread {
|
||||
dataService.updateLinkReadingProgress(itemID: item.unwrappedID, readingProgress: 0.1, anchorIndex: 0)
|
||||
dataService.updateLinkReadingProgress(itemID: item.unwrappedID, readingProgress: 0.1, anchorIndex: 0, force: false)
|
||||
}
|
||||
Task {
|
||||
await audioController.preload(itemIDs: [item.unwrappedID])
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ struct SafariWebLink: Identifiable {
|
|||
return
|
||||
}
|
||||
|
||||
dataService.updateLinkReadingProgress(itemID: itemID, readingProgress: readingProgress, anchorIndex: anchorIndex)
|
||||
dataService.updateLinkReadingProgress(itemID: itemID, readingProgress: readingProgress, anchorIndex: anchorIndex, force: false)
|
||||
replyHandler(["result": true], nil)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -740,7 +740,7 @@
|
|||
let anchorIndex = Int((player?.currentItem as? SpeechPlayerItem)?.speechItem.htmlIdx ?? "") ?? 0
|
||||
|
||||
if let itemID = itemAudioProperties?.itemID {
|
||||
dataService.updateLinkReadingProgress(itemID: itemID, readingProgress: percentProgress, anchorIndex: anchorIndex)
|
||||
dataService.updateLinkReadingProgress(itemID: itemID, readingProgress: percentProgress, anchorIndex: anchorIndex, force: true)
|
||||
}
|
||||
|
||||
if let itemID = itemAudioProperties?.itemID, let player = player, let currentItem = player.currentItem {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,79 +1 @@
|
|||
import Foundation
|
||||
import Models
|
||||
import SwiftGraphQL
|
||||
|
||||
public enum ReminderItemId {
|
||||
case clientRequest(id: String)
|
||||
case link(id: String)
|
||||
|
||||
var linkId: String? {
|
||||
switch self {
|
||||
case .clientRequest:
|
||||
return nil
|
||||
case let .link(id):
|
||||
return id
|
||||
}
|
||||
}
|
||||
|
||||
var clientRequestId: String? {
|
||||
switch self {
|
||||
case .link:
|
||||
return nil
|
||||
case let .clientRequest(id):
|
||||
return id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public extension DataService {
|
||||
func createReminder(
|
||||
reminderItemId: ReminderItemId,
|
||||
remindAt: Date
|
||||
) async throws {
|
||||
enum MutationResult {
|
||||
case complete(id: String)
|
||||
case error(errorCode: Enums.CreateReminderErrorCode)
|
||||
}
|
||||
|
||||
let selection = Selection<MutationResult, Unions.CreateReminderResult> {
|
||||
try $0.on(
|
||||
createReminderError: .init { .error(errorCode: try $0.errorCodes().first ?? .badRequest) },
|
||||
createReminderSuccess: .init {
|
||||
.complete(id: try $0.reminder(selection: Selection.Reminder { try $0.id() }))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
let mutation = Selection.Mutation {
|
||||
try $0.createReminder(
|
||||
input: InputObjects.CreateReminderInput(
|
||||
archiveUntil: true,
|
||||
clientRequestId: OptionalArgument(reminderItemId.clientRequestId),
|
||||
linkId: OptionalArgument(reminderItemId.linkId),
|
||||
remindAt: DateTime(from: remindAt),
|
||||
sendNotification: true
|
||||
),
|
||||
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 .complete:
|
||||
continuation.resume()
|
||||
case let .error(errorCode: errorCode):
|
||||
continuation.resume(throwing: BasicError.message(messageText: errorCode.rawValue))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,13 +4,15 @@ import Models
|
|||
import SwiftGraphQL
|
||||
|
||||
extension DataService {
|
||||
public func updateLinkReadingProgress(itemID: String, readingProgress: Double, anchorIndex: Int) {
|
||||
public func updateLinkReadingProgress(itemID: String, readingProgress: Double, anchorIndex: Int, force: Bool?) {
|
||||
backgroundContext.perform { [weak self] in
|
||||
guard let self = self else { return }
|
||||
guard let linkedItem = LinkedItem.lookup(byID: itemID, inContext: self.backgroundContext) else { return }
|
||||
|
||||
if readingProgress != 0, readingProgress < linkedItem.readingProgress {
|
||||
return
|
||||
if let force = force, !force {
|
||||
if readingProgress != 0, readingProgress < linkedItem.readingProgress {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
print("updating reading progress: ", readingProgress, anchorIndex)
|
||||
|
|
@ -24,12 +26,13 @@ extension DataService {
|
|||
self.syncLinkReadingProgress(
|
||||
itemID: linkedItem.unwrappedID,
|
||||
readingProgress: readingProgress,
|
||||
anchorIndex: anchorIndex
|
||||
anchorIndex: anchorIndex,
|
||||
force: force
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func syncLinkReadingProgress(itemID: String, readingProgress: Double, anchorIndex: Int) {
|
||||
func syncLinkReadingProgress(itemID: String, readingProgress: Double, anchorIndex: Int, force: Bool?) {
|
||||
enum MutationResult {
|
||||
case saved(readAt: Date?)
|
||||
case error(errorCode: Enums.SaveArticleReadingProgressErrorCode)
|
||||
|
|
@ -49,8 +52,9 @@ extension DataService {
|
|||
let mutation = Selection.Mutation {
|
||||
try $0.saveArticleReadingProgress(
|
||||
input: InputObjects.SaveArticleReadingProgressInput(
|
||||
force: OptionalArgument(force),
|
||||
id: itemID,
|
||||
readingProgressAnchorIndex: anchorIndex,
|
||||
readingProgressAnchorIndex: OptionalArgument(anchorIndex),
|
||||
readingProgressPercent: readingProgress
|
||||
),
|
||||
selection: selection
|
||||
|
|
|
|||
|
|
@ -154,7 +154,8 @@ public extension DataService {
|
|||
syncLinkReadingProgress(
|
||||
itemID: item.unwrappedID,
|
||||
readingProgress: item.readingProgress,
|
||||
anchorIndex: Int(item.readingProgressAnchor)
|
||||
anchorIndex: Int(item.readingProgressAnchor),
|
||||
force: item.isPDF
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ extension DataService {
|
|||
createdAt: try $0.createdAt().value ?? Date(),
|
||||
savedAt: try $0.savedAt().value ?? Date(),
|
||||
readAt: try $0.readAt()?.value,
|
||||
updatedAt: try $0.updatedAt().value ?? Date(),
|
||||
updatedAt: try $0.updatedAt()?.value ?? Date(),
|
||||
state: try $0.state()?.rawValue.asArticleContentStatus ?? .succeeded,
|
||||
readingProgress: try $0.readingProgressPercent(),
|
||||
readingProgressAnchor: try $0.readingProgressAnchorIndex(),
|
||||
|
|
|
|||
|
|
@ -258,7 +258,7 @@ private let libraryArticleSelection = Selection.Article {
|
|||
createdAt: try $0.createdAt().value ?? Date(),
|
||||
savedAt: try $0.savedAt().value ?? Date(),
|
||||
readAt: try $0.readAt()?.value,
|
||||
updatedAt: try $0.updatedAt().value ?? Date(),
|
||||
updatedAt: try $0.updatedAt()?.value ?? Date(),
|
||||
state: try $0.state()?.rawValue.asArticleContentStatus ?? .succeeded,
|
||||
readingProgress: try $0.readingProgressPercent(),
|
||||
readingProgressAnchor: try $0.readingProgressAnchorIndex(),
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ public extension DataService {
|
|||
status: try SubscriptionStatus.make(from: $0.status()),
|
||||
unsubscribeHttpUrl: try $0.unsubscribeHttpUrl(),
|
||||
unsubscribeMailTo: try $0.unsubscribeMailTo(),
|
||||
updatedAt: try $0.updatedAt().value,
|
||||
updatedAt: try $0.updatedAt()?.value ?? Date(),
|
||||
url: try $0.url(),
|
||||
icon: try $0.icon()
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import Foundation
|
||||
import Models
|
||||
import SwiftGraphQL
|
||||
|
||||
|
|
@ -22,7 +23,7 @@ let highlightSelection = Selection.Highlight {
|
|||
patch: try $0.patch() ?? "",
|
||||
annotation: try $0.annotation(),
|
||||
createdAt: try $0.createdAt().value,
|
||||
updatedAt: try $0.updatedAt().value,
|
||||
updatedAt: try $0.updatedAt()?.value ?? Date(),
|
||||
createdByMe: try $0.createdByMe(),
|
||||
createdBy: try $0.user(selection: userProfileSelection),
|
||||
positionPercent: try $0.highlightPositionPercent(),
|
||||
|
|
|
|||
Loading…
Reference in a new issue