// // ContactsViewController.swift // ContactsApp // // Created by User on 3/13/20. // Copyright © 2020 jheisecke. All rights reserved. // import UIKit import ContactsUI class ContactsViewController: UIViewController { @IBOutlet weak var searchBar: UISearchBar! @IBOutlet weak var contactsTable: UITableView! var contactStructArray = [ContactStruct]() var contactAux = [ContactStruct]() var contactStruct : ContactStruct? let contactStore = CNContactStore() override func viewDidLoad() { super.viewDidLoad() contactsTable.register(UINib(nibName: "ContactSection", bundle: nil), forHeaderFooterViewReuseIdentifier: "headerId") importContacts() searchBar.delegate = self contactsTable.tableFooterView = UIView(frame: .zero) searchBar.placeholder = NSLocalizedString("Nombre...", comment: "") } func importContacts() { self.contactStructArray = [] let keys = [CNContactFormatter.descriptorForRequiredKeys(for: .fullName), CNContactEmailAddressesKey, CNContactPhoneNumbersKey, CNContactImageDataKey] as [Any] let request = CNContactFetchRequest( keysToFetch: keys as! [CNKeyDescriptor]) request.sortOrder = CNContactSortOrder.givenName do { var auxLetter = "" var contacts = [CNContact]() var isNotTheFirst = false try self.contactStore.enumerateContacts(with: request) { (contact, stop) in if contact.givenName.prefix(1) == auxLetter { contacts.append(contact) } else { if isNotTheFirst { let contactsExpandables = ContactStruct(isExpanded: true, contacts: contacts, letter: auxLetter) self.contactStructArray.append(contactsExpandables) //guardamos el contacto expandible anterior auxLetter = String(contact.givenName.prefix(1)) //guardamos la nueva letra contacts = [CNContact]() //inicializamos nuevamente el array de contactos contacts.append(contact) //guardamos el nuevo contacto } else { contacts.append(contact) auxLetter = String(contact.givenName.prefix(1)) //auxLetter tiene la primera letra del nombre isNotTheFirst = true //la siguiente vez que las letras no sean iguales guardara en el array } } } self.contactStructArray.append(ContactStruct(isExpanded: true, contacts: contacts, letter: auxLetter)) //agregamos el ultimo nombre self.contactAux = self.contactStructArray } catch { print("unable to fetch contacts") } } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if let singleContactVC = segue.destination as? SingleContactViewController { if let selectedCnt = sender as? CNContact { singleContactVC.selectedContact = selectedCnt } } } } extension ContactsViewController: UITableViewDelegate, UITableViewDataSource { func numberOfSections(in tableView: UITableView) -> Int { return contactStructArray.count } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if !contactStructArray[section].isExpanded { return 0 } return contactStructArray[section].contacts.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "contactName")! let contactCell = contactStructArray[indexPath.section].contacts[indexPath.row] let givenName = "\(contactCell.givenName) " let familyName: NSMutableAttributedString = NSMutableAttributedString(string: contactCell.familyName) let attributes: [NSAttributedString.Key: Any] = [ .font: UIFont.boldSystemFont(ofSize: 15) ] let fullName = NSMutableAttributedString(string: givenName, attributes: attributes) fullName.append(familyName) cell.textLabel?.attributedText = fullName return cell } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let selectedContact = contactStructArray[indexPath.section].contacts[indexPath.row] performSegue(withIdentifier: "gotocontact", sender: selectedContact) } func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat { return 40 } func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { let header = contactsTable.dequeueReusableHeaderFooterView(withIdentifier: "headerId") as! ContactSectionView header.contentView.backgroundColor = .systemGray4 header.labelExpandable.setTitle("Λ", for: .normal) header.labelExpandable.setTitleColor(.black, for: .normal) header.labelExpandable.titleLabel?.font = UIFont.boldSystemFont(ofSize: 15) header.labelExpandable.addTarget(self, action: #selector(interactSection), for: .touchUpInside) header.labelExpandable.tag = section header.labelLetter.text = contactStructArray[section].letter return header//ʌΛ } @objc func interactSection(button : UIButton) { //contactsBackup = contacts let section = button.tag var indexPaths = [IndexPath]() for row in contactStructArray[section].contacts.indices { let indexPath = IndexPath(row: row, section: section) indexPaths.append(indexPath) } let isExpanded = contactStructArray[section].isExpanded contactStructArray[section].isExpanded = !isExpanded button.setTitle(isExpanded ? "V" : "Λ", for: .normal) if isExpanded { contactsTable.deleteRows(at: indexPaths, with: .top) } else { contactsTable.insertRows(at: indexPaths, with: .bottom) } } } extension ContactsViewController: UISearchBarDelegate, UISearchDisplayDelegate, UISearchResultsUpdating { func updateSearchResults(for searchController: UISearchController) { } func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { contactStructArray = contactAux } func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { var foundContacts = [ContactStruct]() if searchText == "" { contactStructArray = contactAux contactsTable.reloadData() } else { for indexContact in contactAux.indices{ let contactFound = contactAux[indexContact].contacts.filter( { let fullName = "\($0.givenName) \($0.familyName)" return fullName.lowercased().contains(searchText.lowercased()) } ) if !contactFound.isEmpty { foundContacts.append(ContactStruct(isExpanded: true, contacts: contactFound, letter: contactAux[indexContact].letter)) } } contactStructArray = foundContacts contactsTable.reloadData() } } }