Commit c19fadbf authored by CZ1004's avatar CZ1004

【新增】联系人主要功能逻辑代码

parent 6e41a98b
...@@ -21,7 +21,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { ...@@ -21,7 +21,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
window = UIWindow(frame: UIScreen.main.bounds) window = UIWindow(frame: UIScreen.main.bounds)
window?.backgroundColor = UIColor.colorWithHex(hexStr: launchColor) window?.backgroundColor = .white
window?.overrideUserInterfaceStyle = .light window?.overrideUserInterfaceStyle = .light
let Ssoryboard = UIStoryboard(name: "LauchVC", bundle: nil) let Ssoryboard = UIStoryboard(name: "LauchVC", bundle: nil)
......
...@@ -227,7 +227,21 @@ extension ContactBackupDetailViewController:UITableViewDelegate,UITableViewDataS ...@@ -227,7 +227,21 @@ extension ContactBackupDetailViewController:UITableViewDelegate,UITableViewDataS
let alertVc = ContactBacRestoreAlertView(frame: self.view.bounds) let alertVc = ContactBacRestoreAlertView(frame: self.view.bounds)
self.view.addSubview(alertVc) self.view.addSubview(alertVc)
alertVc.sureCallBack = { alertVc.sureCallBack = {
ContactManager.performAtomicRestore(self.dataSourceModel) { success, error in
if success {
print("恢复成功!")
DispatchQueue.main.async {
// 再次请求数据 重新刷新页面
let buAlertVc = ContactRestoreSuccessView(frame: self.view.bounds)
cWindow?.addSubview(buAlertVc)
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
buAlertVc.removeFromSuperview()
}
}
} else {
print("失败原因: \(error?.localizedDescription ?? "未知错误")")
}
}
} }
} }
......
...@@ -33,6 +33,7 @@ class ContactBackupViewController : BaseViewController { ...@@ -33,6 +33,7 @@ class ContactBackupViewController : BaseViewController {
// 默认页面 // 默认页面
func setDefaultPage(){ func setDefaultPage(){
self.normalView.removeFromSuperview()
self.view.addSubview(self.emptyView) self.view.addSubview(self.emptyView)
self.emptyView.snp.makeConstraints { make in self.emptyView.snp.makeConstraints { make in
......
...@@ -39,6 +39,8 @@ class ContactIncompleteViewController : BaseViewController { ...@@ -39,6 +39,8 @@ class ContactIncompleteViewController : BaseViewController {
// 默认页面 // 默认页面
func setDefaultPage(){ func setDefaultPage(){
self.normalView.removeFromSuperview()
self.selectAllButton.isHidden = true
self.view.addSubview(self.emptyView) self.view.addSubview(self.emptyView)
self.emptyView.snp.makeConstraints { make in self.emptyView.snp.makeConstraints { make in
...@@ -49,6 +51,7 @@ class ContactIncompleteViewController : BaseViewController { ...@@ -49,6 +51,7 @@ class ContactIncompleteViewController : BaseViewController {
} }
func setNormalPage(){ func setNormalPage(){
self.emptyView.removeFromSuperview() self.emptyView.removeFromSuperview()
self.selectAllButton.isHidden = false
self.view.addSubview(self.normalView) self.view.addSubview(self.normalView)
self.normalView.snp.makeConstraints { make in self.normalView.snp.makeConstraints { make in
...@@ -94,6 +97,9 @@ class ContactIncompleteViewController : BaseViewController { ...@@ -94,6 +97,9 @@ class ContactIncompleteViewController : BaseViewController {
} }
self.normalView.tableView.reloadData() self.normalView.tableView.reloadData()
} }
self.normalView.dataClearCallBack = {
self.setDefaultPage()
}
self.setDefaultPage() self.setDefaultPage()
} }
} }
...@@ -106,7 +112,6 @@ extension ContactIncompleteViewController { ...@@ -106,7 +112,6 @@ extension ContactIncompleteViewController {
self.setNormalPage() self.setNormalPage()
self.normalView.dataSourceModel = data self.normalView.dataSourceModel = data
DispatchQueue.main.async { DispatchQueue.main.async {
self.normalView.sortContacts()
self.normalView.subTitleLabel.text = "\(data.count) Contacts" self.normalView.subTitleLabel.text = "\(data.count) Contacts"
self.normalView.tableView.reloadData() self.normalView.tableView.reloadData()
} }
......
...@@ -41,6 +41,7 @@ class ContactViewController : BaseViewController { ...@@ -41,6 +41,7 @@ class ContactViewController : BaseViewController {
} }
func setDefaultPage(){ func setDefaultPage(){
self.moduleView.removeFromSuperview()
self.view.addSubview(self.emptyView) self.view.addSubview(self.emptyView)
self.emptyView.snp.makeConstraints { make in self.emptyView.snp.makeConstraints { make in
make.top.equalTo(self.navView.snp.bottom).offset(0) make.top.equalTo(self.navView.snp.bottom).offset(0)
......
//
// ContactsDupPreViewController.swift
// PhoneManager
//
// Created by edy on 2025/5/8.
//
import Foundation
class ContactsDupPreViewController : BaseViewController {
var dataSourceModel : [String:[ContactModel]] = [:]
lazy var navView : ContactNavView = {
let view = ContactNavView()
return view
}()
lazy var emptyView:ContactNoDupPreView = {
let view = ContactNoDupPreView()
return view
}()
lazy var normalView : ContactDupPreNormalView = {
let view = ContactDupPreNormalView()
return view
}()
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()
self.normalView.dataChangeCallBack = {[weak self] isClear in
guard let self else {return}
if isClear {
DispatchQueue.main.async {
self.setDefaultPage()
}
}
}
}
// 默认页面
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()
}
}
}
extension ContactsDupPreViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if self.dataSourceModel.count > 0 {
self.setNormalPage()
var finallyData : [[ContactModel]] = []
for (_,value) in self.dataSourceModel {
finallyData.append(value)
}
self.normalView.dataSourceModel = finallyData
DispatchQueue.main.async {
self.normalView.subTitleLabel.text = "\(self.dataSourceModel.count) Contacts"
var count : Int = 0
for item in finallyData {
count += item.count
}
self.normalView.mergeButtonView.mergeButton.setTitle("Merge \(count) Contacts", for: .normal)
self.normalView.tableView.reloadData()
}
}else{
self.setDefaultPage()
}
}
}
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
import Foundation import Foundation
import SnapKit import SnapKit
import Contacts
class ContactsDupViewController : BaseViewController { class ContactsDupViewController : BaseViewController {
var dataSourceModel : [[ContactModel]]? var dataSourceModel : [[ContactModel]]?
...@@ -38,6 +39,7 @@ class ContactsDupViewController : BaseViewController { ...@@ -38,6 +39,7 @@ class ContactsDupViewController : BaseViewController {
// 默认页面 // 默认页面
func setDefaultPage(){ func setDefaultPage(){
self.normalView.removeFromSuperview() self.normalView.removeFromSuperview()
self.selectAllButton.isHidden = true
self.view.addSubview(self.emptyView) self.view.addSubview(self.emptyView)
self.emptyView.snp.makeConstraints { make in self.emptyView.snp.makeConstraints { make in
...@@ -45,20 +47,12 @@ class ContactsDupViewController : BaseViewController { ...@@ -45,20 +47,12 @@ class ContactsDupViewController : BaseViewController {
make.left.right.equalToSuperview() make.left.right.equalToSuperview()
make.bottom.equalToSuperview() make.bottom.equalToSuperview()
} }
self.navView.addSubview(self.selectAllButton)
self.selectAllButton.snp.makeConstraints { make in
make.right.equalTo(-15 * RScreenW())
make.centerY.equalTo(self.navView.backButton.snp.centerY)
widthConstraint = make.width.equalTo(115).constraint
make.height.equalTo(32)
}
} }
func setNormalPage(){ func setNormalPage(){
self.emptyView.removeFromSuperview() self.emptyView.removeFromSuperview()
self.view.addSubview(self.normalView) self.view.addSubview(self.normalView)
self.selectAllButton.isHidden = false
self.normalView.snp.makeConstraints { make in self.normalView.snp.makeConstraints { make in
make.top.equalTo(self.navView.snp.bottom).offset(0) make.top.equalTo(self.navView.snp.bottom).offset(0)
make.left.right.equalToSuperview() make.left.right.equalToSuperview()
...@@ -77,6 +71,14 @@ class ContactsDupViewController : BaseViewController { ...@@ -77,6 +71,14 @@ class ContactsDupViewController : BaseViewController {
make.height.equalTo(statusBarHeight + 44) make.height.equalTo(statusBarHeight + 44)
} }
self.navView.addSubview(self.selectAllButton)
self.selectAllButton.snp.makeConstraints { make in
make.right.equalTo(-15 * RScreenW())
make.centerY.equalTo(self.navView.backButton.snp.centerY)
widthConstraint = make.width.equalTo(115).constraint
make.height.equalTo(32)
}
self.setDefaultPage() self.setDefaultPage()
...@@ -116,16 +118,17 @@ class ContactsDupViewController : BaseViewController { ...@@ -116,16 +118,17 @@ class ContactsDupViewController : BaseViewController {
} }
} }
} }
let dataUpdated = Notification.Name(ContactDupPreNormalView.CONTACT_MERGED)
NotificationCenter.default.addObserver(self, selector: #selector(handleDataUpdated(_:)), name: dataUpdated, object: nil)
} }
} }
extension ContactsDupViewController { extension ContactsDupViewController {
override func viewWillAppear(_ animated: Bool) { override func viewWillAppear(_ animated: Bool) {
// 重新获取下重复项的数据
super.viewWillAppear(animated) super.viewWillAppear(animated)
if let data = self.dataSourceModel { if let data = self.dataSourceModel {
if data.count > 0 { if data.count > 0 {
...@@ -154,5 +157,55 @@ extension ContactsDupViewController { ...@@ -154,5 +157,55 @@ extension ContactsDupViewController {
} }
return totalElementCount return totalElementCount
} }
@objc func handleDataUpdated(_ notification: Notification) {
// 重新获取下重复项的数据
let store = CNContactStore()
let keysToFetch = [
CNContactGivenNameKey as CNKeyDescriptor,
CNContactFamilyNameKey as CNKeyDescriptor,
CNContactPhoneNumbersKey as CNKeyDescriptor
]
do {
let request = CNContactFetchRequest(keysToFetch: keysToFetch)
// 创建数组
var duplicates : [[ContactModel]] = []
var contactsByName: [String: [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 {
if contactsByName[fullName] == nil {
contactsByName[fullName] = [model]
} else {
contactsByName[fullName]?.append(model)
}
}
duplicates = contactsByName.values.filter { $0.count > 1 }
}
DispatchQueue.main.async {
self.dataSourceModel = self.sortDupDataSource(orgData: duplicates)
self.normalView.tableView.reloadData()
}
} catch {
DispatchQueue.main.async {
print("获取联系人信息时发生错误: \(error)")
}
}
}
/// 重复项排序-做一个反序操作,让最新添加的联系人显示在最前面
/// - Parameter orgData: 原始数据
/// - Returns: 排序后的数据
func sortDupDataSource(orgData:[[ContactModel]])->[[ContactModel]]{
return orgData.map { $0.reversed() }
}
} }
//
// CustomContactViewController.swift
// PhoneManager
//
// Created by edy on 2025/5/8.
//
import ContactsUI
// 步骤1: 创建子类继承 CNContactViewController
class CustomContactViewController: CNContactViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupCancelButton()
}
// 自定义取消按钮
private func setupCancelButton() {
navigationItem.leftBarButtonItem = UIBarButtonItem(
title: "Cancel",
style: .plain,
target: self,
action: #selector(dismissEditor))
}
}
extension CustomContactViewController {
@objc private func dismissEditor() {
dismiss(animated: true, completion: nil)
}
// 使用自定义视图控制器
func presentCustomContactEditor(with identifier: String , viewController: UIViewController) {
let contactStore = CNContactStore()
let keys = [CNContactViewController.descriptorForRequiredKeys()]
do {
let contact = try contactStore.unifiedContact(withIdentifier: identifier, keysToFetch: keys)
let mutableContact = contact.mutableCopy() as! CNMutableContact
// 步骤4: 使用自定义子类初始化
let editVC = CustomContactViewController(for: mutableContact)
editVC.contactStore = contactStore
let navController = UINavigationController(rootViewController: editVC)
viewController.present(navController, animated: true)
} catch {
print("获取联系人失败: \(error)")
}
}
}
This diff is collapsed.
...@@ -6,7 +6,10 @@ ...@@ -6,7 +6,10 @@
// //
import Foundation import Foundation
import SnapKit
class ContactAllView : UIView { class ContactAllView : UIView {
private var bottomConstraint: Constraint?
var dataSourceModel : [ContactModel] = [] var dataSourceModel : [ContactModel] = []
...@@ -59,10 +62,6 @@ class ContactAllView : UIView { ...@@ -59,10 +62,6 @@ class ContactAllView : UIView {
lazy var deleteButton : DeleteButtonView = { lazy var deleteButton : DeleteButtonView = {
let deleteButton = DeleteButtonView() let deleteButton = DeleteButtonView()
// 设置删除按钮
deleteButton.layer.cornerRadius = 23
deleteButton.clipsToBounds = true
deleteButton.isHidden = true
return deleteButton return deleteButton
}() }()
...@@ -91,13 +90,12 @@ class ContactAllView : UIView { ...@@ -91,13 +90,12 @@ class ContactAllView : UIView {
make.top.equalTo(self.subTitleLabel.snp.bottom).offset(16 * RScreenH()) make.top.equalTo(self.subTitleLabel.snp.bottom).offset(16 * RScreenH())
make.left.equalToSuperview().offset(15 * RScreenW()) make.left.equalToSuperview().offset(15 * RScreenW())
make.right.equalToSuperview().offset(-15 * RScreenW()) make.right.equalToSuperview().offset(-15 * RScreenW())
make.bottom.equalToSuperview().offset(-102 * RScreenH()) make.bottom.equalToSuperview().offset(-safeHeight)
} }
self.deleteButton.snp.makeConstraints { make in self.deleteButton.snp.makeConstraints { make in
make.top.equalTo(self.tableView.snp.bottom).offset(16 * RScreenH()) make.left.right.equalToSuperview()
make.width.equalTo(345 * RScreenW()) self.bottomConstraint = make.bottom.equalToSuperview().offset(68).constraint
make.height.equalTo(46) make.height.equalTo(68)
make.centerX.equalToSuperview()
} }
// 排序 // 排序
...@@ -125,6 +123,11 @@ extension ContactAllView : UITableViewDataSource,UITableViewDelegate { ...@@ -125,6 +123,11 @@ extension ContactAllView : UITableViewDataSource,UITableViewDelegate {
return sectionedContacts[sectionTitle]?.count ?? 0 return sectionedContacts[sectionTitle]?.count ?? 0
} }
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! CustomContactAllViewTableViewCell
cell.selectContact(cell.selectButton)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomContactAllViewTableViewCell", for: indexPath) as! CustomContactAllViewTableViewCell let cell = tableView.dequeueReusableCell(withIdentifier: "CustomContactAllViewTableViewCell", for: indexPath) as! CustomContactAllViewTableViewCell
let sectionTitle = sectionTitles[indexPath.section] let sectionTitle = sectionTitles[indexPath.section]
...@@ -148,11 +151,18 @@ extension ContactAllView : UITableViewDataSource,UITableViewDelegate { ...@@ -148,11 +151,18 @@ extension ContactAllView : UITableViewDataSource,UITableViewDelegate {
// 判断button是否显示 // 判断button是否显示
if self.selectedContacts.count > 0 { if self.selectedContacts.count > 0 {
// 设置button的title // 设置button的title
self.deleteButton.titleLabel.text = "Delete \(self.selectedContacts.count) Contact" self.deleteButton.deleteButton.setTitle("Delete \(self.selectedContacts.count) Contact", for: .normal)
self.deleteButton.isHidden = false UIView.animate(withDuration: 0.1) {
// 更新约束
self.bottomConstraint?.update(offset: -safeHeight)
self.layoutIfNeeded()
}
}else{ }else{
UIView.animate(withDuration: 0.1) {
self.deleteButton.isHidden = true // 更新约束
self.bottomConstraint?.update(offset: 68)
self.layoutIfNeeded()
}
} }
} }
...@@ -269,8 +279,8 @@ extension ContactAllView : UITableViewDataSource,UITableViewDelegate { ...@@ -269,8 +279,8 @@ extension ContactAllView : UITableViewDataSource,UITableViewDelegate {
// 备份成功 // 备份成功
success() success()
DispatchQueue.main.async { DispatchQueue.main.async {
let buAlertVc = ContactBackUpCompletedAlertView(frame: (self.responderViewController()?.view.bounds)!) let buAlertVc = ContactBackUpCompletedAlertView(frame: (cWindow?.bounds)!)
self.responderViewController()?.view.addSubview(buAlertVc) cWindow?.addSubview(buAlertVc)
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
buAlertVc.removeFromSuperview() buAlertVc.removeFromSuperview()
} }
......
...@@ -76,7 +76,7 @@ class ContactBackUpNormalView : UIView { ...@@ -76,7 +76,7 @@ class ContactBackUpNormalView : UIView {
make.top.equalTo(self.addButon.snp.bottom).offset(16) make.top.equalTo(self.addButon.snp.bottom).offset(16)
make.left.equalToSuperview().offset(15 * RScreenW()) make.left.equalToSuperview().offset(15 * RScreenW())
make.right.equalToSuperview().offset(-15 * RScreenW()) make.right.equalToSuperview().offset(-15 * RScreenW())
make.bottom.equalToSuperview() make.bottom.equalToSuperview().offset(-safeHeight)
} }
} }
} }
...@@ -125,8 +125,8 @@ extension ContactBackUpNormalView : UITableViewDelegate,UITableViewDataSource{ ...@@ -125,8 +125,8 @@ extension ContactBackUpNormalView : UITableViewDelegate,UITableViewDataSource{
} }
DispatchQueue.main.async { DispatchQueue.main.async {
// 弹框提示成功 // 弹框提示成功
let buAlertVc = ContactBackUpDeleteCompletedAlertView(frame: (self.responderViewController()?.view.bounds)!) let buAlertVc = ContactBackUpDeleteCompletedAlertView(frame: (cWindow?.bounds)!)
self.responderViewController()?.view.addSubview(buAlertVc) cWindow?.addSubview(buAlertVc)
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
buAlertVc.removeFromSuperview() buAlertVc.removeFromSuperview()
} }
...@@ -168,8 +168,8 @@ extension ContactBackUpNormalView : UITableViewDelegate,UITableViewDataSource{ ...@@ -168,8 +168,8 @@ extension ContactBackUpNormalView : UITableViewDelegate,UITableViewDataSource{
let vm = BackupViewModel() let vm = BackupViewModel()
vm.backupAllContacts(self.dataSourceAllModel ?? []) { finished, error in vm.backupAllContacts(self.dataSourceAllModel ?? []) { finished, error in
DispatchQueue.main.async { DispatchQueue.main.async {
let buAlertVc = ContactBackUpCompletedAlertView(frame: (self.responderViewController()?.view.bounds)!) let buAlertVc = ContactBackUpCompletedAlertView(frame: (cWindow?.bounds)!)
self.responderViewController()?.view.addSubview(buAlertVc) cWindow?.addSubview(buAlertVc)
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
buAlertVc.removeFromSuperview() buAlertVc.removeFromSuperview()
} }
......
...@@ -72,7 +72,7 @@ class CustomContactAllViewTableViewCell : UITableViewCell { ...@@ -72,7 +72,7 @@ class CustomContactAllViewTableViewCell : UITableViewCell {
} }
extension CustomContactAllViewTableViewCell { extension CustomContactAllViewTableViewCell {
@objc private func selectContact(_ sender: UIButton) { @objc func selectContact(_ sender: UIButton) {
sender.isSelected = !sender.isSelected sender.isSelected = !sender.isSelected
buttonSelectCallBack(model!,sender.isSelected) buttonSelectCallBack(model!,sender.isSelected)
} }
......
//
// CustomContactDupTableViewCell.swift
// PhoneManager
//
// Created by edy on 2025/5/6.
//
import Foundation
class CustomContactDupPreTableViewCell : UITableViewCell {
var indexPath: IndexPath?
var cellSelectCallCack : (IndexPath,Bool)->Void = {index,choose in}
var model : [ContactModel] = [] {
didSet{
DispatchQueue.main.async {
if self.model.count > 0 {
self.nameLabel.text = self.model.first?.name
self.numberLabel.text = self.getPhoneNumberString(contacts: self.model)
}else {
self.nameLabel.text = ""
self.numberLabel.text = ""
}
}
}
}
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 numberLabel : UILabel = {
let label = UILabel()
label.textColor = UIColor(red: 0.4, green: 0.4, blue: 0.4, alpha: 1)
label.font = UIFont.systemFont(ofSize: 14, weight: .regular)
return label
}()
lazy var moreButton : UIButton = {
let button = UIButton(type: .custom)
button.setImage(UIImage(named: "icon_left_setting_grey"), for: .normal)
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.numberLabel)
self.backView.addSubview(self.moreButton)
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.top.equalToSuperview().offset(16)
make.width.equalTo(210)
make.height.equalTo(22)
}
self.numberLabel.snp.makeConstraints { make in
make.left.equalToSuperview().offset(16 * RScreenH())
make.top.equalTo(self.nameLabel.snp.bottom).offset(0)
make.right.equalTo(self.moreButton.snp.left).offset(0)
make.height.equalTo(20)
}
self.moreButton.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 CustomContactDupPreTableViewCell {
func getPhoneNumberString(contacts : [ContactModel]) -> String{
var photoNumbers : [String] = []
for item in contacts {
if let tempNumbers = item.phoneNumber {
photoNumbers = photoNumbers + tempNumbers
}
}
let nonEmptyStrings = photoNumbers.filter {!$0.isEmpty}
if nonEmptyStrings.count <= 0 {
return ""
}
return photoNumbers.joined(separator: " / ")
}
}
...@@ -81,7 +81,7 @@ class CustomContactDupTableViewCell : UITableViewCell { ...@@ -81,7 +81,7 @@ class CustomContactDupTableViewCell : UITableViewCell {
self.numberLabel.snp.makeConstraints { make in self.numberLabel.snp.makeConstraints { make in
make.left.equalToSuperview().offset(16 * RScreenH()) make.left.equalToSuperview().offset(16 * RScreenH())
make.top.equalTo(self.nameLabel.snp.bottom).offset(0) make.top.equalTo(self.nameLabel.snp.bottom).offset(0)
make.width.equalTo(210) make.right.equalTo(self.selectButton.snp.left).offset(0)
make.height.equalTo(20) make.height.equalTo(20)
} }
...@@ -100,7 +100,7 @@ class CustomContactDupTableViewCell : UITableViewCell { ...@@ -100,7 +100,7 @@ class CustomContactDupTableViewCell : UITableViewCell {
} }
extension CustomContactDupTableViewCell { extension CustomContactDupTableViewCell {
@objc private func selectContact(_ sender: UIButton) { @objc func selectContact(_ sender: UIButton) {
sender.isSelected = !sender.isSelected sender.isSelected = !sender.isSelected
if let indexPath = self.indexPath { if let indexPath = self.indexPath {
self.cellSelectCallCack(indexPath,sender.isSelected) self.cellSelectCallCack(indexPath,sender.isSelected)
......
//
// CustomDupHeaderView.swift
// PhoneManager
//
// Created by edy on 2025/5/7.
//
import Foundation
class CustomDupPreHeaderView : UITableViewHeaderFooterView {
var model : [ContactModel] = [] {
didSet{
DispatchQueue.main.async {
self.tiplabel.text = "\(self.model.count) Contacts Merged"
}
}
}
// 当前的section
var currentSection : Int = 0
var headerCallback : ([ContactModel],Int)->Void = {array,currentSection in}
var selectStatus : Bool = false
lazy var tiplabel : UILabel = {
let label = UILabel()
label.text = "\(self.model.count) Contacts Merged"
label.textAlignment = .left
label.font = UIFont.systemFont(ofSize: 16, weight: .medium)
label.textColor = UIColor(red: 0.4, green: 0.4, blue: 0.4, alpha: 1)
return label
}()
lazy var deSelectButton : UIButton = {
let button = UIButton(type: .custom)
button.setImage(UIImage(named: "ic_close_similar"), for: .normal)
button.addTarget(self, action: #selector(removeCurrentData), for: .touchUpInside)
return button
}()
override init(reuseIdentifier: String?) {
super.init(reuseIdentifier: reuseIdentifier)
self.backgroundColor = .clear
self.addSubview(self.tiplabel)
self.tiplabel.snp.makeConstraints { make in
make.left.top.equalToSuperview()
make.width.equalTo(200)
make.height.equalTo(22)
}
self.addSubview(self.deSelectButton)
self.deSelectButton.snp.makeConstraints { make in
make.width.equalTo(20)
make.height.equalTo(20)
make.right.equalToSuperview()
make.centerY.equalTo(self.tiplabel.snp.centerY)
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension CustomDupPreHeaderView {
@objc func removeCurrentData(){
self.headerCallback(self.model,currentSection)
}
}
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
import Foundation import Foundation
class ContactBackUpCompletedAlertView : UIView { class ContactBackUpCompletedAlertView : UIView {
var sureCallBack: ()->Void = {}
// 懒加载背景视图 // 懒加载背景视图
private lazy var backgroundView: UIView = { private lazy var backgroundView: UIView = {
......
//
// ContactRestoreSuccessView.swift
// PhoneManager
//
// Created by edy on 2025/5/8.
//
import Foundation
class ContactRestoreSuccessView : UIView {
// 懒加载背景视图
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 = "Backup restored"
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.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(95)
}
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(20)
}
}
}
...@@ -10,43 +10,40 @@ class DeleteButtonView : UIView { ...@@ -10,43 +10,40 @@ class DeleteButtonView : UIView {
var submitCallBack : (()->Void) = {} var submitCallBack : (()->Void) = {}
lazy var imageView : UIImageView = { lazy var deleteButton : UIButton = {
let imageView = UIImageView() let view = UIButton(type: .custom)
imageView.image = UIImage(named: "ic_delete_duplicates") view.backgroundColor = UIColor(red: 0, green: 0.51, blue: 1, alpha: 1)
return imageView view.setTitleColor(.white, for: .normal)
}() view.clipsToBounds = true
view.layer.cornerRadius = 23
lazy var titleLabel : UILabel = { view.titleLabel?.font = UIFont.systemFont(ofSize: 16, weight: .bold)
let label = UILabel() view.setTitle("See Merge Preview", for: .normal)
label.textAlignment = .left view.setImage(UIImage(named: "ic_hebing"), for: .normal)
label.textColor = UIColor(red: 1, green: 1, blue: 1, alpha: 1)
return label // 设置间距为 8
let spacing: CGFloat = 8
// 获取图片和文字的大小
let imageSize = view.imageView?.image?.size ?? .zero
let titleSize = view.titleLabel?.intrinsicContentSize ?? .zero
// 计算 imageEdgeInsets 和 titleEdgeInsets
view.imageEdgeInsets = UIEdgeInsets(top: 0, left: -spacing / 2, bottom: 0, right: spacing / 2)
view.titleEdgeInsets = UIEdgeInsets(top: 0, left: spacing / 2, bottom: 0, right: -spacing / 2)
view.addTarget(self, action: #selector(deleteButtonAction), for: .touchUpInside)
return view
}() }()
override init(frame: CGRect) { 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)
super.init(frame: frame)
self.backgroundColor = .white
self.addSubview(self.deleteButton)
self.imageView.snp.makeConstraints { make in self.deleteButton.snp.makeConstraints { make in
make.width.height.equalTo(20) make.left.equalToSuperview().offset(15)
make.centerY.equalToSuperview() make.right.equalToSuperview().offset(-15)
make.left.equalToSuperview().offset(94 * RScreenW()) make.height.equalTo(46)
} make.top.equalToSuperview().offset(16)
self.titleLabel.snp.makeConstraints { make in
make.left.equalTo(self.imageView.snp.right).offset(8 * RScreenW())
make.centerY.equalToSuperview()
make.height.equalTo(22)
} }
} }
...@@ -60,7 +57,7 @@ class DeleteButtonView : UIView { ...@@ -60,7 +57,7 @@ class DeleteButtonView : UIView {
extension DeleteButtonView { extension DeleteButtonView {
@objc func submitAction(){ @objc func deleteButtonAction(){
submitCallBack() submitCallBack()
} }
} }
...@@ -6,21 +6,28 @@ ...@@ -6,21 +6,28 @@
// //
import Foundation import Foundation
import SnapKit
class ContactDupNormalView : UIView { class ContactDupNormalView : UIView {
var dataSourceModel : [[ContactModel]] = [] var dataSourceModel : [[ContactModel]] = []
var selectData: [String : [ContactModel]] = [:] var preButtonShowStatus : Bool = false
var selectData: [String : [ContactModel]] = [:] {
didSet {
// 是否更新底部合并预览按钮
showPreMergeButton()
}
}
var dataChangeCallBack:(Bool)->Void = {changed in} var dataChangeCallBack:(Bool)->Void = {changed in}
/// 选择的联系人 private var bottomConstraint: Constraint?
private var selectedContacts: [ContactModel] = []
lazy var titleLabel: UILabel = { lazy var titleLabel: UILabel = {
let label = UILabel() let label = UILabel()
label.text = "All contacts" label.text = "Duplicates"
label.font = UIFont.systemFont(ofSize: 20, weight: .bold) label.font = UIFont.systemFont(ofSize: 20, weight: .bold)
label.textColor = UIColor(red: 0.2, green: 0.2, blue: 0.2, alpha: 1) label.textColor = UIColor(red: 0.2, green: 0.2, blue: 0.2, alpha: 1)
label.textAlignment = .left label.textAlignment = .left
...@@ -50,11 +57,18 @@ class ContactDupNormalView : UIView { ...@@ -50,11 +57,18 @@ class ContactDupNormalView : UIView {
return tableView return tableView
}() }()
lazy var preButtonView : MergePreButtonView = {
let view = MergePreButtonView()
return view
}()
override init(frame: CGRect) { override init(frame: CGRect) {
super.init(frame: frame) super.init(frame: frame)
self.addSubview(self.titleLabel) self.addSubview(self.titleLabel)
self.addSubview(self.subTitleLabel) self.addSubview(self.subTitleLabel)
self.addSubview(self.tableView) self.addSubview(self.tableView)
self.addSubview(self.preButtonView)
self.titleLabel.snp.makeConstraints { make in self.titleLabel.snp.makeConstraints { make in
make.left.equalToSuperview().offset(15 * RScreenW()) make.left.equalToSuperview().offset(15 * RScreenW())
...@@ -74,7 +88,19 @@ class ContactDupNormalView : UIView { ...@@ -74,7 +88,19 @@ class ContactDupNormalView : UIView {
make.top.equalTo(self.subTitleLabel.snp.bottom).offset(16 * RScreenH()) make.top.equalTo(self.subTitleLabel.snp.bottom).offset(16 * RScreenH())
make.left.equalToSuperview().offset(15 * RScreenW()) make.left.equalToSuperview().offset(15 * RScreenW())
make.right.equalToSuperview().offset(-15 * RScreenW()) make.right.equalToSuperview().offset(-15 * RScreenW())
make.bottom.equalToSuperview().offset(-44 * RScreenH()) make.bottom.equalToSuperview().offset(-safeHeight)
}
self.preButtonView.snp.makeConstraints { make in
make.left.right.equalToSuperview()
self.bottomConstraint = make.bottom.equalToSuperview().offset(68).constraint
make.height.equalTo(68)
}
self.preButtonView.mergePreCallBack = {
let vc = ContactsDupPreViewController()
vc.dataSourceModel = self.selectData
self.responderViewController()?.navigationController?.pushViewController(vc, animated: true)
} }
} }
...@@ -155,6 +181,16 @@ extension ContactDupNormalView : UITableViewDelegate,UITableViewDataSource{ ...@@ -155,6 +181,16 @@ extension ContactDupNormalView : UITableViewDelegate,UITableViewDataSource{
return 34 return 34
} }
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// 调起系统弹窗
let cell = tableView.cellForRow(at: indexPath) as! CustomContactDupTableViewCell
if let model = cell.model {
if let vc = self.responderViewController() {
ContactManager.callContactWithIdentifier(model, viewController: vc)
}
}
}
// MARK: 辅助方法 // MARK: 辅助方法
...@@ -215,6 +251,40 @@ extension ContactDupNormalView : UITableViewDelegate,UITableViewDataSource{ ...@@ -215,6 +251,40 @@ extension ContactDupNormalView : UITableViewDelegate,UITableViewDataSource{
} }
return false return false
} }
// 是否显示预览按钮
func showPreMergeButton(){
var show : Bool = false
for(_,value) in self.selectData {
// 判断至少有一组且大于2的开始合并
if value.count >= 2{
show = true
}
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
// 如果有且当前是显示的
if show {
if self.preButtonShowStatus == false {
self.preButtonShowStatus = true
UIView.animate(withDuration: 0.1) {
// 更新约束
self.bottomConstraint?.update(offset: -safeHeight)
self.layoutIfNeeded()
}
}
}else {
if self.preButtonShowStatus == true {
self.preButtonShowStatus = false
UIView.animate(withDuration: 0.1) {
// 更新约束
self.bottomConstraint?.update(offset: 68)
self.layoutIfNeeded()
}
}
}
}
}
} }
//
// ContactDupPreNormalView.swift
// PhoneManager
//
// Created by edy on 2025/5/8.
//
import Foundation
class ContactDupPreNormalView : UIView {
static let CONTACT_MERGED = "contact_merged"
var dataSourceModel : [[ContactModel]] = []
var preButtonShowStatus : Bool = false
// 如果将不想合并的重复联系人删除完了,就显示没有预览可用页面
var dataChangeCallBack : (Bool)->Void = {isClear in}
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 = "\(self.dataSourceModel.count) 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 tableView : UITableView = {
let tableView = UITableView(frame: CGRect(x: 0, y: 0, width: 0, height: 12), style: UITableView.Style.grouped)
tableView.dataSource = self
tableView.delegate = self
tableView.register(CustomContactDupPreTableViewCell.self, forCellReuseIdentifier: "CustomContactDupPreTableViewCell")
tableView.separatorStyle = .none
tableView.backgroundColor = .clear
tableView.showsVerticalScrollIndicator = false
if #available(iOS 15.0, *) {
tableView.sectionHeaderTopPadding = 0
}
return tableView
}()
lazy var mergeButtonView : MergeButtonView = {
let view = MergeButtonView()
return view
}()
override init(frame: CGRect) {
super.init(frame: frame)
self.addSubview(self.titleLabel)
self.addSubview(self.subTitleLabel)
self.addSubview(self.tableView)
self.addSubview(self.mergeButtonView)
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.tableView.snp.makeConstraints { make in
make.top.equalTo(self.subTitleLabel.snp.bottom).offset(16 * RScreenH())
make.left.equalToSuperview().offset(15 * RScreenW())
make.right.equalToSuperview().offset(-15 * RScreenW())
make.bottom.equalToSuperview().offset(-safeHeight - 68)
}
self.mergeButtonView.snp.makeConstraints { make in
make.left.right.equalToSuperview()
make.bottom.equalToSuperview().offset(-safeHeight)
make.height.equalTo(68)
}
self.mergeButtonView.mergeCallBack = {
ContactManager.mergeContacts(groups: self.dataSourceModel) { result in
switch result {
case .success(let newIDs):
print("新联系人ID: \(newIDs)")
DispatchQueue.main.async {
self.removeData()
// 弹框提示成功
let buAlertVc = ContactBackUpDeleteCompletedAlertView(frame: (cWindow?.bounds)!)
cWindow?.addSubview(buAlertVc)
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
buAlertVc.removeFromSuperview()
}
}
break
case .failure(let error):
print("合并失败: \(error.localizedDescription)")
}
}
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
/// 合并成功后移除数据源
func removeData(){
self.dataSourceModel.removeAll()
self.tableView.reloadData()
// 更新下头部数据
self.subTitleLabel.text = "\(self.dataSourceModel.count) Contacts"
self.dataChangeCallBack(true)
// 发起通知
let dataUpdated = Notification.Name(ContactDupPreNormalView.CONTACT_MERGED)
NotificationCenter.default.post(name: dataUpdated, object: nil, userInfo: nil)
}
}
extension ContactDupPreNormalView : UITableViewDelegate,UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return self.dataSourceModel.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// 调起系统弹窗
let cell = tableView.cellForRow(at: indexPath) as! CustomContactDupPreTableViewCell
if let model = cell.model.first {
if let vc = self.responderViewController() {
ContactManager.callContactWithIdentifier(model, viewController: vc)
}
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomContactDupPreTableViewCell", for: indexPath) as! CustomContactDupPreTableViewCell
cell.indexPath = indexPath
cell.model = self.dataSourceModel[indexPath.section]
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 77 + 8 * RScreenH()
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = CustomDupPreHeaderView(frame: CGRect(x: 0 , y: 0, width: self.tableView.width, height: 22))
view.model = self.dataSourceModel[section]
view.currentSection = section
view.headerCallback = { array, currentSection in
self.dataSourceModel.remove(at: currentSection)
DispatchQueue.main.async {
self.tableView.reloadData()
self.subTitleLabel.text = "\(self.dataSourceModel.count) Contacts"
if self.dataSourceModel.count == 0 {
self.dataChangeCallBack(true)
}
}
}
return view
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 34
}
}
//
// ContactNoDupPreView.swift
// PhoneManager
//
// Created by edy on 2025/5/8.
//
import Foundation
class ContactNoDupPreView : 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 Preview Available"
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 back and select duplicate contacts to see a preview"
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")
}
}
//
// MergeButtonView.swift
// PhoneManager
//
// Created by edy on 2025/5/8.
//
import Foundation
import Contacts
class MergeButtonView : UIView {
var mergeCallBack : ()->Void = {}
lazy var mergeButton : UIButton = {
let view = UIButton(type: .custom)
view.backgroundColor = UIColor(red: 0, green: 0.51, blue: 1, alpha: 1)
view.setTitleColor(.white, for: .normal)
view.clipsToBounds = true
view.layer.cornerRadius = 23
view.titleLabel?.font = UIFont.systemFont(ofSize: 16, weight: .bold)
view.setTitle("Merge 0 Contacts", for: .normal)
view.setImage(UIImage(named: "ic_hebing"), for: .normal)
// 设置间距为 8
let spacing: CGFloat = 8
// 获取图片和文字的大小
let imageSize = view.imageView?.image?.size ?? .zero
let titleSize = view.titleLabel?.intrinsicContentSize ?? .zero
// 计算 imageEdgeInsets 和 titleEdgeInsets
view.imageEdgeInsets = UIEdgeInsets(top: 0, left: -spacing / 2, bottom: 0, right: spacing / 2)
view.titleEdgeInsets = UIEdgeInsets(top: 0, left: spacing / 2, bottom: 0, right: -spacing / 2)
view.addTarget(self, action: #selector(merge), for: .touchUpInside)
return view
}()
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = .white
self.addSubview(self.mergeButton)
self.mergeButton.snp.makeConstraints { make in
make.left.equalToSuperview().offset(15)
make.right.equalToSuperview().offset(-15)
make.height.equalTo(46)
make.top.equalToSuperview().offset(16)
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension MergeButtonView {
@objc func merge (){
// 弹出提示框
alertWhenMergeContact()
}
func alertWhenMergeContact() {
// 删除之前弹出是否需要备份
let alertVc = ContactBackupAlertView()
alertVc.frame = (self.responderViewController()?.view.bounds)!
self.responderViewController()?.view.addSubview(alertVc)
alertVc.sureCallBack = {[weak self] isSure in
guard let self else {return}
if isSure {
backupContactsByselect {
// 备份完成后开始合并
self.mergeCallBack()
}
}else{
// 直接合并
self.mergeCallBack()
}
}
}
func backupContactsByselect(success:@escaping()->Void){
// 直接备份所有联系人
let vm = BackupViewModel()
// 获取所有联系人
let store = CNContactStore()
let keysToFetch = [
CNContactGivenNameKey as CNKeyDescriptor,
CNContactFamilyNameKey as CNKeyDescriptor,
CNContactPhoneNumbersKey as CNKeyDescriptor
]
do {
let request = CNContactFetchRequest(keysToFetch: keysToFetch)
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)
allContacts.append(model)
}
vm.backupPartialContacts(allContacts) { finised, error in
if finised {
// 备份成功
success()
DispatchQueue.main.async {
let buAlertVc = ContactBackUpCompletedAlertView(frame: (cWindow?.bounds)!)
cWindow?.addSubview(buAlertVc)
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
buAlertVc.removeFromSuperview()
}
}
}else{
Print("备份失败")
}
}
} catch {
DispatchQueue.main.async {
print("获取联系人信息时发生错误: \(error)")
}
}
}
}
//
// MergePreButtonView.swift
// PhoneManager
//
// Created by edy on 2025/5/8.
//
import Foundation
class MergePreButtonView : UIView {
var mergePreCallBack : ()->Void = {}
lazy var mergePreButton : UIButton = {
let view = UIButton(type: .custom)
view.backgroundColor = UIColor(red: 0, green: 0.51, blue: 1, alpha: 1)
view.setTitleColor(.white, for: .normal)
view.clipsToBounds = true
view.layer.cornerRadius = 23
view.titleLabel?.font = UIFont.systemFont(ofSize: 16, weight: .bold)
view.setTitle("See Merge Preview", for: .normal)
view.setImage(UIImage(named: "ic_hebing"), for: .normal)
// 设置间距为 8
let spacing: CGFloat = 8
// 获取图片和文字的大小
let imageSize = view.imageView?.image?.size ?? .zero
let titleSize = view.titleLabel?.intrinsicContentSize ?? .zero
// 计算 imageEdgeInsets 和 titleEdgeInsets
view.imageEdgeInsets = UIEdgeInsets(top: 0, left: -spacing / 2, bottom: 0, right: spacing / 2)
view.titleEdgeInsets = UIEdgeInsets(top: 0, left: spacing / 2, bottom: 0, right: -spacing / 2)
view.addTarget(self, action: #selector(mergePre), for: .touchUpInside)
return view
}()
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = .white
self.addSubview(self.mergePreButton)
self.mergePreButton.snp.makeConstraints { make in
make.left.equalToSuperview().offset(15)
make.right.equalToSuperview().offset(-15)
make.height.equalTo(46)
make.top.equalToSuperview().offset(16)
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension MergePreButtonView {
@objc func mergePre (){
self.mergePreCallBack()
}
}
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
import Foundation import Foundation
import GoogleMobileAds import GoogleMobileAds
import ContactsUI
class Singleton { class Singleton {
// 使用静态常量来保存单例实例 // 使用静态常量来保存单例实例
......
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