Commit 32a0013f authored by shenyong's avatar shenyong

权限页面

parent 59bbb91d
...@@ -106,6 +106,12 @@ class CompressController : BaseViewController { ...@@ -106,6 +106,12 @@ class CompressController : BaseViewController {
/// 获取当前页面数据 /// 获取当前页面数据
func getViewData(){ func getViewData(){
if PhotoAndVideoMananger.mananger.permissionStatus == .denied{
loadPermissView(CGRect(x: 0, y: 200, width: ScreenW, height: 450))
return
}
self.resourceData.removeAll() self.resourceData.removeAll()
let datas = Singleton.shared.resourceModel let datas = Singleton.shared.resourceModel
if datas.count > 0 { if datas.count > 0 {
......
...@@ -137,7 +137,7 @@ class HomeInfoViewController:BaseViewController { ...@@ -137,7 +137,7 @@ class HomeInfoViewController:BaseViewController {
// 没有订阅 // 没有订阅
let view : AdvTipDeleteView = AdvTipDeleteView(frame: self.view.bounds) let view : AdvTipDeleteView = AdvTipDeleteView(frame: self.view.bounds)
view.dataSource = array as! [AssetModel] view.dataSource = array
// 获取当前免费次数 // 获取当前免费次数
let freeCount = AdvManager.shared.defaultFreeTimes let freeCount = AdvManager.shared.defaultFreeTimes
...@@ -152,7 +152,7 @@ class HomeInfoViewController:BaseViewController { ...@@ -152,7 +152,7 @@ class HomeInfoViewController:BaseViewController {
}else { }else {
// 获取次数对应的删除照片数量 // 获取次数对应的删除照片数量
var freeDeleteCount = AdvManager.shared.advDeleteResouceDic[freeCount]! var freeDeleteCount = AdvManager.shared.advDeleteResouceDic[freeCount]!
let tempArray = array as! [AssetModel] let tempArray = array
if freeCount > 1 { if freeCount > 1 {
// 如果是前两次,可以免费删除5张照片 // 如果是前两次,可以免费删除5张照片
if tempArray.count > freeDeleteCount { if tempArray.count > freeDeleteCount {
...@@ -166,7 +166,7 @@ class HomeInfoViewController:BaseViewController { ...@@ -166,7 +166,7 @@ class HomeInfoViewController:BaseViewController {
}else { }else {
// 如果小于直接删除 // 如果小于直接删除
HomePayViewController.show { HomePayViewController.show {
deleteOp(imgs: array as! [AssetModel],isAfterAdv: false) deleteOp(imgs: array,isAfterAdv: false)
} }
} }
...@@ -247,6 +247,7 @@ class HomeInfoViewController:BaseViewController { ...@@ -247,6 +247,7 @@ class HomeInfoViewController:BaseViewController {
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.font = UIFont.systemFont(ofSize: 16, weight: .bold) label.font = UIFont.systemFont(ofSize: 16, weight: .bold)
label.textAlignment = .center label.textAlignment = .center
label.isHidden = true
return label return label
}() }()
...@@ -367,20 +368,25 @@ class HomeInfoViewController:BaseViewController { ...@@ -367,20 +368,25 @@ class HomeInfoViewController:BaseViewController {
//设置空白页 //设置空白页
func setDefaultPage(){ func setDefaultPage(){
DispatchQueue.main.async { DispatchQueue.main.async {
if self.ids?.count == 0 { if PhotoAndVideoMananger.mananger.permissionStatus == .denied{
if self.type == .SimilarVideos{ self.loadPermissView()
self.defaultImageView.image = UIImage(named: "img_vedio_defpage")
}else {
self.defaultImageView.image = UIImage(named: "img_photo__home_defpage")
}
self.defaultImageView.isHidden = false
self.defaultTipLabel.isHidden = false
self.seletedAllBtn.isHidden = true
}else{ }else{
self.defaultImageView.isHidden = true if self.ids?.count == 0 {
self.defaultTipLabel.isHidden = true if self.type == .SimilarVideos{
self.seletedAllBtn.isHidden = false self.defaultImageView.image = UIImage(named: "img_vedio_defpage")
}else {
self.defaultImageView.image = UIImage(named: "img_photo__home_defpage")
}
self.defaultImageView.isHidden = false
self.defaultTipLabel.isHidden = false
self.seletedAllBtn.isHidden = true
}else{
self.defaultImageView.isHidden = true
self.defaultTipLabel.isHidden = true
self.seletedAllBtn.isHidden = false
}
} }
} }
} }
...@@ -400,3 +406,14 @@ class HomeInfoViewController:BaseViewController { ...@@ -400,3 +406,14 @@ class HomeInfoViewController:BaseViewController {
} }
} }
extension UIViewController{
func loadPermissView(_ frame:CGRect = CGRect(x: 0, y: 100+kSafeAreaInsets.top, width: ScreenW, height: 450)){
let permissionView = Bundle.main.loadNibNamed("PMPermissionView", owner: nil)?.last as! PMPermissionView
permissionView.frame = frame
self.view.addSubview(permissionView)
}
}
...@@ -185,19 +185,24 @@ class HomePhotosDetailViewController : BaseViewController { ...@@ -185,19 +185,24 @@ class HomePhotosDetailViewController : BaseViewController {
//设置空白页 //设置空白页
func setDefaultPage(){ func setDefaultPage(){
DispatchQueue.main.async { DispatchQueue.main.async {
if self.resourceData.count == 0 { if PhotoAndVideoMananger.mananger.permissionStatus == .denied{
self.defaultImageView.isHidden = false self.loadPermissView()
self.defaultTipLabel.isHidden = false
self.currentHeaderView?.btnView.isHidden = true
self.videoDetailNavView?.seletedAllBtn.isHidden = true
self.deleteButton.isHidden = true
}else{ }else{
self.defaultImageView.isHidden = true if self.resourceData.count == 0 {
self.defaultTipLabel.isHidden = true self.defaultImageView.isHidden = false
self.currentHeaderView?.btnView.isHidden = false self.defaultTipLabel.isHidden = false
self.videoDetailNavView?.seletedAllBtn.isHidden = false self.currentHeaderView?.btnView.isHidden = true
self.deleteButton.isHidden = false self.videoDetailNavView?.seletedAllBtn.isHidden = true
self.deleteButton.isHidden = true
}else{
self.defaultImageView.isHidden = true
self.defaultTipLabel.isHidden = true
self.currentHeaderView?.btnView.isHidden = false
self.videoDetailNavView?.seletedAllBtn.isHidden = false
self.deleteButton.isHidden = false
}
} }
} }
} }
......
...@@ -518,18 +518,22 @@ extension HomeVideoDetailController:WaterfallMutiSectionDelegate,UICollectionVie ...@@ -518,18 +518,22 @@ extension HomeVideoDetailController:WaterfallMutiSectionDelegate,UICollectionVie
func setDefaultPage(){ func setDefaultPage(){
DispatchQueue.main.async { DispatchQueue.main.async {
if self.resourceData.count == 0 { if PhotoAndVideoMananger.mananger.permissionStatus == .denied{
self.defaultImageView.isHidden = false self.loadPermissView()
self.defaultTipLabel.isHidden = false
self.currentHeaderView?.btnView.isHidden = true
self.videoDetailNavView?.seletedAllBtn.isHidden = true
self.deleteButton.isHidden = true
}else{ }else{
self.defaultImageView.isHidden = true if self.resourceData.count == 0 {
self.defaultTipLabel.isHidden = true self.defaultImageView.isHidden = false
self.currentHeaderView?.btnView.isHidden = false self.defaultTipLabel.isHidden = false
self.videoDetailNavView?.seletedAllBtn.isHidden = false self.currentHeaderView?.btnView.isHidden = true
self.deleteButton.isHidden = false self.videoDetailNavView?.seletedAllBtn.isHidden = true
self.deleteButton.isHidden = true
}else{
self.defaultImageView.isHidden = true
self.defaultTipLabel.isHidden = true
self.currentHeaderView?.btnView.isHidden = false
self.videoDetailNavView?.seletedAllBtn.isHidden = false
self.deleteButton.isHidden = false
}
} }
} }
} }
......
...@@ -281,6 +281,7 @@ class HomeViewController:BaseViewController { ...@@ -281,6 +281,7 @@ class HomeViewController:BaseViewController {
Singleton.shared.startCountdown {} Singleton.shared.startCountdown {}
if !isShowCharge { if !isShowCharge {
NotificationManager().configNotifications()
return return
} }
......
...@@ -19,7 +19,7 @@ class HomeInfoView :UIView{ ...@@ -19,7 +19,7 @@ class HomeInfoView :UIView{
var callBack:callBack<Any> = {text in} var callBack:callBack<Any> = {text in}
var deleteCallBack:callBack<Any> = {array in } var deleteCallBack:callBack<[AssetModel]> = {array in }
lazy var tableView:UITableView = { lazy var tableView:UITableView = {
......
...@@ -25,5 +25,4 @@ class PMPermissionView: UIView { ...@@ -25,5 +25,4 @@ class PMPermissionView: UIView {
} }
} }
} }
} }
...@@ -11,28 +11,29 @@ ...@@ -11,28 +11,29 @@
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/> <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="EwM-B0-fXo" customClass="PMPermissionView" customModule="PhoneManager" customModuleProvider="target"> <view contentMode="scaleToFill" id="EwM-B0-fXo" customClass="PMPermissionView" customModule="PhoneManager" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="529" height="489"/> <rect key="frame" x="0.0" y="0.0" width="543" height="449"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews> <subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_queshengtu" translatesAutoresizingMaskIntoConstraints="NO" id="qhV-IF-vsx"> <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_queshengtu" translatesAutoresizingMaskIntoConstraints="NO" id="qhV-IF-vsx">
<rect key="frame" x="170" y="100" width="189" height="189"/> <rect key="frame" x="177" y="100" width="189" height="189"/>
</imageView> </imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Access permission is required to start scan" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ci8-h6-fiE"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Access permission is required to start scan" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ci8-h6-fiE">
<rect key="frame" x="22" y="297" width="485" height="20"/> <rect key="frame" x="22" y="297" width="499" height="20"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="16"/> <fontDescription key="fontDescription" type="boldSystem" pointSize="16"/>
<color key="textColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="textColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="e8v-Xy-wvP"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Phone Manager We need access to all the photos in your photo library" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="e8v-Xy-wvP">
<rect key="frame" x="24" y="320" width="480" height="38.333333333333314"/> <rect key="frame" x="109" y="320" width="325" height="38.333333333333314"/>
<string key="text">Phone Manager We need access to all the photos <constraints>
in your photo library</string> <constraint firstAttribute="width" constant="325" id="7Q3-fW-f7G"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="16"/> </constraints>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="fRi-wi-J8I"> <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="fRi-wi-J8I">
<rect key="frame" x="170" y="371.33333333333331" width="189" height="46"/> <rect key="frame" x="177" y="371.33333333333331" width="189" height="46"/>
<color key="backgroundColor" red="0.0" green="0.50980392159999999" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="backgroundColor" red="0.0" green="0.50980392159999999" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints> <constraints>
<constraint firstAttribute="height" constant="46" id="2ml-bk-VZ7"/> <constraint firstAttribute="height" constant="46" id="2ml-bk-VZ7"/>
...@@ -57,16 +58,15 @@ in your photo library</string> ...@@ -57,16 +58,15 @@ in your photo library</string>
<constraint firstItem="fRi-wi-J8I" firstAttribute="centerX" secondItem="qhV-IF-vsx" secondAttribute="centerX" id="06a-VZ-yHW"/> <constraint firstItem="fRi-wi-J8I" firstAttribute="centerX" secondItem="qhV-IF-vsx" secondAttribute="centerX" id="06a-VZ-yHW"/>
<constraint firstItem="ci8-h6-fiE" firstAttribute="leading" secondItem="Z86-W8-437" secondAttribute="leading" constant="22" id="2pS-Hl-sgb"/> <constraint firstItem="ci8-h6-fiE" firstAttribute="leading" secondItem="Z86-W8-437" secondAttribute="leading" constant="22" id="2pS-Hl-sgb"/>
<constraint firstItem="ci8-h6-fiE" firstAttribute="centerX" secondItem="qhV-IF-vsx" secondAttribute="centerX" id="Fv3-iO-5BI"/> <constraint firstItem="ci8-h6-fiE" firstAttribute="centerX" secondItem="qhV-IF-vsx" secondAttribute="centerX" id="Fv3-iO-5BI"/>
<constraint firstItem="e8v-Xy-wvP" firstAttribute="leading" secondItem="Z86-W8-437" secondAttribute="leading" constant="24" id="Ygj-Ix-aYR"/> <constraint firstItem="e8v-Xy-wvP" firstAttribute="centerX" secondItem="ci8-h6-fiE" secondAttribute="centerX" id="OZD-Bq-U2s"/>
<constraint firstItem="qhV-IF-vsx" firstAttribute="top" secondItem="EwM-B0-fXo" secondAttribute="top" constant="100" id="fx5-wC-f0q"/> <constraint firstItem="qhV-IF-vsx" firstAttribute="top" secondItem="EwM-B0-fXo" secondAttribute="top" constant="100" id="fx5-wC-f0q"/>
<constraint firstItem="fRi-wi-J8I" firstAttribute="top" secondItem="e8v-Xy-wvP" secondAttribute="bottom" constant="13" id="jys-rP-uUI"/> <constraint firstItem="fRi-wi-J8I" firstAttribute="top" secondItem="e8v-Xy-wvP" secondAttribute="bottom" constant="13" id="jys-rP-uUI"/>
<constraint firstItem="Z86-W8-437" firstAttribute="trailing" secondItem="e8v-Xy-wvP" secondAttribute="trailing" constant="25" id="p6c-uL-oEh"/>
<constraint firstItem="e8v-Xy-wvP" firstAttribute="top" secondItem="ci8-h6-fiE" secondAttribute="bottom" constant="3" id="tgi-kq-3Ap"/> <constraint firstItem="e8v-Xy-wvP" firstAttribute="top" secondItem="ci8-h6-fiE" secondAttribute="bottom" constant="3" id="tgi-kq-3Ap"/>
<constraint firstItem="ci8-h6-fiE" firstAttribute="top" secondItem="qhV-IF-vsx" secondAttribute="bottom" constant="8" id="uKW-kw-KCJ"/> <constraint firstItem="ci8-h6-fiE" firstAttribute="top" secondItem="qhV-IF-vsx" secondAttribute="bottom" constant="8" id="uKW-kw-KCJ"/>
<constraint firstItem="Z86-W8-437" firstAttribute="trailing" secondItem="ci8-h6-fiE" secondAttribute="trailing" constant="22" id="wMs-cZ-eGL"/> <constraint firstItem="Z86-W8-437" firstAttribute="trailing" secondItem="ci8-h6-fiE" secondAttribute="trailing" constant="22" id="wMs-cZ-eGL"/>
</constraints> </constraints>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/> <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<point key="canvasLocation" x="284.73282442748092" y="-315.14084507042253"/> <point key="canvasLocation" x="295.41984732824426" y="-329.22535211267609"/>
</view> </view>
</objects> </objects>
<resources> <resources>
......
...@@ -58,7 +58,7 @@ ...@@ -58,7 +58,7 @@
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="XPg-Ph-1k0"> <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="XPg-Ph-1k0">
<rect key="frame" x="15" y="876" width="410" height="46"/> <rect key="frame" x="15" y="870" width="410" height="46"/>
<color key="backgroundColor" red="0.0" green="0.50980392156862742" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="backgroundColor" red="0.0" green="0.50980392156862742" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints> <constraints>
<constraint firstAttribute="height" constant="46" id="DDB-jE-Azu"/> <constraint firstAttribute="height" constant="46" id="DDB-jE-Azu"/>
...@@ -82,7 +82,7 @@ ...@@ -82,7 +82,7 @@
<constraint firstAttribute="trailing" secondItem="OOD-68-wMD" secondAttribute="trailing" constant="25" id="Vcx-gz-lAI"/> <constraint firstAttribute="trailing" secondItem="OOD-68-wMD" secondAttribute="trailing" constant="25" id="Vcx-gz-lAI"/>
<constraint firstItem="XMa-dY-JFG" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="40" id="a0g-kE-ugQ"/> <constraint firstItem="XMa-dY-JFG" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="40" id="a0g-kE-ugQ"/>
<constraint firstItem="LIQ-mA-CKi" firstAttribute="leading" secondItem="5sP-3G-R5V" secondAttribute="leading" id="cqt-w5-eff"/> <constraint firstItem="LIQ-mA-CKi" firstAttribute="leading" secondItem="5sP-3G-R5V" secondAttribute="leading" id="cqt-w5-eff"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" secondItem="XPg-Ph-1k0" secondAttribute="bottom" id="dX6-cv-Gto" customClass="ScreenHeightRatioConstraint" customModule="PhoneManager" customModuleProvider="target"/> <constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" secondItem="XPg-Ph-1k0" secondAttribute="bottom" constant="6" id="dX6-cv-Gto" customClass="ScreenHeightRatioConstraint" customModule="PhoneManager" customModuleProvider="target"/>
<constraint firstItem="dRr-c6-YoB" firstAttribute="top" secondItem="5sP-3G-R5V" secondAttribute="bottom" constant="20" id="eD3-DG-qkC" customClass="ScreenHeightRatioConstraint" customModule="PhoneManager" customModuleProvider="target"/> <constraint firstItem="dRr-c6-YoB" firstAttribute="top" secondItem="5sP-3G-R5V" secondAttribute="bottom" constant="20" id="eD3-DG-qkC" customClass="ScreenHeightRatioConstraint" customModule="PhoneManager" customModuleProvider="target"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="5sP-3G-R5V" secondAttribute="trailing" constant="53" id="h2C-hf-maH"/> <constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="5sP-3G-R5V" secondAttribute="trailing" constant="53" id="h2C-hf-maH"/>
<constraint firstItem="OOD-68-wMD" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="25" id="jJ3-Yj-u0w"/> <constraint firstItem="OOD-68-wMD" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="25" id="jJ3-Yj-u0w"/>
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
</constraints> </constraints>
</imageView> </imageView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ybT-3z-Wb2"> <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ybT-3z-Wb2">
<rect key="frame" x="15" y="852" width="400" height="46"/> <rect key="frame" x="15" y="846" width="400" height="46"/>
<color key="backgroundColor" red="0.0" green="0.50980392159999999" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="backgroundColor" red="0.0" green="0.50980392159999999" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints> <constraints>
<constraint firstAttribute="height" constant="46" id="4Qc-vw-6p8"/> <constraint firstAttribute="height" constant="46" id="4Qc-vw-6p8"/>
...@@ -62,7 +62,7 @@ ...@@ -62,7 +62,7 @@
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="VkR-UI-FBK" secondAttribute="trailing" constant="25" id="4JU-rc-hns"/> <constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="VkR-UI-FBK" secondAttribute="trailing" constant="25" id="4JU-rc-hns"/>
<constraint firstItem="ybT-3z-Wb2" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="15" id="IIW-NA-SQU"/> <constraint firstItem="ybT-3z-Wb2" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="15" id="IIW-NA-SQU"/>
<constraint firstItem="QGK-yy-jOF" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="Kee-LL-a9m"/> <constraint firstItem="QGK-yy-jOF" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="Kee-LL-a9m"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" secondItem="ybT-3z-Wb2" secondAttribute="bottom" id="NWj-ld-9UY"/> <constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" secondItem="ybT-3z-Wb2" secondAttribute="bottom" constant="6" id="NWj-ld-9UY"/>
<constraint firstItem="VkR-UI-FBK" firstAttribute="top" secondItem="h8I-lL-ELV" secondAttribute="bottom" constant="18" id="aYz-ey-Yc7"/> <constraint firstItem="VkR-UI-FBK" firstAttribute="top" secondItem="h8I-lL-ELV" secondAttribute="bottom" constant="18" id="aYz-ey-Yc7"/>
<constraint firstItem="QGK-yy-jOF" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" constant="46" id="cHD-Cc-XiT"/> <constraint firstItem="QGK-yy-jOF" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" constant="46" id="cHD-Cc-XiT"/>
<constraint firstItem="h8I-lL-ELV" firstAttribute="top" secondItem="QGK-yy-jOF" secondAttribute="bottom" constant="55" id="dDM-Pu-5g1"/> <constraint firstItem="h8I-lL-ELV" firstAttribute="top" secondItem="QGK-yy-jOF" secondAttribute="bottom" constant="55" id="dDM-Pu-5g1"/>
......
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="KHL-A7-P8d"> <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="KHL-A7-P8d">
<rect key="frame" x="15" y="772" width="363" height="46"/> <rect key="frame" x="15" y="766" width="363" height="46"/>
<color key="backgroundColor" red="0.0" green="0.50980392159999999" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="backgroundColor" red="0.0" green="0.50980392159999999" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints> <constraints>
<constraint firstAttribute="height" constant="46" id="bCa-jh-IT1"/> <constraint firstAttribute="height" constant="46" id="bCa-jh-IT1"/>
...@@ -61,7 +61,7 @@ ...@@ -61,7 +61,7 @@
<constraint firstAttribute="trailing" secondItem="KHL-A7-P8d" secondAttribute="trailing" constant="15" id="MaN-MT-FnY"/> <constraint firstAttribute="trailing" secondItem="KHL-A7-P8d" secondAttribute="trailing" constant="15" id="MaN-MT-FnY"/>
<constraint firstItem="dcU-ld-SUp" firstAttribute="top" secondItem="OpM-5k-AoO" secondAttribute="bottom" constant="80" id="Okf-QC-Jrn" customClass="ScreenHeightRatioConstraint" customModule="PhoneManager" customModuleProvider="target"/> <constraint firstItem="dcU-ld-SUp" firstAttribute="top" secondItem="OpM-5k-AoO" secondAttribute="bottom" constant="80" id="Okf-QC-Jrn" customClass="ScreenHeightRatioConstraint" customModule="PhoneManager" customModuleProvider="target"/>
<constraint firstItem="KHL-A7-P8d" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="15" id="Rl4-Mh-CiF"/> <constraint firstItem="KHL-A7-P8d" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="15" id="Rl4-Mh-CiF"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" secondItem="KHL-A7-P8d" secondAttribute="bottom" id="SCz-tZ-pgH"/> <constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" secondItem="KHL-A7-P8d" secondAttribute="bottom" constant="6" id="SCz-tZ-pgH"/>
<constraint firstItem="dcU-ld-SUp" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="USR-RC-nO5"/> <constraint firstItem="dcU-ld-SUp" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="USR-RC-nO5"/>
<constraint firstItem="LeZ-aM-wDE" firstAttribute="top" secondItem="dcU-ld-SUp" secondAttribute="bottom" constant="18" id="Zga-Sv-DYE" customClass="ScreenHeightRatioConstraint" customModule="PhoneManager" customModuleProvider="target"/> <constraint firstItem="LeZ-aM-wDE" firstAttribute="top" secondItem="dcU-ld-SUp" secondAttribute="bottom" constant="18" id="Zga-Sv-DYE" customClass="ScreenHeightRatioConstraint" customModule="PhoneManager" customModuleProvider="target"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="LeZ-aM-wDE" secondAttribute="trailing" constant="25" id="lAh-or-e83"/> <constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="LeZ-aM-wDE" secondAttribute="trailing" constant="25" id="lAh-or-e83"/>
......
...@@ -10,17 +10,17 @@ class NotificationManager { ...@@ -10,17 +10,17 @@ class NotificationManager {
func configNotifications(){ func configNotifications(){
if let secondlaunch = UserDefaults.standard.value(forKey: "notifications_is_secondlaunch") as? Bool{ // if let secondlaunch = UserDefaults.standard.value(forKey: "notifications_is_secondlaunch") as? Bool{
if secondlaunch{ // if secondlaunch{
Print("二次启动,获取通知权限") // Print("二次启动,获取通知权限")
scheduleLocalNotifications() // scheduleLocalNotifications()
} // }
}else{ // }else{
UserDefaults.standard.setValue(true, forKey: "notifications_is_secondlaunch") // UserDefaults.standard.setValue(true, forKey: "notifications_is_secondlaunch")
UserDefaults.standard.synchronize() // UserDefaults.standard.synchronize()
Print("启动第一次,记录下") // Print("启动第一次,记录下")
} // }
scheduleLocalNotifications()
} }
// 调度本地通知 // 调度本地通知
......
...@@ -55,6 +55,8 @@ class PhotoAndVideoMananger { ...@@ -55,6 +55,8 @@ class PhotoAndVideoMananger {
var ids:[String] = [] var ids:[String] = []
var permissionStatus:PHAuthorizationStatus = .notDetermined
// 定义 // 定义
private let hashDistance = 100 private let hashDistance = 100
...@@ -91,10 +93,12 @@ class PhotoAndVideoMananger { ...@@ -91,10 +93,12 @@ class PhotoAndVideoMananger {
class func getPrivacy(suc:@escaping callBack<Any> = {text in}) { class func getPrivacy(suc:@escaping callBack<Any> = {text in}) {
PHPhotoLibrary.requestAuthorization { status in PHPhotoLibrary.requestAuthorization { status in
PhotoAndVideoMananger.mananger.permissionStatus = status
switch status { switch status {
case .authorized: case .authorized:
// 用户授权访问照片库,可以继续操作 // 用户授权访问照片库,可以继续操作
Print("用户授权访问照片库,可以继续操作") Print("用户授权访问照片库,可以继续操作")
suc(PrivacyType.authorized) suc(PrivacyType.authorized)
case .denied: case .denied:
Print("用户拒绝访问或者权限受限") Print("用户拒绝访问或者权限受限")
......
//
// PhotoSimilarOptimizer.swift
// PhotoSimilar
//
// Created by edy on 2024/1/24.
//
import Foundation
import Photos
import CoreImage
import UIKit
class PhotoSimilarOptimizer {
static let shared = PhotoSimilarOptimizer()
private init() {}
// MARK: - 配置参数
private let timeWindowInSeconds: TimeInterval = 600 // 10分钟时间窗口
private let fileSizeThreshold: Double = 0.3 // 文件大小相差阈值(30%)
private let resolutionThreshold: Double = 0.2 // 分辨率相差阈值(20%)
private let hashDistanceThreshold: Int = 20 // pHash汉明距离阈值
// MARK: - 缓存
private var hashCache: [String: String] = [:] // 图片hash缓存
private let cacheQueue = DispatchQueue(label: "com.photoSimilar.cache")
// MARK: - 主要处理流程
func findSimilarAssets(in assets: [PHAsset],
progressHandler: (([PHAsset]) -> Void)?,
completionHandler: (([[PHAsset]]) -> Void)?) {
// 1. 按时间窗口预分组
let timeGroups = groupAssetsByTimeWindow(assets)
// 2. 创建并发处理队列
let processingQueue = OperationQueue()
processingQueue.maxConcurrentOperationCount = 4
let dispatchGroup = DispatchGroup()
var finalGroups: [[PHAsset]] = []
let resultQueue = DispatchQueue(label: "com.photoSimilar.result")
// 3. 处理每个时间窗口
for timeGroup in timeGroups {
dispatchGroup.enter()
processingQueue.addOperation {
// 3.1 按文件大小预分组
let sizeGroups = self.groupAssetsBySize(timeGroup)
// 3.2 在每个大小组内进行相似度比较
for sizeGroup in sizeGroups {
let similarGroups = self.findSimilarInGroup(sizeGroup)
// 3.3 合并结果
if !similarGroups.isEmpty {
resultQueue.sync {
for group in similarGroups {
finalGroups.append(group)
DispatchQueue.main.async {
progressHandler?(group)
}
}
}
}
}
dispatchGroup.leave()
}
}
// 4. 完成处理
dispatchGroup.notify(queue: .main) {
completionHandler?(finalGroups)
}
}
// MARK: - 辅助方法
// 按时间窗口分组
private func groupAssetsByTimeWindow(_ assets: [PHAsset]) -> [[PHAsset]] {
let sortedAssets = assets.sorted { ($0.creationDate ?? Date()) > ($1.creationDate ?? Date()) }
var timeGroups: [[PHAsset]] = []
var currentGroup: [PHAsset] = []
var lastTimestamp: Date?
for asset in sortedAssets {
let currentTime = asset.creationDate ?? Date()
if let lastTime = lastTimestamp {
let timeDiff = abs(currentTime.timeIntervalSince(lastTime))
if timeDiff > timeWindowInSeconds {
if !currentGroup.isEmpty {
timeGroups.append(currentGroup)
currentGroup = []
}
}
}
currentGroup.append(asset)
lastTimestamp = currentTime
}
if !currentGroup.isEmpty {
timeGroups.append(currentGroup)
}
return timeGroups
}
// 按文件大小分组
private func groupAssetsBySize(_ assets: [PHAsset]) -> [[PHAsset]] {
var sizeGroups: [[PHAsset]] = []
var processedAssets = Set<String>()
for asset in assets {
if processedAssets.contains(asset.localIdentifier) {
continue
}
var currentGroup = [asset]
processedAssets.insert(asset.localIdentifier)
// 查找大小相近的资产
for compareAsset in assets {
if processedAssets.contains(compareAsset.localIdentifier) {
continue
}
if isFileSizeSimilar(asset, compareAsset) {
currentGroup.append(compareAsset)
processedAssets.insert(compareAsset.localIdentifier)
}
}
if currentGroup.count > 1 {
sizeGroups.append(currentGroup)
}
}
return sizeGroups
}
// 文件大小比较
private func isFileSizeSimilar(_ asset1: PHAsset, _ asset2: PHAsset) -> Bool {
let size1 = Double(asset1.pixelWidth * asset1.pixelHeight)
let size2 = Double(asset2.pixelWidth * asset2.pixelHeight)
let ratio = abs(size1 - size2) / max(size1, size2)
return ratio <= fileSizeThreshold
}
// 在组内查找相似资产
private func findSimilarInGroup(_ assets: [PHAsset]) -> [[PHAsset]] {
var similarGroups: [[PHAsset]] = []
var processedAssets = Set<String>()
for asset in assets {
if processedAssets.contains(asset.localIdentifier) {
continue
}
var currentGroup = [asset]
processedAssets.insert(asset.localIdentifier)
for compareAsset in assets {
if processedAssets.contains(compareAsset.localIdentifier) {
continue
}
if areAssetsSimilar(asset, compareAsset) {
currentGroup.append(compareAsset)
processedAssets.insert(compareAsset.localIdentifier)
}
}
if currentGroup.count > 1 {
similarGroups.append(currentGroup)
}
}
return similarGroups
}
// 相似度比较
private func areAssetsSimilar(_ asset1: PHAsset, _ asset2: PHAsset) -> Bool {
// 1. 检查分辨率
if !isResolutionSimilar(asset1, asset2) {
return false
}
// 2. 计算并比较pHash
return compareAssetHashes(asset1, asset2)
}
// 分辨率比较
private func isResolutionSimilar(_ asset1: PHAsset, _ asset2: PHAsset) -> Bool {
let res1 = Double(asset1.pixelWidth * asset1.pixelHeight)
let res2 = Double(asset2.pixelWidth * asset2.pixelHeight)
let ratio = abs(res1 - res2) / max(res1, res2)
return ratio <= resolutionThreshold
}
// 比较图片哈希值
private func compareAssetHashes(_ asset1: PHAsset, _ asset2: PHAsset) -> Bool {
let options = PHImageRequestOptions()
options.isSynchronous = true
options.version = .original
let targetSize = CGSize(width: 32, height: 32)
var hash1: String?
var hash2: String?
// 从缓存获取或计算hash
let id1 = asset1.localIdentifier
let id2 = asset2.localIdentifier
cacheQueue.sync {
hash1 = hashCache[id1]
hash2 = hashCache[id2]
}
if hash1 == nil {
PHImageManager.default().requestImage(for: asset1, targetSize: targetSize, contentMode: .aspectFit, options: options) { image, _ in
if let image = image {
hash1 = self.calculateImageHash(image)
self.cacheQueue.sync {
self.hashCache[id1] = hash1
}
}
}
}
if hash2 == nil {
PHImageManager.default().requestImage(for: asset2, targetSize: targetSize, contentMode: .aspectFit, options: options) { image, _ in
if let image = image {
hash2 = self.calculateImageHash(image)
self.cacheQueue.sync {
self.hashCache[id2] = hash2
}
}
}
}
guard let h1 = hash1, let h2 = hash2 else { return false }
let distance = calculateHammingDistance(h1, h2)
return distance < hashDistanceThreshold
}
// 计算图片hash
private func calculateImageHash(_ image: UIImage) -> String {
guard let cgImage = image.cgImage else { return "" }
let ciImage = CIImage(cgImage: cgImage)
guard let filter = CIFilter(name: "CIPhotoEffectNoir"),
let outputImage = filter.outputImage else {
return ""
}
filter.setValue(ciImage, forKey: kCIInputImageKey)
let context = CIContext()
guard let scaledImage = context.createCGImage(outputImage, from: outputImage.extent),
let pixelData = UIImage(cgImage: scaledImage).cgImage?.dataProvider?.data,
let data = CFDataGetBytePtr(pixelData) else {
return ""
}
var pixels = Array(repeating: UInt8(0), count: 1024)
for i in 0..<32 {
for j in 0..<32 {
let pixelIndex = (i * 32 + j) * 4
let gray = UInt8(
0.299 * Double(data[pixelIndex]) +
0.587 * Double(data[pixelIndex + 1]) +
0.114 * Double(data[pixelIndex + 2])
)
pixels[i * 32 + j] = gray
}
}
let average = UInt8(pixels.reduce(0, { UInt32($0) + UInt32($1) }) / UInt32(pixels.count))
return pixels.map { $0 > average ? "1" : "0" }.joined()
}
// 计算汉明距离
private func calculateHammingDistance(_ hash1: String, _ hash2: String) -> Int {
guard hash1.count == hash2.count else { return Int.max }
return zip(hash1, hash2).filter { $0 != $1 }.count
}
}
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