diff --git a/Zotero/Scenes/Detail/HTML:EPUB/HtmlEpubCoordinator.swift b/Zotero/Scenes/Detail/HTML:EPUB/HtmlEpubCoordinator.swift index fd9aa0c73..22743649c 100644 --- a/Zotero/Scenes/Detail/HTML:EPUB/HtmlEpubCoordinator.swift +++ b/Zotero/Scenes/Detail/HTML:EPUB/HtmlEpubCoordinator.swift @@ -219,7 +219,7 @@ extension HtmlEpubCoordinator: HtmlEpubSidebarCoordinatorDelegate { popoverDelegate: UIPopoverPresentationControllerDelegate, userInterfaceStyle: UIUserInterfaceStyle ) -> PublishSubject? { - guard let currentNavigationController = navigationController, let annotation = viewModel.state.selectedAnnotationKey.flatMap({ viewModel.state.annotations[$0] }) else { return nil } + guard let currentNavigationController = navigationController, let annotation = viewModel.state.annotationPopoverKey.flatMap({ viewModel.state.annotations[$0] }) else { return nil } DDLogInfo("HtmlEpubCoordinator: show annotation popover") diff --git a/Zotero/Scenes/Detail/HTML:EPUB/Models/HtmlEpubReaderAction.swift b/Zotero/Scenes/Detail/HTML:EPUB/Models/HtmlEpubReaderAction.swift index 24db68ba4..257133ae9 100644 --- a/Zotero/Scenes/Detail/HTML:EPUB/Models/HtmlEpubReaderAction.swift +++ b/Zotero/Scenes/Detail/HTML:EPUB/Models/HtmlEpubReaderAction.swift @@ -14,6 +14,7 @@ enum HtmlEpubReaderAction { case deinitialiseReader case deselectAnnotationDuringEditing(String) case deselectSelectedAnnotation + case hideAnnotationPopover case initialiseReader case loadDocument case parseAndCacheComment(key: String, comment: String) @@ -22,9 +23,9 @@ enum HtmlEpubReaderAction { case saveAnnotations([String: Any]) case searchAnnotations(String) case searchDocument(String) - case selectAnnotationDuringEditing(String) - case selectAnnotationFromSidebar(String) - case selectAnnotationFromDocument(key: String, rect: CGRect) + case selectAnnotationDuringEditing(key: String) + case selectAnnotationFromSidebar(key: String) + case selectAnnotationFromDocument(key: String) case setColor(key: String, color: String) case setComment(key: String, comment: NSAttributedString) case setCommentActive(Bool) @@ -33,6 +34,7 @@ enum HtmlEpubReaderAction { case setTags(key: String, tags: [Tag]) case setToolOptions(color: String?, size: CGFloat?, tool: AnnotationTool) case setViewState([String: Any]) + case showAnnotationPopover(key: String, rect: CGRect) case toggleTool(AnnotationTool) case updateAnnotationProperties(key: String, color: String, lineWidth: CGFloat, pageLabel: String, updateSubsequentLabels: Bool, highlightText: String) } diff --git a/Zotero/Scenes/Detail/HTML:EPUB/Models/HtmlEpubReaderState.swift b/Zotero/Scenes/Detail/HTML:EPUB/Models/HtmlEpubReaderState.swift index 8284ed8a5..6a18a280f 100644 --- a/Zotero/Scenes/Detail/HTML:EPUB/Models/HtmlEpubReaderState.swift +++ b/Zotero/Scenes/Detail/HTML:EPUB/Models/HtmlEpubReaderState.swift @@ -26,6 +26,7 @@ struct HtmlEpubReaderState: ViewModelState { static let sidebarEditingSelection = Changes(rawValue: 1 << 7) static let settings = Changes(rawValue: 1 << 8) static let readerInitialised = Changes(rawValue: 1 << 9) + static let popover = Changes(rawValue: 1 << 10) } struct DocumentData { @@ -73,7 +74,11 @@ struct HtmlEpubReaderState: ViewModelState { var annotationSearchTerm: String? var annotationFilter: AnnotationsFilter? var selectedAnnotationKey: String? - var selectedAnnotationRect: CGRect? + var selectedAnnotationCommentActive: Bool + /// Selected annotations when annotations are being edited in sidebar + var selectedAnnotationsDuringEditing: Set + var annotationPopoverKey: String? + var annotationPopoverRect: CGRect? var documentSearchTerm: String? var comments: [String: NSAttributedString] var changes: Changes @@ -86,12 +91,9 @@ struct HtmlEpubReaderState: ViewModelState { var focusSidebarKey: String? /// Annotation key to focus in document var focusDocumentKey: String? - var selectedAnnotationCommentActive: Bool var sidebarEditingEnabled: Bool var notificationToken: NotificationToken? var deletionEnabled: Bool - /// Selected annotations when annotations are being edited in sidebar - var selectedAnnotationsDuringEditing: Set init(url: URL, key: String, settings: HtmlEpubSettings, libraryId: LibraryIdentifier, userId: Int, username: String) { let originalFile = Files.file(from: url) diff --git a/Zotero/Scenes/Detail/HTML:EPUB/ViewModels/HtmlEpubReaderActionHandler.swift b/Zotero/Scenes/Detail/HTML:EPUB/ViewModels/HtmlEpubReaderActionHandler.swift index d9daf9cf0..d41c7a41f 100644 --- a/Zotero/Scenes/Detail/HTML:EPUB/ViewModels/HtmlEpubReaderActionHandler.swift +++ b/Zotero/Scenes/Detail/HTML:EPUB/ViewModels/HtmlEpubReaderActionHandler.swift @@ -70,12 +70,26 @@ final class HtmlEpubReaderActionHandler: ViewModelActionHandler, BackgroundDbPro case .selectAnnotationFromSidebar(let key): update(viewModel: viewModel) { state in - _select(data: (key, nil), didSelectInDocument: false, state: &state) + _select(key: key, didSelectInDocument: false, state: &state) } - case .selectAnnotationFromDocument(let key, let rect): + case .selectAnnotationFromDocument(let key): update(viewModel: viewModel) { state in - _select(data: (key, rect), didSelectInDocument: true, state: &state) + _select(key: key, didSelectInDocument: true, state: &state) + } + + case .showAnnotationPopover(let key, let rect): + update(viewModel: viewModel) { state in + state.annotationPopoverKey = key + state.annotationPopoverRect = rect + state.changes.insert(.popover) + } + + case .hideAnnotationPopover: + update(viewModel: viewModel) { state in + state.annotationPopoverKey = nil + state.annotationPopoverRect = nil + state.changes.insert(.popover) } case .setComment(let key, let comment): @@ -91,7 +105,7 @@ final class HtmlEpubReaderActionHandler: ViewModelActionHandler, BackgroundDbPro case .deselectSelectedAnnotation: update(viewModel: viewModel) { state in - _select(data: nil, didSelectInDocument: false, state: &state) + _select(key: nil, didSelectInDocument: false, state: &state) } case .parseAndCacheComment(key: let key, comment: let comment): @@ -188,7 +202,7 @@ final class HtmlEpubReaderActionHandler: ViewModelActionHandler, BackgroundDbPro if enabled { // Deselect selected annotation before editing - _select(data: nil, didSelectInDocument: false, state: &state) + _select(key: nil, didSelectInDocument: false, state: &state) } else { // Deselect selected annotations during editing state.selectedAnnotationsDuringEditing = [] @@ -365,12 +379,11 @@ final class HtmlEpubReaderActionHandler: ViewModelActionHandler, BackgroundDbPro } } - private func _select(data: (String, CGRect?)?, didSelectInDocument: Bool, state: inout HtmlEpubReaderState) { - guard data?.0 != state.selectedAnnotationKey else { return } + private func _select(key: String?, didSelectInDocument: Bool, state: inout HtmlEpubReaderState) { + guard key != state.selectedAnnotationKey else { return } if let existing = state.selectedAnnotationKey { add(updatedAnnotationKey: existing, state: &state) - if state.selectedAnnotationCommentActive { state.selectedAnnotationCommentActive = false state.changes.insert(.activeComment) @@ -379,21 +392,17 @@ final class HtmlEpubReaderActionHandler: ViewModelActionHandler, BackgroundDbPro state.changes.insert(.selection) - guard let (key, rect) = data else { + guard let key else { state.selectedAnnotationKey = nil - state.selectedAnnotationRect = nil return } state.selectedAnnotationKey = key - state.selectedAnnotationRect = rect - if !didSelectInDocument { state.focusDocumentKey = key } else { state.focusSidebarKey = key } - add(updatedAnnotationKey: key, state: &state) func add(updatedAnnotationKey key: String, state: inout HtmlEpubReaderState) { @@ -792,7 +801,7 @@ final class HtmlEpubReaderActionHandler: ViewModelActionHandler, BackgroundDbPro // Update selection if selectionDeleted { - _select(data: nil, didSelectInDocument: true, state: &state) + _select(key: nil, didSelectInDocument: true, state: &state) } // Disable sidebar editing if there are no results @@ -829,11 +838,6 @@ final class HtmlEpubReaderActionHandler: ViewModelActionHandler, BackgroundDbPro extension RItem { fileprivate var htmlEpubAnnotation: (HtmlEpubAnnotation, [String: Any])? { - let tags = Array(tags.map({ typedTag in - let color: String? = (typedTag.tag?.color ?? "").isEmpty ? nil : typedTag.tag?.color - return Tag(name: typedTag.tag?.name ?? "", color: color ?? "") - })) - var type: AnnotationType? var position: [String: Any] = [:] var text: String? @@ -845,11 +849,8 @@ extension RItem { for field in fields { switch (field.key, field.baseKey) { - case (FieldKeys.Item.Annotation.Position.htmlEpubType, FieldKeys.Item.Annotation.position): - position[FieldKeys.Item.Annotation.Position.htmlEpubType] = field.value - - case (FieldKeys.Item.Annotation.Position.htmlEpubValue, FieldKeys.Item.Annotation.position): - position[FieldKeys.Item.Annotation.Position.htmlEpubValue] = field.value + case (_, FieldKeys.Item.Annotation.position): + position[field.key] = field.value case (FieldKeys.Item.Annotation.type, nil): type = AnnotationType(rawValue: field.value) @@ -882,7 +883,12 @@ extension RItem { return nil } - let json: [String: Any] = [ + let tags = Array(tags.map({ typedTag in + let color: String? = (typedTag.tag?.color ?? "").isEmpty ? nil : typedTag.tag?.color + return Tag(name: typedTag.tag?.name ?? "", color: color ?? "") + })) + + var json: [String: Any] = [ "id": key, "dateCreated": DateFormatter.iso8601WithFractionalSeconds.string(from: dateAdded), "dateModified": DateFormatter.iso8601WithFractionalSeconds.string(from: dateModified), @@ -896,6 +902,10 @@ extension RItem { "position": position, "tags": tags.map({ ["name": $0.name, "color": $0.color] }) ] + for (key, value) in unknown { + json[key] = value + } + let annotation = HtmlEpubAnnotation( key: key, type: type, diff --git a/Zotero/Scenes/Detail/HTML:EPUB/Views/HtmlEpubDocumentViewController.swift b/Zotero/Scenes/Detail/HTML:EPUB/Views/HtmlEpubDocumentViewController.swift index 43e6d759b..63997386d 100644 --- a/Zotero/Scenes/Detail/HTML:EPUB/Views/HtmlEpubDocumentViewController.swift +++ b/Zotero/Scenes/Detail/HTML:EPUB/Views/HtmlEpubDocumentViewController.swift @@ -208,7 +208,7 @@ class HtmlEpubDocumentViewController: UIViewController { switch event { case "onInitialized": - self.viewModel.process(action: .loadDocument) + viewModel.process(action: .loadDocument) case "onSaveAnnotations": guard let params = data["params"] as? [String: Any] else { @@ -225,7 +225,7 @@ class HtmlEpubDocumentViewController: UIViewController { } if params.isEmpty { - viewModel.process(action: .deselectSelectedAnnotation) + viewModel.process(action: .hideAnnotationPopover) return } @@ -236,7 +236,18 @@ class HtmlEpubDocumentViewController: UIViewController { let navigationBarInset = (parentDelegate?.statusBarHeight ?? 0) + (parentDelegate?.navigationBarHeight ?? 0) let rect = CGRect(x: rectArray[0], y: rectArray[1] + navigationBarInset, width: rectArray[2] - rectArray[0], height: rectArray[3] - rectArray[1]) - viewModel.process(action: .selectAnnotationFromDocument(key: key, rect: rect)) + viewModel.process(action: .showAnnotationPopover(key: key, rect: rect)) + + case "onSelectAnnotations": + guard let params = data["params"] as? [String: Any], let ids = params["ids"] as? [String] else { + DDLogWarn("HtmlEpubDocumentViewController: event \(event) missing params - \(message)") + return + } + if let key = ids.first { + viewModel.process(action: .selectAnnotationFromDocument(key: key)) + } else { + viewModel.process(action: .deselectSelectedAnnotation) + } case "onChangeViewState": guard let params = data["params"] as? [String: Any] else { diff --git a/Zotero/Scenes/Detail/HTML:EPUB/Views/HtmlEpubReaderViewController.swift b/Zotero/Scenes/Detail/HTML:EPUB/Views/HtmlEpubReaderViewController.swift index 598791f71..787e40383 100644 --- a/Zotero/Scenes/Detail/HTML:EPUB/Views/HtmlEpubReaderViewController.swift +++ b/Zotero/Scenes/Detail/HTML:EPUB/Views/HtmlEpubReaderViewController.swift @@ -274,7 +274,13 @@ class HtmlEpubReaderViewController: UIViewController, ParentWithSidebarControlle navigationController?.overrideUserInterfaceStyle = state.settings.appearance.userInterfaceStyle } - handleAnnotationPopover() + if state.changes.contains(.popover) { + if let key = state.annotationPopoverKey, let rect = state.annotationPopoverRect { + showPopover(forKey: key, rect: rect) + } else { + hidePopover() + } + } func select(activeTool tool: AnnotationTool?) { if let tool = activeAnnotationTool { @@ -290,21 +296,22 @@ class HtmlEpubReaderViewController: UIViewController, ParentWithSidebarControlle func show(error: HtmlEpubReaderState.Error) { } - func handleAnnotationPopover() { - if let key = state.selectedAnnotationKey { - if !isSidebarVisible, let rect = state.selectedAnnotationRect { - let observable = coordinatorDelegate?.showAnnotationPopover( - viewModel: viewModel, - sourceRect: rect, - popoverDelegate: self, - userInterfaceStyle: viewModel.state.settings.appearance.userInterfaceStyle - ) - observe(key: key, popoverObservable: observable) - } - } else if navigationController?.presentedViewController is AnnotationPopover || - (navigationController?.presentedViewController as? UINavigationController)?.topViewController is AnnotationPopover { - navigationController?.dismiss(animated: true) - } + func showPopover(forKey key: String, rect: CGRect) { + guard !isSidebarVisible else { return } + let observable = coordinatorDelegate?.showAnnotationPopover( + viewModel: viewModel, + sourceRect: rect, + popoverDelegate: self, + userInterfaceStyle: viewModel.state.settings.appearance.userInterfaceStyle + ) + observe(key: key, popoverObservable: observable) + } + + func hidePopover() { + guard navigationController?.presentedViewController is AnnotationPopover || + (navigationController?.presentedViewController as? UINavigationController)?.topViewController is AnnotationPopover + else { return } + navigationController?.dismiss(animated: true) } func observe(key: String, popoverObservable observable: PublishSubject?) { diff --git a/Zotero/Scenes/Detail/HTML:EPUB/Views/HtmlEpubSidebarViewController.swift b/Zotero/Scenes/Detail/HTML:EPUB/Views/HtmlEpubSidebarViewController.swift index 1bbc242f8..057c9670d 100644 --- a/Zotero/Scenes/Detail/HTML:EPUB/Views/HtmlEpubSidebarViewController.swift +++ b/Zotero/Scenes/Detail/HTML:EPUB/Views/HtmlEpubSidebarViewController.swift @@ -419,9 +419,9 @@ extension HtmlEpubSidebarViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { guard let key = dataSource.itemIdentifier(for: indexPath) else { return } if viewModel.state.sidebarEditingEnabled { - viewModel.process(action: .selectAnnotationDuringEditing(key)) + viewModel.process(action: .selectAnnotationDuringEditing(key: key)) } else { - viewModel.process(action: .selectAnnotationFromSidebar(key)) + viewModel.process(action: .selectAnnotationFromSidebar(key: key)) } }