Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Option to download files at sync time #863

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ZShare/ViewModels/ExtensionViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1780,7 +1780,7 @@ final class ExtensionViewModel {
self.state = state
} catch let error {
DDLogError("ExtensionViewModel: can't load collections - \(error)")
let library = Library(identifier: ExtensionViewModel.defaultLibraryId, name: RCustomLibraryType.myLibrary.libraryName, metadataEditable: true, filesEditable: true)
let library = Library(identifier: ExtensionViewModel.defaultLibraryId, name: RCustomLibraryType.myLibrary.libraryName, metadataEditable: true, filesEditable: true, fileSyncType: .asNeeded)
self.state.collectionPickerState = .picked(library, nil)
}
}
Expand Down
20 changes: 20 additions & 0 deletions Zotero.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -962,8 +962,14 @@
B3BD86BC258CBCD600EF6674 /* SearchBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3BD86BB258CBCD600EF6674 /* SearchBar.swift */; };
B3BF7EE728A51BDC00A5A659 /* DeleteTagFromItemDbRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3BF7EE628A51BDC00A5A659 /* DeleteTagFromItemDbRequest.swift */; };
B3BF7EE928A51EDA00A5A659 /* EditTagsForItemDbRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3BF7EE828A51EDA00A5A659 /* EditTagsForItemDbRequest.swift */; };
B3C176892B69007D00222CBA /* LibraryFileSyncType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3C176882B69007D00222CBA /* LibraryFileSyncType.swift */; };
B3C1768A2B6900E100222CBA /* LibraryFileSyncType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3C176882B69007D00222CBA /* LibraryFileSyncType.swift */; };
B3C1768C2B690CBA00222CBA /* FileDownloadSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3C1768B2B690CBA00222CBA /* FileDownloadSettingsView.swift */; };
B3C1768E2B692FDC00222CBA /* EditLibrarySyncTypeDbRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3C1768D2B692FDC00222CBA /* EditLibrarySyncTypeDbRequest.swift */; };
B3C43C2028589F300007076D /* NotePreviewGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3C43C1F28589F300007076D /* NotePreviewGenerator.swift */; };
B3C43C212858A84A0007076D /* NotePreviewGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3C43C1F28589F300007076D /* NotePreviewGenerator.swift */; };
B3C58A642B91D78700A5C91F /* ReadAttachmentItemsNotInArrayDbRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3C58A632B91D78700A5C91F /* ReadAttachmentItemsNotInArrayDbRequest.swift */; };
B3C58A652B91D82600A5C91F /* ReadAttachmentItemsNotInArrayDbRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3C58A632B91D78700A5C91F /* ReadAttachmentItemsNotInArrayDbRequest.swift */; };
B3C6AB28248E1B720009AC96 /* SyncBatchProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3C6AB27248E1B720009AC96 /* SyncBatchProcessor.swift */; };
B3C6AB2B248E3EB90009AC96 /* ApiOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3C6AB2A248E3EB90009AC96 /* ApiOperation.swift */; };
B3C6AB2D248E3F840009AC96 /* AsynchronousOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3C6AB2C248E3F840009AC96 /* AsynchronousOperation.swift */; };
Expand Down Expand Up @@ -1940,7 +1946,11 @@
B3BD86BB258CBCD600EF6674 /* SearchBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchBar.swift; sourceTree = "<group>"; };
B3BF7EE628A51BDC00A5A659 /* DeleteTagFromItemDbRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeleteTagFromItemDbRequest.swift; sourceTree = "<group>"; };
B3BF7EE828A51EDA00A5A659 /* EditTagsForItemDbRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditTagsForItemDbRequest.swift; sourceTree = "<group>"; };
B3C176882B69007D00222CBA /* LibraryFileSyncType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryFileSyncType.swift; sourceTree = "<group>"; };
B3C1768B2B690CBA00222CBA /* FileDownloadSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileDownloadSettingsView.swift; sourceTree = "<group>"; };
B3C1768D2B692FDC00222CBA /* EditLibrarySyncTypeDbRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditLibrarySyncTypeDbRequest.swift; sourceTree = "<group>"; };
B3C43C1F28589F300007076D /* NotePreviewGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotePreviewGenerator.swift; sourceTree = "<group>"; };
B3C58A632B91D78700A5C91F /* ReadAttachmentItemsNotInArrayDbRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadAttachmentItemsNotInArrayDbRequest.swift; sourceTree = "<group>"; };
B3C6AB27248E1B720009AC96 /* SyncBatchProcessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncBatchProcessor.swift; sourceTree = "<group>"; };
B3C6AB2A248E3EB90009AC96 /* ApiOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiOperation.swift; sourceTree = "<group>"; };
B3C6AB2C248E3F840009AC96 /* AsynchronousOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsynchronousOperation.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2355,6 +2365,7 @@
B3863FCB2AD830F0005082F0 /* EditCreatorItemDetailDbRequest.swift */,
B32861E528BFACD4007B5A5C /* EditItemFieldsDbRequest.swift */,
B305644923FC051E003304F2 /* EditItemFromDetailDbRequest.swift */,
B3C1768D2B692FDC00222CBA /* EditLibrarySyncTypeDbRequest.swift */,
B305644D23FC051E003304F2 /* EditNoteDbRequest.swift */,
B3BF7EE828A51EDA00A5A659 /* EditTagsForItemDbRequest.swift */,
B3863FCF2AD83698005082F0 /* EditTypeItemDetailDbRequest.swift */,
Expand Down Expand Up @@ -2390,6 +2401,7 @@
B34341AA260A48A200093E63 /* ReadAllWritableGroupsDbRequest.swift */,
B31EEE5924EBD18200E3B3AD /* ReadAnnotationsDbRequest.swift */,
B305646523FC051E003304F2 /* ReadAnyChangedObjectsInLibraryDbRequest.swift */,
B3C58A632B91D78700A5C91F /* ReadAttachmentItemsNotInArrayDbRequest.swift */,
B305644523FC051E003304F2 /* ReadAttachmentUploadsDbRequest.swift */,
B3F55A1829EED4CB00A6716E /* ReadAutomaticTagsDbRequest.swift */,
B3EBC9B0283E392900286A9E /* ReadBaseTagsToDeleteDbRequest.swift */,
Expand Down Expand Up @@ -2639,6 +2651,7 @@
B3CBB122248A44D100C4228F /* KeyboardData.swift */,
B305653823FC051E003304F2 /* KeyedResponse.swift */,
B305653923FC051E003304F2 /* Library.swift */,
B3C176882B69007D00222CBA /* LibraryFileSyncType.swift */,
B341C8CA25CBFAD3005562E5 /* LibraryIdentifier.swift */,
B361A3002511F98700271173 /* LinkMode.swift */,
B3E44641248FBE9B007FE8AB /* LinkType.swift */,
Expand Down Expand Up @@ -4132,6 +4145,7 @@
B3E8FE8427143BDD00F51458 /* Views */ = {
isa = PBXGroup;
children = (
B3C1768B2B690CBA00222CBA /* FileDownloadSettingsView.swift */,
B3E8FE8527143BDD00F51458 /* SyncSettingsView.swift */,
);
path = Views;
Expand Down Expand Up @@ -4867,6 +4881,7 @@
B34A73002670C9ED00A7B186 /* SyncRepoResponseDbRequest.swift in Sources */,
B30566A823FC051F003304F2 /* Convertible.swift in Sources */,
B3868540270DC3AA0068A022 /* WebDavScheme.swift in Sources */,
B3C1768C2B690CBA00222CBA /* FileDownloadSettingsView.swift in Sources */,
B3B953CA245981AD00FC96DB /* PDFReaderAction.swift in Sources */,
B3229FD328C0A09200DAF3B7 /* EditAnnotationPathsDbRequest.swift in Sources */,
B3231334243F0F0000F1905A /* SceneDelegate.swift in Sources */,
Expand All @@ -4890,6 +4905,7 @@
B3BF7EE928A51EDA00A5A659 /* EditTagsForItemDbRequest.swift in Sources */,
B30565D223FC051E003304F2 /* ReadCollectionsDbRequest.swift in Sources */,
B3E8FE2F271429C300F51458 /* ExportLocale.swift in Sources */,
B3C1768E2B692FDC00222CBA /* EditLibrarySyncTypeDbRequest.swift in Sources */,
B3764D9D2574F2DE0024274F /* ColorPickerCircleView.swift in Sources */,
B30565C223FC051E003304F2 /* ReadTagPickerTagsDbRequest.swift in Sources */,
B340692224A60D6A009ECE48 /* Rounding+Extensions.swift in Sources */,
Expand Down Expand Up @@ -4961,10 +4977,12 @@
B3C9D60824DA9D40003EA1EE /* CollectionsSearchState.swift in Sources */,
B34DF1B525768BB70019CCD1 /* TextFieldCell.swift in Sources */,
B3593F50241A61C700760E20 /* CollectionsState.swift in Sources */,
B3C58A642B91D78700A5C91F /* ReadAttachmentItemsNotInArrayDbRequest.swift in Sources */,
B3401D5B2567DAAE00BB8D6E /* AnnotationPopoverCoordinator.swift in Sources */,
B39505E82AE9469300F73079 /* AnnotationPopoverState.swift in Sources */,
B3B953D22459B4D800FC96DB /* UITableViewCell+SwiftUI.swift in Sources */,
B353F204242E52610062EE24 /* Database.swift in Sources */,
B3C176892B69007D00222CBA /* LibraryFileSyncType.swift in Sources */,
B30565E023FC051E003304F2 /* ReadAnyChangedObjectsInLibraryDbRequest.swift in Sources */,
B30566C023FC051F003304F2 /* DownloadBatch.swift in Sources */,
B305660D23FC051E003304F2 /* AttachmentUploadRequest.swift in Sources */,
Expand Down Expand Up @@ -5631,6 +5649,7 @@
B3593F192668E74800FA4BB2 /* Style.swift in Sources */,
B3CF8830266DFFAF009CFC20 /* ReadStylesDbRequest.swift in Sources */,
B3FC7435272195D600F55531 /* WebDavDeleteRequest.swift in Sources */,
B3C1768A2B6900E100222CBA /* LibraryFileSyncType.swift in Sources */,
B33E8A4327B6768D00CBC7DE /* CollectionTreeBuilder.swift in Sources */,
B32EBFC5276A89360003897E /* URLSessionCreator.swift in Sources */,
B34A73012670CC3300A7B186 /* SyncRepoResponseDbRequest.swift in Sources */,
Expand All @@ -5645,6 +5664,7 @@
B30566E223FC0810003304F2 /* DeletionsRequest.swift in Sources */,
B3100922272C098D003FC743 /* ReadWebDavDeletionsDbRequest.swift in Sources */,
B305673A23FC0938003304F2 /* SyncScheduler.swift in Sources */,
B3C58A652B91D82600A5C91F /* ReadAttachmentItemsNotInArrayDbRequest.swift in Sources */,
B357DEE7241661E300E06153 /* DebugLogging.swift in Sources */,
B305673123FC0923003304F2 /* SubmitUpdateSyncAction.swift in Sources */,
B305670523FC08A8003304F2 /* ReadAllGroupsDbRequest.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ final class AttachmentDownloader: NSObject {
var totalBatchCount = 0
var remainingBatchCount = 0

self.accessQueue.sync { [weak self] in
accessQueue.sync { [weak self] in
guard let self else { return }
progress = batchProgress
remainingBatchCount = queue.count + activeDownloads.count
Expand Down Expand Up @@ -342,10 +342,10 @@ final class AttachmentDownloader: NSObject {

case .importedFile, .importedUrl:
switch location {
case .local:
case .local, .remoteMissing:
break

case .remote, .remoteMissing, .localAndChangedRemotely:
case .remote, .localAndChangedRemotely:
DDLogInfo("AttachmentDownloader: batch download remote\(location == .remoteMissing ? "ly missing" : "") file \(attachment.key)")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
DDLogInfo("AttachmentDownloader: batch download remote\(location == .remoteMissing ? "ly missing" : "") file \(attachment.key)")
DDLogInfo("AttachmentDownloader: batch download remote file \(attachment.key)")

let file = Files.attachmentFile(in: attachment.libraryId, key: attachment.key, filename: filename, contentType: contentType)
let progress = Progress(totalUnitCount: 100)
Expand Down Expand Up @@ -504,7 +504,7 @@ final class AttachmentDownloader: NSObject {
}

func finishExtraction(downloader: AttachmentDownloader) {
self.dbQueue.async { [weak downloader] in
downloader.dbQueue.async { [weak downloader] in
guard let downloader else { return }
do {
let request = MarkFileAsDownloadedDbRequest(key: download.key, libraryId: download.libraryId, downloaded: true, compressed: false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,21 @@ struct ChangedItemsDeletedAlertQueueHandler: ConflictAlertQueueHandler {
let alertAction: ConflictAlertQueueAction
let completion: () -> Void

init(items: [(String, String)], completion: @escaping ([String], [String]) -> Void) {
self.count = items.count
init(conflicts: [PerformItemDeletionsDbRequest.Conflict], completion: @escaping ([String], [String]) -> Void) {
self.count = conflicts.count

var toDelete: [String] = []
var toRestore: [String] = []

self.alertAction = { index, completion in
let (key, title) = items[index]
let controller = UIAlertController(title: L10n.warning, message: L10n.Sync.ConflictResolution.changedItemDeleted(title), preferredStyle: .alert)
let conflict = conflicts[index]
let controller = UIAlertController(title: L10n.warning, message: L10n.Sync.ConflictResolution.changedItemDeleted(conflict.title), preferredStyle: .alert)
controller.addAction(UIAlertAction(title: L10n.restore, style: .default, handler: { _ in
toRestore.append(key)
toRestore.append(conflict.key)
completion()
}))
controller.addAction(UIAlertAction(title: L10n.delete, style: .destructive, handler: { _ in
toDelete.append(key)
toDelete.append(conflict.key)
completion()
}))
return controller
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ struct CreateTranslatedItemsDbRequest: DbRequest {

func process(in database: Realm) throws {
for response in self.responses {
let (item, _) = try StoreItemDbRequest(
let response = try StoreItemDbRequest(
response: response,
schemaController: self.schemaController,
dateParser: self.dateParser,
Expand All @@ -29,25 +29,25 @@ struct CreateTranslatedItemsDbRequest: DbRequest {
)
.process(in: database)

item.changeType = .user
for field in item.fields {
response.item.changeType = .user
for field in response.item.fields {
field.changed = true
}

var changes: RItemChanges = [.type, .fields, .trash, .tags]
if !item.collections.isEmpty {
if !response.item.collections.isEmpty {
changes.insert(.collections)
}
if !item.relations.isEmpty {
if !response.item.relations.isEmpty {
changes.insert(.relations)
}
if !item.creators.isEmpty {
if !response.item.creators.isEmpty {
changes.insert(.creators)
}
if !item.tags.isEmpty {
if !response.item.tags.isEmpty {
changes.insert(.tags)
}
item.changes.append(RObjectChange.create(changes: changes))
response.item.changes.append(RObjectChange.create(changes: changes))
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// EditLibrarySyncTypeDbRequest.swift
// Zotero
//
// Created by Michal Rentka on 30.01.2024.
// Copyright © 2024 Corporation for Digital Scholarship. All rights reserved.
//

import Foundation

import RealmSwift

struct EditLibrarySyncTypeDbRequest: DbRequest {
let identifier: LibraryIdentifier
let syncType: LibraryFileSyncType

var needsWrite: Bool { return true }

func process(in database: Realm) throws {
switch identifier {
case .custom(let type):
guard let library = database.object(ofType: RCustomLibrary.self, forPrimaryKey: type.rawValue) else { return }
library.fileSyncType = syncType

case .group(let groupId):
guard let group = database.object(ofType: RGroup.self, forPrimaryKey: groupId) else { return }
group.fileSyncType = syncType
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,29 @@ struct PerformItemDeletionsDbRequest: DbResponseRequest {
case restoreConflicts
}

typealias Response = [(String, String)]
struct DeletedItem {
let key: String
let parentKey: String?
}

struct Conflict {
let key: String
let title: String
}

typealias Response = ([DeletedItem], [Conflict])

let libraryId: LibraryIdentifier
let keys: [String]
let conflictMode: ConflictResolutionMode

var needsWrite: Bool { return true }

func process(in database: Realm) throws -> [(String, String)] {
func process(in database: Realm) throws -> ([DeletedItem], [Conflict]) {
let objects = database.objects(RItem.self).filter(.keys(keys, in: libraryId))
var conflicts: [(String, String)] = []

var deleted: [DeletedItem] = []
var conflicts: [Conflict] = []

for object in objects {
guard !object.isInvalidated else { continue } // If object is invalidated it has already been removed by some parent before
Expand All @@ -39,7 +51,7 @@ struct PerformItemDeletionsDbRequest: DbResponseRequest {
case .resolveConflicts:
if object.selfOrChildChanged {
// If remotely deleted item is changed locally, we need to show CR, so we return keys of such items
conflicts.append((object.key, object.displayTitle))
conflicts.append(Conflict(key: object.key, title: object.displayTitle))
continue
}

Expand All @@ -53,11 +65,12 @@ struct PerformItemDeletionsDbRequest: DbResponseRequest {
break
}

deleted.append(DeletedItem(key: object.key, parentKey: object.parent?.key))
object.willRemove(in: database)
database.delete(object)
}

return conflicts
return (deleted, conflicts)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,21 @@ import Foundation

import RealmSwift

struct ReadCustomLibrary: DbResponseRequest {
typealias Response = RCustomLibrary

let type: RCustomLibraryType

var needsWrite: Bool { return false }

func process(in database: Realm) throws -> RCustomLibrary {
guard let library = database.objects(RCustomLibrary.self).filter("type == %@", type).first else {
throw DbError.objectNotFound
}
return library
}
}

struct ReadAllCustomLibrariesDbRequest: DbResponseRequest {
typealias Response = Results<RCustomLibrary>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// ReadAttachmentItemsNotInSetDbRequest.swift
// Zotero
//
// Created by Michal Rentka on 01.02.2024.
// Copyright © 2024 Corporation for Digital Scholarship. All rights reserved.
//

import Foundation

import RealmSwift

struct ReadAttachmentItemsNotInArrayDbRequest: DbResponseRequest {
typealias Response = Results<RItem>

let keys: [String]
let libraryId: LibraryIdentifier

var needsWrite: Bool { return false }

func process(in database: Realm) throws -> Results<RItem> {
return database.objects(RItem.self).filter(.allAttachments(for: .custom(.all), libraryId: libraryId)).filter(.key(notIn: keys))
}
}
Loading