Commit 21848fa1 authored by shenyong's avatar shenyong

引入新相册资源管理类

parent a3d9d9ea
//
// ActorManager.swift
// CleanPhoto
//
// Created by edy on 2025/5/9.
//
import Foundation
import UIKit
// 图片状态管理 actor
actor PhotoSimilarStateManager {
private var timeGroups: [TimeGroupModel] = []
private var similarGroups: [SimilarGroupModel] = []
private var pendingSimilarGroups: [SimilarGroupModel] = []
private var processedGroupCount: Int = 0
private var assetsImageCache: [String: UIImage] = [:]
private var hashCache: [String: String] = [:]
func appendTimeGroup(_ group: TimeGroupModel) {
timeGroups.append(group)
}
func appendSimilarGroup(_ group: SimilarGroupModel) {
pendingSimilarGroups.append(group)
processedGroupCount += 1
}
func getAllTimeGroups() -> [TimeGroupModel] {
return timeGroups
}
func getpendingSimilarGroups() -> [SimilarGroupModel] {
return pendingSimilarGroups
}
func getAllSimilarGroups() -> [SimilarGroupModel] {
return similarGroups
}
func getCachedImage(for identifier: String) -> UIImage? {
return assetsImageCache[identifier]
}
func setCachedImage(_ image: UIImage, for identifier: String) {
assetsImageCache[identifier] = image
}
func shouldSavePendingGroups() -> Bool {
return processedGroupCount >= 10
}
func getCachedHash(for identifier: String) async -> String? {
return hashCache[identifier]
}
func setCachedHash(_ hash: String, for identifier: String) async {
hashCache[identifier] = hash
}
func savePendingGroups() {
similarGroups.append(contentsOf: pendingSimilarGroups)
pendingSimilarGroups.removeAll()
processedGroupCount = 0
}
func loadStoredData(timeGroups: [TimeGroupModel], similarGroups: [SimilarGroupModel]) {
self.timeGroups = timeGroups
self.similarGroups = similarGroups
}
}
// 截图状态管理 actor
actor ScreenshotSimilarStateManager {
private var timeGroups: [TimeGroupModel] = []
private var similarGroups: [SimilarGroupModel] = []
private var pendingSimilarGroups: [SimilarGroupModel] = []
private var processedGroupCount: Int = 0
private var assetsImageCache: [String: UIImage] = [:]
private var hashCache: [String: String] = [:]
func appendTimeGroup(_ group: TimeGroupModel) {
timeGroups.append(group)
}
func appendSimilarGroup(_ group: SimilarGroupModel) {
pendingSimilarGroups.append(group)
processedGroupCount += 1
}
func getAllTimeGroups() -> [TimeGroupModel] {
return timeGroups
}
func getpendingSimilarGroups() -> [SimilarGroupModel] {
return pendingSimilarGroups
}
func getAllSimilarGroups() -> [SimilarGroupModel] {
return similarGroups
}
func getCachedImage(for identifier: String) -> UIImage? {
return assetsImageCache[identifier]
}
func setCachedImage(_ image: UIImage, for identifier: String) {
assetsImageCache[identifier] = image
}
func shouldSavePendingGroups() -> Bool {
return processedGroupCount >= 10
}
func getCachedHash(for identifier: String) async -> String? {
return hashCache[identifier]
}
func setCachedHash(_ hash: String, for identifier: String) async {
hashCache[identifier] = hash
}
func savePendingGroups() {
similarGroups.append(contentsOf: pendingSimilarGroups)
pendingSimilarGroups.removeAll()
processedGroupCount = 0
}
func loadStoredData(timeGroups: [TimeGroupModel], similarGroups: [SimilarGroupModel]) {
self.timeGroups = timeGroups
self.similarGroups = similarGroups
}
}
// 视频状态管理 actor
actor VideoSimilarStateManager {
private var timeGroups: [TimeGroupModel] = []
private var similarGroups: [SimilarGroupModel] = []
private var pendingSimilarGroups: [SimilarGroupModel] = []
private var processedGroupCount: Int = 0
private var assetsImageCache: [String: UIImage] = [:]
private var hashCache: [String: String] = [:]
func appendTimeGroup(_ group: TimeGroupModel) {
timeGroups.append(group)
}
func appendSimilarGroup(_ group: SimilarGroupModel) {
pendingSimilarGroups.append(group)
processedGroupCount += 1
}
func getAllTimeGroups() -> [TimeGroupModel] {
return timeGroups
}
func getpendingSimilarGroups() -> [SimilarGroupModel] {
return pendingSimilarGroups
}
func getAllSimilarGroups() -> [SimilarGroupModel] {
return similarGroups
}
func getCachedImage(for identifier: String) -> UIImage? {
return assetsImageCache[identifier]
}
func setCachedImage(_ image: UIImage, for identifier: String) {
assetsImageCache[identifier] = image
}
func shouldSavePendingGroups() -> Bool {
return processedGroupCount >= 10
}
func getCachedHash(for identifier: String) async -> String? {
return hashCache[identifier]
}
func setCachedHash(_ hash: String, for identifier: String) async {
hashCache[identifier] = hash
}
func savePendingGroups() {
similarGroups.append(contentsOf: pendingSimilarGroups)
pendingSimilarGroups.removeAll()
processedGroupCount = 0
}
func loadStoredData(timeGroups: [TimeGroupModel], similarGroups: [SimilarGroupModel]) {
self.timeGroups = timeGroups
self.similarGroups = similarGroups
}
}
actor PhotoDuplicateStateManager {
private var duplicateGroups: [DuplicateGroupModel] = []
private var pendingDuplicateGroups: [DuplicateGroupModel] = []
// 缓存
private var imageCache: [String: UIImage] = [:]
private var hashCache: [String: String] = [:]
// MARK: - 公共方法
func loadStoredData(duplicateGroups: [DuplicateGroupModel]) {
self.duplicateGroups = duplicateGroups
}
func getAllDuplicateGroups() -> [DuplicateGroupModel] {
return duplicateGroups
}
func appendDuplicateGroup(_ group: DuplicateGroupModel) {
pendingDuplicateGroups.append(group)
}
func shouldSavePendingGroups() -> Bool {
return pendingDuplicateGroups.count >= 5
}
func savePendingGroups() {
duplicateGroups.append(contentsOf: pendingDuplicateGroups)
pendingDuplicateGroups.removeAll()
}
func getPendingDuplicateGroups() -> [DuplicateGroupModel] {
return pendingDuplicateGroups
}
// MARK: - 缓存相关
func getCachedImage(for identifier: String) -> UIImage? {
return imageCache[identifier]
}
func setCachedImage(_ image: UIImage, for identifier: String) {
imageCache[identifier] = image
}
func getCachedHash(for identifier: String) -> String? {
return hashCache[identifier]
}
func setCachedHash(_ hash: String, for identifier: String) {
hashCache[identifier] = hash
}
}
This diff is collapsed.
//
// AssetModel.swift
// CleanPhoto
//
// Created by edy on 2025/5/7.
//
import Foundation
struct AssetModel :Codable,Hashable {
var localIdentifier : String
var assetSize : Double
var createDate : Date
var mediaType:Int // 1 图片 2视频
init(localIdentifier: String, assetSize: Double, createDate: Date,mediaType:Int = 1) {
self.localIdentifier = localIdentifier
self.assetSize = assetSize
self.createDate = createDate
self.mediaType = mediaType
}
func hash(into hasher: inout Hasher) {
hasher.combine(localIdentifier)
hasher.combine(assetSize)
hasher.combine(createDate)
hasher.combine(mediaType)
}
static func ==(lhs: AssetModel, rhs: AssetModel) -> Bool {
return lhs.localIdentifier == rhs.localIdentifier &&
lhs.assetSize == rhs.assetSize &&
lhs.createDate == rhs.createDate && lhs.mediaType == rhs.mediaType
}
}
struct AssetFileModel:Codable{
var videoAssets:[AssetModel] = []
var otherAssets:[AssetModel] = []
var screenShotAssets:[AssetModel] = []
var photosAssets:[AssetModel] = []
}
// 添加媒体类型枚举
enum MediaType {
case video
case screenshot
case photo
case other
}
extension MediaType{
var dbValue:String{
switch self {
case .video:
return "video"
case .screenshot:
return "screenshot"
case .photo:
return "photo"
case .other:
return "other"
}
}
}
// 时间组模型
struct TimeGroupModel: Codable {
let groupId: String
let startTime: TimeInterval
let endTime: TimeInterval
var isProcessed: Bool
}
// 相似图片组模型
struct SimilarGroupModel: Codable {
let groupId: String
var assets: [AssetModel]
}
// 重复图片组模型
struct DuplicateGroupModel: Codable {
let groupId: String
let assets: [AssetModel]
}
......@@ -358,28 +358,28 @@ class HomePhotosModel:Codable {
}
class AssetModel :Codable,Hashable {
var localIdentifier : String
var assetSize : Double
var createDate : Date
init(localIdentifier: String, assetSize: Double, createDate: Date) {
self.localIdentifier = localIdentifier
self.assetSize = assetSize
self.createDate = createDate
}
func hash(into hasher: inout Hasher) {
hasher.combine(localIdentifier)
hasher.combine(assetSize)
hasher.combine(createDate)
}
static func ==(lhs: AssetModel, rhs: AssetModel) -> Bool {
return lhs.localIdentifier == rhs.localIdentifier &&
lhs.assetSize == rhs.assetSize &&
lhs.createDate == rhs.createDate
}
}
//class AssetModel :Codable,Hashable {
// var localIdentifier : String
// var assetSize : Double
// var createDate : Date
// init(localIdentifier: String, assetSize: Double, createDate: Date) {
// self.localIdentifier = localIdentifier
// self.assetSize = assetSize
// self.createDate = createDate
// }
//
// func hash(into hasher: inout Hasher) {
// hasher.combine(localIdentifier)
// hasher.combine(assetSize)
// hasher.combine(createDate)
// }
//
// static func ==(lhs: AssetModel, rhs: AssetModel) -> Bool {
// return lhs.localIdentifier == rhs.localIdentifier &&
// lhs.assetSize == rhs.assetSize &&
// lhs.createDate == rhs.createDate
// }
//}
......@@ -21,10 +21,10 @@ class TrashViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
configUI()
}
func configUI(){
view.backgroundColor = .white
contentScrollView = UIScrollView(frame: CGRect(x: 0, y: 0, width: ScreenW, height: contentH))
......@@ -79,7 +79,6 @@ class TrashViewController: UIViewController {
otherView.frame = CGRect(x: viewWidth, y: 0, width: viewWidth, height: contentH)
shotView.frame = CGRect(x: viewWidth*2, y: 0, width: viewWidth, height: contentH)
chatView.frame = CGRect(x: viewWidth*3, y: 0, width: viewWidth, height: contentH)
}
lazy var videoView:TrashContenView = {
......@@ -107,44 +106,46 @@ class TrashViewController: UIViewController {
}()
lazy var collectionView:UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width: view.width, height: view.height)
layout.scrollDirection = .horizontal
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
let collectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: view.width, height: view.height), collectionViewLayout:layout)
collectionView.isPagingEnabled = true
collectionView.delegate = self
collectionView.backgroundColor = .white
collectionView.dataSource = self
collectionView.register(UINib(nibName: "TrashContenViewCell", bundle: nil), forCellWithReuseIdentifier: "TrashContenViewCell0")
collectionView.register(UINib(nibName: "TrashContenViewCell", bundle: nil), forCellWithReuseIdentifier: "TrashContenViewCell1")
collectionView.register(UINib(nibName: "TrashContenViewCell", bundle: nil), forCellWithReuseIdentifier: "TrashContenViewCell2")
collectionView.register(UINib(nibName: "TrashContenViewCell", bundle: nil), forCellWithReuseIdentifier: "TrashContenViewCell3")
return collectionView
}()
//
// lazy var collectionView:UICollectionView = {
// let layout = UICollectionViewFlowLayout()
// layout.itemSize = CGSize(width: view.width, height: view.height)
// layout.scrollDirection = .horizontal
// layout.minimumInteritemSpacing = 0
// layout.minimumLineSpacing = 0
// let collectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: view.width, height: view.height), collectionViewLayout:layout)
// collectionView.isPagingEnabled = true
// collectionView.delegate = self
// collectionView.backgroundColor = .white
// collectionView.dataSource = self
// collectionView.register(UINib(nibName: "TrashContenViewCell", bundle: nil), forCellWithReuseIdentifier: "TrashContenViewCell0")
// collectionView.register(UINib(nibName: "TrashContenViewCell", bundle: nil), forCellWithReuseIdentifier: "TrashContenViewCell1")
// collectionView.register(UINib(nibName: "TrashContenViewCell", bundle: nil), forCellWithReuseIdentifier: "TrashContenViewCell2")
// collectionView.register(UINib(nibName: "TrashContenViewCell", bundle: nil), forCellWithReuseIdentifier: "TrashContenViewCell3")
//
// return collectionView
// }()
}
extension TrashViewController:UICollectionViewDelegate,UICollectionViewDataSource{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return source.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TrashContenViewCell\(indexPath.row)", for: indexPath) as! TrashContenViewCell
cell.trashType = source[indexPath.row]
return cell
}
}
//extension TrashViewController:UICollectionViewDelegate,UICollectionViewDataSource{
//
// func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// return source.count
// }
//
// func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TrashContenViewCell\(indexPath.row)", for: indexPath) as! TrashContenViewCell
// cell.trashType = source[indexPath.row]
// return cell
// }
//
//}
extension TrashViewController:UIScrollViewDelegate{
......@@ -170,7 +171,4 @@ extension TrashViewController:UIScrollViewDelegate{
self.currentPage = currentPage + 1
}
}
......@@ -21,8 +21,21 @@ class TrashContenAssetCell: UICollectionViewCell {
assetImage.cornerCut(radius: 8, corner: .allCorners)
}
var model:AssetModel?{
didSet{
guard let model = model else{
return
}
}
// assetImage.im
}
@IBAction func removeClick(_ sender: Any) {
}
}
......@@ -22,6 +22,8 @@ class TrashContenView: UIView {
var scrollLine:UIView!
let lineW:CGFloat = (ScreenW - 62) / 4.0
var dataSource:[AssetModel] = []
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .white
......@@ -32,6 +34,17 @@ class TrashContenView: UIView {
fatalError("init(coder:) has not been implemented")
}
func getData(){
// dataSource = TrashDatabase.shared.queryByMediaType(trashType.dbType).compactMap({ (localIdentifier: String, assetSize: Double, createDate: Date, mediaType: Int) in
// return AssetModel.init(localIdentifier: localIdentifier, assetSize: assetSize, createDate: createDate)
// })
collectionView.reloadData()
}
func configUI(){
let layout = UICollectionViewFlowLayout()
layout.minimumInteritemSpacing = 12
......@@ -223,7 +236,7 @@ class TrashContenView: UIView {
case .chat:
scrollLine.frame = lineFour.frame
}
collectionView.reloadData()
getData()
}
}
}
......@@ -236,24 +249,11 @@ extension TrashContenView:UICollectionViewDelegate,UICollectionViewDataSource,UI
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 20 //section == 0 ? 1 : 20
return dataSource.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// if indexPath.section == 0{
// let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TrashContenTitleCell", for: indexPath) as! TrashContenTitleCell
// cell.trashType = trashType
// return cell
// }
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TrashContenAssetCell", for: indexPath) as! TrashContenAssetCell
return cell
}
// func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize{
// return indexPath.section == 0 ? CGSize(width: ScreenW, height: 92) : CGSize(width: (ScreenW-56)/3, height: (ScreenW-56)/3)
// }
//
// func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets{
// return section == 0 ? UIEdgeInsets() : UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16)
// }
}
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