@ -37,6 +37,7 @@
#import "UIFont + OWS . h "
#import "UIFont + OWS . h "
#import "UIUtil . h "
#import "UIUtil . h "
#import "UIViewController + CameraPermissions . h "
#import "UIViewController + CameraPermissions . h "
#import "UIViewController + OWS . h "
#import < AddressBookUI / AddressBookUI . h >
#import < AddressBookUI / AddressBookUI . h >
#import < ContactsUI / CNContactViewController . h >
#import < ContactsUI / CNContactViewController . h >
#import < JSQMessagesViewController / JSQMessagesBubbleImage . h >
#import < JSQMessagesViewController / JSQMessagesBubbleImage . h >
@ -108,7 +109,9 @@ typedef enum : NSUInteger {
@ property ( nonatomic , strong ) TSVideoAttachmentAdapter * currentMediaAdapter ;
@ property ( nonatomic , strong ) TSVideoAttachmentAdapter * currentMediaAdapter ;
@ property ( nonatomic , retain ) NSTimer * readTimer ;
@ property ( nonatomic , retain ) NSTimer * readTimer ;
@ property ( nonatomic , strong ) UILabel * navbarTitleLabel ;
@ property ( nonatomic , strong ) UIView * navigationBarTitleView ;
@ property ( nonatomic , strong ) UILabel * navigationBarTitleLabel ;
@ property ( nonatomic , strong ) UILabel * navigationBarSubtitleLabel ;
@ property ( nonatomic , retain ) UIButton * attachButton ;
@ property ( nonatomic , retain ) UIButton * attachButton ;
@ property ( nonatomic ) CGFloat previousCollectionViewFrameWidth ;
@ property ( nonatomic ) CGFloat previousCollectionViewFrameWidth ;
@ -281,11 +284,6 @@ typedef enum : NSUInteger {
}
}
}
}
- ( void ) didMoveToParentViewController : ( UIViewController * ) parent
{
[ self setupTitleLabelGestureRecognizer ] ;
}
- ( void ) registerCustomMessageNibs
- ( void ) registerCustomMessageNibs
{
{
[ self . collectionView registerNib : [ OWSCallCollectionViewCell nib ]
[ self . collectionView registerNib : [ OWSCallCollectionViewCell nib ]
@ -495,48 +493,163 @@ typedef enum : NSUInteger {
if ( isGroupConversation && [ navTitle length ] == 0 ) {
if ( isGroupConversation && [ navTitle length ] == 0 ) {
navTitle = NSLocalizedString ( @ "NEW_GROUP_DEFAULT_TITLE ", @ "") ;
navTitle = NSLocalizedString ( @ "NEW_GROUP_DEFAULT_TITLE ", @ "") ;
}
}
self . title = navTitle ;
self . title = nil ;
if ( [ navTitle isEqualToString : self . navigationBarTitleLabel . text ] ) {
return ;
}
self . navigationBarTitleLabel . text = navTitle ;
/ / Changing the title requires relayout of the nav bar contents .
OWSDisappearingMessagesConfiguration * configuration =
[ OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID : self . thread . uniqueId ] ;
[ self setBarButtonItemsForDisappearingMessagesConfiguration : configuration ] ;
}
}
- ( void ) setBarButtonItemsForDisappearingMessagesConfiguration :
- ( void ) setBarButtonItemsForDisappearingMessagesConfiguration :
( OWSDisappearingMessagesConfiguration * ) disappearingMessagesConfiguration
( OWSDisappearingMessagesConfiguration * ) disappearingMessagesConfiguration
{
{
UIBarButtonItem * backItem = [ self createOWSBackButton ] ;
const CGFloat kTitleVSpacing = 0. f ;
if ( !self . navigationBarTitleView ) {
self . navigationBarTitleView = [ UIView new ] ;
[ self . navigationBarTitleView addGestureRecognizer : [ [ UITapGestureRecognizer alloc ] initWithTarget : self
action : @ selector ( navigationTitleTapped : ) ] ] ;
self . navigationBarTitleLabel = [ UILabel new ] ;
self . navigationBarTitleLabel . textColor = [ UIColor whiteColor ] ;
self . navigationBarTitleLabel . font = [ UIFont ows_boldFontWithSize : 18. f ] ;
self . navigationBarTitleLabel . lineBreakMode = NSLineBreakByTruncatingTail ;
[ self . navigationBarTitleView addSubview : self . navigationBarTitleLabel ] ;
self . navigationBarSubtitleLabel = [ UILabel new ] ;
self . navigationBarSubtitleLabel . textColor = [ UIColor colorWithWhite : 0.85 f alpha : 1. f ] ;
self . navigationBarSubtitleLabel . font = [ UIFont ows_boldFontWithSize : 9. f ] ;
self . navigationBarSubtitleLabel . text = NSLocalizedString ( @ "MESSAGES_VIEW_TITLE_SUBTITLE ",
@ "The subtitle for the messages view title indicates that the title can be tapped to access settings for this conversation . ") ;
[ self . navigationBarTitleView addSubview : self . navigationBarSubtitleLabel ] ;
}
/ / We need to manually resize and position the title views ;
/ / iOS AutoLayout doesn ' t work inside navigation bar items .
[ self . navigationBarTitleLabel sizeToFit ] ;
[ self . navigationBarSubtitleLabel sizeToFit ] ;
const CGFloat kShortScreenDimension = MIN ( [ UIScreen mainScreen ] . bounds . size . width ,
[ UIScreen mainScreen ] . bounds . size . height ) ;
/ / We want to leave space for the "back " button , the "timer " button , and the "call "
/ / button , and all of the whitespace around these views . There
/ / isn ' t a convenient way to calculate these in a navigation bar , so we just leave
/ / a constant amount of space which will be safe unless Apple makes radical changes
/ / to the appearance of the navigation bar .
int rightBarButtonItemCount = 0 ;
if ( [ self canCall ] ) {
rightBarButtonItemCount + + ;
}
if ( disappearingMessagesConfiguration . isEnabled ) {
rightBarButtonItemCount + + ;
}
CGFloat rightBarButtonSize = 0 ;
switch ( rightBarButtonItemCount ) {
case 0 :
rightBarButtonSize = 65 ;
break ;
case 1 :
rightBarButtonSize = 100 ;
break ;
default :
OWSAssert ( 0 ) ;
/ / In production , fall through to the largest defined case .
case 2 :
rightBarButtonSize = 145 ;
break ;
}
CGFloat maxTitleViewWidth = kShortScreenDimension - rightBarButtonSize ;
const CGFloat titleViewWidth = MIN ( maxTitleViewWidth ,
MAX ( self . navigationBarTitleLabel . frame . size . width ,
self . navigationBarSubtitleLabel . frame . size . width ) ) ;
self . navigationBarTitleView . frame = CGRectMake ( 0 , 0 ,
titleViewWidth ,
self . navigationBarTitleLabel . frame . size . height +
self . navigationBarSubtitleLabel . frame . size . height +
kTitleVSpacing ) ;
self . navigationBarTitleLabel . frame = CGRectMake ( 0 ,
0 ,
titleViewWidth ,
self . navigationBarTitleLabel . frame . size . height ) ;
self . navigationBarSubtitleLabel . frame = CGRectMake ( 0 ,
self . navigationBarTitleView . frame . size . height - self . navigationBarSubtitleLabel . frame . size . height ,
titleViewWidth ,
self . navigationBarSubtitleLabel . frame . size . height ) ;
self . navigationItem . leftBarButtonItems = @ [
backItem ,
[ [ UIBarButtonItem alloc ] initWithCustomView : self . navigationBarTitleView ] ,
] ;
if ( self . userLeftGroup ) {
if ( self . userLeftGroup ) {
self . navigationItem . rightBarButtonItems = @ [ ] ;
self . navigationItem . rightBarButtonItems = @ [ ] ;
return ;
return ;
}
}
const CGFloat kBarButtonSize = 44 ;
NSMutableArray < UIBarButtonItem * > * barButtons = [ NSMutableArray new ] ;
NSMutableArray < UIBarButtonItem * > * barButtons = [ NSMutableArray new ] ;
if ( [ self canCall ] ) {
if ( [ self canCall ] ) {
UIBarButtonItem * callButton = [ [ UIBarButtonItem alloc ] initWithImage : [ UIImage imageNamed : @ "btnPhone - - white "]
/ / We use UIButtons with [ UIBarButtonItem initWithCustomView : ...] instead of
style : UIBarButtonItemStylePlain
/ / UIBarButtonItem in order to ensure that these buttons are spaced tightly .
target : self
/ / The contents of the navigation bar are cramped in this view .
action : @ selector ( callAction ) ] ;
UIButton * callButton = [ UIButton buttonWithType : UIButtonTypeCustom ] ;
UIImage * image = [ UIImage imageNamed : @ "button_phone_white "] ;
[ callButton setImage : image
forState : UIControlStateNormal ] ;
UIEdgeInsets imageEdgeInsets = UIEdgeInsetsZero ;
/ / We normally would want to use left and right insets that ensure the button
/ / is square and the icon is centered . However UINavigationBar doesn ' t offer us
/ / control over the margins and spacing of its content , and the buttons end up
/ / too far apart and too far from the edge of the screen . So we use a smaller
/ / right inset tighten up the layout .
imageEdgeInsets . left = round ( ( kBarButtonSize - image . size . width ) * 0.5 f ) ;
imageEdgeInsets . right = round ( ( kBarButtonSize - ( image . size . width + imageEdgeInsets . left ) ) * 0.5 f ) ;
imageEdgeInsets . top = round ( ( kBarButtonSize - image . size . height ) * 0.5 f ) ;
imageEdgeInsets . bottom = round ( kBarButtonSize - ( image . size . height + imageEdgeInsets . top ) ) ;
callButton . imageEdgeInsets = imageEdgeInsets ;
callButton . accessibilityLabel = NSLocalizedString ( @ "CALL_LABEL ", "Accessibilty label for placing call button ") ;
callButton . accessibilityLabel = NSLocalizedString ( @ "CALL_LABEL ", "Accessibilty label for placing call button ") ;
callButton . imageInsets = UIEdgeInsetsMake ( 0 , - 10 , 0 , 10 ) ;
[ callButton addTarget : self
[ barButtons addObject : callButton ] ;
action : @ selector ( callAction : )
} else if ( [ self . thread isGroupThread ] ) {
forControlEvents : UIControlEventTouchUpInside ] ;
UIBarButtonItem * manageGroupButton =
callButton . frame = CGRectMake ( 0 , 0 ,
[ [ UIBarButtonItem alloc ] initWithImage : [ UIImage imageNamed : @ "contact - options - action "]
round ( image . size . width + imageEdgeInsets . left + imageEdgeInsets . right ) ,
style : UIBarButtonItemStylePlain
round ( image . size . height + imageEdgeInsets . top + imageEdgeInsets . bottom ) ) ;
target : self
[ barButtons addObject : [ [ UIBarButtonItem alloc ] initWithCustomView : callButton ] ] ;
action : @ selector ( didTapManageGroupButton : ) ] ;
/ / Hack to shrink button image
manageGroupButton . imageInsets = UIEdgeInsetsMake ( 10 , 20 , 10 , 0 ) ;
manageGroupButton . accessibilityLabel = NSLocalizedString ( @ "GROUP_SETTINGS_LABEL ", @ "Accessibilty label for group settings ") ;
[ barButtons addObject : manageGroupButton ] ;
}
}
if ( disappearingMessagesConfiguration . isEnabled ) {
if ( disappearingMessagesConfiguration . isEnabled ) {
UIBarButtonItem * timerButton = [ [ UIBarButtonItem alloc ] initWithImage : [ UIImage imageNamed : @ "ic_timer "]
UIButton * timerButton = [ UIButton buttonWithType : UIButtonTypeCustom ] ;
style : UIBarButtonItemStylePlain
UIImage * image = [ UIImage imageNamed : @ "button_timer_white "] ;
target : self
[ timerButton setImage : image
action : @ selector ( didTapTimerInNavbar ) ] ;
forState : UIControlStateNormal ] ;
UIEdgeInsets imageEdgeInsets = UIEdgeInsetsZero ;
/ / We normally would want to use left and right insets that ensure the button
/ / is square and the icon is centered . However UINavigationBar doesn ' t offer us
/ / control over the margins and spacing of its content , and the buttons end up
/ / too far apart and too far from the edge of the screen . So we use a smaller
/ / right inset tighten up the layout .
imageEdgeInsets . left = round ( ( kBarButtonSize - image . size . width ) * 0.5 f ) ;
imageEdgeInsets . right = round ( ( kBarButtonSize - ( image . size . width + imageEdgeInsets . left ) ) * 0.5 f ) ;
imageEdgeInsets . top = round ( ( kBarButtonSize - image . size . height ) * 0.5 f ) ;
imageEdgeInsets . bottom = round ( kBarButtonSize - ( image . size . height + imageEdgeInsets . top ) ) ;
timerButton . imageEdgeInsets = imageEdgeInsets ;
timerButton . accessibilityLabel = NSLocalizedString ( @ "DISAPPEARING_MESSAGES_LABEL ", @ "Accessibility label for disappearing messages ") ;
timerButton . accessibilityLabel = NSLocalizedString ( @ "DISAPPEARING_MESSAGES_LABEL ", @ "Accessibility label for disappearing messages ") ;
NSString * formatString = NSLocalizedString ( @ "DISAPPEARING_MESSAGES_HINT ", @ "Accessibility hint that contains current timeout information ") ;
NSString * formatString = NSLocalizedString ( @ "DISAPPEARING_MESSAGES_HINT ", @ "Accessibility hint that contains current timeout information ") ;
timerButton . accessibilityHint = [ NSString stringWithFormat : formatString , [ disappearingMessagesConfiguration durationString ] ] ;
timerButton . accessibilityHint = [ NSString stringWithFormat : formatString , [ disappearingMessagesConfiguration durationString ] ] ;
[ barButtons addObject : timerButton ] ;
[ timerButton addTarget : self
action : @ selector ( didTapTimerInNavbar : )
forControlEvents : UIControlEventTouchUpInside ] ;
timerButton . frame = CGRectMake ( 0 , 0 ,
round ( image . size . width + imageEdgeInsets . left + imageEdgeInsets . right ) ,
round ( image . size . height + imageEdgeInsets . top + imageEdgeInsets . bottom ) ) ;
[ barButtons addObject : [ [ UIBarButtonItem alloc ] initWithCustomView : timerButton ] ] ;
}
}
self . navigationItem . rightBarButtonItems = [ barButtons copy ] ;
self . navigationItem . rightBarButtonItems = [ barButtons copy ] ;
@ -554,28 +667,6 @@ typedef enum : NSUInteger {
self . inputToolbar . maximumHeight = 300 ;
self . inputToolbar . maximumHeight = 300 ;
}
}
- ( void ) setupTitleLabelGestureRecognizer
{
/ / Called on load / unload , but we only want to init once .
if ( self . navbarTitleLabel ) {
return ;
}
UILabel * navbarTitleLabel = [ self findNavbarTitleLabel ] ;
if ( !navbarTitleLabel ) {
DDLogError ( @ "%@ Unable to find navbar title label. Skipping gesture recognition", self.tag);
return ;
}
self . navbarTitleLabel = navbarTitleLabel ;
navbarTitleLabel . userInteractionEnabled = YES ;
navbarTitleLabel . superview . userInteractionEnabled = YES ;
UITapGestureRecognizer * titleTapRecognizer =
[ [ UITapGestureRecognizer alloc ] initWithTarget : self action : @ selector ( didTapTitle ) ] ;
[ navbarTitleLabel addGestureRecognizer : titleTapRecognizer ] ;
}
- ( nullable UILabel * ) findNavbarTitleLabel
- ( nullable UILabel * ) findNavbarTitleLabel
{
{
for ( UIView * view in self . navigationController . navigationBar . subviews ) {
for ( UIView * view in self . navigationController . navigationBar . subviews ) {
@ -637,7 +728,7 @@ typedef enum : NSUInteger {
#pragma mark - Calls
#pragma mark - Calls
- ( void ) callAction {
- ( void ) callAction : ( id ) sender {
OWSAssert ( [ self . thread isKindOfClass : [ TSContactThread class ] ] ) ;
OWSAssert ( [ self . thread isKindOfClass : [ TSContactThread class ] ] ) ;
if ( ![ self canCall ] ) {
if ( ![ self canCall ] ) {
@ -1129,13 +1220,7 @@ typedef enum : NSUInteger {
[ self showConversationSettings ] ;
[ self showConversationSettings ] ;
}
}
- ( void ) didTapManageGroupButton : ( id ) sender
- ( void ) didTapTimerInNavbar : ( id ) sender
{
DDLogDebug ( @ "%@ Tapped options menu in navbar", self.tag);
[ self showConversationSettings ] ;
}
- ( void ) didTapTimerInNavbar
{
{
DDLogDebug ( @ "%@ Tapped timer in navbar", self.tag);
DDLogDebug ( @ "%@ Tapped timer in navbar", self.tag);
[ self showConversationSettings ] ;
[ self showConversationSettings ] ;
@ -2316,6 +2401,14 @@ typedef enum : NSUInteger {
return @ [ ] ;
return @ [ ] ;
}
}
#pragma mark - Event Handling
- ( void ) navigationTitleTapped : ( UIGestureRecognizer * ) gestureRecognizer {
if ( gestureRecognizer . state == UIGestureRecognizerStateRecognized ) {
[ self showConversationSettings ] ;
}
}
#pragma mark - Logging
#pragma mark - Logging
+ ( NSString * ) tag
+ ( NSString * ) tag