Commit aa8c57c4 authored by shenyong's avatar shenyong

1.启动内购页面UI重写

2.功能引导页完成
3.本地通知功能
4.自定义评价弹窗
5.删除完成庆祝页
parent 4abddffe
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "img_dian_guide@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "img_dian_guide@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "img_file_guide@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "img_file_guide@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "tu1@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "tu1@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "tu2@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "tu2@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "photos@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "photos@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "tu3@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "tu3@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "tu4@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "tu4@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "sreenshot@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "sreenshot@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "video@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "video@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "icon2@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "icon2@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "icon1@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "icon1@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "pingjiatu@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "pingjiatu@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -299,6 +299,7 @@ class CompressCompletedViewController : BaseViewController{
var count = 0
for data in self.model! {
let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: [data.ident], options: nil)
let fileSize = FileTool().calculateTotalAssetSize(fetchResult: fetchResult)
let assetToDelete = fetchResult.firstObject
PHPhotoLibrary.shared().performChanges ({
PHAssetChangeRequest.deleteAssets([assetToDelete] as NSFastEnumeration)
......@@ -308,6 +309,7 @@ class CompressCompletedViewController : BaseViewController{
let deleteModel = AssetModel(localIdentifier: data.ident, assetSize: data.orgSize, createDate: data.createDate)
PhotoDataManager.manager.removeDataWhenDeleteInPage(data: [deleteModel])
print("删除文件成功")
self.showDeleteSuccess(fileCount:1, fileSize: fileSize)
}else {
if let error = error {
print("删除文件时出错: \(error.localizedDescription)")
......@@ -321,6 +323,18 @@ class CompressCompletedViewController : BaseViewController{
}
}
// 删除成功页面
func showDeleteSuccess(fileCount:Int,fileSize:Int64){
DispatchQueue.main.async {
let vc = DelSuccessViewController()
vc.delType = fileCount > 1 ? "photos" : "photo"
vc.fileSzie = fileSize
vc.fileCount = fileCount
vc.modalPresentationStyle = .fullScreen
self.present(vc, animated: true)
}
}
func jumpToCompressVC(){
DispatchQueue.main.async {
if let targetVC = self.navigationController?.viewControllers.first(where: { $0 is CompressController }) {
......
......@@ -6,6 +6,7 @@
//
import UIKit
import Photos
class HomeInfoViewController:BaseViewController {
......@@ -61,14 +62,18 @@ class HomeInfoViewController:BaseViewController {
for item in imgs {
tempStringArray.append(item.localIdentifier)
}
let fetchs = PHAsset.fetchAssets(withLocalIdentifiers: tempStringArray, options: nil)
let fileSize = FileTool().calculateTotalAssetSize(fetchResult: fetchs)
PhotoAndVideoMananger.deleteAssets(localIdentifiers: tempStringArray) {[weak self] in
guard let self else {return}
// 更新免费次数
if isAfterAdv == false {
updateFreeTimes()
}
self.showDeleteSuccess(fileCount: tempStringArray.count, fileSize: fileSize)
// 删除缓存数据
PhotoDataManager.manager.removeDataWhenDeleteInPage(data: imgs)
......@@ -246,6 +251,66 @@ class HomeInfoViewController:BaseViewController {
titleView.model.title = ""
showTipsVC()
}
// 删除成功页面
func showDeleteSuccess(fileCount:Int,fileSize:Int64){
DispatchQueue.main.async {
let vc = DelSuccessViewController()
vc.delType = fileCount > 1 ? "photos" : "photo"
vc.fileSzie = fileSize
vc.fileCount = fileCount
vc.modalPresentationStyle = .fullScreen
self.present(vc, animated: true)
}
}
func showTipsVC(){
guard let type = self.type else{
return
}
guard TipsManager.getLoadStauts(type) == false else{
return
}
switch type {
case .duplicates:
let vc = TipsDuplicatesSimilarController()
vc.type = .duplicates
vc.modalPresentationStyle = .fullScreen
self.present(vc, animated: true)
case .similar:
let vc = TipsDuplicatesSimilarController()
vc.type = .similar
vc.modalPresentationStyle = .fullScreen
self.present(vc, animated: true)
case .videos:
let vc = TipsVideoPhotoController()
vc.type = .video
vc.modalPresentationStyle = .fullScreen
self.present(vc, animated: true)
case .similarScreenshots:
break
case .screenshots:
let vc = TipsScreenShotController()
vc.modalPresentationStyle = .fullScreen
self.present(vc, animated: true)
case .SimilarVideos:
break
case .Other:
let vc = TipsVideoPhotoController()
vc.type = .photo
vc.modalPresentationStyle = .fullScreen
self.present(vc, animated: true)
}
TipsManager.saveLoadStatus(type)
}
override func addViews() {
......
......@@ -191,6 +191,30 @@ class HomePhotosDetailViewController : BaseViewController {
// 添加垃圾桶功能
setUI()
showTipsVC()
}
func showTipsVC(){
guard let mediaType = mediaType else{
return
}
guard TipsManager.getLoadStauts(mediaType) == false else{
return
}
if mediaType == .screenshots{
let vc = TipsScreenShotController()
vc.modalPresentationStyle = .fullScreen
self.present(vc, animated: true)
}else{
let vc = TipsVideoPhotoController()
vc.type = .photo
vc.modalPresentationStyle = .fullScreen
self.present(vc, animated: true)
}
TipsManager.saveLoadStatus(mediaType)
}
......@@ -509,6 +533,7 @@ extension HomePhotosDetailViewController:WaterfallMutiSectionDelegate,UICollecti
self.selectedModel = tempArray
let allIdent = self.selectedModel.map{ $0.localIdentifier }
let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: allIdent, options: nil)
let fileSize = FileTool().calculateTotalAssetSize(fetchResult: fetchResult)
PHPhotoLibrary.shared().performChanges ({
PHAssetChangeRequest.deleteAssets(fetchResult as NSFastEnumeration)
}){ success, error in
......@@ -517,6 +542,7 @@ extension HomePhotosDetailViewController:WaterfallMutiSectionDelegate,UICollecti
if isAfterAdv == false {
self.updateFreeTimes()
}
self.showDeleteSuccess(fileCount: allIdent.count, fileSize: fileSize)
self.updateCurrentPageWhenDeleteAny()
}else {
if let error = error {
......@@ -536,6 +562,18 @@ extension HomePhotosDetailViewController:WaterfallMutiSectionDelegate,UICollecti
}
}
// 删除成功页面
func showDeleteSuccess(fileCount:Int,fileSize:Int64){
DispatchQueue.main.async {
let vc = DelSuccessViewController()
vc.delType = fileCount > 1 ? "photos" : "photo"
vc.fileSzie = fileSize
vc.fileCount = fileCount
vc.modalPresentationStyle = .fullScreen
self.present(vc, animated: true)
}
}
func updateCurrentPageWhenDeleteAny(){
for item in self.selectedModel {
// 移除当前数据
......
......@@ -161,8 +161,8 @@ class HomeVideoDetailController :BaseViewController {
view.backgroundColor = .white
self.navigationController?.navigationBar.isHidden = true
setUI()
showTipsVC()
}
override func viewWillAppear(_ animated: Bool) {
......@@ -173,6 +173,19 @@ class HomeVideoDetailController :BaseViewController {
self.collectionView.reloadData()
}
}
func showTipsVC(){
guard TipsManager.getLoadStauts(.videos) == false else{
return
}
let vc = TipsVideoPhotoController()
vc.type = .video
vc.modalPresentationStyle = .fullScreen
self.present(vc, animated: true)
TipsManager.saveLoadStatus(.videos)
}
}
......@@ -440,6 +453,7 @@ extension HomeVideoDetailController:WaterfallMutiSectionDelegate,UICollectionVie
self.selectedModel = tempArray
// 删除当前选择
let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: self.selectedModel.map{$0.localIdentifier}, options: nil)
let fileSize = FileTool().calculateTotalAssetSize(fetchResult: fetchResult)
PHPhotoLibrary.shared().performChanges ({
PHAssetChangeRequest.deleteAssets(fetchResult as NSFastEnumeration)
}){ success, error in
......@@ -448,7 +462,9 @@ extension HomeVideoDetailController:WaterfallMutiSectionDelegate,UICollectionVie
// 如果是看广告删除的,且还有免费次数
if isAfterAdv == false {
self.updateFreeTimes()
}
self.showDeleteSuccess(fileCount: self.selectedModel.count, fileSize: fileSize)
// 移除当前总数据源的数据
self.updateCurrentPageWhenDeleteAny()
}else {
......@@ -460,6 +476,18 @@ extension HomeVideoDetailController:WaterfallMutiSectionDelegate,UICollectionVie
}
}
// 删除成功页面
func showDeleteSuccess(fileCount:Int,fileSize:Int64){
DispatchQueue.main.async {
let vc = DelSuccessViewController()
vc.delType = fileCount > 1 ? "videos" : "video"
vc.fileSzie = fileSize
vc.fileCount = fileCount
vc.modalPresentationStyle = .fullScreen
self.present(vc, animated: true)
}
}
func setDefaultPage(){
DispatchQueue.main.async {
if self.resourceData.count == 0 {
......
......@@ -95,6 +95,8 @@ class HomeViewController:BaseViewController {
// 调用下追踪权限
checkTrackingAuthorization()
NotificationManager().configNotifications()
let dataUpdated = Notification.Name("DataUpdatedNotification")
NotificationCenter.default.addObserver(self, selector: #selector(handleDataUpdated(_:)), name: dataUpdated, object: nil)
......
//
// HomePayDueView.swift
// PhoneManager
//
// Created by edy on 2025/4/27.
//
import UIKit
import StoreKit
class HomePayDueView: UIView {
@IBOutlet weak var dueDay: UILabel!
@IBOutlet weak var dueTime: UILabel!
@IBOutlet weak var freeTime: UILabel!
@IBOutlet weak var priceL: UILabel!
@IBOutlet weak var saveL: UILabel!
@IBOutlet weak var freePrice: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
freeTime.layer.cornerRadius = 8
freeTime.layer.masksToBounds = true
saveL.layer.cornerRadius = 8
saveL.layer.masksToBounds = true
}
func reloadUI(_ type:Int,product1:SKProduct?,product2:SKProduct?){
guard let pord = product1,let pord1 = product2 else { return }
if type == 0{
// 免费试用订阅
dueDay.text = "Due today"
freeTime.isHidden = false
freePrice.isHidden = false
saveL.isHidden = true
priceL.text = "\(pord.localizedPrice)"
priceL.font = UIFont.systemFont(ofSize: 12, weight: .regular)
dueTime.text = "Due" + getDateSevenDaysLater()
}else{
//永久付费
dueDay.text = "One-time payment"
dueTime.text = "Lifetime"
freeTime.isHidden = true
freePrice.isHidden = true
saveL.isHidden = false
priceL.text = "\(pord1.localizedPrice)"
priceL.font = UIFont.systemFont(ofSize: 14, weight: .regular)
}
}
func getDateSevenDaysLater() -> String {
// 获取今天的日期
let today = Date()
// 创建一个日历实例
let calendar = Calendar.current
// 计算今天的7天后的日期
if let sevenDaysLater = calendar.date(byAdding: .day, value: 7, to: today) {
// 创建一个日期格式化器
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMMM dd, yyyy" // 设置日期格式为 "March 24, 2025"
// 格式化日期并返回字符串
return dateFormatter.string(from: sevenDaysLater)
}
return ""
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="a70-YD-Ya9" customClass="HomePayDueView" customModule="PhoneManager" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="411" height="105"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="img_dian_guide" translatesAutoresizingMaskIntoConstraints="NO" id="qbo-Qr-z3x">
<rect key="frame" x="15" y="36" width="7" height="33"/>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Due today" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ud9-QB-E4h">
<rect key="frame" x="30" y="30" width="70" height="20"/>
<constraints>
<constraint firstAttribute="height" constant="20" id="k6M-MG-H5l"/>
</constraints>
<fontDescription key="fontDescription" type="boldSystem" pointSize="14"/>
<color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Due March 24,2025" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ath-uh-IP1">
<rect key="frame" x="30" y="58" width="112" height="17"/>
<constraints>
<constraint firstAttribute="height" constant="17" id="ymm-FM-0sg"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="$0.00" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="L36-Ja-KtD">
<rect key="frame" x="363" y="32.666666666666664" width="33" height="15"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="$298.00" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ifj-ms-WlU">
<rect key="frame" x="348" y="59" width="48" height="15"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="7 days free" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ojb-9V-tC4">
<rect key="frame" x="272" y="29.666666666666671" width="85" height="21"/>
<color key="backgroundColor" red="0.32156862745098036" green="0.7803921568627451" blue="0.46274509803921571" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" constant="85" id="6LD-4Y-C7t"/>
<constraint firstAttribute="height" constant="21" id="YL8-Mf-YdS"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Save 89%" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Wpu-I6-q6N">
<rect key="frame" x="311" y="29.666666666666671" width="85" height="21"/>
<color key="backgroundColor" red="0.32156862749999998" green="0.78039215689999997" blue="0.46274509800000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="21" id="HGB-v2-yhW"/>
<constraint firstAttribute="width" constant="85" id="eSe-ik-cPa"/>
</constraints>
<fontDescription key="fontDescription" type="boldSystem" pointSize="14"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<viewLayoutGuide key="safeArea" id="rsc-7Q-a6D"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="Wpu-I6-q6N" firstAttribute="centerY" secondItem="Ud9-QB-E4h" secondAttribute="centerY" id="7iY-TV-9Vq"/>
<constraint firstItem="ath-uh-IP1" firstAttribute="leading" secondItem="qbo-Qr-z3x" secondAttribute="trailing" constant="8" id="7kZ-YS-OlZ"/>
<constraint firstItem="ojb-9V-tC4" firstAttribute="centerY" secondItem="Ud9-QB-E4h" secondAttribute="centerY" id="DHP-vG-Hmx"/>
<constraint firstItem="qbo-Qr-z3x" firstAttribute="leading" secondItem="rsc-7Q-a6D" secondAttribute="leading" constant="15" id="INS-5o-2hg"/>
<constraint firstItem="Ifj-ms-WlU" firstAttribute="centerY" secondItem="ath-uh-IP1" secondAttribute="centerY" id="N6t-57-WJE"/>
<constraint firstItem="qbo-Qr-z3x" firstAttribute="centerY" secondItem="a70-YD-Ya9" secondAttribute="centerY" id="OUE-cR-dyo"/>
<constraint firstItem="L36-Ja-KtD" firstAttribute="leading" secondItem="ojb-9V-tC4" secondAttribute="trailing" constant="6" id="W5w-LL-k4i"/>
<constraint firstAttribute="trailing" secondItem="Wpu-I6-q6N" secondAttribute="trailing" constant="15" id="Xea-6S-2zJ"/>
<constraint firstItem="rsc-7Q-a6D" firstAttribute="trailing" secondItem="Ifj-ms-WlU" secondAttribute="trailing" constant="15" id="eI7-NB-IHa"/>
<constraint firstItem="Ud9-QB-E4h" firstAttribute="top" secondItem="qbo-Qr-z3x" secondAttribute="top" constant="-6" id="f3Y-3H-6F1"/>
<constraint firstItem="L36-Ja-KtD" firstAttribute="centerY" secondItem="Ud9-QB-E4h" secondAttribute="centerY" id="glH-OH-L3u"/>
<constraint firstAttribute="trailing" secondItem="L36-Ja-KtD" secondAttribute="trailing" constant="15" id="kfM-I0-ybd"/>
<constraint firstItem="Ud9-QB-E4h" firstAttribute="leading" secondItem="qbo-Qr-z3x" secondAttribute="trailing" constant="8" id="o6F-nL-e5Y"/>
<constraint firstItem="ath-uh-IP1" firstAttribute="top" secondItem="Ud9-QB-E4h" secondAttribute="bottom" constant="8" id="oPg-br-azI"/>
</constraints>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<connections>
<outlet property="dueDay" destination="Ud9-QB-E4h" id="0gl-3M-Pae"/>
<outlet property="dueTime" destination="ath-uh-IP1" id="1lU-uG-Gf9"/>
<outlet property="freePrice" destination="L36-Ja-KtD" id="NH4-WZ-Wva"/>
<outlet property="freeTime" destination="ojb-9V-tC4" id="14m-8G-ySn"/>
<outlet property="priceL" destination="Ifj-ms-WlU" id="5nx-Ip-tGm"/>
<outlet property="saveL" destination="Wpu-I6-q6N" id="dcT-hq-PiW"/>
</connections>
<point key="canvasLocation" x="142.74809160305344" y="234.1549295774648"/>
</view>
</objects>
<resources>
<image name="img_dian_guide" width="7" height="33"/>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>
......@@ -16,11 +16,11 @@ class HomePayView:UIView {
private var closeBtn:UIButton?
private var titleLabel1:UILabel?
private var titleLabel2:UILabel?
private var photoImage:UIImageView?
private var icloudImage:UIImageView?
private var photoImage:UIImageView!
private var icloudImage:UIImageView!
private var photoLabel:UILabel?
private var icloudLabel:UILabel?
private var animationLabel:UILabel?
// private var animationLabel:UILabel?
private var contentView2:UIView?
private var contentView2Title:UILabel?
private var contentView2Switch:UISwitch?
......@@ -38,6 +38,11 @@ class HomePayView:UIView {
private var normalContentTitle:UILabel?
private var normalContentMoney:UILabel?
private var trailTitle:UILabel!
private var tipsView:UIView!
private var memSize:UILabel!
var sizeLabel:UILabel!
var type = 0 {
didSet {
setIsSelect()
......@@ -98,29 +103,12 @@ class HomePayView:UIView {
let animationView = LottieAnimationView(name: "onboardingStorageLight")
animationView.animationSpeed = -1.0
animationView.layer.cornerRadius = 8
animationView.contentMode = .scaleAspectFill
animationView.clipsToBounds = true
return animationView
}()
private lazy var yearNorBtn: PMButton = {
let btn = PMButton(type: .custom)
btn.backgroundColor = .colorWithHex(hexStr: "#F2F6FC")
btn.setTitles(["3 days free trial",""])
btn.addTarget(self, action: #selector(TheFrial), for: .touchUpInside)
addSubview(btn)
return btn
}()
private lazy var forever: PMButton = {
let fever = PMButton(type: .custom)
fever.setTitles([""])
fever.backgroundColor = .colorWithHex(hexStr: "#F2F6FC")
fever.addTarget(self, action: #selector(FreeTrial), for: .touchUpInside)
addSubview(fever)
return fever
}()
var callBack:callBack<Any> = {text in}
override init(frame: CGRect) {
......@@ -137,21 +125,6 @@ class HomePayView:UIView {
backgroundColor = .white
// restoreBtn = UIButton()
// restoreBtn?.setTitle("Restore Purchase", for: .normal)
// restoreBtn?.setTitleColor(UIColor.colorWithHex(hexStr: "#B3B3B3"), for: .normal)
// restoreBtn?.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .regular)
// restoreBtn?.addTarget(self, action: #selector(restoreTouch), for: .touchUpInside)
// self.addSubview(restoreBtn!)
//
// restoreBtn?.snp.makeConstraints { make in
// make.top.equalToSuperview().offset(statusBarHeight + 10)
// make.left.equalToSuperview().offset(15)
// }
// 确保按钮大小自适应
// restoreBtn?.sizeToFit()
closeBtn = UIButton()
closeBtn?.setImage(UIImage(named: "home_pay_close"), for: .normal)
closeBtn?.addTarget(self, action: #selector(closeBtnClick), for: .touchUpInside)
......@@ -165,7 +138,7 @@ class HomePayView:UIView {
}
titleLabel1 = UILabel()
titleLabel1?.text = "Clean your storage space"
titleLabel1?.text = "Clean your Storage"
titleLabel1?.font = UIFont.systemFont(ofSize: 24, weight: .bold)
titleLabel1?.textColor = UIColor.colorWithHex(hexStr: black3Color)
self.addSubview(titleLabel1!)
......@@ -178,8 +151,8 @@ class HomePayView:UIView {
titleLabel1?.sizeToFit()
titleLabel2 = UILabel()
titleLabel2?.text = "Delete unnecessary content"
titleLabel2?.font = UIFont.systemFont(ofSize: 14, weight: .bold)
titleLabel2?.text = "Get rid of what you don't need"
titleLabel2?.font = UIFont.systemFont(ofSize: 14, weight: .regular)
titleLabel2?.textColor = UIColor.colorWithHex(hexStr: black3Color)
self.addSubview(titleLabel2!)
......@@ -191,45 +164,55 @@ class HomePayView:UIView {
titleLabel2?.sizeToFit()
photoImage = UIImageView(image: UIImage(named: "img_photos_start"))
self.addSubview(photoImage!)
self.addSubview(photoImage)
photoImage?.snp.makeConstraints { make in
make.top.equalTo(titleLabel2!.snp.bottom).offset(24)
make.centerX.equalToSuperview().offset(-52)
make.width.height.equalTo(64)
photoImage.snp.makeConstraints { make in
make.top.equalTo(titleLabel2!.snp.bottom).offset(38)
make.left.equalTo(48.RW())
make.size.equalTo(64)
}
icloudImage = UIImageView(image: UIImage(named: "img_icloud_start"))
self.addSubview(icloudImage!)
icloudImage = UIImageView(image: UIImage(named: "img_file_guide"))
self.addSubview(icloudImage)
icloudImage?.snp.makeConstraints { make in
make.top.equalTo(titleLabel2!.snp.bottom).offset(24)
make.centerX.equalToSuperview().offset(52)
make.width.height.equalTo(64)
icloudImage.snp.makeConstraints { make in
make.left.equalTo(photoImage.snp.right).offset(24.RW())
make.centerY.equalTo(photoImage)
make.size.equalTo(64)
}
photoLabel = UILabel()
photoLabel?.text = "Photos"
photoLabel?.font = UIFont.systemFont(ofSize: 14, weight: .bold)
photoLabel?.textColor = UIColor.colorWithHex(hexStr: black3Color)
photoLabel?.text = "403"
photoLabel?.backgroundColor = UIColor.colorWithHex(hexStr: "#EB4545")
photoLabel?.font = UIFont.systemFont(ofSize: 10, weight: .bold)
photoLabel?.textAlignment = .center
photoLabel?.textColor = .white
photoLabel?.layer.cornerRadius = 12
photoLabel?.layer.masksToBounds = true
self.addSubview(photoLabel!)
photoLabel?.snp.makeConstraints { make in
make.top.equalTo(photoImage!.snp.bottom).offset(16)
make.centerX.equalTo(photoImage!.snp.centerX)
make.top.equalTo(photoImage.snp.top).offset(-12)
make.right.equalTo(photoImage.snp.right).offset(12)
make.size.equalTo(24)
}
photoLabel?.sizeToFit()
icloudLabel = UILabel()
icloudLabel?.text = "iCloud"
icloudLabel?.font = UIFont.systemFont(ofSize: 14, weight: .bold)
icloudLabel?.textColor = UIColor.colorWithHex(hexStr: black3Color)
icloudLabel?.text = "217"
icloudLabel?.textAlignment = .center
icloudLabel?.font = UIFont.systemFont(ofSize: 10, weight: .bold)
icloudLabel?.backgroundColor = UIColor.colorWithHex(hexStr: "#EB4545")
icloudLabel?.textColor = .white
icloudLabel?.layer.cornerRadius = 12
icloudLabel?.layer.masksToBounds = true
self.addSubview(icloudLabel!)
icloudLabel?.snp.makeConstraints { make in
make.top.equalTo(icloudImage!.snp.bottom).offset(16)
make.centerX.equalTo(icloudImage!.snp.centerX)
make.top.equalTo(icloudImage.snp.top).offset(-12)
make.right.equalTo(icloudImage.snp.right).offset(12)
make.size.equalTo(24)
}
icloudLabel?.sizeToFit()
......@@ -238,44 +221,32 @@ class HomePayView:UIView {
playAnimationWithDelay()
animationView.snp.makeConstraints { make in
make.top.equalTo(photoLabel!.snp.bottom).offset(20)
make.top.equalTo(icloudImage!.snp.bottom).offset(24)
make.centerX.equalToSuperview()
make.width.equalTo(196.67)
make.height.equalTo(24)
make.width.equalTo(280)
make.height.equalTo(12)
}
animationLabel = UILabel()
let fullText = "72 from 100% used"
// 创建 NSMutableAttributedString
let attributedString = NSMutableAttributedString(string: fullText)
// 设置 "+80%" 的样式
let blueColor = UIColor.colorWithHex(hexStr: "#E73A3A")
let largeFont = UIFont.systemFont(ofSize: 20, weight: .bold)
let range1 = (fullText as NSString).range(of: "72")
attributedString.addAttribute(.foregroundColor, value: blueColor, range: range1)
attributedString.addAttribute(.font, value: largeFont, range: range1)
// 设置其他文本的样式
let darkGrayColor = UIColor.colorWithHex(hexStr: black3Color)
let smallFont = UIFont.systemFont(ofSize: 20, weight: .regular)
let range2 = NSRange(location: range1.length, length: fullText.count - range1.length)
attributedString.addAttribute(.foregroundColor, value: darkGrayColor, range: range2)
attributedString.addAttribute(.font, value: smallFont, range: range2)
// 将 NSAttributedString 赋值给 UILabel
animationLabel?.attributedText = attributedString
animationLabel?.numberOfLines = 1 // 支持多行
self.addSubview(animationLabel!)
let analysis = UILabel()
analysis.text = "Analysis completed"
analysis.textColor = UIColor.colorWithHex(hexStr: "#B3B3B3")
analysis.font = UIFont.systemFont(ofSize: 14, weight: .bold)
addSubview(analysis)
analysis.snp.makeConstraints { make in
make.left.equalTo(animationView.snp.left)
make.top.equalTo(animationView.snp.bottom).offset(8)
}
memSize = UILabel()
memSize.text = "100%"
memSize.textColor = UIColor.colorWithHex(hexStr: "#B3B3B3")
memSize.font = UIFont.systemFont(ofSize: 14, weight: .bold)
addSubview(memSize)
memSize.snp.makeConstraints { make in
make.right.equalTo(animationView.snp.right)
make.top.equalTo(animationView.snp.bottom).offset(8)
}
animationLabel?.snp.makeConstraints({ make in
make.top.equalTo(animationView.snp.bottom).offset(16)
make.centerX.equalToSuperview()
})
appleLabel = UILabel()
appleLabel?.text = " Secured with Apple"
......@@ -304,27 +275,32 @@ class HomePayView:UIView {
make.centerY.equalTo(appleLabel!)
make.right.equalToSuperview().offset(-marginLR)
}
payButton?.layer.cornerRadius = 8
payButton?.layer.cornerRadius = 25
payButton?.layer.masksToBounds = true
// 额外添加视图
setCenterViewUI()
contentView2 = UIView()
contentView2?.backgroundColor = UIColor.colorWithHex(hexStr: "#F2F6FC")
self.addSubview(contentView2!)
contentView2?.snp.makeConstraints({ make in
make.top.equalTo(forever.snp.bottom).offset(20)
make.top.equalTo(tipsView.snp.bottom).offset(12)
make.centerX.equalToSuperview()
make.width.equalToSuperview().offset(-30)
make.height.equalTo(60)
})
payButton?.snp.makeConstraints({ make in
make.centerX.equalToSuperview()
make.top.equalTo(contentView2!.snp.bottom).offset(20)
make.top.equalTo(payDueView.snp.bottom).offset(20)
make.width.equalToSuperview().offset(-30)
make.height.equalTo(69)
make.height.equalTo(50)
})
contentView2?.layer.cornerRadius = 12
contentView2?.layer.masksToBounds = true
contentView2Title = UILabel()
contentView2Title?.text = "Free trial enabled"
contentView2Title?.font = UIFont.systemFont(ofSize: 16, weight: .bold)
......@@ -352,16 +328,6 @@ class HomePayView:UIView {
}
contentView2Switch?.addTarget(self, action: #selector(switchValueChanged(_:)), for: .valueChanged)
forever.snp.makeConstraints { make in
make.left.right.equalTo(self.contentView2!)
make.top.equalTo(yearNorBtn.snp.bottom).offset(20)
make.height.equalTo(69)
}
yearNorBtn.snp.makeConstraints { make in
make.left.right.equalTo(self.contentView2!)
make.top.equalTo(animationLabel!.snp.bottom).offset(75)
make.height.equalTo(69)
}
privavye_Label.snp.makeConstraints { make in
make.left.right.equalTo(self.contentView2!)
make.top.equalTo(ppBtn.snp.bottom).offset(15)
......@@ -417,33 +383,34 @@ class HomePayView:UIView {
}
var product : SKProduct? {
didSet{
guard let prod = product else { return }
yearNorBtn.setTitles(["\(prod.localizedPrice) per year","3 days free trial"])
}
}
var product : SKProduct?
var product1 : SKProduct? {
didSet{
guard let prod = product1 else { return }
forever.setTitles(["\(prod.localizedPrice), Lifetime"])
}
var product1 : SKProduct?
func reloadSKPorduct(product:SKProduct?,product1:SKProduct?){
self.product = product
self.product1 = product1
payDueView.reloadUI(type, product1: product, product2: product1)
}
private func setIsSelect() -> Void {
yearNorBtn.isSelect = type == 0
forever.isSelect = type == 1
contentView2Switch?.isOn = type == 0
payButton?.setTitle(type == 0 ? "Try Free" : "Start Planning", for: .normal)
payButton?.setTitle(type == 0 ? "Try Free" : "Start Now", for: .normal)
payDueView.reloadUI(type, product1: product, product2: product1)
if let pord = product,type == 0{
trailTitle.attributedText = nil
trailTitle.text = "Free for 7 days, then \(pord.localizedPrice)/week"
}
@objc private func FreeTrial() -> Void {
type = 1
if let pord = product1,type == 1{
trailTitle.text = "\(pord.localizedPrice)/Lifetime"
setAttributedString(price: pord.localizedPrice)
}
@objc private func TheFrial() {
type = 0
}
@objc func closeBtnClick() {
......@@ -473,6 +440,7 @@ class HomePayView:UIView {
@objc func switchValueChanged(_ sender: UISwitch) {
type = sender.isOn ? 0 : 1
}
@objc func restoreTouch() -> Void {
......@@ -483,4 +451,130 @@ class HomePayView:UIView {
callBack(CommonPush.pay)
}
func setCenterViewUI(){
tipsView = UIView()
tipsView.backgroundColor = UIColor.colorWithHex(hexStr: "#F2F6FC")
tipsView.layer.cornerRadius = 12
addSubview(tipsView)
let tiptTitle = UILabel()
tiptTitle.text = "Phone Manager"
tiptTitle.textColor = UIColor.colorWithHex(hexStr: black3Color)
tiptTitle.font = UIFont.systemFont(ofSize: 16, weight: .bold)
tipsView.addSubview(tiptTitle)
tiptTitle.snp.makeConstraints { make in
make.left.equalTo(16)
make.top.equalTo(16)
}
let subTitle = UILabel()
subTitle.text = "Smart Cleaning, Video Compressor, Secret Storage, Manage Contacts, No Ads and Limits."
subTitle.textColor = UIColor.colorWithHex(hexStr: black6Color)
subTitle.numberOfLines = 2
subTitle.font = UIFont.systemFont(ofSize: 12, weight: .regular)
tipsView.addSubview(subTitle)
subTitle.snp.makeConstraints { make in
make.left.equalTo(16)
make.right.equalTo(-16)
make.top.equalTo(tiptTitle.snp.bottom).offset(8)
}
trailTitle = UILabel()
trailTitle.text = "Free for 7 days, then $6.99/week"
trailTitle.textColor = UIColor.colorWithHex(hexStr: black3Color)
trailTitle.font = UIFont.systemFont(ofSize: 12, weight: .regular)
tipsView.addSubview(trailTitle)
trailTitle.snp.makeConstraints { make in
make.left.equalTo(16)
make.right.equalTo(-16)
make.top.equalTo(subTitle.snp.bottom).offset(8)
}
tipsView.snp.makeConstraints { make in
make.top.equalTo(animationView.snp.bottom).offset(92)
make.left.right.equalToSuperview().inset(12)
make.height.equalTo(121)
}
let freespace = UILabel()
freespace.font = UIFont.systemFont(ofSize: 12, weight: .bold)
freespace.textColor = UIColor.colorWithHex(hexStr: "#B3B3B3")
addSubview(freespace)
sizeLabel = UILabel()
sizeLabel.text = "54.2 GB"
sizeLabel.textColor = UIColor.colorWithHex(hexStr: black3Color)
sizeLabel.font = UIFont.systemFont(ofSize: 12, weight: .bold)
addSubview(sizeLabel)
freespace.snp.makeConstraints { make in
make.left.equalTo(icloudImage!.snp.right).offset(24.RW())
make.top.equalTo(titleLabel2!.snp.bottom).offset(42)
make.height.equalTo(17)
}
sizeLabel.snp.makeConstraints { make in
make.top.equalTo(freespace.snp.bottom).offset(0)
make.left.equalTo(icloudImage!.snp.right).offset(24)
make.height.equalTo(39)
}
let fullText = FileTool().formatBytes(FileTool().getStorageInfo(for: .free) ?? 0 )
// 创建一个可变的富文本字符串
let attributedString = NSMutableAttributedString(string: fullText)
// 设置前半部分(动态数值)的范围
let regularFont = UIFont.systemFont(ofSize: 28, weight: .bold) // 设置常规字体大小
attributedString.addAttribute(.font, value: regularFont, range: NSRange.init(location: 0,length:fullText.count-2))
// 设置“GB”部分的范围并将字体大小设置为12
let smallFont = UIFont.systemFont(ofSize: 12, weight: .bold) // 设置字体大小为12
attributedString.addAttribute(.font, value: smallFont, range:NSRange.init(location: fullText.count-2, length: 2))
// 将富文本赋值给UILabel
sizeLabel.attributedText = attributedString
payDueView.snp.makeConstraints { make in
make.left.right.equalToSuperview()
make.top.equalTo(tipsView.snp.bottom).offset(90)
make.height.equalTo(50)
}
}
func setAttributedString(price:String){
// 定义动态的文本
let sizeValue = price // 这里可以是任何动态数值,例如来自其他计算或输入
let unit = "/Lifetime"
let fullText = "\(sizeValue) \(unit)"
// 创建一个可变的富文本字符串
let attributedString = NSMutableAttributedString(string: fullText)
// 设置前半部分(动态数值)的范围
let regularFont = UIFont.systemFont(ofSize: 18, weight: .regular) // 设置常规字体大小
let range1 = (fullText as NSString).range(of: sizeValue)
attributedString.addAttribute(.font, value: regularFont, range: range1)
// 设置“GB”部分的范围并将字体大小设置为12
let smallFont = UIFont.systemFont(ofSize: 14, weight: .regular) // 设置字体大小为12
let range2 = (fullText as NSString).range(of: unit)
attributedString.addAttribute(.font, value: smallFont, range: range2)
trailTitle.attributedText = attributedString
}
lazy var payDueView:HomePayDueView = {
let payDueView = Bundle.main.loadNibNamed("HomePayDueView", owner: nil, options: nil)?.last as! HomePayDueView
addSubview(payDueView)
return payDueView
}()
}
......@@ -112,8 +112,9 @@ extension HomePayViewController {
let p1 = currentProduct?.first,
let p2 = currentProduct?.last
else { return }
homePayView?.product = p1
homePayView?.product1 = p2
homePayView?.reloadSKPorduct(product: p1, product1: p2)
// homePayView?.product = p1
// homePayView?.product1 = p2
}
private func storeKeD() -> Void {
......
//
// CustomRateView.swift
// PhoneManager
//
// Created by edy on 2025/4/27.
//
import UIKit
class CustomRate{
// 自定义初始化方法
func show() {
let view = Bundle.main.loadNibNamed("CustomRateView", owner: nil)?.last as! CustomRateView
view.frame = CGRect.init(x: 0, y: 0, width:ScreenW, height: ScreenH)
view.show()
}
}
class CustomRateView: UIView {
@IBOutlet weak var bgView: UIView!
@IBOutlet weak var okBtn: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
okBtn.layer.cornerRadius = 15
bgView.layer.cornerRadius = 12
}
@IBAction func okClick(_ sender: Any) {
guard let url = URL(string: "https://apps.apple.com/us/app/id\(APPConfig.APPID)?action=write-review") else {
return
}
if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
}
@IBAction func noClick(_ sender: Any) {
self.alpha = 1
UIView.animate(withDuration: 0.2) {
self.alpha = 0
}completion: { _ in
self.removeFromSuperview()
}
}
func show(){
KEYWINDOW()?.addSubview(self)
self.alpha = 0
UIView.animate(withDuration: 0.2) {
self.alpha = 1
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="6qH-5M-OIW" customClass="CustomRateView" customModule="PhoneManager" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="eO0-mO-cv0">
<rect key="frame" x="15" y="235" width="363" height="370"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_rate_simle" translatesAutoresizingMaskIntoConstraints="NO" id="wNX-WZ-HxL">
<rect key="frame" x="112" y="35" width="139" height="139"/>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Hey, do you like PhoneManager?" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ka6-1V-usy">
<rect key="frame" x="16" y="194" width="331" height="24"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="20"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="So, could you please rate us on the App Store?" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="DpR-9g-ROc">
<rect key="frame" x="20" y="224" width="323" height="17"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" red="0.33333334329999997" green="0.33333334329999997" blue="0.33333334329999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="1Uo-ks-UkN">
<rect key="frame" x="20" y="257" width="323" height="46"/>
<color key="backgroundColor" red="0.0" green="0.50980392159999999" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="46" id="gvU-wv-6JI"/>
</constraints>
<fontDescription key="fontDescription" type="boldSystem" pointSize="16"/>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" title="OK"/>
<connections>
<action selector="okClick:" destination="6qH-5M-OIW" eventType="touchUpInside" id="zpI-EB-wAO"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="1EK-jZ-7MV">
<rect key="frame" x="126" y="315" width="111" height="32"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="16"/>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" title="No, Thank you">
<color key="titleColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="noClick:" destination="6qH-5M-OIW" eventType="touchUpInside" id="j6b-pb-M6h"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="ka6-1V-usy" firstAttribute="leading" secondItem="eO0-mO-cv0" secondAttribute="leading" constant="16" id="0A6-BH-8Sr"/>
<constraint firstItem="1EK-jZ-7MV" firstAttribute="top" secondItem="1Uo-ks-UkN" secondAttribute="bottom" constant="12" id="3SY-W0-oUX"/>
<constraint firstItem="1Uo-ks-UkN" firstAttribute="leading" secondItem="eO0-mO-cv0" secondAttribute="leading" constant="20" id="8HA-G5-A7A"/>
<constraint firstItem="wNX-WZ-HxL" firstAttribute="top" secondItem="eO0-mO-cv0" secondAttribute="top" constant="35" id="FXq-i7-bhO"/>
<constraint firstItem="DpR-9g-ROc" firstAttribute="top" secondItem="ka6-1V-usy" secondAttribute="bottom" constant="6" id="H6a-Vq-fsl"/>
<constraint firstItem="1EK-jZ-7MV" firstAttribute="centerX" secondItem="1Uo-ks-UkN" secondAttribute="centerX" id="HOi-y2-0I1"/>
<constraint firstAttribute="trailing" secondItem="1Uo-ks-UkN" secondAttribute="trailing" constant="20" id="IbL-jb-AR6"/>
<constraint firstItem="wNX-WZ-HxL" firstAttribute="centerX" secondItem="eO0-mO-cv0" secondAttribute="centerX" id="PA1-8i-rIP"/>
<constraint firstAttribute="trailing" secondItem="DpR-9g-ROc" secondAttribute="trailing" constant="20" id="SA7-0D-qqp"/>
<constraint firstItem="DpR-9g-ROc" firstAttribute="leading" secondItem="eO0-mO-cv0" secondAttribute="leading" constant="20" id="VFt-lh-z7M"/>
<constraint firstItem="1Uo-ks-UkN" firstAttribute="top" secondItem="DpR-9g-ROc" secondAttribute="bottom" constant="16" id="eMT-yH-PKn"/>
<constraint firstItem="ka6-1V-usy" firstAttribute="top" secondItem="wNX-WZ-HxL" secondAttribute="bottom" constant="20" id="gjg-1p-0ZY"/>
<constraint firstAttribute="height" constant="370" id="rQr-Wr-23b"/>
<constraint firstAttribute="trailing" secondItem="ka6-1V-usy" secondAttribute="trailing" constant="16" id="xwQ-Wf-8Rz"/>
</constraints>
</view>
</subviews>
<viewLayoutGuide key="safeArea" id="LTt-HW-XdR"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.5" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="eO0-mO-cv0" firstAttribute="leading" secondItem="LTt-HW-XdR" secondAttribute="leading" constant="15" id="EOH-0c-Twg"/>
<constraint firstItem="LTt-HW-XdR" firstAttribute="trailing" secondItem="eO0-mO-cv0" secondAttribute="trailing" constant="15" id="TZF-xM-ND5"/>
<constraint firstItem="eO0-mO-cv0" firstAttribute="top" secondItem="LTt-HW-XdR" secondAttribute="top" constant="176" id="eZu-0d-lB0"/>
</constraints>
<connections>
<outlet property="bgView" destination="eO0-mO-cv0" id="oYY-Ia-swm"/>
<outlet property="okBtn" destination="1Uo-ks-UkN" id="DHs-t0-6Mz"/>
</connections>
<point key="canvasLocation" x="88" y="-4"/>
</view>
</objects>
<resources>
<image name="icon_rate_simle" width="139" height="139"/>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>
//
// DelSuccessViewController.swift
// PhoneManager
//
// Created by edy on 2025/4/27.
//
import UIKit
import Photos
import Lottie
class DelSuccessViewController: UIViewController {
@IBOutlet weak var bottomBtn: UIButton!
@IBOutlet weak var bottomText: UILabel!
@IBOutlet weak var points: UILabel!
@IBOutlet weak var delText: UILabel!
var delType:String = "photo"
var fileCount:Int = 0
var fileSzie:Int64 = 0
override func viewDidLoad() {
super.viewDidLoad()
bottomBtn.layer.cornerRadius = 15
animationView.frame = CGRect(x: (ScreenW-250)/2+20, y: 80, width: 250, height: 250) // 设置 frame
view.addSubview(animationView)
startAnimation()
reloadUI()
}
lazy var animationView : LottieAnimationView = {
let animationView = LottieAnimationView(name: "delSuccessCelebrate")
animationView.loopMode = .playOnce
return animationView
}()
func startAnimation() {
// 播放动画
animationView.play { [weak self] finished in
// 动画结束后等待 2 秒再重新播放
guard let self = self else { return }
if finished {
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
self.startAnimation() // 重新开始动画
}
}
}
}
@IBAction func closeClick(_ sender: Any) {
self.dismiss(animated: true)
}
func reloadUI(){
let size = fileSzie
points.text = "Save 10 points"
delText.text = "\(fileCount) \(delType)(\(FileTool().formatBytes(size)))"
bottomText.text = "Clear the \"Recently Deleted\" album on iPhone to free up \(FileTool().formatBytes(size)) of space."
// 设置 points 标签
let pointsAttributedString = NSMutableAttributedString(string: "Save 10 points")
let pointsRange = (points.text! as NSString).range(of: "10 points")
pointsAttributedString.addAttribute(.foregroundColor, value:UIColor.colorWithHex(hexStr: "#0082FF"), range: pointsRange)
points.attributedText = pointsAttributedString
// 设置 delText 标签
let formattedSize = FileTool().formatBytes(size)
let delTextString = "\(fileCount) \(delType)(\(formattedSize))"
let delTextAttributedString = NSMutableAttributedString(string: delTextString)
// 设置 fetchResult.count 和 delType 的范围
let countRange = (delTextString as NSString).range(of: "\(fileCount)")
let delTypeRange = (delTextString as NSString).range(of: delType)
// 设置颜色为蓝色
delTextAttributedString.addAttribute(.foregroundColor, value: UIColor.colorWithHex(hexStr: "#0082FF"), range: countRange)
delTextAttributedString.addAttribute(.foregroundColor, value: UIColor.colorWithHex(hexStr: "#0082FF"), range: delTypeRange)
// 其他文本设置为灰色
let otherRange = (delTextString as NSString).range(of: "(\(formattedSize))") // 获取其他文本的范围
delTextAttributedString.addAttribute(.foregroundColor, value: UIColor.colorWithHex(hexStr: "#1A1A1A"), range: otherRange)
delText.attributedText = delTextAttributedString
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="DelSuccessViewController" customModule="PhoneManager" customModuleProvider="target">
<connections>
<outlet property="bottomBtn" destination="LCj-Gz-gce" id="BOZ-jZ-MLX"/>
<outlet property="bottomText" destination="nIS-b5-Znx" id="ASM-VW-Ehs"/>
<outlet property="delText" destination="zkh-yv-aYk" id="ech-5X-5e2"/>
<outlet property="points" destination="mhe-iG-xpQ" id="Txp-U4-fpy"/>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Congratulate!" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Wuv-Jo-ClG">
<rect key="frame" x="116.00000000000001" y="305" width="161.33333333333337" height="30"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="25"/>
<color key="textColor" red="0.1019607843" green="0.1019607843" blue="0.1019607843" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_congratulate_star" translatesAutoresizingMaskIntoConstraints="NO" id="V9c-pl-MwJ">
<rect key="frame" x="43" y="378" width="46" height="46"/>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="You have deleted" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Npn-Yc-tdh">
<rect key="frame" x="103" y="378" width="124.33333333333331" height="19.333333333333314"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="0.1019607843" green="0.1019607843" blue="0.1019607843" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Used Phone Manager" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gYc-Ja-g1G">
<rect key="frame" x="103" y="457" width="156" height="20"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="0.1019607843" green="0.1019607843" blue="0.1019607843" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_congratulate_points" translatesAutoresizingMaskIntoConstraints="NO" id="WJ0-hg-B3V">
<rect key="frame" x="43" y="457" width="46" height="46"/>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Save 10 points" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mhe-iG-xpQ">
<rect key="frame" x="103" y="486" width="105" height="20"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="0.1019607843" green="0.1019607843" blue="0.1019607843" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Clear the &quot;Recently Deleted&quot; album on iPhone to free up 3.9 MB of space." textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="nIS-b5-Znx">
<rect key="frame" x="32" y="536" width="329" height="33.666666666666629"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="LCj-Gz-gce">
<rect key="frame" x="15" y="742" width="363" height="46"/>
<color key="backgroundColor" red="0.0" green="0.50980392159999999" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="46" id="i6j-as-anp"/>
</constraints>
<fontDescription key="fontDescription" type="boldSystem" pointSize="16"/>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" title="Fantastic"/>
<connections>
<action selector="closeClick:" destination="-1" eventType="touchUpInside" id="efb-fY-cER"/>
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="1 video(3.9 MB)" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="zkh-yv-aYk">
<rect key="frame" x="103" y="406.33333333333331" width="113.33333333333331" height="20"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="0.1019607843" green="0.1019607843" blue="0.1019607843" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="LCj-Gz-gce" secondAttribute="trailing" constant="15" id="0CP-MC-Lr5"/>
<constraint firstItem="LCj-Gz-gce" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="15" id="2Xv-th-L23"/>
<constraint firstItem="V9c-pl-MwJ" firstAttribute="top" secondItem="Npn-Yc-tdh" secondAttribute="top" id="5QM-aj-IeW"/>
<constraint firstItem="Wuv-Jo-ClG" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" constant="246" id="D2b-Te-XzC"/>
<constraint firstItem="gYc-Ja-g1G" firstAttribute="leading" secondItem="WJ0-hg-B3V" secondAttribute="trailing" constant="14" id="EhM-Yr-SAL"/>
<constraint firstItem="zkh-yv-aYk" firstAttribute="top" secondItem="Npn-Yc-tdh" secondAttribute="bottom" constant="9" id="EjO-a7-oYm"/>
<constraint firstItem="zkh-yv-aYk" firstAttribute="leading" secondItem="V9c-pl-MwJ" secondAttribute="trailing" constant="14" id="H7C-tK-dfK"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" secondItem="LCj-Gz-gce" secondAttribute="bottom" constant="30" id="Tfh-Lq-LH9"/>
<constraint firstItem="WJ0-hg-B3V" firstAttribute="trailing" secondItem="V9c-pl-MwJ" secondAttribute="trailing" id="Ua4-M7-B4Z"/>
<constraint firstItem="V9c-pl-MwJ" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="43" id="Yy5-S5-Cya"/>
<constraint firstItem="V9c-pl-MwJ" firstAttribute="top" secondItem="Wuv-Jo-ClG" secondAttribute="bottom" constant="43" id="Zve-oH-e3d"/>
<constraint firstItem="nIS-b5-Znx" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="32" id="eXY-M7-Pr3"/>
<constraint firstItem="Npn-Yc-tdh" firstAttribute="leading" secondItem="V9c-pl-MwJ" secondAttribute="trailing" constant="14" id="fsX-Yg-e6H"/>
<constraint firstItem="WJ0-hg-B3V" firstAttribute="top" secondItem="V9c-pl-MwJ" secondAttribute="bottom" constant="33" id="jde-oz-U0Z"/>
<constraint firstItem="Wuv-Jo-ClG" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="jvn-y1-rhk"/>
<constraint firstItem="mhe-iG-xpQ" firstAttribute="leading" secondItem="WJ0-hg-B3V" secondAttribute="trailing" constant="14" id="mtk-S9-8gj"/>
<constraint firstItem="nIS-b5-Znx" firstAttribute="top" secondItem="mhe-iG-xpQ" secondAttribute="bottom" constant="30" id="o7O-fW-YYu"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="nIS-b5-Znx" secondAttribute="trailing" constant="32" id="rBI-QN-iRX"/>
<constraint firstItem="mhe-iG-xpQ" firstAttribute="top" secondItem="gYc-Ja-g1G" secondAttribute="bottom" constant="9" id="tOz-jV-5rW"/>
<constraint firstItem="WJ0-hg-B3V" firstAttribute="top" secondItem="gYc-Ja-g1G" secondAttribute="top" id="xJX-Y8-jCb"/>
</constraints>
<point key="canvasLocation" x="23.664122137404579" y="19.718309859154932"/>
</view>
</objects>
<resources>
<image name="icon_congratulate_points" width="46" height="46"/>
<image name="icon_congratulate_star" width="46" height="46"/>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>
//
// GuideTipsModel.swift
// PhoneManager
//
// Created by edy on 2025/4/27.
//
import Foundation
enum GuideTipsType{
case duplicates,similar,video,photo
}
extension GuideTipsType{
var tipOneIcon:String{
switch self {
case .duplicates:
return "tips_duplicates_1"
case .similar:
return "tips_similar_1"
case .video:
return "tips_video"
case .photo:
return "tips_photos"
}
}
var tipTwoIcon:String{
switch self {
case .duplicates:
return "tips_duplicates_2"
case .similar:
return "tips_similar_2"
case .video:
return ""
case .photo:
return ""
}
}
var title:String{
switch self {
case .duplicates:
return "Duplicates"
case .similar:
return "Similar photos"
case .video:
return "Video"
case .photo:
return "Photo"
}
}
var lineText:String{
switch self {
case .duplicates:
return "2 Duplicates"
case .similar:
return "2 Similar"
case .video:
return ""
case .photo:
return ""
}
}
var text:String{
switch self {
case .duplicates:
return "These are duplicate photos - they are completely identical to each other. Immediately delete all duplicate items and keep the original version."
case .similar:
return "We will group similar photos together and provide recommendations for the best photos. Please safely view and select the photos you want to move to the trash can."
case .video:
return "View all of your videos. Sort them by size or date. View the video that occupies the maximum space."
case .photo:
return "These are photos that do not belong to any category. Sort them by size or date. Delete unnecessary photos."
}
}
}
struct TipsManager{
static func saveLoadStatus(_ type:PhotsFileType){
let key = "isFirstShow_\(type.rawValue)"
UserDefaults.standard.set(true, forKey:key)
UserDefaults.standard.synchronize()
}
static func getLoadStauts(_ type:PhotsFileType) ->Bool{
let key = "isFirstShow_\(type.rawValue)"
if let show = UserDefaults.standard.value(forKey: key) as? Bool{
return show
}
return false
}
}
//
// TipsDuplicatesSimilarController.swift
// PhoneManager
//
// Created by edy on 2025/4/27.
//
import UIKit
class TipsDuplicatesSimilarController: UIViewController {
@IBOutlet weak var lineText: UILabel!
@IBOutlet weak var startBtn: UIButton!
@IBOutlet weak var iconOne: UIImageView!
@IBOutlet weak var iconTwo: UIImageView!
@IBOutlet weak var mainTitle: UILabel!
@IBOutlet weak var subTitle: UILabel!
var type:GuideTipsType = .duplicates
override func viewDidLoad() {
super.viewDidLoad()
startBtn.layer.cornerRadius = 15
lineText.text = type.lineText
iconOne.image = UIImage.init(named: type.tipOneIcon)
iconTwo.image = UIImage.init(named: type.tipTwoIcon)
mainTitle.text = type.title
subTitle.text = type.text
}
@IBAction func startClick(_ sender: Any) {
self.dismiss(animated: true)
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="TipsDuplicatesSimilarController" customModule="PhoneManager" customModuleProvider="target">
<connections>
<outlet property="iconOne" destination="5sP-3G-R5V" id="ypq-LB-87o"/>
<outlet property="iconTwo" destination="LIQ-mA-CKi" id="Uzy-Sr-7tG"/>
<outlet property="lineText" destination="XMa-dY-JFG" id="WBd-Yf-wR9"/>
<outlet property="mainTitle" destination="U5t-M8-fCd" id="jid-KN-rNY"/>
<outlet property="startBtn" destination="XPg-Ph-1k0" id="7Mg-rg-FE6"/>
<outlet property="subTitle" destination="OOD-68-wMD" id="d2D-yK-Txg"/>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="tips_duplicates_1" translatesAutoresizingMaskIntoConstraints="NO" id="5sP-3G-R5V">
<rect key="frame" x="41" y="202" width="299" height="137.33333333333337"/>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="2 Duplicates" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="XMa-dY-JFG">
<rect key="frame" x="40" y="164" width="97" height="20"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="16"/>
<color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="tips_duplicates_1" translatesAutoresizingMaskIntoConstraints="NO" id="LIQ-mA-CKi">
<rect key="frame" x="41" y="397.33333333333331" width="299" height="137.33333333333331"/>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="2 Duplicates" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dRr-c6-YoB">
<rect key="frame" x="40" y="359.33333333333331" width="97" height="20"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="16"/>
<color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Duplicates" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="U5t-M8-fCd">
<rect key="frame" x="128.33333333333334" y="561.66666666666663" width="124.66666666666666" height="30"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="25"/>
<color key="textColor" red="0.10196078431372549" green="0.10196078431372549" blue="0.10196078431372549" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</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="OOD-68-wMD">
<rect key="frame" x="25" y="609.66666666666663" width="343" height="50.333333333333371"/>
<string key="text">These are duplicate photos - they are completely identical to each other. Immediately delete all duplicate items and keep the original version.</string>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="XPg-Ph-1k0">
<rect key="frame" x="15" y="756" width="363" height="46"/>
<color key="backgroundColor" red="0.0" green="0.50980392156862742" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="46" id="DDB-jE-Azu"/>
</constraints>
<fontDescription key="fontDescription" type="boldSystem" pointSize="16"/>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" title="Let's start now"/>
<connections>
<action selector="startClick:" destination="-1" eventType="touchUpInside" id="nw0-Kr-1dU"/>
</connections>
</button>
</subviews>
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="U5t-M8-fCd" firstAttribute="top" secondItem="LIQ-mA-CKi" secondAttribute="bottom" constant="27" id="1A7-xR-AKP"/>
<constraint firstItem="XPg-Ph-1k0" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="15" id="8I8-jV-uJS"/>
<constraint firstItem="dRr-c6-YoB" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="40" id="BiE-te-3l5"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="XPg-Ph-1k0" secondAttribute="trailing" constant="15" id="Cb3-BS-U7O"/>
<constraint firstItem="5sP-3G-R5V" firstAttribute="top" secondItem="XMa-dY-JFG" secondAttribute="bottom" constant="18" id="TXF-uB-G74"/>
<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="LIQ-mA-CKi" firstAttribute="leading" secondItem="5sP-3G-R5V" secondAttribute="leading" id="cqt-w5-eff"/>
<constraint firstAttribute="bottom" secondItem="XPg-Ph-1k0" secondAttribute="bottom" constant="50" id="e8U-6l-271"/>
<constraint firstItem="dRr-c6-YoB" firstAttribute="top" secondItem="5sP-3G-R5V" secondAttribute="bottom" constant="20" id="eD3-DG-qkC"/>
<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="top" secondItem="U5t-M8-fCd" secondAttribute="bottom" constant="18" id="lO2-YE-hId"/>
<constraint firstItem="XMa-dY-JFG" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" constant="105" id="lQN-9H-9H5"/>
<constraint firstItem="LIQ-mA-CKi" firstAttribute="trailing" secondItem="5sP-3G-R5V" secondAttribute="trailing" id="qKI-bl-RGS"/>
<constraint firstItem="LIQ-mA-CKi" firstAttribute="top" secondItem="dRr-c6-YoB" secondAttribute="bottom" constant="18" id="qWW-HD-yM0"/>
<constraint firstItem="U5t-M8-fCd" firstAttribute="centerX" secondItem="LIQ-mA-CKi" secondAttribute="centerX" id="yXP-XE-VJ9"/>
<constraint firstItem="5sP-3G-R5V" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="41" id="zUb-2g-3eW"/>
</constraints>
<point key="canvasLocation" x="126" y="20"/>
</view>
</objects>
<resources>
<image name="tips_duplicates_1" width="281" height="137.33332824707031"/>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>
//
// TipsScreenShotController.swift
// PhoneManager
//
// Created by edy on 2025/4/27.
//
import UIKit
class TipsScreenShotController: UIViewController {
@IBOutlet weak var startBtn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
startBtn.layer.cornerRadius = 15
}
@IBAction func startClick(_ sender: Any) {
self.dismiss(animated: true)
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="TipsScreenShotController" customModule="PhoneManager" customModuleProvider="target">
<connections>
<outlet property="startBtn" destination="ybT-3z-Wb2" id="Gl8-Ue-VUX"/>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="430" height="932"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="tips_sreenshot" translatesAutoresizingMaskIntoConstraints="NO" id="QGK-yy-jOF">
<rect key="frame" x="17" y="105" width="396" height="396"/>
</imageView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ybT-3z-Wb2">
<rect key="frame" x="15" y="822" width="400" height="46"/>
<color key="backgroundColor" red="0.0" green="0.50980392159999999" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="46" id="4Qc-vw-6p8"/>
</constraints>
<fontDescription key="fontDescription" type="boldSystem" pointSize="16"/>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" title="Let's start now"/>
<connections>
<action selector="startClick:" destination="-1" eventType="touchUpInside" id="1KQ-NC-6EU"/>
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="ScreenShot" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="h8I-lL-ELV">
<rect key="frame" x="146.66666666666666" y="556" width="136.99999999999997" height="30"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="25"/>
<color key="textColor" red="0.1019607843" green="0.1019607843" blue="0.1019607843" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</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="VkR-UI-FBK">
<rect key="frame" x="25" y="604" width="380" height="50.333333333333371"/>
<string key="text">We will group similar screenshots together so that you can view them faster! Please safely view and select the customer cut-off you want to move to the trash can.</string>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="ybT-3z-Wb2" secondAttribute="trailing" constant="15" id="1CR-10-bnb"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="VkR-UI-FBK" secondAttribute="trailing" constant="25" id="4JU-rc-hns"/>
<constraint firstItem="QGK-yy-jOF" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="17" id="I80-yL-ctf"/>
<constraint firstItem="ybT-3z-Wb2" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="15" id="IIW-NA-SQU"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" secondItem="ybT-3z-Wb2" secondAttribute="bottom" constant="30" 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="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="VkR-UI-FBK" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="25" id="qMJ-l4-yde"/>
<constraint firstItem="h8I-lL-ELV" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="qMT-Hi-GFU"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="QGK-yy-jOF" secondAttribute="trailing" constant="17" id="tuK-Vk-YgB"/>
</constraints>
<point key="canvasLocation" x="82" y="24"/>
</view>
</objects>
<resources>
<image name="tips_sreenshot" width="341" height="396"/>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>
//
// TipsVideoPhotoController.swift
// PhoneManager
//
// Created by edy on 2025/4/27.
//
import UIKit
class TipsVideoPhotoController: UIViewController {
@IBOutlet weak var startBtn: UIButton!
@IBOutlet weak var mainTitle: UILabel!
@IBOutlet weak var icon: UIImageView!
@IBOutlet weak var subtitle: UILabel!
var type:GuideTipsType = .duplicates
override func viewDidLoad() {
super.viewDidLoad()
startBtn.layer.cornerRadius = 15
icon.image = UIImage.init(named: type.tipOneIcon)
mainTitle.text = type.title
subtitle.text = type.text
}
@IBAction func startClick(_ sender: Any) {
self.dismiss(animated: true)
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="TipsVideoPhotoController" customModule="PhoneManager" customModuleProvider="target">
<connections>
<outlet property="icon" destination="OpM-5k-AoO" id="Y63-tI-7xy"/>
<outlet property="mainTitle" destination="dcU-ld-SUp" id="ngg-L4-U4l"/>
<outlet property="startBtn" destination="KHL-A7-P8d" id="qKH-gd-iBZ"/>
<outlet property="subtitle" destination="LeZ-aM-wDE" id="SaD-9Z-sOc"/>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="tips_photos" translatesAutoresizingMaskIntoConstraints="NO" id="OpM-5k-AoO">
<rect key="frame" x="65.666666666666686" y="169" width="262" height="306"/>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Other photos" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dcU-ld-SUp">
<rect key="frame" x="119.66666666666667" y="555" width="153.66666666666663" height="30"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="25"/>
<color key="textColor" red="0.1019607843" green="0.1019607843" blue="0.1019607843" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="These are photos that do not belong to any category. Sort them by size or date. Delete unnecessary photos." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="LeZ-aM-wDE">
<rect key="frame" x="25" y="603" width="343" height="50.333333333333371"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="KHL-A7-P8d">
<rect key="frame" x="15" y="742" width="363" height="46"/>
<color key="backgroundColor" red="0.0" green="0.50980392159999999" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="46" id="bCa-jh-IT1"/>
</constraints>
<fontDescription key="fontDescription" type="boldSystem" pointSize="16"/>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" title="Let's start now"/>
<connections>
<action selector="startClick:" destination="-1" eventType="touchUpInside" id="66j-JZ-X0u"/>
</connections>
</button>
</subviews>
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="OpM-5k-AoO" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="0N1-Db-xJx"/>
<constraint firstItem="OpM-5k-AoO" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" constant="110" id="BQx-h1-esb"/>
<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"/>
<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" constant="30" id="SCz-tZ-pgH"/>
<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"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="LeZ-aM-wDE" secondAttribute="trailing" constant="25" id="lAh-or-e83"/>
<constraint firstItem="LeZ-aM-wDE" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="25" id="plq-KA-cxw"/>
</constraints>
<point key="canvasLocation" x="22" y="20"/>
</view>
</objects>
<resources>
<image name="tips_photos" width="262" height="306"/>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>
//
// FileManager.swift
// PhoneManager
//
// Created by edy on 2025/4/27.
//
import Foundation
import Photos
struct FileTool{
enum StorageType{
case total,used,free
}
func getStorageInfo(for type: StorageType) -> Int64? {
let fileManager = FileManager.default
do {
// 获取主目录的文件系统属性
let systemAttributes = try fileManager.attributesOfFileSystem(forPath: NSHomeDirectory())
// 获取总存储和可用空间
guard let totalSize = systemAttributes[FileAttributeKey.systemSize] as? NSNumber,
let freeSize = systemAttributes[FileAttributeKey.systemFreeSize] as? NSNumber else {
return nil // 返回 nil 如果无法获取所需信息
}
switch type {
case .total:
return totalSize.int64Value // 返回总存储
case .free:
return freeSize.int64Value // 返回可用存储
case .used:
let usedSize = totalSize.int64Value - freeSize.int64Value // 计算已用存储
return usedSize
}
} catch {
print("Error retrieving storage info: \(error)")
return nil
}
}
func formatBytes(_ bytes: Int64) -> String {
let formatter = ByteCountFormatter()
formatter.allowedUnits = [.useKB, .useMB, .useGB] // 选择合适的单位
formatter.countStyle = .file
return formatter.string(fromByteCount: bytes)
}
func calculateTotalAssetSize(fetchResult: PHFetchResult<PHAsset>) -> Int64 {
var totalSize: Int64 = 0
fetchResult.enumerateObjects { (asset, index, stop) in
let resources = PHAssetResource.assetResources(for: asset)
print("当前 asset: \(asset)")
print("资源数量: \(resources.count)")
for resource in resources {
print("资源类型: \(resource.type)")
if let fileSize = resource.value(forKey: "fileSize") as? Int64 {
print("文件大小: \(fileSize)")
totalSize += fileSize
} else {
print("无法获取文件大小")
}
}
}
return totalSize
}
}
import UserNotifications
class NotificationManager {
func configNotifications(){
if let secondlaunch = UserDefaults.standard.value(forKey: "notifications_is_secondlaunch") as? Bool{
if secondlaunch{
Print("二次启动,获取通知权限")
scheduleLocalNotifications()
}
}else{
UserDefaults.standard.setValue(true, forKey: "notifications_is_secondlaunch")
UserDefaults.standard.synchronize()
Print("启动第一次,记录下")
}
}
// 调度本地通知
func scheduleLocalNotifications() {
// 请求通知权限
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { granted, error in
if granted {
// 创建并调度通知
// self.createNotifications()
self.scheduleNotificationsEveryTwoMinutes()
} else {
print("通知权限未被授予: \(String(describing: error))")
}
}
}
// 创建并调度通知
private func createNotifications() {
let content = UNMutableNotificationContent()
content.title = NotificationManagerData().getShowTitle()
content.body = NotificationManagerData().getAlertSubtitle()
content.sound = UNNotificationSound.default
// 定义每天的通知时间
let notificationTimes = [
(hour: 9, minute: 0), // 早上 9 点
(hour: 15, minute: 0), // 下午 3 点
(hour: 21, minute: 0) // 晚上 9 点
]
// 创建通知
for time in notificationTimes {
var dateComponents = DateComponents()
dateComponents.hour = time.hour
dateComponents.minute = time.minute
// 设置触发条件为每天
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
// 创建请求
let request = UNNotificationRequest(identifier: "\(time.hour)-\(time.minute)", content: content, trigger: trigger)
// 添加请求到通知中心
UNUserNotificationCenter.current().add(request) { error in
if let error = error {
print("添加通知请求时出错: \(error)")
}
}
}
}
// 每 2 分钟调度一次通知
func scheduleNotificationsEveryTwoMinutes() {
let content = UNMutableNotificationContent()
content.title = NotificationManagerData().getShowTitle()
content.body = NotificationManagerData().getAlertSubtitle()
content.sound = UNNotificationSound.default
// 创建触发条件为每 2 分钟
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 600, repeats: true)
// 创建请求
let request = UNNotificationRequest(identifier: "twoMinuteNotification", content: content, trigger: trigger)
// 添加请求到通知中心
UNUserNotificationCenter.current().add(request) { error in
if let error = error {
print("添加每 2 分钟通知请求时出错: \(error)")
}
}
}
// 取消所有通知
func cancelAllLocalNotifications() {
UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
print("所有本地通知已被取消")
}
}
struct NotificationManagerData{
func getShowTitle() ->String{
return "You can free up more storage space!"
}
func getAlertSubtitle() ->String{
return "100 videos and 100 photos are waiting in the \"video&others\" section."
}
}
......@@ -665,6 +665,7 @@ class PhotoAndVideoMananger {
}
}
// MARK: - 新方法处理相似图片向下-------------------------------------------------------
// 做一下缓存
......
//
// APPConfig.swift
// PhoneManager
//
// Created by edy on 2025/4/27.
//
import Foundation
struct APPConfig{
static let APPID = "1530333201"
}
func KEYWINDOW() ->UIWindow?{
return UIApplication.shared.windows.first{$0.isKeyWindow}
}
......@@ -2,6 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>aps-environment</key>
<string>development</string>
<key>com.apple.security.application-groups</key>
<array>
<string>group.com.app.phonemanager</string>
......
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