From d161e5ff3d6ed4e22c122665c1a6c9fe6c0a9989 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Wed, 26 Sep 2018 16:24:15 -0400 Subject: [PATCH] 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);