|
|
|
@ -13,6 +13,7 @@ typedef NS_ENUM(NSUInteger, OWSBubbleShapeViewMode) {
|
|
|
|
|
OWSBubbleShapeViewMode_Draw,
|
|
|
|
|
OWSBubbleShapeViewMode_Shadow,
|
|
|
|
|
OWSBubbleShapeViewMode_Clip,
|
|
|
|
|
OWSBubbleShapeViewMode_InnerShadow,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
@interface OWSBubbleShapeView ()
|
|
|
|
@ -30,13 +31,8 @@ typedef NS_ENUM(NSUInteger, OWSBubbleShapeViewMode) {
|
|
|
|
|
|
|
|
|
|
@implementation OWSBubbleShapeView
|
|
|
|
|
|
|
|
|
|
- (instancetype)init
|
|
|
|
|
- (void)configure
|
|
|
|
|
{
|
|
|
|
|
self = [super init];
|
|
|
|
|
if (!self) {
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.mode = OWSBubbleShapeViewMode_Draw;
|
|
|
|
|
self.opaque = NO;
|
|
|
|
|
self.backgroundColor = [UIColor clearColor];
|
|
|
|
@ -46,29 +42,67 @@ typedef NS_ENUM(NSUInteger, OWSBubbleShapeViewMode) {
|
|
|
|
|
[self.layer addSublayer:self.shapeLayer];
|
|
|
|
|
|
|
|
|
|
self.maskLayer = [CAShapeLayer new];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- (instancetype)initDraw
|
|
|
|
|
{
|
|
|
|
|
self = [super init];
|
|
|
|
|
if (!self) {
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.mode = OWSBubbleShapeViewMode_Draw;
|
|
|
|
|
|
|
|
|
|
[self configure];
|
|
|
|
|
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (OWSBubbleShapeView *)bubbleDrawView
|
|
|
|
|
- (instancetype)initShadow
|
|
|
|
|
{
|
|
|
|
|
OWSBubbleShapeView *instance = [OWSBubbleShapeView new];
|
|
|
|
|
instance.mode = OWSBubbleShapeViewMode_Draw;
|
|
|
|
|
return instance;
|
|
|
|
|
self = [super init];
|
|
|
|
|
if (!self) {
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.mode = OWSBubbleShapeViewMode_Shadow;
|
|
|
|
|
|
|
|
|
|
[self configure];
|
|
|
|
|
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (OWSBubbleShapeView *)bubbleShadowView
|
|
|
|
|
- (instancetype)initClip
|
|
|
|
|
{
|
|
|
|
|
OWSBubbleShapeView *instance = [OWSBubbleShapeView new];
|
|
|
|
|
instance.mode = OWSBubbleShapeViewMode_Shadow;
|
|
|
|
|
return instance;
|
|
|
|
|
self = [super init];
|
|
|
|
|
if (!self) {
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.mode = OWSBubbleShapeViewMode_Clip;
|
|
|
|
|
|
|
|
|
|
[self configure];
|
|
|
|
|
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (OWSBubbleShapeView *)bubbleClipView
|
|
|
|
|
- (instancetype)initInnerShadowWithColor:(UIColor *)color radius:(CGFloat)radius opacity:(float)opacity
|
|
|
|
|
{
|
|
|
|
|
OWSBubbleShapeView *instance = [OWSBubbleShapeView new];
|
|
|
|
|
instance.mode = OWSBubbleShapeViewMode_Clip;
|
|
|
|
|
return instance;
|
|
|
|
|
self = [super init];
|
|
|
|
|
if (!self) {
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.mode = OWSBubbleShapeViewMode_InnerShadow;
|
|
|
|
|
_innerShadowColor = color;
|
|
|
|
|
_innerShadowRadius = radius;
|
|
|
|
|
_innerShadowOpacity = opacity;
|
|
|
|
|
|
|
|
|
|
[self configure];
|
|
|
|
|
[self updateLayers];
|
|
|
|
|
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)setFillColor:(nullable UIColor *)fillColor
|
|
|
|
@ -92,6 +126,27 @@ typedef NS_ENUM(NSUInteger, OWSBubbleShapeViewMode) {
|
|
|
|
|
[self updateLayers];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)setInnerShadowColor:(nullable UIColor *)innerShadowColor
|
|
|
|
|
{
|
|
|
|
|
_innerShadowColor = innerShadowColor;
|
|
|
|
|
|
|
|
|
|
[self updateLayers];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)setInnerShadowRadius:(CGFloat)innerShadowRadius
|
|
|
|
|
{
|
|
|
|
|
_innerShadowRadius = innerShadowRadius;
|
|
|
|
|
|
|
|
|
|
[self updateLayers];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)setInnerShadowOpacity:(float)innerShadowOpacity
|
|
|
|
|
{
|
|
|
|
|
_innerShadowOpacity = innerShadowOpacity;
|
|
|
|
|
|
|
|
|
|
[self updateLayers];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)setFrame:(CGRect)frame
|
|
|
|
|
{
|
|
|
|
|
BOOL didChange = !CGRectEqualToRect(self.frame, frame);
|
|
|
|
@ -188,6 +243,32 @@ typedef NS_ENUM(NSUInteger, OWSBubbleShapeViewMode) {
|
|
|
|
|
self.maskLayer.path = bezierPath.CGPath;
|
|
|
|
|
self.layer.mask = self.maskLayer;
|
|
|
|
|
break;
|
|
|
|
|
case OWSBubbleShapeViewMode_InnerShadow: {
|
|
|
|
|
self.maskLayer.path = bezierPath.CGPath;
|
|
|
|
|
self.layer.mask = self.maskLayer;
|
|
|
|
|
|
|
|
|
|
// Inner shadow.
|
|
|
|
|
// This should usually not be visible; it is used to distinguish
|
|
|
|
|
// profile pics from the background if they are similar.
|
|
|
|
|
self.shapeLayer.frame = self.bounds;
|
|
|
|
|
self.shapeLayer.masksToBounds = YES;
|
|
|
|
|
CGRect shadowBounds = self.bounds;
|
|
|
|
|
UIBezierPath *shadowPath = [bezierPath copy];
|
|
|
|
|
// This can be any value large enough to cast a sufficiently large shadow.
|
|
|
|
|
CGFloat shadowInset = -(self.innerShadowRadius * 4.f);
|
|
|
|
|
[shadowPath
|
|
|
|
|
appendPath:[UIBezierPath bezierPathWithRect:CGRectInset(shadowBounds, shadowInset, shadowInset)]];
|
|
|
|
|
// This can be any color since the fill should be clipped.
|
|
|
|
|
self.shapeLayer.fillColor = UIColor.blackColor.CGColor;
|
|
|
|
|
self.shapeLayer.path = shadowPath.CGPath;
|
|
|
|
|
self.shapeLayer.fillRule = kCAFillRuleEvenOdd;
|
|
|
|
|
self.shapeLayer.shadowColor = self.innerShadowColor.CGColor;
|
|
|
|
|
self.shapeLayer.shadowRadius = self.innerShadowRadius;
|
|
|
|
|
self.shapeLayer.shadowOpacity = self.innerShadowOpacity;
|
|
|
|
|
self.shapeLayer.shadowOffset = CGSizeZero;
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[CATransaction commit];
|
|
|
|
|