From 27b6a5e5bb604dd31228416df29547583a0388e3 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Mon, 11 Jun 2018 15:31:54 -0400 Subject: [PATCH] Open message search results. --- .../ConversationViewController.h | 4 +- .../ConversationViewController.m | 38 +++++++++++++++++-- .../ConversationSearchViewController.swift | 4 +- .../HomeView/HomeViewController.h | 3 ++ .../HomeView/HomeViewController.m | 15 ++++++-- Signal/src/call/OutboundCallInitiator.swift | 5 +-- Signal/src/environment/SignalApp.h | 11 +++++- Signal/src/environment/SignalApp.m | 13 ++++++- .../utils/ConversationSearcher.swift | 12 ++++-- 9 files changed, 84 insertions(+), 21 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.h b/Signal/src/ViewControllers/ConversationView/ConversationViewController.h index 002a95218..31d7841c1 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.h +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.h @@ -19,7 +19,9 @@ typedef NS_ENUM(NSUInteger, ConversationViewAction) { @property (nonatomic, readonly) TSThread *thread; -- (void)configureForThread:(TSThread *)thread action:(ConversationViewAction)action; +- (void)configureForThread:(TSThread *)thread + action:(ConversationViewAction)action + focusMessageId:(nullable NSString *)focusMessageId; - (void)popKeyBoard; diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index 861314ec2..de074d384 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -195,6 +195,8 @@ typedef enum : NSUInteger { @property (nonatomic) NSUInteger lastRangeLength; @property (nonatomic) ConversationViewAction actionOnOpen; +@property (nonatomic, nullable) NSString *focusMessageIdOnOpen; + @property (nonatomic) BOOL peek; @property (nonatomic, readonly) OWSContactsManager *contactsManager; @@ -426,11 +428,16 @@ typedef enum : NSUInteger { [self hideInputIfNeeded]; } -- (void)configureForThread:(TSThread *)thread action:(ConversationViewAction)action +- (void)configureForThread:(TSThread *)thread + action:(ConversationViewAction)action + focusMessageId:(nullable NSString *)focusMessageId { + OWSAssert(thread); + _thread = thread; _isGroupConversation = [self.thread isKindOfClass:[TSGroupThread class]]; self.actionOnOpen = action; + self.focusMessageIdOnOpen = focusMessageId; _cellMediaCache = [NSCache new]; // Cache the cell media for ~24 cells. self.cellMediaCache.countLimit = 24; @@ -698,13 +705,35 @@ typedef enum : NSUInteger { return nil; } +- (NSIndexPath *_Nullable)indexPathOfMessageOnOpen +{ + OWSAssert(self.focusMessageIdOnOpen); + + NSInteger row = 0; + for (ConversationViewItem *viewItem in self.viewItems) { + if ([viewItem.interaction.uniqueId isEqualToString:self.focusMessageIdOnOpen]) { + return [NSIndexPath indexPathForRow:row inSection:0]; + } + row++; + } + return nil; +} + - (void)scrollToDefaultPosition { if (self.isUserScrolling) { return; } - NSIndexPath *_Nullable indexPath = [self indexPathOfUnreadMessagesIndicator]; + NSIndexPath *_Nullable indexPath = nil; + if (self.focusMessageIdOnOpen) { + indexPath = [self indexPathOfMessageOnOpen]; + } + + if (!indexPath) { + indexPath = [self indexPathOfUnreadMessagesIndicator]; + } + if (indexPath) { if (indexPath.section == 0 && indexPath.row == 0) { [self.collectionView setContentOffset:CGPointZero animated:NO]; @@ -1081,8 +1110,9 @@ typedef enum : NSUInteger { break; } + // Clear the "on open" state after the view has been presented. self.actionOnOpen = ConversationViewActionNone; - + self.focusMessageIdOnOpen = nil; self.isViewCompletelyAppeared = YES; self.viewHasEverAppeared = YES; @@ -1557,7 +1587,7 @@ typedef enum : NSUInteger { // Don’t auto-scroll after “loading more messages” unless we have “more unseen messages”. // // Otherwise, tapping on "load more messages" autoscrolls you downward which is completely wrong. - if (hasEarlierUnseenMessages) { + if (hasEarlierUnseenMessages && !self.focusMessageIdOnOpen) { [self scrollToUnreadIndicatorAnimated]; } } diff --git a/Signal/src/ViewControllers/HomeView/ConversationSearchViewController.swift b/Signal/src/ViewControllers/HomeView/ConversationSearchViewController.swift index 46f5b99b0..a68001c76 100644 --- a/Signal/src/ViewControllers/HomeView/ConversationSearchViewController.swift +++ b/Signal/src/ViewControllers/HomeView/ConversationSearchViewController.swift @@ -79,7 +79,9 @@ class ConversationSearchViewController: UITableViewController { } let thread = searchResult.thread - SignalApp.shared().presentConversation(for: thread.threadRecord, action: .compose) + SignalApp.shared().presentConversation(for: thread.threadRecord, + action: .compose, + focusMessageId: searchResult.messageId) } } diff --git a/Signal/src/ViewControllers/HomeView/HomeViewController.h b/Signal/src/ViewControllers/HomeView/HomeViewController.h index a19c94488..d86824b5b 100644 --- a/Signal/src/ViewControllers/HomeView/HomeViewController.h +++ b/Signal/src/ViewControllers/HomeView/HomeViewController.h @@ -11,6 +11,9 @@ @interface HomeViewController : OWSViewController - (void)presentThread:(TSThread *)thread action:(ConversationViewAction)action; +- (void)presentThread:(TSThread *)thread + action:(ConversationViewAction)action + focusMessageId:(nullable NSString *)focusMessageId; - (void)showNewConversationView; diff --git a/Signal/src/ViewControllers/HomeView/HomeViewController.m b/Signal/src/ViewControllers/HomeView/HomeViewController.m index 5a858829e..fb4d3c048 100644 --- a/Signal/src/ViewControllers/HomeView/HomeViewController.m +++ b/Signal/src/ViewControllers/HomeView/HomeViewController.m @@ -424,7 +424,7 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations ConversationViewController *vc = [ConversationViewController new]; TSThread *thread = [self threadForIndexPath:indexPath]; self.lastThread = thread; - [vc configureForThread:thread action:ConversationViewActionNone]; + [vc configureForThread:thread action:ConversationViewActionNone focusMessageId:nil]; [vc peekSetup]; return vc; @@ -1000,6 +1000,13 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations } - (void)presentThread:(TSThread *)thread action:(ConversationViewAction)action +{ + [self presentThread:thread action:action focusMessageId:nil]; +} + +- (void)presentThread:(TSThread *)thread + action:(ConversationViewAction)action + focusMessageId:(nullable NSString *)focusMessageId { if (thread == nil) { OWSFail(@"Thread unexpectedly nil"); @@ -1008,11 +1015,11 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations // We do this synchronously if we're already on the main thread. DispatchMainThreadSafe(^{ - ConversationViewController *mvc = [ConversationViewController new]; - [mvc configureForThread:thread action:action]; + ConversationViewController *viewController = [ConversationViewController new]; + [viewController configureForThread:thread action:action focusMessageId:focusMessageId]; self.lastThread = thread; - [self pushTopLevelViewController:mvc animateDismissal:YES animatePresentation:YES]; + [self pushTopLevelViewController:viewController animateDismissal:YES animatePresentation:YES]; }); } diff --git a/Signal/src/call/OutboundCallInitiator.swift b/Signal/src/call/OutboundCallInitiator.swift index b3900960f..cc2f49626 100644 --- a/Signal/src/call/OutboundCallInitiator.swift +++ b/Signal/src/call/OutboundCallInitiator.swift @@ -45,10 +45,7 @@ import SignalMessaging isVideo: Bool) -> Bool { // Rather than an init-assigned dependency property, we access `callUIAdapter` via Environment // because it can change after app launch due to user settings - guard let callUIAdapter = SignalApp.shared().callUIAdapter else { - owsFail("\(TAG) can't initiate call because callUIAdapter is nil") - return false - } + let callUIAdapter = SignalApp.shared().callUIAdapter guard let frontmostViewController = UIApplication.shared.frontmostViewController else { owsFail("\(TAG) could not identify frontmostViewController in \(#function)") return false diff --git a/Signal/src/environment/SignalApp.h b/Signal/src/environment/SignalApp.h index 05231e32a..f9277ec49 100644 --- a/Signal/src/environment/SignalApp.h +++ b/Signal/src/environment/SignalApp.h @@ -4,6 +4,8 @@ #import "ConversationViewController.h" +NS_ASSUME_NONNULL_BEGIN + @class AccountManager; @class CallService; @class CallUIAdapter; @@ -17,8 +19,8 @@ @interface SignalApp : NSObject -@property (nonatomic, weak) HomeViewController *homeViewController; -@property (nonatomic, weak) OWSNavigationController *signUpFlowNavigationController; +@property (nonatomic, nullable, weak) HomeViewController *homeViewController; +@property (nonatomic, nullable, weak) OWSNavigationController *signUpFlowNavigationController; // TODO: Convert to singletons? @property (nonatomic, readonly) OWSWebRTCCallMessageHandler *callMessageHandler; @@ -40,6 +42,9 @@ - (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; #pragma mark - Methods @@ -48,3 +53,5 @@ + (void)clearAllNotifications; @end + +NS_ASSUME_NONNULL_END diff --git a/Signal/src/environment/SignalApp.m b/Signal/src/environment/SignalApp.m index de9e7a952..4d95b7d8d 100644 --- a/Signal/src/environment/SignalApp.m +++ b/Signal/src/environment/SignalApp.m @@ -13,6 +13,8 @@ #import #import +NS_ASSUME_NONNULL_BEGIN + @interface SignalApp () @property (nonatomic) OWSWebRTCCallMessageHandler *callMessageHandler; @@ -186,6 +188,13 @@ } - (void)presentConversationForThread:(TSThread *)thread action:(ConversationViewAction)action +{ + [self presentConversationForThread:thread action:action focusMessageId:nil]; +} + +- (void)presentConversationForThread:(TSThread *)thread + action:(ConversationViewAction)action + focusMessageId:(nullable NSString *)focusMessageId { OWSAssertIsOnMainThread(); @@ -207,7 +216,7 @@ } } - [self.homeViewController presentThread:thread action:action]; + [self.homeViewController presentThread:thread action:action focusMessageId:focusMessageId]; }); } @@ -248,3 +257,5 @@ } @end + +NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/utils/ConversationSearcher.swift b/SignalMessaging/utils/ConversationSearcher.swift index 32f4bab1d..2c68cc250 100644 --- a/SignalMessaging/utils/ConversationSearcher.swift +++ b/SignalMessaging/utils/ConversationSearcher.swift @@ -7,10 +7,14 @@ import SignalServiceKit public class ConversationSearchResult { public let thread: ThreadViewModel + + public let messageId: String? + public let snippet: String? - init(thread: ThreadViewModel, snippet: String?) { + init(thread: ThreadViewModel, messageId: String?, snippet: String?) { self.thread = thread + self.messageId = messageId self.snippet = snippet } } @@ -71,7 +75,7 @@ public class ConversationSearcher: NSObject { if let thread = match as? TSThread { let threadViewModel = ThreadViewModel(thread: thread, transaction: transaction) let snippet: String? = thread.lastMessageText(transaction: transaction) - let searchResult = ConversationSearchResult(thread: threadViewModel, snippet: snippet) + let searchResult = ConversationSearchResult(thread: threadViewModel, messageId: nil, snippet: snippet) if let contactThread = thread as? TSContactThread { let recipientId = contactThread.contactIdentifier() @@ -82,14 +86,14 @@ public class ConversationSearcher: NSObject { let thread = message.thread(with: transaction) let threadViewModel = ThreadViewModel(thread: thread, transaction: transaction) - let searchResult = ConversationSearchResult(thread: threadViewModel, snippet: snippet) + let searchResult = ConversationSearchResult(thread: threadViewModel, messageId: message.uniqueId, snippet: snippet) messages.append(searchResult) } else if let signalAccount = match as? SignalAccount { let searchResult = ContactSearchResult(signalAccount: signalAccount) contacts.append(searchResult) } else { - Logger.debug("\(self.logTag) in \(#function) unhandled item: \(match)") + owsFail("\(self.logTag) in \(#function) unhandled item: \(match)") } }