From 85c4b3d745c76bcbeefe5d16e15d0718b6f6b60b Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Thu, 27 Jan 2022 14:19:07 +1100 Subject: [PATCH] show recent search result as default for global search screen --- Session.xcodeproj/project.pbxproj | 4 +++ .../GlobalSearchViewController.swift | 36 +++++++++++++++++-- .../Storage+RecentSearchResults.swift | 31 ++++++++++++++++ .../Translations/en.lproj/Localizable.strings | 2 ++ Session/Shared/ConversationCell.swift | 8 +++++ 5 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 Session/Home/GlobalSearch/Storage+RecentSearchResults.swift diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index 10dfc1ac7..f1e7d2d4e 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -141,6 +141,7 @@ 7B4C75CD26BB92060000AC89 /* DeletedMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B4C75CC26BB92060000AC89 /* DeletedMessageView.swift */; }; 7B7CB18B270591630079FF93 /* ShareLogsModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B7CB18A270591630079FF93 /* ShareLogsModal.swift */; }; 7BA7F4BB279F9F5800B3A466 /* EmptySearchResultCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BA7F4BA279F9F5800B3A466 /* EmptySearchResultCell.swift */; }; + 7BA7F4BD27A216B600B3A466 /* Storage+RecentSearchResults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BA7F4BC27A216B600B3A466 /* Storage+RecentSearchResults.swift */; }; 7BA9057E27911C5800998B3C /* GlobalSearchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BA9057D27911C5800998B3C /* GlobalSearchViewController.swift */; }; 7BC01A3E241F40AB00BC7C55 /* NotificationServiceExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BC01A3D241F40AB00BC7C55 /* NotificationServiceExtension.swift */; }; 7BC01A42241F40AB00BC7C55 /* SessionNotificationServiceExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 7BC01A3B241F40AB00BC7C55 /* SessionNotificationServiceExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; @@ -1110,6 +1111,7 @@ 7B4C75CC26BB92060000AC89 /* DeletedMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeletedMessageView.swift; sourceTree = ""; }; 7B7CB18A270591630079FF93 /* ShareLogsModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareLogsModal.swift; sourceTree = ""; }; 7BA7F4BA279F9F5800B3A466 /* EmptySearchResultCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptySearchResultCell.swift; sourceTree = ""; }; + 7BA7F4BC27A216B600B3A466 /* Storage+RecentSearchResults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+RecentSearchResults.swift"; sourceTree = ""; }; 7BA9057D27911C5800998B3C /* GlobalSearchViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalSearchViewController.swift; sourceTree = ""; }; 7BC01A3B241F40AB00BC7C55 /* SessionNotificationServiceExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SessionNotificationServiceExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 7BC01A3D241F40AB00BC7C55 /* NotificationServiceExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationServiceExtension.swift; sourceTree = ""; }; @@ -2030,6 +2032,7 @@ children = ( 7BA9057D27911C5800998B3C /* GlobalSearchViewController.swift */, 7BA7F4BA279F9F5800B3A466 /* EmptySearchResultCell.swift */, + 7BA7F4BC27A216B600B3A466 /* Storage+RecentSearchResults.swift */, ); path = GlobalSearch; sourceTree = ""; @@ -4911,6 +4914,7 @@ 3427C64320F500E000EEC730 /* OWSMessageTimerView.m in Sources */, B90418E6183E9DD40038554A /* DateUtil.m in Sources */, C33100092558FF6D00070591 /* UserCell.swift in Sources */, + 7BA7F4BD27A216B600B3A466 /* Storage+RecentSearchResults.swift in Sources */, B8269D2925C7A4B400488AB4 /* InputView.swift in Sources */, C374EEE225DA26740073A857 /* LinkPreviewModal.swift in Sources */, 3496956F21A301A100DCFE74 /* OWSBackupLazyRestore.swift in Sources */, diff --git a/Session/Home/GlobalSearch/GlobalSearchViewController.swift b/Session/Home/GlobalSearch/GlobalSearchViewController.swift index 23b95120d..785069316 100644 --- a/Session/Home/GlobalSearch/GlobalSearchViewController.swift +++ b/Session/Home/GlobalSearch/GlobalSearchViewController.swift @@ -9,6 +9,7 @@ class GlobalSearchViewController: BaseVC, UITableViewDelegate, UITableViewDataSo refreshSearchResults() } } + var recentSearchResults: [String] = [] var searchResultSet: HomeScreenSearchResultSet = HomeScreenSearchResultSet.empty private var lastSearchText: String? var searcher: FullTextSearcher { @@ -20,6 +21,7 @@ class GlobalSearchViewController: BaseVC, UITableViewDelegate, UITableViewDataSo case noResults case contacts case messages + case recent } // MARK: UI Components @@ -87,6 +89,7 @@ class GlobalSearchViewController: BaseVC, UITableViewDelegate, UITableViewDataSo } private func reloadTableData() { + recentSearchResults = Array(Storage.shared.getRecentSearchResults().reversed()) tableView.reloadData() } @@ -208,23 +211,33 @@ extension GlobalSearchViewController { let sectionResults = searchResultSet.messages guard let searchResult = sectionResults[safe: indexPath.row], let threadId = searchResult.thread.threadRecord.uniqueId, let thread = TSThread.fetch(uniqueId: threadId) else { return } show(thread, highlightedMessageID: searchResult.messageId, animated: true) + case .recent: + guard let threadId = recentSearchResults[safe: indexPath.row], let thread = TSThread.fetch(uniqueId: threadId) else { return } + show(thread, highlightedMessageID: nil, animated: true, isFromRecent: true) } } - private func show(_ thread: TSThread, highlightedMessageID: String?, animated: Bool) { + private func show(_ thread: TSThread, highlightedMessageID: String?, animated: Bool, isFromRecent: Bool = false) { + if let threadId = thread.uniqueId { + Storage.shared.addSearchResults(threadID: threadId) + } + DispatchMainThreadSafe { if let presentedVC = self.presentedViewController { presentedVC.dismiss(animated: false, completion: nil) } let conversationVC = ConversationVC(thread: thread, focusedMessageID: highlightedMessageID) - self.navigationController?.pushViewController(conversationVC, animated: true) + var viewControllers = self.navigationController?.viewControllers + if isFromRecent, let index = viewControllers?.firstIndex(of: self) { viewControllers?.remove(at: index) } + viewControllers?.append(conversationVC) + self.navigationController?.setViewControllers(viewControllers!, animated: true) } } // MARK: UITableViewDataSource public func numberOfSections(in tableView: UITableView) -> Int { - return 3 + return 4 } public func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { @@ -279,6 +292,12 @@ extension GlobalSearchViewController { } else { return nil } + case .recent: + if recentSearchResults.count > 0 && searchText.isEmpty { + return NSLocalizedString("SEARCH_SECTION_RECENT", comment: "") + } else { + return nil + } } } @@ -291,6 +310,8 @@ extension GlobalSearchViewController { return searchResultSet.conversations.count case .messages: return searchResultSet.messages.count + case .recent: + return searchText.isEmpty ? recentSearchResults.count : 0 } } @@ -325,6 +346,15 @@ extension GlobalSearchViewController { cell.threadViewModel = searchResult?.thread cell.configure(messageDate: searchResult?.messageDate, snippet: searchResult?.snippet, searchText: searchResultSet.searchText) return cell + case .recent: + let cell = tableView.dequeueReusableCell(withIdentifier: ConversationCell.reuseIdentifier) as! ConversationCell + cell.isShowingGlobalSearchResult = true + dbReadConnection.read { transaction in + guard let threadId = self.recentSearchResults[safe: indexPath.row], let thread = TSThread.fetch(uniqueId: threadId, transaction: transaction) else { return } + cell.threadViewModel = ThreadViewModel(thread: thread, transaction: transaction) + } + cell.configureForRecent() + return cell } } } diff --git a/Session/Home/GlobalSearch/Storage+RecentSearchResults.swift b/Session/Home/GlobalSearch/Storage+RecentSearchResults.swift new file mode 100644 index 000000000..8fdf903ed --- /dev/null +++ b/Session/Home/GlobalSearch/Storage+RecentSearchResults.swift @@ -0,0 +1,31 @@ +// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. + +extension Storage{ + + private static let recentSearchResultDatabaseCollection = "RecentSearchResultDatabaseCollection" + private static let recentSearchResultKey = "RecentSearchResult" + + public func getRecentSearchResults() -> [String] { + var result: [String]? + Storage.read { transaction in + result = transaction.object(forKey: Storage.recentSearchResultKey, inCollection: Storage.recentSearchResultDatabaseCollection) as? [String] + } + return result ?? [] + } + + public func clearRecentSearchResults() { + Storage.write { transaction in + transaction.removeObject(forKey: Storage.recentSearchResultKey, inCollection: Storage.recentSearchResultDatabaseCollection) + } + } + + public func addSearchResults(threadID: String) { + var recentSearchResults = getRecentSearchResults() + if recentSearchResults.count > 20 { recentSearchResults.remove(at: 0) } // Limit the size of the collection to 20 + if let index = recentSearchResults.firstIndex(of: threadID) { recentSearchResults.remove(at: index) } + recentSearchResults.append(threadID) + Storage.write { transaction in + transaction.setObject(recentSearchResults, forKey: Storage.recentSearchResultKey, inCollection: Storage.recentSearchResultDatabaseCollection) + } + } +} diff --git a/Session/Meta/Translations/en.lproj/Localizable.strings b/Session/Meta/Translations/en.lproj/Localizable.strings index 32f3a032b..41b55e8bd 100644 --- a/Session/Meta/Translations/en.lproj/Localizable.strings +++ b/Session/Meta/Translations/en.lproj/Localizable.strings @@ -581,3 +581,5 @@ "UNPIN_BUTTON_TEXT" = "Unpin"; "SEARCH_SECTION_CONTACTS" = "Contacts and Groups"; "SEARCH_SECTION_MESSAGES" = "Messages"; +"SEARCH_SECTION_RECENT" = "Recent"; +"RECENT_SEARCH_LAST_MESSAGE_DATETIME" = "last message: %@"; diff --git a/Session/Shared/ConversationCell.swift b/Session/Shared/ConversationCell.swift index 3e5d3072e..5c40eb6e7 100644 --- a/Session/Shared/ConversationCell.swift +++ b/Session/Shared/ConversationCell.swift @@ -209,6 +209,14 @@ final class ConversationCell : UITableViewCell { hasMentionView.isHidden = true } + public func configureForRecent() { + displayNameLabel.attributedText = NSMutableAttributedString(string: getDisplayName(), attributes: [.foregroundColor:Colors.text]) + bottomLabelStackView.isHidden = false + let snippet = String(format: NSLocalizedString("RECENT_SEARCH_LAST_MESSAGE_DATETIME", comment: ""), DateUtil.formatDate(forDisplay: threadViewModel.lastMessageDate)) + snippetLabel.attributedText = NSMutableAttributedString(string: snippet, attributes: [.foregroundColor:Colors.text.withAlphaComponent(Values.lowOpacity)]) + timestampLabel.isHidden = true + } + public func configure(messageDate: Date?, snippet: String?, searchText: String) { let normalizedSearchText = searchText.lowercased() if let messageDate = messageDate, let snippet = snippet {