mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
Rework appearance of the unread indicator.
// FREEBIE
This commit is contained in:
parent
1bbae071f1
commit
dab8ddb37d
2 changed files with 123 additions and 43 deletions
|
@ -59,6 +59,7 @@
|
||||||
#import <JSQMessagesViewController/JSQMessagesBubbleImage.h>
|
#import <JSQMessagesViewController/JSQMessagesBubbleImage.h>
|
||||||
#import <JSQMessagesViewController/JSQMessagesBubbleImageFactory.h>
|
#import <JSQMessagesViewController/JSQMessagesBubbleImageFactory.h>
|
||||||
#import <JSQMessagesViewController/JSQMessagesCollectionViewFlowLayoutInvalidationContext.h>
|
#import <JSQMessagesViewController/JSQMessagesCollectionViewFlowLayoutInvalidationContext.h>
|
||||||
|
#import <JSQMessagesViewController/JSQMessagesCollectionViewLayoutAttributes.h>
|
||||||
#import <JSQMessagesViewController/JSQMessagesTimestampFormatter.h>
|
#import <JSQMessagesViewController/JSQMessagesTimestampFormatter.h>
|
||||||
#import <JSQMessagesViewController/JSQSystemSoundPlayer+JSQMessages.h>
|
#import <JSQMessagesViewController/JSQSystemSoundPlayer+JSQMessages.h>
|
||||||
#import <JSQMessagesViewController/UIColor+JSQMessages.h>
|
#import <JSQMessagesViewController/UIColor+JSQMessages.h>
|
||||||
|
@ -109,6 +110,40 @@ typedef enum : NSUInteger {
|
||||||
kMediaTypeVideo,
|
kMediaTypeVideo,
|
||||||
} kMediaTypes;
|
} kMediaTypes;
|
||||||
|
|
||||||
|
@protocol OWSMessagesCollectionViewFlowLayoutDelegate <NSObject>
|
||||||
|
|
||||||
|
- (BOOL)isSpecialItemAtIndexPath:(NSIndexPath *)indexPath;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
|
@interface OWSMessagesCollectionViewFlowLayout : JSQMessagesCollectionViewFlowLayout
|
||||||
|
|
||||||
|
@property (nonatomic, weak) id<OWSMessagesCollectionViewFlowLayoutDelegate> delegate;
|
||||||
|
|
||||||
|
@property (nonatomic) CGRect lastBounds;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
|
@implementation OWSMessagesCollectionViewFlowLayout
|
||||||
|
|
||||||
|
- (CGSize)sizeForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||||
|
{
|
||||||
|
// The unread indicator should be sized according to its desired size.
|
||||||
|
if ([self.delegate isSpecialItemAtIndexPath:indexPath]) {
|
||||||
|
CGSize messageBubbleSize = [self messageBubbleSizeForItemAtIndexPath:indexPath];
|
||||||
|
CGFloat finalHeight = messageBubbleSize.height;
|
||||||
|
return CGSizeMake(CGRectGetWidth(self.collectionView.frame), ceilf((float)finalHeight));
|
||||||
|
} else {
|
||||||
|
return [super sizeForItemAtIndexPath:indexPath];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
|
|
||||||
@interface MessagesViewController () <AVAudioPlayerDelegate,
|
@interface MessagesViewController () <AVAudioPlayerDelegate,
|
||||||
|
@ -117,6 +152,7 @@ typedef enum : NSUInteger {
|
||||||
CNContactViewControllerDelegate,
|
CNContactViewControllerDelegate,
|
||||||
JSQMessagesComposerTextViewPasteDelegate,
|
JSQMessagesComposerTextViewPasteDelegate,
|
||||||
OWSConversationSettingsViewDelegate,
|
OWSConversationSettingsViewDelegate,
|
||||||
|
OWSMessagesCollectionViewFlowLayoutDelegate,
|
||||||
OWSTextViewPasteDelegate,
|
OWSTextViewPasteDelegate,
|
||||||
OWSVoiceMemoGestureDelegate,
|
OWSVoiceMemoGestureDelegate,
|
||||||
UIDocumentMenuDelegate,
|
UIDocumentMenuDelegate,
|
||||||
|
@ -1097,6 +1133,9 @@ typedef enum : NSUInteger {
|
||||||
self.view.frame = viewFrame;
|
self.view.frame = viewFrame;
|
||||||
self.collectionView.frame = viewFrame;
|
self.collectionView.frame = viewFrame;
|
||||||
|
|
||||||
|
OWSMessagesCollectionViewFlowLayout *layout = [OWSMessagesCollectionViewFlowLayout new];
|
||||||
|
layout.delegate = self;
|
||||||
|
self.collectionView.collectionViewLayout = layout;
|
||||||
[self.collectionView.collectionViewLayout setMessageBubbleFont:[UIFont ows_dynamicTypeBodyFont]];
|
[self.collectionView.collectionViewLayout setMessageBubbleFont:[UIFont ows_dynamicTypeBodyFont]];
|
||||||
|
|
||||||
self.collectionView.showsVerticalScrollIndicator = NO;
|
self.collectionView.showsVerticalScrollIndicator = NO;
|
||||||
|
@ -3867,6 +3906,14 @@ typedef enum : NSUInteger {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - OWSMessagesCollectionViewFlowLayoutDelegate
|
||||||
|
|
||||||
|
- (BOOL)isSpecialItemAtIndexPath:(NSIndexPath *)indexPath
|
||||||
|
{
|
||||||
|
TSInteraction *interaction = [self interactionAtIndexPath:indexPath];
|
||||||
|
return [interaction isKindOfClass:[TSUnreadIndicatorInteraction class]];
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - Class methods
|
#pragma mark - Class methods
|
||||||
|
|
||||||
+ (UINib *)nib
|
+ (UINib *)nib
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
#import "OWSUnreadIndicatorCell.h"
|
#import "OWSUnreadIndicatorCell.h"
|
||||||
#import "NSBundle+JSQMessages.h"
|
#import "NSBundle+JSQMessages.h"
|
||||||
#import "OWSBezierPathView.h"
|
|
||||||
#import "TSUnreadIndicatorInteraction.h"
|
#import "TSUnreadIndicatorInteraction.h"
|
||||||
#import "UIColor+OWS.h"
|
#import "UIColor+OWS.h"
|
||||||
#import "UIFont+OWS.h"
|
#import "UIFont+OWS.h"
|
||||||
|
@ -13,10 +12,12 @@
|
||||||
|
|
||||||
@interface OWSUnreadIndicatorCell ()
|
@interface OWSUnreadIndicatorCell ()
|
||||||
|
|
||||||
|
@property (nonatomic) UIView *titleBackgroundView;
|
||||||
|
@property (nonatomic) UIView *titleTopHighlightView;
|
||||||
|
@property (nonatomic) UIView *titleBottomHighlightView;
|
||||||
|
@property (nonatomic) UIView *titlePillView;
|
||||||
@property (nonatomic) UILabel *titleLabel;
|
@property (nonatomic) UILabel *titleLabel;
|
||||||
@property (nonatomic) UILabel *subtitleLabel;
|
@property (nonatomic) UILabel *subtitleLabel;
|
||||||
@property (nonatomic) OWSBezierPathView *leftPathView;
|
|
||||||
@property (nonatomic) OWSBezierPathView *rightPathView;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@ -34,11 +35,27 @@
|
||||||
self.backgroundColor = [UIColor whiteColor];
|
self.backgroundColor = [UIColor whiteColor];
|
||||||
|
|
||||||
if (!self.titleLabel) {
|
if (!self.titleLabel) {
|
||||||
|
self.titleBackgroundView = [UIView new];
|
||||||
|
self.titleBackgroundView.backgroundColor = [UIColor colorWithRGBHex:0xe2e2e2];
|
||||||
|
[self.contentView addSubview:self.titleBackgroundView];
|
||||||
|
|
||||||
|
self.titleTopHighlightView = [UIView new];
|
||||||
|
self.titleTopHighlightView.backgroundColor = [UIColor whiteColor];
|
||||||
|
[self.titleBackgroundView addSubview:self.titleTopHighlightView];
|
||||||
|
|
||||||
|
self.titleBottomHighlightView = [UIView new];
|
||||||
|
self.titleBottomHighlightView.backgroundColor = [UIColor colorWithRGBHex:0xd1d1d1];
|
||||||
|
[self.titleBackgroundView addSubview:self.titleBottomHighlightView];
|
||||||
|
|
||||||
|
self.titlePillView = [UIView new];
|
||||||
|
self.titlePillView.backgroundColor = [UIColor whiteColor];
|
||||||
|
[self.titleBackgroundView addSubview:self.titlePillView];
|
||||||
|
|
||||||
self.titleLabel = [UILabel new];
|
self.titleLabel = [UILabel new];
|
||||||
self.titleLabel.text = [OWSUnreadIndicatorCell titleForInteraction:self.interaction];
|
self.titleLabel.text = [OWSUnreadIndicatorCell titleForInteraction:self.interaction];
|
||||||
self.titleLabel.textColor = [UIColor ows_infoMessageBorderColor];
|
self.titleLabel.textColor = [UIColor blackColor];
|
||||||
self.titleLabel.font = [OWSUnreadIndicatorCell textFont];
|
self.titleLabel.font = [OWSUnreadIndicatorCell textFont];
|
||||||
[self.contentView addSubview:self.titleLabel];
|
[self.titlePillView addSubview:self.titleLabel];
|
||||||
|
|
||||||
self.subtitleLabel = [UILabel new];
|
self.subtitleLabel = [UILabel new];
|
||||||
self.subtitleLabel.text = [OWSUnreadIndicatorCell subtitleForInteraction:self.interaction];
|
self.subtitleLabel.text = [OWSUnreadIndicatorCell subtitleForInteraction:self.interaction];
|
||||||
|
@ -48,27 +65,6 @@
|
||||||
self.subtitleLabel.lineBreakMode = NSLineBreakByWordWrapping;
|
self.subtitleLabel.lineBreakMode = NSLineBreakByWordWrapping;
|
||||||
self.subtitleLabel.textAlignment = NSTextAlignmentCenter;
|
self.subtitleLabel.textAlignment = NSTextAlignmentCenter;
|
||||||
[self.contentView addSubview:self.subtitleLabel];
|
[self.contentView addSubview:self.subtitleLabel];
|
||||||
|
|
||||||
CGFloat kLineThickness = 0.5f;
|
|
||||||
CGFloat kLineMargin = 5.f;
|
|
||||||
ConfigureShapeLayerBlock configureShapeLayerBlock = ^(CAShapeLayer *layer, CGRect bounds) {
|
|
||||||
OWSCAssert(layer);
|
|
||||||
|
|
||||||
CGRect pathBounds
|
|
||||||
= CGRectMake(0, (bounds.size.height - kLineThickness) * 0.5f, bounds.size.width, kLineThickness);
|
|
||||||
pathBounds = CGRectInset(pathBounds, kLineMargin, 0);
|
|
||||||
UIBezierPath *path = [UIBezierPath bezierPathWithRect:pathBounds];
|
|
||||||
layer.path = path.CGPath;
|
|
||||||
layer.fillColor = [[UIColor ows_infoMessageBorderColor] colorWithAlphaComponent:0.5f].CGColor;
|
|
||||||
};
|
|
||||||
|
|
||||||
self.leftPathView = [OWSBezierPathView new];
|
|
||||||
self.leftPathView.configureShapeLayerBlock = configureShapeLayerBlock;
|
|
||||||
[self.contentView addSubview:self.leftPathView];
|
|
||||||
|
|
||||||
self.rightPathView = [OWSBezierPathView new];
|
|
||||||
self.rightPathView.configureShapeLayerBlock = configureShapeLayerBlock;
|
|
||||||
[self.contentView addSubview:self.rightPathView];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,7 +106,27 @@
|
||||||
return 3.f;
|
return 3.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CGFloat)vMargin
|
+ (CGFloat)titleInnerHMargin
|
||||||
|
{
|
||||||
|
return 10.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CGFloat)titleInnerVMargin
|
||||||
|
{
|
||||||
|
return 5.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CGFloat)titleOuterVMargin
|
||||||
|
{
|
||||||
|
return 5.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CGFloat)topVMargin
|
||||||
|
{
|
||||||
|
return 5.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (CGFloat)bottomVMargin
|
||||||
{
|
{
|
||||||
return 5.f;
|
return 5.f;
|
||||||
}
|
}
|
||||||
|
@ -120,35 +136,52 @@
|
||||||
[super layoutSubviews];
|
[super layoutSubviews];
|
||||||
|
|
||||||
[self.titleLabel sizeToFit];
|
[self.titleLabel sizeToFit];
|
||||||
if (self.subtitleLabel.text.length < 1) {
|
|
||||||
[self.titleLabel centerOnSuperview];
|
// It's a bit of a hack, but we use a view that extends _outside_ the cell's bounds
|
||||||
} else {
|
// to draw its background, since we want the background to extend to the edges of the
|
||||||
|
// collection view.
|
||||||
|
//
|
||||||
|
// This layout logic assumes that the cell insets are symmetrical and can be deduced
|
||||||
|
// from the cell frame.
|
||||||
|
CGRect titleBackgroundViewFrame = CGRectMake(-self.left,
|
||||||
|
OWSUnreadIndicatorCell.topVMargin,
|
||||||
|
self.width + self.left * 2.f,
|
||||||
|
self.titleLabel.height + OWSUnreadIndicatorCell.titleInnerVMargin * 2.f
|
||||||
|
+ OWSUnreadIndicatorCell.titleOuterVMargin * 2.f);
|
||||||
|
self.titleBackgroundView.frame = [self convertRect:titleBackgroundViewFrame toView:self.contentView];
|
||||||
|
|
||||||
|
self.titleTopHighlightView.frame = CGRectMake(0, 0, self.titleBackgroundView.width, 1.f);
|
||||||
|
self.titleBottomHighlightView.frame
|
||||||
|
= CGRectMake(0, self.titleBackgroundView.height - 1.f, self.titleBackgroundView.width, 1.f);
|
||||||
|
|
||||||
|
self.titlePillView.frame = CGRectMake(0,
|
||||||
|
0,
|
||||||
|
self.titleLabel.width + OWSUnreadIndicatorCell.titleInnerHMargin * 2.f,
|
||||||
|
self.titleLabel.height + OWSUnreadIndicatorCell.titleInnerVMargin * 2.f);
|
||||||
|
self.titlePillView.layer.cornerRadius = self.titlePillView.height * 0.5f;
|
||||||
|
[self.titlePillView centerOnSuperview];
|
||||||
|
|
||||||
|
[self.titleLabel centerOnSuperview];
|
||||||
|
|
||||||
|
if (self.subtitleLabel.text.length > 0) {
|
||||||
CGSize subtitleSize = [self.subtitleLabel
|
CGSize subtitleSize = [self.subtitleLabel
|
||||||
sizeThatFits:CGSizeMake(
|
sizeThatFits:CGSizeMake(
|
||||||
self.contentView.width - [OWSUnreadIndicatorCell subtitleHMargin] * 2.f, CGFLOAT_MAX)];
|
self.contentView.width - [OWSUnreadIndicatorCell subtitleHMargin] * 2.f, CGFLOAT_MAX)];
|
||||||
CGFloat contentHeight
|
|
||||||
= ceil(self.titleLabel.height) + OWSUnreadIndicatorCell.subtitleVSpacing + ceil(subtitleSize.height);
|
|
||||||
|
|
||||||
self.titleLabel.frame = CGRectMake(round((self.titleLabel.superview.width - self.titleLabel.width) * 0.5f),
|
|
||||||
round((self.titleLabel.superview.height - contentHeight) * 0.5f),
|
|
||||||
ceil(self.titleLabel.width),
|
|
||||||
ceil(self.titleLabel.height));
|
|
||||||
self.subtitleLabel.frame = CGRectMake(round((self.titleLabel.superview.width - subtitleSize.width) * 0.5f),
|
self.subtitleLabel.frame = CGRectMake(round((self.titleLabel.superview.width - subtitleSize.width) * 0.5f),
|
||||||
round(self.titleLabel.bottom + OWSUnreadIndicatorCell.subtitleVSpacing),
|
round(self.titleBackgroundView.bottom + OWSUnreadIndicatorCell.subtitleVSpacing),
|
||||||
ceil(subtitleSize.width),
|
ceil(subtitleSize.width),
|
||||||
ceil(subtitleSize.height));
|
ceil(subtitleSize.height));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.leftPathView.frame = CGRectMake(0, self.titleLabel.top, self.titleLabel.left, self.titleLabel.height);
|
|
||||||
self.rightPathView.frame = CGRectMake(
|
|
||||||
self.titleLabel.right, self.titleLabel.top, self.width - self.titleLabel.right, self.titleLabel.height);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CGSize)cellSizeForInteraction:(TSUnreadIndicatorInteraction *)interaction
|
+ (CGSize)cellSizeForInteraction:(TSUnreadIndicatorInteraction *)interaction
|
||||||
collectionViewWidth:(CGFloat)collectionViewWidth
|
collectionViewWidth:(CGFloat)collectionViewWidth
|
||||||
{
|
{
|
||||||
CGSize result = CGSizeMake(collectionViewWidth, 0);
|
CGSize result = CGSizeMake(collectionViewWidth, 0);
|
||||||
result.height += self.vMargin * 2.f;
|
result.height += self.titleInnerVMargin * 2.f;
|
||||||
|
result.height += self.titleOuterVMargin * 2.f;
|
||||||
|
result.height += self.topVMargin;
|
||||||
|
result.height += self.bottomVMargin;
|
||||||
|
|
||||||
NSString *title = [self titleForInteraction:interaction];
|
NSString *title = [self titleForInteraction:interaction];
|
||||||
NSString *subtitle = [self subtitleForInteraction:interaction];
|
NSString *subtitle = [self subtitleForInteraction:interaction];
|
||||||
|
|
Loading…
Reference in a new issue