v0.1: Fixed replies icons
This commit is contained in:
@@ -559,6 +559,7 @@ final class AppState: NSObject, ObservableObject {
|
||||
annotations = []
|
||||
return
|
||||
}
|
||||
hideReplyMarkers(in: document)
|
||||
annotations = AnnotationReader.snapshots(in: document)
|
||||
}
|
||||
|
||||
@@ -854,6 +855,22 @@ final class AppState: NSObject, ObservableObject {
|
||||
pdfView.go(to: selection)
|
||||
}
|
||||
|
||||
private func hideReplyMarkers(in document: PDFDocument) {
|
||||
var changedPages = Set<PDFPage>()
|
||||
|
||||
for pageIndex in 0..<document.pageCount {
|
||||
guard let page = document.page(at: pageIndex) else { continue }
|
||||
for annotation in page.annotations where AnnotationKeys.isReply(annotation) {
|
||||
AnnotationFactory.hideReplyMarker(annotation, on: page)
|
||||
changedPages.insert(page)
|
||||
}
|
||||
}
|
||||
|
||||
for page in changedPages {
|
||||
pdfView?.annotationsChanged(on: page)
|
||||
}
|
||||
}
|
||||
|
||||
private func navigate(to page: PDFPage, pageIndex: Int) {
|
||||
guard let pdfView else { return }
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ final class AcademicPDFView: PDFView {
|
||||
let point = convert(event.locationInWindow, from: nil)
|
||||
|
||||
if let page = page(for: point, nearest: false) {
|
||||
closeNativePopups(on: page)
|
||||
let pagePoint = convert(point, to: page)
|
||||
|
||||
if placementTool != nil {
|
||||
@@ -38,6 +39,14 @@ final class AcademicPDFView: PDFView {
|
||||
|
||||
super.mouseDown(with: event)
|
||||
window?.makeFirstResponder(self)
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let self,
|
||||
let page = self.page(for: point, nearest: false)
|
||||
else {
|
||||
return
|
||||
}
|
||||
self.closeNativePopups(on: page)
|
||||
}
|
||||
}
|
||||
|
||||
override func rightMouseDown(with event: NSEvent) {
|
||||
@@ -116,12 +125,12 @@ final class AcademicPDFView: PDFView {
|
||||
|
||||
private func editableAnnotation(on page: PDFPage, at point: CGPoint) -> PDFAnnotation? {
|
||||
if let direct = page.annotation(at: point),
|
||||
let editable = editableParent(for: direct) {
|
||||
let editable = editableParent(for: direct, on: page) {
|
||||
return editable
|
||||
}
|
||||
|
||||
for annotation in page.annotations.reversed() {
|
||||
guard let editable = editableParent(for: annotation) else { continue }
|
||||
guard let editable = editableParent(for: annotation, on: page) else { continue }
|
||||
|
||||
if annotation.bounds.insetBy(dx: -8, dy: -8).contains(point) {
|
||||
return editable
|
||||
@@ -141,11 +150,27 @@ final class AcademicPDFView: PDFView {
|
||||
return nil
|
||||
}
|
||||
|
||||
private func editableParent(for annotation: PDFAnnotation) -> PDFAnnotation? {
|
||||
private func editableParent(for annotation: PDFAnnotation, on page: PDFPage) -> PDFAnnotation? {
|
||||
if let owner = popupOwner(for: annotation, on: page) {
|
||||
return isEditableAcademicAnnotation(owner) ? owner : nil
|
||||
}
|
||||
|
||||
let parent = AnnotationFactory.parentAnnotation(for: annotation)
|
||||
return isEditableAcademicAnnotation(parent) ? parent : nil
|
||||
}
|
||||
|
||||
private func popupOwner(for annotation: PDFAnnotation, on page: PDFPage) -> PDFAnnotation? {
|
||||
guard AnnotationKeys.annotation(annotation, hasSubtype: .popup) else { return nil }
|
||||
|
||||
if let parent = annotation.value(forAnnotationKey: .parent) as? PDFAnnotation {
|
||||
return parent
|
||||
}
|
||||
|
||||
return page.annotations.first { candidate in
|
||||
candidate.popup === annotation
|
||||
}
|
||||
}
|
||||
|
||||
private func isTextMarkup(_ annotation: PDFAnnotation) -> Bool {
|
||||
AnnotationKeys.annotation(annotation, hasSubtype: .highlight)
|
||||
|| AnnotationKeys.annotation(annotation, hasSubtype: .underline)
|
||||
@@ -166,7 +191,6 @@ final class AcademicPDFView: PDFView {
|
||||
|| AnnotationKeys.annotation(annotation, hasSubtype: .underline)
|
||||
|| AnnotationKeys.annotation(annotation, hasSubtype: .text)
|
||||
|| AnnotationKeys.annotation(annotation, hasSubtype: .freeText)
|
||||
|| AnnotationKeys.annotation(annotation, hasSubtype: .popup)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -206,8 +206,8 @@ public enum AnnotationFactory {
|
||||
?? UUID().uuidString
|
||||
_ = annotation.setValue(parentIdentifier, forAnnotationKey: AnnotationKeys.inReplyTo)
|
||||
_ = annotation.setValue("R", forAnnotationKey: AnnotationKeys.replyType)
|
||||
let popup = makePopupIfNeeded(for: annotation, on: page, open: false)
|
||||
return AnnotationInsertion(page: page, annotation: annotation, popup: popup)
|
||||
hideReplyMarker(annotation, on: page)
|
||||
return AnnotationInsertion(page: page, annotation: annotation, popup: nil)
|
||||
}
|
||||
|
||||
public static func updateComment(
|
||||
@@ -241,6 +241,11 @@ public enum AnnotationFactory {
|
||||
return nil
|
||||
}
|
||||
|
||||
if AnnotationKeys.isReply(annotation) {
|
||||
hideReplyMarker(annotation, on: page)
|
||||
return nil
|
||||
}
|
||||
|
||||
if let popup = annotation.popup {
|
||||
popup.contents = text
|
||||
popup.userName = author
|
||||
@@ -309,6 +314,25 @@ public enum AnnotationFactory {
|
||||
return popup
|
||||
}
|
||||
|
||||
public static func hideReplyMarker(_ annotation: PDFAnnotation, on page: PDFPage) {
|
||||
guard AnnotationKeys.isReply(annotation) else { return }
|
||||
|
||||
let pageBounds = page.bounds(for: .cropBox)
|
||||
annotation.bounds = CGRect(
|
||||
x: pageBounds.maxX + 32,
|
||||
y: pageBounds.maxY + 32,
|
||||
width: 1,
|
||||
height: 1
|
||||
)
|
||||
annotation.shouldDisplay = true
|
||||
annotation.shouldPrint = false
|
||||
|
||||
if let popup = annotation.popup {
|
||||
page.removeAnnotation(popup)
|
||||
annotation.popup = nil
|
||||
}
|
||||
}
|
||||
|
||||
public static func parentAnnotation(for annotation: PDFAnnotation) -> PDFAnnotation {
|
||||
if AnnotationKeys.annotation(annotation, hasSubtype: .popup),
|
||||
let parent = annotation.value(forAnnotationKey: .parent) as? PDFAnnotation {
|
||||
|
||||
@@ -180,7 +180,7 @@ public enum AnnotationKeys {
|
||||
) -> String? {
|
||||
if let parentID = annotation.value(forAnnotationKey: inReplyTo) as? String,
|
||||
!parentID.isEmpty {
|
||||
return parentID
|
||||
return stableIDForAnnotation(named: parentID, in: document) ?? parentID
|
||||
}
|
||||
|
||||
guard let parent = annotation.value(forAnnotationKey: inReplyTo) as? PDFAnnotation else {
|
||||
@@ -199,6 +199,20 @@ public enum AnnotationKeys {
|
||||
return stableID(for: parent, pageIndex: pageIndex, annotationIndex: annotationIndex)
|
||||
}
|
||||
|
||||
private static func stableIDForAnnotation(named name: String, in document: PDFDocument?) -> String? {
|
||||
guard let document else { return nil }
|
||||
|
||||
for pageIndex in 0..<document.pageCount {
|
||||
guard let page = document.page(at: pageIndex) else { continue }
|
||||
for (annotationIndex, candidate) in page.annotations.enumerated() {
|
||||
guard candidate.value(forAnnotationKey: .name) as? String == name else { continue }
|
||||
return stableID(for: candidate, pageIndex: pageIndex, annotationIndex: annotationIndex)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
public static func isReply(_ annotation: PDFAnnotation) -> Bool {
|
||||
annotation.value(forAnnotationKey: inReplyTo) is PDFAnnotation
|
||||
|| annotation.value(forAnnotationKey: inReplyTo) is String
|
||||
|
||||
Reference in New Issue
Block a user