diff --git a/Zotero/Controllers/AnnotationColorGenerator.swift b/Zotero/Controllers/AnnotationColorGenerator.swift index 7522f4ff3..64a77dc50 100644 --- a/Zotero/Controllers/AnnotationColorGenerator.swift +++ b/Zotero/Controllers/AnnotationColorGenerator.swift @@ -11,12 +11,35 @@ import UIKit struct AnnotationColorGenerator { private static let highlightOpacity: CGFloat = 0.5 private static let highlightDarkOpacity: CGFloat = 0.5 + private static let underlineOpacity: CGFloat = 1 + private static let underlineDarkOpacity: CGFloat = 1 - static func color(from color: UIColor, isHighlight: Bool, userInterfaceStyle: UIUserInterfaceStyle) -> (color: UIColor, alpha: CGFloat, blendMode: CGBlendMode?) { - if !isHighlight { + static func color(from color: UIColor, type: AnnotationType?, userInterfaceStyle: UIUserInterfaceStyle) -> (color: UIColor, alpha: CGFloat, blendMode: CGBlendMode?) { + let opacity: CGFloat + switch type { + case .none, .note, .image, .ink, .freeText: return (color, 1, nil) + + case .highlight: + switch userInterfaceStyle { + case .dark: + opacity = Self.highlightDarkOpacity + + default: + opacity = Self.highlightOpacity + } + + case .underline: + switch userInterfaceStyle { + case .dark: + opacity = Self.underlineDarkOpacity + + default: + opacity = Self.underlineOpacity + } } + let adjustedColor: UIColor switch userInterfaceStyle { case .dark: var hue: CGFloat = 0 @@ -27,17 +50,28 @@ struct AnnotationColorGenerator { color.getHue(&hue, saturation: &sat, brightness: &brg, alpha: &alpha) let adjustedSat = min(1, (sat * 1.2)) - let adjustedColor = UIColor(hue: hue, saturation: adjustedSat, brightness: brg, alpha: AnnotationColorGenerator.highlightDarkOpacity) - return (adjustedColor, AnnotationColorGenerator.highlightDarkOpacity, .lighten) + adjustedColor = UIColor(hue: hue, saturation: adjustedSat, brightness: brg, alpha: opacity) default: - let adjustedColor = color.withAlphaComponent(AnnotationColorGenerator.highlightOpacity) - return (adjustedColor, AnnotationColorGenerator.highlightOpacity, .multiply) + adjustedColor = color.withAlphaComponent(opacity) } + + return (adjustedColor, opacity, Self.blendMode(for: userInterfaceStyle, type: type)) } - static func blendMode(for userInterfaceStyle: UIUserInterfaceStyle, isHighlight: Bool) -> CGBlendMode? { - guard isHighlight else { return nil } - return userInterfaceStyle == .dark ? .lighten : .multiply + static func blendMode(for userInterfaceStyle: UIUserInterfaceStyle, type: AnnotationType?) -> CGBlendMode? { + switch type { + case .none, .note, .image, .ink, .freeText: + return nil + + case .highlight, .underline: + switch userInterfaceStyle { + case .dark: + return .lighten + + default: + return .multiply + } + } } } diff --git a/Zotero/Controllers/AnnotationConverter.swift b/Zotero/Controllers/AnnotationConverter.swift index f35ce2aa4..87fd2b90d 100644 --- a/Zotero/Controllers/AnnotationConverter.swift +++ b/Zotero/Controllers/AnnotationConverter.swift @@ -26,7 +26,7 @@ struct AnnotationConverter { /// - returns: Sort index (5 places for page, 6 places for character offset, 5 places for y position) static func sortIndex(from annotation: PSPDFKit.Annotation, boundingBoxConverter: AnnotationBoundingBoxConverter?) -> String { let rect: CGRect - if annotation is PSPDFKit.HighlightAnnotation { + if annotation is PSPDFKit.HighlightAnnotation || annotation is PSPDFKit.UnderlineAnnotation { rect = annotation.rects?.first ?? annotation.boundingBox } else { rect = annotation.boundingBox @@ -243,7 +243,7 @@ struct AnnotationConverter { ) -> PSPDFKit.Annotation { let (color, alpha, blendMode) = AnnotationColorGenerator.color( from: UIColor(hex: zoteroAnnotation.color), - isHighlight: (zoteroAnnotation.type == .highlight), + type: zoteroAnnotation.type, userInterfaceStyle: interfaceStyle ) let annotation: PSPDFKit.Annotation diff --git a/Zotero/Controllers/Database/Requests/SplitAnnotationsDbRequest.swift b/Zotero/Controllers/Database/Requests/SplitAnnotationsDbRequest.swift index d168d2457..a474cec5a 100644 --- a/Zotero/Controllers/Database/Requests/SplitAnnotationsDbRequest.swift +++ b/Zotero/Controllers/Database/Requests/SplitAnnotationsDbRequest.swift @@ -38,7 +38,7 @@ struct SplitAnnotationsDbRequest: DbRequest { guard let annotationType = item.fields.filter(.key(FieldKeys.Item.Annotation.type)).first.flatMap({ AnnotationType(rawValue: $0.value) }) else { return } switch annotationType { - case .highlight: + case .highlight, .underline: let rects = item.rects.map({ CGRect(x: $0.minX, y: $0.minY, width: ($0.maxX - $0.minY), height: ($0.maxY - $0.minY)) }) guard let splitRects = AnnotationSplitter.splitRectsIfNeeded(rects: Array(rects)) else { return } diff --git a/Zotero/Models/AnnotationsConfig.swift b/Zotero/Models/AnnotationsConfig.swift index 754f608f5..ae0765b56 100644 --- a/Zotero/Models/AnnotationsConfig.swift +++ b/Zotero/Models/AnnotationsConfig.swift @@ -13,6 +13,8 @@ import PSPDFKit struct AnnotationsConfig { static let defaultActiveColor = "#ffd400" static let allColors: [String] = ["#ffd400", "#ff6666", "#5fb236", "#2ea8e5", "#a28ae5", "#e56eee", "#f19837", "#aaaaaa", "#000000"] + static let typesWithColorVariation: [AnnotationType?] = [.none, .highlight, .underline] + static let userInterfaceStylesWithVarition: [UIUserInterfaceStyle] = [.light, .dark] static let colorNames: [String: String] = [ "#ffd400": "Yellow", "#ff6666": "Red", @@ -53,16 +55,14 @@ struct AnnotationsConfig { private static func createColorVariationMap() -> [String: String] { var map: [String: String] = [:] - for hexBaseColor in self.allColors { + for hexBaseColor in allColors { let baseColor = UIColor(hex: hexBaseColor) - let color1 = AnnotationColorGenerator.color(from: baseColor, isHighlight: false, userInterfaceStyle: .light).color - map[color1.hexString] = hexBaseColor - let color2 = AnnotationColorGenerator.color(from: baseColor, isHighlight: false, userInterfaceStyle: .dark).color - map[color2.hexString] = hexBaseColor - let color3 = AnnotationColorGenerator.color(from: baseColor, isHighlight: true, userInterfaceStyle: .light).color - map[color3.hexString] = hexBaseColor - let color4 = AnnotationColorGenerator.color(from: baseColor, isHighlight: true, userInterfaceStyle: .dark).color - map[color4.hexString] = hexBaseColor + for type in typesWithColorVariation { + for userInterfaceStyle in userInterfaceStylesWithVarition { + let variation = AnnotationColorGenerator.color(from: baseColor, type: type, userInterfaceStyle: userInterfaceStyle).color + map[variation.hexString] = hexBaseColor + } + } } return map } diff --git a/Zotero/Models/Defaults.swift b/Zotero/Models/Defaults.swift index f2ad55e51..cf4f94859 100644 --- a/Zotero/Models/Defaults.swift +++ b/Zotero/Models/Defaults.swift @@ -200,6 +200,8 @@ final class Defaults { self.squareColorHex = AnnotationsConfig.defaultActiveColor self.noteColorHex = AnnotationsConfig.defaultActiveColor self.highlightColorHex = AnnotationsConfig.defaultActiveColor + self.underlineColorHex = AnnotationsConfig.defaultActiveColor + self.textColorHex = AnnotationsConfig.defaultActiveColor self.pdfSettings = PDFSettings.default #endif } diff --git a/Zotero/Scenes/Detail/PDF/ViewModels/PDFReaderActionHandler.swift b/Zotero/Scenes/Detail/PDF/ViewModels/PDFReaderActionHandler.swift index 504c73178..bbc427f0e 100644 --- a/Zotero/Scenes/Detail/PDF/ViewModels/PDFReaderActionHandler.swift +++ b/Zotero/Scenes/Detail/PDF/ViewModels/PDFReaderActionHandler.swift @@ -279,7 +279,7 @@ final class PDFReaderActionHandler: ViewModelActionHandler, BackgroundDbProcessi let baseColor = annotation.baseColor let (color, alpha, blendMode) = AnnotationColorGenerator.color( from: UIColor(hex: baseColor), - isHighlight: (annotation is PSPDFKit.HighlightAnnotation), + type: annotation.type.annotationType, userInterfaceStyle: interfaceStyle ) annotation.color = color @@ -1155,7 +1155,7 @@ final class PDFReaderActionHandler: ViewModelActionHandler, BackgroundDbProcessi private func addImage(onPage pageIndex: PageIndex, origin: CGPoint, in viewModel: ViewModel) { guard let activeColor = viewModel.state.toolColors[tool(from: .image)] else { return } - let color = AnnotationColorGenerator.color(from: activeColor, isHighlight: false, userInterfaceStyle: viewModel.state.interfaceStyle).color + let color = AnnotationColorGenerator.color(from: activeColor, type: .image, userInterfaceStyle: viewModel.state.interfaceStyle).color let rect = CGRect(origin: origin, size: CGSize(width: 100, height: 100)) let square = SquareAnnotation() @@ -1171,7 +1171,7 @@ final class PDFReaderActionHandler: ViewModelActionHandler, BackgroundDbProcessi private func addNote(onPage pageIndex: PageIndex, origin: CGPoint, in viewModel: ViewModel) { guard let activeColor = viewModel.state.toolColors[tool(from: .note)] else { return } - let color = AnnotationColorGenerator.color(from: activeColor, isHighlight: false, userInterfaceStyle: viewModel.state.interfaceStyle).color + let color = AnnotationColorGenerator.color(from: activeColor, type: .note, userInterfaceStyle: viewModel.state.interfaceStyle).color let rect = CGRect(origin: origin, size: AnnotationsConfig.noteAnnotationSize) let note = NoteAnnotation(contents: "") @@ -1187,7 +1187,7 @@ final class PDFReaderActionHandler: ViewModelActionHandler, BackgroundDbProcessi private func addHighlightOrUnderline(isHighlight: Bool, onPage pageIndex: PageIndex, rects: [CGRect], in viewModel: ViewModel) { guard let activeColor = viewModel.state.toolColors[tool(from: isHighlight ? .highlight : .underline)] else { return } - let (color, alpha, blendMode) = AnnotationColorGenerator.color(from: activeColor, isHighlight: true, userInterfaceStyle: viewModel.state.interfaceStyle) + let (color, alpha, blendMode) = AnnotationColorGenerator.color(from: activeColor, type: isHighlight ? .highlight : .underline, userInterfaceStyle: viewModel.state.interfaceStyle) let annotation = isHighlight ? HighlightAnnotation() : UnderlineAnnotation() annotation.rects = rects @@ -1350,7 +1350,7 @@ final class PDFReaderActionHandler: ViewModelActionHandler, BackgroundDbProcessi } if changes.contains(.color), let (color, interfaceStyle) = color { - let (_color, alpha, blendMode) = AnnotationColorGenerator.color(from: UIColor(hex: color), isHighlight: (annotation.type == .highlight), userInterfaceStyle: interfaceStyle) + let (_color, alpha, blendMode) = AnnotationColorGenerator.color(from: UIColor(hex: color), type: annotation.type, userInterfaceStyle: interfaceStyle) pdfAnnotation.color = _color pdfAnnotation.alpha = alpha if let blendMode { @@ -1458,7 +1458,7 @@ final class PDFReaderActionHandler: ViewModelActionHandler, BackgroundDbProcessi for annotation in annotations { guard let tool = tool(from: annotation), let activeColor = state.toolColors[tool] else { continue } // `AnnotationStateManager` doesn't apply the `blendMode` to created annotations, so it needs to be applied to newly created annotations here. - let (_, _, blendMode) = AnnotationColorGenerator.color(from: activeColor, isHighlight: (annotation is PSPDFKit.HighlightAnnotation), userInterfaceStyle: state.interfaceStyle) + let (_, _, blendMode) = AnnotationColorGenerator.color(from: activeColor, type: annotation.type.annotationType, userInterfaceStyle: state.interfaceStyle) annotation.blendMode = blendMode ?? .normal // Either annotation is new (key not assigned) or the user used undo/redo and we check whether the annotation exists in DB @@ -1468,11 +1468,11 @@ final class PDFReaderActionHandler: ViewModelActionHandler, BackgroundDbProcessi } var workingAnnotation = annotation - if let transformedHighlightAnnotation = transformHighlightRectsIfNeeded(annotation: annotation) { - DDLogInfo("PDFReaderActionHandler: did transform highlight annotation rects") + if let transformedAnnotation = transformHighlightOrUnderlineRectsIfNeeded(annotation: annotation) { + DDLogInfo("PDFReaderActionHandler: did transform highlight/underline annotation rects") toRemove.append(annotation) - toAdd.append(transformedHighlightAnnotation) - workingAnnotation = transformedHighlightAnnotation + toAdd.append(transformedAnnotation) + workingAnnotation = transformedAnnotation } let splitAnnotations = splitIfNeeded(annotation: workingAnnotation) @@ -1495,22 +1495,25 @@ final class PDFReaderActionHandler: ViewModelActionHandler, BackgroundDbProcessi return (keptAsIs, toRemove, toAdd) // TODO: Remove if issues are fixed in PSPDFKit - /// Transforms highlight annotation if needed. + /// Transforms highlight/underline annotation if needed. /// (a) Merges rects that are in the same text line. - /// (b) Trims different line rects that overlap. - /// If not a higlight annotation, or transformations are not needed, it returns nil. + /// (b) Trims different line rects that overlap. (only for highlight annotations) + /// If not a higlight/underline annotation, or transformations are not needed, it returns nil. /// Issue appeared in PSPDFKit 13.5.0 /// - parameter annotation: Annotation to be transformed if needed - func transformHighlightRectsIfNeeded(annotation: PSPDFKit.Annotation) -> PSPDFKit.Annotation? { - guard annotation is HighlightAnnotation, let rects = annotation.rects, rects.count > 1 else { return nil } + func transformHighlightOrUnderlineRectsIfNeeded(annotation: PSPDFKit.Annotation) -> PSPDFKit.Annotation? { + guard annotation is HighlightAnnotation || annotation is UnderlineAnnotation, let rects = annotation.rects, rects.count > 1 else { return nil } + let isHighlight = annotation is HighlightAnnotation var workingRects = rects - workingRects = mergeHighlightRectsIfNeeded(workingRects) - workingRects = trimOverlappingHighlightRectsIfNeeded(workingRects) + workingRects = mergeHighlightOrUnderlineRectsIfNeeded(workingRects) + if isHighlight { + workingRects = trimOverlappingHighlightRectsIfNeeded(workingRects) + } guard workingRects != rects else { return nil } - return copyHighlightAnnotation(from: annotation, with: workingRects) + return copyHighlightOrUnderlineAnnotation(isHighlight: isHighlight, from: annotation, with: workingRects) - func mergeHighlightRectsIfNeeded(_ rects: [CGRect]) -> [CGRect] { - // Check if there are gaps for sequential highlight rects on the same line, and if so transform the annotation to eliminate them. + func mergeHighlightOrUnderlineRectsIfNeeded(_ rects: [CGRect]) -> [CGRect] { + // Check if there are gaps for sequential highlight/underline rects on the same line, and if so transform the annotation to eliminate them. var mergedRects: [CGRect] = [] for rect in rects { guard let previousRect = mergedRects.last, rect.minY == previousRect.minY, rect.height == previousRect.height else { @@ -1547,8 +1550,8 @@ final class PDFReaderActionHandler: ViewModelActionHandler, BackgroundDbProcessi return trimmedRects } - func copyHighlightAnnotation(from annotation: PSPDFKit.Annotation, with rects: [CGRect]) -> HighlightAnnotation { - let newAnnotation = HighlightAnnotation() + func copyHighlightOrUnderlineAnnotation(isHighlight: Bool, from annotation: PSPDFKit.Annotation, with rects: [CGRect]) -> Annotation { + let newAnnotation = isHighlight ? HighlightAnnotation() : UnderlineAnnotation() newAnnotation.rects = rects newAnnotation.boundingBox = AnnotationBoundingBoxCalculator.boundingBox(from: rects) newAnnotation.alpha = annotation.alpha @@ -1564,20 +1567,21 @@ final class PDFReaderActionHandler: ViewModelActionHandler, BackgroundDbProcessi /// - parameter annotation: Annotation to split /// - returns: Array with original annotation if limit was not exceeded. Otherwise array of new split annotations. func splitIfNeeded(annotation: PSPDFKit.Annotation) -> [PSPDFKit.Annotation] { - if let annotation = annotation as? HighlightAnnotation, let rects = annotation.rects, let splitRects = AnnotationSplitter.splitRectsIfNeeded(rects: rects) { - return createAnnotations(from: splitRects, original: annotation) + if annotation is HighlightAnnotation || annotation is UnderlineAnnotation, let rects = annotation.rects, let splitRects = AnnotationSplitter.splitRectsIfNeeded(rects: rects) { + let isHighlight = annotation is HighlightAnnotation + return createHighlightOrUnderlineAnnotations(isHighlight: isHighlight, from: splitRects, original: annotation) } if let annotation = annotation as? InkAnnotation, let paths = annotation.lines, let splitPaths = AnnotationSplitter.splitPathsIfNeeded(paths: paths) { - return createAnnotations(from: splitPaths, original: annotation) + return createInkAnnotations(from: splitPaths, original: annotation) } return [annotation] - func createAnnotations(from splitRects: [[CGRect]], original: HighlightAnnotation) -> [HighlightAnnotation] { + func createHighlightOrUnderlineAnnotations(isHighlight: Bool, from splitRects: [[CGRect]], original: Annotation) -> [Annotation] { guard splitRects.count > 1 else { return [original] } - return splitRects.map { rects -> HighlightAnnotation in - let new = HighlightAnnotation() + return splitRects.map { rects -> Annotation in + let new = isHighlight ? HighlightAnnotation() : UnderlineAnnotation() new.rects = rects new.boundingBox = AnnotationBoundingBoxCalculator.boundingBox(from: rects) new.alpha = original.alpha @@ -1589,7 +1593,7 @@ final class PDFReaderActionHandler: ViewModelActionHandler, BackgroundDbProcessi } } - func createAnnotations(from splitPaths: [[[DrawingPoint]]], original: InkAnnotation) -> [InkAnnotation] { + func createInkAnnotations(from splitPaths: [[[DrawingPoint]]], original: InkAnnotation) -> [InkAnnotation] { guard splitPaths.count > 1 else { return [original] } return splitPaths.map { paths in let new = InkAnnotation(lines: paths) @@ -2352,7 +2356,7 @@ final class PDFReaderActionHandler: ViewModelActionHandler, BackgroundDbProcessi if pdfAnnotation.baseColor != annotation.color { let hexColor = annotation.color - let (color, alpha, blendMode) = AnnotationColorGenerator.color(from: UIColor(hex: hexColor), isHighlight: (annotation.type == .highlight), userInterfaceStyle: interfaceStyle) + let (color, alpha, blendMode) = AnnotationColorGenerator.color(from: UIColor(hex: hexColor), type: annotation.type, userInterfaceStyle: interfaceStyle) pdfAnnotation.color = color pdfAnnotation.alpha = alpha if let blendMode { diff --git a/Zotero/Scenes/Detail/PDF/Views/PDFDocumentViewController.swift b/Zotero/Scenes/Detail/PDF/Views/PDFDocumentViewController.swift index 7ab91fd28..400223bfb 100644 --- a/Zotero/Scenes/Detail/PDF/Views/PDFDocumentViewController.swift +++ b/Zotero/Scenes/Detail/PDF/Views/PDFDocumentViewController.swift @@ -94,9 +94,9 @@ final class PDFDocumentViewController: UIViewController { guard self.viewIfLoaded != nil else { return } coordinator.animate(alongsideTransition: { _ in - // Update highlight selection if needed - if let annotation = self.viewModel.state.selectedAnnotation, let pageIndex = self.pdfController?.pageIndex, let pageView = self.pdfController?.pageViewForPage(at: pageIndex) { - self.updateSelection(on: pageView, annotation: annotation) + // Update highlight/underline selection if needed + if let annotation = self.viewModel.state.selectedAnnotation, let pdfController = self.pdfController { + self.updateSelectionOnVisiblePages(of: pdfController, annotation: annotation) } }, completion: nil) } @@ -162,8 +162,19 @@ final class PDFDocumentViewController: UIViewController { stateManager.setState(annotationTool, variant: nil) - if let color = color { - let (_color, _, blendMode) = AnnotationColorGenerator.color(from: color, isHighlight: (annotationTool == .highlight), userInterfaceStyle: self.viewModel.state.interfaceStyle) + if let color { + let type: AnnotationType? + switch annotationTool { + case .highlight: + type = .highlight + + case .underline: + type = .underline + + default: + type = nil + } + let (_color, _, blendMode) = AnnotationColorGenerator.color(from: color, type: type, userInterfaceStyle: viewModel.state.interfaceStyle) stateManager.drawColor = _color stateManager.blendMode = blendMode ?? .normal } @@ -292,6 +303,12 @@ final class PDFDocumentViewController: UIViewController { case .ink: return .ink + case .underline: + return .underline + + case .freeText: + return .freeText + default: return nil } @@ -420,7 +437,18 @@ final class PDFDocumentViewController: UIViewController { } private func set(color: UIColor, for tool: PSPDFKit.Annotation.Tool, in stateManager: AnnotationStateManager) { - let toolColor = tool == .highlight ? AnnotationColorGenerator.color(from: color, isHighlight: true, userInterfaceStyle: self.viewModel.state.interfaceStyle).color : color + let type: AnnotationType? + switch tool { + case .highlight: + type = .highlight + + case .underline: + type = .underline + + default: + type = nil + } + let toolColor = AnnotationColorGenerator.color(from: color, type: type, userInterfaceStyle: viewModel.state.interfaceStyle).color stateManager.setLastUsedColor(toolColor, annotationString: tool) if stateManager.state == tool { stateManager.drawColor = toolColor @@ -477,11 +505,9 @@ final class PDFDocumentViewController: UIViewController { /// - parameter pageIndex: Page index of page where (de)selection should happen. /// - parameter document: Active `Document` instance. private func select(annotation: PDFAnnotation?, pageIndex: PageIndex, document: PSPDFKit.Document) { - guard let pageView = self.pdfController?.pageViewForPage(at: pageIndex) else { return } - - self.updateSelection(on: pageView, annotation: annotation) + guard let pdfController, let pageView = updateSelectionOnVisiblePages(of: pdfController, annotation: annotation) ?? pdfController.pageViewForPage(at: pageIndex) else { return } - if let annotation = annotation, let pdfAnnotation = document.annotation(on: Int(pageIndex), with: annotation.key) { + if let annotation, let pdfAnnotation = document.annotation(on: Int(pageView.pageIndex), with: annotation.key) { if !pageView.selectedAnnotations.contains(pdfAnnotation) { pageView.selectedAnnotations = [pdfAnnotation] } @@ -500,21 +526,25 @@ final class PDFDocumentViewController: UIViewController { } } - /// Updates `SelectionView` for `PDFPageView` based on selected annotation. - /// - parameter pageView: `PDFPageView` instance for given page. - /// - parameter selectedAnnotation: Selected annotation or `nil` if there is no selection. - private func updateSelection(on pageView: PDFPageView, annotation: PDFAnnotation?) { - // Delete existing custom highlight selection view - if let view = self.selectionView { - view.removeFromSuperview() - } - - guard let selection = annotation, (selection.type == .highlight || selection.type == .underline) && selection.page == Int(pageView.pageIndex) else { return } - // Add custom highlight selection view if needed + /// Updates `SelectionView` for visible `PDFPageView`s of `PDFViewController` based on selected annotation. + /// - parameter pdfController: `PDFViewController` instance for given PDF view controller. + /// - parameter selectedAnnotation: `PDFAnnotation` Selected annotation or `nil` if there is no selection. + /// - returns: Returns the affected`PDFPageView` if a `SelectionView` was added, otherwise `nil` + @discardableResult + private func updateSelectionOnVisiblePages(of pdfController: PDFViewController, annotation: PDFAnnotation?) -> PDFPageView? { + // Delete existing custom highlight/underline selection view + selectionView?.removeFromSuperview() + + guard let selection = annotation, + selection.type == .highlight || selection.type == .underline, + let pageView = pdfController.visiblePageViews.first(where: { $0.pageIndex == PageIndex(selection.page) }) + else { return nil } + // Add custom highlight/underline selection view if needed let frame = pageView.convert(selection.boundingBox(boundingBoxConverter: self), from: pageView.pdfCoordinateSpace) let selectionView = SelectionView(frame: frame) pageView.annotationContainerView.addSubview(selectionView) self.selectionView = selectionView + return pageView } // MARK: - Setups @@ -582,10 +612,9 @@ final class PDFDocumentViewController: UIViewController { builder.showForwardActionButton = false builder.contentMenuConfiguration = ContentMenuConfiguration { $0.annotationToolChoices = { _, _, _, _ in - return [.highlight] + return [.highlight, .underline] } } - builder.freeTextAccessoryViewEnabled = false builder.scrubberBarType = .horizontal // builder.thumbnailBarMode = .scrubberBar builder.markupAnnotationMergeBehavior = .never @@ -785,11 +814,16 @@ extension PDFDocumentViewController: PDFViewControllerDelegate { } case .PSPDFKit.annotate: - let actions = [ - action.replacing(title: L10n.Pdf.highlight, handler: createHighlightActionHandler(for: pageView, in: viewModel)), - UIAction(title: L10n.Pdf.underline, identifier: .underline, handler: createUnderlineActionHandler(for: pageView, in: viewModel)) - ] - return UIMenu(options: [.displayInline], children: actions) + switch action.identifier { + case .pspdfkitAnnotationToolHighlight: + return action.replacing(title: L10n.Pdf.highlight, handler: createHighlightActionHandler(for: pageView, in: viewModel)) + + case .pspdfkitAnnotationToolUnderline: + return action.replacing(title: L10n.Pdf.underline, handler: createUnderlineActionHandler(for: pageView, in: viewModel)) + + default: + return action + } default: return action @@ -799,8 +833,8 @@ extension PDFDocumentViewController: PDFViewControllerDelegate { switch menu.identifier { case .PSPDFKit.annotate: return [ - UIAction(title: L10n.Pdf.highlight, handler: createHighlightActionHandler(for: pageView, in: viewModel)), - UIAction(title: L10n.Pdf.underline, identifier: .underline, handler: createUnderlineActionHandler(for: pageView, in: viewModel)) + UIAction(title: L10n.Pdf.highlight, identifier: .pspdfkitAnnotationToolHighlight, handler: createHighlightActionHandler(for: pageView, in: viewModel)), + UIAction(title: L10n.Pdf.underline, identifier: .pspdfkitAnnotationToolUnderline, handler: createUnderlineActionHandler(for: pageView, in: viewModel)) ] default: @@ -931,9 +965,8 @@ extension PDFDocumentViewController: UIPencilInteractionDelegate { extension PDFDocumentViewController: UIPopoverPresentationControllerDelegate { func popoverPresentationControllerDidDismissPopover(_ popoverPresentationController: UIPopoverPresentationController) { - if self.viewModel.state.selectedAnnotation?.type == .highlight { - self.viewModel.process(action: .deselectSelectedAnnotation) - } + guard let type = viewModel.state.selectedAnnotation?.type, type == .highlight || type == .underline else { return } + viewModel.process(action: .deselectSelectedAnnotation) } } @@ -1122,5 +1155,6 @@ extension UIAction { } extension UIAction.Identifier { - fileprivate static let underline = UIAction.Identifier(rawValue: "org.zotero.menu") + fileprivate static let pspdfkitAnnotationToolHighlight = UIAction.Identifier(rawValue: "com.pspdfkit.action.annotation-tool-Highlight") + fileprivate static let pspdfkitAnnotationToolUnderline = UIAction.Identifier(rawValue: "com.pspdfkit.action.annotation-tool-Underline") }