Merge commit '95d16d967a5c7595812221665bedf34f48e55023'

This commit is contained in:
Ali 2020-06-05 19:55:56 +04:00
commit db5ba5b97c
89 changed files with 5112 additions and 4204 deletions

View File

@ -5522,6 +5522,11 @@ Any member of this group will be able to see messages in the channel.";
"Conversation.Timer.Title" = "Send With Timer";
"Conversation.Timer.Send" = "Send With Timer";
"Paint.Pen" = "Pen";
"Paint.Marker" = "Marker";
"Paint.Neon" = "Neon";
"Paint.Arrow" = "Arrow";
"Conversation.NoticeInvitedByInChannel" = "%@ invited you to this channel";
"Conversation.NoticeInvitedByInGroup" = "%@ invited you to this group";

View File

@ -1,7 +1,7 @@
{
"images" : [
{
"filename" : "ic_editor_font.pdf",
"filename" : "ic_menu_brush4.pdf",
"idiom" : "universal"
}
],

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_menu_brush2.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_menu_brush3.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_menu_brush1.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_editor_brush4.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_editor_brush2.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_editor_brush3.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_editor_brush1.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_menu_font3.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_menu_font2.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_menu_font1.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_editor_font3.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_editor_font2.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "ic_editor_font1.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -3,13 +3,18 @@
#import <LegacyComponents/TGMediaSelectionContext.h>
@class AVURLAsset;
@class TGMediaAsset;
@interface TGCameraCapturedVideo : NSObject <TGMediaEditableItem, TGMediaSelectableItem>
@property (nonatomic, readonly) AVURLAsset *avAsset;
@property (nonatomic, readonly) SSignal *avAsset;
@property (nonatomic, readonly) NSTimeInterval videoDuration;
@property (nonatomic, readonly) bool isAnimation;
@property (nonatomic, readonly) TGMediaAsset *originalAsset;
- (instancetype)initWithURL:(NSURL *)url;
- (instancetype)initWithAsset:(TGMediaAsset *)asset;
- (void)_cleanUp;

View File

@ -7,7 +7,7 @@
@interface TGMediaPickerGalleryVideoItem : TGMediaPickerGalleryItem <TGModernGallerySelectableItem, TGModernGalleryEditableItem>
@property (nonatomic, readonly) AVAsset *avAsset;
@property (nonatomic, readonly) SSignal *avAsset;
@property (nonatomic, readonly) CGSize dimensions;
- (SSignal *)durationSignal;

View File

@ -52,7 +52,7 @@
@interface TGMediaSelectionChange : NSObject
@property (nonatomic, readonly) id<TGMediaSelectableItem> item;
@property (nonatomic, readonly) NSObject <TGMediaSelectableItem> *item;
@property (nonatomic, readonly) bool selected;
@property (nonatomic, readonly) bool animated;
@property (nonatomic, readonly, strong) id sender;

View File

@ -4,6 +4,12 @@
@class TGPhotoPaintEntitySelectionView;
@class TGPaintUndoManager;
@interface UIView (PixelColor)
- (UIColor *)colorAtPoint:(CGPoint)point;
@end
@interface TGPhotoPaintEntityView : UIView
{
NSInteger _entityUUID;
@ -55,4 +61,4 @@
- (void)fadeIn;
- (void)fadeOut;
@end
@end

View File

@ -4,9 +4,9 @@
@class TGPhotoPaintFont;
typedef enum {
TGPhotoPaintTextEntityStyleBorder,
TGPhotoPaintTextEntityStyleClassic,
TGPhotoPaintTextEntityStyleFrame
TGPhotoPaintTextEntityStyleOutlined,
TGPhotoPaintTextEntityStyleRegular,
TGPhotoPaintTextEntityStyleFramed
} TGPhotoPaintTextEntityStyle;
@interface TGPhotoPaintTextEntity : TGPhotoPaintEntity

View File

@ -270,13 +270,21 @@
GPUImageOutput *currentInput = _currentInput;
if ([currentInput isKindOfClass:[PGVideoMovie class]]) {
if (!_playing) {
_playing = true;
[_videoQueue dispatch:^{
if ([currentInput isKindOfClass:[PGVideoMovie class]]) {
[(PGVideoMovie *)currentInput startProcessing];
}
}];
if (capture) {
if ([currentInput isKindOfClass:[PGVideoMovie class]])
[(PGVideoMovie *)currentInput process];
[_finalFilter useNextFrameForImageCapture];
if (completion != nil)
completion();
} else {
if (!_playing) {
_playing = true;
[_videoQueue dispatch:^{
if ([currentInput isKindOfClass:[PGVideoMovie class]]) {
[(PGVideoMovie *)currentInput startProcessing];
}
}];
}
}
} else if ([currentInput isKindOfClass:[GPUImageTextureInput class]]) {
if (capture)

View File

@ -14,6 +14,7 @@
- (void)cancelProcessing;
- (void)processMovieFrame:(CMSampleBufferRef)movieSampleBuffer;
- (void)process;
- (void)reprocessCurrent;
@end

View File

@ -250,6 +250,11 @@ NSString *const kYUVVideoRangeConversionForLAFragmentShaderString = SHADER_STRIN
[self processPixelBufferAtTime:outputItemTime];
}
- (void)process {
_shouldReprocessCurrentFrame = true;
[self displayLinkCallback:displayLink];
}
- (void)processPixelBufferAtTime:(CMTime)outputItemTime
{
if ([playerItemOutput hasNewPixelBufferForItemTime:outputItemTime] || _shouldReprocessCurrentFrame)

View File

@ -178,7 +178,13 @@ const NSUInteger TGAttachmentDisplayedAssetLimit = 500;
if (strongSelf == nil)
return;
NSInteger index = [strongSelf->_fetchResult indexOfAsset:(TGMediaAsset *)change.item];
NSInteger index = 0;
if ([change.item isKindOfClass:[TGCameraCapturedVideo class]]) {
index = [strongSelf->_fetchResult indexOfAsset:((TGCameraCapturedVideo *)change.item).originalAsset];
} else {
index = [strongSelf->_fetchResult indexOfAsset:(TGMediaAsset *)change.item];
}
[strongSelf updateSendButtonsFromIndex:index];
[strongSelf updateSelectionIndexes];
@ -917,7 +923,7 @@ const NSUInteger TGAttachmentDisplayedAssetLimit = 500;
if ([editableItem isKindOfClass:[TGMediaAsset class]]) {
return [TGMediaAssetImageSignals avAssetForVideoAsset:(TGMediaAsset *)editableItem];
} else if ([editableItem isKindOfClass:[TGCameraCapturedVideo class]]) {
return [SSignal single:((TGCameraCapturedVideo *)editableItem).avAsset];
return ((TGCameraCapturedVideo *)editableItem).avAsset;
} else {
return [editableItem originalImageSignal:position];
}

View File

@ -3,21 +3,49 @@
#import <LegacyComponents/TGMediaAssetImageSignals.h>
#import <LegacyComponents/TGPhotoEditorUtils.h>
#import "LegacyComponentsGlobals.h"
#import "TGStringUtils.h"
#import "TGMediaAsset.h"
#import "TGMediaAsset+TGMediaEditableItem.h"
#import "TGGifConverter.h"
@interface TGCameraCapturedVideo ()
{
CGSize _cachedSize;
NSTimeInterval _cachedDuration;
AVURLAsset *_cachedAVAsset;
}
@end
@implementation TGCameraCapturedVideo
+ (NSURL *)videoURLForAsset:(TGMediaAsset *)asset {
NSURL *convertedGifsUrl = [NSURL fileURLWithPath:[[[LegacyComponentsGlobals provider] dataStoragePath] stringByAppendingPathComponent:@"convertedGifs"]];
[[NSFileManager defaultManager] createDirectoryAtPath:convertedGifsUrl.path withIntermediateDirectories:true attributes:nil error:nil];
return [convertedGifsUrl URLByAppendingPathComponent:[NSString stringWithFormat:@"%@.mp4", [TGStringUtils md5:asset.identifier]]];
}
- (instancetype)initWithURL:(NSURL *)url
{
self = [super init];
if (self != nil)
{
_avAsset = [[AVURLAsset alloc] initWithURL:url options:nil];
_cachedAVAsset = [[AVURLAsset alloc] initWithURL:url options:nil];
_cachedSize = CGSizeZero;
_cachedDuration = 0.0;
}
return self;
}
- (instancetype)initWithAsset:(TGMediaAsset *)asset
{
self = [super init];
if (self != nil)
{
_originalAsset = asset;
_cachedSize = CGSizeZero;
_cachedDuration = 0.0;
}
@ -26,7 +54,9 @@
- (void)_cleanUp
{
[[NSFileManager defaultManager] removeItemAtPath:_avAsset.URL.path error:nil];
if (_originalAsset == nil) {
[[NSFileManager defaultManager] removeItemAtPath:_cachedAVAsset.URL.path error:nil];
}
}
- (bool)isVideo
@ -34,9 +64,47 @@
return true;
}
- (bool)isAnimation {
return _originalAsset != nil;
}
- (SSignal *)avAsset {
if (_originalAsset != nil) {
if (_cachedAVAsset != nil) {
return [SSignal single:_cachedAVAsset];
} else {
NSURL *videoUrl = [TGCameraCapturedVideo videoURLForAsset:_originalAsset];
return [[TGMediaAssetImageSignals imageDataForAsset:_originalAsset allowNetworkAccess:false] mapToSignal:^SSignal *(TGMediaAssetImageData *assetData) {
NSData *data = assetData.imageData;
const char *gif87Header = "GIF87";
const char *gif89Header = "GIF89";
if (data.length >= 5 && (!memcmp(data.bytes, gif87Header, 5) || !memcmp(data.bytes, gif89Header, 5)))
{
return [[TGGifConverter convertGifToMp4:data] map:^id(NSDictionary *result)
{
NSString *filePath = result[@"path"];
[[NSFileManager defaultManager] moveItemAtPath:filePath toPath:videoUrl.path error:nil];
return [AVURLAsset assetWithURL:videoUrl];
}];
} else {
return [SSignal complete];
}
}];
}
} else {
return [SSignal single:_cachedAVAsset];
}
}
- (NSString *)uniqueIdentifier
{
return _avAsset.URL.absoluteString;
if (_originalAsset) {
return _originalAsset.uniqueIdentifier;
} else {
return _cachedAVAsset.URL.absoluteString;
}
}
- (CGSize)originalSize
@ -44,7 +112,11 @@
if (!CGSizeEqualToSize(_cachedSize, CGSizeZero))
return _cachedSize;
AVAssetTrack *track = _avAsset.tracks.firstObject;
if (_originalAsset != nil) {
return [_originalAsset originalSize];
}
AVAssetTrack *track = _cachedAVAsset.tracks.firstObject;
_cachedSize = CGRectApplyAffineTransform((CGRect){ CGPointZero, track.naturalSize }, track.preferredTransform).size;
return _cachedSize;
}
@ -59,29 +131,41 @@
if (_cachedDuration > DBL_EPSILON)
return _cachedDuration;
_cachedDuration = CMTimeGetSeconds(_avAsset.duration);
if (_cachedAVAsset != nil) {
_cachedDuration = CMTimeGetSeconds(_cachedAVAsset.duration);
}
return _cachedDuration;
}
- (SSignal *)thumbnailImageSignal
{
CGFloat thumbnailImageSide = TGPhotoEditorScreenImageMaxSize().width;
CGSize size = TGScaleToSize(self.originalSize, CGSizeMake(thumbnailImageSide, thumbnailImageSide));
if (_originalAsset != nil) {
return [_originalAsset thumbnailImageSignal];
} else {
CGFloat thumbnailImageSide = TGPhotoEditorScreenImageMaxSize().width;
CGSize size = TGScaleToSize(self.originalSize, CGSizeMake(thumbnailImageSide, thumbnailImageSide));
return [TGMediaAssetImageSignals videoThumbnailForAVAsset:_avAsset size:size timestamp:kCMTimeZero];
return [TGMediaAssetImageSignals videoThumbnailForAVAsset:_cachedAVAsset size:size timestamp:kCMTimeZero];
}
}
- (SSignal *)screenImageSignal:(NSTimeInterval)__unused position
- (SSignal *)screenImageSignal:(NSTimeInterval)position
{
CGFloat imageSide = 1280.0f;
CGSize size = TGScaleToSize(self.originalSize, CGSizeMake(imageSide, imageSide));
return [TGMediaAssetImageSignals videoThumbnailForAVAsset:_avAsset size:size timestamp:kCMTimeZero];
if (_originalAsset != nil) {
return [_originalAsset screenImageSignal:position];
} else {
CGFloat imageSide = 1280.0f;
CGSize size = TGScaleToSize(self.originalSize, CGSizeMake(imageSide, imageSide));
return [TGMediaAssetImageSignals videoThumbnailForAVAsset:_cachedAVAsset size:size timestamp:kCMTimeZero];
}
}
- (SSignal *)originalImageSignal:(NSTimeInterval)position
{
return [TGMediaAssetImageSignals videoThumbnailForAVAsset:_avAsset size:self.originalSize timestamp:CMTimeMakeWithSeconds(position, NSEC_PER_SEC)];
return [[self avAsset] mapToSignal:^SSignal *(AVURLAsset *avAsset) {
return [TGMediaAssetImageSignals videoThumbnailForAVAsset:avAsset size:self.originalSize timestamp:CMTimeMakeWithSeconds(position, NSEC_PER_SEC)];
}];
}
@end

View File

@ -1772,7 +1772,7 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
if ([editableItem isKindOfClass:[TGMediaAsset class]]) {
return [TGMediaAssetImageSignals avAssetForVideoAsset:(TGMediaAsset *)editableItem];
} else if ([editableItem isKindOfClass:[TGCameraCapturedVideo class]]) {
return [SSignal single:((TGCameraCapturedVideo *)editableItem).avAsset];
return ((TGCameraCapturedVideo *)editableItem).avAsset;
} else {
return [editableItem originalImageSignal:position];
}
@ -2467,7 +2467,9 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
else if ([item isKindOfClass:[TGCameraCapturedVideo class]])
{
TGCameraCapturedVideo *video = (TGCameraCapturedVideo *)item;
return [SSignal single:@{@"type": @"video", @"url": video.avAsset.URL}];
return [[video avAsset] mapToSignal:^SSignal *(AVURLAsset *avAsset) {
return [SSignal single:@{@"type": @"video", @"url": avAsset.URL}];
}];
}
return [SSignal complete];
@ -2689,9 +2691,11 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
};
CGSize imageSize = TGFillSize(asset.originalSize, CGSizeMake(512, 512));
SSignal *trimmedVideoThumbnailSignal = [[TGMediaAssetImageSignals videoThumbnailForAVAsset:video.avAsset size:imageSize timestamp:CMTimeMakeWithSeconds(adjustments.trimStartValue, NSEC_PER_SEC)] map:^UIImage *(UIImage *image)
{
SSignal *trimmedVideoThumbnailSignal = [[video avAsset] mapToSignal:^SSignal *(AVURLAsset *avAsset) {
return [[TGMediaAssetImageSignals videoThumbnailForAVAsset:avAsset size:imageSize timestamp:CMTimeMakeWithSeconds(adjustments.trimStartValue, NSEC_PER_SEC)] map:^UIImage *(UIImage *image)
{
return cropVideoThumbnail(image, TGScaleToFill(asset.originalSize, CGSizeMake(512, 512)), asset.originalSize, true);
}];
}];
SSignal *videoThumbnailSignal = [inlineThumbnailSignal(asset) map:^UIImage *(UIImage *image)
@ -2709,7 +2713,7 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
{
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
dict[@"type"] = @"cameraVideo";
dict[@"url"] = video.avAsset.URL;
// dict[@"url"] = video.avAsset.URL;
dict[@"previewImage"] = image;
dict[@"adjustments"] = adjustments;
dict[@"dimensions"] = [NSValue valueWithCGSize:dimensions];

View File

@ -1026,7 +1026,7 @@
if ([editableItem isKindOfClass:[TGMediaAsset class]]) {
return [TGMediaAssetImageSignals avAssetForVideoAsset:(TGMediaAsset *)editableItem];
} else if ([editableItem isKindOfClass:[TGCameraCapturedVideo class]]) {
return [SSignal single:((TGCameraCapturedVideo *)editableItem).avAsset];
return ((TGCameraCapturedVideo *)editableItem).avAsset;
} else {
return [editableItem originalImageSignal:position];
}

View File

@ -38,7 +38,7 @@
- (TGPhotoEditorTab)toolbarTabs
{
return TGPhotoEditorCropTab | TGPhotoEditorToolsTab | TGPhotoEditorPaintTab | TGPhotoEditorTimerTab;
return TGPhotoEditorCropTab | TGPhotoEditorToolsTab | TGPhotoEditorPaintTab;
}

View File

@ -77,7 +77,11 @@ const CGFloat TGGifConverterMaximumSide = 720.0f;
return;
}
CGSize targetSize = TGFitSizeF(CGSizeMake(sourceWidth, sourceHeight), CGSizeMake(TGGifConverterMaximumSide, TGGifConverterMaximumSide));
const CGFloat blockSize = 16.0f;
CGFloat renderWidth = CGFloor(sourceWidth / blockSize) * blockSize;
CGFloat renderHeight = CGFloor(sourceHeight * renderWidth / sourceWidth);
CGSize targetSize = TGFitSizeF(CGSizeMake(renderWidth, renderHeight), CGSizeMake(TGGifConverterMaximumSide, TGGifConverterMaximumSide));
NSDictionary *videoCleanApertureSettings = @
{
@ -122,8 +126,8 @@ const CGFloat TGGifConverterMaximumSide = 720.0f;
NSDictionary *attributes = @
{
(NSString *)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_32ARGB),
(NSString *)kCVPixelBufferWidthKey : @(sourceWidth),
(NSString *)kCVPixelBufferHeightKey : @(sourceHeight),
(NSString *)kCVPixelBufferWidthKey : @(renderWidth),
(NSString *)kCVPixelBufferHeightKey : @(renderHeight),
(NSString *)kCVPixelBufferCGImageCompatibilityKey : @YES,
(NSString *)kCVPixelBufferCGBitmapContextCompatibilityKey : @YES
};
@ -148,7 +152,7 @@ const CGFloat TGGifConverterMaximumSide = 720.0f;
if (gifProperties != NULL)
{
CVPixelBufferRef pxBuffer = [self newBufferFrom:imgRef withPixelBufferPool:adaptor.pixelBufferPool andAttributes:adaptor.sourcePixelBufferAttributes];
CVPixelBufferRef pxBuffer = [self newBufferFrom:imgRef size:targetSize withPixelBufferPool:adaptor.pixelBufferPool andAttributes:adaptor.sourcePixelBufferAttributes];
if (pxBuffer != NULL)
{
if (previewImage == nil) {
@ -231,13 +235,10 @@ const CGFloat TGGifConverterMaximumSide = 720.0f;
}];
};
+ (CVPixelBufferRef)newBufferFrom:(CGImageRef)frame withPixelBufferPool:(CVPixelBufferPoolRef)pixelBufferPool andAttributes:(NSDictionary *)attributes
+ (CVPixelBufferRef)newBufferFrom:(CGImageRef)frame size:(CGSize)size withPixelBufferPool:(CVPixelBufferPoolRef)pixelBufferPool andAttributes:(NSDictionary *)attributes
{
NSParameterAssert(frame);
size_t width = CGImageGetWidth(frame);
size_t height = CGImageGetHeight(frame);
size_t bpc = 8;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CVPixelBufferRef pxBuffer = NULL;
@ -246,7 +247,7 @@ const CGFloat TGGifConverterMaximumSide = 720.0f;
if (pixelBufferPool)
status = CVPixelBufferPoolCreatePixelBuffer(kCFAllocatorDefault, pixelBufferPool, &pxBuffer);
else
status = CVPixelBufferCreate(kCFAllocatorDefault, width, height, kCVPixelFormatType_32ARGB, (__bridge CFDictionaryRef)attributes, &pxBuffer);
status = CVPixelBufferCreate(kCFAllocatorDefault, size.width, size.height, kCVPixelFormatType_32ARGB, (__bridge CFDictionaryRef)attributes, &pxBuffer);
NSAssert(status == kCVReturnSuccess, @"Could not create a pixel buffer");
@ -255,10 +256,10 @@ const CGFloat TGGifConverterMaximumSide = 720.0f;
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(pxBuffer);
CGContextRef context = CGBitmapContextCreate(pxData, width, height, bpc, bytesPerRow, colorSpace, kCGImageAlphaNoneSkipFirst);
CGContextRef context = CGBitmapContextCreate(pxData, size.width, size.height, 8, bytesPerRow, colorSpace, kCGImageAlphaNoneSkipFirst);
NSAssert(context, @"Could not create a context");
CGContextDrawImage(context, CGRectMake(0, 0, width, height), frame);
CGContextDrawImage(context, CGRectMake(0, 0, size.width, size.height), frame);
CVPixelBufferUnlockBaseAddress(pxBuffer, 0);

View File

@ -434,7 +434,7 @@
if ([editableItem isKindOfClass:[TGMediaAsset class]]) {
return [TGMediaAssetImageSignals avAssetForVideoAsset:(TGMediaAsset *)editableItem];
} else if ([editableItem isKindOfClass:[TGCameraCapturedVideo class]]) {
return [SSignal single:((TGCameraCapturedVideo *)editableItem).avAsset];
return ((TGCameraCapturedVideo *)editableItem).avAsset;
} else {
return [editableItem originalImageSignal:position];
}

View File

@ -21,6 +21,7 @@
#import "TGModernGallerySelectableItem.h"
#import "TGModernGalleryEditableItem.h"
#import "TGMediaPickerGalleryPhotoItem.h"
#import "TGMediaPickerGalleryVideoItem.h"
#import "TGMediaPickerGalleryPhotoItemView.h"
#import "TGMediaPickerGalleryVideoItemView.h"
@ -150,6 +151,8 @@
[strongSelf.window endEditing:true];
if (strongSelf->_doneLongPressed != nil)
strongSelf->_doneLongPressed(strongSelf->_currentItem);
[[NSUserDefaults standardUserDefaults] setObject:@(3) forKey:@"TG_displayedMediaTimerTooltip_v3"];
};
_muteButton = [[TGModernButton alloc] initWithFrame:CGRectMake(0, 0, 39.0f, 39.0f)];
@ -571,7 +574,15 @@
[strongSelf->_portraitToolbarView setEditButtonsEnabled:available animated:true];
[strongSelf->_landscapeToolbarView setEditButtonsEnabled:available animated:true];
bool sendableAsGif = !strongSelf->_inhibitMute && [strongItemView isKindOfClass:[TGMediaPickerGalleryVideoItemView class]];
if ([strongSelf->_currentItem isKindOfClass:[TGMediaPickerGalleryVideoItem class]]) {
TGMediaPickerGalleryVideoItem *item = (TGMediaPickerGalleryVideoItem *)strongSelf->_currentItem;
if ([item.asset isKindOfClass:[TGCameraCapturedVideo class]] && ((TGCameraCapturedVideo *)item.asset).isAnimation) {
sendableAsGif = false;
}
}
strongSelf->_muteButton.hidden = !sendableAsGif;
}
}]];
@ -911,7 +922,7 @@
- (bool)shouldDisplayTooltip
{
return ![[[NSUserDefaults standardUserDefaults] objectForKey:@"TG_displayedMediaTimerTooltip_v2"] boolValue];
return [[[NSUserDefaults standardUserDefaults] objectForKey:@"TG_displayedMediaTimerTooltip_v3"] intValue] < 3;
}
- (void)setupTooltip:(CGRect)rect
@ -919,7 +930,7 @@
if (_tooltipContainerView != nil || !_hasTimer)
return;
_tooltipTimer = [TGTimerTarget scheduledMainThreadTimerWithTarget:self action:@selector(tooltipTimerTick) interval:2.5 repeat:false];
_tooltipTimer = [TGTimerTarget scheduledMainThreadTimerWithTarget:self action:@selector(tooltipTimerTick) interval:3.5 repeat:false];
_tooltipContainerView = [[TGMenuContainerView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, self.frame.size.width, self.frame.size.height)];
[self addSubview:_tooltipContainerView];
@ -934,7 +945,8 @@
[_tooltipContainerView showMenuFromRect:rect animated:false];
[[NSUserDefaults standardUserDefaults] setObject:@true forKey:@"TG_displayedMediaTimerTooltip_v2"];
int counter = [[[NSUserDefaults standardUserDefaults] objectForKey:@"TG_displayedMediaTimerTooltip_v3"] intValue];
[[NSUserDefaults standardUserDefaults] setObject:@(counter + 1) forKey:@"TG_displayedMediaTimerTooltip_v3"];
}
- (void)tooltipTimerTick

View File

@ -575,7 +575,7 @@
if ([editableItem isKindOfClass:[TGMediaAsset class]]) {
return [TGMediaAssetImageSignals avAssetForVideoAsset:(TGMediaAsset *)editableItem];
} else if ([editableItem isKindOfClass:[TGCameraCapturedVideo class]]) {
return [SSignal single:((TGCameraCapturedVideo *)editableItem).avAsset];
return ((TGCameraCapturedVideo *)editableItem).avAsset;
} else {
return [editableItem originalImageSignal:position];
}

View File

@ -1,7 +1,5 @@
#import "TGMediaPickerGalleryPhotoItemView.h"
#import <PhotosUI/PhotosUI.h>
#import "LegacyComponentsInternal.h"
#import "TGFont.h"
#import "TGStringUtils.h"
@ -34,7 +32,6 @@
void (^_currentAvailabilityObserver)(bool);
UIView *_temporaryRepView;
PHLivePhotoView *_livePhotoView;
UIView *_contentView;
UIView *_contentWrapperView;
@ -116,11 +113,6 @@
{
_imageView.hidden = false;
[_imageView reset];
if (_livePhotoView != nil)
{
[_livePhotoView removeFromSuperview];
_livePhotoView = nil;
}
[self setProgressVisible:false value:0.0f animated:false];
}
@ -231,8 +223,7 @@
}
[strongSelf reset];
strongSelf->_livePhotoView.frame = strongSelf->_imageView.frame;
}]];
if (!item.asFile)

View File

@ -50,9 +50,7 @@
return;
if (next.selected)
{
[strongSelf addSelectedItem:next.item];
}
else if (!strongSelf->_keepItems)
[strongSelf removeSelectedItem:next.item];
}]];

View File

@ -25,7 +25,7 @@
return CGSizeZero;
}
- (AVAsset *)avAsset
- (SSignal *)avAsset
{
if ([self.asset isKindOfClass:[TGCameraCapturedVideo class]])
return ((TGCameraCapturedVideo *)self.asset).avAsset;
@ -70,10 +70,13 @@
- (TGPhotoEditorTab)toolbarTabs
{
if ([self.asset isKindOfClass:[TGMediaAsset class]] && ((TGMediaAsset *)self.asset).subtypes & TGMediaAssetSubtypePhotoLive)
return TGPhotoEditorCropTab | TGPhotoEditorPaintTab | TGPhotoEditorToolsTab | TGPhotoEditorTimerTab;
else
if ([self.asset isKindOfClass:[TGMediaAsset class]] && ((TGMediaAsset *)self.asset).subtypes & TGMediaAssetSubtypePhotoLive) {
return TGPhotoEditorCropTab | TGPhotoEditorPaintTab | TGPhotoEditorToolsTab;
} else if ([self.asset isKindOfClass:[TGCameraCapturedVideo class]] && ((TGCameraCapturedVideo *)self.asset).isAnimation) {
return TGPhotoEditorCropTab | TGPhotoEditorPaintTab | TGPhotoEditorToolsTab;
} else {
return TGPhotoEditorCropTab | TGPhotoEditorToolsTab | TGPhotoEditorPaintTab | TGPhotoEditorQualityTab;
}
}
- (Class)viewClass

View File

@ -1045,16 +1045,16 @@
if (_videoView != nil)
{
SMetaDisposable *currentAudioSession = _currentAudioSession;
// if (currentAudioSession)
// {
if (currentAudioSession)
{
// _videoView.deallocBlock = ^
// {
// [[SQueue concurrentDefaultQueue] dispatch:^
// {
// [currentAudioSession setDisposable:nil];
// }];
[[SQueue concurrentDefaultQueue] dispatch:^
{
[currentAudioSession setDisposable:nil];
}];
// };
// }
}
// [_videoView cleanupPlayer];
_photoEditor.previewOutput = nil;
@ -1092,10 +1092,14 @@
[self inhibitVolumeOverlay];
SSignal *itemSignal = nil;
if ([self.item.asset isKindOfClass:[TGMediaAsset class]])
if ([self.item.asset isKindOfClass:[TGMediaAsset class]]) {
itemSignal = [TGMediaAssetImageSignals playerItemForVideoAsset:(TGMediaAsset *)self.item.asset];
else if (self.item.avAsset != nil)
itemSignal = [SSignal single:[AVPlayerItem playerItemWithAsset:self.item.avAsset]];
}
else if (self.item.avAsset != nil) {
itemSignal = [self.item.avAsset mapToSignal:^SSignal *(AVAsset *avAsset) {
return [SSignal single:[AVPlayerItem playerItemWithAsset:avAsset]];
}];
}
[_playerItemDisposable setDisposable:[[itemSignal deliverOn:[SQueue mainQueue]] startWithNext:^(AVPlayerItem *playerItem)
{
@ -1546,7 +1550,7 @@
if (timestamps.count == 0)
return;
AVAsset *avAsset = self.item.avAsset ?: _player.currentItem.asset;
SSignal *avAsset = self.item.avAsset ?: [SSignal single:_player.currentItem.asset];
TGMediaEditingContext *editingContext = self.item.editingContext;
id<TGMediaEditableItem> editableItem = self.item.editableMediaItem;
@ -1554,7 +1558,9 @@
if ([self.item.asset isKindOfClass:[TGMediaAsset class]] && ![self itemIsLivePhoto])
thumbnailsSignal = [TGMediaAssetImageSignals videoThumbnailsForAsset:self.item.asset size:size timestamps:timestamps];
else if (avAsset != nil)
thumbnailsSignal = [TGMediaAssetImageSignals videoThumbnailsForAVAsset:avAsset size:size timestamps:timestamps];
thumbnailsSignal = [avAsset mapToSignal:^SSignal *(AVAsset *avAsset) {
return [TGMediaAssetImageSignals videoThumbnailsForAVAsset:avAsset size:size timestamps:timestamps];
}];
_requestingThumbnails = true;

View File

@ -370,13 +370,18 @@
case TGMediaAssetGifType:
{
// TGCameraCapturedVideo *convertedAsset = [[TGCameraCapturedVideo alloc] initWithAsset:asset];
// galleryItem = [[TGMediaPickerGalleryVideoItem alloc] initWithAsset:convertedAsset];
galleryItem = [[TGMediaPickerGalleryGifItem alloc] initWithAsset:asset];
}
break;
default:
{
galleryItem = [[TGMediaPickerGalleryPhotoItem alloc] initWithAsset:asset];
if (asset.subtypes & TGMediaAssetSubtypePhotoLive)
galleryItem = [[TGMediaPickerGalleryVideoItem alloc] initWithAsset:asset];
else
galleryItem = [[TGMediaPickerGalleryPhotoItem alloc] initWithAsset:asset];
}
break;
}

View File

@ -68,7 +68,7 @@ const CGFloat TGPhotoCounterButtonMaskFade = 18;
_countLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, -0.5f, frame.size.width + 1.0, frame.size.height)];
_countLabel.backgroundColor = [UIColor clearColor];
_countLabel.font = [TGFont roundedFontOfSize:17];
_countLabel.font = [TGFont roundedFontOfSize:18];
_countLabel.text = [TGStringUtils stringWithLocalizedNumber:0];
_countLabel.textColor = [UIColor whiteColor];
[_wrapperView addSubview:_countLabel];
@ -299,15 +299,15 @@ const CGFloat TGPhotoCounterButtonMaskFade = 18;
{
labelOrigin = 12 + TGScreenPixel + (38 - labelWidth) / 2;
if ([_countLabel.text isEqualToString:@"1"] || [_countLabel.text isEqualToString:@"4"])
labelOrigin -= 2 * TGScreenPixel;
// if ([_countLabel.text isEqualToString:@"1"] || [_countLabel.text isEqualToString:@"4"])
// labelOrigin -= 2 * TGScreenPixel;
}
else
{
labelOrigin = (processingLabelWidth > 0) ? -processingLabelWidth + 19 + 13 - 4.5f: 64 - 38 + (38 - labelWidth) / 2.0f - 13;
}
_countLabel.frame = CGRectMake(labelOrigin, 6.0f, labelWidth, _countLabel.frame.size.height);
_countLabel.frame = CGRectMake(labelOrigin, 5.0 + TGScreenPixel, labelWidth, _countLabel.frame.size.height);
_countLabel.transform = transform;
}

View File

@ -0,0 +1,5 @@
#import "TGPaintBrush.h"
@interface TGPaintArrowBrush : TGPaintBrush
@end

View File

@ -0,0 +1,90 @@
#import "TGPaintArrowBrush.h"
const CGFloat TGPaintArrowBrushHardness = 0.92f;
@implementation TGPaintArrowBrush
- (CGFloat)spacing
{
return 0.15f;
}
- (CGFloat)alpha
{
return 0.85f;
}
- (CGFloat)angle
{
return 0.0f;
}
//- (CGFloat)dynamic
//{
// return 0.75f;
//}
- (bool)arrow
{
return true;
}
- (CGImageRef)generateRadialStampForSize:(CGSize)size hardness:(CGFloat)hardness
{
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceGray();
CGContextRef ctx = CGBitmapContextCreate(NULL, (NSInteger)size.width, (NSInteger)size.height, 8, (NSInteger)size.width, colorspace, kCGImageAlphaNone);
CGContextSetGrayFillColor(ctx, 0.0f, 1.0f);
CGContextFillRect(ctx, CGRectMake(0, 0, size.width, size.height));
NSArray *colors = @[(__bridge id) [UIColor whiteColor].CGColor, (__bridge id) [UIColor blackColor].CGColor];
const CGFloat locations[] = {0.0, 1.0};
CGGradientRef gradientRef = CGGradientCreateWithColors(colorspace, (__bridge CFArrayRef) colors, locations);
CGPoint center = CGPointMake(size.width / 2, size.height / 2);
CGFloat maxRadius = size.width / 2;
CGFloat hFactor = hardness * 0.99;
CGGradientDrawingOptions options = kCGGradientDrawsBeforeStartLocation |kCGGradientDrawsAfterEndLocation;
CGContextDrawRadialGradient(ctx, gradientRef, center, hFactor * maxRadius, center, maxRadius, options);
CGImageRef image = CGBitmapContextCreateImage(ctx);
CGContextRelease(ctx);
CGColorSpaceRelease(colorspace);
CGGradientRelease(gradientRef);
return image;
}
- (CGImageRef)stampRef
{
static CGImageRef image = NULL;
if (image == NULL)
image = [self generateRadialStampForSize:TGPaintBrushTextureSize hardness:TGPaintArrowBrushHardness];
return image;
}
- (CGImageRef)previewStampRef
{
if (_previewStampRef == NULL)
_previewStampRef = [self generateRadialStampForSize:TGPaintBrushPreviewTextureSize hardness:TGPaintArrowBrushHardness];
return _previewStampRef;
}
static UIImage *radialBrushPreviewImage = nil;
- (UIImage *)previewImage
{
return radialBrushPreviewImage;
}
- (void)setPreviewImage:(UIImage *)previewImage
{
radialBrushPreviewImage = previewImage;
}
@end

View File

@ -10,7 +10,9 @@
@property (nonatomic, readonly) CGFloat alpha;
@property (nonatomic, readonly) CGFloat angle;
@property (nonatomic, readonly) CGFloat scale;
@property (nonatomic, readonly) CGFloat dynamic;
@property (nonatomic, readonly) bool lightSaber;
@property (nonatomic, readonly) bool arrow;
@property (nonatomic, readonly) CGImageRef stampRef;
@property (nonatomic, readonly) CGImageRef previewStampRef;
@ -20,4 +22,4 @@
@end
extern const CGSize TGPaintBrushTextureSize;
extern const CGSize TGPaintBrushPreviewTextureSize;
extern const CGSize TGPaintBrushPreviewTextureSize;

View File

@ -61,6 +61,11 @@ const CGSize TGPaintBrushPreviewTextureSize = { 64.0f, 64.0f };
return 1.0f;
}
- (CGFloat)dynamic
{
return 0.0f;
}
- (bool)lightSaber
{
return false;

View File

@ -283,10 +283,11 @@ const NSUInteger TGPaintBrushPreviewSegmentsCount = 100;
[self _setupBrush];
[_renderState reset];
_path.remainder = 0.0f;
_path.pressureRemainder = 0.0f;
_path.brush = brush;
[TGPaintRender renderPath:_path renderState:_renderState];
if (_brush.lightSaber)
{
glBindFramebuffer(GL_FRAMEBUFFER, _lightFramebuffer);

View File

@ -9,6 +9,7 @@
#import "TGPaintPath.h"
#import "TGPaintState.h"
#import "TGPaintCanvas.h"
#import "TGPaintBrush.h"
#import <LegacyComponents/TGPaintUtils.h>
@interface TGPaintInput ()
@ -19,6 +20,8 @@
CGPoint _lastLocation;
CGFloat _lastRemainder;
CGFloat _lastPressureRemainder;
CGFloat _lastAngle;
TGPaintPoint *_points[3];
NSInteger _pointsCount;
@ -48,7 +51,7 @@
CGPoint midPoint1 = TGPaintMultiplyPoint(TGPaintAddPoints(prev1.CGPoint, prev2.CGPoint), 0.5f);
CGFloat midPressure1 = (prev1.z + prev2.z) * 0.5f;
CGPoint midPoint2 = TGPaintMultiplyPoint(TGPaintAddPoints(cur.CGPoint, prev1.CGPoint), 0.5f);
CGFloat midPressure2 = (cur.z + prev2.z) * 0.5f;
CGFloat midPressure2 = (cur.z + prev1.z) * 0.5f;
NSInteger segmentDistance = 2;
CGFloat distance = TGPaintDistance(midPoint1, midPoint2);
@ -126,12 +129,15 @@
if (_pointsCount != 0)
pressure = (pressure + _points[_pointsCount - 1].z) / 2.0f;
pressure = 1.0f;
TGPaintPoint *point = [TGPaintPoint pointWithX:location.x y:location.y z:pressure];
_points[_pointsCount++] = point;
if (_pointsCount == 3)
{
CGPoint prev = _points[1].CGPoint;
CGPoint cur = _points[2].CGPoint;
_lastAngle = atan2(cur.y - prev.y, cur.x - prev.x);
[self smoothenAndPaintPoints:canvas ended:false];
_moved = true;
}
@ -156,6 +162,22 @@
else
{
[self smoothenAndPaintPoints:canvas ended:true];
if (canvas.state.brush.arrow) {
CGFloat arrowLength = canvas.state.weight * 4.5;
CGFloat angle = _lastAngle;
TGPaintPoint *tip = [TGPaintPoint pointWithX:location.x y:location.y z:0.8];
TGPaintPoint *leftTip = [TGPaintPoint pointWithX:location.x + cos(angle - M_PI_4 * 3) * arrowLength y:location.y + sin(angle - M_PI_4 * 3.2) * arrowLength z:1.0];
leftTip.edge = true;
TGPaintPath *left = [[TGPaintPath alloc] initWithPoints:@[tip, leftTip]];
[self paintPath:left inCanvas:canvas];
TGPaintPoint *rightTip = [TGPaintPoint pointWithX:location.x + cos(angle + M_PI_4 * 3) * arrowLength y:location.y + sin(angle + M_PI_4 * 3.2) * arrowLength z:1.0];
rightTip.edge = true;
TGPaintPath *right = [[TGPaintPath alloc] initWithPoints:@[tip, rightTip]];
[self paintPath:right inCanvas:canvas];
}
}
_pointsCount = 0;
@ -181,16 +203,20 @@
path.brush = canvas.state.brush;
path.baseWeight = canvas.state.weight;
if (_clearBuffer)
if (_clearBuffer) {
_lastRemainder = 0.0f;
_lastPressureRemainder = 0.0f;
}
path.remainder = _lastRemainder;
path.pressureRemainder = _lastPressureRemainder;
[canvas.painting paintStroke:path clearBuffer:_clearBuffer completion:^
{
TGDispatchOnMainThread(^
{
_lastRemainder = path.remainder;
_lastPressureRemainder = path.pressureRemainder;
_clearBuffer = false;
});
}];

View File

@ -43,6 +43,7 @@ typedef enum
@property (nonatomic, strong) TGPaintBrush *brush;
@property (nonatomic, assign) CGFloat remainder;
@property (nonatomic, assign) CGFloat pressureRemainder;
- (instancetype)initWithPoint:(TGPaintPoint *)point;
- (instancetype)initWithPoints:(NSArray *)points;

View File

@ -19,6 +19,11 @@ const CGFloat TGPaintRadialBrushHardness = 0.92f;
return 0.0f;
}
//- (CGFloat)dynamic
//{
// return 0.75f;
//}
- (CGImageRef)generateRadialStampForSize:(CGSize)size hardness:(CGFloat)hardness
{
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceGray();

View File

@ -14,6 +14,7 @@ const NSInteger TGPaintRenderStateDefaultSize = 256;
}
@property (nonatomic, assign) CGFloat brushWeight;
@property (nonatomic, assign) CGFloat brushDynamic;
@property (nonatomic, assign) CGFloat spacing;
@property (nonatomic, assign) CGFloat alpha;
@property (nonatomic, assign) CGFloat angle;
@ -23,6 +24,7 @@ const NSInteger TGPaintRenderStateDefaultSize = 256;
@property (nonatomic, readonly) NSUInteger count;
@property (nonatomic, assign) CGFloat remainder;
@property (nonatomic, assign) CGFloat pressureRemainder;
- (void)reset;
@ -103,6 +105,7 @@ const NSInteger TGPaintRenderStateDefaultSize = 256;
}
_remainder = 0;
_pressureRemainder = 0;
}
@end
@ -120,18 +123,15 @@ typedef struct
+ (void)_paintStamp:(TGPaintPoint *)point state:(TGPaintRenderState *)state
{
CGFloat weight = state.brushWeight;
CGPoint start = point.CGPoint;
CGFloat brushSize = weight;
CGFloat rotationalScatter = 0.0f;
CGFloat brushSize = state.brushWeight * state.scale;
CGFloat angleOffset = fabs(state.angle) > FLT_EPSILON ? state.angle : 0.0f;
CGFloat alpha = MIN(1.0f, state.alpha * 1.55f);
[state prepare];
[state appendValuesCount:1];
[state addPoint:start size:brushSize angle:rotationalScatter + angleOffset alpha:alpha index:0];
[state appendValuesCount:4];
for (NSInteger i = 0; i < 4; i++) {
[state addPoint:point.CGPoint size:brushSize angle:angleOffset alpha:alpha index:i];
}
}
+ (void)_paintFromPoint:(TGPaintPoint *)lastLocation toPoint:(TGPaintPoint *)location state:(TGPaintRenderState *)state
@ -139,6 +139,7 @@ typedef struct
CGFloat lastP = lastLocation.z;
CGFloat p = location.z;
CGFloat pDelta = p - lastP;
CGFloat pChange = 0.0f;
CGFloat f, distance = TGPaintDistance(lastLocation.CGPoint, location.CGPoint);
CGPoint vector = TGPaintSubtractPoints(location.CGPoint, lastLocation.CGPoint);
@ -148,8 +149,8 @@ typedef struct
CGFloat brushWeight = state.brushWeight * state.scale;
CGFloat step = MAX(1.0f, state.spacing * brushWeight);
CGFloat pressure = lastP;
CGFloat pressureStep = 0.0f;
CGFloat pressure = lastP + state.pressureRemainder;
CGFloat pressureStep = pressureStep = pDelta / ((distance - state.remainder) / step);
if (distance > 0.0f)
unitVector = TGPaintMultiplyPoint(vector, 1.0f / distance);
@ -168,27 +169,29 @@ typedef struct
for (f = state.remainder; f <= distance; f += step, pressure += pressureStep)
{
CGFloat alpha = boldenFirst ? boldenedAlpha : state.alpha;
CGFloat brushSize = brushWeight;
// CGFloat brushSize = MIN(brushWeight, brushWeight - pressure * brushWeight * 0.55f);
CGFloat brushSize = MAX(1.0, brushWeight - state.brushDynamic * pressure * brushWeight);
// CGFloat brushSize = brushWeight;
[state addPoint:start size:brushSize angle:vectorAngle alpha:alpha index:i];
start = TGPaintAddPoints(start, TGPaintMultiplyPoint(unitVector, step));
i++;
boldenFirst = false;
pressureStep = pDelta / (distance / step);
pChange += pressureStep;
i++;
}
// NSLog(@"final pressure %f", pressure);
if (boldenLast)
{
[state appendValuesCount:1];
CGFloat brushSize = MIN(brushWeight, brushWeight - pressure * brushWeight * 0.65f);
CGFloat brushSize = MAX(1.0, brushWeight - state.brushDynamic * pressure * brushWeight);
[state addPoint:location.CGPoint size:brushSize angle:vectorAngle alpha:boldenedAlpha index:i];
}
state.remainder = f - distance;
state.pressureRemainder = pChange - pDelta;
}
+ (CGRect)_drawWithState:(TGPaintRenderState *)state
@ -292,6 +295,7 @@ typedef struct
+ (CGRect)renderPath:(TGPaintPath *)path renderState:(TGPaintRenderState *)renderState
{
renderState.brushWeight = path.baseWeight;
renderState.brushDynamic = path.brush.dynamic;
renderState.spacing = path.brush.spacing;
renderState.alpha = path.brush.alpha;
renderState.angle = path.brush.angle;
@ -313,6 +317,7 @@ typedef struct
}
path.remainder = renderState.remainder;
path.pressureRemainder = renderState.pressureRemainder;
return [self _drawWithState:renderState];
}

View File

@ -4,7 +4,7 @@
@interface TGPaintSwatch : NSObject
@property (nonatomic, readonly) UIColor *color;
@property (nonatomic, readonly) CGFloat colorLocaton;
@property (nonatomic, readonly) CGFloat colorLocation;
@property (nonatomic, readonly) CGFloat brushWeight;
+ (instancetype)swatchWithColor:(UIColor *)color colorLocation:(CGFloat)colorLocation brushWeight:(CGFloat)brushWeight;

View File

@ -11,14 +11,14 @@
return false;
TGPaintSwatch *swatch = (TGPaintSwatch *)object;
return [swatch.color isEqual:self.color] && fabs(swatch.colorLocaton - self.colorLocaton) < FLT_EPSILON && fabs(swatch.brushWeight - self.brushWeight) < FLT_EPSILON;
return [swatch.color isEqual:self.color] && fabs(swatch.colorLocation - self.colorLocation) < FLT_EPSILON && fabs(swatch.brushWeight - self.brushWeight) < FLT_EPSILON;
}
+ (instancetype)swatchWithColor:(UIColor *)color colorLocation:(CGFloat)colorLocation brushWeight:(CGFloat)brushWeight
{
TGPaintSwatch *swatch = [[TGPaintSwatch alloc] init];
swatch->_color = color;
swatch->_colorLocaton = colorLocation;
swatch->_colorLocation = colorLocation;
swatch->_brushWeight = brushWeight;
return swatch;

View File

@ -10,19 +10,20 @@
#import "TGPaintBrush.h"
#import "TGPaintBrushPreview.h"
const CGFloat TGPhotoBrushSettingsViewMargin = 19.0f;
const CGFloat TGPhotoBrushSettingsViewMargin = 10.0f;
const CGFloat TGPhotoBrushSettingsItemHeight = 44.0f;
@interface TGPhotoBrushSettingsView ()
{
NSArray *_brushes;
TGPaintBrushPreview *_preview;
UIImageView *_backgroundView;
UIView *_wrapperView;
UIView *_contentView;
UIVisualEffectView *_effectView;
NSArray *_brushViews;
NSArray *_brushIconViews;
NSArray *_brushSeparatorViews;
UIImageView *_selectedCheckView;
UIImage *_landscapeLeftBackgroundImage;
UIImage *_landscapeRightBackgroundImage;
@ -40,80 +41,110 @@ const CGFloat TGPhotoBrushSettingsItemHeight = 44.0f;
if (self != nil)
{
_brushes = brushes;
_preview = preview;
_interfaceOrientation = UIInterfaceOrientationPortrait;
_backgroundView = [[UIImageView alloc] init];
//_backgroundView.alpha = 0.98f;
[self addSubview:_backgroundView];
_wrapperView = [[UIView alloc] init];
_wrapperView.clipsToBounds = true;
_wrapperView.layer.cornerRadius = 12.0;
[self addSubview:_wrapperView];
_effectView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]];
_effectView.alpha = 0.0f;
_effectView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[_wrapperView addSubview:_effectView];
_contentView = [[UIView alloc] init];
_contentView.alpha = 0.0f;
_contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[_wrapperView addSubview:_contentView];
UIFont *font = [UIFont systemFontOfSize:17];
NSMutableArray *brushViews = [[NSMutableArray alloc] init];
NSMutableArray *brushIconViews = [[NSMutableArray alloc] init];
NSMutableArray *separatorViews = [[NSMutableArray alloc] init];
[brushes enumerateObjectsUsingBlock:^(__unused TGPaintBrush *brush, NSUInteger index, __unused BOOL *stop)
{
TGModernButton *button = [[TGModernButton alloc] initWithFrame:CGRectMake(0, TGPhotoBrushSettingsViewMargin + index * TGPhotoBrushSettingsItemHeight, 0, 0)];
button.tag = index;
button.imageView.contentMode = UIViewContentModeCenter;
button.contentEdgeInsets = UIEdgeInsetsMake(0.0f, 30.0f, 0.0f, 0.0f);
[button addTarget:self action:@selector(brushButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:button];
NSString *title;
UIImage *icon;
switch (index) {
case 0:
title = TGLocalized(@"Paint.Pen");
icon = [UIImage imageNamed:@"Editor/BrushPen"];
break;
case 1:
title = TGLocalized(@"Paint.Marker");
icon = [UIImage imageNamed:@"Editor/BrushMarker"];
break;
case 2:
title = TGLocalized(@"Paint.Neon");
icon = [UIImage imageNamed:@"Editor/BrushNeon"];
break;
case 3:
title = TGLocalized(@"Paint.Arrow");
icon = [UIImage imageNamed:@"Editor/BrushArrow"];
break;
default:
break;
}
TGModernButton *button = [[TGModernButton alloc] initWithFrame:CGRectMake(0, index * TGPhotoBrushSettingsItemHeight, 0, 0)];
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
button.titleLabel.font = font;
button.contentEdgeInsets = UIEdgeInsetsMake(0.0f, 16.0f, 0.0f, 0.0f);
button.tag = index;
[button setTitle:title forState:UIControlStateNormal];
[button setTitleColor:[UIColor whiteColor]];
[button addTarget:self action:@selector(brushButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
[_contentView addSubview:button];
[brushViews addObject:button];
UIImageView *iconView = [[UIImageView alloc] initWithImage:TGTintedImage(icon, [UIColor whiteColor])];
[button addSubview:iconView];
[brushIconViews addObject:iconView];
if (index != brushes.count - 1)
{
UIView *separatorView = [[UIView alloc] init];
separatorView.backgroundColor = UIColorRGB(0xd6d6da);
[self addSubview:separatorView];
separatorView.backgroundColor = UIColorRGBA(0xffffff, 0.2);
[_contentView addSubview:separatorView];
[separatorViews addObject:separatorView];
}
}];
_brushViews = brushViews;
_brushIconViews = brushIconViews;
_brushSeparatorViews = separatorViews;
_selectedCheckView = [[UIImageView alloc] initWithImage:TGComponentsImageNamed(@"PaintCheck")];
_selectedCheckView.frame = CGRectMake(15.0f, 16.0f, _selectedCheckView.frame.size.width, _selectedCheckView.frame.size.height);
}
return self;
}
- (void)brushButtonPressed:(TGModernButton *)sender
{
[sender addSubview:_selectedCheckView];
if (self.brushChanged != nil)
self.brushChanged(_brushes[sender.tag]);
}
- (void)present
{
self.alpha = 0.0f;
self.layer.rasterizationScale = TGScreenScaling();
self.layer.shouldRasterize = true;
[self _setupBrushPreviews];
[UIView animateWithDuration:0.2 animations:^
[UIView animateWithDuration:0.25 animations:^
{
self.alpha = 1.0f;
_effectView.alpha = 1.0f;
_contentView.alpha = 1.0f;
} completion:^(__unused BOOL finished)
{
//self.layer.shouldRasterize = false;
}];
}
- (void)dismissWithCompletion:(void (^)(void))completion
{
self.layer.rasterizationScale = TGScreenScaling();
self.layer.shouldRasterize = true;
[UIView animateWithDuration:0.15 animations:^
[UIView animateWithDuration:0.2 animations:^
{
self.alpha = 0.0f;
_effectView.alpha = 0.0f;
_contentView.alpha = 0.0f;
} completion:^(__unused BOOL finished)
{
if (completion != nil)
@ -121,90 +152,38 @@ const CGFloat TGPhotoBrushSettingsItemHeight = 44.0f;
}];
}
- (void)_setupBrushPreviews
{
[_brushes enumerateObjectsUsingBlock:^(TGPaintBrush *aBrush, NSUInteger index, __unused BOOL *stop)
{
UIImage *image = aBrush.previewImage;
if (image == nil)
{
image = [_preview imageForBrush:aBrush size:CGSizeMake([self sizeThatFits:CGSizeZero].width - 85.0f, TGPhotoBrushSettingsItemHeight)];
aBrush.previewImage = image;
}
[_brushViews[index] setImage:image forState:UIControlStateNormal];
}];
}
- (TGPaintBrush *)brush
{
return _brushes[_selectedCheckView.superview.tag];
}
- (void)setBrush:(TGPaintBrush *)brush
{
[_brushes enumerateObjectsUsingBlock:^(TGPaintBrush *aBrush, NSUInteger index, BOOL *stop)
{
if ([brush isEqual:aBrush])
{
[_brushViews[index] addSubview:_selectedCheckView];
*stop = true;
}
}];
}
- (CGSize)sizeThatFits:(CGSize)__unused size
{
return CGSizeMake(256, _brushViews.count * TGPhotoBrushSettingsItemHeight + TGPhotoBrushSettingsViewMargin * 2);
return CGSizeMake(220, _brushViews.count * TGPhotoBrushSettingsItemHeight + TGPhotoBrushSettingsViewMargin * 2);
}
- (void)setInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
_interfaceOrientation = interfaceOrientation;
switch (self.interfaceOrientation)
{
case UIInterfaceOrientationLandscapeLeft:
{
_backgroundView.image = [TGPhotoPaintSettingsView landscapeLeftBackgroundImage];
}
break;
case UIInterfaceOrientationLandscapeRight:
{
_backgroundView.image = [TGPhotoPaintSettingsView landscapeRightBackgroundImage];
}
break;
default:
{
_backgroundView.image = [TGPhotoPaintSettingsView portraitBackgroundImage];
}
break;
}
[self setNeedsLayout];
}
- (void)layoutSubviews
{
CGFloat arrowSize = 0.0f;
switch (self.interfaceOrientation)
{
case UIInterfaceOrientationLandscapeLeft:
{
_backgroundView.frame = CGRectMake(TGPhotoBrushSettingsViewMargin - 13.0f, TGPhotoBrushSettingsViewMargin, self.frame.size.width - TGPhotoBrushSettingsViewMargin * 2 + 13.0f, self.frame.size.height - TGPhotoBrushSettingsViewMargin * 2);
_wrapperView.frame = CGRectMake(TGPhotoBrushSettingsViewMargin - arrowSize, TGPhotoBrushSettingsViewMargin, self.frame.size.width - TGPhotoBrushSettingsViewMargin * 2 + arrowSize, self.frame.size.height - TGPhotoBrushSettingsViewMargin * 2);
}
break;
case UIInterfaceOrientationLandscapeRight:
{
_backgroundView.frame = CGRectMake(TGPhotoBrushSettingsViewMargin, TGPhotoBrushSettingsViewMargin, self.frame.size.width - TGPhotoBrushSettingsViewMargin * 2 + 13.0f, self.frame.size.height - TGPhotoBrushSettingsViewMargin * 2);
_wrapperView.frame = CGRectMake(TGPhotoBrushSettingsViewMargin, TGPhotoBrushSettingsViewMargin, self.frame.size.width - TGPhotoBrushSettingsViewMargin * 2 + arrowSize, self.frame.size.height - TGPhotoBrushSettingsViewMargin * 2);
}
break;
default:
{
_backgroundView.frame = CGRectMake(TGPhotoBrushSettingsViewMargin, TGPhotoBrushSettingsViewMargin, self.frame.size.width - TGPhotoBrushSettingsViewMargin * 2, self.frame.size.height - TGPhotoBrushSettingsViewMargin * 2 + 13.0f);
_wrapperView.frame = CGRectMake(TGPhotoBrushSettingsViewMargin, TGPhotoBrushSettingsViewMargin, self.frame.size.width - TGPhotoBrushSettingsViewMargin * 2, self.frame.size.height - TGPhotoBrushSettingsViewMargin * 2 + arrowSize);
}
break;
}
@ -213,13 +192,17 @@ const CGFloat TGPhotoBrushSettingsItemHeight = 44.0f;
[_brushViews enumerateObjectsUsingBlock:^(TGModernButton *view, NSUInteger index, __unused BOOL *stop)
{
view.frame = CGRectMake(TGPhotoBrushSettingsViewMargin, TGPhotoBrushSettingsViewMargin + TGPhotoBrushSettingsItemHeight * index, self.frame.size.width - TGPhotoBrushSettingsViewMargin * 2, TGPhotoBrushSettingsItemHeight);
view.frame = CGRectMake(0.0f, TGPhotoBrushSettingsItemHeight * index, _contentView.frame.size.width, TGPhotoBrushSettingsItemHeight);
}];
[_brushIconViews enumerateObjectsUsingBlock:^(UIImageView *view, NSUInteger index, __unused BOOL *stop)
{
view.frame = CGRectMake(_contentView.frame.size.width - 42.0f, (TGPhotoBrushSettingsItemHeight - view.frame.size.height) / 2.0, view.frame.size.width, view.frame.size.height);
}];
[_brushSeparatorViews enumerateObjectsUsingBlock:^(UIView *view, NSUInteger index, __unused BOOL *stop)
{
view.frame = CGRectMake(TGPhotoBrushSettingsViewMargin + 44.0f, TGPhotoBrushSettingsViewMargin + TGPhotoBrushSettingsItemHeight * (index + 1), self.frame.size.width - TGPhotoBrushSettingsViewMargin * 2 - 44.0f, thickness);
view.frame = CGRectMake(0.0f, TGPhotoBrushSettingsItemHeight * (index + 1), _contentView.frame.size.width, thickness);
}];
}

View File

@ -1552,7 +1552,7 @@
if ([item isKindOfClass:[TGMediaAsset class]])
assetSignal = [TGMediaAssetImageSignals avAssetForVideoAsset:(TGMediaAsset *)item];
else if ([item isKindOfClass:[TGCameraCapturedVideo class]])
assetSignal = [SSignal single:((TGCameraCapturedVideo *)item).avAsset];
assetSignal = ((TGCameraCapturedVideo *)item).avAsset;
[assetSignal startWithNext:^(AVAsset *asset)
{

View File

@ -15,6 +15,8 @@
- (void)updateVisibility:(bool)visible;
- (UIColor *)colorAtPoint:(CGPoint)point;
- (void)setupWithPaintingData:(TGPaintingData *)paintingData;
- (TGPhotoPaintEntityView *)createEntityViewWithEntity:(TGPhotoPaintEntity *)entity;

View File

@ -47,7 +47,7 @@
- (void)handleTap:(UITapGestureRecognizer *)gestureRecognizer
{
CGPoint location = [gestureRecognizer locationInView:self];
CGPoint point = [gestureRecognizer locationInView:self];
NSMutableArray *intersectedViews = [[NSMutableArray alloc] init];
for (TGPhotoPaintEntityView *view in self.subviews)
@ -55,7 +55,7 @@
if (![view isKindOfClass:[TGPhotoPaintEntityView class]])
continue;
if ([view pointInside:[view convertPoint:location fromView:self] withEvent:nil])
if ([view pointInside:[view convertPoint:point fromView:self] withEvent:nil])
[intersectedViews addObject:view];
}
@ -65,7 +65,7 @@
__block TGPhotoPaintEntityView *subresult = nil;
[intersectedViews enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(TGPhotoPaintEntityView *view, __unused NSUInteger index, BOOL *stop)
{
if ([view precisePointInside:[view convertPoint:location fromView:self]])
if ([view precisePointInside:[view convertPoint:point fromView:self]])
{
subresult = view;
*stop = true;
@ -83,6 +83,40 @@
self.entitySelected(result);
}
- (UIColor *)colorAtPoint:(CGPoint)point {
NSMutableArray *intersectedViews = [[NSMutableArray alloc] init];
for (TGPhotoPaintEntityView *view in self.subviews)
{
if (![view isKindOfClass:[TGPhotoPaintEntityView class]])
continue;
if ([view pointInside:[view convertPoint:point fromView:self] withEvent:nil])
[intersectedViews addObject:view];
}
TGPhotoPaintEntityView *result = nil;
if (intersectedViews.count > 1)
{
__block TGPhotoPaintEntityView *subresult = nil;
[intersectedViews enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(TGPhotoPaintEntityView *view, __unused NSUInteger index, BOOL *stop)
{
if ([view precisePointInside:[view convertPoint:point fromView:self]])
{
subresult = view;
*stop = true;
}
}];
result = subresult ?: intersectedViews.lastObject;
}
else if (intersectedViews.count == 1)
{
result = intersectedViews.firstObject;
}
return [result colorAtPoint:[result convertPoint:point fromView:self]];
}
- (NSUInteger)entitiesCount
{
return MAX(0, (NSInteger)self.subviews.count - 1);

View File

@ -137,7 +137,7 @@ const CGFloat TGPhotoPaintDefaultColorLocation = 1.0f;
- (void)setSwatch:(TGPaintSwatch *)swatch
{
[self setLocation:swatch.colorLocaton];
[self setLocation:swatch.colorLocation];
[self setWeight:swatch.brushWeight];
}

View File

@ -23,6 +23,7 @@
#import "TGPaintRadialBrush.h"
#import "TGPaintEllipticalBrush.h"
#import "TGPaintNeonBrush.h"
#import "TGPaintArrowBrush.h"
#import "TGPaintCanvas.h"
#import "TGPaintingWrapperView.h"
#import "TGPaintState.h"
@ -45,6 +46,7 @@
#import "TGPhotoEntitiesContainerView.h"
#import "TGPhotoStickerEntityView.h"
#import "TGPhotoTextEntityView.h"
#import "TGPhotoPaintEyedropperView.h"
#import "TGPaintFaceDetector.h"
#import "TGPhotoMaskPosition.h"
@ -83,6 +85,7 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
UIView *_contentWrapperView;
UIView *_dimView;
TGModernButton *_doneButton;
TGPhotoPaintActionsView *_landscapeActionsView;
TGPhotoPaintActionsView *_portraitActionsView;
@ -104,6 +107,7 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
TGPhotoPaintSelectionContainerView *_selectionContainerView;
TGPhotoPaintEntitySelectionView *_entitySelectionView;
TGPhotoPaintEyedropperView *_eyedropperView;
TGPhotoTextEntityView *_editedTextView;
CGPoint _editedTextCenter;
@ -122,6 +126,11 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
bool _enableStickers;
NSData *_eyedropperBackgroundData;
CGSize _eyedropperBackgroundSize;
NSInteger _eyedropperBackgroundBytesPerRow;
CGBitmapInfo _eyedropperBackgroundInfo;
id<LegacyComponentsContext> _context;
}
@ -151,10 +160,11 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
[
[[TGPaintRadialBrush alloc] init],
[[TGPaintEllipticalBrush alloc] init],
[[TGPaintNeonBrush alloc] init]
[[TGPaintNeonBrush alloc] init],
[[TGPaintArrowBrush alloc] init],
];
_selectedTextFont = [[TGPhotoPaintFont availableFonts] firstObject];
_selectedTextStyle = TGPhotoPaintTextEntityStyleBorder;
_selectedTextStyle = TGPhotoPaintTextEntityStyleFramed;
if (_photoEditor.paintingData.undoManager != nil)
_undoManager = [_photoEditor.paintingData.undoManager copy];
@ -265,11 +275,30 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
_dimView.backgroundColor = UIColorRGBA(0x000000, 0.4f);
_dimView.userInteractionEnabled = false;
[_entitiesContainerView addSubview:_dimView];
_selectionContainerView = [[TGPhotoPaintSelectionContainerView alloc] init];
_selectionContainerView.clipsToBounds = false;
[_containerView addSubview:_selectionContainerView];
_eyedropperView = [[TGPhotoPaintEyedropperView alloc] init];
_eyedropperView.locationChanged = ^(CGPoint location, bool finished) {
__strong TGPhotoPaintController *strongSelf = weakSelf;
if (strongSelf != nil)
{
UIColor *color = [strongSelf colorAtPoint:location];
strongSelf->_eyedropperView.color = color;
if (finished) {
TGPaintSwatch *swatch = [TGPaintSwatch swatchWithColor:color colorLocation:0.5 brushWeight:strongSelf->_portraitSettingsView.swatch.brushWeight];
[strongSelf setCurrentSwatch:swatch sender:nil];
[strongSelf commitEyedropper:false];
}
}
};
_eyedropperView.hidden = true;
[_selectionContainerView addSubview:_eyedropperView];
_wrapperView = [[TGPhotoPaintSparseView alloc] initWithFrame:CGRectZero];
[self.view addSubview:_wrapperView];
@ -307,12 +336,22 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
_landscapeActionsView.clearPressed = clearPressed;
[_wrapperView addSubview:_landscapeActionsView];
_doneButton = [[TGModernButton alloc] init];
_doneButton.alpha = 0.0f;
_doneButton.userInteractionEnabled = false;
[_doneButton setTitle:TGLocalized(@"Common.Done") forState:UIControlStateNormal];
_doneButton.titleLabel.font = TGSystemFontOfSize(17.0);
[_doneButton sizeToFit];
[_wrapperView addSubview:_doneButton];
void (^settingsPressed)(void) = ^
{
__strong TGPhotoPaintController *strongSelf = weakSelf;
if (strongSelf == nil)
return;
[strongSelf commitEyedropper:true];
if ([strongSelf->_currentEntityView isKindOfClass:[TGPhotoTextEntityView class]])
[strongSelf presentTextSettingsView];
else if ([strongSelf->_currentEntityView isKindOfClass:[TGPhotoStickerEntityView class]])
@ -321,11 +360,22 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
[strongSelf presentBrushSettingsView];
};
void (^eyedropperPressed)(void) = ^
{
__strong TGPhotoPaintController *strongSelf = weakSelf;
if (strongSelf == nil)
return;
[self enableEyedropper];
};
void (^beganColorPicking)(void) = ^
{
__strong TGPhotoPaintController *strongSelf = weakSelf;
if (strongSelf == nil)
return;
[strongSelf commitEyedropper:true];
if (![strongSelf->_currentEntityView isKindOfClass:[TGPhotoTextEntityView class]])
[strongSelf setDimHidden:false animated:true];
@ -346,6 +396,8 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
if (strongSelf == nil)
return;
[strongSelf commitEyedropper:true];
[strongSelf setCurrentSwatch:swatch sender:sender];
if (![strongSelf->_currentEntityView isKindOfClass:[TGPhotoTextEntityView class]])
@ -353,6 +405,7 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
};
_portraitSettingsView = [[TGPhotoPaintSettingsView alloc] initWithContext:_context];
_portraitSettingsView.eyedropperPressed = eyedropperPressed;
_portraitSettingsView.beganColorPicking = beganColorPicking;
_portraitSettingsView.changedColor = changedColor;
_portraitSettingsView.finishedColorPicking = finishedColorPicking;
@ -362,6 +415,7 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
[_portraitToolsWrapperView addSubview:_portraitSettingsView];
_landscapeSettingsView = [[TGPhotoPaintSettingsView alloc] initWithContext:_context];
_landscapeSettingsView.eyedropperPressed = eyedropperPressed;
_landscapeSettingsView.beganColorPicking = beganColorPicking;
_landscapeSettingsView.changedColor = changedColor;
_landscapeSettingsView.finishedColorPicking = finishedColorPicking;
@ -497,6 +551,8 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
- (void)handleTabAction:(TGPhotoEditorTab)tab
{
[self commitEyedropper:true];
switch (tab)
{
case TGPhotoEditorStickerTab:
@ -625,6 +681,49 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
#pragma mark - Data Handling
- (UIImage *)eyedropperImage
{
UIImage *backgroundImage = [self.photoEditor currentResultImage];
CGSize fittedSize = TGFitSize(_painting.size, TGPhotoEditorResultImageMaxSize);
UIImage *paintingImage = _painting.isEmpty ? nil : [_painting imageWithSize:fittedSize andData:NULL];
NSMutableArray *entities = [[NSMutableArray alloc] init];
UIImage *entitiesImage = nil;
if (paintingImage == nil && _entitiesContainerView.entitiesCount < 1)
{
return backgroundImage;
}
else if (_entitiesContainerView.entitiesCount > 0)
{
for (TGPhotoPaintEntityView *view in _entitiesContainerView.subviews)
{
if (![view isKindOfClass:[TGPhotoPaintEntityView class]])
continue;
TGPhotoPaintEntity *entity = [view entity];
if (entity != nil) {
[entities addObject:entity];
}
}
entitiesImage = [_entitiesContainerView imageInRect:_entitiesContainerView.bounds background:nil still:true];
}
if (entitiesImage == nil && paintingImage == nil) {
return backgroundImage;
} else {
UIGraphicsBeginImageContextWithOptions(fittedSize, false, 1.0);
[backgroundImage drawInRect:CGRectMake(0.0, 0.0, fittedSize.width, fittedSize.height)];
[paintingImage drawInRect:CGRectMake(0.0, 0.0, fittedSize.width, fittedSize.height)];
[entitiesImage drawInRect:CGRectMake(0.0, 0.0, fittedSize.width, fittedSize.height)];
UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return result;
}
}
- (TGPaintingData *)_prepareResultData
{
if (_resultData != nil)
@ -698,6 +797,60 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
return [self _prepareResultData];
}
- (void)enableEyedropper {
if (!_eyedropperView.isHidden)
return;
[self selectEntityView:nil];
self.controlVideoPlayback(false);
[_entitiesContainerView updateVisibility:false];
UIImage *image = [self eyedropperImage];
CGImageRef cgImage = image.CGImage;
CFDataRef pixelData = CGDataProviderCopyData(CGImageGetDataProvider(cgImage));
_eyedropperBackgroundData = (__bridge NSData *)pixelData;
_eyedropperBackgroundSize = image.size;
_eyedropperBackgroundBytesPerRow = CGImageGetBytesPerRow(cgImage);
_eyedropperBackgroundInfo = CGImageGetBitmapInfo(cgImage);
[_eyedropperView update];
[_eyedropperView present];
}
- (void)commitEyedropper:(bool)immediate {
self.controlVideoPlayback(true);
[_entitiesContainerView updateVisibility:true];
_eyedropperBackgroundData = nil;
_eyedropperBackgroundSize = CGSizeZero;
_eyedropperBackgroundBytesPerRow = 0;
_eyedropperBackgroundInfo = 0;
double timeout = immediate ? 0.0 : 0.2;
TGDispatchAfter(timeout, dispatch_get_main_queue(), ^{
[_eyedropperView dismiss];
});
}
- (UIColor *)colorFromData:(NSData *)data width:(NSInteger)width height:(NSInteger)height x:(NSInteger)x y:(NSInteger)y bpr:(NSInteger)bpr {
uint8_t *pixel = (uint8_t *)data.bytes + bpr * y + x * 4;
if (_eyedropperBackgroundInfo & kCGBitmapByteOrder32Little) {
return [UIColor colorWithRed:pixel[2] / 255.0 green:pixel[1] / 255.0 blue:pixel[0] / 255.0 alpha:1.0];
} else {
return [UIColor colorWithRed:pixel[0] / 255.0 green:pixel[1] / 255.0 blue:pixel[2] / 255.0 alpha:1.0];
}
}
- (UIColor *)colorAtPoint:(CGPoint)point
{
CGPoint convertedPoint = CGPointMake(point.x / _eyedropperView.bounds.size.width * _eyedropperBackgroundSize.width, point.y / _eyedropperView.bounds.size.height * _eyedropperBackgroundSize.height);
UIColor *backgroundColor = [self colorFromData:_eyedropperBackgroundData width:_eyedropperBackgroundSize.width height:_eyedropperBackgroundSize.height x:convertedPoint.x y:convertedPoint.y bpr:_eyedropperBackgroundBytesPerRow];
return backgroundColor;
}
#pragma mark - Entities
- (void)selectEntityView:(TGPhotoPaintEntityView *)view
@ -734,7 +887,7 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
if ([view isKindOfClass:[TGPhotoTextEntityView class]])
{
TGPaintSwatch *textSwatch = ((TGPhotoPaintTextEntity *)view.entity).swatch;
[self setCurrentSwatch:[TGPaintSwatch swatchWithColor:textSwatch.color colorLocation:textSwatch.colorLocaton brushWeight:_portraitSettingsView.swatch.brushWeight] sender:nil];
[self setCurrentSwatch:[TGPaintSwatch swatchWithColor:textSwatch.color colorLocation:textSwatch.colorLocation brushWeight:_portraitSettingsView.swatch.brushWeight] sender:nil];
}
_entitySelectionView = [view createSelectionView];
@ -1061,7 +1214,7 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
TGPaintSwatch *currentSwatch = _portraitSettingsView.swatch;
TGPaintSwatch *whiteSwatch = [TGPaintSwatch swatchWithColor:[UIColor whiteColor] colorLocation:1.0f brushWeight:currentSwatch.brushWeight];
TGPaintSwatch *blackSwatch = [TGPaintSwatch swatchWithColor:[UIColor blackColor] colorLocation:0.85f brushWeight:currentSwatch.brushWeight];
[self setCurrentSwatch:_selectedTextStyle == TGPhotoPaintTextEntityStyleBorder ? blackSwatch : whiteSwatch sender:nil];
[self setCurrentSwatch:_selectedTextStyle == TGPhotoPaintTextEntityStyleOutlined ? blackSwatch : whiteSwatch sender:nil];
CGFloat maxWidth = [self fittedContentSize].width - 26.0f;
TGPhotoPaintTextEntity *entity = [[TGPhotoPaintTextEntity alloc] initWithText:@"" font:_selectedTextFont swatch:_portraitSettingsView.swatch baseFontSize:[self _textBaseFontSizeForCurrentPainting] maxWidth:maxWidth style:_selectedTextStyle];
@ -1258,13 +1411,35 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
- (void)updateSettingsButton
{
if ([_currentEntityView isKindOfClass:[TGPhotoTextEntityView class]])
[self setSettingsButtonIcon:TGPhotoPaintSettingsViewIconText];
else if ([_currentEntityView isKindOfClass:[TGPhotoStickerEntityView class]])
if ([_currentEntityView isKindOfClass:[TGPhotoTextEntityView class]]) {
TGPhotoPaintSettingsViewIcon icon;
switch (((TGPhotoTextEntityView *)_currentEntityView).entity.style) {
case TGPhotoPaintTextEntityStyleRegular:
icon = TGPhotoPaintSettingsViewIconTextRegular;
break;
case TGPhotoPaintTextEntityStyleOutlined:
icon = TGPhotoPaintSettingsViewIconTextOutlined;
break;
case TGPhotoPaintTextEntityStyleFramed:
icon = TGPhotoPaintSettingsViewIconTextFramed;
break;
}
[self setSettingsButtonIcon:icon];
}
else if ([_currentEntityView isKindOfClass:[TGPhotoStickerEntityView class]]) {
[self setSettingsButtonIcon:TGPhotoPaintSettingsViewIconMirror];
else
[self setSettingsButtonIcon:TGPhotoPaintSettingsViewIconBrush];
}
else {
TGPhotoPaintSettingsViewIcon icon = TGPhotoPaintSettingsViewIconBrushPen;
if ([_canvasView.state.brush isKindOfClass:[TGPaintEllipticalBrush class]]) {
icon = TGPhotoPaintSettingsViewIconBrushMarker;
} else if ([_canvasView.state.brush isKindOfClass:[TGPaintNeonBrush class]]) {
icon = TGPhotoPaintSettingsViewIconBrushNeon;
} else if ([_canvasView.state.brush isKindOfClass:[TGPaintArrowBrush class]]) {
icon = TGPhotoPaintSettingsViewIconBrushArrow;
}
[self setSettingsButtonIcon:icon];
}
[self _updateTabs];
}
@ -1347,12 +1522,13 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
if (strongSelf == nil)
return;
if (strongSelf->_canvasView.state.eraser && brush.lightSaber)
if (strongSelf->_canvasView.state.eraser && (brush.lightSaber || brush.arrow))
brush = strongSelf->_brushes.firstObject;
[strongSelf->_canvasView setBrush:brush];
[strongSelf settingsWrapperPressed];
[strongSelf updateSettingsButton];
};
_settingsView = view;
[view sizeToFit];
@ -1383,6 +1559,7 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
[textView setFont:font];
[strongSelf settingsWrapperPressed];
[strongSelf updateSettingsButton];
};
view.styleChanged = ^(TGPhotoPaintTextEntityStyle style)
{
@ -1392,13 +1569,13 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
strongSelf->_selectedTextStyle = style;
if (style == TGPhotoPaintTextEntityStyleBorder && [strongSelf->_portraitSettingsView.swatch.color isEqual:[UIColor whiteColor]])
if (style == TGPhotoPaintTextEntityStyleOutlined && [strongSelf->_portraitSettingsView.swatch.color isEqual:[UIColor whiteColor]])
{
TGPaintSwatch *currentSwatch = strongSelf->_portraitSettingsView.swatch;
TGPaintSwatch *blackSwatch = [TGPaintSwatch swatchWithColor:[UIColor blackColor] colorLocation:0.85f brushWeight:currentSwatch.brushWeight];
[strongSelf setCurrentSwatch:blackSwatch sender:nil];
}
else if (style != TGPhotoPaintTextEntityStyleBorder && [strongSelf->_portraitSettingsView.swatch.color isEqual:UIColorRGB(0x000000)])
else if (style != TGPhotoPaintTextEntityStyleOutlined && [strongSelf->_portraitSettingsView.swatch.color isEqual:UIColorRGB(0x000000)])
{
TGPaintSwatch *currentSwatch = strongSelf->_portraitSettingsView.swatch;
TGPaintSwatch *whiteSwatch = [TGPaintSwatch swatchWithColor:[UIColor whiteColor] colorLocation:1.0f brushWeight:currentSwatch.brushWeight];
@ -1409,6 +1586,7 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
[textView setStyle:style];
[strongSelf settingsWrapperPressed];
[strongSelf updateSettingsButton];
};
_settingsView = view;
@ -1429,13 +1607,14 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
if (_canvasView.state.eraser)
{
if (_canvasView.state.brush.lightSaber)
if (_canvasView.state.brush.lightSaber || _canvasView.state.brush.arrow)
[_canvasView setBrush:_brushes.firstObject];
}
[_portraitSettingsView setHighlighted:_canvasView.state.isEraser];
[_landscapeSettingsView setHighlighted:_canvasView.state.isEraser];
[self updateSettingsButton];
[self _updateTabs];
}
@ -1934,17 +2113,22 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
[_dimView.superview insertSubview:_dimView belowSubview:_currentEntityView];
else
[_dimView.superview bringSubviewToFront:_dimView];
[_doneButton.superview bringSubviewToFront:_doneButton];
}
else
{
[_entitySelectionView fadeIn];
[_dimView.superview bringSubviewToFront:_dimView];
[_doneButton.superview bringSubviewToFront:_doneButton];
}
void (^changeBlock)(void) = ^
{
_dimView.alpha = hidden ? 0.0f : 1.0f;
_doneButton.alpha = hidden ? 0.0f : 1.0f;
};
if (animated)
@ -2016,6 +2200,8 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
_settingsViewWrapper.frame = self.parentViewController.view.bounds;
_doneButton.frame = CGRectMake(screenEdges.right - _doneButton.frame.size.width - 8.0, screenEdges.top + 2.0, _doneButton.frame.size.width, _doneButton.frame.size.height);
if (_settingsView != nil)
[_settingsView setInterfaceOrientation:orientation];
@ -2151,6 +2337,7 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
_selectionContainerView.transform = CGAffineTransformRotate(rotationTransform, rotation);
_selectionContainerView.frame = previewFrame;
_eyedropperView.frame = _selectionContainerView.bounds;
_containerView.frame = CGRectMake(containerFrame.origin.x, containerFrame.origin.y + offsetHeight, containerFrame.size.width, containerFrame.size.height);
}

View File

@ -221,3 +221,27 @@ const CGFloat TGPhotoPaintEntityMinScale = 0.12f;
}
@end
@implementation UIView (PixelColor)
- (UIColor *)colorAtPoint:(CGPoint)point
{
if (point.x > self.bounds.size.width || point.y > self.bounds.size.height)
return nil;
unsigned char pixel[4] = {0};
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(pixel, 1, 1, 8, 4, colorSpace, kCGBitmapAlphaInfoMask & kCGImageAlphaPremultipliedLast);
CGContextTranslateCTM(context, -point.x, -point.y);
[self.layer renderInContext:context];
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
return [UIColor colorWithRed:pixel[0] / 255.0 green:pixel[1] / 255.0 blue:pixel[2] / 255.0 alpha:pixel[3] / 255.0];
}
@end

View File

@ -0,0 +1,13 @@
#import <UIKit/UIKit.h>
@interface TGPhotoPaintEyedropperView : UIView
@property (nonatomic, strong) UIColor *color;
@property (nonatomic, copy) void(^locationChanged)(CGPoint, bool);
- (void)update;
- (void)present;
- (void)dismiss;
@end

View File

@ -0,0 +1,157 @@
#import "TGPhotoPaintEyedropperView.h"
#import "TGImageUtils.h"
@interface TGPhotoPaintEyedropperIndicatorView : UIView
@property (nonatomic, strong) UIColor *color;
@end
@implementation TGPhotoPaintEyedropperIndicatorView
-(instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self != nil) {
self.backgroundColor = [UIColor clearColor];
self.opaque = false;
self.userInteractionEnabled = false;
}
return self;
}
- (void)setColor:(UIColor *)color {
_color = color;
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGFloat lineWidth = 1.0f + TGScreenPixel;
CGContextSetFillColorWithColor(context, _color.CGColor);
CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextSaveGState(context);
CGContextScaleCTM(context, 0.333333, 0.333333);
CGContextSetLineWidth(context, lineWidth * 3.0);
TGDrawSvgPath(context, @"M75,0.5 C54.4273931,0.5 35.8023931,8.83869653 22.3205448,22.3205448 C8.83869653,35.8023931 0.5,54.4273931 0.5,75 C0.5,94.6543797 10.7671345,116.856807 23.8111444,136.192682 C42.4188317,163.77591 66.722394,185.676747 75,185.676747 C83.277606,185.676747 107.581168,163.77591 126.188856,136.192682 C139.232866,116.856807 149.5,94.6543797 149.5,75 C149.5,54.4273931 141.161303,35.8023931 127.679455,22.3205448 C114.197607,8.83869653 95.5726069,0.5 75,0.5 Z");
TGDrawSvgPath(context, @"M75,0.5 C54.4273931,0.5 35.8023931,8.83869653 22.3205448,22.3205448 C8.83869653,35.8023931 0.5,54.4273931 0.5,75 C0.5,94.6543797 10.7671345,116.856807 23.8111444,136.192682 C42.4188317,163.77591 66.722394,185.676747 75,185.676747 C83.277606,185.676747 107.581168,163.77591 126.188856,136.192682 C139.232866,116.856807 149.5,94.6543797 149.5,75 C149.5,54.4273931 141.161303,35.8023931 127.679455,22.3205448 C114.197607,8.83869653 95.5726069,0.5 75,0.5 S");
CGContextRestoreGState(context);
CGContextSetLineWidth(context, lineWidth);
CGContextFillEllipseInRect(context, CGRectMake(20.0, 68.0, 11.0, 11.0));
CGContextStrokeEllipseInRect(context, CGRectMake(20.0, 68.0, 11.0, 11.0));
}
@end
@interface TGPhotoPaintEyedropperView() <UIGestureRecognizerDelegate>
@end
@implementation TGPhotoPaintEyedropperView
{
TGPhotoPaintEyedropperIndicatorView *_indicatorView;
UITapGestureRecognizer *_tapGestureRecognizer;
UIPanGestureRecognizer *_panGestureRecognizer;
}
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self != nil) {
_indicatorView = [[TGPhotoPaintEyedropperIndicatorView alloc] initWithFrame:CGRectMake(0.0, 0.0, 51.0, 81.0)];
_indicatorView.layer.anchorPoint = CGPointMake(0.5, 0.92);
[self addSubview:_indicatorView];
_tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
[self addGestureRecognizer:_tapGestureRecognizer];
_panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
_panGestureRecognizer.delegate = self;
[self addGestureRecognizer:_panGestureRecognizer];
}
return self;
}
- (void)setColor:(UIColor *)color {
_color = color;
_indicatorView.color = color;
}
- (void)handleTap:(UITapGestureRecognizer *)gestureRecognizer {
CGPoint location = [gestureRecognizer locationInView:self];
[self layoutIndicator:location];
self.locationChanged(location, true);
}
- (void)handlePan:(UIPanGestureRecognizer *)gestureRecognizer {
CGPoint location = [gestureRecognizer locationInView:self];
switch (gestureRecognizer.state)
{
case UIGestureRecognizerStateChanged:
{
[self layoutIndicator:location];
self.locationChanged(location, false);
}
break;
case UIGestureRecognizerStateEnded:
{
[self layoutIndicator:location];
self.locationChanged(location, true);
}
break;
default:
break;
}
}
- (void)update {
CGPoint location = CGPointMake(self.bounds.size.width / 2.0, self.bounds.size.height / 2.0);
self.locationChanged(location, false);
[self layoutIndicator:location];
}
- (void)present {
self.hidden = false;
_indicatorView.alpha = 0.0f;
_indicatorView.transform = CGAffineTransformMakeScale(0.2, 0.2);
[UIView animateWithDuration:0.2 animations:^
{
_indicatorView.alpha = 1.0f;
_indicatorView.transform = CGAffineTransformIdentity;
} completion:^(__unused BOOL finished)
{
}];
}
- (void)dismiss {
if (self.hidden)
return;
[UIView animateWithDuration:0.15 animations:^
{
_indicatorView.alpha = 0.0f;
_indicatorView.transform = CGAffineTransformMakeScale(0.2, 0.2);
} completion:^(__unused BOOL finished)
{
self.hidden = true;
}];
}
- (void)layoutIndicator:(CGPoint)point {
_indicatorView.center = CGPointMake(point.x, point.y);
}
@end

View File

@ -6,8 +6,13 @@
typedef enum
{
TGPhotoPaintSettingsViewIconBrush,
TGPhotoPaintSettingsViewIconText,
TGPhotoPaintSettingsViewIconBrushPen,
TGPhotoPaintSettingsViewIconBrushMarker,
TGPhotoPaintSettingsViewIconBrushNeon,
TGPhotoPaintSettingsViewIconBrushArrow,
TGPhotoPaintSettingsViewIconTextRegular,
TGPhotoPaintSettingsViewIconTextOutlined,
TGPhotoPaintSettingsViewIconTextFramed,
TGPhotoPaintSettingsViewIconMirror
} TGPhotoPaintSettingsViewIcon;
@ -17,7 +22,9 @@ typedef enum
@property (nonatomic, copy) void (^changedColor)(TGPhotoPaintSettingsView *sender, TGPaintSwatch *swatch);
@property (nonatomic, copy) void (^finishedColorPicking)(TGPhotoPaintSettingsView *sender, TGPaintSwatch *swatch);
@property (nonatomic, copy) void (^eyedropperPressed)(void);
@property (nonatomic, copy) void (^settingsPressed)(void);
@property (nonatomic, readonly) UIButton *settingsButton;
@property (nonatomic, strong) TGPaintSwatch *swatch;

View File

@ -14,6 +14,7 @@ const CGFloat TGPhotoPaintSettingsPadPickerWidth = 360.0f;
@interface TGPhotoPaintSettingsView ()
{
TGPhotoPaintColorPicker *_colorPicker;
TGModernButton *_eyedropperButton;
TGModernButton *_settingsButton;
TGPhotoPaintSettingsViewIcon _icon;
@ -54,7 +55,13 @@ const CGFloat TGPhotoPaintSettingsPadPickerWidth = 360.0f;
};
[self addSubview:_colorPicker];
_icon = TGPhotoPaintSettingsViewIconBrush;
_icon = TGPhotoPaintSettingsViewIconBrushPen;
_eyedropperButton = [[TGModernButton alloc] initWithFrame:CGRectMake(0, 0, 44.0f, 44.0f)];
_eyedropperButton.exclusiveTouch = true;
[_eyedropperButton setImage:TGTintedImage([UIImage imageNamed:@"Editor/Eyedropper"], [UIColor whiteColor]) forState:UIControlStateNormal];
[_eyedropperButton addTarget:self action:@selector(eyedropperButtonPressed) forControlEvents:UIControlEventTouchUpInside];
// [self addSubview:_eyedropperButton];
_settingsButton = [[TGModernButton alloc] initWithFrame:CGRectMake(0, 0, 44.0f, 44.0f)];
_settingsButton.exclusiveTouch = true;
@ -85,6 +92,12 @@ const CGFloat TGPhotoPaintSettingsPadPickerWidth = 360.0f;
_colorPicker.orientation = interfaceOrientation;
}
- (void)eyedropperButtonPressed
{
if (self.eyedropperPressed != nil)
self.eyedropperPressed();
}
- (void)settingsButtonPressed
{
if (self.settingsPressed != nil)
@ -143,25 +156,35 @@ const CGFloat TGPhotoPaintSettingsPadPickerWidth = 360.0f;
- (UIImage *)_imageForIcon:(TGPhotoPaintSettingsViewIcon)icon highlighted:(bool)highlighted
{
UIColor *color = highlighted ? [TGPhotoEditorInterfaceAssets accentColor] : [UIColor whiteColor];
UIImage *iconImage = nil;
switch (icon)
{
case TGPhotoPaintSettingsViewIconBrush:
iconImage = TGTintedImage([UIImage imageNamed:@"Editor/Brush"], [UIColor whiteColor]);
case TGPhotoPaintSettingsViewIconBrushPen:
iconImage = TGTintedImage([UIImage imageNamed:@"Editor/BrushSelectedPen"], color);
break;
case TGPhotoPaintSettingsViewIconText:
iconImage = TGTintedImage([UIImage imageNamed:@"Editor/Font"], [UIColor whiteColor]);
case TGPhotoPaintSettingsViewIconBrushMarker:
iconImage = TGTintedImage([UIImage imageNamed:@"Editor/BrushSelectedMarker"], color);
break;
case TGPhotoPaintSettingsViewIconBrushNeon:
iconImage = TGTintedImage([UIImage imageNamed:@"Editor/BrushSelectedNeon"], color);
break;
case TGPhotoPaintSettingsViewIconBrushArrow:
iconImage = TGTintedImage([UIImage imageNamed:@"Editor/BrushSelectedArrow"], color);
break;
case TGPhotoPaintSettingsViewIconTextRegular:
iconImage = TGTintedImage([UIImage imageNamed:@"Editor/TextSelectedRegular"], color);
break;
case TGPhotoPaintSettingsViewIconTextOutlined:
iconImage = TGTintedImage([UIImage imageNamed:@"Editor/TextSelectedOutlined"], color);
break;
case TGPhotoPaintSettingsViewIconTextFramed:
iconImage = TGTintedImage([UIImage imageNamed:@"Editor/TextSelectedFramed"], color);
break;
case TGPhotoPaintSettingsViewIconMirror:
iconImage = TGTintedImage([UIImage imageNamed:@"Editor/Flip"], [UIColor whiteColor]);
iconImage = TGTintedImage([UIImage imageNamed:@"Editor/Flip"], color);
break;
}
if (highlighted)
iconImage = TGTintedImage(iconImage, [TGPhotoEditorInterfaceAssets accentColor]);
return iconImage;
}
@ -188,22 +211,27 @@ const CGFloat TGPhotoPaintSettingsPadPickerWidth = 360.0f;
- (void)layoutSubviews
{
CGFloat leftInset = 23.0f;
CGFloat rightInset = 66.0f;
CGFloat colorPickerHeight = 10.0f;
if (self.frame.size.width > self.frame.size.height)
{
if ([_context currentSizeClass] == UIUserInterfaceSizeClassRegular)
{
_colorPicker.frame = CGRectMake(ceil((self.frame.size.width - TGPhotoPaintSettingsPadPickerWidth) / 2.0f), ceil((self.frame.size.height - 18.0f) / 2.0f), TGPhotoPaintSettingsPadPickerWidth, 18.0f);
_colorPicker.frame = CGRectMake(ceil((self.frame.size.width - TGPhotoPaintSettingsPadPickerWidth) / 2.0f), ceil((self.frame.size.height - colorPickerHeight) / 2.0f), TGPhotoPaintSettingsPadPickerWidth, colorPickerHeight);
_settingsButton.frame = CGRectMake(CGRectGetMaxX(_colorPicker.frame) + 11.0f, floor((self.frame.size.height - _settingsButton.frame.size.height) / 2.0f) + 1.0f, _settingsButton.frame.size.width, _settingsButton.frame.size.height);
}
else
{
_colorPicker.frame = CGRectMake(23.0f, ceil((self.frame.size.height - 18.0f) / 2.0f), self.frame.size.width - 23.0f - 66.0f, 18.0f);
_colorPicker.frame = CGRectMake(leftInset, ceil((self.frame.size.height - colorPickerHeight) / 2.0f), self.frame.size.width - leftInset - rightInset, colorPickerHeight);
_eyedropperButton.frame = CGRectMake(10.0f, floor((self.frame.size.height - _eyedropperButton.frame.size.height) / 2.0f) + 1.0f, _eyedropperButton.frame.size.width, _eyedropperButton.frame.size.height);
_settingsButton.frame = CGRectMake(self.frame.size.width - _settingsButton.frame.size.width - 10.0f, floor((self.frame.size.height - _settingsButton.frame.size.height) / 2.0f) + 1.0f, _settingsButton.frame.size.width, _settingsButton.frame.size.height);
}
}
else
{
_colorPicker.frame = CGRectMake(ceil((self.frame.size.width - 18.0f) / 2.0f), 66.0f, 18.0f, self.frame.size.height - 23.0f - 66.0f);
_colorPicker.frame = CGRectMake(ceil((self.frame.size.width - colorPickerHeight) / 2.0f), rightInset, colorPickerHeight, self.frame.size.height - leftInset - rightInset);
_eyedropperButton.frame = CGRectMake(floor((self.frame.size.width - _eyedropperButton.frame.size.width) / 2.0f), self.frame.size.height - _eyedropperButton.frame.size.height - 10.0, _eyedropperButton.frame.size.width, _eyedropperButton.frame.size.height);
_settingsButton.frame = CGRectMake(floor((self.frame.size.width - _settingsButton.frame.size.width) / 2.0f), 10.0f, _settingsButton.frame.size.width, _settingsButton.frame.size.height);
}
}

View File

@ -128,8 +128,8 @@ const NSTimeInterval TGPhotoQualityPreviewDuration = 15.0f;
CGSize dimensions = CGSizeZero;
if ([self.item isKindOfClass:[TGMediaAsset class]])
dimensions = ((TGMediaAsset *)self.item).dimensions;
else if ([self.item isKindOfClass:[TGCameraCapturedVideo class]])
dimensions = [((TGCameraCapturedVideo *)self.item).avAsset tracksWithMediaType:AVMediaTypeVideo].firstObject.naturalSize;
// else if ([self.item isKindOfClass:[TGCameraCapturedVideo class]])
// dimensions = [((TGCameraCapturedVideo *)self.item).avAsset tracksWithMediaType:AVMediaTypeVideo].firstObject.naturalSize;
if (!CGSizeEqualToSize(dimensions, CGSizeZero))
_quality.maximumValue = [TGMediaVideoConverter bestAvailablePresetForDimensions:dimensions] - 1;
@ -641,7 +641,7 @@ const NSTimeInterval TGPhotoQualityPreviewDuration = 15.0f;
[self updateInfo];
SSignal *assetSignal = [self.item isKindOfClass:[TGMediaAsset class]] ? [TGMediaAssetImageSignals avAssetForVideoAsset:(TGMediaAsset *)self.item] : [SSignal single:((TGCameraCapturedVideo *)self.item).avAsset];
SSignal *assetSignal = [self.item isKindOfClass:[TGMediaAsset class]] ? [TGMediaAssetImageSignals avAssetForVideoAsset:(TGMediaAsset *)self.item] : ((TGCameraCapturedVideo *)self.item).avAsset;
if ([self.item isKindOfClass:[TGMediaAsset class]])
[self _updateVideoDuration:((TGMediaAsset *)self.item).videoDuration hasAudio:true];

View File

@ -120,7 +120,11 @@ const CGFloat TGPhotoStickerSelectionViewHandleSide = 30.0f;
- (bool)precisePointInside:(CGPoint)point
{
return [_stickerView pointInside:[_stickerView convertPoint:point fromView:self] withEvent:nil];
CGPoint imagePoint = [_stickerView convertPoint:point fromView:self];
if (![_stickerView pointInside:[_stickerView convertPoint:point fromView:self] withEvent:nil])
return false;
return [_stickerView isOpaqueAtPoint:imagePoint];
}
- (void)mirror

View File

@ -184,7 +184,7 @@ const CGFloat TGPhotoTextSelectionViewHandleSide = 30.0f;
{
_style = style;
switch (_style) {
case TGPhotoPaintTextEntityStyleClassic:
case TGPhotoPaintTextEntityStyleRegular:
_textView.layer.shadowColor = [[UIColor blackColor] CGColor];
_textView.layer.shadowOffset = CGSizeMake(0.0f, 4.0f);
_textView.layer.shadowOpacity = 0.4f;
@ -206,7 +206,7 @@ const CGFloat TGPhotoTextSelectionViewHandleSide = 30.0f;
- (void)updateColor
{
switch (_style) {
case TGPhotoPaintTextEntityStyleClassic:
case TGPhotoPaintTextEntityStyleRegular:
{
_textView.textColor = _swatch.color;
_textView.strokeColor = nil;
@ -214,7 +214,7 @@ const CGFloat TGPhotoTextSelectionViewHandleSide = 30.0f;
}
break;
case TGPhotoPaintTextEntityStyleBorder:
case TGPhotoPaintTextEntityStyleOutlined:
{
_textView.textColor = [UIColor whiteColor];
_textView.strokeColor = _swatch.color;
@ -222,7 +222,7 @@ const CGFloat TGPhotoTextSelectionViewHandleSide = 30.0f;
}
break;
case TGPhotoPaintTextEntityStyleFrame:
case TGPhotoPaintTextEntityStyleFramed:
{
CGFloat lightness = 0.0f;
CGFloat r = 0.0f;
@ -646,8 +646,6 @@ const CGFloat TGPhotoTextSelectionViewHandleSide = 30.0f;
if (i == 0) {
last = cur;
} else if (i > 0 && fabs(CGRectGetMaxY(last) - CGRectGetMinY(cur)) < 10.0) {
NSValue *lastValue = [self.rectArray objectAtIndex:i-1];
last = lastValue.CGRectValue;
CGPoint a = cur.origin;
CGPoint b = CGPointMake(CGRectGetMaxX(cur), cur.origin.y);
CGPoint c = CGPointMake(last.origin.x, CGRectGetMaxY(last));
@ -690,6 +688,8 @@ const CGFloat TGPhotoTextSelectionViewHandleSide = 30.0f;
[addPath addLineToPoint:CGPointMake(d.x + _radius, d.y)];
[self.path appendPath:addPath];
}
last = cur;
}
}
[self.path fill];

View File

@ -8,9 +8,6 @@
@property (nonatomic, copy) void (^fontChanged)(TGPhotoPaintFont *font);
@property (nonatomic, copy) void (^styleChanged)(TGPhotoPaintTextEntityStyle style);
@property (nonatomic, strong) TGPhotoPaintFont *font;
@property (nonatomic, assign) TGPhotoPaintTextEntityStyle style;
- (instancetype)initWithFonts:(NSArray *)fonts selectedFont:(TGPhotoPaintFont *)font selectedStyle:(TGPhotoPaintTextEntityStyle)selectedStyle;
@end

View File

@ -8,7 +8,7 @@
#import <LegacyComponents/TGModernButton.h>
#import "TGPhotoTextEntityView.h"
const CGFloat TGPhotoTextSettingsViewMargin = 19.0f;
const CGFloat TGPhotoTextSettingsViewMargin = 10.0f;
const CGFloat TGPhotoTextSettingsItemHeight = 44.0f;
@interface TGPhotoTextSettingsView ()
@ -17,11 +17,13 @@ const CGFloat TGPhotoTextSettingsItemHeight = 44.0f;
UIInterfaceOrientation _interfaceOrientation;
UIImageView *_backgroundView;
UIView *_wrapperView;
UIView *_contentView;
UIVisualEffectView *_effectView;
NSArray *_fontViews;
NSArray *_fontIconViews;
NSArray *_fontSeparatorViews;
UIImageView *_selectedCheckView;
}
@end
@ -38,95 +40,91 @@ const CGFloat TGPhotoTextSettingsItemHeight = 44.0f;
_interfaceOrientation = UIInterfaceOrientationPortrait;
_backgroundView = [[UIImageView alloc] init];
_backgroundView.alpha = 0.98f;
[self addSubview:_backgroundView];
_wrapperView = [[UIView alloc] init];
_wrapperView.clipsToBounds = true;
_wrapperView.layer.cornerRadius = 12.0;
[self addSubview:_wrapperView];
_effectView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]];
_effectView.alpha = 0.0f;
_effectView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[_wrapperView addSubview:_effectView];
_contentView = [[UIView alloc] init];
_contentView.alpha = 0.0f;
_contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[_wrapperView addSubview:_contentView];
NSMutableArray *fontViews = [[NSMutableArray alloc] init];
NSMutableArray *fontIconViews = [[NSMutableArray alloc] init];
NSMutableArray *separatorViews = [[NSMutableArray alloc] init];
UIFont *font = [UIFont boldSystemFontOfSize:18];
UIFont *font = [UIFont systemFontOfSize:17];
TGModernButton *outlineButton = [[TGModernButton alloc] initWithFrame:CGRectMake(0, TGPhotoTextSettingsViewMargin, 0, 0)];
outlineButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
outlineButton.titleLabel.font = font;
outlineButton.contentEdgeInsets = UIEdgeInsetsMake(0.0f, 44.0f, 0.0f, 0.0f);
outlineButton.tag = TGPhotoPaintTextEntityStyleBorder;
[outlineButton setTitle:@"" forState:UIControlStateNormal];
[outlineButton setTitleColor:[UIColor clearColor]];
[outlineButton addTarget:self action:@selector(styleValueChanged:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:outlineButton];
[fontViews addObject:outlineButton];
TGPhotoTextView *textView = [[TGPhotoTextView alloc] init];
textView.backgroundColor = [UIColor clearColor];
textView.textColor = [UIColor whiteColor];
textView.strokeWidth = 3.0f;
textView.strokeColor = [UIColor blackColor];
textView.strokeOffset = CGPointMake(0.0f, 0.5f);
textView.font = font;
textView.text = TGLocalized(@"Paint.Outlined");
[textView sizeToFit];
textView.frame = CGRectMake(39.0f, ceil((TGPhotoTextSettingsItemHeight - textView.frame.size.height) / 2.0f) - 1.0f, ceil(textView.frame.size.width), ceil(textView.frame.size.height + 0.5f));
[outlineButton addSubview:textView];
UIView *separatorView = [[UIView alloc] init];
separatorView.backgroundColor = UIColorRGB(0xd6d6da);
[self addSubview:separatorView];
[separatorViews addObject:separatorView];
TGModernButton *regularButton = [[TGModernButton alloc] initWithFrame:CGRectMake(0, TGPhotoTextSettingsViewMargin + TGPhotoTextSettingsItemHeight, 0, 0)];
regularButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
regularButton.titleLabel.font = font;
regularButton.contentEdgeInsets = UIEdgeInsetsMake(0.0f, 44.0f, 0.0f, 0.0f);
regularButton.tag = TGPhotoPaintTextEntityStyleClassic;
[regularButton setTitle:TGLocalized(@"Paint.Regular") forState:UIControlStateNormal];
[regularButton setTitleColor:[UIColor blackColor]];
[regularButton addTarget:self action:@selector(styleValueChanged:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:regularButton];
[fontViews addObject:regularButton];
separatorView = [[UIView alloc] init];
separatorView.backgroundColor = UIColorRGB(0xd6d6da);
[self addSubview:separatorView];
[separatorViews addObject:separatorView];
TGModernButton *frameButton = [[TGModernButton alloc] initWithFrame:CGRectMake(0, TGPhotoTextSettingsViewMargin + TGPhotoTextSettingsItemHeight + TGPhotoTextSettingsItemHeight, 0, 0)];
TGModernButton *frameButton = [[TGModernButton alloc] initWithFrame:CGRectZero];
frameButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
frameButton.titleLabel.font = font;
frameButton.contentEdgeInsets = UIEdgeInsetsMake(0.0f, 44.0f, 0.0f, 0.0f);
frameButton.tag = TGPhotoPaintTextEntityStyleFrame;
[frameButton setTitle:@"" forState:UIControlStateNormal];
[frameButton setTitleColor:[UIColor blackColor]];
frameButton.contentEdgeInsets = UIEdgeInsetsMake(0.0f, 16.0f, 0.0f, 0.0f);
frameButton.tag = TGPhotoPaintTextEntityStyleFramed;
[frameButton setTitle:TGLocalized(@"Paint.Framed") forState:UIControlStateNormal];
[frameButton setTitleColor:[UIColor whiteColor]];
[frameButton addTarget:self action:@selector(styleValueChanged:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:frameButton];
[_contentView addSubview:frameButton];
[fontViews addObject:frameButton];
textView = [[TGPhotoTextView alloc] init];
textView.backgroundColor = [UIColor clearColor];
textView.textColor = [UIColor whiteColor];
textView.frameColor = [UIColor blackColor];
textView.font = font;
textView.text = TGLocalized(@"Paint.Framed");
[textView sizeToFit];
textView.frame = CGRectMake(39.0f, ceil((TGPhotoTextSettingsItemHeight - textView.frame.size.height) / 2.0f) - 1.0f, ceil(textView.frame.size.width), ceil(textView.frame.size.height + 0.5f));
[frameButton addSubview:textView];
UIImageView *iconView = [[UIImageView alloc] initWithImage:TGTintedImage([UIImage imageNamed:@"Editor/TextFramed"], [UIColor whiteColor])];
[frameButton addSubview:iconView];
[fontIconViews addObject:iconView];
TGModernButton *outlineButton = [[TGModernButton alloc] initWithFrame:CGRectZero];
outlineButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
outlineButton.titleLabel.font = font;
outlineButton.contentEdgeInsets = UIEdgeInsetsMake(0.0f, 16.0f, 0.0f, 0.0f);
outlineButton.tag = TGPhotoPaintTextEntityStyleOutlined;
[outlineButton setTitle:TGLocalized(@"Paint.Outlined") forState:UIControlStateNormal];
[outlineButton setTitleColor:[UIColor whiteColor]];
[outlineButton addTarget:self action:@selector(styleValueChanged:) forControlEvents:UIControlEventTouchUpInside];
[_contentView addSubview:outlineButton];
[fontViews addObject:outlineButton];
iconView = [[UIImageView alloc] initWithImage:TGTintedImage([UIImage imageNamed:@"Editor/TextOutlined"], [UIColor whiteColor])];
[outlineButton addSubview:iconView];
[fontIconViews addObject:iconView];
UIView *separatorView = [[UIView alloc] init];
separatorView.backgroundColor = UIColorRGBA(0xffffff, 0.2);
[_contentView addSubview:separatorView];
[separatorViews addObject:separatorView];
TGModernButton *regularButton = [[TGModernButton alloc] initWithFrame:CGRectZero];
regularButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
regularButton.titleLabel.font = font;
regularButton.contentEdgeInsets = UIEdgeInsetsMake(0.0f, 16.0f, 0.0f, 0.0f);
regularButton.tag = TGPhotoPaintTextEntityStyleRegular;
[regularButton setTitle:TGLocalized(@"Paint.Regular") forState:UIControlStateNormal];
[regularButton setTitleColor:[UIColor whiteColor]];
[regularButton addTarget:self action:@selector(styleValueChanged:) forControlEvents:UIControlEventTouchUpInside];
[_contentView addSubview:regularButton];
[fontViews addObject:regularButton];
iconView = [[UIImageView alloc] initWithImage:TGTintedImage([UIImage imageNamed:@"Editor/TextRegular"], [UIColor whiteColor])];
[regularButton addSubview:iconView];
[fontIconViews addObject:iconView];
separatorView = [[UIView alloc] init];
separatorView.backgroundColor = UIColorRGBA(0xffffff, 0.2);
[_contentView addSubview:separatorView];
[separatorViews addObject:separatorView];
_fontViews = fontViews;
_fontIconViews = fontIconViews;
_fontSeparatorViews = separatorViews;
_selectedCheckView = [[UIImageView alloc] initWithImage:TGComponentsImageNamed(@"PaintCheck")];
_selectedCheckView.frame = CGRectMake(15.0f, 16.0f, _selectedCheckView.frame.size.width, _selectedCheckView.frame.size.height);
[self setStyle:selectedStyle];
}
return self;
}
- (void)fontButtonPressed:(TGModernButton *)sender
{
[sender addSubview:_selectedCheckView];
if (self.fontChanged != nil)
self.fontChanged(_fonts[sender.tag]);
}
@ -139,28 +137,22 @@ const CGFloat TGPhotoTextSettingsItemHeight = 44.0f;
- (void)present
{
self.alpha = 0.0f;
self.layer.rasterizationScale = TGScreenScaling();
self.layer.shouldRasterize = true;
[UIView animateWithDuration:0.2 animations:^
[UIView animateWithDuration:0.25 animations:^
{
self.alpha = 1.0f;
_effectView.alpha = 1.0f;
_contentView.alpha = 1.0f;
} completion:^(__unused BOOL finished)
{
self.layer.shouldRasterize = false;
}];
}
- (void)dismissWithCompletion:(void (^)(void))completion
{
self.layer.rasterizationScale = TGScreenScaling();
self.layer.shouldRasterize = true;
[UIView animateWithDuration:0.15 animations:^
[UIView animateWithDuration:0.2 animations:^
{
self.alpha = 0.0f;
_effectView.alpha = 0.0f;
_contentView.alpha = 0.0f;
} completion:^(__unused BOOL finished)
{
if (completion != nil)
@ -168,81 +160,38 @@ const CGFloat TGPhotoTextSettingsItemHeight = 44.0f;
}];
}
- (TGPhotoPaintTextEntityStyle)style
{
return (TGPhotoPaintTextEntityStyle)_selectedCheckView.superview.tag;
}
- (void)setStyle:(TGPhotoPaintTextEntityStyle)style
{
[_fontViews[style] addSubview:_selectedCheckView];
}
- (NSString *)font
{
return _fonts[_selectedCheckView.superview.tag];
}
- (void)setFont:(TGPhotoPaintFont *)__unused font
{
}
- (CGSize)sizeThatFits:(CGSize)__unused size
{
return CGSizeMake(256, _fontViews.count * TGPhotoTextSettingsItemHeight + TGPhotoTextSettingsViewMargin * 2);
return CGSizeMake(220, _fontViews.count * TGPhotoTextSettingsItemHeight + TGPhotoTextSettingsViewMargin * 2);
}
- (void)setInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
_interfaceOrientation = interfaceOrientation;
switch (self.interfaceOrientation)
{
case UIInterfaceOrientationLandscapeLeft:
{
_backgroundView.image = [TGPhotoPaintSettingsView landscapeLeftBackgroundImage];
}
break;
case UIInterfaceOrientationLandscapeRight:
{
_backgroundView.image = [TGPhotoPaintSettingsView landscapeRightBackgroundImage];
}
break;
default:
{
_backgroundView.image = [TGPhotoPaintSettingsView portraitBackgroundImage];
}
break;
}
[self setNeedsLayout];
}
- (void)layoutSubviews
{
CGFloat arrowSize = 0.0f;
switch (self.interfaceOrientation)
{
case UIInterfaceOrientationLandscapeLeft:
{
_backgroundView.image = [TGTintedImage(TGComponentsImageNamed(@"PaintPopupLandscapeLeftBackground"), UIColorRGB(0xf7f7f7)) resizableImageWithCapInsets:UIEdgeInsetsMake(32.0f, 32.0f, 32.0f, 32.0f)];
_backgroundView.frame = CGRectMake(TGPhotoTextSettingsViewMargin - 13.0f, TGPhotoTextSettingsViewMargin, self.frame.size.width - TGPhotoTextSettingsViewMargin * 2 + 13.0f, self.frame.size.height - TGPhotoTextSettingsViewMargin * 2);
_wrapperView.frame = CGRectMake(TGPhotoTextSettingsViewMargin - arrowSize, TGPhotoTextSettingsViewMargin, self.frame.size.width - TGPhotoTextSettingsViewMargin * 2 + arrowSize, self.frame.size.height - TGPhotoTextSettingsViewMargin * 2);
}
break;
case UIInterfaceOrientationLandscapeRight:
{
_backgroundView.image = [TGTintedImage(TGComponentsImageNamed(@"PaintPopupLandscapeRightBackground"), UIColorRGB(0xf7f7f7)) resizableImageWithCapInsets:UIEdgeInsetsMake(32.0f, 32.0f, 32.0f, 32.0f)];
_backgroundView.frame = CGRectMake(TGPhotoTextSettingsViewMargin, TGPhotoTextSettingsViewMargin, self.frame.size.width - TGPhotoTextSettingsViewMargin * 2 + 13.0f, self.frame.size.height - TGPhotoTextSettingsViewMargin * 2);
_wrapperView.frame = CGRectMake(TGPhotoTextSettingsViewMargin, TGPhotoTextSettingsViewMargin, self.frame.size.width - TGPhotoTextSettingsViewMargin * 2 + arrowSize, self.frame.size.height - TGPhotoTextSettingsViewMargin * 2);
}
break;
default:
{
_backgroundView.image = [TGTintedImage(TGComponentsImageNamed(@"PaintPopupPortraitBackground"), UIColorRGB(0xf7f7f7)) resizableImageWithCapInsets:UIEdgeInsetsMake(32.0f, 32.0f, 32.0f, 32.0f)];
_backgroundView.frame = CGRectMake(TGPhotoTextSettingsViewMargin, TGPhotoTextSettingsViewMargin, self.frame.size.width - TGPhotoTextSettingsViewMargin * 2, self.frame.size.height - TGPhotoTextSettingsViewMargin * 2 + 13.0f);
_wrapperView.frame = CGRectMake(TGPhotoTextSettingsViewMargin, TGPhotoTextSettingsViewMargin, self.frame.size.width - TGPhotoTextSettingsViewMargin * 2, self.frame.size.height - TGPhotoTextSettingsViewMargin * 2 + arrowSize);
}
break;
}
@ -251,13 +200,17 @@ const CGFloat TGPhotoTextSettingsItemHeight = 44.0f;
[_fontViews enumerateObjectsUsingBlock:^(TGModernButton *view, NSUInteger index, __unused BOOL *stop)
{
view.frame = CGRectMake(TGPhotoTextSettingsViewMargin, TGPhotoTextSettingsViewMargin + TGPhotoTextSettingsItemHeight * index, self.frame.size.width - TGPhotoTextSettingsViewMargin * 2, TGPhotoTextSettingsItemHeight);
view.frame = CGRectMake(0.0, TGPhotoTextSettingsItemHeight * index, _contentView.frame.size.width, TGPhotoTextSettingsItemHeight);
}];
[_fontIconViews enumerateObjectsUsingBlock:^(UIImageView *view, NSUInteger index, __unused BOOL *stop)
{
view.frame = CGRectMake(_contentView.frame.size.width - 42.0f, (TGPhotoTextSettingsItemHeight - view.frame.size.height) / 2.0, view.frame.size.width, view.frame.size.height);
}];
[_fontSeparatorViews enumerateObjectsUsingBlock:^(UIView *view, NSUInteger index, __unused BOOL *stop)
{
view.frame = CGRectMake(TGPhotoTextSettingsViewMargin + 44.0f, TGPhotoTextSettingsViewMargin + TGPhotoTextSettingsItemHeight * (index + 1), self.frame.size.width - TGPhotoTextSettingsViewMargin * 2 - 44.0f, thickness);
view.frame = CGRectMake(0.0, TGPhotoTextSettingsItemHeight * (index + 1), _contentView.frame.size.width, thickness);
}];
}

View File

@ -32,6 +32,7 @@
TGMediaPickerGalleryModel *model = [[TGMediaPickerGalleryModel alloc] initWithContext:windowContext items:@[galleryItem] focusItem:galleryItem selectionContext:nil editingContext:editingContext hasCaptions:true allowCaptionEntities:true hasTimer:false onlyCrop:false inhibitDocumentCaptions:false hasSelectionPanel:false hasCamera:false recipientName:recipientName];
model.controller = galleryController;
model.stickersContext = stickersContext;
//model.suggestionContext = self.suggestionContext;
model.willFinishEditingItem = ^(id<TGMediaEditableItem> editableItem, id<TGMediaEditAdjustments> adjustments, id representation, bool hasChanges)

View File

@ -91,7 +91,7 @@ const NSTimeInterval TGVideoEditMaximumGifDuration = 30.5;
} else if ([dict[@"type"] isEqualToString:@"text"]) {
UIImage *renderImage = [[UIImage alloc] initWithData:dict[@"data"]];
if (renderImage != nil) {
TGPhotoPaintTextEntity *entity = [[TGPhotoPaintTextEntity alloc] initWithText:nil font:nil swatch:nil baseFontSize:0.0 maxWidth:0.0 style:TGPhotoPaintTextEntityStyleClassic];
TGPhotoPaintTextEntity *entity = [[TGPhotoPaintTextEntity alloc] initWithText:nil font:nil swatch:nil baseFontSize:0.0 maxWidth:0.0 style:TGPhotoPaintTextEntityStyleRegular];
entity.uuid = [dict[@"uuid"] integerValue];
entity.position = [dict[@"position"] CGPointValue];
entity.scale = [dict[@"scale"] floatValue];

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "tenor@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "tenor@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -108,6 +108,18 @@ private func selectionChangedSignal(selectionState: TGMediaSelectionContext) ->
}
}
public struct WebSearchConfiguration: Equatable {
public let gifProvider: String?
public init(appConfiguration: AppConfiguration) {
var gifProvider: String? = nil
if let data = appConfiguration.data, let value = data["gif_search_branding"] as? String {
gifProvider = value
}
self.gifProvider = gifProvider
}
}
public final class WebSearchController: ViewController {
private var validLayout: ContainerViewLayout?
@ -169,9 +181,19 @@ public final class WebSearchController: ViewController {
return WebSearchSettings.defaultSettings
}
}
let gifProvider = self.context.account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration])
|> map { view -> String? in
guard let appConfiguration = view.values[PreferencesKeys.appConfiguration] as? AppConfiguration else {
return nil
}
let configuration = WebSearchConfiguration(appConfiguration: appConfiguration)
return configuration.gifProvider
}
|> distinctUntilChanged
self.disposable = ((combineLatest(settings, context.sharedContext.presentationData))
|> deliverOnMainQueue).start(next: { [weak self] settings, presentationData in
self.disposable = ((combineLatest(settings, context.sharedContext.presentationData, gifProvider))
|> deliverOnMainQueue).start(next: { [weak self] settings, presentationData, gifProvider in
guard let strongSelf = self else {
return
}
@ -183,6 +205,9 @@ public final class WebSearchController: ViewController {
if current.presentationData !== presentationData {
updated = updated.withUpdatedPresentationData(presentationData)
}
if current.gifProvider != gifProvider {
updated = updated.withUpdatedGifProvider(gifProvider)
}
return updated
}
})
@ -314,13 +339,14 @@ public final class WebSearchController: ViewController {
let previousInterfaceState = self.interfaceState
let previousTheme = self.interfaceState.presentationData.theme
let previousStrings = self.interfaceState.presentationData.theme
let previousGifProvider = self.interfaceState.gifProvider
let updatedInterfaceState = f(self.interfaceState)
self.interfaceState = updatedInterfaceState
self.interfaceStatePromise.set(updatedInterfaceState)
if self.isNodeLoaded {
if previousTheme !== updatedInterfaceState.presentationData.theme || previousStrings !== updatedInterfaceState.presentationData.strings {
if previousTheme !== updatedInterfaceState.presentationData.theme || previousStrings !== updatedInterfaceState.presentationData.strings || previousGifProvider != updatedInterfaceState.gifProvider {
self.controllerNode.updatePresentationData(theme: updatedInterfaceState.presentationData.theme, strings: updatedInterfaceState.presentationData.strings)
}
if previousInterfaceState != self.interfaceState {

View File

@ -348,8 +348,26 @@ class WebSearchControllerNode: ASDisplayNode {
self.segmentedControlNode.updateTheme(SegmentedControlTheme(theme: self.theme))
self.toolbarBackgroundNode.backgroundColor = self.theme.rootController.navigationBar.backgroundColor
self.toolbarSeparatorNode.backgroundColor = self.theme.rootController.navigationBar.separatorColor
self.attributionNode.image = generateTintedImage(image: UIImage(bundleImageName: "Media Grid/Giphy"), color: self.theme.list.itemSecondaryTextColor)
}
let gifProviderImage: UIImage?
if let gifProvider = self.webSearchInterfaceState.gifProvider {
switch gifProvider {
case "tenor":
gifProviderImage = generateTintedImage(image: UIImage(bundleImageName: "Media Grid/Tenor"), color: self.theme.list.itemSecondaryTextColor)
case "giphy":
gifProviderImage = generateTintedImage(image: UIImage(bundleImageName: "Media Grid/Giphy"), color: self.theme.list.itemSecondaryTextColor)
default:
gifProviderImage = nil
}
} else {
gifProviderImage = nil
}
let previousGifProviderImage = self.attributionNode.image
self.attributionNode.image = gifProviderImage
if previousGifProviderImage == nil, let validLayout = self.containerLayout {
self.containerLayoutUpdated(validLayout.0, navigationBarHeight: validLayout.1, transition: .immediate)
}
}
@ -386,7 +404,7 @@ class WebSearchControllerNode: ASDisplayNode {
transition.updateFrame(node: self.toolbarSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: toolbarY), size: CGSize(width: layout.size.width, height: UIScreenPixel)))
if let image = self.attributionNode.image {
transition.updateFrame(node: self.attributionNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - image.size.width) / 2.0), y: toolbarY + floor((toolbarHeight - image.size.height) / 2.0)), size: image.size))
self.attributionNode.frame = CGRect(origin: CGPoint(x: floor((layout.size.width - image.size.width) / 2.0), y: toolbarY + floor((toolbarHeight - image.size.height) / 2.0)), size: image.size)
transition.updateAlpha(node: self.attributionNode, alpha: self.webSearchInterfaceState.state?.scope == .gifs ? 1.0 : 0.0)
}
@ -456,6 +474,7 @@ class WebSearchControllerNode: ASDisplayNode {
}
func updateInterfaceState(_ interfaceState: WebSearchInterfaceState, animated: Bool) {
let previousGifProvider = self.webSearchInterfaceState.gifProvider
self.webSearchInterfaceState = interfaceState
self.webSearchInterfaceStatePromise.set(self.webSearchInterfaceState)
@ -463,6 +482,10 @@ class WebSearchControllerNode: ASDisplayNode {
self.segmentedControlNode.selectedIndex = Int(state.scope.rawValue)
}
if previousGifProvider != interfaceState.gifProvider {
self.applyPresentationData(themeUpdated: false)
}
if let validLayout = self.containerLayout {
self.containerLayoutUpdated(validLayout.0, navigationBarHeight: validLayout.1, transition: animated ? .animated(duration: 0.4, curve: .spring) : .immediate)
}

View File

@ -11,26 +11,33 @@ struct WebSearchInterfaceInnerState: Equatable {
struct WebSearchInterfaceState: Equatable {
let state: WebSearchInterfaceInnerState?
let presentationData: PresentationData
let gifProvider: String?
init (presentationData: PresentationData) {
self.state = nil
self.presentationData = presentationData
self.gifProvider = nil
}
init(state: WebSearchInterfaceInnerState?, presentationData: PresentationData) {
init(state: WebSearchInterfaceInnerState?, presentationData: PresentationData, gifProvider: String? = nil) {
self.state = state
self.presentationData = presentationData
self.gifProvider = gifProvider
}
func withUpdatedScope(_ scope: WebSearchScope) -> WebSearchInterfaceState {
return WebSearchInterfaceState(state: WebSearchInterfaceInnerState(scope: scope, query: self.state?.query ?? ""), presentationData: self.presentationData)
return WebSearchInterfaceState(state: WebSearchInterfaceInnerState(scope: scope, query: self.state?.query ?? ""), presentationData: self.presentationData, gifProvider: self.gifProvider)
}
func withUpdatedQuery(_ query: String) -> WebSearchInterfaceState {
return WebSearchInterfaceState(state: WebSearchInterfaceInnerState(scope: self.state?.scope ?? .images, query: query), presentationData: self.presentationData)
return WebSearchInterfaceState(state: WebSearchInterfaceInnerState(scope: self.state?.scope ?? .images, query: query), presentationData: self.presentationData, gifProvider: self.gifProvider)
}
func withUpdatedPresentationData(_ presentationData: PresentationData) -> WebSearchInterfaceState {
return WebSearchInterfaceState(state: self.state, presentationData: presentationData)
return WebSearchInterfaceState(state: self.state, presentationData: presentationData, gifProvider: self.gifProvider)
}
func withUpdatedGifProvider(_ gifProvider: String?) -> WebSearchInterfaceState {
return WebSearchInterfaceState(state: self.state, presentationData: self.presentationData, gifProvider: gifProvider)
}
}