Skip to content

Commit

Permalink
Create parent for item that has its metadata retrieved
Browse files Browse the repository at this point in the history
  • Loading branch information
mvasilak committed Feb 17, 2025
1 parent 62fdc7e commit d59b444
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 16 deletions.
4 changes: 3 additions & 1 deletion ZShare/View Controllers/ShareViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -749,7 +749,9 @@ final class ShareViewController: UIViewController {
pdfWorkerController: pdfWorkerController,
apiClient: apiClient,
translatorsController: translatorsController,
schemaController: schemaController
schemaController: schemaController,
dbStorage: dbStorage,
dateParser: dateParser
)
recognizerController.webViewProvider = self

Expand Down
5 changes: 4 additions & 1 deletion ZShare/ViewModels/ExtensionViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,7 @@ final class ExtensionViewModel {
}

func recognize(file: FileData) {
recognizerController.queue(task: RecognizerController.RecognizerTask(file: file)) { [weak self] observable in
recognizerController.queue(task: RecognizerController.RecognizerTask(file: file, kind: .simple)) { [weak self] observable in
guard let self else { return }
observable?.subscribe { [weak self] update in
guard let self else { return }
Expand All @@ -561,6 +561,9 @@ final class ExtensionViewModel {
// attachment is only used to get an optional URL, so we can safely pass an empty dictionary
state.processedAttachment = .itemWithAttachment(item: item, attachment: [:], attachmentFile: file)
self.state = state

case .createdParent:
break
}
}
.disposed(by: disposeBag)
Expand Down
4 changes: 3 additions & 1 deletion Zotero/Controllers/Controllers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,9 @@ final class UserControllers {
pdfWorkerController: pdfWorkerController,
apiClient: controllers.apiClient,
translatorsController: controllers.translatorsAndStylesController,
schemaController: controllers.schemaController
schemaController: controllers.schemaController,
dbStorage: dbStorage,
dateParser: controllers.dateParser
)
self.webSocketController = webSocketController
self.fileCleanupController = fileCleanupController
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,17 @@ import Foundation
import CocoaLumberjackSwift
import RealmSwift

struct CreateTranslatedItemsDbRequest: DbRequest {
struct CreateTranslatedItemsDbRequest: DbResponseRequest {
typealias Response = [RItem]

let responses: [ItemResponse]
unowned let schemaController: SchemaController
unowned let dateParser: DateParser

var needsWrite: Bool { return true }

func process(in database: Realm) throws {
func process(in database: Realm) throws -> [RItem] {
var items: [RItem] = []
for response in self.responses {
let (item, _) = try StoreItemDbRequest(
response: response,
Expand Down Expand Up @@ -48,6 +51,9 @@ struct CreateTranslatedItemsDbRequest: DbRequest {
changes.insert(.tags)
}
item.changes.append(RObjectChange.create(changes: changes))

items.append(item)
}
return items
}
}
2 changes: 1 addition & 1 deletion Zotero/Controllers/IdentifierLookupController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ final class IdentifierLookupController {

func storeDataAndDownloadAttachmentIfNecessary(identifier: String, response: ItemResponse, attachments: [(Attachment, URL)]) throws {
let request = CreateTranslatedItemsDbRequest(responses: [response], schemaController: schemaController, dateParser: dateParser)
try dbStorage.perform(request: request, on: backgroundQueue)
_ = try dbStorage.perform(request: request, on: backgroundQueue)
changeLookup(
for: identifier,
to: .translated(.init(response: response, attachments: attachments, libraryId: libraryId, collectionKeys: collectionKeys))
Expand Down
66 changes: 60 additions & 6 deletions Zotero/Controllers/RecognizerController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,13 @@ final class RecognizerController {
}

struct RecognizerTask: Hashable {
enum Kind: Hashable {
case simple
case createParentForItem(libraryId: LibraryIdentifier, key: String)
}

let file: FileData
let kind: Kind
}

enum Error: Swift.Error {
Expand All @@ -83,6 +89,7 @@ final class RecognizerController {
case remoteRecognizerFailed
case noRemainingIdentifiersForLookup
case unexpectedState
case cantCreateParentForItem
}

struct Update {
Expand All @@ -93,6 +100,7 @@ final class RecognizerController {
case remoteRecognitionInProgress(data: [String: Any])
case identifierLookupInProgress(response: RemoteRecognizerResponse, identifier: String)
case translated(item: ItemResponse)
case createdParent(key: String)
}

let task: RecognizerTask
Expand All @@ -111,9 +119,12 @@ final class RecognizerController {
private unowned let apiClient: ApiClient
private unowned let translatorsController: TranslatorsAndStylesController
private unowned let schemaController: SchemaController
private unowned let dbStorage: DbStorage
private unowned let dateParser: DateParser
private let dispatchSpecificKey: DispatchSpecificKey<String>
private let accessQueueLabel: String
private let accessQueue: DispatchQueue
private let backgroundQueue: DispatchQueue
private let disposeBag: DisposeBag

internal weak var webViewProvider: WebViewProvider?
Expand All @@ -124,15 +135,26 @@ final class RecognizerController {
private var lookupWebViewHandlersByRecognizerTask: [RecognizerTask: LookupWebViewHandler] = [:]

// MARK: Object Lifecycle
init(pdfWorkerController: PDFWorkerController, apiClient: ApiClient, translatorsController: TranslatorsAndStylesController, schemaController: SchemaController) {
init(
pdfWorkerController: PDFWorkerController,
apiClient: ApiClient,
translatorsController: TranslatorsAndStylesController,
schemaController: SchemaController,
dbStorage: DbStorage,
dateParser: DateParser
) {
self.pdfWorkerController = pdfWorkerController
self.apiClient = apiClient
self.translatorsController = translatorsController
self.schemaController = schemaController
self.dbStorage = dbStorage
self.dateParser = dateParser
dispatchSpecificKey = DispatchSpecificKey<String>()
accessQueueLabel = "org.zotero.RecognizerController.accessQueue"
accessQueue = DispatchQueue(label: accessQueueLabel, qos: .userInteractive, attributes: .concurrent)
accessQueue.setSpecific(key: dispatchSpecificKey, value: accessQueueLabel)
backgroundQueue = DispatchQueue(label: "org.zotero.RecognizerController.backgroundQueue", qos: .userInitiated)

disposeBag = DisposeBag()
}

Expand Down Expand Up @@ -412,9 +434,7 @@ final class RecognizerController {
if copyTagsAsAutomatic, !itemResponse.tags.isEmpty {
itemResponse = itemResponse.copyWithAutomaticTags
}
cleanupTask(for: task) { observable in
observable?.on(.next(Update(task: task, kind: .translated(item: itemResponse))))
}
createParentIfNeeded(for: task, with: itemResponse, schemaController: schemaController, dateParser: dateParser)
}

case .failure(let error):
Expand Down Expand Up @@ -470,8 +490,42 @@ final class RecognizerController {
rects: nil,
paths: nil
)
cleanupTask(for: task) { observable in
observable?.on(.next(Update(task: task, kind: .translated(item: itemResponse))))
createParentIfNeeded(for: task, with: itemResponse, schemaController: schemaController, dateParser: dateParser)
}

func createParentIfNeeded(for task: RecognizerTask, with itemResponse: ItemResponse, schemaController: SchemaController, dateParser: DateParser) {
switch task.kind {
case .simple:
cleanupTask(for: task) { observable in
observable?.on(.next(Update(task: task, kind: .translated(item: itemResponse))))
}

case .createParentForItem(let libraryId, let key):
backgroundQueue.async { [weak self] in
guard let self else { return }
let response = itemResponse.copy(libraryId: libraryId, collectionKeys: [], tags: [])
var update: Update?
do {
try dbStorage.perform(on: backgroundQueue) { coordinator in
let items = try coordinator.perform(request: CreateTranslatedItemsDbRequest(responses: [response], schemaController: schemaController, dateParser: dateParser))
guard let parent = items.first else {
update = Update(task: task, kind: .failed(.cantCreateParentForItem))
return
}
try coordinator.perform(request: MoveItemsToParentDbRequest(itemKeys: [key], parentKey: parent.key, libraryId: libraryId))
update = Update(task: task, kind: .createdParent(key: parent.key))
coordinator.invalidate()
}
} catch let error {
DDLogError("RecognizerController: can't create parent for item - \(error)")
update = Update(task: task, kind: .failed(error as! Error))
}
cleanupTask(for: task) { observable in
if let update {
observable?.on(.next(update))
}
}
}
}
}
}
Expand Down
7 changes: 3 additions & 4 deletions Zotero/Scenes/Detail/Items/Views/ItemsViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -172,11 +172,10 @@ final class ItemsViewController: BaseItemsViewController {
file.mimeType == "application/pdf",
let recognizerController = controllers.userControllers?.recognizerController
else { return }
recognizerController.queue(task: RecognizerController.RecognizerTask(file: file)) { [weak self] observable in
recognizerController.queue(task: RecognizerController.RecognizerTask(file: file, kind: .createParentForItem(libraryId: library.identifier, key: key))) { [weak self] observable in
guard let self else { return }
observable?.subscribe { update in
// TODO: Implement
print("Recognizer controller update: \(update)")
observable?.subscribe { _ in
// TODO: Implement update of UI according to updates
}
.disposed(by: disposeBag)
}
Expand Down

0 comments on commit d59b444

Please sign in to comment.