session-ios/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageFooterView.m
2018-07-02 15:27:24 -04:00

190 lines
5.7 KiB
Objective-C

//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import "OWSMessageFooterView.h"
#import "DateUtil.h"
#import "Signal-Swift.h"
#import <QuartzCore/QuartzCore.h>
NS_ASSUME_NONNULL_BEGIN
@interface OWSMessageFooterView ()
@property (nonatomic) UILabel *timestampLabel;
@property (nonatomic) UIImageView *statusIndicatorImageView;
@end
@implementation OWSMessageFooterView
// `[UIView init]` invokes `[self initWithFrame:...]`.
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
[self commontInit];
}
return self;
}
- (void)commontInit
{
// Ensure only called once.
OWSAssert(!self.timestampLabel);
self.layoutMargins = UIEdgeInsetsZero;
self.axis = UILayoutConstraintAxisHorizontal;
self.spacing = self.hSpacing;
self.alignment = UIStackViewAlignmentCenter;
self.timestampLabel = [UILabel new];
[self addArrangedSubview:self.timestampLabel];
self.statusIndicatorImageView = [UIImageView new];
[self.statusIndicatorImageView setContentHuggingHigh];
[self addArrangedSubview:self.statusIndicatorImageView];
}
- (void)configureFonts
{
self.timestampLabel.font = UIFont.ows_dynamicTypeCaption1Font;
}
- (CGFloat)hSpacing
{
// TODO: Review constant.
return 8.f;
}
- (CGFloat)maxImageWidth
{
return 18.f;
}
- (CGFloat)imageHeight
{
return 12.f;
}
#pragma mark - Load
- (void)configureWithConversationViewItem:(ConversationViewItem *)viewItem isOverlayingMedia:(BOOL)isOverlayingMedia
{
OWSAssert(viewItem);
[self configureLabelsWithConversationViewItem:viewItem];
UIColor *textColor;
if (isOverlayingMedia) {
textColor = [UIColor whiteColor];
} else if (viewItem.interaction.interactionType == OWSInteractionType_IncomingMessage) {
textColor = [UIColor colorWithWhite:1.f alpha:0.7f];
} else {
textColor = [UIColor ows_light60Color];
}
self.timestampLabel.textColor = textColor;
if (viewItem.interaction.interactionType == OWSInteractionType_OutgoingMessage) {
TSOutgoingMessage *outgoingMessage = (TSOutgoingMessage *)viewItem.interaction;
UIImage *_Nullable statusIndicatorImage = nil;
MessageReceiptStatus messageStatus =
[MessageRecipientStatusUtils recipientStatusWithOutgoingMessage:outgoingMessage];
switch (messageStatus) {
case MessageReceiptStatusUploading:
case MessageReceiptStatusSending:
statusIndicatorImage = [UIImage imageNamed:@"message_status_sending"];
[self animateSpinningIcon];
break;
case MessageReceiptStatusSent:
case MessageReceiptStatusSkipped:
statusIndicatorImage = [UIImage imageNamed:@"message_status_sent"];
break;
case MessageReceiptStatusDelivered:
case MessageReceiptStatusRead:
statusIndicatorImage = [UIImage imageNamed:@"message_status_delivered"];
break;
case MessageReceiptStatusFailed:
// TODO:
statusIndicatorImage = [UIImage imageNamed:@"message_status_sending"];
break;
}
OWSAssert(statusIndicatorImage);
OWSAssert(statusIndicatorImage.size.width <= self.maxImageWidth);
self.statusIndicatorImageView.image =
[statusIndicatorImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
if (messageStatus == MessageReceiptStatusRead) {
// TODO: Tint the icon with the conversation color.
self.statusIndicatorImageView.tintColor = textColor;
} else {
self.statusIndicatorImageView.tintColor = textColor;
}
self.statusIndicatorImageView.hidden = NO;
} else {
self.statusIndicatorImageView.image = nil;
self.statusIndicatorImageView.hidden = YES;
}
}
- (void)animateSpinningIcon
{
CABasicAnimation *animation;
animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
animation.toValue = @(M_PI * 2.0);
const CGFloat kPeriodSeconds = 1.f;
animation.duration = kPeriodSeconds;
animation.cumulative = YES;
animation.repeatCount = HUGE_VALF;
[self.statusIndicatorImageView.layer addAnimation:animation forKey:@"animation"];
}
- (void)configureLabelsWithConversationViewItem:(ConversationViewItem *)viewItem
{
OWSAssert(viewItem);
[self configureFonts];
self.timestampLabel.text = [DateUtil formatTimestampShort:viewItem.interaction.timestamp];
}
- (CGSize)measureWithConversationViewItem:(ConversationViewItem *)viewItem
{
OWSAssert(viewItem);
[self configureLabelsWithConversationViewItem:viewItem];
CGSize result = CGSizeZero;
result.height = MAX(self.timestampLabel.font.lineHeight, self.imageHeight);
if (viewItem.interaction.interactionType == OWSInteractionType_OutgoingMessage) {
result.width = ([self.timestampLabel sizeThatFits:CGSizeZero].width + self.maxImageWidth + self.hSpacing);
} else {
result.width = [self.timestampLabel sizeThatFits:CGSizeZero].width;
}
return CGSizeCeil(result);
}
- (nullable NSString *)messageStatusTextForConversationViewItem:(ConversationViewItem *)viewItem
{
OWSAssert(viewItem);
if (viewItem.interaction.interactionType != OWSInteractionType_OutgoingMessage) {
return nil;
}
TSOutgoingMessage *outgoingMessage = (TSOutgoingMessage *)viewItem.interaction;
NSString *statusMessage = [MessageRecipientStatusUtils receiptMessageWithOutgoingMessage:outgoingMessage];
return statusMessage;
}
- (void)prepareForReuse
{
[self.statusIndicatorImageView.layer removeAllAnimations];
}
@end
NS_ASSUME_NONNULL_END