use stateobject to keep track of pdf document

This commit is contained in:
Satindar Dhillon 2022-05-22 23:24:37 -07:00
parent 3f68a179c8
commit 11b5dc3172
3 changed files with 121 additions and 93 deletions

View file

@ -8,6 +8,11 @@ import Utils
import Services
struct PDFViewer: View {
final class PDFStateObject: ObservableObject {
@Published var document: Document?
@Published var coordinator: PDFViewCoordinator?
}
@EnvironmentObject var dataService: DataService
struct ShareLink: Identifiable {
@ -16,117 +21,124 @@ import Utils
}
let pdfURL: URL
let document: Document
let viewModel: PDFViewerViewModel
let coordinator: PDFViewCoordinator
@StateObject var pdfStateObject = PDFStateObject()
@State var readerView: Bool = false
@State private var shareLink: ShareLink?
init(remoteURL: URL, viewModel: PDFViewerViewModel) {
self.pdfURL = viewModel.dataURL(remoteURL: remoteURL)
self.viewModel = viewModel
self.document = HighlightedDocument(url: pdfURL, viewModel: viewModel)
self.coordinator = PDFViewCoordinator(document: document, viewModel: viewModel)
}
var body: some View {
PDFView(document: document)
.useParentNavigationBar(true)
.updateConfiguration { builder in
builder.textSelectionShouldSnapToWord = true
}
.updateControllerConfiguration { controller in
print("document is valid", document.isValid)
coordinator.setController(controller: controller, dataService: dataService)
// Disable the Document Editor
controller.navigationItem.setRightBarButtonItems(
[controller.thumbnailsButtonItem],
for: .thumbnails,
animated: false
)
let barButtonItems = [
UIBarButtonItem(
image: UIImage(systemName: "textformat"),
style: .plain,
target: controller.settingsButtonItem.target,
action: controller.settingsButtonItem.action
),
UIBarButtonItem(
image: UIImage(systemName: "book"),
style: .plain,
target: coordinator,
action: #selector(PDFViewCoordinator.toggleReaderView)
),
UIBarButtonItem(
image: UIImage(systemName: "magnifyingglass"),
style: .plain,
target: controller.searchButtonItem.target,
action: controller.searchButtonItem.action
)
]
document.areAnnotationsEnabled = true
coordinator.viewer = self
if viewModel.pdfItem.readingProgressAnchor > 0 {
let pageIndex = UInt(viewModel.pdfItem.readingProgressAnchor)
controller.setPageIndex(pageIndex, animated: false)
if let document = pdfStateObject.document, let coordinator = pdfStateObject.coordinator {
PDFView(document: document)
.useParentNavigationBar(true)
.updateConfiguration { builder in
builder.textSelectionShouldSnapToWord = true
}
.updateControllerConfiguration { controller in
print("document is valid", document.isValid)
coordinator.setController(controller: controller, dataService: dataService)
controller.navigationItem.setRightBarButtonItems(barButtonItems, for: .document, animated: false)
}
.onShouldShowMenuItemsForSelectedText(perform: { pageView, menuItems, selectedText in
let copy = menuItems.first(where: { $0.identifier == "Copy" })
let highlight = MenuItem(title: "Highlight", block: {
_ = self.coordinator.highlightSelection(
pageView: pageView,
selectedText: selectedText,
dataService: dataService
// Disable the Document Editor
controller.navigationItem.setRightBarButtonItems(
[controller.thumbnailsButtonItem],
for: .thumbnails,
animated: false
)
})
let barButtonItems = [
UIBarButtonItem(
image: UIImage(systemName: "textformat"),
style: .plain,
target: controller.settingsButtonItem.target,
action: controller.settingsButtonItem.action
),
UIBarButtonItem(
image: UIImage(systemName: "book"),
style: .plain,
target: coordinator,
action: #selector(PDFViewCoordinator.toggleReaderView)
),
UIBarButtonItem(
image: UIImage(systemName: "magnifyingglass"),
style: .plain,
target: controller.searchButtonItem.target,
action: controller.searchButtonItem.action
)
]
document.areAnnotationsEnabled = true
coordinator.viewer = self
if viewModel.pdfItem.readingProgressAnchor > 0 {
let pageIndex = UInt(viewModel.pdfItem.readingProgressAnchor)
controller.setPageIndex(pageIndex, animated: false)
}
controller.navigationItem.setRightBarButtonItems(barButtonItems, for: .document, animated: false)
}
.onShouldShowMenuItemsForSelectedText(perform: { pageView, menuItems, selectedText in
let copy = menuItems.first(where: { $0.identifier == "Copy" })
let highlight = MenuItem(title: "Highlight", block: {
_ = coordinator.highlightSelection(
pageView: pageView,
selectedText: selectedText,
dataService: dataService
)
})
// let share = MenuItem(title: "Share", block: {
// let shortId = self.coordinator.highlightSelection(pageView: pageView, selectedText: selectedText)
// if let shareURL = viewModel.highlightShareURL(shortId: shortId) {
// shareLink = ShareLink(id: UUID(), url: shareURL)
// }
// })
return [copy, highlight /* , share */ ].compactMap { $0 }
})
.onShouldShowMenuItemsForSelectedAnnotations(perform: { _, menuItems, annotations in
var result = [MenuItem]()
if let copy = menuItems.first(where: { $0.identifier == "Copy" }) {
result.append(copy)
}
let remove = MenuItem(title: "Remove", block: {
self.coordinator.remove(dataService: dataService, annotations: annotations)
return [copy, highlight /* , share */ ].compactMap { $0 }
})
result.append(remove)
.onShouldShowMenuItemsForSelectedAnnotations(perform: { _, menuItems, annotations in
var result = [MenuItem]()
if let copy = menuItems.first(where: { $0.identifier == "Copy" }) {
result.append(copy)
}
let highlights = annotations?.compactMap { $0 as? HighlightAnnotation }
let shortId = highlights.flatMap { coordinator.shortHighlightIds($0).first }
if let shortId = shortId, FeatureFlag.enableShareButton {
let share = MenuItem(title: "Share", block: {
if let shareURL = viewModel.highlightShareURL(dataService: dataService, shortId: shortId) {
shareLink = ShareLink(id: UUID(), url: shareURL)
}
let remove = MenuItem(title: "Remove", block: {
coordinator.remove(dataService: dataService, annotations: annotations)
})
result.append(share)
}
result.append(remove)
return result
})
.fullScreenCover(isPresented: $readerView, content: {
PDFReaderViewController(document: document)
})
.accentColor(Color(red: 255 / 255.0, green: 234 / 255.0, blue: 159 / 255.0))
.sheet(item: $shareLink) {
ShareSheet(activityItems: [$0.url])
}
let highlights = annotations?.compactMap { $0 as? HighlightAnnotation }
let shortId = highlights.flatMap { coordinator.shortHighlightIds($0).first }
if let shortId = shortId, FeatureFlag.enableShareButton {
let share = MenuItem(title: "Share", block: {
if let shareURL = viewModel.highlightShareURL(dataService: dataService, shortId: shortId) {
shareLink = ShareLink(id: UUID(), url: shareURL)
}
})
result.append(share)
}
return result
})
.fullScreenCover(isPresented: $readerView, content: {
PDFReaderViewController(document: document)
})
.accentColor(Color(red: 255 / 255.0, green: 234 / 255.0, blue: 159 / 255.0))
.sheet(item: $shareLink) {
ShareSheet(activityItems: [$0.url])
}
} else {
Text("Loading...")
.task {
let document = HighlightedDocument(url: pdfURL, viewModel: viewModel)
pdfStateObject.document = document
pdfStateObject.coordinator = PDFViewCoordinator(document: document, viewModel: viewModel)
}
}
}
class PDFViewCoordinator: NSObject, PDFDocumentViewControllerDelegate, PDFViewControllerDelegate {

View file

@ -11,7 +11,12 @@ struct FeedCardNavigationLink: View {
@ObservedObject var viewModel: HomeFeedViewModel
var body: some View {
let destination = LinkItemDetailView(viewModel: LinkItemDetailViewModel(item: item, pdfItem: PDFItem.make(item: item)))
let destination = LinkItemDetailView(
viewModel: LinkItemDetailViewModel(
linkedItemObjectID: item.objectID,
dataService: dataService
)
)
#if os(iOS)
let modifiedDestination = destination
.navigationTitle("")
@ -50,7 +55,12 @@ struct GridCardNavigationLink: View {
@ObservedObject var viewModel: HomeFeedViewModel
var body: some View {
let destination = LinkItemDetailView(viewModel: LinkItemDetailViewModel(item: item, pdfItem: PDFItem.make(item: item)))
let destination = LinkItemDetailView(
viewModel: LinkItemDetailViewModel(
linkedItemObjectID: item.objectID,
dataService: dataService
)
)
#if os(iOS)
let modifiedDestination = destination
.navigationTitle("")

View file

@ -1,4 +1,5 @@
import Combine
import CoreData
import Models
import Services
import SwiftUI
@ -12,9 +13,14 @@ import Views
var subscriptions = Set<AnyCancellable>()
init(item: LinkedItem?, pdfItem: PDFItem?) {
self.item = item
self.pdfItem = pdfItem
init(linkedItemObjectID: NSManagedObjectID, dataService: DataService) {
if let linkedItem = dataService.viewContext.object(with: linkedItemObjectID) as? LinkedItem {
self.pdfItem = PDFItem.make(item: linkedItem)
self.item = linkedItem
} else {
self.pdfItem = nil
self.item = nil
}
}
func handleArchiveAction(dataService: DataService) {