diff --git a/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.h b/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.h index d98d6b862..0a1e8813b 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.h +++ b/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.h @@ -36,6 +36,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 53e56335b..942c6ccb7 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationInputToolbar.m @@ -236,6 +236,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 ea2b27d4e..868142685 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -1023,6 +1023,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, diff --git a/Signal/src/ViewControllers/MediaDetailViewController.m b/Signal/src/ViewControllers/MediaDetailViewController.m index 84aff9dde..af8370a62 100644 --- a/Signal/src/ViewControllers/MediaDetailViewController.m +++ b/Signal/src/ViewControllers/MediaDetailViewController.m @@ -356,7 +356,10 @@ NS_ASSUME_NONNULL_BEGIN - (void)updateFooterBarButtonItemsWithIsPlayingVideo:(BOOL)isPlayingVideo { - OWSAssert(self.footerBar); + if (!self.footerBar) { + DDLogVerbose(@"%@ No footer bar visible.", self.logTag); + return; + } NSMutableArray *toolbarItems = [NSMutableArray new];