mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Cleanup
This commit is contained in:
parent
60a17360c5
commit
0de85afbfa
@ -58,10 +58,6 @@ typedef enum {
|
||||
|
||||
- (id<LegacyComponentsAccessChecker>)accessChecker;
|
||||
|
||||
- (SSignal *)stickerPacksSignal;
|
||||
- (SSignal *)maskStickerPacksSignal;
|
||||
- (SSignal *)recentStickerMasksSignal;
|
||||
|
||||
- (id<SDisposable>)requestAudioSession:(TGAudioSessionType)type interrupted:(void (^)())interrupted;
|
||||
|
||||
- (SThreadPool *)sharedMediaImageProcessingThreadPool;
|
||||
@ -71,11 +67,6 @@ typedef enum {
|
||||
- (NSString *)localDocumentDirectoryForLocalDocumentId:(int64_t)localDocumentId version:(int32_t)version;
|
||||
- (NSString *)localDocumentDirectoryForDocumentId:(int64_t)documentId version:(int32_t)version;
|
||||
|
||||
- (SSignal *)jsonForHttpLocation:(NSString *)httpLocation;
|
||||
- (SSignal *)dataForHttpLocation:(NSString *)httpLocation;
|
||||
|
||||
- (NSOperation<LegacyHTTPRequestOperation> *)makeHTTPRequestOperationWithRequest:(NSURLRequest *)request;
|
||||
|
||||
- (void)pausePictureInPicturePlayback;
|
||||
- (void)resumePictureInPicturePlayback;
|
||||
- (void)maybeReleaseVolumeOverlay;
|
||||
|
@ -1,19 +0,0 @@
|
||||
#import "PGPhotoEditorItem.h"
|
||||
|
||||
@class PGPhotoFilterDefinition;
|
||||
@class PGPhotoProcessPass;
|
||||
|
||||
@interface PGPhotoFilter : NSObject <PGPhotoEditorItem, NSCopying>
|
||||
{
|
||||
PGPhotoProcessPass *_pass;
|
||||
}
|
||||
|
||||
@property (nonatomic, readonly) PGPhotoFilterDefinition *definition;
|
||||
@property (nonatomic, retain) PGPhotoProcessPass *pass;
|
||||
@property (nonatomic, readonly) PGPhotoProcessPass *optimizedPass;
|
||||
|
||||
- (void)invalidate;
|
||||
|
||||
+ (PGPhotoFilter *)filterWithDefinition:(PGPhotoFilterDefinition *)definition;
|
||||
|
||||
@end
|
@ -1,242 +0,0 @@
|
||||
#import "PGPhotoFilter.h"
|
||||
|
||||
#import "TGPhotoEditorGenericToolView.h"
|
||||
|
||||
#import "PGPhotoFilterDefinition.h"
|
||||
|
||||
#import "PGPhotoCustomFilterPass.h"
|
||||
#import "PGPhotoLookupFilterPass.h"
|
||||
#import "PGPhotoProcessPass.h"
|
||||
|
||||
@interface PGPhotoFilter ()
|
||||
{
|
||||
PGPhotoProcessPass *_parameter;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation PGPhotoFilter
|
||||
|
||||
@synthesize value = _value;
|
||||
@synthesize tempValue = _tempValue;
|
||||
@synthesize parameters = _parameters;
|
||||
@synthesize beingEdited = _beingEdited;
|
||||
@synthesize shouldBeSkipped = _shouldBeSkipped;
|
||||
@synthesize parametersChanged = _parametersChanged;
|
||||
@synthesize disabled = _disabled;
|
||||
@synthesize segmented = _segmented;
|
||||
|
||||
- (instancetype)initWithDefinition:(PGPhotoFilterDefinition *)definition
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
_definition = definition;
|
||||
_value = @(self.defaultValue);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)copyWithZone:(NSZone *)__unused zone
|
||||
{
|
||||
PGPhotoFilter *filter = [[PGPhotoFilter alloc] initWithDefinition:self.definition];
|
||||
filter.value = self.value;
|
||||
return filter;
|
||||
}
|
||||
|
||||
- (NSString *)title
|
||||
{
|
||||
return _definition.title;
|
||||
}
|
||||
|
||||
- (NSString *)identifier
|
||||
{
|
||||
return _definition.identifier;
|
||||
}
|
||||
|
||||
- (PGPhotoProcessPass *)pass
|
||||
{
|
||||
if (_pass == nil)
|
||||
{
|
||||
switch (_definition.type)
|
||||
{
|
||||
case PGPhotoFilterTypeCustom:
|
||||
{
|
||||
_pass = [[PGPhotoCustomFilterPass alloc] initWithShaderFile:_definition.shaderFilename textureFiles:_definition.textureFilenames];
|
||||
}
|
||||
break;
|
||||
|
||||
case PGPhotoFilterTypeLookup:
|
||||
{
|
||||
_pass = [[PGPhotoLookupFilterPass alloc] initWithLookupImage:[UIImage imageNamed:[NSString stringWithFormat:@"%@.png", _definition.lookupFilename]]];
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
_pass = [[PGPhotoProcessPass alloc] init];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[self updatePassParameters];
|
||||
|
||||
return _pass;
|
||||
}
|
||||
|
||||
- (PGPhotoProcessPass *)optimizedPass
|
||||
{
|
||||
switch (_definition.type)
|
||||
{
|
||||
case PGPhotoFilterTypeCustom:
|
||||
{
|
||||
return [[PGPhotoCustomFilterPass alloc] initWithShaderFile:_definition.shaderFilename textureFiles:_definition.textureFilenames optimized:true];
|
||||
}
|
||||
break;
|
||||
|
||||
case PGPhotoFilterTypeLookup:
|
||||
{
|
||||
return [[PGPhotoLookupFilterPass alloc] initWithLookupImage:[UIImage imageNamed:[NSString stringWithFormat:@"%@.png", _definition.lookupFilename]]];
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return [[PGPhotoProcessPass alloc] init];
|
||||
}
|
||||
|
||||
- (Class)valueClass
|
||||
{
|
||||
return [NSNumber class];
|
||||
}
|
||||
|
||||
- (CGFloat)minimumValue
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
- (CGFloat)maximumValue
|
||||
{
|
||||
return 100.0f;
|
||||
}
|
||||
|
||||
- (CGFloat)defaultValue
|
||||
{
|
||||
return 100.0f;
|
||||
}
|
||||
|
||||
- (id)tempValue
|
||||
{
|
||||
if (self.disabled)
|
||||
{
|
||||
if ([_tempValue isKindOfClass:[NSNumber class]])
|
||||
return @0;
|
||||
}
|
||||
|
||||
return _tempValue;
|
||||
}
|
||||
|
||||
- (id)displayValue
|
||||
{
|
||||
if (self.beingEdited)
|
||||
return self.tempValue;
|
||||
|
||||
return self.value;
|
||||
}
|
||||
|
||||
- (void)setValue:(id)value
|
||||
{
|
||||
_value = value;
|
||||
|
||||
if (!self.beingEdited)
|
||||
[self updateParameters];
|
||||
}
|
||||
|
||||
- (void)setTempValue:(id)tempValue
|
||||
{
|
||||
_tempValue = tempValue;
|
||||
|
||||
if (self.beingEdited)
|
||||
[self updateParameters];
|
||||
}
|
||||
|
||||
- (NSArray *)parameters
|
||||
{
|
||||
return _parameters;
|
||||
}
|
||||
|
||||
- (void)updateParameters
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)updatePassParameters
|
||||
{
|
||||
CGFloat value = ((NSNumber *)self.displayValue).floatValue / self.maximumValue;
|
||||
|
||||
if ([_pass isKindOfClass:[PGPhotoLookupFilterPass class]])
|
||||
{
|
||||
PGPhotoLookupFilterPass *pass = (PGPhotoLookupFilterPass *)_pass;
|
||||
[pass setIntensity:value];
|
||||
}
|
||||
else if ([_pass isKindOfClass:[PGPhotoCustomFilterPass class]])
|
||||
{
|
||||
PGPhotoCustomFilterPass *pass = (PGPhotoCustomFilterPass *)_pass;
|
||||
[pass setIntensity:value];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)invalidate
|
||||
{
|
||||
_pass = nil;
|
||||
_value = @(self.defaultValue);
|
||||
}
|
||||
|
||||
- (void)reset
|
||||
{
|
||||
[_pass.filter removeAllTargets];
|
||||
}
|
||||
|
||||
- (id<TGPhotoEditorToolView>)itemControlViewWithChangeBlock:(void (^)(id newValue, bool animated))changeBlock
|
||||
{
|
||||
__weak PGPhotoFilter *weakSelf = self;
|
||||
|
||||
id<TGPhotoEditorToolView> view = [[TGPhotoEditorGenericToolView alloc] initWithEditorItem:self];
|
||||
view.valueChanged = ^(id newValue, bool animated)
|
||||
{
|
||||
__strong PGPhotoFilter *strongSelf = weakSelf;
|
||||
if (strongSelf == nil)
|
||||
return;
|
||||
|
||||
strongSelf.tempValue = newValue;
|
||||
|
||||
if (changeBlock != nil)
|
||||
changeBlock(newValue, animated);
|
||||
};
|
||||
return view;
|
||||
}
|
||||
|
||||
- (UIView <TGPhotoEditorToolView> *)itemAreaViewWithChangeBlock:(void (^)(id newValue))__unused changeBlock
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object
|
||||
{
|
||||
if (object == self)
|
||||
return YES;
|
||||
|
||||
if (!object || ![object isKindOfClass:[self class]])
|
||||
return NO;
|
||||
|
||||
return ([[(PGPhotoFilter *)object definition].identifier isEqualToString:self.definition.identifier]);
|
||||
}
|
||||
|
||||
+ (PGPhotoFilter *)filterWithDefinition:(PGPhotoFilterDefinition *)definition
|
||||
{
|
||||
return [[[self class] alloc] initWithDefinition:definition];
|
||||
}
|
||||
|
||||
@end
|
@ -1,21 +0,0 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef enum {
|
||||
PGPhotoFilterTypePassThrough,
|
||||
PGPhotoFilterTypeLookup,
|
||||
PGPhotoFilterTypeCustom
|
||||
} PGPhotoFilterType;
|
||||
|
||||
@interface PGPhotoFilterDefinition : NSObject
|
||||
|
||||
@property (readonly, nonatomic) NSString *identifier;
|
||||
@property (readonly, nonatomic) NSString *title;
|
||||
@property (readonly, nonatomic) PGPhotoFilterType type;
|
||||
@property (readonly, nonatomic) NSString *lookupFilename;
|
||||
@property (readonly, nonatomic) NSString *shaderFilename;
|
||||
@property (readonly, nonatomic) NSArray *textureFilenames;
|
||||
|
||||
+ (PGPhotoFilterDefinition *)originalFilterDefinition;
|
||||
+ (PGPhotoFilterDefinition *)definitionWithDictionary:(NSDictionary *)dictionary;
|
||||
|
||||
@end
|
@ -1,35 +0,0 @@
|
||||
#import "PGPhotoFilterDefinition.h"
|
||||
|
||||
@implementation PGPhotoFilterDefinition
|
||||
|
||||
+ (PGPhotoFilterDefinition *)originalFilterDefinition
|
||||
{
|
||||
PGPhotoFilterDefinition *definition = [[PGPhotoFilterDefinition alloc] init];
|
||||
definition->_type = PGPhotoFilterTypePassThrough;
|
||||
definition->_identifier = @"0_0";
|
||||
definition->_title = @"Original";
|
||||
|
||||
return definition;
|
||||
}
|
||||
|
||||
+ (PGPhotoFilterDefinition *)definitionWithDictionary:(NSDictionary *)dictionary
|
||||
{
|
||||
PGPhotoFilterDefinition *definition = [[PGPhotoFilterDefinition alloc] init];
|
||||
|
||||
if ([dictionary[@"type"] isEqualToString:@"lookup"])
|
||||
definition->_type = PGPhotoFilterTypeLookup;
|
||||
else if ([dictionary[@"type"] isEqualToString:@"custom"])
|
||||
definition->_type = PGPhotoFilterTypeCustom;
|
||||
else
|
||||
return nil;
|
||||
|
||||
definition->_identifier = dictionary[@"id"];
|
||||
definition->_title = dictionary[@"title"];
|
||||
definition->_lookupFilename = dictionary[@"lookup_name"];
|
||||
definition->_shaderFilename = dictionary[@"shader_name"];
|
||||
definition->_textureFilenames = dictionary[@"texture_names"];
|
||||
|
||||
return definition;
|
||||
}
|
||||
|
||||
@end
|
@ -1,20 +0,0 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class PGPhotoEditor;
|
||||
@class PGPhotoFilter;
|
||||
|
||||
@interface PGPhotoFilterThumbnailManager : NSObject
|
||||
|
||||
@property (nonatomic, weak) PGPhotoEditor *photoEditor;
|
||||
|
||||
- (void)setThumbnailImage:(UIImage *)image;
|
||||
- (void)requestThumbnailImageForFilter:(PGPhotoFilter *)filter completion:(void (^)(UIImage *thumbnailImage, bool cached, bool finished))completion;
|
||||
- (void)startCachingThumbnailImagesForFilters:(NSArray *)filters;
|
||||
- (void)stopCachingThumbnailImagesForFilters:(NSArray *)filters;
|
||||
- (void)stopCachingThumbnailImagesForAllFilters;
|
||||
- (void)invalidateThumbnailImages;
|
||||
|
||||
- (void)haltCaching;
|
||||
|
||||
@end
|
@ -1,277 +0,0 @@
|
||||
#import "PGPhotoFilterThumbnailManager.h"
|
||||
|
||||
#import <LegacyComponents/TGMemoryImageCache.h>
|
||||
#import <pthread.h>
|
||||
|
||||
#import <SSignalKit/SSignalKit.h>
|
||||
|
||||
#import "PGPhotoEditor.h"
|
||||
#import "PGPhotoFilter.h"
|
||||
#import "PGPhotoFilterDefinition.h"
|
||||
#import "PGPhotoProcessPass.h"
|
||||
#import "PGPhotoEditorPicture.h"
|
||||
|
||||
const NSUInteger TGFilterThumbnailCacheSoftMemoryLimit = 2 * 1024 * 1024;
|
||||
const NSUInteger TGFilterThumbnailCacheHardMemoryLimit = 2 * 1024 * 1024;
|
||||
|
||||
@interface PGPhotoFilterThumbnailManager ()
|
||||
{
|
||||
TGMemoryImageCache *_filterThumbnailCache;
|
||||
SQueue *_cachingQueue;
|
||||
|
||||
UIImage *_thumbnailImage;
|
||||
PGPhotoEditorPicture *_thumbnailPicture;
|
||||
|
||||
SQueue *_filteringQueue;
|
||||
dispatch_queue_t _prepQueue;
|
||||
|
||||
pthread_rwlock_t _callbackLock;
|
||||
NSMutableDictionary *_callbacksForId;
|
||||
|
||||
NSInteger _version;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation PGPhotoFilterThumbnailManager
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
[self invalidateThumbnailImages];
|
||||
|
||||
_prepQueue = dispatch_queue_create("ph.pictogra.Pictograph.FilterThumbnailQueue", DISPATCH_QUEUE_CONCURRENT);
|
||||
|
||||
_cachingQueue = [[SQueue alloc] init];
|
||||
_callbacksForId = [[NSMutableDictionary alloc] init];
|
||||
|
||||
_filteringQueue = [[SQueue alloc] init];
|
||||
pthread_rwlock_init(&_callbackLock, NULL);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setThumbnailImage:(UIImage *)image
|
||||
{
|
||||
[self invalidateThumbnailImages];
|
||||
_thumbnailImage = image;
|
||||
|
||||
//_thumbnailPicture = [[PGPhotoEditorPicture alloc] initWithImage:_thumbnailImage];
|
||||
}
|
||||
|
||||
- (void)requestThumbnailImageForFilter:(PGPhotoFilter *)filter completion:(void (^)(UIImage *image, bool cached, bool finished))completion
|
||||
{
|
||||
if (filter.definition.type == PGPhotoFilterTypePassThrough)
|
||||
{
|
||||
if (completion != nil)
|
||||
{
|
||||
if (_thumbnailImage != nil)
|
||||
completion(_thumbnailImage, true, true);
|
||||
else
|
||||
completion(nil, true, false);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
UIImage *cachedImage = [_filterThumbnailCache imageForKey:filter.identifier attributes:nil];
|
||||
if (cachedImage != nil)
|
||||
{
|
||||
if (completion != nil)
|
||||
completion(cachedImage, true, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_thumbnailImage == nil)
|
||||
{
|
||||
completion(nil, true, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (completion != nil)
|
||||
completion(_thumbnailImage, true, false);
|
||||
|
||||
NSInteger version = _version;
|
||||
|
||||
__weak PGPhotoFilterThumbnailManager *weakSelf = self;
|
||||
[self _addCallback:completion forId:filter.identifier createCallback:^
|
||||
{
|
||||
__strong PGPhotoFilterThumbnailManager *strongSelf = weakSelf;
|
||||
if (strongSelf == nil)
|
||||
return;
|
||||
|
||||
if (version != strongSelf->_version)
|
||||
return;
|
||||
|
||||
[strongSelf renderFilterThumbnailWithPicture:strongSelf->_thumbnailPicture filter:filter completion:^(UIImage *result)
|
||||
{
|
||||
[strongSelf _processCompletionForId:filter.identifier withResult:result];
|
||||
}];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)startCachingThumbnailImagesForFilters:(NSArray *)filters
|
||||
{
|
||||
if (_thumbnailImage == nil)
|
||||
return;
|
||||
|
||||
NSMutableArray *filtersToStartCaching = [[NSMutableArray alloc] init];
|
||||
|
||||
for (PGPhotoFilter *filter in filters)
|
||||
{
|
||||
if (filter.definition.type != PGPhotoFilterTypePassThrough && [_filterThumbnailCache imageForKey:filter.identifier attributes:nil] == nil)
|
||||
[filtersToStartCaching addObject:filter];
|
||||
}
|
||||
|
||||
NSInteger version = _version;
|
||||
|
||||
[_cachingQueue dispatch:^
|
||||
{
|
||||
if (version != _version)
|
||||
return;
|
||||
|
||||
for (PGPhotoFilter *filter in filtersToStartCaching)
|
||||
{
|
||||
__weak PGPhotoFilterThumbnailManager *weakSelf = self;
|
||||
[self _addCallback:nil forId:filter.identifier createCallback:^
|
||||
{
|
||||
__strong PGPhotoFilterThumbnailManager *strongSelf = weakSelf;
|
||||
if (strongSelf == nil)
|
||||
return;
|
||||
|
||||
if (version != strongSelf->_version)
|
||||
return;
|
||||
|
||||
[strongSelf renderFilterThumbnailWithPicture:strongSelf->_thumbnailPicture filter:filter completion:^(UIImage *result)
|
||||
{
|
||||
[strongSelf _processCompletionForId:filter.identifier withResult:result];
|
||||
}];
|
||||
}];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)stopCachingThumbnailImagesForFilters:(NSArray *)__unused filters
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)stopCachingThumbnailImagesForAllFilters
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)_processCompletionForId:(NSString *)filterId withResult:(UIImage *)result
|
||||
{
|
||||
[_filterThumbnailCache setImage:result forKey:filterId attributes:nil];
|
||||
|
||||
NSArray *callbacks = [self _callbacksForId:filterId];
|
||||
[self _removeCallbacksForId:filterId];
|
||||
|
||||
for (id callback in callbacks)
|
||||
{
|
||||
void(^callbackBlock)(UIImage *image, bool cached, bool finished) = callback;
|
||||
if (callbackBlock != nil)
|
||||
callbackBlock(result, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)renderFilterThumbnailWithPicture:(PGPhotoEditorPicture *)picture filter:(PGPhotoFilter *)filter completion:(void (^)(UIImage *result))completion
|
||||
{
|
||||
PGPhotoEditor *photoEditor = self.photoEditor;
|
||||
if (photoEditor == nil)
|
||||
return;
|
||||
|
||||
NSInteger version = _version;
|
||||
dispatch_async(_prepQueue, ^
|
||||
{
|
||||
GPUImageOutput<GPUImageInput> *gpuFilter = filter.optimizedPass.filter;
|
||||
[_filteringQueue dispatch:^
|
||||
{
|
||||
if (version != _version)
|
||||
return;
|
||||
|
||||
[picture addTarget:gpuFilter];
|
||||
[gpuFilter useNextFrameForImageCapture];
|
||||
[picture processSynchronous:true completion:^
|
||||
{
|
||||
UIImage *image = [gpuFilter imageFromCurrentFramebufferWithOrientation:UIImageOrientationUp];
|
||||
[picture removeAllTargets];
|
||||
|
||||
if (completion != nil)
|
||||
completion(image);
|
||||
}];
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)invalidateThumbnailImages
|
||||
{
|
||||
_version = lrand48();
|
||||
|
||||
_filterThumbnailCache = [[TGMemoryImageCache alloc] initWithSoftMemoryLimit:TGFilterThumbnailCacheSoftMemoryLimit
|
||||
hardMemoryLimit:TGFilterThumbnailCacheHardMemoryLimit];
|
||||
}
|
||||
|
||||
- (void)haltCaching
|
||||
{
|
||||
_version = lrand48();
|
||||
}
|
||||
|
||||
- (void)_addCallback:(void (^)(UIImage *, bool, bool))callback forId:(NSString *)filterId createCallback:(void (^)(void))createCallback
|
||||
{
|
||||
if (filterId == nil)
|
||||
{
|
||||
callback(nil, true, false);
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_rwlock_rdlock(&_callbackLock);
|
||||
|
||||
bool isInitial = false;
|
||||
if (_callbacksForId[filterId] == nil)
|
||||
{
|
||||
isInitial = true;
|
||||
_callbacksForId[filterId] = [[NSMutableArray alloc] init];
|
||||
}
|
||||
|
||||
if (callback != nil)
|
||||
{
|
||||
NSMutableArray *callbacksForId = _callbacksForId[filterId];
|
||||
[callbacksForId addObject:callback];
|
||||
_callbacksForId[filterId] = callbacksForId;
|
||||
}
|
||||
|
||||
if (isInitial && createCallback != nil)
|
||||
createCallback();
|
||||
|
||||
pthread_rwlock_unlock(&_callbackLock);
|
||||
}
|
||||
|
||||
- (NSArray *)_callbacksForId:(NSString *)filterId
|
||||
{
|
||||
if (filterId == nil)
|
||||
return nil;
|
||||
|
||||
__block NSArray *callbacksForId;
|
||||
|
||||
pthread_rwlock_rdlock(&_callbackLock);
|
||||
callbacksForId = _callbacksForId[filterId];
|
||||
pthread_rwlock_unlock(&_callbackLock);
|
||||
|
||||
return [callbacksForId copy];
|
||||
}
|
||||
|
||||
- (void)_removeCallbacksForId:(NSString *)filterId
|
||||
{
|
||||
if (filterId == nil)
|
||||
return;
|
||||
|
||||
pthread_rwlock_rdlock(&_callbackLock);
|
||||
[_callbacksForId removeObjectForKey:filterId];
|
||||
pthread_rwlock_unlock(&_callbackLock);
|
||||
}
|
||||
|
||||
@end
|
@ -280,17 +280,22 @@
|
||||
|
||||
_sliderView.frame = CGRectMake((self.frame.size.width - 32) / 2, TGPhotoEditorSliderViewMargin, 32, self.frame.size.height - 2 * TGPhotoEditorSliderViewMargin);
|
||||
|
||||
CGFloat titleOffset = 10;
|
||||
if (MAX(_offButton.title.length, MAX(_radialButton.title.length, _linearButton.title.length)) > 7) {
|
||||
titleOffset = -2;
|
||||
}
|
||||
|
||||
[UIView performWithoutAnimation:^
|
||||
{
|
||||
if (orientation == UIInterfaceOrientationLandscapeLeft)
|
||||
{
|
||||
_titleLabel.transform = CGAffineTransformMakeRotation(M_PI_2);
|
||||
_titleLabel.frame = CGRectMake(self.frame.size.width - _titleLabel.frame.size.width - 10, (self.frame.size.height - _titleLabel.frame.size.height) / 2, _titleLabel.frame.size.width, _titleLabel.frame.size.height);
|
||||
_titleLabel.frame = CGRectMake(self.frame.size.width - _titleLabel.frame.size.width - titleOffset, (self.frame.size.height - _titleLabel.frame.size.height) / 2, _titleLabel.frame.size.width, _titleLabel.frame.size.height);
|
||||
}
|
||||
else if (orientation == UIInterfaceOrientationLandscapeRight)
|
||||
{
|
||||
_titleLabel.transform = CGAffineTransformMakeRotation(-M_PI_2);
|
||||
_titleLabel.frame = CGRectMake(10, (self.frame.size.height - _titleLabel.frame.size.height) / 2, _titleLabel.frame.size.width, _titleLabel.frame.size.height);
|
||||
_titleLabel.frame = CGRectMake(titleOffset, (self.frame.size.height - _titleLabel.frame.size.height) / 2, _titleLabel.frame.size.width, _titleLabel.frame.size.height);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
@ -121,7 +121,7 @@
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
_imageView.frame = CGRectMake((self.frame.size.width - 50) / 2, (self.frame.size.height - 68) / 2, 50, 50);
|
||||
_titleLabel.frame = CGRectMake(0, _imageView.frame.origin.y +_imageView.frame.size.height - 1, self.frame.size.width, 16);
|
||||
_titleLabel.frame = CGRectMake(0, _imageView.frame.origin.y + _imageView.frame.size.height - 1, self.frame.size.width, 16);
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -1,9 +1,7 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class PGPhotoFilter;
|
||||
@class PGPhotoTool;
|
||||
|
||||
@protocol TGPhotoEditorCollectionViewFiltersDataSource;
|
||||
@protocol TGPhotoEditorCollectionViewToolsDataSource;
|
||||
|
||||
@interface TGPhotoEditorCollectionView : UICollectionView <UICollectionViewDelegate, UICollectionViewDataSource>
|
||||
@ -11,9 +9,7 @@
|
||||
@property (nonatomic, copy) void(^interactionBegan)(void);
|
||||
@property (nonatomic, copy) void(^interactionEnded)(void);
|
||||
|
||||
@property (nonatomic, weak) id <TGPhotoEditorCollectionViewFiltersDataSource> filtersDataSource;
|
||||
@property (nonatomic, weak) id <TGPhotoEditorCollectionViewToolsDataSource> toolsDataSource;
|
||||
@property (nonatomic, strong) UIImage *filterThumbnailImage;
|
||||
|
||||
@property (nonatomic, readonly) bool hasAnyTracking;
|
||||
|
||||
@ -24,15 +20,6 @@
|
||||
|
||||
@end
|
||||
|
||||
@protocol TGPhotoEditorCollectionViewFiltersDataSource <NSObject>
|
||||
|
||||
- (NSInteger)numberOfFiltersInCollectionView:(TGPhotoEditorCollectionView *)collectionView;
|
||||
- (PGPhotoFilter *)collectionView:(TGPhotoEditorCollectionView *)collectionView filterAtIndex:(NSInteger)index;
|
||||
- (void)collectionView:(TGPhotoEditorCollectionView *)collectionView didSelectFilterWithIndex:(NSInteger)index;
|
||||
- (void)collectionView:(TGPhotoEditorCollectionView *)collectionView requestThumbnailImageForFilterAtIndex:(NSInteger)index completion:(void (^)(UIImage *thumbnailImage, bool cached, bool finished))completion;
|
||||
|
||||
@end
|
||||
|
||||
@protocol TGPhotoEditorCollectionViewToolsDataSource <NSObject>
|
||||
|
||||
- (NSInteger)numberOfToolsInCollectionView:(TGPhotoEditorCollectionView *)collectionView;
|
||||
|
@ -2,9 +2,6 @@
|
||||
|
||||
#import "LegacyComponentsInternal.h"
|
||||
|
||||
#import "PGPhotoFilter.h"
|
||||
|
||||
#import "TGPhotoFilterCell.h"
|
||||
#import "TGPhotoToolCell.h"
|
||||
|
||||
#import "TGPhotoEditorSliderView.h"
|
||||
@ -43,7 +40,6 @@ const CGPoint TGPhotoEditorEdgeScrollTriggerOffset = { 100, 150 };
|
||||
self.showsHorizontalScrollIndicator = false;
|
||||
self.showsVerticalScrollIndicator = false;
|
||||
|
||||
[self registerClass:[TGPhotoFilterCell class] forCellWithReuseIdentifier:TGPhotoFilterCellKind];
|
||||
[self registerClass:[TGPhotoToolCell class] forCellWithReuseIdentifier:TGPhotoToolCellKind];
|
||||
}
|
||||
return self;
|
||||
@ -106,13 +102,6 @@ const CGPoint TGPhotoEditorEdgeScrollTriggerOffset = { 100, 150 };
|
||||
|
||||
- (void)setSelectedItemIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
NSArray *visibleItemsIndexPathes = self.indexPathsForVisibleItems;
|
||||
for (NSIndexPath *i in visibleItemsIndexPathes)
|
||||
{
|
||||
UICollectionViewCell *cell = [self cellForItemAtIndexPath:i];
|
||||
if ([cell isKindOfClass:[TGPhotoFilterCell class]])
|
||||
[(TGPhotoFilterCell *)cell setFilterSelected:[i isEqual:indexPath]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)selectItemAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated scrollPosition:(UICollectionViewScrollPosition)scrollPosition
|
||||
@ -140,12 +129,9 @@ const CGPoint TGPhotoEditorEdgeScrollTriggerOffset = { 100, 150 };
|
||||
|
||||
- (NSInteger)collectionView:(UICollectionView *)__unused collectionView numberOfItemsInSection:(NSInteger)__unused section
|
||||
{
|
||||
id <TGPhotoEditorCollectionViewFiltersDataSource> filtersDataSource = self.filtersDataSource;
|
||||
id <TGPhotoEditorCollectionViewToolsDataSource> toolsDataSource = self.toolsDataSource;
|
||||
|
||||
if ([filtersDataSource respondsToSelector:@selector(numberOfFiltersInCollectionView:)])
|
||||
return [filtersDataSource numberOfFiltersInCollectionView:self];
|
||||
else if ([toolsDataSource respondsToSelector:@selector(numberOfToolsInCollectionView:)])
|
||||
if ([toolsDataSource respondsToSelector:@selector(numberOfToolsInCollectionView:)])
|
||||
return [toolsDataSource numberOfToolsInCollectionView:self];
|
||||
|
||||
return 0;
|
||||
@ -153,29 +139,11 @@ const CGPoint TGPhotoEditorEdgeScrollTriggerOffset = { 100, 150 };
|
||||
|
||||
- (UICollectionViewCell *)collectionView:(UICollectionView *)__unused collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
id<TGPhotoEditorCollectionViewFiltersDataSource> filtersDataSource = self.filtersDataSource;
|
||||
id<TGPhotoEditorCollectionViewToolsDataSource> toolsDataSource = self.toolsDataSource;
|
||||
|
||||
UICollectionViewCell *cell = nil;
|
||||
|
||||
if ([filtersDataSource respondsToSelector:@selector(collectionView:filterAtIndex:)])
|
||||
{
|
||||
PGPhotoFilter *filter = [filtersDataSource collectionView:self filterAtIndex:indexPath.row];
|
||||
|
||||
cell = [self dequeueReusableCellWithReuseIdentifier:TGPhotoFilterCellKind forIndexPath:indexPath];
|
||||
[(TGPhotoFilterCell *)cell setPhotoFilter:filter];
|
||||
[(TGPhotoFilterCell *)cell setFilterSelected:[_selectedItemIndexPath isEqual:indexPath]];
|
||||
|
||||
[filtersDataSource collectionView:self requestThumbnailImageForFilterAtIndex:indexPath.row completion:^(UIImage *thumbnailImage, bool cached, __unused bool finished)
|
||||
{
|
||||
TGDispatchOnMainThread(^
|
||||
{
|
||||
if ([[(TGPhotoFilterCell *)cell filterIdentifier] isEqualToString:filter.identifier])
|
||||
[(TGPhotoFilterCell *)cell setImage:thumbnailImage animated:!cached];
|
||||
});
|
||||
}];
|
||||
}
|
||||
else if ([toolsDataSource respondsToSelector:@selector(collectionView:toolAtIndex:)])
|
||||
if ([toolsDataSource respondsToSelector:@selector(collectionView:toolAtIndex:)])
|
||||
{
|
||||
cell = [self dequeueReusableCellWithReuseIdentifier:TGPhotoToolCellKind forIndexPath:indexPath];
|
||||
cell.alpha = 1.0f;
|
||||
@ -231,97 +199,6 @@ const CGPoint TGPhotoEditorEdgeScrollTriggerOffset = { 100, 150 };
|
||||
block();
|
||||
}
|
||||
|
||||
- (void)collectionView:(UICollectionView *)__unused collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
id<TGPhotoEditorCollectionViewFiltersDataSource> filtersDataSource = self.filtersDataSource;
|
||||
|
||||
if ([filtersDataSource respondsToSelector:@selector(collectionView:didSelectFilterWithIndex:)])
|
||||
{
|
||||
bool vertical = false;
|
||||
if (self.frame.size.height > self.frame.size.width)
|
||||
vertical = true;
|
||||
|
||||
CGFloat screenSize = 0;
|
||||
CGFloat contentSize = 0;
|
||||
CGFloat contentOffset = 0;
|
||||
CGFloat itemPosition = 0;
|
||||
CGFloat itemSize = 0;
|
||||
CGFloat targetOverlap = 0;
|
||||
CGFloat startInset = 0;
|
||||
CGFloat endInset = 0;
|
||||
|
||||
CGFloat triggerOffset = 0;
|
||||
|
||||
if (!vertical)
|
||||
{
|
||||
screenSize = self.frame.size.width;
|
||||
contentSize = self.contentSize.width;
|
||||
contentOffset = self.contentOffset.x;
|
||||
itemPosition = [self.collectionViewLayout layoutAttributesForItemAtIndexPath:indexPath].frame.origin.x;
|
||||
itemSize = ((UICollectionViewFlowLayout *)self.collectionViewLayout).itemSize.width;
|
||||
startInset = self.contentInset.left;
|
||||
endInset = self.contentInset.right;
|
||||
triggerOffset = TGPhotoEditorEdgeScrollTriggerOffset.x;
|
||||
targetOverlap = itemSize / 2 + ((UICollectionViewFlowLayout *)self.collectionViewLayout).minimumLineSpacing;
|
||||
}
|
||||
else
|
||||
{
|
||||
screenSize = self.frame.size.height;
|
||||
contentSize = self.contentSize.height;
|
||||
contentOffset = self.contentOffset.y;
|
||||
itemPosition = [self.collectionViewLayout layoutAttributesForItemAtIndexPath:indexPath].frame.origin.y;
|
||||
itemSize = ((UICollectionViewFlowLayout *)self.collectionViewLayout).itemSize.height;
|
||||
startInset = self.contentInset.top;
|
||||
endInset = self.contentInset.bottom;
|
||||
triggerOffset = TGPhotoEditorEdgeScrollTriggerOffset.y;
|
||||
targetOverlap = itemSize + 2 * ((UICollectionViewFlowLayout *)self.collectionViewLayout).minimumLineSpacing;
|
||||
}
|
||||
|
||||
CGFloat itemsScreenPosition = itemPosition - contentOffset;
|
||||
|
||||
if (itemsScreenPosition < triggerOffset)
|
||||
{
|
||||
CGFloat targetContentOffset = MAX(-startInset, itemPosition - targetOverlap);
|
||||
|
||||
if (!vertical && targetContentOffset < startInset + itemSize)
|
||||
targetContentOffset = -startInset;
|
||||
|
||||
if (contentOffset > targetContentOffset)
|
||||
{
|
||||
if (!vertical)
|
||||
[self setContentOffset:CGPointMake(targetContentOffset, -self.contentInset.top) animated:YES];
|
||||
else
|
||||
[self setContentOffset:CGPointMake(-self.contentInset.left, targetContentOffset) animated:YES];
|
||||
|
||||
self.scrollEnabled = false;
|
||||
}
|
||||
}
|
||||
else if (itemsScreenPosition > screenSize - triggerOffset)
|
||||
{
|
||||
CGFloat targetContentOffset = MIN(contentSize - screenSize + endInset,
|
||||
itemPosition - screenSize + itemSize + targetOverlap);
|
||||
|
||||
if (!vertical && targetContentOffset > contentSize - screenSize - endInset - itemSize)
|
||||
targetContentOffset = contentSize - screenSize + endInset;
|
||||
|
||||
if (contentOffset < targetContentOffset)
|
||||
{
|
||||
if (!vertical)
|
||||
[self setContentOffset:CGPointMake(targetContentOffset, -self.contentInset.top) animated:YES];
|
||||
else
|
||||
[self setContentOffset:CGPointMake(-self.contentInset.left, targetContentOffset) animated:YES];
|
||||
|
||||
self.scrollEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
[filtersDataSource collectionView:self didSelectFilterWithIndex:indexPath.row];
|
||||
|
||||
_selectedItemIndexPath = indexPath;
|
||||
[self setSelectedItemIndexPath:indexPath];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)collectionView:(UICollectionView *)__unused collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)__unused indexPath
|
||||
{
|
||||
return false;
|
||||
|
@ -1,19 +0,0 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class PGPhotoFilter;
|
||||
|
||||
@interface TGPhotoFilterCell : UICollectionViewCell
|
||||
|
||||
@property (nonatomic, readonly) NSString *filterIdentifier;
|
||||
|
||||
- (void)setPhotoFilter:(PGPhotoFilter *)photoFilter;
|
||||
- (void)setFilterSelected:(BOOL)selected;
|
||||
|
||||
- (void)setImage:(UIImage *)image;
|
||||
- (void)setImage:(UIImage *)image animated:(bool)animated;
|
||||
|
||||
+ (CGFloat)filterCellWidth;
|
||||
|
||||
@end
|
||||
|
||||
extern NSString * const TGPhotoFilterCellKind;
|
@ -1,126 +0,0 @@
|
||||
#import "TGPhotoFilterCell.h"
|
||||
|
||||
#import "PGPhotoFilter.h"
|
||||
#import "PGPhotoFilterDefinition.h"
|
||||
|
||||
#import "TGPhotoEditorInterfaceAssets.h"
|
||||
|
||||
NSString * const TGPhotoFilterCellKind = @"TGPhotoFilterCellKind";
|
||||
|
||||
@interface TGPhotoFilterCell ()
|
||||
{
|
||||
UIImageView *_imageView;
|
||||
UIImageView *_selectionView;
|
||||
UILabel *_titleLabel;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation TGPhotoFilterCell
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self != nil)
|
||||
{
|
||||
_imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.width)];
|
||||
_imageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
[self addSubview:_imageView];
|
||||
|
||||
_titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, _imageView.frame.origin.y + _imageView.frame.size.height + 5, frame.size.width, 17)];
|
||||
_titleLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
||||
_titleLabel.backgroundColor = [UIColor clearColor];
|
||||
_titleLabel.font = [TGPhotoEditorInterfaceAssets editorItemTitleFont];
|
||||
_titleLabel.textAlignment = NSTextAlignmentCenter;
|
||||
_titleLabel.textColor = [TGPhotoEditorInterfaceAssets editorItemTitleColor];
|
||||
_titleLabel.highlightedTextColor = [TGPhotoEditorInterfaceAssets editorActiveItemTitleColor];
|
||||
[self addSubview:_titleLabel];
|
||||
|
||||
static UIImage *selectionImage = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^
|
||||
{
|
||||
CGFloat width = [TGPhotoFilterCell filterCellWidth];
|
||||
UIGraphicsBeginImageContextWithOptions(CGSizeMake(width, width), false, 0.0f);
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
CGContextSetFillColorWithColor(context, [TGPhotoEditorInterfaceAssets filterSelectionColor].CGColor);
|
||||
|
||||
UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(3, 3, width - 2 * 3, width - 2 * 3)];
|
||||
[path appendPath:[UIBezierPath bezierPathWithRect:CGRectMake(0, 0, width, width)]];
|
||||
path.usesEvenOddFillRule = true;
|
||||
[path fill];
|
||||
|
||||
selectionImage = [UIGraphicsGetImageFromCurrentImageContext() resizableImageWithCapInsets:UIEdgeInsetsMake(3, 3, 3, 3)];
|
||||
UIGraphicsEndImageContext();
|
||||
});
|
||||
|
||||
_selectionView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.width)];
|
||||
_selectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
_selectionView.image = selectionImage;
|
||||
_selectionView.hidden = true;
|
||||
[self addSubview:_selectionView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setPhotoFilter:(PGPhotoFilter *)photoFilter
|
||||
{
|
||||
_filterIdentifier = photoFilter.identifier;
|
||||
_titleLabel.text = photoFilter.definition.title;
|
||||
}
|
||||
|
||||
- (void)setFilterSelected:(BOOL)selected
|
||||
{
|
||||
[super setSelected:selected];
|
||||
|
||||
_titleLabel.highlighted = selected;
|
||||
_selectionView.hidden = !selected;
|
||||
}
|
||||
|
||||
- (void)setImage:(UIImage *)image
|
||||
{
|
||||
[self setImage:image animated:false];
|
||||
}
|
||||
|
||||
- (void)setImage:(UIImage *)image animated:(bool)animated
|
||||
{
|
||||
if (_imageView.image == nil)
|
||||
animated = false;
|
||||
|
||||
if (animated)
|
||||
{
|
||||
UIImageView *transitionView = [[UIImageView alloc] initWithImage:_imageView.image];
|
||||
transitionView.frame = _imageView.frame;
|
||||
[self insertSubview:transitionView aboveSubview:_imageView];
|
||||
|
||||
_imageView.image = image;
|
||||
|
||||
[UIView animateWithDuration:0.3f animations:^
|
||||
{
|
||||
transitionView.alpha = 0.0f;
|
||||
} completion:^(__unused BOOL finished)
|
||||
{
|
||||
[transitionView removeFromSuperview];
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
_imageView.image = image;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setSelected:(BOOL)__unused selected
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)setHighlighted:(BOOL)__unused highlighted
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
+ (CGFloat)filterCellWidth
|
||||
{
|
||||
return 64;
|
||||
}
|
||||
|
||||
@end
|
@ -1,221 +0,0 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import LegacyComponents
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import SyncCore
|
||||
import SwiftSignalKit
|
||||
import Display
|
||||
import StickerResources
|
||||
|
||||
public func stickerFromLegacyDocument(_ documentAttachment: TGDocumentMediaAttachment) -> TelegramMediaFile? {
|
||||
if documentAttachment.isSticker() {
|
||||
for case let sticker as TGDocumentAttributeSticker in documentAttachment.attributes {
|
||||
var attributes: [TelegramMediaFileAttribute] = []
|
||||
var packReference: StickerPackReference?
|
||||
if let legacyPackReference = sticker.packReference as? TGStickerPackIdReference {
|
||||
packReference = .id(id: legacyPackReference.packId, accessHash: legacyPackReference.packAccessHash)
|
||||
} else if let legacyPackReference = sticker.packReference as? TGStickerPackShortnameReference {
|
||||
packReference = .name(legacyPackReference.shortName)
|
||||
}
|
||||
attributes.append(.Sticker(displayText: sticker.alt, packReference: packReference, maskData: nil))
|
||||
|
||||
var fileReference: Data?
|
||||
if let originInfo = documentAttachment.originInfo, let data = originInfo.fileReference {
|
||||
fileReference = data
|
||||
}
|
||||
|
||||
return TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.CloudFile, id: documentAttachment.documentId), partialReference: nil, resource: CloudDocumentMediaResource(datacenterId: Int(documentAttachment.datacenterId), fileId: documentAttachment.documentId, accessHash: documentAttachment.accessHash, size: Int(documentAttachment.size), fileReference: fileReference, fileName: documentAttachment.fileName()), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: documentAttachment.mimeType, size: Int(documentAttachment.size), attributes: attributes)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func legacyComponentsStickers(postbox: Postbox, namespace: Int32) -> SSignal {
|
||||
return SSignal { subscriber in
|
||||
let disposable = (postbox.itemCollectionsView(orderedItemListCollectionIds: [], namespaces: [namespace], aroundIndex: nil, count: 200 * 200)).start(next: { view in
|
||||
var stickerPackDocuments: [ItemCollectionId: [Any]] = [:]
|
||||
|
||||
for entry in view.entries {
|
||||
if let item = entry.item as? StickerPackItem {
|
||||
if item.file.isAnimatedSticker {
|
||||
continue
|
||||
}
|
||||
let document = TGDocumentMediaAttachment()
|
||||
document.documentId = item.file.fileId.id
|
||||
if let resource = item.file.resource as? CloudDocumentMediaResource {
|
||||
document.accessHash = resource.accessHash
|
||||
document.datacenterId = Int32(resource.datacenterId)
|
||||
var stickerPackId: Int64 = 0
|
||||
var accessHash: Int64 = 0
|
||||
for case let .Sticker(sticker) in item.file.attributes {
|
||||
if let packReference = sticker.packReference, case let .id(id, h) = packReference {
|
||||
stickerPackId = id
|
||||
accessHash = h
|
||||
}
|
||||
break
|
||||
}
|
||||
document.originInfo = TGMediaOriginInfo(fileReference: resource.fileReference ?? Data(), fileReferences: [:], stickerPackId: stickerPackId, accessHash: accessHash)
|
||||
}
|
||||
document.mimeType = item.file.mimeType
|
||||
if let size = item.file.size {
|
||||
document.size = Int32(size)
|
||||
}
|
||||
if let thumbnail = item.file.previewRepresentations.first {
|
||||
let imageInfo = TGImageInfo()
|
||||
let encoder = PostboxEncoder()
|
||||
encoder.encodeRootObject(thumbnail.resource)
|
||||
let dataString = encoder.makeData().base64EncodedString(options: [])
|
||||
imageInfo.addImage(with: thumbnail.dimensions.cgSize, url: dataString)
|
||||
document.thumbnailInfo = imageInfo
|
||||
}
|
||||
var attributes: [Any] = []
|
||||
for attribute in item.file.attributes {
|
||||
switch attribute {
|
||||
case let .Sticker(displayText, _, maskData):
|
||||
attributes.append(TGDocumentAttributeSticker(alt: displayText, packReference: nil, mask: maskData.flatMap {
|
||||
return TGStickerMaskDescription(n: $0.n, point: CGPoint(x: CGFloat($0.x), y: CGFloat($0.y)), zoom: CGFloat($0.zoom))
|
||||
}))
|
||||
case let .ImageSize(size):
|
||||
attributes.append(TGDocumentAttributeImageSize(size: size.cgSize))
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
document.attributes = attributes
|
||||
if stickerPackDocuments[entry.index.collectionId] == nil {
|
||||
stickerPackDocuments[entry.index.collectionId] = []
|
||||
}
|
||||
stickerPackDocuments[entry.index.collectionId]!.append(document)
|
||||
}
|
||||
}
|
||||
|
||||
let stickerPacks = NSMutableArray()
|
||||
for (id, info, _) in view.collectionInfos {
|
||||
if let info = info as? StickerPackCollectionInfo, !info.flags.contains(.isAnimated) {
|
||||
let pack = TGStickerPack(packReference: TGStickerPackIdReference(), title: info.title, stickerAssociations: [], documents: stickerPackDocuments[id] ?? [], packHash: info.hash, hidden: false, isMask: true, isFeatured: false, installedDate: 0)!
|
||||
stickerPacks.add(pack)
|
||||
}
|
||||
}
|
||||
|
||||
var dict: [AnyHashable: Any] = [:]
|
||||
dict["packs"] = stickerPacks
|
||||
subscriber?.putNext(dict)
|
||||
})
|
||||
|
||||
return SBlockDisposable {
|
||||
disposable.dispose()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class LegacyStickerImageDataTask: NSObject {
|
||||
private let disposable = DisposableSet()
|
||||
|
||||
init(account: Account, file: TelegramMediaFile, small: Bool, fitSize: CGSize, completion: @escaping (UIImage?) -> Void) {
|
||||
super.init()
|
||||
|
||||
self.disposable.add(chatMessageLegacySticker(account: account, file: file, small: small, fitSize: fitSize, fetched: true, onlyFullSize: true).start(next: { generator in
|
||||
if let image = generator(TransformImageArguments(corners: ImageCorners(), imageSize: fitSize, boundingSize: fitSize, intrinsicInsets: UIEdgeInsets()))?.generateImage() {
|
||||
completion(image)
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.disposable.dispose()
|
||||
}
|
||||
|
||||
func cancel() {
|
||||
self.disposable.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
private let sharedImageCache = TGMemoryImageCache(softMemoryLimit: 2 * 1024 * 1024, hardMemoryLimit: 3 * 1024 * 1024)!
|
||||
|
||||
final class LegacyStickerImageDataSource: TGImageDataSource {
|
||||
private let account: () -> Account?
|
||||
|
||||
init(account: @escaping () -> Account?) {
|
||||
self.account = account
|
||||
|
||||
super.init()
|
||||
}
|
||||
|
||||
override func canHandleUri(_ uri: String!) -> Bool {
|
||||
if let uri = uri {
|
||||
if uri.hasPrefix("sticker-preview://") {
|
||||
return true
|
||||
} else if uri.hasPrefix("sticker://") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override func loadDataSync(withUri uri: String!, canWait: Bool, acceptPartialData: Bool, asyncTaskId: AutoreleasingUnsafeMutablePointer<AnyObject?>!, progress: ((Float) -> Void)!, partialCompletion: ((TGDataResource?) -> Void)!, completion: ((TGDataResource?) -> Void)!) -> TGDataResource! {
|
||||
if let image = sharedImageCache.image(forKey: uri, attributes: nil) {
|
||||
return TGDataResource(image: image, decoded: true)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
override func loadDataAsync(withUri uri: String!, progress: ((Float) -> Void)!, partialCompletion: ((TGDataResource?) -> Void)!, completion: ((TGDataResource?) -> Void)!) -> Any! {
|
||||
if let account = self.account() {
|
||||
let args: [AnyHashable : Any]
|
||||
var highQuality: Bool
|
||||
if uri.hasPrefix("sticker-preview://") {
|
||||
let argumentsString = String(uri[uri.index(uri.startIndex, offsetBy: "sticker-preview://?".count)...])
|
||||
args = TGStringUtils.argumentDictionary(inUrlString: argumentsString)!
|
||||
highQuality = Int((args["highQuality"] as! String))! != 0
|
||||
} else if uri.hasPrefix("sticker://") {
|
||||
let argumentsString = String(uri[uri.index(uri.startIndex, offsetBy: "sticker://?".count)...])
|
||||
args = TGStringUtils.argumentDictionary(inUrlString: argumentsString)!
|
||||
highQuality = true
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let documentId = Int64((args["documentId"] as! String))!
|
||||
let datacenterId = Int((args["datacenterId"] as! String))!
|
||||
let accessHash = Int64((args["accessHash"] as! String))!
|
||||
let size: Int? = nil
|
||||
|
||||
let width = Int((args["width"] as! String))!
|
||||
let height = Int((args["height"] as! String))!
|
||||
|
||||
if width < 128 {
|
||||
highQuality = false
|
||||
}
|
||||
|
||||
let fitSize = CGSize(width: CGFloat(width), height: CGFloat(height))
|
||||
|
||||
var attributes: [TelegramMediaFileAttribute] = []
|
||||
if let originInfoString = args["origin_info"] as? String, let originInfo = TGMediaOriginInfo(stringRepresentation: originInfoString), let stickerPackId = originInfo.stickerPackId?.int64Value, let stickerPackAccessHash = originInfo.stickerPackAccessHash?.int64Value {
|
||||
attributes.append(.Sticker(displayText: "", packReference: .id(id: stickerPackId, accessHash: stickerPackAccessHash), maskData: nil))
|
||||
}
|
||||
|
||||
var previewRepresentations: [TelegramMediaImageRepresentation] = []
|
||||
if let legacyThumbnailUri = args["legacyThumbnailUri"] as? String, let data = Data(base64Encoded: legacyThumbnailUri, options: []) {
|
||||
if let resource = PostboxDecoder(buffer: MemoryBuffer(data: data)).decodeRootObject() as? TelegramMediaResource {
|
||||
previewRepresentations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 140, height: 140), resource: resource, progressiveSizes: []))
|
||||
}
|
||||
}
|
||||
|
||||
return LegacyStickerImageDataTask(account: account, file: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.CloudFile, id: documentId), partialReference: nil, resource: CloudDocumentMediaResource(datacenterId: datacenterId, fileId: documentId, accessHash: accessHash, size: size, fileReference: nil, fileName: fileNameFromFileAttributes(attributes)), previewRepresentations: previewRepresentations, videoThumbnails: [], immediateThumbnailData: nil, mimeType: "image/webp", size: size, attributes: attributes), small: !highQuality, fitSize: fitSize, completion: { image in
|
||||
if let image = image {
|
||||
sharedImageCache.setImage(image, forKey: uri, attributes: nil)
|
||||
completion?(TGDataResource(image: image, decoded: true))
|
||||
}
|
||||
})
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
override func cancelTask(byId taskId: Any!) {
|
||||
if let task = taskId as? LegacyStickerImageDataTask {
|
||||
task.cancel()
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
import Foundation
|
||||
import MtProtoKit
|
||||
|
||||
import LegacyComponents
|
||||
|
||||
@objc class LegacyHTTPOperationImpl: AFHTTPRequestOperation, LegacyHTTPRequestOperation {
|
||||
}
|
@ -1,193 +0,0 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import LegacyComponents
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import SyncCore
|
||||
import SwiftSignalKit
|
||||
import Display
|
||||
|
||||
private let sharedImageCache = TGMemoryImageCache(softMemoryLimit: 2 * 1024 * 1024, hardMemoryLimit: 3 * 1024 * 1024)!
|
||||
|
||||
private let placeholderImage = generateFilledCircleImage(diameter: 40.0, color: UIColor(rgb: 0xf2f2f2))
|
||||
|
||||
private final class LegacyLocationVenueIconTask: NSObject {
|
||||
private let disposable = DisposableSet()
|
||||
|
||||
init(account: Account, url: String, completion: @escaping (Data?) -> Void) {
|
||||
super.init()
|
||||
|
||||
let resource = HttpReferenceMediaResource(url: url, size: nil)
|
||||
self.disposable.add(account.postbox.mediaBox.resourceData(resource).start(next: { data in
|
||||
if data.complete {
|
||||
if let loadedData = try? Data(contentsOf: URL(fileURLWithPath: data.path)) {
|
||||
completion(loadedData)
|
||||
}
|
||||
}
|
||||
}))
|
||||
self.disposable.add(account.postbox.mediaBox.fetchedResource(resource, parameters: nil).start())
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.disposable.dispose()
|
||||
}
|
||||
|
||||
func cancel() {
|
||||
self.disposable.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
private let genericIconImage = TGComponentsImageNamed("LocationMessagePinIcon")?.precomposed()
|
||||
|
||||
final class LegacyLocationVenueIconDataSource: TGImageDataSource {
|
||||
private let account: () -> Account?
|
||||
|
||||
init(account: @escaping () -> Account?) {
|
||||
self.account = account
|
||||
|
||||
super.init()
|
||||
}
|
||||
|
||||
override func canHandleUri(_ uri: String!) -> Bool {
|
||||
if let uri = uri {
|
||||
if uri.hasPrefix("location-venue-icon://") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override func loadAttributeSync(forUri uri: String!, attribute: String!) -> Any! {
|
||||
if attribute == "placeholder" {
|
||||
return placeholderImage
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
override func loadDataSync(withUri uri: String!, canWait: Bool, acceptPartialData: Bool, asyncTaskId: AutoreleasingUnsafeMutablePointer<AnyObject?>!, progress: ((Float) -> Void)!, partialCompletion: ((TGDataResource?) -> Void)!, completion: ((TGDataResource?) -> Void)!) -> TGDataResource! {
|
||||
if let image = sharedImageCache.image(forKey: uri, attributes: nil) {
|
||||
return TGDataResource(image: image, decoded: true)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
private static func unavailableImage(for uri: String) -> TGDataResource? {
|
||||
let args: [AnyHashable : Any]
|
||||
let argumentsString = String(uri[uri.index(uri.startIndex, offsetBy: "location-venue-icon://".count)...])
|
||||
args = TGStringUtils.argumentDictionary(inUrlString: argumentsString)!
|
||||
|
||||
guard let width = Int((args["width"] as! String)), width > 1 else {
|
||||
return nil
|
||||
}
|
||||
guard let height = Int((args["height"] as! String)), height > 1 else {
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let colorN = (args["color"] as? String).flatMap({ Int($0) }) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let color = UIColor(rgb: UInt32(colorN))
|
||||
|
||||
let size = CGSize(width: CGFloat(width), height: CGFloat(height))
|
||||
|
||||
guard let iconSourceImage = genericIconImage.flatMap({ generateTintedImage(image: $0, color: color) }) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(iconSourceImage.size, false, iconSourceImage.scale)
|
||||
var context = UIGraphicsGetCurrentContext()!
|
||||
iconSourceImage.draw(at: CGPoint())
|
||||
context.setBlendMode(.sourceAtop)
|
||||
context.setFillColor(color.cgColor)
|
||||
context.fill(CGRect(origin: CGPoint(), size: iconSourceImage.size))
|
||||
|
||||
let tintedIconImage = UIGraphicsGetImageFromCurrentImageContext()
|
||||
UIGraphicsEndImageContext()
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
|
||||
context = UIGraphicsGetCurrentContext()!
|
||||
let fitSize = CGSize(width: size.width - 4.0 * 2.0, height: size.height - 4.0 * 2.0)
|
||||
let imageSize = iconSourceImage.size.aspectFitted(fitSize)
|
||||
let imageRect = CGRect(origin: CGPoint(x: floor((size.width - imageSize.width) / 2.0), y: floor((size.height - imageSize.height) / 2.0)), size: imageSize)
|
||||
tintedIconImage?.draw(in: imageRect)
|
||||
|
||||
let iconImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext()
|
||||
|
||||
if let iconImage = iconImage {
|
||||
sharedImageCache.setImage(iconImage, forKey: uri, attributes: nil)
|
||||
return TGDataResource(image: iconImage, decoded: true)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
override func loadDataAsync(withUri uri: String!, progress: ((Float) -> Void)!, partialCompletion: ((TGDataResource?) -> Void)!, completion: ((TGDataResource?) -> Void)!) -> Any! {
|
||||
if let account = self.account() {
|
||||
let args: [AnyHashable : Any]
|
||||
let argumentsString = String(uri[uri.index(uri.startIndex, offsetBy: "location-venue-icon://".count)...])
|
||||
args = TGStringUtils.argumentDictionary(inUrlString: argumentsString)!
|
||||
|
||||
guard let width = Int((args["width"] as! String)), width > 1 else {
|
||||
return nil
|
||||
}
|
||||
guard let height = Int((args["height"] as! String)), height > 1 else {
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let colorN = (args["color"] as? String).flatMap({ Int($0) }) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let type = args["type"] as? String else {
|
||||
return LegacyLocationVenueIconDataSource.unavailableImage(for: uri)
|
||||
}
|
||||
|
||||
let color = UIColor(rgb: UInt32(colorN))
|
||||
|
||||
let url = "https://ss3.4sqi.net/img/categories_v2/\(type)_88.png"
|
||||
|
||||
let size = CGSize(width: CGFloat(width), height: CGFloat(height))
|
||||
|
||||
return LegacyLocationVenueIconTask(account: account, url: url, completion: { data in
|
||||
if let data = data, let iconSourceImage = UIImage(data: data) {
|
||||
UIGraphicsBeginImageContextWithOptions(iconSourceImage.size, false, iconSourceImage.scale)
|
||||
var context = UIGraphicsGetCurrentContext()!
|
||||
iconSourceImage.draw(at: CGPoint())
|
||||
context.setBlendMode(.sourceAtop)
|
||||
context.setFillColor(color.cgColor)
|
||||
context.fill(CGRect(origin: CGPoint(), size: iconSourceImage.size))
|
||||
|
||||
let tintedIconImage = UIGraphicsGetImageFromCurrentImageContext()
|
||||
UIGraphicsEndImageContext()
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
|
||||
context = UIGraphicsGetCurrentContext()!
|
||||
let imageRect = CGRect(x: 4.0, y: 4.0, width: size.width - 4.0 * 2.0, height: size.height - 4.0 * 2.0)
|
||||
tintedIconImage?.draw(in: imageRect)
|
||||
|
||||
let iconImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext()
|
||||
|
||||
if let iconImage = iconImage {
|
||||
sharedImageCache.setImage(iconImage, forKey: uri, attributes: nil)
|
||||
completion?(TGDataResource(image: iconImage, decoded: true))
|
||||
}
|
||||
} else {
|
||||
if let image = LegacyLocationVenueIconDataSource.unavailableImage(for: uri) {
|
||||
completion?(image)
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
override func cancelTask(byId taskId: Any!) {
|
||||
if let disposable = taskId as? LegacyLocationVenueIconTask {
|
||||
disposable.cancel()
|
||||
}
|
||||
}
|
||||
}
|
@ -196,30 +196,6 @@ private final class LegacyComponentsGlobalsProviderImpl: NSObject, LegacyCompone
|
||||
return LegacyComponentsAccessCheckerImpl(context: legacyContext)
|
||||
}
|
||||
|
||||
public func stickerPacksSignal() -> SSignal! {
|
||||
if let legacyContext = legacyContext {
|
||||
return legacyComponentsStickers(postbox: legacyContext.account.postbox, namespace: Namespaces.ItemCollection.CloudStickerPacks)
|
||||
} else {
|
||||
var dict: [AnyHashable: Any] = [:]
|
||||
dict["packs"] = NSArray()
|
||||
return SSignal.single(dict)
|
||||
}
|
||||
}
|
||||
|
||||
public func maskStickerPacksSignal() -> SSignal! {
|
||||
if let legacyContext = legacyContext {
|
||||
return legacyComponentsStickers(postbox: legacyContext.account.postbox, namespace: Namespaces.ItemCollection.CloudMaskPacks)
|
||||
} else {
|
||||
var dict: [AnyHashable: Any] = [:]
|
||||
dict["packs"] = NSArray()
|
||||
return SSignal.single(dict)
|
||||
}
|
||||
}
|
||||
|
||||
public func recentStickerMasksSignal() -> SSignal! {
|
||||
return SSignal.single(NSArray())
|
||||
}
|
||||
|
||||
public func request(_ type: TGAudioSessionType, interrupted: (() -> Void)!) -> SDisposable! {
|
||||
if let legacyContext = legacyContext {
|
||||
let convertedType: ManagedAudioSessionType
|
||||
@ -262,40 +238,6 @@ private final class LegacyComponentsGlobalsProviderImpl: NSObject, LegacyCompone
|
||||
return ""
|
||||
}
|
||||
|
||||
public func json(forHttpLocation httpLocation: String!) -> SSignal! {
|
||||
return self.data(forHttpLocation: httpLocation).map(toSignal: { next in
|
||||
if let next = next as? Data {
|
||||
if let object = try? JSONSerialization.jsonObject(with: next, options: []) {
|
||||
return SSignal.single(object)
|
||||
}
|
||||
}
|
||||
return SSignal.fail(nil)
|
||||
})
|
||||
}
|
||||
|
||||
public func data(forHttpLocation httpLocation: String!) -> SSignal! {
|
||||
return SSignal { subscriber in
|
||||
if let httpLocation = httpLocation, let url = URL(string: httpLocation) {
|
||||
let disposable = MTHttpRequestOperation.data(forHttpUrl: url).start(next: { next in
|
||||
subscriber?.putNext(next)
|
||||
}, error: { error in
|
||||
subscriber?.putError(error)
|
||||
}, completed: {
|
||||
subscriber?.putCompletion()
|
||||
})
|
||||
return SBlockDisposable(block: {
|
||||
disposable?.dispose()
|
||||
})
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func makeHTTPRequestOperation(with request: URLRequest!) -> (Operation & LegacyHTTPRequestOperation)! {
|
||||
return LegacyHTTPOperationImpl(request: request)
|
||||
}
|
||||
|
||||
public func pausePictureInPicturePlayback() {
|
||||
|
||||
}
|
||||
@ -377,15 +319,9 @@ public func initializeLegacyComponents(application: UIApplication?, currentSizeC
|
||||
|
||||
TGRemoteImageView.setSharedCache(TGCache())
|
||||
|
||||
TGImageDataSource.register(LegacyStickerImageDataSource(account: {
|
||||
return legacyContext?.account
|
||||
}))
|
||||
TGImageDataSource.register(LegacyPeerAvatarPlaceholderDataSource(account: {
|
||||
return legacyContext?.account
|
||||
}))
|
||||
TGImageDataSource.register(LegacyLocationVenueIconDataSource(account: {
|
||||
return legacyContext?.account
|
||||
}))
|
||||
ASActor.registerClass(LegacyImageDownloadActor.self)
|
||||
LegacyComponentsGlobals.setProvider(LegacyComponentsGlobalsProviderImpl())
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user