Commit ea238559 authored by CZ1004's avatar CZ1004

Merge branch 'Advertisement' of…

Merge branch 'Advertisement' of http://gitlab.zhangxindiet.com/ShuMing/phonemanager into Advertisement

* 'Advertisement' of http://gitlab.zhangxindiet.com/ShuMing/phonemanager:
  fix bugs
  取消删除照片动画立即小时处理
  1.删除加载动画 2.启动页面重制完成 3.UI适配修复 4.通知功能完善
parents 0dbf1f97 5f11fba4
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "huadong@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "huadong@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "lunbo@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "lunbo@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "lunbo@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "lunbo@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "tongjitu@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "tongjitu@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "lunbo@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "lunbo@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "shuye@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "shuye@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "zhaopian@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "icon_fanhui@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "icon_fanhui@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
......@@ -303,23 +303,28 @@ class CompressCompletedViewController : BaseViewController{
let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: idents, options: nil)
let fileSize = FileTool().calculateTotalAssetSize(fetchResult: fetchResult)
let assetToDelete = fetchResult.firstObject
PMLoadingHUD.share.show()
PHPhotoLibrary.shared().performChanges ({
PHAssetChangeRequest.deleteAssets([assetToDelete] as NSFastEnumeration)
}){ success, error in
if(success){
var models :[AssetModel] = []
var count = 0
for ele in self.model! {
count = count + 1
self.updateCompressData(flag: ele.ident)
let deleteModel = AssetModel(localIdentifier: ele.ident, assetSize: ele.orgSize, createDate: ele.createDate)
models.append(deleteModel)
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
PMLoadingHUD.share.disMiss()
var models :[AssetModel] = []
var count = 0
for ele in self.model! {
count = count + 1
self.updateCompressData(flag: ele.ident)
let deleteModel = AssetModel(localIdentifier: ele.ident, assetSize: ele.orgSize, createDate: ele.createDate)
models.append(deleteModel)
}
PhotoDataManager.manager.removeDataWhenDeleteInPage(data: models)
print("删除文件成功")
self.showDeleteSuccess(fileCount:count, fileSize: fileSize)
self.jumpToCompressVC()
}
PhotoDataManager.manager.removeDataWhenDeleteInPage(data: models)
print("删除文件成功")
self.showDeleteSuccess(fileCount:count, fileSize: fileSize)
self.jumpToCompressVC()
}else {
PMLoadingHUD.share.disMiss()
if let error = error {
print("删除文件时出错: \(error.localizedDescription)")
}
......
......@@ -64,39 +64,47 @@ class HomeInfoViewController:BaseViewController {
}
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()
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
PMLoadingHUD.share.disMiss()
// 更新免费次数
if isAfterAdv == false {
updateFreeTimes()
}
}
self.showDeleteSuccess(fileCount: tempStringArray.count, fileSize: fileSize)
self.showDeleteSuccess(fileCount: tempStringArray.count, fileSize: fileSize)
// 删除缓存数据
PhotoDataManager.manager.removeDataWhenDeleteInPage(data: imgs)
// 更新下ids
PhotoDataManager.manager.loadFromFileSystem(resultModel: {[weak self] model in
DispatchQueue.main.async {
if self?.type == .duplicates {
self?.ids = model.titleModelArray[0].assets
}
if self?.type == .similar {
self?.ids = model.titleModelArray[1].assets
}
if self?.type == .SimilarVideos {
self?.ids = model.otherModelArray[3].assets
}
if self?.type == .similarScreenshots {
self?.ids = model.otherModelArray[1].assets
// 删除缓存数据
PhotoDataManager.manager.removeDataWhenDeleteInPage(data: imgs)
// 更新下ids
PhotoDataManager.manager.loadFromFileSystem(resultModel: {[weak self] model in
DispatchQueue.main.async {
if self?.type == .duplicates {
self?.ids = model.titleModelArray[0].assets
}
if self?.type == .similar {
self?.ids = model.titleModelArray[1].assets
}
if self?.type == .SimilarVideos {
self?.ids = model.otherModelArray[3].assets
}
if self?.type == .similarScreenshots {
self?.ids = model.otherModelArray[1].assets
}
self?.tablewView.ids = self?.ids
self?.tablewView.deleteModel(array: imgs)
}
self?.tablewView.ids = self?.ids
self?.tablewView.deleteModel(array: imgs)
}
})
})
}
// 更新下首页数据以及缓存数据
let dataUpdated = Notification.Name("DataUpdatedNotification")
NotificationCenter.default.post(name: dataUpdated, object: nil, userInfo: nil)
......
......@@ -557,21 +557,30 @@ extension HomePhotosDetailViewController:WaterfallMutiSectionDelegate,UICollecti
let allIdent = self.selectedModel.map{ $0.localIdentifier }
let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: allIdent, options: nil)
let fileSize = FileTool().calculateTotalAssetSize(fetchResult: fetchResult)
PMLoadingHUD.share.show()
PHPhotoLibrary.shared().performChanges ({
PHAssetChangeRequest.deleteAssets(fetchResult as NSFastEnumeration)
}){ success, error in
if(success){
print("删除文件成功")
if isAfterAdv == false {
self.updateFreeTimes()
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
PMLoadingHUD.share.disMiss()
if isAfterAdv == false {
self.updateFreeTimes()
}
self.showDeleteSuccess(fileCount: allIdent.count, fileSize: fileSize)
self.updateCurrentPageWhenDeleteAny()
}
self.showDeleteSuccess(fileCount: allIdent.count, fileSize: fileSize)
self.updateCurrentPageWhenDeleteAny()
}else {
PMLoadingHUD.share.disMiss()
if let error = error {
print("删除文件时出错: \(error.localizedDescription)")
}
}
}
}
......
......@@ -473,25 +473,29 @@ extension HomeVideoDetailController:WaterfallMutiSectionDelegate,UICollectionVie
// 删除当前选择
let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: self.selectedModel.map{$0.localIdentifier}, options: nil)
let fileSize = FileTool().calculateTotalAssetSize(fetchResult: fetchResult)
PMLoadingHUD.share.show()
PHPhotoLibrary.shared().performChanges ({
PHAssetChangeRequest.deleteAssets(fetchResult as NSFastEnumeration)
}){ success, error in
if(success){
print("删除文件成功")
// 如果是看广告删除的,且还有免费次数
if isAfterAdv == false {
self.updateFreeTimes()
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
PMLoadingHUD.share.disMiss()
print("删除文件成功")
// 如果是看广告删除的,且还有免费次数
if isAfterAdv == false {
self.updateFreeTimes()
}
self.showDeleteSuccess(fileCount: self.selectedModel.count, fileSize: fileSize)
// 移除当前总数据源的数据
self.updateCurrentPageWhenDeleteAny()
}
self.showDeleteSuccess(fileCount: self.selectedModel.count, fileSize: fileSize)
// 移除当前总数据源的数据
self.updateCurrentPageWhenDeleteAny()
}else {
PMLoadingHUD.share.disMiss()
if let error = error {
print("删除文件时出错: \(error.localizedDescription)")
}
}
}
}
......
......@@ -70,7 +70,7 @@ class LandingVC:UIViewController {
}else {
changeCurrentIndex(index: nextIndex)
// changeCurrentIndex(index: nextIndex)
}
}
......
//
// NewGuideViewController.swift
// PhoneManager
//
// Created by edy on 2025/4/28.
//
import UIKit
class NewGuideViewController: UIViewController {
@IBOutlet weak var privacyL: UILabel!
@IBOutlet weak var dotImage: UIImageView!
@IBOutlet weak var collectionView: UICollectionView!
var timer: Timer?
@IBOutlet weak var startBtn: UIButton!
@IBOutlet weak var termsL: UILabel!
let dots = ["icon_guide_one","icon_guide_two","icon_guide_three"]
var index = 0
override func viewDidLoad() {
super.viewDidLoad()
configUI()
startTimer()
}
func configUI(){
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.minimumLineSpacing = 0
layout.minimumInteritemSpacing = 0
collectionView.setCollectionViewLayout(layout, animated: false)
collectionView.delegate = self
collectionView.dataSource = self
collectionView.isScrollEnabled = false
collectionView.backgroundColor = .white
collectionView.isPagingEnabled = true // 启用分页
collectionView.showsHorizontalScrollIndicator = false
collectionView.register(UINib.init(nibName: "NewGuideOneCell", bundle: nil), forCellWithReuseIdentifier: "NewGuideOneCell")
collectionView.register(UINib.init(nibName: "NewGuideTwoCell", bundle: nil), forCellWithReuseIdentifier: "NewGuideTwoCell")
collectionView.register(UINib.init(nibName: "NewGuideThreeCell", bundle: nil), forCellWithReuseIdentifier: "NewGuideThreeCell")
privacyL.addUnderline()
termsL.addUnderline()
let onetap = UITapGestureRecognizer(target: self, action: #selector(pricyClick))
privacyL.isUserInteractionEnabled = true
privacyL.addGestureRecognizer(onetap)
let twotap = UITapGestureRecognizer(target: self, action: #selector(termClick))
termsL.isUserInteractionEnabled = true
termsL.addGestureRecognizer(twotap)
}
@IBAction func nextClick(_ sender: Any) {
if index < 2{
index += 1
collectionView.scrollToItem(at: IndexPath(row: index, section: 0), at: .centeredHorizontally, animated: true)
}else{
enterHome()
}
dotImage.image = UIImage.init(named: dots[index])
}
@objc func pricyClick(){
let vc:PrivacyPolicyWebViewController = PrivacyPolicyWebViewController()
vc.hidesBottomBarWhenPushed = true
self.navigationController?.pushViewController(vc, animated: true)
}
@objc func termClick(){
let vc:TermOfUseWebViewController = TermOfUseWebViewController()
vc.hidesBottomBarWhenPushed = true
self.navigationController?.pushViewController(vc, animated: true)
}
func enterHome(){
let vc:HomeViewController = HomeViewController()
let nav = BaseNavViewController(rootViewController: vc)
cWindow?.rootViewController = nav
let transition = CATransition()
transition.duration = 0.5
transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
// 添加动画到 window 的 layer
cWindow?.layer.add(transition, forKey: kCATransition)
// 显示 window
cWindow?.makeKeyAndVisible()
UserDef.shard.isShowLanding = true
UserDef.shard.saveUserDefToSandBox()
}
deinit{
timer?.invalidate()
}
func startTimer() {
// 创建定时器,每隔 3 秒调用一次
// timer = Timer.scheduledTimer(timeInterval: 3.5, target: self, selector: #selector(advanceToNextItem), userInfo: nil, repeats: true)
}
@objc func advanceToNextItem() {
if index < 2{
index += 1
collectionView.scrollToItem(at: IndexPath(row: index, section: 0), at: .centeredHorizontally, animated: true)
}else{
timer?.invalidate()
}
dotImage.image = UIImage.init(named: dots[index])
}
}
extension NewGuideViewController:UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return dots.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.row == 0{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "NewGuideOneCell", for: indexPath) as! NewGuideOneCell
return cell
}
if indexPath.row == 1{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "NewGuideTwoCell", for: indexPath) as! NewGuideTwoCell
return cell
}
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "NewGuideThreeCell", for: indexPath) as! NewGuideThreeCell
return cell
}
// MARK: - UICollectionViewDelegateFlowLayout
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return collectionView.bounds.size // 让单元格大小与 UICollectionView 的大小一致
}
}
This diff is collapsed.
......@@ -22,6 +22,8 @@ class PermissionVC:UIViewController {
private var isTOUClick:Bool = false
private var isNextClick:Bool = false
lazy var animationView:LottieAnimationView = {
let animationView = LottieAnimationView(name: "onboardingStorageLight")
......@@ -170,18 +172,18 @@ class PermissionVC:UIViewController {
private func gotoNext() {
guard isNextClick == false else{
return
}
isNextClick = true
DispatchQueue.main.async {[weak self] in
guard let self else {return}
let Ssoryboard = UIStoryboard(name: "LandingVC", bundle: nil)
if let current = Ssoryboard.instantiateViewController(identifier: "LandingVCID") as? LandingVC {
self.navigationController?.pushViewController(current, animated: true)
}
let vc = NewGuideViewController()
self.navigationController?.pushViewController(vc, animated: true)
}
}
private func ppClick() {
......
//
// NewGuideOneCell.swift
// PhoneManager
//
// Created by edy on 2025/4/28.
//
import UIKit
class NewGuideOneCell: UICollectionViewCell {
@IBOutlet weak var subtitle: UILabel!
@IBOutlet weak var htitle: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
setSubtitleAttr()
sethtitleAttr()
}
func setSubtitleAttr(){
// 创建富文本
let fullText = "Over 1000+ users worldwide"
// 创建可变的富文本字符串
let attributedString = NSMutableAttributedString(string: fullText)
// 定义 "1000+" 的范围
let range = (fullText as NSString).range(of: "1000+")
// 设置其他部分的属性(字体颜色为黑色,Regular 字体)
attributedString.addAttribute(.foregroundColor, value: UIColor.colorWithHex(hexStr: "#151515"), range: NSRange(location: 0, length: fullText.count))
attributedString.addAttribute(.font, value: UIFont.systemFont(ofSize: 24), range: NSRange(location: 0, length: fullText.count))
// 设置 "1000+" 的属性(字体颜色为蓝色,字体加粗)
attributedString.addAttribute(.foregroundColor, value: UIColor.colorWithHex(hexStr: "#0183FF"), range: range)
attributedString.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: 24), range: range)
// 将属性字符串设置为 UILabel 的文本
subtitle.attributedText = attributedString
}
func sethtitleAttr(){
// 创建富文本
let fullText = "Selected 'Phone manager'"
// 创建可变的富文本字符串
let attributedString = NSMutableAttributedString(string: fullText)
let range = (fullText as NSString).range(of: "'Phone manager'")
attributedString.addAttribute(.foregroundColor, value: UIColor.colorWithHex(hexStr: "#262626"), range: NSRange(location: 0, length: fullText.count))
attributedString.addAttribute(.foregroundColor, value: UIColor.colorWithHex(hexStr: "#0183FF"), range: range)
// 将属性字符串设置为 UILabel 的文本
htitle.attributedText = attributedString
}
}
//
// NewGuideThreeCell.swift
// PhoneManager
//
// Created by edy on 2025/4/28.
//
import UIKit
class NewGuideThreeCell: UICollectionViewCell {
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
}
<?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="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"/>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" id="gTV-IL-0wX" customClass="NewGuideThreeCell" customModule="PhoneManager" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="414" height="678"/>
<autoresizingMask key="autoresizingMask"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="414" height="678"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_guide_tongjitu" translatesAutoresizingMaskIntoConstraints="NO" id="vPU-c0-KKP">
<rect key="frame" x="85" y="316" width="244" height="239"/>
<constraints>
<constraint firstAttribute="height" constant="239" id="4zt-cu-Hqj" customClass="ScreenWidthRatioConstraint" customModule="PhoneManager" customModuleProvider="target"/>
<constraint firstAttribute="width" constant="244" id="gAB-82-r6I" customClass="ScreenWidthRatioConstraint" customModule="PhoneManager" customModuleProvider="target"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Experience higher accuracy and professionalism" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ZvL-Z4-1T4">
<rect key="frame" x="41.666666666666657" y="47" width="331" height="60"/>
<constraints>
<constraint firstAttribute="width" constant="331" id="Mal-f3-hVk"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="25"/>
<color key="textColor" red="0.08235294118" green="0.08235294118" blue="0.08235294118" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="1.56X" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="N0R-LM-a3O">
<rect key="frame" x="142.66666666666666" y="157" width="128.99999999999997" height="59"/>
<constraints>
<constraint firstAttribute="height" constant="59" id="A7Z-VL-TvL"/>
</constraints>
<fontDescription key="fontDescription" type="boldSystem" pointSize="48"/>
<color key="textColor" red="0.0" green="0.50980392159999999" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Industry average" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="HR3-Fr-izE">
<rect key="frame" x="96" y="216" width="222" height="43"/>
<constraints>
<constraint firstAttribute="height" constant="43" id="pQw-Xg-8E2"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="31"/>
<color key="textColor" red="0.08235294118" green="0.08235294118" blue="0.08235294118" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</view>
<viewLayoutGuide key="safeArea" id="ZTg-uK-7eu"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="HR3-Fr-izE" firstAttribute="top" secondItem="N0R-LM-a3O" secondAttribute="bottom" id="6eV-Ep-auM"/>
<constraint firstItem="ZvL-Z4-1T4" firstAttribute="centerX" secondItem="gTV-IL-0wX" secondAttribute="centerX" id="8X2-pX-F3n"/>
<constraint firstItem="vPU-c0-KKP" firstAttribute="centerX" secondItem="gTV-IL-0wX" secondAttribute="centerX" id="HLK-ZG-TjB"/>
<constraint firstItem="vPU-c0-KKP" firstAttribute="top" secondItem="HR3-Fr-izE" secondAttribute="bottom" constant="57" id="HPy-W3-HcW"/>
<constraint firstItem="N0R-LM-a3O" firstAttribute="top" secondItem="ZvL-Z4-1T4" secondAttribute="bottom" constant="50" id="IRN-zP-UZ0"/>
<constraint firstItem="HR3-Fr-izE" firstAttribute="centerX" secondItem="N0R-LM-a3O" secondAttribute="centerX" id="O9d-fI-MXB"/>
<constraint firstItem="N0R-LM-a3O" firstAttribute="centerX" secondItem="ZvL-Z4-1T4" secondAttribute="centerX" id="qXa-FX-3CI"/>
<constraint firstItem="ZvL-Z4-1T4" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" constant="47" id="zT2-fE-W1k"/>
</constraints>
<size key="customSize" width="414" height="678"/>
<point key="canvasLocation" x="62.595419847328245" y="241.5492957746479"/>
</collectionViewCell>
</objects>
<resources>
<image name="icon_guide_tongjitu" width="244" height="239"/>
</resources>
</document>
//
// NewGuideTwoCell.swift
// PhoneManager
//
// Created by edy on 2025/4/28.
//
import UIKit
import Lottie
class NewGuideTwoCell: UICollectionViewCell {
@IBOutlet weak var photoL: UILabel!
var sizeL:UILabel!
override func awakeFromNib() {
super.awakeFromNib()
contentView.addSubview(animationView)
animationView.snp.makeConstraints { make in
make.width.equalTo(270)
make.height.equalTo(27)
make.centerX.equalToSuperview()
make.top.equalTo(photoL.snp.bottom).offset(10)
}
sizeL = UILabel()
let sizeValue = FileTool().formatBytes(FileTool().getStorageInfo(for: .used) ?? 0 )
sizeL.text = "\(sizeValue) used"
sizeL.textColor = UIColor.colorWithHex(hexStr: "#151515")
sizeL.font = UIFont.systemFont(ofSize: 18, weight: .medium)
contentView.addSubview(sizeL)
sizeL.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.top.equalTo(animationView.snp.bottom).offset(5)
}
playAnimationWithDelay()
}
lazy var animationView:LottieAnimationView = {
let animationView = LottieAnimationView(name: "onboardingStorageLight")
animationView.animationSpeed = -1.0
animationView.layer.cornerRadius = 14
animationView.contentMode = .scaleAspectFill
animationView.clipsToBounds = true
return animationView
}()
func playAnimationWithDelay() {
// 播放动画
animationView.play(fromProgress: 0.4, toProgress: 1, loopMode: .playOnce) {[weak self] finished in
if finished {
// 动画播放完成后,延迟 2 秒再重新播放
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
self?.playAnimationWithDelay()
}
}
}
}
}
......@@ -131,9 +131,8 @@ class HomePayView:UIView {
self.addSubview(closeBtn!)
closeBtn?.snp.makeConstraints { make in
// make.centerY.equalTo(restoreBtn!)
make.top.equalToSuperview().offset(statusBarHeight + 10)
make.right.equalToSuperview().offset(-15)
make.left.equalToSuperview().offset(15)
make.width.height.equalTo(28)
}
......@@ -144,7 +143,7 @@ class HomePayView:UIView {
self.addSubview(titleLabel1!)
titleLabel1?.snp.makeConstraints { make in
make.top.equalToSuperview().offset(statusBarHeight + 68)
make.top.equalToSuperview().offset(statusBarHeight + (ScreenH <= 667 ? 35 : 68.RH()))
make.centerX.equalToSuperview()
}
......@@ -167,7 +166,7 @@ class HomePayView:UIView {
self.addSubview(photoImage)
photoImage.snp.makeConstraints { make in
make.top.equalTo(titleLabel2!.snp.bottom).offset(38)
make.top.equalTo(titleLabel2!.snp.bottom).offset(38.RH())
make.left.equalTo(48.RW())
make.size.equalTo(64)
}
......@@ -275,7 +274,7 @@ class HomePayView:UIView {
make.centerY.equalTo(appleLabel!)
make.right.equalToSuperview().offset(-marginLR)
}
payButton?.layer.cornerRadius = 25
payButton?.layer.cornerRadius = 32.5
payButton?.layer.masksToBounds = true
// 额外添加视图
......@@ -294,12 +293,11 @@ class HomePayView:UIView {
make.centerX.equalToSuperview()
make.top.equalTo(payDueView.snp.bottom).offset(20)
make.width.equalToSuperview().offset(-30)
make.height.equalTo(50)
make.height.equalTo(65)
})
contentView2?.layer.cornerRadius = 12
contentView2?.layer.masksToBounds = true
contentView2Title = UILabel()
contentView2Title?.text = "Free trial enabled"
......@@ -495,9 +493,9 @@ class HomePayView:UIView {
}
tipsView.snp.makeConstraints { make in
make.top.equalTo(animationView.snp.bottom).offset(92)
make.top.equalTo(animationView.snp.bottom).offset(ScreenH <= 667.0 ? 50 : 92.RH())
make.left.right.equalToSuperview().inset(12)
make.height.equalTo(121)
make.height.equalTo(110)
}
let freespace = UILabel()
......
//
// PMLoadingView.swift
// PhoneManager
//
// Created by edy on 2025/4/28.
//
import UIKit
import Lottie
class PMLoadingHUD{
static let share = PMLoadingHUD()
lazy var loadingView:PMLoadingView = {
let loadingView = PMLoadingView()
loadingView.frame = CGRect(x: 0, y: 0, width: ScreenW, height: ScreenH)
return loadingView
}()
func show(){
DispatchQueue.main.async {
KEYWINDOW()?.addSubview(self.loadingView)
self.loadingView.animationView.play()
}
}
func disMiss(){
DispatchQueue.main.async {
self.loadingView.animationView.stop()
self.loadingView.removeFromSuperview()
}
}
}
class PMLoadingView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = UIColor.black.withAlphaComponent(0.8)
addSubview(animationView)
animationView.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.centerY.equalToSuperview()
make.width.equalTo(300)
make.height.equalTo(200)
}
let title = UILabel()
title.text = "Deleting..."
title.textColor = .white
title.font = UIFont.systemFont(ofSize: 18, weight: .semibold)
addSubview(title)
let subtitle = UILabel()
subtitle.text = "Please wait on the screen. This might take several minutes."
subtitle.textColor = .white
subtitle.numberOfLines = 0
subtitle.textAlignment = .center
subtitle.font = UIFont.systemFont(ofSize: 18, weight: .semibold)
addSubview(subtitle)
title.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.top.equalTo(animationView.snp.bottom).offset(-80)
}
subtitle.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.width.equalTo(250)
make.top.equalTo(title.snp.bottom).offset(2)
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
lazy var animationView : LottieAnimationView = {
let animationView = LottieAnimationView(name: "PMAnimationLoaing")
animationView.loopMode = .loop
return animationView
}()
}
......@@ -18,6 +18,8 @@ class CustomRate{
}
class CustomRateView: UIView {
@IBOutlet weak var bgView: UIView!
......
......@@ -16,6 +16,7 @@ class DelSuccessViewController: UIViewController {
@IBOutlet weak var points: UILabel!
@IBOutlet weak var delText: UILabel!
@IBOutlet weak var conTitle: UILabel!
var delType:String = "photo"
var fileCount:Int = 0
......@@ -25,8 +26,15 @@ class DelSuccessViewController: UIViewController {
super.viewDidLoad()
bottomBtn.layer.cornerRadius = 15
animationView.frame = CGRect(x: (ScreenW-250)/2+20, y: 80, width: 250, height: 250) // 设置 frame
// animationView.frame = CGRect(x: (ScreenW-CGFloat(250.RH()))/2 + 20.RW(), y: 70.RH(), width: 250.RH(), height: 250.RH()) // 设置 frame
view.addSubview(animationView)
animationView.snp.makeConstraints { make in
make.centerX.equalToSuperview().offset(20.RW())
make.bottom.equalTo(conTitle.snp.top).offset(15)
make.size.equalTo(250)
}
startAnimation()
reloadUI()
}
......@@ -90,11 +98,6 @@ class DelSuccessViewController: UIViewController {
let otherRange = (delTextString as NSString).range(of: "(\(formattedSize))") // 获取其他文本的范围
delTextAttributedString.addAttribute(.foregroundColor, value: UIColor.colorWithHex(hexStr: "#1A1A1A"), range: otherRange)
delText.attributedText = delTextAttributedString
}
}
......@@ -13,6 +13,7 @@
<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="conTitle" destination="Wuv-Jo-ClG" id="8fE-sb-OjD"/>
<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"/>
......@@ -85,13 +86,13 @@
<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="Wuv-Jo-ClG" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" constant="246" id="D2b-Te-XzC" customClass="ScreenHeightRatioConstraint" customModule="PhoneManager" customModuleProvider="target"/>
<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="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="43" id="Yy5-S5-Cya" customClass="ScreenWidthRatioConstraint" customModule="PhoneManager" customModuleProvider="target"/>
<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"/>
......
......@@ -23,7 +23,7 @@ class TipsDuplicatesSimilarController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
startBtn.layer.cornerRadius = 15
startBtn.layer.cornerRadius = 23
lineText.text = type.lineText
iconOne.image = UIImage.init(named: type.tipOneIcon)
......
......@@ -13,7 +13,7 @@ class TipsScreenShotController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
startBtn.layer.cornerRadius = 15
startBtn.layer.cornerRadius = 23
}
......
......@@ -21,7 +21,11 @@
<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"/>
<rect key="frame" x="44.666666666666657" y="105" width="341" height="396"/>
<constraints>
<constraint firstAttribute="height" constant="396" id="SIW-Kc-ZGi" customClass="ScreenHeightRatioConstraint" customModule="PhoneManager" customModuleProvider="target"/>
<constraint firstAttribute="width" constant="341" id="hZh-ma-7Bw" customClass="ScreenHeightRatioConstraint" customModule="PhoneManager" customModuleProvider="target"/>
</constraints>
</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"/>
......@@ -55,15 +59,14 @@
<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="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" 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>
......
......@@ -19,7 +19,7 @@ class TipsVideoPhotoController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
startBtn.layer.cornerRadius = 15
startBtn.layer.cornerRadius = 23
icon.image = UIImage.init(named: type.tipOneIcon)
......
......@@ -24,16 +24,16 @@
<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"/>
<rect key="frame" x="65.666666666666686" y="159" 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"/>
<rect key="frame" x="119.66666666666667" y="545" 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"/>
<rect key="frame" x="25" y="593" 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"/>
......@@ -56,13 +56,13 @@
<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 firstItem="OpM-5k-AoO" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" constant="100" id="BQx-h1-esb" customClass="ScreenHeightRatioConstraint" customModule="PhoneManager" customModuleProvider="target"/>
<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="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="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="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="LeZ-aM-wDE" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="25" id="plq-KA-cxw"/>
</constraints>
......
......@@ -2,7 +2,14 @@ import UserNotifications
class NotificationManager {
private var photos:Int = 10
private var videos:Int = 10
private var duplicates:Int = 10
private var similar:Int = 10
private var duplicatesSize:String = "100 MB"
func configNotifications(){
if let secondlaunch = UserDefaults.standard.value(forKey: "notifications_is_secondlaunch") as? Bool{
if secondlaunch{
Print("二次启动,获取通知权限")
......@@ -22,8 +29,7 @@ class NotificationManager {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { granted, error in
if granted {
// 创建并调度通知
// self.createNotifications()
self.scheduleNotificationsEveryTwoMinutes()
self.getCacheData()
} else {
print("通知权限未被授予: \(String(describing: error))")
}
......@@ -32,11 +38,6 @@ class NotificationManager {
// 创建并调度通知
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 点
......@@ -45,7 +46,7 @@ class NotificationManager {
]
// 创建通知
for time in notificationTimes {
for (index, time) in notificationTimes.enumerated() {
var dateComponents = DateComponents()
dateComponents.hour = time.hour
dateComponents.minute = time.minute
......@@ -53,6 +54,12 @@ class NotificationManager {
// 设置触发条件为每天
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
// 创建通知内容
let content = UNMutableNotificationContent()
content.title = getAlertMessage(index: index).0 // 根据时间点选择标题
content.body = getAlertMessage(index: index).1 // 根据时间点选择消息
content.sound = UNNotificationSound.default
// 创建请求
let request = UNNotificationRequest(identifier: "\(time.hour)-\(time.minute)", content: content, trigger: trigger)
......@@ -68,15 +75,17 @@ class NotificationManager {
// 每 2 分钟调度一次通知
func scheduleNotificationsEveryTwoMinutes() {
let content = UNMutableNotificationContent()
content.title = NotificationManagerData().getShowTitle()
content.body = NotificationManagerData().getAlertSubtitle()
content.title = ""//getAlertMessage().0
content.body = ""//getAlertMessage().1
content.sound = UNNotificationSound.default
// 创建触发条件为每 2 分钟
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 600, repeats: true)
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 60, repeats: true)
// 创建请求
let request = UNNotificationRequest(identifier: "twoMinuteNotification", content: content, trigger: trigger)
let date = Date().getDateString()
let id = date
let request = UNNotificationRequest(identifier: id, content: content, trigger: trigger)
// 添加请求到通知中心
UNUserNotificationCenter.current().add(request) { error in
......@@ -91,17 +100,87 @@ class NotificationManager {
UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
print("所有本地通知已被取消")
}
}
func getCacheData(){
PhotoDataManager.manager.loadFromFileSystem(resultModel: { model in
if let duplicates = model.titleModelArray.safeGet(index: 0)?.assets{
self.duplicates = duplicates.count
}
if let size = model.titleModelArray.safeGet(index: 0)?.allFileSize{
self.duplicatesSize = FileTool().formatBytes(Int64(size))
}
if let similar = model.titleModelArray.safeGet(index: 1)?.assets{
self.similar = similar.count
}
if let videos = model.otherModelArray.safeGet(index: 0)?.assets{
self.videos = videos.count
}
if let photos = model.otherModelArray.safeGet(index: 4)?.assets{
self.photos = photos.count
}
Print("缓存数据获取完成,注册通知")
self.createNotifications()
})
}
func getAlertMessage(index:Int) ->(String,String){
let titlts = ["You can free up more storage space!",
"More space is waiting to be cleared up",
"Arrange the photos in a secret space to gain more space!"]
let message = ["\(self.videos) videos and \(self.photos) photos are waiting in the \"video&others\" section.",
"\(self.duplicates) photos are waiting to be cleaned up in duplicates, approximately \(duplicatesSize).",
"\(self.similar) photos are placed in the \"Secret Space\" to free up more storage space."]
return (titlts[index],message[index])
}
struct NotificationManagerData{
func getShowTitle() ->String{
return "You can free up more storage space!"
}
// 扩展 Array
extension Array {
// 安全获取元素的方法
func safeGet(index: Int) -> Element? {
// 检查索引是否在有效范围内
guard index >= 0 && index < self.count else {
print("Index \(index) is out of bounds for array of size \(self.count).")
return nil // 返回 nil 表示越界
}
return self[index] // 返回对应的元素
}
}
extension Date {
/// 将 Date 转换为指定格式的字符串
/// - Parameter format: 日期格式字符串
/// - Returns: 格式化后的日期字符串
func toString(format: String) -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = format
return dateFormatter.string(from: self)
}
func getAlertSubtitle() ->String{
return "100 videos and 100 photos are waiting in the \"video&others\" section."
func getDateString(format:String = "yyyy-MM-dd HH:mm") ->String{
let dateFormatter = DateFormatter.init()
dateFormatter.dateFormat = format
dateFormatter.locale = .current
let dateStr = dateFormatter.string(from: self)
return dateStr
}
}
......@@ -697,6 +697,7 @@ class PhotoAndVideoMananger {
let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: localIdentifiers, options: nil)
// 开始删除操作
PMLoadingHUD.share.show()
PHPhotoLibrary.shared().performChanges({
// 创建删除请求
PHAssetChangeRequest.deleteAssets(fetchResult)
......@@ -704,6 +705,7 @@ class PhotoAndVideoMananger {
if success {
suc()
} else if let error = error {
PMLoadingHUD.share.disMiss()
print("删除失败: \(error.localizedDescription)")
}
}
......@@ -1175,14 +1177,20 @@ class SecretPhotoManager: NSObject, PhotoPickerControllerDelegate , CameraContro
func deleteAssets(_ assets:[PHAsset] = []) -> Void {
if assets.count > 0 {
PMLoadingHUD.share.show()
PHPhotoLibrary.shared().performChanges({
PHAssetChangeRequest.deleteAssets(assets as NSFastEnumeration)
}) { success, error in
if success {
print("删除成功")
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
PMLoadingHUD.share.disMiss()
}
} else if let error = error {
print("删除失败: \(error.localizedDescription)")
}
}
}
}
......
......@@ -63,3 +63,16 @@ func RScreenH() -> CGFloat {
return radio
}
let kSafeAreaInsets:UIEdgeInsets = kcWindow.safeAreaInsets
let kcWindow:UIWindow = {
if #available(iOS 13, *) {
return UIApplication.shared.connectedScenes
.compactMap { $0 as? UIWindowScene }
.first?.windows.first ?? UIWindow()
} else {
return UIApplication.shared.keyWindow ?? UIWindow()
}
}()
......@@ -245,6 +245,9 @@ extension Date {
return toDate
}
}
extension SKProduct {
......@@ -259,3 +262,44 @@ extension SKProduct {
return formatter.string(from: priceNumber) ?? ""
}
}
var borderWKey = "borderWKey"
var borderCKey = "borderCKey"
@IBDesignable
extension UIView {
@IBInspectable var Radius:Double {
set {
self.layer.cornerRadius = newValue
self.clipsToBounds = true
}
get {
return 0
}
}
@IBInspectable var borderColor:UIColor {
set {
self.layer.borderColor = newValue.cgColor
self.layer.borderWidth = self.borderWidth
self.clipsToBounds = true
objc_setAssociatedObject(self, &borderCKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
get {
return objc_getAssociatedObject(self, &borderCKey) as? UIColor ?? UIColor.clear
}
}
@IBInspectable var borderWidth:Double {
set {
self.layer.borderColor = self.borderColor.cgColor
self.layer.borderWidth = newValue
self.clipsToBounds = true
objc_setAssociatedObject(self, &borderWKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
get {
return objc_getAssociatedObject(self, &borderWKey) as? Double ?? 0.0
}
}
}
//
// ScreenHeightRatioConstraint.swift
// PhoneManager
//
// Created by edy on 2025/4/28.
//
import Foundation
import UIKit
class ScreenHeightRatioConstraint: NSLayoutConstraint {
// 存储比例基准值(812)
private let standardHeight: CGFloat = 812.0
override func awakeFromNib() {
super.awakeFromNib()
updateConstant()
}
private func updateConstant() {
// 获取当前屏幕高度
let screenHeight = UIScreen.main.bounds.height
// 确保 screenHeight 和 standardHeight 都是有效的
guard standardHeight.isFinite && screenHeight.isFinite else {
self.constant = 0 // 设置为默认值以避免崩溃
return
}
// 计算新的约束常量(直接使用屏幕高度与标准高度的比率)
let calculatedConstant = (screenHeight / 812.0) * self.constant
// 检查 calculatedConstant 是否为有限值
if calculatedConstant.isFinite {
self.constant = calculatedConstant
} else {
self.constant = 0 // 设置为默认值以避免崩溃
}
}
}
class ScreenWidthRatioConstraint: NSLayoutConstraint {
// 存储比例基准值(812)
private let standardWidth: CGFloat = 375.0
override func awakeFromNib() {
super.awakeFromNib()
updateConstant()
}
private func updateConstant() {
// 获取当前屏幕高度
let screenWidth = UIScreen.main.bounds.width
// 确保 screenHeight 和 standardHeight 都是有效的
guard standardWidth.isFinite && screenWidth.isFinite else {
self.constant = 0 // 设置为默认值以避免崩溃
return
}
// 计算新的约束常量(直接使用屏幕高度与标准高度的比率)
let calculatedConstant = (screenWidth / 375.0) * self.constant
// 检查 calculatedConstant 是否为有限值
if calculatedConstant.isFinite {
self.constant = calculatedConstant
} else {
self.constant = 0 // 设置为默认值以避免崩溃
}
}
}
......@@ -100,3 +100,51 @@ extension UILabel {
}
}
}
extension UILabel {
/// 获取label高度
/// - Parameters:
/// - maxSize: 最大高度,宽
/// - Returns: <#description#>
public func textHeight() -> CGSize {
let maxSize = CGSize(width: ScreenW, height: CGFloat(MAXFLOAT))
let attributedStr = NSMutableAttributedString.init(string: text ?? "")
let size = attributedStr.boundingRect(with: maxSize, options: .usesLineFragmentOrigin, context: nil).size
return size
}
/// 根据高度动态计算宽度(new)
func getLabelWidth(height: CGFloat) -> CGFloat {
return sizeThatFits(CGSize(width:CGFloat(MAXFLOAT), height: height)).width
}
/// 根据宽度动态计算高度(new)
func getLabelHeight(width: CGFloat) -> CGFloat {
return sizeThatFits(CGSize(width:width, height: CGFloat(MAXFLOAT))).height
}
/// 中间加下划线
func addLineInMiddle() {
guard let text = text else { return }
let attribute = NSMutableAttributedString.init(string: text)
attribute.addAttribute(NSAttributedString.Key.strikethroughStyle, value: NSNumber.init(value: 1), range: NSRange(location: 0, length: text.count))
attributedText = attribute
}
/// 中间加下划线
func addUnderline() {
guard let text = text else { return }
let attribute = NSMutableAttributedString(string: text)
// 添加下划线属性
attribute.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: NSRange(location: 0, length: text.count))
// 设置 UILabel 的 attributedText
attributedText = attribute
}
}
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