Commit 9febb62f authored by CZ1004's avatar CZ1004

Merge branch 'dev_main' into dev_zhaoqian

* dev_main:
  处理退款,修复保留bug,首页视频播放
  优化图片加载器
  订阅增加类型获取,新增年费会员
  年费会员界面,启动引导页结构更改
parents 78402c67 10caad0a
......@@ -27,13 +27,19 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
window?.backgroundColor = .white
window?.overrideUserInterfaceStyle = .light
let Ssoryboard = UIStoryboard(name: "LauchVC", bundle: nil)
if let current = Ssoryboard.instantiateViewController(identifier: "LauchVCID") as? LauchVC {
window?.rootViewController = current
let rootNav = BaseNavViewController(rootViewController: HomeViewController())
window?.rootViewController = rootNav
window?.makeKeyAndVisible()
}
// let Ssoryboard = UIStoryboard(name: "LauchVC", bundle: nil)
//
// if let current = Ssoryboard.instantiateViewController(identifier: "LauchVCID") as? LauchVC {
//
// window?.rootViewController = current
// window?.makeKeyAndVisible()
// }
let battery = WidgetPublicModel.battery()
let storage = WidgetPublicModel.UseDiskSpace() * 100
widgetAppgourp.share.PushWidgetData(battery: Int(battery), storage: Int(storage))
......@@ -52,6 +58,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
// 相册基本资源加载
PhotoManager.shared.config()
// 设置app动态按钮
setupDynamicShortcuts()
return true
}
......@@ -128,20 +136,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
private func setupDefault() {
IAPManager.share.checkSubscriptionState { isSubscribed, expiresDate in
Print("是否内购---",isSubscribed)
}
NetStatusManager.manager.startNet { status in
switch status {
case .NoNet:
break
case .WIFI,.WWAN:
if (PhotoAndVideoMananger.mananger.allAssets.count == 0) {
PhotoAndVideoMananger.mananger.setAssets()
}
break
}
}
......
//
// AppDelegateEx.swift
// PhoneManager
//
// Created by edy on 2025/5/19.
//
import Foundation
import UIKit
extension AppDelegate{
func setupDynamicShortcuts() {
let shortcutItem = UIApplicationShortcutItem(
type: "com.app.phonemanager.iap.distance",
localizedTitle: "Unlock Exclusive Discounts",
localizedSubtitle: "Your special offer is awaiting—don't miss this limited-time second chance benefit!",
icon: UIApplicationShortcutIcon(systemImageName: "star.fill"),
userInfo: nil
)
UIApplication.shared.shortcutItems = [shortcutItem]
}
// 处理快捷方式点击
func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
// 处理快捷方式点击事件
switch shortcutItem.type {
case "com.app.phonemanager.iap.distance":
// 执行相应操作
IAPManager.share.showYearPage = true
if IAPManager.share.isHotLaunch{
// 热启动走这里
switch IAPManager.share.subscriptionType {
case .none,.week:
let vc:PayDistanceViewController = PayDistanceViewController()
let nav:BaseNavViewController = BaseNavViewController(rootViewController: vc)
nav.modalPresentationStyle = .fullScreen
guard let rt = UIViewController.topMostViewController() else { return }
rt.present(nav, animated: true)
default:
let vc : PayCompletedViewController = PayCompletedViewController()
guard let rt = UIViewController.topMostViewController() else { return }
vc.modalPresentationStyle = .fullScreen
rt.present(vc, animated: true)
}
}
completionHandler(true)
default:
completionHandler(false)
}
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Frame@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Frame@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Frame_1171276222@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Frame_1171276222@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
......@@ -2,7 +2,12 @@ import UIKit
import Photos
// 图片缓存管理(单例)
private let imageCache = NSCache<NSString, UIImage>()
private let imageCache: NSCache<NSString, UIImage> = {
let cache = NSCache<NSString, UIImage>()
cache.totalCostLimit = 50 * 1024 * 1024 // 50MB
cache.countLimit = 100 // 最多缓存100张图片
return cache
}()
extension UIImageView {
// 关联对象键,用于存储当前请求的 localIdentifier
......@@ -34,7 +39,7 @@ extension UIImageView {
// 加载图片的主方法
func loadImage(
withLocalIdentifier identifier: String,
targetSize: CGSize = PHImageManagerMaximumSize,
targetSize: CGSize = CGSize(width: 300, height: 300),
placeholder: UIImage? = nil,
completion: ((UIImage?) -> Void)? = nil
) {
......@@ -67,9 +72,19 @@ extension UIImageView {
// 6. 配置图片请求选项
let options = PHImageRequestOptions()
options.version = .current
options.deliveryMode = .highQualityFormat
options.deliveryMode = .highQualityFormat // 改为渐进式加载
options.isNetworkAccessAllowed = true
options.resizeMode = .exact
options.resizeMode = .fast // 改为快速加载模式
options.isSynchronous = false
options.progressHandler = { progress, error, stop, info in
DispatchQueue.main.async {
// 可以在这里添加加载进度的处理
// print("Loading progress: \(progress)")
if let error = error {
print("Loading error: \(error.localizedDescription)")
}
}
}
// 7. 请求图片
currentRequestID = PHImageManager.default().requestImage(
......@@ -116,9 +131,18 @@ extension UIImageView {
}
}
// 清理缓存
@objc func clearCacheOnMemoryWarning() {
imageCache.removeAllObjects()
}
// 命名空间
struct AssetLoader {
fileprivate weak var imageView: UIImageView?
func clearImageCache() {
imageCache.removeAllObjects()
}
}
var asset: AssetLoader {
......
......@@ -34,6 +34,12 @@ enum BaseDataLoadingState {
case failed(Error)
}
enum FileType {
case json
case plist
case all
}
class PhotoManager{
......@@ -137,9 +143,14 @@ class PhotoManager{
private func requestAuthorization(){
// 获取基础数据
requestAuthorization {[weak self] _ in
requestAuthorization {[weak self] permission in
guard let weakSelf = self else { return }
if permission{
weakSelf.getBaseAssetGroup()
}else{
//weakSelf.clearLocalData()
}
}
}
......@@ -204,6 +215,7 @@ class PhotoManager{
let start = CFAbsoluteTimeGetCurrent()
self.videoModels = await convertAssetsToModel(for: self.videoAssets, mediaType: 2)
self.videoModels.sort { $0.createDate > $1.createDate }
let duration = CFAbsoluteTimeGetCurrent() - start
print("视频转换总耗时: \(duration)秒")
let videoTotalSize = Int64(self.videoModels.reduce(0){$0+$1.assetSize})
......@@ -233,6 +245,7 @@ class PhotoManager{
let start = CFAbsoluteTimeGetCurrent()
self.otherModels = await convertAssetsToModel(for: self.otherAssets, mediaType: 1)
self.otherModels.sort { $0.createDate > $1.createDate }
let duration = CFAbsoluteTimeGetCurrent() - start
print("其他图片转换总耗时: \(duration)秒")
let otherTotalSize = Int64(self.otherModels.reduce(0){$0+$1.assetSize})
......@@ -258,11 +271,11 @@ class PhotoManager{
self.screenShotTotalSize = screenShotTotalSize
complectionHandler?(localModels, screenShotTotalSize)
}
return
}
let start = CFAbsoluteTimeGetCurrent()
self.screenShotModels = await convertAssetsToModel(for: self.screenShotAssets, mediaType: 1)
self.screenShotModels.sort { $0.createDate > $1.createDate }
let duration = CFAbsoluteTimeGetCurrent() - start
print("截图转换总耗时: \(duration)秒")
let screenShotTotalSize = Int64(self.screenShotModels.reduce(0){$0+$1.assetSize})
......@@ -748,6 +761,11 @@ extension PhotoManager{
}
}
// 清楚本地存储数据
func clearLocalData(){
}
func removeAssets(withIdentifiers identifiers: [String], from assets: [AssetModel]) -> [AssetModel] {
let identifierSet = Set(identifiers)
......
......@@ -14,8 +14,12 @@ class HomeViewController:BaseViewController {
private var isShowCharge:Bool = false
private var canShowIAP:Bool = false
var homeView:HomeView?
fileprivate func junmToModule(_ cIndex: Int, _ self: HomeViewController) {
switch cIndex {
......@@ -107,7 +111,7 @@ class HomeViewController:BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
loadLaunchView()
self.setupUI()
// 调用下追踪权限
......@@ -182,6 +186,65 @@ class HomeViewController:BaseViewController {
}
func loadLaunchView(){
let luanch = HomeLaunchView(frame: CGRect(x: 0, y: 0, width: ScreenW, height: ScreenH))
luanch.show()
luanch.disMissBlock = {[weak self] in
guard let weakSelf = self else { return }
guard UserDef.shard.isShowLanding else{
return
}
weakSelf.showIAPVC()
}
if !UserDef.shard.isShowLanding{
let Ssoryboard = UIStoryboard(name: "PermissionVC", bundle: nil)
if let current = Ssoryboard.instantiateViewController(identifier: "PermissionVCID") as? PermissionVC {
self.navigationController?.pushViewController(current, animated: false)
}
}
NotificationCenter.default.addObserver(forName: .guidePageClose, object: nil, queue: nil) {[weak self] _ in
guard let weakSelf = self else { return }
weakSelf.showIAPVC()
}
}
func showIAPVC(){
IAPManager.share.isHotLaunch = true
IAPManager.share.checkSubscriptionState { isSubscribed,type,expiresDate in
Print("是否内购---",isSubscribed)
if IAPManager.share.showYearPage{
//按钮启动
switch type {
case .none,.week:
let vc:PayDistanceViewController = PayDistanceViewController()
let nav:BaseNavViewController = BaseNavViewController(rootViewController: vc)
nav.modalPresentationStyle = .fullScreen
self.present(nav, animated: true)
case .lifetime,.year:
let vc : PayCompletedViewController = PayCompletedViewController()
vc.modalPresentationStyle = .fullScreen
self.present(vc, animated: true)
}
}else{
// 正常启动
if !isSubscribed{
DispatchQueue.main.async {
if !IAPManager.share.showYearPage{
HomePayViewController.show {
NotificationManager().configNotifications()
}
}
}
}
}
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
......@@ -203,6 +266,21 @@ class HomeViewController:BaseViewController {
homeView?.viewModel.reloadTrashAndKeep()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.barHidden = false
// 开启定时器
Singleton.shared.startCountdown {}
if !isShowCharge {
NotificationManager().configNotifications()
return
}
}
}
extension HomeViewController {
......@@ -259,3 +337,4 @@ extension HomeViewController {
}
}
}
......@@ -60,10 +60,10 @@ class HomeCollectionViewHeader : UICollectionReusableView {
self.addSubview(self.permissionView)
self.permissionView.snp.makeConstraints { make in
make.top.equalTo(self.progressBar.snp.bottom).offset(-92)
make.top.equalTo(progressBar.snp.bottom).offset(10)
make.left.equalToSuperview().offset(-22)
make.right.equalToSuperview().offset(22)
make.height.equalTo(449)
make.height.equalTo(340)
}
......@@ -206,6 +206,7 @@ class CustomProgressBar: UIView {
progressLayer.frame = CGRect(x: 0, y: 0, width: ScreenW-48, height: 10)
progressLayer.cornerRadius = 5
progressLayer.masksToBounds = true
updateProgress()
}
......
......@@ -135,11 +135,4 @@ class HomeVideoDetailCustomHeaderView : UICollectionReusableView {
GETCURRENTNAV()?.pushViewController(vc, animated: true)
}
func GETCURRENTNAV() -> UINavigationController? {
let k = UIApplication.shared.windows.filter({$0.isKeyWindow}).first
let pre = k?.rootViewController?.presentedViewController
let rt = k?.rootViewController
return (pre as? UINavigationController) ?? ((rt as? UITabBarController)?.selectedViewController as? UINavigationController) ?? (rt as? UINavigationController)
}
}
......@@ -51,7 +51,7 @@ class HomeView:UIView {
sview.register(HomeTitleCollectionCell.self, forCellWithReuseIdentifier: HomeTitleCollectionCell.identifiers)
sview.register(HomeOtherCollectionCell.self, forCellWithReuseIdentifier: HomeOtherCollectionCell.identifier)
sview.register(HomeVideoCoverCell.classForCoder(), forCellWithReuseIdentifier: "HomeVideoCoverCell")
sview.register(HomeCollectionViewHeader.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "HomeCollectionViewHeader")
sview.register(UICollectionReusableView.self,forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter,withReuseIdentifier: "HomeCollectionViewFooter")
......@@ -278,11 +278,19 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
return cell
case 1:
if viewModel.cardGroup[indexPath.row].folderName == HomeUIEnum.SimilarVideos.title || viewModel.cardGroup[indexPath.row].folderName == HomeUIEnum.Videos.title{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HomeVideoCoverCell", for: indexPath) as! HomeVideoCoverCell
let model = viewModel.cardGroup[indexPath.row]
cell.reloadUIWithModel(model: model)
return cell
}else{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: HomeOtherCollectionCell.identifier, for: indexPath) as! HomeOtherCollectionCell
cell.dealMediaType(indexPath.row)
let model = viewModel.cardGroup[indexPath.row]
cell.reloadUIWithModel(model: model)
return cell
}
default:
return UICollectionViewCell()
}
......@@ -402,9 +410,9 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
func referenceSizeForHeader(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> CGSize {
if section == 0 {
if PhotoManager.shared.permissionStatus == .authorized{
return CGSize(width: self.collectionView.width, height: 76 + (self.homeNavView?.height ?? 0))
return CGSize(width:ScreenW-(marginLR*2), height: 76 + (self.homeNavView?.height ?? 0))
}else{
return CGSize(width: self.collectionView.width, height: 404)
return CGSize(width:ScreenW-(marginLR*2), height: 450)
}
}
return CGSize.zero
......
......@@ -12,7 +12,7 @@ class HomeTitleCollectionCell:UICollectionViewCell {
static let identifiers = "HomeTitleCollectionCellID"
private var titleLabel: UILabel?
private var titleLabel: UILabel!
public var fileLabel:UILabel?
......@@ -48,8 +48,8 @@ class HomeTitleCollectionCell:UICollectionViewCell {
titleLabel = UILabel()
titleLabel?.font = UIFont.systemFont(ofSize: 16, weight: .bold)
titleLabel?.textColor = UIColor.colorWithHex(hexStr: black3Color)
titleLabel.font = UIFont.systemFont(ofSize: 16, weight: .bold)
titleLabel.textColor = UIColor.colorWithHex(hexStr: black3Color)
fileLabel = UILabel()
fileLabel?.font = UIFont.systemFont(ofSize: 14, weight: .bold)
......@@ -118,8 +118,8 @@ class HomeTitleCollectionCell:UICollectionViewCell {
guard let model = model else { return }
self.model = model
titleLabel?.text = model.folderName
titleLabel?.sizeToFit()
titleLabel.text = model.folderName
titleLabel.sizeToFit()
var count = 0
......@@ -137,8 +137,8 @@ class HomeTitleCollectionCell:UICollectionViewCell {
assetsModels = assets.compactMap({ model in
return ImageCollectionModel.init(asset: model)
})
collectionView?.reloadData()
}
collectionView?.reloadData()
}
......@@ -155,12 +155,12 @@ class HomeTitleCollectionCell:UICollectionViewCell {
super.layoutSubviews()
titleLabel?.snp.makeConstraints({ make in
titleLabel.snp.makeConstraints({ make in
make.top.left.equalTo(16)
})
titleLabel?.sizeToFit()
titleLabel.sizeToFit()
fileLabel?.snp.makeConstraints({ make in
......@@ -172,9 +172,9 @@ class HomeTitleCollectionCell:UICollectionViewCell {
collectionView?.snp.makeConstraints({ make in
make.left.equalTo(16)
make.bottom.equalTo(-16)
make.bottom.equalTo(0)
make.right.equalTo(-16)
make.top.equalTo(48)
make.top.equalTo(titleLabel.snp.bottom).offset(13)
})
nextImage?.snp.makeConstraints({ make in
......@@ -205,7 +205,7 @@ extension HomeTitleCollectionCell:UICollectionViewDelegate,UICollectionViewDataS
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
// 计算 cell 宽度
return CGSize(width:collectionView.height - 2.5, height: collectionView.height - 2.5) // 宽高相等,形成网格
return CGSize(width:collectionView.height - 18, height: collectionView.height - 18) // 宽高相等,形成网格
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
......
//
// HomeVideoCoverCell.swift
// PhoneManager
//
// Created by edy on 2025/5/20.
//
import UIKit
import AVKit
class HomeVideoCoverCell: UICollectionViewCell {
var videoUrl:URL?
override init(frame: CGRect) {
super.init(frame: frame)
setupUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupUI() {
backgroundColor = .white
self.contentView.addSubview(self.titleLabel)
self.contentView.addSubview(self.imageView)
contentView.layer.addSublayer(playerLayer)
self.contentView.addSubview(self.infoBackView)
self.infoBackView.addSubview(self.countLabel)
self.infoBackView.addSubview(self.sizeLabel)
self.infoBackView.addSubview(self.moreImageView)
}
func reloadUIWithModel(model:HomePhotosModel?){
// 1. 先重置状态
guard let model else {
playerLayer.isHidden = true
videoPlayer.pause()
return
}
// 设置标题
self.titleLabel.text = model.folderName
// 获取数量
var count = 0
for item in model.assets {
count = count + item.count
}
// 设置数量文字
self.countLabel.text = "\(count) Videos"
// 设置文件大小文字
let sizeKB : Double = model.allFileSize/1000
if sizeKB < 1000{
self.sizeLabel.text = String(format: "(%.2lf) KB" ,sizeKB)
}else if sizeKB < (1000 * 1000) && sizeKB > 1000{
self.sizeLabel.text = String(format: "(%.2lf) MB" ,sizeKB/1000)
}else{
self.sizeLabel.text = String(format: "(%.2lf) GB" ,sizeKB/(1000 * 1000))
}
// 2. 设置新数据
if let id = model.assets.first?.first?.localIdentifier{
// 保存当前的 identifier 用于验证
let currentID = id
imageView.asset.load(withLocalIdentifier:id,placeholder: UIImage(named: "videosmoren"))
PhotoManager.shared.getVideoURL(localIdentifier:id, completion: {[weak self] url in
guard let weakSelf = self else { return }
// 验证 ID 是否匹配,避免 cell 重用导致的错误
if currentID == id {
weakSelf.configure(with: url)
}
})
}else{
self.imageView.image = UIImage.init(named: "videosmoren")
playerLayer.isHidden = true
videoPlayer.pause()
}
}
public let imageView: UIImageView = {
let iv = UIImageView()
iv.contentMode = .scaleAspectFill
iv.clipsToBounds = true
iv.layer.cornerRadius = 8
iv.backgroundColor = .clear
return iv
}()
private let infoBackView: UIView = {
let iv = UIView()
iv.clipsToBounds = true
iv.layer.cornerRadius = 8
iv.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.4)
return iv
}()
public var countLabel: UILabel = {
let label = UILabel()
label.textColor = .white
label.font = .systemFont(ofSize: 14, weight: .medium)
label.textAlignment = .left
return label
}()
let sizeLabel: UILabel = {
let label = UILabel()
label.textColor = .white
label.font = .systemFont(ofSize: 10, weight: .medium)
label.textAlignment = .left
return label
}()
private let moreImageView: UIImageView = {
let iv = UIImageView()
iv.contentMode = .scaleAspectFill
iv.image = UIImage(named: "icon_left_setting_grey")
iv.backgroundColor = .clear
return iv
}()
private let titleLabel: UILabel = {
let label = UILabel()
label.font = .systemFont(ofSize: 16, weight: .bold)
label.textColor = UIColor.colorWithHex(hexStr: black3Color)
label.textAlignment = .left
label.numberOfLines = 0
return label
}()
override func layoutSubviews() {
self.layer.cornerRadius = 12
self.layer.masksToBounds = true
imageView.snp.makeConstraints { make in
make.top.equalTo(self.titleLabel.snp.bottom).offset(8)
make.left.equalToSuperview().offset(16)
make.width.equalToSuperview().offset(-32)
make.height.equalTo(self.width - 32)
}
self.infoBackView.snp.makeConstraints { make in
make.left.right.bottom.equalTo(imageView)
make.height.equalTo(40)
}
titleLabel.snp.makeConstraints { make in
make.left.top.equalToSuperview().offset(16)
make.width.equalToSuperview().offset(-32)
}
self.countLabel.snp.makeConstraints { make in
make.left.equalToSuperview().offset(12)
make.top.equalToSuperview().offset(3)
make.height.equalTo(20)
}
self.sizeLabel.snp.makeConstraints { make in
make.left.equalToSuperview().offset(12)
make.top.equalTo(countLabel.snp.bottom).offset(-2)
make.height.equalTo(14)
}
self.moreImageView.snp.makeConstraints { make in
make.width.height.equalTo(20)
make.right.equalToSuperview().offset(-12)
make.centerY.equalToSuperview()
}
playerLayer.frame = imageView.frame
playerLayer.cornerRadius = 8
playerLayer.masksToBounds = true
}
lazy var videoPlayer:AVPlayer = {
let palyer = AVPlayer.init()
palyer.volume = 0
// 设置音频会话,允许混音
try? AVAudioSession.sharedInstance().setCategory(.playback, options: .mixWithOthers)
try? AVAudioSession.sharedInstance().setActive(true)
return palyer
}()
lazy var playerLayer:AVPlayerLayer = {
let playerLayer = AVPlayerLayer.init(player: videoPlayer)
playerLayer.backgroundColor = UIColor.black.cgColor
playerLayer.isHidden = true
return playerLayer
}()
deinit{
NotificationCenter.default.removeObserver(self)
}
}
extension HomeVideoCoverCell{
func configure(with videoURL: URL?) {
guard let videoURL = videoURL else{
playerLayer.isHidden = true
videoPlayer.pause()
return
}
playerLayer.isHidden = false
if videoURL == videoUrl{
Print("地址相同,无需刷新")
return
}
videoUrl = videoURL
Print("地址不同,需刷新")
let item = AVPlayerItem.init(url: videoURL)
videoPlayer.replaceCurrentItem(with: item)
videoPlayer.play()
NotificationCenter.default.addObserver(self,
selector: #selector(playerDidFinishPlaying),
name: .AVPlayerItemDidPlayToEndTime,
object: item)
}
@objc private func playerDidFinishPlaying() {
videoPlayer.seek(to: .zero)
videoPlayer.play()
}
}
......@@ -121,6 +121,10 @@ class HomeViewModel {
return
}
guard photoManager.permissionStatus == .authorized else{
return
}
totalFilesCount = photoManager.allAssets.count
hadLoad = true
......
......@@ -80,6 +80,7 @@ class MaintaiDetailViewController: BaseViewController {
if isSelectAll{
let ids = viewModel.souces.flatMap{$0}.compactMap{$0.localIdentifier}
if GroupDatabase.shared.batchDelete(localIdentifiers: ids){
selectAsset.removeAll()
self.navigationController?.popViewController(animated: true)
}
isSelectAll = false
......@@ -175,7 +176,7 @@ extension MaintaiDetailViewController:UITableViewDelegate,UITableViewDataSource{
}
// 拿到当前在选中数据的下标
let selectIndex = selectAsset.firstIndex(where: {
var selectIndex = selectAsset.firstIndex(where: {
$0 == cell.selectAsset
})
......@@ -191,11 +192,15 @@ extension MaintaiDetailViewController:UITableViewDelegate,UITableViewDataSource{
weakSelf.selectAsset[sIndex] = selects
}else{
weakSelf.selectAsset.remove(at: sIndex)
selectIndex = nil
}
}else{
Print("没有任何选中数据")
weakSelf.selectAsset.append(selects)
selectIndex = weakSelf.selectAsset.firstIndex(where: {
$0 == selects
})
}
weakSelf.dealMutilImagePick()
}
......@@ -238,8 +243,10 @@ extension MaintaiDetailViewController:UITableViewDelegate,UITableViewDataSource{
}else{
maintaiBottomView.disMiss()
}
tableView.reloadData()
// tableView.reloadData()
// UIView.performWithoutAnimation {
// self.tableView.reloadData()
// }
}
func dealPickAssetModel(index:Int){
......
......@@ -21,10 +21,10 @@
<rect key="frame" x="0.0" y="0.0" width="269" height="253"/>
</imageView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="oJ5-js-pjw">
<rect key="frame" x="234" y="213" width="30" height="30"/>
<rect key="frame" x="235" y="219" width="34" height="34"/>
<constraints>
<constraint firstAttribute="width" constant="30" id="gGs-ha-T24"/>
<constraint firstAttribute="height" constant="30" id="mvi-bY-CFY"/>
<constraint firstAttribute="width" constant="34" id="gGs-ha-T24"/>
<constraint firstAttribute="height" constant="34" id="mvi-bY-CFY"/>
</constraints>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" image="icon_maintai_unselect_big"/>
......@@ -38,8 +38,8 @@
<viewLayoutGuide key="safeArea" id="ZTg-uK-7eu"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="T4a-zL-UKQ" secondAttribute="bottom" id="B7R-M8-dpU"/>
<constraint firstAttribute="bottom" secondItem="oJ5-js-pjw" secondAttribute="bottom" constant="10" id="BfF-Td-Tcc"/>
<constraint firstAttribute="trailing" secondItem="oJ5-js-pjw" secondAttribute="trailing" constant="5" id="Iw9-UA-zNe"/>
<constraint firstAttribute="bottom" secondItem="oJ5-js-pjw" secondAttribute="bottom" id="BfF-Td-Tcc"/>
<constraint firstAttribute="trailing" secondItem="oJ5-js-pjw" secondAttribute="trailing" id="Iw9-UA-zNe"/>
<constraint firstItem="T4a-zL-UKQ" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="MoV-lR-Hqz"/>
<constraint firstItem="T4a-zL-UKQ" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" id="dJs-Pa-MhO"/>
<constraint firstAttribute="trailing" secondItem="T4a-zL-UKQ" secondAttribute="trailing" id="gyj-E3-guF"/>
......
......@@ -43,7 +43,7 @@ class MaintaiDetailImageSmallCell: UICollectionViewCell {
selectBtn.addTarget(self, action: #selector(selectChange), for: .touchUpInside)
selectBtn.snp.makeConstraints { make in
make.right.bottom.equalTo(0)
make.size.equalTo(20)
make.size.equalTo(30)
}
}
......
......@@ -58,8 +58,8 @@ class MaintaiDetailTableViewCell: UITableViewCell {
func configChild(){
let layout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width: smallW, height: smallW)
layout.minimumLineSpacing = 8
layout.minimumInteritemSpacing = 8
layout.minimumLineSpacing = 12
layout.minimumInteritemSpacing = 12
layout.sectionInset = UIEdgeInsets(top: 0, left: 12, bottom: 0, right: 12)
layout.scrollDirection = .horizontal
......@@ -135,8 +135,9 @@ extension MaintaiDetailTableViewCell:UIScrollViewDelegate{
Print("主图滑动距离",scrollView.contentOffset.x)
let index = Int(scrollView.contentOffset.x/bigW)
Print("小图滑动到下标\(index)")
let space:CGFloat = (self.smallW + 12) * CGFloat(index)
UIView.animate(withDuration: 0.3) {
self.pageCollectionView.contentOffset = CGPoint(x: index * Int(self.smallW+8)+4, y: 0)
self.pageCollectionView.contentOffset = CGPoint(x:space, y: 0)
}
}
}
......@@ -183,8 +184,9 @@ extension MaintaiDetailTableViewCell:UIScrollViewDelegate{
Print("小图滑动距离",offsetX)
let index = Int((offsetX/(smallW+12)).rounded()) //Int(offsetX/(smallW+12).rounded()) //rounded(offsetX/smallW)
Print("大图滑动到下标\(index)")
let space:CGFloat = (self.smallW + 12) * CGFloat(index)
UIView.animate(withDuration: 0.3) {
self.pageCollectionView.contentOffset = CGPoint(x: index * Int(self.smallW+8)+4, y: 0)
self.pageCollectionView.contentOffset = CGPoint(x: space, y: 0)
}
self.mainCollectionView.contentOffset = CGPoint(x: index * Int(self.bigW), y: 0)
draggView = .null
......
......@@ -37,23 +37,20 @@ class MaintaiDetialVideoCell: UITableViewCell {
contentView.bringSubviewToFront(selectBtn)
selectBtn.addTarget(self, action: #selector(selectChange), for: .touchUpInside)
selectBtn.snp.makeConstraints { make in
make.right.equalTo(-15)
make.bottom.equalTo(-10)
make.size.equalTo(30)
make.right.equalTo(-22)
make.bottom.equalTo(0)
make.size.equalTo(34)
}
}
private func setupPlayer() {
// 创建播放器层
// playerLayer = AVPlayerLayer()
// playerLayer?.videoGravity = .resizeAspect
contentView.layer.addSublayer(playerLayer)
}
override func layoutSubviews() {
super.layoutSubviews()
// 设置播放器层的frame
playerLayer.frame = CGRect(x: 15, y: 10, width: contentView.width-30, height: contentView.height-20)
playerLayer.frame = CGRect(x: 22, y: 10, width: contentView.width-44, height: contentView.height-10)
playerLayer.cornerRadius = 15
playerLayer.masksToBounds = true
}
......@@ -92,7 +89,9 @@ class MaintaiDetialVideoCell: UITableViewCell {
return
}
if videoPlayer.rate != 0{
return
}
let item = AVPlayerItem.init(url: videoURL)
......@@ -100,45 +99,24 @@ class MaintaiDetialVideoCell: UITableViewCell {
videoPlayer.play()
// // 创建播放器项
// let playerItem = AVPlayerItem(url: videoURL)
//
// // 创建播放器
// player = AVPlayer(playerItem: playerItem)
// playerLayer?.player = player
//
// // 设置静音
// player?.volume = 0
//
// // 播放视频
// player?.play()
//
// 添加播放完成的观察者
NotificationCenter.default.addObserver(self,
selector: #selector(playerDidFinishPlaying),
name: .AVPlayerItemDidPlayToEndTime,
object: item)
}
//
@objc private func playerDidFinishPlaying() {
// // 播放结束后不做任何操作,因为只需要播放一次
// player?.pause()
// player?.seek(to: .zero)
//playerLayer.player?.seek(to: .zero)
videoPlayer.seek(to: .zero)
videoPlayer.play()
}
//
// override func prepareForReuse() {
// super.prepareForReuse()
// // 清理播放器
// player?.pause()
// player = nil
// NotificationCenter.default.removeObserver(self)
// }
//
@objc func selectChange(){
selectChangeBlock?()
}
deinit{
NotificationCenter.default.removeObserver(self)
}
}
......@@ -24,6 +24,7 @@ class NewGuideViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.transitioningDelegate = self
configUI()
startTimer()
}
......@@ -81,24 +82,27 @@ class NewGuideViewController: UIViewController {
}
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)
// 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()
// 显示 window
cWindow?.makeKeyAndVisible()
self.navigationController?.popToRootViewController(animated: false)
UserDef.shard.isShowLanding = true
UserDef.shard.saveUserDefToSandBox()
NotificationCenter.default.post(name: .guidePageClose, object: nil)
}
deinit{
......@@ -145,3 +149,10 @@ extension NewGuideViewController:UICollectionViewDelegate,UICollectionViewDataSo
}
}
extension NewGuideViewController: UIViewControllerTransitioningDelegate {
func animationController(forDismissed dismissedController: UIViewController) -> UIViewControllerAnimatedTransitioning? {
// pop 时触发消失动画(等同于 popToRootViewController)
return FadeOutPopTransition()
}
}
//
// HomeLaunchView.swift
// PhoneManager
//
// Created by edy on 2025/5/19.
//
import UIKit
import Lottie
class HomeLaunchView:UIView {
var disMissBlock:(() ->Void)?
override init(frame: CGRect) {
super.init(frame: frame)
self.frame = frame
configUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func configUI(){
backgroundColor = UIColor.colorWithHex(hexStr: "#0082FF")
let logoImage = UIImageView()
logoImage.image = UIImage.init(named: "icon_phone_manager")
addSubview(logoImage)
let nameImage = UIImageView()
nameImage.image = UIImage.init(named: "icon_phone_manager_name")
addSubview(nameImage)
addSubview(LaunchingLoop)
logoImage.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.top.equalTo(kSafeAreaInsets.top+150)
}
nameImage.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.top.equalTo(logoImage.snp.bottom).offset(12)
}
LaunchingLoop.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.width.height.equalTo(150)
make.bottom.equalToSuperview().offset(-60 * RScreenH())
}
}
func show(){
KEYWINDOW()?.addSubview(self)
DispatchQueue.main.asyncAfter(deadline: .now() + 3, execute: {
self.alpha = 1
UIView.animate(withDuration: 0.3) {
self.alpha = 0
}completion: { _ in
self.removeFromSuperview()
}
self.disMissBlock?()
})
}
private lazy var LaunchingLoop: LottieAnimationView = {
let animationView = LottieAnimationView(name: "launch_loaing")
animationView.loopMode = .loop
animationView.play()
return animationView
}()
}
......@@ -29,40 +29,33 @@ class LauchVC:UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// backView.addSubview(LaunchingView)
backView.addSubview(LaunchingLoop)
// LaunchingView.snp.makeConstraints { make in
// make.centerX.equalToSuperview()
// make.centerY.equalToSuperview().offset(-140 * RScreenH())
// make.width.equalToSuperview()
// make.height.equalTo(LaunchingView.snp.width)
// }
view.addSubview(LaunchingLoop)
LaunchingLoop.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.width.height.equalTo(150)
make.bottom.equalToSuperview().offset(-60 * RScreenH())
}
DispatchQueue.main.asyncAfter(deadline: .now() + 3, execute: {
var vc:UIViewController?
if (UserDef.shard.isShowLanding) {
vc = HomeViewController()
}else {
let Ssoryboard = UIStoryboard(name: "PermissionVC", bundle: nil)
if let current = Ssoryboard.instantiateViewController(identifier: "PermissionVCID") as? PermissionVC {
vc = current
}
}
guard let vc else {return}
let nav = BaseNavViewController(rootViewController: vc)
cWindow?.rootViewController = nav
let transition = CATransition()
transition.duration = 0.5
transition.subtype = CATransitionSubtype.fromRight // 从左侧推入
transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
cWindow?.layer.add(transition, forKey: kCATransition)
cWindow?.makeKeyAndVisible()
self.dismiss(animated: false)
// var vc:UIViewController?
// if (UserDef.shard.isShowLanding) {
// vc = HomeViewController()
// }else {
// let Ssoryboard = UIStoryboard(name: "PermissionVC", bundle: nil)
// if let current = Ssoryboard.instantiateViewController(identifier: "PermissionVCID") as? PermissionVC {
// vc = current
// }
// }
// guard let vc else {return}
// let nav = BaseNavViewController(rootViewController: vc)
// cWindow?.rootViewController = nav
// let transition = CATransition()
// transition.duration = 0.5
// transition.subtype = CATransitionSubtype.fromRight // 从左侧推入
// transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
// cWindow?.layer.add(transition, forKey: kCATransition)
// cWindow?.makeKeyAndVisible()
})
}
}
//
// LaunchViewController.swift
// PhoneManager
//
// Created by edy on 2025/5/19.
//
import UIKit
import Lottie
class LaunchViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.colorWithHex(hexStr: "#0082FF")
let logoImage = UIImageView()
logoImage.image = UIImage.init(named: "icon_phone_manager")
view.addSubview(logoImage)
let nameImage = UIImageView()
nameImage.image = UIImage.init(named: "icon_phone_manager_name")
view.addSubview(nameImage)
view.addSubview(LaunchingLoop)
logoImage.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.top.equalTo(kSafeAreaInsets.top+150)
}
nameImage.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.top.equalTo(logoImage.snp.bottom).offset(12)
}
LaunchingLoop.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.width.height.equalTo(150)
make.bottom.equalToSuperview().offset(-60 * RScreenH())
}
DispatchQueue.main.asyncAfter(deadline: .now() + 3, execute: {
self.dismiss(animated: true)
})
}
private lazy var LaunchingLoop: LottieAnimationView = {
let animationView = LottieAnimationView(name: "launch_loaing")
animationView.loopMode = .loop
animationView.play()
return animationView
}()
}
......@@ -46,8 +46,11 @@ class HomePayDueView: UIView {
func reloadUI(_ type:Int,week:SKProduct?,life:SKProduct?){
guard let pord = week,let pord1 = life else { return }
guard let pord = week,let pord1 = life else {
self.isHidden = true
return
}
self.isHidden = false
if type == 0{
// 免费试用订阅
dueDay.text = "Due today"
......
//
// PayDistanceAnimaeView.swift
// PhoneManager
//
// Created by edy on 2025/5/19.
//
import UIKit
class PayDistanceAnimaeView: UIView {
/*
// Only override draw() if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func draw(_ rect: CGRect) {
// Drawing code
}
*/
}
......@@ -10,6 +10,7 @@ import StoreKit
import SVProgressHUD
class HomePayViewController:UIViewController {
private var homePayView:HomePayView?
......@@ -121,7 +122,7 @@ extension HomePayViewController {
IAPManager.share.fetchProducts { [weak self] products in
guard let weakSelf = self else { return }
DispatchQueue.main.async {
if let (weekProduct, lifetimeProduct) = products {
if let (weekProduct, lifetimeProduct,_) = products {
weakSelf.homePayView?.reloadSKPorduct(week: weekProduct, life: lifetimeProduct)
}
}
......@@ -129,7 +130,7 @@ extension HomePayViewController {
}
private func payTouch() -> Void {
IAPManager.share.purchase((homePayView?.type == 0) ? .subscribe : .nonConsumable) {[weak self] result in
IAPManager.share.purchase((homePayView?.type == 0) ? .weekSubscribe : .nonConsumable) {[weak self] result in
guard let weakSelf = self else { return }
switch result {
case .success(let success):
......@@ -182,4 +183,5 @@ extension HomePayViewController {
rt.present(nav, animated: true)
}
}
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13142" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12042"/>
<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" customClass="PayDistanceViewController" customModuleProvider="target">
<connections>
<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="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
</view>
</objects>
</document>
......@@ -11,20 +11,20 @@
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="EwM-B0-fXo" customClass="PMPermissionView" customModule="PhoneManager" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="543" height="449"/>
<rect key="frame" x="0.0" y="0.0" width="470" height="337"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_queshengtu" translatesAutoresizingMaskIntoConstraints="NO" id="qhV-IF-vsx">
<rect key="frame" x="177" y="100" width="189" height="189"/>
<rect key="frame" x="140.66666666666666" y="0.0" width="188.99999999999997" height="189"/>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Access permission is required to start scan" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ci8-h6-fiE">
<rect key="frame" x="5" y="297" width="533" height="20"/>
<rect key="frame" x="5" y="197" width="460" height="20"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="16"/>
<color key="textColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Phone Manager We need access to all the photos in your photo library" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="e8v-Xy-wvP">
<rect key="frame" x="109" y="320" width="325" height="38.333333333333314"/>
<rect key="frame" x="72.666666666666686" y="220" width="325" height="38.333333333333314"/>
<constraints>
<constraint firstAttribute="width" constant="325" id="7Q3-fW-f7G"/>
</constraints>
......@@ -33,7 +33,7 @@
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="fRi-wi-J8I">
<rect key="frame" x="177" y="371.33333333333331" width="189" height="46"/>
<rect key="frame" x="140.66666666666666" y="271.33333333333331" width="188.99999999999997" 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="2ml-bk-VZ7"/>
......@@ -59,14 +59,14 @@
<constraint firstItem="ci8-h6-fiE" firstAttribute="leading" secondItem="Z86-W8-437" secondAttribute="leading" constant="5" id="2pS-Hl-sgb"/>
<constraint firstItem="ci8-h6-fiE" firstAttribute="centerX" secondItem="qhV-IF-vsx" secondAttribute="centerX" id="Fv3-iO-5BI"/>
<constraint firstItem="e8v-Xy-wvP" firstAttribute="centerX" secondItem="ci8-h6-fiE" secondAttribute="centerX" id="OZD-Bq-U2s"/>
<constraint firstItem="qhV-IF-vsx" firstAttribute="top" secondItem="EwM-B0-fXo" secondAttribute="top" constant="100" id="fx5-wC-f0q"/>
<constraint firstItem="qhV-IF-vsx" firstAttribute="top" secondItem="EwM-B0-fXo" secondAttribute="top" id="fx5-wC-f0q"/>
<constraint firstItem="fRi-wi-J8I" firstAttribute="top" secondItem="e8v-Xy-wvP" secondAttribute="bottom" constant="13" id="jys-rP-uUI"/>
<constraint firstItem="e8v-Xy-wvP" firstAttribute="top" secondItem="ci8-h6-fiE" secondAttribute="bottom" constant="3" id="tgi-kq-3Ap"/>
<constraint firstItem="ci8-h6-fiE" firstAttribute="top" secondItem="qhV-IF-vsx" secondAttribute="bottom" constant="8" id="uKW-kw-KCJ"/>
<constraint firstItem="Z86-W8-437" firstAttribute="trailing" secondItem="ci8-h6-fiE" secondAttribute="trailing" constant="5" id="wMs-cZ-eGL"/>
</constraints>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<point key="canvasLocation" x="295.41984732824426" y="-329.22535211267609"/>
<point key="canvasLocation" x="239.69465648854961" y="-368.66197183098592"/>
</view>
</objects>
<resources>
......
......@@ -70,4 +70,8 @@ struct FileTool{
return totalSize
}
}
......@@ -83,3 +83,11 @@ public func Alert( _ title:String? , _ message:String) -> Void {
alert.addAction(UIAlertAction(title: "OK", style: .cancel))
cWindow?.rootViewController?.present(alert, animated: true)
}
func GETCURRENTNAV() -> UINavigationController? {
let k = UIApplication.shared.windows.filter({$0.isKeyWindow}).first
let pre = k?.rootViewController?.presentedViewController
let rt = k?.rootViewController
return (pre as? UINavigationController) ?? ((rt as? UITabBarController)?.selectedViewController as? UINavigationController) ?? (rt as? UINavigationController)
}
//
// FadeOutTransition.swift
// PhoneManager
//
// Created by edy on 2025/5/19.
//
import Foundation
import UIKit
// 自定义转场动画(用于消失时的渐隐效果)
class FadeOutTransition: NSObject, UIViewControllerAnimatedTransitioning {
// 动画时长(可自定义)
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.3 // 0.3秒渐隐
}
// 执行动画
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
// 获取即将消失的控制器(被弹出的控制器)
guard let fromVC = transitionContext.viewController(forKey: .from),
let toVC = transitionContext.viewController(forKey: .to) else { return }
// 将目标控制器的视图添加到容器视图(确保转场后界面正确)
transitionContext.containerView.addSubview(toVC.view)
// 渐隐动画:将 fromVC 的视图透明度从 1 降到 0
UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: {
fromVC.view.alpha = 0
}) { (_) in
// 动画完成后,标记转场结束
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
}
}
}
// 自定义转场动画(用于 pop 时的渐隐效果)
class FadeOutPopTransition: NSObject, UIViewControllerAnimatedTransitioning {
// 动画时长
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.3 // 0.3秒渐隐
}
// 执行动画
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
// 获取当前视图控制器(即将消失的控制器)
guard let fromVC = transitionContext.viewController(forKey: .from),
let toVC = transitionContext.viewController(forKey: .to) else { return }
// 将目标控制器(RootViewController)的视图添加到容器视图
transitionContext.containerView.addSubview(toVC.view)
// 渐隐动画:当前控制器视图透明度从 1 降到 0
UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: {
fromVC.view.alpha = 0
}) { (_) in
// 动画完成后,标记转场结束
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
}
}
}
......@@ -15,4 +15,8 @@ extension NSNotification.Name {
//监听拿到基本相册资源
static let getBaseAssetsSuccess: NSNotification.Name = NSNotification.Name(rawValue: "getBaseAssetsSuccess")
//首次打开引导页关闭
static let guidePageClose: NSNotification.Name = NSNotification.Name(rawValue: "guidePageClose")
}
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