session-ios/Signal/src/view controllers/InboxTableViewCell.m

280 lines
11 KiB
Mathematica
Raw Normal View History

2014-10-29 21:58:58 +01:00
//
// TableViewCell.m
// Signal
//
// Created by Dylan Bourgeois on 27/10/14.
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
#import "InboxTableViewCell.h"
#import "Environment.h"
#import "PreferencesUtil.h"
2014-10-29 21:58:58 +01:00
#import "Util.h"
#import "UIImage+JSQMessages.h"
#import "TSGroupThread.h"
#import "TSContactThread.h"
#import "JSQMessagesAvatarImageFactory.h"
#import "TSMessagesManager.h"
2014-10-29 21:58:58 +01:00
#define ARCHIVE_IMAGE_VIEW_WIDTH 22.0f
#define DELETE_IMAGE_VIEW_WIDTH 19.0f
#define TIME_LABEL_SIZE 11
2014-10-29 21:58:58 +01:00
#define DATE_LABEL_SIZE 13
2015-01-24 04:26:04 +01:00
#define SWIPE_ARCHIVE_OFFSET -50
2014-10-29 21:58:58 +01:00
@interface InboxTableViewCell ()
@property NSUInteger unreadMessages;
@property UIView *messagesBadge;
@property UILabel *unreadLabel;
@end
@implementation InboxTableViewCell
2014-10-29 21:58:58 +01:00
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
+ (instancetype)inboxTableViewCell {
InboxTableViewCell *cell = [NSBundle.mainBundle loadNibNamed:NSStringFromClass(self.class)
owner:self
options:nil][0];
2014-10-29 21:58:58 +01:00
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
[cell initializeLayout];
return cell;
}
- (void)initializeLayout {
_scrollView.contentSize = CGSizeMake(CGRectGetWidth(_contentContainerView.bounds),
CGRectGetHeight(_scrollView.frame));
_scrollView.contentOffset = CGPointMake(CGRectGetWidth(_archiveView.frame), 0);
_archiveImageView.image = [_archiveImageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
self.selectionStyle = UITableViewCellSelectionStyleDefault;
2014-10-29 21:58:58 +01:00
}
- (NSString *)reuseIdentifier {
return NSStringFromClass(self.class);
}
-(void)configureWithThread:(TSThread*)thread {
if (!_threadId || ![_threadId isEqualToString:thread.uniqueId]) {
self.hidden = YES;
}
NSString *name = thread.name;
_threadId = thread.uniqueId;
NSString *snippetLabel = thread.lastMessageLabel;
NSAttributedString *attributedDate = [self dateAttributedString:thread.lastMessageDate];
NSUInteger unreadCount = [[TSMessagesManager sharedManager] unreadMessagesInThread:thread];
dispatch_async(dispatch_get_main_queue(), ^{
_nameLabel.text = name;
_snippetLabel.text = snippetLabel;
_timeLabel.attributedText = attributedDate;
if([thread isKindOfClass:[TSGroupThread class]]) {
_contactPictureView.image = ((TSGroupThread*)thread).groupModel.groupImage!=nil ? ((TSGroupThread*)thread).groupModel.groupImage : [UIImage imageNamed:@"empty-group-avatar"];
if([_nameLabel.text length]==0) {
_nameLabel.text = NSLocalizedString(@"NEW_GROUP_DEFAULT_TITLE", @"");
}
if(_contactPictureView.image!=nil) {
dispatch_async(dispatch_get_main_queue(), ^{
[UIUtil applyRoundedBorderToImageView:&_contactPictureView];
});
}
}
else {
NSMutableString *initials = [NSMutableString string];
if([name length]>0) {
NSArray *words = [name componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
for (NSString * word in words) {
if ([word length] > 0) {
NSString *firstLetter = [word substringToIndex:1];
[initials appendString:[firstLetter uppercaseString]];
}
}
}
NSRange stringRange = {0, MIN([initials length], (NSUInteger)3)}; //Rendering max 3 letters.
initials = [[initials substringWithRange:stringRange] mutableCopy];
UIColor *backgroundColor = thread.isGroupThread ? [UIColor whiteColor] : [UIColor backgroundColorForContact:((TSContactThread*)thread).contactIdentifier];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
UIImage* image = [[JSQMessagesAvatarImageFactory avatarImageWithUserInitials:initials backgroundColor:backgroundColor textColor:[UIColor whiteColor] font:[UIFont ows_boldFontWithSize:36.0] diameter:100] avatarImage];
dispatch_async(dispatch_get_main_queue(), ^{
_contactPictureView.image = thread.image!=nil ? thread.image : image;
if(thread.image!=nil) {
[UIUtil applyRoundedBorderToImageView:&_contactPictureView];
}
});
});
}
self.separatorInset = UIEdgeInsetsMake(0,_contactPictureView.frame.size.width*1.5f, 0, 0);
if (thread.hasUnreadMessages) {
[self updateCellForUnreadMessage];
} else {
[self updateCellForReadMessage];
}
[self setUnreadMsgCount:unreadCount];
self.hidden = NO;
});
2014-10-29 21:58:58 +01:00
}
-(void)configureForState:(CellState)state
{
switch (state) {
case kArchiveState:
_archiveImageView.image = [[UIImage imageNamed:@"cellBtnMoveToInbox--blue"]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
2014-10-29 21:58:58 +01:00
break;
case kInboxState:
break;
default:
break;
}
}
-(void)updateCellForUnreadMessage
{
2015-02-12 23:08:57 +01:00
_nameLabel.font = [UIFont ows_boldFontWithSize:14.0f];
_nameLabel.textColor = [UIColor ows_blackColor];
_snippetLabel.font = [UIFont ows_mediumFontWithSize:12];
_snippetLabel.textColor = [UIColor ows_blackColor];
2015-02-12 23:08:57 +01:00
_timeLabel.textColor = [UIColor ows_materialBlueColor];
}
-(void)updateCellForReadMessage
{
_nameLabel.font = [UIFont ows_boldFontWithSize:14.0f];
_nameLabel.textColor = [UIColor ows_blackColor];
_snippetLabel.textColor = [UIColor lightGrayColor];
_timeLabel.textColor = [UIColor ows_darkGrayColor];
}
2014-10-29 21:58:58 +01:00
#pragma mark - Date formatting
- (NSAttributedString *)dateAttributedString:(NSDate *)date {
2015-02-12 23:08:57 +01:00
NSString *timeString;
2014-10-29 21:58:58 +01:00
if ([DateUtil dateIsToday:date]) {
2015-02-12 23:08:57 +01:00
timeString = [[DateUtil timeFormatter] stringFromDate:date];
} else {
timeString = [[DateUtil dateFormatter] stringFromDate:date];
}
2014-10-29 21:58:58 +01:00
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:timeString];
[attributedString addAttribute:NSForegroundColorAttributeName
value:[UIColor ows_darkGrayColor]
2014-10-29 21:58:58 +01:00
range:NSMakeRange(0, timeString.length)];
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
2014-10-29 21:58:58 +01:00
[attributedString addAttribute:NSFontAttributeName
value:[UIFont ows_regularFontWithSize:TIME_LABEL_SIZE]
2014-10-29 21:58:58 +01:00
range:NSMakeRange(0, timeString.length)];
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
2014-10-29 21:58:58 +01:00
return attributedString;
}
#pragma mark - UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (_scrollView.contentOffset.x < 0) {
_archiveImageView.image = [_archiveImageView.image jsq_imageMaskedWithColor:[UIColor ows_materialBlueColor]];
2014-10-29 21:58:58 +01:00
_archiveImageView.bounds = CGRectMake(_archiveImageView.bounds.origin.x,
_archiveImageView.bounds.origin.y,
ARCHIVE_IMAGE_VIEW_WIDTH,
_archiveImageView.bounds.size.height);
} else {
_archiveImageView.image = [_archiveImageView.image jsq_imageMaskedWithColor:[UIColor ows_darkGrayColor]];
2014-10-29 21:58:58 +01:00
double ratio = (_archiveView.frame.size.width/2.0f - _scrollView.contentOffset.x) / (_archiveView.frame.size.width/2.0f);
double newWidth = ARCHIVE_IMAGE_VIEW_WIDTH/2.0f + (ARCHIVE_IMAGE_VIEW_WIDTH * ratio)/2.0f;
_archiveImageView.bounds = CGRectMake(_archiveImageView.bounds.origin.x,
_archiveImageView.bounds.origin.y,
(CGFloat)newWidth,
_archiveImageView.bounds.size.height);
}
}
- (void)setUnreadMsgCount:(NSUInteger)unreadMessages {
if (_unreadMessages != unreadMessages) {
_unreadMessages = unreadMessages;
if (_unreadMessages > 0) {
if (_messagesBadge == nil) {
static UIImage *backgroundImage = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
{
UIGraphicsBeginImageContextWithOptions(CGSizeMake(25.0f, 25.0f), false, 0.0f);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [UIColor ows_materialBlueColor].CGColor);
CGContextFillEllipseInRect(context, CGRectMake(0.0f, 0.0f, 25.0f, 25.0f));
backgroundImage = [UIGraphicsGetImageFromCurrentImageContext() stretchableImageWithLeftCapWidth:8 topCapHeight:8];
UIGraphicsEndImageContext();
});
_messagesBadge = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f,
_messageCounter.frame.size
.height,
_messageCounter.frame.size.width)];
_messagesBadge.userInteractionEnabled = NO;
_messagesBadge.layer.zPosition = 2000;
UIImageView *unreadBackground = [[UIImageView alloc] initWithImage:backgroundImage];
[_messageCounter addSubview:unreadBackground];
_unreadLabel = [[UILabel alloc] init];
_unreadLabel.backgroundColor = [UIColor clearColor];
_unreadLabel.textColor = [UIColor whiteColor];
_unreadLabel.font = [UIFont systemFontOfSize:12];
[_messageCounter addSubview:_unreadLabel];
}
_unreadLabel.text = [[NSNumber numberWithUnsignedInteger:unreadMessages] stringValue];
[_unreadLabel sizeToFit];
CGPoint offset = CGPointMake(0.0f, 5.0f);
_unreadLabel.frame = CGRectMake(offset.x + floor((2.0f*(25 - _unreadLabel.frame.size.width)/ 2.0f)/2.0f), offset.y, _unreadLabel.frame.size.width, _unreadLabel.frame.size.height);
_messageCounter.hidden = NO;
} else {
_messageCounter.hidden = YES;
}
}
}
2014-10-29 21:58:58 +01:00
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView
withVelocity:(CGPoint)velocity
targetContentOffset:(inout CGPoint *)targetContentOffset {
2015-01-24 04:26:04 +01:00
if (_scrollView.contentOffset.x < SWIPE_ARCHIVE_OFFSET) {
// archive the thread
2014-10-29 21:58:58 +01:00
[_delegate tableViewCellTappedArchive:self];
[Environment.preferences setHasArchivedAMessage:YES];
}
else {
2015-01-24 04:26:04 +01:00
// don't do anything
2014-10-29 21:58:58 +01:00
*targetContentOffset = CGPointMake(CGRectGetWidth(_archiveView.frame), 0);
}
}
#pragma mark - Animation
-(void)animateDisappear
{
[UIView animateWithDuration:1.0f animations:^(){
self.alpha = 0;
}];
}
@end