Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
C
contact-list-app
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Luis Zarza
contact-list-app
Commits
73d919d6
Commit
73d919d6
authored
Mar 16, 2020
by
Luis Zarza
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
first commit
parent
e842e5e9
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
322 additions
and
8 deletions
+322
-8
contact-list-app.xcodeproj/project.pbxproj
+4
-0
contact-list-app.xcodeproj/xcuserdata/roshka.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
+6
-0
contact-list-app/Assets.xcassets/roshka.imageset/3RAw8Hjd_400x400.png
+0
-0
contact-list-app/Assets.xcassets/roshka.imageset/Contents.json
+22
-0
contact-list-app/Base.lproj/Main.storyboard
+0
-0
contact-list-app/ContactProfileVC.swift
+118
-0
contact-list-app/Info.plist
+4
-0
contact-list-app/ViewController.swift
+168
-8
No files found.
contact-list-app.xcodeproj/project.pbxproj
View file @
73d919d6
...
...
@@ -15,6 +15,7 @@
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 */
;
};
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 */
/* Begin PBXContainerItemProxy section */
...
...
@@ -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
;
};
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>"
;
};
BBE208CA241ADD6C00A7D661
/* ContactProfileVC.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
ContactProfileVC.swift
;
sourceTree
=
"<group>"
;
};
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
...
...
@@ -106,6 +108,7 @@
BBE208A3241A541600A7D661
/* Assets.xcassets */
,
BBE208A5241A541600A7D661
/* LaunchScreen.storyboard */
,
BBE208A8241A541600A7D661
/* Info.plist */
,
BBE208CA241ADD6C00A7D661
/* ContactProfileVC.swift */
,
);
path
=
"contact-list-app"
;
sourceTree
=
"<group>"
;
...
...
@@ -262,6 +265,7 @@
BBE2089F241A540F00A7D661
/* ViewController.swift in Sources */
,
BBE2089B241A540F00A7D661
/* AppDelegate.swift in Sources */
,
BBE2089D241A540F00A7D661
/* SceneDelegate.swift in Sources */
,
BBE208CB241ADD6C00A7D661
/* ContactProfileVC.swift in Sources */
,
);
runOnlyForDeploymentPostprocessing
=
0
;
};
...
...
contact-list-app.xcodeproj/xcuserdata/roshka.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
0 → 100644
View file @
73d919d6
<?xml version="1.0" encoding="UTF-8"?>
<Bucket
uuid =
"E62FFFE2-E3E7-4856-BC3B-99F22A3963AA"
type =
"1"
version =
"2.0"
>
</Bucket>
contact-list-app/Assets.xcassets/roshka.imageset/3RAw8Hjd_400x400.png
0 → 100644
View file @
73d919d6
63.4 KB
contact-list-app/Assets.xcassets/roshka.imageset/Contents.json
0 → 100644
View file @
73d919d6
{
"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
contact-list-app/Base.lproj/Main.storyboard
View file @
73d919d6
This diff is collapsed.
Click to expand it.
contact-list-app/ContactProfileVC.swift
0 → 100644
View file @
73d919d6
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
}
}
}
contact-list-app/Info.plist
View file @
73d919d6
...
...
@@ -2,6 +2,10 @@
<
!
D
O
C
TYP
E
plist
PU
B
LI
C
"-//
A
ppl
e
//
D
T
D
PLIST
1
.
0
//
E
N"
"http://www.
a
ppl
e
.
c
om/
D
T
D
s/Prop
e
rtyList-
1
.
0
.
d
t
d
"
>
<
plist
v
e
rsion="
1
.
0
"
>
<
d
i
c
t
>
<
k
e
y
>
NSPhotoLibraryUsageDescription
<
/k
e
y
>
<
string
>
$
(
PRODUCT_NAME
)
photo
use
<
/string
>
<
k
e
y
>
NSContactsUsageDescription
<
/k
e
y
>
<
string
>
$
(
PRODUCT_NAME
)
contact
use
<
/string
>
<
k
e
y
>
CFBundleDevelopmentRegion
<
/k
e
y
>
<
string
>
$
(
DEVELOPMENT_LANGUAGE
)<
/string
>
<
k
e
y
>
CFBundleExecutable
<
/k
e
y
>
...
...
contact-list-app/ViewController.swift
View file @
73d919d6
//
// ViewController.swift
// contact-list-app
//
// Created by Mobile Roshka on 3/12/20.
// Copyright © 2020 Mobile Roshka. All rights reserved.
//
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
{
let
contactStore
=
CNContactStore
()
var
contacts
=
[
CNContact
]()
var
dataSource
:[
ContactList
]?
=
[]
var
backUpContacts
:[
CNContact
]
=
[]
var
isHidden
=
false
@IBOutlet
weak
var
contacsTable
:
UITableView
!
override
func
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
)
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment