Commit 253a5552 authored by yqz's avatar yqz

Merge branch 'develop_0409' into yQz0507

* develop_0409:
  【优化】部分功能新增优化
  【新增】垃圾桶详情以及部分优化
  【新增】添加视频、截图、其他选择按钮
  【新增】撤回功能,照片详情页面
  【优化】处理部分逻辑
  【新增】左滑垃圾桶功能
  【新增】垃圾桶功能
  【新增】内部勾选框
parents 73b3ed19 38989c96
This diff is collapsed.
...@@ -55,6 +55,40 @@ class AppDelegate: UIResponder, UIApplicationDelegate { ...@@ -55,6 +55,40 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
return true return true
} }
func applicationWillTerminate(_ application: UIApplication) {
// 保存单利中所有垃圾桶的数据
saveDataToTrashDB(data: Singleton.shared.trashData)
// 保存单利中所有垃圾桶的数据
saveDataToKeepListhDB(data: Singleton.shared.keepList)
}
func saveDataToTrashDB(data : [TrashTypeEnum : [AssetModel]]){
for (key,value) in data {
for item in value {
let success = TrashDatabase.shared.insert(localIdentifier: item.localIdentifier, assetSize: item.assetSize, createDate: item.createDate, mediaType: key.dbType)
if !success {
Print("保存单利数据到数据库失败")
}
}
}
Singleton.shared.trashData = [:]
}
func saveDataToKeepListhDB(data : [TrashTypeEnum : [AssetModel]]){
for (key,value) in data {
let uniqueId = UUID().uuidString
for item in value {
let success = GroupDatabase.shared.insert(localIdentifier: item.localIdentifier, assetSize: item.assetSize, createDate: item.createDate, mediaType: key == TrashTypeEnum.video ? 2 : 1,groupId: uniqueId)
if !success {
Print("保存保留列表数据失败")
}
}
}
Singleton.shared.keepList = [:]
}
func applicationDidBecomeActive(_ application: UIApplication) { func applicationDidBecomeActive(_ application: UIApplication) {
NotificationCenter.default.post(name: Notification.Name("applicationDidBecomeActive"), object: nil) NotificationCenter.default.post(name: Notification.Name("applicationDidBecomeActive"), object: nil)
......
{
"images" : [
{
"filename" : "icon_dingyue.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "icon_dingyue@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "icon_dingyue@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "Frame.png",
"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" : [
{
"filename" : "Frame.png",
"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" : [
{
"filename" : "Frame.png",
"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" : [
{
"filename" : "Frame.png",
"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" : [
{
"filename" : "Group_1171275102.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Group_1171275102@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Group_1171275102@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
This diff is collapsed.
...@@ -198,6 +198,64 @@ class TrashDatabase { ...@@ -198,6 +198,64 @@ class TrashDatabase {
return result return result
} }
// 批量删除数据
func batchDelete(localIdentifiers: [String]) -> Bool {
// 使用事务来确保原子性
let beginTransaction = "BEGIN TRANSACTION;"
let commitTransaction = "COMMIT TRANSACTION;"
let rollbackTransaction = "ROLLBACK TRANSACTION;"
// 准备删除语句
let deleteStatementString = "DELETE FROM trash WHERE localIdentifier = ?;"
var deleteStatement: OpaquePointer?
// 开始事务
if sqlite3_exec(db, beginTransaction, nil, nil, nil) != SQLITE_OK {
print("开始事务失败")
return false
}
// 准备删除语句
if sqlite3_prepare_v2(db, deleteStatementString, -1, &deleteStatement, nil) == SQLITE_OK {
// 遍历所有需要删除的标识符
for identifier in localIdentifiers {
// 重置语句以重新使用
sqlite3_reset(deleteStatement)
// 绑定参数
sqlite3_bind_text(deleteStatement, 1, (identifier as NSString).utf8String, -1, nil)
// 执行删除
if sqlite3_step(deleteStatement) != SQLITE_DONE {
print("删除数据失败: \(identifier)")
// 如果有任何失败,回滚事务
sqlite3_exec(db, rollbackTransaction, nil, nil, nil)
sqlite3_finalize(deleteStatement)
return false
}
}
// 完成后释放语句
sqlite3_finalize(deleteStatement)
// 提交事务
if sqlite3_exec(db, commitTransaction, nil, nil, nil) == SQLITE_OK {
print("成功批量删除数据")
return true
} else {
print("提交事务失败")
sqlite3_exec(db, rollbackTransaction, nil, nil, nil)
return false
}
}
// 如果准备语句失败
print("准备删除语句失败")
sqlite3_exec(db, rollbackTransaction, nil, nil, nil)
return false
}
deinit { deinit {
sqlite3_close(db) sqlite3_close(db)
} }
......
...@@ -26,7 +26,7 @@ class ChargeGuideController : BaseViewController,UIScrollViewDelegate,UINavigati ...@@ -26,7 +26,7 @@ class ChargeGuideController : BaseViewController,UIScrollViewDelegate,UINavigati
"Scroll the page and select Charger section", "Scroll the page and select Charger section",
"Select 'ls Connected' and 'Run lmmediately',then tap on Next", "Select 'ls Connected' and 'Run lmmediately',then tap on Next",
"Tap on New Blank Automation to connect the app", "Tap on New Blank Automation to connect the app",
"Type 'Cleanup' & select Run Charging Animation and tap on Done!" "Type 'PhoneManager' & select Run Charging Animation and tap on Done!"
] ]
let numberOfPages = 7 let numberOfPages = 7
......
...@@ -17,6 +17,8 @@ typealias CompressSelectCellCallback = (AssetModel,Bool)->Void ...@@ -17,6 +17,8 @@ typealias CompressSelectCellCallback = (AssetModel,Bool)->Void
class CompressSelectCell : UICollectionViewCell { class CompressSelectCell : UICollectionViewCell {
var indexPath : IndexPath?
var callBack : CompressSelectCellCallback = {model,choose in} var callBack : CompressSelectCellCallback = {model,choose in}
var currentMediaType : CompressType = .compressPhoto { var currentMediaType : CompressType = .compressPhoto {
...@@ -146,6 +148,10 @@ class CompressSelectCell : UICollectionViewCell { ...@@ -146,6 +148,10 @@ class CompressSelectCell : UICollectionViewCell {
@objc func selectClick(){ @objc func selectClick(){
// 判断是图片还是视频
if self.currentMediaType == .compressPhoto {
self.choose = !self.choose
}else {
let vc = PMShowImgVideoController() let vc = PMShowImgVideoController()
vc.getVideoURLFromLocalIdentifier(localIdentifier: self.model?.localIdentifier ?? "") {[weak self] url, error in vc.getVideoURLFromLocalIdentifier(localIdentifier: self.model?.localIdentifier ?? "") {[weak self] url, error in
guard let self else {return} guard let self else {return}
...@@ -161,6 +167,7 @@ class CompressSelectCell : UICollectionViewCell { ...@@ -161,6 +167,7 @@ class CompressSelectCell : UICollectionViewCell {
} }
} }
} }
}
override init(frame: CGRect) { override init(frame: CGRect) {
...@@ -225,23 +232,31 @@ class CompressSelectCell : UICollectionViewCell { ...@@ -225,23 +232,31 @@ class CompressSelectCell : UICollectionViewCell {
@objc func imageClick(){ @objc func imageClick(){
if self.currentMediaType == .compressPhoto { if self.currentMediaType == .compressPhoto {
// 点击之后跳转详情页面 // 点击之后跳转详情页面
if let tempModel = self.model { if let tempModel = self.model {
let vc = PMShowImgVideoController() let vc = PMShowImgVideoController()
vc.state = .similarPhotos vc.state = .similarPhotos
vc.currentIdx = 0 vc.currentIdx = 0
vc.oldPageIndexPath = indexPath
let dataSource = ImageSeletedCollectionItem() let dataSource = ImageSeletedCollectionItem()
dataSource.isSeleted = true dataSource.isSeleted = self.choose
dataSource.id = tempModel dataSource.id = tempModel
// 获取image // 获取image
dataSource.image = PhotoAndVideoMananger.mananger.getImageFromAssetID(id: tempModel.localIdentifier) dataSource.image = PhotoAndVideoMananger.mananger.getImageFromAssetID(id: tempModel.localIdentifier)
vc.homeDataSource = [dataSource] vc.homeDataSource = [dataSource]
vc.backOrgPageCallBack = {[weak self]index,data in
guard let self else {return}
if let data = data{
if let item = data.first{
self.choose = item.isSeleted ?? false
}
}
}
self.responderViewController()?.navigationController?.pushViewController(vc, animated: true) self.responderViewController()?.navigationController?.pushViewController(vc, animated: true)
} }
}else{ }else{
...@@ -253,12 +268,21 @@ class CompressSelectCell : UICollectionViewCell { ...@@ -253,12 +268,21 @@ class CompressSelectCell : UICollectionViewCell {
let vc = PMShowImgVideoController() let vc = PMShowImgVideoController()
vc.state = .similarVideos vc.state = .similarVideos
vc.currentIdx = 0 vc.currentIdx = 0
vc.oldPageIndexPath = self.indexPath
let dataSource = ImageSeletedCollectionItem() let dataSource = ImageSeletedCollectionItem()
dataSource.isSeleted = true dataSource.isSeleted = self.choose
dataSource.id = tempModel dataSource.id = tempModel
dataSource.image = image dataSource.image = image
// 表示这个是视频 // 表示这个是视频
vc.homeDataSource = [dataSource] vc.homeDataSource = [dataSource]
vc.backOrgPageCallBack = {[weak self]index,data in
guard let self else {return}
if let data = data{
if let item = data.first{
self.choose = item.isSeleted ?? false
}
}
}
vc.getVideoURLFromLocalIdentifier(localIdentifier: tempModel.localIdentifier) { url, error in vc.getVideoURLFromLocalIdentifier(localIdentifier: tempModel.localIdentifier) { url, error in
if url != nil{ if url != nil{
DispatchQueue.main.async { DispatchQueue.main.async {
......
...@@ -19,8 +19,16 @@ class CompressCompletedViewController : BaseViewController{ ...@@ -19,8 +19,16 @@ class CompressCompletedViewController : BaseViewController{
var currentMediaType : CompressType = .compressPhoto var currentMediaType : CompressType = .compressPhoto
lazy var bacView : UIView = {
let view = UIView()
view.layer.cornerRadius = 115
view.backgroundColor = UIColor(red: 0, green: 0.51, blue: 1, alpha: 1)
return view
}()
lazy var animationView : LottieAnimationView = { lazy var animationView : LottieAnimationView = {
let animationView = LottieAnimationView(name: "CompressCompletedLight") let animationView = LottieAnimationView(name: "iOS压缩完成")
animationView.layer.cornerRadius = 12 animationView.layer.cornerRadius = 12
animationView.backgroundColor = .clear animationView.backgroundColor = .clear
animationView.loopMode = .loop animationView.loopMode = .loop
...@@ -153,6 +161,7 @@ class CompressCompletedViewController : BaseViewController{ ...@@ -153,6 +161,7 @@ class CompressCompletedViewController : BaseViewController{
self.view.backgroundColor = UIColor(red: 0.95, green: 0.96, blue: 0.99, alpha: 1) self.view.backgroundColor = UIColor(red: 0.95, green: 0.96, blue: 0.99, alpha: 1)
self.titleView.isHidden = true self.titleView.isHidden = true
self.view.addSubview(self.bacView)
self.view.addSubview(self.animationView) self.view.addSubview(self.animationView)
self.view.addSubview(self.tipLabel) self.view.addSubview(self.tipLabel)
self.view.addSubview(self.detailTiplabel) self.view.addSubview(self.detailTiplabel)
...@@ -168,7 +177,11 @@ class CompressCompletedViewController : BaseViewController{ ...@@ -168,7 +177,11 @@ class CompressCompletedViewController : BaseViewController{
self.infoView.addSubview(self.finalTipLabel) self.infoView.addSubview(self.finalTipLabel)
self.view.addSubview(self.completedButton) self.view.addSubview(self.completedButton)
self.bacView.snp.makeConstraints { make in
make.top.equalTo(statusBarHeight + 60)
make.width.height.equalTo(230)
make.centerX.equalToSuperview()
}
self.animationView.snp.makeConstraints { make in self.animationView.snp.makeConstraints { make in
make.top.equalTo(statusBarHeight + 60) make.top.equalTo(statusBarHeight + 60)
make.width.height.equalTo(230) make.width.height.equalTo(230)
...@@ -366,7 +379,7 @@ class CompressCompletedViewController : BaseViewController{ ...@@ -366,7 +379,7 @@ class CompressCompletedViewController : BaseViewController{
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
setUI() setUI()
self.animationView.play(fromProgress: 0, toProgress: 1,loopMode: .playOnce) self.animationView.play(fromProgress: 0, toProgress: 1,loopMode: .loop)
} }
......
...@@ -174,6 +174,7 @@ extension CompressController:WaterfallMutiSectionDelegate,UICollectionViewDataSo ...@@ -174,6 +174,7 @@ extension CompressController:WaterfallMutiSectionDelegate,UICollectionViewDataSo
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CompressSelectCell", for: indexPath) as! CompressSelectCell let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CompressSelectCell", for: indexPath) as! CompressSelectCell
cell.currentMediaType = self.currentResourceType cell.currentMediaType = self.currentResourceType
cell.model = self.resourceData[indexPath.row] cell.model = self.resourceData[indexPath.row]
cell.indexPath = indexPath
if self.selectedModel.count == 0 { if self.selectedModel.count == 0 {
cell.choose = false cell.choose = false
} }
...@@ -255,6 +256,7 @@ extension CompressController:WaterfallMutiSectionDelegate,UICollectionViewDataSo ...@@ -255,6 +256,7 @@ extension CompressController:WaterfallMutiSectionDelegate,UICollectionViewDataSo
if self.currentResourceType != flag { if self.currentResourceType != flag {
self.currentResourceType = flag self.currentResourceType = flag
// 先移除下,防止点到 // 先移除下,防止点到
self.selectedModel.removeAll()
self.resourceData.removeAll() self.resourceData.removeAll()
// 如果是图片,直接从缓存中加载 // 如果是图片,直接从缓存中加载
if self.currentResourceType == .compressPhoto { if self.currentResourceType == .compressPhoto {
...@@ -366,9 +368,13 @@ extension CompressController:WaterfallMutiSectionDelegate,UICollectionViewDataSo ...@@ -366,9 +368,13 @@ extension CompressController:WaterfallMutiSectionDelegate,UICollectionViewDataSo
func jumpToNextPage(){ func jumpToNextPage(){
// 先将值传到下一个页面 // 先将值传到下一个页面
let vc : CompressQualityController = CompressQualityController() let vc : CompressQualityController = CompressQualityController()
vc.model = self.selectedModel
vc.currentMediaType = self.currentResourceType vc.currentMediaType = self.currentResourceType
vc.detailTiplabel.text = "You've selected \(self.selectedModel.count) out of \(self.resourceData.count) photos to compress." vc.model = self.selectedModel
if self.currentResourceType == .compressPhoto{
vc.detailTiplabel.text = "You've selected \(self.selectedModel.count) photos(A total of \(self.resourceData.count)) to compress."
}else{
vc.detailTiplabel.text = "You've selected \(self.selectedModel.count) videos(A total of \(self.resourceData.count)) to compress."
}
self.navigationController?.pushViewController(vc, animated: true) self.navigationController?.pushViewController(vc, animated: true)
// 然后清理下当前页面的值 // 然后清理下当前页面的值
......
...@@ -7,29 +7,70 @@ ...@@ -7,29 +7,70 @@
import Foundation import Foundation
/// 压缩多少枚举
enum CompressQualityType {
// 压缩少量
case low
// 压缩中等
case mid
// 压缩较多
case high
}
class CompressQualityController : BaseViewController{ class CompressQualityController : BaseViewController{
var model : [AssetModel]? { var model : [AssetModel]? {
didSet{ didSet{
let ident = model!.first!.localIdentifier if let model = model {
if let modelFirst = model.first {
if self.currentMediaType == .compressPhoto {
let ident = modelFirst.localIdentifier
let image = PhotoAndVideoMananger.mananger.getImageFromAssetID(id: ident) let image = PhotoAndVideoMananger.mananger.getImageFromAssetID(id: ident)
self.imageView.image = image self.imageView.image = image
}else {
// 获取视频的URL
PhotoAndVideoMananger.mananger.getVideoURLFromLocalIdentifier(localIdentifier: modelFirst.localIdentifier) { url, error in
if let url = url {
self.videoView.videoUrl = url
}
}
}
}
}
} }
} }
var currentQulityType : Int = 0 var currentQulityType : Int = 0
var currentMediaType : CompressType = .compressPhoto var currentMediaType : CompressType = .compressPhoto {
didSet{
self.imageView.isHidden = currentMediaType == .compressVideo
self.videoView.isHidden = currentMediaType == .compressPhoto
}
}
private var compressNav:CompressNavView? private var compressNav:CompressNavView?
lazy var videoView : VideoPlayView = {
let view = VideoPlayView()
view.clipsToBounds = true
view.layer.cornerRadius = 12
view.backgroundColor = UIColor(red: 0.95, green: 0.96, blue: 0.99, alpha: 1)
return view
}()
lazy var imageView: UIImageView = { lazy var imageView: UIImageView = {
let imageView = UIImageView() let imageView = UIImageView()
imageView.clipsToBounds = true imageView.clipsToBounds = true
imageView.layer.cornerRadius = 12 imageView.layer.cornerRadius = 12
imageView.contentMode = .scaleAspectFit imageView.contentMode = .scaleAspectFill
imageView.backgroundColor = UIColor(red: 0.95, green: 0.96, blue: 0.99, alpha: 1) imageView.backgroundColor = UIColor(red: 0.95, green: 0.96, blue: 0.99, alpha: 1)
return imageView return imageView
}() }()
...@@ -46,7 +87,7 @@ class CompressQualityController : BaseViewController{ ...@@ -46,7 +87,7 @@ class CompressQualityController : BaseViewController{
lazy var detailTiplabel: UILabel = { lazy var detailTiplabel: UILabel = {
let label = UILabel() let label = UILabel()
label.text = "You've selected 2 out of 253 photos to compress." label.text = "You've selected 2 photos(A total of 17) to compress."
label.textAlignment = .left label.textAlignment = .left
label.font = UIFont.systemFont(ofSize: 12, weight: .regular) label.font = UIFont.systemFont(ofSize: 12, weight: .regular)
label.backgroundColor = .clear label.backgroundColor = .clear
...@@ -56,6 +97,7 @@ class CompressQualityController : BaseViewController{ ...@@ -56,6 +97,7 @@ class CompressQualityController : BaseViewController{
let view = QualityView() let view = QualityView()
view.type = 0 view.type = 0
view.selectedImageView.image = UIImage(named: "ic_unsel_com") view.selectedImageView.image = UIImage(named: "ic_unsel_com")
view.layer.borderWidth = 1
return view return view
}() }()
...@@ -76,6 +118,14 @@ class CompressQualityController : BaseViewController{ ...@@ -76,6 +118,14 @@ class CompressQualityController : BaseViewController{
}() }()
lazy var buttonBacView: UIView = {
let view = UIView()
view.backgroundColor = .white
view.addTopShadow()
return view
}()
lazy var submitButton : UIButton = { lazy var submitButton : UIButton = {
let view = UIButton() let view = UIButton()
view.setTitle("Compress", for: UIControl.State.normal) view.setTitle("Compress", for: UIControl.State.normal)
...@@ -95,13 +145,15 @@ class CompressQualityController : BaseViewController{ ...@@ -95,13 +145,15 @@ class CompressQualityController : BaseViewController{
make.top.centerX.width.equalToSuperview() make.top.centerX.width.equalToSuperview()
make.height.equalTo(statusBarHeight + 44) make.height.equalTo(statusBarHeight + 44)
}) })
self.view.addSubview(self.videoView)
self.view.addSubview(self.imageView) self.view.addSubview(self.imageView)
self.view.addSubview(self.tipLabel) self.view.addSubview(self.tipLabel)
self.view.addSubview(self.detailTiplabel) self.view.addSubview(self.detailTiplabel)
self.view.addSubview(self.lowQualityView) self.view.addSubview(self.lowQualityView)
self.view.addSubview(self.mediumQualityView) self.view.addSubview(self.mediumQualityView)
self.view.addSubview(self.highQualityView) self.view.addSubview(self.highQualityView)
self.view.addSubview(self.submitButton) self.view.addSubview(self.buttonBacView)
self.buttonBacView.addSubview(self.submitButton)
self.imageView.snp.makeConstraints { make in self.imageView.snp.makeConstraints { make in
make.top.equalTo(self.compressNav!.height + 20) make.top.equalTo(self.compressNav!.height + 20)
...@@ -109,6 +161,13 @@ class CompressQualityController : BaseViewController{ ...@@ -109,6 +161,13 @@ class CompressQualityController : BaseViewController{
make.right.equalToSuperview().offset(-15) make.right.equalToSuperview().offset(-15)
make.height.equalTo(259) make.height.equalTo(259)
} }
self.videoView.snp.makeConstraints { make in
make.top.equalTo(self.compressNav!.height + 20)
make.left.equalToSuperview().offset(15)
make.right.equalToSuperview().offset(-15)
make.height.equalTo(259)
}
self.tipLabel.snp.makeConstraints { make in self.tipLabel.snp.makeConstraints { make in
make.top.equalTo(self.imageView.snp.bottom).offset(28) make.top.equalTo(self.imageView.snp.bottom).offset(28)
make.left.equalToSuperview().offset(15) make.left.equalToSuperview().offset(15)
...@@ -140,11 +199,19 @@ class CompressQualityController : BaseViewController{ ...@@ -140,11 +199,19 @@ class CompressQualityController : BaseViewController{
make.height.equalTo(61) make.height.equalTo(61)
} }
self.buttonBacView.snp.makeConstraints { make in
make.bottom.equalTo(-safeHeight)
make.left.equalToSuperview()
make.right.equalToSuperview()
make.height.equalTo(68)
}
self.submitButton.snp.makeConstraints { make in self.submitButton.snp.makeConstraints { make in
make.bottom.equalTo(-40)
make.left.equalToSuperview().offset(15) make.left.equalToSuperview().offset(15)
make.right.equalToSuperview().offset(-15) make.right.equalToSuperview().offset(-15)
make.height.equalTo(46) make.height.equalTo(46)
make.centerY.equalToSuperview()
} }
} }
...@@ -161,25 +228,61 @@ class CompressQualityController : BaseViewController{ ...@@ -161,25 +228,61 @@ class CompressQualityController : BaseViewController{
guard let self else {return} guard let self else {return}
self.currentQulityType = 0 self.currentQulityType = 0
self.lowQualityView.selectedImageView.image = UIImage(named: "ic_unsel_com") self.lowQualityView.selectedImageView.image = UIImage(named: "ic_unsel_com")
self.lowQualityView.layer.borderWidth = 1
self.mediumQualityView.layer.borderWidth = 0
self.highQualityView.layer.borderWidth = 0
self.mediumQualityView.selectedImageView.image = UIImage(named: "ic_sel_com") self.mediumQualityView.selectedImageView.image = UIImage(named: "ic_sel_com")
self.highQualityView.selectedImageView.image = UIImage(named: "ic_sel_com") self.highQualityView.selectedImageView.image = UIImage(named: "ic_sel_com")
setButtonTitleByType(type: .low)
} }
self.mediumQualityView.callBack = {[weak self] type in self.mediumQualityView.callBack = {[weak self] type in
guard let self else {return} guard let self else {return}
self.currentQulityType = 1 self.currentQulityType = 1
self.lowQualityView.selectedImageView.image = UIImage(named: "ic_sel_com") self.lowQualityView.selectedImageView.image = UIImage(named: "ic_sel_com")
self.lowQualityView.layer.borderWidth = 0
self.mediumQualityView.layer.borderWidth = 1
self.highQualityView.layer.borderWidth = 0
self.mediumQualityView.selectedImageView.image = UIImage(named: "ic_unsel_com") self.mediumQualityView.selectedImageView.image = UIImage(named: "ic_unsel_com")
self.highQualityView.selectedImageView.image = UIImage(named: "ic_sel_com") self.highQualityView.selectedImageView.image = UIImage(named: "ic_sel_com")
setButtonTitleByType(type: .mid)
} }
self.highQualityView.callBack = {[weak self] type in self.highQualityView.callBack = {[weak self] type in
guard let self else {return} guard let self else {return}
self.currentQulityType = 2 self.currentQulityType = 2
self.lowQualityView.selectedImageView.image = UIImage(named: "ic_sel_com") self.lowQualityView.selectedImageView.image = UIImage(named: "ic_sel_com")
self.lowQualityView.layer.borderWidth = 0
self.mediumQualityView.layer.borderWidth = 0
self.highQualityView.layer.borderWidth = 1
self.mediumQualityView.selectedImageView.image = UIImage(named: "ic_sel_com") self.mediumQualityView.selectedImageView.image = UIImage(named: "ic_sel_com")
self.highQualityView.selectedImageView.image = UIImage(named: "ic_unsel_com") self.highQualityView.selectedImageView.image = UIImage(named: "ic_unsel_com")
setButtonTitleByType(type: .high)
}
// 设置默认值
setButtonTitleByType(type: .low)
}
func setButtonTitleByType(type : CompressQualityType){
var size : Double = 0.0
if let array = self.model{
for item in array {
size = size + item.assetSize
}
}
// 求和之后看点击的是哪个
var compressSize : Double = 0.0
if type == .low {
compressSize = size * 0.2
}else if type == .mid {
compressSize = size * 0.5
}else {
compressSize = size * 0.8
} }
self.submitButton.setTitle("Compress \(formatFileSize(compressSize))", for: .normal)
} }
fileprivate func updateNextView(_ compressAllSize: Double, _ compressingView: CompressingView,_ comDataSource : [Data],_ comVideoDataSource : [URL?]) { fileprivate func updateNextView(_ compressAllSize: Double, _ compressingView: CompressingView,_ comDataSource : [Data],_ comVideoDataSource : [URL?]) {
......
...@@ -9,6 +9,7 @@ import Foundation ...@@ -9,6 +9,7 @@ import Foundation
class CompressNavView : UIView { class CompressNavView : UIView {
private var backButton:UIButton! private var backButton:UIButton!
private var titleLabel:UILabel!
private var proBtn:UIButton! private var proBtn:UIButton!
override init(frame: CGRect) { override init(frame: CGRect) {
...@@ -38,13 +39,27 @@ class CompressNavView : UIView { ...@@ -38,13 +39,27 @@ class CompressNavView : UIView {
make.width.height.equalTo(iconWH) make.width.height.equalTo(iconWH)
} }
titleLabel = UILabel()
titleLabel.text = "Compress"
titleLabel.font = UIFont.systemFont(ofSize: 20, weight: .bold)
titleLabel.textColor = UIColor(red: 0.2, green: 0.2, blue: 0.2, alpha: 1)
titleLabel.textAlignment = .center
self.addSubview(titleLabel)
proBtn = UIButton(frame: CGRect(x: 0, y: 0, width: 70, height: iconWH)) proBtn = UIButton(frame: CGRect(x: 0, y: 0, width: 70, height: iconWH))
proBtn.setBackgroundImage(UIImage(named: "home_pro_star_back"), for: .normal) proBtn.setBackgroundImage(UIImage(named: "ic_pro_home"), for: .normal)
proBtn.addTarget(self, action: #selector(proBtnClick), for: .touchUpInside) proBtn.addTarget(self, action: #selector(proBtnClick), for: .touchUpInside)
self.addSubview(proBtn) self.addSubview(proBtn)
proBtn.snp.makeConstraints { make in titleLabel.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.centerY.equalTo(navCenterY)
make.width.equalTo(100)
make.height.equalTo(28)
}
proBtn.snp.makeConstraints { make in
make.centerY.equalTo(navCenterY) make.centerY.equalTo(navCenterY)
make.right.equalToSuperview().offset(-15) make.right.equalToSuperview().offset(-15)
make.width.equalTo(70) make.width.equalTo(70)
......
...@@ -41,6 +41,14 @@ class QualityView : UIView{ ...@@ -41,6 +41,14 @@ class QualityView : UIView{
make.width.equalTo(24) make.width.equalTo(24)
make.height.equalTo(24) make.height.equalTo(24)
} }
self.layer.borderColor = UIColor(red: 0, green: 0.51, blue: 1, alpha: 1).cgColor
// 给自身添加手势
let tap = UITapGestureRecognizer()
tap.addTarget(self, action: #selector(selectClick))
self.isUserInteractionEnabled = true
self.addGestureRecognizer(tap)
} }
required init?(coder: NSCoder) { required init?(coder: NSCoder) {
...@@ -51,6 +59,7 @@ class QualityView : UIView{ ...@@ -51,6 +59,7 @@ class QualityView : UIView{
let label = UILabel() let label = UILabel()
label.text = "Low quality" label.text = "Low quality"
label.textAlignment = .left label.textAlignment = .left
label.textColor = UIColor(red: 0.2, green: 0.2, blue: 0.2, alpha: 1)
label.font = UIFont.systemFont(ofSize: 14, weight: .bold) label.font = UIFont.systemFont(ofSize: 14, weight: .bold)
label.backgroundColor = .clear label.backgroundColor = .clear
return label return label
...@@ -60,6 +69,7 @@ class QualityView : UIView{ ...@@ -60,6 +69,7 @@ class QualityView : UIView{
let label = UILabel() let label = UILabel()
label.text = "Compress up to 80% of the size" label.text = "Compress up to 80% of the size"
label.textAlignment = .left label.textAlignment = .left
label.textColor = UIColor(red: 0.4, green: 0.4, blue: 0.4, alpha: 1)
label.font = UIFont.systemFont(ofSize: 12, weight: .regular) label.font = UIFont.systemFont(ofSize: 12, weight: .regular)
label.backgroundColor = .clear label.backgroundColor = .clear
return label return label
......
//
// VideoPlayView.swift
// PhoneManager
//
// Created by edy on 2025/5/15.
//
import UIKit
class VideoPlayView: UIView {
var videoUrl : URL? {
didSet {
if let url = videoUrl {
self.videoView.playVideo(from: url)
self.videoView.pause()
}
}
}
lazy var playImageView : UIImageView = {
let imageView = UIImageView()
imageView.backgroundColor = .clear
imageView.image = UIImage(named: "playImage")
return imageView
}()
lazy var timeLabel : UILabel = {
let label = UILabel()
label.textColor = .white
label.text = "00:00"
label.font = UIFont.systemFont(ofSize: 14, weight: .semibold)
label.textAlignment = .right
return label
}()
lazy var videoView : SecretVideoPlayer = {
let view = SecretVideoPlayer()
view.clipsToBounds = true
view.layer.cornerRadius = 12
view.backgroundColor = UIColor(red: 0.95, green: 0.96, blue: 0.99, alpha: 1)
return view
}()
override init(frame: CGRect) {
super.init(frame: frame)
self.addSubview(self.videoView)
self.videoView.snp.makeConstraints { make in
make.left.top.right.bottom.equalToSuperview()
}
self.addSubview(self.timeLabel)
self.timeLabel.snp.makeConstraints { make in
make.right.equalToSuperview().offset(-8)
make.top.equalToSuperview().offset(8)
make.height.equalTo(20)
}
self.videoView.callBackCurrtntTimeString = {[weak self]text in
guard let self else {return}
DispatchQueue.main.async {
self.timeLabel.text = text
}
}
self.videoView.tapPauseCallback = {[weak self] state in
guard let self else {return}
if state == .playing {
self.playImageView.isHidden = true
}
if state == .pause {
self.playImageView.isHidden = false
}
if state == .end {
self.playImageView.isHidden = false
self.timeLabel.text = "00:00"
}
}
self.addSubview(self.playImageView)
self.playImageView.snp.makeConstraints { make in
make.width.height.equalTo(18)
make.center.equalToSuperview()
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
//
// VideoViewController.swift
// PhoneManager
//
// Created by edy on 2025/5/13.
//
import Foundation
import AVKit
import MediaPlayer
class VideoViewController: UIViewController {
var url : URL?
var isAutoPlay : Bool = true
// 系统播放器控制器
let playerViewController = AVPlayerViewController()
override func viewDidLoad() {
super.viewDidLoad()
setupPlayer()
}
func setupPlayer() {
// 1. 创建播放器
if let url = self.url {
let player = AVPlayer(url: url)
// 2. 配置播放器控制器
playerViewController.player = player
playerViewController.delegate = self
playerViewController.showsPlaybackControls = true
// 3. 添加到当前视图
addChild(playerViewController)
view.addSubview(playerViewController.view)
playerViewController.view.frame = view.bounds
playerViewController.didMove(toParent: self)
// 4. 自动播放
if self.isAutoPlay {
player.play()
}
}
}
}
// MARK: - AVPlayerViewControllerDelegate
extension VideoViewController: AVPlayerViewControllerDelegate {
// 处理全屏切换
func playerViewController(_ playerViewController: AVPlayerViewController,
willBeginFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) {
}
func playerViewController(_ playerViewController: AVPlayerViewController,
willEndFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) {
}
}
...@@ -39,7 +39,8 @@ class HomePhotosDetailViewController : BaseViewController { ...@@ -39,7 +39,8 @@ class HomePhotosDetailViewController : BaseViewController {
for item in self.model.assets { for item in self.model.assets {
dataArray = dataArray + item dataArray = dataArray + item
} }
self.resourceData = dataArray self.resourceData = self.filterTrashData(array: dataArray)
self.selectedModel = self.filterTrashData(array: self.selectedModel)
self.sortByType(sortType: self.currentSort) self.sortByType(sortType: self.currentSort)
} }
...@@ -48,11 +49,7 @@ class HomePhotosDetailViewController : BaseViewController { ...@@ -48,11 +49,7 @@ class HomePhotosDetailViewController : BaseViewController {
var datas : [AssetModel] = [] var datas : [AssetModel] = []
// 排序 // 排序
var currentSort : Int = 0 { var currentSort : Int = 0
didSet{
clearSelected()
}
}
// 当前页面选中的 // 当前页面选中的
var selectedModel : [AssetModel] = [] { var selectedModel : [AssetModel] = [] {
...@@ -117,6 +114,15 @@ class HomePhotosDetailViewController : BaseViewController { ...@@ -117,6 +114,15 @@ class HomePhotosDetailViewController : BaseViewController {
}() }()
/// 过滤垃圾桶数据
/// - Parameter array: 当前数据
/// - Returns: 过滤后的数据
func filterTrashData(array : [AssetModel]) -> [AssetModel]{
let data = TrashDataManager.getCurrentMediaTypeTrashData(mediaType: self.mediaType == PhotsFileType.Other ? TrashTypeEnum.other : TrashTypeEnum.shot)
return array.filter({!data.map({$0.localIdentifier}).contains($0.localIdentifier)})
}
func setUI(){ func setUI(){
...@@ -153,6 +159,28 @@ class HomePhotosDetailViewController : BaseViewController { ...@@ -153,6 +159,28 @@ class HomePhotosDetailViewController : BaseViewController {
} }
} }
self.videoDetailNavView?.startSelectCallBack = {[weak self] choose in
guard let self else {return}
if !choose {
self.selectedModel.removeAll()
}
DispatchQueue.main.async {
UIView.transition(with: self.collectionView, duration: 0.3, options: .transitionCrossDissolve, animations: {
self.collectionView.reloadData()
}, completion: nil)
if self.selectedModel.count > 0 {
self.deleteButton.backgroundColor = UIColor(red: 0, green: 0.51, blue: 1, alpha: 1)
}else{
self.deleteButton.backgroundColor = UIColor(red: 0.7, green: 0.7, blue: 0.7, alpha: 1)
self.deleteButton.setTitle("Delete", for: .normal)
}
}
}
self.view.insertSubview(collectionView, at: 0) self.view.insertSubview(collectionView, at: 0)
...@@ -193,13 +221,13 @@ class HomePhotosDetailViewController : BaseViewController { ...@@ -193,13 +221,13 @@ class HomePhotosDetailViewController : BaseViewController {
self.defaultImageView.isHidden = false self.defaultImageView.isHidden = false
self.defaultTipLabel.isHidden = false self.defaultTipLabel.isHidden = false
self.currentHeaderView?.btnView.isHidden = true self.currentHeaderView?.btnView.isHidden = true
self.videoDetailNavView?.seletedAllBtn.isHidden = true self.videoDetailNavView?.startSelectButton.isHidden = true
self.deleteButton.isHidden = true self.deleteButton.isHidden = true
}else{ }else{
self.defaultImageView.isHidden = true self.defaultImageView.isHidden = true
self.defaultTipLabel.isHidden = true self.defaultTipLabel.isHidden = true
self.currentHeaderView?.btnView.isHidden = false self.currentHeaderView?.btnView.isHidden = false
self.videoDetailNavView?.seletedAllBtn.isHidden = false self.videoDetailNavView?.startSelectButton.isHidden = false
self.deleteButton.isHidden = false self.deleteButton.isHidden = false
} }
} }
...@@ -303,24 +331,35 @@ extension HomePhotosDetailViewController:WaterfallMutiSectionDelegate,UICollecti ...@@ -303,24 +331,35 @@ extension HomePhotosDetailViewController:WaterfallMutiSectionDelegate,UICollecti
}else{ }else{
cell.choose = false cell.choose = false
} }
if let view = self.videoDetailNavView {
cell.selectImageView.isHidden = !view.startSelectButton.isSelected
cell.extensionView.isHidden = !view.startSelectButton.isSelected
}
cell.cellCallBack = {[weak self] ident,order in cell.cellCallBack = {[weak self] ident,order in
guard let self else {return} guard let self else {return}
DispatchQueue.main.async { DispatchQueue.main.async {
// 点击之后跳转详情页面 // 点击之后跳转详情页面
let vc = PMShowImgVideoController() if self.mediaType == .screenshots {
vc.state = .similarPhotos let vc = PhotoRemoveViewController(data: self.resourceData,currentIndex: indexPath.row,mediaType: .shot)
vc.currentIdx = 0 vc.dismissCallback = {
let dataSource = ImageSeletedCollectionItem() self.dealData()
dataSource.isSeleted = true UIView.transition(with: self.collectionView, duration: 0.3, options: .transitionCrossDissolve, animations: {
dataSource.id = ident self.collectionView.reloadData()
// 获取image }, completion: nil)
dataSource.image = PhotoAndVideoMananger.mananger.getImageFromAssetID(id: ident.localIdentifier) }
vc.homeDataSource = [dataSource] self.navigationController?.pushViewController(vc, animated: true)
}
if self.mediaType == .Other {
let vc = PhotoRemoveViewController(data: self.resourceData,currentIndex: indexPath.row,mediaType: .other)
vc.dismissCallback = {
self.dealData()
UIView.transition(with: self.collectionView, duration: 0.3, options: .transitionCrossDissolve, animations: {
self.collectionView.reloadData()
}, completion: nil)
}
self.navigationController?.pushViewController(vc, animated: true) self.navigationController?.pushViewController(vc, animated: true)
}
} }
} }
cell.clickCallBack = {[weak self] click,order in cell.clickCallBack = {[weak self] click,order in
...@@ -655,9 +694,6 @@ extension HomePhotosDetailViewController:WaterfallMutiSectionDelegate,UICollecti ...@@ -655,9 +694,6 @@ extension HomePhotosDetailViewController:WaterfallMutiSectionDelegate,UICollecti
// 清理下缓存数据 // 清理下缓存数据
PhotoDataManager.manager.removeDataWhenDeleteInPage(data: self.selectedModel) PhotoDataManager.manager.removeDataWhenDeleteInPage(data: self.selectedModel)
// 更新页面 // 更新页面
DispatchQueue.main.async { DispatchQueue.main.async {
// 删除完成之后,移除下当前选择的数据 // 删除完成之后,移除下当前选择的数据
...@@ -672,10 +708,4 @@ extension HomePhotosDetailViewController:WaterfallMutiSectionDelegate,UICollecti ...@@ -672,10 +708,4 @@ extension HomePhotosDetailViewController:WaterfallMutiSectionDelegate,UICollecti
setDefaultPage() setDefaultPage()
} }
func clearSelected() {
self.selectedModel.removeAll()
}
} }
...@@ -32,18 +32,15 @@ class HomeVideoDetailController :BaseViewController { ...@@ -32,18 +32,15 @@ class HomeVideoDetailController :BaseViewController {
for item in self.model.assets { for item in self.model.assets {
dataArray = dataArray + item dataArray = dataArray + item
} }
self.resourceData = dataArray self.resourceData = self.filterTrashData(array: dataArray)
self.selectedModel = self.filterTrashData(array: self.selectedModel)
self.sortByType(sortType: self.currentSort) self.sortByType(sortType: self.currentSort)
} }
var model : HomePhotosModel var model : HomePhotosModel
// 排序 // 排序
var currentSort : Int = 0 { var currentSort : Int = 0
didSet{
clearSelected()
}
}
// 当前页面选中的 // 当前页面选中的
var selectedModel : [AssetModel] = [] { var selectedModel : [AssetModel] = [] {
...@@ -112,6 +109,14 @@ class HomeVideoDetailController :BaseViewController { ...@@ -112,6 +109,14 @@ class HomeVideoDetailController :BaseViewController {
return label return label
}() }()
/// 过滤垃圾桶数据
/// - Parameter array: 当前数据
/// - Returns: 过滤后的数据
func filterTrashData(array : [AssetModel]) -> [AssetModel]{
let data = TrashDataManager.getCurrentMediaTypeTrashData(mediaType: .video)
return array.filter({!data.map({$0.localIdentifier}).contains($0.localIdentifier)})
}
func setUI(){ func setUI(){
videoDetailNavView = VideoDetaiNavView(frame: CGRect(x: 0, y: 0, width: self.view.width, height: statusBarHeight + 44)) videoDetailNavView = VideoDetaiNavView(frame: CGRect(x: 0, y: 0, width: self.view.width, height: statusBarHeight + 44))
...@@ -145,6 +150,27 @@ class HomeVideoDetailController :BaseViewController { ...@@ -145,6 +150,27 @@ class HomeVideoDetailController :BaseViewController {
} }
self.videoDetailNavView?.startSelectCallBack = {[weak self] choose in
guard let self else {return}
if !choose {
self.selectedModel.removeAll()
}
DispatchQueue.main.async {
UIView.transition(with: self.collectionView, duration: 0.3, options: .transitionCrossDissolve, animations: {
self.collectionView.reloadData()
}, completion: nil)
if self.selectedModel.count > 0 {
self.deleteButton.backgroundColor = UIColor(red: 0, green: 0.51, blue: 1, alpha: 1)
}else{
self.deleteButton.backgroundColor = UIColor(red: 0.7, green: 0.7, blue: 0.7, alpha: 1)
self.deleteButton.setTitle("Delete", for: .normal)
}
}
}
self.view.insertSubview(collectionView, at: 0) self.view.insertSubview(collectionView, at: 0)
...@@ -230,6 +256,11 @@ extension HomeVideoDetailController:WaterfallMutiSectionDelegate,UICollectionVie ...@@ -230,6 +256,11 @@ extension HomeVideoDetailController:WaterfallMutiSectionDelegate,UICollectionVie
cell.choose = false cell.choose = false
} }
if let view = self.videoDetailNavView {
cell.selectImageView.isHidden = !view.startSelectButton.isSelected
cell.extensionView.isHidden = !view.startSelectButton.isSelected
}
cell.clickCallBack = {[weak self] click,order in cell.clickCallBack = {[weak self] click,order in
guard let self else {return} guard let self else {return}
if click == true { if click == true {
...@@ -253,32 +284,14 @@ extension HomeVideoDetailController:WaterfallMutiSectionDelegate,UICollectionVie ...@@ -253,32 +284,14 @@ extension HomeVideoDetailController:WaterfallMutiSectionDelegate,UICollectionVie
// 获取视频的图片 // 获取视频的图片
PhotoAndVideoMananger.mananger.getVideoImageByIdent(ident: ident) { image in PhotoAndVideoMananger.mananger.getVideoImageByIdent(ident: ident) { image in
// 点击之后跳转详情页面 // 点击之后跳转详情页面
let vc = PMShowImgVideoController() let vc = PhotoRemoveViewController(data: self.resourceData,currentIndex: indexPath.row,mediaType: .video)
vc.state = .similarVideos vc.dismissCallback = {
vc.currentIdx = 0 self.dealData()
let dataSource = ImageSeletedCollectionItem() UIView.transition(with: self.collectionView, duration: 0.3, options: .transitionCrossDissolve, animations: {
dataSource.isSeleted = true self.collectionView.reloadData()
dataSource.id = ident }, completion: nil)
dataSource.image = image
// 表示这个是视频
vc.homeDataSource = [dataSource]
vc.getVideoURLFromLocalIdentifier(localIdentifier: ident.localIdentifier) { url, error in
if url != nil{
DispatchQueue.main.async {
vc.url = url
self.navigationController?.pushViewController(vc, animated: true)
}
}else{
let alert = UIAlertController(title: nil, message: "ICloud video cannot be viewed", preferredStyle: .alert)
self.present(alert, animated: true, completion: nil)
// 2 秒后关闭弹窗
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
alert.dismiss(animated: true, completion: nil)
}
}
} }
self.navigationController?.pushViewController(vc, animated: true)
} errorHandler: { } errorHandler: {
DispatchQueue.main.async { DispatchQueue.main.async {
let alert = UIAlertController(title: nil, message: "Get Video image failure", preferredStyle: .alert) let alert = UIAlertController(title: nil, message: "Get Video image failure", preferredStyle: .alert)
...@@ -547,13 +560,13 @@ extension HomeVideoDetailController:WaterfallMutiSectionDelegate,UICollectionVie ...@@ -547,13 +560,13 @@ extension HomeVideoDetailController:WaterfallMutiSectionDelegate,UICollectionVie
self.defaultImageView.isHidden = false self.defaultImageView.isHidden = false
self.defaultTipLabel.isHidden = false self.defaultTipLabel.isHidden = false
self.currentHeaderView?.btnView.isHidden = true self.currentHeaderView?.btnView.isHidden = true
self.videoDetailNavView?.seletedAllBtn.isHidden = true self.videoDetailNavView?.startSelectButton.isHidden = true
self.deleteButton.isHidden = true self.deleteButton.isHidden = true
}else{ }else{
self.defaultImageView.isHidden = true self.defaultImageView.isHidden = true
self.defaultTipLabel.isHidden = true self.defaultTipLabel.isHidden = true
self.currentHeaderView?.btnView.isHidden = false self.currentHeaderView?.btnView.isHidden = false
self.videoDetailNavView?.seletedAllBtn.isHidden = false self.videoDetailNavView?.startSelectButton.isHidden = false
self.deleteButton.isHidden = false self.deleteButton.isHidden = false
} }
} }
...@@ -593,11 +606,6 @@ extension HomeVideoDetailController:WaterfallMutiSectionDelegate,UICollectionVie ...@@ -593,11 +606,6 @@ extension HomeVideoDetailController:WaterfallMutiSectionDelegate,UICollectionVie
} }
func clearSelected() {
self.selectedModel.removeAll()
}
/// 改变标题 /// 改变标题
func changeHeaderTitle(){ func changeHeaderTitle(){
var title : String = "Largest" var title : String = "Largest"
......
//
// PhotoDetailViewController.swift
// PhoneManager
//
// Created by edy on 2025/5/14.
//
import UIKit
class PhotoDetailViewController : BaseViewController {
lazy var showView : PMScaleImageView = {
let view = PMScaleImageView()
return view
}()
lazy var closeButton : UIButton = {
let view = UIButton(type: .custom)
view.setImage(UIImage(named: "ic_close_charging"), for: .normal)
view.addTarget(self, action: #selector(closeButtonAction), for: .touchUpInside)
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(self.closeButton)
self.closeButton.snp.makeConstraints { make in
make.left.equalToSuperview().offset(15)
make.top.equalToSuperview().offset(statusBarHeight + 8)
make.width.height.equalTo(28)
}
self.view.addSubview(self.showView)
self.showView.snp.makeConstraints { make in
make.left.right.equalToSuperview()
make.top.equalTo(statusBarHeight + 44)
make.bottom.equalTo(-safeHeight)
}
}
@objc func closeButtonAction(){
self.dismiss(animated: true)
}
}
...@@ -21,13 +21,13 @@ class PhotoSlideViewController: BaseViewController { ...@@ -21,13 +21,13 @@ class PhotoSlideViewController: BaseViewController {
private lazy var topView: AnchorRotatableView = { private lazy var topView: AnchorRotatableView = {
let view = AnchorRotatableView() let view = AnchorRotatableView()
view.configure(anchorPoint: CGPoint(x: 0.5, y: 0.5))
return view return view
}() }()
private lazy var bottomView: AnchorRotatableView = { private lazy var bottomView: AnchorRotatableView = {
let view = AnchorRotatableView() let view = AnchorRotatableView()
view.configure(anchorPoint: CGPoint(x: 0.5, y: 0.5))
return view return view
}() }()
...@@ -119,7 +119,8 @@ class PhotoSlideViewController: BaseViewController { ...@@ -119,7 +119,8 @@ class PhotoSlideViewController: BaseViewController {
updateCardTransform(translation: translation) updateCardTransform(translation: translation)
updateButtons(progress: progress,translation: translation) updateButtons(progress: progress,translation: translation)
case .ended, .cancelled: case .ended, .cancelled:
endDragAnimation(velocity: velocity) break
// endDragAnimation(velocity: velocity)
default: break default: break
} }
} }
......
...@@ -40,10 +40,3 @@ class AnchorRotatableView: UIView { ...@@ -40,10 +40,3 @@ class AnchorRotatableView: UIView {
} }
extension AnchorRotatableView {
func configure(anchorPoint: CGPoint) {
layer.anchorPoint = anchorPoint
}
}
...@@ -42,7 +42,7 @@ class HomeInfoView :UIView { ...@@ -42,7 +42,7 @@ class HomeInfoView :UIView {
lazy var headerView:HomeInfoTitleView = { lazy var headerView:HomeInfoTitleView = {
let sview:HomeInfoTitleView = HomeInfoTitleView(frame: CGRect(x: 0, y: 0, width: width, height: 84)) let sview:HomeInfoTitleView = HomeInfoTitleView(frame: CGRect(x: 0, y: 0, width: width, height: 84))
sview.titleLabel.text = self.titleText sview.titleLabel.text = self.titleText
sview.filterButton.isHidden = self.type != .similar sview.filterButton.isHidden = self.type != .similar && self.type != .SimilarVideos
tableView.addSubview(sview) tableView.addSubview(sview)
return sview return sview
}() }()
...@@ -117,7 +117,13 @@ class HomeInfoView :UIView { ...@@ -117,7 +117,13 @@ class HomeInfoView :UIView {
// 从源头获取相似数据 // 从源头获取相似数据
PhotoDataManager.manager.loadFromFileSystem(resultModel: {[weak self] model in PhotoDataManager.manager.loadFromFileSystem(resultModel: {[weak self] model in
guard let self else {return} guard let self else {return}
let tempData = self.filterDataByDate(orgModels: model.titleModelArray[1].assets, startDate: filterModel.startDate, endDate: filterModel.endDate) var dataS : [[AssetModel]] = []
if self.type == .SimilarVideos{
dataS = model.otherModelArray[3].assets
}else {
dataS = model.titleModelArray[1].assets
}
let tempData = self.filterDataByDate(orgModels: dataS , startDate: filterModel.startDate, endDate: filterModel.endDate)
// 重新更新下数据源 // 重新更新下数据源
self.ids = self.sortData(source: tempData, type: filterModel.sortType) self.ids = self.sortData(source: tempData, type: filterModel.sortType)
var tempModels : [HomeInfoTableItem] = [] var tempModels : [HomeInfoTableItem] = []
...@@ -307,6 +313,33 @@ extension HomeInfoView:UITableViewDataSource,UITableViewDelegate { ...@@ -307,6 +313,33 @@ extension HomeInfoView:UITableViewDataSource,UITableViewDelegate {
self.tableScrollToNextRow() self.tableScrollToNextRow()
} }
// 重新设置models
func resetModels(){
var newArray : [HomeInfoTableItem] = []
for array in ids ?? [] {
var smodels:[ImageSeletedCollectionItem] = []
for id in array {
let smodel = ImageSeletedCollectionItem()
smodel.id = id
smodel.isSeleted = false
smodels.append(smodel)
}
let smodel = HomeInfoTableItem()
smodel.type = type
smodel.smodels = smodels
smodel.titleText = titleText
newArray.append(smodel)
}
self.models = newArray
}
/// 让表格自动滚动一行 /// 让表格自动滚动一行
private func tableScrollToNextRow(){ private func tableScrollToNextRow(){
...@@ -345,6 +378,11 @@ extension HomeInfoView:UITableViewDataSource,UITableViewDelegate { ...@@ -345,6 +378,11 @@ extension HomeInfoView:UITableViewDataSource,UITableViewDelegate {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: HomeInfoTableViewCell.identifier, for: indexPath) as! HomeInfoTableViewCell let cell = tableView.dequeueReusableCell(withIdentifier: HomeInfoTableViewCell.identifier, for: indexPath) as! HomeInfoTableViewCell
cell.saveKeepListFinishedCallback = {
self.ids?.remove(at: indexPath.section)
self.resetModels()
tableView.deleteRows(at: [indexPath], with: .automatic)
}
cell.type = self.type cell.type = self.type
cell.model = models[indexPath.row] cell.model = models[indexPath.row]
...@@ -492,7 +530,7 @@ class HomeInfoTitleView:UIView { ...@@ -492,7 +530,7 @@ class HomeInfoTitleView:UIView {
self.filterButton.snp.makeConstraints { make in self.filterButton.snp.makeConstraints { make in
make.top.equalToSuperview().offset(35) make.centerY.equalTo(self.titleLabel.snp.centerY)
make.right.equalToSuperview().offset(-15) make.right.equalToSuperview().offset(-15)
make.height.equalTo(28) make.height.equalTo(28)
make.width.equalTo(98) make.width.equalTo(98)
......
//
// PhotoRemoveNavView.swift
// PhoneManager
//
// Created by edy on 2025/5/13.
//
import UIKit
import SnapKit
class PhotoRemoveNavView: UIView {
public var backButton:UIButton!
public var sizeLbel : UILabel!
public var titleLbel : UILabel!
public var resetButton :UIButton!
private var topConstraint: Constraint?
var reSetCallBack:()->Void = {}
public var mediaType : TrashTypeEnum = .shot {
didSet{
if mediaType == .video {
self.sizeLbel.isHidden = false
self.topConstraint?.update(offset: 22 + statusBarHeight)
}else{
self.sizeLbel.isHidden = true
self.topConstraint?.update(offset: 6 + statusBarHeight)
}
}
}
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
backButton = UIButton()
backButton.setImage(UIImage(named: "nav_back"), for: .normal)
backButton.addTarget(self, action: #selector(backBtnClick), for: .touchUpInside)
self.addSubview(backButton)
backButton.snp.makeConstraints { make in
make.centerY.equalTo(navCenterY)
make.left.equalToSuperview().offset(marginLR)
make.width.height.equalTo(iconWH)
}
sizeLbel = UILabel()
sizeLbel.textColor = UIColor(red: 0.07, green: 0.07, blue: 0.07, alpha: 1)
sizeLbel.font = UIFont.systemFont(ofSize: 12, weight: .medium)
self.addSubview(sizeLbel)
sizeLbel.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.top.equalToSuperview().offset(statusBarHeight)
make.height.equalTo(22)
}
titleLbel = UILabel()
titleLbel.textColor = UIColor(red: 0.07, green: 0.07, blue: 0.07, alpha: 1)
titleLbel.font = UIFont.systemFont(ofSize: 12, weight: .medium)
self.addSubview(titleLbel)
titleLbel.snp.makeConstraints { make in
make.centerX.equalToSuperview()
self.topConstraint = make.top.equalToSuperview().offset(6 + statusBarHeight).constraint
make.height.equalTo(22)
}
resetButton = UIButton()
resetButton.setImage(UIImage(named: "Frame 3"), for: .normal)
resetButton.addTarget(self, action: #selector(resetButtonAction), for: .touchUpInside)
resetButton.isHidden = true
self.addSubview(resetButton)
resetButton.snp.makeConstraints { make in
make.centerY.equalTo(navCenterY)
make.right.equalToSuperview().offset(-marginLR)
make.width.height.equalTo(iconWH)
}
}
@objc private func backBtnClick() {
self.responderViewController()?.navigationController?.popViewController(animated: true)
}
@objc private func resetButtonAction() {
self.reSetCallBack()
}
}
//
// AnchorRotatableView.swift
// AIClean
//
// Created by 赵前 on 2025/5/10.
//
import Foundation
import UIKit
class PhotosRemoveBaseView: UIView {
var currentIndex : Int?
var initialCenter: CGPoint = .zero
var url : URL?
var innerVideoController : VideoViewController?
func reload(index:Int) -> Void {
if let url = url {
self.innerVideoController = VideoViewController()
if let vc = self.innerVideoController {
vc.isAutoPlay = index == 0
vc.url = url
self.imageView.removeFromSuperview()
self.addSubview(vc.view)
vc.view.snp.makeConstraints { make in
make.left.top.bottom.right.equalToSuperview()
}
}
}
}
var mediaType : TrashTypeEnum?
lazy var maskTempleteView : UIView = {
let view = UIView(frame: CGRectMake(0, 0, self.width, self.height))
return view
}()
private let imageView = UIImageView()
private let leftButton = UIButton()
private let rightButton = UIButton()
override init(frame: CGRect) {
super.init(frame: frame)
self.layer.cornerRadius = 20
self.clipsToBounds = true
setupUI()
self.imageView.isUserInteractionEnabled = true
let tap = UITapGestureRecognizer()
tap.addTarget(self, action: #selector(showDeatail))
self.imageView.addGestureRecognizer(tap)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupUI() {
// 配置图片视图
imageView.contentMode = .scaleAspectFit
addSubview(imageView)
leftButton.frame = CGRect(x: self.width / 2 - 45.5, y: self.height / 2 - 21, width: 95, height: 42)
leftButton.setTitle("Delete", for: .normal)
leftButton.backgroundColor = UIColor(red: 0.95, green: 0.21, blue: 0.21, alpha: 1)
leftButton.tintColor = .white
leftButton.layer.cornerRadius = 21
leftButton.clipsToBounds = true
leftButton.alpha = 0
addSubview(leftButton)
rightButton.frame = CGRect(x: self.width / 2 - 45.5, y: self.height / 2 - 21, width: 95, height: 42)
rightButton.setTitle("Retain", for: .normal)
rightButton.backgroundColor = UIColor(red: 0.18, green: 0.76, blue: 0.35, alpha: 1)
rightButton.tintColor = .white
rightButton.layer.cornerRadius = 21
rightButton.clipsToBounds = true
rightButton.alpha = 0
addSubview(rightButton)
}
func configure(with image: UIImage) {
imageView.image = image
imageView.frame = bounds
}
func showLeftButton() {
self.leftButton.center = self.center
UIView.animate(withDuration: 0.2) {
self.leftButton.alpha = 1
self.maskTempleteView.backgroundColor = UIColor(red: 0.95, green: 0.21, blue: 0.21, alpha: 0.4000)
self.addSubview(self.maskTempleteView)
self.rightButton.alpha = 0
}
}
func showRightButton() {
self.rightButton.center = self.center
UIView.animate(withDuration: 0.2) {
self.rightButton.alpha = 1
self.maskTempleteView.backgroundColor = UIColor(red: 0.26, green: 0.78, blue: 0.41, alpha: 0.4000)
self.addSubview(self.maskTempleteView)
self.leftButton.alpha = 0
}
}
func hideButtons() {
UIView.animate(withDuration: 0.2) {
self.leftButton.alpha = 0
self.rightButton.alpha = 0
self.maskTempleteView.removeFromSuperview()
self.leftButton.center = self.center
self.rightButton.center = self.center
}
}
@objc func showDeatail(){
let vc : PhotoDetailViewController = PhotoDetailViewController()
vc.showView.icon = self.imageView.image
vc.modalPresentationStyle = .fullScreen
self.responderViewController()?.present(vc, animated: true)
}
}
//
// TrashSubView.swift
// PhoneManager
//
// Created by edy on 2025/5/13.
//
import UIKit
class TrashSubView: UIView {
var clearTashDataCallBack : ()->Void = {}
var presentTashDetailViewClickCallBack : ()->Void = {}
lazy var resourceCountlabel : UILabel = {
let label = UILabel()
label.font = UIFont.systemFont(ofSize: 24, weight: .semibold)
label.textColor = UIColor(red: 0, green: 0, blue: 0, alpha: 1)
return label
}()
lazy var tipLabel : UILabel = {
let label = UILabel()
label.text = "The photo in the trash can"
label.font = UIFont.systemFont(ofSize: 12, weight: .semibold)
label.textColor = UIColor(red: 0, green: 0, blue: 0, alpha: 1)
label.numberOfLines = 0
return label
}()
lazy var emptyButton: UIButton = {
let button = UIButton(type: .custom)
button.setImage(UIImage(named: "ic_delete_duplicates"), for: .normal)
button.backgroundColor = UIColor(red: 0, green: 0.51, blue: 1, alpha: 1)
button.setTitle("Empty the garbage", for: .normal)
button.setTitleColor(.white, for: .normal)
button.titleLabel?.font = UIFont.systemFont(ofSize: 12, weight: .semibold)
button.layer.cornerRadius = 19
button.clipsToBounds = true
button.addTarget(self, action: #selector(emptyButtonAction), for: .touchUpInside)
return button
}()
override init(frame: CGRect) {
super.init(frame: frame)
// 给当前视图添加手势
addTapGestureToSelf()
// 添加UI
addUIViews()
setUILocation()
}
private func addUIViews(){
self.addSubview(self.resourceCountlabel)
self.addSubview(self.tipLabel)
self.addSubview(self.emptyButton)
}
private func setUILocation(){
self.resourceCountlabel.snp.makeConstraints { make in
make.left.equalToSuperview().offset(16)
make.centerY.equalToSuperview()
make.height.equalTo(22)
make.width.equalTo(30)
}
self.tipLabel.snp.makeConstraints { make in
make.top.equalToSuperview().offset(17)
make.bottom.equalToSuperview().offset(-17)
make.left.equalTo(self.resourceCountlabel.snp.right).offset(11)
make.width.equalTo(100)
}
self.emptyButton.snp.makeConstraints { make in
make.right.equalToSuperview().offset(-9)
make.height.equalTo(38)
make.centerY.equalToSuperview()
make.width.equalTo(145)
}
}
private func addTapGestureToSelf(){
self.isUserInteractionEnabled = true
let tap = UITapGestureRecognizer()
tap.addTarget(self, action: #selector(tapHandle))
self.addGestureRecognizer(tap)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension TrashSubView {
@objc func emptyButtonAction(){
self.clearTashDataCallBack()
}
@objc func tapHandle(){
self.presentTashDetailViewClickCallBack()
}
}
...@@ -13,6 +13,22 @@ class VideoDetaiNavView : UIView { ...@@ -13,6 +13,22 @@ class VideoDetaiNavView : UIView {
private var backButton:UIButton! private var backButton:UIButton!
var startSelectCallBack : (Bool)->Void = {choose in}
lazy var startSelectButton:UIButton = {
let button :UIButton = UIButton()
button.setTitle("Select", for: .normal)
button.setTitle("Cancel", for: .selected)
button.setTitleColor(UIColor(red: 0, green: 0.51, blue: 1, alpha: 1), for: .normal)
button.backgroundColor = UIColor(red: 0.95, green: 0.96, blue: 0.98, alpha: 1)
button.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .semibold)
button.layer.cornerRadius = 12
button.clipsToBounds = true
button.addTarget(self, action: #selector(startSelectButtonAction), for: .touchUpInside)
return button
}()
lazy var seletedAllBtn:UIButton = { lazy var seletedAllBtn:UIButton = {
let btn:UIButton = UIButton(frame: CGRect(x: 0, y: 0, width: 115, height: 32)) let btn:UIButton = UIButton(frame: CGRect(x: 0, y: 0, width: 115, height: 32))
...@@ -53,20 +69,23 @@ class VideoDetaiNavView : UIView { ...@@ -53,20 +69,23 @@ class VideoDetaiNavView : UIView {
self.addSubview(self.seletedAllBtn) self.addSubview(self.seletedAllBtn)
seletedAllBtn.x = self.width - marginLR - seletedAllBtn.width seletedAllBtn.x = marginLR
seletedAllBtn.centerY = navCenterY seletedAllBtn.centerY = navCenterY
// self.seletedAllBtn.snp.makeConstraints { make in
// make.right.equalToSuperview().offset(-23)
// make.centerY.equalTo(self.backButton.snp.centerY)
// }
backButton.snp.makeConstraints { make in backButton.snp.makeConstraints { make in
make.centerY.equalTo(navCenterY) make.centerY.equalTo(navCenterY)
make.left.equalToSuperview().offset(marginLR) make.left.equalToSuperview().offset(marginLR)
make.width.height.equalTo(iconWH) make.width.height.equalTo(iconWH)
} }
self.addSubview(self.startSelectButton)
self.startSelectButton.snp.makeConstraints { make in
make.centerY.equalTo(self.backButton.snp.centerY)
make.right.equalToSuperview().offset(-marginLR)
make.width.equalTo(91)
make.height.equalTo(24)
}
self.seletedAllBtn.isHidden = true
} }
...@@ -78,12 +97,21 @@ class VideoDetaiNavView : UIView { ...@@ -78,12 +97,21 @@ class VideoDetaiNavView : UIView {
DispatchQueue.main.async {[weak self] in DispatchQueue.main.async {[weak self] in
guard let self else {return} guard let self else {return}
// seletedAllBtn.isSelected = !seletedAllBtn.isSelected
seletedAllBtn.isSelected = !seletedAllBtn.isSelected seletedAllBtn.isSelected = !seletedAllBtn.isSelected
self.seletedAllBtn.width = seletedAllBtn.isSelected ? 131 : 115 self.seletedAllBtn.width = seletedAllBtn.isSelected ? 131 : 115
seletedAllBtn.x = self.width - marginLR - seletedAllBtn.width seletedAllBtn.x = marginLR
self.selectAllCallBack(seletedAllBtn.isSelected) self.selectAllCallBack(seletedAllBtn.isSelected)
} }
} }
@objc func startSelectButtonAction(){
self.startSelectButton.isSelected = !self.startSelectButton.isSelected
self.seletedAllBtn.isHidden = !self.startSelectButton.isSelected
if !self.startSelectButton.isSelected{
seletedAllBtn.isSelected = true
seletedAllBtnClick()
}
self.startSelectCallBack(self.startSelectButton.isSelected)
}
} }
...@@ -32,7 +32,7 @@ class YearMonthPickerView: UIView { ...@@ -32,7 +32,7 @@ class YearMonthPickerView: UIView {
return picker return picker
}() }()
private let years = Array(Array(Calendar.current.component(.year, from: Date())-30...Calendar.current.component(.year, from: Date())).reversed()) private let years = Array(Array(1970...Calendar.current.component(.year, from: Date())).reversed())
private lazy var months: [String] = { private lazy var months: [String] = {
let formatter = DateFormatter() let formatter = DateFormatter()
......
...@@ -24,6 +24,8 @@ class HomeInfoTableViewCell:UITableViewCell { ...@@ -24,6 +24,8 @@ class HomeInfoTableViewCell:UITableViewCell {
var callBack:callBack<Any> = {text in} var callBack:callBack<Any> = {text in}
var saveKeepListFinishedCallback : ()->Void = {}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier) super.init(style: style, reuseIdentifier: reuseIdentifier)
...@@ -217,10 +219,27 @@ extension HomeInfoTableViewCell:UICollectionViewDelegate,UICollectionViewDataSou ...@@ -217,10 +219,27 @@ extension HomeInfoTableViewCell:UICollectionViewDelegate,UICollectionViewDataSou
// 显示保留按钮或者最佳匹配结果按钮 // 显示保留按钮或者最佳匹配结果按钮
cell.allKeepButton.isHidden = indexPath.item != 0 || self.type == .duplicates cell.allKeepButton.isHidden = indexPath.item != 0 || self.type == .duplicates
cell.bestResultButton.isHidden = indexPath.item != 0 || self.type == .duplicates cell.bestResultButton.isHidden = indexPath.item != 0 || self.type == .duplicates
cell.model = model?.smodels?[indexPath.row] cell.model = model?.smodels?[indexPath.row]
cell.photsFileType = model?.type cell.photsFileType = model?.type
cell.keepAllCallBack = {
//存到保留列表
saveAllDataToKeepList()
self.saveKeepListFinishedCallback()
}
// 存全部数据到保留列表
func saveAllDataToKeepList(){
let uniqueId = UUID().uuidString
if let tempModel = self.model?.smodels {
for item in tempModel {
if let assetModel = item.id {
let success = GroupDatabase.shared.insert(localIdentifier: assetModel.localIdentifier, assetSize: assetModel.assetSize, createDate: assetModel.createDate, mediaType: self.type == .SimilarVideos ? 2 : 1 , groupId: uniqueId)
if success == false {
Print("存入当前数据到保留列表失败")
}
}
}
}
}
cell.callBack = {[weak self] _ in cell.callBack = {[weak self] _ in
...@@ -253,9 +272,22 @@ extension HomeInfoTableViewCell:UICollectionViewDelegate,UICollectionViewDataSou ...@@ -253,9 +272,22 @@ extension HomeInfoTableViewCell:UICollectionViewDelegate,UICollectionViewDataSou
}else{ }else{
vc.state = .similarPhotos vc.state = .similarPhotos
} }
vc.oldPageIndexPath = indexPath
vc.currentIdx = indexPath.row vc.currentIdx = indexPath.row
vc.homeDataSource = self.model?.smodels vc.homeDataSource = self.model?.smodels
self.responderViewController()?.navigationController?.pushViewController(vc, animated: true) self.responderViewController()?.navigationController?.pushViewController(vc, animated: true)
vc.backOrgPageCallBack = {[weak self]index,data in
guard let self else {return}
self.model?.smodels = data
DispatchQueue.main.async{
if let view = self.collectionView{
UIView.transition(with: view, duration: 0.3, options: .transitionCrossDissolve, animations: {
view.reloadData()
}, completion: nil)
}
}
}
} }
} }
......
...@@ -80,14 +80,12 @@ class HomeVideoDetailCell : UICollectionViewCell { ...@@ -80,14 +80,12 @@ class HomeVideoDetailCell : UICollectionViewCell {
lazy var backImageView: UIImageView = { lazy var backImageView: UIImageView = {
let view = UIImageView() let view = UIImageView()
view.isUserInteractionEnabled = true
view.contentMode = .scaleAspectFill view.contentMode = .scaleAspectFill
view.clipsToBounds = true view.clipsToBounds = true
view.layer.masksToBounds = true view.layer.masksToBounds = true
view.layer.cornerRadius = 12 view.layer.cornerRadius = 12
view.isUserInteractionEnabled = true view.isUserInteractionEnabled = true
let tap = UITapGestureRecognizer() let tap = UITapGestureRecognizer()
tap.addTarget(self, action: #selector(cellClick)) tap.addTarget(self, action: #selector(cellClick))
view.addGestureRecognizer(tap) view.addGestureRecognizer(tap)
......
...@@ -19,6 +19,8 @@ class ImageSeletedCollectionCell:UICollectionViewCell { ...@@ -19,6 +19,8 @@ class ImageSeletedCollectionCell:UICollectionViewCell {
var callBack:callBack<Any> = {text in} var callBack:callBack<Any> = {text in}
var keepAllCallBack : ()->Void = {}
lazy var allKeepButton : UIButton = { lazy var allKeepButton : UIButton = {
let button = UIButton(type: .custom) let button = UIButton(type: .custom)
...@@ -37,8 +39,8 @@ class ImageSeletedCollectionCell:UICollectionViewCell { ...@@ -37,8 +39,8 @@ class ImageSeletedCollectionCell:UICollectionViewCell {
let button = UIButton(type: .custom) let button = UIButton(type: .custom)
button.layer.cornerRadius = 8 button.layer.cornerRadius = 8
button.clipsToBounds = true button.clipsToBounds = true
button.backgroundColor = UIColor(red: 0, green: 0.51, blue: 1, alpha: 1) button.backgroundColor = UIColor(red: 1, green: 0.65, blue: 0, alpha: 1)
button.setTitle( "Best result", for: .normal) button.setTitle( "Best", for: .normal)
button.setImage(UIImage(named: "Frame"), for: .normal) button.setImage(UIImage(named: "Frame"), for: .normal)
button.setTitleColor(.white, for: .normal) button.setTitleColor(.white, for: .normal)
button.isHidden = true button.isHidden = true
...@@ -179,7 +181,7 @@ class ImageSeletedCollectionCell:UICollectionViewCell { ...@@ -179,7 +181,7 @@ class ImageSeletedCollectionCell:UICollectionViewCell {
self.bestResultButton.snp.makeConstraints { make in self.bestResultButton.snp.makeConstraints { make in
make.left.bottom.equalToSuperview() make.left.bottom.equalToSuperview()
make.width.equalTo(81) make.width.equalTo(52)
make.height.equalTo(16) make.height.equalTo(16)
} }
...@@ -222,6 +224,8 @@ class ImageSeletedCollectionCell:UICollectionViewCell { ...@@ -222,6 +224,8 @@ class ImageSeletedCollectionCell:UICollectionViewCell {
extension ImageSeletedCollectionCell { extension ImageSeletedCollectionCell {
@objc func allKeepButtonAction(){ @objc func allKeepButtonAction(){
Print("点击了全部保留按钮") Print("点击了全部保留按钮")
self.keepAllCallBack()
} }
} }
...@@ -29,6 +29,21 @@ class PMShowImgCell: UICollectionViewCell { ...@@ -29,6 +29,21 @@ class PMShowImgCell: UICollectionViewCell {
} }
} }
lazy var bestResultButton:UIButton = {
let button = UIButton(type: .custom)
button.setImage(UIImage(named: "Frame"), for: .normal)
button.setTitle("Best", for: .normal)
button.setTitleColor(.white, for: .normal)
button.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .semibold)
button.layer.cornerRadius = 10.5
button.clipsToBounds = true
button.backgroundColor = UIColor(red: 1, green: 0.65, blue: 0, alpha: 1)
contentView.addSubview(button)
return button
}()
private lazy var iconView: UIImageView = { private lazy var iconView: UIImageView = {
let info = UIImageView() let info = UIImageView()
info.contentMode = .scaleAspectFill info.contentMode = .scaleAspectFill
...@@ -63,6 +78,14 @@ class PMShowImgCell: UICollectionViewCell { ...@@ -63,6 +78,14 @@ class PMShowImgCell: UICollectionViewCell {
} }
private func setup() -> Void { private func setup() -> Void {
bestResultButton.snp.makeConstraints { make in
make.left.equalToSuperview().offset(15)
make.top.equalToSuperview().offset(34)
make.width.equalTo(63)
make.height.equalTo(21)
}
iconView.snp.makeConstraints { make in iconView.snp.makeConstraints { make in
make.left.right.bottom.top.equalToSuperview() make.left.right.bottom.top.equalToSuperview()
} }
...@@ -74,5 +97,7 @@ class PMShowImgCell: UICollectionViewCell { ...@@ -74,5 +97,7 @@ class PMShowImgCell: UICollectionViewCell {
make.width.height.equalTo(iconWH) make.width.height.equalTo(iconWH)
make.bottom.equalToSuperview().offset(-10) make.bottom.equalToSuperview().offset(-10)
} }
self.contentView.bringSubviewToFront(self.bestResultButton)
} }
} }
...@@ -17,6 +17,8 @@ class PMShowVideoCell: UICollectionViewCell { ...@@ -17,6 +17,8 @@ class PMShowVideoCell: UICollectionViewCell {
var type : Int = 0 var type : Int = 0
var innerVideoController : VideoViewController?
func reload() -> Void { func reload() -> Void {
var url : URL? var url : URL?
if type == 0 { if type == 0 {
...@@ -25,25 +27,39 @@ class PMShowVideoCell: UICollectionViewCell { ...@@ -25,25 +27,39 @@ class PMShowVideoCell: UICollectionViewCell {
url = homeResouceUrl url = homeResouceUrl
} }
if let url = url { if let url = url {
player.playVideo(from: url) self.innerVideoController = VideoViewController()
if let vc = self.innerVideoController {
vc.url = url
self.contentView.addSubview(vc.view)
self.contentView.bringSubviewToFront(self.selectBtn)
vc.view.snp.makeConstraints { make in
make.left.top.bottom.right.equalToSuperview()
}
}
} }
} }
override init(frame: CGRect) { override init(frame: CGRect) {
super.init(frame: frame) super.init(frame: frame)
setup() self.contentView.addSubview(self.selectBtn)
selectBtn.snp.makeConstraints { make in
make.right.equalToSuperview()
make.width.height.equalTo(iconWH)
make.bottom.equalToSuperview().offset(-10)
}
bestResultButton.snp.makeConstraints { make in
make.left.equalToSuperview().offset(15)
make.top.equalToSuperview().offset(34)
make.width.equalTo(63)
make.height.equalTo(21)
}
self.contentView.bringSubviewToFront(self.bestResultButton)
} }
required init?(coder: NSCoder) { required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
private func setup() -> Void {
player.snp.makeConstraints { make in
make.left.top.bottom.right.equalToSuperview()
}
}
var zPlayer : SecretVideoPlayer { var zPlayer : SecretVideoPlayer {
get { get {
return player return player
...@@ -57,4 +73,44 @@ class PMShowVideoCell: UICollectionViewCell { ...@@ -57,4 +73,44 @@ class PMShowVideoCell: UICollectionViewCell {
contentView.addSubview(p) contentView.addSubview(p)
return p return p
}() }()
var callblock:(()->Void) = {}
@objc private func selectTap() -> Void {
callblock()
}
var isCurrent:Bool = false {
didSet {
selectBtn.isSelected = isCurrent
}
}
lazy var selectBtn: UIButton = {
let select = UIButton(type: .custom)
select.setImage(UIImage(named: "home_info_norl"), for: .normal)
select.setImage(UIImage(named: "home_info_seleted"), for: .selected)
select.addTarget(self, action: #selector(selectTap), for: .touchUpInside)
contentView.addSubview(select)
return select
}()
lazy var bestResultButton:UIButton = {
let button = UIButton(type: .custom)
button.setImage(UIImage(named: "Frame"), for: .normal)
button.setTitle("Best", for: .normal)
button.setTitleColor(.white, for: .normal)
button.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .semibold)
button.layer.cornerRadius = 10.5
button.clipsToBounds = true
button.backgroundColor = UIColor(red: 1, green: 0.65, blue: 0, alpha: 1)
contentView.addSubview(button)
return button
}()
} }
...@@ -21,16 +21,32 @@ class PMShowImgVideoController: BaseViewController { ...@@ -21,16 +21,32 @@ class PMShowImgVideoController: BaseViewController {
// 资源类型 0-图片 1-视频 // 资源类型 0-图片 1-视频
var homeMediaType : Int = 0 var homeMediaType : Int = 0
// 记录原来进来的
var oldPageIndexPath : IndexPath?
var state:ShowState = .secret var state:ShowState = .secret
var imageVideoPath:[String] = [] var imageVideoPath:[String] = []
// 首页过来的数据 // 首页过来的数据
var homeDataSource : [ImageSeletedCollectionItem]? var homeDataSource : [ImageSeletedCollectionItem]? {
didSet{
if let data = homeDataSource {
for (index,item) in data.enumerated() {
if item.isSeleted == true {
selectSet.add(index)
}
}
}
}
}
var currentIdx = 0 var currentIdx = 0
var selectSet = NSMutableSet() var selectSet = NSMutableSet()
var backOrgPageCallBack : (IndexPath?,[ImageSeletedCollectionItem]?)->Void = {index,data in}
var url : URL? var url : URL?
override func viewDidLoad() { override func viewDidLoad() {
...@@ -53,6 +69,19 @@ class PMShowImgVideoController: BaseViewController { ...@@ -53,6 +69,19 @@ class PMShowImgVideoController: BaseViewController {
self.MaxCollection.scrollToItem(at: IndexPath(row: currentIdx, section: 0), at: .centeredHorizontally, animated: false) self.MaxCollection.scrollToItem(at: IndexPath(row: currentIdx, section: 0), at: .centeredHorizontally, animated: false)
} }
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// 离开返回上一个把选择的数据带过去
for item in self.selectSet {
if let index = item as? Int {
self.homeDataSource?[index].isSeleted = true
}
}
self.backOrgPageCallBack(self.oldPageIndexPath,self.homeDataSource)
}
private lazy var MaxCollection: UICollectionView = { private lazy var MaxCollection: UICollectionView = {
let flowlayout = UICollectionViewFlowLayout() let flowlayout = UICollectionViewFlowLayout()
flowlayout.sectionInset = UIEdgeInsets() flowlayout.sectionInset = UIEdgeInsets()
...@@ -131,8 +160,10 @@ extension PMShowImgVideoController : UICollectionViewDelegate,UICollectionViewDa ...@@ -131,8 +160,10 @@ extension PMShowImgVideoController : UICollectionViewDelegate,UICollectionViewDa
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if collectionView == bottItems { if collectionView == bottItems {
if selectSet.contains(indexPath.row) { if selectSet.contains(indexPath.row) {
self.homeDataSource?[indexPath.row].isSeleted = false
selectSet.remove(indexPath.row) selectSet.remove(indexPath.row)
}else{ }else{
self.homeDataSource?[indexPath.row].isSeleted = true
selectSet.add(indexPath.row) selectSet.add(indexPath.row)
} }
self.MaxCollection.reloadData() self.MaxCollection.reloadData()
...@@ -158,7 +189,7 @@ extension PMShowImgVideoController : UICollectionViewDelegate,UICollectionViewDa ...@@ -158,7 +189,7 @@ extension PMShowImgVideoController : UICollectionViewDelegate,UICollectionViewDa
let showName = imageVideoPath[indexPath.row] let showName = imageVideoPath[indexPath.row]
if !showName.hasSuffix(".png") { if !showName.hasSuffix(".png") {
guard let zCell:PMShowVideoCell = cell as? PMShowVideoCell else { return } guard let zCell:PMShowVideoCell = cell as? PMShowVideoCell else { return }
zCell.zPlayer.pause() zCell.innerVideoController?.playerViewController.player?.pause()
} }
} }
} }
...@@ -172,12 +203,16 @@ extension PMShowImgVideoController : UICollectionViewDelegate,UICollectionViewDa ...@@ -172,12 +203,16 @@ extension PMShowImgVideoController : UICollectionViewDelegate,UICollectionViewDa
showName.loadPhotoOrVideo { durs, icon in showName.loadPhotoOrVideo { durs, icon in
cell.icon = icon cell.icon = icon
} }
cell.bestResultButton.isHidden = indexPath.row != 0
cell.isCurrent = selectSet.contains(indexPath.row) cell.isCurrent = selectSet.contains(indexPath.row)
cell.callblock = {[weak self] in cell.callblock = {[weak self] in
guard let self = self else { return } guard let self = self else { return }
if self.selectSet.contains(indexPath.row){ if self.selectSet.contains(indexPath.row){
self.homeDataSource?[indexPath.row].isSeleted = false
self.selectSet.remove(indexPath.row) self.selectSet.remove(indexPath.row)
}else{ }else{
self.homeDataSource?[indexPath.row].isSeleted = true
self.selectSet.add(indexPath.row) self.selectSet.add(indexPath.row)
} }
self.MaxCollection.reloadData() self.MaxCollection.reloadData()
...@@ -186,8 +221,21 @@ extension PMShowImgVideoController : UICollectionViewDelegate,UICollectionViewDa ...@@ -186,8 +221,21 @@ extension PMShowImgVideoController : UICollectionViewDelegate,UICollectionViewDa
return cell return cell
}else{ }else{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PMShowVideoCellID, for: indexPath) as! PMShowVideoCell let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PMShowVideoCellID, for: indexPath) as! PMShowVideoCell
cell.isCurrent = selectSet.contains(indexPath.row)
cell.playURL = showName cell.playURL = showName
cell.reload() cell.reload()
cell.callblock = {[weak self] in
guard let self = self else { return }
if self.selectSet.contains(indexPath.row){
self.homeDataSource?[indexPath.row].isSeleted = false
self.selectSet.remove(indexPath.row)
}else{
self.homeDataSource?[indexPath.row].isSeleted = true
self.selectSet.add(indexPath.row)
}
self.MaxCollection.reloadData()
self.bottItems.reloadData()
}
return cell return cell
} }
}else{ }else{
...@@ -208,11 +256,14 @@ extension PMShowImgVideoController : UICollectionViewDelegate,UICollectionViewDa ...@@ -208,11 +256,14 @@ extension PMShowImgVideoController : UICollectionViewDelegate,UICollectionViewDa
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PMShowImgCellID, for: indexPath) as! PMShowImgCell let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PMShowImgCellID, for: indexPath) as! PMShowImgCell
cell.icon = self.homeDataSource![indexPath.row].image ?? UIImage() cell.icon = self.homeDataSource![indexPath.row].image ?? UIImage()
cell.isCurrent = selectSet.contains(indexPath.row) cell.isCurrent = selectSet.contains(indexPath.row)
cell.bestResultButton.isHidden = indexPath.row != 0
cell.callblock = {[weak self] in cell.callblock = {[weak self] in
guard let self = self else { return } guard let self = self else { return }
if self.selectSet.contains(indexPath.row){ if self.selectSet.contains(indexPath.row){
self.homeDataSource?[indexPath.row].isSeleted = false
self.selectSet.remove(indexPath.row) self.selectSet.remove(indexPath.row)
}else{ }else{
self.homeDataSource?[indexPath.row].isSeleted = true
self.selectSet.add(indexPath.row) self.selectSet.add(indexPath.row)
} }
self.MaxCollection.reloadData() self.MaxCollection.reloadData()
...@@ -247,6 +298,20 @@ extension PMShowImgVideoController : UICollectionViewDelegate,UICollectionViewDa ...@@ -247,6 +298,20 @@ extension PMShowImgVideoController : UICollectionViewDelegate,UICollectionViewDa
} }
// 表示这个是视频 // 表示这个是视频
cell.type = 1 cell.type = 1
cell.isCurrent = selectSet.contains(indexPath.row)
cell.bestResultButton.isHidden = indexPath.row != 0
cell.callblock = {[weak self] in
guard let self = self else { return }
if self.selectSet.contains(indexPath.row){
self.homeDataSource?[indexPath.row].isSeleted = false
self.selectSet.remove(indexPath.row)
}else{
self.homeDataSource?[indexPath.row].isSeleted = true
self.selectSet.add(indexPath.row)
}
self.MaxCollection.reloadData()
self.bottItems.reloadData()
}
return cell return cell
}else{ }else{
if indexPath.row < self.homeDataSource?.count ?? 0 { if indexPath.row < self.homeDataSource?.count ?? 0 {
......
...@@ -329,6 +329,16 @@ extension SecretViewController : UICollectionViewDelegate,UICollectionViewDataSo ...@@ -329,6 +329,16 @@ extension SecretViewController : UICollectionViewDelegate,UICollectionViewDataSo
let play = PMShowImgVideoController() let play = PMShowImgVideoController()
play.currentIdx = indexPath.row play.currentIdx = indexPath.row
play.imageVideoPath = dataSource play.imageVideoPath = dataSource
play.oldPageIndexPath = indexPath
play.backOrgPageCallBack = {[weak self]index,data in
guard let self else {return}
self.selectArray = play.selectSet
DispatchQueue.main.async{
UIView.transition(with: self.secretCollect, duration: 0.3, options: .transitionCrossDissolve, animations: {
self.secretCollect.reloadData()
}, completion: nil)
}
}
self.navigationController?.pushViewController(play, animated: true) self.navigationController?.pushViewController(play, animated: true)
} }
......
...@@ -11,6 +11,12 @@ import AVFoundation ...@@ -11,6 +11,12 @@ import AVFoundation
class SecretVideoPlayer: UIView { class SecretVideoPlayer: UIView {
var callBackCurrtntTimeString : (String)->Void = {currentTimeString in }
var tapPauseCallback : (playState)->Void = {state in}
var timeObserverToken: Any?
private var player: AVPlayer? private var player: AVPlayer?
var isLooping = false var isLooping = false
...@@ -48,11 +54,11 @@ class SecretVideoPlayer: UIView { ...@@ -48,11 +54,11 @@ class SecretVideoPlayer: UIView {
state = .playing state = .playing
player?.seek(to: CMTime.zero) player?.seek(to: CMTime.zero)
resume() resume()
} }else{
else{
state = .pause state = .pause
pause() pause()
} }
self.tapPauseCallback(state)
} }
private func setupPlayerLayer() { private func setupPlayerLayer() {
...@@ -91,15 +97,31 @@ class SecretVideoPlayer: UIView { ...@@ -91,15 +97,31 @@ class SecretVideoPlayer: UIView {
} }
NotificationCenter.default.addObserver( NotificationCenter.default.addObserver(
self, self,
selector: #selector(playerItemDidReachEnd), selector: #selector( playerItemDidReachEnd),
name: .AVPlayerItemDidPlayToEndTime, name: .AVPlayerItemDidPlayToEndTime,
object: player?.currentItem object: player?.currentItem
) )
addTimeObserver()
state = .playing state = .playing
player?.play() player?.play()
} }
func addTimeObserver(){
let interval = CMTime(seconds: 0.1, preferredTimescale: CMTimeScale(NSEC_PER_SEC))
timeObserverToken = player?.addPeriodicTimeObserver(forInterval: interval, queue: .main) { [weak self] time in
guard let self = self, let currentItem = self.player?.currentItem else { return }
let currentTime = time.seconds
let totalDuration = currentItem.duration.seconds
// 更新进度标签
self.callBackCurrtntTimeString("\(self.formatTime(seconds: currentTime))")
}
}
// 播放完成回调 // 播放完成回调
@objc private func playerItemDidReachEnd(notification: Notification) { @objc private func playerItemDidReachEnd(notification: Notification) {
if isLooping { if isLooping {
...@@ -107,6 +129,7 @@ class SecretVideoPlayer: UIView { ...@@ -107,6 +129,7 @@ class SecretVideoPlayer: UIView {
player?.play() player?.play()
} }
state = .end state = .end
self.tapPauseCallback(state)
} }
// 暂停播放 // 暂停播放
...@@ -128,10 +151,30 @@ class SecretVideoPlayer: UIView { ...@@ -128,10 +151,30 @@ class SecretVideoPlayer: UIView {
name: .AVPlayerItemDidPlayToEndTime, name: .AVPlayerItemDidPlayToEndTime,
object: nil object: nil
) )
if let token = timeObserverToken {
self.player?.removeTimeObserver(token)
timeObserverToken = nil
}
} }
// 清理资源 // 清理资源
deinit { deinit {
removeObservers() removeObservers()
} }
func formatTime(seconds: Double) -> String {
guard !seconds.isNaN else { return "00:00" }
let totalSeconds = Int(seconds)
let hours = totalSeconds / 3600
let minutes = (totalSeconds % 3600) / 60
let seconds = totalSeconds % 60
if hours > 0 {
return String(format: "%02d:%02d:%02d", hours, minutes, seconds)
} else {
return String(format: "%02d:%02d", minutes, seconds)
}
}
} }
...@@ -7,7 +7,9 @@ ...@@ -7,7 +7,9 @@
import UIKit import UIKit
class TrashViewController: UIViewController { class TrashViewController: BaseViewController {
var dissmisCallBack:()->Void = {}
var source:[TrashTypeEnum] = [.video,.other,.shot,.chat] var source:[TrashTypeEnum] = [.video,.other,.shot,.chat]
...@@ -17,11 +19,42 @@ class TrashViewController: UIViewController { ...@@ -17,11 +19,42 @@ class TrashViewController: UIViewController {
var currentType:TrashTypeEnum = .other var currentType:TrashTypeEnum = .other
let pageCount = 4 // 总页数 let pageCount = 4 // 总页数
var currentPage = 1 var currentPage = 1 {
didSet{
self.setDelButtonUI()
}
}
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
configUI() configUI()
getTrashDataAndRefreshPage()
setContentOffSet()
}
/// 获取垃圾桶数据
private func getTrashDataAndRefreshPage(){
for item in self.source {
let data = TrashDataManager.getCurrentMediaTypeTrashData(mediaType: item)
for view in self.contentScrollView.subviews {
if view.isKind(of: TrashContenView.self){
let tempView = view as! TrashContenView
if tempView.trashType == item{
tempView.mediaType = item
tempView.dataSource = data
}
}
}
}
// 将所有数据获取完成之后,重新刷新下删除按钮
setDelButtonUI()
}
// 在第一次进去的时候执行一次
private func setContentOffSet(){
self.contentScrollView.contentOffset = CGPointMake(ScreenW * CGFloat(self.currentPage - 1), 0)
} }
...@@ -42,7 +75,8 @@ class TrashViewController: UIViewController { ...@@ -42,7 +75,8 @@ class TrashViewController: UIViewController {
delBtn.setTitleColor(.white, for: .normal) delBtn.setTitleColor(.white, for: .normal)
delBtn.titleLabel?.font = UIFont.systemFont(ofSize: 16, weight: .semibold) delBtn.titleLabel?.font = UIFont.systemFont(ofSize: 16, weight: .semibold)
delBtn.backgroundColor = UIColor.colorWithHex(hexStr: "#0082FF") delBtn.backgroundColor = UIColor.colorWithHex(hexStr: "#0082FF")
delBtn.layer.cornerRadius = 10 delBtn.layer.cornerRadius = 20
delBtn.addTarget(self, action: #selector(delBtnAction), for: .touchUpInside)
view.addSubview(delBtn) view.addSubview(delBtn)
delBtn.snp.makeConstraints { make in delBtn.snp.makeConstraints { make in
...@@ -65,6 +99,12 @@ class TrashViewController: UIViewController { ...@@ -65,6 +99,12 @@ class TrashViewController: UIViewController {
contentScrollView.addSubview(otherView) contentScrollView.addSubview(otherView)
contentScrollView.addSubview(shotView) contentScrollView.addSubview(shotView)
contentScrollView.addSubview(chatView) contentScrollView.addSubview(chatView)
videoView.deleteButton = delBtn
otherView.deleteButton = delBtn
shotView.deleteButton = delBtn
chatView.deleteButton = delBtn
} }
override func viewWillLayoutSubviews() { override func viewWillLayoutSubviews() {
...@@ -171,4 +211,64 @@ extension TrashViewController:UIScrollViewDelegate{ ...@@ -171,4 +211,64 @@ extension TrashViewController:UIScrollViewDelegate{
self.currentPage = currentPage + 1 self.currentPage = currentPage + 1
} }
@objc func delBtnAction(){
let info = self.getTypeByCurrentPage(pageIndex: currentPage)
let data = TrashDataManager.getCurrentMediaTypeTrashData(mediaType: info.0)
if data.count > 0 {
TrashDataManager.clearTrashData(mediaType: info.0) {
info.1.dataSource.removeAll()
}
}
}
private func getTypeByCurrentPage(pageIndex : Int)->(TrashTypeEnum,TrashContenView){
if self.currentPage == 1 {
return (TrashTypeEnum.video,self.videoView)
}
if self.currentPage == 2 {
return (TrashTypeEnum.other,self.otherView)
}
if self.currentPage == 3 {
return (TrashTypeEnum.shot,self.shotView)
}
if self.currentPage == 4 {
return (TrashTypeEnum.chat,self.chatView)
}
return (TrashTypeEnum.video,self.videoView)
}
private func setDelButtonUI(){
let info = self.getTypeByCurrentPage(pageIndex: currentPage)
let data : [AssetModel] = TrashDataManager.getCurrentMediaTypeTrashData(mediaType: info.0)
let type : TrashTypeEnum = info.0
DispatchQueue.main.async {
if data.count <= 0{
self.delBtn.setTitle("Delete", for: .normal)
self.delBtn.backgroundColor = UIColor(red: 0.6, green: 0.6, blue: 0.6, alpha: 1)
}else {
self.delBtn.backgroundColor = UIColor(red: 0, green: 0.51, blue: 1, alpha: 1)
if type == .video{
self.delBtn.setTitle("Delete \(data.count) \(self.getUnits(type:type,data:data))", for: .normal)
}else {
self.delBtn.setTitle("Delete \(data.count) \(self.getUnits(type:type,data:data))", for: .normal)
}
}
}
}
// 获取单位复数
private func getUnits(type:TrashTypeEnum,data: [AssetModel])->String{
if data.count > 1 {
return type == .video ? "videos" : "photos"
}else {
return type == .video ? "video" : "photo"
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.dissmisCallBack()
}
} }
//
// TrashDataManager.swift
// PhoneManager
//
// Created by edy on 2025/5/14.
//
import UIKit
class TrashDataManager {
// 撤销当前类型垃圾桶某个数据
static func revokeTrashData(mediaType: TrashTypeEnum?, identifier:String, comlete:@escaping ()->Void){
// 清空单利和数据库的数据
clearCurrentMediaTypeTrashSigtonData(mediaType: mediaType,identifier: identifier)
clearCurrentMediaTypeTrashDBData(mediaType: mediaType,identifier: identifier)
comlete()
}
/// 清除当前类型垃圾桶的所有数据
static func clearTrashData(mediaType: TrashTypeEnum?, comlete:@escaping ()->Void){
let trashData = self.getCurrentMediaTypeTrashData(mediaType: mediaType)
if trashData.count > 0 {
PhotoAndVideoMananger.deleteAssets(localIdentifiers: trashData.map({$0.localIdentifier})) {
// 清空单利和数据库的数据
clearCurrentMediaTypeTrashSigtonData(mediaType: mediaType)
clearCurrentMediaTypeTrashDBData(mediaType: mediaType)
// 删除完成之后回调
comlete()
}
}else{
comlete()
}
}
static func clearCurrentMediaTypeTrashSigtonData(mediaType:TrashTypeEnum?,identifier:String? = nil){
if let type = mediaType {
if identifier == nil{
Singleton.shared.trashData[type] = []
}else {
Singleton.shared.trashData[type] = Singleton.shared.trashData[type]?.filter({$0.localIdentifier != identifier})
}
Print("删除单利中当前垃圾桶数据成功")
}
}
static func clearCurrentMediaTypeTrashDBData(mediaType:TrashTypeEnum?,identifier:String? = nil){
if let type = mediaType {
if identifier == nil{
let dataDB = TrashDatabase.shared.queryByMediaType(type.dbType)
let success = TrashDatabase.shared.batchDelete(localIdentifiers: dataDB.map({$0.localIdentifier}))
if !success {
Print("删除数据库当前垃圾桶数据失败")
}
}else{
let success = TrashDatabase.shared.delete(localIdentifier: identifier!)
if !success {
Print("删除数据库当前数据失败")
}
}
}
}
static func getCurrentMediaTypeTrashData(mediaType: TrashTypeEnum?) -> [AssetModel]{
var assetModel : [AssetModel] = []
if let type = mediaType{
// 从数据库拿数据
let dataDB = TrashDatabase.shared.queryByMediaType(type.dbType)
for item in dataDB {
assetModel.append(AssetModel.init(localIdentifier: item.localIdentifier, assetSize: item.assetSize, createDate: item.createDate, mediaType: item.mediaType))
}
// 从单利拿数据
if let type = mediaType{
if let dataSg = Singleton.shared.trashData[type]{
assetModel = assetModel + dataSg
}
}
}
return assetModel
}
}
...@@ -7,8 +7,11 @@ ...@@ -7,8 +7,11 @@
import Foundation import Foundation
enum TrashTypeEnum{ enum TrashTypeEnum : String, CaseIterable{
case video,other,shot,chat case video = "Video"
case other = "Other"
case shot = "Screenshot"
case chat = "Chat"
var dbType:Int{ var dbType:Int{
switch self { switch self {
......
...@@ -9,6 +9,10 @@ import UIKit ...@@ -9,6 +9,10 @@ import UIKit
class TrashContenAssetCell: UICollectionViewCell { class TrashContenAssetCell: UICollectionViewCell {
var mediaType : TrashTypeEnum?
var revokeCallBack:()->Void = {}
@IBOutlet weak var assetImage: UIImageView! @IBOutlet weak var assetImage: UIImageView!
override func awakeFromNib() { override func awakeFromNib() {
...@@ -24,16 +28,29 @@ class TrashContenAssetCell: UICollectionViewCell { ...@@ -24,16 +28,29 @@ class TrashContenAssetCell: UICollectionViewCell {
var model:AssetModel?{ var model:AssetModel?{
didSet{ didSet{
guard let model = model else{ guard let model = model else{return}
return if self.mediaType == .video {
PhotoAndVideoMananger.mananger.getPreImageFromVideo(identifier: model.localIdentifier, completed: { [weak self] image in
guard let self else {return}
DispatchQueue.main.async {
self.assetImage.image = image
}
})
}else {
DispatchQueue.main.async {
self.assetImage.image = PhotoAndVideoMananger.mananger.getImageFromAssetID(id: model.localIdentifier)
}
} }
} }
// assetImage.im
} }
@IBAction func removeClick(_ sender: Any) { @IBAction func removeClick(_ sender: Any) {
// 移除数据
if let model = self.model {
TrashDataManager.revokeTrashData(mediaType: self.mediaType,identifier: model.localIdentifier) {
self.revokeCallBack()
}
}
} }
......
...@@ -11,6 +11,13 @@ class TrashContenView: UIView { ...@@ -11,6 +11,13 @@ class TrashContenView: UIView {
var collectionView: UICollectionView! var collectionView: UICollectionView!
var mediaType : TrashTypeEnum?
var defaultView : TrashDefaultView = {
let view = TrashDefaultView()
return view
}()
var typeLabel:UILabel! var typeLabel:UILabel!
var sizeLabel:UILabel! var sizeLabel:UILabel!
...@@ -19,10 +26,16 @@ class TrashContenView: UIView { ...@@ -19,10 +26,16 @@ class TrashContenView: UIView {
var lineThree: UIView! var lineThree: UIView!
var lineFour: UIView! var lineFour: UIView!
var deleteButton : UIButton?
var scrollLine:UIView! var scrollLine:UIView!
let lineW:CGFloat = (ScreenW - 62) / 4.0 let lineW:CGFloat = (ScreenW - 62) / 4.0
var dataSource:[AssetModel] = [] var dataSource:[AssetModel] = [] {
didSet{
self.resetContenViewUI()
}
}
override init(frame: CGRect) { override init(frame: CGRect) {
super.init(frame: frame) super.init(frame: frame)
...@@ -45,6 +58,18 @@ class TrashContenView: UIView { ...@@ -45,6 +58,18 @@ class TrashContenView: UIView {
/// 当数据为空的时候显示默认页面
func setDefauleUI(){
self.collectionView.removeFromSuperview()
self.defaultView.mediaType = self.mediaType
self.addSubview(self.defaultView)
self.defaultView.snp.makeConstraints { make in
make.left.top.right.bottom.equalToSuperview()
}
}
func configUI(){ func configUI(){
let layout = UICollectionViewFlowLayout() let layout = UICollectionViewFlowLayout()
layout.minimumInteritemSpacing = 12 layout.minimumInteritemSpacing = 12
...@@ -254,6 +279,75 @@ extension TrashContenView:UICollectionViewDelegate,UICollectionViewDataSource,UI ...@@ -254,6 +279,75 @@ extension TrashContenView:UICollectionViewDelegate,UICollectionViewDataSource,UI
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TrashContenAssetCell", for: indexPath) as! TrashContenAssetCell let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TrashContenAssetCell", for: indexPath) as! TrashContenAssetCell
// 设置image
cell.mediaType = self.trashType
cell.model = self.dataSource[indexPath.item]
cell.revokeCallBack = {
// 重新设置数据源
self.dataSource = TrashDataManager.getCurrentMediaTypeTrashData(mediaType: self.mediaType)
}
return cell return cell
} }
/// 重新刷新页面UI
private func resetContenViewUI(){
DispatchQueue.main.async {
// 设置数量
if self.trashType == .video{
self.sizeLabel.text = "\(self.dataSource.count) \(self.getUnits()) · \(self.getDataSize(array: self.dataSource))"
}else{
self.sizeLabel.text = "\(self.dataSource.count) \(self.getUnits()) · \(self.getDataSize(array: self.dataSource))"
}
// 设置标题
self.typeLabel.text = "Trash Can · \(self.trashType.rawValue)"
// 设置button的文字和样式
self.setDeleteButtonUI()
if self.dataSource.count > 0 {
self.collectionView.reloadData()
}else {
self.setDefauleUI()
}
}
}
/// 获取资源总大小
/// - Parameter array: 资源数组
/// - Returns: 格式化后的总大小
func getDataSize(array : [AssetModel]) -> String{
var size : Double = 0.0
for item in array {
size = size + item.assetSize
}
return formatFileSize(size)
}
private func setDeleteButtonUI(){
if let deleteButton = self.deleteButton {
if self.dataSource.count <= 0{
deleteButton.setTitle("Delete", for: .normal)
deleteButton.backgroundColor = UIColor(red: 0.6, green: 0.6, blue: 0.6, alpha: 1)
return
}
deleteButton.backgroundColor = UIColor(red: 0, green: 0.51, blue: 1, alpha: 1)
if self.trashType == .video{
deleteButton.setTitle("Delete \(self.dataSource.count) \(self.getUnits())", for: .normal)
}else {
deleteButton.setTitle("Delete \(self.dataSource.count) \(self.getUnits())", for: .normal)
}
}
}
// 获取单位复数
private func getUnits()->String{
if self.dataSource.count > 1 {
return self.trashType == .video ? "videos" : "photos"
}else {
return self.trashType == .video ? "video" : "photo"
}
}
} }
//
// TrashDefaultView.swift
// PhoneManager
//
// Created by edy on 2025/5/15.
//
import UIKit
class TrashDefaultView: UIView {
static let jumpToPhotosDetailPageName = Notification.Name("jumpToPhotosDetailPageName")
static let jumpToVideosDetailPageName = Notification.Name("jumpToVideosDetailPageName")
var mediaType : TrashTypeEnum?
lazy var logImageView : UIImageView = {
let imageView = UIImageView()
imageView.image = UIImage(named: "Frame 4")
return imageView
}()
lazy var tipLabel: UILabel = {
let label = UILabel()
label.text = "Your trash can is empty!!"
label.textAlignment = .center
label.textColor = UIColor(red: 0.07, green: 0.07, blue: 0.07, alpha: 1)
label.font = UIFont.systemFont(ofSize: 17, weight: .semibold)
label.backgroundColor = .clear
return label
}()
lazy var detailTiplabel: UILabel = {
let label = UILabel()
label.text = "Once you start sending the video photos to the trash can, they will be displayed here."
label.textColor = UIColor(red: 0.4, green: 0.4, blue: 0.4, alpha: 1)
label.textAlignment = .center
label.font = UIFont.systemFont(ofSize: 12, weight: .semibold)
label.backgroundColor = .clear
label.numberOfLines = 0
return label
}()
lazy var startButton : UIButton = {
let view = UIButton()
view.setTitle("Start cleaning", for: UIControl.State.normal)
view.setTitleColor(UIColor(red: 1, green: 1, blue: 1, alpha: 1), for: .normal)
view.titleLabel?.font = UIFont.systemFont(ofSize: 12, weight: .semibold)
view.clipsToBounds = true
view.layer.cornerRadius = 16.5
view.backgroundColor = UIColor(red: 0, green: 0.51, blue: 1, alpha: 1)
view.addTarget(self, action: #selector(startButtonAction), for: .touchUpInside)
return view
}()
override init(frame: CGRect) {
super.init(frame: frame)
self.addSubview(self.logImageView)
self.addSubview(self.tipLabel)
self.addSubview(self.detailTiplabel)
self.addSubview(self.startButton)
self.logImageView.snp.makeConstraints { make in
make.width.equalTo(230)
make.height.equalTo(154)
make.centerX.equalToSuperview()
make.top.equalToSuperview().offset(105)
}
self.tipLabel.snp.makeConstraints { make in
make.left.equalToSuperview().offset(15)
make.right.equalToSuperview().offset(-15)
make.top.equalTo(self.logImageView.snp.bottom).offset(30)
make.height.equalTo(22)
}
self.detailTiplabel.snp.makeConstraints { make in
make.left.equalToSuperview().offset(15)
make.right.equalToSuperview().offset(-15)
make.top.equalTo(self.tipLabel.snp.bottom).offset(5)
make.height.equalTo(44)
}
self.startButton.snp.makeConstraints { make in
make.width.equalTo(107)
make.height.equalTo(33)
make.top.equalTo(self.detailTiplabel.snp.bottom).offset(30)
make.centerX.equalToSuperview()
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc func startButtonAction(){
// 跳转页面
if let type = self.mediaType {
switch type {
case .video:
jumpToVideoDetailPage(type: type)
break
case .other,.shot:
jumpToPhotosDetailPage(type: type)
break
case .chat:
break
}
}
}
func jumpToPhotosDetailPage(type: TrashTypeEnum){
self.responderViewController()?.dismiss(animated: true, completion: {
NotificationCenter.default.post(name: TrashDefaultView.jumpToPhotosDetailPageName, object: nil,userInfo: ["type":self.mediaType?.rawValue ?? ""])
})
// PhotoDataManager.manager.loadFromFileSystem { model in
// let data = type == .other ? model.otherModelArray[4] : model.otherModelArray[2]
// let vc:HomePhotosDetailViewController = HomePhotosDetailViewController(model: data)
// vc.mediaType = type == .other ? .Other : PhotsFileType.screenshots
// vc.dealData()
// self.responderViewController()?.navigationController?.pushViewController(vc, animated: true)
// }
}
func jumpToVideoDetailPage(type: TrashTypeEnum){
self.responderViewController()?.dismiss(animated: true, completion: {
NotificationCenter.default.post(name: TrashDefaultView.jumpToVideosDetailPageName, object: nil)
})
}
}
...@@ -670,9 +670,9 @@ class PhotoAndVideoMananger { ...@@ -670,9 +670,9 @@ class PhotoAndVideoMananger {
if success { if success {
suc() suc()
} else if let error = error { } else if let error = error {
PMLoadingHUD.share.disMiss()
print("删除失败: \(error.localizedDescription)") print("删除失败: \(error.localizedDescription)")
} }
PMLoadingHUD.share.disMiss()
} }
} }
...@@ -1329,4 +1329,71 @@ extension PhotoAndVideoMananger{ ...@@ -1329,4 +1329,71 @@ extension PhotoAndVideoMananger{
return zip(hash1, hash2).filter { $0 != $1 }.count return zip(hash1, hash2).filter { $0 != $1 }.count
} }
/// 根据LocalIdentifier获取视频的URL
/// - Parameters:
/// - localIdentifier: 资源标识
/// - completion: 回调
func getVideoURLFromLocalIdentifier(localIdentifier: String, completion: @escaping (URL?, Error?) -> Void) {
// 通过 localIdentifier 获取 PHAsset
let fetchOptions = PHFetchOptions()
let assets = PHAsset.fetchAssets(withLocalIdentifiers: [localIdentifier], options: fetchOptions)
guard let asset = assets.firstObject, asset.mediaType == .video else {
DispatchQueue.main.async {
completion(nil, NSError(domain: "com.example.error", code: 1, userInfo: [NSLocalizedDescriptionKey: "未找到对应视频资源"]))
}
return
}
let options = PHVideoRequestOptions()
options.isNetworkAccessAllowed = true // 允许从网络下载
options.deliveryMode = .automatic // 要求高质量格式
PHImageManager.default().requestAVAsset(forVideo: asset, options: options) { (avAsset, audioMix, info) in
if let error = info?[PHImageErrorKey] as? Error {
DispatchQueue.main.async {
completion(nil, error)
}
return
}
if let urlAsset = avAsset as? AVURLAsset {
DispatchQueue.main.async {
completion(urlAsset.url, nil)
}
} else {
DispatchQueue.main.async {
completion(nil, NSError(domain: "CustomErrorDomain", code: -1, userInfo: [NSLocalizedDescriptionKey: "Failed to get video URL"]))
}
}
}
}
/// 获取视频第一帧图片显示
/// - Parameters:
/// - identifier: 图片唯一标识
/// - completed: 回调
func getPreImageFromVideo(identifier : String?,completed: @escaping (UIImage)->Void){
if identifier == nil{
completed(UIImage())
return
}
let options = PHImageRequestOptions()
options.version = .current
options.deliveryMode = .highQualityFormat
options.isNetworkAccessAllowed = true
options.isSynchronous = false
if let videoAsset = PhotoAndVideoMananger.mananger.getPHAsssetwithID(ids: [identifier!]){
PHImageManager.default().requestImage(for: videoAsset, targetSize: CGSize(width: 400, height: 400), contentMode: PHImageContentMode.aspectFit, options: options) { image, _ in
if let thumbnailImage = image {
completed(thumbnailImage)
} else {
completed(UIImage())
}
}
}else {
completed(UIImage())
}
}
} }
...@@ -63,7 +63,6 @@ class PMScaleImageView: UIView , UIScrollViewDelegate { ...@@ -63,7 +63,6 @@ class PMScaleImageView: UIView , UIScrollViewDelegate {
}() }()
func scrollViewDidZoom(_ scrollView: UIScrollView) { func scrollViewDidZoom(_ scrollView: UIScrollView) {
Print(scrollView.zoomScale)
if scrollView.zoomScale > 1.5 { if scrollView.zoomScale > 1.5 {
self.Radius = 16 self.Radius = 16
}else{ }else{
......
...@@ -12,6 +12,14 @@ var blurKey = "blurKey" ...@@ -12,6 +12,14 @@ var blurKey = "blurKey"
extension UIView { extension UIView {
func addTopShadow() {
layer.masksToBounds = false
layer.shadowColor = UIColor(red: 0, green: 0.51, blue: 1, alpha: 0.15).cgColor
layer.shadowOpacity = 1
layer.shadowOffset = CGSize(width: 0, height: -2) // 负值使阴影显示在顶部
layer.shadowRadius = 14
}
func responderViewController() -> UIViewController? { func responderViewController() -> UIViewController? {
for view in sequence(first: self.superview, next: { $0?.superview }) { for view in sequence(first: self.superview, next: { $0?.superview }) {
......
...@@ -19,6 +19,10 @@ class Singleton { ...@@ -19,6 +19,10 @@ class Singleton {
var maxDeleteCount : Int = 25 var maxDeleteCount : Int = 25
var trashData : [TrashTypeEnum : [AssetModel]] = [:]
var keepList : [TrashTypeEnum : [AssetModel]] = [:]
var photoPermission : PrivacyType? var photoPermission : PrivacyType?
......
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