Skip to content
Merged
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 Brand/Database.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ import Foundation
//
let databaseName = "nextcloud.realm"
let tableAccountBackup = "tableAccountBackup.json"
let databaseSchemaVersion: UInt64 = 422
let databaseSchemaVersion: UInt64 = 423
4 changes: 2 additions & 2 deletions Nextcloud.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -6740,7 +6740,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 12;
CURRENT_PROJECT_VERSION = 13;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = NKUJUXUJ3B;
Expand Down Expand Up @@ -6808,7 +6808,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 12;
CURRENT_PROJECT_VERSION = 13;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = NKUJUXUJ3B;
Expand Down
27 changes: 27 additions & 0 deletions Tests/NextcloudUnitTests/NCAutoUploadDateTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,31 @@ struct NCAutoUploadDateTests {
let decoded = try JSONDecoder().decode(tableAccountCodable.self, from: oldData)
#expect(tableAccount(codableObject: decoded).autoUploadSinceDate == account.autoUploadSinceDate)
}

@Test("Whole-library selection survives backup with a nonempty progress date")
func wholeLibrarySelectionWithProgress() throws {
let account = tableAccount()
account.autoUploadAllPhotos = true
account.autoUploadSinceDate = Date(timeIntervalSince1970: 100)
let data = try JSONEncoder().encode(account.tableAccountToCodable())
let decoded = try JSONDecoder().decode(tableAccountCodable.self, from: data)
let restored = tableAccount(codableObject: decoded)
#expect(restored.autoUploadAllPhotos)
#expect(restored.autoUploadSinceDate == account.autoUploadSinceDate)
}

@Test("Older backups infer the library selection from their existing date")
func previousBackupSelectionCompatibility() throws {
let dates: [Date?] = [nil, Date(timeIntervalSince1970: 100)]
for date in dates {
let account = tableAccount()
account.autoUploadSinceDate = date
let data = try JSONEncoder().encode(account.tableAccountToCodable())
var json = try #require(JSONSerialization.jsonObject(with: data) as? [String: Any])
json.removeValue(forKey: "autoUploadAllPhotos")
let oldData = try JSONSerialization.data(withJSONObject: json)
let decoded = try JSONDecoder().decode(tableAccountCodable.self, from: oldData)
#expect(tableAccount(codableObject: decoded).autoUploadAllPhotos == (date == nil))
}
}
}
20 changes: 20 additions & 0 deletions iOSClient/Data/NCManageDatabase+Account.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class tableAccount: Object {
@objc dynamic var autoUploadWWAnVideo: Bool = false
/// Incremental restart date; nil scans the whole library. Advances only past confirmed uploads.
@objc dynamic var autoUploadSinceDate: Date?
/// Preserves the whole-library selection independently of incremental progress.
@objc dynamic var autoUploadAllPhotos = false
/// Ignores completed uploads from previous sessions while preserving the local history.
@objc dynamic var autoUploadForceReupload = false
@objc dynamic var backend = ""
Expand Down Expand Up @@ -78,6 +80,7 @@ class tableAccount: Object {
autoUploadWWAnPhoto: self.autoUploadWWAnPhoto,
autoUploadWWAnVideo: self.autoUploadWWAnVideo,
autoUploadSinceDate: self.autoUploadSinceDate,
autoUploadAllPhotos: self.autoUploadAllPhotos,
autoUploadForceReupload: self.autoUploadForceReupload,
user: self.user,
userId: self.userId,
Expand All @@ -100,6 +103,7 @@ class tableAccount: Object {
self.autoUploadWWAnPhoto = codableObject.autoUploadWWAnPhoto
self.autoUploadWWAnVideo = codableObject.autoUploadWWAnVideo
self.autoUploadSinceDate = codableObject.autoUploadSinceDate
self.autoUploadAllPhotos = codableObject.autoUploadAllPhotos ?? (codableObject.autoUploadSinceDate == nil)
self.autoUploadForceReupload = codableObject.autoUploadForceReupload ?? false

self.user = codableObject.user
Expand All @@ -123,6 +127,8 @@ struct tableAccountCodable: Codable {
var autoUploadWWAnPhoto: Bool
var autoUploadWWAnVideo: Bool
var autoUploadSinceDate: Date?
// Optional so older backups infer the selection from their restart date.
var autoUploadAllPhotos: Bool?
// Optional so backups written before this setting remain readable.
var autoUploadForceReupload: Bool?

Expand Down Expand Up @@ -397,6 +403,19 @@ extension NCManageDatabase {
guard let current = realm.objects(tableAccount.self).filter("account == %@", account).first,
!current.autoUploadStart else { return }
current.autoUploadSinceDate = date
current.autoUploadAllPhotos = date == nil
}
}

/// Selecting the whole library preserves the date until the next Start.
func setAutoUploadAllPhotosAsync(_ allPhotos: Bool, account: String) async {
await core.performRealmWriteAsync { realm in
guard let current = realm.objects(tableAccount.self).filter("account == %@", account).first,
!current.autoUploadStart else { return }
current.autoUploadAllPhotos = allPhotos
if !allPhotos, current.autoUploadSinceDate == nil {
current.autoUploadSinceDate = Date.now
}
}
}

Expand All @@ -414,6 +433,7 @@ extension NCManageDatabase {
guard let current = accounts.filter("account == %@", account).first else { return }
if enabled, !accounts.filter("autoUploadStart == true AND account != %@", account).isEmpty { return }
if current.autoUploadStart != enabled {
if enabled, current.autoUploadAllPhotos { current.autoUploadSinceDate = nil }
current.autoUploadSessionIdentifier = UUID().uuidString
current.autoUploadStart = enabled
}
Expand Down
8 changes: 8 additions & 0 deletions iOSClient/Data/NCManageDatabaseCore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@ final class NCManageDatabaseCore {
}
}

if oldSchemaVersion < 423 {
migration.enumerateObjects(ofType: tableAccount.className()) { _, newObject in
guard let newObject else { return }
let sinceDate = newObject.value("autoUploadSinceDate", as: Date.self)
newObject.setValueSafely(sinceDate == nil, for: "autoUploadAllPhotos")
}
}

//
// AUTOMATIC / DEFENSIVE MIGRATIONS
//
Expand Down
22 changes: 19 additions & 3 deletions iOSClient/Settings/AutoUpload/NCAutoUploadModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ class NCAutoUploadModel: ObservableObject, ViewOnAppearHandling {
/// The incremental restart date, editable while Auto Upload is stopped.
@Published var autoUploadSinceDate: Date?
@Published var autoUploadForceReupload = false
var autoUploadTimespan: AutoUploadTimespan { autoUploadSinceDate == nil ? .allPhotos : .fromDate }
@Published var autoUploadAllPhotos = false
var autoUploadTimespan: AutoUploadTimespan { autoUploadAllPhotos ? .allPhotos : .fromDate }
/// Whether Photos permissions have been granted or not.
@Published var photosPermissionsGranted = true
/// Whether `Always` location authorization has been granted, enabling background location-based auto upload.
Expand Down Expand Up @@ -96,6 +97,7 @@ class NCAutoUploadModel: ObservableObject, ViewOnAppearHandling {
autoUploadCreateSubfolder = tableAccount.autoUploadCreateSubfolder
autoUploadSubfolderGranularity = Granularity(rawValue: tableAccount.autoUploadSubfolderGranularity) ?? .monthly
autoUploadSinceDate = tableAccount.autoUploadSinceDate
autoUploadAllPhotos = tableAccount.autoUploadAllPhotos
autoUploadForceReupload = tableAccount.autoUploadForceReupload
}

Expand Down Expand Up @@ -154,10 +156,22 @@ class NCAutoUploadModel: ObservableObject, ViewOnAppearHandling {
}
}

/// Starts from the whole library or the current incremental restart date.
/// Changes the selection without discarding progress before Start is pressed.
@MainActor
func handleAutoUploadTimespan(_ timespan: AutoUploadTimespan) {
handleAutoUploadSinceDate(timespan == .allPhotos ? nil : autoUploadSinceDate ?? Date.now)
guard !isChangingAutoUpload, !autoUploadStart else { return }
isChangingAutoUpload = true
let accountIdentifier = session.account
autoUploadAllPhotos = timespan == .allPhotos
let allPhotos = autoUploadAllPhotos
Task {
defer { isChangingAutoUpload = false }
await database.setAutoUploadAllPhotosAsync(allPhotos, account: accountIdentifier)
if let account = await database.getTableAccountAsync(predicate: NSPredicate(format: "account == %@", accountIdentifier)) {
autoUploadSinceDate = account.autoUploadSinceDate
autoUploadAllPhotos = account.autoUploadAllPhotos
}
}
}

/// Saves a new incremental restart date only while Auto Upload is stopped.
Expand All @@ -167,6 +181,7 @@ class NCAutoUploadModel: ObservableObject, ViewOnAppearHandling {
isChangingAutoUpload = true
let accountIdentifier = session.account
autoUploadSinceDate = date
autoUploadAllPhotos = date == nil
Task {
defer { isChangingAutoUpload = false }
await database.setAutoUploadSinceDateAsync(date, account: accountIdentifier)
Expand Down Expand Up @@ -245,6 +260,7 @@ class NCAutoUploadModel: ObservableObject, ViewOnAppearHandling {
return
}

autoUploadSinceDate = updatedAccount.autoUploadSinceDate
// Stop remains available during the legacy initial scan.
isChangingAutoUpload = false
_ = await NCAutoUpload.shared.startManualAutoUploadForAlbums(
Expand Down
4 changes: 2 additions & 2 deletions iOSClient/Settings/AutoUpload/NCAutoUploadView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,7 @@ struct NCAutoUploadView: View {
.accessibilityAddTraits(model.autoUploadTimespan == timespan ? .isSelected : [])
}

if model.autoUploadSinceDate != nil {
if model.autoUploadTimespan == .fromDate {
VStack(alignment: .leading, spacing: 4) {
VStack(alignment: .leading, spacing: 12) {
Text("_autoupload_start_date_")
Expand Down Expand Up @@ -582,7 +582,7 @@ struct NCAutoUploadView: View {
return NSLocalizedString("_autoupload_force_reupload_footer_", comment: "")
}
let destination = model.returnPath()
if model.autoUploadSinceDate != nil {
if model.autoUploadTimespan == .fromDate {
return String(format: NSLocalizedString("_autoupload_date_range_footer_", comment: ""), destination)
}
return String(format: NSLocalizedString("_autoupload_whole_library_description_", comment: ""), destination)
Expand Down
Loading