From 0a6f1598fbeea6144eef845a2072d224b1f0f323 Mon Sep 17 00:00:00 2001 From: Miltiadis Vasilakis Date: Mon, 17 Feb 2025 19:29:10 +0200 Subject: [PATCH] Retrieve metadata and create parent if needed for added files --- .../Requests/CreateAttachmentsDbRequest.swift | 16 +++++++++------- Zotero/Scenes/Detail/DetailCoordinator.swift | 3 ++- .../ViewModels/ItemDetailActionHandler.swift | 2 +- .../Items/ViewModels/ItemsActionHandler.swift | 19 +++++++++++++++++-- .../ViewModels/NoteEditorActionHandler.swift | 2 +- 5 files changed, 30 insertions(+), 12 deletions(-) diff --git a/Zotero/Controllers/Database/Requests/CreateAttachmentsDbRequest.swift b/Zotero/Controllers/Database/Requests/CreateAttachmentsDbRequest.swift index 0506c8173..9a789e76a 100644 --- a/Zotero/Controllers/Database/Requests/CreateAttachmentsDbRequest.swift +++ b/Zotero/Controllers/Database/Requests/CreateAttachmentsDbRequest.swift @@ -12,7 +12,7 @@ import CocoaLumberjackSwift import RealmSwift struct CreateAttachmentsDbRequest: DbResponseRequest { - typealias Response = [(String, String)] + typealias Response = (succeeded: [Attachment], failed: [(String, String)]) let attachments: [Attachment] let parentKey: String? @@ -21,8 +21,8 @@ struct CreateAttachmentsDbRequest: DbResponseRequest { var needsWrite: Bool { return true } - func process(in database: Realm) throws -> [(String, String)] { - guard let libraryId = attachments.first?.libraryId else { return [] } + func process(in database: Realm) throws -> (succeeded: [Attachment], failed: [(String, String)]) { + guard let libraryId = attachments.first?.libraryId else { return ([], []) } let parent = parentKey.flatMap({ database.objects(RItem.self).uniqueObject(key: $0, libraryId: libraryId) }) if let parent = parent { @@ -30,11 +30,12 @@ struct CreateAttachmentsDbRequest: DbResponseRequest { parent.version = parent.version } + var succeeded: [Attachment] = [] var failed: [(String, String)] = [] for attachment in attachments { do { - let attachment = try CreateAttachmentDbRequest( + let item = try CreateAttachmentDbRequest( attachment: attachment, parentKey: nil, localizedType: localizedType, @@ -43,15 +44,16 @@ struct CreateAttachmentsDbRequest: DbResponseRequest { tags: [] ).process(in: database) if let parent = parent { - attachment.parent = parent - attachment.changes.append(RObjectChange.create(changes: RItemChanges.parent)) + item.parent = parent + item.changes.append(RObjectChange.create(changes: RItemChanges.parent)) } + succeeded.append(attachment) } catch let error { DDLogError("CreateAttachmentsDbRequest: could not create attachment - \(error)") failed.append((attachment.key, attachment.title)) } } - return failed + return (succeeded, failed) } } diff --git a/Zotero/Scenes/Detail/DetailCoordinator.swift b/Zotero/Scenes/Detail/DetailCoordinator.swift index b82a8068e..ec1cdfa39 100644 --- a/Zotero/Scenes/Detail/DetailCoordinator.swift +++ b/Zotero/Scenes/Detail/DetailCoordinator.swift @@ -192,7 +192,8 @@ final class DetailCoordinator: Coordinator { citationController: userControllers.citationController, fileCleanupController: userControllers.fileCleanupController, syncScheduler: userControllers.syncScheduler, - htmlAttributedStringConverter: controllers.htmlAttributedStringConverter + htmlAttributedStringConverter: controllers.htmlAttributedStringConverter, + recognizerController: userControllers.recognizerController ) let controller = ItemsViewController(viewModel: ViewModel(initialState: state, handler: handler), controllers: controllers, coordinatorDelegate: self) controller.tagFilterDelegate = itemsTagFilterDelegate diff --git a/Zotero/Scenes/Detail/ItemDetail/ViewModels/ItemDetailActionHandler.swift b/Zotero/Scenes/Detail/ItemDetail/ViewModels/ItemDetailActionHandler.swift index ee93bbe9d..ad5fc97a6 100644 --- a/Zotero/Scenes/Detail/ItemDetail/ViewModels/ItemDetailActionHandler.swift +++ b/Zotero/Scenes/Detail/ItemDetail/ViewModels/ItemDetailActionHandler.swift @@ -528,7 +528,7 @@ final class ItemDetailActionHandler: ViewModelActionHandler, BackgroundDbProcess state.error = .cantAddAttachments(.allFailedCreation) state.attachments.removeAll(where: { attachment in return attachments.contains(where: { $0.key == attachment.key }) }) - case .success(let failed): + case .success(let (_, failed)): guard !failed.isEmpty else { return } state.error = .cantAddAttachments(.someFailedCreation(failed.map({ $0.1 }))) state.attachments.removeAll(where: { attachment in return failed.contains(where: { $0.0 == attachment.key }) }) diff --git a/Zotero/Scenes/Detail/Items/ViewModels/ItemsActionHandler.swift b/Zotero/Scenes/Detail/Items/ViewModels/ItemsActionHandler.swift index 956284f62..b617758fe 100644 --- a/Zotero/Scenes/Detail/Items/ViewModels/ItemsActionHandler.swift +++ b/Zotero/Scenes/Detail/Items/ViewModels/ItemsActionHandler.swift @@ -26,6 +26,7 @@ final class ItemsActionHandler: BaseItemsActionHandler, ViewModelActionHandler { private unowned let fileCleanupController: AttachmentFileCleanupController private unowned let syncScheduler: SynchronizationScheduler private unowned let htmlAttributedStringConverter: HtmlAttributedStringConverter + private unowned let recognizerController: RecognizerController private let disposeBag: DisposeBag init( @@ -37,7 +38,8 @@ final class ItemsActionHandler: BaseItemsActionHandler, ViewModelActionHandler { citationController: CitationController, fileCleanupController: AttachmentFileCleanupController, syncScheduler: SynchronizationScheduler, - htmlAttributedStringConverter: HtmlAttributedStringConverter + htmlAttributedStringConverter: HtmlAttributedStringConverter, + recognizerController: RecognizerController ) { self.fileStorage = fileStorage self.schemaController = schemaController @@ -47,6 +49,7 @@ final class ItemsActionHandler: BaseItemsActionHandler, ViewModelActionHandler { self.fileCleanupController = fileCleanupController self.syncScheduler = syncScheduler self.htmlAttributedStringConverter = htmlAttributedStringConverter + self.recognizerController = recognizerController self.disposeBag = DisposeBag() super.init(dbStorage: dbStorage) } @@ -496,7 +499,19 @@ final class ItemsActionHandler: BaseItemsActionHandler, ViewModelActionHandler { guard let self, let viewModel else { return } switch result { - case .success(let failed): + case .success(let (succeeded, failed)): + for attachment in succeeded { + if let file = attachment.file as? FileData, file.mimeType == "application/pdf" { + let task = RecognizerController.RecognizerTask(file: file, kind: .createParentForItem(libraryId: libraryId, key: attachment.key)) + recognizerController.queue(task: task) { [weak self] observable in + guard let self else { return } + observable?.subscribe { _ in + // TODO: Implement update of UI according to updates + } + .disposed(by: disposeBag) + } + } + } guard !failed.isEmpty else { return } update(viewModel: viewModel) { state in state.error = .attachmentAdding(.someFailed(failed.map({ $0.1 }))) diff --git a/Zotero/Scenes/General/ViewModels/NoteEditorActionHandler.swift b/Zotero/Scenes/General/ViewModels/NoteEditorActionHandler.swift index f3a88df7c..f0f68ecda 100644 --- a/Zotero/Scenes/General/ViewModels/NoteEditorActionHandler.swift +++ b/Zotero/Scenes/General/ViewModels/NoteEditorActionHandler.swift @@ -117,7 +117,7 @@ struct NoteEditorActionHandler: ViewModelActionHandler, BackgroundDbProcessingAc DDLogInfo("NoteEditorActionHandler: submit \(images.count) images") do { - let failedKeys = try dbStorage.perform(request: request, on: backgroundQueue).map({ $0.0 }) + let failedKeys = try dbStorage.perform(request: request, on: backgroundQueue).1.map({ $0.0 }) let successfulImages = images.filter({ !failedKeys.contains($0.1.key) }).map({ NoteEditorState.CreatedImage(nodeId: $0.0, key: $0.1.key) }) DDLogInfo("NoteEditorActionHandler: successfully created \(successfulImages)") update(viewModel: viewModel) { state in