Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Sign in / Register
Toggle navigation
P
PhoneManager
Project
Project
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
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Yang
PhoneManager
Commits
fbb3d06c
Commit
fbb3d06c
authored
Apr 20, 2025
by
CZ1004
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
修改
parent
409eabe4
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
32 changed files
with
2385 additions
and
0 deletions
+2385
-0
project.pbxproj
PhoneManager.xcodeproj/project.pbxproj
+2
-0
Contents.json
PhoneManager/Assets.xcassets/Contact/Contents.json
+6
-0
Contents.json
...s.xcassets/Contact/btn_add_contact.imageset/Contents.json
+23
-0
btn_add_contact.png
...sets/Contact/btn_add_contact.imageset/btn_add_contact.png
+0
-0
btn_add_contact@2x.png
...s/Contact/btn_add_contact.imageset/btn_add_contact@2x.png
+0
-0
btn_add_contact@3x.png
...s/Contact/btn_add_contact.imageset/btn_add_contact@3x.png
+0
-0
Contents.json
....xcassets/Contact/ic_unsel_com_red.imageset/Contents.json
+23
-0
ic_unsel_com_red.png
...ts/Contact/ic_unsel_com_red.imageset/ic_unsel_com_red.png
+0
-0
ic_unsel_com_red@2x.png
...Contact/ic_unsel_com_red.imageset/ic_unsel_com_red@2x.png
+0
-0
ic_unsel_com_red@3x.png
...Contact/ic_unsel_com_red.imageset/ic_unsel_com_red@3x.png
+0
-0
ContactAllViewController.swift
...Session/Contact/Controller/ContactAllViewController.swift
+88
-0
ContactBackupViewController.swift
...sion/Contact/Controller/ContactBackupViewController.swift
+94
-0
ContactIncompleteViewController.swift
.../Contact/Controller/ContactIncompleteViewController.swift
+49
-0
ContactViewController.swift
...ss/Session/Contact/Controller/ContactViewController.swift
+164
-0
ContactsDupViewController.swift
...ession/Contact/Controller/ContactsDupViewController.swift
+51
-0
ContactModuleModel.swift
...ager/Class/Session/Contact/Model/ContactModuleModel.swift
+69
-0
ContactAllView.swift
...nager/Class/Session/Contact/View/All/ContactAllView.swift
+340
-0
ContactNoAllView.swift
...ger/Class/Session/Contact/View/All/ContactNoAllView.swift
+84
-0
ContactBackUpNormalView.swift
...ss/Session/Contact/View/Bac/ContactBackUpNormalView.swift
+234
-0
ContactNoBackUpView.swift
.../Class/Session/Contact/View/Bac/ContactNoBackUpView.swift
+82
-0
BackupViewModel.swift
.../Session/Contact/View/Bac/ViewModel/BackupViewModel.swift
+109
-0
CustomContactAllViewTableViewCell.swift
...Contact/View/Cell/CustomContactAllViewTableViewCell.swift
+79
-0
ContactBackUpCompletedAlertView.swift
...ew/Common/AlertView/ContactBackUpCompletedAlertView.swift
+85
-0
ContactBackupAlertView.swift
...ontact/View/Common/AlertView/ContactBackupAlertView.swift
+139
-0
ContactDeleteAlertView.swift
...ontact/View/Common/AlertView/ContactDeleteAlertView.swift
+165
-0
ContactNavView.swift
...er/Class/Session/Contact/View/Common/ContactNavView.swift
+44
-0
DeleteButtonView.swift
.../Class/Session/Contact/View/Common/DeleteButtonView.swift
+66
-0
ContactNoDupView.swift
...ger/Class/Session/Contact/View/Dup/ContactNoDupView.swift
+70
-0
ContactNoIncomView.swift
...r/Class/Session/Contact/View/Inc/ContactNoIncomView.swift
+87
-0
ContactModuleView.swift
...ass/Session/Contact/View/MenuView/ContactModuleView.swift
+216
-0
HomeViewController.swift
PhoneManager/Class/Session/Home/HomeViewController.swift
+11
-0
TabbarImtesData.json
PhoneManager/Class/Session/Home/Model/TabbarImtesData.json
+5
-0
No files found.
PhoneManager.xcodeproj/project.pbxproj
View file @
fbb3d06c
...
@@ -247,6 +247,7 @@
...
@@ -247,6 +247,7 @@
DEVELOPMENT_TEAM
=
7X8JL97Z3E
;
DEVELOPMENT_TEAM
=
7X8JL97Z3E
;
GENERATE_INFOPLIST_FILE
=
YES
;
GENERATE_INFOPLIST_FILE
=
YES
;
INFOPLIST_FILE
=
PhoneManager/Info.plist
;
INFOPLIST_FILE
=
PhoneManager/Info.plist
;
INFOPLIST_KEY_NSContactsUsageDescription
=
"访问你的相册"
;
INFOPLIST_KEY_NSLocalNetworkUsageDescription
=
"We need to access the network to load content"
;
INFOPLIST_KEY_NSLocalNetworkUsageDescription
=
"We need to access the network to load content"
;
INFOPLIST_KEY_NSPhotoLibraryUsageDescription
=
"We need album permission to access image storage information"
;
INFOPLIST_KEY_NSPhotoLibraryUsageDescription
=
"We need album permission to access image storage information"
;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents
=
YES
;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents
=
YES
;
...
@@ -284,6 +285,7 @@
...
@@ -284,6 +285,7 @@
DEVELOPMENT_TEAM
=
7X8JL97Z3E
;
DEVELOPMENT_TEAM
=
7X8JL97Z3E
;
GENERATE_INFOPLIST_FILE
=
YES
;
GENERATE_INFOPLIST_FILE
=
YES
;
INFOPLIST_FILE
=
PhoneManager/Info.plist
;
INFOPLIST_FILE
=
PhoneManager/Info.plist
;
INFOPLIST_KEY_NSContactsUsageDescription
=
"访问你的相册"
;
INFOPLIST_KEY_NSLocalNetworkUsageDescription
=
"We need to access the network to load content"
;
INFOPLIST_KEY_NSLocalNetworkUsageDescription
=
"We need to access the network to load content"
;
INFOPLIST_KEY_NSPhotoLibraryUsageDescription
=
"We need album permission to access image storage information"
;
INFOPLIST_KEY_NSPhotoLibraryUsageDescription
=
"We need album permission to access image storage information"
;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents
=
YES
;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents
=
YES
;
...
...
PhoneManager/Assets.xcassets/Contact/Contents.json
0 → 100644
View file @
fbb3d06c
{
"info"
:
{
"author"
:
"xcode"
,
"version"
:
1
}
}
PhoneManager/Assets.xcassets/Contact/btn_add_contact.imageset/Contents.json
0 → 100644
View file @
fbb3d06c
{
"images"
:
[
{
"filename"
:
"btn_add_contact.png"
,
"idiom"
:
"universal"
,
"scale"
:
"1x"
},
{
"filename"
:
"btn_add_contact@2x.png"
,
"idiom"
:
"universal"
,
"scale"
:
"2x"
},
{
"filename"
:
"btn_add_contact@3x.png"
,
"idiom"
:
"universal"
,
"scale"
:
"3x"
}
],
"info"
:
{
"author"
:
"xcode"
,
"version"
:
1
}
}
PhoneManager/Assets.xcassets/Contact/btn_add_contact.imageset/btn_add_contact.png
0 → 100644
View file @
fbb3d06c
2 KB
PhoneManager/Assets.xcassets/Contact/btn_add_contact.imageset/btn_add_contact@2x.png
0 → 100644
View file @
fbb3d06c
3.98 KB
PhoneManager/Assets.xcassets/Contact/btn_add_contact.imageset/btn_add_contact@3x.png
0 → 100644
View file @
fbb3d06c
5.29 KB
PhoneManager/Assets.xcassets/Contact/ic_unsel_com_red.imageset/Contents.json
0 → 100644
View file @
fbb3d06c
{
"images"
:
[
{
"filename"
:
"ic_unsel_com_red.png"
,
"idiom"
:
"universal"
,
"scale"
:
"1x"
},
{
"filename"
:
"ic_unsel_com_red@2x.png"
,
"idiom"
:
"universal"
,
"scale"
:
"2x"
},
{
"filename"
:
"ic_unsel_com_red@3x.png"
,
"idiom"
:
"universal"
,
"scale"
:
"3x"
}
],
"info"
:
{
"author"
:
"xcode"
,
"version"
:
1
}
}
PhoneManager/Assets.xcassets/Contact/ic_unsel_com_red.imageset/ic_unsel_com_red.png
0 → 100644
View file @
fbb3d06c
1001 Bytes
PhoneManager/Assets.xcassets/Contact/ic_unsel_com_red.imageset/ic_unsel_com_red@2x.png
0 → 100644
View file @
fbb3d06c
1.95 KB
PhoneManager/Assets.xcassets/Contact/ic_unsel_com_red.imageset/ic_unsel_com_red@3x.png
0 → 100644
View file @
fbb3d06c
2.59 KB
PhoneManager/Class/Session/Contact/Controller/ContactAllViewController.swift
0 → 100644
View file @
fbb3d06c
//
// AllContactViewController.swift
// PhoneManager
//
// Created by 赵前 on 2025/4/19.
//
import
Foundation
class
ContactAllViewController
:
BaseViewController
{
var
dataSourceModel
:
[
ContactModel
]
=
[]
lazy
var
navView
:
ContactNavView
=
{
let
view
=
ContactNavView
()
return
view
}()
lazy
var
emptyView
:
ContactNoAllView
=
{
let
view
=
ContactNoAllView
()
return
view
}()
lazy
var
normalView
:
ContactAllView
=
{
let
view
=
ContactAllView
()
return
view
}()
// 默认页面
func
setDefaultPage
(){
self
.
normalView
.
removeFromSuperview
()
self
.
view
.
addSubview
(
self
.
emptyView
)
self
.
emptyView
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalTo
(
self
.
navView
.
snp
.
bottom
)
.
offset
(
0
)
make
.
left
.
right
.
equalToSuperview
()
make
.
bottom
.
equalToSuperview
()
}
}
func
setNormalPage
(){
self
.
emptyView
.
removeFromSuperview
()
self
.
view
.
addSubview
(
self
.
normalView
)
self
.
normalView
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalTo
(
self
.
navView
.
snp
.
bottom
)
.
offset
(
0
)
make
.
left
.
right
.
equalToSuperview
()
make
.
bottom
.
equalToSuperview
()
}
}
override
func
viewDidLoad
()
{
super
.
viewDidLoad
()
self
.
view
.
backgroundColor
=
.
white
self
.
view
.
addSubview
(
self
.
navView
)
self
.
navView
.
snp
.
makeConstraints
{
make
in
make
.
top
.
left
.
right
.
equalToSuperview
()
make
.
height
.
equalTo
(
statusBarHeight
+
44
)
}
}
}
extension
ContactAllViewController
{
override
func
viewWillAppear
(
_
animated
:
Bool
)
{
super
.
viewWillAppear
(
animated
)
if
self
.
dataSourceModel
.
count
>
0
{
self
.
setNormalPage
()
self
.
normalView
.
dataSourceModel
=
self
.
dataSourceModel
DispatchQueue
.
main
.
async
{
self
.
normalView
.
subTitleLabel
.
text
=
"
\(
self
.
dataSourceModel
.
count
)
Contacts"
self
.
normalView
.
sortContacts
()
self
.
normalView
.
tableView
.
reloadData
()
self
.
normalView
.
setupCustomIndexView
()
}
}
else
{
self
.
setDefaultPage
()
}
}
}
PhoneManager/Class/Session/Contact/Controller/ContactBackupViewController.swift
0 → 100644
View file @
fbb3d06c
//
// ContactBackupViewController.swift
// PhoneManager
//
// Created by 赵前 on 2025/4/19.
//
import
Foundation
class
ContactBackupViewController
:
BaseViewController
{
var
dataSourceModel
:
[
BackupInfoModel
]?
// 总数据
var
dataSourceAllModel
:
ContactModuleModel
?
lazy
var
navView
:
ContactNavView
=
{
let
view
=
ContactNavView
()
return
view
}()
lazy
var
emptyView
:
ContactNoBackUpView
=
{
let
view
=
ContactNoBackUpView
()
return
view
}()
lazy
var
normalView
:
ContactBackUpNormalView
=
{
let
view
=
ContactBackUpNormalView
()
return
view
}()
// 默认页面
func
setDefaultPage
(){
self
.
view
.
addSubview
(
self
.
emptyView
)
self
.
emptyView
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalTo
(
self
.
navView
.
snp
.
bottom
)
.
offset
(
0
)
make
.
left
.
right
.
equalToSuperview
()
make
.
bottom
.
equalToSuperview
()
}
}
// 默认页面
func
setNormalPage
(){
self
.
emptyView
.
removeFromSuperview
()
self
.
view
.
addSubview
(
self
.
normalView
)
self
.
normalView
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalTo
(
self
.
navView
.
snp
.
bottom
)
.
offset
(
0
)
make
.
left
.
right
.
equalToSuperview
()
make
.
bottom
.
equalToSuperview
()
}
}
override
func
viewDidLoad
()
{
super
.
viewDidLoad
()
self
.
view
.
backgroundColor
=
.
white
self
.
view
.
addSubview
(
self
.
navView
)
self
.
navView
.
snp
.
makeConstraints
{
make
in
make
.
top
.
left
.
right
.
equalToSuperview
()
make
.
height
.
equalTo
(
statusBarHeight
+
44
)
}
self
.
setDefaultPage
()
}
}
extension
ContactBackupViewController
{
override
func
viewWillAppear
(
_
animated
:
Bool
)
{
super
.
viewWillAppear
(
animated
)
// 请求下数据
let
vm
=
BackupViewModel
()
vm
.
retrieveContactsFromBackup
{[
weak
self
]
info
,
error
in
guard
let
self
else
{
return
}
if
error
!=
nil
{
Print
(
"取出备份错误
\(
String
(
describing
:
error
?
.
localizedDescription
)
)
"
)
return
}
DispatchQueue
.
main
.
async
{
self
.
setNormalPage
()
self
.
dataSourceModel
=
info
self
.
normalView
.
dataSourceModel
=
info
??
[]
self
.
normalView
.
dataSourceAllModel
=
self
.
dataSourceAllModel
?
.
allContacts
self
.
normalView
.
tableView
.
reloadData
()
}
}
}
}
PhoneManager/Class/Session/Contact/Controller/ContactIncompleteViewController.swift
0 → 100644
View file @
fbb3d06c
//
// ContactIncompleteViewController.swift
// PhoneManager
//
// Created by 赵前 on 2025/4/19.
//
import
Foundation
class
ContactIncompleteViewController
:
BaseViewController
{
var
dataSourceModel
:
[
ContactModel
]?
lazy
var
navView
:
ContactNavView
=
{
let
view
=
ContactNavView
()
return
view
}()
lazy
var
emptyView
:
ContactNoIncomView
=
{
let
view
=
ContactNoIncomView
()
return
view
}()
// 默认页面
func
setDefaultPage
(){
self
.
view
.
addSubview
(
self
.
emptyView
)
self
.
emptyView
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalTo
(
self
.
navView
.
snp
.
bottom
)
.
offset
(
0
)
make
.
left
.
right
.
equalToSuperview
()
make
.
bottom
.
equalToSuperview
()
}
}
override
func
viewDidLoad
()
{
super
.
viewDidLoad
()
self
.
view
.
backgroundColor
=
.
white
self
.
view
.
addSubview
(
self
.
navView
)
self
.
navView
.
snp
.
makeConstraints
{
make
in
make
.
top
.
left
.
right
.
equalToSuperview
()
make
.
height
.
equalTo
(
statusBarHeight
+
44
)
}
self
.
setDefaultPage
()
}
}
PhoneManager/Class/Session/Contact/Controller/ContactViewController.swift
0 → 100644
View file @
fbb3d06c
//
// ContactViewController.swift
// PhoneManager
//
// Created by edy on 2025/4/18.
//
import
Foundation
import
Contacts
class
ContactViewController
:
BaseViewController
{
var
dataSourceModel
:
ContactModuleModel
=
ContactModuleModel
(
duplicates
:
[],
incompleteContacts
:
[],
backups
:
[],
allContacts
:
[])
lazy
var
navView
:
ContactNavView
=
{
let
view
=
ContactNavView
()
return
view
}()
lazy
var
emptyView
:
ContactDefaultView
=
{
let
view
=
ContactDefaultView
()
return
view
}()
lazy
var
moduleView
:
ContactModuleView
=
{
let
view
=
ContactModuleView
()
return
view
}()
override
func
viewDidLoad
()
{
self
.
view
.
backgroundColor
=
.
white
self
.
view
.
addSubview
(
self
.
navView
)
self
.
navView
.
snp
.
makeConstraints
{
make
in
make
.
top
.
left
.
right
.
equalToSuperview
()
make
.
height
.
equalTo
(
statusBarHeight
+
44
)
}
}
func
setDefaultPage
(){
self
.
view
.
addSubview
(
self
.
emptyView
)
self
.
emptyView
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalTo
(
self
.
navView
.
snp
.
bottom
)
.
offset
(
0
)
make
.
left
.
right
.
equalToSuperview
()
make
.
bottom
.
equalToSuperview
()
}
}
func
setNormalPage
(){
self
.
emptyView
.
removeFromSuperview
()
self
.
view
.
addSubview
(
self
.
moduleView
)
self
.
moduleView
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalTo
(
self
.
navView
.
snp
.
bottom
)
.
offset
(
0
)
make
.
left
.
right
.
equalToSuperview
()
make
.
bottom
.
equalToSuperview
()
}
}
override
func
viewWillAppear
(
_
animated
:
Bool
)
{
super
.
viewWillAppear
(
animated
)
// 请求联系人权限
self
.
setDefaultPage
()
requestContactsPermission
{
permission
in
DispatchQueue
.
main
.
async
{
if
permission
{
// 有权限
self
.
updateModuleData
()
self
.
setNormalPage
()
// 初始化数据
self
.
initContatsInfo
()
}
}
}
}
}
extension
ContactViewController
{
/// 更新模块显示的数据
func
updateModuleData
()
{
var
moduleViewData
:
[
ModuleDataModel
]
=
[]
let
model1
=
ModuleDataModel
.
init
(
titleText
:
"Duplicates"
,
subTitleText
:
"
\(
String
(
describing
:
self
.
dataSourceModel
.
duplicates
.
count
)
)
Duplicates"
)
let
model2
=
ModuleDataModel
.
init
(
titleText
:
"Incomplete Contacts"
,
subTitleText
:
"
\(
String
(
describing
:
self
.
dataSourceModel
.
incompleteContacts
.
count
)
)
Incomplete Contacts"
)
let
model3
=
ModuleDataModel
.
init
(
titleText
:
"Backups"
,
subTitleText
:
"
\(
String
(
describing
:
self
.
dataSourceModel
.
backups
.
count
)
)
Backups"
)
let
model4
=
ModuleDataModel
.
init
(
titleText
:
"All Contacts"
,
subTitleText
:
"
\(
String
(
describing
:
self
.
dataSourceModel
.
allContacts
.
count
)
)
Contacts"
)
moduleViewData
.
append
(
model1
)
moduleViewData
.
append
(
model2
)
moduleViewData
.
append
(
model3
)
moduleViewData
.
append
(
model4
)
self
.
moduleView
.
moduleViewData
=
moduleViewData
self
.
moduleView
.
dataSourceModel
=
self
.
dataSourceModel
}
/// 初始化联系人数据
func
initContatsInfo
()
{
let
store
=
CNContactStore
()
let
keysToFetch
=
[
CNContactGivenNameKey
as
CNKeyDescriptor
,
CNContactFamilyNameKey
as
CNKeyDescriptor
,
CNContactPhoneNumbersKey
as
CNKeyDescriptor
]
do
{
let
request
=
CNContactFetchRequest
(
keysToFetch
:
keysToFetch
)
// 创建数组
var
incompleteContacts
:
[
ContactModel
]
=
[]
var
allContacts
:
[
ContactModel
]
=
[]
try
store
.
enumerateContacts
(
with
:
request
)
{
contact
,
stop
in
let
givenName
=
contact
.
givenName
let
familyName
=
contact
.
familyName
let
fullName
=
"
\(
familyName
)
\(
givenName
)
"
let
phoneNumbers
=
contact
.
phoneNumbers
.
map
{
$0
.
value
.
stringValue
}
let
model
=
ContactModel
.
init
(
name
:
fullName
,
phoneNumber
:
phoneNumbers
,
identifier
:
contact
.
identifier
)
if
fullName
.
isEmpty
||
phoneNumbers
.
count
<=
0
{
incompleteContacts
.
append
(
model
)
}
allContacts
.
append
(
model
)
self
.
dataSourceModel
=
ContactModuleModel
.
init
(
duplicates
:
[],
incompleteContacts
:
incompleteContacts
,
backups
:
[],
allContacts
:
allContacts
)
}
DispatchQueue
.
main
.
async
{
self
.
updateModuleData
()
self
.
moduleView
.
tableView
.
reloadData
()
}
}
catch
{
DispatchQueue
.
main
.
async
{
print
(
"获取联系人信息时发生错误:
\(
error
)
"
)
}
}
}
func
requestContactsPermission
(
completion
:
@escaping
(
Bool
)
->
Void
)
{
let
store
=
CNContactStore
()
switch
CNContactStore
.
authorizationStatus
(
for
:
.
contacts
)
{
case
.
authorized
:
// 已经授权
completion
(
true
)
case
.
denied
,
.
restricted
:
// 被拒绝或受限
completion
(
false
)
case
.
notDetermined
:
// 未确定,请求授权
store
.
requestAccess
(
for
:
.
contacts
)
{
granted
,
error
in
if
let
error
=
error
{
print
(
"请求联系人权限时发生错误:
\(
error
)
"
)
}
completion
(
granted
)
}
case
.
limited
:
// 不分联系人权限
completion
(
true
)
@unknown
default
:
completion
(
false
)
}
}
}
PhoneManager/Class/Session/Contact/Controller/ContactsDupViewController.swift
0 → 100644
View file @
fbb3d06c
//
// ContactsDupViewController.swift
// PhoneManager
//
// Created by 赵前 on 2025/4/19.
//
import
Foundation
class
ContactsDupViewController
:
BaseViewController
{
var
dataSourceModel
:
[[
ContactModel
]]?
lazy
var
navView
:
ContactNavView
=
{
let
view
=
ContactNavView
()
return
view
}()
lazy
var
emptyView
:
ContactNoDupView
=
{
let
view
=
ContactNoDupView
()
return
view
}()
// 默认页面
func
setDefaultPage
(){
self
.
view
.
addSubview
(
self
.
emptyView
)
self
.
emptyView
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalTo
(
self
.
navView
.
snp
.
bottom
)
.
offset
(
0
)
make
.
left
.
right
.
equalToSuperview
()
make
.
bottom
.
equalToSuperview
()
}
}
override
func
viewDidLoad
()
{
super
.
viewDidLoad
()
self
.
view
.
backgroundColor
=
.
white
self
.
view
.
addSubview
(
self
.
navView
)
self
.
navView
.
snp
.
makeConstraints
{
make
in
make
.
top
.
left
.
right
.
equalToSuperview
()
make
.
height
.
equalTo
(
statusBarHeight
+
44
)
}
self
.
setDefaultPage
()
}
}
PhoneManager/Class/Session/Contact/Model/ContactModuleModel.swift
0 → 100644
View file @
fbb3d06c
//
// ContactModuleModel.swift
// PhoneManager
//
// Created by edy on 2025/4/18.
//
import
Foundation
import
Contacts
struct
ContactModel
:
Codable
,
Equatable
{
// 联系人名字
var
name
:
String
// 联系人电话
var
phoneNumber
:
[
String
]?
// 唯一id
var
identifier
:
String
init
(
name
:
String
,
phoneNumber
:
[
String
]?
=
nil
,
identifier
:
String
)
{
self
.
name
=
name
self
.
phoneNumber
=
phoneNumber
self
.
identifier
=
identifier
}
}
extension
ContactModel
{
init
?(
contact
:
CNContact
)
{
let
fullName
=
"
\(
contact
.
givenName
)
\(
contact
.
familyName
)
"
.
trimmingCharacters
(
in
:
.
whitespaces
)
let
phoneNumbers
=
contact
.
phoneNumbers
.
map
{
$0
.
value
.
stringValue
}
let
uniqueID
=
contact
.
identifier
if
fullName
.
isEmpty
||
phoneNumbers
.
isEmpty
||
uniqueID
.
isEmpty
{
return
nil
}
self
.
name
=
fullName
self
.
phoneNumber
=
phoneNumbers
self
.
identifier
=
uniqueID
}
}
struct
ContactModuleModel
{
var
duplicates
:
[[
ContactModel
]]
var
incompleteContacts
:
[
ContactModel
]
var
backups
:
[
BackupInfoModel
]
var
allContacts
:
[
ContactModel
]
init
(
duplicates
:
[[
ContactModel
]],
incompleteContacts
:
[
ContactModel
],
backups
:
[
BackupInfoModel
],
allContacts
:
[
ContactModel
])
{
self
.
duplicates
=
duplicates
self
.
incompleteContacts
=
incompleteContacts
self
.
backups
=
backups
self
.
allContacts
=
allContacts
}
}
struct
ModuleDataModel
{
var
titleText
:
String
var
subTitleText
:
String
init
(
titleText
:
String
,
subTitleText
:
String
)
{
self
.
titleText
=
titleText
self
.
subTitleText
=
subTitleText
}
}
PhoneManager/Class/Session/Contact/View/All/ContactAllView.swift
0 → 100644
View file @
fbb3d06c
This diff is collapsed.
Click to expand it.
PhoneManager/Class/Session/Contact/View/All/ContactNoAllView.swift
0 → 100644
View file @
fbb3d06c
//
// ContactNoAll.swift
// PhoneManager
//
// Created by 赵前 on 2025/4/19.
//
import
Foundation
class
ContactNoAllView
:
UIView
{
lazy
var
titleLabel
:
UILabel
=
{
let
label
=
UILabel
()
label
.
text
=
"All contacts"
label
.
font
=
UIFont
.
systemFont
(
ofSize
:
20
,
weight
:
.
bold
)
label
.
textColor
=
UIColor
(
red
:
0.2
,
green
:
0.2
,
blue
:
0.2
,
alpha
:
1
)
label
.
textAlignment
=
.
left
return
label
}()
lazy
var
subTitleLabel
:
UILabel
=
{
let
label
=
UILabel
()
label
.
text
=
"0 Contacts"
label
.
font
=
UIFont
.
systemFont
(
ofSize
:
14
,
weight
:
.
regular
)
label
.
textColor
=
UIColor
(
red
:
0.2
,
green
:
0.2
,
blue
:
0.2
,
alpha
:
1
)
label
.
textAlignment
=
.
left
return
label
}()
lazy
var
tipLabel
:
UILabel
=
{
let
label
=
UILabel
()
label
.
text
=
"No Contacts"
label
.
font
=
UIFont
.
systemFont
(
ofSize
:
24
,
weight
:
.
bold
)
label
.
textColor
=
UIColor
(
red
:
0.2
,
green
:
0.2
,
blue
:
0.2
,
alpha
:
1
)
label
.
textAlignment
=
.
center
return
label
}()
lazy
var
subTipLabel
:
UILabel
=
{
let
label
=
UILabel
()
label
.
text
=
"Go add a contact!"
label
.
font
=
UIFont
.
systemFont
(
ofSize
:
14
,
weight
:
.
regular
)
label
.
textColor
=
UIColor
(
red
:
0.4
,
green
:
0.4
,
blue
:
0.4
,
alpha
:
1
)
label
.
textAlignment
=
.
center
return
label
}()
override
init
(
frame
:
CGRect
)
{
super
.
init
(
frame
:
frame
)
self
.
addSubview
(
self
.
titleLabel
)
self
.
addSubview
(
self
.
subTitleLabel
)
self
.
addSubview
(
self
.
tipLabel
)
self
.
addSubview
(
self
.
subTipLabel
)
self
.
titleLabel
.
snp
.
makeConstraints
{
make
in
make
.
left
.
equalToSuperview
()
.
offset
(
15
*
RScreenW
())
make
.
top
.
equalToSuperview
()
.
offset
(
14
*
RScreenH
())
make
.
width
.
equalTo
(
345
*
RScreenW
())
make
.
height
.
equalTo
(
32
)
}
self
.
subTitleLabel
.
snp
.
makeConstraints
{
make
in
make
.
left
.
equalToSuperview
()
.
offset
(
15
*
RScreenW
())
make
.
top
.
equalTo
(
self
.
titleLabel
.
snp
.
bottom
)
.
offset
(
2
*
RScreenH
())
make
.
width
.
equalTo
(
345
*
RScreenW
())
make
.
height
.
equalTo
(
20
)
}
self
.
tipLabel
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalTo
(
self
.
subTitleLabel
.
snp
.
bottom
)
.
offset
(
218
*
RScreenH
())
make
.
width
.
equalTo
(
315
*
RScreenW
())
make
.
height
.
equalTo
(
34
)
make
.
centerX
.
equalToSuperview
()
}
self
.
subTipLabel
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalTo
(
self
.
tipLabel
.
snp
.
bottom
)
.
offset
(
8
*
RScreenH
())
make
.
width
.
equalTo
(
315
*
RScreenW
())
make
.
height
.
equalTo
(
20
)
make
.
centerX
.
equalToSuperview
()
}
}
required
init
?(
coder
:
NSCoder
)
{
fatalError
(
"init(coder:) has not been implemented"
)
}
}
PhoneManager/Class/Session/Contact/View/Bac/ContactBackUpNormalView.swift
0 → 100644
View file @
fbb3d06c
//
// ContactBackUpView.swift
// PhoneManager
//
// Created by 赵前 on 2025/4/20.
//
import
Foundation
class
ContactBackUpNormalView
:
UIView
{
var
dataSourceModel
:
[
BackupInfoModel
]
=
[]
var
dataSourceAllModel
:
[
ContactModel
]?
lazy
var
titleLabel
:
UILabel
=
{
let
label
=
UILabel
()
label
.
text
=
"Backups"
label
.
font
=
UIFont
.
systemFont
(
ofSize
:
20
,
weight
:
.
bold
)
label
.
textColor
=
UIColor
(
red
:
0.2
,
green
:
0.2
,
blue
:
0.2
,
alpha
:
1
)
label
.
textAlignment
=
.
left
return
label
}()
private
lazy
var
addButon
:
UIButton
=
{
let
button
=
UIButton
()
button
.
addTarget
(
self
,
action
:
#selector(
addBackupAction
)
,
for
:
.
touchUpInside
)
button
.
backgroundColor
=
.
clear
button
.
setImage
(
UIImage
(
named
:
"btn_add_contact"
),
for
:
.
normal
)
return
button
}()
// 懒加载 tableView
lazy
var
tableView
:
UITableView
=
{
let
tableView
=
UITableView
()
tableView
.
delegate
=
self
tableView
.
dataSource
=
self
tableView
.
register
(
ContactBackupCell
.
self
,
forCellReuseIdentifier
:
ContactBackupCell
.
identifier
)
tableView
.
separatorStyle
=
.
none
return
tableView
}()
override
init
(
frame
:
CGRect
)
{
super
.
init
(
frame
:
frame
)
self
.
backgroundColor
=
.
white
setupUI
()
}
required
init
?(
coder
:
NSCoder
)
{
fatalError
(
"init(coder:) has not been implemented"
)
}
private
func
setupUI
()
{
self
.
addSubview
(
self
.
titleLabel
)
self
.
addSubview
(
self
.
addButon
)
self
.
addSubview
(
self
.
tableView
)
self
.
titleLabel
.
snp
.
makeConstraints
{
make
in
make
.
left
.
equalToSuperview
()
.
offset
(
15
*
RScreenW
())
make
.
top
.
equalToSuperview
()
.
offset
(
14
*
RScreenH
())
make
.
width
.
equalTo
(
345
*
RScreenW
())
make
.
height
.
equalTo
(
32
)
}
self
.
addButon
.
snp
.
makeConstraints
{
make
in
make
.
right
.
equalToSuperview
()
.
offset
(
-
15
*
RScreenW
())
make
.
centerY
.
equalTo
(
self
.
titleLabel
.
snp
.
centerY
)
make
.
width
.
equalTo
(
28
)
make
.
height
.
equalTo
(
28
)
}
self
.
tableView
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalTo
(
self
.
addButon
.
snp
.
bottom
)
.
offset
(
16
)
make
.
left
.
equalToSuperview
()
.
offset
(
15
*
RScreenW
())
make
.
right
.
equalToSuperview
()
.
offset
(
-
15
*
RScreenW
())
make
.
bottom
.
equalToSuperview
()
}
}
}
extension
ContactBackUpNormalView
:
UITableViewDelegate
,
UITableViewDataSource
{
func
tableView
(
_
tableView
:
UITableView
,
numberOfRowsInSection
section
:
Int
)
->
Int
{
return
dataSourceModel
.
count
}
func
tableView
(
_
tableView
:
UITableView
,
heightForRowAt
indexPath
:
IndexPath
)
->
CGFloat
{
return
74
}
func
tableView
(
_
tableView
:
UITableView
,
cellForRowAt
indexPath
:
IndexPath
)
->
UITableViewCell
{
let
cell
=
tableView
.
dequeueReusableCell
(
withIdentifier
:
ContactBackupCell
.
identifier
,
for
:
indexPath
)
as!
ContactBackupCell
let
backupInfo
=
dataSourceModel
[
indexPath
.
row
]
let
dateFormatter
=
DateFormatter
()
dateFormatter
.
dateFormat
=
"dd MMM yyyy"
let
dateString
=
dateFormatter
.
string
(
from
:
backupInfo
.
backupTime
)
dateFormatter
.
dateFormat
=
"HH:mm"
let
timeString
=
dateFormatter
.
string
(
from
:
backupInfo
.
backupTime
)
cell
.
configure
(
title
:
dateString
,
subtitle
:
"
\(
backupInfo
.
contactCount
)
Contacts"
,
time
:
timeString
)
return
cell
}
@objc(tableView:trailingSwipeActionsConfigurationForRowAtIndexPath:)
func
tableView
(
_
tableView
:
UITableView
,
trailingSwipeActionsConfigurationForRowAt
indexPath
:
IndexPath
)
->
UISwipeActionsConfiguration
?
{
let
deleteAction
=
UIContextualAction
(
style
:
.
destructive
,
title
:
nil
)
{
[
weak
self
]
(
action
,
view
,
completionHandler
)
in
self
?
.
dataSourceModel
.
remove
(
at
:
indexPath
.
row
)
tableView
.
deleteRows
(
at
:
[
indexPath
],
with
:
.
automatic
)
completionHandler
(
true
)
}
deleteAction
.
backgroundColor
=
.
red
deleteAction
.
image
=
UIImage
(
named
:
"ic_delete_email"
)
let
configuration
=
UISwipeActionsConfiguration
(
actions
:
[
deleteAction
])
return
configuration
}
@objc
func
addBackupAction
()
{
let
vm
=
BackupViewModel
()
vm
.
backupAllContacts
(
self
.
dataSourceAllModel
??
[])
{
finished
,
error
in
DispatchQueue
.
main
.
async
{
let
buAlertVc
=
ContactBackUpCompletedAlertView
(
frame
:
(
self
.
responderViewController
()?
.
view
.
bounds
)
!
)
self
.
responderViewController
()?
.
view
.
addSubview
(
buAlertVc
)
DispatchQueue
.
main
.
asyncAfter
(
deadline
:
.
now
()
+
1
)
{
buAlertVc
.
removeFromSuperview
()
}
// 再次请求数据 重新刷新页面
self
.
updateData
()
}
}
}
func
updateData
(){
let
vm
=
BackupViewModel
()
vm
.
retrieveContactsFromBackup
{
model
,
error
in
if
let
error
=
error
{
Print
(
"更新数据失败
\(
error
.
localizedDescription
)
"
)
}
DispatchQueue
.
main
.
async
{
self
.
dataSourceModel
=
model
!
self
.
tableView
.
reloadData
()
}
}
}
}
class
ContactBackupCell
:
UITableViewCell
{
static
let
identifier
=
"ContactBackupCell"
// 懒加载 UI 元素
private
lazy
var
titleLabel
:
UILabel
=
{
let
label
=
UILabel
()
label
.
font
=
UIFont
.
boldSystemFont
(
ofSize
:
16
)
label
.
textColor
=
UIColor
(
red
:
0.2
,
green
:
0.2
,
blue
:
0.2
,
alpha
:
1
)
return
label
}()
private
lazy
var
subtitleLabel
:
UILabel
=
{
let
label
=
UILabel
()
label
.
font
=
UIFont
.
systemFont
(
ofSize
:
14
,
weight
:
.
regular
)
label
.
textColor
=
UIColor
(
red
:
0.4
,
green
:
0.4
,
blue
:
0.4
,
alpha
:
1
)
return
label
}()
private
lazy
var
timeLabel
:
UILabel
=
{
let
label
=
UILabel
()
label
.
font
=
UIFont
.
systemFont
(
ofSize
:
12
,
weight
:
.
regular
)
label
.
textColor
=
UIColor
(
red
:
0.7
,
green
:
0.7
,
blue
:
0.7
,
alpha
:
1
)
label
.
textAlignment
=
.
right
return
label
}()
lazy
var
moreImageView
:
UIImageView
=
{
let
imageView
=
UIImageView
()
imageView
.
image
=
UIImage
(
named
:
"icon_left_setting_grey"
)
imageView
.
contentMode
=
.
scaleAspectFit
return
imageView
}()
override
init
(
style
:
UITableViewCell
.
CellStyle
,
reuseIdentifier
:
String
?)
{
super
.
init
(
style
:
style
,
reuseIdentifier
:
reuseIdentifier
)
self
.
backgroundColor
=
UIColor
(
red
:
0.95
,
green
:
0.96
,
blue
:
0.99
,
alpha
:
1
)
self
.
clipsToBounds
=
true
self
.
layer
.
cornerRadius
=
12
self
.
selectionStyle
=
.
none
setupUI
()
}
required
init
?(
coder
:
NSCoder
)
{
fatalError
(
"init(coder:) has not been implemented"
)
}
private
func
setupUI
()
{
contentView
.
addSubview
(
titleLabel
)
contentView
.
addSubview
(
subtitleLabel
)
contentView
.
addSubview
(
timeLabel
)
contentView
.
addSubview
(
moreImageView
)
titleLabel
.
snp
.
makeConstraints
{
make
in
make
.
top
.
left
.
equalToSuperview
()
.
offset
(
16
)
make
.
width
.
equalTo
(
200
)
make
.
height
.
equalTo
(
22
)
}
subtitleLabel
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalTo
(
self
.
titleLabel
.
snp
.
bottom
)
.
offset
(
0
)
make
.
left
.
equalToSuperview
()
.
offset
(
16
)
make
.
width
.
equalTo
(
200
)
make
.
height
.
equalTo
(
22
)
}
moreImageView
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalToSuperview
()
.
offset
(
16
)
make
.
right
.
equalToSuperview
()
.
offset
(
-
16
)
make
.
width
.
equalTo
(
20
)
make
.
height
.
equalTo
(
20
)
}
timeLabel
.
snp
.
makeConstraints
{
make
in
make
.
right
.
equalToSuperview
()
.
offset
(
-
16
)
make
.
width
.
equalTo
(
40
)
make
.
height
.
equalTo
(
17
)
make
.
centerY
.
equalTo
(
self
.
subtitleLabel
.
snp
.
centerY
)
}
}
func
configure
(
title
:
String
,
subtitle
:
String
,
time
:
String
)
{
titleLabel
.
text
=
title
subtitleLabel
.
text
=
subtitle
timeLabel
.
text
=
time
}
}
PhoneManager/Class/Session/Contact/View/Bac/ContactNoBackUpView.swift
0 → 100644
View file @
fbb3d06c
//
// ContactNoBackUpView.swift
// PhoneManager
//
// Created by 赵前 on 2025/4/19.
//
import
Foundation
class
ContactNoBackUpView
:
UIView
{
lazy
var
titleLabel
:
UILabel
=
{
let
label
=
UILabel
()
label
.
text
=
"Backups"
label
.
font
=
UIFont
.
systemFont
(
ofSize
:
20
,
weight
:
.
bold
)
label
.
textColor
=
UIColor
(
red
:
0.2
,
green
:
0.2
,
blue
:
0.2
,
alpha
:
1
)
label
.
textAlignment
=
.
left
return
label
}()
lazy
var
imageView
:
UIImageView
=
{
let
imageView
=
UIImageView
()
imageView
.
image
=
UIImage
(
named
:
"btn_add_contact"
)
return
imageView
}()
lazy
var
tipLabel
:
UILabel
=
{
let
label
=
UILabel
()
label
.
text
=
"No Backup"
label
.
font
=
UIFont
.
systemFont
(
ofSize
:
24
,
weight
:
.
bold
)
label
.
textColor
=
UIColor
(
red
:
0.2
,
green
:
0.2
,
blue
:
0.2
,
alpha
:
1
)
label
.
textAlignment
=
.
center
return
label
}()
lazy
var
subTipLabel
:
UILabel
=
{
let
label
=
UILabel
()
label
.
text
=
"You can back up your contacts."
label
.
font
=
UIFont
.
systemFont
(
ofSize
:
14
,
weight
:
.
regular
)
label
.
textColor
=
UIColor
(
red
:
0.4
,
green
:
0.4
,
blue
:
0.4
,
alpha
:
1
)
label
.
textAlignment
=
.
center
return
label
}()
override
init
(
frame
:
CGRect
)
{
super
.
init
(
frame
:
frame
)
self
.
addSubview
(
self
.
titleLabel
)
self
.
addSubview
(
self
.
imageView
)
self
.
addSubview
(
self
.
tipLabel
)
self
.
addSubview
(
self
.
subTipLabel
)
self
.
titleLabel
.
snp
.
makeConstraints
{
make
in
make
.
left
.
equalToSuperview
()
.
offset
(
15
*
RScreenW
())
make
.
top
.
equalToSuperview
()
.
offset
(
14
*
RScreenH
())
make
.
width
.
equalTo
(
345
*
RScreenW
())
make
.
height
.
equalTo
(
32
)
}
self
.
imageView
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalTo
(
self
.
titleLabel
.
snp
.
bottom
)
.
offset
(
170
*
RScreenH
())
make
.
width
.
height
.
equalTo
(
58
)
make
.
centerX
.
equalToSuperview
()
}
self
.
tipLabel
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalTo
(
self
.
imageView
.
snp
.
bottom
)
.
offset
(
12
*
RScreenH
())
make
.
width
.
equalTo
(
315
*
RScreenW
())
make
.
height
.
equalTo
(
34
)
make
.
centerX
.
equalToSuperview
()
}
self
.
subTipLabel
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalTo
(
self
.
tipLabel
.
snp
.
bottom
)
.
offset
(
8
*
RScreenH
())
make
.
width
.
equalTo
(
315
*
RScreenW
())
make
.
height
.
equalTo
(
20
)
make
.
centerX
.
equalToSuperview
()
}
}
required
init
?(
coder
:
NSCoder
)
{
fatalError
(
"init(coder:) has not been implemented"
)
}
}
PhoneManager/Class/Session/Contact/View/Bac/ViewModel/BackupViewModel.swift
0 → 100644
View file @
fbb3d06c
//
// BackupViewModel.swift
// PhoneManager
//
// Created by 赵前 on 2025/4/20.
//
import
Foundation
import
Contacts
struct
BackupInfoModel
:
Codable
{
let
backupTime
:
Date
private(set)
var
contactCount
:
Int
let
contacts
:
[
ContactModel
]
// 初始化方法
init
(
backupTime
:
Date
=
Date
(),
contacts
:
[
ContactModel
])
{
self
.
backupTime
=
backupTime
self
.
contactCount
=
contacts
.
count
self
.
contacts
=
contacts
}
// 手动实现 Decodable 协议的 init(from:) 方法
init
(
from
decoder
:
Decoder
)
throws
{
let
container
=
try
decoder
.
container
(
keyedBy
:
CodingKeys
.
self
)
let
dateFormatter
=
DateFormatter
()
dateFormatter
.
dateFormat
=
"yyyy-MM-dd'T'HH:mm:ssZ"
// 与 ISO8601 格式匹配
if
let
backupTimeString
=
try
?
container
.
decode
(
String
.
self
,
forKey
:
.
backupTime
),
let
backupTime
=
dateFormatter
.
date
(
from
:
backupTimeString
)
{
self
.
backupTime
=
backupTime
}
else
{
self
.
backupTime
=
try
container
.
decode
(
Date
.
self
,
forKey
:
.
backupTime
)
}
self
.
contacts
=
try
container
.
decode
([
ContactModel
]
.
self
,
forKey
:
.
contacts
)
self
.
contactCount
=
contacts
.
count
}
private
enum
CodingKeys
:
String
,
CodingKey
{
case
backupTime
case
contactCount
case
contacts
}
}
class
BackupViewModel
{
// 备份部分联系人到沙盒
func
backupPartialContacts
(
_
customContacts
:
[
ContactModel
],
completion
:
@escaping
(
Bool
,
Error
?)
->
Void
)
{
let
newBackupInfo
=
BackupInfoModel
(
contacts
:
customContacts
)
guard
let
documentsDirectory
=
FileManager
.
default
.
urls
(
for
:
.
documentDirectory
,
in
:
.
userDomainMask
)
.
first
else
{
completion
(
false
,
NSError
(
domain
:
"ContactBackupError"
,
code
:
1
,
userInfo
:
[
NSLocalizedDescriptionKey
:
"无法获取沙盒目录"
]))
return
}
let
backupFileURL
=
documentsDirectory
.
appendingPathComponent
(
"partial_contacts_backup.json"
)
var
existingBackups
:
[
BackupInfoModel
]
=
[]
if
let
data
=
try
?
Data
(
contentsOf
:
backupFileURL
)
{
let
decoder
=
JSONDecoder
()
decoder
.
dateDecodingStrategy
=
.
iso8601
do
{
existingBackups
=
try
decoder
.
decode
([
BackupInfoModel
]
.
self
,
from
:
data
)
}
catch
{
print
(
"Failed to decode existing backups:
\(
error
)
"
)
}
}
existingBackups
.
append
(
newBackupInfo
)
do
{
let
encoder
=
JSONEncoder
()
encoder
.
dateEncodingStrategy
=
.
iso8601
let
jsonData
=
try
encoder
.
encode
(
existingBackups
)
try
jsonData
.
write
(
to
:
backupFileURL
)
completion
(
true
,
nil
)
}
catch
{
completion
(
false
,
error
)
}
}
// 备份所有联系人到沙盒
func
backupAllContacts
(
_
customContacts
:
[
ContactModel
],
completion
:
@escaping
(
Bool
,
Error
?)
->
Void
)
{
backupPartialContacts
(
customContacts
)
{
success
,
error
in
completion
(
success
,
error
)
}
}
// 从沙盒中取出联系人并转换为自定义模型
func
retrieveContactsFromBackup
(
completion
:
@escaping
([
BackupInfoModel
]?,
Error
?)
->
Void
)
{
guard
let
documentsDirectory
=
FileManager
.
default
.
urls
(
for
:
.
documentDirectory
,
in
:
.
userDomainMask
)
.
first
else
{
completion
(
nil
,
NSError
(
domain
:
"ContactBackupError"
,
code
:
1
,
userInfo
:
[
NSLocalizedDescriptionKey
:
"无法获取沙盒目录"
]))
return
}
let
backupFileURL
=
documentsDirectory
.
appendingPathComponent
(
"partial_contacts_backup.json"
)
do
{
let
jsonData
=
try
Data
(
contentsOf
:
backupFileURL
)
let
decoder
=
JSONDecoder
()
decoder
.
dateDecodingStrategy
=
.
iso8601
// 尝试解码为 BackupInfoModel 数组
let
backupInfos
=
try
decoder
.
decode
([
BackupInfoModel
]
.
self
,
from
:
jsonData
)
completion
(
backupInfos
,
nil
)
}
catch
{
Print
(
error
.
localizedDescription
)
completion
(
nil
,
error
)
}
}
}
PhoneManager/Class/Session/Contact/View/Cell/CustomContactAllViewTableViewCell.swift
0 → 100644
View file @
fbb3d06c
//
// CustomContactAllViewTableViewCell.swift
// PhoneManager
//
// Created by 赵前 on 2025/4/19.
//
import
Foundation
class
CustomContactAllViewTableViewCell
:
UITableViewCell
{
var
model
:
ContactModel
?
var
buttonSelectCallBack
:
(
ContactModel
,
Bool
)
->
Void
=
{
model
,
selected
in
}
lazy
var
backView
:
UIView
=
{
let
view
=
UIView
()
view
.
backgroundColor
=
UIColor
(
red
:
0.95
,
green
:
0.96
,
blue
:
0.99
,
alpha
:
1
)
view
.
clipsToBounds
=
true
view
.
layer
.
cornerRadius
=
12
return
view
}()
lazy
var
nameLabel
:
UILabel
=
{
let
label
=
UILabel
()
label
.
textColor
=
UIColor
(
red
:
0.2
,
green
:
0.2
,
blue
:
0.2
,
alpha
:
1
)
label
.
font
=
UIFont
.
systemFont
(
ofSize
:
16
,
weight
:
.
bold
)
return
label
}()
lazy
var
selectButton
:
UIButton
=
{
let
button
=
UIButton
(
type
:
.
custom
)
button
.
setImage
(
UIImage
(
named
:
"ic_sel_com"
),
for
:
.
normal
)
button
.
setImage
(
UIImage
(
named
:
"ic_unsel_com_red"
),
for
:
.
selected
)
button
.
addTarget
(
self
,
action
:
#selector(
selectContact(_:)
)
,
for
:
.
touchUpInside
)
return
button
}()
override
init
(
style
:
UITableViewCell
.
CellStyle
,
reuseIdentifier
:
String
?)
{
super
.
init
(
style
:
style
,
reuseIdentifier
:
reuseIdentifier
)
self
.
selectionStyle
=
.
none
self
.
contentView
.
addSubview
(
self
.
backView
)
self
.
backView
.
addSubview
(
self
.
nameLabel
)
self
.
backView
.
addSubview
(
self
.
selectButton
)
self
.
backView
.
snp
.
makeConstraints
{
make
in
make
.
left
.
right
.
top
.
equalToSuperview
()
make
.
height
.
equalTo
(
71
)
}
self
.
nameLabel
.
snp
.
makeConstraints
{
make
in
make
.
left
.
equalToSuperview
()
.
offset
(
16
*
RScreenH
())
make
.
centerY
.
equalToSuperview
()
make
.
width
.
equalTo
(
210
)
make
.
height
.
equalTo
(
22
)
}
self
.
selectButton
.
snp
.
makeConstraints
{
make
in
make
.
width
.
height
.
equalTo
(
24
)
make
.
centerY
.
equalToSuperview
()
make
.
right
.
equalToSuperview
()
.
offset
(
-
16
*
RScreenW
())
}
}
required
init
?(
coder
:
NSCoder
)
{
fatalError
(
"init(coder:) has not been implemented"
)
}
}
extension
CustomContactAllViewTableViewCell
{
@objc
private
func
selectContact
(
_
sender
:
UIButton
)
{
sender
.
isSelected
=
!
sender
.
isSelected
buttonSelectCallBack
(
model
!
,
sender
.
isSelected
)
}
}
PhoneManager/Class/Session/Contact/View/Common/AlertView/ContactBackUpCompletedAlertView.swift
0 → 100644
View file @
fbb3d06c
//
// ContactBackUpCompletedAlertView.swift
// PhoneManager
//
// Created by 赵前 on 2025/4/20.
//
import
Foundation
class
ContactBackUpCompletedAlertView
:
UIView
{
var
sureCallBack
:
()
->
Void
=
{}
// 懒加载背景视图
private
lazy
var
backgroundView
:
UIView
=
{
let
view
=
UIView
()
view
.
backgroundColor
=
UIColor
.
black
.
withAlphaComponent
(
0.5
)
return
view
}()
// 懒加载卡片视图
private
lazy
var
cardView
:
UIView
=
{
let
view
=
UIView
()
view
.
backgroundColor
=
.
white
view
.
layer
.
cornerRadius
=
10
view
.
clipsToBounds
=
true
return
view
}()
private
lazy
var
imageView
:
UIImageView
=
{
let
view
=
UIImageView
()
view
.
backgroundColor
=
.
clear
view
.
image
=
UIImage
(
named
:
"ic_ok_duolicates"
)
return
view
}()
// 懒加载标题标签
private
lazy
var
titleLabel
:
UILabel
=
{
let
label
=
UILabel
()
label
.
text
=
"Backing up is completed"
label
.
font
=
UIFont
.
systemFont
(
ofSize
:
14
,
weight
:
.
regular
)
label
.
textColor
=
UIColor
(
red
:
0.4
,
green
:
0.4
,
blue
:
0.4
,
alpha
:
1
)
label
.
textAlignment
=
.
center
label
.
numberOfLines
=
0
return
label
}()
override
init
(
frame
:
CGRect
)
{
super
.
init
(
frame
:
frame
)
self
.
backgroundColor
=
UIColor
(
red
:
0
,
green
:
0
,
blue
:
0
,
alpha
:
0.5000
)
setupViews
()
}
required
init
?(
coder
:
NSCoder
)
{
fatalError
(
"init(coder:) has not been implemented"
)
}
private
func
setupViews
()
{
self
.
addSubview
(
backgroundView
)
backgroundView
.
snp
.
makeConstraints
{
make
in
make
.
edges
.
equalToSuperview
()
}
self
.
addSubview
(
cardView
)
cardView
.
snp
.
makeConstraints
{
make
in
make
.
center
.
equalToSuperview
()
make
.
width
.
equalTo
(
175
)
make
.
height
.
equalTo
(
115
)
}
cardView
.
addSubview
(
imageView
)
imageView
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalToSuperview
()
.
offset
(
20
)
make
.
width
.
height
.
equalTo
(
35
)
make
.
centerX
.
equalToSuperview
()
}
cardView
.
addSubview
(
titleLabel
)
titleLabel
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalTo
(
self
.
imageView
.
snp
.
bottom
)
.
offset
(
0
)
make
.
left
.
right
.
equalToSuperview
()
.
inset
(
20
)
make
.
height
.
equalTo
(
40
)
}
}
}
PhoneManager/Class/Session/Contact/View/Common/AlertView/ContactBackupAlertView.swift
0 → 100644
View file @
fbb3d06c
//
// ContactBackupAlertView.swift
// PhoneManager
//
// Created by 赵前 on 2025/4/20.
//
import
Foundation
class
ContactBackupAlertView
:
UIView
{
var
sureCallBack
:
(
Bool
)
->
Void
=
{
isSure
in
}
// 懒加载背景视图
private
lazy
var
backgroundView
:
UIView
=
{
let
view
=
UIView
()
view
.
backgroundColor
=
UIColor
.
black
.
withAlphaComponent
(
0.5
)
return
view
}()
// 懒加载卡片视图
private
lazy
var
cardView
:
UIView
=
{
let
view
=
UIView
()
view
.
backgroundColor
=
.
white
view
.
layer
.
cornerRadius
=
10
view
.
clipsToBounds
=
true
return
view
}()
// 懒加载标题标签
private
lazy
var
titleLabel
:
UILabel
=
{
let
label
=
UILabel
()
label
.
text
=
"Would you like to back up your contacts before making any changes?"
label
.
font
=
UIFont
.
systemFont
(
ofSize
:
20
,
weight
:
.
bold
)
label
.
textColor
=
UIColor
(
red
:
0
,
green
:
0
,
blue
:
0
,
alpha
:
1
)
label
.
textAlignment
=
.
center
label
.
numberOfLines
=
0
return
label
}()
// 懒加载副标题标签
private
lazy
var
subtitleLabel
:
UILabel
=
{
let
label
=
UILabel
()
label
.
text
=
"Changes cannot be reversed if you do not back up your contacts"
label
.
font
=
UIFont
.
systemFont
(
ofSize
:
14
,
weight
:
.
regular
)
label
.
textColor
=
UIColor
(
red
:
0
,
green
:
0
,
blue
:
0
,
alpha
:
1
)
label
.
numberOfLines
=
0
label
.
textAlignment
=
.
center
return
label
}()
// 懒加载取消按钮
private
lazy
var
cancelButton
:
UIButton
=
{
let
button
=
UIButton
()
button
.
setTitle
(
"No, Thanks"
,
for
:
.
normal
)
button
.
backgroundColor
=
.
clear
button
.
setTitleColor
(
UIColor
(
red
:
0.4
,
green
:
0.4
,
blue
:
0.4
,
alpha
:
1
),
for
:
.
normal
)
button
.
titleLabel
?
.
font
=
UIFont
.
systemFont
(
ofSize
:
16
,
weight
:
.
bold
)
button
.
layer
.
cornerRadius
=
23
button
.
addTarget
(
self
,
action
:
#selector(
dismissAlert
)
,
for
:
.
touchUpInside
)
return
button
}()
// 懒加载确认按钮
private
lazy
var
yesButton
:
UIButton
=
{
let
button
=
UIButton
()
button
.
setTitle
(
"Back up"
,
for
:
.
normal
)
button
.
backgroundColor
=
UIColor
(
red
:
0
,
green
:
0.51
,
blue
:
1
,
alpha
:
1
)
button
.
titleLabel
?
.
font
=
UIFont
.
systemFont
(
ofSize
:
16
,
weight
:
.
bold
)
button
.
setTitleColor
(
.
white
,
for
:
.
normal
)
button
.
layer
.
cornerRadius
=
23
button
.
addTarget
(
self
,
action
:
#selector(
sureAlert
)
,
for
:
.
touchUpInside
)
return
button
}()
override
init
(
frame
:
CGRect
)
{
super
.
init
(
frame
:
frame
)
self
.
backgroundColor
=
UIColor
(
red
:
0
,
green
:
0
,
blue
:
0
,
alpha
:
0.5000
)
setupViews
()
}
required
init
?(
coder
:
NSCoder
)
{
fatalError
(
"init(coder:) has not been implemented"
)
}
private
func
setupViews
()
{
self
.
addSubview
(
backgroundView
)
backgroundView
.
snp
.
makeConstraints
{
make
in
make
.
edges
.
equalToSuperview
()
}
self
.
addSubview
(
cardView
)
cardView
.
snp
.
makeConstraints
{
make
in
make
.
center
.
equalToSuperview
()
make
.
width
.
equalTo
(
345
)
make
.
height
.
equalTo
(
288
)
}
cardView
.
addSubview
(
titleLabel
)
titleLabel
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalToSuperview
()
.
offset
(
28
)
make
.
left
.
right
.
equalToSuperview
()
.
inset
(
20
)
make
.
height
.
equalTo
(
84
)
}
cardView
.
addSubview
(
subtitleLabel
)
subtitleLabel
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalTo
(
titleLabel
.
snp
.
bottom
)
.
offset
(
8
)
make
.
left
.
right
.
equalToSuperview
()
.
inset
(
20
)
make
.
height
.
equalTo
(
40
)
}
cardView
.
addSubview
(
yesButton
)
yesButton
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalTo
(
subtitleLabel
.
snp
.
bottom
)
.
offset
(
16
)
make
.
left
.
right
.
equalToSuperview
()
.
inset
(
20
)
make
.
height
.
equalTo
(
46
)
}
cardView
.
addSubview
(
cancelButton
)
cancelButton
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalTo
(
yesButton
.
snp
.
bottom
)
.
offset
(
4
)
make
.
left
.
right
.
equalToSuperview
()
.
inset
(
20
)
make
.
height
.
equalTo
(
46
)
}
}
@objc
private
func
dismissAlert
()
{
self
.
removeFromSuperview
()
sureCallBack
(
false
)
}
@objc
private
func
sureAlert
()
{
self
.
removeFromSuperview
()
sureCallBack
(
true
)
}
}
PhoneManager/Class/Session/Contact/View/Common/AlertView/ContactDeleteAlertView.swift
0 → 100644
View file @
fbb3d06c
//
// ContactDeleteAlertViewController.swift
// PhoneManager
//
// Created by 赵前 on 2025/4/19.
//
import
Foundation
class
ContactDeleteAlertView
:
UIView
{
var
sureCallBack
:
()
->
Void
=
{}
// 懒加载背景视图
private
lazy
var
backgroundView
:
UIView
=
{
let
view
=
UIView
()
view
.
backgroundColor
=
UIColor
.
black
.
withAlphaComponent
(
0.5
)
return
view
}()
// 懒加载卡片视图
private
lazy
var
cardView
:
UIView
=
{
let
view
=
UIView
()
view
.
backgroundColor
=
.
white
view
.
layer
.
cornerRadius
=
10
view
.
clipsToBounds
=
true
return
view
}()
// 懒加载标题标签
private
lazy
var
titleLabel
:
UILabel
=
{
let
label
=
UILabel
()
label
.
text
=
"Are you sure?"
label
.
font
=
UIFont
.
systemFont
(
ofSize
:
17
,
weight
:
.
bold
)
label
.
textColor
=
UIColor
(
red
:
0
,
green
:
0
,
blue
:
0
,
alpha
:
1
)
label
.
textAlignment
=
.
center
return
label
}()
// 懒加载副标题标签
private
lazy
var
subtitleLabel
:
UILabel
=
{
let
label
=
UILabel
()
label
.
text
=
"Your contacts will be removed from your iPhone and iCloud. This process cannot be reversed"
label
.
font
=
UIFont
.
systemFont
(
ofSize
:
13
,
weight
:
.
regular
)
label
.
textColor
=
UIColor
(
red
:
0
,
green
:
0
,
blue
:
0
,
alpha
:
1
)
label
.
numberOfLines
=
0
label
.
textAlignment
=
.
center
return
label
}()
// 懒加载取消按钮
private
lazy
var
cancelButton
:
UIButton
=
{
let
button
=
UIButton
()
button
.
setTitle
(
"Cancel"
,
for
:
.
normal
)
button
.
backgroundColor
=
.
clear
button
.
setTitleColor
(
UIColor
(
red
:
0
,
green
:
0.48
,
blue
:
1
,
alpha
:
1
),
for
:
.
normal
)
button
.
layer
.
cornerRadius
=
5
button
.
titleLabel
?
.
font
=
UIFont
.
systemFont
(
ofSize
:
17
,
weight
:
.
regular
)
button
.
addTarget
(
self
,
action
:
#selector(
dismissAlert
)
,
for
:
.
touchUpInside
)
return
button
}()
// 懒加载确认按钮
private
lazy
var
yesButton
:
UIButton
=
{
let
button
=
UIButton
()
button
.
setTitle
(
"Yes"
,
for
:
.
normal
)
button
.
backgroundColor
=
.
clear
button
.
setTitleColor
(
UIColor
(
red
:
0
,
green
:
0.48
,
blue
:
1
,
alpha
:
1
),
for
:
.
normal
)
button
.
layer
.
cornerRadius
=
5
button
.
titleLabel
?
.
font
=
UIFont
.
systemFont
(
ofSize
:
17
,
weight
:
.
regular
)
button
.
addTarget
(
self
,
action
:
#selector(
sureAlert
)
,
for
:
.
touchUpInside
)
return
button
}()
// 懒加载顶部边线
private
lazy
var
topBorder
:
UIView
=
{
let
view
=
UIView
()
view
.
backgroundColor
=
UIColor
(
red
:
0.24
,
green
:
0.24
,
blue
:
0.26
,
alpha
:
0.3600
)
return
view
}()
// 懒加载中间分割线
private
lazy
var
middleBorder
:
UIView
=
{
let
view
=
UIView
()
view
.
backgroundColor
=
UIColor
(
red
:
0.24
,
green
:
0.24
,
blue
:
0.26
,
alpha
:
0.3600
)
return
view
}()
override
init
(
frame
:
CGRect
)
{
super
.
init
(
frame
:
frame
)
self
.
backgroundColor
=
UIColor
(
red
:
0
,
green
:
0
,
blue
:
0
,
alpha
:
0.5000
)
setupViews
()
}
required
init
?(
coder
:
NSCoder
)
{
fatalError
(
"init(coder:) has not been implemented"
)
}
private
func
setupViews
()
{
self
.
addSubview
(
backgroundView
)
backgroundView
.
snp
.
makeConstraints
{
make
in
make
.
edges
.
equalToSuperview
()
}
self
.
addSubview
(
cardView
)
cardView
.
snp
.
makeConstraints
{
make
in
make
.
center
.
equalToSuperview
()
make
.
width
.
equalTo
(
270
)
make
.
height
.
equalTo
(
154
)
}
cardView
.
addSubview
(
titleLabel
)
titleLabel
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalToSuperview
()
.
offset
(
16
)
make
.
left
.
right
.
equalToSuperview
()
.
inset
(
16
)
make
.
height
.
equalTo
(
22
)
}
cardView
.
addSubview
(
subtitleLabel
)
subtitleLabel
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalTo
(
titleLabel
.
snp
.
bottom
)
.
offset
(
2
)
make
.
left
.
right
.
equalToSuperview
()
.
inset
(
16
)
make
.
height
.
equalTo
(
54
)
}
cardView
.
addSubview
(
cancelButton
)
cancelButton
.
snp
.
makeConstraints
{
make
in
make
.
left
.
equalToSuperview
()
make
.
bottom
.
equalToSuperview
()
make
.
width
.
equalTo
(
cardView
.
snp
.
width
)
.
multipliedBy
(
0.5
)
make
.
height
.
equalTo
(
44
)
}
cardView
.
addSubview
(
yesButton
)
yesButton
.
snp
.
makeConstraints
{
make
in
make
.
right
.
equalToSuperview
()
make
.
bottom
.
equalToSuperview
()
make
.
width
.
equalTo
(
cardView
.
snp
.
width
)
.
multipliedBy
(
0.5
)
make
.
height
.
equalTo
(
44
)
}
cardView
.
addSubview
(
topBorder
)
topBorder
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalTo
(
cancelButton
.
snp
.
top
)
make
.
left
.
right
.
equalTo
(
cardView
)
make
.
height
.
equalTo
(
0.5
)
}
cardView
.
addSubview
(
middleBorder
)
middleBorder
.
snp
.
makeConstraints
{
make
in
make
.
centerX
.
equalTo
(
cardView
)
make
.
top
.
equalTo
(
cancelButton
.
snp
.
top
)
make
.
bottom
.
equalTo
(
cancelButton
.
snp
.
bottom
)
make
.
width
.
equalTo
(
0.5
)
}
}
@objc
private
func
dismissAlert
()
{
self
.
removeFromSuperview
()
}
@objc
private
func
sureAlert
()
{
self
.
removeFromSuperview
()
sureCallBack
()
}
}
PhoneManager/Class/Session/Contact/View/Common/ContactNavView.swift
0 → 100644
View file @
fbb3d06c
//
// ContactNavView.swift
// PhoneManager
//
// Created by edy on 2025/4/18.
//
import
Foundation
class
ContactNavView
:
UIView
{
private
var
backButton
:
UIButton
!
override
init
(
frame
:
CGRect
)
{
super
.
init
(
frame
:
frame
)
setupUI
()
}
required
init
?(
coder
:
NSCoder
)
{
fatalError
(
"init(coder:) has not been implemented"
)
}
private
func
setupUI
()
{
backgroundColor
=
.
white
backButton
=
UIButton
()
backButton
.
setImage
(
UIImage
(
named
:
"nav_back"
),
for
:
.
normal
)
backButton
.
addTarget
(
self
,
action
:
#selector(
backBtnClick
)
,
for
:
.
touchUpInside
)
self
.
addSubview
(
backButton
)
backButton
.
snp
.
makeConstraints
{
make
in
make
.
centerY
.
equalTo
(
navCenterY
)
make
.
left
.
equalToSuperview
()
.
offset
(
marginLR
)
make
.
width
.
height
.
equalTo
(
iconWH
)
}
}
@objc
private
func
backBtnClick
()
{
self
.
responderViewController
()?
.
navigationController
?
.
popViewController
(
animated
:
true
)
}
}
PhoneManager/Class/Session/Contact/View/Common/DeleteButtonView.swift
0 → 100644
View file @
fbb3d06c
//
// DeleteButtonView.swift
// PhoneManager
//
// Created by 赵前 on 2025/4/19.
//
import
Foundation
class
DeleteButtonView
:
UIView
{
var
submitCallBack
:
(()
->
Void
)
=
{}
lazy
var
imageView
:
UIImageView
=
{
let
imageView
=
UIImageView
()
imageView
.
image
=
UIImage
(
named
:
"ic_delete_duplicates"
)
return
imageView
}()
lazy
var
titleLabel
:
UILabel
=
{
let
label
=
UILabel
()
label
.
textAlignment
=
.
left
label
.
textColor
=
UIColor
(
red
:
1
,
green
:
1
,
blue
:
1
,
alpha
:
1
)
return
label
}()
override
init
(
frame
:
CGRect
)
{
super
.
init
(
frame
:
frame
)
self
.
isUserInteractionEnabled
=
true
self
.
backgroundColor
=
UIColor
(
red
:
0
,
green
:
0.51
,
blue
:
1
,
alpha
:
1
)
let
tap
=
UITapGestureRecognizer
()
tap
.
addTarget
(
self
,
action
:
#selector(
submitAction
)
)
self
.
addGestureRecognizer
(
tap
)
self
.
addSubview
(
self
.
imageView
)
self
.
addSubview
(
self
.
titleLabel
)
self
.
imageView
.
snp
.
makeConstraints
{
make
in
make
.
width
.
height
.
equalTo
(
20
)
make
.
centerY
.
equalToSuperview
()
make
.
left
.
equalToSuperview
()
.
offset
(
94
*
RScreenW
())
}
self
.
titleLabel
.
snp
.
makeConstraints
{
make
in
make
.
left
.
equalTo
(
self
.
imageView
.
snp
.
right
)
.
offset
(
8
*
RScreenW
())
make
.
centerY
.
equalToSuperview
()
make
.
height
.
equalTo
(
22
)
}
}
required
init
?(
coder
:
NSCoder
)
{
fatalError
(
"init(coder:) has not been implemented"
)
}
}
extension
DeleteButtonView
{
@objc
func
submitAction
(){
submitCallBack
()
}
}
PhoneManager/Class/Session/Contact/View/Dup/ContactNoDupView.swift
0 → 100644
View file @
fbb3d06c
//
// ContactNoDupView.swift
// PhoneManager
//
// Created by 赵前 on 2025/4/19.
//
import
Foundation
class
ContactNoDupView
:
UIView
{
lazy
var
titleLabel
:
UILabel
=
{
let
label
=
UILabel
()
label
.
text
=
"Duplicates"
label
.
font
=
UIFont
.
systemFont
(
ofSize
:
20
,
weight
:
.
bold
)
label
.
textColor
=
UIColor
(
red
:
0.2
,
green
:
0.2
,
blue
:
0.2
,
alpha
:
1
)
label
.
textAlignment
=
.
left
return
label
}()
lazy
var
subTitleLabel
:
UILabel
=
{
let
label
=
UILabel
()
label
.
text
=
"0 Contacts"
label
.
font
=
UIFont
.
systemFont
(
ofSize
:
14
,
weight
:
.
regular
)
label
.
textColor
=
UIColor
(
red
:
0.2
,
green
:
0.2
,
blue
:
0.2
,
alpha
:
1
)
label
.
textAlignment
=
.
left
return
label
}()
lazy
var
tipLabel
:
UILabel
=
{
let
label
=
UILabel
()
label
.
text
=
"No duplicate item"
label
.
font
=
UIFont
.
systemFont
(
ofSize
:
24
,
weight
:
.
bold
)
label
.
textColor
=
UIColor
(
red
:
0.2
,
green
:
0.2
,
blue
:
0.2
,
alpha
:
1
)
label
.
textAlignment
=
.
center
return
label
}()
override
init
(
frame
:
CGRect
)
{
super
.
init
(
frame
:
frame
)
self
.
addSubview
(
self
.
titleLabel
)
self
.
addSubview
(
self
.
subTitleLabel
)
self
.
addSubview
(
self
.
tipLabel
)
self
.
titleLabel
.
snp
.
makeConstraints
{
make
in
make
.
left
.
equalToSuperview
()
.
offset
(
15
*
RScreenW
())
make
.
top
.
equalToSuperview
()
.
offset
(
14
*
RScreenH
())
make
.
width
.
equalTo
(
345
*
RScreenW
())
make
.
height
.
equalTo
(
32
)
}
self
.
subTitleLabel
.
snp
.
makeConstraints
{
make
in
make
.
left
.
equalToSuperview
()
.
offset
(
15
*
RScreenW
())
make
.
top
.
equalTo
(
self
.
titleLabel
.
snp
.
bottom
)
.
offset
(
2
*
RScreenH
())
make
.
width
.
equalTo
(
345
*
RScreenW
())
make
.
height
.
equalTo
(
20
)
}
self
.
tipLabel
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalTo
(
self
.
subTitleLabel
.
snp
.
bottom
)
.
offset
(
218
*
RScreenH
())
make
.
width
.
equalTo
(
315
*
RScreenW
())
make
.
height
.
equalTo
(
34
)
make
.
centerX
.
equalToSuperview
()
}
}
required
init
?(
coder
:
NSCoder
)
{
fatalError
(
"init(coder:) has not been implemented"
)
}
}
PhoneManager/Class/Session/Contact/View/Inc/ContactNoIncomView.swift
0 → 100644
View file @
fbb3d06c
//
// ContactNoIncomView.swift
// PhoneManager
//
// Created by 赵前 on 2025/4/19.
//
import
Foundation
class
ContactNoIncomView
:
UIView
{
lazy
var
titleLabel
:
UILabel
=
{
let
label
=
UILabel
()
label
.
text
=
"Incomplete Contacts"
label
.
font
=
UIFont
.
systemFont
(
ofSize
:
20
,
weight
:
.
bold
)
label
.
textColor
=
UIColor
(
red
:
0.2
,
green
:
0.2
,
blue
:
0.2
,
alpha
:
1
)
label
.
textAlignment
=
.
left
return
label
}()
lazy
var
subTitleLabel
:
UILabel
=
{
let
label
=
UILabel
()
label
.
text
=
"0 Contacts"
label
.
font
=
UIFont
.
systemFont
(
ofSize
:
14
,
weight
:
.
regular
)
label
.
textColor
=
UIColor
(
red
:
0.2
,
green
:
0.2
,
blue
:
0.2
,
alpha
:
1
)
label
.
textAlignment
=
.
left
return
label
}()
lazy
var
tipLabel
:
UILabel
=
{
let
label
=
UILabel
()
label
.
text
=
"No Contacts"
label
.
font
=
UIFont
.
systemFont
(
ofSize
:
24
,
weight
:
.
bold
)
label
.
textColor
=
UIColor
(
red
:
0.2
,
green
:
0.2
,
blue
:
0.2
,
alpha
:
1
)
label
.
textAlignment
=
.
center
return
label
}()
lazy
var
subTipLabel
:
UILabel
=
{
let
label
=
UILabel
()
label
.
text
=
"You can add new contacts from Contacts app in your phone."
label
.
font
=
UIFont
.
systemFont
(
ofSize
:
14
,
weight
:
.
regular
)
label
.
textColor
=
UIColor
(
red
:
0.4
,
green
:
0.4
,
blue
:
0.4
,
alpha
:
1
)
label
.
numberOfLines
=
0
label
.
textAlignment
=
.
center
return
label
}()
override
init
(
frame
:
CGRect
)
{
super
.
init
(
frame
:
frame
)
self
.
addSubview
(
self
.
titleLabel
)
self
.
addSubview
(
self
.
subTitleLabel
)
self
.
addSubview
(
self
.
tipLabel
)
self
.
addSubview
(
self
.
subTipLabel
)
self
.
titleLabel
.
snp
.
makeConstraints
{
make
in
make
.
left
.
equalToSuperview
()
.
offset
(
15
*
RScreenW
())
make
.
top
.
equalToSuperview
()
.
offset
(
14
*
RScreenH
())
make
.
width
.
equalTo
(
345
*
RScreenW
())
make
.
height
.
equalTo
(
32
)
}
self
.
subTitleLabel
.
snp
.
makeConstraints
{
make
in
make
.
left
.
equalToSuperview
()
.
offset
(
15
*
RScreenW
())
make
.
top
.
equalTo
(
self
.
titleLabel
.
snp
.
bottom
)
.
offset
(
2
*
RScreenH
())
make
.
width
.
equalTo
(
345
*
RScreenW
())
make
.
height
.
equalTo
(
20
)
}
self
.
tipLabel
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalTo
(
self
.
subTitleLabel
.
snp
.
bottom
)
.
offset
(
218
*
RScreenH
())
make
.
width
.
equalTo
(
315
*
RScreenW
())
make
.
height
.
equalTo
(
34
)
make
.
centerX
.
equalToSuperview
()
}
self
.
subTipLabel
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalTo
(
self
.
tipLabel
.
snp
.
bottom
)
.
offset
(
8
*
RScreenH
())
make
.
width
.
equalTo
(
315
*
RScreenW
())
make
.
height
.
equalTo
(
40
)
make
.
centerX
.
equalToSuperview
()
}
}
required
init
?(
coder
:
NSCoder
)
{
fatalError
(
"init(coder:) has not been implemented"
)
}
}
PhoneManager/Class/Session/Contact/View/MenuView/ContactModuleView.swift
0 → 100644
View file @
fbb3d06c
//
// ContactModuleView.swift
// PhoneManager
//
// Created by edy on 2025/4/18.
//
import
Foundation
class
ContactModuleView
:
UIView
{
// 总数据
var
dataSourceModel
:
ContactModuleModel
?
// 当前页面显示数据
var
moduleViewData
:
[
ModuleDataModel
]
=
[]
lazy
var
titleLabel
:
UILabel
=
{
let
label
=
UILabel
()
label
.
text
=
"Contacts"
label
.
font
=
UIFont
.
systemFont
(
ofSize
:
20
,
weight
:
.
bold
)
label
.
textColor
=
UIColor
(
red
:
0.2
,
green
:
0.2
,
blue
:
0.2
,
alpha
:
1
)
label
.
textAlignment
=
.
left
return
label
}()
lazy
var
tableView
:
UITableView
=
{
let
tableView
=
UITableView
(
frame
:
CGRect
(
x
:
0
,
y
:
0
,
width
:
0
,
height
:
12
),
style
:
UITableView
.
Style
.
plain
)
tableView
.
dataSource
=
self
tableView
.
delegate
=
self
tableView
.
register
(
CustomContactModuleTableViewCell
.
self
,
forCellReuseIdentifier
:
"CustomContactModuleTableViewCell"
)
tableView
.
separatorStyle
=
.
none
tableView
.
backgroundColor
=
.
clear
tableView
.
isScrollEnabled
=
false
// 设置分隔线样式
tableView
.
separatorStyle
=
.
none
tableView
.
showsVerticalScrollIndicator
=
false
if
#available(iOS 15.0, *)
{
tableView
.
sectionHeaderTopPadding
=
0
}
return
tableView
}()
override
init
(
frame
:
CGRect
)
{
super
.
init
(
frame
:
frame
)
self
.
addSubview
(
self
.
titleLabel
)
self
.
addSubview
(
self
.
tableView
)
setupTableViewConstraints
()
}
private
func
setupTableViewConstraints
()
{
self
.
titleLabel
.
snp
.
makeConstraints
{
make
in
make
.
left
.
equalToSuperview
()
.
offset
(
15
*
RScreenW
())
make
.
top
.
equalToSuperview
()
.
offset
(
14
*
RScreenH
())
make
.
width
.
equalTo
(
345
*
RScreenW
())
make
.
height
.
equalTo
(
32
)
}
self
.
tableView
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalTo
(
self
.
titleLabel
.
snp
.
bottom
)
.
offset
(
18
*
RScreenH
())
make
.
width
.
equalTo
(
345
*
RScreenW
())
make
.
centerX
.
equalToSuperview
()
make
.
bottom
.
equalToSuperview
()
.
offset
(
-
34
)
}
}
required
init
?(
coder
:
NSCoder
)
{
fatalError
(
"init(coder:) has not been implemented"
)
}
}
extension
ContactModuleView
:
UITableViewDataSource
,
UITableViewDelegate
{
func
numberOfSections
(
in
tableView
:
UITableView
)
->
Int
{
return
self
.
moduleViewData
.
count
}
func
tableView
(
_
tableView
:
UITableView
,
numberOfRowsInSection
section
:
Int
)
->
Int
{
return
1
}
func
tableView
(
_
tableView
:
UITableView
,
cellForRowAt
indexPath
:
IndexPath
)
->
UITableViewCell
{
let
cell
=
tableView
.
dequeueReusableCell
(
withIdentifier
:
"CustomContactModuleTableViewCell"
,
for
:
indexPath
)
as!
CustomContactModuleTableViewCell
let
titleText
=
self
.
moduleViewData
[
indexPath
.
section
]
.
titleText
let
subTitleText
=
self
.
moduleViewData
[
indexPath
.
section
]
.
subTitleText
cell
.
configure
(
title
:
titleText
,
subtitle
:
subTitleText
)
return
cell
}
func
tableView
(
_
tableView
:
UITableView
,
heightForRowAt
indexPath
:
IndexPath
)
->
CGFloat
{
return
74
}
// 实现 UITableViewDelegate 协议方法,设置 header 的高度
func
tableView
(
_
tableView
:
UITableView
,
heightForHeaderInSection
section
:
Int
)
->
CGFloat
{
return
section
==
0
?
0
:
12
}
// 实现 UITableViewDelegate 协议方法,返回 header 视图
func
tableView
(
_
tableView
:
UITableView
,
viewForHeaderInSection
section
:
Int
)
->
UIView
?
{
let
headerView
=
UIView
()
headerView
.
backgroundColor
=
.
clear
return
headerView
}
func
tableView
(
_
tableView
:
UITableView
,
didSelectRowAt
indexPath
:
IndexPath
)
{
// 跳转新页面
if
indexPath
.
section
==
0
{
// 跳转重复联系人页面
let
vc
:
ContactsDupViewController
=
ContactsDupViewController
()
vc
.
dataSourceModel
=
self
.
dataSourceModel
?
.
duplicates
self
.
responderViewController
()?
.
navigationController
?
.
pushViewController
(
vc
,
animated
:
true
)
}
if
indexPath
.
section
==
1
{
// 跳转不完整联系人页面
let
vc
:
ContactIncompleteViewController
=
ContactIncompleteViewController
()
vc
.
dataSourceModel
=
self
.
dataSourceModel
?
.
incompleteContacts
self
.
responderViewController
()?
.
navigationController
?
.
pushViewController
(
vc
,
animated
:
true
)
}
if
indexPath
.
section
==
2
{
// 跳转备份页面
let
vc
:
ContactBackupViewController
=
ContactBackupViewController
()
vc
.
dataSourceModel
=
self
.
dataSourceModel
?
.
backups
vc
.
dataSourceAllModel
=
self
.
dataSourceModel
self
.
responderViewController
()?
.
navigationController
?
.
pushViewController
(
vc
,
animated
:
true
)
}
if
indexPath
.
section
==
3
{
// 跳转所有联系人页面
let
vc
:
ContactAllViewController
=
ContactAllViewController
()
vc
.
dataSourceModel
=
self
.
dataSourceModel
!.
allContacts
self
.
responderViewController
()?
.
navigationController
?
.
pushViewController
(
vc
,
animated
:
true
)
}
}
}
class
CustomContactModuleTableViewCell
:
UITableViewCell
{
// 主标题标签
lazy
var
titleLabel
:
UILabel
=
{
let
label
=
UILabel
()
label
.
font
=
UIFont
.
systemFont
(
ofSize
:
16
,
weight
:
.
bold
)
label
.
textColor
=
UIColor
(
red
:
0.2
,
green
:
0.2
,
blue
:
0.2
,
alpha
:
1
)
return
label
}()
// 副标题标签
lazy
var
subtitleLabel
:
UILabel
=
{
let
label
=
UILabel
()
label
.
font
=
UIFont
.
systemFont
(
ofSize
:
14
,
weight
:
.
regular
)
label
.
textColor
=
UIColor
(
red
:
0.4
,
green
:
0.4
,
blue
:
0.4
,
alpha
:
1
)
return
label
}()
// 箭头图片视图
lazy
var
arrowImageView
:
UIImageView
=
{
let
imageView
=
UIImageView
(
image
:
UIImage
(
named
:
"icon_left_setting_grey"
))
return
imageView
}()
override
init
(
style
:
UITableViewCell
.
CellStyle
,
reuseIdentifier
:
String
?)
{
super
.
init
(
style
:
style
,
reuseIdentifier
:
reuseIdentifier
)
setupUI
()
setupConstraints
()
self
.
layer
.
cornerRadius
=
12
self
.
clipsToBounds
=
true
self
.
selectionStyle
=
.
none
self
.
backgroundColor
=
UIColor
(
red
:
0.95
,
green
:
0.96
,
blue
:
0.99
,
alpha
:
1
)
}
required
init
?(
coder
:
NSCoder
)
{
fatalError
(
"init(coder:) has not been implemented"
)
}
private
func
setupUI
()
{
self
.
addSubview
(
titleLabel
)
self
.
addSubview
(
subtitleLabel
)
self
.
addSubview
(
arrowImageView
)
}
private
func
setupConstraints
()
{
titleLabel
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalToSuperview
()
.
inset
(
16
)
make
.
left
.
equalToSuperview
()
.
offset
(
16
)
make
.
height
.
equalTo
(
22
)
make
.
width
.
equalTo
(
238
)
}
subtitleLabel
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalTo
(
titleLabel
.
snp
.
bottom
)
.
offset
(
0
)
make
.
left
.
equalToSuperview
()
.
offset
(
16
)
make
.
height
.
equalTo
(
20
)
make
.
width
.
equalTo
(
238
)
}
arrowImageView
.
snp
.
makeConstraints
{
make
in
make
.
centerY
.
equalToSuperview
()
make
.
width
.
height
.
equalTo
(
20
)
make
.
right
.
equalToSuperview
()
.
offset
(
-
16
)
}
}
func
configure
(
title
:
String
,
subtitle
:
String
)
{
titleLabel
.
text
=
title
subtitleLabel
.
text
=
subtitle
}
}
PhoneManager/Class/Session/Home/HomeViewController.swift
View file @
fbb3d06c
...
@@ -54,6 +54,16 @@ class HomeViewController:BaseViewController {
...
@@ -54,6 +54,16 @@ class HomeViewController:BaseViewController {
}
}
case
2
:
case
2
:
DispatchQueue
.
main
.
async
{[
weak
self
]
in
guard
let
self
else
{
return
}
let
vc
:
ContactViewController
=
ContactViewController
()
self
.
navigationController
?
.
pushViewController
(
vc
,
animated
:
true
)
}
case
3
:
DispatchQueue
.
main
.
async
{[
weak
self
]
in
DispatchQueue
.
main
.
async
{[
weak
self
]
in
guard
let
self
else
{
return
}
guard
let
self
else
{
return
}
...
@@ -63,6 +73,7 @@ class HomeViewController:BaseViewController {
...
@@ -63,6 +73,7 @@ class HomeViewController:BaseViewController {
self
.
navigationController
?
.
pushViewController
(
vc
,
animated
:
true
)
self
.
navigationController
?
.
pushViewController
(
vc
,
animated
:
true
)
}
}
default
:
default
:
break
break
}
}
...
...
PhoneManager/Class/Session/Home/Model/TabbarImtesData.json
View file @
fbb3d06c
...
@@ -9,6 +9,11 @@
...
@@ -9,6 +9,11 @@
"heightImage"
:
"tabbar_secret_hight"
,
"heightImage"
:
"tabbar_secret_hight"
,
"text"
:
"Secret Space"
,
"text"
:
"Secret Space"
,
},
},
{
"normalImage"
:
"ic_contacts_home_pre"
,
"heightImage"
:
"tabbar_contacts_hight"
,
"text"
:
"Contacts"
,
},
{
{
"normalImage"
:
"ic_cmpress_home_pre"
,
"normalImage"
:
"ic_cmpress_home_pre"
,
"heightImage"
:
"tabbar_cmpress_high"
,
"heightImage"
:
"tabbar_cmpress_high"
,
...
...
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