mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-09-04 03:40:45 +00:00
305 lines
10 KiB
Objective-C
305 lines
10 KiB
Objective-C
//
|
|
// ASPINRemoteImageDownloader.m
|
|
// AsyncDisplayKit
|
|
//
|
|
// Created by Garrett Moon on 2/5/16.
|
|
//
|
|
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
|
// This source code is licensed under the BSD-style license found in the
|
|
// LICENSE file in the root directory of this source tree. An additional grant
|
|
// of patent rights can be found in the PATENTS file in the same directory.
|
|
//
|
|
|
|
#if PIN_REMOTE_IMAGE
|
|
#import <AsyncDisplayKit/ASPINRemoteImageDownloader.h>
|
|
|
|
#import <AsyncDisplayKit/ASAssert.h>
|
|
#import <AsyncDisplayKit/ASThread.h>
|
|
#import <AsyncDisplayKit/ASImageContainerProtocolCategories.h>
|
|
|
|
#if __has_include (<PINRemoteImage/PINAnimatedImage.h>)
|
|
#define PIN_ANIMATED_AVAILABLE 1
|
|
#import <PINRemoteImage/PINAnimatedImage.h>
|
|
#import <PINRemoteImage/PINAlternateRepresentationProvider.h>
|
|
#else
|
|
#define PIN_ANIMATED_AVAILABLE 0
|
|
#endif
|
|
|
|
#import <PINRemoteImage/PINRemoteImageManager.h>
|
|
#import <PINRemoteImage/NSData+ImageDetectors.h>
|
|
#import <PINRemoteImage/PINRemoteImageCaching.h>
|
|
|
|
#if PIN_ANIMATED_AVAILABLE
|
|
|
|
@interface ASPINRemoteImageDownloader () <PINRemoteImageManagerAlternateRepresentationProvider>
|
|
|
|
@end
|
|
|
|
@interface PINAnimatedImage (ASPINRemoteImageDownloader) <ASAnimatedImageProtocol>
|
|
|
|
@end
|
|
|
|
@implementation PINAnimatedImage (ASPINRemoteImageDownloader)
|
|
|
|
- (void)setCoverImageReadyCallback:(void (^)(UIImage * _Nonnull))coverImageReadyCallback
|
|
{
|
|
self.infoCompletion = coverImageReadyCallback;
|
|
}
|
|
|
|
- (void (^)(UIImage * _Nonnull))coverImageReadyCallback
|
|
{
|
|
return self.infoCompletion;
|
|
}
|
|
|
|
- (void)setPlaybackReadyCallback:(dispatch_block_t)playbackReadyCallback
|
|
{
|
|
self.fileReady = playbackReadyCallback;
|
|
}
|
|
|
|
- (dispatch_block_t)playbackReadyCallback
|
|
{
|
|
return self.fileReady;
|
|
}
|
|
|
|
- (BOOL)isDataSupported:(NSData *)data
|
|
{
|
|
return [data pin_isGIF];
|
|
}
|
|
|
|
@end
|
|
#endif
|
|
|
|
@interface ASPINRemoteImageManager : PINRemoteImageManager
|
|
@end
|
|
|
|
@implementation ASPINRemoteImageManager
|
|
|
|
//Share image cache with sharedImageManager image cache.
|
|
- (id <PINRemoteImageCaching>)defaultImageCache
|
|
{
|
|
return [[PINRemoteImageManager sharedImageManager] cache];
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
static ASPINRemoteImageDownloader *sharedDownloader = nil;
|
|
|
|
@interface ASPINRemoteImageDownloader ()
|
|
@end
|
|
|
|
@implementation ASPINRemoteImageDownloader
|
|
|
|
+ (instancetype)sharedDownloader
|
|
{
|
|
|
|
static dispatch_once_t onceToken = 0;
|
|
dispatch_once(&onceToken, ^{
|
|
sharedDownloader = [[ASPINRemoteImageDownloader alloc] init];
|
|
});
|
|
return sharedDownloader;
|
|
}
|
|
|
|
+ (void)setSharedImageManagerWithConfiguration:(nullable NSURLSessionConfiguration *)configuration
|
|
{
|
|
NSAssert(sharedDownloader == nil, @"Singleton has been created and session can no longer be configured.");
|
|
__unused PINRemoteImageManager *sharedManager = [self sharedPINRemoteImageManagerWithConfiguration:configuration];
|
|
}
|
|
|
|
+ (PINRemoteImageManager *)sharedPINRemoteImageManagerWithConfiguration:(NSURLSessionConfiguration *)configuration
|
|
{
|
|
static ASPINRemoteImageManager *sharedPINRemoteImageManager;
|
|
static dispatch_once_t onceToken;
|
|
dispatch_once(&onceToken, ^{
|
|
|
|
#if PIN_ANIMATED_AVAILABLE
|
|
// Check that Carthage users have linked both PINRemoteImage & PINCache by testing for one file each
|
|
if (!(NSClassFromString(@"PINRemoteImageManager"))) {
|
|
NSException *e = [NSException
|
|
exceptionWithName:@"FrameworkSetupException"
|
|
reason:@"Missing the path to the PINRemoteImage framework."
|
|
userInfo:nil];
|
|
@throw e;
|
|
}
|
|
if (!(NSClassFromString(@"PINCache"))) {
|
|
NSException *e = [NSException
|
|
exceptionWithName:@"FrameworkSetupException"
|
|
reason:@"Missing the path to the PINCache framework."
|
|
userInfo:nil];
|
|
@throw e;
|
|
}
|
|
sharedPINRemoteImageManager = [[ASPINRemoteImageManager alloc] initWithSessionConfiguration:configuration
|
|
alternativeRepresentationProvider:[self sharedDownloader]];
|
|
#else
|
|
sharedPINRemoteImageManager = [[ASPINRemoteImageManager alloc] initWithSessionConfiguration:configuration];
|
|
#endif
|
|
});
|
|
return sharedPINRemoteImageManager;
|
|
}
|
|
|
|
- (PINRemoteImageManager *)sharedPINRemoteImageManager
|
|
{
|
|
return [ASPINRemoteImageDownloader sharedPINRemoteImageManagerWithConfiguration:nil];
|
|
}
|
|
|
|
- (BOOL)sharedImageManagerSupportsMemoryRemoval
|
|
{
|
|
static BOOL sharedImageManagerSupportsMemoryRemoval = NO;
|
|
static dispatch_once_t onceToken;
|
|
dispatch_once(&onceToken, ^{
|
|
sharedImageManagerSupportsMemoryRemoval = [[[self sharedPINRemoteImageManager] cache] respondsToSelector:@selector(removeObjectForKeyFromMemory:)];
|
|
});
|
|
return sharedImageManagerSupportsMemoryRemoval;
|
|
}
|
|
|
|
#pragma mark ASImageProtocols
|
|
|
|
#if PIN_ANIMATED_AVAILABLE
|
|
- (nullable id <ASAnimatedImageProtocol>)animatedImageWithData:(NSData *)animatedImageData
|
|
{
|
|
return [[PINAnimatedImage alloc] initWithAnimatedImageData:animatedImageData];
|
|
}
|
|
#endif
|
|
|
|
- (id <ASImageContainerProtocol>)synchronouslyFetchedCachedImageWithURL:(NSURL *)URL;
|
|
{
|
|
PINRemoteImageManager *manager = [self sharedPINRemoteImageManager];
|
|
PINRemoteImageManagerResult *result = [manager synchronousImageFromCacheWithURL:URL processorKey:nil options:PINRemoteImageManagerDownloadOptionsSkipDecode];
|
|
|
|
#if PIN_ANIMATED_AVAILABLE
|
|
if (result.alternativeRepresentation) {
|
|
return result.alternativeRepresentation;
|
|
}
|
|
#endif
|
|
return result.image;
|
|
}
|
|
|
|
- (void)cachedImageWithURL:(NSURL *)URL
|
|
callbackQueue:(dispatch_queue_t)callbackQueue
|
|
completion:(ASImageCacherCompletion)completion
|
|
{
|
|
// We do not check the cache here and instead check it in downloadImageWithURL to avoid checking the cache twice.
|
|
// If we're targeting the main queue and we're on the main thread, complete immediately.
|
|
if (ASDisplayNodeThreadIsMain() && callbackQueue == dispatch_get_main_queue()) {
|
|
completion(nil);
|
|
} else {
|
|
dispatch_async(callbackQueue, ^{
|
|
completion(nil);
|
|
});
|
|
}
|
|
}
|
|
|
|
- (void)clearFetchedImageFromCacheWithURL:(NSURL *)URL
|
|
{
|
|
if ([self sharedImageManagerSupportsMemoryRemoval]) {
|
|
PINRemoteImageManager *manager = [self sharedPINRemoteImageManager];
|
|
NSString *key = [manager cacheKeyForURL:URL processorKey:nil];
|
|
[[manager cache] removeObjectForKeyFromMemory:key];
|
|
}
|
|
}
|
|
|
|
- (nullable id)downloadImageWithURL:(NSURL *)URL
|
|
callbackQueue:(dispatch_queue_t)callbackQueue
|
|
downloadProgress:(ASImageDownloaderProgress)downloadProgress
|
|
completion:(ASImageDownloaderCompletion)completion;
|
|
{
|
|
return [[self sharedPINRemoteImageManager] downloadImageWithURL:URL options:PINRemoteImageManagerDownloadOptionsSkipDecode progressDownload:^(int64_t completedBytes, int64_t totalBytes) {
|
|
if (downloadProgress == nil) { return; }
|
|
|
|
/// If we're targeting the main queue and we're on the main thread, call immediately.
|
|
if (ASDisplayNodeThreadIsMain() && callbackQueue == dispatch_get_main_queue()) {
|
|
downloadProgress(completedBytes / (CGFloat)totalBytes);
|
|
} else {
|
|
dispatch_async(callbackQueue, ^{
|
|
downloadProgress(completedBytes / (CGFloat)totalBytes);
|
|
});
|
|
}
|
|
} completion:^(PINRemoteImageManagerResult * _Nonnull result) {
|
|
/// If we're targeting the main queue and we're on the main thread, complete immediately.
|
|
if (ASDisplayNodeThreadIsMain() && callbackQueue == dispatch_get_main_queue()) {
|
|
#if PIN_ANIMATED_AVAILABLE
|
|
if (result.alternativeRepresentation) {
|
|
completion(result.alternativeRepresentation, result.error, result.UUID);
|
|
} else {
|
|
completion(result.image, result.error, result.UUID);
|
|
}
|
|
#else
|
|
completion(result.image, result.error, result.UUID);
|
|
#endif
|
|
} else {
|
|
dispatch_async(callbackQueue, ^{
|
|
#if PIN_ANIMATED_AVAILABLE
|
|
if (result.alternativeRepresentation) {
|
|
completion(result.alternativeRepresentation, result.error, result.UUID);
|
|
} else {
|
|
completion(result.image, result.error, result.UUID);
|
|
}
|
|
#else
|
|
completion(result.image, result.error, result.UUID);
|
|
#endif
|
|
});
|
|
}
|
|
}];
|
|
}
|
|
|
|
- (void)cancelImageDownloadForIdentifier:(id)downloadIdentifier
|
|
{
|
|
if (!downloadIdentifier) {
|
|
return;
|
|
}
|
|
|
|
ASDisplayNodeAssert([downloadIdentifier isKindOfClass:[NSUUID class]], @"downloadIdentifier must be NSUUID");
|
|
[[self sharedPINRemoteImageManager] cancelTaskWithUUID:downloadIdentifier];
|
|
}
|
|
|
|
- (void)setProgressImageBlock:(ASImageDownloaderProgressImage)progressBlock callbackQueue:(dispatch_queue_t)callbackQueue withDownloadIdentifier:(id)downloadIdentifier
|
|
{
|
|
ASDisplayNodeAssert([downloadIdentifier isKindOfClass:[NSUUID class]], @"downloadIdentifier must be NSUUID");
|
|
|
|
if (progressBlock) {
|
|
[[self sharedPINRemoteImageManager] setProgressImageCallback:^(PINRemoteImageManagerResult * _Nonnull result) {
|
|
dispatch_async(callbackQueue, ^{
|
|
progressBlock(result.image, result.renderedImageQuality, result.UUID);
|
|
});
|
|
} ofTaskWithUUID:downloadIdentifier];
|
|
} else {
|
|
[[self sharedPINRemoteImageManager] setProgressImageCallback:nil ofTaskWithUUID:downloadIdentifier];
|
|
}
|
|
}
|
|
|
|
- (void)setPriority:(ASImageDownloaderPriority)priority withDownloadIdentifier:(id)downloadIdentifier
|
|
{
|
|
ASDisplayNodeAssert([downloadIdentifier isKindOfClass:[NSUUID class]], @"downloadIdentifier must be NSUUID");
|
|
|
|
PINRemoteImageManagerPriority pi_priority = PINRemoteImageManagerPriorityMedium;
|
|
switch (priority) {
|
|
case ASImageDownloaderPriorityPreload:
|
|
pi_priority = PINRemoteImageManagerPriorityMedium;
|
|
break;
|
|
|
|
case ASImageDownloaderPriorityImminent:
|
|
pi_priority = PINRemoteImageManagerPriorityHigh;
|
|
break;
|
|
|
|
case ASImageDownloaderPriorityVisible:
|
|
pi_priority = PINRemoteImageManagerPriorityVeryHigh;
|
|
break;
|
|
}
|
|
[[self sharedPINRemoteImageManager] setPriority:pi_priority ofTaskWithUUID:downloadIdentifier];
|
|
}
|
|
|
|
#pragma mark - PINRemoteImageManagerAlternateRepresentationProvider
|
|
|
|
- (id)alternateRepresentationWithData:(NSData *)data options:(PINRemoteImageManagerDownloadOptions)options
|
|
{
|
|
#if PIN_ANIMATED_AVAILABLE
|
|
if ([data pin_isGIF]) {
|
|
return data;
|
|
}
|
|
#endif
|
|
return nil;
|
|
}
|
|
|
|
@end
|
|
#endif
|