From 7e8b2e30346ea7541ac21dbff258a8f845adba8b Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Sat, 18 Aug 2018 22:54:35 +0200 Subject: [PATCH] Faster conversation presentation. There are multiple places in the codebase we present a conversation. We used to have some very conservative machinery around how this was done, for fear of failing to present the call view controller, which would have left a hidden call in the background. We've since addressed that concern more thoroughly via the separate calling UIWindow. As such, the remaining presentation machinery is overly complex and inflexible for what we need. Sometimes we want to animate-push the conversation. (tap on home, tap on "send message" in contact card/group members) Sometimes we want to dismiss a modal, to reveal the conversation behind it (contact picker, group creation) Sometimes we want to present the conversation with no animation (becoming active from a notification) We also want to ensure that we're never pushing more than one conversation view controller, which was previously a problem since we were "pushing" a newly constructed VC in response to these myriad actions. It turned out there were certain code paths that caused multiple actions to be fired in rapid succession which pushed multiple ConversationVC's. The built-in method: `setViewControllers:animated` easily ensures we only have one ConversationVC on the stack, while being composable enough to faciliate the various more efficient animations we desire. The only thing lost with the complex methods is that the naive `presentViewController:` can fail, e.g. if another view is already presented. E.g. if an alert appears *just* before the user taps compose, the contact picker will fail to present. Since we no longer depend on this for presenting the CallViewController, this isn't catostrophic, and in fact, arguable preferable, since we want the user to read and dismiss any alert explicitly. // FREEBIE --- .../ContactShareViewHelper.swift | 4 +- .../ContactViewController.swift | 6 +- .../ConversationViewController.m | 33 +++---- .../ViewControllers/DebugUI/DebugUIContacts.m | 5 +- .../ViewControllers/DebugUI/DebugUIStress.m | 2 +- .../ConversationSearchViewController.swift | 9 +- .../HomeView/HomeViewController.h | 14 ++- .../HomeView/HomeViewController.m | 85 ++----------------- .../NewContactThreadViewController.m | 7 +- .../ViewControllers/NewGroupViewController.m | 28 +++--- .../ViewControllers/ProfileViewController.h | 2 +- .../ViewControllers/ProfileViewController.m | 8 +- .../ShowGroupMembersViewController.m | 8 +- Signal/src/environment/SignalApp.h | 22 +++-- Signal/src/environment/SignalApp.m | 37 ++++---- Signal/src/network/PushManager.m | 6 +- 16 files changed, 107 insertions(+), 169 deletions(-) diff --git a/Signal/src/ViewControllers/ContactShareViewHelper.swift b/Signal/src/ViewControllers/ContactShareViewHelper.swift index 18efd9eac..e16b05c68 100644 --- a/Signal/src/ViewControllers/ContactShareViewHelper.swift +++ b/Signal/src/ViewControllers/ContactShareViewHelper.swift @@ -62,12 +62,12 @@ public class ContactShareViewHelper: NSObject, CNContactViewControllerDelegate { } guard phoneNumbers.count > 1 else { let recipientId = phoneNumbers.first! - SignalApp.shared().presentConversation(forRecipientId: recipientId, action: action) + SignalApp.shared().presentConversation(forRecipientId: recipientId, action: action, animated: true) return } showPhoneNumberPicker(phoneNumbers: phoneNumbers, fromViewController: fromViewController, completion: { (recipientId) in - SignalApp.shared().presentConversation(forRecipientId: recipientId, action: action) + SignalApp.shared().presentConversation(forRecipientId: recipientId, action: action, animated: true) }) } diff --git a/Signal/src/ViewControllers/ContactViewController.swift b/Signal/src/ViewControllers/ContactViewController.swift index 80c689a0c..e7cab0f3d 100644 --- a/Signal/src/ViewControllers/ContactViewController.swift +++ b/Signal/src/ViewControllers/ContactViewController.swift @@ -544,17 +544,17 @@ class ContactViewController: OWSViewController, ContactShareViewHelperDelegate { actionSheet.addAction(UIAlertAction(title: NSLocalizedString("ACTION_SEND_MESSAGE", comment: "Label for 'send message' button in contact view."), style: .default) { _ in - SignalApp.shared().presentConversation(forRecipientId: e164, action: .compose) + SignalApp.shared().presentConversation(forRecipientId: e164, action: .compose, animated: true) }) actionSheet.addAction(UIAlertAction(title: NSLocalizedString("ACTION_AUDIO_CALL", comment: "Label for 'audio call' button in contact view."), style: .default) { _ in - SignalApp.shared().presentConversation(forRecipientId: e164, action: .audioCall) + SignalApp.shared().presentConversation(forRecipientId: e164, action: .audioCall, animated: true) }) actionSheet.addAction(UIAlertAction(title: NSLocalizedString("ACTION_VIDEO_CALL", comment: "Label for 'video call' button in contact view."), style: .default) { _ in - SignalApp.shared().presentConversation(forRecipientId: e164, action: .videoCall) + SignalApp.shared().presentConversation(forRecipientId: e164, action: .videoCall, animated: true) }) } else { // TODO: We could offer callPhoneNumberWithSystemCall. diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index 69676d7d3..75a628e75 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -1133,22 +1133,6 @@ typedef enum : NSUInteger { [self updateBackButtonUnreadCount]; [self autoLoadMoreIfNecessary]; - switch (self.actionOnOpen) { - case ConversationViewActionNone: - break; - case ConversationViewActionCompose: - [self popKeyBoard]; - break; - case ConversationViewActionAudioCall: - [self startAudioCall]; - break; - case ConversationViewActionVideoCall: - [self startVideoCall]; - break; - } - - // Clear the "on open" state after the view has been presented. - self.actionOnOpen = ConversationViewActionNone; self.focusMessageIdOnOpen = nil; self.isViewCompletelyAppeared = YES; @@ -1173,6 +1157,23 @@ typedef enum : NSUInteger { [self becomeFirstResponder]; } } + + switch (self.actionOnOpen) { + case ConversationViewActionNone: + break; + case ConversationViewActionCompose: + [self popKeyBoard]; + break; + case ConversationViewActionAudioCall: + [self startAudioCall]; + break; + case ConversationViewActionVideoCall: + [self startVideoCall]; + break; + } + + // Clear the "on open" state after the view has been presented. + self.actionOnOpen = ConversationViewActionNone; } // `viewWillDisappear` is called whenever the view *starts* to disappear, diff --git a/Signal/src/ViewControllers/DebugUI/DebugUIContacts.m b/Signal/src/ViewControllers/DebugUI/DebugUIContacts.m index 0766aa528..cfa0de37e 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUIContacts.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUIContacts.m @@ -1338,7 +1338,7 @@ NS_ASSUME_NONNULL_BEGIN { NSString *recipientId = [self unregisteredRecipientId]; TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactId:recipientId]; - [SignalApp.sharedApp presentConversationForThread:thread]; + [SignalApp.sharedApp presentConversationForThread:thread animated:YES]; } + (void)createUnregisteredGroupThread @@ -1356,7 +1356,8 @@ NS_ASSUME_NONNULL_BEGIN TSGroupModel *model = [[TSGroupModel alloc] initWithTitle:groupName memberIds:recipientIds image:nil groupId:groupId]; TSGroupThread *thread = [TSGroupThread getOrCreateThreadWithGroupModel:model]; - [SignalApp.sharedApp presentConversationForThread:thread]; + + [SignalApp.sharedApp presentConversationForThread:thread animated:YES]; } @end diff --git a/Signal/src/ViewControllers/DebugUI/DebugUIStress.m b/Signal/src/ViewControllers/DebugUI/DebugUIStress.m index 715bb843d..4a0c99bdd 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUIStress.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUIStress.m @@ -512,7 +512,7 @@ NS_ASSUME_NONNULL_BEGIN }]; OWSAssert(thread); - [SignalApp.sharedApp presentConversationForThread:thread]; + [SignalApp.sharedApp presentConversationForThread:thread animated:YES]; } @end diff --git a/Signal/src/ViewControllers/HomeView/ConversationSearchViewController.swift b/Signal/src/ViewControllers/HomeView/ConversationSearchViewController.swift index 372191ef1..e4af0591d 100644 --- a/Signal/src/ViewControllers/HomeView/ConversationSearchViewController.swift +++ b/Signal/src/ViewControllers/HomeView/ConversationSearchViewController.swift @@ -137,7 +137,7 @@ class ConversationSearchViewController: UITableViewController { } let thread = searchResult.thread - SignalApp.shared().presentConversation(for: thread.threadRecord, action: .compose) + SignalApp.shared().presentConversation(for: thread.threadRecord, action: .compose, animated: true) case .contacts: let sectionResults = searchResultSet.contacts @@ -146,7 +146,7 @@ class ConversationSearchViewController: UITableViewController { return } - SignalApp.shared().presentConversation(forRecipientId: searchResult.recipientId, action: .compose) + SignalApp.shared().presentConversation(forRecipientId: searchResult.recipientId, action: .compose, animated: true) case .messages: let sectionResults = searchResultSet.messages @@ -157,8 +157,9 @@ class ConversationSearchViewController: UITableViewController { let thread = searchResult.thread SignalApp.shared().presentConversation(for: thread.threadRecord, - action: .compose, - focusMessageId: searchResult.messageId) + action: .none, + focusMessageId: searchResult.messageId, + animated: true) } } diff --git a/Signal/src/ViewControllers/HomeView/HomeViewController.h b/Signal/src/ViewControllers/HomeView/HomeViewController.h index 821c34a85..26396befd 100644 --- a/Signal/src/ViewControllers/HomeView/HomeViewController.h +++ b/Signal/src/ViewControllers/HomeView/HomeViewController.h @@ -12,20 +12,16 @@ NS_ASSUME_NONNULL_BEGIN @interface HomeViewController : OWSViewController -- (void)presentThread:(TSThread *)thread action:(ConversationViewAction)action; +- (void)presentThread:(TSThread *)thread action:(ConversationViewAction)action animated:(BOOL)isAnimated; + - (void)presentThread:(TSThread *)thread action:(ConversationViewAction)action - focusMessageId:(nullable NSString *)focusMessageId; + focusMessageId:(nullable NSString *)focusMessageId + animated:(BOOL)isAnimated; +// Used by force-touch Springboard icon shortcut - (void)showNewConversationView; -- (void)presentTopLevelModalViewController:(UIViewController *)viewController - animateDismissal:(BOOL)animateDismissal - animatePresentation:(BOOL)animatePresentation; -- (void)pushTopLevelViewController:(UIViewController *)viewController - animateDismissal:(BOOL)animateDismissal - animatePresentation:(BOOL)animatePresentation; - @end NS_ASSUME_NONNULL_END diff --git a/Signal/src/ViewControllers/HomeView/HomeViewController.m b/Signal/src/ViewControllers/HomeView/HomeViewController.m index d2423deff..064ee9cda 100644 --- a/Signal/src/ViewControllers/HomeView/HomeViewController.m +++ b/Signal/src/ViewControllers/HomeView/HomeViewController.m @@ -554,9 +554,8 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations // // We just want to make sure contact access is *complete* before showing the compose // screen to avoid flicker. - OWSNavigationController *navigationController = - [[OWSNavigationController alloc] initWithRootViewController:viewController]; - [self presentTopLevelModalViewController:navigationController animateDismissal:YES animatePresentation:YES]; + OWSNavigationController *modal = [[OWSNavigationController alloc] initWithRootViewController:viewController]; + [self.navigationController presentViewController:modal animated:YES completion:nil]; }]; } @@ -744,8 +743,6 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations ExperienceUpgradesPageViewController *experienceUpgradeViewController = [[ExperienceUpgradesPageViewController alloc] initWithExperienceUpgrades:unseenUpgrades]; [self presentViewController:experienceUpgradeViewController animated:YES completion:nil]; - } else if (!self.hasEverAppeared && [ProfileViewController shouldDisplayProfileViewOnLaunch]) { - [ProfileViewController presentForUpgradeOrNag:self]; } else { [OWSAlerts showIOSUpgradeNagIfNecessary]; } @@ -1156,7 +1153,7 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations } case HomeViewControllerSectionConversations: { TSThread *thread = [self threadForIndexPath:indexPath]; - [self presentThread:thread action:ConversationViewActionNone]; + [self presentThread:thread action:ConversationViewActionNone animated:YES]; [tableView deselectRowAtIndexPath:indexPath animated:YES]; break; } @@ -1167,14 +1164,15 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations } } -- (void)presentThread:(TSThread *)thread action:(ConversationViewAction)action +- (void)presentThread:(TSThread *)thread action:(ConversationViewAction)action animated:(BOOL)isAnimated { - [self presentThread:thread action:action focusMessageId:nil]; + [self presentThread:thread action:action focusMessageId:nil animated:isAnimated]; } - (void)presentThread:(TSThread *)thread action:(ConversationViewAction)action focusMessageId:(nullable NSString *)focusMessageId + animated:(BOOL)isAnimated { if (thread == nil) { OWSFail(@"Thread unexpectedly nil"); @@ -1183,79 +1181,14 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations // We do this synchronously if we're already on the main thread. DispatchMainThreadSafe(^{ - ConversationViewController *viewController = [ConversationViewController new]; - [viewController configureForThread:thread action:action focusMessageId:focusMessageId]; + ConversationViewController *conversationVC = [ConversationViewController new]; + [conversationVC configureForThread:thread action:action focusMessageId:focusMessageId]; self.lastThread = thread; - [self pushTopLevelViewController:viewController animateDismissal:YES animatePresentation:YES]; + [self.navigationController setViewControllers:@[ self, conversationVC ] animated:isAnimated]; }); } -- (void)presentTopLevelModalViewController:(UIViewController *)viewController - animateDismissal:(BOOL)animateDismissal - animatePresentation:(BOOL)animatePresentation -{ - OWSAssertIsOnMainThread(); - OWSAssert(viewController); - - [self presentViewControllerWithBlock:^{ - [self presentViewController:viewController animated:animatePresentation completion:nil]; - } - animateDismissal:animateDismissal]; -} - -- (void)pushTopLevelViewController:(UIViewController *)viewController - animateDismissal:(BOOL)animateDismissal - animatePresentation:(BOOL)animatePresentation -{ - OWSAssertIsOnMainThread(); - OWSAssert(viewController); - - [self presentViewControllerWithBlock:^{ - [self.navigationController pushViewController:viewController animated:animatePresentation]; - } - animateDismissal:animateDismissal]; -} - -- (void)presentViewControllerWithBlock:(void (^)(void))presentationBlock animateDismissal:(BOOL)animateDismissal -{ - OWSAssertIsOnMainThread(); - OWSAssert(presentationBlock); - - // Presenting a "top level" view controller has three steps: - // - // First, dismiss any presented modal. - // Second, pop to the root view controller if necessary. - // Third present the new view controller using presentationBlock. - - // Define a block to perform the second step. - void (^dismissNavigationBlock)(void) = ^{ - if (self.navigationController.viewControllers.lastObject != self) { - [CATransaction begin]; - [CATransaction setCompletionBlock:^{ - presentationBlock(); - }]; - - [self.navigationController popToViewController:self animated:animateDismissal]; - - [CATransaction commit]; - } else { - presentationBlock(); - } - }; - - // Perform the first step. - if (self.presentedViewController) { - if ([self.presentedViewController isKindOfClass:[CallViewController class]]) { - OWSProdInfo([OWSAnalyticsEvents errorCouldNotPresentViewDueToCall]); - return; - } - [self.presentedViewController dismissViewControllerAnimated:animateDismissal completion:dismissNavigationBlock]; - } else { - dismissNavigationBlock(); - } -} - #pragma mark - Groupings - (YapDatabaseViewMappings *)threadMappings diff --git a/Signal/src/ViewControllers/NewContactThreadViewController.m b/Signal/src/ViewControllers/NewContactThreadViewController.m index 30b192bb3..1664821e2 100644 --- a/Signal/src/ViewControllers/NewContactThreadViewController.m +++ b/Signal/src/ViewControllers/NewContactThreadViewController.m @@ -823,11 +823,8 @@ NS_ASSUME_NONNULL_BEGIN - (void)newConversationWithThread:(TSThread *)thread { OWSAssert(thread != nil); - [self dismissViewControllerAnimated:YES - completion:^() { - [SignalApp.sharedApp presentConversationForThread:thread - action:ConversationViewActionCompose]; - }]; + [SignalApp.sharedApp presentConversationForThread:thread action:ConversationViewActionCompose animated:NO]; + [self.presentingViewController dismissViewControllerAnimated:YES completion:nil]; } - (void)showNewGroupView:(id)sender diff --git a/Signal/src/ViewControllers/NewGroupViewController.m b/Signal/src/ViewControllers/NewGroupViewController.m index 23cc2dd0a..a88417265 100644 --- a/Signal/src/ViewControllers/NewGroupViewController.m +++ b/Signal/src/ViewControllers/NewGroupViewController.m @@ -452,30 +452,24 @@ const NSUInteger kNewGroupViewControllerAvatarWidth = 68; DDLogError(@"Group creation successful."); dispatch_async(dispatch_get_main_queue(), ^{ - [self dismissViewControllerAnimated:YES - completion:^{ - // Pop to new group thread. - [SignalApp.sharedApp presentConversationForThread:thread]; - }]; - + [SignalApp.sharedApp presentConversationForThread:thread action:ConversationViewActionCompose animated:NO]; + [self.presentingViewController dismissViewControllerAnimated:YES completion:nil]; }); }; void (^failureHandler)(NSError *error) = ^(NSError *error) { DDLogError(@"Group creation failed: %@", error); + // Add an error message to the new group indicating + // that group creation didn't succeed. + TSErrorMessage *errorMessage = [[TSErrorMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] + inThread:thread + failedMessageType:TSErrorMessageGroupCreationFailed]; + [errorMessage save]; + dispatch_async(dispatch_get_main_queue(), ^{ - [self dismissViewControllerAnimated:YES - completion:^{ - // Add an error message to the new group indicating - // that group creation didn't succeed. - [[[TSErrorMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] - inThread:thread - failedMessageType:TSErrorMessageGroupCreationFailed] - save]; - - [SignalApp.sharedApp presentConversationForThread:thread]; - }]; + [SignalApp.sharedApp presentConversationForThread:thread action:ConversationViewActionCompose animated:NO]; + [self.presentingViewController dismissViewControllerAnimated:YES completion:nil]; }); }; diff --git a/Signal/src/ViewControllers/ProfileViewController.h b/Signal/src/ViewControllers/ProfileViewController.h index eecb2bae3..b53c2a0d7 100644 --- a/Signal/src/ViewControllers/ProfileViewController.h +++ b/Signal/src/ViewControllers/ProfileViewController.h @@ -16,7 +16,7 @@ NS_ASSUME_NONNULL_BEGIN + (void)presentForAppSettings:(UINavigationController *)navigationController; + (void)presentForRegistration:(UINavigationController *)navigationController; -+ (void)presentForUpgradeOrNag:(HomeViewController *)presentingController NS_SWIFT_NAME(presentForUpgradeOrNag(from:)); ++ (void)presentForUpgradeOrNag:(HomeViewController *)fromViewController NS_SWIFT_NAME(presentForUpgradeOrNag(from:)); @end diff --git a/Signal/src/ViewControllers/ProfileViewController.m b/Signal/src/ViewControllers/ProfileViewController.m index 47ee60750..a698b4f35 100644 --- a/Signal/src/ViewControllers/ProfileViewController.m +++ b/Signal/src/ViewControllers/ProfileViewController.m @@ -558,15 +558,13 @@ NSString *const kProfileView_LastPresentedDate = @"kProfileView_LastPresentedDat [navigationController pushViewController:vc animated:YES]; } -+ (void)presentForUpgradeOrNag:(HomeViewController *)presentingController ++ (void)presentForUpgradeOrNag:(HomeViewController *)fromViewController { - OWSAssert(presentingController); + OWSAssert(fromViewController); ProfileViewController *vc = [[ProfileViewController alloc] initWithMode:ProfileViewMode_UpgradeOrNag]; OWSNavigationController *navigationController = [[OWSNavigationController alloc] initWithRootViewController:vc]; - [presentingController presentTopLevelModalViewController:navigationController - animateDismissal:YES - animatePresentation:YES]; + [fromViewController presentViewController:navigationController animated:YES completion:nil]; } #pragma mark - AvatarViewHelperDelegate diff --git a/Signal/src/ViewControllers/ThreadSettings/ShowGroupMembersViewController.m b/Signal/src/ViewControllers/ThreadSettings/ShowGroupMembersViewController.m index d9a7960ed..e81502d29 100644 --- a/Signal/src/ViewControllers/ThreadSettings/ShowGroupMembersViewController.m +++ b/Signal/src/ViewControllers/ThreadSettings/ShowGroupMembersViewController.m @@ -403,12 +403,16 @@ NS_ASSUME_NONNULL_BEGIN { OWSAssert(recipientId.length > 0); - [SignalApp.sharedApp presentConversationForRecipientId:recipientId action:ConversationViewActionCompose]; + [SignalApp.sharedApp presentConversationForRecipientId:recipientId + action:ConversationViewActionCompose + animated:YES]; } - (void)callMember:(NSString *)recipientId { - [SignalApp.sharedApp presentConversationForRecipientId:recipientId action:ConversationViewActionAudioCall]; + [SignalApp.sharedApp presentConversationForRecipientId:recipientId + action:ConversationViewActionAudioCall + animated:YES]; } - (void)showSafetyNumberView:(NSString *)recipientId diff --git a/Signal/src/environment/SignalApp.h b/Signal/src/environment/SignalApp.h index f9277ec49..4cea69f28 100644 --- a/Signal/src/environment/SignalApp.h +++ b/Signal/src/environment/SignalApp.h @@ -35,16 +35,24 @@ NS_ASSUME_NONNULL_BEGIN + (instancetype)sharedApp; -#pragma mark - View Convenience Methods +#pragma mark - Conversation Presentation + +- (void)presentConversationForRecipientId:(NSString *)recipientId animated:(BOOL)isAnimated; + +- (void)presentConversationForRecipientId:(NSString *)recipientId + action:(ConversationViewAction)action + animated:(BOOL)isAnimated; + +- (void)presentConversationForThreadId:(NSString *)threadId animated:(BOOL)isAnimated; + +- (void)presentConversationForThread:(TSThread *)thread animated:(BOOL)isAnimated; + +- (void)presentConversationForThread:(TSThread *)thread action:(ConversationViewAction)action animated:(BOOL)isAnimated; -- (void)presentConversationForRecipientId:(NSString *)recipientId; -- (void)presentConversationForRecipientId:(NSString *)recipientId action:(ConversationViewAction)action; -- (void)presentConversationForThreadId:(NSString *)threadId; -- (void)presentConversationForThread:(TSThread *)thread; -- (void)presentConversationForThread:(TSThread *)thread action:(ConversationViewAction)action; - (void)presentConversationForThread:(TSThread *)thread action:(ConversationViewAction)action - focusMessageId:(nullable NSString *)focusMessageId; + focusMessageId:(nullable NSString *)focusMessageId + animated:(BOOL)isAnimated; #pragma mark - Methods diff --git a/Signal/src/environment/SignalApp.m b/Signal/src/environment/SignalApp.m index f33802f2b..ca458c72c 100644 --- a/Signal/src/environment/SignalApp.m +++ b/Signal/src/environment/SignalApp.m @@ -152,24 +152,24 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - View Convenience Methods -- (void)presentConversationForRecipientId:(NSString *)recipientId +- (void)presentConversationForRecipientId:(NSString *)recipientId animated:(BOOL)isAnimated { - [self presentConversationForRecipientId:recipientId action:ConversationViewActionNone]; + [self presentConversationForRecipientId:recipientId action:ConversationViewActionNone animated:(BOOL)isAnimated]; } -- (void)presentConversationForRecipientId:(NSString *)recipientId action:(ConversationViewAction)action +- (void)presentConversationForRecipientId:(NSString *)recipientId + action:(ConversationViewAction)action + animated:(BOOL)isAnimated { - DispatchMainThreadSafe(^{ - __block TSThread *thread = nil; - [OWSPrimaryStorage.dbReadWriteConnection - readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - thread = [TSContactThread getOrCreateThreadWithContactId:recipientId transaction:transaction]; - }]; - [self presentConversationForThread:thread action:action]; - }); + __block TSThread *thread = nil; + [OWSPrimaryStorage.dbReadWriteConnection + readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { + thread = [TSContactThread getOrCreateThreadWithContactId:recipientId transaction:transaction]; + }]; + [self presentConversationForThread:thread action:action animated:(BOOL)isAnimated]; } -- (void)presentConversationForThreadId:(NSString *)threadId +- (void)presentConversationForThreadId:(NSString *)threadId animated:(BOOL)isAnimated { OWSAssert(threadId.length > 0); @@ -179,22 +179,23 @@ NS_ASSUME_NONNULL_BEGIN return; } - [self presentConversationForThread:thread]; + [self presentConversationForThread:thread animated:isAnimated]; } -- (void)presentConversationForThread:(TSThread *)thread +- (void)presentConversationForThread:(TSThread *)thread animated:(BOOL)isAnimated { - [self presentConversationForThread:thread action:ConversationViewActionNone]; + [self presentConversationForThread:thread action:ConversationViewActionNone animated:isAnimated]; } -- (void)presentConversationForThread:(TSThread *)thread action:(ConversationViewAction)action +- (void)presentConversationForThread:(TSThread *)thread action:(ConversationViewAction)action animated:(BOOL)isAnimated { - [self presentConversationForThread:thread action:action focusMessageId:nil]; + [self presentConversationForThread:thread action:action focusMessageId:nil animated:isAnimated]; } - (void)presentConversationForThread:(TSThread *)thread action:(ConversationViewAction)action focusMessageId:(nullable NSString *)focusMessageId + animated:(BOOL)isAnimated { OWSAssertIsOnMainThread(); @@ -216,7 +217,7 @@ NS_ASSUME_NONNULL_BEGIN } } - [self.homeViewController presentThread:thread action:action focusMessageId:focusMessageId]; + [self.homeViewController presentThread:thread action:action focusMessageId:focusMessageId animated:isAnimated]; }); } diff --git a/Signal/src/network/PushManager.m b/Signal/src/network/PushManager.m index 1585a192a..2d3db83ae 100644 --- a/Signal/src/network/PushManager.m +++ b/Signal/src/network/PushManager.m @@ -154,7 +154,11 @@ NSString *const Signal_Message_MarkAsRead_Identifier = @"Signal_Message_MarkAsRe } self.hasPresentedConversationSinceLastDeactivation = YES; - [SignalApp.sharedApp presentConversationForThreadId:threadId]; + + // This will happen before the app is visible. By making this animated:NO, the conversation screen + // will be visible to the user immediately upon opening the app, rather than having to watch it animate + // in from the homescreen. + [SignalApp.sharedApp presentConversationForThreadId:threadId animated:NO]; } - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification