Performance updates & smarter layout (2 lines)

- Adding support for ContactsUI when adding contacts on iOS 9.
- Multiple performance updates by liberating the main thread and
reusing tableview cells.
This commit is contained in:
Frederic Jacobs 2015-10-31 16:53:32 +01:00
parent 047262b95a
commit ef6e658c38
12 changed files with 350 additions and 208 deletions

View File

@ -394,6 +394,8 @@
B6B096931A1D25ED008BFAA6 /* NSData+messagePadding.m in Sources */ = {isa = PBXBuildFile; fileRef = B6B0965C1A1D25ED008BFAA6 /* NSData+messagePadding.m */; };
B6B096951A1D25ED008BFAA6 /* NSURLSessionDataTask+StatusCode.m in Sources */ = {isa = PBXBuildFile; fileRef = B6B096601A1D25ED008BFAA6 /* NSURLSessionDataTask+StatusCode.m */; };
B6B1013C196D213F007E3930 /* SignalKeyingStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = B6B1013B196D213F007E3930 /* SignalKeyingStorage.m */; };
B6B226971BE4B7D200860F4D /* ContactsUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B6B226961BE4B7D200860F4D /* ContactsUI.framework */; };
B6B2269A1BE4C59200860F4D /* APNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = B6B226991BE4C59200860F4D /* APNavigationController.m */; };
B6B50AAB1A4192C500F8F607 /* TSMessagesManager+attachments.m in Sources */ = {isa = PBXBuildFile; fileRef = B6B50AAA1A4192C500F8F607 /* TSMessagesManager+attachments.m */; };
B6B9ECFC198B31BA00C620D3 /* PushManager.m in Sources */ = {isa = PBXBuildFile; fileRef = B6B9ECFB198B31BA00C620D3 /* PushManager.m */; };
B6BADBE41B88CB940086A80D /* TSUpdateAttributesRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = B6BADBE31B88CB940086A80D /* TSUpdateAttributesRequest.m */; };
@ -1062,6 +1064,9 @@
B6B096601A1D25ED008BFAA6 /* NSURLSessionDataTask+StatusCode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSURLSessionDataTask+StatusCode.m"; sourceTree = "<group>"; };
B6B1013A196D213F007E3930 /* SignalKeyingStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SignalKeyingStorage.h; sourceTree = "<group>"; };
B6B1013B196D213F007E3930 /* SignalKeyingStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SignalKeyingStorage.m; sourceTree = "<group>"; };
B6B226961BE4B7D200860F4D /* ContactsUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ContactsUI.framework; path = System/Library/Frameworks/ContactsUI.framework; sourceTree = SDKROOT; };
B6B226981BE4C59200860F4D /* APNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APNavigationController.h; sourceTree = "<group>"; };
B6B226991BE4C59200860F4D /* APNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APNavigationController.m; sourceTree = "<group>"; };
B6B50AA91A4192C500F8F607 /* TSMessagesManager+attachments.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "TSMessagesManager+attachments.h"; sourceTree = "<group>"; };
B6B50AAA1A4192C500F8F607 /* TSMessagesManager+attachments.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "TSMessagesManager+attachments.m"; sourceTree = "<group>"; };
B6B9ECFA198B31BA00C620D3 /* PushManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PushManager.h; sourceTree = "<group>"; };
@ -1227,6 +1232,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
B6B226971BE4B7D200860F4D /* ContactsUI.framework in Frameworks */,
B6FE7EB71ADD62FA00A6D22F /* PushKit.framework in Frameworks */,
FC3BD9881A30A790005B96BB /* Social.framework in Frameworks */,
FCB11D8C1A129A76002F93FB /* CoreMedia.framework in Frameworks */,
@ -1853,6 +1859,8 @@
76EB04FE18170B33006006FC /* view controllers */ = {
isa = PBXGroup;
children = (
B6B226981BE4C59200860F4D /* APNavigationController.h */,
B6B226991BE4C59200860F4D /* APNavigationController.m */,
B6BADBE51B88D1AC0086A80D /* LockInteractionController.h */,
B6BADBE61B88D1AC0086A80D /* LockInteractionController.m */,
FCFD25791A1543D500F4C644 /* Signup */,
@ -2449,6 +2457,7 @@
D221A08C169C9E5E00537ABF /* Frameworks */ = {
isa = PBXGroup;
children = (
B6B226961BE4B7D200860F4D /* ContactsUI.framework */,
B6FE7EB61ADD62FA00A6D22F /* PushKit.framework */,
FC3BD9871A30A790005B96BB /* Social.framework */,
B60EDE031A05A01700D73516 /* AudioToolbox.framework */,
@ -3174,6 +3183,7 @@
B6B1013C196D213F007E3930 /* SignalKeyingStorage.m in Sources */,
76EB059218170B33006006FC /* UnrecognizedRequestFailure.m in Sources */,
76EB05F818170B33006006FC /* CallConnectUtil_Initiator.m in Sources */,
B6B2269A1BE4C59200860F4D /* APNavigationController.m in Sources */,
B6B096761A1D25ED008BFAA6 /* TSServerMessage.m in Sources */,
B63761E319E1F487005735D1 /* AFHTTPSessionManager+SignalMethods.m in Sources */,
76EB05CC18170B33006006FC /* ShortAuthenticationStringGenerator.m in Sources */,

View File

@ -4,6 +4,7 @@
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9049"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<capability name="Segues with Peek and Pop" minToolsVersion="7.1"/>
</dependencies>
<scenes>
<!--Conversations-->
@ -40,22 +41,25 @@
<constraint firstAttribute="centerY" secondItem="Srx-i1-WhD" secondAttribute="centerY" constant="95" id="XST-YY-qXT"/>
</constraints>
</view>
<tableView hidden="YES" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" showsHorizontalScrollIndicator="NO" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="PaA-ol-uQT">
<tableView hidden="YES" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" showsHorizontalScrollIndicator="NO" dataMode="prototypes" style="plain" separatorStyle="default" allowsSelectionDuringEditing="YES" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="PaA-ol-uQT">
<rect key="frame" x="0.0" y="64" width="330" height="504"/>
<animations/>
<color key="backgroundColor" red="0.94901960780000005" green="0.94901960780000005" blue="0.94901960780000005" alpha="1" colorSpace="calibratedRGB"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<prototypes>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="showCell" id="bnD-Ld-pC4">
<rect key="frame" x="0.0" y="22" width="330" height="44"/>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="cells" id="Ao0-kZ-6Fk">
<rect key="frame" x="0.0" y="28" width="330" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="bnD-Ld-pC4" id="9EM-iT-Acg">
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Ao0-kZ-6Fk" id="Kzg-Il-hgK">
<rect key="frame" x="0.0" y="0.0" width="297" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<animations/>
</tableViewCellContentView>
<animations/>
<connections>
<segue destination="DtA-8O-wrT" kind="push" identifier="showSegue" id="06M-BZ-tnn"/>
<segue destination="DtA-8O-wrT" kind="push" identifier="showSegue" id="ANb-Oa-vQe">
<segue key="commit" inheritsFrom="parent" id="3Aj-hB-zgq"/>
<segue key="preview" inheritsFrom="commit" id="ktS-lA-hcf"/>
</segue>
</connections>
</tableViewCell>
</prototypes>
@ -2040,8 +2044,9 @@ A0 09 9A FF A8 8A 09 99</string>
<image name="speaker-inactive" width="80" height="80"/>
</resources>
<inferredMetricsTieBreakers>
<segue reference="ANb-Oa-vQe"/>
<segue reference="DR8-fx-0PD"/>
<segue reference="D0d-4f-lcI"/>
<segue reference="xo7-5J-BJb"/>
<segue reference="D0d-4f-lcI"/>
</inferredMetricsTieBreakers>
</document>

View File

@ -32,5 +32,6 @@
- (NSUInteger)unreadMessagesCount;
- (NSUInteger)unreadMessagesCountExcept:(TSThread*)thread;
- (NSUInteger)unreadMessagesInThread:(TSThread*)thread;
@end

View File

@ -407,6 +407,14 @@
return numberOfItems;
}
- (NSUInteger)unreadMessagesInThread:(TSThread*)thread {
__block NSUInteger numberOfItems;
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
numberOfItems = [[transaction ext:TSUnreadDatabaseViewExtensionName] numberOfItemsInGroup:thread.uniqueId];
}];
return numberOfItems;
}
- (void)notifyUserForCall:(TSCall*)call inThread:(TSThread*)thread {
if ([UIApplication sharedApplication].applicationState != UIApplicationStateActive){
// Remove previous notification of call and show missed notification.

View File

@ -60,9 +60,9 @@
frame.origin.y = CGRectGetMaxY(self.navigationBar.frame);
self.dropDownToolbar.frame = frame;
[UIView animateWithDuration:0.25 animations:^{
CGRect frame = self.dropDownToolbar.frame;
frame.origin.y = 0.;
weakSelf.dropDownToolbar.frame = frame;
CGRect finalframe = self.dropDownToolbar.frame;
finalframe.origin.y = 0.;
weakSelf.dropDownToolbar.frame = finalframe;
} completion:^(BOOL finished) {
weakSelf.isDropDownVisible = !weakSelf.isDropDownVisible;
weakSelf.dropDownToolbar.hidden = YES;
@ -86,9 +86,9 @@
self.dropDownToolbar.hidden = NO;
self.dropDownToolbar.frame = frame;
[UIView animateWithDuration:0.25 animations:^{
CGRect frame = self.dropDownToolbar.frame;
frame.origin.y = CGRectGetMaxY(self.navigationBar.frame);
weakSelf.dropDownToolbar.frame = frame;
CGRect finalframe = self.dropDownToolbar.frame;
finalframe.origin.y = CGRectGetMaxY(self.navigationBar.frame);
weakSelf.dropDownToolbar.frame = finalframe;
} completion:^(BOOL finished) {
weakSelf.isDropDownVisible = !weakSelf.isDropDownVisible;
}];

View File

@ -34,7 +34,9 @@ typedef enum : NSUInteger {
@property (nonatomic, strong) IBOutlet UIView *archiveView;
@property (nonatomic, strong) IBOutlet UIImageView *archiveImageView;
@property (nonatomic, retain) IBOutlet UIView *messageCounter;
@property (nonatomic, assign) id<TableViewCellDelegate> delegate;
@property (nonatomic, retain) NSString *threadId;
+ (instancetype)inboxTableViewCell;
- (void)configureWithThread:(TSThread*)thread;

View File

@ -14,12 +14,22 @@
#import "TSGroupThread.h"
#import "TSContactThread.h"
#import "JSQMessagesAvatarImageFactory.h"
#import "TSMessagesManager.h"
#define ARCHIVE_IMAGE_VIEW_WIDTH 22.0f
#define DELETE_IMAGE_VIEW_WIDTH 19.0f
#define TIME_LABEL_SIZE 11
#define DATE_LABEL_SIZE 13
#define SWIPE_ARCHIVE_OFFSET -50
@interface InboxTableViewCell ()
@property NSUInteger unreadMessages;
@property UIView *messagesBadge;
@property UILabel *unreadLabel;
@end
@implementation InboxTableViewCell
+ (instancetype)inboxTableViewCell {
@ -37,6 +47,8 @@
_scrollView.contentOffset = CGPointMake(CGRectGetWidth(_archiveView.frame), 0);
_archiveImageView.image = [_archiveImageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
self.selectionStyle = UITableViewCellSelectionStyleDefault;
}
- (NSString *)reuseIdentifier {
@ -44,47 +56,71 @@
}
-(void)configureWithThread:(TSThread*)thread {
_nameLabel.text = thread.name;
_snippetLabel.text = thread.lastMessageLabel;
_timeLabel.attributedText = [self dateAttributedString:thread.lastMessageDate];
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) {
[UIUtil applyRoundedBorderToImageView:&_contactPictureView];
}
if (!_threadId || ![_threadId isEqualToString:thread.uniqueId]) {
self.hidden = YES;
}
else {
NSMutableString *initials = [NSMutableString string];
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.name length]>0) {
NSArray *words = [thread.name componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
for (NSString * word in words) {
if ([word length] > 0) {
NSString *firstLetter = [word substringToIndex:1];
[initials appendString:[firstLetter uppercaseString]];
}
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];
});
}
}
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];
UIImage* image = [[JSQMessagesAvatarImageFactory avatarImageWithUserInitials:initials backgroundColor:backgroundColor textColor:[UIColor whiteColor] font:[UIFont ows_boldFontWithSize:36.0] diameter:100] avatarImage];
_contactPictureView.image = thread.image!=nil ? thread.image : image;
if(thread.image!=nil) {
[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];
}
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;
});
}
-(void)configureForState:(CellState)state
@ -104,14 +140,18 @@
-(void)updateCellForUnreadMessage
{
_nameLabel.font = [UIFont ows_boldFontWithSize:14.0f];
_nameLabel.textColor = [UIColor ows_blackColor];
_snippetLabel.font = [UIFont ows_mediumFontWithSize:12];
_snippetLabel.textColor = [UIColor ows_blackColor];
_timeLabel.textColor = [UIColor ows_materialBlueColor];
}
-(void)updateCellForReadMessage
{
_nameLabel.font = [UIFont ows_regularFontWithSize:14.0f];
_nameLabel.font = [UIFont ows_boldFontWithSize:14.0f];
_nameLabel.textColor = [UIColor ows_blackColor];
_snippetLabel.textColor = [UIColor lightGrayColor];
_timeLabel.textColor = [UIColor ows_darkGrayColor];
}
#pragma mark - Date formatting
@ -165,6 +205,53 @@
}
}
- (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;
}
}
}
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView
withVelocity:(CGPoint)velocity
targetContentOffset:(inout CGPoint *)targetContentOffset {

View File

@ -1,7 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6254" systemVersion="14C109" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9059" systemVersion="15B42" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6247"/>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9049"/>
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
</dependencies>
<objects>
@ -11,20 +13,22 @@
<rect key="frame" x="0.0" y="0.0" width="400" height="72"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<tableViewCellContentView key="contentView" multipleTouchEnabled="YES" contentMode="center" tableViewCell="axX-Rb-kiK" id="BRG-hJ-lRa">
<rect key="frame" x="0.0" y="0.0" width="318" height="71"/>
<rect key="frame" x="0.0" y="0.0" width="400" height="71"/>
<autoresizingMask key="autoresizingMask" flexibleMaxY="YES"/>
<subviews>
<view contentMode="scaleToFill" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="yBY-TS-2tI" userLabel="Archive View">
<rect key="frame" x="-32" y="1" width="200" height="72"/>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="yBY-TS-2tI" userLabel="Archive View">
<rect key="frame" x="-32" y="0.0" width="200" height="72"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="cellBtnMoveToArchive--blue" translatesAutoresizingMaskIntoConstraints="NO" id="WyX-Hb-Mpn">
<rect key="frame" x="60" y="25" width="22" height="22"/>
<animations/>
<constraints>
<constraint firstAttribute="width" constant="22" id="POu-Gs-JsW"/>
<constraint firstAttribute="height" constant="22" id="oci-BQ-wXb"/>
</constraints>
</imageView>
</subviews>
<animations/>
<color key="backgroundColor" red="0.79607843137254897" green="0.8901960784313725" blue="0.98039215686274506" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="WyX-Hb-Mpn" firstAttribute="top" secondItem="yBY-TS-2tI" secondAttribute="top" constant="25" id="D9f-ck-Her"/>
@ -33,21 +37,20 @@
<constraint firstAttribute="height" constant="72" id="nSm-46-Dix"/>
</constraints>
</view>
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" ambiguous="YES" alwaysBounceHorizontal="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bG5-iK-ql3" customClass="NextResponderScrollView">
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" alwaysBounceHorizontal="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" canCancelContentTouches="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bG5-iK-ql3" customClass="NextResponderScrollView">
<rect key="frame" x="0.0" y="0.0" width="400" height="72"/>
<subviews>
<view contentMode="scaleToFill" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="kq8-RD-txC" userLabel="Container View">
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="kq8-RD-txC" userLabel="Container View">
<rect key="frame" x="0.0" y="0.0" width="400" height="72"/>
<subviews>
<view contentMode="scaleToFill" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Wco-u2-Bz6">
<rect key="frame" x="0.0" y="0.0" width="400" height="72"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="contact_default_feed.png" translatesAutoresizingMaskIntoConstraints="NO" id="p9o-x6-nT5">
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="p9o-x6-nT5">
<rect key="frame" x="10" y="10" width="52" height="53"/>
<animations/>
</imageView>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" ambiguous="YES" text="Thursday" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bp6-EC-9eP">
<rect key="frame" x="317" y="20" width="56" height="17"/>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" misplaced="YES" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" enabled="NO" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bp6-EC-9eP">
<rect key="frame" x="383" y="10" width="0.0" height="0.0"/>
<animations/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="height" constant="17" id="kgo-Kw-ZP3"/>
</constraints>
@ -55,158 +58,77 @@
<color key="textColor" red="0.13725490200000001" green="0.1215686275" blue="0.12549019610000001" alpha="1" colorSpace="calibratedRGB"/>
<color key="highlightedColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Qgj-EY-BWC">
<rect key="frame" x="75" y="29" width="234" height="35"/>
<fontDescription key="fontDescription" name="HelveticaNeue" family="Helvetica Neue" pointSize="12"/>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" enabled="NO" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Qgj-EY-BWC">
<rect key="frame" x="75" y="29" width="235" height="33"/>
<animations/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<fontDescription key="fontDescription" name="HelveticaNeue" family="Helvetica Neue" pointSize="14"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" fixedFrame="YES" text="Name Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gWV-cB-qZe">
<rect key="frame" x="74" y="12" width="180" height="30"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Bold" family="Helvetica Neue" pointSize="14"/>
<color key="textColor" red="0.11764705882352941" green="0.11764705882352941" blue="0.11764705882352941" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="highlightedColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<view userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="KNJ-HQ-UVM" userLabel="New Messages Tag">
<rect key="frame" x="353" y="35" width="27" height="27"/>
<animations/>
<color key="backgroundColor" red="0.25882352939999997" green="0.74901960779999999" blue="0.25098039220000001" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" constant="27" id="S3w-sZ-O53"/>
<constraint firstAttribute="width" secondItem="KNJ-HQ-UVM" secondAttribute="height" multiplier="1:1" id="pRB-Zk-iwR"/>
</constraints>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mfN-2A-QxN">
<rect key="frame" x="75" y="6" width="236" height="25"/>
<animations/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="16"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<animations/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="width" secondItem="Wco-u2-Bz6" secondAttribute="width" id="1T6-40-omZ"/>
<constraint firstAttribute="centerX" secondItem="Wco-u2-Bz6" secondAttribute="centerX" constant="-10" id="3FF-mP-SEU"/>
<constraint firstItem="Wco-u2-Bz6" firstAttribute="leading" secondItem="kq8-RD-txC" secondAttribute="leading" id="7CN-Mr-Ecm"/>
<constraint firstAttribute="height" secondItem="Wco-u2-Bz6" secondAttribute="height" id="EXS-jQ-F5B"/>
<constraint firstAttribute="width" secondItem="Wco-u2-Bz6" secondAttribute="width" id="GAp-II-hEP"/>
<constraint firstAttribute="centerY" secondItem="Wco-u2-Bz6" secondAttribute="centerY" id="GZX-5M-GH9"/>
<constraint firstAttribute="bottom" secondItem="Wco-u2-Bz6" secondAttribute="bottom" id="IZD-iJ-o1H"/>
<constraint firstAttribute="centerX" secondItem="Wco-u2-Bz6" secondAttribute="centerX" constant="102" id="Mt5-CN-g2H"/>
<constraint firstAttribute="centerX" secondItem="Wco-u2-Bz6" secondAttribute="centerX" id="Szl-70-i1e"/>
<constraint firstAttribute="centerY" secondItem="Wco-u2-Bz6" secondAttribute="centerY" id="asx-dO-cbp"/>
<constraint firstAttribute="trailing" secondItem="Wco-u2-Bz6" secondAttribute="trailing" constant="102" id="bSf-ft-rxR"/>
<constraint firstItem="Wco-u2-Bz6" firstAttribute="top" secondItem="kq8-RD-txC" secondAttribute="top" id="dXQ-dR-4SK"/>
<constraint firstItem="bp6-EC-9eP" firstAttribute="trailing" secondItem="Wco-u2-Bz6" secondAttribute="trailing" constant="-27" id="eJL-bU-QWF"/>
<constraint firstItem="bp6-EC-9eP" firstAttribute="top" secondItem="Wco-u2-Bz6" secondAttribute="top" constant="20" id="pBv-RK-St3"/>
<constraint firstItem="KNJ-HQ-UVM" firstAttribute="top" secondItem="bp6-EC-9eP" secondAttribute="bottom" constant="8" id="Xxt-Pd-bUm"/>
<constraint firstItem="Qgj-EY-BWC" firstAttribute="top" secondItem="kq8-RD-txC" secondAttribute="top" constant="29" id="YQx-hl-fQf"/>
</constraints>
<variation key="default">
<mask key="constraints">
<exclude reference="1T6-40-omZ"/>
<exclude reference="3FF-mP-SEU"/>
<exclude reference="7CN-Mr-Ecm"/>
<exclude reference="GZX-5M-GH9"/>
<exclude reference="IZD-iJ-o1H"/>
<exclude reference="Mt5-CN-g2H"/>
<exclude reference="bSf-ft-rxR"/>
<exclude reference="dXQ-dR-4SK"/>
</mask>
</variation>
</view>
</subviews>
<animations/>
<constraints>
<constraint firstAttribute="trailing" secondItem="kq8-RD-txC" secondAttribute="trailing" id="3iz-A6-N93"/>
<constraint firstAttribute="bottom" secondItem="kq8-RD-txC" secondAttribute="bottom" id="4a6-E0-eBE"/>
<constraint firstItem="kq8-RD-txC" firstAttribute="top" secondItem="bG5-iK-ql3" secondAttribute="top" id="AG5-dI-2pd"/>
<constraint firstItem="kq8-RD-txC" firstAttribute="top" secondItem="bG5-iK-ql3" secondAttribute="top" id="An4-9G-IYU"/>
<constraint firstAttribute="trailing" secondItem="kq8-RD-txC" secondAttribute="trailing" id="CWM-Sv-BB9"/>
<constraint firstItem="kq8-RD-txC" firstAttribute="leading" secondItem="bG5-iK-ql3" secondAttribute="leading" id="HqR-mX-M8E"/>
<constraint firstAttribute="centerX" secondItem="kq8-RD-txC" secondAttribute="centerX" constant="-102" id="LkM-VZ-WRa"/>
<constraint firstItem="kq8-RD-txC" firstAttribute="leading" secondItem="bG5-iK-ql3" secondAttribute="leading" id="TDZ-oq-p0x"/>
<constraint firstAttribute="trailing" secondItem="kq8-RD-txC" secondAttribute="trailing" constant="-204" id="Vnt-oN-8TR"/>
<constraint firstAttribute="trailing" secondItem="KNJ-HQ-UVM" secondAttribute="trailing" constant="20" id="J8b-wh-IUa"/>
<constraint firstAttribute="trailing" secondItem="Qgj-EY-BWC" secondAttribute="trailing" constant="90" id="LNQ-nI-2z4"/>
<constraint firstAttribute="trailing" secondItem="bp6-EC-9eP" secondAttribute="trailing" constant="17" id="ZIh-x7-oZT"/>
<constraint firstItem="kq8-RD-txC" firstAttribute="centerX" secondItem="bG5-iK-ql3" secondAttribute="centerX" id="dF0-aa-sOI"/>
<constraint firstItem="bp6-EC-9eP" firstAttribute="top" secondItem="bG5-iK-ql3" secondAttribute="top" constant="10" id="ghx-vM-qjc"/>
<constraint firstItem="kq8-RD-txC" firstAttribute="leading" secondItem="bG5-iK-ql3" secondAttribute="leading" id="lDQ-73-Y5y"/>
<constraint firstItem="kq8-RD-txC" firstAttribute="width" secondItem="bG5-iK-ql3" secondAttribute="width" id="lpQ-vV-DDu"/>
<constraint firstAttribute="bottom" secondItem="kq8-RD-txC" secondAttribute="bottom" id="nsI-NR-f3Y"/>
<constraint firstAttribute="centerY" secondItem="kq8-RD-txC" secondAttribute="centerY" id="q6R-fT-3Qv"/>
<constraint firstAttribute="height" constant="72" id="s7n-Dd-n3b"/>
<constraint firstItem="kq8-RD-txC" firstAttribute="height" secondItem="bG5-iK-ql3" secondAttribute="height" id="uTM-6V-qUa"/>
<constraint firstItem="Qgj-EY-BWC" firstAttribute="leading" secondItem="bG5-iK-ql3" secondAttribute="leading" constant="75" id="vVN-fS-XXB"/>
<constraint firstItem="kq8-RD-txC" firstAttribute="centerY" secondItem="bG5-iK-ql3" secondAttribute="centerY" id="zll-OP-FWQ"/>
</constraints>
<variation key="default">
<mask key="constraints">
<exclude reference="3iz-A6-N93"/>
<exclude reference="4a6-E0-eBE"/>
<exclude reference="AG5-dI-2pd"/>
<exclude reference="An4-9G-IYU"/>
<exclude reference="CWM-Sv-BB9"/>
<exclude reference="HqR-mX-M8E"/>
<exclude reference="LkM-VZ-WRa"/>
<exclude reference="TDZ-oq-p0x"/>
<exclude reference="Vnt-oN-8TR"/>
<exclude reference="dF0-aa-sOI"/>
<exclude reference="lDQ-73-Y5y"/>
<exclude reference="nsI-NR-f3Y"/>
<exclude reference="zll-OP-FWQ"/>
</mask>
</variation>
<variation key="heightClass=regular-widthClass=compact">
<mask key="constraints">
<exclude reference="s7n-Dd-n3b"/>
<include reference="4a6-E0-eBE"/>
<include reference="AG5-dI-2pd"/>
<include reference="CWM-Sv-BB9"/>
<exclude reference="TDZ-oq-p0x"/>
<exclude reference="Vnt-oN-8TR"/>
<include reference="dF0-aa-sOI"/>
<include reference="lDQ-73-Y5y"/>
<exclude reference="lpQ-vV-DDu"/>
<exclude reference="q6R-fT-3Qv"/>
<exclude reference="uTM-6V-qUa"/>
<include reference="zll-OP-FWQ"/>
</mask>
</variation>
<connections>
<outlet property="delegate" destination="axX-Rb-kiK" id="TMe-oF-FQE"/>
</connections>
</scrollView>
</subviews>
<animations/>
<color key="backgroundColor" red="0.94901960780000005" green="0.94901960780000005" blue="0.94901960780000005" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="centerX" secondItem="bG5-iK-ql3" secondAttribute="centerX" id="1eG-bp-0aH"/>
<constraint firstAttribute="centerX" secondItem="yBY-TS-2tI" secondAttribute="centerX" constant="100" id="45M-LI-hyw"/>
<constraint firstAttribute="centerY" secondItem="yBY-TS-2tI" secondAttribute="centerY" constant="-0.5" id="4d0-90-jLX"/>
<constraint firstItem="bG5-iK-ql3" firstAttribute="centerY" secondItem="yBY-TS-2tI" secondAttribute="centerY" id="5Va-qA-vJx"/>
<constraint firstItem="bG5-iK-ql3" firstAttribute="leading" secondItem="BRG-hJ-lRa" secondAttribute="leadingMargin" constant="-8" id="Dmq-W5-Xkr"/>
<constraint firstItem="bG5-iK-ql3" firstAttribute="trailing" secondItem="yBY-TS-2tI" secondAttribute="trailing" constant="400" id="Efu-Ej-DLZ"/>
<constraint firstItem="yBY-TS-2tI" firstAttribute="leading" secondItem="BRG-hJ-lRa" secondAttribute="leadingMargin" constant="-8" id="HBi-XD-XdK"/>
<constraint firstAttribute="centerY" secondItem="bG5-iK-ql3" secondAttribute="centerY" constant="-0.25" id="IQe-4d-baG"/>
<constraint firstAttribute="centerY" secondItem="yBY-TS-2tI" secondAttribute="centerY" constant="-0.5" id="LFd-ft-Cx2"/>
<constraint firstAttribute="trailing" secondItem="bG5-iK-ql3" secondAttribute="trailing" id="Wbl-He-blg"/>
<constraint firstItem="yBY-TS-2tI" firstAttribute="leading" secondItem="BRG-hJ-lRa" secondAttribute="leadingMargin" constant="-40" id="ZTu-mT-wNL"/>
<constraint firstItem="bG5-iK-ql3" firstAttribute="leading" secondItem="BRG-hJ-lRa" secondAttribute="leading" id="byS-fb-Uet"/>
<constraint firstItem="yBY-TS-2tI" firstAttribute="leading" secondItem="BRG-hJ-lRa" secondAttribute="leadingMargin" constant="-8" id="dJ9-E4-MkG"/>
<constraint firstAttribute="trailingMargin" secondItem="bG5-iK-ql3" secondAttribute="trailing" constant="-8" id="ikW-Es-Ngp"/>
<constraint firstItem="yBY-TS-2tI" firstAttribute="leading" secondItem="BRG-hJ-lRa" secondAttribute="leadingMargin" id="lMh-PN-kR2"/>
<constraint firstItem="bG5-iK-ql3" firstAttribute="bottom" secondItem="yBY-TS-2tI" secondAttribute="bottom" id="opm-uv-Fhc"/>
</constraints>
<variation key="default">
<mask key="constraints">
<exclude reference="5Va-qA-vJx"/>
<exclude reference="Efu-Ej-DLZ"/>
<exclude reference="Wbl-He-blg"/>
<exclude reference="byS-fb-Uet"/>
<exclude reference="opm-uv-Fhc"/>
<exclude reference="45M-LI-hyw"/>
<exclude reference="HBi-XD-XdK"/>
<exclude reference="LFd-ft-Cx2"/>
<exclude reference="dJ9-E4-MkG"/>
<exclude reference="lMh-PN-kR2"/>
</mask>
</variation>
<variation key="heightClass=regular-widthClass=compact">
<mask key="constraints">
<exclude reference="1eG-bp-0aH"/>
<include reference="5Va-qA-vJx"/>
<exclude reference="Dmq-W5-Xkr"/>
<exclude reference="IQe-4d-baG"/>
<include reference="Wbl-He-blg"/>
<include reference="byS-fb-Uet"/>
<exclude reference="ikW-Es-Ngp"/>
<include reference="opm-uv-Fhc"/>
</mask>
</variation>
</tableViewCellContentView>
<animations/>
<connections>
<outlet property="archiveImageView" destination="WyX-Hb-Mpn" id="99i-j3-F49"/>
<outlet property="archiveView" destination="yBY-TS-2tI" id="Olb-KX-yw5"/>
<outlet property="contactPictureView" destination="p9o-x6-nT5" id="oUA-O3-JIc"/>
<outlet property="contentContainerView" destination="kq8-RD-txC" id="yaJ-z3-8sC"/>
<outlet property="nameLabel" destination="gWV-cB-qZe" id="drr-G2-EB6"/>
<outlet property="messageCounter" destination="KNJ-HQ-UVM" id="Ysu-EC-k1P"/>
<outlet property="nameLabel" destination="mfN-2A-QxN" id="Jr0-05-R1t"/>
<outlet property="scrollView" destination="bG5-iK-ql3" id="wEp-AH-Pdu"/>
<outlet property="snippetLabel" destination="Qgj-EY-BWC" id="EIb-je-Cw5"/>
<outlet property="timeLabel" destination="bp6-EC-9eP" id="O4O-ST-o3v"/>
@ -216,6 +138,5 @@
</objects>
<resources>
<image name="cellBtnMoveToArchive--blue" width="30" height="30"/>
<image name="contact_default_feed.png" width="242" height="242"/>
</resources>
</document>

View File

@ -29,6 +29,9 @@
- (void)setupWithTSIdentifier:(NSString*)identifier;
- (void)setupWithTSGroup:(TSGroupModel*)model;
- (void)peekSetup;
- (void)popped;
- (void)setComposeOnOpen:(BOOL)compose;
- (TSThread*)thread;

View File

@ -9,6 +9,7 @@
#import "AppDelegate.h"
#import <AddressBookUI/AddressBookUI.h>
#import <ContactsUI/CNContactViewController.h>
#import "MessagesViewController.h"
#import "FullImageViewController.h"
@ -99,6 +100,7 @@ typedef enum : NSUInteger {
@property BOOL isVisible;
@property (nonatomic) BOOL composeOnOpen;
@property (nonatomic) BOOL peek;
@end
@ -131,6 +133,16 @@ typedef enum : NSUInteger {
isGroupConversation = YES;
}
- (void)peekSetup {
_peek = YES;
[self setComposeOnOpen:NO];
}
- (void)popped {
_peek = NO;
[self hideInputIfNeeded];
}
- (void)setComposeOnOpen:(BOOL)compose {
_composeOnOpen = compose;
}
@ -145,13 +157,18 @@ typedef enum : NSUInteger {
}
- (void)hideInputIfNeeded {
if (_peek) {
[self inputToolbar].hidden = YES;
return;
}
if([_thread isKindOfClass:[TSGroupThread class]] && ![((TSGroupThread*)_thread).groupModel.groupMemberIds containsObject:[SignalKeyingStorage.localNumber toE164]]) {
[self inputToolbar].hidden= YES; // user has requested they leave the group. further sends disallowed
self.navigationItem.rightBarButtonItem = nil; // further group action disallowed
}
else if(![self isTextSecureReachable] ){
} else if(![self isTextSecureReachable] ){
[self inputToolbar].hidden= YES; // only RedPhone
} else {
[self inputToolbar].hidden= NO;
[self loadDraftInCompose];
}
}
@ -234,22 +251,28 @@ typedef enum : NSUInteger {
}
- (void)viewDidAppear:(BOOL)animated {
[self updateBackButton];
[super viewDidAppear:animated];
[self markAllMessagesAsRead];
[self startReadTimer];
_isVisible = YES;
[self initializeTitleLabelGestureRecognizer];
[self updateBackButton];
[self updateBackButtonAsync];
if (_composeOnOpen) {
[self popKeyBoard];
}
}
- (void)updateBackButton {
[self setUnreadCount:[[TSMessagesManager sharedManager] unreadMessagesCountExcept:self.thread]];
- (void)updateBackButtonAsync {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSUInteger count = [[TSMessagesManager sharedManager] unreadMessagesCountExcept:self.thread];
dispatch_async(dispatch_get_main_queue() , ^{
if (self) {
[self setUnreadCount:count];
}
});
});
}
- (void)viewWillDisappear:(BOOL)animated {
@ -474,22 +497,53 @@ typedef enum : NSUInteger {
Contact *contact = [[[Environment getCurrent] contactsManager] latestContactForPhoneNumber:[self phoneNumberForThread]];
if (!contact) {
ABUnknownPersonViewController *view = [[ABUnknownPersonViewController alloc] init];
ABRecordRef aContact = ABPersonCreate();
CFErrorRef anError = NULL;
ABMultiValueRef phone = ABMultiValueCreateMutable(kABMultiStringPropertyType);
ABMultiValueAddValueAndLabel(phone, (__bridge CFTypeRef) [self phoneNumberForThread].toE164, kABPersonPhoneMainLabel, NULL);
ABRecordSetValue(aContact, kABPersonPhoneProperty, phone, &anError);
CFRelease(phone);
if (!anError && aContact) {
view.displayedPerson = aContact; // Assume person is already defined.
view.allowsAddingToAddressBook = YES;
[self.navigationController pushViewController:view animated:YES];
if (!(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(NSFoundationVersionNumber_iOS_9))) {
ABUnknownPersonViewController *view = [[ABUnknownPersonViewController alloc] init];
ABRecordRef aContact = ABPersonCreate();
CFErrorRef anError = NULL;
ABMultiValueRef phone = ABMultiValueCreateMutable(kABMultiStringPropertyType);
ABMultiValueAddValueAndLabel(phone, (__bridge CFTypeRef) [self phoneNumberForThread].toE164, kABPersonPhoneMainLabel, NULL);
ABRecordSetValue(aContact, kABPersonPhoneProperty, phone, &anError);
CFRelease(phone);
if (!anError && aContact) {
view.displayedPerson = aContact; // Assume person is already defined.
view.allowsAddingToAddressBook = YES;
[self.navigationController pushViewController:view animated:YES];
}
} else {
CNContactStore *contactStore = [Environment getCurrent].contactsManager.contactStore;
CNMutableContact *cncontact = [[CNMutableContact alloc] init];
cncontact.phoneNumbers = @[[CNLabeledValue labeledValueWithLabel:nil value:[CNPhoneNumber phoneNumberWithStringValue:[self phoneNumberForThread].toE164]]];
CNContactViewController *controller = [CNContactViewController viewControllerForUnknownContact:cncontact];
controller.allowsActions = NO;
controller.allowsEditing = YES;
controller.contactStore = contactStore;
[self.navigationController pushViewController:controller animated:YES];
// The "Add to existing contacts" is known to be destroying the view controller stack on iOS 9 http://stackoverflow.com/questions/32973254/cncontactviewcontroller-forunknowncontact-unusable-destroys-interface
// Warning the user
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"iOS 9 Bug" message:@"iOS 9 introduced a bug that prevents us from adding this number to an existing contact from the app. You can still create a new contact for this number or copy-paste it into an existing contact sheet." preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:[UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleCancel handler:nil]];
[alertController addAction:[UIAlertAction actionWithTitle:@"Copy number" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
pasteboard.string = [self phoneNumberForThread].toE164;
[controller.navigationController popViewControllerAnimated:YES];
}]];
[controller presentViewController:alertController animated:YES completion:nil];
}
}
}
@ -1349,7 +1403,7 @@ typedef enum : NSUInteger {
- (void)yapDatabaseModified:(NSNotification *)notification {
[self updateBackButton];
[self updateBackButtonAsync];
if(isGroupConversation) {
[self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {

View File

@ -13,7 +13,7 @@
#import "TSGroupModel.h"
#import "CallState.h"
@interface SignalsViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, TableViewCellDelegate>
@interface SignalsViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, TableViewCellDelegate, UIViewControllerPreviewingDelegate>
@property (nonatomic) NSString *contactIdentifierFromCompose;
@property (nonatomic) TSGroupModel *groupFromCompose;

View File

@ -27,8 +27,6 @@
#define CELL_HEIGHT 72.0f
#define HEADER_HEIGHT 44.0f
static NSString *const inboxTableViewCell = @"inBoxTableViewCell";
static NSString *const kSegueIndentifier = @"showSegue";
static NSString* const kShowSignupFlowSegue = @"showSignupFlow";
@ -40,6 +38,7 @@ static NSString* const kShowSignupFlowSegue = @"showSignupFlow";
@property (nonatomic) CellState viewingThreadsIn;
@property (nonatomic) long inboxCount;
@property (nonatomic, retain) UISegmentedControl *segmentedControl;
@property (nonatomic) NSArray<id<UIPreviewActionItem>> *previewActions;
@end
@ -75,6 +74,56 @@ static NSString* const kShowSignupFlowSegue = @"showSignupFlow";
[self.segmentedControl addTarget:self action:@selector(swappedSegmentedControl) forControlEvents:UIControlEventValueChanged];
self.navigationItem.titleView = self.segmentedControl;
[self.segmentedControl setSelectedSegmentIndex:0];
if ([self.traitCollection
respondsToSelector:@selector(forceTouchCapability)] &&
(self.traitCollection.forceTouchCapability ==
UIForceTouchCapabilityAvailable))
{
[self registerForPreviewingWithDelegate:self sourceView:self.view];
}
}
- (UIViewController *)previewingContext:
(id<UIViewControllerPreviewing>)previewingContext
viewControllerForLocation:(CGPoint)location {
NSIndexPath *indexPath = [self.tableView
indexPathForRowAtPoint:location];
MessagesViewController * vc = [[MessagesViewController alloc] initWithNibName:nil bundle:nil];
TSThread *thread = [self threadForIndexPath:indexPath];
[vc setupWithThread:thread];
[vc peekSetup];
return vc;
}
- (void)previewingContext:(id<UIViewControllerPreviewing>)previewingContext
commitViewController:(UIViewController *)viewControllerToCommit {
MessagesViewController *vc = (MessagesViewController*)viewControllerToCommit;
[vc popped];
[self.navigationController pushViewController:vc
animated:NO];
}
- (NSArray<id<UIPreviewActionItem>> *)previewActionItems {
return self.previewActions;
}
- (NSArray<id<UIPreviewActionItem>> *)previewActions {
if (_previewActions == nil) {
UIPreviewAction *printAction = [UIPreviewAction
actionWithTitle:@"Print"
style:UIPreviewActionStyleDefault
handler:^(UIPreviewAction * _Nonnull action,
UIViewController * _Nonnull previewViewController) {
// ... code to handle action here
}];
_previewActions = @[printAction];
}
return _previewActions;
}
- (void)swappedSegmentedControl {
@ -117,7 +166,7 @@ static NSString* const kShowSignupFlowSegue = @"showSignupFlow";
- (InboxTableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {
InboxTableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:inboxTableViewCell];
InboxTableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:NSStringFromClass([InboxTableViewCell class])];
TSThread *thread = [self threadForIndexPath:indexPath];
if (!cell) {
@ -125,8 +174,10 @@ static NSString* const kShowSignupFlowSegue = @"showSignupFlow";
cell.delegate = self;
}
[cell configureWithThread:thread];
[cell configureForState:self.viewingThreadsIn == kInboxState ? kInboxState : kArchiveState];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[cell configureWithThread:thread];
[cell configureForState:self.viewingThreadsIn == kInboxState ? kInboxState : kArchiveState];
});
if ((unsigned long)indexPath.row == [self.threadMappings numberOfItemsInSection:0]-1) {
cell.separatorInset = UIEdgeInsetsMake(0.f, cell.bounds.size.width, 0.f, 0.f);