Commit e667bf42 authored by CZ1004's avatar CZ1004

【新增】左滑垃圾桶功能

parent e3c81dec
//
// GroupDatabase.swift
// PhoneManager
//
// Created by edy on 2025/5/12.
//
import Foundation
import SQLite3
class GroupDatabase {
static let shared = GroupDatabase()
private var db: OpaquePointer?
private let dbPath: String
private init() {
let fileURL = try! FileManager.default
.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
.appendingPathComponent("maintaiGroup.sqlite")
dbPath = fileURL.path
if sqlite3_open(dbPath, &db) != SQLITE_OK {
print("无法打开数据库")
return
}
createTable()
}
private func createTable() {
let createTableString = """
CREATE TABLE IF NOT EXISTS groups(
localIdentifier TEXT PRIMARY KEY,
assetSize DOUBLE,
createDate DOUBLE,
mediaType INTEGER,
groupId TEXT
);
"""
var createTableStatement: OpaquePointer?
if sqlite3_prepare_v2(db, createTableString, -1, &createTableStatement, nil) == SQLITE_OK {
if sqlite3_step(createTableStatement) == SQLITE_DONE {
print("成功创建groups表")
} else {
print("创建表失败")
}
} else {
print("创建表语句准备失败")
}
sqlite3_finalize(createTableStatement)
}
// 插入数据(带去重检查)
func insert(localIdentifier: String, assetSize: Double, createDate: Date, mediaType: Int, groupId: String) -> Bool {
// 先检查是否已存在相同的 localIdentifier
if let _ = query(localIdentifier: localIdentifier) {
// 如果已存在,则执行更新操作
return update(localIdentifier: localIdentifier, assetSize: assetSize, createDate: createDate, mediaType: mediaType, groupId: groupId)
}
// 如果不存在,执行插入操作
let insertStatementString = "INSERT INTO groups (localIdentifier, assetSize, createDate, mediaType, groupId) VALUES (?, ?, ?, ?, ?);"
var insertStatement: OpaquePointer?
if sqlite3_prepare_v2(db, insertStatementString, -1, &insertStatement, nil) == SQLITE_OK {
sqlite3_bind_text(insertStatement, 1, (localIdentifier as NSString).utf8String, -1, nil)
sqlite3_bind_double(insertStatement, 2, assetSize)
sqlite3_bind_double(insertStatement, 3, createDate.timeIntervalSince1970)
sqlite3_bind_int(insertStatement, 4, Int32(mediaType))
sqlite3_bind_text(insertStatement, 5, (groupId as NSString).utf8String, -1, nil)
if sqlite3_step(insertStatement) == SQLITE_DONE {
print("成功插入数据")
sqlite3_finalize(insertStatement)
return true
} else {
print("插入数据失败")
}
}
sqlite3_finalize(insertStatement)
return false
}
// 删除数据
func delete(localIdentifier: String) -> Bool {
let deleteStatementString = "DELETE FROM groups WHERE localIdentifier = ?;"
var deleteStatement: OpaquePointer?
if sqlite3_prepare_v2(db, deleteStatementString, -1, &deleteStatement, nil) == SQLITE_OK {
sqlite3_bind_text(deleteStatement, 1, (localIdentifier as NSString).utf8String, -1, nil)
if sqlite3_step(deleteStatement) == SQLITE_DONE {
print("成功删除数据")
sqlite3_finalize(deleteStatement)
return true
} else {
print("删除数据失败")
}
}
sqlite3_finalize(deleteStatement)
return false
}
// 更新数据
func update(localIdentifier: String, assetSize: Double, createDate: Date, mediaType: Int, groupId: String) -> Bool {
let updateStatementString = "UPDATE groups SET assetSize = ?, createDate = ?, mediaType = ?, groupId = ? WHERE localIdentifier = ?;"
var updateStatement: OpaquePointer?
if sqlite3_prepare_v2(db, updateStatementString, -1, &updateStatement, nil) == SQLITE_OK {
sqlite3_bind_double(updateStatement, 1, assetSize)
sqlite3_bind_double(updateStatement, 2, createDate.timeIntervalSince1970)
sqlite3_bind_int(updateStatement, 3, Int32(mediaType))
sqlite3_bind_text(updateStatement, 4, (groupId as NSString).utf8String, -1, nil)
sqlite3_bind_text(updateStatement, 5, (localIdentifier as NSString).utf8String, -1, nil)
if sqlite3_step(updateStatement) == SQLITE_DONE {
print("成功更新数据")
sqlite3_finalize(updateStatement)
return true
} else {
print("更新数据失败")
}
}
sqlite3_finalize(updateStatement)
return false
}
// 查询所有数据
func queryAll() -> [(localIdentifier: String, assetSize: Double, createDate: Date, mediaType: Int, groupId: String)] {
let queryStatementString = "SELECT * FROM groups;"
var queryStatement: OpaquePointer?
var result: [(localIdentifier: String, assetSize: Double, createDate: Date, mediaType: Int, groupId: String)] = []
if sqlite3_prepare_v2(db, queryStatementString, -1, &queryStatement, nil) == SQLITE_OK {
while sqlite3_step(queryStatement) == SQLITE_ROW {
let localIdentifier = String(cString: sqlite3_column_text(queryStatement, 0))
let assetSize = sqlite3_column_double(queryStatement, 1)
let createDate = Date(timeIntervalSince1970: sqlite3_column_double(queryStatement, 2))
let mediaType = Int(sqlite3_column_int(queryStatement, 3))
let groupId = String(cString: sqlite3_column_text(queryStatement, 4))
result.append((localIdentifier, assetSize, createDate, mediaType, groupId))
}
}
sqlite3_finalize(queryStatement)
return result
}
// 根据localIdentifier查询单条数据
func query(localIdentifier: String) -> (localIdentifier: String, assetSize: Double, createDate: Date, mediaType: Int, groupId: String)? {
let queryStatementString = "SELECT * FROM groups WHERE localIdentifier = ?;"
var queryStatement: OpaquePointer?
if sqlite3_prepare_v2(db, queryStatementString, -1, &queryStatement, nil) == SQLITE_OK {
sqlite3_bind_text(queryStatement, 1, (localIdentifier as NSString).utf8String, -1, nil)
if sqlite3_step(queryStatement) == SQLITE_ROW {
let localIdentifier = String(cString: sqlite3_column_text(queryStatement, 0))
let assetSize = sqlite3_column_double(queryStatement, 1)
let createDate = Date(timeIntervalSince1970: sqlite3_column_double(queryStatement, 2))
let mediaType = Int(sqlite3_column_int(queryStatement, 3))
let groupId = String(cString: sqlite3_column_text(queryStatement, 4))
sqlite3_finalize(queryStatement)
return (localIdentifier, assetSize, createDate, mediaType, groupId)
}
}
sqlite3_finalize(queryStatement)
return nil
}
// 根据mediaType查询数据
func queryByMediaType(_ mediaType: Int) -> [(localIdentifier: String, assetSize: Double, createDate: Date, mediaType: Int, groupId: String)] {
let queryStatementString = "SELECT * FROM groups WHERE mediaType = ?;"
var queryStatement: OpaquePointer?
var result: [(localIdentifier: String, assetSize: Double, createDate: Date, mediaType: Int, groupId: String)] = []
if sqlite3_prepare_v2(db, queryStatementString, -1, &queryStatement, nil) == SQLITE_OK {
sqlite3_bind_int(queryStatement, 1, Int32(mediaType))
while sqlite3_step(queryStatement) == SQLITE_ROW {
let localIdentifier = String(cString: sqlite3_column_text(queryStatement, 0))
let assetSize = sqlite3_column_double(queryStatement, 1)
let createDate = Date(timeIntervalSince1970: sqlite3_column_double(queryStatement, 2))
let mediaType = Int(sqlite3_column_int(queryStatement, 3))
let groupId = String(cString: sqlite3_column_text(queryStatement, 4))
result.append((localIdentifier, assetSize, createDate, mediaType, groupId))
}
}
sqlite3_finalize(queryStatement)
return result
}
// 根据groupId查询数据
func queryByGroupId(_ groupId: String) -> [(localIdentifier: String, assetSize: Double, createDate: Date, mediaType: Int, groupId: String)] {
let queryStatementString = "SELECT * FROM groups WHERE groupId = ?;"
var queryStatement: OpaquePointer?
var result: [(localIdentifier: String, assetSize: Double, createDate: Date, mediaType: Int, groupId: String)] = []
if sqlite3_prepare_v2(db, queryStatementString, -1, &queryStatement, nil) == SQLITE_OK {
sqlite3_bind_text(queryStatement, 1, (groupId as NSString).utf8String, -1, nil)
while sqlite3_step(queryStatement) == SQLITE_ROW {
let localIdentifier = String(cString: sqlite3_column_text(queryStatement, 0))
let assetSize = sqlite3_column_double(queryStatement, 1)
let createDate = Date(timeIntervalSince1970: sqlite3_column_double(queryStatement, 2))
let mediaType = Int(sqlite3_column_int(queryStatement, 3))
let groupId = String(cString: sqlite3_column_text(queryStatement, 4))
result.append((localIdentifier, assetSize, createDate, mediaType, groupId))
}
}
sqlite3_finalize(queryStatement)
return result
}
// 批量删除数据
func batchDelete(localIdentifiers: [String]) -> Bool {
// 使用事务来确保原子性
let beginTransaction = "BEGIN TRANSACTION;"
let commitTransaction = "COMMIT TRANSACTION;"
let rollbackTransaction = "ROLLBACK TRANSACTION;"
// 准备删除语句
let deleteStatementString = "DELETE FROM groups 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 {
sqlite3_close(db)
}
}
......@@ -197,7 +197,65 @@ class TrashDatabase {
sqlite3_finalize(queryStatement)
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 {
sqlite3_close(db)
}
......
......@@ -26,7 +26,7 @@ class ChargeGuideController : BaseViewController,UIScrollViewDelegate,UINavigati
"Scroll the page and select Charger section",
"Select 'ls Connected' and 'Run lmmediately',then tap on Next",
"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
......
......@@ -227,10 +227,6 @@ class CompressSelectCell : UICollectionViewCell {
@objc func imageClick(){
if self.currentMediaType == .compressPhoto {
// 点击之后跳转详情页面
if let tempModel = self.model {
......
......@@ -13,6 +13,8 @@ class VideoViewController: UIViewController {
var url : URL?
var isAutoPlay : Bool = true
// 系统播放器控制器
let playerViewController = AVPlayerViewController()
......@@ -38,7 +40,9 @@ class VideoViewController: UIViewController {
playerViewController.didMove(toParent: self)
// 4. 自动播放
player.play()
if self.isAutoPlay {
player.play()
}
}
}
......
......@@ -253,40 +253,8 @@ extension HomeVideoDetailController:WaterfallMutiSectionDelegate,UICollectionVie
// 获取视频的图片
PhotoAndVideoMananger.mananger.getVideoImageByIdent(ident: ident) { image in
// 点击之后跳转详情页面
let vc = PMShowImgVideoController()
vc.state = .similarVideos
vc.currentIdx = 0
let dataSource = ImageSeletedCollectionItem()
dataSource.isSeleted = cell.choose
dataSource.id = ident
dataSource.image = image
// 表示这个是视频
vc.homeDataSource = [dataSource]
vc.backOrgPageCallBack = {[weak self]index,data in
guard let self else {return}
if let data = data{
if let item = data.first{
cell.choose = item.isSeleted ?? false
}
}
}
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)
}
}
}
let vc = PhotoRemoveViewController(data: self.resourceData,currentIndex: indexPath.row,mediaType: .video)
self.navigationController?.pushViewController(vc, animated: true)
} errorHandler: {
DispatchQueue.main.async {
let alert = UIAlertController(title: nil, message: "Get Video image failure", preferredStyle: .alert)
......
......@@ -7,6 +7,7 @@
import UIKit
import SnapKit
import Photos
class PhotoRemoveViewController: BaseViewController {
......@@ -63,7 +64,9 @@ class PhotoRemoveViewController: BaseViewController {
super.viewDidLoad()
formatter.dateStyle = .medium
formatter.timeStyle = .none
if let type = self.mediaType {
self.navView.mediaType = type
}
self.view.addSubview(self.navView)
self.navView.snp.makeConstraints { make in
make.top.left.right.equalToSuperview()
......@@ -78,14 +81,36 @@ class PhotoRemoveViewController: BaseViewController {
make.height.equalTo(78)
}
getData()
self.trashSubView.clearTashDataCallBack = {[weak self] in
guard let self else {return}
// 清除垃圾桶数据
TrashDataManager.clearTrashData(mediaType: self.mediaType) {[weak self] in
guard let self else {return}
self.showCurrentPageUIWhenTashDataChanged()
}
}
self.trashSubView.presentTashDetailViewClickCallBack = {
// 进入垃圾桶详情页面
DispatchQueue.main.async {
let vc : TrashViewController = TrashViewController()
self.present(vc, animated: true)
}
}
showCurrentPageUIWhenTashDataChanged()
}
func changeDateToString() -> String{
let model = self.dataModel[self.currentIndex]
return formatter.string(from: model.createDate)
}
func chengeSizeToString()-> String {
let model = self.dataModel[self.currentIndex]
return formatFileSize(model.assetSize)
}
func showTrashView(){
DispatchQueue.main.async {
self.trashSubView.isHidden = false
......@@ -106,7 +131,7 @@ class PhotoRemoveViewController: BaseViewController {
}
}
func getData(){
func showCurrentPageUIWhenTashDataChanged(){
if let type = self.mediaType{
// 从数据库拿数据
let dataDB = TrashDatabase.shared.queryByMediaType(type.dbType)
......@@ -115,24 +140,27 @@ class PhotoRemoveViewController: BaseViewController {
assetModel.append(AssetModel.init(localIdentifier: item.localIdentifier, assetSize: item.assetSize, createDate: item.createDate, mediaType: item.mediaType))
}
// 从单利拿数据
if let type = self.mediaType{
if let dataSg = Singleton.shared.trashData[type]{
assetModel = assetModel + dataSg
if assetModel.count > 0 {
// 显示垃圾桶
self.trashSubView.resourceCountlabel.text = String(assetModel.count)
self.showTrashView()
}else{
self.hideTrashView()
}
// 如果单利中有当前数据,显示撤回按钮
if dataSg.count > 0{
self.navView.resetButton.isHidden = false
}else{
DispatchQueue.main.async {
if let type = self.mediaType{
if let dataSg = Singleton.shared.trashData[type]{
assetModel = assetModel + dataSg
// 如果单利中有当前数据,显示撤回按钮
if dataSg.count > 0{
self.navView.resetButton.isHidden = false
}else{
self.navView.resetButton.isHidden = true
}
}else {
self.navView.resetButton.isHidden = true
}
}else {
self.navView.resetButton.isHidden = true
}
if assetModel.count > 0 {
// 显示垃圾桶
self.trashSubView.resourceCountlabel.text = String(assetModel.count)
self.showTrashView()
}else{
self.hideTrashView()
}
}
......@@ -144,6 +172,7 @@ class PhotoRemoveViewController: BaseViewController {
// 只创建两个视图
for _ in 0..<2 {
let photoView = PhotosRemoveBaseView()
photoView.mediaType = self.mediaType
photoView.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(handlePan)))
view.addSubview(photoView)
photoView.frame = CGRectMake(15, statusBarHeight + 44, self.view.width - 30, self.view.height - 78 - safeHeight - statusBarHeight - 44)
......@@ -167,7 +196,7 @@ class PhotoRemoveViewController: BaseViewController {
Singleton.shared.trashData[type] = [self.dataModel[currentIndex]]
}
}
self.getData()
self.showCurrentPageUIWhenTashDataChanged()
}
func saveDataToTrashDB(){
if let type = self.mediaType{
......@@ -181,7 +210,7 @@ class PhotoRemoveViewController: BaseViewController {
Singleton.shared.trashData[type] = []
}
}
getData()
showCurrentPageUIWhenTashDataChanged()
}
// 将数据存到保留列表
......@@ -189,9 +218,16 @@ class PhotoRemoveViewController: BaseViewController {
// 如果单利中有数据,那么先把单利中的数据存到数据库
saveDataToTrashDB()
//FIXME: 保留当前图片到保留列表
// 保留当前图片到保留列表
if let type = self.mediaType{
let item = self.dataModel[currentIndex]
let success = GroupDatabase.shared.insert(localIdentifier: item.localIdentifier, assetSize: item.assetSize, createDate: item.createDate, mediaType: type.dbType, groupId: UUID().uuidString)
if success {
Print("存入保留列表成功")
}else{
Print("存入保留列表失败")
}
}
}
......@@ -253,10 +289,21 @@ class PhotoRemoveViewController: BaseViewController {
private func updateViewContents() {
for (index, view) in photoViews.enumerated() {
let imageIndex = (currentIndex + index) % dataModel.count
view.configure(with: PhotoAndVideoMananger.mananger.getImageFromAssetID(id: dataModel[imageIndex].localIdentifier) ?? UIImage())
if self.mediaType == .video{
self.getVideoURLFromLocalIdentifier(localIdentifier: dataModel[imageIndex].localIdentifier) { url, error in
if url != nil {
view.url = url
view.reload(index: index)
}
}
}else {
view.configure(with: PhotoAndVideoMananger.mananger.getImageFromAssetID(id: dataModel[imageIndex].localIdentifier) ?? UIImage())
}
}
// 设置顶部title
self.navView.titleLbel.text = changeDateToString()
self.navView.sizeLbel.text = chengeSizeToString()
}
private func updateActionButton(for view: PhotosRemoveBaseView, translation: CGPoint) {
......@@ -289,7 +336,7 @@ class PhotoRemoveViewController: BaseViewController {
private func resetViewPosition(_ view: PhotosRemoveBaseView) {
UIView.animate(withDuration: 0.3) {
view.transform = .identity
view.center = self.view.center
view.frame = CGRectMake(15, statusBarHeight + 44, self.view.width - 30, self.view.height - 78 - safeHeight - statusBarHeight - 44)
view.hideButtons()
}
}
......@@ -324,4 +371,40 @@ class PhotoRemoveViewController: BaseViewController {
view.bringSubviewToFront(photoViews[1])
view.bringSubviewToFront(photoViews[0])
}
private 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"]))
}
}
}
}
}
......@@ -6,15 +6,32 @@
//
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?
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)
......@@ -41,6 +58,18 @@ class PhotoRemoveNavView: UIView {
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)
......@@ -48,7 +77,7 @@ class PhotoRemoveNavView: UIView {
titleLbel.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.top.equalToSuperview().offset(6 + statusBarHeight)
self.topConstraint = make.top.equalToSuperview().offset(6 + statusBarHeight).constraint
make.height.equalTo(22)
}
......
......@@ -14,45 +14,76 @@ class PhotosRemoveBaseView: UIView {
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()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupUI() {
// 配置图片视图
imageView.contentMode = .scaleAspectFill
imageView.layer.cornerRadius = 20
imageView.clipsToBounds = true
imageView.contentMode = .scaleAspectFit
addSubview(imageView)
// 配置按钮
let buttonSize: CGFloat = 300
leftButton.frame = CGRect(x: 0, y: 0, width: buttonSize, height: buttonSize)
leftButton.setImage(UIImage(named:"Frame 2"), for: .normal) // 替换你的图标
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: 0, y: 0, width: buttonSize, height: buttonSize)
rightButton.setImage(UIImage(named:"Group_1171275102"), for: .normal) // 替换你的图标
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)
leftButton.center = cWindow!.center
rightButton.center = cWindow!.center
}
func configure(with image: UIImage) {
......@@ -61,15 +92,21 @@ class PhotosRemoveBaseView: UIView {
}
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
}
}
......@@ -78,8 +115,9 @@ class PhotosRemoveBaseView: UIView {
UIView.animate(withDuration: 0.2) {
self.leftButton.alpha = 0
self.rightButton.alpha = 0
self.leftButton.center = cWindow!.center
self.rightButton.center = cWindow!.center
self.maskTempleteView.removeFromSuperview()
self.leftButton.center = self.center
self.rightButton.center = self.center
}
}
}
......@@ -9,6 +9,10 @@ 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)
......@@ -33,14 +37,27 @@ class TrashSubView: UIView {
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()
......@@ -59,7 +76,13 @@ class TrashSubView: UIView {
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) {
......@@ -67,3 +90,12 @@ class TrashSubView: UIView {
}
}
extension TrashSubView {
@objc func emptyButtonAction(){
self.clearTashDataCallBack()
}
@objc func tapHandle(){
self.presentTashDetailViewClickCallBack()
}
}
......@@ -22,6 +22,26 @@ class TrashViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
configUI()
getTrashDataAndRefreshPage()
}
/// 获取垃圾桶数据
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.dataSource = data
DispatchQueue.main.async {
tempView.collectionView.reloadData()
}
}
}
}
}
}
......
//
// TrashDataManager.swift
// PhoneManager
//
// Created by edy on 2025/5/14.
//
import UIKit
class TrashDataManager {
/// 清除当前垃圾桶的数据
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()
clearCurrentMediaTypeTrashDBData()
// 删除完成之后重新
comlete()
}
}else{
comlete()
}
func clearCurrentMediaTypeTrashSigtonData(){
if let type = mediaType {
Singleton.shared.trashData[type] = []
Print("删除单利中当前垃圾桶数据成功")
}
}
func clearCurrentMediaTypeTrashDBData(){
if let type = mediaType {
let dataDB = TrashDatabase.shared.queryByMediaType(type.dbType)
let success = TrashDatabase.shared.batchDelete(localIdentifiers: dataDB.map({$0.localIdentifier}))
if success {
Print("删除数据库当前垃圾桶数据成功")
}else {
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,7 +7,7 @@
import Foundation
enum TrashTypeEnum{
enum TrashTypeEnum : CaseIterable{
case video,other,shot,chat
var dbType:Int{
......
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