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
56bb9c9b
Commit
56bb9c9b
authored
May 06, 2025
by
CZ1004
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
【优化】优化视频压缩代码,添加重复联系人UI
parent
28ae9c45
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
484 additions
and
145 deletions
+484
-145
img_bj_battery.png
...ssets/Charge/img_bj_battery 1.imageset/img_bj_battery.png
+0
-0
img_bj_battery@2x.png
...ts/Charge/img_bj_battery 1.imageset/img_bj_battery@2x.png
+0
-0
img_bj_battery@3x.png
...ts/Charge/img_bj_battery 1.imageset/img_bj_battery@3x.png
+0
-0
AdvManager.swift
...ager/Class/Session/Advertisement/Manager/AdvManager.swift
+31
-9
CompressViewModel.swift
.../Class/Session/Compress/ViewModel/CompressViewModel.swift
+44
-90
ContactAllViewController.swift
...Session/Contact/Controller/ContactAllViewController.swift
+16
-11
ContactBackupViewController.swift
...sion/Contact/Controller/ContactBackupViewController.swift
+14
-13
ContactIncompleteViewController.swift
.../Contact/Controller/ContactIncompleteViewController.swift
+14
-11
ContactViewController.swift
...ss/Session/Contact/Controller/ContactViewController.swift
+28
-5
ContactsDupViewController.swift
...ession/Contact/Controller/ContactsDupViewController.swift
+49
-0
ContactModuleModel.swift
...ager/Class/Session/Contact/Model/ContactModuleModel.swift
+4
-4
CustomContactDupTableViewCell.swift
...ion/Contact/View/Cell/CustomContactDupTableViewCell.swift
+117
-0
ContactDupNormalView.swift
...Class/Session/Contact/View/Dup/ContactDupNormalView.swift
+151
-0
ContactModuleView.swift
...ass/Session/Contact/View/MenuView/ContactModuleView.swift
+1
-1
HomeViewController.swift
...er/Class/Session/Home/Controller/HomeViewController.swift
+13
-0
TabbarImtesData.json
PhoneManager/Class/Session/Home/Model/TabbarImtesData.json
+1
-0
Info.plist
PhoneManager/Info.plist
+1
-1
No files found.
PhoneManager/Assets.xcassets/Charge/img_bj_battery 1.imageset/img_bj_battery.png
deleted
100644 → 0
View file @
28ae9c45
188 KB
PhoneManager/Assets.xcassets/Charge/img_bj_battery 1.imageset/img_bj_battery@2x.png
deleted
100644 → 0
View file @
28ae9c45
985 KB
PhoneManager/Assets.xcassets/Charge/img_bj_battery 1.imageset/img_bj_battery@3x.png
deleted
100644 → 0
View file @
28ae9c45
This diff is collapsed.
Click to expand it.
PhoneManager/Class/Session/Advertisement/Manager/AdvManager.swift
View file @
56bb9c9b
...
@@ -9,11 +9,22 @@ import Foundation
...
@@ -9,11 +9,22 @@ import Foundation
import
GoogleMobileAds
import
GoogleMobileAds
import
UserMessagingPlatform
import
UserMessagingPlatform
enum
AdvertisementType
{
case
rewardedInterstitialType
case
interstitialType
}
class
AdvManager
:
NSObject
,
FullScreenContentDelegate
{
class
AdvManager
:
NSObject
,
FullScreenContentDelegate
{
// fixme:上线前更改
private
static
let
REWARDED_INTERSTITIALAD_KEY
:
String
=
"ca-app-pub-3480207748580737/4276457203"
// private static let REWARDED_INTERSTITIALAD_KEY : String = "ca-app-pub-3480207748580737/4276457203"
private
static
let
INTERSTITIALAD_KEY
:
String
=
"ca-app-pub-3480207748580737/5836950888"
// private static let INTERSTITIALAD_KEY : String = "ca-app-pub-3480207748580737/5836950888"
// info.plist: ca-app-pub-3480207748580737~4236262472
private
static
let
REWARDED_INTERSTITIALAD_KEY
:
String
=
"ca-app-pub-3940256099942544/6978759866"
private
static
let
INTERSTITIALAD_KEY
:
String
=
"ca-app-pub-3940256099942544/4411468910"
static
let
shared
:
AdvManager
=
AdvManager
()
static
let
shared
:
AdvManager
=
AdvManager
()
...
@@ -26,6 +37,8 @@ class AdvManager : NSObject,FullScreenContentDelegate {
...
@@ -26,6 +37,8 @@ class AdvManager : NSObject,FullScreenContentDelegate {
// 插页广告
// 插页广告
var
interstitial
:
InterstitialAd
?
var
interstitial
:
InterstitialAd
?
var
currentAdvType
:
AdvertisementType
=
.
rewardedInterstitialType
var
currentTimes
:
Int
=
3
var
currentTimes
:
Int
=
3
/// 默认每日免费删除次数
/// 默认每日免费删除次数
...
@@ -137,9 +150,11 @@ class AdvManager : NSObject,FullScreenContentDelegate {
...
@@ -137,9 +150,11 @@ class AdvManager : NSObject,FullScreenContentDelegate {
/// - Parameter completed: 准备完成后回调
/// - Parameter completed: 准备完成后回调
func
showInterstitialAd
(
vc
:
UIViewController
)
{
func
showInterstitialAd
(
vc
:
UIViewController
)
{
guard
let
ad
=
self
.
interstitial
else
{
guard
let
ad
=
self
.
interstitial
else
{
self
.
currentAdvType
=
.
rewardedInterstitialType
self
.
showRewardedInterstitialAd
(
vc
:
vc
)
self
.
showRewardedInterstitialAd
(
vc
:
vc
)
return
return
}
}
self
.
currentAdvType
=
.
interstitialType
ad
.
present
(
from
:
vc
)
ad
.
present
(
from
:
vc
)
}
}
...
@@ -156,12 +171,19 @@ class AdvManager : NSObject,FullScreenContentDelegate {
...
@@ -156,12 +171,19 @@ class AdvManager : NSObject,FullScreenContentDelegate {
func
adDidDismissFullScreenContent
(
_
ad
:
FullScreenPresentingAd
)
{
func
adDidDismissFullScreenContent
(
_
ad
:
FullScreenPresentingAd
)
{
print
(
"Ad did dismiss full screen content."
)
print
(
"Ad did dismiss full screen content."
)
self
.
rewardedInterstitialAd
=
nil
if
self
.
currentAdvType
==
.
interstitialType
{
// 广告结束之后缓存新的
// 如果播放的是插页广告,播放完成应该再缓存一份
Task
{
self
.
interstitial
=
nil
// 同时load两个广告内容
Task
{
await
self
.
loadInterstitial
()
await
self
.
loadInterstitial
()
await
self
.
loadRewardedInterstitialAd
()
}
}
else
{
// 如果播放的是插页激励,则应该同时缓存两个(因为只有在插页广告没有的情况下才会到插页激励广告)
self
.
rewardedInterstitialAd
=
nil
Task
{
await
self
.
loadInterstitial
()
await
self
.
loadRewardedInterstitialAd
()
}
}
}
// 更新值
// 更新值
...
...
PhoneManager/Class/Session/Compress/ViewModel/CompressViewModel.swift
View file @
56bb9c9b
...
@@ -190,14 +190,22 @@ class CompressViewModel{
...
@@ -190,14 +190,22 @@ class CompressViewModel{
Print
(
"---------原始大小:
\(
originalSize
)
"
)
Print
(
"---------原始大小:
\(
originalSize
)
"
)
//
激进
压缩设置
// 压缩设置
let
targetBitrate
:
Float
let
targetBitrate
:
Float
if
originalBitrate
>
0
{
if
originalBitrate
>
0
{
// 强制压缩到原始比特率的quality比例,最低不低于500kbps
// 强制压缩到原始比特率的quality比例,最低不低于500kbps
targetBitrate
=
max
(
originalBitrate
*
quality
,
500_000
)
// 最低500kbps
if
(
originalSize
<=
100000
){
// 当大小已经没有100KB时,按照0.95去压缩
targetBitrate
=
min
(
originalBitrate
*
quality
,
originalBitrate
*
0.95
)
}
else
{
// 最低500kbps
targetBitrate
=
max
(
originalBitrate
*
quality
,
500_000
)
}
}
else
{
}
else
{
// 无法获取原始比特率时的默认值
// 无法获取原始比特率时的默认值
targetBitrate
=
quality
*
1_000_000
// 1Mbps为基准
// 1Mbps为基准
targetBitrate
=
quality
*
1_000_000
}
}
// 创建输出URL
// 创建输出URL
...
@@ -205,19 +213,24 @@ class CompressViewModel{
...
@@ -205,19 +213,24 @@ class CompressViewModel{
.
appendingPathComponent
(
UUID
()
.
uuidString
)
.
appendingPathComponent
(
UUID
()
.
uuidString
)
.
appendingPathExtension
(
"mp4"
)
.
appendingPathExtension
(
"mp4"
)
//
激进
压缩参数
// 压缩参数
let
compressionProperties
:
[
String
:
Any
]
=
[
let
compressionProperties
:
[
String
:
Any
]
=
[
AVVideoAverageBitRateKey
:
targetBitrate
,
AVVideoAverageBitRateKey
:
targetBitrate
,
AVVideoMaxKeyFrameIntervalKey
:
120
,
// 关键帧间隔加大到4秒(30fps)
// 关键帧间隔加大到4秒(30fps)
AVVideoProfileLevelKey
:
AVVideoProfileLevelH264Baseline30
,
// 使用基线配置
AVVideoMaxKeyFrameIntervalKey
:
120
,
AVVideoAllowFrameReorderingKey
:
false
,
// 禁用B帧
// 使用基线配置
AVVideoExpectedSourceFrameRateKey
:
15
// 降低帧率到15fps
AVVideoProfileLevelKey
:
AVVideoProfileLevelH264Baseline30
,
// 禁用B帧
AVVideoAllowFrameReorderingKey
:
false
,
// 降低帧率到15fps
AVVideoExpectedSourceFrameRateKey
:
15
]
]
let
videoSettings
:
[
String
:
Any
]
=
[
let
videoSettings
:
[
String
:
Any
]
=
[
AVVideoCodecKey
:
AVVideoCodecType
.
h264
,
AVVideoCodecKey
:
AVVideoCodecType
.
h264
,
AVVideoWidthKey
:
videoTrack
.
naturalSize
.
width
/
2
,
// 分辨率减半
// 分辨率减半
AVVideoHeightKey
:
videoTrack
.
naturalSize
.
height
/
2
,
AVVideoWidthKey
:
videoTrack
.
naturalSize
.
width
*
2
/
3
,
AVVideoHeightKey
:
videoTrack
.
naturalSize
.
height
*
2
/
3
,
AVVideoScalingModeKey
:
AVVideoScalingModeResizeAspect
,
AVVideoScalingModeKey
:
AVVideoScalingModeResizeAspect
,
AVVideoCompressionPropertiesKey
:
compressionProperties
AVVideoCompressionPropertiesKey
:
compressionProperties
]
]
...
@@ -225,9 +238,12 @@ class CompressViewModel{
...
@@ -225,9 +238,12 @@ class CompressViewModel{
// 音频设置也进行压缩
// 音频设置也进行压缩
let
audioSettings
:
[
String
:
Any
]
=
[
let
audioSettings
:
[
String
:
Any
]
=
[
AVFormatIDKey
:
kAudioFormatMPEG4AAC
,
AVFormatIDKey
:
kAudioFormatMPEG4AAC
,
AVNumberOfChannelsKey
:
1
,
// 单声道
// 单声道
AVSampleRateKey
:
22050
,
// 降低采样率
AVNumberOfChannelsKey
:
1
,
AVEncoderBitRateKey
:
64_000
// 64kbps音频比特率
// 降低采样率
AVSampleRateKey
:
22050
,
// 64kbps音频比特率
AVEncoderBitRateKey
:
64_000
]
]
// 创建导出会话
// 创建导出会话
...
@@ -257,7 +273,7 @@ class CompressViewModel{
...
@@ -257,7 +273,7 @@ class CompressViewModel{
let
compressedSize
=
attributes
[
.
size
]
as?
NSNumber
{
let
compressedSize
=
attributes
[
.
size
]
as?
NSNumber
{
if
compressedSize
.
doubleValue
>=
originalSize
{
if
compressedSize
.
doubleValue
>=
originalSize
{
// 如果压缩后
仍然
大于等于原始大小,使用更激进的设置重新压缩
// 如果压缩后大于等于原始大小,使用更激进的设置重新压缩
try
?
FileManager
.
default
.
removeItem
(
at
:
outputURL
)
try
?
FileManager
.
default
.
removeItem
(
at
:
outputURL
)
self
.
recompressWithMoreAggressiveSettings
(
avAsset
:
avAsset
,
originalSize
:
originalSize
,
index
:
index
)
{
url
,
error
in
self
.
recompressWithMoreAggressiveSettings
(
avAsset
:
avAsset
,
originalSize
:
originalSize
,
index
:
index
)
{
url
,
error
in
outputURLs
[
index
]
=
url
outputURLs
[
index
]
=
url
...
@@ -288,74 +304,6 @@ class CompressViewModel{
...
@@ -288,74 +304,6 @@ class CompressViewModel{
}
}
}
}
private
static
func
videoComposition
(
for
asset
:
AVAsset
,
quality
:
Float
)
->
AVVideoComposition
?
{
guard
let
videoTrack
=
asset
.
tracks
(
withMediaType
:
.
video
)
.
first
else
{
return
nil
}
// 1. 获取原始视频的比特率作为参考
let
originalBitrate
=
videoTrack
.
estimatedDataRate
let
targetBitrate
:
Float
// 2. 根据质量参数和原始比特率计算目标比特率
if
originalBitrate
>
0
{
// 确保压缩后的比特率不超过原始比特率的quality比例
// 例如quality=0.7表示压缩到原始比特率的70%
// 最多压缩到95%,避免质量损失太小
targetBitrate
=
min
(
originalBitrate
*
quality
,
originalBitrate
*
0.95
)
}
else
{
// 无法获取原始比特率时的默认值
targetBitrate
=
quality
*
5_000_000
// 5Mbps为基准
}
// 3. 设置更高效的关键帧间隔(从默认的10秒改为30秒)
let
videoCompressionProperties
:
[
String
:
Any
]
=
[
AVVideoAverageBitRateKey
:
targetBitrate
,
// 关键帧间隔(帧数),30fps时约为3秒
AVVideoMaxKeyFrameIntervalKey
:
90
,
AVVideoProfileLevelKey
:
AVVideoProfileLevelH264HighAutoLevel
,
// 禁用B帧可减小文件但可能降低质量
AVVideoAllowFrameReorderingKey
:
false
]
// 4. 保持原始分辨率
let
naturalSize
=
videoTrack
.
naturalSize
let
videoSettings
:
[
String
:
Any
]
=
[
AVVideoCodecKey
:
AVVideoCodecType
.
h264
,
AVVideoWidthKey
:
naturalSize
.
width
,
AVVideoHeightKey
:
naturalSize
.
height
,
AVVideoScalingModeKey
:
AVVideoScalingModeResizeAspect
,
AVVideoCompressionPropertiesKey
:
videoCompressionProperties
]
let
composition
=
AVMutableVideoComposition
()
composition
.
renderSize
=
naturalSize
composition
.
frameDuration
=
CMTime
(
value
:
1
,
timescale
:
30
)
let
instruction
=
AVMutableVideoCompositionInstruction
()
instruction
.
timeRange
=
CMTimeRange
(
start
:
.
zero
,
duration
:
asset
.
duration
)
let
layerInstruction
=
AVMutableVideoCompositionLayerInstruction
(
assetTrack
:
videoTrack
)
instruction
.
layerInstructions
=
[
layerInstruction
]
composition
.
instructions
=
[
instruction
]
return
composition
}
private
static
func
presetName
(
for
quality
:
Float
)
->
String
{
switch
quality
{
case
0.8
...
1.0
:
return
AVAssetExportPresetHighestQuality
case
0.6
..<
0.8
:
return
AVAssetExportPreset1280x720
case
0.4
..<
0.6
:
return
AVAssetExportPreset960x540
case
0.2
..<
0.4
:
return
AVAssetExportPreset640x480
default
:
return
AVAssetExportPresetLowQuality
}
}
...
@@ -473,17 +421,20 @@ class CompressViewModel{
...
@@ -473,17 +421,20 @@ class CompressViewModel{
// 更激进的设置
// 更激进的设置
let
compressionProperties
:
[
String
:
Any
]
=
[
let
compressionProperties
:
[
String
:
Any
]
=
[
AVVideoAverageBitRateKey
:
250_000
,
// 固定250kbps
// 固定250kbps
AVVideoMaxKeyFrameIntervalKey
:
240
,
// 关键帧间隔8秒
AVVideoAverageBitRateKey
:
250_000
,
// 关键帧间隔8秒
AVVideoMaxKeyFrameIntervalKey
:
240
,
AVVideoProfileLevelKey
:
AVVideoProfileLevelH264Baseline30
,
AVVideoProfileLevelKey
:
AVVideoProfileLevelH264Baseline30
,
AVVideoAllowFrameReorderingKey
:
false
,
AVVideoAllowFrameReorderingKey
:
false
,
AVVideoExpectedSourceFrameRateKey
:
10
// 帧率降到10fps
// 帧率降到10fps
AVVideoExpectedSourceFrameRateKey
:
10
]
]
let
videoSettings
:
[
String
:
Any
]
=
[
let
videoSettings
:
[
String
:
Any
]
=
[
AVVideoCodecKey
:
AVVideoCodecType
.
h264
,
AVVideoCodecKey
:
AVVideoCodecType
.
h264
,
AVVideoWidthKey
:
videoTrack
.
naturalSize
.
width
/
4
,
// 分辨率降到1/4
AVVideoWidthKey
:
videoTrack
.
naturalSize
.
width
/
2
,
AVVideoHeightKey
:
videoTrack
.
naturalSize
.
height
/
4
,
AVVideoHeightKey
:
videoTrack
.
naturalSize
.
height
/
2
,
AVVideoScalingModeKey
:
AVVideoScalingModeResizeAspect
,
AVVideoScalingModeKey
:
AVVideoScalingModeResizeAspect
,
AVVideoCompressionPropertiesKey
:
compressionProperties
AVVideoCompressionPropertiesKey
:
compressionProperties
]
]
...
@@ -491,8 +442,10 @@ class CompressViewModel{
...
@@ -491,8 +442,10 @@ class CompressViewModel{
let
audioSettings
:
[
String
:
Any
]
=
[
let
audioSettings
:
[
String
:
Any
]
=
[
AVFormatIDKey
:
kAudioFormatMPEG4AAC
,
AVFormatIDKey
:
kAudioFormatMPEG4AAC
,
AVNumberOfChannelsKey
:
1
,
AVNumberOfChannelsKey
:
1
,
AVSampleRateKey
:
16000
,
// 16kHz采样率
// 16kHz采样率
AVEncoderBitRateKey
:
32_000
// 32kbps音频比特率
AVSampleRateKey
:
16000
,
// 32kbps音频比特率
AVEncoderBitRateKey
:
32_000
]
]
guard
let
exportSession
=
AVAssetExportSession
(
asset
:
avAsset
,
presetName
:
AVAssetExportPresetLowQuality
)
else
{
guard
let
exportSession
=
AVAssetExportSession
(
asset
:
avAsset
,
presetName
:
AVAssetExportPresetLowQuality
)
else
{
...
@@ -541,7 +494,8 @@ class CompressViewModel{
...
@@ -541,7 +494,8 @@ class CompressViewModel{
let
audioMix
=
AVMutableAudioMix
()
let
audioMix
=
AVMutableAudioMix
()
let
audioInputParams
=
AVMutableAudioMixInputParameters
(
track
:
audioTrack
)
let
audioInputParams
=
AVMutableAudioMixInputParameters
(
track
:
audioTrack
)
audioInputParams
.
audioTimePitchAlgorithm
=
.
timeDomain
// 保持音频处理简单
// 保持音频处理简单
audioInputParams
.
audioTimePitchAlgorithm
=
.
timeDomain
audioMix
.
inputParameters
=
[
audioInputParams
]
audioMix
.
inputParameters
=
[
audioInputParams
]
return
audioMix
return
audioMix
...
...
PhoneManager/Class/Session/Contact/Controller/ContactAllViewController.swift
View file @
56bb9c9b
...
@@ -10,7 +10,7 @@ import Foundation
...
@@ -10,7 +10,7 @@ import Foundation
class
ContactAllViewController
:
BaseViewController
{
class
ContactAllViewController
:
BaseViewController
{
var
dataSourceModel
:
[
ContactModel
]
=
[]
var
dataSourceModel
:
[
ContactModel
]
?
lazy
var
navView
:
ContactNavView
=
{
lazy
var
navView
:
ContactNavView
=
{
let
view
=
ContactNavView
()
let
view
=
ContactNavView
()
...
@@ -71,18 +71,23 @@ extension ContactAllViewController {
...
@@ -71,18 +71,23 @@ extension ContactAllViewController {
override
func
viewWillAppear
(
_
animated
:
Bool
)
{
override
func
viewWillAppear
(
_
animated
:
Bool
)
{
super
.
viewWillAppear
(
animated
)
super
.
viewWillAppear
(
animated
)
if
self
.
dataSourceModel
.
count
>
0
{
if
let
data
=
self
.
dataSourceModel
{
self
.
setNormalPage
()
if
data
.
count
>
0
{
self
.
normalView
.
dataSourceModel
=
self
.
dataSourceModel
self
.
setNormalPage
()
DispatchQueue
.
main
.
async
{
self
.
normalView
.
dataSourceModel
=
data
self
.
normalView
.
subTitleLabel
.
text
=
"
\(
self
.
dataSourceModel
.
count
)
Contacts"
DispatchQueue
.
main
.
async
{
self
.
normalView
.
sortContacts
()
self
.
normalView
.
subTitleLabel
.
text
=
"
\(
data
.
count
)
Contacts"
self
.
normalView
.
tableView
.
reloadData
()
self
.
normalView
.
sortContacts
()
self
.
normalView
.
setupCustomIndexView
()
self
.
normalView
.
tableView
.
reloadData
()
self
.
normalView
.
setupCustomIndexView
()
}
}
else
{
self
.
setDefaultPage
()
}
}
}
else
{
}
else
{
self
.
setDefaultPage
()
self
.
setDefaultPage
()
}
}
}
}
}
}
PhoneManager/Class/Session/Contact/Controller/ContactBackupViewController.swift
View file @
56bb9c9b
...
@@ -73,22 +73,23 @@ class ContactBackupViewController : BaseViewController {
...
@@ -73,22 +73,23 @@ class ContactBackupViewController : BaseViewController {
let
vm
=
BackupViewModel
()
let
vm
=
BackupViewModel
()
// 备份之前先看看是否有可用的联系人
// 备份之前先看看是否有可用的联系人
if
let
data
=
self
.
dataSourceAllModel
{
vm
.
backupAllContacts
(
data
.
allContacts
)
{
finished
,
error
in
vm
.
backupAllContacts
(
self
.
dataSourceAllModel
!.
allContacts
)
{
finished
,
error
in
if
let
error
=
error
{
if
let
error
=
error
{
Print
(
"添加失败,
\(
error
.
localizedDescription
)
"
)
Print
(
"添加失败,
\(
error
.
localizedDescription
)
"
)
}
}
DispatchQueue
.
main
.
async
{
DispatchQueue
.
main
.
async
{
// 再次请求数据 重新刷新页面
// 再次请求数据 重新刷新页面
let
buAlertVc
=
ContactBackUpCompletedAlertView
(
frame
:
self
.
view
.
bounds
)
let
buAlertVc
=
ContactBackUpCompletedAlertView
(
frame
:
self
.
view
.
bounds
)
self
.
view
.
addSubview
(
buAlertVc
)
self
.
view
.
addSubview
(
buAlertVc
)
DispatchQueue
.
main
.
asyncAfter
(
deadline
:
.
now
()
+
1
)
{
DispatchQueue
.
main
.
asyncAfter
(
deadline
:
.
now
()
+
1
)
{
buAlertVc
.
removeFromSuperview
()
buAlertVc
.
removeFromSuperview
()
self
.
updateCurrentPageData
()
self
.
updateCurrentPageData
()
}
}
}
}
}
}
}
}
}
}
}
}
}
...
...
PhoneManager/Class/Session/Contact/Controller/ContactIncompleteViewController.swift
View file @
56bb9c9b
...
@@ -12,7 +12,7 @@ class ContactIncompleteViewController : BaseViewController {
...
@@ -12,7 +12,7 @@ class ContactIncompleteViewController : BaseViewController {
private
var
widthConstraint
:
Constraint
?
private
var
widthConstraint
:
Constraint
?
var
dataSourceModel
:
[
ContactModel
]
=
[]
var
dataSourceModel
:
[
ContactModel
]
?
lazy
var
navView
:
ContactNavView
=
{
lazy
var
navView
:
ContactNavView
=
{
let
view
=
ContactNavView
()
let
view
=
ContactNavView
()
...
@@ -101,17 +101,20 @@ class ContactIncompleteViewController : BaseViewController {
...
@@ -101,17 +101,20 @@ class ContactIncompleteViewController : BaseViewController {
extension
ContactIncompleteViewController
{
extension
ContactIncompleteViewController
{
override
func
viewWillAppear
(
_
animated
:
Bool
)
{
override
func
viewWillAppear
(
_
animated
:
Bool
)
{
super
.
viewWillAppear
(
animated
)
super
.
viewWillAppear
(
animated
)
if
let
data
=
self
.
dataSourceModel
{
if
self
.
dataSourceModel
.
count
>
0
{
if
data
.
count
>
0
{
self
.
setNormalPage
()
self
.
setNormalPage
()
self
.
normalView
.
dataSourceModel
=
self
.
dataSourceModel
self
.
normalView
.
dataSourceModel
=
data
DispatchQueue
.
main
.
async
{
DispatchQueue
.
main
.
async
{
self
.
normalView
.
sortContacts
()
self
.
normalView
.
sortContacts
()
self
.
normalView
.
subTitleLabel
.
text
=
"
\(
self
.
dataSourceModel
.
count
)
Contacts"
self
.
normalView
.
subTitleLabel
.
text
=
"
\(
data
.
count
)
Contacts"
self
.
normalView
.
tableView
.
reloadData
()
self
.
normalView
.
tableView
.
reloadData
()
}
}
else
{
self
.
setDefaultPage
()
}
}
}
else
{
}
else
{
self
.
setDefaultPage
()
self
.
setDefaultPage
()
}
}
}
}
...
...
PhoneManager/Class/Session/Contact/Controller/ContactViewController.swift
View file @
56bb9c9b
...
@@ -112,18 +112,33 @@ extension ContactViewController{
...
@@ -112,18 +112,33 @@ extension ContactViewController{
// 创建数组
// 创建数组
var
incompleteContacts
:
[
ContactModel
]
=
[]
var
incompleteContacts
:
[
ContactModel
]
=
[]
var
allContacts
:
[
ContactModel
]
=
[]
var
allContacts
:
[
ContactModel
]
=
[]
var
duplicates
:
[[
ContactModel
]]
=
[]
var
contactsByName
:
[
String
:
[
ContactModel
]]
=
[:]
try
store
.
enumerateContacts
(
with
:
request
)
{
contact
,
stop
in
try
store
.
enumerateContacts
(
with
:
request
)
{
contact
,
stop
in
let
givenName
=
contact
.
givenName
let
givenName
=
contact
.
givenName
let
familyName
=
contact
.
familyName
let
familyName
=
contact
.
familyName
let
fullName
=
"
\(
familyName
)
\(
givenName
)
"
let
fullName
=
"
\(
familyName
)\(
givenName
)
"
let
phoneNumbers
=
contact
.
phoneNumbers
.
map
{
$0
.
value
.
stringValue
}
let
phoneNumbers
=
contact
.
phoneNumbers
.
map
{
$0
.
value
.
stringValue
}
let
model
=
ContactModel
.
init
(
name
:
fullName
,
phoneNumber
:
phoneNumbers
,
identifier
:
contact
.
identifier
)
let
model
=
ContactModel
.
init
(
name
:
fullName
,
phoneNumber
:
phoneNumbers
,
identifier
:
contact
.
identifier
)
if
fullName
.
isEmpty
||
phoneNumbers
.
count
<=
0
{
if
fullName
.
isEmpty
||
phoneNumbers
.
count
<=
0
{
incompleteContacts
.
append
(
model
)
incompleteContacts
.
append
(
model
)
}
}
allContacts
.
append
(
model
)
allContacts
.
append
(
model
)
self
.
dataSourceModel
=
ContactModuleModel
.
init
(
duplicates
:
[],
incompleteContacts
:
incompleteContacts
,
backups
:
[],
allContacts
:
allContacts
)
if
!
fullName
.
isEmpty
{
if
contactsByName
[
fullName
]
==
nil
{
contactsByName
[
fullName
]
=
[
model
]
}
else
{
contactsByName
[
fullName
]?
.
append
(
model
)
}
}
duplicates
=
contactsByName
.
values
.
filter
{
$0
.
count
>
1
}
}
}
self
.
dataSourceModel
=
ContactModuleModel
.
init
(
duplicates
:
sortDupDataSource
(
orgData
:
duplicates
),
incompleteContacts
:
incompleteContacts
,
backups
:
[],
allContacts
:
allContacts
)
DispatchQueue
.
main
.
async
{
DispatchQueue
.
main
.
async
{
self
.
updateModuleData
()
self
.
updateModuleData
()
self
.
moduleView
.
tableView
.
reloadData
()
self
.
moduleView
.
tableView
.
reloadData
()
...
@@ -148,13 +163,13 @@ extension ContactViewController{
...
@@ -148,13 +163,13 @@ extension ContactViewController{
self
.
moduleView
.
tableView
.
reloadData
()
self
.
moduleView
.
tableView
.
reloadData
()
}
}
}
}
// fixme:获取重复数据
}
}
// MARK: 辅助方法
/// 获取联系人权限
/// - Parameter completion: 回调
func
requestContactsPermission
(
completion
:
@escaping
(
Bool
)
->
Void
)
{
func
requestContactsPermission
(
completion
:
@escaping
(
Bool
)
->
Void
)
{
let
store
=
CNContactStore
()
let
store
=
CNContactStore
()
switch
CNContactStore
.
authorizationStatus
(
for
:
.
contacts
)
{
switch
CNContactStore
.
authorizationStatus
(
for
:
.
contacts
)
{
...
@@ -180,4 +195,12 @@ extension ContactViewController{
...
@@ -180,4 +195,12 @@ extension ContactViewController{
}
}
}
}
/// 重复项排序-做一个反序操作,让最新添加的联系人显示在最前面
/// - Parameter orgData: 原始数据
/// - Returns: 排序后的数据
func
sortDupDataSource
(
orgData
:[[
ContactModel
]])
->
[[
ContactModel
]]{
return
orgData
.
map
{
$0
.
reversed
()
}
}
}
}
PhoneManager/Class/Session/Contact/Controller/ContactsDupViewController.swift
View file @
56bb9c9b
...
@@ -19,10 +19,15 @@ class ContactsDupViewController : BaseViewController {
...
@@ -19,10 +19,15 @@ class ContactsDupViewController : BaseViewController {
let
view
=
ContactNoDupView
()
let
view
=
ContactNoDupView
()
return
view
return
view
}()
}()
lazy
var
normalView
:
ContactDupNormalView
=
{
let
view
=
ContactDupNormalView
()
return
view
}()
// 默认页面
// 默认页面
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
...
@@ -32,6 +37,17 @@ class ContactsDupViewController : BaseViewController {
...
@@ -32,6 +37,17 @@ class ContactsDupViewController : BaseViewController {
}
}
}
}
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
()
{
override
func
viewDidLoad
()
{
super
.
viewDidLoad
()
super
.
viewDidLoad
()
...
@@ -49,3 +65,36 @@ class ContactsDupViewController : BaseViewController {
...
@@ -49,3 +65,36 @@ class ContactsDupViewController : BaseViewController {
}
}
extension
ContactsDupViewController
{
override
func
viewWillAppear
(
_
animated
:
Bool
)
{
super
.
viewWillAppear
(
animated
)
if
let
data
=
self
.
dataSourceModel
{
if
data
.
count
>
0
{
self
.
setNormalPage
()
self
.
normalView
.
dataSourceModel
=
data
DispatchQueue
.
main
.
async
{
self
.
normalView
.
subTitleLabel
.
text
=
"
\(
self
.
getCountFromDataSource
(
data
:
data
)
)
Contacts"
self
.
normalView
.
tableView
.
reloadData
()
}
}
else
{
self
.
setDefaultPage
()
}
}
else
{
self
.
setDefaultPage
()
}
}
func
getCountFromDataSource
(
data
:[[
ContactModel
]])
->
Int
{
var
totalElementCount
=
0
for
subArray
in
data
{
totalElementCount
+=
subArray
.
count
}
return
totalElementCount
}
}
PhoneManager/Class/Session/Contact/Model/ContactModuleModel.swift
View file @
56bb9c9b
...
@@ -40,13 +40,13 @@ extension ContactModel {
...
@@ -40,13 +40,13 @@ extension ContactModel {
struct
ContactModuleModel
{
struct
ContactModuleModel
{
var
duplicates
:
[[
ContactModel
]]
var
duplicates
:
[[
ContactModel
]]
=
[]
var
incompleteContacts
:
[
ContactModel
]
var
incompleteContacts
:
[
ContactModel
]
=
[]
var
backups
:
[
BackupInfoModel
]
var
backups
:
[
BackupInfoModel
]
=
[]
var
allContacts
:
[
ContactModel
]
var
allContacts
:
[
ContactModel
]
=
[]
init
(
duplicates
:
[[
ContactModel
]],
incompleteContacts
:
[
ContactModel
],
backups
:
[
BackupInfoModel
],
allContacts
:
[
ContactModel
])
{
init
(
duplicates
:
[[
ContactModel
]],
incompleteContacts
:
[
ContactModel
],
backups
:
[
BackupInfoModel
],
allContacts
:
[
ContactModel
])
{
self
.
duplicates
=
duplicates
self
.
duplicates
=
duplicates
...
...
PhoneManager/Class/Session/Contact/View/Cell/CustomContactDupTableViewCell.swift
0 → 100644
View file @
56bb9c9b
//
// CustomContactDupTableViewCell.swift
// PhoneManager
//
// Created by edy on 2025/5/6.
//
import
Foundation
class
CustomContactDupTableViewCell
:
UITableViewCell
{
var
model
:
ContactModel
?{
didSet
{
self
.
nameLabel
.
text
=
model
?
.
name
if
let
numbers
=
model
?
.
phoneNumber
{
self
.
numberLabel
.
text
=
getPhoneNumberString
(
photoNumbers
:
numbers
)
}
else
{
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
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
.
numberLabel
)
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
.
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
.
width
.
equalTo
(
210
)
make
.
height
.
equalTo
(
20
)
}
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
CustomContactDupTableViewCell
{
@objc
private
func
selectContact
(
_
sender
:
UIButton
)
{
sender
.
isSelected
=
!
sender
.
isSelected
// buttonSelectCallBack(model!,sender.isSelected)
}
func
getPhoneNumberString
(
photoNumbers
:
[
String
])
->
String
{
var
tempNumbers
=
photoNumbers
let
nonEmptyStrings
=
tempNumbers
.
filter
{
!
$0
.
isEmpty
}
if
nonEmptyStrings
.
count
<=
0
{
return
""
}
return
photoNumbers
.
joined
(
separator
:
" / "
)
}
}
PhoneManager/Class/Session/Contact/View/Dup/ContactDupNormalView.swift
0 → 100644
View file @
56bb9c9b
//
// ContactDupNormalView.swift
// PhoneManager
//
// Created by edy on 2025/5/6.
//
import
Foundation
class
ContactDupNormalView
:
UIView
{
var
dataSourceModel
:
[[
ContactModel
]]
=
[]
var
selectData
:
[
Int
:
[
ContactModel
]]
=
[:]
/// 选择的联系人
private
var
selectedContacts
:
[
ContactModel
]
=
[]
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
=
"
\(
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
(
CustomContactDupTableViewCell
.
self
,
forCellReuseIdentifier
:
"CustomContactDupTableViewCell"
)
tableView
.
separatorStyle
=
.
none
tableView
.
backgroundColor
=
.
clear
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
.
subTitleLabel
)
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
.
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
(
-
44
*
RScreenH
())
}
}
required
init
?(
coder
:
NSCoder
)
{
fatalError
(
"init(coder:) has not been implemented"
)
}
}
extension
ContactDupNormalView
:
UITableViewDelegate
,
UITableViewDataSource
{
func
numberOfSections
(
in
tableView
:
UITableView
)
->
Int
{
return
self
.
dataSourceModel
.
count
}
func
tableView
(
_
tableView
:
UITableView
,
numberOfRowsInSection
section
:
Int
)
->
Int
{
return
self
.
dataSourceModel
[
section
]
.
count
}
func
tableView
(
_
tableView
:
UITableView
,
cellForRowAt
indexPath
:
IndexPath
)
->
UITableViewCell
{
let
cell
=
tableView
.
dequeueReusableCell
(
withIdentifier
:
"CustomContactDupTableViewCell"
,
for
:
indexPath
)
as!
CustomContactDupTableViewCell
cell
.
model
=
self
.
dataSourceModel
[
indexPath
.
section
][
indexPath
.
row
]
return
cell
}
func
tableView
(
_
tableView
:
UITableView
,
heightForRowAt
indexPath
:
IndexPath
)
->
CGFloat
{
return
77
+
8
*
RScreenH
()
}
func
tableView
(
_
tableView
:
UITableView
,
viewForHeaderInSection
section
:
Int
)
->
UIView
?
{
let
view
=
UIView
(
frame
:
CGRect
(
x
:
0
,
y
:
0
,
width
:
self
.
tableView
.
width
,
height
:
22
))
view
.
backgroundColor
=
.
clear
let
label
=
UILabel
(
frame
:
CGRect
(
x
:
0
,
y
:
0
,
width
:
200
,
height
:
22
))
label
.
text
=
"
\(
self
.
dataSourceModel
[
section
]
.
count
)
Duplicate Contacts"
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
)
view
.
addSubview
(
label
)
let
selectLabel
=
UILabel
(
frame
:
CGRect
(
x
:
0
,
y
:
0
,
width
:
100
,
height
:
22
))
selectLabel
.
center
=
CGPointMake
(
self
.
tableView
.
width
-
50
,
label
.
centerY
)
selectLabel
.
textAlignment
=
.
right
selectLabel
.
textColor
=
UIColor
(
red
:
0
,
green
:
0.51
,
blue
:
1
,
alpha
:
1
)
selectLabel
.
text
=
"Select All"
let
tap
=
UITapGestureRecognizer
()
tap
.
addTarget
(
self
,
action
:
#selector(
cellSelectTap
)
)
selectLabel
.
isUserInteractionEnabled
=
true
selectLabel
.
addGestureRecognizer
(
tap
)
view
.
addSubview
(
selectLabel
)
return
view
}
func
tableView
(
_
tableView
:
UITableView
,
heightForHeaderInSection
section
:
Int
)
->
CGFloat
{
return
34
}
// MARK: 响应方法
@objc
func
cellSelectTap
(){
}
// MARK: 辅助方法
}
PhoneManager/Class/Session/Contact/View/MenuView/ContactModuleView.swift
View file @
56bb9c9b
...
@@ -123,7 +123,7 @@ extension ContactModuleView:UITableViewDataSource, UITableViewDelegate {
...
@@ -123,7 +123,7 @@ extension ContactModuleView:UITableViewDataSource, UITableViewDelegate {
if
indexPath
.
section
==
1
{
if
indexPath
.
section
==
1
{
// 跳转不完整联系人页面
// 跳转不完整联系人页面
let
vc
:
ContactIncompleteViewController
=
ContactIncompleteViewController
()
let
vc
:
ContactIncompleteViewController
=
ContactIncompleteViewController
()
vc
.
dataSourceModel
=
self
.
dataSourceModel
!
.
incompleteContacts
vc
.
dataSourceModel
=
self
.
dataSourceModel
?
.
incompleteContacts
self
.
responderViewController
()?
.
navigationController
?
.
pushViewController
(
vc
,
animated
:
true
)
self
.
responderViewController
()?
.
navigationController
?
.
pushViewController
(
vc
,
animated
:
true
)
}
}
if
indexPath
.
section
==
2
{
if
indexPath
.
section
==
2
{
...
...
PhoneManager/Class/Session/Home/Controller/HomeViewController.swift
View file @
56bb9c9b
...
@@ -53,6 +53,19 @@ class HomeViewController:BaseViewController {
...
@@ -53,6 +53,19 @@ 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
)
}
break
case
3
:
DispatchQueue
.
main
.
async
{[
weak
self
]
in
guard
let
self
else
{
return
}
}
break
case
4
:
DispatchQueue
.
main
.
async
{[
weak
self
]
in
DispatchQueue
.
main
.
async
{[
weak
self
]
in
guard
let
self
else
{
return
}
guard
let
self
else
{
return
}
let
vc
:
CompressController
=
CompressController
()
let
vc
:
CompressController
=
CompressController
()
...
...
PhoneManager/Class/Session/Home/Model/TabbarImtesData.json
View file @
56bb9c9b
...
@@ -14,6 +14,7 @@
...
@@ -14,6 +14,7 @@
"heightImage"
:
"tabbar_contacts_hight"
,
"heightImage"
:
"tabbar_contacts_hight"
,
"text"
:
"Contacts"
,
"text"
:
"Contacts"
,
},
},
{
"normalImage"
:
"ic_email_home_pre"
,
"normalImage"
:
"ic_email_home_pre"
,
"heightImage"
:
"tabbar_email_hight"
,
"heightImage"
:
"tabbar_email_hight"
,
"text"
:
"Email Cleaner"
,
"text"
:
"Email Cleaner"
,
...
...
PhoneManager/Info.plist
View file @
56bb9c9b
...
@@ -26,7 +26,7 @@
...
@@ -26,7 +26,7 @@
<
fa
ls
e
/
>
<
fa
ls
e
/
>
<
/
d
i
c
t
>
<
/
d
i
c
t
>
<
k
e
y
>
GADApplicationIdentifier
<
/k
e
y
>
<
k
e
y
>
GADApplicationIdentifier
<
/k
e
y
>
<
string
>
ca-app-pub-3
480207748580737
~
4236262472
<
/string
>
<
string
>
ca-app-pub-3
940256099942544
~
1458002511
<
/string
>
<
k
e
y
>
SKAdNetworkItems
<
/k
e
y
>
<
k
e
y
>
SKAdNetworkItems
<
/k
e
y
>
<
a
rr
a
y
>
<
a
rr
a
y
>
<
d
i
c
t
>
<
d
i
c
t
>
...
...
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