Commit 73d919d6 by Luis Zarza

first commit

parent e842e5e9
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
BBE208A7241A541600A7D661 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BBE208A5241A541600A7D661 /* LaunchScreen.storyboard */; }; BBE208A7241A541600A7D661 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BBE208A5241A541600A7D661 /* LaunchScreen.storyboard */; };
BBE208B2241A541700A7D661 /* contact_list_appTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBE208B1241A541700A7D661 /* contact_list_appTests.swift */; }; BBE208B2241A541700A7D661 /* contact_list_appTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBE208B1241A541700A7D661 /* contact_list_appTests.swift */; };
BBE208BD241A541700A7D661 /* contact_list_appUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBE208BC241A541700A7D661 /* contact_list_appUITests.swift */; }; BBE208BD241A541700A7D661 /* contact_list_appUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBE208BC241A541700A7D661 /* contact_list_appUITests.swift */; };
BBE208CB241ADD6C00A7D661 /* ContactProfileVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBE208CA241ADD6C00A7D661 /* ContactProfileVC.swift */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
...@@ -49,6 +50,7 @@ ...@@ -49,6 +50,7 @@
BBE208B8241A541700A7D661 /* contact-list-appUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "contact-list-appUITests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; BBE208B8241A541700A7D661 /* contact-list-appUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "contact-list-appUITests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
BBE208BC241A541700A7D661 /* contact_list_appUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = contact_list_appUITests.swift; sourceTree = "<group>"; }; BBE208BC241A541700A7D661 /* contact_list_appUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = contact_list_appUITests.swift; sourceTree = "<group>"; };
BBE208BE241A541700A7D661 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; BBE208BE241A541700A7D661 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
BBE208CA241ADD6C00A7D661 /* ContactProfileVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactProfileVC.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
...@@ -106,6 +108,7 @@ ...@@ -106,6 +108,7 @@
BBE208A3241A541600A7D661 /* Assets.xcassets */, BBE208A3241A541600A7D661 /* Assets.xcassets */,
BBE208A5241A541600A7D661 /* LaunchScreen.storyboard */, BBE208A5241A541600A7D661 /* LaunchScreen.storyboard */,
BBE208A8241A541600A7D661 /* Info.plist */, BBE208A8241A541600A7D661 /* Info.plist */,
BBE208CA241ADD6C00A7D661 /* ContactProfileVC.swift */,
); );
path = "contact-list-app"; path = "contact-list-app";
sourceTree = "<group>"; sourceTree = "<group>";
...@@ -262,6 +265,7 @@ ...@@ -262,6 +265,7 @@
BBE2089F241A540F00A7D661 /* ViewController.swift in Sources */, BBE2089F241A540F00A7D661 /* ViewController.swift in Sources */,
BBE2089B241A540F00A7D661 /* AppDelegate.swift in Sources */, BBE2089B241A540F00A7D661 /* AppDelegate.swift in Sources */,
BBE2089D241A540F00A7D661 /* SceneDelegate.swift in Sources */, BBE2089D241A540F00A7D661 /* SceneDelegate.swift in Sources */,
BBE208CB241ADD6C00A7D661 /* ContactProfileVC.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
......
<?xml version="1.0" encoding="UTF-8"?>
<Bucket
uuid = "E62FFFE2-E3E7-4856-BC3B-99F22A3963AA"
type = "1"
version = "2.0">
</Bucket>
{
"images" : [
{
"idiom" : "universal",
"filename" : "3RAw8Hjd_400x400.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
\ No newline at end of file
import UIKit
import Contacts
struct ContactProfile{
var phonNumbersList:[String]
var emailAdressList: [String]
}
class PhoneNumberCell: UITableViewCell{
@IBOutlet weak var phoneIconImg: UIImageView!
@IBOutlet weak var phoneNumberLbl: UILabel!
}
class EmailAddressCell: UITableViewCell{
@IBOutlet weak var emailAddressLbl: UILabel!
}
class ContactProfileVC: UIViewController {
var contact: CNContact?
var contactProfileData:ContactProfile?
@IBOutlet weak var nameLbl: UILabel!
@IBOutlet weak var profilePic: UIImageView!
@IBOutlet weak var contactPhoneNumbersTable: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
//call the main function
main()
}
func main(){
//set profile pic
setProfilePic()
//set contact name
nameLbl.text = "\(contact!.givenName) \(contact!.familyName)"
//get contact's incoming data
setContactProfileAttributes()
//set tableView handlers to this instance
contactPhoneNumbersTable.dataSource = self
contactPhoneNumbersTable.delegate = self
}
func setContactProfileAttributes(){
var phoneNumbers:[String] = []
var emailAddressList:[String] = []
//get phone numbers
contact!.phoneNumbers.forEach( {phoneNumber in
phoneNumbers.append(phoneNumber.value.stringValue)
})
//get emails
contact!.emailAddresses.forEach({emailAddress in
emailAddressList.append(emailAddress.value as String)
})
//append to contact's attributes
contactProfileData = ContactProfile(phonNumbersList: phoneNumbers, emailAdressList: emailAddressList)
}
func setProfilePic(){
if contact!.imageDataAvailable {
print("imagen disponible")
if let image = UIImage.init(data:contact!.imageData!) {
profilePic.image = image
profilePic.layer.cornerRadius = profilePic.frame.width/2
}
}else{
print("no image data available")
}
}
}
extension ContactProfileVC: UITableViewDelegate, UITableViewDataSource{
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0{//phones
let cell = tableView.dequeueReusableCell(withIdentifier: "contactPhoneNumberCell") as! PhoneNumberCell
cell.phoneNumberLbl.text = contactProfileData!.phonNumbersList[indexPath.row]
return cell
}else{ //emails
let cell = tableView.dequeueReusableCell(withIdentifier: "emailAddressCellID") as! EmailAddressCell
cell.emailAddressLbl.text = contactProfileData!.emailAdressList[indexPath.row]
return cell
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if section == 0 {
return "Phones"
}else{
return "Emails"
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return contactProfileData!.phonNumbersList.count
}else{
return contactProfileData!.emailAdressList.count
}
}
}
...@@ -2,6 +2,10 @@ ...@@ -2,6 +2,10 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>NSPhotoLibraryUsageDescription</key>
<string> $(PRODUCT_NAME) photo use</string>
<key>NSContactsUsageDescription</key>
<string> $(PRODUCT_NAME) contact use</string>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string> <string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
......
//
// ViewController.swift
// contact-list-app
//
// Created by Mobile Roshka on 3/12/20.
// Copyright © 2020 Mobile Roshka. All rights reserved.
//
import UIKit import UIKit
import Contacts
struct ContactList {
var firstLetter:String
var contactList:[CNContact]
var backUpContacts:[CNContact] = []
var isHidden = false
}
class ContactCell: UITableViewCell{
@IBOutlet weak var nameLbl: UILabel!
@IBOutlet weak var profilePic: UIImageView!
}
class ViewController: UIViewController { class ViewController: UIViewController {
let contactStore = CNContactStore()
var contacts = [CNContact]()
var dataSource:[ContactList]? = []
var backUpContacts:[CNContact] = []
var isHidden = false
@IBOutlet weak var contacsTable: UITableView!
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
// Do any additional setup after loading the view. //call the main functions
main()
}
func main(){
//get contacts from device
getAllContacts()
//sort in alphabetical order
sortContacts()
//set tableView handlers to this instance
contacsTable.dataSource = self
contacsTable.delegate = self
} }
func sortContacts(){
var pivot = contacts[0].givenName.prefix(1) //first letter from first contact
var temp: [CNContact] = [] //temp array to storage contacts
for i in (0...contacts.count-2){
if pivot == contacts[i+1].givenName.prefix(1){
temp.append(contacts[i])
}else{
temp.append(contacts[i])
dataSource!.append(ContactList(firstLetter: String(pivot), contactList: temp))
pivot = contacts[i+1].givenName.prefix(1)
temp = []
}
}
//ask for the last contact
if contacts[contacts.count-1].givenName.prefix(1) == dataSource![dataSource!.count-1].firstLetter{ //last group
dataSource![dataSource!.count-1].contactList.append(contacts[contacts.count-1])
}else{ //new group
dataSource!.append(ContactList(firstLetter: String(pivot), contactList: [contacts[contacts.count-1]]))
}
}
func getAllContacts(){
//keys
let keys = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactImageDataKey, CNContactImageDataAvailableKey, CNContactPhoneNumbersKey, CNContactEmailAddressesKey] as [CNKeyDescriptor]
//request
let request = CNContactFetchRequest(keysToFetch: keys)
request.sortOrder = .givenName
do {
try self.contactStore.enumerateContacts(with: request) {
(contact, stop) in
// Array containing all unified contacts from everywhere
self.contacts.append(contact)
print("success")
}
}
catch {
print("unable to fetch contacts")
}
}
@objc func foldContacts(_ sender: UIButton) -> Void{
if let section = sender.tag as? Int {
if dataSource![section].isHidden { //show contacts
dataSource![section].contactList = dataSource![section].backUpContacts
dataSource![section].isHidden = false
}else { //hide contacts
dataSource![section].backUpContacts = dataSource![section].contactList
dataSource![section].contactList = []
dataSource![section].isHidden = true
}
}
//reload table view
contacsTable.reloadData()
}
} }
extension ViewController: UITableViewDelegate, UITableViewDataSource{
func numberOfSections(in tableView: UITableView) -> Int {
return dataSource!.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataSource![section].contactList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "contactCell" , for: indexPath) as! ContactCell
cell.nameLbl.text = "\(dataSource![indexPath.section].contactList[indexPath.row].givenName) \(dataSource![indexPath.section].contactList[indexPath.row].familyName)"
if dataSource![indexPath.section].contactList[indexPath.row].imageDataAvailable {
if let image = UIImage.init(data:dataSource![indexPath.section].contactList[indexPath.row].imageData!) {
cell.profilePic.image = image
cell.profilePic.layer.cornerRadius = cell.profilePic.frame.width/2
}
}else{
//poner icono por defecto
cell.profilePic.image = UIImage(systemName: "person.fill")
}
return cell
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView.init(frame: CGRect(x: 0, y: 0, width: tableView.frame.width, height: 200))
headerView.backgroundColor = UIColor.link
//label
let label = UILabel()
label.frame = CGRect.init(x: 30, y: 10, width: headerView.frame.width-10, height: 25)
label.textColor = UIColor.white
label.text = dataSource![section].firstLetter
label.font = UIFont.boldSystemFont(ofSize: 16.0)
//button
let foldButton = UIButton()
foldButton.frame = CGRect(x: headerView.frame.width-80, y: 10, width: 30, height: 30)
foldButton.backgroundColor = UIColor.white
foldButton.setTitle("+", for: .normal)
foldButton.layer.cornerRadius = foldButton.frame.width/2
foldButton.tag = section
foldButton.addTarget(self, action: #selector(foldContacts(_ :)), for: .touchUpInside)
//add subview to container
headerView.addSubview(label)
headerView.addSubview(foldButton)
return headerView
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 50
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let contacProfileVC = self.storyboard?.instantiateViewController(withIdentifier: "contactProfileID") as! ContactProfileVC
contacProfileVC.contact = dataSource![indexPath.section].contactList[indexPath.row]
show(contacProfileVC, sender: nil)
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment