diff --git a/Signal/Images.xcassets/NavBarBack.imageset/Contents.json b/Signal/Images.xcassets/NavBarBack.imageset/Contents.json new file mode 100644 index 000000000..c218bb0d1 --- /dev/null +++ b/Signal/Images.xcassets/NavBarBack.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "NavBarBackWhite@1x.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "NavBarBackWhite@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "NavBarBackWhite@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Signal/Images.xcassets/NavBarBack.imageset/NavBarBackWhite@1x.png b/Signal/Images.xcassets/NavBarBack.imageset/NavBarBackWhite@1x.png new file mode 100644 index 000000000..b3b418577 Binary files /dev/null and b/Signal/Images.xcassets/NavBarBack.imageset/NavBarBackWhite@1x.png differ diff --git a/Signal/Images.xcassets/NavBarBack.imageset/NavBarBackWhite@2x.png b/Signal/Images.xcassets/NavBarBack.imageset/NavBarBackWhite@2x.png new file mode 100644 index 000000000..dcaa33b20 Binary files /dev/null and b/Signal/Images.xcassets/NavBarBack.imageset/NavBarBackWhite@2x.png differ diff --git a/Signal/Images.xcassets/NavBarBack.imageset/NavBarBackWhite@3x.png b/Signal/Images.xcassets/NavBarBack.imageset/NavBarBackWhite@3x.png new file mode 100644 index 000000000..fb55818f3 Binary files /dev/null and b/Signal/Images.xcassets/NavBarBack.imageset/NavBarBackWhite@3x.png differ diff --git a/Signal/Images.xcassets/phone_white_thin.imageset/Contents.json b/Signal/Images.xcassets/phone_white_thin.imageset/Contents.json new file mode 100644 index 000000000..313e1dfa3 --- /dev/null +++ b/Signal/Images.xcassets/phone_white_thin.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "phone_white_thin@1x.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "phone_white_thin@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "phone_white_thin@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Signal/Images.xcassets/phone_white_thin.imageset/phone_white_thin@1x.png b/Signal/Images.xcassets/phone_white_thin.imageset/phone_white_thin@1x.png new file mode 100644 index 000000000..4a7cc84a7 Binary files /dev/null and b/Signal/Images.xcassets/phone_white_thin.imageset/phone_white_thin@1x.png differ diff --git a/Signal/Images.xcassets/phone_white_thin.imageset/phone_white_thin@2x.png b/Signal/Images.xcassets/phone_white_thin.imageset/phone_white_thin@2x.png new file mode 100644 index 000000000..9a5fcef42 Binary files /dev/null and b/Signal/Images.xcassets/phone_white_thin.imageset/phone_white_thin@2x.png differ diff --git a/Signal/Images.xcassets/phone_white_thin.imageset/phone_white_thin@3x.png b/Signal/Images.xcassets/phone_white_thin.imageset/phone_white_thin@3x.png new file mode 100644 index 000000000..3002a9820 Binary files /dev/null and b/Signal/Images.xcassets/phone_white_thin.imageset/phone_white_thin@3x.png differ diff --git a/Signal/Images.xcassets/settings_white_thin.imageset/Contents.json b/Signal/Images.xcassets/settings_white_thin.imageset/Contents.json new file mode 100644 index 000000000..a20c2e0a9 --- /dev/null +++ b/Signal/Images.xcassets/settings_white_thin.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "settings_white_thin@1x.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "settings_white_thin@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "settings_white_thin@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Signal/Images.xcassets/settings_white_thin.imageset/settings_white_thin@1x.png b/Signal/Images.xcassets/settings_white_thin.imageset/settings_white_thin@1x.png new file mode 100644 index 000000000..002908a3f Binary files /dev/null and b/Signal/Images.xcassets/settings_white_thin.imageset/settings_white_thin@1x.png differ diff --git a/Signal/Images.xcassets/settings_white_thin.imageset/settings_white_thin@2x.png b/Signal/Images.xcassets/settings_white_thin.imageset/settings_white_thin@2x.png new file mode 100644 index 000000000..a68c6c57f Binary files /dev/null and b/Signal/Images.xcassets/settings_white_thin.imageset/settings_white_thin@2x.png differ diff --git a/Signal/Images.xcassets/settings_white_thin.imageset/settings_white_thin@3x.png b/Signal/Images.xcassets/settings_white_thin.imageset/settings_white_thin@3x.png new file mode 100644 index 000000000..565619576 Binary files /dev/null and b/Signal/Images.xcassets/settings_white_thin.imageset/settings_white_thin@3x.png differ diff --git a/Signal/Images.xcassets/timer_white_thin.imageset/Contents.json b/Signal/Images.xcassets/timer_white_thin.imageset/Contents.json new file mode 100644 index 000000000..55a0c8af3 --- /dev/null +++ b/Signal/Images.xcassets/timer_white_thin.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "timer_white_thin@1x.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "timer_white_thin@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "timer_white_thin@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Signal/Images.xcassets/timer_white_thin.imageset/timer_white_thin@1x.png b/Signal/Images.xcassets/timer_white_thin.imageset/timer_white_thin@1x.png new file mode 100644 index 000000000..92d5d3bec Binary files /dev/null and b/Signal/Images.xcassets/timer_white_thin.imageset/timer_white_thin@1x.png differ diff --git a/Signal/Images.xcassets/timer_white_thin.imageset/timer_white_thin@2x.png b/Signal/Images.xcassets/timer_white_thin.imageset/timer_white_thin@2x.png new file mode 100644 index 000000000..946c330fe Binary files /dev/null and b/Signal/Images.xcassets/timer_white_thin.imageset/timer_white_thin@2x.png differ diff --git a/Signal/Images.xcassets/timer_white_thin.imageset/timer_white_thin@3x.png b/Signal/Images.xcassets/timer_white_thin.imageset/timer_white_thin@3x.png new file mode 100644 index 000000000..0aa4a5af0 Binary files /dev/null and b/Signal/Images.xcassets/timer_white_thin.imageset/timer_white_thin@3x.png differ diff --git a/Signal/src/view controllers/MessagesViewController.m b/Signal/src/view controllers/MessagesViewController.m index e6cd6ac0a..6180ef009 100644 --- a/Signal/src/view controllers/MessagesViewController.m +++ b/Signal/src/view controllers/MessagesViewController.m @@ -108,7 +108,9 @@ typedef enum : NSUInteger { @property (nonatomic, strong) TSVideoAttachmentAdapter *currentMediaAdapter; @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) CGFloat previousCollectionViewFrameWidth; @@ -281,11 +283,6 @@ typedef enum : NSUInteger { } } -- (void)didMoveToParentViewController:(UIViewController *)parent -{ - [self setupTitleLabelGestureRecognizer]; -} - - (void)registerCustomMessageNibs { [self.collectionView registerNib:[OWSCallCollectionViewCell nib] @@ -495,13 +492,81 @@ typedef enum : NSUInteger { if (isGroupConversation && [navTitle length] == 0) { 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: (OWSDisappearingMessagesConfiguration *)disappearingMessagesConfiguration - { + UIImage *backImage = [UIImage imageNamed:@"NavBarBack"]; + OWSAssert(backImage); + UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithImage:backImage style:UIBarButtonItemStylePlain target:self action:@selector(backButtonPressed:)]; + + 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.85f 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, the "call" or + // "group settings" 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. + const CGFloat kMaxTitleViewWidth = kShortScreenDimension - 145; + const CGFloat titleViewWidth = MIN(kMaxTitleViewWidth, + 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) { self.navigationItem.rightBarButtonItems = @[]; return; @@ -509,36 +574,48 @@ typedef enum : NSUInteger { NSMutableArray *barButtons = [NSMutableArray new]; if ([self canCall]) { - UIBarButtonItem *callButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"btnPhone--white"] - style:UIBarButtonItemStylePlain - target:self - action:@selector(callAction)]; + // We use UIButtons with [UIBarButtonItem initWithCustomView:...] instead of + // UIBarButtonItem in order to ensure that these buttons are spaced tightly. + // The contents of the navigation bar are cramped in this view. + UIButton *callButton = [UIButton buttonWithType:UIButtonTypeCustom]; + // The "phone_white_thin" image is slightly assymetric in order + // to avoid an excessive margin against the right edge of the screen. + [callButton setImage:[UIImage imageNamed:@"phone_white_thin"] + forState:UIControlStateNormal]; callButton.accessibilityLabel = NSLocalizedString(@"CALL_LABEL", "Accessibilty label for placing call button"); - callButton.imageInsets = UIEdgeInsetsMake(0, -10, 0, 10); - [barButtons addObject:callButton]; + [callButton addTarget:self + action:@selector(callAction:) + forControlEvents:UIControlEventTouchUpInside]; + [callButton sizeToFit]; + [barButtons addObject:[[UIBarButtonItem alloc] initWithCustomView:callButton]]; } else if ([self.thread isGroupThread]) { - UIBarButtonItem *manageGroupButton = - [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"contact-options-action"] - style:UIBarButtonItemStylePlain - target:self - action:@selector(didTapManageGroupButton:)]; - // Hack to shrink button image - manageGroupButton.imageInsets = UIEdgeInsetsMake(10, 20, 10, 0); + UIButton *manageGroupButton = [UIButton buttonWithType:UIButtonTypeCustom]; + // The "phone_white_thin" image is slightly assymetric in order + // to avoid an excessive margin against the right edge of the screen. + [manageGroupButton setImage:[UIImage imageNamed:@"settings_white_thin"] + forState:UIControlStateNormal]; manageGroupButton.accessibilityLabel = NSLocalizedString(@"GROUP_SETTINGS_LABEL", @"Accessibilty label for group settings"); - [barButtons addObject:manageGroupButton]; + [manageGroupButton addTarget:self + action:@selector(didTapManageGroupButton:) + forControlEvents:UIControlEventTouchUpInside]; + [manageGroupButton sizeToFit]; + [barButtons addObject:[[UIBarButtonItem alloc] initWithCustomView:manageGroupButton]]; } if (disappearingMessagesConfiguration.isEnabled) { - UIBarButtonItem *timerButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ic_timer"] - style:UIBarButtonItemStylePlain - target:self - action:@selector(didTapTimerInNavbar)]; + UIButton *timerButton = [UIButton buttonWithType:UIButtonTypeCustom]; + [timerButton setImage:[UIImage imageNamed:@"timer_white_thin"] + forState:UIControlStateNormal]; timerButton.accessibilityLabel = NSLocalizedString(@"DISAPPEARING_MESSAGES_LABEL", @"Accessibility label for disappearing messages"); NSString *formatString = NSLocalizedString(@"DISAPPEARING_MESSAGES_HINT", @"Accessibility hint that contains current timeout information"); timerButton.accessibilityHint = [NSString stringWithFormat:formatString, [disappearingMessagesConfiguration durationString]]; - [barButtons addObject:timerButton]; + [timerButton addTarget:self + action:@selector(didTapTimerInNavbar:) + forControlEvents:UIControlEventTouchUpInside]; + [timerButton sizeToFit]; + [barButtons addObject:[[UIBarButtonItem alloc] initWithCustomView:timerButton]]; } - + self.navigationItem.rightBarButtonItems = [barButtons copy]; } @@ -554,28 +631,6 @@ typedef enum : NSUInteger { 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 { for (UIView *view in self.navigationController.navigationBar.subviews) { @@ -637,7 +692,7 @@ typedef enum : NSUInteger { #pragma mark - Calls -- (void)callAction { +- (void)callAction:(id)sender { OWSAssert([self.thread isKindOfClass:[TSContactThread class]]); if (![self canCall]) { @@ -1135,7 +1190,7 @@ typedef enum : NSUInteger { [self showConversationSettings]; } -- (void)didTapTimerInNavbar +- (void)didTapTimerInNavbar:(id)sender { DDLogDebug(@"%@ Tapped timer in navbar", self.tag); [self showConversationSettings]; @@ -2316,6 +2371,18 @@ typedef enum : NSUInteger { return @[]; } +#pragma mark - Event Handling + +- (void)backButtonPressed:(id)sender { + [self.navigationController popViewControllerAnimated:YES]; +} + +- (void)navigationTitleTapped:(UIGestureRecognizer *)gestureRecognizer { + if (gestureRecognizer.state == UIGestureRecognizerStateRecognized) { + [self showConversationSettings]; + } +} + #pragma mark - Logging + (NSString *)tag diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index 80a6aeec5..302c2f4fd 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -250,9 +250,6 @@ /* Generic notice when message failed to send. */ "ERROR_DESCRIPTION_CLIENT_SENDING_FAILURE" = "Failed to send message."; -/* Error mesage indicating that message send is disabled due to prekey update failures */ -"ERROR_DESCRIPTION_MESSAGE_SEND_DISABLED_PREKEY_UPDATE_FAILURES" = "ERROR_DESCRIPTION_MESSAGE_SEND_DISABLED_PREKEY_UPDATE_FAILURES"; - /* Generic error used whenver Signal can't contact the server */ "ERROR_DESCRIPTION_NO_INTERNET" = "Signal was unable to connect to the internet. Please try from another WiFi network or use mobile data."; @@ -463,6 +460,9 @@ /* No comment provided by engineer. */ "MESSAGE_COMPOSEVIEW_TITLE" = "New Message"; +/* The subtitle for the messages view title indicates that the title can be tapped to access settings for this conversation. */ +"MESSAGES_VIEW_TITLE_SUBTITLE" = "Tap here for settings"; + /* {{number of minutes}} embedded in strings, e.g. 'Alice updated disappearing messages expiration to {{5 minutes}}'. See other *_TIME_AMOUNT strings */ "MINUTES_TIME_AMOUNT" = "%u minutes";