From 549342c702b90e50e275a930f09ed9af1f17fe78 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Mon, 11 Jun 2018 14:24:29 -0400 Subject: [PATCH] Show empty results text // FREEBIE --- .../ConversationSearchViewController.swift | 65 +++++++++++++++++-- .../translations/en.lproj/Localizable.strings | 3 + .../utils/ConversationSearcher.swift | 8 ++- 3 files changed, 69 insertions(+), 7 deletions(-) diff --git a/Signal/src/ViewControllers/HomeView/ConversationSearchViewController.swift b/Signal/src/ViewControllers/HomeView/ConversationSearchViewController.swift index a1853916b..46f5b99b0 100644 --- a/Signal/src/ViewControllers/HomeView/ConversationSearchViewController.swift +++ b/Signal/src/ViewControllers/HomeView/ConversationSearchViewController.swift @@ -33,6 +33,7 @@ class ConversationSearchViewController: UITableViewController { tableView.rowHeight = UITableViewAutomaticDimension tableView.estimatedRowHeight = 60 + tableView.register(EmptySearchResultCell.self, forCellReuseIdentifier: EmptySearchResultCell.reuseIdentifier) tableView.register(ConversationSearchResultCell.self, forCellReuseIdentifier: ConversationSearchResultCell.reuseIdentifier) tableView.register(MessageSearchResultCell.self, forCellReuseIdentifier: MessageSearchResultCell.reuseIdentifier) tableView.register(ContactSearchResultCell.self, forCellReuseIdentifier: ContactSearchResultCell.reuseIdentifier) @@ -92,8 +93,7 @@ class ConversationSearchViewController: UITableViewController { switch searchSection { case .noResults: - // We don't display a "no results" cell, we simply display no results. - return 0 + return searchResultSet.isEmpty ? 1 : 0 case .conversations: return searchResultSet.conversations.count case .contacts: @@ -111,23 +111,39 @@ class ConversationSearchViewController: UITableViewController { switch searchSection { case .noResults: - return UITableViewCell() + guard let cell = tableView.dequeueReusableCell(withIdentifier: EmptySearchResultCell.reuseIdentifier) as? EmptySearchResultCell else { + owsFail("cell was unexpectedly nil") + return UITableViewCell() + } + + guard indexPath.row == 0 else { + owsFail("searchResult was unexpected index") + return UITableViewCell() + } + + let searchText = self.searchResultSet.searchText + cell.configure(searchText: searchText) + return cell case .conversations: guard let cell = tableView.dequeueReusableCell(withIdentifier: ConversationSearchResultCell.reuseIdentifier) as? ConversationSearchResultCell else { + owsFail("cell was unexpectedly nil") return UITableViewCell() } guard let searchResult = self.searchResultSet.conversations[safe: indexPath.row] else { + owsFail("searchResult was unexpectedly nil") return UITableViewCell() } cell.configure(searchResult: searchResult) return cell case .contacts: guard let cell = tableView.dequeueReusableCell(withIdentifier: ContactSearchResultCell.reuseIdentifier) as? ContactSearchResultCell else { + owsFail("cell was unexpectedly nil") return UITableViewCell() } guard let searchResult = self.searchResultSet.contacts[safe: indexPath.row] else { + owsFail("searchResult was unexpectedly nil") return UITableViewCell() } @@ -135,10 +151,12 @@ class ConversationSearchViewController: UITableViewController { return cell case .messages: guard let cell = tableView.dequeueReusableCell(withIdentifier: MessageSearchResultCell.reuseIdentifier) as? MessageSearchResultCell else { + owsFail("cell was unexpectedly nil") return UITableViewCell() } guard let searchResult = self.searchResultSet.messages[safe: indexPath.row] else { + owsFail("searchResult was unexpectedly nil") return UITableViewCell() } @@ -148,7 +166,7 @@ class ConversationSearchViewController: UITableViewController { } override func numberOfSections(in tableView: UITableView) -> Int { - return 3 + return 4 } override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { @@ -349,3 +367,42 @@ class ContactSearchResultCell: UITableViewCell { self.snippetLabel.text = searchResult.recipientId } } + +class EmptySearchResultCell: UITableViewCell { + static let reuseIdentifier = "EmptySearchResultCell" + + let messageLabel: UILabel + override init(style: UITableViewCellStyle, reuseIdentifier: String?) { + self.messageLabel = UILabel() + super.init(style: style, reuseIdentifier: reuseIdentifier) + + messageLabel.font = UIFont.ows_dynamicTypeBody + messageLabel.textAlignment = .center + messageLabel.numberOfLines = 3 + + contentView.addSubview(messageLabel) + + messageLabel.autoSetDimension(.height, toSize: 150) + + messageLabel.autoPinEdge(toSuperviewMargin: .top, relation: .greaterThanOrEqual) + messageLabel.autoPinEdge(toSuperviewMargin: .leading, relation: .greaterThanOrEqual) + messageLabel.autoPinEdge(toSuperviewMargin: .bottom, relation: .greaterThanOrEqual) + messageLabel.autoPinEdge(toSuperviewMargin: .trailing, relation: .greaterThanOrEqual) + + messageLabel.autoVCenterInSuperview() + messageLabel.autoHCenterInSuperview() + + messageLabel.setContentHuggingHigh() + messageLabel.setCompressionResistanceHigh() + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + public func configure(searchText: String) { + let format = NSLocalizedString("HOME_VIEW_SEARCH_NO_RESULTS_FORMAT", comment: "Format string when search returns no results. Embeds {{search term}}") + let messageText: String = NSString(format: format as NSString, searchText) as String + self.messageLabel.text = messageText + } +} diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index 10a9e08af..a2cfc385e 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -989,6 +989,9 @@ /* Placeholder text for search bar which filters conversations. */ "HOME_VIEW_CONVERSATION_SEARCHBAR_PLACEHOLDER" = "Search"; +/* Format string when search returns no results. Embeds {{search term}} */ +"HOME_VIEW_SEARCH_NO_RESULTS_FORMAT" = "No results found for '%@'"; + /* Title for the home view's 'archive' mode. */ "HOME_VIEW_TITLE_ARCHIVE" = "Archive"; diff --git a/SignalMessaging/utils/ConversationSearcher.swift b/SignalMessaging/utils/ConversationSearcher.swift index 91f01d11d..32f4bab1d 100644 --- a/SignalMessaging/utils/ConversationSearcher.swift +++ b/SignalMessaging/utils/ConversationSearcher.swift @@ -27,18 +27,20 @@ public class ContactSearchResult { } public class SearchResultSet { + public let searchText: String public let conversations: [ConversationSearchResult] public let contacts: [ContactSearchResult] public let messages: [ConversationSearchResult] - public init(conversations: [ConversationSearchResult], contacts: [ContactSearchResult], messages: [ConversationSearchResult]) { + public init(searchText: String, conversations: [ConversationSearchResult], contacts: [ContactSearchResult], messages: [ConversationSearchResult]) { + self.searchText = searchText self.conversations = conversations self.contacts = contacts self.messages = messages } public class var empty: SearchResultSet { - return SearchResultSet(conversations: [], contacts: [], messages: []) + return SearchResultSet(searchText: "", conversations: [], contacts: [], messages: []) } public var isEmpty: Bool { @@ -94,7 +96,7 @@ public class ConversationSearcher: NSObject { // Only show contacts which were not included in an existing 1:1 conversation. let otherContacts: [ContactSearchResult] = contacts.filter { !existingConversationRecipientIds.contains($0.recipientId) } - return SearchResultSet(conversations: conversations, contacts: otherContacts, messages: messages) + return SearchResultSet(searchText: searchText, conversations: conversations, contacts: otherContacts, messages: messages) } @objc(filterThreads:withSearchText:)