|  |  |  | @ -5,6 +5,7 @@ | 
		
	
		
			
				|  |  |  |  | #import "OWSQuotedMessageView.h" | 
		
	
		
			
				|  |  |  |  | #import "ConversationViewItem.h" | 
		
	
		
			
				|  |  |  |  | #import "Environment.h" | 
		
	
		
			
				|  |  |  |  | #import "OWSMessageCell.h" | 
		
	
		
			
				|  |  |  |  | #import "Signal-Swift.h" | 
		
	
		
			
				|  |  |  |  | #import <SignalMessaging/OWSContactsManager.h> | 
		
	
		
			
				|  |  |  |  | #import <SignalMessaging/SignalMessaging-Swift.h> | 
		
	
	
		
			
				
					|  |  |  | @ -18,16 +19,47 @@ NS_ASSUME_NONNULL_BEGIN | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | @interface OWSQuotedMessageView () | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | @property (nonatomic, readonly) ConversationViewItem *viewItem; | 
		
	
		
			
				|  |  |  |  | @property (nonatomic, readonly) TSQuotedMessage *quotedMessage; | 
		
	
		
			
				|  |  |  |  | @property (nonatomic, nullable, readonly) DisplayableText *displayableQuotedText; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | @property (nonatomic, readonly) UIFont *textMessageFont; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | @property (nonatomic, readonly) UIColor *strokeColor; | 
		
	
		
			
				|  |  |  |  | @property (nonatomic, readonly) CGFloat strokeThickness; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | // TODO: Replace with a bubble stroke view. | 
		
	
		
			
				|  |  |  |  | @property (nonatomic) CAShapeLayer *shapeLayer; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | @property (nonatomic, weak) OWSBubbleView *bubbleView; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | @end | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | @implementation OWSQuotedMessageView | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | - (instancetype)initWithViewItem:(ConversationViewItem *)viewItem | 
		
	
		
			
				|  |  |  |  |                  //                   quotedMessage:(TSQuotedMessage *)quotedMessage | 
		
	
		
			
				|  |  |  |  |                  textMessageFont:(UIFont *)textMessageFont | 
		
	
		
			
				|  |  |  |  | + (OWSQuotedMessageView *)quotedMessageViewForConversation:(TSQuotedMessage *)quotedMessage | 
		
	
		
			
				|  |  |  |  |                                      displayableQuotedText:(nullable DisplayableText *)displayableQuotedText | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  |     OWSAssert(quotedMessage); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     return | 
		
	
		
			
				|  |  |  |  |         [[OWSQuotedMessageView alloc] initWithQuotedMessage:quotedMessage displayableQuotedText:displayableQuotedText]; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | + (OWSQuotedMessageView *)quotedMessageViewForPreview:(TSQuotedMessage *)quotedMessage | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  |     OWSAssert(quotedMessage); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     DisplayableText *_Nullable displayableQuotedText = nil; | 
		
	
		
			
				|  |  |  |  |     if (quotedMessage.body.length > 0) { | 
		
	
		
			
				|  |  |  |  |         displayableQuotedText = [DisplayableText displayableText:quotedMessage.body]; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     return | 
		
	
		
			
				|  |  |  |  |         [[OWSQuotedMessageView alloc] initWithQuotedMessage:quotedMessage displayableQuotedText:displayableQuotedText]; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | - (instancetype)initWithQuotedMessage:(TSQuotedMessage *)quotedMessage | 
		
	
		
			
				|  |  |  |  |                 displayableQuotedText:(nullable DisplayableText *)displayableQuotedText | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  |     self = [super init]; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					|  |  |  | @ -35,37 +67,31 @@ NS_ASSUME_NONNULL_BEGIN | 
		
	
		
			
				|  |  |  |  |         return self; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     OWSAssert(viewItem); | 
		
	
		
			
				|  |  |  |  |     //    OWSAssert(quotedMessage); | 
		
	
		
			
				|  |  |  |  |     OWSAssert(textMessageFont); | 
		
	
		
			
				|  |  |  |  |     OWSAssert(quotedMessage); | 
		
	
		
			
				|  |  |  |  |     OWSAssert(displayableQuotedText); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     _viewItem = viewItem; | 
		
	
		
			
				|  |  |  |  |     //    _quotedMessage = quotedMessage; | 
		
	
		
			
				|  |  |  |  |     _textMessageFont = textMessageFont; | 
		
	
		
			
				|  |  |  |  |     _quotedMessage = quotedMessage; | 
		
	
		
			
				|  |  |  |  |     _displayableQuotedText = displayableQuotedText; | 
		
	
		
			
				|  |  |  |  |     _textMessageFont = OWSMessageCell.defaultTextMessageFont; | 
		
	
		
			
				|  |  |  |  |     _strokeColor = OWSMessagesBubbleImageFactory.bubbleColorIncoming; | 
		
	
		
			
				|  |  |  |  |     _strokeThickness = 1.f; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     return self; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |     self.shapeLayer = [CAShapeLayer new]; | 
		
	
		
			
				|  |  |  |  |     [self.layer addSublayer:self.shapeLayer]; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | - (BOOL)isIncoming | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  |     return self.viewItem.interaction.interactionType == OWSInteractionType_IncomingMessage; | 
		
	
		
			
				|  |  |  |  |     return self; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | - (BOOL)hasQuotedAttachmentThumbnail | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  |     // This should always be valid for the appropriate cell types. | 
		
	
		
			
				|  |  |  |  |     OWSAssert(self.viewItem); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     return (self.viewItem.hasQuotedAttachment && | 
		
	
		
			
				|  |  |  |  |         [TSAttachmentStream hasThumbnailForMimeType:self.viewItem.quotedAttachmentMimetype]); | 
		
	
		
			
				|  |  |  |  |     return (self.quotedMessage.contentType.length > 0 && | 
		
	
		
			
				|  |  |  |  |         [TSAttachmentStream hasThumbnailForMimeType:self.quotedMessage.contentType]); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | #pragma mark - | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | - (void)createContents | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  |     OWSAssert(self.viewItem.isQuotedReply); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     self.backgroundColor = [UIColor whiteColor]; | 
		
	
		
			
				|  |  |  |  |     self.userInteractionEnabled = NO; | 
		
	
		
			
				|  |  |  |  |     self.layoutMargins = UIEdgeInsetsZero; | 
		
	
	
		
			
				
					|  |  |  | @ -91,14 +117,15 @@ NS_ASSUME_NONNULL_BEGIN | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     OWSContactsManager *contactsManager = Environment.current.contactsManager; | 
		
	
		
			
				|  |  |  |  |     NSString *quotedAuthor = [contactsManager displayNameForPhoneIdentifier:self.viewItem.quotedRecipientId]; | 
		
	
		
			
				|  |  |  |  |     NSString *quotedAuthor = [contactsManager displayNameForPhoneIdentifier:self.quotedMessage.authorId]; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     UILabel *quotedAuthorLabel = [UILabel new]; | 
		
	
		
			
				|  |  |  |  |     { | 
		
	
		
			
				|  |  |  |  |         quotedAuthorLabel.text = quotedAuthor; | 
		
	
		
			
				|  |  |  |  |         quotedAuthorLabel.font = self.quotedAuthorFont; | 
		
	
		
			
				|  |  |  |  |         quotedAuthorLabel.textColor | 
		
	
		
			
				|  |  |  |  |             = (self.isIncoming ? [UIColor colorWithRGBHex:0xd84315] : [UIColor colorWithRGBHex:0x007884]); | 
		
	
		
			
				|  |  |  |  |         // TODO: | 
		
	
		
			
				|  |  |  |  |         quotedAuthorLabel.textColor = [UIColor ows_darkGrayColor]; | 
		
	
		
			
				|  |  |  |  |         //            = (self.isIncoming ? [UIColor colorWithRGBHex:0xd84315] : [UIColor colorWithRGBHex:0x007884]); | 
		
	
		
			
				|  |  |  |  |         quotedAuthorLabel.numberOfLines = 1; | 
		
	
		
			
				|  |  |  |  |         quotedAuthorLabel.lineBreakMode = NSLineBreakByTruncatingTail; | 
		
	
		
			
				|  |  |  |  |         [self addSubview:quotedAuthorLabel]; | 
		
	
	
		
			
				
					|  |  |  | @ -135,8 +162,12 @@ NS_ASSUME_NONNULL_BEGIN | 
		
	
		
			
				|  |  |  |  |         [stripeAndTextContainer setCompressionResistanceLow]; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         // Stripe. | 
		
	
		
			
				|  |  |  |  |         BOOL isIncomingQuote | 
		
	
		
			
				|  |  |  |  |             = ![NSObject isNullableObject:self.quotedMessage.authorId equalTo:TSAccountManager.localNumber]; | 
		
	
		
			
				|  |  |  |  |         UIColor *stripeColor = (isIncomingQuote ? OWSMessagesBubbleImageFactory.bubbleColorIncoming | 
		
	
		
			
				|  |  |  |  |                                                 : OWSMessagesBubbleImageFactory.bubbleColorOutgoingSent); | 
		
	
		
			
				|  |  |  |  |         UIView *quoteStripView = [UIView containerView]; | 
		
	
		
			
				|  |  |  |  |         quoteStripView.backgroundColor = (self.isIncoming ? [UIColor whiteColor] : [UIColor colorWithRGBHex:0x007884]); | 
		
	
		
			
				|  |  |  |  |         quoteStripView.backgroundColor = stripeColor; | 
		
	
		
			
				|  |  |  |  |         quoteStripView.userInteractionEnabled = NO; | 
		
	
		
			
				|  |  |  |  |         [stripeAndTextContainer addSubview:quoteStripView]; | 
		
	
		
			
				|  |  |  |  |         [quoteStripView autoPinHeightToSuperview]; | 
		
	
	
		
			
				
					|  |  |  | @ -163,15 +194,8 @@ NS_ASSUME_NONNULL_BEGIN | 
		
	
		
			
				|  |  |  |  | // TODO: Class method? | 
		
	
		
			
				|  |  |  |  | - (CGSize)sizeForMaxWidth:(CGFloat)maxWidth | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  |     OWSAssert(self.viewItem); | 
		
	
		
			
				|  |  |  |  |     OWSAssert([self.viewItem.interaction isKindOfClass:[TSMessage class]]); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     CGSize result = CGSizeZero; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     if (!self.viewItem.isQuotedReply) { | 
		
	
		
			
				|  |  |  |  |         return result; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     result.width += self.quotedContentHInset; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     CGFloat thumbnailHeight = 0.f; | 
		
	
	
		
			
				
					|  |  |  | @ -192,7 +216,7 @@ NS_ASSUME_NONNULL_BEGIN | 
		
	
		
			
				|  |  |  |  |         CGFloat maxQuotedAuthorWidth = maxWidth - result.width; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         OWSContactsManager *contactsManager = Environment.current.contactsManager; | 
		
	
		
			
				|  |  |  |  |         NSString *quotedAuthor = [contactsManager displayNameForPhoneIdentifier:self.viewItem.quotedRecipientId]; | 
		
	
		
			
				|  |  |  |  |         NSString *quotedAuthor = [contactsManager displayNameForPhoneIdentifier:self.quotedMessage.authorId]; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         UILabel *quotedAuthorLabel = [UILabel new]; | 
		
	
		
			
				|  |  |  |  |         quotedAuthorLabel.text = quotedAuthor; | 
		
	
	
		
			
				
					|  |  |  | @ -253,10 +277,10 @@ NS_ASSUME_NONNULL_BEGIN | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | - (NSString *)quotedSnippet | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  |     if (self.viewItem.hasQuotedText && self.viewItem.displayableQuotedText.displayText.length > 0) { | 
		
	
		
			
				|  |  |  |  |         return self.viewItem.displayableQuotedText.displayText; | 
		
	
		
			
				|  |  |  |  |     if (self.displayableQuotedText.displayText.length > 0) { | 
		
	
		
			
				|  |  |  |  |         return self.displayableQuotedText.displayText; | 
		
	
		
			
				|  |  |  |  |     } else { | 
		
	
		
			
				|  |  |  |  |         NSString *mimeType = self.viewItem.quotedAttachmentMimetype; | 
		
	
		
			
				|  |  |  |  |         NSString *mimeType = self.quotedMessage.contentType; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         if (mimeType.length > 0) { | 
		
	
		
			
				|  |  |  |  |             return [TSAttachment emojiForMimeType:mimeType]; | 
		
	
	
		
			
				
					|  |  |  | @ -299,7 +323,7 @@ NS_ASSUME_NONNULL_BEGIN | 
		
	
		
			
				|  |  |  |  | // TODO: | 
		
	
		
			
				|  |  |  |  | - (CGFloat)quotedReplyStripeThickness | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  |     return 3.f; | 
		
	
		
			
				|  |  |  |  |     return 2.f; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | // TODO: | 
		
	
	
		
			
				
					|  |  |  | @ -342,6 +366,101 @@ NS_ASSUME_NONNULL_BEGIN | 
		
	
		
			
				|  |  |  |  |     return 8.f; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | #pragma mark - Stroke | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | //- (instancetype)init | 
		
	
		
			
				|  |  |  |  | //{ | 
		
	
		
			
				|  |  |  |  | //    self = [super init]; | 
		
	
		
			
				|  |  |  |  | //    if (!self) { | 
		
	
		
			
				|  |  |  |  | //        return self; | 
		
	
		
			
				|  |  |  |  | //    } | 
		
	
		
			
				|  |  |  |  | // | 
		
	
		
			
				|  |  |  |  | //    self.opaque = NO; | 
		
	
		
			
				|  |  |  |  | //    self.backgroundColor = [UIColor clearColor]; | 
		
	
		
			
				|  |  |  |  | // | 
		
	
		
			
				|  |  |  |  | // | 
		
	
		
			
				|  |  |  |  | //    [self updateLayers]; | 
		
	
		
			
				|  |  |  |  | // | 
		
	
		
			
				|  |  |  |  | //    return self; | 
		
	
		
			
				|  |  |  |  | //} | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | - (void)setStrokeColor:(UIColor *)strokeColor | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  |     _strokeColor = strokeColor; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     [self updateLayers]; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | - (void)setStrokeThickness:(CGFloat)strokeThickness | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  |     _strokeThickness = strokeThickness; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     [self updateLayers]; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | - (void)setFrame:(CGRect)frame | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  |     BOOL didChange = !CGRectEqualToRect(self.frame, frame); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     [super setFrame:frame]; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     if (didChange) { | 
		
	
		
			
				|  |  |  |  |         [self updateLayers]; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | - (void)setBounds:(CGRect)bounds | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  |     BOOL didChange = !CGRectEqualToRect(self.bounds, bounds); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     [super setBounds:bounds]; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     if (didChange) { | 
		
	
		
			
				|  |  |  |  |         [self updateLayers]; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | - (void)setCenter:(CGPoint)center | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  |     [super setCenter:center]; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     [self updateLayers]; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | - (void)updateLayers | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  |     if (!self.shapeLayer) { | 
		
	
		
			
				|  |  |  |  |         return; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     // Don't fill the shape layer; we just want a stroke around the border. | 
		
	
		
			
				|  |  |  |  |     self.shapeLayer.fillColor = [UIColor clearColor].CGColor; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     self.clipsToBounds = YES; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     if (!self.bubbleView) { | 
		
	
		
			
				|  |  |  |  |         return; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     self.shapeLayer.strokeColor = self.strokeColor.CGColor; | 
		
	
		
			
				|  |  |  |  |     self.shapeLayer.lineWidth = self.strokeThickness; | 
		
	
		
			
				|  |  |  |  |     self.shapeLayer.zPosition = 100.f; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     UIBezierPath *bezierPath = [UIBezierPath new]; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     UIBezierPath *boundsBezierPath = [UIBezierPath bezierPathWithRect:self.bounds]; | 
		
	
		
			
				|  |  |  |  |     [bezierPath appendPath:boundsBezierPath]; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     UIBezierPath *bubbleBezierPath = [self.bubbleView maskPath]; | 
		
	
		
			
				|  |  |  |  |     // We need to convert between coordinate systems using layers, not views. | 
		
	
		
			
				|  |  |  |  |     CGPoint bubbleOffset = [self.layer convertPoint:CGPointZero fromLayer:self.bubbleView.layer]; | 
		
	
		
			
				|  |  |  |  |     CGAffineTransform transform = CGAffineTransformMakeTranslation(bubbleOffset.x, bubbleOffset.y); | 
		
	
		
			
				|  |  |  |  |     [bubbleBezierPath applyTransform:transform]; | 
		
	
		
			
				|  |  |  |  |     [bezierPath appendPath:bubbleBezierPath]; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     self.shapeLayer.path = bezierPath.CGPath; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | @end | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | NS_ASSUME_NONNULL_END | 
		
	
	
		
			
				
					|  |  |  | 
 |