diff --git a/Signal/src/Signal-Bridging-Header.h b/Signal/src/Signal-Bridging-Header.h index 6b738b044..88c2b1bf1 100644 --- a/Signal/src/Signal-Bridging-Header.h +++ b/Signal/src/Signal-Bridging-Header.h @@ -5,6 +5,7 @@ #import "AppSettingsViewController.h" #import "AttachmentSharing.h" #import "ContactTableViewCell.h" +#import "ConversationViewController.h" #import "DateUtil.h" #import "DebugUIPage.h" #import "Environment.h" @@ -42,6 +43,7 @@ #import #import #import +#import #import #import #import diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.h b/Signal/src/ViewControllers/ConversationView/ConversationViewController.h index 4ca34e2df..424956643 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.h +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.h @@ -5,6 +5,7 @@ #import @class TSThread; +@class JSQMessagesBubbleImage; extern NSString *const ConversationViewControllerDidAppearNotification; @@ -23,4 +24,11 @@ extern NSString *const ConversationViewControllerDidAppearNotification; - (void)peekSetup; - (void)popped; +#pragma mark shared bubble styles + ++ (JSQMessagesBubbleImage *)outgoingBubbleImageData; ++ (JSQMessagesBubbleImage *)incomingBubbleImageData; ++ (JSQMessagesBubbleImage *)currentlyOutgoingBubbleImageData; ++ (JSQMessagesBubbleImage *)outgoingMessageFailedImageData; + @end diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index 5a8e792d8..377b656f9 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -259,11 +259,6 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) { @property (nonatomic) YapDatabaseConnection *uiDatabaseConnection; @property (nonatomic) YapDatabaseViewMappings *messageMappings; -@property (nonatomic) JSQMessagesBubbleImage *outgoingBubbleImageData; -@property (nonatomic) JSQMessagesBubbleImage *incomingBubbleImageData; -@property (nonatomic) JSQMessagesBubbleImage *currentlyOutgoingBubbleImageData; -@property (nonatomic) JSQMessagesBubbleImage *outgoingMessageFailedImageData; - @property (nonatomic) MPMoviePlayerController *videoPlayer; @property (nonatomic) AVAudioRecorder *audioRecorder; @property (nonatomic) OWSAudioAttachmentPlayer *audioAttachmentPlayer; @@ -1541,15 +1536,75 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) { self.collectionView.collectionViewLayout.messageBubbleLeftRightMargin = 80.0f; } - // Bubbles self.collectionView.collectionViewLayout.bubbleSizeCalculator = [OWSMessagesBubblesSizeCalculator new]; - JSQMessagesBubbleImageFactory *bubbleFactory = [[JSQMessagesBubbleImageFactory alloc] init]; - self.incomingBubbleImageData = - [bubbleFactory incomingMessagesBubbleImageWithColor:[UIColor jsq_messageBubbleLightGrayColor]]; - self.outgoingBubbleImageData = [bubbleFactory outgoingMessagesBubbleImageWithColor:[UIColor ows_materialBlueColor]]; - self.currentlyOutgoingBubbleImageData = - [bubbleFactory outgoingMessagesBubbleImageWithColor:[UIColor ows_fadedBlueColor]]; - self.outgoingMessageFailedImageData = [bubbleFactory outgoingMessagesBubbleImageWithColor:[UIColor grayColor]]; +} + ++ (JSQMessagesBubbleImageFactory *)sharedBubbleImageFactory +{ + AssertIsOnMainThread(); + + static JSQMessagesBubbleImageFactory *bubbleImageFactory; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + bubbleImageFactory = [JSQMessagesBubbleImageFactory new]; + }); + + return bubbleImageFactory; +} + ++ (JSQMessagesBubbleImage *)outgoingBubbleImageData +{ + AssertIsOnMainThread(); + + static JSQMessagesBubbleImage *bubbleImage; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + bubbleImage = + [[self sharedBubbleImageFactory] outgoingMessagesBubbleImageWithColor:[UIColor ows_materialBlueColor]]; + }); + + return bubbleImage; +} + ++ (JSQMessagesBubbleImage *)incomingBubbleImageData +{ + AssertIsOnMainThread(); + + static JSQMessagesBubbleImage *bubbleImage; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + bubbleImage = [[self sharedBubbleImageFactory] + incomingMessagesBubbleImageWithColor:[UIColor jsq_messageBubbleLightGrayColor]]; + }); + + return bubbleImage; +} + ++ (JSQMessagesBubbleImage *)currentlyOutgoingBubbleImageData +{ + AssertIsOnMainThread(); + + static JSQMessagesBubbleImage *bubbleImage; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + bubbleImage = + [[self sharedBubbleImageFactory] outgoingMessagesBubbleImageWithColor:[UIColor ows_fadedBlueColor]]; + }); + + return bubbleImage; +} + ++ (JSQMessagesBubbleImage *)outgoingMessageFailedImageData +{ + AssertIsOnMainThread(); + + static JSQMessagesBubbleImage *bubbleImage; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + bubbleImage = [[self sharedBubbleImageFactory] outgoingMessagesBubbleImageWithColor:[UIColor grayColor]]; + }); + + return bubbleImage; } #pragma mark - Identity @@ -1831,19 +1886,19 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) { TSOutgoingMessage *outgoingMessage = (TSOutgoingMessage *)message; switch (outgoingMessage.messageState) { case TSOutgoingMessageStateUnsent: - return self.outgoingMessageFailedImageData; + return [[self class] outgoingMessageFailedImageData]; case TSOutgoingMessageStateAttemptingOut: - return self.currentlyOutgoingBubbleImageData; + return [[self class] currentlyOutgoingBubbleImageData]; case TSOutgoingMessageStateSent_OBSOLETE: case TSOutgoingMessageStateDelivered_OBSOLETE: OWSFail(@"%@ Obsolete message state.", self.tag); - return self.outgoingBubbleImageData; + return [[self class] outgoingBubbleImageData]; case TSOutgoingMessageStateSentToService: - return self.outgoingBubbleImageData; + return [[self class] outgoingBubbleImageData]; } } - return self.incomingBubbleImageData; + return [[self class] incomingBubbleImageData]; } - (id)collectionView:(JSQMessagesCollectionView *)collectionView diff --git a/Signal/src/ViewControllers/MessageMetadataViewController.swift b/Signal/src/ViewControllers/MessageMetadataViewController.swift index 5c824445c..90e56f139 100644 --- a/Signal/src/ViewControllers/MessageMetadataViewController.swift +++ b/Signal/src/ViewControllers/MessageMetadataViewController.swift @@ -280,13 +280,24 @@ class MessageMetadataViewController: OWSViewController { bodyLabel.numberOfLines = 10 bodyLabel.lineBreakMode = .byWordWrapping - let bubbleView = UIView() - bubbleView.backgroundColor = isIncoming ? UIColor.jsq_messageBubbleLightGray() : UIColor.ows_materialBlue() + let bubbleImageData = isIncoming ? ConversationViewController.incomingBubbleImageData() : ConversationViewController.outgoingBubbleImageData() + let leadingMargin: CGFloat = isIncoming ? 15 : 10 + let trailingMargin: CGFloat = isIncoming ? 10 : 15 + + let bubbleView = UIImageView(image: bubbleImageData!.messageBubbleImage) + bubbleView.layer.cornerRadius = 10 bubbleView.addSubview(bodyLabel) - bodyLabel.autoPinLeadingToSuperView(withMargin:10) - bodyLabel.autoPinTrailingToSuperView(withMargin:10) - bodyLabel.autoPinHeightToSuperview(withMargin:10) + bodyLabel.autoPinLeadingToSuperView(withMargin: leadingMargin) + bodyLabel.autoPinTrailingToSuperView(withMargin: trailingMargin) + bodyLabel.autoPinHeightToSuperview(withMargin: 10) + + // Try to hug content both horizontally and vertically, but *prefer* wide and short, to narrow and tall. + // While never exceeding max width, and never cropping content. + bodyLabel.setContentHuggingPriority(UILayoutPriorityDefaultLow, for: .horizontal) + bodyLabel.setContentHuggingPriority(UILayoutPriorityDefaultHigh, for: .vertical) + bodyLabel.setContentCompressionResistancePriority(UILayoutPriorityRequired, for: .vertical) + bodyLabel.autoSetDimension(.width, toSize:ScaleFromIPhone5(210), relation:.lessThanOrEqual) let bubbleSpacer = UIView() @@ -295,8 +306,6 @@ class MessageMetadataViewController: OWSViewController { row.addSubview(bubbleSpacer) bubbleView.autoPinHeightToSuperview() - bubbleView.setContentHuggingHorizontalHigh() - bubbleView.setCompressionResistanceHigh() bubbleSpacer.autoPinHeightToSuperview() bubbleSpacer.setContentHuggingLow()