Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Sign in / Register
Toggle navigation
P
PhoneManager
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Yang
PhoneManager
Commits
63c05ef8
Commit
63c05ef8
authored
May 15, 2025
by
shenyong
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
首页数据构造修改
parent
a7703dda
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
807 additions
and
285 deletions
+807
-285
AppDelegate.swift
PhoneManager/AppDelegate.swift
+1
-0
TrashDatabase.swift
PhoneManager/Class/Database/TrashDatabase.swift
+11
-0
AssetSizeCache.swift
...Manager/Class/Manager/PMPhotoManager/AssetSizeCache.swift
+73
-0
PHImageLoad.swift
PhoneManager/Class/Manager/PMPhotoManager/PHImageLoad.swift
+0
-0
PhotoCleanTool.swift
...Manager/Class/Manager/PMPhotoManager/PhotoCleanTool.swift
+35
-0
PhotoDuplicateManager.swift
.../Class/Manager/PMPhotoManager/PhotoDuplicateManager.swift
+249
-40
PhotoManager.swift
PhoneManager/Class/Manager/PMPhotoManager/PhotoManager.swift
+46
-6
PhotoSimilarManager.swift
...er/Class/Manager/PMPhotoManager/PhotoSimilarManager.swift
+1
-2
ScreenShotSimilarManager.swift
...ass/Manager/PMPhotoManager/ScreenShotSimilarManager.swift
+1
-1
VideoSimilarManager.swift
...er/Class/Manager/PMPhotoManager/VideoSimilarManager.swift
+1
-1
HomeCollectionViewHeader.swift
...nager/Class/Page/Home/View/HomeCollectionViewHeader.swift
+4
-1
HomeView.swift
PhoneManager/Class/Page/Home/View/HomeView.swift
+61
-50
HomeOtherCollectionCell.swift
...r/Class/Page/Home/View/cell/HomeOtherCollectionCell.swift
+8
-0
HomeTitleCollectionCell.swift
...r/Class/Page/Home/View/cell/HomeTitleCollectionCell.swift
+17
-9
ImageCollectionCell.swift
...nager/Class/Page/Home/View/cell/ImageCollectionCell.swift
+0
-2
HomeViewModel.swift
PhoneManager/Class/Page/Home/ViewModel/HomeViewModel.swift
+299
-173
No files found.
PhoneManager/AppDelegate.swift
View file @
63c05ef8
...
@@ -45,6 +45,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
...
@@ -45,6 +45,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
AdvManager
.
shared
.
initAdertisementSDK
()
AdvManager
.
shared
.
initAdertisementSDK
()
PMEmailManager
.
shareManager
.
restore
()
PMEmailManager
.
shareManager
.
restore
()
// 相册基本资源加载
PhotoManager
.
shared
.
config
()
PhotoManager
.
shared
.
config
()
return
true
return
true
...
...
PhoneManager/Class/Database/TrashDatabase.swift
View file @
63c05ef8
...
@@ -260,3 +260,14 @@ class TrashDatabase {
...
@@ -260,3 +260,14 @@ class TrashDatabase {
sqlite3_close
(
db
)
sqlite3_close
(
db
)
}
}
}
}
extension
TrashDatabase
{
func
dealHomeData
(
type
:
Int
){
}
}
PhoneManager/Class/Manager/PMPhotoManager/AssetSizeCache.swift
0 → 100644
View file @
63c05ef8
import
Foundation
import
Photos
actor
AssetSizeCache
{
static
let
shared
=
AssetSizeCache
()
private
let
cache
:
NSCache
<
NSString
,
NSNumber
>
=
NSCache
<
NSString
,
NSNumber
>
()
private
let
fileQueue
=
DispatchQueue
(
label
:
"com.assetsize.fileoperations"
,
qos
:
.
utility
)
// 临时存储,用于跟踪修改
private
var
tempStorage
:
[
String
:
Int64
]
=
[:]
private
var
hasChanges
:
Bool
=
false
private
let
cachePath
:
String
=
{
let
paths
=
FileManager
.
default
.
urls
(
for
:
.
documentDirectory
,
in
:
.
userDomainMask
)
return
paths
[
0
]
.
appendingPathComponent
(
"AssetSizeCache.plist"
)
.
path
}()
private
init
()
{
Task
{
await
loadCache
()
}
}
private
func
loadCache
()
{
fileQueue
.
sync
{
if
let
dict
=
NSDictionary
(
contentsOfFile
:
cachePath
)
as?
[
String
:
Int64
]
{
for
(
key
,
value
)
in
dict
{
cache
.
setObject
(
NSNumber
(
value
:
value
),
forKey
:
key
as
NSString
)
tempStorage
[
key
]
=
value
}
}
}
}
func
getSize
(
for
asset
:
PHAsset
)
->
Int64
?
{
// 优先从内存缓存中读取
if
let
size
=
tempStorage
[
asset
.
localIdentifier
]
{
return
size
}
return
cache
.
object
(
forKey
:
asset
.
localIdentifier
as
NSString
)?
.
int64Value
}
func
setSize
(
_
size
:
Int64
,
for
asset
:
PHAsset
)
{
cache
.
setObject
(
NSNumber
(
value
:
size
),
forKey
:
asset
.
localIdentifier
as
NSString
)
tempStorage
[
asset
.
localIdentifier
]
=
size
hasChanges
=
true
}
// 手动触发保存到文件
func
saveToFile
()
{
guard
hasChanges
else
{
return
}
let
path
=
self
.
cachePath
let
storageToSave
=
self
.
tempStorage
fileQueue
.
async
{
(
storageToSave
as
NSDictionary
)
.
write
(
toFile
:
path
,
atomically
:
true
)
}
hasChanges
=
false
}
func
clearCache
()
{
cache
.
removeAllObjects
()
tempStorage
.
removeAll
()
hasChanges
=
true
let
path
=
self
.
cachePath
fileQueue
.
async
{
try
?
FileManager
.
default
.
removeItem
(
atPath
:
path
)
}
}
}
PhoneManager/Class/Manager/PMPhotoManager/
SY
PHImageLoad.swift
→
PhoneManager/Class/Manager/PMPhotoManager/PHImageLoad.swift
View file @
63c05ef8
File moved
PhoneManager/Class/Manager/PMPhotoManager/PhotoCleanTool.swift
0 → 100644
View file @
63c05ef8
//
// PhotoCleanTool.swift
// PhoneManager
//
// Created by edy on 2025/5/15.
//
import
Foundation
struct
PhotoCleanTool
{
// app内手动删除资源
func
deleteLocalResouces
(
for
ids
:[
String
]){
let
other
=
PhotoManager
.
shared
.
otherModels
.
filter
{
ids
.
contains
(
$0
.
localIdentifier
)}
let
screen
=
PhotoManager
.
shared
.
screenShotModels
.
filter
{
ids
.
contains
(
$0
.
localIdentifier
)}
let
video
=
PhotoManager
.
shared
.
videoModels
.
filter
{
ids
.
contains
(
$0
.
localIdentifier
)}
PhotoManager
.
shared
.
otherModels
=
other
PhotoManager
.
shared
.
screenShotModels
=
screen
PhotoManager
.
shared
.
videoModels
=
video
}
// 删除无效资源
func
cleanIneffectiveResources
(){
}
}
PhoneManager/Class/Manager/PMPhotoManager/PhotoDuplicateManager.swift
View file @
63c05ef8
...
@@ -9,9 +9,9 @@ import Foundation
...
@@ -9,9 +9,9 @@ import Foundation
import
Photos
import
Photos
import
UIKit
import
UIKit
@MainActor
// 移除顶层的 @MainActor
class
PhotoDuplicateManager
:
@unchecked
Sendable
{
class
PhotoDuplicateManager
:
@unchecked
Sendable
{
static
let
shared
=
PhotoDuplicateManager
()
static
let
shared
=
PhotoDuplicateManager
()
private
let
stateManager
=
PhotoDuplicateStateManager
()
// 使用新的状态管理器
private
let
stateManager
=
PhotoDuplicateStateManager
()
// 使用新的状态管理器
private
init
()
{}
private
init
()
{}
...
@@ -39,9 +39,11 @@ class PhotoDuplicateManager: @unchecked Sendable {
...
@@ -39,9 +39,11 @@ class PhotoDuplicateManager: @unchecked Sendable {
mediaType
:
MediaType
=
.
photo
,
mediaType
:
MediaType
=
.
photo
,
loacalHandler
:
(([[
AssetModel
]])
->
Void
)?,
loacalHandler
:
(([[
AssetModel
]])
->
Void
)?,
progressHandler
:
(([
AssetModel
])
->
Void
)?,
progressHandler
:
(([
AssetModel
])
->
Void
)?,
completionHandler
:
(([[
AssetModel
]])
->
Void
)?)
{
completionHandler
:
(([[
AssetModel
]])
->
Void
)?)
{
Task
{
Task
.
detached
(
priority
:
.
background
)
{
[
weak
self
]
in
guard
let
self
=
self
else
{
return
}
// 1. 加载本地数据
// 1. 加载本地数据
await
loadStoredData
()
await
loadStoredData
()
print
(
"本地数据加载完成"
)
print
(
"本地数据加载完成"
)
...
@@ -50,9 +52,6 @@ class PhotoDuplicateManager: @unchecked Sendable {
...
@@ -50,9 +52,6 @@ class PhotoDuplicateManager: @unchecked Sendable {
let
cachedGroups
=
await
stateManager
.
getAllDuplicateGroups
()
let
cachedGroups
=
await
stateManager
.
getAllDuplicateGroups
()
print
(
"通知已缓存的结果"
,
cachedGroups
.
count
)
print
(
"通知已缓存的结果"
,
cachedGroups
.
count
)
await
MainActor
.
run
{
await
MainActor
.
run
{
// for group in cachedGroups {
// progressHandler?(group.assets)
// }
let
groups
=
cachedGroups
.
map
{
$0
.
assets
}
let
groups
=
cachedGroups
.
map
{
$0
.
assets
}
loacalHandler
?(
groups
)
loacalHandler
?(
groups
)
}
}
...
@@ -65,8 +64,8 @@ class PhotoDuplicateManager: @unchecked Sendable {
...
@@ -65,8 +64,8 @@ class PhotoDuplicateManager: @unchecked Sendable {
for
asset
in
assets
{
for
asset
in
assets
{
// 创建特征键(分辨率+创建时间+文件大小)
// 创建特征键(分辨率+创建时间+文件大小)
let
resolution
=
"
\(
asset
.
pixelWidth
)
x
\(
asset
.
pixelHeight
)
"
let
resolution
=
"
\(
asset
.
pixelWidth
)
x
\(
asset
.
pixelHeight
)
"
// let createTime = asset.creationDate?.timeIntervalSince1970 ?? 0
// let createTime = asset.creationDate?.timeIntervalSince1970 ?? 0
let
fileSize
=
getAssetSize
(
asset
)
let
fileSize
=
await
getAssetSize
(
asset
:
asset
)
let
featureKey
=
"
\(
resolution
)
_
\(
fileSize
)
"
let
featureKey
=
"
\(
resolution
)
_
\(
fileSize
)
"
if
tempGroups
[
featureKey
]
==
nil
{
if
tempGroups
[
featureKey
]
==
nil
{
...
@@ -149,45 +148,212 @@ class PhotoDuplicateManager: @unchecked Sendable {
...
@@ -149,45 +148,212 @@ class PhotoDuplicateManager: @unchecked Sendable {
completionHandler
?(
allGroups
.
map
{
$0
.
assets
})
completionHandler
?(
allGroups
.
map
{
$0
.
assets
})
}
}
}
}
}
// MARK: - 辅助方法
}
nonisolated
private
func
areAssetsExactlyDuplicate
(
_
assets
:
[
PHAsset
])
->
Bool
{
// func findDuplicateAssets(
guard
let
firstAsset
=
assets
.
first
else
{
return
false
}
// in assets: [PHAsset],
// mediaType: MediaType = .photo,
return
assets
.
allSatisfy
{
asset
in
// loacalHandler: @Sendable @escaping ([[AssetModel]]) -> Void,
// 检查分辨率完全相同
// progressHandler: @Sendable @escaping ([AssetModel]) -> Void,
if
asset
.
pixelWidth
!=
firstAsset
.
pixelWidth
||
// completionHandler: @Sendable @escaping ([[AssetModel]]) -> Void
asset
.
pixelHeight
!=
firstAsset
.
pixelHeight
{
// ) {
return
false
// // 使用后台优先级
}
// Task.detached(priority: .background) { [weak self] in
// guard let self = self else { return }
// 检查文件大小完全相同
//
let
firstSize
=
getAssetSize
(
firstAsset
)
// do {
let
currentSize
=
getAssetSize
(
asset
)
// // 批量处理,减少主线程切换
if
firstSize
!=
currentSize
{
// let batchSize = 100
return
false
// var accumulatedProgress: [AssetModel] = []
}
//
// for i in stride(from: 0, to: assets.count, by: batchSize) {
// 检查创建时间是否接近(避免连拍照片)
// let end = min(i + batchSize, assets.count)
// if let time1 = asset.creationDate,
// let batchAssets = Array(assets[i..<end])
// let time2 = firstAsset.creationDate {
//
// let timeDiff = abs(time1.timeIntervalSince(time2))
// // 处理一批资源
// if timeDiff < 1.0 { // 1秒内的连拍照片不算重复
// let results = try await self.processBatch(batchAssets)
// return false
// accumulatedProgress.append(contentsOf: results)
//
// // 每处理一定数量后才更新UI
// if accumulatedProgress.count >= 50 {
// await MainActor.run {
// progressHandler(accumulatedProgress)
// }
// accumulatedProgress.removeAll()
// }
//
// // 给主线程喘息的机会
// try await Task.sleep(nanoseconds: 1_000_000) // 1ms
// }
//
// // 1. 加载本地数据
// await self.loadStoredData()
// print("本地数据加载完成")
//
// // 2. 通知已缓存的结果
// let cachedGroups = await self.stateManager.getAllDuplicateGroups()
// print("通知已缓存的结果", cachedGroups.count)
//
// await MainActor.run {
// let groups = cachedGroups.map { $0.assets }
// loacalHandler(groups)
// }
//
// // 3. 按特征预分组(分辨率、时间、文件大小)
// let featureGroups = try await self.groupAssetsByFeatures(assets)
//
// // 如果没有需要处理的组,直接返回缓存结果
// if featureGroups.isEmpty {
// let total = cachedGroups.map { $0.assets }
// await MainActor.run {
// completionHandler(total)
// }
// return
// }
//
// // 4. 并发处理每组资源
// try await self.processFeatureGroups(featureGroups, progressHandler: progressHandler)
//
// // 5. 完成处理
// if await !self.stateManager.getPendingDuplicateGroups().isEmpty {
// await self.savePendingDuplicateGroups()
// }
//
// let allGroups = await self.stateManager.getAllDuplicateGroups()
// await MainActor.run {
// print("执行完毕")
// completionHandler(allGroups.map { $0.assets })
// }
// } catch {
// print("查找重复资源失败: \(error)")
// await MainActor.run {
// completionHandler([]) // 返回空数组或错误处理
// }
// }
// }
// }
// }
return
true
// }
}
}
// 按特征分组(分辨率、文件大小等)
// private func groupAssetsByFeatures(_ assets: [PHAsset]) async throws -> [[PHAsset]] {
// var tempGroups: [String: [PHAsset]] = [:]
//
// // 使用串行队列确保线程安全
// let queue = DispatchQueue(label: "com.example.assetGrouping")
//
// // 并发处理所有资源
// await withThrowingTaskGroup(of: Void.self) { group in
// for asset in assets {
// group.addTask {
// // 创建特征键(分辨率+文件大小)
// let resolution = "\(asset.pixelWidth)x\(asset.pixelHeight)"
// let fileSize = await self.getAssetSize(asset: asset)
// let featureKey = "\(resolution)_\(fileSize)"
//
// // 使用同步队列更新共享字典
// queue.sync {
// if tempGroups[featureKey] == nil {
// tempGroups[featureKey] = []
// }
// tempGroups[featureKey]?.append(asset)
// }
// }
// }
// }
//
// // 只保留有多个资源的组
// return tempGroups.values.filter { $0.count > 1 }
// }
// 处理特征分组并查找重复项
// private func processFeatureGroups(
// _ featureGroups: [[PHAsset]],
// progressHandler: (([AssetModel]) -> Void)?
// ) async throws {
// let maxConcurrency = 2 // 最大并发数
// let batchSize = max(1, featureGroups.count / maxConcurrency)
//
// for batchIndex in stride(from: 0, to: featureGroups.count, by: batchSize) {
// let endIndex = min(batchIndex + batchSize, featureGroups.count)
// let batch = Array(featureGroups[batchIndex..<endIndex])
//
// await withThrowingTaskGroup(of: Void.self) { group in
// for assets in batch {
// group.addTask { [weak self] in
// guard let self = self else { return }
//
// // 只需要计算phash值并比较
// var hashGroups: [String: [PHAsset]] = [:]
//
// // 处理单个组内的资源,控制并发
// await withThrowingTaskGroup(of: Void.self) { innerGroup in
// for asset in assets {
// innerGroup.addTask {
// if let hash = await self.getOrCalculateHash(for: asset) {
// // 使用同步队列更新共享字典
// DispatchQueue.global().sync {
// if hashGroups[hash] == nil {
// hashGroups[hash] = []
// }
// hashGroups[hash]?.append(asset)
// }
// }
// }
// }
// }
//
// // 找出phash值相同的组
// let duplicateGroups = hashGroups.values.filter { $0.count > 1 }
//
// // 处理找到的重复组
// for duplicateGroup in duplicateGroups {
// let groupId = UUID().uuidString
// let assetModels = await self.createAssetModels(from: duplicateGroup)
//
// // 通知进度
// await MainActor.run {
// progressHandler?(assetModels)
// }
//
// // 保存重复组
// await self.stateManager.appendDuplicateGroup(
// DuplicateGroupModel(groupId: groupId, assets: assetModels)
// )
//
// if await self.stateManager.shouldSavePendingGroups() {
// await self.savePendingDuplicateGroups()
// }
// }
// }
// }
// }
// }
// }
// MARK: - 辅助方法
nonisolated
private
func
getAssetSize
(
_
asset
:
PHAsset
)
->
Int64
{
// nonisolated private func getAssetSize(_ asset: PHAsset) -> Int64 {
// if let resource = PHAssetResource.assetResources(for: asset).first,
// let size = resource.value(forKey: "fileSize") as? Int64 {
// return size
// }
// return 0
// }
func
getAssetSize
(
asset
:
PHAsset
)
async
->
Int64
{
// 先尝试从缓存获取
if
let
cachedSize
=
await
AssetSizeCache
.
shared
.
getSize
(
for
:
asset
)
{
return
cachedSize
}
// 如果缓存中没有,则计算大小
if
let
resource
=
PHAssetResource
.
assetResources
(
for
:
asset
)
.
first
,
if
let
resource
=
PHAssetResource
.
assetResources
(
for
:
asset
)
.
first
,
let
size
=
resource
.
value
(
forKey
:
"fileSize"
)
as?
Int64
{
let
size
=
resource
.
value
(
forKey
:
"fileSize"
)
as?
Int64
{
// 将计算结果存入缓存
await
AssetSizeCache
.
shared
.
setSize
(
size
,
for
:
asset
)
return
size
return
size
}
}
return
0
return
0
}
}
...
@@ -197,7 +363,7 @@ class PhotoDuplicateManager: @unchecked Sendable {
...
@@ -197,7 +363,7 @@ class PhotoDuplicateManager: @unchecked Sendable {
for
asset
in
assets
{
for
asset
in
assets
{
modelGroup
.
addTask
{
modelGroup
.
addTask
{
let
size
=
self
.
getAssetSize
(
asset
)
let
size
=
await
self
.
getAssetSize
(
asset
:
asset
)
return
AssetModel
(
return
AssetModel
(
localIdentifier
:
asset
.
localIdentifier
,
localIdentifier
:
asset
.
localIdentifier
,
assetSize
:
Double
(
size
),
assetSize
:
Double
(
size
),
...
@@ -304,4 +470,47 @@ extension PhotoDuplicateManager {
...
@@ -304,4 +470,47 @@ extension PhotoDuplicateManager {
let
average
=
UInt8
(
pixels
.
reduce
(
0
,
{
UInt32
(
$0
)
+
UInt32
(
$1
)
})
/
UInt32
(
pixels
.
count
))
let
average
=
UInt8
(
pixels
.
reduce
(
0
,
{
UInt32
(
$0
)
+
UInt32
(
$1
)
})
/
UInt32
(
pixels
.
count
))
return
pixels
.
map
{
$0
>
average
?
"1"
:
"0"
}
.
joined
()
return
pixels
.
map
{
$0
>
average
?
"1"
:
"0"
}
.
joined
()
}
}
// private func processBatch(_ assets: [PHAsset]) async throws -> [AssetModel] {
// var results: [AssetModel] = []
//
// // 按特征预分组
// let featureGroups = try await self.groupAssetsByFeatures(assets)
//
// // 处理每个特征组
// for assets in featureGroups {
// // 计算hash并分组
// var hashGroups: [String: [PHAsset]] = [:]
//
// for asset in assets {
// if let hash = await self.getOrCalculateHash(for: asset) {
// if hashGroups[hash] == nil {
// hashGroups[hash] = []
// }
// hashGroups[hash]?.append(asset)
// }
// }
//
// // 找出hash值相同的组
// let duplicateGroups = hashGroups.values.filter { $0.count > 1 }
//
// // 处理找到的重复组
// for duplicateGroup in duplicateGroups {
// let assetModels = await self.createAssetModels(from: duplicateGroup)
// results.append(contentsOf: assetModels)
//
// // 保存到状态管理器
// let groupId = UUID().uuidString
// await self.stateManager.appendDuplicateGroup(
// DuplicateGroupModel(groupId: groupId, assets: assetModels)
// )
// }
// }
//
// return results
//
// }
}
}
PhoneManager/Class/Manager/PMPhotoManager/PhotoManager.swift
View file @
63c05ef8
...
@@ -88,6 +88,15 @@ class PhotoManager{
...
@@ -88,6 +88,15 @@ class PhotoManager{
// 重复图片分组
// 重复图片分组
var
duplicateModels
:[[
AssetModel
]]
=
[]
var
duplicateModels
:[[
AssetModel
]]
=
[]
// 过滤垃圾桶/保留相似图片分组
var
filterSimilarModels
:[[
AssetModel
]]
=
[]
// 过滤垃圾桶/保留相似截图分组
var
filterSimilarScreenShotModels
:[[
AssetModel
]]
=
[]
// 过滤垃圾桶/保留相似视频分组
var
filterSimilarVideoModels
:[[
AssetModel
]]
=
[]
// // 过滤垃圾桶/保留重复图片分组
// var filterDuplicateModels:[[AssetModel]] = []
// 截图
// 截图
var
screenShotModels
:[
AssetModel
]
=
[]
var
screenShotModels
:[
AssetModel
]
=
[]
// 视频
// 视频
...
@@ -95,6 +104,14 @@ class PhotoManager{
...
@@ -95,6 +104,14 @@ class PhotoManager{
// 其他
// 其他
var
otherModels
:[
AssetModel
]
=
[]
var
otherModels
:[
AssetModel
]
=
[]
// 过滤垃圾桶/保留截图
var
filterScreenShotModels
:[
AssetModel
]
=
[]
// 过滤垃圾桶/保留视频
var
filterVideoModels
:[
AssetModel
]
=
[]
// 过滤垃圾桶/保留其他
var
filterOtherModels
:[
AssetModel
]
=
[]
private(set)
var
screenShotTotalSize
:
Int64
=
0
private(set)
var
screenShotTotalSize
:
Int64
=
0
private(set)
var
videoTotalSize
:
Int64
=
0
private(set)
var
videoTotalSize
:
Int64
=
0
private(set)
var
otherTotalSize
:
Int64
=
0
private(set)
var
otherTotalSize
:
Int64
=
0
...
@@ -331,13 +348,30 @@ extension PhotoManager{
...
@@ -331,13 +348,30 @@ extension PhotoManager{
// 获取文件大小
// 获取文件大小
func
getAssetSize
(
for
asset
:
PHAsset
)
->
Int64
{
// func getAssetSize(for asset:PHAsset) ->Int64{
// if let resource = PHAssetResource.assetResources(for: asset).first,
// let size = resource.value(forKey: "fileSize") as? Int64 {
// return size
// } else {
// return 0
// }
// }
func
getAssetSize
(
for
asset
:
PHAsset
)
async
->
Int64
{
// 先尝试从缓存获取
if
let
cachedSize
=
await
AssetSizeCache
.
shared
.
getSize
(
for
:
asset
)
{
return
cachedSize
}
// 如果缓存中没有,则计算大小
if
let
resource
=
PHAssetResource
.
assetResources
(
for
:
asset
)
.
first
,
if
let
resource
=
PHAssetResource
.
assetResources
(
for
:
asset
)
.
first
,
let
size
=
resource
.
value
(
forKey
:
"fileSize"
)
as?
Int64
{
let
size
=
resource
.
value
(
forKey
:
"fileSize"
)
as?
Int64
{
// 将计算结果存入缓存
await
AssetSizeCache
.
shared
.
setSize
(
size
,
for
:
asset
)
return
size
return
size
}
else
{
return
0
}
}
return
0
}
}
...
@@ -585,6 +619,10 @@ extension PhotoManager{
...
@@ -585,6 +619,10 @@ extension PhotoManager{
}
}
}
}
func
getTotalSize
(
source
:[[
AssetModel
]])
->
Double
{
return
source
.
flatMap
{
$0
}
.
reduce
(
0
){
$0
+
$1
.
assetSize
}
}
// 获取所有资产的总数
// 获取所有资产的总数
// func fetchTotalAssets(completion: @escaping ([PHAsset]) -> Void) {
// func fetchTotalAssets(completion: @escaping ([PHAsset]) -> Void) {
// DispatchQueue.global(qos: .background).async {
// DispatchQueue.global(qos: .background).async {
...
@@ -606,10 +644,9 @@ extension PhotoManager{
...
@@ -606,10 +644,9 @@ extension PhotoManager{
// }
// }
}
}
extension
PhotoManager
{
extension
PhotoManager
{
// 批量转模型
func
convertAssetsToModel
(
for
assets
:
[
PHAsset
],
mediaType
:
Int
)
async
->
[
AssetModel
]
{
func
convertAssetsToModel
(
for
assets
:
[
PHAsset
],
mediaType
:
Int
)
async
->
[
AssetModel
]
{
let
batchSize
=
4
// 控制并发数量
let
batchSize
=
4
// 控制并发数量
var
results
:
[
AssetModel
]
=
[]
var
results
:
[
AssetModel
]
=
[]
...
@@ -624,7 +661,7 @@ extension PhotoManager{
...
@@ -624,7 +661,7 @@ extension PhotoManager{
group
.
addTask
{
group
.
addTask
{
return
AssetModel
(
return
AssetModel
(
localIdentifier
:
asset
.
localIdentifier
,
localIdentifier
:
asset
.
localIdentifier
,
assetSize
:
Double
(
self
.
getAssetSize
(
for
:
asset
)),
assetSize
:
Double
(
await
self
.
getAssetSize
(
for
:
asset
)),
createDate
:
asset
.
creationDate
??
Date
(),
createDate
:
asset
.
creationDate
??
Date
(),
mediaType
:
mediaType
mediaType
:
mediaType
)
)
...
@@ -640,6 +677,7 @@ extension PhotoManager{
...
@@ -640,6 +677,7 @@ extension PhotoManager{
return
results
return
results
}
}
// 获取总数据
func
getModelsData
(){
func
getModelsData
(){
Task
{
Task
{
let
start
=
CFAbsoluteTimeGetCurrent
()
let
start
=
CFAbsoluteTimeGetCurrent
()
...
@@ -660,3 +698,5 @@ extension PhotoManager{
...
@@ -660,3 +698,5 @@ extension PhotoManager{
}
}
}
}
}
}
PhoneManager/Class/Manager/PMPhotoManager/PhotoSimilarManager.swift
View file @
63c05ef8
...
@@ -10,7 +10,7 @@ import Photos
...
@@ -10,7 +10,7 @@ import Photos
import
UIKit
import
UIKit
@MainActor
class
PhotoSimilarManager
:
@unchecked
Sendable
{
class
PhotoSimilarManager
:
@unchecked
Sendable
{
static
let
shared
=
PhotoSimilarManager
()
static
let
shared
=
PhotoSimilarManager
()
...
@@ -198,7 +198,6 @@ class PhotoSimilarManager: @unchecked Sendable {
...
@@ -198,7 +198,6 @@ class PhotoSimilarManager: @unchecked Sendable {
}
else
{
}
else
{
assetSize
=
0
assetSize
=
0
}
}
let
model
=
AssetModel
(
let
model
=
AssetModel
(
localIdentifier
:
asset
.
localIdentifier
,
localIdentifier
:
asset
.
localIdentifier
,
assetSize
:
assetSize
,
assetSize
:
assetSize
,
...
...
PhoneManager/Class/Manager/PMPhotoManager/ScreenShotSimilarManager.swift
View file @
63c05ef8
...
@@ -9,7 +9,7 @@ import Foundation
...
@@ -9,7 +9,7 @@ import Foundation
import
Photos
import
Photos
import
UIKit
import
UIKit
@MainActor
class
ScreenshotSimilarJSONManager
:
@unchecked
Sendable
{
class
ScreenshotSimilarJSONManager
:
@unchecked
Sendable
{
static
let
shared
=
ScreenshotSimilarJSONManager
()
static
let
shared
=
ScreenshotSimilarJSONManager
()
...
...
PhoneManager/Class/Manager/PMPhotoManager/VideoSimilarManager.swift
View file @
63c05ef8
...
@@ -44,7 +44,7 @@ private actor VideoAssetCacheManager {
...
@@ -44,7 +44,7 @@ private actor VideoAssetCacheManager {
}
}
@MainActor
class
VideoSimilarJSONManager
:
@unchecked
Sendable
{
class
VideoSimilarJSONManager
:
@unchecked
Sendable
{
static
let
shared
=
VideoSimilarJSONManager
()
static
let
shared
=
VideoSimilarJSONManager
()
private
let
stateManager
=
VideoSimilarStateManager
()
private
let
stateManager
=
VideoSimilarStateManager
()
...
...
PhoneManager/Class/Page/Home/View/HomeCollectionViewHeader.swift
View file @
63c05ef8
...
@@ -162,6 +162,9 @@ class CustomProgressBar: UIView {
...
@@ -162,6 +162,9 @@ class CustomProgressBar: UIView {
var
chaoticProgress
:
CGFloat
=
0
{
var
chaoticProgress
:
CGFloat
=
0
{
didSet
{
didSet
{
guard
chaoticProgress
!=
oldValue
else
{
return
}
scheduleProgressUpdate
()
scheduleProgressUpdate
()
}
}
}
}
...
@@ -240,7 +243,7 @@ class CustomProgressBar: UIView {
...
@@ -240,7 +243,7 @@ class CustomProgressBar: UIView {
guard
let
self
=
self
else
{
return
}
guard
let
self
=
self
else
{
return
}
// 计算总容量和各部分比例
// 计算总容量和各部分比例
let
total
=
max
(
self
.
totalProgress
,
0.001
)
// 避免除以0
let
total
=
max
(
self
.
totalProgress
+
self
.
chaoticProgress
,
0.001
)
// 避免除以0
let
usedRatio
=
min
(
max
(
self
.
usedProgress
/
total
,
0
),
1
)
let
usedRatio
=
min
(
max
(
self
.
usedProgress
/
total
,
0
),
1
)
let
chaoticRatio
=
min
(
max
(
self
.
chaoticProgress
/
total
,
0
),
1
)
let
chaoticRatio
=
min
(
max
(
self
.
chaoticProgress
/
total
,
0
),
1
)
...
...
PhoneManager/Class/Page/Home/View/HomeView.swift
View file @
63c05ef8
...
@@ -31,8 +31,9 @@ class HomeView:UIView {
...
@@ -31,8 +31,9 @@ class HomeView:UIView {
// var model:PhotosManagerModel?
// var model:PhotosManagerModel?
var
viewModel
:
HomeViewModel
?
// var viewModel:HomeviewModel
private
var
viewModel
=
HomeViewModel
.
shared
var
attribet
:
NSAttributedString
?
var
attribet
:
NSAttributedString
?
...
@@ -73,41 +74,51 @@ class HomeView:UIView {
...
@@ -73,41 +74,51 @@ class HomeView:UIView {
override
init
(
frame
:
CGRect
)
{
override
init
(
frame
:
CGRect
)
{
super
.
init
(
frame
:
frame
)
super
.
init
(
frame
:
frame
)
viewModel
=
HomeViewModel
()
//
viewModel = HomeViewModel()
setupUI
()
setupUI
()
viewModel
?
.
setupBindings
()
viewModel
.
setupBindings
()
viewModel
?
.
homeDataChanged
=
{[
weak
self
]
section
,
row
in
viewModel
.
homeDataChanged
=
{[
weak
self
]
section
,
row
in
guard
let
weakSelf
=
self
else
{
return
}
guard
let
weakSelf
=
self
else
{
return
}
DispatchQueue
.
main
.
async
{
if
let
cell
=
weakSelf
.
collectionView
.
cellForItem
(
at
:
IndexPath
(
row
:
row
,
section
:
section
))
as?
HomeTitleCollectionCell
{
if
let
cell
=
weakSelf
.
collectionView
.
cellForItem
(
at
:
IndexPath
(
row
:
row
,
section
:
section
))
as?
HomeTitleCollectionCell
{
// 只更新需要改变的内容
// 只更新需要改变的内容
let
model
=
weakSelf
.
viewModel
?
.
headerGroup
[
row
]
let
model
=
weakSelf
.
viewModel
.
headerGroup
[
row
]
cell
.
reloadUIWithModel
(
model
:
model
)
cell
.
reloadUIWithModel
(
model
:
model
)
}
}
if
let
cell
=
weakSelf
.
collectionView
.
cellForItem
(
at
:
IndexPath
(
row
:
row
,
section
:
section
))
as?
HomeOtherCollectionCell
{
if
let
cell
=
weakSelf
.
collectionView
.
cellForItem
(
at
:
IndexPath
(
row
:
row
,
section
:
section
))
as?
HomeOtherCollectionCell
{
// 只更新需要改变的内容
// 只更新需要改变的内容
let
model
=
weakSelf
.
viewModel
?
.
cardGroup
[
row
]
let
model
=
weakSelf
.
viewModel
.
cardGroup
[
row
]
cell
.
reloadUIWithModel
(
model
:
model
)
cell
.
reloadUIWithModel
(
model
:
model
)
}
weakSelf
.
homeHeader
?
.
progressBar
.
chaoticProgress
=
CGFloat
(
weakSelf
.
viewModel
.
totalSize
)
weakSelf
.
reloadHeadSize
()
}
}
weakSelf
.
homeHeader
?
.
progressBar
.
chaoticProgress
=
CGFloat
(
weakSelf
.
viewModel
?
.
totalSize
??
0
)
weakSelf
.
reloadHeadSize
()
}
}
viewModel
?
.
coverHadChange
=
{
[
weak
self
]
in
viewModel
.
reloadCellHeight
=
{
[
weak
self
]
in
guard
let
weakSelf
=
self
else
{
return
}
guard
let
weakSelf
=
self
else
{
return
}
print
(
"刷新一次封面"
)
DispatchQueue
.
main
.
async
{
weakSelf
.
collectionView
.
reloadData
()
weakSelf
.
collectionView
.
reloadData
()
}
}
}
// viewModel.coverHadChange = { [weak self] in
// guard let weakSelf = self else { return }
// print("刷新一次封面")
// weakSelf.collectionView.reloadData()
// }
collectionView
.
reloadData
()
collectionView
.
reloadData
()
}
}
func
reloadHeadSize
(){
func
reloadHeadSize
(){
self
.
attribet
=
setFileAndCount
(
count
:
viewModel
?
.
totalFilesCount
??
0
,
fileSize
:
Double
(
viewModel
?
.
totalSize
??
0
))
self
.
attribet
=
setFileAndCount
(
count
:
viewModel
.
totalFilesCount
,
fileSize
:
Double
(
viewModel
.
totalSize
))
tipLabel
.
attributedText
=
attribet
tipLabel
.
attributedText
=
attribet
}
}
...
@@ -230,10 +241,10 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
...
@@ -230,10 +241,10 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
switch
section
{
switch
section
{
case
0
:
case
0
:
return
viewModel
?
.
headerGroup
.
count
??
0
// model?.titleModelArray.count ?? 0
return
viewModel
.
headerGroup
.
count
// model?.titleModelArray.count ?? 0
case
1
:
case
1
:
return
viewModel
?
.
cardGroup
.
count
??
0
//model?.otherModelArray.count ?? 0
return
viewModel
.
cardGroup
.
count
//model?.otherModelArray.count ?? 0
default
:
default
:
return
0
return
0
...
@@ -248,7 +259,7 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
...
@@ -248,7 +259,7 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
switch
section
{
switch
section
{
case
0
:
case
0
:
let
cell
=
collectionView
.
dequeueReusableCell
(
withReuseIdentifier
:
HomeTitleCollectionCell
.
identifiers
,
for
:
indexPath
)
as!
HomeTitleCollectionCell
let
cell
=
collectionView
.
dequeueReusableCell
(
withReuseIdentifier
:
HomeTitleCollectionCell
.
identifiers
,
for
:
indexPath
)
as!
HomeTitleCollectionCell
let
model
=
viewModel
?
.
headerGroup
[
indexPath
.
row
]
let
model
=
viewModel
.
headerGroup
[
indexPath
.
row
]
cell
.
reloadUIWithModel
(
model
:
model
)
cell
.
reloadUIWithModel
(
model
:
model
)
// cell.reloadCoverData()
// cell.reloadCoverData()
cell
.
homeTititlAction
=
{[
weak
self
]
idx
in
cell
.
homeTititlAction
=
{[
weak
self
]
idx
in
...
@@ -259,14 +270,14 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
...
@@ -259,14 +270,14 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
self
.
titleCallBack
(
model
,
.
similar
)
self
.
titleCallBack
(
model
,
.
similar
)
}
}
}
}
cell
.
reloadCoverData
(
viewModel
?
.
headCoverImages
[
indexPath
.
row
]
??
[])
// cell.reloadCoverData(viewModel
.headCoverImages[indexPath.row] ?? [])
if
indexPath
.
row
==
0
{
//
if indexPath.row == 0 {
self
.
dupHeadCell
=
cell
//
self.dupHeadCell = cell
// cell.reloadCoverData(viewModel?
.dupCoverImage ?? [])
// // cell.reloadCoverData(viewModel
.dupCoverImage ?? [])
}
else
{
//
}else{
// cell.reloadCoverData(viewModel?
.similarCoverImage ?? [])
// // cell.reloadCoverData(viewModel
.similarCoverImage ?? [])
self
.
similarHeadCell
=
cell
//
self.similarHeadCell = cell
}
//
}
if
cell
.
model
?
.
assets
.
count
??
0
>
0
{
if
cell
.
model
?
.
assets
.
count
??
0
>
0
{
cell
.
fileLabel
?
.
isHidden
=
false
cell
.
fileLabel
?
.
isHidden
=
false
...
@@ -278,15 +289,15 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
...
@@ -278,15 +289,15 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
case
1
:
case
1
:
let
cell
=
collectionView
.
dequeueReusableCell
(
withReuseIdentifier
:
HomeOtherCollectionCell
.
identifier
,
for
:
indexPath
)
as!
HomeOtherCollectionCell
let
cell
=
collectionView
.
dequeueReusableCell
(
withReuseIdentifier
:
HomeOtherCollectionCell
.
identifier
,
for
:
indexPath
)
as!
HomeOtherCollectionCell
cell
.
dealMediaType
(
indexPath
.
row
)
cell
.
dealMediaType
(
indexPath
.
row
)
let
model
=
viewModel
?
.
cardGroup
[
indexPath
.
row
]
let
model
=
viewModel
.
cardGroup
[
indexPath
.
row
]
cell
.
reloadUIWithModel
(
model
:
model
)
cell
.
reloadUIWithModel
(
model
:
model
)
Task
{
//
Task {
if
let
image
=
await
viewModel
?
.
coverCache
.
getImage
(
index
:
indexPath
.
row
)
{
// if let image = await viewModel
.coverCache.getImage(index: indexPath.row) {
await
MainActor
.
run
{
//
await MainActor.run {
cell
.
setCoverImageOrVideo
(
image
:
image
)
//
cell.setCoverImageOrVideo(image: image)
}
//
}
}
//
}
}
//
}
return
cell
return
cell
default
:
default
:
return
UICollectionViewCell
()
return
UICollectionViewCell
()
...
@@ -298,10 +309,10 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
...
@@ -298,10 +309,10 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
if
indexPath
.
section
==
0
{
if
indexPath
.
section
==
0
{
let
model
=
viewModel
?
.
headerGroup
[
indexPath
.
row
]
//model?.titleModelArray[indexPath.row]
let
model
=
viewModel
.
headerGroup
[
indexPath
.
row
]
//model?.titleModelArray[indexPath.row]
if
model
?
.
assets
.
count
??
0
>
0
{
if
model
.
assets
.
count
>
0
{
return
(
model
?
.
assets
.
first
?
.
count
??
0
)
>
2
?
((
collection
.
width
-
marginLR
-
20
)
/
2.5
)
+
64
:
((
collection
.
width
-
2
*
marginLR
-
10
)
/
2
)
+
64
return
(
model
.
assets
.
first
?
.
count
??
0
)
>
2
?
((
collection
.
width
-
marginLR
-
20
)
/
2.5
)
+
64
:
((
collection
.
width
-
2
*
marginLR
-
10
)
/
2
)
+
64
}
else
{
}
else
{
return
52
return
52
...
@@ -310,9 +321,9 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
...
@@ -310,9 +321,9 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
}
else
{
}
else
{
let
model
=
viewModel
?
.
cardGroup
[
indexPath
.
row
]
//model?.otherModelArray[indexPath.row]
let
model
=
viewModel
.
cardGroup
[
indexPath
.
row
]
//model?.otherModelArray[indexPath.row]
return
itemWidth
+
12
+
UILabel
.
getSizeWith
(
font
:
UIFont
.
systemFont
(
ofSize
:
16
,
weight
:
.
bold
),
lineSpacing
:
5
,
width
:
itemWidth
-
32
,
numberOfLines
:
0
,
content
:
model
?
.
folderName
??
""
)
.
height
return
itemWidth
+
12
+
UILabel
.
getSizeWith
(
font
:
UIFont
.
systemFont
(
ofSize
:
16
,
weight
:
.
bold
),
lineSpacing
:
5
,
width
:
itemWidth
-
32
,
numberOfLines
:
0
,
content
:
model
.
folderName
)
.
height
}
}
}
}
...
@@ -360,7 +371,7 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
...
@@ -360,7 +371,7 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
func
collectionView
(
_
collectionView
:
UICollectionView
,
didSelectItemAt
indexPath
:
IndexPath
)
{
func
collectionView
(
_
collectionView
:
UICollectionView
,
didSelectItemAt
indexPath
:
IndexPath
)
{
if
(
indexPath
.
section
==
0
)
{
if
(
indexPath
.
section
==
0
)
{
let
smodel
=
viewModel
?
.
headerGroup
[
indexPath
.
row
]
//model?.titleModelArray[indexPath.row]
let
smodel
=
viewModel
.
headerGroup
[
indexPath
.
row
]
//model?.titleModelArray[indexPath.row]
if
indexPath
.
row
==
0
{
if
indexPath
.
row
==
0
{
titleCallBack
(
smodel
,
.
duplicates
)
titleCallBack
(
smodel
,
.
duplicates
)
}
else
{
}
else
{
...
@@ -368,8 +379,8 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
...
@@ -368,8 +379,8 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
}
}
}
else
{
}
else
{
guard
let
smodel
=
viewModel
?
.
cardGroup
[
indexPath
.
row
]
else
{
return
}
//model?.otherModelArray[indexPath.row]
//guard let smodel = viewModel
.cardGroup[indexPath.row] else { return } //model?.otherModelArray[indexPath.row]
let
smodel
=
viewModel
.
cardGroup
[
indexPath
.
row
]
otherItemCallBack
(
smodel
,
indexPath
.
row
)
otherItemCallBack
(
smodel
,
indexPath
.
row
)
}
}
}
}
...
@@ -385,8 +396,8 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
...
@@ -385,8 +396,8 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
}
}
header
.
cleanNowButtonCallback
=
{[
weak
self
]
in
header
.
cleanNowButtonCallback
=
{[
weak
self
]
in
guard
let
self
=
self
else
{
return
}
guard
let
self
=
self
else
{
return
}
let
smodel
=
self
.
viewModel
?
.
headerGroup
[
0
]
//self.model?.titleModelArray
[0]
let
smodel
=
self
.
viewModel
.
headerGroup
[
0
]
let
vc
=
HomeInfoViewController
(
ids
:
smodel
!.
assets
,
type
:
.
duplicates
,
titleText
:
smodel
!
.
folderName
)
let
vc
=
HomeInfoViewController
(
ids
:
smodel
.
assets
,
type
:
.
duplicates
,
titleText
:
smodel
.
folderName
)
self
.
responderViewController
()?
.
navigationController
?
.
pushViewController
(
vc
,
animated
:
true
)
self
.
responderViewController
()?
.
navigationController
?
.
pushViewController
(
vc
,
animated
:
true
)
}
}
if
indexPath
.
section
!=
0
{
if
indexPath
.
section
!=
0
{
...
...
PhoneManager/Class/Page/Home/View/cell/HomeOtherCollectionCell.swift
View file @
63c05ef8
...
@@ -281,6 +281,14 @@ class HomeOtherCollectionCell: UICollectionViewCell {
...
@@ -281,6 +281,14 @@ class HomeOtherCollectionCell: UICollectionViewCell {
}
else
{
}
else
{
self
.
sizeLabel
.
text
=
String
(
format
:
"(%.2lf) GB"
,
sizeKB
/
(
1000
*
1000
))
self
.
sizeLabel
.
text
=
String
(
format
:
"(%.2lf) GB"
,
sizeKB
/
(
1000
*
1000
))
}
}
let
placeImage
=
self
.
mediaType
==
0
?
"othermoren"
:
self
.
mediaType
==
2
?
"photosmoren"
:
"videosmoren"
if
let
id
=
model
.
assets
.
first
?
.
first
?
.
localIdentifier
{
imageView
.
asset
.
load
(
withLocalIdentifier
:
id
,
placeholder
:
UIImage
(
named
:
placeImage
))
}
else
{
self
.
imageView
.
image
=
UIImage
.
init
(
named
:
placeImage
)
}
}
}
...
...
PhoneManager/Class/Page/Home/View/cell/HomeTitleCollectionCell.swift
View file @
63c05ef8
...
@@ -131,18 +131,26 @@ class HomeTitleCollectionCell:UICollectionViewCell {
...
@@ -131,18 +131,26 @@ class HomeTitleCollectionCell:UICollectionViewCell {
fileLabel
?
.
text
=
"
\(
count
)
"
+
" Photos "
+
(
model
.
allFileSize
>
0
?
"(
\(
formatFileSize
(
model
.
allFileSize
)
)
)"
:
"(Calculating...)"
)
fileLabel
?
.
text
=
"
\(
count
)
"
+
" Photos "
+
(
model
.
allFileSize
>
0
?
"(
\(
formatFileSize
(
model
.
allFileSize
)
)
)"
:
"(Calculating...)"
)
fileLabel
?
.
sizeToFit
()
fileLabel
?
.
sizeToFit
()
collectionView
?
.
reloadData
()
}
func
reloadCoverData
(
_
assets
:[
AssetModel
]){
assetsModels
.
removeAll
()
assetsModels
.
removeAll
()
assetsModels
=
assets
.
compactMap
({
model
in
return
ImageCollectionModel
.
init
(
asset
:
model
)
if
let
assets
=
model
.
assets
.
first
{
})
assetsModels
=
assets
.
compactMap
({
model
in
Print
(
"刷新头部封面
\(
self
)
"
,
assets
.
count
)
return
ImageCollectionModel
.
init
(
asset
:
model
)
collectionView
?
.
reloadData
()
})
collectionView
?
.
reloadData
()
}
}
}
// func reloadCoverData(_ assets:[AssetModel]){
// assetsModels.removeAll()
// assetsModels = assets.compactMap({ model in
// return ImageCollectionModel.init(asset: model)
// })
// Print("刷新头部封面\(self)",assets.count)
// collectionView?.reloadData()
// }
override
func
layoutSubviews
()
{
override
func
layoutSubviews
()
{
super
.
layoutSubviews
()
super
.
layoutSubviews
()
...
...
PhoneManager/Class/Page/Home/View/cell/ImageCollectionCell.swift
View file @
63c05ef8
...
@@ -47,8 +47,6 @@ class ImageCollectionCell:UICollectionViewCell {
...
@@ -47,8 +47,6 @@ class ImageCollectionCell:UICollectionViewCell {
backImageView
?
.
asset
.
load
(
withLocalIdentifier
:
model
.
asset
.
localIdentifier
,
placeholder
:
UIImage
.
init
(
named
:
"othermoren"
))
backImageView
?
.
asset
.
load
(
withLocalIdentifier
:
model
.
asset
.
localIdentifier
,
placeholder
:
UIImage
.
init
(
named
:
"othermoren"
))
}
}
}
}
...
...
PhoneManager/Class/Page/Home/ViewModel/HomeViewModel.swift
View file @
63c05ef8
...
@@ -4,82 +4,119 @@ import Combine
...
@@ -4,82 +4,119 @@ import Combine
class
HomeViewModel
{
class
HomeViewModel
{
// 封面图片资源缓存
static
let
shared
=
HomeViewModel
()
actor
CoverCacheActor
{
private
init
(){}
private
var
cardCoverImage
:[
UIImage
?]
=
[
UIImage
.
init
(
named
:
"videosmoren"
),
func
config
(){}
UIImage
.
init
(
named
:
"photosmoren"
),
UIImage
.
init
(
named
:
"photosmoren"
),
UIImage
.
init
(
named
:
"videosmoren"
),
let
trash
=
TrashDatabase
.
shared
.
queryAll
()
.
compactMap
{
$0
.
localIdentifier
}
UIImage
.
init
(
named
:
"othermoren"
)
]
let
keep
=
GroupDatabase
.
shared
.
queryAll
()
.
compactMap
{
$0
.
localIdentifier
}
func
getImage
(
index
:
Int
)
->
UIImage
?{
// 封面图片资源缓存
return
cardCoverImage
.
safeGet
(
index
:
index
)
??
nil
// actor CoverCacheActor {
}
//
// private var cardCoverImage:[UIImage?] = [
// UIImage.init(named: "videosmoren"),
func
setImage
(
index
:
Int
,
image
:
UIImage
?)
{
// UIImage.init(named: "photosmoren"),
guard
let
image
=
image
else
{
// UIImage.init(named: "photosmoren"),
return
// UIImage.init(named: "videosmoren"),
}
// UIImage.init(named: "othermoren")
if
cardCoverImage
.
count
>
index
{
// ]
cardCoverImage
[
index
]
=
image
//
}
// func getImage(index:Int) ->UIImage?{
}
// return cardCoverImage.safeGet(index: index) ?? nil
}
// }
//
//
// func setImage(index:Int,image:UIImage?) {
// guard let image = image else{
// return
// }
// if cardCoverImage.count > index{
// cardCoverImage[index] = image
// }
// }
// }
private
var
photoManager
=
PhotoManager
.
shared
private
var
photoManager
=
PhotoManager
.
shared
let
coverCache
=
CoverCacheActor
()
//
let coverCache = CoverCacheActor()
// 相册资源总大小
// 相册资源总大小
var
totalSize
:
Int64
{
var
totalSize
:
Int64
{
return
videoSize
+
otherSize
+
screentSize
return
photoManager
.
videoTotalSize
+
photoManager
.
otherTotalSize
+
photoManager
.
screenShotTotalSize
//
videoSize + otherSize + screentSize
}
}
var
videoSize
:
Int64
=
0
// var videoSize:Int64 = 0
var
otherSize
:
Int64
=
0
// var otherSize:Int64 = 0
var
screentSize
:
Int64
=
0
// var screentSize:Int64 = 0
var
totalFilesCount
:
Int
=
0
var
totalFilesCount
:
Int
=
0
// 首页UI数据结构
// 首页UI数据结构
var
headerGroup
:[
HomePhotosModel
]
=
[
var
headerGroup
:[
HomePhotosModel
]{
HomePhotosModel
.
init
(
folderName
:
HomeUIEnum
.
Dublicates
.
title
,
allFileSize
:
0
,
assets
:
[]),
return
[
HomePhotosModel
.
init
(
folderName
:
HomeUIEnum
.
Similar
.
title
,
allFileSize
:
0
,
assets
:
[])
HomePhotosModel
.
init
(
]
folderName
:
HomeUIEnum
.
Dublicates
.
title
,
allFileSize
:
getTotalSize
(
source
:
photoManager
.
duplicateModels
),
var
cardGroup
:[
HomePhotosModel
]
=
[
assets
:
photoManager
.
duplicateModels
),
HomePhotosModel
.
init
(
folderName
:
HomeUIEnum
.
Videos
.
title
,
allFileSize
:
0
,
assets
:
[]),
HomePhotosModel
.
init
(
folderName
:
HomeUIEnum
.
SimilarScreenshots
.
title
,
allFileSize
:
0
,
assets
:
[]),
HomePhotosModel
.
init
(
HomePhotosModel
.
init
(
folderName
:
HomeUIEnum
.
Screensshots
.
title
,
allFileSize
:
0
,
assets
:
[]),
folderName
:
HomeUIEnum
.
Similar
.
title
,
HomePhotosModel
.
init
(
folderName
:
HomeUIEnum
.
SimilarVideos
.
title
,
allFileSize
:
0
,
assets
:
[]),
allFileSize
:
getTotalSize
(
source
:
photoManager
.
filterSimilarModels
),
HomePhotosModel
.
init
(
folderName
:
HomeUIEnum
.
Other
.
title
,
allFileSize
:
0
,
assets
:
[]),
assets
:
photoManager
.
filterSimilarModels
)
]
]
}
// 首页UI数据结构
var
cardGroup
:[
HomePhotosModel
]{
return
[
HomePhotosModel
.
init
(
folderName
:
HomeUIEnum
.
Videos
.
title
,
allFileSize
:
getTotalSize
(
source
:
[
photoManager
.
filterVideoModels
]),
assets
:
[
photoManager
.
filterVideoModels
]),
HomePhotosModel
.
init
(
folderName
:
HomeUIEnum
.
SimilarScreenshots
.
title
,
allFileSize
:
getTotalSize
(
source
:
photoManager
.
filterSimilarScreenShotModels
),
assets
:
photoManager
.
filterSimilarScreenShotModels
),
HomePhotosModel
.
init
(
folderName
:
HomeUIEnum
.
Screensshots
.
title
,
allFileSize
:
getTotalSize
(
source
:
[
photoManager
.
filterScreenShotModels
]),
assets
:[
photoManager
.
filterScreenShotModels
]),
HomePhotosModel
.
init
(
folderName
:
HomeUIEnum
.
SimilarVideos
.
title
,
allFileSize
:
getTotalSize
(
source
:
photoManager
.
filterSimilarVideoModels
),
assets
:
photoManager
.
filterSimilarVideoModels
),
HomePhotosModel
.
init
(
folderName
:
HomeUIEnum
.
Other
.
title
,
allFileSize
:
getTotalSize
(
source
:
[
photoManager
.
filterOtherModels
]),
assets
:
[
photoManager
.
filterOtherModels
]),
]
}
func
getTotalSize
(
source
:[[
AssetModel
]])
->
Double
{
return
source
.
flatMap
{
$0
}
.
reduce
(
0
){
$0
+
$1
.
assetSize
}
}
var
hadLoad
=
false
var
hadLoad
=
false
// 数据获取回调
// 数据获取回调
var
homeDataChanged
:((
_
section
:
Int
,
_
row
:
Int
)
->
Void
)?
var
homeDataChanged
:((
_
section
:
Int
,
_
row
:
Int
)
->
Void
)?
// 封面获取回调
var
reloadCellHeight
:(()
->
Void
)?
var
coverHadChange
:(()
->
Void
)?
// 添加状态变化的回调闭包
// var dupCoverImage:[AssetModel] = []
var
onLoadingStateChanged
:
((
BaseDataLoadingState
)
->
Void
)?
//
// var similarCoverImage:[AssetModel] = []
var
dupCoverImage
:[
AssetModel
]
=
[]
//
// var headCoverImages:[[AssetModel]]{
var
similarCoverImage
:[
AssetModel
]
=
[]
// return [
// dupCoverImage,
var
headCoverImages
:[[
AssetModel
]]{
// similarCoverImage
return
[
// ]
dupCoverImage
,
// }
similarCoverImage
]
}
func
setupBindings
()
{
func
setupBindings
()
{
...
@@ -106,9 +143,11 @@ class HomeViewModel {
...
@@ -106,9 +143,11 @@ class HomeViewModel {
photoManager
.
convertScreenShotModels
{[
weak
self
]
screens
,
size
in
photoManager
.
convertScreenShotModels
{[
weak
self
]
screens
,
size
in
guard
let
weakSelf
=
self
else
{
return
}
guard
let
weakSelf
=
self
else
{
return
}
let
type
=
HomeUIEnum
.
Screensshots
let
type
=
HomeUIEnum
.
Screensshots
weakSelf
.
cardGroup
[
type
.
index
]
=
HomePhotosModel
.
init
(
folderName
:
type
.
title
,
allFileSize
:
Double
(
size
),
assets
:
[
screens
])
// weakSelf.cardGroup[type.index] = HomePhotosModel.init(folderName: type.title, allFileSize: Double(size), assets: [screens])
weakSelf
.
getCoverImage
(
type
:
type
,
identifier
:
screens
.
first
?
.
localIdentifier
)
weakSelf
.
screentSize
=
size
// weakSelf.getCoverImage(type: type, identifier: screens.first?.localIdentifier)
//weakSelf.screentSize = size
weakSelf
.
filterResource
()
weakSelf
.
homeDataChanged
?(
1
,
type
.
index
)
weakSelf
.
homeDataChanged
?(
1
,
type
.
index
)
}
}
...
@@ -116,9 +155,10 @@ class HomeViewModel {
...
@@ -116,9 +155,10 @@ class HomeViewModel {
guard
let
weakSelf
=
self
else
{
return
}
guard
let
weakSelf
=
self
else
{
return
}
let
type
=
HomeUIEnum
.
Other
let
type
=
HomeUIEnum
.
Other
weakSelf
.
cardGroup
[
type
.
index
]
=
HomePhotosModel
.
init
(
folderName
:
type
.
title
,
allFileSize
:
Double
(
size
),
assets
:
[
others
])
// weakSelf.cardGroup[type.index] = HomePhotosModel.init(folderName: type.title, allFileSize: Double(size), assets: [others])
weakSelf
.
getCoverImage
(
type
:
type
,
identifier
:
others
.
first
?
.
localIdentifier
)
// weakSelf.getCoverImage(type: type, identifier: others.first?.localIdentifier)
weakSelf
.
otherSize
=
size
// weakSelf.otherSize = size
weakSelf
.
filterResource
()
weakSelf
.
homeDataChanged
?(
1
,
type
.
index
)
weakSelf
.
homeDataChanged
?(
1
,
type
.
index
)
}
}
...
@@ -126,9 +166,10 @@ class HomeViewModel {
...
@@ -126,9 +166,10 @@ class HomeViewModel {
guard
let
weakSelf
=
self
else
{
return
}
guard
let
weakSelf
=
self
else
{
return
}
let
type
=
HomeUIEnum
.
Videos
let
type
=
HomeUIEnum
.
Videos
weakSelf
.
cardGroup
[
type
.
index
]
=
HomePhotosModel
.
init
(
folderName
:
type
.
title
,
allFileSize
:
Double
(
size
),
assets
:
[
videos
])
// weakSelf.cardGroup[type.index] = HomePhotosModel.init(folderName: type.title, allFileSize: Double(size), assets: [videos])
weakSelf
.
getCoverImage
(
type
:
type
,
identifier
:
videos
.
first
?
.
localIdentifier
)
// weakSelf.getCoverImage(type: type, identifier: videos.first?.localIdentifier)
weakSelf
.
videoSize
=
size
// weakSelf.videoSize = size
weakSelf
.
filterResource
()
weakSelf
.
homeDataChanged
?(
1
,
type
.
index
)
weakSelf
.
homeDataChanged
?(
1
,
type
.
index
)
}
}
startMainTask
()
startMainTask
()
...
@@ -136,185 +177,270 @@ class HomeViewModel {
...
@@ -136,185 +177,270 @@ class HomeViewModel {
func
startMainTask
(){
func
startMainTask
(){
DispatchQueue
.
main
.
async
{[
weak
self
]
in
getSimilarOptimizer
()
guard
let
weakSelf
=
self
else
{
return
}
getSimilarScreenOptimizer
()
weakSelf
.
getSimilarOptimizer
()
getSimilarVideoOptimizer
()
weakSelf
.
getSimilarScreenOptimizer
()
getGroupDuplicateImages
()
weakSelf
.
getSimilarVideoOptimizer
()
weakSelf
.
getGroupDuplicateImages
()
// DispatchQueue.main.async {[weak self] in
}
// guard let weakSelf = self else { return }
// weakSelf.getSimilarOptimizer()
// weakSelf.getSimilarScreenOptimizer()
// weakSelf.getSimilarVideoOptimizer()
// //weakSelf.getGroupDuplicateImages()
// }
}
}
// 获取相似图片
// 获取相似图片
@MainActor
func
getSimilarOptimizer
(){
func
getSimilarOptimizer
(){
let
type
=
HomeUIEnum
.
Similar
let
type
=
HomeUIEnum
.
Similar
var
currentGorup
:[[
AssetModel
]]
=
[]
// var currentGorup:[[AssetModel]] = []
var
currentSize
:
Double
=
0
// var currentSize:Double = 0
var
firstId
:
String
?
// var firstId:String?
var
hadblock
=
false
PhotoSimilarManager
.
shared
.
findSimilarAssets
(
in
:
photoManager
.
otherAssets
)
{[
weak
self
]
group
in
PhotoSimilarManager
.
shared
.
findSimilarAssets
(
in
:
photoManager
.
otherAssets
)
{[
weak
self
]
group
in
guard
let
weakSelf
=
self
else
{
return
}
guard
let
weakSelf
=
self
else
{
return
}
currentGorup
.
append
(
group
)
//
currentGorup.append(group)
currentSize
+=
group
.
reduce
(
0
){
$0
+
$1
.
assetSize
}
//
currentSize += group.reduce(0){$0+$1.assetSize}
// weakSelf.totalSize += Int64(currentSize)
// weakSelf.totalSize += Int64(currentSize)
weakSelf
.
headerGroup
[
type
.
index
]
.
assets
=
currentGorup
// weakSelf.headerGroup[type.index].assets = currentGorup
weakSelf
.
headerGroup
[
type
.
index
]
.
allFileSize
=
currentSize
// weakSelf.headerGroup[type.index].allFileSize = currentSize
weakSelf
.
photoManager
.
similarModels
.
append
(
group
)
if
let
id
=
currentGorup
.
first
?
.
first
?
.
localIdentifier
{
// if let id = weakSelf.photoManager.similarModels.first?.first?.localIdentifier{
if
firstId
!=
id
{
// if firstId != id{
firstId
=
id
// firstId = id
weakSelf
.
similarCoverImage
=
group
// weakSelf.similarCoverImage = group
weakSelf
.
coverHadChange
?()
// weakSelf.coverHadChange?()
}
// }
// }
if
!
hadblock
{
weakSelf
.
reloadCellHeight
?()
hadblock
=
true
}
}
weakSelf
.
homeDataChanged
?(
0
,
type
.
index
)
weakSelf
.
homeDataChanged
?(
0
,
type
.
index
)
}
completionHandler
:
{[
weak
self
]
totalGroup
in
}
completionHandler
:
{[
weak
self
]
totalGroup
in
guard
let
weakSelf
=
self
else
{
return
}
guard
let
weakSelf
=
self
else
{
return
}
print
(
"获取相似图片完成"
,
totalGroup
.
count
)
print
(
"获取相似图片完成"
,
totalGroup
.
count
)
weakSelf
.
photoManager
.
similarModels
=
totalGroup
weakSelf
.
photoManager
.
similarModels
=
totalGroup
weakSelf
.
filterResource
()
weakSelf
.
homeDataChanged
?(
0
,
type
.
index
)
}
}
}
}
// 获取相似截图
// 获取相似截图
@MainActor
func
getSimilarScreenOptimizer
(){
func
getSimilarScreenOptimizer
(){
let
type
=
HomeUIEnum
.
SimilarScreenshots
let
type
=
HomeUIEnum
.
SimilarScreenshots
var
currentGorup
:[[
AssetModel
]]
=
[]
//
var currentGorup:[[AssetModel]] = []
var
currentSize
:
Double
=
0
//
var currentSize:Double = 0
var
firstId
:
String
?
//
var firstId:String?
ScreenshotSimilarJSONManager
.
shared
.
findSimilarAssets
(
in
:
photoManager
.
screenShotAssets
)
{[
weak
self
]
group
in
ScreenshotSimilarJSONManager
.
shared
.
findSimilarAssets
(
in
:
photoManager
.
screenShotAssets
)
{[
weak
self
]
group
in
guard
let
weakSelf
=
self
else
{
return
}
guard
let
weakSelf
=
self
else
{
return
}
currentGorup
.
append
(
group
)
//
currentGorup.append(group)
currentSize
+=
group
.
reduce
(
0
){
$0
+
$1
.
assetSize
}
//
currentSize += group.reduce(0){$0+$1.assetSize}
// weakSelf.totalSize += Int64(currentSize)
// weakSelf.totalSize += Int64(currentSize)
weakSelf
.
cardGroup
[
type
.
index
]
.
assets
=
currentGorup
//
weakSelf.cardGroup[type.index].assets = currentGorup
weakSelf
.
cardGroup
[
type
.
index
]
.
allFileSize
=
currentSize
//
weakSelf.cardGroup[type.index].allFileSize = currentSize
//
if
let
id
=
currentGorup
.
first
?
.
first
?
.
localIdentifier
{
//
if let id = currentGorup.first?.first?.localIdentifier{
if
firstId
!=
id
{
//
if firstId != id{
firstId
=
id
//
firstId = id
weakSelf
.
getCoverImage
(
type
:
type
,
identifier
:
firstId
)
//
weakSelf.getCoverImage(type: type, identifier: firstId)
}
//
}
}
//
}
weakSelf
.
photoManager
.
similarScreenShotModels
.
append
(
group
)
weakSelf
.
homeDataChanged
?(
1
,
type
.
index
)
weakSelf
.
homeDataChanged
?(
1
,
type
.
index
)
}
completionHandler
:
{[
weak
self
]
totalGroup
in
}
completionHandler
:
{[
weak
self
]
totalGroup
in
guard
let
weakSelf
=
self
else
{
return
}
guard
let
weakSelf
=
self
else
{
return
}
print
(
"获取相似截图完成"
,
totalGroup
.
count
)
print
(
"获取相似截图完成"
,
totalGroup
.
count
)
weakSelf
.
filterResource
()
weakSelf
.
photoManager
.
similarScreenShotModels
=
totalGroup
weakSelf
.
photoManager
.
similarScreenShotModels
=
totalGroup
}
}
}
}
@MainActor
func
getSimilarVideoOptimizer
(){
func
getSimilarVideoOptimizer
(){
let
type
=
HomeUIEnum
.
SimilarVideos
let
type
=
HomeUIEnum
.
SimilarVideos
var
currentGorup
:[[
AssetModel
]]
=
[]
//
var currentGorup:[[AssetModel]] = []
var
currentSize
:
Double
=
0
//
var currentSize:Double = 0
var
firstId
:
String
?
//
var firstId:String?
VideoSimilarJSONManager
.
shared
.
findSimilarVideos
(
in
:
photoManager
.
videoAssets
)
{[
weak
self
]
group
in
VideoSimilarJSONManager
.
shared
.
findSimilarVideos
(
in
:
photoManager
.
videoAssets
)
{[
weak
self
]
group
in
guard
let
weakSelf
=
self
else
{
return
}
guard
let
weakSelf
=
self
else
{
return
}
currentGorup
.
append
(
group
)
// currentGorup.append(group)
currentSize
+=
group
.
reduce
(
0
){
$0
+
$1
.
assetSize
}
// currentSize += group.reduce(0){$0+$1.assetSize}
//
weakSelf
.
cardGroup
[
type
.
index
]
.
assets
=
currentGorup
// weakSelf.cardGroup[type.index].assets = currentGorup
weakSelf
.
cardGroup
[
type
.
index
]
.
allFileSize
=
currentSize
// weakSelf.cardGroup[type.index].allFileSize = currentSize
//
if
let
id
=
currentGorup
.
first
?
.
first
?
.
localIdentifier
{
// if let id = currentGorup.first?.first?.localIdentifier{
if
firstId
!=
id
{
// if firstId != id{
firstId
=
id
// firstId = id
weakSelf
.
getCoverImage
(
type
:
type
,
identifier
:
firstId
)
// weakSelf.getCoverImage(type: type, identifier: firstId)
}
// }
}
// }
weakSelf
.
photoManager
.
similarVideoModels
.
append
(
group
)
weakSelf
.
homeDataChanged
?(
1
,
type
.
index
)
weakSelf
.
homeDataChanged
?(
1
,
type
.
index
)
}
completionHandler
:
{[
weak
self
]
totalGroup
in
}
completionHandler
:
{[
weak
self
]
totalGroup
in
print
(
"获取相似视频完成"
,
totalGroup
.
count
)
print
(
"获取相似视频完成"
,
totalGroup
.
count
)
guard
let
weakSelf
=
self
else
{
return
}
guard
let
weakSelf
=
self
else
{
return
}
weakSelf
.
filterResource
()
weakSelf
.
photoManager
.
similarVideoModels
=
totalGroup
weakSelf
.
photoManager
.
similarVideoModels
=
totalGroup
}
}
}
}
// 获取重复图片
// 获取重复图片
@MainActor
func
getGroupDuplicateImages
(){
func
getGroupDuplicateImages
(){
let
type
=
HomeUIEnum
.
Dublicates
let
type
=
HomeUIEnum
.
Dublicates
var
currentGorup
:[[
AssetModel
]]
=
[]
// var currentGorup:[[AssetModel]] = []
var
currentSize
:
Double
=
0
// var currentSize:Double = 0
var
firstId
:
String
?
// var firstId:String?
PhotoDuplicateManager
.
shared
.
findDuplicateAssets
(
in
:
photoManager
.
otherAssets
,
mediaType
:
.
photo
)
{[
weak
self
]
groups
in
PhotoDuplicateManager
.
shared
.
findDuplicateAssets
(
in
:
photoManager
.
otherAssets
,
mediaType
:
.
photo
)
{[
weak
self
]
groups
in
guard
let
weakSelf
=
self
else
{
return
}
guard
let
weakSelf
=
self
else
{
return
}
// let size = groups.map{$0}.reduce(into: 0){$0+$1.assetSize}
// let size = groups.map{$0}.reduce(into: 0){$0+$1.assetSize}
weakSelf
.
headerGroup
[
type
.
index
]
.
assets
=
groups
//
weakSelf.headerGroup[type.index].assets = groups
weakSelf
.
headerGroup
[
type
.
index
]
.
allFileSize
=
currentSize
//
weakSelf.headerGroup[type.index].allFileSize = currentSize
if
let
id
=
groups
.
first
?
.
first
?
.
localIdentifier
{
weakSelf
.
photoManager
.
duplicateModels
=
groups
if
firstId
!=
id
{
firstId
=
id
weakSelf
.
dupCoverImage
=
groups
.
first
??
[]
weakSelf
.
coverHadChange
?()
}
}
// if let id = groups.first?.first?.localIdentifier{
// if firstId != id{
// firstId = id
// weakSelf.dupCoverImage = groups.first ?? []
// weakSelf.coverHadChange?()
// }
// }
let
currentThread
=
Thread
.
current
if
currentThread
.
isMainThread
{
print
(
"在主线程执行"
)
}
else
{
print
(
"在后台线程执行"
)
}
weakSelf
.
reloadCellHeight
?()
weakSelf
.
homeDataChanged
?(
0
,
type
.
index
)
weakSelf
.
homeDataChanged
?(
0
,
type
.
index
)
}
progressHandler
:
{[
weak
self
]
group
in
}
progressHandler
:
{
group
in
guard
let
weakSelf
=
self
else
{
return
}
// guard let weakSelf = self else { return }
// currentGorup.append(group)
currentGorup
.
append
(
group
)
// currentSize += group.reduce(0){$0+$1.assetSize}
currentSize
+=
group
.
reduce
(
0
){
$0
+
$1
.
assetSize
}
//
// weakSelf.headerGroup[type.index].assets = currentGorup
// weakSelf.headerGroup[type.index].allFileSize = currentSize
weakSelf
.
headerGroup
[
type
.
index
]
.
assets
=
currentGorup
// weakSelf.photoManager.duplicateModels = groups
weakSelf
.
headerGroup
[
type
.
index
]
.
allFileSize
=
currentSize
if
let
id
=
currentGorup
.
first
?
.
first
?
.
localIdentifier
{
// 从 group 中过滤掉存在于 duplicateModels 中的元素
if
firstId
!=
id
{
firstId
=
id
weakSelf
.
dupCoverImage
=
group
weakSelf
.
coverHadChange
?()
}
}
weakSelf
.
homeDataChanged
?(
0
,
type
.
index
)
// let filteredGroup = group.filter { item in
// !weakSelf.photoManager.duplicateModels.flatMap { $0 }.contains(item)
// }
//
//
// if let id = currentGorup.first?.first?.localIdentifier{
// if firstId != id{
// firstId = id
// weakSelf.dupCoverImage = group
// weakSelf.coverHadChange?()
// }
// }
//
// weakSelf.homeDataChanged?(0,type.index)
}
completionHandler
:
{[
weak
self
]
totalGroup
in
}
completionHandler
:
{[
weak
self
]
totalGroup
in
guard
let
weakSelf
=
self
else
{
return
}
guard
let
weakSelf
=
self
else
{
return
}
print
(
"获得重复图片完成"
,
totalGroup
.
count
)
let
currentThread
=
Thread
.
current
if
currentThread
.
isMainThread
{
print
(
"在主线程执行"
)
}
else
{
print
(
"在后台线程执行"
)
}
weakSelf
.
photoManager
.
duplicateModels
=
totalGroup
weakSelf
.
photoManager
.
duplicateModels
=
totalGroup
weakSelf
.
reloadCellHeight
?()
weakSelf
.
homeDataChanged
?(
0
,
type
.
index
)
}
}
}
}
func
getCoverImage
(
type
:
HomeUIEnum
,
identifier
:
String
?){
// func getCoverImage(type:HomeUIEnum,identifier:String?){
guard
let
identifier
=
identifier
else
{
// guard let identifier = identifier else{
return
// return
}
// }
print
(
"执行一次
\(
type
.
title
)
获取封面,id=
\(
identifier
)
"
)
// print("执行一次\(type.title)获取封面,id=\(identifier)")
Task
{
// Task {
PhotoManager
.
shared
.
getImage
(
localIdentifier
:
identifier
,
completion
:
{
[
weak
self
]
image
in
// PhotoManager.shared.getImage(localIdentifier:identifier,completion: { [weak self] image in
guard
let
self
=
self
else
{
return
}
// guard let self = self else { return }
Task
{
// Task {
switch
type
{
// switch type {
case
.
Dublicates
:
// case .Dublicates:
break
// break
case
.
Similar
:
// case .Similar:
break
// break
default
:
// default:
await
self
.
coverCache
.
setImage
(
index
:
type
.
index
,
image
:
image
)
// await self.coverCache.setImage(index: type.index, image: image)
await
MainActor
.
run
{
// await MainActor.run {
self
.
coverHadChange
?()
// self.coverHadChange?()
}
// }
}
// }
}
// }
})
// })
// }
// }
}
extension
HomeViewModel
{
// 基本资源过滤保留和垃圾桶资源
func
filterResource
(){
let
filterArray
=
trash
+
keep
let
others
=
removeAssets
(
withIdentifiers
:
filterArray
,
from
:
photoManager
.
otherModels
)
let
videos
=
removeAssets
(
withIdentifiers
:
filterArray
,
from
:
photoManager
.
videoModels
)
let
screens
=
removeAssets
(
withIdentifiers
:
filterArray
,
from
:
photoManager
.
screenShotModels
)
photoManager
.
filterOtherModels
=
others
photoManager
.
filterVideoModels
=
videos
photoManager
.
filterScreenShotModels
=
screens
let
similarPhotos
=
filterGroups
(
photoManager
.
similarModels
,
byExcludingIDs
:
filterArray
)
let
similarVideos
=
filterGroups
(
photoManager
.
similarVideoModels
,
byExcludingIDs
:
filterArray
)
let
similarShots
=
filterGroups
(
photoManager
.
similarScreenShotModels
,
byExcludingIDs
:
filterArray
)
photoManager
.
filterSimilarModels
=
similarPhotos
photoManager
.
filterSimilarVideoModels
=
similarVideos
photoManager
.
filterSimilarScreenShotModels
=
similarShots
reloadCellHeight
?()
}
func
removeAssets
(
withIdentifiers
identifiers
:
[
String
],
from
assets
:
[
AssetModel
])
->
[
AssetModel
]
{
let
identifierSet
=
Set
(
identifiers
)
return
assets
.
filter
{
!
identifierSet
.
contains
(
$0
.
localIdentifier
)
}
}
func
filterGroups
(
_
groups
:
[[
AssetModel
]],
byExcludingIDs
ids
:
[
String
])
->
[[
AssetModel
]]
{
let
excludeSet
=
Set
(
ids
)
return
groups
.
filter
{
group
in
// 检查子数组中是否所有元素的ID都不在排除列表中
group
.
allSatisfy
{
!
excludeSet
.
contains
(
$0
.
localIdentifier
)
}
}
}
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment