diff --git a/Permanent.xcodeproj/project.pbxproj b/Permanent.xcodeproj/project.pbxproj index 13fc8c72..e95c6010 100644 --- a/Permanent.xcodeproj/project.pbxproj +++ b/Permanent.xcodeproj/project.pbxproj @@ -6014,7 +6014,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 16.1; - MARKETING_VERSION = 1.14.1; + MARKETING_VERSION = 1.14.2; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -6072,7 +6072,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 16.1; - MARKETING_VERSION = 1.14.1; + MARKETING_VERSION = 1.14.2; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; @@ -6101,7 +6101,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.14.1; + MARKETING_VERSION = 1.14.2; OTHER_SWIFT_FLAGS = "$(inherited) -D COCOAPODS"; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.PermanentArchive; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -6134,7 +6134,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.14.1; + MARKETING_VERSION = 1.14.2; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.PermanentArchive; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -6158,7 +6158,7 @@ "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = x86_64; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 16.1; - MARKETING_VERSION = 1.14.1; + MARKETING_VERSION = 1.14.2; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.PermanentArchive.PermanentUITests; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; @@ -6183,7 +6183,7 @@ "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = x86_64; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 16.1; - MARKETING_VERSION = 1.14.1; + MARKETING_VERSION = 1.14.2; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.PermanentArchive.PermanentUITests; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; @@ -6208,7 +6208,7 @@ "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = x86_64; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 16.1; - MARKETING_VERSION = 1.14.1; + MARKETING_VERSION = 1.14.2; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.PermanentArchive.PermanentUITests; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; @@ -6233,7 +6233,7 @@ "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = x86_64; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 16.1; - MARKETING_VERSION = 1.14.1; + MARKETING_VERSION = 1.14.2; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.PermanentArchive.PermanentUITests; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; @@ -6264,7 +6264,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MARKETING_VERSION = 1.14.1; + MARKETING_VERSION = 1.14.2; PRODUCT_BUNDLE_IDENTIFIER = com.vsp.PermanentTests; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; @@ -6294,7 +6294,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MARKETING_VERSION = 1.14.1; + MARKETING_VERSION = 1.14.2; PRODUCT_BUNDLE_IDENTIFIER = com.vsp.PermanentTests; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; @@ -6324,7 +6324,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MARKETING_VERSION = 1.14.1; + MARKETING_VERSION = 1.14.2; PRODUCT_BUNDLE_IDENTIFIER = com.vsp.PermanentTests; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; @@ -6354,7 +6354,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MARKETING_VERSION = 1.14.1; + MARKETING_VERSION = 1.14.2; PRODUCT_BUNDLE_IDENTIFIER = com.vsp.PermanentTests; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; @@ -6390,7 +6390,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.14.1; + MARKETING_VERSION = 1.14.2; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.PermanentArchive.ShareExtension; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -6428,7 +6428,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.14.1; + MARKETING_VERSION = 1.14.2; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.permanent.staging.ShareExtension; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -6466,7 +6466,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.14.1; + MARKETING_VERSION = 1.14.2; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.PermanentArchive.ShareExtension; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -6504,7 +6504,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.14.1; + MARKETING_VERSION = 1.14.2; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.permanent.staging.ShareExtension; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -6573,7 +6573,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 16.1; - MARKETING_VERSION = 1.14.1; + MARKETING_VERSION = 1.14.2; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -6602,7 +6602,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.14.1; + MARKETING_VERSION = 1.14.2; OTHER_SWIFT_FLAGS = "-D COCOAPODS -DSTAGING_ENVIRONMENT"; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.permanent.staging; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -6663,7 +6663,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 16.1; - MARKETING_VERSION = 1.14.1; + MARKETING_VERSION = 1.14.2; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; @@ -6692,7 +6692,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.14.1; + MARKETING_VERSION = 1.14.2; OTHER_SWIFT_FLAGS = "-D COCOAPODS -DSTAGING_ENVIRONMENT"; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.permanent.staging; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -6722,7 +6722,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.14.1; + MARKETING_VERSION = 1.14.2; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.PermanentArchive.PushExtension; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -6751,7 +6751,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.14.1; + MARKETING_VERSION = 1.14.2; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.permanent.staging.PushExtension; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -6780,7 +6780,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.14.1; + MARKETING_VERSION = 1.14.2; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.PermanentArchive.PushExtension; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -6809,7 +6809,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.14.1; + MARKETING_VERSION = 1.14.2; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.permanent.staging.PushExtension; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/Permanent/App/AppDelegate.swift b/Permanent/App/AppDelegate.swift index b1138bc9..7e2b9cc3 100644 --- a/Permanent/App/AppDelegate.swift +++ b/Permanent/App/AppDelegate.swift @@ -13,6 +13,7 @@ import GoogleMaps import StripeApplePay import SwiftUI import KeychainSwift +import SDWebImage @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { @@ -29,6 +30,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { initFirebase() initNotifications() configureLogging() + configureImageCache() StripeAPI.defaultPublishableKey = stripeServiceInfo.publishableKey @@ -285,6 +287,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate { #endif } + fileprivate func configureImageCache() { + let cache = SDImageCache.shared + cache.config.maxDiskSize = 300 * 1024 * 1024 // 300 MB disk cap + cache.config.maxMemoryCost = 50 * 1024 * 1024 // 50 MB memory cap + } + fileprivate func initNotifications() { UNUserNotificationCenter.current().delegate = self diff --git a/Permanent/Common/Base/SwiftUIViews/SectionHeaderView.swift b/Permanent/Common/Base/SwiftUIViews/SectionHeaderView.swift index e2d4df44..a2f4c3d9 100644 --- a/Permanent/Common/Base/SwiftUIViews/SectionHeaderView.swift +++ b/Permanent/Common/Base/SwiftUIViews/SectionHeaderView.swift @@ -14,7 +14,7 @@ struct SectionHeaderView: View { VStack { HStack { let files = selectedFiles - if !files.isEmpty, let url = URL(string: files.first?.thumbnailURL500) { + if !files.isEmpty, let url = URL(string: files.first?.preferredThumbnailURL) { WebImage(url: url) .resizable() .placeholder(content: { diff --git a/Permanent/Common/Managers/AuthenticationManager.swift b/Permanent/Common/Managers/AuthenticationManager.swift index 16824bc8..99bc72c4 100644 --- a/Permanent/Common/Managers/AuthenticationManager.swift +++ b/Permanent/Common/Managers/AuthenticationManager.swift @@ -8,6 +8,7 @@ import UIKit import KeychainSwift import FirebaseMessaging +import SDWebImage class AuthenticationManager { static let shared = AuthenticationManager() @@ -212,6 +213,10 @@ class AuthenticationManager { keychainHandler.clearSession() UserDefaults.standard.set(false, forKey: Constants.Keys.StorageKeys.memberChecklistWasShown) + // Clear cached images to prevent data leaking between accounts + SDImageCache.shared.clearMemory() + SDImageCache.shared.clearDisk() + Messaging.messaging().deleteFCMToken(forSenderID: googleServiceInfo.gcmSenderId) { _ in } } diff --git a/Permanent/Common/Models/Data/ArchiveVO.swift b/Permanent/Common/Models/Data/ArchiveVO.swift index 47bf47c6..6a413f02 100644 --- a/Permanent/Common/Models/Data/ArchiveVO.swift +++ b/Permanent/Common/Models/Data/ArchiveVO.swift @@ -46,6 +46,7 @@ struct ArchiveVOData: Model { let type: String? let thumbStatus: Status? let imageRatio: JSONAny? + let thumbnail256: String? let thumbURL200: String? let thumbURL500: String? let thumbURL1000: String? @@ -64,7 +65,18 @@ struct ArchiveVOData: Model { case archiveID = "archiveId" case publicDT, archiveNbr case archiveVOPublic = "public" - case view, viewProperty, vaultKey, thumbArchiveNbr, imageRatio, type, thumbStatus, thumbURL200, thumbURL500, thumbURL1000, thumbURL2000, thumbDT, status, createdDT, updatedDT + case view, viewProperty, vaultKey, thumbArchiveNbr, imageRatio, type, thumbStatus, thumbnail256, thumbURL200, thumbURL500, thumbURL1000, thumbURL2000, thumbDT, status, createdDT, updatedDT + } +} + +extension ArchiveVOData { + private func nonEmpty(_ value: String?) -> String? { + guard let value = value, !value.isEmpty else { return nil } + return value + } + + var preferredThumbnailURL: String? { + nonEmpty(thumbnail256) ?? nonEmpty(thumbURL500) ?? nonEmpty(thumbURL200) ?? nonEmpty(thumbURL1000) ?? nonEmpty(thumbURL2000) } } @@ -99,6 +111,7 @@ extension ArchiveVOData { type: "archive", thumbStatus: .ok, imageRatio: nil, + thumbnail256: nil, thumbURL200: "https://example.com/thumb200.jpg", thumbURL500: "https://example.com/thumb500.jpg", thumbURL1000: "https://example.com/thumb1000.jpg", diff --git a/Permanent/Common/Models/Data/Folder/FolderVO.swift b/Permanent/Common/Models/Data/Folder/FolderVO.swift index 7666bbb5..ee5a636d 100644 --- a/Permanent/Common/Models/Data/Folder/FolderVO.swift +++ b/Permanent/Common/Models/Data/Folder/FolderVO.swift @@ -31,6 +31,7 @@ struct FolderVOData: Model { let viewProperty, thumbArchiveNbr: String? let type, thumbStatus: String? let imageRatio: JSONAny? + let thumbnail256: String? let thumbURL200: String? let thumbURL500: String? let thumbURL1000: String? @@ -74,7 +75,7 @@ struct FolderVOData: Model { case special, sort case locnID = "locnId" case timeZoneID = "timeZoneId" - case view, viewProperty, thumbArchiveNbr, imageRatio, type, thumbStatus, thumbURL200, thumbURL500, thumbURL1000, thumbURL2000, thumbDT, status, publicDT + case view, viewProperty, thumbArchiveNbr, imageRatio, type, thumbStatus, thumbnail256, thumbURL200, thumbURL500, thumbURL1000, thumbURL2000, thumbDT, status, publicDT case parentFolderID = "parentFolderId" case folderLinkType = "folder_linkType" case folderLinkVOS = "FolderLinkVOs" @@ -102,3 +103,14 @@ struct FolderVOData: Model { case archiveArchiveNbr, returnDataSize, posStart, posLimit, searchScore, createdDT, updatedDT } } + +extension FolderVOData { + private func nonEmpty(_ value: String?) -> String? { + guard let value = value, !value.isEmpty else { return nil } + return value + } + + var preferredThumbnailURL: String? { + nonEmpty(thumbnail256) ?? nonEmpty(thumbURL500) ?? nonEmpty(thumbURL200) ?? nonEmpty(thumbURL1000) ?? nonEmpty(thumbURL2000) + } +} diff --git a/Permanent/Common/Models/Data/Folder/MinFolderVO.swift b/Permanent/Common/Models/Data/Folder/MinFolderVO.swift index a3404ae1..18053f51 100644 --- a/Permanent/Common/Models/Data/Folder/MinFolderVO.swift +++ b/Permanent/Common/Models/Data/Folder/MinFolderVO.swift @@ -23,6 +23,7 @@ struct MinFolderVO: Codable { let viewProperty, thumbArchiveNbr: JSONAny? let type, thumbStatus: String? let imageRatio: JSONAny? + let thumbnail256: String? let thumbURL200: String? let thumbURL500: String? let thumbURL1000: String? @@ -67,7 +68,7 @@ struct MinFolderVO: Codable { case special, sort case locnID = "locnId" case timeZoneID = "timeZoneId" - case view, viewProperty, thumbArchiveNbr, imageRatio, type, thumbStatus, thumbURL200, thumbURL500, thumbURL1000, thumbURL2000, thumbDT, status, publicDT + case view, viewProperty, thumbArchiveNbr, imageRatio, type, thumbStatus, thumbnail256, thumbURL200, thumbURL500, thumbURL1000, thumbURL2000, thumbDT, status, publicDT case parentFolderID = "parentFolderId" case folderLinkType = "folder_linkType" case folderLinkVOS = "FolderLinkVOs" @@ -95,3 +96,14 @@ struct MinFolderVO: Codable { case archiveArchiveNbr, returnDataSize, posStart, posLimit, searchScore, createdDT, updatedDT } } + +extension MinFolderVO { + private func nonEmpty(_ value: String?) -> String? { + guard let value = value, !value.isEmpty else { return nil } + return value + } + + var preferredThumbnailURL: String? { + nonEmpty(thumbnail256) ?? nonEmpty(thumbURL500) ?? nonEmpty(thumbURL200) ?? nonEmpty(thumbURL1000) ?? nonEmpty(thumbURL2000) + } +} diff --git a/Permanent/Common/Models/Data/FolderV2Models.swift b/Permanent/Common/Models/Data/FolderV2Models.swift index 2e35674e..0bdde827 100644 --- a/Permanent/Common/Models/Data/FolderV2Models.swift +++ b/Permanent/Common/Models/Data/FolderV2Models.swift @@ -83,12 +83,14 @@ struct FolderPathsV2: Model { } struct ThumbnailUrlsV2: Model { + let url256: String? let url200: String? let url500: String? let url1000: String? let url2000: String? enum CodingKeys: String, CodingKey { + case url256 = "256" case url200 = "200" case url500 = "500" case url1000 = "1000" @@ -122,6 +124,7 @@ struct FolderChildV2Data: Model { let description: String? let downloadName: String? let uploadFileName: String? + let thumbnail256: String? let thumbUrl200: String? let thumbUrl500: String? let thumbUrl1000: String? @@ -145,7 +148,7 @@ struct FolderChildV2Data: Model { /// Returns the best available thumbnail URL var bestThumbnailURL: String? { - return thumbUrl500 ?? thumbUrl200 ?? thumbUrl1000 + thumbnail256 ?? thumbUrl500 ?? thumbUrl200 ?? thumbUrl1000 ?? thumbUrl2000 } } diff --git a/Permanent/Common/Models/Data/ItemVO.swift b/Permanent/Common/Models/Data/ItemVO.swift index 194554a0..edd9effe 100644 --- a/Permanent/Common/Models/Data/ItemVO.swift +++ b/Permanent/Common/Models/Data/ItemVO.swift @@ -21,6 +21,7 @@ struct ItemVO: Model { let view: String? let viewProperty, thumbArchiveNbr: JSONAny? let imageRatio, type, thumbStatus: String? + let thumbnail256: String? let thumbURL200: String? let thumbURL500: String? let thumbURL1000: String? @@ -70,7 +71,7 @@ struct ItemVO: Model { case special, sort case locnID = "locnId" case timeZoneID = "timeZoneId" - case view, viewProperty, thumbArchiveNbr, imageRatio, type, thumbStatus, thumbURL200, thumbURL500, thumbURL1000, thumbURL2000, thumbDT, status, publicDT + case view, viewProperty, thumbArchiveNbr, imageRatio, type, thumbStatus, thumbnail256, thumbURL200, thumbURL500, thumbURL1000, thumbURL2000, thumbDT, status, publicDT case parentFolderID = "parentFolderId" case folderLinkType = "folder_linkType" case folderLinkVOS = "FolderLinkVOs" @@ -110,3 +111,14 @@ struct ItemVO: Model { case createdDT, updatedDT } } + +extension ItemVO { + private func nonEmpty(_ value: String?) -> String? { + guard let value = value, !value.isEmpty else { return nil } + return value + } + + var preferredThumbnailURL: String? { + nonEmpty(thumbnail256) ?? nonEmpty(thumbURL500) ?? nonEmpty(thumbURL200) ?? nonEmpty(thumbURL1000) ?? nonEmpty(thumbURL2000) + } +} diff --git a/Permanent/Common/Models/Data/ParentFolderVO.swift b/Permanent/Common/Models/Data/ParentFolderVO.swift index da20e605..cb1dac9e 100644 --- a/Permanent/Common/Models/Data/ParentFolderVO.swift +++ b/Permanent/Common/Models/Data/ParentFolderVO.swift @@ -23,6 +23,7 @@ struct ParentFolderVO: Model { let viewProperty, thumbArchiveNbr: JSONAny? let type, thumbStatus: String? let imageRatio: JSONAny? + let thumbnail256: String? let thumbURL200: String? let thumbURL500: String? let thumbURL1000: String? @@ -63,7 +64,7 @@ struct ParentFolderVO: Model { case special, sort case locnID = "locnId" case timeZoneID = "timeZoneId" - case view, viewProperty, thumbArchiveNbr, imageRatio, type, thumbStatus, thumbURL200, thumbURL500, thumbURL1000, thumbURL2000, thumbDT, status, publicDT + case view, viewProperty, thumbArchiveNbr, imageRatio, type, thumbStatus, thumbnail256, thumbURL200, thumbURL500, thumbURL1000, thumbURL2000, thumbDT, status, publicDT case parentFolderID = "parentFolderId" case folderLinkType = "folder_linkType" case folderLinkVOS = "FolderLinkVOs" @@ -91,3 +92,14 @@ struct ParentFolderVO: Model { case archiveArchiveNbr, returnDataSize, posStart, posLimit, searchScore, createdDT, updatedDT } } + +extension ParentFolderVO { + private func nonEmpty(_ value: String?) -> String? { + guard let value = value, !value.isEmpty else { return nil } + return value + } + + var preferredThumbnailURL: String? { + nonEmpty(thumbnail256) ?? nonEmpty(thumbURL500) ?? nonEmpty(thumbURL200) ?? nonEmpty(thumbURL1000) ?? nonEmpty(thumbURL2000) + } +} diff --git a/Permanent/Common/Models/Data/RecordV2Models.swift b/Permanent/Common/Models/Data/RecordV2Models.swift index e188c319..f81600ff 100644 --- a/Permanent/Common/Models/Data/RecordV2Models.swift +++ b/Permanent/Common/Models/Data/RecordV2Models.swift @@ -29,6 +29,7 @@ struct RecordV2Data: Model { let displayTimeInEDTF: String? let fileCreatedAt: String? let imageRatio: Double? + let thumbnail256: String? let thumbUrl200: String? let thumbUrl500: String? let thumbUrl1000: String? @@ -52,6 +53,21 @@ struct RecordV2Data: Model { let archive: RecordArchiveV2? } +extension RecordV2Data { + private func nonEmpty(_ value: String?) -> String? { + guard let value = value, !value.isEmpty else { return nil } + return value + } + + var resolvedThumbnail256: String? { + nonEmpty(thumbnail256) ?? nonEmpty(thumbnailUrls?.url256) + } + + var preferredThumbnailURL: String? { + resolvedThumbnail256 ?? nonEmpty(thumbUrl500) ?? nonEmpty(thumbUrl200) ?? nonEmpty(thumbUrl1000) ?? nonEmpty(thumbUrl2000) + } +} + struct LocationV2: Model { let id: String? let streetNumber: String? @@ -88,6 +104,7 @@ struct RecordShareV2: Model { struct RecordShareArchiveV2: Model { let archiveId: String? + let thumbnail256: String? let thumbUrl200: String? let thumbUrl500: String? let thumbUrl1000: String? @@ -97,6 +114,7 @@ struct RecordShareArchiveV2: Model { enum CodingKeys: String, CodingKey { case archiveId = "id" // Map "id" from JSON to archiveId + case thumbnail256 case thumbUrl200 case thumbUrl500 case thumbUrl1000 @@ -106,6 +124,21 @@ struct RecordShareArchiveV2: Model { } } +extension RecordShareArchiveV2 { + private func nonEmpty(_ value: String?) -> String? { + guard let value = value, !value.isEmpty else { return nil } + return value + } + + var resolvedThumbnail256: String? { + nonEmpty(thumbnail256) ?? nonEmpty(thumbnailUrls?.url256) + } + + var preferredThumbnailURL: String? { + resolvedThumbnail256 ?? nonEmpty(thumbUrl500) ?? nonEmpty(thumbUrl200) ?? nonEmpty(thumbUrl1000) ?? nonEmpty(thumbUrl2000) + } +} + struct RecordArchiveV2: Model { let id: String? let archiveNumber: String? diff --git a/Permanent/Common/Models/Data/RecordVO.swift b/Permanent/Common/Models/Data/RecordVO.swift index 8439e9d7..77f322a7 100644 --- a/Permanent/Common/Models/Data/RecordVO.swift +++ b/Permanent/Common/Models/Data/RecordVO.swift @@ -29,6 +29,7 @@ struct RecordVOData: Model { let encryption, metaToken: String? let refArchiveNbr: JSONAny? let type, thumbStatus: String? + let thumbnail256: String? let thumbURL200, thumbURL500, thumbURL1000, thumbURL2000: String? let thumbDT, fileStatus: String? let status: String? @@ -69,7 +70,7 @@ struct RecordVOData: Model { case displayDT, displayEndDT, derivedDT, derivedEndDT, derivedCreatedDT case locnID = "locnId" case timeZoneID = "timeZoneId" - case view, viewProperty, imageRatio, encryption, metaToken, refArchiveNbr, type, thumbStatus, thumbURL200, thumbURL500, thumbURL1000, thumbURL2000, thumbDT, fileStatus, status, processedDT + case view, viewProperty, imageRatio, encryption, metaToken, refArchiveNbr, type, thumbStatus, thumbnail256, thumbURL200, thumbURL500, thumbURL1000, thumbURL2000, thumbDT, fileStatus, status, processedDT case folderLinkVOS = "FolderLinkVOs" case folderLinkID = "folder_linkId" case parentFolderID = "parentFolderId" @@ -99,3 +100,14 @@ struct RecordVOData: Model { case searchScore, archiveArchiveNbr, createdDT, updatedDT } } + +extension RecordVOData { + private func nonEmpty(_ value: String?) -> String? { + guard let value = value, !value.isEmpty else { return nil } + return value + } + + var preferredThumbnailURL: String? { + nonEmpty(thumbnail256) ?? nonEmpty(thumbURL500) ?? nonEmpty(thumbURL200) ?? nonEmpty(thumbURL1000) ?? nonEmpty(thumbURL2000) + } +} diff --git a/Permanent/Common/Scenes/Share Preview/Models/FileVM.swift b/Permanent/Common/Scenes/Share Preview/Models/FileVM.swift index a1adb78f..8b3af950 100644 --- a/Permanent/Common/Scenes/Share Preview/Models/FileVM.swift +++ b/Permanent/Common/Scenes/Share Preview/Models/FileVM.swift @@ -21,7 +21,7 @@ struct FileVM: File { init(record: RecordVOData) { name = record.displayName ?? "" date = record.displayDT ?? "" - thumbStringURL = record.thumbURL500 ?? "" + thumbStringURL = record.preferredThumbnailURL ?? "" } } diff --git a/Permanent/Modules/Archives/Cells/ArchiveTableViewCell.swift b/Permanent/Modules/Archives/Cells/ArchiveTableViewCell.swift index 12bba182..9f765845 100644 --- a/Permanent/Modules/Archives/Cells/ArchiveTableViewCell.swift +++ b/Permanent/Modules/Archives/Cells/ArchiveTableViewCell.swift @@ -44,7 +44,7 @@ class ArchiveTableViewCell: UITableViewCell { } func updateCell(model: ShareVOData) { - archiveImageView.load(urlString: model.archiveVO?.thumbURL200 ?? "") + archiveImageView.load(urlString: model.archiveVO?.preferredThumbnailURL ?? "") archiveNameLabel.text = .init(format: .archiveName, model.archiveVO?.fullName ?? "") if ShareStatus.status(forValue: model.status ?? "") != .pending { diff --git a/Permanent/Modules/Archives/ViewController/ArchivesViewController.swift b/Permanent/Modules/Archives/ViewController/ArchivesViewController.swift index aa0f4c40..b380cd00 100644 --- a/Permanent/Modules/Archives/ViewController/ArchivesViewController.swift +++ b/Permanent/Modules/Archives/ViewController/ArchivesViewController.swift @@ -376,7 +376,7 @@ extension ArchivesViewController: UITableViewDataSource, UITableViewDelegate { let archiveVO = tableViewData[indexPath.row] tableViewCell.updateCell(withArchiveVO: archiveVO, isDefault: archiveVO.archiveID == viewModel?.defaultArchiveId, isManaging: isManaging) - tableViewCell.rightButtonAction = rightButtonAction(archiveName: archiveVO.fullName ?? "", archiveThumbnail: archiveVO.thumbURL200 ?? "", archive: archiveVO) + tableViewCell.rightButtonAction = rightButtonAction(archiveName: archiveVO.fullName ?? "", archiveThumbnail: archiveVO.preferredThumbnailURL ?? "", archive: archiveVO) cell = tableViewCell } diff --git a/Permanent/Modules/EditMetadata/ViewModels/MetadataEditFileNamesViewModel.swift b/Permanent/Modules/EditMetadata/ViewModels/MetadataEditFileNamesViewModel.swift index 0c8c753d..84467dd1 100644 --- a/Permanent/Modules/EditMetadata/ViewModels/MetadataEditFileNamesViewModel.swift +++ b/Permanent/Modules/EditMetadata/ViewModels/MetadataEditFileNamesViewModel.swift @@ -33,7 +33,7 @@ class MetadataEditFileNamesViewModel: ObservableObject { self.selectedFiles = selectedFiles self.hasUpdates = hasUpdates - imagePreviewURL = selectedFiles.first?.thumbnailURL500 + imagePreviewURL = selectedFiles.first?.preferredThumbnailURL fileNamePreview = selectedFiles.first?.name if let size = selectedFiles.first?.size { fileSizePreview = size.bytesToReadableForm(useDecimal: true) diff --git a/Permanent/Modules/EditMetadata/Views/MetadataEditFileNamesView.swift b/Permanent/Modules/EditMetadata/Views/MetadataEditFileNamesView.swift index 116deab4..9d63d8da 100644 --- a/Permanent/Modules/EditMetadata/Views/MetadataEditFileNamesView.swift +++ b/Permanent/Modules/EditMetadata/Views/MetadataEditFileNamesView.swift @@ -184,7 +184,7 @@ struct MetadataEditFileNames_Previews: PreviewProvider { @State static var hasUpdates: Bool = true static var previews: some View { - let file = FileModel(model: FolderVOData(folderID: 22, archiveNbr: nil, archiveID: 22, displayName: "TestFile", displayDT: nil, displayEndDT: nil, derivedDT: nil, derivedEndDT: nil, note: nil, voDescription: nil, special: nil, sort: nil, locnID: nil, timeZoneID: nil, view: nil, viewProperty: nil, thumbArchiveNbr: nil, type: nil, thumbStatus: nil, imageRatio: nil, thumbURL200: nil, thumbURL500: "https://img.freepik.com/free-photo/bright-yellow-fire-blazing-against-night-sky-generated-by-ai_188544-11620.jpg?t=st=1690878101~exp=1690881701~hmac=103cd63a2a40c4feeda570cad19c0c3cc8de275d6d6c2731ee33c3310669f67c&w=2000", thumbURL1000: nil, thumbURL2000: nil, thumbDT: nil, status: nil, publicDT: nil, parentFolderID: nil, folderLinkType: nil, folderLinkVOS: nil, accessRole: nil, position: nil, pathAsFolderLinkID: nil, shareDT: nil, pathAsText: nil, folderLinkID: nil, parentFolderLinkID: nil, parentFolderVOS: nil, parentArchiveNbr: nil, parentDisplayName: nil, pathAsArchiveNbr: nil, childFolderVOS: nil, recordVOS: nil, locnVO: nil, timezoneVO: nil, directiveVOS: nil, tagVOS: nil, sharedArchiveVOS: nil, folderSizeVO: nil, attachmentRecordVOS: nil, hasAttachments: nil, childItemVOS: nil, shareVOS: nil, accessVO: nil, returnDataSize: nil, archiveArchiveNbr: nil, accessVOS: nil, posStart: nil, posLimit: nil, searchScore: nil, createdDT: nil, updatedDT: nil)) + let file = FileModel(model: FolderVOData(folderID: 22, archiveNbr: nil, archiveID: 22, displayName: "TestFile", displayDT: nil, displayEndDT: nil, derivedDT: nil, derivedEndDT: nil, note: nil, voDescription: nil, special: nil, sort: nil, locnID: nil, timeZoneID: nil, view: nil, viewProperty: nil, thumbArchiveNbr: nil, type: nil, thumbStatus: nil, imageRatio: nil, thumbnail256: nil, thumbURL200: nil, thumbURL500: "https://img.freepik.com/free-photo/bright-yellow-fire-blazing-against-night-sky-generated-by-ai_188544-11620.jpg?t=st=1690878101~exp=1690881701~hmac=103cd63a2a40c4feeda570cad19c0c3cc8de275d6d6c2731ee33c3310669f67c&w=2000", thumbURL1000: nil, thumbURL2000: nil, thumbDT: nil, status: nil, publicDT: nil, parentFolderID: nil, folderLinkType: nil, folderLinkVOS: nil, accessRole: nil, position: nil, pathAsFolderLinkID: nil, shareDT: nil, pathAsText: nil, folderLinkID: nil, parentFolderLinkID: nil, parentFolderVOS: nil, parentArchiveNbr: nil, parentDisplayName: nil, pathAsArchiveNbr: nil, childFolderVOS: nil, recordVOS: nil, locnVO: nil, timezoneVO: nil, directiveVOS: nil, tagVOS: nil, sharedArchiveVOS: nil, folderSizeVO: nil, attachmentRecordVOS: nil, hasAttachments: nil, childItemVOS: nil, shareVOS: nil, accessVO: nil, returnDataSize: nil, archiveArchiveNbr: nil, accessVOS: nil, posStart: nil, posLimit: nil, searchScore: nil, createdDT: nil, updatedDT: nil)) MetadataEditFileNamesView(viewModel: MetadataEditFileNamesViewModel(selectedFiles: [file], hasUpdates: $hasUpdates)) } } diff --git a/Permanent/Modules/EditMetadata/Views/MetadataEditView.swift b/Permanent/Modules/EditMetadata/Views/MetadataEditView.swift index 4b6236c3..f62db7f2 100644 --- a/Permanent/Modules/EditMetadata/Views/MetadataEditView.swift +++ b/Permanent/Modules/EditMetadata/Views/MetadataEditView.swift @@ -211,7 +211,7 @@ struct MetadataEditView: View { struct MetadataEditView_Previews: PreviewProvider { static var previews: some View { - let file = FileModel(model: FolderVOData(folderID: 22, archiveNbr: nil, archiveID: 22, displayName: "TestFile", displayDT: nil, displayEndDT: nil, derivedDT: nil, derivedEndDT: nil, note: nil, voDescription: nil, special: nil, sort: nil, locnID: nil, timeZoneID: nil, view: nil, viewProperty: nil, thumbArchiveNbr: nil, type: nil, thumbStatus: nil, imageRatio: nil, thumbURL200: nil, thumbURL500: "https://img.freepik.com/free-photo/bright-yellow-fire-blazing-against-night-sky-generated-by-ai_188544-11620.jpg?t=st=1690878101~exp=1690881701~hmac=103cd63a2a40c4feeda570cad19c0c3cc8de275d6d6c2731ee33c3310669f67c&w=2000", thumbURL1000: nil, thumbURL2000: nil, thumbDT: nil, status: nil, publicDT: nil, parentFolderID: nil, folderLinkType: nil, folderLinkVOS: nil, accessRole: nil, position: nil, pathAsFolderLinkID: nil, shareDT: nil, pathAsText: nil, folderLinkID: nil, parentFolderLinkID: nil, parentFolderVOS: nil, parentArchiveNbr: nil, parentDisplayName: nil, pathAsArchiveNbr: nil, childFolderVOS: nil, recordVOS: nil, locnVO: nil, timezoneVO: nil, directiveVOS: nil, tagVOS: nil, sharedArchiveVOS: nil, folderSizeVO: nil, attachmentRecordVOS: nil, hasAttachments: nil, childItemVOS: nil, shareVOS: nil, accessVO: nil, returnDataSize: nil, archiveArchiveNbr: nil, accessVOS: nil, posStart: nil, posLimit: nil, searchScore: nil, createdDT: nil, updatedDT: nil)) + let file = FileModel(model: FolderVOData(folderID: 22, archiveNbr: nil, archiveID: 22, displayName: "TestFile", displayDT: nil, displayEndDT: nil, derivedDT: nil, derivedEndDT: nil, note: nil, voDescription: nil, special: nil, sort: nil, locnID: nil, timeZoneID: nil, view: nil, viewProperty: nil, thumbArchiveNbr: nil, type: nil, thumbStatus: nil, imageRatio: nil, thumbnail256: nil, thumbURL200: nil, thumbURL500: "https://img.freepik.com/free-photo/bright-yellow-fire-blazing-against-night-sky-generated-by-ai_188544-11620.jpg?t=st=1690878101~exp=1690881701~hmac=103cd63a2a40c4feeda570cad19c0c3cc8de275d6d6c2731ee33c3310669f67c&w=2000", thumbURL1000: nil, thumbURL2000: nil, thumbDT: nil, status: nil, publicDT: nil, parentFolderID: nil, folderLinkType: nil, folderLinkVOS: nil, accessRole: nil, position: nil, pathAsFolderLinkID: nil, shareDT: nil, pathAsText: nil, folderLinkID: nil, parentFolderLinkID: nil, parentFolderVOS: nil, parentArchiveNbr: nil, parentDisplayName: nil, pathAsArchiveNbr: nil, childFolderVOS: nil, recordVOS: nil, locnVO: nil, timezoneVO: nil, directiveVOS: nil, tagVOS: nil, sharedArchiveVOS: nil, folderSizeVO: nil, attachmentRecordVOS: nil, hasAttachments: nil, childItemVOS: nil, shareVOS: nil, accessVO: nil, returnDataSize: nil, archiveArchiveNbr: nil, accessVOS: nil, posStart: nil, posLimit: nil, searchScore: nil, createdDT: nil, updatedDT: nil)) MetadataEditView(viewModel: FilesMetadataViewModel(files: [file])) } } diff --git a/Permanent/Modules/FileOperations/Cells/FileDetailsTopCollectionViewCell.swift b/Permanent/Modules/FileOperations/Cells/FileDetailsTopCollectionViewCell.swift index 51a4067e..262a724a 100644 --- a/Permanent/Modules/FileOperations/Cells/FileDetailsTopCollectionViewCell.swift +++ b/Permanent/Modules/FileOperations/Cells/FileDetailsTopCollectionViewCell.swift @@ -6,6 +6,7 @@ // import UIKit +import SDWebImage class FileDetailsTopCollectionViewCell: FileDetailsBaseCollectionViewCell { @@ -24,11 +25,40 @@ class FileDetailsTopCollectionViewCell: FileDetailsBaseCollectionViewCell { activityIndicator.startAnimating() imageView.image = nil - let urlString = viewModel.file.thumbnailURL2000 ?? viewModel.fileThumbnailURL() ?? "" - guard let url = URL(string: urlString) else { return } - imageView.sd_setImage(with: url) { image, error, cacheType, url in - self.activityIndicator.stopAnimating() + // Stage 1: Load the 256px thumbnail quickly + let thumbnailURLString = viewModel.file.preferredThumbnailURL ?? viewModel.fileThumbnailURL() ?? "" + guard let thumbnailURL = URL(string: thumbnailURLString) else { return } + + // Determine the full-res download URL if available + let fullResURLString = viewModel.fileVO()?.downloadURL + let fullResURL = fullResURLString.flatMap { URL(string: $0) } + + imageView.sd_setImage(with: thumbnailURL) { [weak self] _, error, _, _ in + guard let self = self else { return } + + if let fullResURL = fullResURL, fullResURL != thumbnailURL { + // Stage 2: Upgrade to full-res from download URL + self.imageView.sd_setImage( + with: fullResURL, + placeholderImage: self.imageView.image, + options: [.avoidAutoSetImage, .retryFailed], + progress: nil + ) { [weak self] image, _, cacheType, _ in + guard let self = self, let image = image else { return } + self.activityIndicator.stopAnimating() + + if cacheType == .memory { + self.imageView.image = image + } else { + UIView.transition(with: self.imageView, duration: 0.3, options: .transitionCrossDissolve) { + self.imageView.image = image + } + } + } + } else { + self.activityIndicator.stopAnimating() + } } } diff --git a/Permanent/Modules/FileOperations/ViewController/FilePreviewViewController.swift b/Permanent/Modules/FileOperations/ViewController/FilePreviewViewController.swift index f75c022d..03463330 100644 --- a/Permanent/Modules/FileOperations/ViewController/FilePreviewViewController.swift +++ b/Permanent/Modules/FileOperations/ViewController/FilePreviewViewController.swift @@ -10,6 +10,7 @@ import WebKit import AVKit import PDFKit import SwiftUI +import SDWebImage class FilePreviewViewController: BaseViewController { override var supportedInterfaceOrientations: UIInterfaceOrientationMask { @@ -70,12 +71,14 @@ class FilePreviewViewController: BaseViewController { styleNavBar() } + var imagePreviewVC: ImagePreviewViewController? + func loadVM() { guard recordLoaded == false else { return } if isViewLoaded { activityIndicator.startAnimating() - if let url = URL(string: file.thumbnailURL) { + if let url = URL(string: file.preferredThumbnailURL) { thumbnailImageView.sd_setImage(with: url) } } @@ -83,8 +86,8 @@ class FilePreviewViewController: BaseViewController { if viewModel == nil || viewModel?.recordVO == nil { viewModel = FilePreviewViewModel(file: file) - if file.type == .image, let url = URL(string: file.thumbnailURL2000) { - loadImage(withURL: url) + if file.type == .image, let thumbnailURLString = file.preferredThumbnailURL { + loadThumbnailPreview(urlString: thumbnailURLString) } viewModel?.getRecord(file: file, then: { [weak self] record in @@ -98,8 +101,8 @@ class FilePreviewViewController: BaseViewController { self?.retryButton.isHidden = false } }) - } else if file.type == .image, let url = URL(string: file.thumbnailURL2000) { - loadImage(withURL: url) + } else if file.type == .image, let thumbnailURLString = file.preferredThumbnailURL { + loadThumbnailPreview(urlString: thumbnailURLString) } else { loadRecord() } @@ -168,7 +171,9 @@ class FilePreviewViewController: BaseViewController { let contentType = fileVO.contentType { switch fileType { case FileType.image: - if let url = URL(string: self.viewModel?.fileThumbnailURL()) { + // Use download URL for full-res; fall back to thumbnail URL + let fullResURL = fileVO.downloadURL ?? self.viewModel?.fileThumbnailURL() + if let urlString = fullResURL, let url = URL(string: urlString) { self.loadImage(withURL: url) } @@ -189,9 +194,8 @@ class FilePreviewViewController: BaseViewController { let downloadURL = URL(string: downloadURLString) { switch fileType { case FileType.image: - if let url = URL(string: self.viewModel?.fileThumbnailURL()) { - self.loadImage(withURL: url) - } + // Use download URL for full-resolution image + self.loadImage(withURL: downloadURL) case FileType.video: self.loadVideo(withURL: downloadURL, contentType: contentType) @@ -215,28 +219,102 @@ class FilePreviewViewController: BaseViewController { } } - func loadImage(withURL url: URL) { - let imagePreviewVC = ImagePreviewViewController() - imagePreviewVC.delegate = self - addChild(imagePreviewVC) - imagePreviewVC.view.frame = view.bounds - imagePreviewVC.view.autoresizingMask = [.flexibleWidth, .flexibleHeight] - // Insert view under the spinner - view.insertSubview(imagePreviewVC.view, at: 0) - imagePreviewVC.didMove(toParent: self) - imagePreviewVC.imageView.sd_setImage(with: url) { _, error, _, _ in + /// Loads the 256px thumbnail into the zoomable image preview as a quick placeholder. + private func loadThumbnailPreview(urlString: String) { + guard let url = URL(string: urlString) else { return } + + let previewVC = ImagePreviewViewController() + previewVC.delegate = self + self.imagePreviewVC = previewVC + + addChild(previewVC) + previewVC.view.frame = view.bounds + previewVC.view.autoresizingMask = [.flexibleWidth, .flexibleHeight] + view.insertSubview(previewVC.view, at: 0) + previewVC.didMove(toParent: self) + + previewVC.imageView.sd_setImage(with: url) { [weak self] _, error, _, _ in + guard let self = self else { return } self.activityIndicator.stopAnimating() self.thumbnailImageView.isHidden = true if error != nil { self.errorLabel.isHidden = false self.retryButton.isHidden = false - - imagePreviewVC.view.removeFromSuperview() - imagePreviewVC.removeFromParent() - imagePreviewVC.didMove(toParent: nil) + self.removeImagePreviewVC() + } else { + previewVC.newImageLoaded() + } + } + } + + /// Upgrades the existing image preview from thumbnail to full-resolution using the download URL. + /// SDWebImage caches the full-res image, so subsequent opens load instantly from disk. + private func upgradeToFullResolution(urlString: String) { + guard let url = URL(string: urlString), + let previewVC = self.imagePreviewVC else { return } + + // Check if SDWebImage already has this URL cached (from a previous open) + let cachedFromMemory = SDImageCache.shared.imageFromMemoryCache(forKey: urlString) != nil + + previewVC.imageView.sd_setImage( + with: url, + placeholderImage: previewVC.imageView.image, + options: [.avoidAutoSetImage, .retryFailed], + progress: nil + ) { [weak previewVC] image, _, cacheType, _ in + guard let previewVC = previewVC, let image = image else { return } + + if cachedFromMemory || cacheType == .memory { + // Cached in memory — swap immediately, no animation needed + previewVC.imageView.image = image + previewVC.newImageLoaded() } else { - imagePreviewVC.newImageLoaded() + // Downloaded or loaded from disk — crossfade for smooth transition + UIView.transition(with: previewVC.imageView, duration: 0.3, options: .transitionCrossDissolve) { + previewVC.imageView.image = image + } completion: { _ in + previewVC.newImageLoaded() + } + } + } + } + + private func removeImagePreviewVC() { + imagePreviewVC?.view.removeFromSuperview() + imagePreviewVC?.removeFromParent() + imagePreviewVC?.didMove(toParent: nil) + imagePreviewVC = nil + } + + func loadImage(withURL url: URL) { + if imagePreviewVC != nil { + // Image preview already showing thumbnail — upgrade to full-res + upgradeToFullResolution(urlString: url.absoluteString) + } else { + // No preview yet (e.g. record already loaded) — load directly + let previewVC = ImagePreviewViewController() + previewVC.delegate = self + self.imagePreviewVC = previewVC + + addChild(previewVC) + previewVC.view.frame = view.bounds + previewVC.view.autoresizingMask = [.flexibleWidth, .flexibleHeight] + view.insertSubview(previewVC.view, at: 0) + previewVC.didMove(toParent: self) + + previewVC.imageView.sd_setImage(with: url) { [weak self] _, error, _, _ in + guard let self = self else { return } + self.activityIndicator.stopAnimating() + self.thumbnailImageView.isHidden = true + + if error != nil { + self.errorLabel.isHidden = false + self.retryButton.isHidden = false + self.removeImagePreviewVC() + } else { + previewVC.newImageLoaded() + } } } } diff --git a/Permanent/Modules/Onboarding/Screens/Container/OnboardingContainerViewModel.swift b/Permanent/Modules/Onboarding/Screens/Container/OnboardingContainerViewModel.swift index 54892ef7..8f79954d 100644 --- a/Permanent/Modules/Onboarding/Screens/Container/OnboardingContainerViewModel.swift +++ b/Permanent/Modules/Onboarding/Screens/Container/OnboardingContainerViewModel.swift @@ -71,7 +71,7 @@ class OnboardingContainerViewModel: ObservableObject { let status = archive.archiveVO?.status, let archiveID = archive.archiveVO?.archiveID, status == ArchiveVOData.Status.pending || status == ArchiveVOData.Status.ok { - allArchives.append(OnboardingArchive(fullname: fullName, accessType: AccessRole.roleForValue(archive.archiveVO?.accessRole).groupName, status: status, archiveID: archiveID, thumbnailURL: archive.archiveVO?.thumbURL200 ?? "", isThumbnailGenerated: archive.archiveVO?.thumbStatus != .genAvatar ? true : false)) + allArchives.append(OnboardingArchive(fullname: fullName, accessType: AccessRole.roleForValue(archive.archiveVO?.accessRole).groupName, status: status, archiveID: archiveID, thumbnailURL: archive.archiveVO?.preferredThumbnailURL ?? "", isThumbnailGenerated: archive.archiveVO?.thumbStatus != .genAvatar ? true : false)) } } } else { @@ -98,4 +98,3 @@ class OnboardingContainerViewModel: ObservableObject { updateAccountOperation.execute(in: APIRequestDispatcher()) {_ in} } } - diff --git a/Permanent/Modules/Onboarding/Screens/WhatsImportant/OnboardingWhatsImportantViewModel.swift b/Permanent/Modules/Onboarding/Screens/WhatsImportant/OnboardingWhatsImportantViewModel.swift index 6c280a76..61016016 100644 --- a/Permanent/Modules/Onboarding/Screens/WhatsImportant/OnboardingWhatsImportantViewModel.swift +++ b/Permanent/Modules/Onboarding/Screens/WhatsImportant/OnboardingWhatsImportantViewModel.swift @@ -221,7 +221,7 @@ class OnboardingWhatsImportantViewModel: ObservableObject { let status = archive.archiveVO?.status, let archiveID = archive.archiveVO?.archiveID, status == ArchiveVOData.Status.ok { - containerViewModel.allArchives.append(OnboardingArchive(fullname: fullName, accessType: AccessRole.roleForValue(archive.archiveVO?.accessRole).groupName, status: status, archiveID: archiveID, thumbnailURL: archive.archiveVO?.thumbURL200 ?? "", isThumbnailGenerated: archive.archiveVO?.thumbStatus != .genAvatar ? true : false)) + containerViewModel.allArchives.append(OnboardingArchive(fullname: fullName, accessType: AccessRole.roleForValue(archive.archiveVO?.accessRole).groupName, status: status, archiveID: archiveID, thumbnailURL: archive.archiveVO?.preferredThumbnailURL ?? "", isThumbnailGenerated: archive.archiveVO?.thumbStatus != .genAvatar ? true : false)) } } } else { diff --git a/Permanent/Modules/PublicProfile/ViewController/PublicArchiveViewController.swift b/Permanent/Modules/PublicProfile/ViewController/PublicArchiveViewController.swift index 6d6d537c..254d93dc 100644 --- a/Permanent/Modules/PublicProfile/ViewController/PublicArchiveViewController.swift +++ b/Permanent/Modules/PublicProfile/ViewController/PublicArchiveViewController.swift @@ -421,7 +421,7 @@ extension PublicArchiveViewController: MyFilesViewModelPickerDelegate { if self.isPickingProfilePicture { self.viewModel?.updateProfilePicture(file: file, then: { status in self.dismiss(animated: true, completion: { - if status == .success, let thumbURL = URL(string: file.thumbnailURL2000) { + if status == .success, let thumbURL = URL(string: file.preferredThumbnailURL) { self.profilePhotoImageView.sd_setImage(with: thumbURL) AuthenticationManager.shared.syncSession { [weak self] status in switch status { @@ -439,7 +439,7 @@ extension PublicArchiveViewController: MyFilesViewModelPickerDelegate { } else { self.viewModel?.updateBanner(thumbArchiveNbr: file.archiveNo, then: { status in self.dismiss(animated: true, completion: { - if status == .success, let thumbURL = URL(string: file.thumbnailURL2000) { + if status == .success, let thumbURL = URL(string: file.preferredThumbnailURL) { self.profileBannerImageView.sd_setImage(with: thumbURL) } else { self.showErrorAlert(message: .errorMessage) diff --git a/Permanent/Modules/PublicProfile/ViewController/PublicProfilePageViewController.swift b/Permanent/Modules/PublicProfile/ViewController/PublicProfilePageViewController.swift index 49c400f4..2fd969b1 100644 --- a/Permanent/Modules/PublicProfile/ViewController/PublicProfilePageViewController.swift +++ b/Permanent/Modules/PublicProfile/ViewController/PublicProfilePageViewController.swift @@ -310,6 +310,7 @@ class PublicProfilePageViewController: BaseViewController String? { - let stringURL: String? = recordVO?.recordVO?.thumbURL2000 + let stringURL: String? = recordVO?.recordVO?.preferredThumbnailURL return stringURL } diff --git a/PermanentTests/SessionTests.swift b/PermanentTests/SessionTests.swift index c2dd4afc..d4f97362 100644 --- a/PermanentTests/SessionTests.swift +++ b/PermanentTests/SessionTests.swift @@ -15,7 +15,7 @@ class SessionTests: XCTestCase { let accountVO = AccountVOData(accountID: 1000, primaryEmail: "email@email.com", fullName: "Test Account", address: "Street", address2: nil, country: nil, city: nil, state: nil, zip: nil, primaryPhone: nil, level: nil, apiToken: nil, betaParticipant: nil, facebookAccountID: nil, googleAccountID: nil, status: nil, type: nil, emailStatus: nil, phoneStatus: nil, notificationPreferences: nil, agreed: nil, optIn: nil, emailArray: nil, inviteCode: nil, rememberMe: nil, keepLoggedIn: nil, accessRole: nil, spaceTotal: nil, spaceLeft: nil, fileTotal: nil, fileLeft: nil, changePrimaryEmail: nil, changePrimaryPhone: nil, createdDT: "2021-01-27T19:48:08", updatedDT: nil, hideChecklist: false) - let archiveVO = ArchiveVOData(childFolderVOS: nil, folderSizeVOS: nil, recordVOS: nil, accessRole: "access.role.owner", fullName: "test name", spaceTotal: nil, spaceLeft: nil, fileTotal: nil, fileLeft: nil, relationType: nil, homeCity: nil, homeState: nil, homeCountry: nil, itemVOS: nil, birthDay: nil, company: nil, archiveVODescription: nil, archiveID: 1653, publicDT: "2021-01-27T19:48:08", archiveNbr: "00in-0000", view: nil, viewProperty: nil, archiveVOPublic: nil, vaultKey: nil, thumbArchiveNbr: "00in-000v", type: "type.archive.person", thumbStatus: ArchiveVOData.Status.ok, imageRatio: nil, thumbURL200: "https://stagingcdn.permanent.org/00in-0000.thumb.w200?t=1686306811&Expires=1686306811&Signature=ZXjq08upvH73kyiLZJb-IYlSO4Jz6SaICjGBwHlL-UaQqpd1VAK6KWKnkIQtrLgsfhdkUhwa-TZT5tBSOhFDoeXfxOSLEEF19ml0W~rhyWjXpxhbMhqCL3s43lQ4p0uTeo4KuGXxx6-egFIZK2Z-5hzL52e5tpUJ6r5gENiiSL5r02ZapGmnKDN-UmF6vxaGLYrIAFZ5CpIuV6zCLjaKjLl-P2Ehp~LVTogJF9Tq7vibVTwYcagN4dnO9iDRp4u2alv0SceW2n8NavGaby1tnvQekVnqajbL0Utl1s3kUxiZ2V9VQmGrNRrZ4RRC8lB1xG8hDlb4GpUaQ0H86xiESg__&Key-Pair-Id=APKAJP2D34UGZ6IG443Q", thumbURL500: "https://stagingcdn.permanent.org/00in-0000.thumb.w500?t=1686306811&Expires=1686306811&Signature=e5W18KBakMSwIr5EHohYgHf3Nz23VA7eb6-x-3D1NH6Lsq-hxJyIHf9CTCmcksK-HR-CJKyrnIDjA2frUwpT274sPQ4fqVbXh~Od5i7Nh2gv9Gogs73z2QZ5a4Vrnuxhl6ncxWlVixs8AiUu~3ZgjfGQjmk2YODr8aIfp2siAg3SoN0NG1tHQ5AY7QfzrnXRCx55-~g3DaPcU8nuOfhwHAmlQzzvkortQIT2v2OP81~Kh8FW64go7Da~L~4BLPclq2xBcgl9Nk3NKMDIsCPVcVOOOTODz5yvwUbrhxZ7MmPHSxaGxLe8hvJqbrWP~hWgcouM-BLMvFupsRe1thYQhA__&Key-Pair-Id=APKAJP2D34UGZ6IG443Q", thumbURL1000: "https://stagingcdn.permanent.org/00in-0000.thumb.w1000?t=1686306811&Expires=1686306811&Signature=Y72DJ9LSrpWQIy2UkUWGil6ZkKaOl2CDJMD9mhxKjl7uPgDpcb3h8KKnjI34~1GyRgsDbB~rE2-TjhO2y7zm2YMfhHEu7yggh8F8wpVBJnETi-O4R0sceWu3pgeSXkyQ5rW~I3mkGPRV8IyoC2s1ByTN1Tsk0s9zGVyGZ3YleJMxikKt3YRM~PEOE69d414aVlI8RxPRkwnHl10T51V5lpTRHANUkuGlt0UclXfMbNkv3aS2r50Ejyj3nbML48oVXXzuwswLnY5GQ0FAq-kPggPlDI-7WSAmozkVHscsO5RE1FUiYNy-TqhKBPE~hk6BDd70n9cMyDr~O2ac9IhoUg__&Key-Pair-Id=APKAJP2D34UGZ6IG443Q", thumbURL2000: "https://stagingcdn.permanent.org/00in-0000.thumb.w2000?t=1686306811&Expires=1686306811&Signature=Bay2a-H0hfxh91Tzdz3MmK6sZBuCkK0TTuu54nhQojMqbXzlFZ-Hxqchcixa0lweYW41v4iRJBymD49af92VMlFZYgDwmw8ER6P3iofgGI99y8nMaPGrMsZNV834p-xiZsgD53WLnuR7m5hEOy588-EBYqZjTp9pBCAKaPV-5IcjngvNOh6LcYmX~9kvWchG~NMamkmRLZ0mb5wGNtjny6ZCMcuCC5ta4hdro~NYhGCOqEnz9d35ofjdSqorxIB2gyX2mpIJsyYy9DoEIB5hFwQIgUP9DMZexEB3Bj1sArP5HJ54IKYwqsvXSy64EQMGHSlSMRiu7FAqvttaUhyINg__&Key-Pair-Id=APKAJP2D34UGZ6IG443Q", thumbDT: "2023-06-09T10:33:31", createdDT: "2021-01-27T19:48:08", updatedDT: "2022-07-07T07:45:44", status: ArchiveVOData.Status.ok) + let archiveVO = ArchiveVOData(childFolderVOS: nil, folderSizeVOS: nil, recordVOS: nil, accessRole: "access.role.owner", fullName: "test name", spaceTotal: nil, spaceLeft: nil, fileTotal: nil, fileLeft: nil, relationType: nil, homeCity: nil, homeState: nil, homeCountry: nil, itemVOS: nil, birthDay: nil, company: nil, archiveVODescription: nil, archiveID: 1653, publicDT: "2021-01-27T19:48:08", archiveNbr: "00in-0000", view: nil, viewProperty: nil, archiveVOPublic: nil, vaultKey: nil, thumbArchiveNbr: "00in-000v", type: "type.archive.person", thumbStatus: ArchiveVOData.Status.ok, imageRatio: nil, thumbnail256: nil, thumbURL200: "https://stagingcdn.permanent.org/00in-0000.thumb.w200?t=1686306811&Expires=1686306811&Signature=ZXjq08upvH73kyiLZJb-IYlSO4Jz6SaICjGBwHlL-UaQqpd1VAK6KWKnkIQtrLgsfhdkUhwa-TZT5tBSOhFDoeXfxOSLEEF19ml0W~rhyWjXpxhbMhqCL3s43lQ4p0uTeo4KuGXxx6-egFIZK2Z-5hzL52e5tpUJ6r5gENiiSL5r02ZapGmnKDN-UmF6vxaGLYrIAFZ5CpIuV6zCLjaKjLl-P2Ehp~LVTogJF9Tq7vibVTwYcagN4dnO9iDRp4u2alv0SceW2n8NavGaby1tnvQekVnqajbL0Utl1s3kUxiZ2V9VQmGrNRrZ4RRC8lB1xG8hDlb4GpUaQ0H86xiESg__&Key-Pair-Id=APKAJP2D34UGZ6IG443Q", thumbURL500: "https://stagingcdn.permanent.org/00in-0000.thumb.w500?t=1686306811&Expires=1686306811&Signature=e5W18KBakMSwIr5EHohYgHf3Nz23VA7eb6-x-3D1NH6Lsq-hxJyIHf9CTCmcksK-HR-CJKyrnIDjA2frUwpT274sPQ4fqVbXh~Od5i7Nh2gv9Gogs73z2QZ5a4Vrnuxhl6ncxWlVixs8AiUu~3ZgjfGQjmk2YODr8aIfp2siAg3SoN0NG1tHQ5AY7QfzrnXRCx55-~g3DaPcU8nuOfhwHAmlQzzvkortQIT2v2OP81~Kh8FW64go7Da~L~4BLPclq2xBcgl9Nk3NKMDIsCPVcVOOOTODz5yvwUbrhxZ7MmPHSxaGxLe8hvJqbrWP~hWgcouM-BLMvFupsRe1thYQhA__&Key-Pair-Id=APKAJP2D34UGZ6IG443Q", thumbURL1000: "https://stagingcdn.permanent.org/00in-0000.thumb.w1000?t=1686306811&Expires=1686306811&Signature=Y72DJ9LSrpWQIy2UkUWGil6ZkKaOl2CDJMD9mhxKjl7uPgDpcb3h8KKnjI34~1GyRgsDbB~rE2-TjhO2y7zm2YMfhHEu7yggh8F8wpVBJnETi-O4R0sceWu3pgeSXkyQ5rW~I3mkGPRV8IyoC2s1ByTN1Tsk0s9zGVyGZ3YleJMxikKt3YRM~PEOE69d414aVlI8RxPRkwnHl10T51V5lpTRHANUkuGlt0UclXfMbNkv3aS2r50Ejyj3nbML48oVXXzuwswLnY5GQ0FAq-kPggPlDI-7WSAmozkVHscsO5RE1FUiYNy-TqhKBPE~hk6BDd70n9cMyDr~O2ac9IhoUg__&Key-Pair-Id=APKAJP2D34UGZ6IG443Q", thumbURL2000: "https://stagingcdn.permanent.org/00in-0000.thumb.w2000?t=1686306811&Expires=1686306811&Signature=Bay2a-H0hfxh91Tzdz3MmK6sZBuCkK0TTuu54nhQojMqbXzlFZ-Hxqchcixa0lweYW41v4iRJBymD49af92VMlFZYgDwmw8ER6P3iofgGI99y8nMaPGrMsZNV834p-xiZsgD53WLnuR7m5hEOy588-EBYqZjTp9pBCAKaPV-5IcjngvNOh6LcYmX~9kvWchG~NMamkmRLZ0mb5wGNtjny6ZCMcuCC5ta4hdro~NYhGCOqEnz9d35ofjdSqorxIB2gyX2mpIJsyYy9DoEIB5hFwQIgUP9DMZexEB3Bj1sArP5HJ54IKYwqsvXSy64EQMGHSlSMRiu7FAqvttaUhyINg__&Key-Pair-Id=APKAJP2D34UGZ6IG443Q", thumbDT: "2023-06-09T10:33:31", createdDT: "2021-01-27T19:48:08", updatedDT: "2022-07-07T07:45:44", status: ArchiveVOData.Status.ok) let token: String = "token" diff --git a/PermanentTests/ShareExtensionTests.swift b/PermanentTests/ShareExtensionTests.swift index dcf8ff0d..af16e7fc 100644 --- a/PermanentTests/ShareExtensionTests.swift +++ b/PermanentTests/ShareExtensionTests.swift @@ -13,9 +13,9 @@ import KeychainSwift class ShareExtensionTests: XCTestCase { var sut: ShareExtensionViewModel! - let archiveNegativeTests = ArchiveVOData(childFolderVOS: nil, folderSizeVOS: nil, recordVOS: nil, accessRole: nil, fullName: nil, spaceTotal: nil, spaceLeft: nil, fileTotal: nil, fileLeft: nil, relationType: nil, homeCity: nil, homeState: nil, homeCountry: nil, itemVOS: nil, birthDay: nil, company: nil, archiveVODescription: nil, archiveID: nil, publicDT: nil, archiveNbr: nil, view: nil, viewProperty: nil, archiveVOPublic: nil, vaultKey: nil, thumbArchiveNbr: nil, type: nil, thumbStatus: nil, imageRatio: nil, thumbURL200: nil, thumbURL500: nil, thumbURL1000: nil, thumbURL2000: nil, thumbDT: nil, createdDT: nil, updatedDT: nil, status: nil) + let archiveNegativeTests = ArchiveVOData(childFolderVOS: nil, folderSizeVOS: nil, recordVOS: nil, accessRole: nil, fullName: nil, spaceTotal: nil, spaceLeft: nil, fileTotal: nil, fileLeft: nil, relationType: nil, homeCity: nil, homeState: nil, homeCountry: nil, itemVOS: nil, birthDay: nil, company: nil, archiveVODescription: nil, archiveID: nil, publicDT: nil, archiveNbr: nil, view: nil, viewProperty: nil, archiveVOPublic: nil, vaultKey: nil, thumbArchiveNbr: nil, type: nil, thumbStatus: nil, imageRatio: nil, thumbnail256: nil, thumbURL200: nil, thumbURL500: nil, thumbURL1000: nil, thumbURL2000: nil, thumbDT: nil, createdDT: nil, updatedDT: nil, status: nil) - let archivePositiveTests = ArchiveVOData(childFolderVOS: nil, folderSizeVOS: nil, recordVOS: nil, accessRole: "access.role.owner", fullName: "test name", spaceTotal: nil, spaceLeft: nil, fileTotal: nil, fileLeft: nil, relationType: nil, homeCity: nil, homeState: nil, homeCountry: nil, itemVOS: nil, birthDay: nil, company: nil, archiveVODescription: nil, archiveID: 1653, publicDT: "2021-01-27T19:48:08", archiveNbr: "00in-0000", view: nil, viewProperty: nil, archiveVOPublic: nil, vaultKey: nil, thumbArchiveNbr: "00in-000v", type: "type.archive.person", thumbStatus: ArchiveVOData.Status.ok, imageRatio: nil, thumbURL200: "https://stagingcdn.permanent.org/00in-0000.thumb.w200?t=1686306811&Expires=1686306811&Signature=ZXjq08upvH73kyiLZJb-IYlSO4Jz6SaICjGBwHlL-UaQqpd1VAK6KWKnkIQtrLgsfhdkUhwa-TZT5tBSOhFDoeXfxOSLEEF19ml0W~rhyWjXpxhbMhqCL3s43lQ4p0uTeo4KuGXxx6-egFIZK2Z-5hzL52e5tpUJ6r5gENiiSL5r02ZapGmnKDN-UmF6vxaGLYrIAFZ5CpIuV6zCLjaKjLl-P2Ehp~LVTogJF9Tq7vibVTwYcagN4dnO9iDRp4u2alv0SceW2n8NavGaby1tnvQekVnqajbL0Utl1s3kUxiZ2V9VQmGrNRrZ4RRC8lB1xG8hDlb4GpUaQ0H86xiESg__&Key-Pair-Id=APKAJP2D34UGZ6IG443Q", thumbURL500: "https://stagingcdn.permanent.org/00in-0000.thumb.w500?t=1686306811&Expires=1686306811&Signature=e5W18KBakMSwIr5EHohYgHf3Nz23VA7eb6-x-3D1NH6Lsq-hxJyIHf9CTCmcksK-HR-CJKyrnIDjA2frUwpT274sPQ4fqVbXh~Od5i7Nh2gv9Gogs73z2QZ5a4Vrnuxhl6ncxWlVixs8AiUu~3ZgjfGQjmk2YODr8aIfp2siAg3SoN0NG1tHQ5AY7QfzrnXRCx55-~g3DaPcU8nuOfhwHAmlQzzvkortQIT2v2OP81~Kh8FW64go7Da~L~4BLPclq2xBcgl9Nk3NKMDIsCPVcVOOOTODz5yvwUbrhxZ7MmPHSxaGxLe8hvJqbrWP~hWgcouM-BLMvFupsRe1thYQhA__&Key-Pair-Id=APKAJP2D34UGZ6IG443Q", thumbURL1000: "https://stagingcdn.permanent.org/00in-0000.thumb.w1000?t=1686306811&Expires=1686306811&Signature=Y72DJ9LSrpWQIy2UkUWGil6ZkKaOl2CDJMD9mhxKjl7uPgDpcb3h8KKnjI34~1GyRgsDbB~rE2-TjhO2y7zm2YMfhHEu7yggh8F8wpVBJnETi-O4R0sceWu3pgeSXkyQ5rW~I3mkGPRV8IyoC2s1ByTN1Tsk0s9zGVyGZ3YleJMxikKt3YRM~PEOE69d414aVlI8RxPRkwnHl10T51V5lpTRHANUkuGlt0UclXfMbNkv3aS2r50Ejyj3nbML48oVXXzuwswLnY5GQ0FAq-kPggPlDI-7WSAmozkVHscsO5RE1FUiYNy-TqhKBPE~hk6BDd70n9cMyDr~O2ac9IhoUg__&Key-Pair-Id=APKAJP2D34UGZ6IG443Q", thumbURL2000: "https://stagingcdn.permanent.org/00in-0000.thumb.w2000?t=1686306811&Expires=1686306811&Signature=Bay2a-H0hfxh91Tzdz3MmK6sZBuCkK0TTuu54nhQojMqbXzlFZ-Hxqchcixa0lweYW41v4iRJBymD49af92VMlFZYgDwmw8ER6P3iofgGI99y8nMaPGrMsZNV834p-xiZsgD53WLnuR7m5hEOy588-EBYqZjTp9pBCAKaPV-5IcjngvNOh6LcYmX~9kvWchG~NMamkmRLZ0mb5wGNtjny6ZCMcuCC5ta4hdro~NYhGCOqEnz9d35ofjdSqorxIB2gyX2mpIJsyYy9DoEIB5hFwQIgUP9DMZexEB3Bj1sArP5HJ54IKYwqsvXSy64EQMGHSlSMRiu7FAqvttaUhyINg__&Key-Pair-Id=APKAJP2D34UGZ6IG443Q", thumbDT: "2023-06-09T10:33:31", createdDT: "2021-01-27T19:48:08", updatedDT: "2022-07-07T07:45:44", status: ArchiveVOData.Status.ok) + let archivePositiveTests = ArchiveVOData(childFolderVOS: nil, folderSizeVOS: nil, recordVOS: nil, accessRole: "access.role.owner", fullName: "test name", spaceTotal: nil, spaceLeft: nil, fileTotal: nil, fileLeft: nil, relationType: nil, homeCity: nil, homeState: nil, homeCountry: nil, itemVOS: nil, birthDay: nil, company: nil, archiveVODescription: nil, archiveID: 1653, publicDT: "2021-01-27T19:48:08", archiveNbr: "00in-0000", view: nil, viewProperty: nil, archiveVOPublic: nil, vaultKey: nil, thumbArchiveNbr: "00in-000v", type: "type.archive.person", thumbStatus: ArchiveVOData.Status.ok, imageRatio: nil, thumbnail256: nil, thumbURL200: "https://stagingcdn.permanent.org/00in-0000.thumb.w200?t=1686306811&Expires=1686306811&Signature=ZXjq08upvH73kyiLZJb-IYlSO4Jz6SaICjGBwHlL-UaQqpd1VAK6KWKnkIQtrLgsfhdkUhwa-TZT5tBSOhFDoeXfxOSLEEF19ml0W~rhyWjXpxhbMhqCL3s43lQ4p0uTeo4KuGXxx6-egFIZK2Z-5hzL52e5tpUJ6r5gENiiSL5r02ZapGmnKDN-UmF6vxaGLYrIAFZ5CpIuV6zCLjaKjLl-P2Ehp~LVTogJF9Tq7vibVTwYcagN4dnO9iDRp4u2alv0SceW2n8NavGaby1tnvQekVnqajbL0Utl1s3kUxiZ2V9VQmGrNRrZ4RRC8lB1xG8hDlb4GpUaQ0H86xiESg__&Key-Pair-Id=APKAJP2D34UGZ6IG443Q", thumbURL500: "https://stagingcdn.permanent.org/00in-0000.thumb.w500?t=1686306811&Expires=1686306811&Signature=e5W18KBakMSwIr5EHohYgHf3Nz23VA7eb6-x-3D1NH6Lsq-hxJyIHf9CTCmcksK-HR-CJKyrnIDjA2frUwpT274sPQ4fqVbXh~Od5i7Nh2gv9Gogs73z2QZ5a4Vrnuxhl6ncxWlVixs8AiUu~3ZgjfGQjmk2YODr8aIfp2siAg3SoN0NG1tHQ5AY7QfzrnXRCx55-~g3DaPcU8nuOfhwHAmlQzzvkortQIT2v2OP81~Kh8FW64go7Da~L~4BLPclq2xBcgl9Nk3NKMDIsCPVcVOOOTODz5yvwUbrhxZ7MmPHSxaGxLe8hvJqbrWP~hWgcouM-BLMvFupsRe1thYQhA__&Key-Pair-Id=APKAJP2D34UGZ6IG443Q", thumbURL1000: "https://stagingcdn.permanent.org/00in-0000.thumb.w1000?t=1686306811&Expires=1686306811&Signature=Y72DJ9LSrpWQIy2UkUWGil6ZkKaOl2CDJMD9mhxKjl7uPgDpcb3h8KKnjI34~1GyRgsDbB~rE2-TjhO2y7zm2YMfhHEu7yggh8F8wpVBJnETi-O4R0sceWu3pgeSXkyQ5rW~I3mkGPRV8IyoC2s1ByTN1Tsk0s9zGVyGZ3YleJMxikKt3YRM~PEOE69d414aVlI8RxPRkwnHl10T51V5lpTRHANUkuGlt0UclXfMbNkv3aS2r50Ejyj3nbML48oVXXzuwswLnY5GQ0FAq-kPggPlDI-7WSAmozkVHscsO5RE1FUiYNy-TqhKBPE~hk6BDd70n9cMyDr~O2ac9IhoUg__&Key-Pair-Id=APKAJP2D34UGZ6IG443Q", thumbURL2000: "https://stagingcdn.permanent.org/00in-0000.thumb.w2000?t=1686306811&Expires=1686306811&Signature=Bay2a-H0hfxh91Tzdz3MmK6sZBuCkK0TTuu54nhQojMqbXzlFZ-Hxqchcixa0lweYW41v4iRJBymD49af92VMlFZYgDwmw8ER6P3iofgGI99y8nMaPGrMsZNV834p-xiZsgD53WLnuR7m5hEOy588-EBYqZjTp9pBCAKaPV-5IcjngvNOh6LcYmX~9kvWchG~NMamkmRLZ0mb5wGNtjny6ZCMcuCC5ta4hdro~NYhGCOqEnz9d35ofjdSqorxIB2gyX2mpIJsyYy9DoEIB5hFwQIgUP9DMZexEB3Bj1sArP5HJ54IKYwqsvXSy64EQMGHSlSMRiu7FAqvttaUhyINg__&Key-Pair-Id=APKAJP2D34UGZ6IG443Q", thumbDT: "2023-06-09T10:33:31", createdDT: "2021-01-27T19:48:08", updatedDT: "2022-07-07T07:45:44", status: ArchiveVOData.Status.ok) let token: String = "token" diff --git a/PermanentTests/ShareItemViewModelTests.swift b/PermanentTests/ShareItemViewModelTests.swift index 57ae52d5..4555a924 100644 --- a/PermanentTests/ShareItemViewModelTests.swift +++ b/PermanentTests/ShareItemViewModelTests.swift @@ -43,7 +43,7 @@ final class ShareItemViewModelTests: XCTestCase { ) XCTAssertEqual(vm.fileName, fileModel.name, "File name should match") - XCTAssertEqual(vm.thumbnailURL, fileModel.thumbnailURL500, "Thumbnail URL should match") + XCTAssertEqual(vm.thumbnailURL, fileModel.preferredThumbnailURL, "Thumbnail URL should match") XCTAssertFalse(vm.isFolder, "Mock file should not be folder") } @@ -1357,3 +1357,411 @@ extension FileModel { ) } } + +final class ThumbnailSelectionTests: XCTestCase { + func testRecordPreferredThumbnailURL_UsesThumbnail256First() throws { + let record = try decode( + RecordVOData.self, + from: """ + { + "thumbnail256": "https://example.com/thumb256.jpg", + "thumbURL200": "https://example.com/thumb200.jpg", + "thumbURL500": "https://example.com/thumb500.jpg", + "thumbURL1000": "https://example.com/thumb1000.jpg", + "thumbURL2000": "https://example.com/thumb2000.jpg" + } + """ + ) + + XCTAssertEqual(record.preferredThumbnailURL, "https://example.com/thumb256.jpg") + } + + func testRecordPreferredThumbnailURL_FallsBackWhenThumbnail256Missing() throws { + let record = try decode( + RecordVOData.self, + from: """ + { + "thumbURL200": "https://example.com/thumb200.jpg", + "thumbURL500": "https://example.com/thumb500.jpg", + "thumbURL1000": "https://example.com/thumb1000.jpg", + "thumbURL2000": "https://example.com/thumb2000.jpg" + } + """ + ) + + XCTAssertEqual(record.preferredThumbnailURL, "https://example.com/thumb500.jpg") + } + + func testRecordPreferredThumbnailURL_UsesNextAvailableFallback() throws { + let record = try decode( + RecordVOData.self, + from: """ + { + "thumbURL1000": "https://example.com/thumb1000.jpg", + "thumbURL2000": "https://example.com/thumb2000.jpg" + } + """ + ) + + XCTAssertEqual(record.preferredThumbnailURL, "https://example.com/thumb1000.jpg") + } + + func testItemPreferredThumbnailURL_UsesThumbnail256First() throws { + let item = try decode( + ItemVO.self, + from: """ + { + "thumbnail256": "https://example.com/thumb256.jpg", + "thumbURL200": "https://example.com/thumb200.jpg", + "thumbURL500": "https://example.com/thumb500.jpg" + } + """ + ) + + XCTAssertEqual(item.preferredThumbnailURL, "https://example.com/thumb256.jpg") + } + + func testFolderPreferredThumbnailURL_FallsBackTo200When500Missing() throws { + let folder = try decode( + FolderVOData.self, + from: """ + { + "thumbURL200": "https://example.com/thumb200.jpg", + "thumbURL1000": "https://example.com/thumb1000.jpg" + } + """ + ) + + XCTAssertEqual(folder.preferredThumbnailURL, "https://example.com/thumb200.jpg") + } + + func testArchivePreferredThumbnailURL_UsesThumbnail256First() throws { + let archive = try decode( + ArchiveVOData.self, + from: """ + { + "thumbnail256": "https://example.com/thumb256.jpg", + "thumbURL500": "https://example.com/thumb500.jpg", + "thumbURL2000": "https://example.com/thumb2000.jpg" + } + """ + ) + + XCTAssertEqual(archive.preferredThumbnailURL, "https://example.com/thumb256.jpg") + } + + func testRecordFileModel_UsesThumbnail256ForPreferredThumbnail() throws { + let record = try decode( + RecordVOData.self, + from: """ + { + "displayName": "IMG_0111", + "displayDT": "2026-04-17T11:44:53", + "thumbnail256": "https://example.com/thumb256.jpg", + "thumbURL200": "https://example.com/thumb200.jpg", + "thumbURL500": "https://example.com/thumb500.jpg", + "type": "type.record.image", + "archiveId": 1, + "archiveNbr": "0fsv-009b", + "recordId": 2137129, + "parentFolderId": 180530, + "parentFolder_linkId": 1356908, + "folder_linkId": 2144172 + } + """ + ) + + let fileModel = FileModel(model: record, permissions: [.read], accessRole: .viewer) + + XCTAssertEqual(fileModel.thumbnailURL256, "https://example.com/thumb256.jpg") + XCTAssertEqual(fileModel.preferredThumbnailURL, "https://example.com/thumb256.jpg") + XCTAssertEqual(fileModel.thumbnailURL500, "https://example.com/thumb256.jpg") + } + + func testFolderFileModel_UsesThumbnail256ForPreferredThumbnail() throws { + let folder = try decode( + FolderVOData.self, + from: """ + { + "displayName": "Public", + "displayDT": "2026-04-17T11:44:53", + "thumbnail256": "https://example.com/thumb256.jpg", + "thumbURL200": "https://example.com/thumb200.jpg", + "thumbURL500": "https://example.com/thumb500.jpg", + "archiveId": 1, + "archiveNbr": "0fsv-0004", + "folderId": 180531, + "parentFolderId": 180528, + "parentFolder_linkId": 1356906, + "folder_linkId": 1356909 + } + """ + ) + + let fileModel = FileModel(model: folder) + + XCTAssertEqual(fileModel.thumbnailURL256, "https://example.com/thumb256.jpg") + XCTAssertEqual(fileModel.preferredThumbnailURL, "https://example.com/thumb256.jpg") + XCTAssertEqual(fileModel.thumbnailURL500, "https://example.com/thumb256.jpg") + } + + func testRecordV2PreferredThumbnailURL_UsesThumbnailUrls256WhenTopLevelThumbnail256Missing() throws { + let record = try decode( + RecordV2Data.self, + from: """ + { + "thumbnailUrls": { + "256": "https://example.com/thumb256.jpg", + "500": "https://example.com/thumb500-from-map.jpg" + }, + "thumbUrl200": "https://example.com/thumb200.jpg", + "thumbUrl500": "https://example.com/thumb500.jpg", + "thumbUrl1000": "https://example.com/thumb1000.jpg", + "thumbUrl2000": "https://example.com/thumb2000.jpg" + } + """ + ) + + XCTAssertEqual(record.resolvedThumbnail256, "https://example.com/thumb256.jpg") + XCTAssertEqual(record.preferredThumbnailURL, "https://example.com/thumb256.jpg") + } + + func testRecordV2PreferredThumbnailURL_PrefersTopLevelThumbnail256OverThumbnailUrls256() throws { + let record = try decode( + RecordV2Data.self, + from: """ + { + "thumbnail256": "https://example.com/top-level-256.jpg", + "thumbnailUrls": { + "256": "https://example.com/nested-256.jpg" + }, + "thumbUrl500": "https://example.com/thumb500.jpg" + } + """ + ) + + XCTAssertEqual(record.resolvedThumbnail256, "https://example.com/top-level-256.jpg") + XCTAssertEqual(record.preferredThumbnailURL, "https://example.com/top-level-256.jpg") + } + + func testRecordV2PreferredThumbnailURL_FallsBackToThumbUrl500WhenNo256IsAvailable() throws { + let record = try decode( + RecordV2Data.self, + from: """ + { + "thumbUrl200": "https://example.com/thumb200.jpg", + "thumbUrl500": "https://example.com/thumb500.jpg", + "thumbUrl1000": "https://example.com/thumb1000.jpg" + } + """ + ) + + XCTAssertNil(record.resolvedThumbnail256) + XCTAssertEqual(record.preferredThumbnailURL, "https://example.com/thumb500.jpg") + } + + func testRecordShareArchiveV2PreferredThumbnailURL_UsesThumbnailUrls256() throws { + let archive = try decode( + RecordShareArchiveV2.self, + from: """ + { + "id": "21588", + "thumbnailUrls": { + "256": "https://example.com/thumb256.jpg" + }, + "thumbUrl500": "https://example.com/thumb500.jpg", + "thumbUrl200": "https://example.com/thumb200.jpg" + } + """ + ) + + XCTAssertEqual(archive.resolvedThumbnail256, "https://example.com/thumb256.jpg") + XCTAssertEqual(archive.preferredThumbnailURL, "https://example.com/thumb256.jpg") + } + + // MARK: - Empty String Handling Tests + + func testRecordV2PreferredThumbnailURL_SkipsEmptyThumbnail256() throws { + let record = try decode( + RecordV2Data.self, + from: """ + { + "thumbnail256": "", + "thumbUrl500": "https://example.com/thumb500.jpg", + "thumbUrl200": "https://example.com/thumb200.jpg" + } + """ + ) + + XCTAssertNil(record.resolvedThumbnail256, "Empty thumbnail256 should be treated as nil") + XCTAssertEqual(record.preferredThumbnailURL, "https://example.com/thumb500.jpg", + "Should fall through to thumbUrl500 when thumbnail256 is empty") + } + + func testRecordV2PreferredThumbnailURL_SkipsEmptyThumbnailUrls256() throws { + let record = try decode( + RecordV2Data.self, + from: """ + { + "thumbnailUrls": { + "256": "" + }, + "thumbUrl500": "https://example.com/thumb500.jpg" + } + """ + ) + + XCTAssertNil(record.resolvedThumbnail256, "Empty thumbnailUrls.256 should be treated as nil") + XCTAssertEqual(record.preferredThumbnailURL, "https://example.com/thumb500.jpg") + } + + func testRecordV2PreferredThumbnailURL_SkipsAllEmptyStrings() throws { + let record = try decode( + RecordV2Data.self, + from: """ + { + "thumbnail256": "", + "thumbUrl500": "", + "thumbUrl200": "", + "thumbUrl1000": "", + "thumbUrl2000": "https://example.com/thumb2000.jpg" + } + """ + ) + + XCTAssertEqual(record.preferredThumbnailURL, "https://example.com/thumb2000.jpg", + "Should skip all empty strings and use the first non-empty URL") + } + + func testRecordV2PreferredThumbnailURL_ReturnsNilWhenAllEmpty() throws { + let record = try decode( + RecordV2Data.self, + from: """ + { + "thumbnail256": "", + "thumbUrl500": "", + "thumbUrl200": "", + "thumbUrl1000": "", + "thumbUrl2000": "" + } + """ + ) + + XCTAssertNil(record.preferredThumbnailURL, + "Should return nil when all thumbnail URLs are empty strings") + } + + func testRecordShareArchiveV2PreferredThumbnailURL_SkipsEmptyStrings() throws { + let archive = try decode( + RecordShareArchiveV2.self, + from: """ + { + "id": "21588", + "thumbnail256": "", + "thumbUrl500": "", + "thumbUrl200": "https://example.com/thumb200.jpg" + } + """ + ) + + XCTAssertNil(archive.resolvedThumbnail256, "Empty thumbnail256 should be treated as nil") + XCTAssertEqual(archive.preferredThumbnailURL, "https://example.com/thumb200.jpg", + "Should skip empty strings and use first valid URL") + } + + func testArchiveVOPreferredThumbnailURL_SkipsEmptyStrings() throws { + let archive = try decode( + ArchiveVOData.self, + from: """ + { + "thumbnail256": "", + "thumbURL500": "", + "thumbURL200": "https://example.com/thumb200.jpg" + } + """ + ) + + XCTAssertEqual(archive.preferredThumbnailURL, "https://example.com/thumb200.jpg", + "Should skip empty strings and use first valid URL") + } + + func testFileModelPreferredThumbnailURL_SkipsEmptyStrings() throws { + let record = try decode( + RecordVOData.self, + from: """ + { + "displayName": "Test.jpg", + "thumbnail256": "", + "thumbURL500": "", + "thumbURL200": "", + "thumbURL1000": "", + "thumbURL2000": "https://example.com/thumb2000.jpg", + "type": "type.record.image", + "archiveId": 1, + "archiveNbr": "0001-0000", + "recordId": 1, + "parentFolderId": 1, + "parentFolder_linkId": 1, + "folder_linkId": 1 + } + """ + ) + + let fileModel = FileModel(model: record, permissions: [.read], accessRole: .viewer) + + XCTAssertEqual(fileModel.preferredThumbnailURL, "https://example.com/thumb2000.jpg", + "Should skip empty strings and use first valid URL") + } + + func testFileModelPreferredThumbnailURL_ReturnsNilWhenAllEmpty() throws { + let record = try decode( + RecordVOData.self, + from: """ + { + "displayName": "Test.jpg", + "thumbnail256": "", + "thumbURL500": "", + "thumbURL200": "", + "thumbURL1000": "", + "thumbURL2000": "", + "type": "type.record.image", + "archiveId": 1, + "archiveNbr": "0001-0000", + "recordId": 1, + "parentFolderId": 1, + "parentFolder_linkId": 1, + "folder_linkId": 1 + } + """ + ) + + let fileModel = FileModel(model: record, permissions: [.read], accessRole: .viewer) + + XCTAssertNil(fileModel.preferredThumbnailURL, + "Should return nil when all thumbnail URLs are empty") + } + + @MainActor + func testShareItemViewModel_ThumbnailURL_WithNoThumbnails() { + let fileModel = FileModel( + name: "Test.jpg", + recordId: 1, + folderLinkId: 1, + archiveNbr: "0001-0000", + type: "type.record.image", + permissions: [.read] + ) + + let vm = ShareItemViewModel( + fileModel: fileModel, + shareManagementRepository: MockShareManagementRepository() + ) + + XCTAssertNil(vm.thumbnailURL, "Should return nil when fileModel has no valid thumbnail URLs") + } +} + +private func decode(_ type: T.Type, from json: String) throws -> T { + let data = Data(json.utf8) + return try JSONDecoder().decode(T.self, from: data) +} diff --git a/PermanentTests/SharePreviewSwiftUIViewModelTests.swift b/PermanentTests/SharePreviewSwiftUIViewModelTests.swift index 1dc3e15f..3996f361 100644 --- a/PermanentTests/SharePreviewSwiftUIViewModelTests.swift +++ b/PermanentTests/SharePreviewSwiftUIViewModelTests.swift @@ -115,7 +115,7 @@ final class SharePreviewSwiftUIViewModelTests: XCTestCase { itemVOS: nil, birthDay: nil, company: nil, archiveVODescription: nil, archiveID: 9999, publicDT: nil, archiveNbr: "9999-0000", view: nil, viewProperty: nil, archiveVOPublic: nil, vaultKey: nil, - thumbArchiveNbr: nil, type: nil, thumbStatus: nil, imageRatio: nil, + thumbArchiveNbr: nil, type: nil, thumbStatus: nil, imageRatio: nil, thumbnail256: nil, thumbURL200: nil, thumbURL500: nil, thumbURL1000: nil, thumbURL2000: nil, thumbDT: nil, createdDT: nil, updatedDT: nil, status: nil ) @@ -158,7 +158,7 @@ final class SharePreviewSwiftUIViewModelTests: XCTestCase { itemVOS: nil, birthDay: nil, company: nil, archiveVODescription: nil, archiveID: 9999, publicDT: nil, archiveNbr: "9999-0000", view: nil, viewProperty: nil, archiveVOPublic: nil, vaultKey: nil, - thumbArchiveNbr: nil, type: nil, thumbStatus: nil, imageRatio: nil, + thumbArchiveNbr: nil, type: nil, thumbStatus: nil, imageRatio: nil, thumbnail256: nil, thumbURL200: nil, thumbURL500: nil, thumbURL1000: nil, thumbURL2000: nil, thumbDT: nil, createdDT: nil, updatedDT: nil, status: nil ) @@ -834,7 +834,7 @@ final class SharePreviewSwiftUIViewModelTests: XCTestCase { birthDay: nil, company: nil, archiveVODescription: nil, archiveID: 9999, publicDT: nil, archiveNbr: "9999-0000", view: nil, viewProperty: nil, archiveVOPublic: nil, vaultKey: nil, thumbArchiveNbr: nil, type: nil, - thumbStatus: nil, imageRatio: nil, thumbURL200: nil, thumbURL500: nil, + thumbStatus: nil, imageRatio: nil, thumbnail256: nil, thumbURL200: nil, thumbURL500: nil, thumbURL1000: nil, thumbURL2000: nil, thumbDT: nil, createdDT: nil, updatedDT: nil, status: nil ) @@ -881,7 +881,7 @@ final class SharePreviewSwiftUIViewModelTests: XCTestCase { birthDay: nil, company: nil, archiveVODescription: nil, archiveID: 9999, publicDT: nil, archiveNbr: "9999-0000", view: nil, viewProperty: nil, archiveVOPublic: nil, vaultKey: nil, thumbArchiveNbr: nil, type: nil, - thumbStatus: nil, imageRatio: nil, thumbURL200: nil, thumbURL500: nil, + thumbStatus: nil, imageRatio: nil, thumbnail256: nil, thumbURL200: nil, thumbURL500: nil, thumbURL1000: nil, thumbURL2000: nil, thumbDT: nil, createdDT: nil, updatedDT: nil, status: nil ) @@ -1199,7 +1199,7 @@ final class SharePreviewSwiftUIViewModelTests: XCTestCase { birthDay: nil, company: nil, archiveVODescription: nil, archiveID: 9999, publicDT: nil, archiveNbr: "9999-0000", view: nil, viewProperty: nil, archiveVOPublic: nil, vaultKey: nil, thumbArchiveNbr: nil, type: nil, - thumbStatus: nil, imageRatio: nil, thumbURL200: nil, thumbURL500: nil, + thumbStatus: nil, imageRatio: nil, thumbnail256: nil, thumbURL200: nil, thumbURL500: nil, thumbURL1000: nil, thumbURL2000: nil, thumbDT: nil, createdDT: nil, updatedDT: nil, status: nil ) @@ -1362,7 +1362,7 @@ final class SharePreviewSwiftUIViewModelTests: XCTestCase { birthDay: nil, company: nil, archiveVODescription: nil, archiveID: 9999, publicDT: nil, archiveNbr: "9999-0000", view: nil, viewProperty: nil, archiveVOPublic: nil, vaultKey: nil, thumbArchiveNbr: nil, type: nil, - thumbStatus: nil, imageRatio: nil, thumbURL200: nil, thumbURL500: nil, + thumbStatus: nil, imageRatio: nil, thumbnail256: nil, thumbURL200: nil, thumbURL500: nil, thumbURL1000: nil, thumbURL2000: nil, thumbDT: nil, createdDT: nil, updatedDT: nil, status: nil ) @@ -1451,7 +1451,7 @@ final class SharePreviewSwiftUIViewModelTests: XCTestCase { birthDay: nil, company: nil, archiveVODescription: nil, archiveID: 10629, publicDT: nil, archiveNbr: "07cm-0000", view: nil, viewProperty: nil, archiveVOPublic: nil, vaultKey: nil, thumbArchiveNbr: nil, type: nil, - thumbStatus: nil, imageRatio: nil, thumbURL200: nil, thumbURL500: nil, + thumbStatus: nil, imageRatio: nil, thumbnail256: nil, thumbURL200: nil, thumbURL500: nil, thumbURL1000: nil, thumbURL2000: nil, thumbDT: nil, createdDT: nil, updatedDT: nil, status: .ok ) @@ -1483,7 +1483,7 @@ final class SharePreviewSwiftUIViewModelTests: XCTestCase { birthDay: nil, company: nil, archiveVODescription: nil, archiveID: 10272, publicDT: nil, archiveNbr: "072p-0000", view: nil, viewProperty: nil, archiveVOPublic: nil, vaultKey: nil, thumbArchiveNbr: nil, type: nil, - thumbStatus: nil, imageRatio: nil, thumbURL200: nil, thumbURL500: nil, + thumbStatus: nil, imageRatio: nil, thumbnail256: nil, thumbURL200: nil, thumbURL500: nil, thumbURL1000: nil, thumbURL2000: nil, thumbDT: nil, createdDT: nil, updatedDT: nil, status: .ok ) @@ -1514,7 +1514,7 @@ final class SharePreviewSwiftUIViewModelTests: XCTestCase { birthDay: nil, company: nil, archiveVODescription: nil, archiveID: 99999, publicDT: nil, archiveNbr: "9999-0000", view: nil, viewProperty: nil, archiveVOPublic: nil, vaultKey: nil, thumbArchiveNbr: nil, type: nil, - thumbStatus: nil, imageRatio: nil, thumbURL200: nil, thumbURL500: nil, + thumbStatus: nil, imageRatio: nil, thumbnail256: nil, thumbURL200: nil, thumbURL500: nil, thumbURL1000: nil, thumbURL2000: nil, thumbDT: nil, createdDT: nil, updatedDT: nil, status: .ok ) @@ -1814,6 +1814,7 @@ private struct RestrictedShareApprovedRepo: SharePreviewRepositoryProtocol { type: data.folderData?.type, thumbStatus: data.folderData?.thumbStatus, imageRatio: data.folderData?.imageRatio, + thumbnail256: data.folderData?.thumbnail256, thumbURL200: data.folderData?.thumbURL200, thumbURL500: data.folderData?.thumbURL500, thumbURL1000: data.folderData?.thumbURL1000, diff --git a/PermanentTests/SharePreviewViewModelTests.swift b/PermanentTests/SharePreviewViewModelTests.swift index 29fff72f..aad3e934 100644 --- a/PermanentTests/SharePreviewViewModelTests.swift +++ b/PermanentTests/SharePreviewViewModelTests.swift @@ -290,6 +290,7 @@ final class SharePreviewViewModelTests: XCTestCase { archiveID: 123, publicDT: nil, archiveNbr: "00te-0000", view: nil, viewProperty: nil, archiveVOPublic: nil, vaultKey: nil, thumbArchiveNbr: nil, type: nil, thumbStatus: nil, imageRatio: nil, + thumbnail256: nil, thumbURL200: nil, thumbURL500: nil, thumbURL1000: nil, thumbURL2000: nil, thumbDT: nil, createdDT: nil, updatedDT: nil, status: nil ) @@ -344,6 +345,7 @@ final class SharePreviewViewModelTests: XCTestCase { archiveID: id, publicDT: nil, archiveNbr: "0001-0000", view: nil, viewProperty: nil, archiveVOPublic: nil, vaultKey: nil, thumbArchiveNbr: nil, type: nil, thumbStatus: nil, imageRatio: nil, + thumbnail256: nil, thumbURL200: nil, thumbURL500: nil, thumbURL1000: nil, thumbURL2000: nil, thumbDT: nil, createdDT: nil, updatedDT: nil, status: .ok )