session-ios/Signal/src/ViewControllers/HomeView/HomeViewCell.m

555 lines
21 KiB
Mathematica
Raw Normal View History

2017-03-09 07:36:09 +01:00
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
2017-03-09 07:36:09 +01:00
//
2014-10-29 21:58:58 +01:00
2018-04-10 19:02:33 +02:00
#import "HomeViewCell.h"
Disappearing Messages * Per thread settings menu accessed by tapping on thread title This removed the toggle-phone behavior. You'll be able to see the phone number in the settings table view. This removed the "add contact" functionality, although it was already broken for ios>=9 (which is basically everybody). The group actions menu was absorbed into this screen * Added a confirm alert to leave group (fixes #938) * New Translation Strings * Extend "Add People" label to fit translations. * resolved issues with translations not fitting in group menu * Fix the long standing type warning where TSCalls were assigned to a TSMessageAdapter. * Can delete info messages Follow the JSQMVC pattern and put UIResponder-able content in the messageBubbleContainer. This gives us more functionality *and* allows us to delete some code. yay! It's still not yet possible to delete phone messages. =( * Fixed some compiler warnings. * xcode8 touching storyboard. So long xcode7! * Fixup multiline info messages. We were seeing info messages like "You set disappearing message timer to 10" instead of "You set disappearing message timer to 10 seconds." Admittedly this isn't a very good fix, as now one liners feel like they have too much padding. If the message is well over one line, we were wrapping properly, but there's a problem when the message is *just barely* two lines, the cell height grows, but the label still thinks it's just one line (as evinced by the one line appearing in the center of the label frame. The result being that the last word of the label is cropped. * Disable group actions after leaving group. // FREEBIE
2016-09-21 14:37:51 +02:00
#import "OWSAvatarBuilder.h"
#import "Signal-Swift.h"
#import <SignalMessaging/OWSFormat.h>
2018-04-11 20:18:09 +02:00
#import <SignalMessaging/OWSMath.h>
#import <SignalMessaging/OWSUserProfile.h>
#import <SignalMessaging/SignalMessaging-Swift.h>
#import <SignalServiceKit/OWSMessageManager.h>
#import <SignalServiceKit/TSContactThread.h>
#import <SignalServiceKit/TSGroupThread.h>
Disappearing Messages * Per thread settings menu accessed by tapping on thread title This removed the toggle-phone behavior. You'll be able to see the phone number in the settings table view. This removed the "add contact" functionality, although it was already broken for ios>=9 (which is basically everybody). The group actions menu was absorbed into this screen * Added a confirm alert to leave group (fixes #938) * New Translation Strings * Extend "Add People" label to fit translations. * resolved issues with translations not fitting in group menu * Fix the long standing type warning where TSCalls were assigned to a TSMessageAdapter. * Can delete info messages Follow the JSQMVC pattern and put UIResponder-able content in the messageBubbleContainer. This gives us more functionality *and* allows us to delete some code. yay! It's still not yet possible to delete phone messages. =( * Fixed some compiler warnings. * xcode8 touching storyboard. So long xcode7! * Fixup multiline info messages. We were seeing info messages like "You set disappearing message timer to 10" instead of "You set disappearing message timer to 10 seconds." Admittedly this isn't a very good fix, as now one liners feel like they have too much padding. If the message is well over one line, we were wrapping properly, but there's a problem when the message is *just barely* two lines, the cell height grows, but the label still thinks it's just one line (as evinced by the one line appearing in the center of the label frame. The result being that the last word of the label is cropped. * Disable group actions after leaving group. // FREEBIE
2016-09-21 14:37:51 +02:00
NS_ASSUME_NONNULL_BEGIN
2018-04-10 19:02:33 +02:00
@interface HomeViewCell ()
@property (nonatomic) AvatarImageView *avatarView;
@property (nonatomic) UILabel *nameLabel;
@property (nonatomic) UILabel *snippetLabel;
@property (nonatomic) UILabel *dateTimeLabel;
@property (nonatomic) MessageStatusView *messageStatusView;
2018-11-01 15:43:13 +01:00
@property (nonatomic) TypingIndicatorView *typingIndicatorView;
@property (nonatomic) UIStackView *previewStackView;
2018-07-09 17:43:46 +02:00
@property (nonatomic) UIView *unreadBadge;
@property (nonatomic) UILabel *unreadLabel;
@property (nonatomic, nullable) ThreadViewModel *thread;
2018-04-10 19:02:33 +02:00
@property (nonatomic, readonly) NSMutableArray<NSLayoutConstraint *> *viewConstraints;
@end
#pragma mark -
2018-04-10 19:02:33 +02:00
@implementation HomeViewCell
2014-10-29 21:58:58 +01:00
#pragma mark - Dependencies
- (OWSContactsManager *)contactsManager
{
OWSAssertDebug(Environment.shared.contactsManager);
return Environment.shared.contactsManager;
}
2018-11-01 15:43:13 +01:00
- (id<OWSTypingIndicators>)typingIndicators
{
return SSKEnvironment.shared.typingIndicators;
}
#pragma mark -
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(nullable NSString *)reuseIdentifier
{
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
[self commontInit];
}
return self;
}
// `[UIView init]` invokes `[self initWithFrame:...]`.
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
[self commontInit];
}
return self;
}
- (void)commontInit
{
OWSAssertDebug(!self.avatarView);
2018-07-13 15:50:49 +02:00
self.backgroundColor = Theme.backgroundColor;
2018-04-10 19:02:33 +02:00
_viewConstraints = [NSMutableArray new];
self.avatarView = [[AvatarImageView alloc] init];
[self.contentView addSubview:self.avatarView];
[self.avatarView autoSetDimension:ALDimensionWidth toSize:self.avatarSize];
[self.avatarView autoSetDimension:ALDimensionHeight toSize:self.avatarSize];
[self.avatarView autoPinLeadingToSuperviewMargin];
[self.avatarView autoVCenterInSuperview];
2018-04-10 19:02:33 +02:00
[self.avatarView setContentHuggingHigh];
[self.avatarView setCompressionResistanceHigh];
2018-06-14 22:15:44 +02:00
// Ensure that the cell's contents never overflow the cell bounds.
[self.avatarView autoPinEdgeToSuperviewMargin:ALEdgeTop relation:NSLayoutRelationGreaterThanOrEqual];
[self.avatarView autoPinEdgeToSuperviewMargin:ALEdgeBottom relation:NSLayoutRelationGreaterThanOrEqual];
2018-04-10 19:02:33 +02:00
self.nameLabel = [UILabel new];
self.nameLabel.lineBreakMode = NSLineBreakByTruncatingTail;
2018-04-10 19:02:33 +02:00
self.nameLabel.font = self.nameFont;
[self.nameLabel setContentHuggingHorizontalLow];
2018-04-10 19:02:33 +02:00
[self.nameLabel setCompressionResistanceHorizontalLow];
self.dateTimeLabel = [UILabel new];
[self.dateTimeLabel setContentHuggingHorizontalHigh];
[self.dateTimeLabel setCompressionResistanceHorizontalHigh];
2018-04-10 19:02:33 +02:00
self.messageStatusView = [MessageStatusView new];
2018-07-05 19:54:10 +02:00
[self.messageStatusView setContentHuggingHorizontalHigh];
[self.messageStatusView setCompressionResistanceHorizontalHigh];
UIStackView *topRowView = [[UIStackView alloc] initWithArrangedSubviews:@[
2018-04-10 19:02:33 +02:00
self.nameLabel,
self.dateTimeLabel,
2018-04-10 19:02:33 +02:00
]];
topRowView.axis = UILayoutConstraintAxisHorizontal;
topRowView.alignment = UIStackViewAlignmentLastBaseline;
topRowView.spacing = 6.f;
self.snippetLabel = [UILabel new];
2018-04-10 19:02:33 +02:00
self.snippetLabel.font = [self snippetFont];
self.snippetLabel.numberOfLines = 1;
self.snippetLabel.lineBreakMode = NSLineBreakByTruncatingTail;
2018-11-01 15:43:13 +01:00
self.typingIndicatorView = [TypingIndicatorView new];
self.previewStackView = [[UIStackView alloc] initWithArrangedSubviews:@[
2018-07-09 17:43:46 +02:00
self.snippetLabel,
2018-11-01 15:43:13 +01:00
self.typingIndicatorView,
]];
self.previewStackView.axis = UILayoutConstraintAxisVertical;
self.previewStackView.alignment = UIStackViewAlignmentLeading;
[self.previewStackView setContentHuggingHorizontalLow];
[self.previewStackView setCompressionResistanceHorizontalLow];
UIStackView *bottomRowView = [[UIStackView alloc] initWithArrangedSubviews:@[
self.previewStackView,
self.messageStatusView,
]];
2018-11-01 15:43:13 +01:00
bottomRowView.axis = UILayoutConstraintAxisHorizontal;
2018-11-01 15:43:13 +01:00
bottomRowView.alignment = UIStackViewAlignmentCenter;
bottomRowView.spacing = 6.f;
UIStackView *vStackView = [[UIStackView alloc] initWithArrangedSubviews:@[
topRowView,
bottomRowView,
2018-07-09 17:43:46 +02:00
]];
vStackView.axis = UILayoutConstraintAxisVertical;
[self.contentView addSubview:vStackView];
[vStackView autoPinLeadingToTrailingEdgeOfView:self.avatarView offset:self.avatarHSpacing];
[vStackView autoVCenterInSuperview];
// Ensure that the cell's contents never overflow the cell bounds.
[vStackView autoPinEdgeToSuperviewMargin:ALEdgeTop relation:NSLayoutRelationGreaterThanOrEqual];
[vStackView autoPinEdgeToSuperviewMargin:ALEdgeBottom relation:NSLayoutRelationGreaterThanOrEqual];
[vStackView autoPinTrailingToSuperviewMargin];
vStackView.userInteractionEnabled = NO;
2018-07-09 17:43:46 +02:00
self.unreadLabel = [UILabel new];
self.unreadLabel.textColor = [UIColor ows_whiteColor];
self.unreadLabel.lineBreakMode = NSLineBreakByTruncatingTail;
self.unreadLabel.textAlignment = NSTextAlignmentCenter;
[self.unreadLabel setContentHuggingHigh];
[self.unreadLabel setCompressionResistanceHigh];
self.unreadBadge = [NeverClearView new];
self.unreadBadge.backgroundColor = [UIColor ows_materialBlueColor];
[self.unreadBadge addSubview:self.unreadLabel];
[self.unreadLabel autoCenterInSuperview];
[self.unreadBadge setContentHuggingHigh];
[self.unreadBadge setCompressionResistanceHigh];
[self.contentView addSubview:self.unreadBadge];
2018-07-09 17:43:46 +02:00
[self.unreadBadge autoAlignAxis:ALAxisHorizontal toSameAxisOfView:self.nameLabel];
}
2018-06-25 20:31:09 +02:00
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
+ (NSString *)cellReuseIdentifier
{
return NSStringFromClass([self class]);
iOS 9 Support - Fixing size classes rendering bugs. - Supporting native iOS San Francisco font. - Quick Reply - Settings now slide to the left as suggested in original designed opposed to modal. - Simplification of restraints on many screens. - Full-API compatiblity with iOS 9 and iOS 8 legacy support. - Customized AddressBook Permission prompt when restrictions are enabled. If user installed Signal previously and already approved access to Contacts, don't bugg him again. - Fixes crash in migration for users who installed Signal <2.1.3 but hadn't signed up yet. - Xcode 7 / iOS 9 Travis Support - Bitcode Support is disabled until it is better understood how exactly optimizations are performed. In a first time, we will split out the crypto code into a separate binary to make it easier to optimize the non-sensitive code. Blog post with more details coming. - Partial ATS support. We are running our own Certificate Authority at Open Whisper Systems. Signal is doing certificate pinning to verify that certificates were signed by our own CA. Unfortunately Apple's App Transport Security requires to hand over chain verification to their framework with no control over the trust store. We have filed a radar to get ATS features with pinned certificates. In the meanwhile, ATS is disabled on our domain. We also followed Amazon's recommendations for our S3 domain we use to upload/download attachments. (#891) - Implement a unified `AFSecurityOWSPolicy` pinning strategy accross libraries (AFNetworking RedPhone/TextSecure & SocketRocket).
2015-09-01 19:22:08 +02:00
}
2018-04-10 19:02:33 +02:00
- (void)initializeLayout
2017-07-21 16:36:45 +02:00
{
self.selectionStyle = UITableViewCellSelectionStyleDefault;
2014-10-29 21:58:58 +01:00
}
Disappearing Messages * Per thread settings menu accessed by tapping on thread title This removed the toggle-phone behavior. You'll be able to see the phone number in the settings table view. This removed the "add contact" functionality, although it was already broken for ios>=9 (which is basically everybody). The group actions menu was absorbed into this screen * Added a confirm alert to leave group (fixes #938) * New Translation Strings * Extend "Add People" label to fit translations. * resolved issues with translations not fitting in group menu * Fix the long standing type warning where TSCalls were assigned to a TSMessageAdapter. * Can delete info messages Follow the JSQMVC pattern and put UIResponder-able content in the messageBubbleContainer. This gives us more functionality *and* allows us to delete some code. yay! It's still not yet possible to delete phone messages. =( * Fixed some compiler warnings. * xcode8 touching storyboard. So long xcode7! * Fixup multiline info messages. We were seeing info messages like "You set disappearing message timer to 10" instead of "You set disappearing message timer to 10 seconds." Admittedly this isn't a very good fix, as now one liners feel like they have too much padding. If the message is well over one line, we were wrapping properly, but there's a problem when the message is *just barely* two lines, the cell height grows, but the label still thinks it's just one line (as evinced by the one line appearing in the center of the label frame. The result being that the last word of the label is cropped. * Disable group actions after leaving group. // FREEBIE
2016-09-21 14:37:51 +02:00
- (nullable NSString *)reuseIdentifier
{
2014-10-29 21:58:58 +01:00
return NSStringFromClass(self.class);
}
- (void)configureWithThread:(ThreadViewModel *)thread
2018-09-09 21:08:23 +02:00
isBlocked:(BOOL)isBlocked
2018-06-12 17:27:32 +02:00
{
[self configureWithThread:thread
2018-09-09 21:08:23 +02:00
isBlocked:isBlocked
2018-06-12 17:27:32 +02:00
overrideSnippet:nil
2018-06-13 16:23:12 +02:00
overrideDate:nil];
2018-06-12 17:27:32 +02:00
}
- (void)configureWithThread:(ThreadViewModel *)thread
2018-09-09 21:08:23 +02:00
isBlocked:(BOOL)isBlocked
2018-06-12 17:27:32 +02:00
overrideSnippet:(nullable NSAttributedString *)overrideSnippet
2018-06-13 16:23:12 +02:00
overrideDate:(nullable NSDate *)overrideDate
Disappearing Messages * Per thread settings menu accessed by tapping on thread title This removed the toggle-phone behavior. You'll be able to see the phone number in the settings table view. This removed the "add contact" functionality, although it was already broken for ios>=9 (which is basically everybody). The group actions menu was absorbed into this screen * Added a confirm alert to leave group (fixes #938) * New Translation Strings * Extend "Add People" label to fit translations. * resolved issues with translations not fitting in group menu * Fix the long standing type warning where TSCalls were assigned to a TSMessageAdapter. * Can delete info messages Follow the JSQMVC pattern and put UIResponder-able content in the messageBubbleContainer. This gives us more functionality *and* allows us to delete some code. yay! It's still not yet possible to delete phone messages. =( * Fixed some compiler warnings. * xcode8 touching storyboard. So long xcode7! * Fixup multiline info messages. We were seeing info messages like "You set disappearing message timer to 10" instead of "You set disappearing message timer to 10 seconds." Admittedly this isn't a very good fix, as now one liners feel like they have too much padding. If the message is well over one line, we were wrapping properly, but there's a problem when the message is *just barely* two lines, the cell height grows, but the label still thinks it's just one line (as evinced by the one line appearing in the center of the label frame. The result being that the last word of the label is cropped. * Disable group actions after leaving group. // FREEBIE
2016-09-21 14:37:51 +02:00
{
2017-12-19 17:38:25 +01:00
OWSAssertIsOnMainThread();
OWSAssertDebug(thread);
2018-07-26 16:54:45 +02:00
[OWSTableItem configureCell:self];
2017-08-23 22:41:31 +02:00
self.thread = thread;
2018-04-10 19:02:33 +02:00
BOOL hasUnreadMessages = thread.hasUnreadMessages;
2017-08-23 22:41:31 +02:00
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(otherUsersProfileDidChange:)
name:kNSNotificationName_OtherUsersProfileDidChange
object:nil];
2018-11-01 15:43:13 +01:00
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(typingIndicatorStateDidChange:)
name:[OWSTypingIndicatorsImpl typingIndicatorStateDidChange]
object:nil];
2017-08-23 22:41:31 +02:00
[self updateNameLabel];
[self updateAvatarView];
// We update the fonts every time this cell is configured to ensure that
// changes to the dynamic type settings are reflected.
self.snippetLabel.font = [self snippetFont];
2018-06-12 17:27:32 +02:00
if (overrideSnippet) {
self.snippetLabel.attributedText = overrideSnippet;
} else {
2018-09-09 21:08:23 +02:00
self.snippetLabel.attributedText = [self attributedSnippetForThread:thread isBlocked:isBlocked];
2018-06-12 17:27:32 +02:00
}
2018-11-01 15:43:13 +01:00
[self updatePreview];
CGFloat previewHeight = MAX(self.snippetLabel.font.lineHeight,
TypingIndicatorView.kMaxRadiusPt);
[self.viewConstraints addObjectsFromArray:@[
[self.previewStackView autoSetDimension:ALDimensionHeight
toSize:previewHeight],
]];
2018-06-13 16:23:12 +02:00
self.dateTimeLabel.text
= (overrideDate ? [self stringForDate:overrideDate] : [self stringForDate:thread.lastMessageDate]);
2018-07-13 15:50:49 +02:00
UIColor *textColor = [Theme secondaryColor];
if (hasUnreadMessages && overrideSnippet == nil) {
2018-07-13 15:50:49 +02:00
textColor = [Theme primaryColor];
2018-07-05 19:20:37 +02:00
self.dateTimeLabel.font = self.dateTimeFont.ows_mediumWeight;
} else {
2018-07-05 19:20:37 +02:00
self.dateTimeLabel.font = self.dateTimeFont;
}
2018-07-05 19:54:10 +02:00
self.dateTimeLabel.textColor = textColor;
2018-07-09 17:43:46 +02:00
NSUInteger unreadCount = thread.unreadCount;
if (overrideSnippet) {
// If we're using the home view cell to render search results,
// don't show "unread badge" or "message status" indicator.
self.unreadBadge.hidden = YES;
2018-07-09 17:43:46 +02:00
self.messageStatusView.hidden = YES;
} else if (unreadCount > 0) {
// If there are unread messages, show the "unread badge."
// The "message status" indicators is redundant.
self.unreadBadge.hidden = NO;
2018-07-09 17:43:46 +02:00
self.messageStatusView.hidden = YES;
self.unreadLabel.text = [OWSFormat formatInt:(int)unreadCount];
self.unreadLabel.font = self.unreadFont;
const int unreadBadgeHeight = (int)ceil(self.unreadLabel.font.lineHeight * 1.5f);
self.unreadBadge.layer.cornerRadius = unreadBadgeHeight / 2;
2018-09-24 21:29:46 +02:00
self.unreadBadge.layer.borderColor = Theme.backgroundColor.CGColor;
self.unreadBadge.layer.borderWidth = 1.f;
2018-07-09 17:43:46 +02:00
[NSLayoutConstraint autoSetPriority:UILayoutPriorityDefaultHigh
forConstraints:^{
// This is a bit arbitrary, but it should scale with the size of dynamic text
2018-07-12 21:02:25 +02:00
CGFloat minMargin = CeilEven(unreadBadgeHeight * .5f);
2018-07-09 17:43:46 +02:00
// Spec check. Should be 12pts (6pt on each side) when using default font size.
OWSAssertDebug(UIFont.ows_dynamicTypeBodyFont.pointSize != 17 || minMargin == 12);
2018-07-09 17:43:46 +02:00
[self.viewConstraints addObjectsFromArray:@[
// badge sizing
2018-07-09 17:43:46 +02:00
[self.unreadBadge autoMatchDimension:ALDimensionWidth
toDimension:ALDimensionWidth
ofView:self.unreadLabel
withOffset:minMargin
relation:NSLayoutRelationGreaterThanOrEqual],
2018-07-09 17:43:46 +02:00
[self.unreadBadge autoSetDimension:ALDimensionWidth
toSize:unreadBadgeHeight
relation:NSLayoutRelationGreaterThanOrEqual],
[self.unreadBadge autoSetDimension:ALDimensionHeight toSize:unreadBadgeHeight],
[self.unreadBadge autoPinEdge:ALEdgeTrailing
toEdge:ALEdgeTrailing
ofView:self.avatarView
withOffset:6.f],
2018-07-09 17:43:46 +02:00
]];
}];
} else {
UIImage *_Nullable statusIndicatorImage = nil;
2018-07-13 15:32:30 +02:00
// TODO: Theme, Review with design.
2018-07-12 23:45:29 +02:00
UIColor *messageStatusViewTintColor
2018-09-19 16:08:27 +02:00
= (Theme.isDarkThemeEnabled ? [UIColor ows_gray25Color] : [UIColor ows_gray45Color]);
2018-07-09 17:43:46 +02:00
BOOL shouldAnimateStatusIcon = NO;
2018-07-09 23:21:46 +02:00
if ([self.thread.lastMessageForInbox isKindOfClass:[TSOutgoingMessage class]]) {
2018-07-09 17:43:46 +02:00
TSOutgoingMessage *outgoingMessage = (TSOutgoingMessage *)self.thread.lastMessageForInbox;
MessageReceiptStatus messageStatus =
[MessageRecipientStatusUtils recipientStatusWithOutgoingMessage:outgoingMessage];
switch (messageStatus) {
case MessageReceiptStatusUploading:
case MessageReceiptStatusSending:
statusIndicatorImage = [UIImage imageNamed:@"message_status_sending"];
shouldAnimateStatusIcon = YES;
break;
case MessageReceiptStatusSent:
case MessageReceiptStatusSkipped:
statusIndicatorImage = [UIImage imageNamed:@"message_status_sent"];
break;
case MessageReceiptStatusDelivered:
statusIndicatorImage = [UIImage imageNamed:@"message_status_delivered"];
break;
2018-07-09 17:43:46 +02:00
case MessageReceiptStatusRead:
2018-07-10 16:35:51 +02:00
statusIndicatorImage = [UIImage imageNamed:@"message_status_read"];
2018-07-09 17:43:46 +02:00
break;
case MessageReceiptStatusFailed:
statusIndicatorImage = [UIImage imageNamed:@"message_status_failed"];
messageStatusViewTintColor = [UIColor ows_destructiveRedColor];
2018-07-09 17:43:46 +02:00
break;
}
2018-07-05 19:54:10 +02:00
}
2018-07-09 17:43:46 +02:00
self.messageStatusView.image = [statusIndicatorImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
self.messageStatusView.tintColor = messageStatusViewTintColor;
self.messageStatusView.hidden = statusIndicatorImage == nil;
self.unreadBadge.hidden = YES;
2018-07-09 17:43:46 +02:00
if (shouldAnimateStatusIcon) {
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.messageStatusView.layer addAnimation:animation forKey:@"animation"];
} else {
[self.messageStatusView.layer removeAllAnimations];
2018-07-05 19:54:10 +02:00
}
}
}
- (void)updateAvatarView
{
ThreadViewModel *thread = self.thread;
if (thread == nil) {
OWSFailDebug(@"thread should not be nil");
self.avatarView.image = nil;
return;
}
self.avatarView.image = [OWSAvatarBuilder buildImageForThread:thread.threadRecord diameter:self.avatarSize];
2018-04-10 19:02:33 +02:00
}
2018-09-09 21:08:23 +02:00
- (NSAttributedString *)attributedSnippetForThread:(ThreadViewModel *)thread isBlocked:(BOOL)isBlocked
2018-04-10 19:02:33 +02:00
{
OWSAssertDebug(thread);
2018-04-10 19:02:33 +02:00
BOOL hasUnreadMessages = thread.hasUnreadMessages;
NSMutableAttributedString *snippetText = [NSMutableAttributedString new];
if (isBlocked) {
// If thread is blocked, don't show a snippet or mute status.
2018-09-09 21:08:23 +02:00
[snippetText appendAttributedString:
[[NSAttributedString alloc]
initWithString:NSLocalizedString(@"HOME_VIEW_BLOCKED_CONVERSATION",
@"Table cell subtitle label for a conversation the user has blocked.")
attributes:@{
NSFontAttributeName : self.snippetFont.ows_mediumWeight,
NSForegroundColorAttributeName : [Theme primaryColor],
}]];
2018-04-10 19:02:33 +02:00
} else {
if ([thread isMuted]) {
[snippetText appendAttributedString:[[NSAttributedString alloc]
2018-07-18 04:20:31 +02:00
initWithString:LocalizationNotNeeded(@"\ue067 ")
2018-04-10 19:02:33 +02:00
attributes:@{
NSFontAttributeName : [UIFont ows_elegantIconsFont:9.f],
2018-07-12 23:45:29 +02:00
NSForegroundColorAttributeName :
2018-07-13 15:50:49 +02:00
(hasUnreadMessages ? [Theme primaryColor]
: [Theme secondaryColor]),
2018-04-10 19:02:33 +02:00
}]];
}
2018-04-21 17:12:58 +02:00
NSString *displayableText = thread.lastMessageText;
2018-04-10 19:02:33 +02:00
if (displayableText) {
[snippetText appendAttributedString:[[NSAttributedString alloc]
initWithString:displayableText
attributes:@{
NSFontAttributeName :
2018-04-16 18:39:11 +02:00
(hasUnreadMessages ? self.snippetFont.ows_mediumWeight
2018-04-10 19:02:33 +02:00
: self.snippetFont),
NSForegroundColorAttributeName :
2018-07-13 15:50:49 +02:00
(hasUnreadMessages ? [Theme primaryColor]
: [Theme secondaryColor]),
2018-04-10 19:02:33 +02:00
}]];
}
}
return snippetText;
2014-10-29 21:58:58 +01:00
}
2017-09-08 16:28:21 +02:00
2014-10-29 21:58:58 +01:00
#pragma mark - Date formatting
- (NSString *)stringForDate:(nullable NSDate *)date
{
if (date == nil) {
OWSFailDebug(@"date was unexpectedly nil");
return @"";
}
2018-06-26 16:17:03 +02:00
return [DateUtil formatDateShort:date];
2018-04-10 19:02:33 +02:00
}
2018-04-10 19:02:33 +02:00
#pragma mark - Constants
2018-07-09 17:43:46 +02:00
- (UIFont *)unreadFont
{
return [UIFont ows_dynamicTypeCaption1Font].ows_mediumWeight;
}
2018-07-05 19:20:37 +02:00
- (UIFont *)dateTimeFont
{
return [UIFont ows_dynamicTypeCaption1Font];
}
2018-04-10 19:02:33 +02:00
- (UIFont *)snippetFont
{
return [UIFont ows_dynamicTypeSubheadlineFont];
2018-04-10 19:02:33 +02:00
}
2018-04-10 19:02:33 +02:00
- (UIFont *)nameFont
{
2018-04-16 18:39:11 +02:00
return [UIFont ows_dynamicTypeBodyFont].ows_mediumWeight;
2018-04-10 19:02:33 +02:00
}
2018-04-10 19:02:33 +02:00
// Used for profile names.
- (UIFont *)nameSecondaryFont
{
2018-07-10 20:33:52 +02:00
return [UIFont ows_dynamicTypeBodyFont].ows_italic;
2014-10-29 21:58:58 +01:00
}
- (NSUInteger)avatarSize
{
return kStandardAvatarSize;
}
- (NSUInteger)avatarHSpacing
{
return 12.f;
}
2018-04-10 19:02:33 +02:00
#pragma mark - Reuse
- (void)prepareForReuse
{
[super prepareForReuse];
2017-11-08 18:56:55 +01:00
2018-04-10 19:02:33 +02:00
[NSLayoutConstraint deactivateConstraints:self.viewConstraints];
[self.viewConstraints removeAllObjects];
self.thread = nil;
2018-06-25 20:31:09 +02:00
self.avatarView.image = nil;
2018-04-10 19:02:33 +02:00
2017-11-08 18:56:55 +01:00
[[NSNotificationCenter defaultCenter] removeObserver:self];
2014-10-29 21:58:58 +01:00
}
2017-08-23 22:41:31 +02:00
#pragma mark - Name
- (void)otherUsersProfileDidChange:(NSNotification *)notification
{
2017-12-19 17:38:25 +01:00
OWSAssertIsOnMainThread();
2017-08-23 22:41:31 +02:00
NSString *recipientId = notification.userInfo[kNSNotificationKey_ProfileRecipientId];
if (recipientId.length == 0) {
return;
}
2018-04-10 19:02:33 +02:00
2017-08-23 22:41:31 +02:00
if (![self.thread isKindOfClass:[TSContactThread class]]) {
return;
}
if (![self.thread.contactIdentifier isEqualToString:recipientId]) {
return;
}
2018-04-10 19:02:33 +02:00
2017-08-23 22:41:31 +02:00
[self updateNameLabel];
[self updateAvatarView];
2017-08-23 22:41:31 +02:00
}
2018-04-10 19:02:33 +02:00
- (void)updateNameLabel
2017-08-23 22:41:31 +02:00
{
2017-12-19 17:38:25 +01:00
OWSAssertIsOnMainThread();
2018-04-10 20:53:40 +02:00
self.nameLabel.font = self.nameFont;
2018-07-13 15:50:49 +02:00
self.nameLabel.textColor = [Theme primaryColor];
2018-04-10 20:53:40 +02:00
ThreadViewModel *thread = self.thread;
2017-08-23 22:41:31 +02:00
if (thread == nil) {
OWSFailDebug(@"thread should not be nil");
2017-08-23 22:41:31 +02:00
self.nameLabel.attributedText = nil;
return;
}
2018-04-10 19:02:33 +02:00
2017-08-23 22:41:31 +02:00
NSAttributedString *name;
if (thread.isGroupThread) {
if (thread.name.length == 0) {
name = [[NSAttributedString alloc] initWithString:[MessageStrings newGroupDefaultTitle]];
2017-08-23 22:41:31 +02:00
} else {
name = [[NSAttributedString alloc] initWithString:thread.name];
}
} else {
name = [self.contactsManager attributedContactOrProfileNameForPhoneIdentifier:thread.contactIdentifier
primaryFont:self.nameFont
secondaryFont:self.nameSecondaryFont];
2017-08-23 22:41:31 +02:00
}
2018-04-10 19:02:33 +02:00
2017-08-23 22:41:31 +02:00
self.nameLabel.attributedText = name;
}
2018-11-01 15:43:13 +01:00
#pragma mark - Typing Indicators
- (void)updatePreview
{
if ([self.typingIndicators typingIndicatorsForThread:self.thread.threadRecord] != nil) {
self.snippetLabel.hidden = YES;
self.typingIndicatorView.hidden = NO;
[self.typingIndicatorView startAnimation];
} else {
self.snippetLabel.hidden = NO;
self.typingIndicatorView.hidden = YES;
[self.typingIndicatorView stopAnimation];
}
}
- (void)typingIndicatorStateDidChange:(NSNotification *)notification
{
OWSAssertIsOnMainThread();
[self updatePreview];
}
2014-10-29 21:58:58 +01:00
@end
Disappearing Messages * Per thread settings menu accessed by tapping on thread title This removed the toggle-phone behavior. You'll be able to see the phone number in the settings table view. This removed the "add contact" functionality, although it was already broken for ios>=9 (which is basically everybody). The group actions menu was absorbed into this screen * Added a confirm alert to leave group (fixes #938) * New Translation Strings * Extend "Add People" label to fit translations. * resolved issues with translations not fitting in group menu * Fix the long standing type warning where TSCalls were assigned to a TSMessageAdapter. * Can delete info messages Follow the JSQMVC pattern and put UIResponder-able content in the messageBubbleContainer. This gives us more functionality *and* allows us to delete some code. yay! It's still not yet possible to delete phone messages. =( * Fixed some compiler warnings. * xcode8 touching storyboard. So long xcode7! * Fixup multiline info messages. We were seeing info messages like "You set disappearing message timer to 10" instead of "You set disappearing message timer to 10 seconds." Admittedly this isn't a very good fix, as now one liners feel like they have too much padding. If the message is well over one line, we were wrapping properly, but there's a problem when the message is *just barely* two lines, the cell height grows, but the label still thinks it's just one line (as evinced by the one line appearing in the center of the label frame. The result being that the last word of the label is cropped. * Disable group actions after leaving group. // FREEBIE
2016-09-21 14:37:51 +02:00
NS_ASSUME_NONNULL_END