From d161e5ff3d6ed4e22c122665c1a6c9fe6c0a9989 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Wed, 26 Sep 2018 16:24:15 -0400 Subject: [PATCH 1/2] Add inner shadows to media thumbnails. --- .../Cells/OWSBubbleShapeView.h | 5 ++ .../Cells/OWSBubbleShapeView.m | 55 +++++++++++++++++++ .../Cells/OWSMessageBubbleView.m | 15 ++--- 3 files changed, 68 insertions(+), 7 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSBubbleShapeView.h b/Signal/src/ViewControllers/ConversationView/Cells/OWSBubbleShapeView.h index f05cc46fe..59ec85199 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSBubbleShapeView.h +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSBubbleShapeView.h @@ -24,11 +24,16 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, nullable) UIColor *strokeColor; @property (nonatomic) CGFloat strokeThickness; +@property (nonatomic, nullable) UIColor *innerShadowColor; +@property (nonatomic) CGFloat innerShadowRadius; +@property (nonatomic) float innerShadowOpacity; + - (instancetype)init NS_UNAVAILABLE; + (OWSBubbleShapeView *)bubbleDrawView; + (OWSBubbleShapeView *)bubbleShadowView; + (OWSBubbleShapeView *)bubbleClipView; ++ (OWSBubbleShapeView *)bubbleInnerShadowView; @end diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSBubbleShapeView.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSBubbleShapeView.m index 7d387696d..b228c9f5d 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSBubbleShapeView.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSBubbleShapeView.m @@ -13,6 +13,7 @@ typedef NS_ENUM(NSUInteger, OWSBubbleShapeViewMode) { OWSBubbleShapeViewMode_Draw, OWSBubbleShapeViewMode_Shadow, OWSBubbleShapeViewMode_Clip, + OWSBubbleShapeViewMode_InnerShadow, }; @interface OWSBubbleShapeView () @@ -71,6 +72,13 @@ typedef NS_ENUM(NSUInteger, OWSBubbleShapeViewMode) { return instance; } ++ (OWSBubbleShapeView *)bubbleInnerShadowView +{ + OWSBubbleShapeView *instance = [OWSBubbleShapeView new]; + instance.mode = OWSBubbleShapeViewMode_InnerShadow; + return instance; +} + - (void)setFillColor:(nullable UIColor *)fillColor { _fillColor = fillColor; @@ -92,6 +100,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 +217,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]; diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m index 0e0c2aa79..33d84165d 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m @@ -352,13 +352,14 @@ const UIDataDetectorTypes kOWSAllowedDataDetectorTypes if (self.hasBodyMediaWithThumbnail) { [self.stackView addArrangedSubview:bodyMediaView]; - OWSBubbleShapeView *strokeView = [OWSBubbleShapeView bubbleDrawView]; - strokeView.strokeThickness = CGHairlineWidth(); - strokeView.strokeColor = (Theme.isDarkThemeEnabled ? [UIColor colorWithWhite:1.f alpha:0.2f] - : [UIColor colorWithWhite:0.f alpha:0.2f]); - [bodyMediaView addSubview:strokeView]; - [self.bubbleView addPartnerView:strokeView]; - [self.viewConstraints addObjectsFromArray:[strokeView ows_autoPinToSuperviewEdges]]; + OWSBubbleShapeView *innerShadowView = [OWSBubbleShapeView bubbleInnerShadowView]; + innerShadowView.innerShadowColor + = (Theme.isDarkThemeEnabled ? UIColor.ows_whiteColor : UIColor.ows_blackColor); + innerShadowView.innerShadowRadius = 0.5f; + innerShadowView.innerShadowOpacity = 0.15f; + [bodyMediaView addSubview:innerShadowView]; + [self.bubbleView addPartnerView:innerShadowView]; + [self.viewConstraints addObjectsFromArray:[innerShadowView ows_autoPinToSuperviewEdges]]; } else { OWSAssertDebug(self.cellType == OWSMessageCellType_ContactShare); From cbaf40d4cefcbd111084cf4174984ea4cd15193e Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Thu, 27 Sep 2018 09:52:12 -0400 Subject: [PATCH 2/2] Respond to CR. --- .../Cells/OWSBubbleShapeView.h | 13 +++- .../Cells/OWSBubbleShapeView.m | 74 +++++++++++++------ .../Cells/OWSMessageBubbleView.m | 14 ++-- 3 files changed, 66 insertions(+), 35 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSBubbleShapeView.h b/Signal/src/ViewControllers/ConversationView/Cells/OWSBubbleShapeView.h index 59ec85199..e804347d1 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSBubbleShapeView.h +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSBubbleShapeView.h @@ -30,10 +30,15 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)init NS_UNAVAILABLE; -+ (OWSBubbleShapeView *)bubbleDrawView; -+ (OWSBubbleShapeView *)bubbleShadowView; -+ (OWSBubbleShapeView *)bubbleClipView; -+ (OWSBubbleShapeView *)bubbleInnerShadowView; +- (instancetype)initDraw NS_DESIGNATED_INITIALIZER; +- (instancetype)initShadow NS_DESIGNATED_INITIALIZER; +; +- (instancetype)initClip NS_DESIGNATED_INITIALIZER; +; +- (instancetype)initInnerShadowWithColor:(UIColor *)color + radius:(CGFloat)radius + opacity:(float)opacity NS_DESIGNATED_INITIALIZER; +; @end diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSBubbleShapeView.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSBubbleShapeView.m index b228c9f5d..ac2d0a5f1 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSBubbleShapeView.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSBubbleShapeView.m @@ -31,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]; @@ -47,36 +42,67 @@ typedef NS_ENUM(NSUInteger, OWSBubbleShapeViewMode) { [self.layer addSublayer:self.shapeLayer]; self.maskLayer = [CAShapeLayer new]; - - return self; } -+ (OWSBubbleShapeView *)bubbleDrawView + +- (instancetype)initDraw { - OWSBubbleShapeView *instance = [OWSBubbleShapeView new]; - instance.mode = OWSBubbleShapeViewMode_Draw; - return instance; + self = [super init]; + if (!self) { + return self; + } + + self.mode = OWSBubbleShapeViewMode_Draw; + + [self configure]; + + return self; } -+ (OWSBubbleShapeView *)bubbleShadowView +- (instancetype)initShadow { - OWSBubbleShapeView *instance = [OWSBubbleShapeView new]; - instance.mode = OWSBubbleShapeViewMode_Shadow; - return instance; + self = [super init]; + if (!self) { + return self; + } + + self.mode = OWSBubbleShapeViewMode_Shadow; + + [self configure]; + + return self; } -+ (OWSBubbleShapeView *)bubbleClipView +- (instancetype)initClip { - OWSBubbleShapeView *instance = [OWSBubbleShapeView new]; - instance.mode = OWSBubbleShapeViewMode_Clip; - return instance; + self = [super init]; + if (!self) { + return self; + } + + self.mode = OWSBubbleShapeViewMode_Clip; + + [self configure]; + + return self; } -+ (OWSBubbleShapeView *)bubbleInnerShadowView +- (instancetype)initInnerShadowWithColor:(UIColor *)color radius:(CGFloat)radius opacity:(float)opacity { - OWSBubbleShapeView *instance = [OWSBubbleShapeView new]; - instance.mode = OWSBubbleShapeViewMode_InnerShadow; - 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 diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m index 33d84165d..04cf543f5 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m @@ -352,11 +352,11 @@ const UIDataDetectorTypes kOWSAllowedDataDetectorTypes if (self.hasBodyMediaWithThumbnail) { [self.stackView addArrangedSubview:bodyMediaView]; - OWSBubbleShapeView *innerShadowView = [OWSBubbleShapeView bubbleInnerShadowView]; - innerShadowView.innerShadowColor - = (Theme.isDarkThemeEnabled ? UIColor.ows_whiteColor : UIColor.ows_blackColor); - innerShadowView.innerShadowRadius = 0.5f; - innerShadowView.innerShadowOpacity = 0.15f; + OWSBubbleShapeView *innerShadowView = [[OWSBubbleShapeView alloc] + initInnerShadowWithColor:(Theme.isDarkThemeEnabled ? UIColor.ows_whiteColor + : UIColor.ows_blackColor) + radius:0.5f + opacity:0.15f]; [bodyMediaView addSubview:innerShadowView]; [self.bubbleView addPartnerView:innerShadowView]; [self.viewConstraints addObjectsFromArray:[innerShadowView ows_autoPinToSuperviewEdges]]; @@ -497,8 +497,8 @@ const UIDataDetectorTypes kOWSAllowedDataDetectorTypes UIView *proxyView = [UIView new]; [self.stackView addArrangedSubview:proxyView]; - OWSBubbleShapeView *shadowView = [OWSBubbleShapeView bubbleShadowView]; - OWSBubbleShapeView *clipView = [OWSBubbleShapeView bubbleClipView]; + OWSBubbleShapeView *shadowView = [[OWSBubbleShapeView alloc] initShadow]; + OWSBubbleShapeView *clipView = [[OWSBubbleShapeView alloc] initClip]; [self addSubview:shadowView]; [self addSubview:clipView];