parent
812797bed7
commit
2368bb8d56
|
@ -67,6 +67,16 @@ public struct ThumbnailProperties: Hashable {
|
|||
|
||||
public extension WebDAV {
|
||||
|
||||
enum ThumbnailPreviewMode {
|
||||
/// Only show a preview thumbnail if there is already one loaded into memory.
|
||||
case memoryOnly
|
||||
/// Allow the disk cache to be loaded if there are no thumbnails in memory.
|
||||
/// Note that this can be an expensive process and is run on the main thread.
|
||||
case diskAllowed
|
||||
/// Load the specific thumbnail if available, from disk if not in memory.
|
||||
case specific(ThumbnailProperties)
|
||||
}
|
||||
|
||||
//MARK: Images
|
||||
|
||||
/// Download and cache an image from the specified file path.
|
||||
|
@ -75,16 +85,40 @@ public extension WebDAV {
|
|||
/// - account: The WebDAV account.
|
||||
/// - password: The WebDAV account's password.
|
||||
/// - options: Options for caching the results. Empty set uses default caching behavior.
|
||||
/// - completion: If account properties are invalid, this will run immediately on the same thread.
|
||||
/// Otherwise, it runs when the network call finishes on a background thread.
|
||||
/// - preview: Behavior for running the completion closure with cached thumbnails before the full-sized image is fetched.
|
||||
/// Note that `.diskAllowed` will load all thumbnails for the given image
|
||||
/// will be fetched on the main thread, which can be an expensive process.
|
||||
/// `.memoryOnly` and `.specific()` are recommended.
|
||||
/// - completion: If account properties are invalid, this will run immediately on the same thread with an error.
|
||||
/// Otherwise, it will run on the main thread with a preview if available and a `preview` mode is provided,
|
||||
/// then runs on a background thread when the network call finishes.
|
||||
/// - image: The image downloaded, if successful.
|
||||
/// The cached image if it has already been downloaded.
|
||||
/// - cachedImageURL: The URL of the cached image.
|
||||
/// - error: A WebDAVError if the call was unsuccessful. `nil` if it was.
|
||||
/// - Returns: The request identifier.
|
||||
@discardableResult
|
||||
func downloadImage<A: WebDAVAccount>(path: String, account: A, password: String, caching options: WebDAVCachingOptions = [], completion: @escaping (_ image: UIImage?, _ error: WebDAVError?) -> Void) -> URLSessionDataTask? {
|
||||
cachingDataTask(cache: imageCache, path: path, account: account, password: password, caching: options, valueFromData: { UIImage(data: $0) }, completion: completion)
|
||||
func downloadImage<A: WebDAVAccount>(path: String, account: A, password: String, caching options: WebDAVCachingOptions = [], preview: ThumbnailPreviewMode? = .none, completion: @escaping (_ image: UIImage?, _ error: WebDAVError?) -> Void) -> URLSessionDataTask? {
|
||||
cachingDataTask(cache: imageCache, path: path, account: account, password: password, caching: options, valueFromData: { UIImage(data: $0) }, placeholder: {
|
||||
// Load placeholder thumbnail
|
||||
var thumbnails = self.getAllMemoryCachedThumbnails(forItemAtPath: path, account: account)?.values
|
||||
|
||||
switch preview {
|
||||
case .none:
|
||||
return nil
|
||||
case .specific(let properties):
|
||||
return self.getCachedThumbnail(forItemAtPath: path, account: account, with: properties)
|
||||
case .memoryOnly:
|
||||
break
|
||||
case .diskAllowed:
|
||||
// Only load from disk if there aren't any in memory
|
||||
if thumbnails?.isEmpty ?? true {
|
||||
thumbnails = self.getAllMemoryCachedThumbnails(forItemAtPath: path, account: account)?.values
|
||||
}
|
||||
}
|
||||
let largestThumbnail = thumbnails?.max(by: { $0.size.width * $0.size.height < $1.size.width * $1.size.height })
|
||||
return largestThumbnail
|
||||
}, completion: completion)
|
||||
}
|
||||
|
||||
//MARK: Thumbnails
|
||||
|
|
|
@ -384,7 +384,10 @@ extension WebDAV {
|
|||
|
||||
//MARK: Standard Requests
|
||||
|
||||
func cachingDataTask<A: WebDAVAccount, Value: Equatable>(cache: Cache<AccountPath, Value>, path: String, account: A, password: String, caching options: WebDAVCachingOptions, valueFromData: @escaping (_ data: Data) -> Value?, completion: @escaping (_ value: Value?, _ error: WebDAVError?) -> Void) -> URLSessionDataTask? {
|
||||
func cachingDataTask<A: WebDAVAccount, Value: Equatable>(
|
||||
cache: Cache<AccountPath, Value>, path: String, account: A, password: String,
|
||||
caching options: WebDAVCachingOptions, valueFromData: @escaping (_ data: Data) -> Value?, placeholder: (() -> Value?)? = nil,
|
||||
completion: @escaping (_ value: Value?, _ error: WebDAVError?) -> Void) -> URLSessionDataTask? {
|
||||
|
||||
// Check cache
|
||||
|
||||
|
@ -407,10 +410,16 @@ extension WebDAV {
|
|||
}
|
||||
}
|
||||
|
||||
// Cached data was not returned. Continue with network fetch.
|
||||
|
||||
if options.contains(.removeExistingCache) {
|
||||
try? deleteCachedData(forItemAtPath: path, account: account)
|
||||
}
|
||||
|
||||
if let placeholderValue = placeholder?() {
|
||||
completion(placeholderValue, nil)
|
||||
}
|
||||
|
||||
// Create network request
|
||||
|
||||
guard let request = authorizedRequest(path: path, account: account, password: password, method: .get) else {
|
||||
|
|
|
@ -511,7 +511,7 @@ final class WebDAVTests: XCTestCase {
|
|||
XCTAssertNoThrow(try webDAV.deleteCachedData(forItemAtPath: imagePath, account: account))
|
||||
}
|
||||
|
||||
//MARK: Image Cache
|
||||
//MARK: Images
|
||||
|
||||
func testDownloadImage() {
|
||||
guard let (account, password) = getAccount() else { return XCTFail() }
|
||||
|
@ -628,6 +628,30 @@ final class WebDAVTests: XCTestCase {
|
|||
XCTAssertFalse(FileManager.default.fileExists(atPath: cachedThumbnailFitURL.path))
|
||||
}
|
||||
|
||||
func testThumbnailPlaceholder() {
|
||||
guard let (account, password) = getAccount() else { return XCTFail() }
|
||||
guard let imagePath = ProcessInfo.processInfo.environment["image_path"] else {
|
||||
return XCTFail("You need to set the image_path in the environment.")
|
||||
}
|
||||
|
||||
let expectation = XCTestExpectation(description: "Fetch image")
|
||||
// Check that the completion closure is run first
|
||||
// on the preview then again for the image itself.
|
||||
expectation.expectedFulfillmentCount = 2
|
||||
|
||||
downloadThumbnail(imagePath: imagePath, account: account, password: password)
|
||||
|
||||
try? webDAV.deleteCachedData(forItemAtPath: imagePath, account: account)
|
||||
webDAV.downloadImage(path: imagePath, account: account, password: password, preview: .memoryOnly) { image, error in
|
||||
XCTAssertNil(error)
|
||||
XCTAssertNotNil(image)
|
||||
expectation.fulfill()
|
||||
}
|
||||
try? webDAV.deleteCachedData(forItemAtPath: imagePath, account: account)
|
||||
|
||||
wait(for: [expectation], timeout: 10.0)
|
||||
}
|
||||
|
||||
//MARK: OCS
|
||||
|
||||
func testColorHex() {
|
||||
|
@ -800,6 +824,7 @@ final class WebDAVTests: XCTestCase {
|
|||
("testThumbnailCacheURL", testThumbnailCacheURL),
|
||||
("testSpecificThumbnailCache", testSpecificThumbnailCache),
|
||||
("testGeneralThumbnailCache", testGeneralThumbnailCache),
|
||||
("testThumbnailPlaceholder", testThumbnailPlaceholder),
|
||||
// OCS
|
||||
("testTheme", testTheme),
|
||||
("testColorHex", testColorHex)
|
||||
|
|
Loading…
Reference in New Issue