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
Show 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 {
AdvManager
.
shared
.
initAdertisementSDK
()
PMEmailManager
.
shareManager
.
restore
()
// 相册基本资源加载
PhotoManager
.
shared
.
config
()
return
true
...
...
PhoneManager/Class/Database/TrashDatabase.swift
View file @
63c05ef8
...
...
@@ -260,3 +260,14 @@ class TrashDatabase {
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
import
Photos
import
UIKit
@MainActor
class
PhotoDuplicateManager
:
@unchecked
Sendable
{
// 移除顶层的 @MainActor
class
PhotoDuplicateManager
:
@unchecked
Sendable
{
static
let
shared
=
PhotoDuplicateManager
()
private
let
stateManager
=
PhotoDuplicateStateManager
()
// 使用新的状态管理器
private
init
()
{}
...
...
@@ -41,7 +41,9 @@ class PhotoDuplicateManager: @unchecked Sendable {
progressHandler
:
(([
AssetModel
])
->
Void
)?,
completionHandler
:
(([[
AssetModel
]])
->
Void
)?)
{
Task
{
Task
.
detached
(
priority
:
.
background
)
{
[
weak
self
]
in
guard
let
self
=
self
else
{
return
}
// 1. 加载本地数据
await
loadStoredData
()
print
(
"本地数据加载完成"
)
...
...
@@ -50,9 +52,6 @@ class PhotoDuplicateManager: @unchecked Sendable {
let
cachedGroups
=
await
stateManager
.
getAllDuplicateGroups
()
print
(
"通知已缓存的结果"
,
cachedGroups
.
count
)
await
MainActor
.
run
{
// for group in cachedGroups {
// progressHandler?(group.assets)
// }
let
groups
=
cachedGroups
.
map
{
$0
.
assets
}
loacalHandler
?(
groups
)
}
...
...
@@ -66,7 +65,7 @@ class PhotoDuplicateManager: @unchecked Sendable {
// 创建特征键(分辨率+创建时间+文件大小)
let
resolution
=
"
\(
asset
.
pixelWidth
)
x
\(
asset
.
pixelHeight
)
"
// let createTime = asset.creationDate?.timeIntervalSince1970 ?? 0
let
fileSize
=
getAssetSize
(
asset
)
let
fileSize
=
await
getAssetSize
(
asset
:
asset
)
let
featureKey
=
"
\(
resolution
)
_
\(
fileSize
)
"
if
tempGroups
[
featureKey
]
==
nil
{
...
...
@@ -149,45 +148,212 @@ class PhotoDuplicateManager: @unchecked Sendable {
completionHandler
?(
allGroups
.
map
{
$0
.
assets
})
}
}
}
// MARK: - 辅助方法
// func findDuplicateAssets(
// in assets: [PHAsset],
// mediaType: MediaType = .photo,
// loacalHandler: @Sendable @escaping ([[AssetModel]]) -> Void,
// progressHandler: @Sendable @escaping ([AssetModel]) -> Void,
// completionHandler: @Sendable @escaping ([[AssetModel]]) -> Void
// ) {
// // 使用后台优先级
// Task.detached(priority: .background) { [weak self] in
// guard let self = self else { return }
//
// do {
// // 批量处理,减少主线程切换
// let batchSize = 100
// var accumulatedProgress: [AssetModel] = []
//
// for i in stride(from: 0, to: assets.count, by: batchSize) {
// let end = min(i + batchSize, assets.count)
// let batchAssets = Array(assets[i..<end])
//
// // 处理一批资源
// let results = try await self.processBatch(batchAssets)
// 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([]) // 返回空数组或错误处理
// }
// }
// }
// }
nonisolated
private
func
areAssetsExactlyDuplicate
(
_
assets
:
[
PHAsset
])
->
Bool
{
guard
let
firstAsset
=
assets
.
first
else
{
return
false
}
// 按特征分组(分辨率、文件大小等)
// 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 }
// }
return
assets
.
allSatisfy
{
asset
in
// 检查分辨率完全相同
if
asset
.
pixelWidth
!=
firstAsset
.
pixelWidth
||
asset
.
pixelHeight
!=
firstAsset
.
pixelHeight
{
return
false
}
// 处理特征分组并查找重复项
// 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()
// }
// }
// }
// }
// }
// }
// }
// 检查文件大小完全相同
let
firstSize
=
getAssetSize
(
firstAsset
)
let
currentSize
=
getAssetSize
(
asset
)
if
firstSize
!=
currentSize
{
return
false
}
// MARK: - 辅助方法
// 检查创建时间是否接近(避免连拍照片)
// if let time1 = asset.creationDate,
// let time2 = firstAsset.creationDate {
// let timeDiff = abs(time1.timeIntervalSince(time2))
// if timeDiff < 1.0 { // 1秒内的连拍照片不算重复
// return false
// 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
// }
return
true
}
func
getAssetSize
(
asset
:
PHAsset
)
async
->
Int64
{
// 先尝试从缓存获取
if
let
cachedSize
=
await
AssetSizeCache
.
shared
.
getSize
(
for
:
asset
)
{
return
cachedSize
}
nonisolated
private
func
getAssetSize
(
_
asset
:
PHAsset
)
->
Int64
{
// 如果缓存中没有,则计算大小
if
let
resource
=
PHAssetResource
.
assetResources
(
for
:
asset
)
.
first
,
let
size
=
resource
.
value
(
forKey
:
"fileSize"
)
as?
Int64
{
// 将计算结果存入缓存
await
AssetSizeCache
.
shared
.
setSize
(
size
,
for
:
asset
)
return
size
}
return
0
}
...
...
@@ -197,7 +363,7 @@ class PhotoDuplicateManager: @unchecked Sendable {
for
asset
in
assets
{
modelGroup
.
addTask
{
let
size
=
self
.
getAssetSize
(
asset
)
let
size
=
await
self
.
getAssetSize
(
asset
:
asset
)
return
AssetModel
(
localIdentifier
:
asset
.
localIdentifier
,
assetSize
:
Double
(
size
),
...
...
@@ -304,4 +470,47 @@ extension PhotoDuplicateManager {
let
average
=
UInt8
(
pixels
.
reduce
(
0
,
{
UInt32
(
$0
)
+
UInt32
(
$1
)
})
/
UInt32
(
pixels
.
count
))
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{
// 重复图片分组
var
duplicateModels
:[[
AssetModel
]]
=
[]
// 过滤垃圾桶/保留相似图片分组
var
filterSimilarModels
:[[
AssetModel
]]
=
[]
// 过滤垃圾桶/保留相似截图分组
var
filterSimilarScreenShotModels
:[[
AssetModel
]]
=
[]
// 过滤垃圾桶/保留相似视频分组
var
filterSimilarVideoModels
:[[
AssetModel
]]
=
[]
// // 过滤垃圾桶/保留重复图片分组
// var filterDuplicateModels:[[AssetModel]] = []
// 截图
var
screenShotModels
:[
AssetModel
]
=
[]
// 视频
...
...
@@ -95,6 +104,14 @@ class PhotoManager{
// 其他
var
otherModels
:[
AssetModel
]
=
[]
// 过滤垃圾桶/保留截图
var
filterScreenShotModels
:[
AssetModel
]
=
[]
// 过滤垃圾桶/保留视频
var
filterVideoModels
:[
AssetModel
]
=
[]
// 过滤垃圾桶/保留其他
var
filterOtherModels
:[
AssetModel
]
=
[]
private(set)
var
screenShotTotalSize
:
Int64
=
0
private(set)
var
videoTotalSize
:
Int64
=
0
private(set)
var
otherTotalSize
:
Int64
=
0
...
...
@@ -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
,
let
size
=
resource
.
value
(
forKey
:
"fileSize"
)
as?
Int64
{
// 将计算结果存入缓存
await
AssetSizeCache
.
shared
.
setSize
(
size
,
for
:
asset
)
return
size
}
else
{
return
0
}
return
0
}
...
...
@@ -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) {
// DispatchQueue.global(qos: .background).async {
...
...
@@ -606,10 +644,9 @@ extension PhotoManager{
// }
}
extension
PhotoManager
{
// 批量转模型
func
convertAssetsToModel
(
for
assets
:
[
PHAsset
],
mediaType
:
Int
)
async
->
[
AssetModel
]
{
let
batchSize
=
4
// 控制并发数量
var
results
:
[
AssetModel
]
=
[]
...
...
@@ -624,7 +661,7 @@ extension PhotoManager{
group
.
addTask
{
return
AssetModel
(
localIdentifier
:
asset
.
localIdentifier
,
assetSize
:
Double
(
self
.
getAssetSize
(
for
:
asset
)),
assetSize
:
Double
(
await
self
.
getAssetSize
(
for
:
asset
)),
createDate
:
asset
.
creationDate
??
Date
(),
mediaType
:
mediaType
)
...
...
@@ -640,6 +677,7 @@ extension PhotoManager{
return
results
}
// 获取总数据
func
getModelsData
(){
Task
{
let
start
=
CFAbsoluteTimeGetCurrent
()
...
...
@@ -660,3 +698,5 @@ extension PhotoManager{
}
}
}
PhoneManager/Class/Manager/PMPhotoManager/PhotoSimilarManager.swift
View file @
63c05ef8
...
...
@@ -10,7 +10,7 @@ import Photos
import
UIKit
@MainActor
class
PhotoSimilarManager
:
@unchecked
Sendable
{
static
let
shared
=
PhotoSimilarManager
()
...
...
@@ -198,7 +198,6 @@ class PhotoSimilarManager: @unchecked Sendable {
}
else
{
assetSize
=
0
}
let
model
=
AssetModel
(
localIdentifier
:
asset
.
localIdentifier
,
assetSize
:
assetSize
,
...
...
PhoneManager/Class/Manager/PMPhotoManager/ScreenShotSimilarManager.swift
View file @
63c05ef8
...
...
@@ -9,7 +9,7 @@ import Foundation
import
Photos
import
UIKit
@MainActor
class
ScreenshotSimilarJSONManager
:
@unchecked
Sendable
{
static
let
shared
=
ScreenshotSimilarJSONManager
()
...
...
PhoneManager/Class/Manager/PMPhotoManager/VideoSimilarManager.swift
View file @
63c05ef8
...
...
@@ -44,7 +44,7 @@ private actor VideoAssetCacheManager {
}
@MainActor
class
VideoSimilarJSONManager
:
@unchecked
Sendable
{
static
let
shared
=
VideoSimilarJSONManager
()
private
let
stateManager
=
VideoSimilarStateManager
()
...
...
PhoneManager/Class/Page/Home/View/HomeCollectionViewHeader.swift
View file @
63c05ef8
...
...
@@ -162,6 +162,9 @@ class CustomProgressBar: UIView {
var
chaoticProgress
:
CGFloat
=
0
{
didSet
{
guard
chaoticProgress
!=
oldValue
else
{
return
}
scheduleProgressUpdate
()
}
}
...
...
@@ -240,7 +243,7 @@ class CustomProgressBar: UIView {
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
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 {
// var model:PhotosManagerModel?
var
viewModel
:
HomeViewModel
?
// var viewModel:HomeviewModel
private
var
viewModel
=
HomeViewModel
.
shared
var
attribet
:
NSAttributedString
?
...
...
@@ -73,41 +74,51 @@ class HomeView:UIView {
override
init
(
frame
:
CGRect
)
{
super
.
init
(
frame
:
frame
)
viewModel
=
HomeViewModel
()
//
viewModel = HomeViewModel()
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
}
DispatchQueue
.
main
.
async
{
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
)
}
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
)
}
weakSelf
.
homeHeader
?
.
progressBar
.
chaoticProgress
=
CGFloat
(
weakSelf
.
viewModel
?
.
totalSize
??
0
)
weakSelf
.
homeHeader
?
.
progressBar
.
chaoticProgress
=
CGFloat
(
weakSelf
.
viewModel
.
totalSize
)
weakSelf
.
reloadHeadSize
()
}
viewModel
?
.
coverHadChange
=
{
[
weak
self
]
in
}
viewModel
.
reloadCellHeight
=
{[
weak
self
]
in
guard
let
weakSelf
=
self
else
{
return
}
print
(
"刷新一次封面"
)
DispatchQueue
.
main
.
async
{
weakSelf
.
collectionView
.
reloadData
()
}
}
// viewModel.coverHadChange = { [weak self] in
// guard let weakSelf = self else { return }
// print("刷新一次封面")
// weakSelf.collectionView.reloadData()
// }
collectionView
.
reloadData
()
}
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
}
...
...
@@ -230,10 +241,10 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
switch
section
{
case
0
:
return
viewModel
?
.
headerGroup
.
count
??
0
// model?.titleModelArray.count ?? 0
return
viewModel
.
headerGroup
.
count
// model?.titleModelArray.count ?? 0
case
1
:
return
viewModel
?
.
cardGroup
.
count
??
0
//model?.otherModelArray.count ?? 0
return
viewModel
.
cardGroup
.
count
//model?.otherModelArray.count ?? 0
default
:
return
0
...
...
@@ -248,7 +259,7 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
switch
section
{
case
0
:
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.reloadCoverData()
cell
.
homeTititlAction
=
{[
weak
self
]
idx
in
...
...
@@ -259,14 +270,14 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
self
.
titleCallBack
(
model
,
.
similar
)
}
}
cell
.
reloadCoverData
(
viewModel
?
.
headCoverImages
[
indexPath
.
row
]
??
[])
if
indexPath
.
row
==
0
{
self
.
dupHeadCell
=
cell
// cell.reloadCoverData(viewModel?
.dupCoverImage ?? [])
}
else
{
// cell.reloadCoverData(viewModel?
.similarCoverImage ?? [])
self
.
similarHeadCell
=
cell
}
// cell.reloadCoverData(viewModel
.headCoverImages[indexPath.row] ?? [])
//
if indexPath.row == 0 {
//
self.dupHeadCell = cell
// // cell.reloadCoverData(viewModel
.dupCoverImage ?? [])
//
}else{
// // cell.reloadCoverData(viewModel
.similarCoverImage ?? [])
//
self.similarHeadCell = cell
//
}
if
cell
.
model
?
.
assets
.
count
??
0
>
0
{
cell
.
fileLabel
?
.
isHidden
=
false
...
...
@@ -278,15 +289,15 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
case
1
:
let
cell
=
collectionView
.
dequeueReusableCell
(
withReuseIdentifier
:
HomeOtherCollectionCell
.
identifier
,
for
:
indexPath
)
as!
HomeOtherCollectionCell
cell
.
dealMediaType
(
indexPath
.
row
)
let
model
=
viewModel
?
.
cardGroup
[
indexPath
.
row
]
let
model
=
viewModel
.
cardGroup
[
indexPath
.
row
]
cell
.
reloadUIWithModel
(
model
:
model
)
Task
{
if
let
image
=
await
viewModel
?
.
coverCache
.
getImage
(
index
:
indexPath
.
row
)
{
await
MainActor
.
run
{
cell
.
setCoverImageOrVideo
(
image
:
image
)
}
}
}
//
Task {
// if let image = await viewModel
.coverCache.getImage(index: indexPath.row) {
//
await MainActor.run {
//
cell.setCoverImageOrVideo(image: image)
//
}
//
}
//
}
return
cell
default
:
return
UICollectionViewCell
()
...
...
@@ -298,10 +309,10 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
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
{
return
(
model
?
.
assets
.
first
?
.
count
??
0
)
>
2
?
((
collection
.
width
-
marginLR
-
20
)
/
2.5
)
+
64
:
((
collection
.
width
-
2
*
marginLR
-
10
)
/
2
)
+
64
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
}
else
{
return
52
...
...
@@ -310,9 +321,9 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
}
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
func
collectionView
(
_
collectionView
:
UICollectionView
,
didSelectItemAt
indexPath
:
IndexPath
)
{
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
{
titleCallBack
(
smodel
,
.
duplicates
)
}
else
{
...
...
@@ -368,8 +379,8 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
}
}
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
)
}
}
...
...
@@ -385,8 +396,8 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
}
header
.
cleanNowButtonCallback
=
{[
weak
self
]
in
guard
let
self
=
self
else
{
return
}
let
smodel
=
self
.
viewModel
?
.
headerGroup
[
0
]
//self.model?.titleModelArray
[0]
let
vc
=
HomeInfoViewController
(
ids
:
smodel
!.
assets
,
type
:
.
duplicates
,
titleText
:
smodel
!
.
folderName
)
let
smodel
=
self
.
viewModel
.
headerGroup
[
0
]
let
vc
=
HomeInfoViewController
(
ids
:
smodel
.
assets
,
type
:
.
duplicates
,
titleText
:
smodel
.
folderName
)
self
.
responderViewController
()?
.
navigationController
?
.
pushViewController
(
vc
,
animated
:
true
)
}
if
indexPath
.
section
!=
0
{
...
...
PhoneManager/Class/Page/Home/View/cell/HomeOtherCollectionCell.swift
View file @
63c05ef8
...
...
@@ -281,6 +281,14 @@ class HomeOtherCollectionCell: UICollectionViewCell {
}
else
{
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 {
fileLabel
?
.
text
=
"
\(
count
)
"
+
" Photos "
+
(
model
.
allFileSize
>
0
?
"(
\(
formatFileSize
(
model
.
allFileSize
)
)
)"
:
"(Calculating...)"
)
fileLabel
?
.
sizeToFit
()
collectionView
?
.
reloadData
()
}
func
reloadCoverData
(
_
assets
:[
AssetModel
]){
assetsModels
.
removeAll
()
if
let
assets
=
model
.
assets
.
first
{
assetsModels
=
assets
.
compactMap
({
model
in
return
ImageCollectionModel
.
init
(
asset
:
model
)
})
Print
(
"刷新头部封面
\(
self
)
"
,
assets
.
count
)
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
()
{
super
.
layoutSubviews
()
...
...
PhoneManager/Class/Page/Home/View/cell/ImageCollectionCell.swift
View file @
63c05ef8
...
...
@@ -48,8 +48,6 @@ class ImageCollectionCell:UICollectionViewCell {
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
class
HomeViewModel
{
// 封面图片资源缓存
actor
CoverCacheActor
{
private
var
cardCoverImage
:[
UIImage
?]
=
[
UIImage
.
init
(
named
:
"videosmoren"
),
UIImage
.
init
(
named
:
"photosmoren"
),
UIImage
.
init
(
named
:
"photosmoren"
),
UIImage
.
init
(
named
:
"videosmoren"
),
UIImage
.
init
(
named
:
"othermoren"
)
]
static
let
shared
=
HomeViewModel
()
func
getImage
(
index
:
Int
)
->
UIImage
?{
return
cardCoverImage
.
safeGet
(
index
:
index
)
??
nil
}
private
init
(){}
func
config
(){}
func
setImage
(
index
:
Int
,
image
:
UIImage
?)
{
guard
let
image
=
image
else
{
return
}
if
cardCoverImage
.
count
>
index
{
cardCoverImage
[
index
]
=
image
}
}
}
let
trash
=
TrashDatabase
.
shared
.
queryAll
()
.
compactMap
{
$0
.
localIdentifier
}
let
keep
=
GroupDatabase
.
shared
.
queryAll
()
.
compactMap
{
$0
.
localIdentifier
}
// 封面图片资源缓存
// actor CoverCacheActor {
//
// private var cardCoverImage:[UIImage?] = [
// UIImage.init(named: "videosmoren"),
// UIImage.init(named: "photosmoren"),
// UIImage.init(named: "photosmoren"),
// UIImage.init(named: "videosmoren"),
// UIImage.init(named: "othermoren")
// ]
//
// 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
let
coverCache
=
CoverCacheActor
()
//
let coverCache = CoverCacheActor()
// 相册资源总大小
var
totalSize
:
Int64
{
return
videoSize
+
otherSize
+
screentSize
return
photoManager
.
videoTotalSize
+
photoManager
.
otherTotalSize
+
photoManager
.
screenShotTotalSize
//
videoSize + otherSize + screentSize
}
var
videoSize
:
Int64
=
0
var
otherSize
:
Int64
=
0
var
screentSize
:
Int64
=
0
// var videoSize:Int64 = 0
// var otherSize:Int64 = 0
// var screentSize:Int64 = 0
var
totalFilesCount
:
Int
=
0
// 首页UI数据结构
var
headerGroup
:[
HomePhotosModel
]
=
[
HomePhotosModel
.
init
(
folderName
:
HomeUIEnum
.
Dublicates
.
title
,
allFileSize
:
0
,
assets
:
[]),
HomePhotosModel
.
init
(
folderName
:
HomeUIEnum
.
Similar
.
title
,
allFileSize
:
0
,
assets
:
[])
var
headerGroup
:[
HomePhotosModel
]{
return
[
HomePhotosModel
.
init
(
folderName
:
HomeUIEnum
.
Dublicates
.
title
,
allFileSize
:
getTotalSize
(
source
:
photoManager
.
duplicateModels
),
assets
:
photoManager
.
duplicateModels
),
HomePhotosModel
.
init
(
folderName
:
HomeUIEnum
.
Similar
.
title
,
allFileSize
:
getTotalSize
(
source
:
photoManager
.
filterSimilarModels
),
assets
:
photoManager
.
filterSimilarModels
)
]
var
cardGroup
:[
HomePhotosModel
]
=
[
HomePhotosModel
.
init
(
folderName
:
HomeUIEnum
.
Videos
.
title
,
allFileSize
:
0
,
assets
:
[]),
HomePhotosModel
.
init
(
folderName
:
HomeUIEnum
.
SimilarScreenshots
.
title
,
allFileSize
:
0
,
assets
:
[]),
HomePhotosModel
.
init
(
folderName
:
HomeUIEnum
.
Screensshots
.
title
,
allFileSize
:
0
,
assets
:
[]),
HomePhotosModel
.
init
(
folderName
:
HomeUIEnum
.
SimilarVideos
.
title
,
allFileSize
:
0
,
assets
:
[]),
HomePhotosModel
.
init
(
folderName
:
HomeUIEnum
.
Other
.
title
,
allFileSize
:
0
,
assets
:
[]),
}
// 首页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
homeDataChanged
:((
_
section
:
Int
,
_
row
:
Int
)
->
Void
)?
// 封面获取回调
var
coverHadChange
:(()
->
Void
)?
// 添加状态变化的回调闭包
var
onLoadingStateChanged
:
((
BaseDataLoadingState
)
->
Void
)?
var
reloadCellHeight
:(()
->
Void
)?
var
dupCoverImage
:[
AssetModel
]
=
[]
var
similarCoverImage
:[
AssetModel
]
=
[]
var
headCoverImages
:[[
AssetModel
]]{
return
[
dupCoverImage
,
similarCoverImage
]
}
//
var dupCoverImage:[AssetModel] = []
//
//
var similarCoverImage:[AssetModel] = []
//
//
var headCoverImages:[[AssetModel]]{
//
return [
//
dupCoverImage,
//
similarCoverImage
//
]
//
}
func
setupBindings
()
{
...
...
@@ -106,9 +143,11 @@ class HomeViewModel {
photoManager
.
convertScreenShotModels
{[
weak
self
]
screens
,
size
in
guard
let
weakSelf
=
self
else
{
return
}
let
type
=
HomeUIEnum
.
Screensshots
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.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
.
filterResource
()
weakSelf
.
homeDataChanged
?(
1
,
type
.
index
)
}
...
...
@@ -116,9 +155,10 @@ class HomeViewModel {
guard
let
weakSelf
=
self
else
{
return
}
let
type
=
HomeUIEnum
.
Other
weakSelf
.
cardGroup
[
type
.
index
]
=
HomePhotosModel
.
init
(
folderName
:
type
.
title
,
allFileSize
:
Double
(
size
),
assets
:
[
others
])
weakSelf
.
getCoverImage
(
type
:
type
,
identifier
:
others
.
first
?
.
localIdentifier
)
weakSelf
.
otherSize
=
size
// weakSelf.cardGroup[type.index] = HomePhotosModel.init(folderName: type.title, allFileSize: Double(size), assets: [others])
// weakSelf.getCoverImage(type: type, identifier: others.first?.localIdentifier)
// weakSelf.otherSize = size
weakSelf
.
filterResource
()
weakSelf
.
homeDataChanged
?(
1
,
type
.
index
)
}
...
...
@@ -126,9 +166,10 @@ class HomeViewModel {
guard
let
weakSelf
=
self
else
{
return
}
let
type
=
HomeUIEnum
.
Videos
weakSelf
.
cardGroup
[
type
.
index
]
=
HomePhotosModel
.
init
(
folderName
:
type
.
title
,
allFileSize
:
Double
(
size
),
assets
:
[
videos
])
weakSelf
.
getCoverImage
(
type
:
type
,
identifier
:
videos
.
first
?
.
localIdentifier
)
weakSelf
.
videoSize
=
size
// weakSelf.cardGroup[type.index] = HomePhotosModel.init(folderName: type.title, allFileSize: Double(size), assets: [videos])
// weakSelf.getCoverImage(type: type, identifier: videos.first?.localIdentifier)
// weakSelf.videoSize = size
weakSelf
.
filterResource
()
weakSelf
.
homeDataChanged
?(
1
,
type
.
index
)
}
startMainTask
()
...
...
@@ -136,39 +177,51 @@ class HomeViewModel {
func
startMainTask
(){
DispatchQueue
.
main
.
async
{[
weak
self
]
in
guard
let
weakSelf
=
self
else
{
return
}
weakSelf
.
getSimilarOptimizer
()
weakSelf
.
getSimilarScreenOptimizer
()
weakSelf
.
getSimilarVideoOptimizer
()
weakSelf
.
getGroupDuplicateImages
()
}
getSimilarOptimizer
()
getSimilarScreenOptimizer
()
getSimilarVideoOptimizer
()
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
var
currentGorup
:[[
AssetModel
]]
=
[]
var
currentSize
:
Double
=
0
var
firstId
:
String
?
// var currentGorup:[[AssetModel]] = []
// var currentSize:Double = 0
// var firstId:String?
var
hadblock
=
false
PhotoSimilarManager
.
shared
.
findSimilarAssets
(
in
:
photoManager
.
otherAssets
)
{[
weak
self
]
group
in
guard
let
weakSelf
=
self
else
{
return
}
currentGorup
.
append
(
group
)
currentSize
+=
group
.
reduce
(
0
){
$0
+
$1
.
assetSize
}
//
currentGorup.append(group)
//
currentSize += group.reduce(0){$0+$1.assetSize}
// weakSelf.totalSize += Int64(currentSize)
weakSelf
.
headerGroup
[
type
.
index
]
.
assets
=
currentGorup
weakSelf
.
headerGroup
[
type
.
index
]
.
allFileSize
=
currentSize
if
let
id
=
currentGorup
.
first
?
.
first
?
.
localIdentifier
{
if
firstId
!=
id
{
firstId
=
id
weakSelf
.
similarCoverImage
=
group
weakSelf
.
coverHadChange
?()
// weakSelf.headerGroup[type.index].assets = currentGorup
// weakSelf.headerGroup[type.index].allFileSize = currentSize
weakSelf
.
photoManager
.
similarModels
.
append
(
group
)
// if let id = weakSelf.photoManager.similarModels.first?.first?.localIdentifier{
// if firstId != id{
// firstId = id
// weakSelf.similarCoverImage = group
// weakSelf.coverHadChange?()
// }
// }
if
!
hadblock
{
weakSelf
.
reloadCellHeight
?()
hadblock
=
true
}
}
weakSelf
.
homeDataChanged
?(
0
,
type
.
index
)
...
...
@@ -176,145 +229,218 @@ class HomeViewModel {
guard
let
weakSelf
=
self
else
{
return
}
print
(
"获取相似图片完成"
,
totalGroup
.
count
)
weakSelf
.
photoManager
.
similarModels
=
totalGroup
weakSelf
.
filterResource
()
weakSelf
.
homeDataChanged
?(
0
,
type
.
index
)
}
}
// 获取相似截图
@MainActor
func
getSimilarScreenOptimizer
(){
func
getSimilarScreenOptimizer
(){
let
type
=
HomeUIEnum
.
SimilarScreenshots
var
currentGorup
:[[
AssetModel
]]
=
[]
var
currentSize
:
Double
=
0
var
firstId
:
String
?
//
var currentGorup:[[AssetModel]] = []
//
var currentSize:Double = 0
//
var firstId:String?
ScreenshotSimilarJSONManager
.
shared
.
findSimilarAssets
(
in
:
photoManager
.
screenShotAssets
)
{[
weak
self
]
group
in
guard
let
weakSelf
=
self
else
{
return
}
currentGorup
.
append
(
group
)
currentSize
+=
group
.
reduce
(
0
){
$0
+
$1
.
assetSize
}
//
currentGorup.append(group)
//
currentSize += group.reduce(0){$0+$1.assetSize}
// weakSelf.totalSize += Int64(currentSize)
weakSelf
.
cardGroup
[
type
.
index
]
.
assets
=
currentGorup
weakSelf
.
cardGroup
[
type
.
index
]
.
allFileSize
=
currentSize
if
let
id
=
currentGorup
.
first
?
.
first
?
.
localIdentifier
{
if
firstId
!=
id
{
firstId
=
id
weakSelf
.
getCoverImage
(
type
:
type
,
identifier
:
firstId
)
}
}
//
weakSelf.cardGroup[type.index].assets = currentGorup
//
weakSelf.cardGroup[type.index].allFileSize = currentSize
//
//
if let id = currentGorup.first?.first?.localIdentifier{
//
if firstId != id{
//
firstId = id
//
weakSelf.getCoverImage(type: type, identifier: firstId)
//
}
//
}
weakSelf
.
photoManager
.
similarScreenShotModels
.
append
(
group
)
weakSelf
.
homeDataChanged
?(
1
,
type
.
index
)
}
completionHandler
:
{[
weak
self
]
totalGroup
in
guard
let
weakSelf
=
self
else
{
return
}
print
(
"获取相似截图完成"
,
totalGroup
.
count
)
weakSelf
.
filterResource
()
weakSelf
.
photoManager
.
similarScreenShotModels
=
totalGroup
}
}
@MainActor
func
getSimilarVideoOptimizer
(){
func
getSimilarVideoOptimizer
(){
let
type
=
HomeUIEnum
.
SimilarVideos
var
currentGorup
:[[
AssetModel
]]
=
[]
var
currentSize
:
Double
=
0
var
firstId
:
String
?
//
var currentGorup:[[AssetModel]] = []
//
var currentSize:Double = 0
//
var firstId:String?
VideoSimilarJSONManager
.
shared
.
findSimilarVideos
(
in
:
photoManager
.
videoAssets
)
{[
weak
self
]
group
in
guard
let
weakSelf
=
self
else
{
return
}
currentGorup
.
append
(
group
)
currentSize
+=
group
.
reduce
(
0
){
$0
+
$1
.
assetSize
}
weakSelf
.
cardGroup
[
type
.
index
]
.
assets
=
currentGorup
weakSelf
.
cardGroup
[
type
.
index
]
.
allFileSize
=
currentSize
if
let
id
=
currentGorup
.
first
?
.
first
?
.
localIdentifier
{
if
firstId
!=
id
{
firstId
=
id
weakSelf
.
getCoverImage
(
type
:
type
,
identifier
:
firstId
)
}
}
// currentGorup.append(group)
// currentSize += group.reduce(0){$0+$1.assetSize}
//
// weakSelf.cardGroup[type.index].assets = currentGorup
// weakSelf.cardGroup[type.index].allFileSize = currentSize
//
// if let id = currentGorup.first?.first?.localIdentifier{
// if firstId != id{
// firstId = id
// weakSelf.getCoverImage(type: type, identifier: firstId)
// }
// }
weakSelf
.
photoManager
.
similarVideoModels
.
append
(
group
)
weakSelf
.
homeDataChanged
?(
1
,
type
.
index
)
}
completionHandler
:
{[
weak
self
]
totalGroup
in
print
(
"获取相似视频完成"
,
totalGroup
.
count
)
guard
let
weakSelf
=
self
else
{
return
}
weakSelf
.
filterResource
()
weakSelf
.
photoManager
.
similarVideoModels
=
totalGroup
}
}
// 获取重复图片
@MainActor
func
getGroupDuplicateImages
(){
func
getGroupDuplicateImages
(){
let
type
=
HomeUIEnum
.
Dublicates
var
currentGorup
:[[
AssetModel
]]
=
[]
var
currentSize
:
Double
=
0
var
firstId
:
String
?
// var currentGorup:[[AssetModel]] = []
// var currentSize:Double = 0
// var firstId:String?
PhotoDuplicateManager
.
shared
.
findDuplicateAssets
(
in
:
photoManager
.
otherAssets
,
mediaType
:
.
photo
)
{[
weak
self
]
groups
in
guard
let
weakSelf
=
self
else
{
return
}
// let size = groups.map{$0}.reduce(into: 0){$0+$1.assetSize}
weakSelf
.
headerGroup
[
type
.
index
]
.
assets
=
groups
weakSelf
.
headerGroup
[
type
.
index
]
.
allFileSize
=
currentSize
// weakSelf.headerGroup[type.index].assets = groups
// weakSelf.headerGroup[type.index].allFileSize = currentSize
weakSelf
.
photoManager
.
duplicateModels
=
groups
// 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
)
}
progressHandler
:
{
group
in
// guard let weakSelf = self else { return }
// currentGorup.append(group)
// currentSize += group.reduce(0){$0+$1.assetSize}
//
// weakSelf.headerGroup[type.index].assets = currentGorup
// weakSelf.headerGroup[type.index].allFileSize = currentSize
// weakSelf.photoManager.duplicateModels = groups
// 从 group 中过滤掉存在于 duplicateModels 中的元素
// 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)
if
let
id
=
groups
.
first
?
.
first
?
.
localIdentifier
{
if
firstId
!=
id
{
firstId
=
id
weakSelf
.
dupCoverImage
=
groups
.
first
??
[]
weakSelf
.
coverHadChange
?()
}
completionHandler
:
{[
weak
self
]
totalGroup
in
guard
let
weakSelf
=
self
else
{
return
}
print
(
"获得重复图片完成"
,
totalGroup
.
count
)
let
currentThread
=
Thread
.
current
if
currentThread
.
isMainThread
{
print
(
"在主线程执行"
)
}
else
{
print
(
"在后台线程执行"
)
}
weakSelf
.
photoManager
.
duplicateModels
=
totalGroup
weakSelf
.
reloadCellHeight
?()
weakSelf
.
homeDataChanged
?(
0
,
type
.
index
)
}
}
weakSelf
.
homeDataChanged
?(
0
,
type
.
index
)
// func getCoverImage(type:HomeUIEnum,identifier:String?){
// guard let identifier = identifier else{
// return
// }
// print("执行一次\(type.title)获取封面,id=\(identifier)")
// Task {
// PhotoManager.shared.getImage(localIdentifier:identifier,completion: { [weak self] image in
// guard let self = self else { return }
// Task {
// switch type {
// case .Dublicates:
// break
// case .Similar:
// break
// default:
// await self.coverCache.setImage(index: type.index, image: image)
// await MainActor.run {
// self.coverHadChange?()
// }
// }
// }
// })
// }
// }
}
progressHandler
:
{[
weak
self
]
group
in
guard
let
weakSelf
=
self
else
{
return
}
}
currentGorup
.
append
(
group
)
currentSize
+=
group
.
reduce
(
0
){
$0
+
$1
.
assetSize
}
extension
HomeViewModel
{
weakSelf
.
headerGroup
[
type
.
index
]
.
assets
=
currentGorup
weakSelf
.
headerGroup
[
type
.
index
]
.
allFileSize
=
currentSize
if
let
id
=
currentGorup
.
first
?
.
first
?
.
localIdentifier
{
if
firstId
!=
id
{
firstId
=
id
weakSelf
.
dupCoverImage
=
group
weakSelf
.
coverHadChange
?()
}
}
// 基本资源过滤保留和垃圾桶资源
func
filterResource
(){
weakSelf
.
homeDataChanged
?(
0
,
type
.
index
)
let
filterArray
=
trash
+
keep
}
completionHandler
:
{[
weak
self
]
totalGroup
in
guard
let
weakSelf
=
self
else
{
return
}
weakSelf
.
photoManager
.
duplicateModels
=
totalGroup
}
}
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
getCoverImage
(
type
:
HomeUIEnum
,
identifier
:
String
?){
guard
let
identifier
=
identifier
else
{
return
}
print
(
"执行一次
\(
type
.
title
)
获取封面,id=
\(
identifier
)
"
)
Task
{
PhotoManager
.
shared
.
getImage
(
localIdentifier
:
identifier
,
completion
:
{
[
weak
self
]
image
in
guard
let
self
=
self
else
{
return
}
Task
{
switch
type
{
case
.
Dublicates
:
break
case
.
Similar
:
break
default
:
await
self
.
coverCache
.
setImage
(
index
:
type
.
index
,
image
:
image
)
await
MainActor
.
run
{
self
.
coverHadChange
?()
}
}
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