From ce0c706f715f518015e51e0bb56f1eb4a9452611 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Mon, 2 Jul 2018 16:53:24 -0600 Subject: [PATCH 01/11] icon tint --- .../ConversationView/ConversationInputToolbar.m | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m b/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m index 9c6ece9cf..96b43b06f 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m @@ -159,8 +159,11 @@ static const CGFloat ConversationInputToolbarBorderViewHeight = 0.5; [self.attachmentButton addTarget:self action:@selector(attachmentButtonPressed) forControlEvents:UIControlEventTouchUpInside]; - [self.attachmentButton setImage:[UIImage imageNamed:@"btnAttachments--blue"] forState:UIControlStateNormal]; + UIImage *attachmentImage = [UIImage imageNamed:@"btnAttachments--blue"]; + [self.attachmentButton setImage:[attachmentImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] + forState:UIControlStateNormal]; self.attachmentButton.contentEdgeInsets = UIEdgeInsetsMake(0, 3, 0, 3); + self.attachmentButton.tintColor = UIColor.ows_navbarIconColor; [self.leftButtonWrapper addSubview:self.attachmentButton]; // TODO: Fix layout in this class. @@ -179,7 +182,7 @@ static const CGFloat ConversationInputToolbarBorderViewHeight = 0.5; _voiceMemoButton = [UIButton buttonWithType:UIButtonTypeCustom]; [self.voiceMemoButton setImage:[voiceMemoIcon imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateNormal]; - self.voiceMemoButton.imageView.tintColor = [UIColor ows_materialBlueColor]; + self.voiceMemoButton.imageView.tintColor = UIColor.ows_navbarIconColor; [self.rightButtonWrapper addSubview:self.voiceMemoButton]; // We want to be permissive about the voice message gesture, so we hang From 84d60f5dc4b0a6f1c2401aef9e96dc71d0079e0d Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Mon, 2 Jul 2018 18:17:45 -0600 Subject: [PATCH 02/11] input toolbar layout tweaks --- .../ConversationInputTextView.m | 19 +++++---- .../ConversationInputToolbar.m | 41 ++++++++++--------- 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/ConversationInputTextView.m b/Signal/src/ViewControllers/ConversationView/ConversationInputTextView.m index 86885e0eb..c25fb3460 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationInputTextView.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationInputTextView.m @@ -27,20 +27,21 @@ NS_ASSUME_NONNULL_BEGIN self.delegate = self; - CGFloat cornerRadius = 6.0f; + // round edge with dynamic type. + CGFloat cornerRadius = 16.0f; - self.backgroundColor = [UIColor whiteColor]; - self.layer.borderColor = [UIColor lightGrayColor].CGColor; + self.backgroundColor = [UIColor ows_light02Color]; + self.layer.borderColor = [UIColor.ows_blackColor colorWithAlphaComponent:0.12f].CGColor; self.layer.borderWidth = 0.5f; self.layer.cornerRadius = cornerRadius; - self.scrollIndicatorInsets = UIEdgeInsetsMake(cornerRadius, 0.0f, cornerRadius, 0.0f); + self.scrollIndicatorInsets = UIEdgeInsetsMake(4, 4, 4, 4); self.scrollEnabled = YES; self.scrollsToTop = NO; self.userInteractionEnabled = YES; - self.font = [UIFont systemFontOfSize:16.0f]; + self.font = [UIFont ows_dynamicTypeBodyFont]; self.textColor = [UIColor blackColor]; self.textAlignment = NSTextAlignmentNatural; @@ -57,7 +58,7 @@ NS_ASSUME_NONNULL_BEGIN // We need to do these steps _after_ placeholderView is configured. self.font = [UIFont ows_dynamicTypeBodyFont]; - self.textContainerInset = UIEdgeInsetsMake(4.0f, 2.0f, 4.0f, 2.0f); + self.textContainerInset = UIEdgeInsetsMake(4.0f, 8.0, 4.0f, 2.0f); self.contentInset = UIEdgeInsetsMake(1.0f, 0.0f, 1.0f, 0.0f); [self ensurePlaceholderConstraints]; @@ -104,10 +105,12 @@ NS_ASSUME_NONNULL_BEGIN CGRect beginningTextRect = [self firstRectForRange:beginningTextRange]; CGFloat topInset = beginningTextRect.origin.y; + CGFloat leftInset = beginningTextRect.origin.x; + // we use Left instead of Leading, since it's based on the prior CGRect offset self.placeholderConstraints = @[ - [self.placeholderView autoPinLeadingToSuperviewMargin], - [self.placeholderView autoPinTrailingToSuperviewMargin], + [self.placeholderView autoPinEdgeToSuperviewEdge:ALEdgeLeft withInset:leftInset], + [self.placeholderView autoPinEdgeToSuperviewEdge:ALEdgeRight], [self.placeholderView autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:topInset], ]; } diff --git a/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m b/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m index 96b43b06f..e1326d821 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m @@ -19,7 +19,6 @@ NS_ASSUME_NONNULL_BEGIN static void *kConversationInputTextViewObservingContext = &kConversationInputTextViewObservingContext; -static const CGFloat ConversationInputToolbarBorderViewHeight = 0.5; #pragma mark - @@ -90,7 +89,7 @@ static const CGFloat ConversationInputToolbarBorderViewHeight = 0.5; { // Since we have `self.autoresizingMask = UIViewAutoresizingFlexibleHeight`, the intrinsicContentSize is used // to determine the height of the rendered inputAccessoryView. - CGFloat height = self.toolbarHeight + ConversationInputToolbarBorderViewHeight; + CGFloat height = self.toolbarHeight; if (self.quotedMessagePreview) { height += self.quotedMessageTopMargin; height += self.quotedMessagePreview.intrinsicContentSize.height; @@ -107,10 +106,14 @@ static const CGFloat ConversationInputToolbarBorderViewHeight = 0.5; if (UIAccessibilityIsReduceTransparencyEnabled()) { self.backgroundColor = [UIColor ows_toolbarBackgroundColor]; } else { - // We can mute the blur by making our background color more opaque. - self.backgroundColor = [[UIColor ows_toolbarBackgroundColor] colorWithAlphaComponent:0.6]; + self.backgroundColor = [UIColor clearColor]; - UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleExtraLight]; + UIBlurEffect *blurEffect; + if (@available(iOS 10, *)) { + blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleProminent]; + } else { + blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleExtraLight]; + } UIVisualEffectView *blurEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect]; [self addSubview:blurEffectView]; [blurEffectView autoPinEdgesToSuperviewEdges]; @@ -118,13 +121,6 @@ static const CGFloat ConversationInputToolbarBorderViewHeight = 0.5; self.autoresizingMask = UIViewAutoresizingFlexibleHeight; - UIView *borderView = [UIView new]; - borderView.backgroundColor = [UIColor colorWithWhite:238 / 255.f alpha:1.f]; - [self addSubview:borderView]; - [borderView autoPinWidthToSuperview]; - [borderView autoPinEdgeToSuperviewEdge:ALEdgeTop]; - [borderView autoSetDimension:ALDimensionHeight toSize:ConversationInputToolbarBorderViewHeight]; - _composeContainer = [UIView containerView]; _contentStackView = [[UIStackView alloc] initWithArrangedSubviews:@[ _composeContainer ]]; _contentStackView.axis = UILayoutConstraintAxisVertical; @@ -171,9 +167,9 @@ static const CGFloat ConversationInputToolbarBorderViewHeight = 0.5; [self.sendButton setTitle:NSLocalizedString(@"SEND_BUTTON_TITLE", @"Label for the send button in the conversation view.") forState:UIControlStateNormal]; - [self.sendButton setTitleColor:[UIColor ows_materialBlueColor] forState:UIControlStateNormal]; + [self.sendButton setTitleColor:UIColor.ows_signalBlueColor forState:UIControlStateNormal]; self.sendButton.titleLabel.textAlignment = NSTextAlignmentCenter; - self.sendButton.titleLabel.font = [UIFont ows_mediumFontWithSize:16.f]; + self.sendButton.titleLabel.font = [UIFont ows_mediumFontWithSize:17.f]; [self.sendButton addTarget:self action:@selector(sendButtonPressed) forControlEvents:UIControlEventTouchUpInside]; [self.rightButtonWrapper addSubview:self.sendButton]; @@ -340,16 +336,23 @@ static const CGFloat ConversationInputToolbarBorderViewHeight = 0.5; const int contentHInset = 6; const int contentHSpacing = 6; + // I'm not sure why this addional offset is necessary, but without it our minTextViewHeight is too short. + const CGFloat kAdditionalUnaccountedForHeight = 1; + // We want to grow the text input area to fit its content within reason. - const CGFloat kMinTextViewHeight = ceil(self.inputTextView.font.lineHeight - + self.inputTextView.textContainerInset.top + self.inputTextView.textContainerInset.bottom - + self.inputTextView.contentInset.top + self.inputTextView.contentInset.bottom); + const CGFloat minTextViewHeight + = ceil(self.inputTextView.font.lineHeight + self.inputTextView.textContainerInset.top + + self.inputTextView.textContainerInset.bottom + self.inputTextView.contentInset.top + + self.inputTextView.contentInset.bottom) + + kAdditionalUnaccountedForHeight; + + // Exactly 4 lines of text with default sizing. const CGFloat kMaxTextViewHeight = 98.f; const CGFloat textViewDesiredHeight = (self.inputTextView.contentSize.height + self.inputTextView.contentInset.top + self.inputTextView.contentInset.bottom); - const CGFloat textViewHeight = ceil(CGFloatClamp(textViewDesiredHeight, kMinTextViewHeight, kMaxTextViewHeight)); - const CGFloat kMinContentHeight = kMinTextViewHeight + textViewVInset * 2; + const CGFloat textViewHeight = ceil(CGFloatClamp(textViewDesiredHeight, minTextViewHeight, kMaxTextViewHeight)); + const CGFloat kMinContentHeight = minTextViewHeight + textViewVInset * 2; self.textViewHeight = textViewHeight; self.toolbarHeight = textViewHeight + textViewVInset * 2; From 7ef693f1b511c4033b6db035eed6243b14567240 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Mon, 2 Jul 2018 18:45:55 -0600 Subject: [PATCH 03/11] pure white blur --- .../ConversationView/ConversationInputToolbar.m | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m b/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m index e1326d821..39eb4f643 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m @@ -106,14 +106,13 @@ static void *kConversationInputTextViewObservingContext = &kConversationInputTex if (UIAccessibilityIsReduceTransparencyEnabled()) { self.backgroundColor = [UIColor ows_toolbarBackgroundColor]; } else { - self.backgroundColor = [UIColor clearColor]; - UIBlurEffect *blurEffect; - if (@available(iOS 10, *)) { - blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleProminent]; - } else { - blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleExtraLight]; - } + // More muted blur effects look gray when overlayed on white. + blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]; + + // We can make our blur effect more muted by increasing this background alpha. + self.backgroundColor = [[UIColor ows_toolbarBackgroundColor] colorWithAlphaComponent:0.4]; + UIVisualEffectView *blurEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect]; [self addSubview:blurEffectView]; [blurEffectView autoPinEdgesToSuperviewEdges]; From 1a00690b1771718d2be3c3d974f110df0e1b4903 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Mon, 2 Jul 2018 20:04:15 -0600 Subject: [PATCH 04/11] Compose to stack view TODO: resize after sending restore actions add padding vcenter icons add new assets --- .../ConversationInputTextView.h | 4 +- .../ConversationInputTextView.m | 16 +- .../ConversationInputToolbar.m | 330 ++++++------------ 3 files changed, 108 insertions(+), 242 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/ConversationInputTextView.h b/Signal/src/ViewControllers/ConversationView/ConversationInputTextView.h index 38cf306e8..8ea7bd93b 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationInputTextView.h +++ b/Signal/src/ViewControllers/ConversationView/ConversationInputTextView.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // NS_ASSUME_NONNULL_BEGIN @@ -18,7 +18,7 @@ NS_ASSUME_NONNULL_BEGIN @protocol ConversationTextViewToolbarDelegate -- (void)textViewDidChange; +- (void)textViewDidChange:(UITextView *)textView; @end diff --git a/Signal/src/ViewControllers/ConversationView/ConversationInputTextView.m b/Signal/src/ViewControllers/ConversationView/ConversationInputTextView.m index c25fb3460..e47550e9d 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationInputTextView.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationInputTextView.m @@ -27,13 +27,9 @@ NS_ASSUME_NONNULL_BEGIN self.delegate = self; - // round edge with dynamic type. - CGFloat cornerRadius = 16.0f; - self.backgroundColor = [UIColor ows_light02Color]; self.layer.borderColor = [UIColor.ows_blackColor colorWithAlphaComponent:0.12f].CGColor; self.layer.borderWidth = 0.5f; - self.layer.cornerRadius = cornerRadius; self.scrollIndicatorInsets = UIEdgeInsetsMake(4, 4, 4, 4); @@ -52,14 +48,13 @@ NS_ASSUME_NONNULL_BEGIN self.placeholderView = [UILabel new]; self.placeholderView.text = NSLocalizedString(@"new_message", @""); - self.placeholderView.textColor = [UIColor lightGrayColor]; + self.placeholderView.textColor = UIColor.ows_light35Color; self.placeholderView.userInteractionEnabled = NO; [self addSubview:self.placeholderView]; // We need to do these steps _after_ placeholderView is configured. self.font = [UIFont ows_dynamicTypeBodyFont]; - self.textContainerInset = UIEdgeInsetsMake(4.0f, 8.0, 4.0f, 2.0f); - self.contentInset = UIEdgeInsetsMake(1.0f, 0.0f, 1.0f, 0.0f); + self.textContainerInset = UIEdgeInsetsMake(7.0f, 12.0f, 7.0f, 12.0f); [self ensurePlaceholderConstraints]; [self updatePlaceholderVisibility]; @@ -75,6 +70,11 @@ NS_ASSUME_NONNULL_BEGIN self.placeholderView.font = font; } +- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)isAnimated +{ + [super setContentOffset:contentOffset animated:false]; +} + - (void)setContentInset:(UIEdgeInsets)contentInset { [super setContentInset:contentInset]; @@ -181,7 +181,7 @@ NS_ASSUME_NONNULL_BEGIN [self updatePlaceholderVisibility]; - [self.textViewToolbarDelegate textViewDidChange]; + [self.textViewToolbarDelegate textViewDidChange:self]; } - (void)textViewDidEndEditing:(UITextView *)textView diff --git a/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m b/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m index 39eb4f643..6da9a42a6 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m @@ -20,6 +20,9 @@ NS_ASSUME_NONNULL_BEGIN static void *kConversationInputTextViewObservingContext = &kConversationInputTextViewObservingContext; +const CGFloat kMinTextViewHeight = 36; +const CGFloat kMaxTextViewHeight = 98; + #pragma mark - @interface ConversationInputToolbar () *contentContraints; @property (nonatomic) NSValue *lastTextContentSize; @property (nonatomic) CGFloat toolbarHeight; @property (nonatomic) CGFloat textViewHeight; +@property (nonatomic, readonly) NSLayoutConstraint *textViewHeightConstraint; #pragma mark - @@ -80,23 +79,11 @@ static void *kConversationInputTextViewObservingContext = &kConversationInputTex return self; } -- (void)dealloc -{ - [self removeKVOObservers]; -} - - (CGSize)intrinsicContentSize { - // Since we have `self.autoresizingMask = UIViewAutoresizingFlexibleHeight`, the intrinsicContentSize is used - // to determine the height of the rendered inputAccessoryView. - CGFloat height = self.toolbarHeight; - if (self.quotedMessagePreview) { - height += self.quotedMessageTopMargin; - height += self.quotedMessagePreview.intrinsicContentSize.height; - } - CGSize newSize = CGSizeMake(self.bounds.size.width, height); - - return newSize; + // Since we have `self.autoresizingMask = UIViewAutoresizingFlexibleHeight`, we must specify + // an intrinsicContentSize. Specifying CGSize.zero causes the height to be determined by autolayout. + return CGSizeZero; } - (void)createContents @@ -111,7 +98,7 @@ static void *kConversationInputTextViewObservingContext = &kConversationInputTex blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]; // We can make our blur effect more muted by increasing this background alpha. - self.backgroundColor = [[UIColor ows_toolbarBackgroundColor] colorWithAlphaComponent:0.4]; + self.backgroundColor = [[UIColor ows_toolbarBackgroundColor] colorWithAlphaComponent:0.4f]; UIVisualEffectView *blurEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect]; [self addSubview:blurEffectView]; @@ -120,31 +107,13 @@ static void *kConversationInputTextViewObservingContext = &kConversationInputTex self.autoresizingMask = UIViewAutoresizingFlexibleHeight; - _composeContainer = [UIView containerView]; - _contentStackView = [[UIStackView alloc] initWithArrangedSubviews:@[ _composeContainer ]]; - _contentStackView.axis = UILayoutConstraintAxisVertical; - - [self addSubview:_contentStackView]; - [_contentStackView autoPinEdgesToSuperviewEdges]; - _inputTextView = [ConversationInputTextView new]; + self.inputTextView.layer.cornerRadius = kMinTextViewHeight / 2.0f; self.inputTextView.textViewToolbarDelegate = self; self.inputTextView.font = [UIFont ows_dynamicTypeBodyFont]; - [self.composeContainer addSubview:self.inputTextView]; - - // We want to be permissive about taps on the send and attachment buttons, - // so we use wrapper views that capture nearby taps. This is a lot easier - // than trying to manipulate the size of the buttons themselves, as you - // can't coordinate the layout of the button content (e.g. image or text) - // using iOS auto layout. - _leftButtonWrapper = [UIView containerView]; - [self.leftButtonWrapper - addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(leftButtonTapped:)]]; - [self.composeContainer addSubview:self.leftButtonWrapper]; - _rightButtonWrapper = [UIView containerView]; - [self.rightButtonWrapper - addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(rightButtonTapped:)]]; - [self.composeContainer addSubview:self.rightButtonWrapper]; + [self.inputTextView setContentHuggingLow]; + + _textViewHeightConstraint = [self.inputTextView autoSetDimension:ALDimensionHeight toSize:kMinTextViewHeight]; _attachmentButton = [[UIButton alloc] init]; self.attachmentButton.accessibilityLabel @@ -159,9 +128,9 @@ static void *kConversationInputTextViewObservingContext = &kConversationInputTex forState:UIControlStateNormal]; self.attachmentButton.contentEdgeInsets = UIEdgeInsetsMake(0, 3, 0, 3); self.attachmentButton.tintColor = UIColor.ows_navbarIconColor; - [self.leftButtonWrapper addSubview:self.attachmentButton]; + [self.attachmentButton setCompressionResistanceHigh]; + [self.attachmentButton setContentHuggingHigh]; - // TODO: Fix layout in this class. _sendButton = [UIButton buttonWithType:UIButtonTypeCustom]; [self.sendButton setTitle:NSLocalizedString(@"SEND_BUTTON_TITLE", @"Label for the send button in the conversation view.") @@ -169,8 +138,9 @@ static void *kConversationInputTextViewObservingContext = &kConversationInputTex [self.sendButton setTitleColor:UIColor.ows_signalBlueColor forState:UIControlStateNormal]; self.sendButton.titleLabel.textAlignment = NSTextAlignmentCenter; self.sendButton.titleLabel.font = [UIFont ows_mediumFontWithSize:17.f]; + [self.sendButton setCompressionResistanceHigh]; + [self.sendButton setContentHuggingHigh]; [self.sendButton addTarget:self action:@selector(sendButtonPressed) forControlEvents:UIControlEventTouchUpInside]; - [self.rightButtonWrapper addSubview:self.sendButton]; UIImage *voiceMemoIcon = [UIImage imageNamed:@"voice-memo-button"]; OWSAssert(voiceMemoIcon); @@ -178,7 +148,8 @@ static void *kConversationInputTextViewObservingContext = &kConversationInputTex [self.voiceMemoButton setImage:[voiceMemoIcon imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateNormal]; self.voiceMemoButton.imageView.tintColor = UIColor.ows_navbarIconColor; - [self.rightButtonWrapper addSubview:self.voiceMemoButton]; + [self.voiceMemoButton setCompressionResistanceHigh]; + [self.voiceMemoButton setContentHuggingHigh]; // We want to be permissive about the voice message gesture, so we hang // the long press GR on the button's wrapper, not the button itself. @@ -186,22 +157,29 @@ static void *kConversationInputTextViewObservingContext = &kConversationInputTex [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)]; longPressGestureRecognizer.minimumPressDuration = 0; longPressGestureRecognizer.delegate = self; - [self.rightButtonWrapper addGestureRecognizer:longPressGestureRecognizer]; self.userInteractionEnabled = YES; - [self addKVOObservers]; + _composeRow = [[UIStackView alloc] + initWithArrangedSubviews:@[ self.attachmentButton, self.inputTextView, self.voiceMemoButton, self.sendButton ]]; + _composeRow.axis = UILayoutConstraintAxisHorizontal; + _composeRow.layoutMarginsRelativeArrangement = YES; + _composeRow.layoutMargins = UIEdgeInsetsMake(6, 8, 6, 8); + _composeRow.alignment = UIStackViewAlignmentBottom; + _composeRow.spacing = 8; + + _contentRows = [[UIStackView alloc] initWithArrangedSubviews:@[ _composeRow ]]; + _contentRows.axis = UILayoutConstraintAxisVertical; - [self ensureShouldShowVoiceMemoButton]; + [self addSubview:_contentRows]; + [_contentRows autoPinEdgesToSuperviewEdges]; - [self ensureContentConstraints]; + [self ensureShouldShowVoiceMemoButtonAnimated:NO]; } - (void)updateFontSizes { self.inputTextView.font = [UIFont ows_dynamicTypeBodyFont]; - - [self ensureContentConstraints]; } - (void)setInputTextViewDelegate:(id)value @@ -225,7 +203,7 @@ static void *kConversationInputTextViewObservingContext = &kConversationInputTex self.inputTextView.text = value; - [self ensureShouldShowVoiceMemoButton]; + [self ensureShouldShowVoiceMemoButtonAnimated:NO]; } - (void)clearTextMessage @@ -254,17 +232,6 @@ static void *kConversationInputTextViewObservingContext = &kConversationInputTex [self.inputTextView reloadInputViews]; } -- (void)setShouldShowVoiceMemoButton:(BOOL)shouldShowVoiceMemoButton -{ - if (_shouldShowVoiceMemoButton == shouldShowVoiceMemoButton) { - return; - } - - _shouldShowVoiceMemoButton = shouldShowVoiceMemoButton; - - [self ensureContentConstraints]; -} - - (void)setQuotedReply:(nullable OWSQuotedReplyModel *)quotedReply { if (quotedReply == _quotedReply) { @@ -292,8 +259,8 @@ static void *kConversationInputTextViewObservingContext = &kConversationInputTex [wrapper addSubview:quotedMessagePreview]; [quotedMessagePreview autoPinToSuperviewMargins]; - // TODO animate - [self.contentStackView insertArrangedSubview:wrapper atIndex:0]; + [self.contentRows insertArrangedSubview:wrapper atIndex:0]; + self.quotedMessagePreview = wrapper; } @@ -304,9 +271,8 @@ static void *kConversationInputTextViewObservingContext = &kConversationInputTex - (void)clearQuotedMessagePreview { - // TODO animate if (self.quotedMessagePreview) { - [self.contentStackView removeArrangedSubview:self.quotedMessagePreview]; + [self.contentRows removeArrangedSubview:self.quotedMessagePreview]; [self.quotedMessagePreview removeFromSuperview]; self.quotedMessagePreview = nil; } @@ -327,113 +293,38 @@ static void *kConversationInputTextViewObservingContext = &kConversationInputTex return self.inputTextView.isFirstResponder; } -- (void)ensureContentConstraints +- (void)ensureShouldShowVoiceMemoButtonAnimated:(BOOL)isAnimated { - [NSLayoutConstraint deactivateConstraints:self.contentContraints]; - - const int textViewVInset = 5; - const int contentHInset = 6; - const int contentHSpacing = 6; - - // I'm not sure why this addional offset is necessary, but without it our minTextViewHeight is too short. - const CGFloat kAdditionalUnaccountedForHeight = 1; - - // We want to grow the text input area to fit its content within reason. - const CGFloat minTextViewHeight - = ceil(self.inputTextView.font.lineHeight + self.inputTextView.textContainerInset.top - + self.inputTextView.textContainerInset.bottom + self.inputTextView.contentInset.top - + self.inputTextView.contentInset.bottom) - + kAdditionalUnaccountedForHeight; - - - // Exactly 4 lines of text with default sizing. - const CGFloat kMaxTextViewHeight = 98.f; - const CGFloat textViewDesiredHeight = (self.inputTextView.contentSize.height + self.inputTextView.contentInset.top - + self.inputTextView.contentInset.bottom); - const CGFloat textViewHeight = ceil(CGFloatClamp(textViewDesiredHeight, minTextViewHeight, kMaxTextViewHeight)); - const CGFloat kMinContentHeight = minTextViewHeight + textViewVInset * 2; - - self.textViewHeight = textViewHeight; - self.toolbarHeight = textViewHeight + textViewVInset * 2; - - self.leftButtonWrapper.hidden = NO; - self.inputTextView.hidden = NO; - self.voiceMemoButton.hidden = NO; - - UIButton *leftButton = self.attachmentButton; - UIButton *rightButton = (self.shouldShowVoiceMemoButton ? self.voiceMemoButton : self.sendButton); - UIButton *inactiveRightButton = (self.shouldShowVoiceMemoButton ? self.sendButton : self.voiceMemoButton); - leftButton.enabled = YES; - rightButton.enabled = YES; - inactiveRightButton.enabled = NO; - leftButton.hidden = NO; - rightButton.hidden = NO; - inactiveRightButton.hidden = YES; - - [leftButton setContentHuggingHigh]; - [rightButton setContentHuggingHigh]; - [leftButton setCompressionResistanceHigh]; - [rightButton setCompressionResistanceHigh]; - [self.inputTextView setCompressionResistanceLow]; - [self.inputTextView setContentHuggingLow]; + void (^updateBlock)(void) = ^{ + if (self.inputTextView.trimmedText.length > 0) { + if (!self.voiceMemoButton.isHidden) { + self.voiceMemoButton.hidden = YES; + } - OWSAssert(leftButton.superview == self.leftButtonWrapper); - OWSAssert(rightButton.superview == self.rightButtonWrapper); - - // The leading and trailing buttons should be center-aligned with the - // inputTextView when the inputTextView is at its minimum size. - // - // We want the leading and trailing buttons to hug the bottom of the input - // toolbar as the inputTextView expands. - // - // Therefore we fix the button heights to the size of the toolbar when - // inputTextView is at its minimum size. - // - // Additionally, we use "wrapper" views around the leading and trailing - // buttons to expand their hot area. - self.contentContraints = @[ - [self.leftButtonWrapper autoPinEdgeToSuperviewEdge:ALEdgeLeft], - [self.leftButtonWrapper autoPinEdgeToSuperviewEdge:ALEdgeTop], - [self.leftButtonWrapper autoPinBottomToSuperviewMarginWithInset:0], - - [leftButton autoSetDimension:ALDimensionHeight toSize:kMinContentHeight], - [leftButton autoPinLeadingToSuperviewMarginWithInset:contentHInset], - [leftButton autoPinTrailingToSuperviewMarginWithInset:contentHSpacing], - [leftButton autoPinEdgeToSuperviewEdge:ALEdgeBottom], - - [self.inputTextView autoPinEdge:ALEdgeLeft toEdge:ALEdgeRight ofView:self.leftButtonWrapper], - [self.inputTextView autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:textViewVInset], - [self.inputTextView autoPinBottomToSuperviewMarginWithInset:textViewVInset], - [self.inputTextView autoSetDimension:ALDimensionHeight toSize:textViewHeight], - - [self.rightButtonWrapper autoPinEdge:ALEdgeLeft toEdge:ALEdgeRight ofView:self.inputTextView], - [self.rightButtonWrapper autoPinEdgeToSuperviewEdge:ALEdgeRight], - [self.rightButtonWrapper autoPinEdgeToSuperviewEdge:ALEdgeTop], - [self.rightButtonWrapper autoPinBottomToSuperviewMarginWithInset:0], - - [rightButton autoSetDimension:ALDimensionHeight toSize:kMinContentHeight], - [rightButton autoPinLeadingToSuperviewMarginWithInset:contentHSpacing], - [rightButton autoPinTrailingToSuperviewMarginWithInset:contentHInset], - [rightButton autoPinEdgeToSuperviewEdge:ALEdgeBottom] - ]; - - // Layout immediately, unless the input toolbar hasn't even been laid out yet. - if (self.bounds.size.width > 0 && self.bounds.size.height > 0) { + if (self.sendButton.isHidden) { + self.sendButton.hidden = NO; + } + } else { + if (self.voiceMemoButton.isHidden) { + self.voiceMemoButton.hidden = NO; + } + + if (!self.sendButton.isHidden) { + self.sendButton.hidden = YES; + } + } [self layoutIfNeeded]; - } -} + }; -- (void)ensureShouldShowVoiceMemoButton -{ - self.shouldShowVoiceMemoButton = self.inputTextView.trimmedText.length < 1; + if (isAnimated) { + [UIView animateWithDuration:0.1 animations:updateBlock]; + } else { + updateBlock(); + } } - (void)handleLongPress:(UIGestureRecognizer *)sender { - if (!self.shouldShowVoiceMemoButton) { - return; - } - switch (sender.state) { case UIGestureRecognizerStatePossible: case UIGestureRecognizerStateCancelled: @@ -490,11 +381,11 @@ static void *kConversationInputTextViewObservingContext = &kConversationInputTex - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { - if ([gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]]) { - return self.shouldShowVoiceMemoButton; - } else { - return YES; - } + // if ([gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]]) { + // return self.shouldShowVoiceMemoButton; + // } else { + return YES; + // } } #pragma mark - Voice Memo @@ -703,21 +594,21 @@ static void *kConversationInputTextViewObservingContext = &kConversationInputTex #pragma mark - Event Handlers -- (void)leftButtonTapped:(UIGestureRecognizer *)sender -{ - if (sender.state == UIGestureRecognizerStateRecognized) { - [self attachmentButtonPressed]; - } -} - -- (void)rightButtonTapped:(UIGestureRecognizer *)sender -{ - if (sender.state == UIGestureRecognizerStateRecognized) { - if (!self.shouldShowVoiceMemoButton) { - [self sendButtonPressed]; - } - } -} +//- (void)leftButtonTapped:(UIGestureRecognizer *)sender +//{ +// if (sender.state == UIGestureRecognizerStateRecognized) { +// [self attachmentButtonPressed]; +// } +//} + +//- (void)rightButtonTapped:(UIGestureRecognizer *)sender +//{ +// if (sender.state == UIGestureRecognizerStateRecognized) { +// if (!self.shouldShowVoiceMemoButton) { +// [self sendButtonPressed]; +// } +// } +//} - (void)sendButtonPressed { @@ -735,58 +626,33 @@ static void *kConversationInputTextViewObservingContext = &kConversationInputTex #pragma mark - ConversationTextViewToolbarDelegate -- (void)textViewDidChange +- (void)textViewDidChange:(UITextView *)textView { OWSAssert(self.inputToolbarDelegate); - - [self ensureShouldShowVoiceMemoButton]; + [self ensureShouldShowVoiceMemoButtonAnimated:YES]; + [self updateHeightWithTextView:textView]; } -#pragma mark - Text Input Sizing - -- (void)addKVOObservers +- (void)updateHeightWithTextView:(UITextView *)textView { - [self.inputTextView addObserver:self - forKeyPath:NSStringFromSelector(@selector(contentSize)) - options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew - context:kConversationInputTextViewObservingContext]; -} + // compute new height assuming width is unchanged + CGSize currentSize = textView.frame.size; + CGFloat newHeight = [self clampedHeightWithTextView:textView fixedWidth:currentSize.width]; -- (void)removeKVOObservers -{ - @try { - [self.inputTextView removeObserver:self - forKeyPath:NSStringFromSelector(@selector(contentSize)) - context:kConversationInputTextViewObservingContext]; - } @catch (NSException *__unused exception) { - // TODO: This try/catch can probably be safely removed. - OWSFail(@"%@ removeKVOObservers failed.", self.logTag); + if (newHeight != self.textViewHeight) { + self.textViewHeight = newHeight; + OWSAssert(self.textViewHeightConstraint); + self.textViewHeightConstraint.constant = newHeight; + [self invalidateIntrinsicContentSize]; } } -- (void)observeValueForKeyPath:(nullable NSString *)keyPath - ofObject:(nullable id)object - change:(nullable NSDictionary *)change - context:(nullable void *)context +- (CGFloat)clampedHeightWithTextView:(UITextView *)textView fixedWidth:(CGFloat)fixedWidth { - if (context == kConversationInputTextViewObservingContext) { - - if (object == self.inputTextView && [keyPath isEqualToString:NSStringFromSelector(@selector(contentSize))]) { - CGSize textContentSize = self.inputTextView.contentSize; - NSValue *_Nullable lastTextContentSize = self.lastTextContentSize; - self.lastTextContentSize = [NSValue valueWithCGSize:textContentSize]; - - // Update view constraints, but only when text content size changes. - // - // NOTE: We use a "fuzzy equals" comparison to avoid infinite recursion, - // since ensureContentConstraints can affect the text content size. - if (!lastTextContentSize || fabs(lastTextContentSize.CGSizeValue.width - textContentSize.width) > 0.1f - || fabs(lastTextContentSize.CGSizeValue.height - textContentSize.height) > 0.1f) { - [self ensureContentConstraints]; - [self invalidateIntrinsicContentSize]; - } - } - } + CGSize fixedWidthSize = CGSizeMake(fixedWidth, CGFLOAT_MAX); + CGSize contentSize = [textView sizeThatFits:fixedWidthSize]; + + return CGFloatClamp(contentSize.height, kMinTextViewHeight, kMaxTextViewHeight); } #pragma mark QuotedReplyPreviewViewDelegate From 17f0400bb54537b9a4ef0fc0581a1255eed012a6 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Mon, 2 Jul 2018 22:28:05 -0600 Subject: [PATCH 05/11] vertically align input toolbar items --- .../ConversationInputToolbar.m | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m b/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m index 6da9a42a6..bcfbfd24c 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m @@ -126,10 +126,8 @@ const CGFloat kMaxTextViewHeight = 98; UIImage *attachmentImage = [UIImage imageNamed:@"btnAttachments--blue"]; [self.attachmentButton setImage:[attachmentImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateNormal]; - self.attachmentButton.contentEdgeInsets = UIEdgeInsetsMake(0, 3, 0, 3); self.attachmentButton.tintColor = UIColor.ows_navbarIconColor; - [self.attachmentButton setCompressionResistanceHigh]; - [self.attachmentButton setContentHuggingHigh]; + [self.attachmentButton autoSetDimensionsToSize:CGSizeMake(40, kMinTextViewHeight)]; _sendButton = [UIButton buttonWithType:UIButtonTypeCustom]; [self.sendButton @@ -138,8 +136,8 @@ const CGFloat kMaxTextViewHeight = 98; [self.sendButton setTitleColor:UIColor.ows_signalBlueColor forState:UIControlStateNormal]; self.sendButton.titleLabel.textAlignment = NSTextAlignmentCenter; self.sendButton.titleLabel.font = [UIFont ows_mediumFontWithSize:17.f]; - [self.sendButton setCompressionResistanceHigh]; - [self.sendButton setContentHuggingHigh]; + self.sendButton.contentEdgeInsets = UIEdgeInsetsMake(0, 4, 0, 4); + [self.sendButton autoSetDimension:ALDimensionHeight toSize:kMinTextViewHeight]; [self.sendButton addTarget:self action:@selector(sendButtonPressed) forControlEvents:UIControlEventTouchUpInside]; UIImage *voiceMemoIcon = [UIImage imageNamed:@"voice-memo-button"]; @@ -148,8 +146,7 @@ const CGFloat kMaxTextViewHeight = 98; [self.voiceMemoButton setImage:[voiceMemoIcon imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateNormal]; self.voiceMemoButton.imageView.tintColor = UIColor.ows_navbarIconColor; - [self.voiceMemoButton setCompressionResistanceHigh]; - [self.voiceMemoButton setContentHuggingHigh]; + [self.voiceMemoButton autoSetDimensionsToSize:CGSizeMake(40, kMinTextViewHeight)]; // We want to be permissive about the voice message gesture, so we hang // the long press GR on the button's wrapper, not the button itself. @@ -157,22 +154,23 @@ const CGFloat kMaxTextViewHeight = 98; [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)]; longPressGestureRecognizer.minimumPressDuration = 0; longPressGestureRecognizer.delegate = self; + [self.voiceMemoButton addGestureRecognizer:longPressGestureRecognizer]; self.userInteractionEnabled = YES; _composeRow = [[UIStackView alloc] initWithArrangedSubviews:@[ self.attachmentButton, self.inputTextView, self.voiceMemoButton, self.sendButton ]]; - _composeRow.axis = UILayoutConstraintAxisHorizontal; - _composeRow.layoutMarginsRelativeArrangement = YES; - _composeRow.layoutMargins = UIEdgeInsetsMake(6, 8, 6, 8); - _composeRow.alignment = UIStackViewAlignmentBottom; - _composeRow.spacing = 8; + self.composeRow.axis = UILayoutConstraintAxisHorizontal; + self.composeRow.layoutMarginsRelativeArrangement = YES; + self.composeRow.layoutMargins = UIEdgeInsetsMake(6, 6, 6, 6); + self.composeRow.alignment = UIStackViewAlignmentBottom; + self.composeRow.spacing = 8; - _contentRows = [[UIStackView alloc] initWithArrangedSubviews:@[ _composeRow ]]; - _contentRows.axis = UILayoutConstraintAxisVertical; + _contentRows = [[UIStackView alloc] initWithArrangedSubviews:@[ self.composeRow ]]; + self.contentRows.axis = UILayoutConstraintAxisVertical; - [self addSubview:_contentRows]; - [_contentRows autoPinEdgesToSuperviewEdges]; + [self addSubview:self.contentRows]; + [self.contentRows autoPinEdgesToSuperviewEdges]; [self ensureShouldShowVoiceMemoButtonAnimated:NO]; } From 1d0a25dba9121c8bead5dd42e702934f931e4b65 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Mon, 2 Jul 2018 22:35:14 -0600 Subject: [PATCH 06/11] cleanup --- .../ConversationInputToolbar.m | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m b/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m index bcfbfd24c..593e13c65 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m @@ -25,9 +25,7 @@ const CGFloat kMaxTextViewHeight = 98; #pragma mark - -@interface ConversationInputToolbar () +@interface ConversationInputToolbar () @property (nonatomic, readonly) ConversationStyle *conversationStyle; @@ -111,7 +109,7 @@ const CGFloat kMaxTextViewHeight = 98; self.inputTextView.layer.cornerRadius = kMinTextViewHeight / 2.0f; self.inputTextView.textViewToolbarDelegate = self; self.inputTextView.font = [UIFont ows_dynamicTypeBodyFont]; - [self.inputTextView setContentHuggingLow]; + [self.inputTextView setContentHuggingHorizontalLow]; _textViewHeightConstraint = [self.inputTextView autoSetDimension:ALDimensionHeight toSize:kMinTextViewHeight]; @@ -153,7 +151,6 @@ const CGFloat kMaxTextViewHeight = 98; UILongPressGestureRecognizer *longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)]; longPressGestureRecognizer.minimumPressDuration = 0; - longPressGestureRecognizer.delegate = self; [self.voiceMemoButton addGestureRecognizer:longPressGestureRecognizer]; self.userInteractionEnabled = YES; @@ -375,17 +372,6 @@ const CGFloat kMaxTextViewHeight = 98; } } -#pragma mark - UIGestureRecognizerDelegate - -- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch -{ - // if ([gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]]) { - // return self.shouldShowVoiceMemoButton; - // } else { - return YES; - // } -} - #pragma mark - Voice Memo - (void)showVoiceMemoUI From 94a23e63b6c6e1c57b0973a849a1de9329c547f1 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Mon, 2 Jul 2018 22:42:32 -0600 Subject: [PATCH 07/11] resize bar after send --- .../ConversationInputToolbar.h | 4 +-- .../ConversationInputToolbar.m | 25 ++++--------------- .../ConversationViewController.m | 4 +-- 3 files changed, 9 insertions(+), 24 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.h b/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.h index 085e25d30..b1c5fb4e7 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.h +++ b/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.h @@ -47,8 +47,8 @@ NS_ASSUME_NONNULL_BEGIN - (void)setInputTextViewDelegate:(id)value; - (NSString *)messageText; -- (void)setMessageText:(NSString *_Nullable)value; -- (void)clearTextMessage; +- (void)setMessageText:(NSString *_Nullable)value animated:(BOOL)isAnimated; +- (void)clearTextMessageAnimated:(BOOL)isAnimated; - (void)toggleDefaultKeyboard; - (void)updateFontSizes; diff --git a/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m b/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m index 593e13c65..39af63b52 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m @@ -192,18 +192,19 @@ const CGFloat kMaxTextViewHeight = 98; return self.inputTextView.trimmedText; } -- (void)setMessageText:(NSString *_Nullable)value +- (void)setMessageText:(NSString *_Nullable)value animated:(BOOL)isAnimated { OWSAssert(self.inputTextView); self.inputTextView.text = value; - [self ensureShouldShowVoiceMemoButtonAnimated:NO]; + [self ensureShouldShowVoiceMemoButtonAnimated:isAnimated]; + [self updateHeightWithTextView:self.inputTextView]; } -- (void)clearTextMessage +- (void)clearTextMessageAnimated:(BOOL)isAnimated { - [self setMessageText:nil]; + [self setMessageText:nil animated:isAnimated]; [self.inputTextView.undoManager removeAllActions]; } @@ -578,22 +579,6 @@ const CGFloat kMaxTextViewHeight = 98; #pragma mark - Event Handlers -//- (void)leftButtonTapped:(UIGestureRecognizer *)sender -//{ -// if (sender.state == UIGestureRecognizerStateRecognized) { -// [self attachmentButtonPressed]; -// } -//} - -//- (void)rightButtonTapped:(UIGestureRecognizer *)sender -//{ -// if (sender.state == UIGestureRecognizerStateRecognized) { -// if (!self.shouldShowVoiceMemoButton) { -// [self sendButtonPressed]; -// } -// } -//} - - (void)sendButtonPressed { OWSAssert(self.inputToolbarDelegate); diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index 1294604a9..2677f4e39 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -3980,7 +3980,7 @@ typedef enum : NSUInteger { [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { draft = [_thread currentDraftWithTransaction:transaction]; }]; - [self.inputToolbar setMessageText:draft]; + [self.inputToolbar setMessageText:draft animated:NO]; } - (void)saveDraft @@ -4417,7 +4417,7 @@ typedef enum : NSUInteger { if (updateKeyboardState) { [self.inputToolbar toggleDefaultKeyboard]; } - [self.inputToolbar clearTextMessage]; + [self.inputToolbar clearTextMessageAnimated:YES]; [self clearDraft]; if (didAddToProfileWhitelist) { [self ensureDynamicInteractions]; From 2b588017f3ba8e5d0ab04a1b3ec315ba0328dcc7 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Mon, 2 Jul 2018 22:55:55 -0600 Subject: [PATCH 08/11] round attachment approval toolbar --- .../attachments/AttachmentApprovalViewController.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/SignalMessaging/attachments/AttachmentApprovalViewController.swift b/SignalMessaging/attachments/AttachmentApprovalViewController.swift index f9b87c7ed..421fe4226 100644 --- a/SignalMessaging/attachments/AttachmentApprovalViewController.swift +++ b/SignalMessaging/attachments/AttachmentApprovalViewController.swift @@ -532,10 +532,13 @@ class CaptioningToolbar: UIView, UITextViewDelegate { textView.delegate = self textView.backgroundColor = UIColor.white - textView.layer.cornerRadius = 4.0 + textView.layer.cornerRadius = kMinTextViewHeight / 2 + textView.addBorder(with: UIColor.lightGray) textView.font = UIFont.ows_dynamicTypeBody textView.returnKeyType = .done + textView.textContainerInset = UIEdgeInsets(top: 7, left: 7, bottom: 7, right: ) + textView.scrollIndicatorInsets = UIEdgeInsets(top: 5, left: 0, bottom: 5, right: 3) let sendTitle = NSLocalizedString("ATTACHMENT_APPROVAL_SEND_BUTTON", comment: "Label for 'send' button in the 'attachment approval' dialog.") sendButton.setTitle(sendTitle, for: .normal) From 83d3f17d44be1eb03fdf17b5a7f9587209f9e640 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Mon, 2 Jul 2018 23:10:50 -0600 Subject: [PATCH 09/11] remove unused code, add comment --- .../ConversationView/ConversationInputTextView.m | 4 ++++ .../ConversationView/ConversationInputToolbar.m | 2 -- .../attachments/AttachmentApprovalViewController.swift | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/ConversationInputTextView.m b/Signal/src/ViewControllers/ConversationView/ConversationInputTextView.m index e47550e9d..78b673148 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationInputTextView.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationInputTextView.m @@ -72,6 +72,10 @@ NS_ASSUME_NONNULL_BEGIN - (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)isAnimated { + // When creating new lines, contentOffset is animated, but because because + // we are simultaneously resizing the text view, this can cause the + // text in the textview to be "too high" in the text view. + // Solution is to disable animation for setting content offset. [super setContentOffset:contentOffset animated:false]; } diff --git a/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m b/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m index 39af63b52..fbead8242 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m @@ -36,8 +36,6 @@ const CGFloat kMaxTextViewHeight = 98; @property (nonatomic, readonly) UIButton *sendButton; @property (nonatomic, readonly) UIButton *voiceMemoButton; -@property (nonatomic) NSValue *lastTextContentSize; -@property (nonatomic) CGFloat toolbarHeight; @property (nonatomic) CGFloat textViewHeight; @property (nonatomic, readonly) NSLayoutConstraint *textViewHeightConstraint; diff --git a/SignalMessaging/attachments/AttachmentApprovalViewController.swift b/SignalMessaging/attachments/AttachmentApprovalViewController.swift index 421fe4226..d0a0d5752 100644 --- a/SignalMessaging/attachments/AttachmentApprovalViewController.swift +++ b/SignalMessaging/attachments/AttachmentApprovalViewController.swift @@ -537,7 +537,7 @@ class CaptioningToolbar: UIView, UITextViewDelegate { textView.addBorder(with: UIColor.lightGray) textView.font = UIFont.ows_dynamicTypeBody textView.returnKeyType = .done - textView.textContainerInset = UIEdgeInsets(top: 7, left: 7, bottom: 7, right: ) + textView.textContainerInset = UIEdgeInsets(top: 7, left: 7, bottom: 7, right: 7) textView.scrollIndicatorInsets = UIEdgeInsets(top: 5, left: 0, bottom: 5, right: 3) let sendTitle = NSLocalizedString("ATTACHMENT_APPROVAL_SEND_BUTTON", comment: "Label for 'send' button in the 'attachment approval' dialog.") From a27ee19f4eabc1061828e9baf561682d9fa520d4 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Mon, 2 Jul 2018 23:33:55 -0600 Subject: [PATCH 10/11] Fix scroll offset for iPhoneX now that content is behind toolbar --- .../ConversationView/ConversationViewController.m | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index 2677f4e39..98c3af041 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -4262,8 +4262,11 @@ typedef enum : NSUInteger { CGFloat contentHeight = self.safeContentHeight; - CGFloat dstY - = MAX(0, contentHeight + self.collectionView.contentInset.bottom - self.collectionView.bounds.size.height); + // bottomLayoutGuide accounts for extra offset needed on iPhoneX + + CGFloat dstY = MAX(0, + contentHeight + self.collectionView.contentInset.bottom + self.bottomLayoutGuide.length + - self.collectionView.bounds.size.height); [self.collectionView setContentOffset:CGPointMake(0, dstY) animated:NO]; [self didScrollToBottom]; From 2b7fc4c9420a6f32d3587212b84956ed796e2d70 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Tue, 3 Jul 2018 10:20:17 -0600 Subject: [PATCH 11/11] CR: fixup false->NO --- .../ConversationView/ConversationInputTextView.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Signal/src/ViewControllers/ConversationView/ConversationInputTextView.m b/Signal/src/ViewControllers/ConversationView/ConversationInputTextView.m index 78b673148..591c5d0d4 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationInputTextView.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationInputTextView.m @@ -76,7 +76,7 @@ NS_ASSUME_NONNULL_BEGIN // we are simultaneously resizing the text view, this can cause the // text in the textview to be "too high" in the text view. // Solution is to disable animation for setting content offset. - [super setContentOffset:contentOffset animated:false]; + [super setContentOffset:contentOffset animated:NO]; } - (void)setContentInset:(UIEdgeInsets)contentInset