Swiftgram/submodules/LegacyComponents/Sources/TGVideoMessageRingView.m
2021-08-05 00:02:35 +02:00

215 lines
6.7 KiB
Objective-C

#import "TGVideoMessageRingView.h"
#import "TGColor.h"
#import "LegacyComponentsInternal.h"
@interface TGVideoMessageShimmerEffectForegroundView : UIView
{
UIView *_imageContainerView;
UIView *_imageView;
CGFloat _size;
bool _hasContainerSize;
CGRect _absoluteRect;
CGSize _containerSize;
}
- (instancetype)initWithSize:(CGFloat)size alpha:(CGFloat)alpha;
@end
@implementation TGVideoMessageShimmerEffectForegroundView
- (instancetype)initWithSize:(CGFloat)size alpha:(CGFloat)alpha {
self = [super initWithFrame:CGRectZero];
if (self != nil) {
_size = size;
_imageContainerView = [[UIView alloc] init];
_imageView = [[UIView alloc] init];
self.clipsToBounds = true;
[_imageContainerView addSubview:_imageView];
[self addSubview:_imageContainerView];
UIGraphicsBeginImageContextWithOptions(CGSizeMake(size, 16), false, 0.0f);
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect bounds = CGRectMake(0, 0, size, 16);
CGContextClearRect(context, bounds);
CGContextClipToRect(context, bounds);
UIColor *transparentColor = [UIColor colorWithWhite:1.0 alpha:0.0];
UIColor *peakColor = [UIColor colorWithWhite:1.0 alpha:alpha];
CGColorRef colors[3] = {
CGColorRetain(transparentColor.CGColor),
CGColorRetain(peakColor.CGColor),
CGColorRetain(transparentColor.CGColor)
};
CFArrayRef colorsArray = CFArrayCreate(kCFAllocatorDefault, (const void **)&colors, 3, NULL);
CGFloat locations[3] = {0.0f, 0.5, 1.0};
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, colorsArray, (CGFloat const *)&locations);
CGContextDrawLinearGradient(context, gradient, CGPointMake(0, 0), CGPointMake(size, 0), kNilOptions);
CFRelease(colorsArray);
CFRelease(colors[0]);
CFRelease(colors[1]);
CGColorSpaceRelease(colorSpace);
CFRelease(gradient);
UIImage *image = [UIGraphicsGetImageFromCurrentImageContext() stretchableImageWithLeftCapWidth:25 topCapHeight:25];
UIGraphicsEndImageContext();
_imageView.backgroundColor = [UIColor colorWithPatternImage:image];
}
return self;
}
- (void)updateAbsoluteRect:(CGRect)absoluteRect containerSize:(CGSize)containerSize {
_hasContainerSize = true;
CGRect previousAbsoluteRect = _absoluteRect;
CGSize previousContainerSize = _containerSize;
_absoluteRect = absoluteRect;
_containerSize = containerSize;
if (!CGSizeEqualToSize(previousContainerSize, containerSize)) {
[self setupAnimation];
}
if (!CGRectEqualToRect(previousAbsoluteRect, absoluteRect)) {
_imageContainerView.frame = CGRectMake(-absoluteRect.origin.x, -absoluteRect.origin.y, containerSize.width, containerSize.height);
}
}
- (void)setupAnimation {
if (!_hasContainerSize) {
return;
}
CGFloat gradientHeight = _size;
_imageView.frame = CGRectMake(-gradientHeight, 0, gradientHeight, _containerSize.height);
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position.x"];
animation.fromValue = @(_imageView.center.x);
animation.toValue = @(_imageView.center.x + _containerSize.width + gradientHeight);
animation.duration = 1.3f;
animation.repeatCount = INFINITY;
animation.beginTime = 1.0;
[_imageView.layer addAnimation:animation forKey:@"position"];
}
@end
@interface TGVideoMessageShimmerView ()
{
TGVideoMessageShimmerEffectForegroundView *_effectView;
UIImageView *_imageView;
UIView *_borderView;
UIView *_borderMaskView;
TGVideoMessageShimmerEffectForegroundView *_borderEffectView;
}
@end
@implementation TGVideoMessageShimmerView
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self != nil) {
self.clipsToBounds = true;
self.layer.cornerRadius = frame.size.width / 2.0f;
if (@available(iOS 13.0, *)) {
self.layer.cornerCurve = kCACornerCurveCircular;
}
_effectView = [[TGVideoMessageShimmerEffectForegroundView alloc] initWithSize:320 alpha:0.3];
_effectView.layer.compositingFilter = @"screenBlendMode";
_effectView.frame = self.bounds;
_borderView = [[UIView alloc] initWithFrame:self.bounds];
_borderMaskView = [[UIView alloc] initWithFrame:self.bounds];
_borderMaskView.layer.borderWidth = 1.0;
_borderMaskView.layer.borderColor = [UIColor whiteColor].CGColor;
_borderMaskView.layer.cornerRadius = frame.size.width / 2.0f;
if (@available(iOS 13.0, *)) {
_borderMaskView.layer.cornerCurve = kCACornerCurveCircular;
}
_borderView.maskView = _borderMaskView;
_borderEffectView = [[TGVideoMessageShimmerEffectForegroundView alloc] initWithSize:400 alpha:0.45];
_borderEffectView.layer.compositingFilter = @"screenBlendMode";
_borderEffectView.frame = self.bounds;
[self addSubview:_effectView];
[self addSubview:_borderView];
[_borderView addSubview:_borderEffectView];
}
return self;
}
- (void)updateAbsoluteRect:(CGRect)absoluteRect containerSize:(CGSize)containerSize {
[_effectView updateAbsoluteRect:absoluteRect containerSize:containerSize];
[_borderEffectView updateAbsoluteRect:absoluteRect containerSize:containerSize];
}
@end
@interface TGVideoMessageRingView ()
{
CGFloat _value;
}
@end
@implementation TGVideoMessageRingView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self != nil)
{
self.backgroundColor = [UIColor clearColor];
}
return self;
}
- (void)setValue:(CGFloat)value
{
_value = value;
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect
{
if (_value < DBL_EPSILON)
return;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, self.accentColor.CGColor);
CGMutablePathRef path = CGPathCreateMutable();
CGPoint centerPoint = CGPointMake(rect.size.width / 2.0f, rect.size.height / 2.0f);
CGFloat lineWidth = 4.0f;
CGPathAddArc(path, NULL, centerPoint.x, centerPoint.y, rect.size.width / 2.0f - lineWidth / 2.0f, -M_PI_2, -M_PI_2 + 2 * M_PI * _value, false);
CGPathRef strokedArc = CGPathCreateCopyByStrokingPath(path, NULL, lineWidth, kCGLineCapRound, kCGLineJoinMiter, 10);
CGPathRelease(path);
CGContextAddPath(context, strokedArc);
CGPathRelease(strokedArc);
CGContextFillPath(context);
}
@end