diff --git a/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.h b/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.h index 5b7df0499..5492be4b2 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.h +++ b/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.h @@ -40,6 +40,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)beginEditingTextMessage; - (void)endEditingTextMessage; +- (BOOL)isInputTextViewFirstResponder; - (void)setInputTextViewDelegate:(id)value; diff --git a/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m b/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m index baa9d95c8..d4a288ad9 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m @@ -240,6 +240,11 @@ static const CGFloat ConversationInputToolbarBorderViewHeight = 0.5; [self.inputTextView resignFirstResponder]; } +- (BOOL)isInputTextViewFirstResponder +{ + return self.inputTextView.isFirstResponder; +} + - (void)ensureContentConstraints { [NSLayoutConstraint deactivateConstraints:self.contentContraints]; diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index ea817812b..666fabd05 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -1013,6 +1013,26 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) { self.isViewCompletelyAppeared = YES; self.viewHasEverAppeared = YES; + + // HACK: Because the inputToolbar is the inputAccessoryView, we make some special considertations WRT it's firstResponder status. + // + // When a view controller is presented, it is first responder. However if we resign first responder + // and the view re-appears, without being presented, the inputToolbar can become invisible. + // e.g. specifically works around the scenario: + // - Present this VC + // - Longpress on a message to show edit menu, which entails making the pressed view the first responder. + // - Begin presenting another view, e.g. swipe-left for details or swipe-right to go back, but quit part way, so that you remain on the conversation view + // - toolbar will be not be visible unless we reaquire first responder. + if (!self.isFirstResponder) { + + // We don't have to worry about the input toolbar being visible if the inputToolbar.textView is first responder + // In fact doing so would unnecessarily dismiss the keyboard which is probably not desirable and at least + // a distracting animation. + if (!self.inputToolbar.isInputTextViewFirstResponder) { + DDLogDebug(@"%@ reclaiming first responder to ensure toolbar is shown.", self.logTag); + [self becomeFirstResponder]; + } + } } // `viewWillDisappear` is called whenever the view *starts* to disappear,