diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index cea499c0f..ec89800b4 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -485,6 +485,7 @@ E197B62418BBF5BB00F073E5 /* SoundPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = E197B62318BBF5BB00F073E5 /* SoundPlayer.m */; }; E197B62718BBF63B00F073E5 /* SoundBoard.m in Sources */ = {isa = PBXBuildFile; fileRef = E197B62618BBF63B00F073E5 /* SoundBoard.m */; }; E1CD329618BCFF9900B1A496 /* SoundInstance.m in Sources */ = {isa = PBXBuildFile; fileRef = E1CD329518BCFF9900B1A496 /* SoundInstance.m */; }; + E94066151DFC5B7B00B15392 /* ContactsPicker.xib in Resources */ = {isa = PBXBuildFile; fileRef = E94066141DFC5B7B00B15392 /* ContactsPicker.xib */; }; EF764C351DB67CC5000D9A87 /* UIViewController+CameraPermissions.m in Sources */ = {isa = PBXBuildFile; fileRef = EF764C341DB67CC5000D9A87 /* UIViewController+CameraPermissions.m */; }; FC31962A1A067D8F0094C78E /* MessageComposeTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FC3196291A067D8F0094C78E /* MessageComposeTableViewController.m */; }; FC31962D1A06A2190094C78E /* FingerprintViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FC31962C1A06A2190094C78E /* FingerprintViewController.m */; }; @@ -1115,6 +1116,7 @@ E1CD329418BCFF9900B1A496 /* SoundInstance.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SoundInstance.h; sourceTree = ""; }; E1CD329518BCFF9900B1A496 /* SoundInstance.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SoundInstance.m; sourceTree = ""; }; E85DB184824BA9DC302EC8B3 /* Pods-SignalTests.app store release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalTests.app store release.xcconfig"; path = "Pods/Target Support Files/Pods-SignalTests/Pods-SignalTests.app store release.xcconfig"; sourceTree = ""; }; + E94066141DFC5B7B00B15392 /* ContactsPicker.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ContactsPicker.xib; sourceTree = ""; }; EF764C331DB67CC5000D9A87 /* UIViewController+CameraPermissions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIViewController+CameraPermissions.h"; path = "util/UIViewController+CameraPermissions.h"; sourceTree = ""; }; EF764C341DB67CC5000D9A87 /* UIViewController+CameraPermissions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIViewController+CameraPermissions.m"; path = "util/UIViewController+CameraPermissions.m"; sourceTree = ""; }; FC3196281A067D8F0094C78E /* MessageComposeTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MessageComposeTableViewController.h; sourceTree = ""; }; @@ -1843,6 +1845,7 @@ 458E38301D6682450094BD24 /* OWSQRCodeScanningViewController.m */, 451764261DE939F300EDB8B9 /* ContactsPicker.swift */, 45514DE11DDFA183003EFF90 /* InviteFlow.swift */, + E94066141DFC5B7B00B15392 /* ContactsPicker.xib */, ); name = "View Controllers"; path = "view controllers"; @@ -2649,6 +2652,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + E94066151DFC5B7B00B15392 /* ContactsPicker.xib in Resources */, AD41D7B61A6F6F0600241130 /* play_button@2x.png in Resources */, AD83FF3F1A73426500B5C81A /* audio_pause_button_blue.png in Resources */, 45E1F3A31DEF1DF000852CF1 /* NoSignalContactsView.xib in Resources */, diff --git a/Signal/src/view controllers/ContactsPicker.swift b/Signal/src/view controllers/ContactsPicker.swift index c67b9a2bd..0a37cb46c 100644 --- a/Signal/src/view controllers/ContactsPicker.swift +++ b/Signal/src/view controllers/ContactsPicker.swift @@ -33,7 +33,10 @@ public enum SubtitleCellValue{ } @available(iOS 9.0, *) -open class ContactsPicker: UITableViewController, UISearchResultsUpdating, UISearchBarDelegate { +open class ContactsPicker: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate { + + @IBOutlet var tableView: UITableView! + @IBOutlet var searchBar: UISearchBar! // MARK: - Properties @@ -42,7 +45,6 @@ open class ContactsPicker: UITableViewController, UISearchResultsUpdating, UISea let contactsManager: OWSContactsManager let collation = UILocalizedIndexedCollation.current() let contactStore = CNContactStore() - lazy var resultSearchController = UISearchController() // Data Source State lazy var sections = [[CNContact]]() @@ -66,8 +68,9 @@ open class ContactsPicker: UITableViewController, UISearchResultsUpdating, UISea super.viewDidLoad() title = NSLocalizedString("INVITE_FRIENDS_PICKER_TITLE", comment: "Navbar title") - // Don't obscure table header (search bar) with table index - tableView.sectionIndexBackgroundColor = UIColor.clear + searchBar.placeholder = NSLocalizedString("INVITE_FRIENDS_PICKER_SEARCHBAR_PLACEHOLDER", comment: "Search") + // Prevent content form going under the navigation bar + self.edgesForExtendedLayout = [] // Auto size cells for dynamic type tableView.estimatedRowHeight = 60.0 @@ -78,7 +81,7 @@ open class ContactsPicker: UITableViewController, UISearchResultsUpdating, UISea registerContactCell() initializeBarButtons() reloadContacts() - initializeSearchBar() + updateSearchResults(searchText: "") NotificationCenter.default.addObserver(self, selector: #selector(self.didChangePreferredContentSize), name: NSNotification.Name.UIContentSizeCategoryDidChange, object: nil) } @@ -86,20 +89,6 @@ open class ContactsPicker: UITableViewController, UISearchResultsUpdating, UISea func didChangePreferredContentSize() { self.tableView.reloadData() } - - func initializeSearchBar() { - self.resultSearchController = ( { - let controller = UISearchController(searchResultsController: nil) - controller.searchResultsUpdater = self - controller.dimsBackgroundDuringPresentation = false - controller.searchBar.sizeToFit() - controller.searchBar.delegate = self - controller.hidesNavigationBarDuringPresentation = false - - self.tableView.tableHeaderView = controller.searchBar - return controller - })() - } func initializeBarButtons() { let cancelButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.cancel, target: self, action: #selector(onTouchCancelButton)) @@ -117,9 +106,9 @@ open class ContactsPicker: UITableViewController, UISearchResultsUpdating, UISea // MARK: - Initializers - override init(style: UITableViewStyle) { + init() { contactsManager = Environment.getCurrent().contactsManager - super.init(style: style) + super.init(nibName: nil, bundle: nil) } required public init?(coder aDecoder: NSCoder) { @@ -132,13 +121,13 @@ open class ContactsPicker: UITableViewController, UISearchResultsUpdating, UISea } convenience public init(delegate: ContactsPickerDelegate?, multiSelection : Bool) { - self.init(style: .plain) + self.init() multiSelectEnabled = multiSelection contactsPickerDelegate = delegate } convenience public init(delegate: ContactsPickerDelegate?, multiSelection : Bool, subtitleCellType: SubtitleCellValue) { - self.init(style: .plain) + self.init() multiSelectEnabled = multiSelection contactsPickerDelegate = delegate subtitleCellValue = subtitleCellType @@ -192,7 +181,6 @@ open class ContactsPicker: UITableViewController, UISearchResultsUpdating, UISea contacts.append(contact) } self.sections = collatedContacts(contacts) - self.tableView.reloadData() } catch let error as NSError { Logger.error("\(self.TAG) Failed to fetch contacts with error:\(error)") } @@ -213,22 +201,22 @@ open class ContactsPicker: UITableViewController, UISearchResultsUpdating, UISea // MARK: - Table View DataSource - override open func numberOfSections(in tableView: UITableView) -> Int { + open func numberOfSections(in tableView: UITableView) -> Int { return self.collation.sectionTitles.count } - override open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - let dataSource = resultSearchController.isActive ? filteredSections : sections + open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + let dataSource = filteredSections return dataSource[section].count } // MARK: - Table View Delegates - override open func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + open func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: contactCellReuseIdentifier, for: indexPath) as! ContactCell - let dataSource = resultSearchController.isActive ? filteredSections : sections + let dataSource = filteredSections let cnContact = dataSource[indexPath.section][indexPath.row] let contact = Contact(contact: cnContact) @@ -247,7 +235,7 @@ open class ContactsPicker: UITableViewController, UISearchResultsUpdating, UISea return cell } - override open func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) { + open func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) { let cell = tableView.cellForRow(at: indexPath) as! ContactCell let deselectedContact = cell.contact! @@ -256,7 +244,7 @@ open class ContactsPicker: UITableViewController, UISearchResultsUpdating, UISea } } - override open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let cell = tableView.cellForRow(at: indexPath) as! ContactCell let selectedContact = cell.contact! @@ -269,23 +257,22 @@ open class ContactsPicker: UITableViewController, UISearchResultsUpdating, UISea if !multiSelectEnabled { //Single selection code - resultSearchController.isActive = false self.dismiss(animated: true) { self.contactsPickerDelegate?.contactsPicker(self, didSelectContact: selectedContact) } } } - override open func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int { + open func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int { return collation.section(forSectionIndexTitle: index) } - override open func sectionIndexTitles(for tableView: UITableView) -> [String]? { + open func sectionIndexTitles(for tableView: UITableView) -> [String]? { return collation.sectionIndexTitles } - override open func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { - let dataSource = resultSearchController.isActive ? filteredSections : sections + open func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { + let dataSource = filteredSections if dataSource[section].count > 0 { return collation.sectionTitles[section] @@ -307,33 +294,25 @@ open class ContactsPicker: UITableViewController, UISearchResultsUpdating, UISea } // MARK: - Search Actions + open func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { + updateSearchResults(searchText: searchText) + } - open func updateSearchResults(for searchController: UISearchController) { - if let searchText = resultSearchController.searchBar.text , searchController.isActive { - - let predicate: NSPredicate - if searchText.characters.count == 0 { - filteredSections = sections - } else { - do { - predicate = CNContact.predicateForContacts(matchingName: searchText) - let filteredContacts = try contactStore.unifiedContacts(matching: predicate, keysToFetch: allowedContactKeys) + open func updateSearchResults(searchText: String) { + let predicate: NSPredicate + if searchText.characters.count == 0 { + filteredSections = sections + } else { + do { + predicate = CNContact.predicateForContacts(matchingName: searchText) + let filteredContacts = try contactStore.unifiedContacts(matching: predicate,keysToFetch: allowedContactKeys) filteredSections = collatedContacts(filteredContacts) - } catch let error as NSError { - Logger.error("\(self.TAG) updating search results failed with error: \(error)") - } + } catch let error as NSError { + Logger.error("\(self.TAG) updating search results failed with error: \(error)") } - - self.tableView.reloadData() } + self.tableView.reloadData() } - - open func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { - DispatchQueue.main.async { - self.tableView.reloadData() - } - } - } @available(iOS 9.0, *) diff --git a/Signal/src/view controllers/ContactsPicker.xib b/Signal/src/view controllers/ContactsPicker.xib new file mode 100644 index 000000000..f25c4fbb9 --- /dev/null +++ b/Signal/src/view controllers/ContactsPicker.xib @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index 06bc48364..fcd61510a 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -364,6 +364,9 @@ /* Text for button at the top of the contact picker */ "INVITE_FRIENDS_CONTACT_TABLE_BUTTON" = "Invite Friends to Signal"; +/* Search */ +"INVITE_FRIENDS_PICKER_SEARCHBAR_PLACEHOLDER" = "Search"; + /* Navbar title */ "INVITE_FRIENDS_PICKER_TITLE" = "Invite Friends";