mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
Size error messages correctly.
* calculate size of info message using the info message font. * offset by the info message header There were instances of lines getting cropped, or an extra line being added. The previous, more conservative, solution was to just make every bubble too big, but it looked terrible. // FREEBIE
This commit is contained in:
parent
b95112356c
commit
94a23021f8
|
@ -3,6 +3,7 @@
|
|||
#import "OWSMessagesBubblesSizeCalculator.h"
|
||||
#import "OWSDisplayedMessageCollectionViewCell.h"
|
||||
#import "TSMessageAdapter.h"
|
||||
#import "UIFont+OWS.h"
|
||||
#import "tgmath.h" // generic math allows fmax to handle CGFLoat correctly on 32 & 64bit.
|
||||
#import <JSQMessagesViewController/JSQMessagesCollectionViewFlowLayout.h>
|
||||
|
||||
|
@ -41,8 +42,14 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
atIndexPath:(NSIndexPath *)indexPath
|
||||
withLayout:(JSQMessagesCollectionViewFlowLayout *)layout
|
||||
{
|
||||
CGSize size;
|
||||
if ([messageData isKindOfClass:[TSMessageAdapter class]]) {
|
||||
TSMessageAdapter *message = (TSMessageAdapter *)messageData;
|
||||
if (message.messageType == TSInfoMessageAdapter || message.messageType == TSErrorMessageAdapter) {
|
||||
return [self messageBubbleSizeForInfoMessageData:messageData atIndexPath:indexPath withLayout:layout];
|
||||
}
|
||||
}
|
||||
|
||||
CGSize size;
|
||||
// BEGIN HACK iOS10EmojiBug see: https://github.com/WhisperSystems/Signal-iOS/issues/1368
|
||||
BOOL isIOS10OrGreater =
|
||||
[[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){.majorVersion = 10 }];
|
||||
|
@ -55,22 +62,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
}
|
||||
// END HACK iOS10EmojiBug see: https://github.com/WhisperSystems/Signal-iOS/issues/1368
|
||||
|
||||
if ([messageData isKindOfClass:[TSMessageAdapter class]]) {
|
||||
TSMessageAdapter *message = (TSMessageAdapter *)messageData;
|
||||
|
||||
|
||||
if (message.messageType == TSInfoMessageAdapter || message.messageType == TSErrorMessageAdapter) {
|
||||
// DDLogVerbose(@"[OWSMessagesBubblesSizeCalculator] superSize.height:%f, superSize.width:%f",
|
||||
// superSize.height,
|
||||
// superSize.width);
|
||||
|
||||
// header icon hangs ouside of the frame a bit.
|
||||
CGFloat headerIconProtrusion = 30.0f; // too much padding with normal font.
|
||||
// CGFloat headerIconProtrusion = 18.0f; // clips
|
||||
size.height += headerIconProtrusion;
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
@ -173,6 +166,83 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return finalSize;
|
||||
}
|
||||
|
||||
|
||||
- (CGSize)messageBubbleSizeForInfoMessageData:(id<JSQMessageData>)messageData
|
||||
atIndexPath:(NSIndexPath *)indexPath
|
||||
withLayout:(JSQMessagesCollectionViewFlowLayout *)layout
|
||||
{
|
||||
NSValue *cachedSize = [self.cache objectForKey:@([messageData messageHash])];
|
||||
if (cachedSize != nil) {
|
||||
return [cachedSize CGSizeValue];
|
||||
}
|
||||
|
||||
CGSize finalSize = CGSizeZero;
|
||||
|
||||
if ([messageData isMediaMessage]) {
|
||||
finalSize = [[messageData media] mediaViewDisplaySize];
|
||||
} else {
|
||||
///////////////////
|
||||
// BEGIN InfoMessage sizing HACK
|
||||
// Braindead, and painstakingly produced.
|
||||
// If you want to change, check for clipping / excess space on 1, 2, and 3 line messages with short and long
|
||||
// words very near the edge.
|
||||
|
||||
// CGSize avatarSize = [self jsq_avatarSizeForMessageData:messageData withLayout:layout];
|
||||
// // from the cell xibs, there is a 2 point space between avatar and bubble
|
||||
// CGFloat spacingBetweenAvatarAndBubble = 2.0f;
|
||||
// CGFloat horizontalContainerInsets = layout.messageBubbleTextViewTextContainerInsets.left + layout.messageBubbleTextViewTextContainerInsets.right;
|
||||
// CGFloat horizontalFrameInsets = layout.messageBubbleTextViewFrameInsets.left + layout.messageBubbleTextViewFrameInsets.right;
|
||||
// CGFloat horizontalInsetsTotal = horizontalContainerInsets + horizontalFrameInsets + spacingBetweenAvatarAndBubble;
|
||||
// CGFloat maximumTextWidth = [self textBubbleWidthForLayout:layout] - avatarSize.width - layout.messageBubbleLeftRightMargin - horizontalInsetsTotal;
|
||||
|
||||
// The full layout width, less the textView margins from xib.
|
||||
// CGFloat horizontalInsetsTotal = 12.0; cropped 3rd line
|
||||
CGFloat horizontalInsetsTotal = 50.0;
|
||||
CGFloat maximumTextWidth = [self textBubbleWidthForLayout:layout] - horizontalInsetsTotal;
|
||||
|
||||
CGRect stringRect = [[messageData text]
|
||||
boundingRectWithSize:CGSizeMake(maximumTextWidth, CGFLOAT_MAX)
|
||||
options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
|
||||
attributes:@{
|
||||
NSFontAttributeName : [UIFont ows_dynamicTypeBodyFont]
|
||||
} // Hack to use a slightly larger than actual font, because I'm seeing messages with higher line count get clipped.
|
||||
context:nil];
|
||||
// END InfoMessage sizing HACK
|
||||
////////////////////
|
||||
|
||||
CGSize stringSize = CGRectIntegral(stringRect).size;
|
||||
|
||||
CGFloat verticalContainerInsets = layout.messageBubbleTextViewTextContainerInsets.top
|
||||
+ layout.messageBubbleTextViewTextContainerInsets.bottom;
|
||||
|
||||
CGFloat verticalFrameInsets
|
||||
= layout.messageBubbleTextViewFrameInsets.top + layout.messageBubbleTextViewFrameInsets.bottom;
|
||||
///////////////////
|
||||
// BEGIN InfoMessage sizing HACK
|
||||
|
||||
CGFloat topIconPortrusion = 28;
|
||||
|
||||
verticalFrameInsets += topIconPortrusion;
|
||||
|
||||
// END InfoMessage sizing HACK
|
||||
///////////////////
|
||||
|
||||
// add extra 2 points of space (`self.additionalInset`), because `boundingRectWithSize:` is slightly off
|
||||
// not sure why. magix. (shrug) if you know, submit a PR
|
||||
CGFloat verticalInsets = verticalContainerInsets + verticalFrameInsets + self.additionalInset;
|
||||
|
||||
// same as above, an extra 2 points of magix
|
||||
CGFloat finalWidth
|
||||
= MAX(stringSize.width + horizontalInsetsTotal, self.minimumBubbleWidth) + self.additionalInset;
|
||||
|
||||
finalSize = CGSizeMake(finalWidth, stringSize.height + verticalInsets);
|
||||
}
|
||||
|
||||
[self.cache setObject:[NSValue valueWithCGSize:finalSize] forKey:@([messageData messageHash])];
|
||||
|
||||
return finalSize;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -158,6 +158,8 @@
|
|||
return UIDeviceFamilyUnknown;
|
||||
}
|
||||
|
||||
// FIXME this is probably broken for new iPhones =(
|
||||
// Who could have guessed that there would ever be a new iPhone model?
|
||||
- (BOOL)isiPhoneVersionSixOrMore {
|
||||
return
|
||||
[[self modelIdentifier] isEqualToString:@"iPhone7,1"] || [[self modelIdentifier] isEqualToString:@"iPhone7,2"];
|
||||
|
|
|
@ -25,5 +25,6 @@
|
|||
|
||||
+ (UIFont *)ows_dynamicTypeBodyFont;
|
||||
+ (UIFont *)ows_dynamicTypeTitle2Font;
|
||||
+ (UIFont *)ows_infoMessageFont;
|
||||
|
||||
@end
|
||||
|
|
|
@ -37,6 +37,11 @@
|
|||
return [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
|
||||
}
|
||||
|
||||
+ (UIFont *)ows_infoMessageFont
|
||||
{
|
||||
return [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline];
|
||||
}
|
||||
|
||||
+ (UIFont *)ows_dynamicTypeTitle2Font {
|
||||
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(_iOS_9)) {
|
||||
return [UIFont preferredFontForTextStyle:UIFontTextStyleTitle2];
|
||||
|
|
|
@ -110,6 +110,8 @@ typedef enum : NSUInteger {
|
|||
@property (nonatomic, strong) UILabel *navbarTitleLabel;
|
||||
@property (nonatomic, retain) UIButton *attachButton;
|
||||
|
||||
@property (nonatomic) CGFloat previousCollectionViewFrameWidth;
|
||||
|
||||
@property NSUInteger page;
|
||||
@property (nonatomic) BOOL composeOnOpen;
|
||||
@property (nonatomic) BOOL peek;
|
||||
|
@ -215,12 +217,6 @@ typedef enum : NSUInteger {
|
|||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
// JSQMVC width is 375px at this point (as specified by the xib), but this causes
|
||||
// our initial bubble calculations to be off since they happen before the containing
|
||||
// view is layed out. https://github.com/jessesquires/JSQMessagesViewController/issues/1257
|
||||
// Resetting here makes sure we've got a good initial width.
|
||||
[self resetFrame];
|
||||
|
||||
[self.navigationController.navigationBar setTranslucent:NO];
|
||||
|
||||
self.messageAdapterCache = [[NSCache alloc] init];
|
||||
|
@ -251,6 +247,23 @@ typedef enum : NSUInteger {
|
|||
[self initializeToolbars];
|
||||
}
|
||||
|
||||
- (void)viewDidLayoutSubviews
|
||||
{
|
||||
[super viewDidLayoutSubviews];
|
||||
|
||||
// JSQMVC width is initially 375px on iphone6/ios9 (as specified by the xib), which causes
|
||||
// our initial bubble calculations to be off since they happen before the containing
|
||||
// view is layed out. https://github.com/jessesquires/JSQMessagesViewController/issues/1257
|
||||
if (CGRectGetWidth(self.collectionView.frame) != self.previousCollectionViewFrameWidth) {
|
||||
// save frame value from next comparison
|
||||
self.previousCollectionViewFrameWidth = CGRectGetWidth(self.collectionView.frame);
|
||||
|
||||
// invalidate layout
|
||||
[self.collectionView.collectionViewLayout
|
||||
invalidateLayoutWithContext:[JSQMessagesCollectionViewFlowLayoutInvalidationContext context]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)didMoveToParentViewController:(UIViewController *)parent
|
||||
{
|
||||
[self setupTitleLabelGestureRecognizer];
|
||||
|
@ -619,7 +632,7 @@ typedef enum : NSUInteger {
|
|||
message = [[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:self.thread
|
||||
messageBody:text
|
||||
attachmentIds:@[]
|
||||
attachmentIds:[NSMutableArray new]
|
||||
expiresInSeconds:configuration.durationSeconds];
|
||||
} else {
|
||||
message = [[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
|
@ -831,6 +844,7 @@ typedef enum : NSUInteger {
|
|||
forIndexPath:indexPath];
|
||||
messageCell.layer.shouldRasterize = YES;
|
||||
messageCell.layer.rasterizationScale = [UIScreen mainScreen].scale;
|
||||
messageCell.textView.textColor = [UIColor darkGrayColor];
|
||||
messageCell.cellTopLabel.attributedText = [self.collectionView.dataSource collectionView:self.collectionView attributedTextForCellTopLabelAtIndexPath:indexPath];
|
||||
|
||||
return messageCell;
|
||||
|
@ -846,7 +860,7 @@ typedef enum : NSUInteger {
|
|||
[OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:self.thread.uniqueId];
|
||||
[self setBarButtonItemsForDisappearingMessagesConfiguration:configuration];
|
||||
|
||||
infoCell.cellLabel.text = [infoMessage text];
|
||||
infoCell.textView.text = [infoMessage text];
|
||||
infoCell.messageBubbleContainerView.layer.borderColor = [[UIColor ows_infoMessageBorderColor] CGColor];
|
||||
infoCell.headerImageView.image = [UIImage imageNamed:@"warning_white"];
|
||||
|
||||
|
@ -857,7 +871,7 @@ typedef enum : NSUInteger {
|
|||
atIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
OWSDisplayedMessageCollectionViewCell *errorCell = [self loadDisplayedMessageCollectionViewCellForIndexPath:indexPath];
|
||||
errorCell.cellLabel.text = [errorMessage text];
|
||||
errorCell.textView.text = [errorMessage text];
|
||||
errorCell.messageBubbleContainerView.layer.borderColor = [[UIColor ows_errorMessageBorderColor] CGColor];
|
||||
errorCell.headerImageView.image = [UIImage imageNamed:@"error_white"];
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ extern const CGFloat OWSDisplayedMessageCellMinimumHeight;
|
|||
|
||||
@interface OWSDisplayedMessageCollectionViewCell : JSQMessagesCollectionViewCell
|
||||
|
||||
@property (weak, nonatomic, readonly) JSQMessagesLabel *cellLabel;
|
||||
@property (weak, nonatomic, readonly) UIImageView *headerImageView;
|
||||
|
||||
@end
|
||||
|
|
|
@ -3,14 +3,13 @@
|
|||
// Portions Copyright (c) 2016 Open Whisper Systems. All rights reserved.
|
||||
|
||||
#import "OWSDisplayedMessageCollectionViewCell.h"
|
||||
|
||||
#import "UIFont+OWS.h"
|
||||
#import <JSQMessagesViewController/UIView+JSQMessages.h>
|
||||
|
||||
const CGFloat OWSDisplayedMessageCellMinimumHeight = 70.0;
|
||||
|
||||
@interface OWSDisplayedMessageCollectionViewCell ()
|
||||
|
||||
@property (weak, nonatomic) IBOutlet JSQMessagesLabel *cellLabel;
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *cellTopLabelHeightConstraint;
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *headerImageView;
|
||||
|
||||
|
@ -43,7 +42,8 @@ const CGFloat OWSDisplayedMessageCellMinimumHeight = 70.0;
|
|||
self.messageBubbleContainerView.layer.borderColor = [[UIColor lightGrayColor] CGColor];
|
||||
self.messageBubbleContainerView.layer.borderWidth = 0.75f;
|
||||
self.messageBubbleContainerView.layer.cornerRadius = 5.0f;
|
||||
self.cellLabel.textColor = [UIColor darkGrayColor];
|
||||
self.textView.font = [UIFont ows_infoMessageFont];
|
||||
self.textView.textColor = [UIColor darkGrayColor];
|
||||
}
|
||||
|
||||
#pragma mark - Collection view cell
|
||||
|
@ -52,7 +52,7 @@ const CGFloat OWSDisplayedMessageCellMinimumHeight = 70.0;
|
|||
{
|
||||
[super prepareForReuse];
|
||||
|
||||
self.cellLabel.text = nil;
|
||||
self.textView.text = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -27,21 +27,18 @@
|
|||
</label>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="qCf-bs-dBd" userLabel="Bubble container">
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Info Message" textAlignment="center" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="OVa-Xw-5vl" customClass="JSQMessagesLabel">
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="14" id="fed-2c-dqd"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" text="Lorem ipsum dolor sit er elit lamet" textAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="gbd-vF-h3e" customClass="JSQMessagesCellTextView">
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleSubhead"/>
|
||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
||||
</textView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="OVa-Xw-5vl" firstAttribute="leading" secondItem="qCf-bs-dBd" secondAttribute="leading" constant="8" id="2IE-8k-czI"/>
|
||||
<constraint firstAttribute="bottom" secondItem="OVa-Xw-5vl" secondAttribute="bottom" constant="8" id="MtI-jW-t1x"/>
|
||||
<constraint firstAttribute="trailing" secondItem="OVa-Xw-5vl" secondAttribute="trailing" constant="8" id="Y8z-8G-PLt"/>
|
||||
<constraint firstItem="OVa-Xw-5vl" firstAttribute="top" secondItem="qCf-bs-dBd" secondAttribute="top" constant="12" id="v5B-tB-pOB"/>
|
||||
<constraint firstAttribute="trailing" secondItem="gbd-vF-h3e" secondAttribute="trailing" constant="6" id="WME-2Q-rFT"/>
|
||||
<constraint firstItem="gbd-vF-h3e" firstAttribute="top" secondItem="qCf-bs-dBd" secondAttribute="top" constant="6" id="Zee-be-E6m"/>
|
||||
<constraint firstAttribute="bottom" secondItem="gbd-vF-h3e" secondAttribute="bottom" id="aCy-5N-gI4"/>
|
||||
<constraint firstItem="gbd-vF-h3e" firstAttribute="leading" secondItem="qCf-bs-dBd" secondAttribute="leading" constant="6" id="wL5-SN-GFl"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="warning_white.png" translatesAutoresizingMaskIntoConstraints="NO" id="ePO-Cy-jUE">
|
||||
|
@ -65,11 +62,11 @@
|
|||
</constraints>
|
||||
<size key="customSize" width="320" height="55"/>
|
||||
<connections>
|
||||
<outlet property="cellLabel" destination="OVa-Xw-5vl" id="7PC-oj-dQZ"/>
|
||||
<outlet property="cellTopLabel" destination="gcR-Rk-KDC" id="Ogk-hD-ge8"/>
|
||||
<outlet property="cellTopLabelHeightConstraint" destination="ckj-xD-FJI" id="wBH-pQ-Wc7"/>
|
||||
<outlet property="headerImageView" destination="ePO-Cy-jUE" id="4uq-2C-V7U"/>
|
||||
<outlet property="messageBubbleContainerView" destination="qCf-bs-dBd" id="WMx-Di-LZG"/>
|
||||
<outlet property="textView" destination="gbd-vF-h3e" id="Ynt-WC-VrK"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="219" y="433"/>
|
||||
</collectionViewCell>
|
||||
|
|
Loading…
Reference in a new issue