Commit ed1cc5a8 authored by yqz's avatar yqz

Merge branch 'dev_main' into yQz0507

* dev_main:
  优化保留 和首页
  【优化】垃圾桶逻辑优化
  app内资源删除

# Conflicts:
#	PhoneManager/Class/Page/Home/Controller/PhotoRemoveViewController.swift
parents 92491362 6a947483
...@@ -69,137 +69,16 @@ actor PhotoSimilarStateManager { ...@@ -69,137 +69,16 @@ actor PhotoSimilarStateManager {
self.timeGroups = timeGroups self.timeGroups = timeGroups
self.similarGroups = similarGroups self.similarGroups = similarGroups
} }
}
// 截图状态管理 actor
actor ScreenshotSimilarStateManager {
private var timeGroups: [TimeGroupModel] = []
private var similarGroups: [SimilarGroupModel] = []
private var pendingSimilarGroups: [SimilarGroupModel] = []
private var processedGroupCount: Int = 0
private var assetsImageCache: [String: UIImage] = [:]
private var hashCache: [String: String] = [:]
func appendTimeGroup(_ group: TimeGroupModel) {
timeGroups.append(group)
}
func appendSimilarGroup(_ group: SimilarGroupModel) {
pendingSimilarGroups.append(group)
processedGroupCount += 1
}
func getAllTimeGroups() -> [TimeGroupModel] {
return timeGroups
}
func getpendingSimilarGroups() -> [SimilarGroupModel] {
return pendingSimilarGroups
}
func getAllSimilarGroups() -> [SimilarGroupModel] {
return similarGroups
}
func getCachedImage(for identifier: String) -> UIImage? {
return assetsImageCache[identifier]
}
func setCachedImage(_ image: UIImage, for identifier: String) {
assetsImageCache[identifier] = image
}
func shouldSavePendingGroups() -> Bool {
return processedGroupCount >= 10
}
func getCachedHash(for identifier: String) async -> String? {
return hashCache[identifier]
}
func setCachedHash(_ hash: String, for identifier: String) async {
hashCache[identifier] = hash
}
func savePendingGroups() {
similarGroups.append(contentsOf: pendingSimilarGroups)
pendingSimilarGroups.removeAll()
processedGroupCount = 0
}
func loadStoredData(timeGroups: [TimeGroupModel], similarGroups: [SimilarGroupModel]) {
self.timeGroups = timeGroups
self.similarGroups = similarGroups
}
}
// 视频状态管理 actor
actor VideoSimilarStateManager {
private var timeGroups: [TimeGroupModel] = []
private var similarGroups: [SimilarGroupModel] = []
private var pendingSimilarGroups: [SimilarGroupModel] = []
private var processedGroupCount: Int = 0
private var assetsImageCache: [String: UIImage] = [:]
private var hashCache: [String: String] = [:]
func appendTimeGroup(_ group: TimeGroupModel) {
timeGroups.append(group)
}
func appendSimilarGroup(_ group: SimilarGroupModel) { func deleteData(for idsToRemove:[String]){
pendingSimilarGroups.append(group) let updateGroups = self.similarGroups.removingGroupsWithEmptyAssetsWithDetails(afterRemovingIDs: idsToRemove)
processedGroupCount += 1 self.similarGroups = updateGroups.updatedGroups
}
func getAllTimeGroups() -> [TimeGroupModel] {
return timeGroups
}
func getpendingSimilarGroups() -> [SimilarGroupModel] {
return pendingSimilarGroups
}
func getAllSimilarGroups() -> [SimilarGroupModel] {
return similarGroups
}
func getCachedImage(for identifier: String) -> UIImage? {
return assetsImageCache[identifier]
}
func setCachedImage(_ image: UIImage, for identifier: String) {
assetsImageCache[identifier] = image
}
func shouldSavePendingGroups() -> Bool {
return processedGroupCount >= 10
}
func getCachedHash(for identifier: String) async -> String? {
return hashCache[identifier]
}
func setCachedHash(_ hash: String, for identifier: String) async {
hashCache[identifier] = hash
}
func savePendingGroups() {
similarGroups.append(contentsOf: pendingSimilarGroups)
pendingSimilarGroups.removeAll()
processedGroupCount = 0
}
func loadStoredData(timeGroups: [TimeGroupModel], similarGroups: [SimilarGroupModel]) {
self.timeGroups = timeGroups
self.similarGroups = similarGroups
} }
} }
actor PhotoDuplicateStateManager { actor PhotoDuplicateStateManager {
private var duplicateGroups: [DuplicateGroupModel] = [] private var duplicateGroups: [SimilarGroupModel] = []
private var pendingDuplicateGroups: [DuplicateGroupModel] = [] private var pendingDuplicateGroups: [SimilarGroupModel] = []
// 缓存 // 缓存
private var imageCache: [String: UIImage] = [:] private var imageCache: [String: UIImage] = [:]
...@@ -207,15 +86,15 @@ actor PhotoDuplicateStateManager { ...@@ -207,15 +86,15 @@ actor PhotoDuplicateStateManager {
// MARK: - 公共方法 // MARK: - 公共方法
func loadStoredData(duplicateGroups: [DuplicateGroupModel]) { func loadStoredData(duplicateGroups: [SimilarGroupModel]) {
self.duplicateGroups = duplicateGroups self.duplicateGroups = duplicateGroups
} }
func getAllDuplicateGroups() -> [DuplicateGroupModel] { func getAllDuplicateGroups() -> [SimilarGroupModel] {
return duplicateGroups return duplicateGroups
} }
func appendDuplicateGroup(_ group: DuplicateGroupModel) { func appendDuplicateGroup(_ group: SimilarGroupModel) {
pendingDuplicateGroups.append(group) pendingDuplicateGroups.append(group)
} }
...@@ -228,7 +107,7 @@ actor PhotoDuplicateStateManager { ...@@ -228,7 +107,7 @@ actor PhotoDuplicateStateManager {
pendingDuplicateGroups.removeAll() pendingDuplicateGroups.removeAll()
} }
func getPendingDuplicateGroups() -> [DuplicateGroupModel] { func getPendingDuplicateGroups() -> [SimilarGroupModel] {
return pendingDuplicateGroups return pendingDuplicateGroups
} }
...@@ -253,5 +132,10 @@ actor PhotoDuplicateStateManager { ...@@ -253,5 +132,10 @@ actor PhotoDuplicateStateManager {
func setCachedHash(_ hash: String, for identifier: String) { func setCachedHash(_ hash: String, for identifier: String) {
hashCache[identifier] = hash hashCache[identifier] = hash
} }
func deleteData(for idsToRemove:[String]){
let updateGroups = self.duplicateGroups.removingGroupsWithEmptyAssetsWithDetails(afterRemovingIDs: idsToRemove)
self.duplicateGroups = updateGroups.updatedGroups
}
} }
...@@ -49,7 +49,7 @@ class PhotoDuplicateManager: @unchecked Sendable { ...@@ -49,7 +49,7 @@ class PhotoDuplicateManager: @unchecked Sendable {
print("本地数据加载完成") print("本地数据加载完成")
// 2. 通知已缓存的结果 // 2. 通知已缓存的结果
let cachedGroups = await stateManager.getAllDuplicateGroups() let cachedGroups = await loadSimilarGroups() //stateManager.getAllDuplicateGroups()
print("通知已缓存的结果", cachedGroups.count) print("通知已缓存的结果", cachedGroups.count)
await MainActor.run { await MainActor.run {
let groups = cachedGroups.map{$0.assets} let groups = cachedGroups.map{$0.assets}
...@@ -126,7 +126,7 @@ class PhotoDuplicateManager: @unchecked Sendable { ...@@ -126,7 +126,7 @@ class PhotoDuplicateManager: @unchecked Sendable {
// 保存重复组 // 保存重复组
await self.stateManager.appendDuplicateGroup( await self.stateManager.appendDuplicateGroup(
DuplicateGroupModel(groupId: groupId, assets: assetModels) SimilarGroupModel(groupId: groupId, assets: assetModels)
) )
if await self.stateManager.shouldSavePendingGroups() { if await self.stateManager.shouldSavePendingGroups() {
...@@ -143,7 +143,7 @@ class PhotoDuplicateManager: @unchecked Sendable { ...@@ -143,7 +143,7 @@ class PhotoDuplicateManager: @unchecked Sendable {
await self.savePendingDuplicateGroups() await self.savePendingDuplicateGroups()
} }
let allGroups = await stateManager.getAllDuplicateGroups() let allGroups = await loadSimilarGroups() //stateManager.getAllDuplicateGroups()
await MainActor.run { await MainActor.run {
print("执行完毕") print("执行完毕")
completionHandler?(allGroups.map { $0.assets }) completionHandler?(allGroups.map { $0.assets })
...@@ -151,196 +151,7 @@ class PhotoDuplicateManager: @unchecked Sendable { ...@@ -151,196 +151,7 @@ class PhotoDuplicateManager: @unchecked Sendable {
} }
} }
// 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([]) // 返回空数组或错误处理
// }
// }
// }
// }
// 按特征分组(分辨率、文件大小等)
// 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 {
// 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 { func getAssetSize(asset: PHAsset) async -> Int64 {
// 先尝试从缓存获取 // 先尝试从缓存获取
if let cachedSize = await AssetSizeCache.shared.getSize(for: asset) { if let cachedSize = await AssetSizeCache.shared.getSize(for: asset) {
...@@ -386,10 +197,10 @@ class PhotoDuplicateManager: @unchecked Sendable { ...@@ -386,10 +197,10 @@ class PhotoDuplicateManager: @unchecked Sendable {
extension PhotoDuplicateManager { extension PhotoDuplicateManager {
private func loadStoredData() async { private func loadStoredData() async {
var loadedDuplicateGroups: [DuplicateGroupModel] = [] var loadedDuplicateGroups: [SimilarGroupModel] = []
if let data = try? Data(contentsOf: URL(fileURLWithPath: duplicateGroupsPath)), if let data = try? Data(contentsOf: URL(fileURLWithPath: duplicateGroupsPath)),
let groups = try? JSONDecoder().decode([DuplicateGroupModel].self, from: data) { let groups = try? JSONDecoder().decode([SimilarGroupModel].self, from: data) {
loadedDuplicateGroups = groups loadedDuplicateGroups = groups
} }
...@@ -398,10 +209,33 @@ extension PhotoDuplicateManager { ...@@ -398,10 +209,33 @@ extension PhotoDuplicateManager {
private func savePendingDuplicateGroups() async { private func savePendingDuplicateGroups() async {
await stateManager.savePendingGroups() await stateManager.savePendingGroups()
if let data = try? JSONEncoder().encode(await stateManager.getAllDuplicateGroups()) { if let data = try? JSONEncoder().encode(await loadSimilarGroups()) {
try? data.write(to: URL(fileURLWithPath: duplicateGroupsPath)) try? data.write(to: URL(fileURLWithPath: duplicateGroupsPath))
} }
} }
private func loadSimilarGroups() async -> [SimilarGroupModel] {
let groups = await stateManager.getAllDuplicateGroups()
// 验证资源有效性
return groups.map { group in
var validAssets = group.assets
validAssets.removeAll { asset in
let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: [asset.localIdentifier], options: nil)
return fetchResult.firstObject == nil
}
return SimilarGroupModel(groupId: group.groupId, assets: validAssets)
}.filter { !$0.assets.isEmpty }
}
// 移除本地文件资源
func removeLocalFileWithIds(for ids:[String]) async{
await stateManager.deleteData(for: ids)
// 保存到文件
if let data = try? JSONEncoder().encode(await loadSimilarGroups()) {
try? data.write(to: URL(fileURLWithPath: duplicateGroupsPath))
}
}
} }
// MARK: - Hash计算相关方法 // MARK: - Hash计算相关方法
...@@ -472,45 +306,6 @@ extension PhotoDuplicateManager { ...@@ -472,45 +306,6 @@ extension PhotoDuplicateManager {
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
//
// }
} }
......
...@@ -113,6 +113,11 @@ class PhotoManager{ ...@@ -113,6 +113,11 @@ class PhotoManager{
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
var trash = TrashDatabase.shared.queryAll().compactMap{$0.localIdentifier}
var keep = GroupDatabase.shared.queryAll().compactMap{$0.localIdentifier}
private var currentPage: Int = 0 private var currentPage: Int = 0
private let pageSize: Int = 50 // 每次加载的数量 private let pageSize: Int = 50 // 每次加载的数量
...@@ -702,24 +707,45 @@ extension PhotoManager{ ...@@ -702,24 +707,45 @@ extension PhotoManager{
extension PhotoManager{ extension PhotoManager{
// 处理app图片删除 // 处理app图片删除
func removeDataWhenDeleteInPage(data:[AssetModel]){ func removeDataWhenDeleteInPage(data:[AssetModel],completionHandler: (() -> Void)? = nil){
let deletes = data.compactMap{$0.localIdentifier}
let others = removeAssets(withIdentifiers: deletes, from: otherModels) Task.detached(priority: .background) { [weak self] in
let videos = removeAssets(withIdentifiers: deletes, from: videoModels) guard let self = self else { return }
let screens = removeAssets(withIdentifiers: deletes, from: screenShotModels)
let deletes = data.compactMap{$0.localIdentifier}
otherModels = others
videoModels = videos // 临时数据更新
screenShotModels = screens let others = removeAssets(withIdentifiers: deletes, from: otherModels)
let videos = removeAssets(withIdentifiers: deletes, from: videoModels)
// 保存到本地 let screens = removeAssets(withIdentifiers: deletes, from: screenShotModels)
saveToLocal(type: "video", models: self.videoModels)
saveToLocal(type: "other", models: self.otherModels) otherModels = others
saveToLocal(type: "screenshot", models: self.screenShotModels) videoModels = videos
screenShotModels = screens
// 临时数据更新
let similarPhotos = filterGroups(similarModels, byExcludingIDs: deletes)
let similarVideos = filterGroups(similarVideoModels, byExcludingIDs: deletes)
let similarShots = filterGroups(similarScreenShotModels, byExcludingIDs: deletes)
let duplicates = filterGroups(duplicateModels, byExcludingIDs: deletes)
similarModels = similarPhotos
similarVideoModels = similarVideos
similarScreenShotModels = similarShots
duplicateModels = duplicates
// 保存到本地
saveToLocal(type: "video", models: self.videoModels)
saveToLocal(type: "other", models: self.otherModels)
saveToLocal(type: "screenshot", models: self.screenShotModels)
await PhotoSimilarManager.shared.removeLocalFileWithIds(for: deletes)
await ScreenshotSimilarJSONManager.shared.removeLocalFileWithIds(for: deletes)
await VideoSimilarJSONManager.shared.removeLocalFileWithIds(for: deletes)
await PhotoDuplicateManager.shared.removeLocalFileWithIds(for: deletes)
completionHandler?()
}
} }
...@@ -736,4 +762,35 @@ extension PhotoManager{ ...@@ -736,4 +762,35 @@ extension PhotoManager{
} }
} }
// 重写获取垃圾桶和保留刷新进行刷新
func reloadTrashAndKeep(){
trash = TrashDatabase.shared.queryAll().compactMap{$0.localIdentifier}
keep = GroupDatabase.shared.queryAll().compactMap{$0.localIdentifier}
filterResource()
}
// 基本资源过滤保留和垃圾桶资源
func filterResource(){
let filterArray = trash + keep
let others = removeAssets(withIdentifiers: filterArray, from: otherModels)
let videos = removeAssets(withIdentifiers: filterArray, from: videoModels)
let screens = removeAssets(withIdentifiers: filterArray, from: screenShotModels)
filterOtherModels = others
filterVideoModels = videos
filterScreenShotModels = screens
let similarPhotos = filterGroups(similarModels, byExcludingIDs: filterArray)
let similarVideos = filterGroups(similarVideoModels, byExcludingIDs: filterArray)
let similarShots = filterGroups(similarScreenShotModels, byExcludingIDs: filterArray)
filterSimilarModels = similarPhotos
filterSimilarVideoModels = similarVideos
filterSimilarScreenShotModels = similarShots
}
} }
...@@ -86,17 +86,18 @@ struct SimilarGroupModel: Codable { ...@@ -86,17 +86,18 @@ struct SimilarGroupModel: Codable {
var assets: [AssetModel] var assets: [AssetModel]
} }
// 重复图片组模型
struct DuplicateGroupModel: Codable {
let groupId: String
let assets: [AssetModel]
}
struct Match { struct Match {
let groupIndex: Int let groupIndex: Int
let matchedElements: [AssetModel] let matchedElements: [AssetModel]
} }
struct RemovalResult {
let updatedGroups: [SimilarGroupModel]
let removedAssets: [AssetModel]
let removedGroups: [SimilarGroupModel]
}
extension Sequence where Element == [AssetModel] { extension Sequence where Element == [AssetModel] {
/// 判断二维数组中是否包含某个子数组,其元素的localIdentifier集合与给定数组完全相同(忽略顺序) /// 判断二维数组中是否包含某个子数组,其元素的localIdentifier集合与给定数组完全相同(忽略顺序)
...@@ -124,3 +125,69 @@ extension Sequence where Element == [AssetModel] { ...@@ -124,3 +125,69 @@ extension Sequence where Element == [AssetModel] {
return matches return matches
} }
} }
extension SimilarGroupModel {
/// 过滤掉assets中包含指定ID的元素
func removingAssets(withIDs ids: Set<String>) -> SimilarGroupModel {
let filteredAssets = self.assets.filter { !ids.contains($0.localIdentifier) }
return SimilarGroupModel(groupId: self.groupId, assets: filteredAssets)
}
}
extension Array where Element == SimilarGroupModel {
/// 批量过滤所有组中的assets,移除包含指定ID的元素,并移除assets为空的组
func removingGroupsWithEmptyAssets(afterRemovingIDs ids: [String]) -> [SimilarGroupModel] {
let idSet = Set(ids)
return self.compactMap { group in
let filteredGroup = group.removingAssets(withIDs: idSet)
return filteredGroup.assets.isEmpty ? nil : filteredGroup
}
}
/// 原地修改:直接在原数组上移除包含指定ID的元素,并移除assets为空的组
mutating func removeGroupsWithEmptyAssetsInPlace(afterRemovingIDs ids: [String]) {
self = self.removingGroupsWithEmptyAssets(afterRemovingIDs: ids)
}
/// 删除日志,拿到执行删除后的更新数据,删除数据,移除的组
func removingGroupsWithEmptyAssetsWithDetails(afterRemovingIDs ids: [String]) -> RemovalResult {
let idSet = Set(ids)
var removedAssets = [AssetModel]()
var removedGroups = [SimilarGroupModel]()
let updated = self.compactMap { (group: SimilarGroupModel) -> SimilarGroupModel? in
let filteredAssets = group.assets.filter { !idSet.contains($0.localIdentifier) }
let removedInGroup = group.assets.filter { idSet.contains($0.localIdentifier) }
removedAssets.append(contentsOf: removedInGroup)
// 修改判断条件:当assets数量小于2时移除整个组
if filteredAssets.count < 2 {
removedGroups.append(group)
return nil
} else {
return SimilarGroupModel(groupId: group.groupId, assets: filteredAssets)
}
}
return RemovalResult(
updatedGroups: updated,
removedAssets: removedAssets,
removedGroups: removedGroups
)
}
}
extension Sequence where Element == [AssetModel] {
/// 删除二维数组中包含指定ID的元素,并移除所有元素数量少于2的子数组
func removingElementsAndSmallGroups(ids: [String]) -> [[AssetModel]] {
let idSet = Set(ids)
return self.compactMap { group in
let filtered = group.filter { !idSet.contains($0.localIdentifier) }
return filtered.count < 2 ? nil : filtered // 修改判断条件
}
}
}
...@@ -59,7 +59,7 @@ class PhotoSimilarManager: @unchecked Sendable { ...@@ -59,7 +59,7 @@ class PhotoSimilarManager: @unchecked Sendable {
} }
// 3. 通知已缓存的结果 // 3. 通知已缓存的结果
let cachedGroups = await stateManager.getAllSimilarGroups() let cachedGroups = await loadSimilarGroups() //await stateManager.getAllSimilarGroups()
print("通知已缓存的结果", cachedGroups.count) print("通知已缓存的结果", cachedGroups.count)
await MainActor.run { await MainActor.run {
for group in cachedGroups { for group in cachedGroups {
...@@ -176,7 +176,8 @@ class PhotoSimilarManager: @unchecked Sendable { ...@@ -176,7 +176,8 @@ class PhotoSimilarManager: @unchecked Sendable {
await savePendingSimilarGroups() await savePendingSimilarGroups()
} }
let allGroups = await stateManager.getAllSimilarGroups() // var allGroups = await stateManager.getAllSimilarGroups()
let allGroups = await loadSimilarGroups()
await MainActor.run { await MainActor.run {
print("执行完毕") print("执行完毕")
completionHandler?(allGroups.map { $0.assets }) completionHandler?(allGroups.map { $0.assets })
...@@ -332,7 +333,7 @@ extension PhotoSimilarManager{ ...@@ -332,7 +333,7 @@ extension PhotoSimilarManager{
private func savePendingSimilarGroups() async { private func savePendingSimilarGroups() async {
await stateManager.savePendingGroups() await stateManager.savePendingGroups()
// 保存到文件 // 保存到文件
if let data = try? JSONEncoder().encode(await stateManager.getAllSimilarGroups()) { if let data = try? JSONEncoder().encode(await loadSimilarGroups()) {
try? data.write(to: URL(fileURLWithPath: similarGroupsPath)) try? data.write(to: URL(fileURLWithPath: similarGroupsPath))
} }
} }
...@@ -349,6 +350,16 @@ extension PhotoSimilarManager{ ...@@ -349,6 +350,16 @@ extension PhotoSimilarManager{
return SimilarGroupModel(groupId: group.groupId, assets: validAssets) return SimilarGroupModel(groupId: group.groupId, assets: validAssets)
}.filter { !$0.assets.isEmpty } }.filter { !$0.assets.isEmpty }
} }
// 移除本地文件资源
func removeLocalFileWithIds(for ids:[String]) async{
await stateManager.deleteData(for: ids)
// 保存到文件
if let data = try? JSONEncoder().encode(await loadSimilarGroups()) {
try? data.write(to: URL(fileURLWithPath: similarGroupsPath))
}
}
} }
// MARK: - pHash获取 // MARK: - pHash获取
......
...@@ -58,7 +58,7 @@ class ScreenshotSimilarJSONManager: @unchecked Sendable { ...@@ -58,7 +58,7 @@ class ScreenshotSimilarJSONManager: @unchecked Sendable {
} }
// 3. 通知已缓存的结果 // 3. 通知已缓存的结果
let cachedGroups = await stateManager.getAllSimilarGroups() let cachedGroups = await loadSimilarGroups() //await stateManager.getAllSimilarGroups()
print("通知已缓存的结果", cachedGroups.count) print("通知已缓存的结果", cachedGroups.count)
await MainActor.run { await MainActor.run {
for group in cachedGroups { for group in cachedGroups {
...@@ -175,7 +175,7 @@ class ScreenshotSimilarJSONManager: @unchecked Sendable { ...@@ -175,7 +175,7 @@ class ScreenshotSimilarJSONManager: @unchecked Sendable {
await savePendingSimilarGroups() await savePendingSimilarGroups()
} }
let allGroups = await stateManager.getAllSimilarGroups() let allGroups = await loadSimilarGroups() //await stateManager.getAllSimilarGroups()
await MainActor.run { await MainActor.run {
print("执行完毕") print("执行完毕")
completionHandler?(allGroups.map { $0.assets }) completionHandler?(allGroups.map { $0.assets })
...@@ -365,7 +365,7 @@ extension ScreenshotSimilarJSONManager{ ...@@ -365,7 +365,7 @@ extension ScreenshotSimilarJSONManager{
private func savePendingSimilarGroups() async { private func savePendingSimilarGroups() async {
await stateManager.savePendingGroups() await stateManager.savePendingGroups()
// 保存到文件 // 保存到文件
if let data = try? JSONEncoder().encode(await stateManager.getAllSimilarGroups()) { if let data = try? JSONEncoder().encode(await loadSimilarGroups()) {
try? data.write(to: URL(fileURLWithPath: similarGroupsPath)) try? data.write(to: URL(fileURLWithPath: similarGroupsPath))
} }
} }
...@@ -382,6 +382,17 @@ extension ScreenshotSimilarJSONManager{ ...@@ -382,6 +382,17 @@ extension ScreenshotSimilarJSONManager{
return SimilarGroupModel(groupId: group.groupId, assets: validAssets) return SimilarGroupModel(groupId: group.groupId, assets: validAssets)
}.filter { !$0.assets.isEmpty } }.filter { !$0.assets.isEmpty }
} }
// 移除本地文件资源
func removeLocalFileWithIds(for ids:[String]) async{
await stateManager.deleteData(for: ids)
// 保存到文件
if let data = try? JSONEncoder().encode(await loadSimilarGroups()) {
try? data.write(to: URL(fileURLWithPath: similarGroupsPath))
}
}
} }
// MARK: - pHash获取 // MARK: - pHash获取
......
...@@ -47,7 +47,7 @@ private actor VideoAssetCacheManager { ...@@ -47,7 +47,7 @@ private actor VideoAssetCacheManager {
class VideoSimilarJSONManager: @unchecked Sendable { class VideoSimilarJSONManager: @unchecked Sendable {
static let shared = VideoSimilarJSONManager() static let shared = VideoSimilarJSONManager()
private let stateManager = VideoSimilarStateManager() private let stateManager = PhotoSimilarStateManager()
private init() {} private init() {}
// 类中添加缓存管理器实例 // 类中添加缓存管理器实例
...@@ -89,7 +89,7 @@ class VideoSimilarJSONManager: @unchecked Sendable { ...@@ -89,7 +89,7 @@ class VideoSimilarJSONManager: @unchecked Sendable {
} }
// 3. 通知已缓存的结果 // 3. 通知已缓存的结果
let cachedGroups = await stateManager.getAllSimilarGroups() let cachedGroups = await loadSimilarGroups() //await stateManager.getAllSimilarGroups()
await MainActor.run { await MainActor.run {
for group in cachedGroups { for group in cachedGroups {
progressHandler?(group.assets) progressHandler?(group.assets)
...@@ -202,7 +202,7 @@ class VideoSimilarJSONManager: @unchecked Sendable { ...@@ -202,7 +202,7 @@ class VideoSimilarJSONManager: @unchecked Sendable {
await savePendingSimilarGroups() await savePendingSimilarGroups()
} }
let allGroups = await stateManager.getAllSimilarGroups() let allGroups = await loadSimilarGroups() //await stateManager.getAllSimilarGroups()
await MainActor.run { await MainActor.run {
completionHandler?(allGroups.map { $0.assets }) completionHandler?(allGroups.map { $0.assets })
} }
...@@ -577,22 +577,55 @@ class VideoSimilarJSONManager: @unchecked Sendable { ...@@ -577,22 +577,55 @@ class VideoSimilarJSONManager: @unchecked Sendable {
return zip(hash1, hash2).filter { $0 != $1 }.count return zip(hash1, hash2).filter { $0 != $1 }.count
} }
private func createAssetModels(from assets: [PHAsset]) -> [AssetModel] { // private func createAssetModels(from assets: [PHAsset]) -> [AssetModel] {
return assets.map { asset in // return assets.map { asset in
let assetSize: Double // let assetSize: Double
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 {
assetSize = Double(size) // assetSize = Double(size)
} else { // } else {
assetSize = 0 // assetSize = 0
// }
//
// return AssetModel(
// localIdentifier: asset.localIdentifier,
// assetSize: assetSize,
// createDate: asset.creationDate ?? Date(),
// mediaType: 2
// )
// }
// }
private func createAssetModels(from assets: [PHAsset]) async -> [AssetModel] {
return await withTaskGroup(of: AssetModel.self) { modelGroup in
var models: [AssetModel] = []
for asset in assets {
modelGroup.addTask {
return await withCheckedContinuation { continuation in
let assetSize: Double
if let resource = PHAssetResource.assetResources(for: asset).first,
let size = resource.value(forKey: "fileSize") as? Int64 {
assetSize = Double(size)
} else {
assetSize = 0
}
let model = AssetModel(
localIdentifier: asset.localIdentifier,
assetSize: assetSize,
createDate: asset.creationDate ?? Date(),
mediaType: 2
)
continuation.resume(returning: model)
}
}
} }
return AssetModel( for await model in modelGroup {
localIdentifier: asset.localIdentifier, models.append(model)
assetSize: assetSize, }
createDate: asset.creationDate ?? Date(), return models
mediaType: 2
)
} }
} }
...@@ -629,10 +662,33 @@ extension VideoSimilarJSONManager { ...@@ -629,10 +662,33 @@ extension VideoSimilarJSONManager {
private func savePendingSimilarGroups() async { private func savePendingSimilarGroups() async {
await stateManager.savePendingGroups() await stateManager.savePendingGroups()
if let data = try? JSONEncoder().encode(await stateManager.getAllSimilarGroups()) { if let data = try? JSONEncoder().encode(await loadSimilarGroups()) {
try? data.write(to: URL(fileURLWithPath: similarGroupsPath)) try? data.write(to: URL(fileURLWithPath: similarGroupsPath))
} }
} }
// 移除本地文件资源
func removeLocalFileWithIds(for ids:[String]) async{
await stateManager.deleteData(for: ids)
// 保存到文件
if let data = try? JSONEncoder().encode(await loadSimilarGroups()) {
try? data.write(to: URL(fileURLWithPath: similarGroupsPath))
}
}
private func loadSimilarGroups() async -> [SimilarGroupModel] {
let groups = await stateManager.getAllSimilarGroups()
// 验证资源有效性
return groups.map { group in
var validAssets = group.assets
validAssets.removeAll { asset in
let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: [asset.localIdentifier], options: nil)
return fetchResult.firstObject == nil
}
return SimilarGroupModel(groupId: group.groupId, assets: validAssets)
}.filter { !$0.assets.isEmpty }
}
} }
......
...@@ -328,7 +328,8 @@ class CompressCompletedViewController : BaseViewController{ ...@@ -328,7 +328,8 @@ class CompressCompletedViewController : BaseViewController{
models.append(deleteModel) models.append(deleteModel)
} }
if(success){ if(success){
PhotoDataManager.manager.removeDataWhenDeleteInPage(data: models) // PhotoDataManager.manager.removeDataWhenDeleteInPage(data: models)
PhotoManager.shared.removeDataWhenDeleteInPage(data: models)
print("删除文件成功") print("删除文件成功")
self.showDeleteSuccess(fileCount:count, fileSize: fileSize) self.showDeleteSuccess(fileCount:count, fileSize: fileSize)
}else { }else {
......
...@@ -113,7 +113,7 @@ class CompressController : BaseViewController { ...@@ -113,7 +113,7 @@ class CompressController : BaseViewController {
/// 获取当前页面数据 /// 获取当前页面数据
func getViewData(){ func getViewData(){
if PhotoAndVideoMananger.mananger.permissionStatus == .denied{ if PhotoManager.shared.permissionStatus == .denied{
loadPermissView(CGRect(x: 0, y: 200, width: ScreenW, height: 450)) loadPermissView(CGRect(x: 0, y: 200, width: ScreenW, height: 450))
return return
} }
...@@ -132,12 +132,12 @@ class CompressController : BaseViewController { ...@@ -132,12 +132,12 @@ class CompressController : BaseViewController {
self.resourceData = datas.sorted {$0.createDate < $1.createDate } self.resourceData = datas.sorted {$0.createDate < $1.createDate }
} }
}else{ }else{
SVProgressHUD.show() PMLoadingHUD.share.show()
CompressViewModel().getAllPhotosToAssets(sortType: self.currentSort, assetType: self.currentResourceType) { [weak self] models in CompressViewModel().getAllPhotosToAssets(sortType: self.currentSort, assetType: self.currentResourceType) { [weak self] models in
guard let self else {return} guard let self else {return}
self.resourceData = models self.resourceData = models
Singleton.shared.resourceModel = self.resourceData Singleton.shared.resourceModel = self.resourceData
SVProgressHUD.dismiss() PMLoadingHUD.share.disMiss()
} }
} }
} }
......
...@@ -90,33 +90,19 @@ class HomeInfoViewController:BaseViewController { ...@@ -90,33 +90,19 @@ class HomeInfoViewController:BaseViewController {
// 更新免费次数 // 更新免费次数
if isAfterAdv == false { if isAfterAdv == false {
updateFreeTimes() updateFreeTimes()
} }
self.showDeleteSuccess(fileCount: tempStringArray.count, fileSize: fileSize) self.showDeleteSuccess(fileCount: tempStringArray.count, fileSize: fileSize)
PhotoManager.shared.removeDataWhenDeleteInPage(data: imgs)
// 删除缓存数据 let new = self.ids?.removingElementsAndSmallGroups(ids: imgs.compactMap{$0.localIdentifier})
PhotoDataManager.manager.removeDataWhenDeleteInPage(data: imgs)
// 更新下ids self.ids = new
PhotoDataManager.manager.loadFromFileSystem(resultModel: {[weak self] model in
DispatchQueue.main.async { self.tablewView.ids = self.ids
if self?.type == .duplicates { self.tablewView.deleteModel(array: imgs)
self?.ids = model.titleModelArray[0].assets
}
if self?.type == .similar {
self?.ids = model.titleModelArray[1].assets
}
if self?.type == .SimilarVideos {
self?.ids = model.otherModelArray[3].assets
}
if self?.type == .similarScreenshots {
self?.ids = model.otherModelArray[1].assets
}
self?.tablewView.ids = self?.ids
self?.tablewView.deleteModel(array: imgs)
}
})
self.setDefaultPage() self.setDefaultPage()
} }
...@@ -422,7 +408,7 @@ class HomeInfoViewController:BaseViewController { ...@@ -422,7 +408,7 @@ class HomeInfoViewController:BaseViewController {
func setDefaultPage(){ func setDefaultPage(){
DispatchQueue.main.async { DispatchQueue.main.async {
if PhotoAndVideoMananger.mananger.permissionStatus == .denied{ if PhotoManager.shared.permissionStatus == .denied{
self.loadPermissView() self.loadPermissView()
}else{ }else{
if self.ids?.count == 0 { if self.ids?.count == 0 {
......
...@@ -20,34 +20,10 @@ class HomePhotosDetailViewController : BaseViewController { ...@@ -20,34 +20,10 @@ class HomePhotosDetailViewController : BaseViewController {
var imageCache = NSCache<NSString, UIImage>() var imageCache = NSCache<NSString, UIImage>()
@MainActor required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
required init(model: HomePhotosModel) {
self.model = model
super.init(nibName: nil, bundle: nil)
}
private var videoDetailNavView:VideoDetaiNavView? private var videoDetailNavView:VideoDetaiNavView?
var resourceData : [AssetModel] = [] var resourceData : [AssetModel] = []
func dealData(){
var dataArray : [AssetModel] = []
for item in self.model.assets {
dataArray = dataArray + item
}
self.resourceData = self.filterTrashData(array: dataArray)
self.selectedModel = self.filterTrashData(array: self.selectedModel)
self.sortByType(sortType: self.currentSort)
}
var model : HomePhotosModel
var datas : [AssetModel] = []
// 排序 // 排序
var currentSort : Int = 0 var currentSort : Int = 0
...@@ -64,6 +40,8 @@ class HomePhotosDetailViewController : BaseViewController { ...@@ -64,6 +40,8 @@ class HomePhotosDetailViewController : BaseViewController {
} }
} }
lazy var defaultImageView : UIImageView = { lazy var defaultImageView : UIImageView = {
let defaultImageView = UIImageView() let defaultImageView = UIImageView()
defaultImageView.image = UIImage(named: "img_photo__home_defpage") defaultImageView.image = UIImage(named: "img_photo__home_defpage")
...@@ -114,15 +92,6 @@ class HomePhotosDetailViewController : BaseViewController { ...@@ -114,15 +92,6 @@ class HomePhotosDetailViewController : BaseViewController {
}() }()
/// 过滤垃圾桶数据
/// - Parameter array: 当前数据
/// - Returns: 过滤后的数据
func filterTrashData(array : [AssetModel]) -> [AssetModel]{
let data = TrashDataManager.getCurrentMediaTypeTrashData(mediaType: self.mediaType == PhotsFileType.Other ? TrashTypeEnum.other : TrashTypeEnum.shot)
return array.filter({!data.map({$0.localIdentifier}).contains($0.localIdentifier)})
}
func setUI(){ func setUI(){
...@@ -214,7 +183,7 @@ class HomePhotosDetailViewController : BaseViewController { ...@@ -214,7 +183,7 @@ class HomePhotosDetailViewController : BaseViewController {
//设置空白页 //设置空白页
func setDefaultPage(){ func setDefaultPage(){
DispatchQueue.main.async { DispatchQueue.main.async {
if PhotoAndVideoMananger.mananger.permissionStatus == .denied{ if PhotoManager.shared.permissionStatus == .denied{
self.loadPermissView() self.loadPermissView()
}else{ }else{
if self.resourceData.count == 0 { if self.resourceData.count == 0 {
...@@ -269,16 +238,77 @@ class HomePhotosDetailViewController : BaseViewController { ...@@ -269,16 +238,77 @@ class HomePhotosDetailViewController : BaseViewController {
} }
// MARK:系统方法
@MainActor required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
required init(mediaType: PhotsFileType) {
self.mediaType = mediaType
super.init(nibName: nil, bundle: nil)
}
override func viewWillAppear(_ animated: Bool) { override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated) super.viewWillAppear(animated)
// 重新设置下数据源
// 目的是为了消除cell 的选择按钮状态 self.getCurrentPageData {
if self.selectedModel.count == 0 { DispatchQueue.main.async {
self.collectionView.reloadData() self.collectionView.reloadData()
}
} }
}
// MARK: 数据操作 - 主要方法
/// 获取当前页面数据
/// - Parameter completed: 完成回调
func getCurrentPageData(completed:@escaping ()->Void){
// FIXME: 从新获取数据
var data = self.mediaType == .Other ? PhotoManager.shared.filterOtherModels : PhotoManager.shared.filterScreenShotModels
// 过滤掉垃圾桶数据
data = self.filterSigtonTrashData(array: data)
self.selectedModel = self.filterSigtonTrashData(array: self.selectedModel)
// 过滤掉保留列表数据
data = self.filterKeepListData(array: data)
self.selectedModel = self.filterKeepListData(array: self.selectedModel)
self.resourceData = data
self.sortByType(sortType: self.currentSort)
completed()
}
// MARK: 数据操作 - 辅助方法
/// 过滤垃圾桶数据 - 当前页面数据本身就是已经过滤了垃圾桶数据库的数据了,所以只需要过滤掉单利中的数据
/// - Parameter array: 当前数据
/// - Returns: 过滤后的数据
func filterSigtonTrashData(array : [AssetModel]) -> [AssetModel]{
let type = self.mediaType == PhotsFileType.Other ? TrashTypeEnum.other : TrashTypeEnum.shot
// 从单利拿数据
let data : [AssetModel] = Singleton.shared.trashData[type] ?? []
return array.filter({!data.map({$0.localIdentifier}).contains($0.localIdentifier)})
}
/// 过滤保留列表数据
/// - Parameter array: 原数据
/// - Returns: 过滤后的数据
func filterKeepListData(array : [AssetModel]) -> [AssetModel]{
let data = KeepListManager.getAllKeepListData()
if data.count > 0 {
return array.filter({!data.map({$0.localIdentifier}).contains($0.localIdentifier)})
}
return array
} }
func getImageFromCache(model: AssetModel,completed:@escaping (UIImage)->Void){ func getImageFromCache(model: AssetModel,completed:@escaping (UIImage)->Void){
let cachedImage = self.imageCache.object(forKey: model.localIdentifier as NSString) let cachedImage = self.imageCache.object(forKey: model.localIdentifier as NSString)
if cachedImage != nil { if cachedImage != nil {
...@@ -342,22 +372,10 @@ extension HomePhotosDetailViewController:WaterfallMutiSectionDelegate,UICollecti ...@@ -342,22 +372,10 @@ extension HomePhotosDetailViewController:WaterfallMutiSectionDelegate,UICollecti
// 点击之后跳转详情页面 // 点击之后跳转详情页面
if self.mediaType == .screenshots { if self.mediaType == .screenshots {
let vc = PhotoRemoveViewController(data: self.resourceData,currentIndex: indexPath.row,mediaType: .shot) let vc = PhotoRemoveViewController(data: self.resourceData,currentIndex: indexPath.row,mediaType: .shot)
vc.dismissCallback = {
self.dealData()
UIView.transition(with: self.collectionView, duration: 0.3, options: .transitionCrossDissolve, animations: {
self.collectionView.reloadData()
}, completion: nil)
}
self.navigationController?.pushViewController(vc, animated: true) self.navigationController?.pushViewController(vc, animated: true)
} }
if self.mediaType == .Other { if self.mediaType == .Other {
let vc = PhotoRemoveViewController(data: self.resourceData,currentIndex: indexPath.row,mediaType: .other) let vc = PhotoRemoveViewController(data: self.resourceData,currentIndex: indexPath.row,mediaType: .other)
vc.dismissCallback = {
self.dealData()
UIView.transition(with: self.collectionView, duration: 0.3, options: .transitionCrossDissolve, animations: {
self.collectionView.reloadData()
}, completion: nil)
}
self.navigationController?.pushViewController(vc, animated: true) self.navigationController?.pushViewController(vc, animated: true)
} }
} }
...@@ -419,7 +437,7 @@ extension HomePhotosDetailViewController:WaterfallMutiSectionDelegate,UICollecti ...@@ -419,7 +437,7 @@ extension HomePhotosDetailViewController:WaterfallMutiSectionDelegate,UICollecti
let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "HomePhotosDetailCustomHeaderView", for: indexPath) as! HomePhotosDetailCustomHeaderView let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "HomePhotosDetailCustomHeaderView", for: indexPath) as! HomePhotosDetailCustomHeaderView
// 记录当前的 headerView // 记录当前的 headerView
header.countLabel.text = "\(self.resourceData.count) Photos" header.countLabel.text = "\(self.resourceData.count) Photos"
header.modelTitlelabel.text = self.model.folderName header.modelTitlelabel.text = self.mediaType?.rawValue
currentHeaderView = header currentHeaderView = header
header.sortCallback = {[weak self] in header.sortCallback = {[weak self] in
...@@ -693,8 +711,10 @@ extension HomePhotosDetailViewController:WaterfallMutiSectionDelegate,UICollecti ...@@ -693,8 +711,10 @@ extension HomePhotosDetailViewController:WaterfallMutiSectionDelegate,UICollecti
} }
// 清理下缓存数据 // 清理下缓存数据
PhotoDataManager.manager.removeDataWhenDeleteInPage(data: self.selectedModel) // PhotoDataManager.manager.removeDataWhenDeleteInPage(data: self.selectedModel)
PhotoManager.shared.removeDataWhenDeleteInPage(data: self.selectedModel) {
//删除完成刷新数据
}
// 更新页面 // 更新页面
DispatchQueue.main.async { DispatchQueue.main.async {
// 删除完成之后,移除下当前选择的数据 // 删除完成之后,移除下当前选择的数据
......
...@@ -18,8 +18,7 @@ class HomeVideoDetailController :BaseViewController { ...@@ -18,8 +18,7 @@ class HomeVideoDetailController :BaseViewController {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
required init(model: HomePhotosModel) { required init() {
self.model = model
super.init(nibName: nil, bundle: nil) super.init(nibName: nil, bundle: nil)
} }
...@@ -27,18 +26,6 @@ class HomeVideoDetailController :BaseViewController { ...@@ -27,18 +26,6 @@ class HomeVideoDetailController :BaseViewController {
var resourceData : [AssetModel] = [] var resourceData : [AssetModel] = []
func dealData(){
var dataArray : [AssetModel] = []
for item in self.model.assets {
dataArray = dataArray + item
}
self.resourceData = self.filterTrashData(array: dataArray)
self.selectedModel = self.filterTrashData(array: self.selectedModel)
self.sortByType(sortType: self.currentSort)
}
var model : HomePhotosModel
// 排序 // 排序
var currentSort : Int = 0 var currentSort : Int = 0
...@@ -65,7 +52,7 @@ class HomeVideoDetailController :BaseViewController { ...@@ -65,7 +52,7 @@ class HomeVideoDetailController :BaseViewController {
let layout = WaterfallMutiSectionFlowLayout() let layout = WaterfallMutiSectionFlowLayout()
layout.delegate = self layout.delegate = self
let sview:UICollectionView = UICollectionView.init(frame: CGRect(x: marginLR, y: self.videoDetailNavView!.height, width: self.view.width - 2 * marginLR, height: self.view.height - self.videoDetailNavView!.height - 102), collectionViewLayout: layout) let sview:UICollectionView = UICollectionView.init(frame: CGRect(x: marginLR, y: statusBarHeight + 44, width: self.view.width - 2 * marginLR, height: self.view.height - (statusBarHeight + 44) - 102), collectionViewLayout: layout)
sview.register(HomeVideoDetailCell.self, forCellWithReuseIdentifier: "HomeVideoDetailCell") sview.register(HomeVideoDetailCell.self, forCellWithReuseIdentifier: "HomeVideoDetailCell")
sview.register(HomeVideoDetailCustomHeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "HomeVideoDetailCustomHeaderView") sview.register(HomeVideoDetailCustomHeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "HomeVideoDetailCustomHeaderView")
...@@ -109,15 +96,50 @@ class HomeVideoDetailController :BaseViewController { ...@@ -109,15 +96,50 @@ class HomeVideoDetailController :BaseViewController {
return label return label
}() }()
/// 过滤垃圾桶数据 // MARK: 数据操作 - 主要方法
/// 获取当前页面数据
/// - Parameter completed: 完成回调
func getCurrentPageData(completed:@escaping ()->Void){
var data = PhotoManager.shared.filterVideoModels
// 过滤掉垃圾桶数据
data = self.filterSigtonTrashData(array: data)
self.selectedModel = self.filterSigtonTrashData(array: self.selectedModel)
// 过滤掉保留列表数据
data = self.filterKeepListData(array: data)
self.selectedModel = self.filterKeepListData(array: self.selectedModel)
self.resourceData = data
self.sortByType(sortType: self.currentSort)
completed()
}
// MARK: 数据操作 - 辅助方法
/// 过滤垃圾桶数据 - 当前页面数据本身就是已经过滤了垃圾桶数据库的数据了,所以只需要过滤掉单利中的数据
/// - Parameter array: 当前数据 /// - Parameter array: 当前数据
/// - Returns: 过滤后的数据 /// - Returns: 过滤后的数据
func filterTrashData(array : [AssetModel]) -> [AssetModel]{ func filterSigtonTrashData(array : [AssetModel]) -> [AssetModel]{
let data = TrashDataManager.getCurrentMediaTypeTrashData(mediaType: .video) // 从单利拿数据
let data = Singleton.shared.trashData[TrashTypeEnum.video] ?? []
return array.filter({!data.map({$0.localIdentifier}).contains($0.localIdentifier)}) return array.filter({!data.map({$0.localIdentifier}).contains($0.localIdentifier)})
} }
/// 过滤保留列表数据
/// - Parameter array: 原数据
/// - Returns: 过滤后的数据
func filterKeepListData(array : [AssetModel]) -> [AssetModel]{
let data = KeepListManager.getAllKeepListData()
if data.count > 0 {
return array.filter({!data.map({$0.localIdentifier}).contains($0.localIdentifier)})
}
return array
}
func setUI(){ func setUI(){
videoDetailNavView = VideoDetaiNavView(frame: CGRect(x: 0, y: 0, width: self.view.width, height: statusBarHeight + 44)) videoDetailNavView = VideoDetaiNavView(frame: CGRect(x: 0, y: 0, width: self.view.width, height: statusBarHeight + 44))
self.view.addSubview(videoDetailNavView!) self.view.addSubview(videoDetailNavView!)
...@@ -209,10 +231,11 @@ class HomeVideoDetailController :BaseViewController { ...@@ -209,10 +231,11 @@ class HomeVideoDetailController :BaseViewController {
override func viewWillAppear(_ animated: Bool) { override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated) super.viewWillAppear(animated)
// 重新设置下数据源
// 目的是为了消除cell 的选择按钮状态 self.getCurrentPageData {
if self.selectedModel.count == 0 { DispatchQueue.main.async {
self.collectionView.reloadData() self.collectionView.reloadData()
}
} }
} }
...@@ -285,12 +308,6 @@ extension HomeVideoDetailController:WaterfallMutiSectionDelegate,UICollectionVie ...@@ -285,12 +308,6 @@ extension HomeVideoDetailController:WaterfallMutiSectionDelegate,UICollectionVie
PhotoAndVideoMananger.mananger.getVideoImageByIdent(ident: ident) { image in PhotoAndVideoMananger.mananger.getVideoImageByIdent(ident: ident) { image in
// 点击之后跳转详情页面 // 点击之后跳转详情页面
let vc = PhotoRemoveViewController(data: self.resourceData,currentIndex: indexPath.row,mediaType: .video) let vc = PhotoRemoveViewController(data: self.resourceData,currentIndex: indexPath.row,mediaType: .video)
vc.dismissCallback = {
self.dealData()
UIView.transition(with: self.collectionView, duration: 0.3, options: .transitionCrossDissolve, animations: {
self.collectionView.reloadData()
}, completion: nil)
}
self.navigationController?.pushViewController(vc, animated: true) self.navigationController?.pushViewController(vc, animated: true)
} errorHandler: { } errorHandler: {
DispatchQueue.main.async { DispatchQueue.main.async {
...@@ -345,6 +362,7 @@ extension HomeVideoDetailController:WaterfallMutiSectionDelegate,UICollectionVie ...@@ -345,6 +362,7 @@ extension HomeVideoDetailController:WaterfallMutiSectionDelegate,UICollectionVie
let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "HomeVideoDetailCustomHeaderView", for: indexPath) as! HomeVideoDetailCustomHeaderView let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "HomeVideoDetailCustomHeaderView", for: indexPath) as! HomeVideoDetailCustomHeaderView
// 记录当前的 headerView // 记录当前的 headerView
currentHeaderView = header currentHeaderView = header
header.compressionTipView.reloadData()
header.sizeLabel.text = "\(self.resourceData.count) Videos" header.sizeLabel.text = "\(self.resourceData.count) Videos"
header.sortCallback = {[weak self] in header.sortCallback = {[weak self] in
guard let self else {return} guard let self else {return}
...@@ -553,7 +571,7 @@ extension HomeVideoDetailController:WaterfallMutiSectionDelegate,UICollectionVie ...@@ -553,7 +571,7 @@ extension HomeVideoDetailController:WaterfallMutiSectionDelegate,UICollectionVie
func setDefaultPage(){ func setDefaultPage(){
DispatchQueue.main.async { DispatchQueue.main.async {
if PhotoAndVideoMananger.mananger.permissionStatus == .denied{ if PhotoManager.shared.permissionStatus == .denied{
self.loadPermissView() self.loadPermissView()
}else{ }else{
if self.resourceData.count == 0 { if self.resourceData.count == 0 {
...@@ -582,9 +600,11 @@ extension HomeVideoDetailController:WaterfallMutiSectionDelegate,UICollectionVie ...@@ -582,9 +600,11 @@ extension HomeVideoDetailController:WaterfallMutiSectionDelegate,UICollectionVie
// 清理下缓存数据 // 清理下缓存数据
PhotoDataManager.manager.removeDataWhenDeleteInPage(data: self.selectedModel) //PhotoDataManager.manager.removeDataWhenDeleteInPage(data: self.selectedModel)
PhotoManager.shared.removeDataWhenDeleteInPage(data: self.selectedModel) {
// 删除完成刷新数据
}
// 更新页面 // 更新页面
......
...@@ -130,8 +130,7 @@ class HomeViewController:BaseViewController { ...@@ -130,8 +130,7 @@ class HomeViewController:BaseViewController {
guard let self else {return} guard let self else {return}
if otherItemRow == 0 { if otherItemRow == 0 {
DispatchQueue.main.async { DispatchQueue.main.async {
let vc:HomeVideoDetailController = HomeVideoDetailController(model: model) let vc:HomeVideoDetailController = HomeVideoDetailController()
vc.dealData()
self.navigationController?.pushViewController(vc, animated: true) self.navigationController?.pushViewController(vc, animated: true)
} }
} }
...@@ -149,16 +148,9 @@ class HomeViewController:BaseViewController { ...@@ -149,16 +148,9 @@ class HomeViewController:BaseViewController {
} }
} }
if otherItemRow == 2 || otherItemRow == 4{ if otherItemRow == 2 || otherItemRow == 4{
DispatchQueue.main.async { DispatchQueue.main.async {
let vc:HomePhotosDetailViewController = HomePhotosDetailViewController(model: model) let vc = HomePhotosDetailViewController(mediaType: otherItemRow == 2 ? .screenshots : .Other)
if otherItemRow == 2 {
vc.mediaType = .screenshots
}else{
vc.mediaType = .Other
}
vc.dealData()
self.navigationController?.pushViewController(vc, animated: true) self.navigationController?.pushViewController(vc, animated: true)
} }
} }
......
...@@ -11,9 +11,6 @@ import Photos ...@@ -11,9 +11,6 @@ import Photos
class PhotoRemoveViewController: BaseViewController { class PhotoRemoveViewController: BaseViewController {
var dismissCallback : ()->Void = {}
var mediaType : TrashTypeEnum? { var mediaType : TrashTypeEnum? {
didSet{ didSet{
if mediaType == .video { if mediaType == .video {
...@@ -121,24 +118,28 @@ class PhotoRemoveViewController: BaseViewController { ...@@ -121,24 +118,28 @@ class PhotoRemoveViewController: BaseViewController {
} }
} }
self.navView.reSetCallBack = { self.navView.reSetCallBack = {
// 拿到单利中最后一个
if self.currentIndex > 0 { if let model = self.getSigtonCurrentMediaTrashLastData(){
self.currentIndex = self.currentIndex - 1 // 判断当前数组中有没有这个数据(有的话表示是在当前页面撤销)
if self.dataModel.map({$0.localIdentifier}).contains(model.localIdentifier){
if self.currentIndex > 0 {
self.currentIndex = self.currentIndex - 1
}
}else{
// 没有这个数据表示从外部跳转进这个页面,当前位置插入一个数据
self.dataModel.insert(model, at: self.currentIndex)
}
// 重新设置下图片 // 重新设置下图片
self.updateViewContents() self.updateViewContents()
// 视图层级处理 // 视图层级处理
self.bringCurrentViewToFront() self.bringCurrentViewToFront()
// 移除当前数据
self.removeCurrentMediaTypeTrashLastData()
// 移除完成后 重新设置下按钮状态
self.showCurrentPageUIWhenTashDataChanged()
} }
// 移除单利中当前类型数组的最后一个数据
self.removeCurrentMediaTypeTrashLastData()
// 移除完成后 重新设置下按钮状态
self.showCurrentPageUIWhenTashDataChanged()
} }
showCurrentPageUIWhenTashDataChanged() showCurrentPageUIWhenTashDataChanged()
...@@ -146,6 +147,20 @@ class PhotoRemoveViewController: BaseViewController { ...@@ -146,6 +147,20 @@ class PhotoRemoveViewController: BaseViewController {
self.addListener() self.addListener()
} }
// 拿到当前类型垃圾桶数据的最后一个
func getSigtonCurrentMediaTrashLastData() -> AssetModel? {
var model : AssetModel?
if let type = self.mediaType{
if let dataSg = Singleton.shared.trashData[type]{
let tempArray = dataSg
if tempArray.count > 0 {
model = tempArray[tempArray.count - 1]
}
}
}
return model
}
// 跳转垃圾桶第几个page // 跳转垃圾桶第几个page
func getJumpPageIndex()->Int{ func getJumpPageIndex()->Int{
if self.mediaType == .video { if self.mediaType == .video {
...@@ -166,25 +181,16 @@ class PhotoRemoveViewController: BaseViewController { ...@@ -166,25 +181,16 @@ class PhotoRemoveViewController: BaseViewController {
let type = notification.userInfo?["type"] as? String else { return } let type = notification.userInfo?["type"] as? String else { return }
if let targetVC = self.navigationController?.viewControllers.first(where: { $0 is HomeViewController }) as? HomeViewController { if let targetVC = self.navigationController?.viewControllers.first(where: { $0 is HomeViewController }) as? HomeViewController {
self.navigationController?.popToViewController(targetVC, animated: false) self.navigationController?.popToViewController(targetVC, animated: false)
PhotoDataManager.manager.loadFromFileSystem { model in let vc:HomePhotosDetailViewController = HomePhotosDetailViewController(mediaType: type == "Other" ? PhotsFileType.Other : PhotsFileType.screenshots)
let data = type == "Other" ? model.otherModelArray[4] : model.otherModelArray[2] targetVC.navigationController?.pushViewController(vc, animated: true)
let vc:HomePhotosDetailViewController = HomePhotosDetailViewController(model: data)
vc.mediaType = type == "Other" ? .Other : PhotsFileType.screenshots
vc.dealData()
targetVC.navigationController?.pushViewController(vc, animated: true)
}
} }
} }
NotificationCenter.default.addObserver(forName: TrashDefaultView.jumpToVideosDetailPageName, object: nil, queue: .main) { [weak self] notification in NotificationCenter.default.addObserver(forName: TrashDefaultView.jumpToVideosDetailPageName, object: nil, queue: .main) { [weak self] notification in
guard let self else {return} guard let self else {return}
if let targetVC = self.navigationController?.viewControllers.first(where: { $0 is HomeViewController }) as? HomeViewController { if let targetVC = self.navigationController?.viewControllers.first(where: { $0 is HomeViewController }) as? HomeViewController {
self.navigationController?.popToViewController(targetVC, animated: false) self.navigationController?.popToViewController(targetVC, animated: false)
PhotoDataManager.manager.loadFromFileSystem { model in let vc:HomeVideoDetailController = HomeVideoDetailController()
let data = model.otherModelArray[0] targetVC.navigationController?.pushViewController(vc, animated: true)
let vc:HomeVideoDetailController = HomeVideoDetailController(model: data)
vc.dealData()
targetVC.navigationController?.pushViewController(vc, animated: true)
}
} }
} }
} }
...@@ -194,6 +200,12 @@ class PhotoRemoveViewController: BaseViewController { ...@@ -194,6 +200,12 @@ class PhotoRemoveViewController: BaseViewController {
if let dataSg = Singleton.shared.trashData[type]{ if let dataSg = Singleton.shared.trashData[type]{
var tempArray = dataSg var tempArray = dataSg
if tempArray.count > 0 { if tempArray.count > 0 {
// 获取最后一个
let identifier = tempArray[tempArray.count - 1].localIdentifier
let success = TrashDatabase.shared.delete(localIdentifier: identifier)
if !success {
Print("删除失败")
}
tempArray.removeLast() tempArray.removeLast()
} }
Singleton.shared.trashData[type] = tempArray Singleton.shared.trashData[type] = tempArray
...@@ -206,7 +218,6 @@ class PhotoRemoveViewController: BaseViewController { ...@@ -206,7 +218,6 @@ class PhotoRemoveViewController: BaseViewController {
super.viewDidDisappear(animated) super.viewDidDisappear(animated)
// 视图消失的时候存到数据库 // 视图消失的时候存到数据库
saveDataToKeepListDB() saveDataToKeepListDB()
self.dismissCallback()
} }
...@@ -252,9 +263,7 @@ class PhotoRemoveViewController: BaseViewController { ...@@ -252,9 +263,7 @@ class PhotoRemoveViewController: BaseViewController {
DispatchQueue.main.async { DispatchQueue.main.async {
if let type = self.mediaType{ if let type = self.mediaType{
if let dataSg = Singleton.shared.trashData[type]{ if let dataSg = Singleton.shared.trashData[type]{
assetModel = assetModel + dataSg
// 如果单利中有当前数据,显示撤回按钮 // 如果单利中有当前数据,显示撤回按钮
if dataSg.count > 0{ if dataSg.count > 0{
self.navView.resetButton.isHidden = false self.navView.resetButton.isHidden = false
}else{ }else{
...@@ -265,6 +274,8 @@ class PhotoRemoveViewController: BaseViewController { ...@@ -265,6 +274,8 @@ class PhotoRemoveViewController: BaseViewController {
self.navView.resetButton.isHidden = true self.navView.resetButton.isHidden = true
} }
} }
if assetModel.count > 0 { if assetModel.count > 0 {
// 显示垃圾桶 // 显示垃圾桶
self.trashSubView.resourceCountlabel.text = String(assetModel.count) self.trashSubView.resourceCountlabel.text = String(assetModel.count)
...@@ -294,16 +305,22 @@ class PhotoRemoveViewController: BaseViewController { ...@@ -294,16 +305,22 @@ class PhotoRemoveViewController: BaseViewController {
} }
// 存垃圾桶数据到单利 // 存垃圾桶数据到单利
func saveDataToSigtonTrash(){ func saveDataToDBAndSigtonTrash(){
// 拿到单利数据 // 拿到单利数据
let model = self.dataModel[currentIndex]
if let type = self.mediaType{ if let type = self.mediaType{
if let dataSg = Singleton.shared.trashData[type]{ if let dataSg = Singleton.shared.trashData[type]{
var tempArray = dataSg var tempArray = dataSg
tempArray.append(self.dataModel[currentIndex]) tempArray.append(model)
Singleton.shared.trashData[type] = tempArray Singleton.shared.trashData[type] = tempArray
}else{ }else{
Singleton.shared.trashData[type] = [self.dataModel[currentIndex]] Singleton.shared.trashData[type] = [self.dataModel[currentIndex]]
} }
// 保存当前数据到数据库
let success = TrashDatabase.shared.insert(localIdentifier: model.localIdentifier, assetSize: model.assetSize, createDate: model.createDate, mediaType: type.dbType)
if !success {
Print("保存数据失败")
}
} }
self.showCurrentPageUIWhenTashDataChanged() self.showCurrentPageUIWhenTashDataChanged()
} }
...@@ -322,17 +339,9 @@ class PhotoRemoveViewController: BaseViewController { ...@@ -322,17 +339,9 @@ class PhotoRemoveViewController: BaseViewController {
} }
} }
func saveDataToTrashDB(){ func clearSigtonTrashData(){
if let type = self.mediaType{ if let type = self.mediaType{
if let dataSg = Singleton.shared.trashData[type]{ Singleton.shared.trashData[type] = []
for item in dataSg{
let success = TrashDatabase.shared.insert(localIdentifier: item.localIdentifier, assetSize: item.assetSize, createDate: item.createDate, mediaType: type.dbType)
if success {
Print("保留单利数据到数据库垃圾桶成功")
}
}
Singleton.shared.trashData[type] = []
}
} }
showCurrentPageUIWhenTashDataChanged() showCurrentPageUIWhenTashDataChanged()
} }
...@@ -387,8 +396,8 @@ class PhotoRemoveViewController: BaseViewController { ...@@ -387,8 +396,8 @@ class PhotoRemoveViewController: BaseViewController {
if abs(actualTranslation.x) > actionMargin || abs(velocity.x) > 500 { if abs(actualTranslation.x) > actionMargin || abs(velocity.x) > 500 {
removeCurrentView(translation: actualTranslation, velocity: velocity) removeCurrentView(translation: actualTranslation, velocity: velocity)
if actualTranslation.x > 0 { if actualTranslation.x > 0 {
// 保存垃圾桶数据到数据库 // 清除单利数据
saveDataToTrashDB() clearSigtonTrashData()
// 保留操作 // 保留操作
self.vibrate() self.vibrate()
saveDataToSigtonKeepList() saveDataToSigtonKeepList()
...@@ -397,6 +406,9 @@ class PhotoRemoveViewController: BaseViewController { ...@@ -397,6 +406,9 @@ class PhotoRemoveViewController: BaseViewController {
// 删除操作,先存到单利 // 删除操作,先存到单利
self.vibrate() self.vibrate()
saveDataToSigtonTrash() saveDataToSigtonTrash()
saveDataToDBAndSigtonTrash()
} }
} else { } else {
resetViewPosition(activeView) resetViewPosition(activeView)
......
...@@ -35,11 +35,14 @@ class HomePhotosModel:Codable { ...@@ -35,11 +35,14 @@ class HomePhotosModel:Codable {
var folderName:String var folderName:String
var allFileSize:Double var allFileSize:Double
var assets:[[AssetModel]] var assets:[[AssetModel]]
var originalAssets:[[AssetModel]]
init(folderName: String, allFileSize: Double, assets: [[AssetModel]]) { init(folderName: String, allFileSize: Double, assets: [[AssetModel]],originalAssets:[[AssetModel]] = []) {
self.folderName = folderName self.folderName = folderName
self.allFileSize = allFileSize self.allFileSize = allFileSize
self.assets = assets self.assets = assets
self.originalAssets = originalAssets
} }
} }
......
...@@ -30,6 +30,7 @@ class HomeCollectionViewHeader : UICollectionReusableView { ...@@ -30,6 +30,7 @@ class HomeCollectionViewHeader : UICollectionReusableView {
lazy var permissionView : PMPermissionView = { lazy var permissionView : PMPermissionView = {
let view = Bundle.main.loadNibNamed("PMPermissionView", owner: nil, options: nil)?.last as! PMPermissionView let view = Bundle.main.loadNibNamed("PMPermissionView", owner: nil, options: nil)?.last as! PMPermissionView
view.isHidden = true
return view return view
}() }()
...@@ -201,14 +202,17 @@ class CustomProgressBar: UIView { ...@@ -201,14 +202,17 @@ class CustomProgressBar: UIView {
idleLabel.font = UIFont.systemFont(ofSize: 12) idleLabel.font = UIFont.systemFont(ofSize: 12)
idleLabel.textColor = UIColor.colorWithHex(hexStr: black6Color) idleLabel.textColor = UIColor.colorWithHex(hexStr: black6Color)
addSubview(idleLabel) addSubview(idleLabel)
progressLayer.frame = CGRect(x: 0, y: 0, width: ScreenW-48, height: 10)
progressLayer.cornerRadius = 5
progressLayer.masksToBounds = true
} }
override func layoutSubviews() { override func layoutSubviews() {
super.layoutSubviews() super.layoutSubviews()
progressLayer.frame = CGRect(x: 0, y: 0, width: bounds.width, height: 10)
progressLayer.cornerRadius = 5 // updateProgress()
progressLayer.masksToBounds = true
updateProgress()
let dotY = progressLayer.frame.maxY + 9 let dotY = progressLayer.frame.maxY + 9
let usedDotX = bounds.minX let usedDotX = bounds.minX
...@@ -230,11 +234,12 @@ class CustomProgressBar: UIView { ...@@ -230,11 +234,12 @@ class CustomProgressBar: UIView {
private func scheduleProgressUpdate() { private func scheduleProgressUpdate() {
// 取消之前的计时器 // 取消之前的计时器
updateTimer?.invalidate() // updateTimer?.invalidate()
// 设置新的计时器,延迟0.2秒更新UI // // 设置新的计时器,延迟0.2秒更新UI
updateTimer = Timer.scheduledTimer(withTimeInterval: 0.2, repeats: false) { [weak self] _ in // updateTimer = Timer.scheduledTimer(withTimeInterval: 0.2, repeats: false) { [weak self] _ in
self?.updateProgress() // self?.updateProgress()
} // }
updateProgress()
} }
private func updateProgress() { private func updateProgress() {
...@@ -248,33 +253,26 @@ class CustomProgressBar: UIView { ...@@ -248,33 +253,26 @@ class CustomProgressBar: UIView {
let chaoticRatio = min(max(self.chaoticProgress / total, 0), 1) let chaoticRatio = min(max(self.chaoticProgress / total, 0), 1)
// 计算实际宽度 // 计算实际宽度
let usedWidth = self.bounds.width * usedRatio let usedWidth = (ScreenW-48) * usedRatio
let chaoticWidth = self.bounds.width * chaoticRatio let chaoticWidth = (ScreenW-48) * chaoticRatio
// 设置进度条背景为白色 // 设置进度条背景为白色
self.progressLayer.backgroundColor = self.idleColor.cgColor self.progressLayer.backgroundColor = self.idleColor.cgColor
// 使用CATransaction确保所有动画同步进行
CATransaction.begin()
CATransaction.setAnimationDuration(0.3)
CATransaction.setAnimationTimingFunction(CAMediaTimingFunction(name: .easeInEaseOut))
// 更新或创建used层 // 更新或创建used层
let usedLayer = self.progressLayer.sublayers?.first as? CALayer ?? CALayer() let usedLayer = self.progressLayer.sublayers?.first as? CALayer ?? CALayer()
usedLayer.frame = CGRect(x: 0, y: 0, width: usedWidth, height: self.progressLayer.bounds.height) usedLayer.frame = CGRect(x: 0, y: 0, width: usedWidth, height: 10)
usedLayer.backgroundColor = self.usedColor.cgColor usedLayer.backgroundColor = self.usedColor.cgColor
// 更新或创建chaotic层 // 更新或创建chaotic层
let chaoticLayer = self.progressLayer.sublayers?[safe: 1] as? CALayer ?? CALayer() let chaoticLayer = self.progressLayer.sublayers?[safe: 1] as? CALayer ?? CALayer()
chaoticLayer.frame = CGRect(x: usedWidth, y: 0, width: chaoticWidth, height: self.progressLayer.bounds.height) chaoticLayer.frame = CGRect(x: usedWidth, y: 0, width: chaoticWidth, height: 10)
chaoticLayer.backgroundColor = self.chaoticColor.cgColor chaoticLayer.backgroundColor = self.chaoticColor.cgColor
// 一次性设置所有子层 // 一次性设置所有子层
if self.progressLayer.sublayers == nil { if self.progressLayer.sublayers == nil {
self.progressLayer.sublayers = [usedLayer, chaoticLayer] self.progressLayer.sublayers = [usedLayer, chaoticLayer]
} }
CATransaction.commit()
} }
} }
......
...@@ -43,7 +43,6 @@ class HomeInfoView :UIView { ...@@ -43,7 +43,6 @@ class HomeInfoView :UIView {
let sview:HomeInfoTitleView = HomeInfoTitleView(frame: CGRect(x: 0, y: 0, width: width, height: 84)) let sview:HomeInfoTitleView = HomeInfoTitleView(frame: CGRect(x: 0, y: 0, width: width, height: 84))
sview.titleLabel.text = self.titleText sview.titleLabel.text = self.titleText
sview.filterButton.isHidden = self.type != .similar && self.type != .SimilarVideos sview.filterButton.isHidden = self.type != .similar && self.type != .SimilarVideos
tableView.addSubview(sview)
return sview return sview
}() }()
...@@ -114,39 +113,35 @@ class HomeInfoView :UIView { ...@@ -114,39 +113,35 @@ class HomeInfoView :UIView {
self.headerView.sortViewSubmitCallBack = {[weak self]filterModel in self.headerView.sortViewSubmitCallBack = {[weak self]filterModel in
guard let self else {return} guard let self else {return}
// 从源头获取相似数据 var dataS : [[AssetModel]] = []
PhotoDataManager.manager.loadFromFileSystem(resultModel: {[weak self] model in if self.type == .SimilarVideos{
guard let self else {return} dataS = PhotoManager.shared.filterSimilarVideoModels
var dataS : [[AssetModel]] = [] }else {
if self.type == .SimilarVideos{ dataS = PhotoManager.shared.filterSimilarModels
dataS = model.otherModelArray[3].assets }
}else { let tempData = self.filterDataByDate(orgModels: dataS , startDate: filterModel.startDate, endDate: filterModel.endDate)
dataS = model.titleModelArray[1].assets // 重新更新下数据源
} self.ids = self.sortData(source: tempData, type: filterModel.sortType)
let tempData = self.filterDataByDate(orgModels: dataS , startDate: filterModel.startDate, endDate: filterModel.endDate) var tempModels : [HomeInfoTableItem] = []
// 重新更新下数据源 for array in self.ids ?? [] {
self.ids = self.sortData(source: tempData, type: filterModel.sortType) var smodels:[ImageSeletedCollectionItem] = []
var tempModels : [HomeInfoTableItem] = [] for id in array {
for array in self.ids ?? [] { let smodel = ImageSeletedCollectionItem()
var smodels:[ImageSeletedCollectionItem] = [] smodel.id = id
for id in array { smodel.isSeleted = false
let smodel = ImageSeletedCollectionItem() smodels.append(smodel)
smodel.id = id
smodel.isSeleted = false
smodels.append(smodel)
}
let smodel = HomeInfoTableItem()
smodel.type = type
smodel.smodels = smodels
smodel.titleText = titleText
tempModels.append(smodel)
}
models = tempModels
DispatchQueue.main.async {
// FIXME: 闪屏
self.tableView.reloadSections(IndexSet(integer: 0), with: .automatic)
} }
}) let smodel = HomeInfoTableItem()
smodel.type = type
smodel.smodels = smodels
smodel.titleText = titleText
tempModels.append(smodel)
}
models = tempModels
DispatchQueue.main.async {
self.setTitleView()
self.tableView.reloadSections(IndexSet(integer: 0), with: .automatic)
}
} }
} }
...@@ -372,7 +367,7 @@ extension HomeInfoView:UITableViewDataSource,UITableViewDelegate { ...@@ -372,7 +367,7 @@ extension HomeInfoView:UITableViewDataSource,UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return ids?.count ?? 0 return models.count
} }
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
...@@ -410,6 +405,12 @@ extension HomeInfoView:UITableViewDataSource,UITableViewDelegate { ...@@ -410,6 +405,12 @@ extension HomeInfoView:UITableViewDataSource,UITableViewDelegate {
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
return UIView() return UIView()
}
func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
tableView.addSubview(self.headerView)
tableView.bringSubviewToFront(self.headerView)
} }
func filterDataByDate(orgModels : [[AssetModel]], startDate:Date? ,endDate : Date?)->[[AssetModel]]{ func filterDataByDate(orgModels : [[AssetModel]], startDate:Date? ,endDate : Date?)->[[AssetModel]]{
...@@ -423,7 +424,7 @@ extension HomeInfoView:UITableViewDataSource,UITableViewDelegate { ...@@ -423,7 +424,7 @@ extension HomeInfoView:UITableViewDataSource,UITableViewDelegate {
array = array.filter({$0.createDate < endDate!}) array = array.filter({$0.createDate < endDate!})
} }
if array.count > 2 { if array.count >= 2 {
tempArray.append(item) tempArray.append(item)
} }
} }
...@@ -573,6 +574,9 @@ class HomeInfoTitleView:UIView { ...@@ -573,6 +574,9 @@ class HomeInfoTitleView:UIView {
@objc func filterButtonAction(){ @objc func filterButtonAction(){
if let cWindow = cWindow { if let cWindow = cWindow {
let filterView : ResourceFilterBoxView = ResourceFilterBoxView.init(frame: cWindow.bounds) let filterView : ResourceFilterBoxView = ResourceFilterBoxView.init(frame: cWindow.bounds)
// 添加毛玻璃效果
cWindow.showBlur()
cWindow.addSubview(filterView) cWindow.addSubview(filterView)
filterView.submitCallBack = {model in filterView.submitCallBack = {model in
DispatchQueue.main.async { DispatchQueue.main.async {
......
...@@ -82,17 +82,17 @@ class HomeView:UIView { ...@@ -82,17 +82,17 @@ class HomeView:UIView {
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 { 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.collectionView.reloadData()
weakSelf.homeHeader?.progressBar.chaoticProgress = CGFloat(weakSelf.viewModel.totalSize) weakSelf.homeHeader?.progressBar.chaoticProgress = CGFloat(weakSelf.viewModel.totalSize)
weakSelf.reloadHeadSize() weakSelf.reloadHeadSize()
} }
...@@ -261,7 +261,6 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol ...@@ -261,7 +261,6 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
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.homeTititlAction = {[weak self] idx in cell.homeTititlAction = {[weak self] idx in
guard let self = self else { return } guard let self = self else { return }
if indexPath.row == 0 { if indexPath.row == 0 {
...@@ -270,14 +269,6 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol ...@@ -270,14 +269,6 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
self.titleCallBack(model,.similar) 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
// }
if cell.model?.assets.count ?? 0 > 0 { if cell.model?.assets.count ?? 0 > 0 {
cell.fileLabel?.isHidden = false cell.fileLabel?.isHidden = false
...@@ -291,13 +282,6 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol ...@@ -291,13 +282,6 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
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 {
// if let image = await viewModel.coverCache.getImage(index: indexPath.row) {
// await MainActor.run {
// cell.setCoverImageOrVideo(image: image)
// }
// }
// }
return cell return cell
default: default:
return UICollectionViewCell() return UICollectionViewCell()
......
...@@ -50,6 +50,7 @@ class ResourceFilterBoxView : UIView { ...@@ -50,6 +50,7 @@ class ResourceFilterBoxView : UIView {
lazy var backView: UIView = { lazy var backView: UIView = {
let view = UIView() let view = UIView()
view.backgroundColor = UIColor(red: 0.07, green: 0.07, blue: 0.07, alpha: 0.8000) view.backgroundColor = UIColor(red: 0.07, green: 0.07, blue: 0.07, alpha: 0.8000)
view.backgroundColor = .clear
view.isUserInteractionEnabled = true view.isUserInteractionEnabled = true
let tap = UITapGestureRecognizer() let tap = UITapGestureRecognizer()
tap.addTarget(self, action: #selector(backViewClick)) tap.addTarget(self, action: #selector(backViewClick))
...@@ -211,6 +212,7 @@ class ResourceFilterBoxView : UIView { ...@@ -211,6 +212,7 @@ class ResourceFilterBoxView : UIView {
// 移除自身 // 移除自身
self.dismissDatePicker() self.dismissDatePicker()
self.removeFromSuperview() self.removeFromSuperview()
cWindow?.hideBlur()
self.submitCallBack(ResourceFilterBoxModel.init(startDate: self.startDate, endDate: self.endDate, sortType: getSortTypeByTag(tag:self.currentIndex))) self.submitCallBack(ResourceFilterBoxModel.init(startDate: self.startDate, endDate: self.endDate, sortType: getSortTypeByTag(tag:self.currentIndex)))
// 开始排序 // 开始排序
...@@ -274,6 +276,7 @@ class ResourceFilterBoxView : UIView { ...@@ -274,6 +276,7 @@ class ResourceFilterBoxView : UIView {
// 移除自身 // 移除自身
self.dismissDatePicker() self.dismissDatePicker()
self.removeFromSuperview() self.removeFromSuperview()
cWindow?.hideBlur()
} }
......
...@@ -9,10 +9,34 @@ import UIKit ...@@ -9,10 +9,34 @@ import UIKit
class VideocompressionHeadView: UIView { class VideocompressionHeadView: UIView {
@IBOutlet weak var sizeL: UILabel!
@IBOutlet weak var sizeW: NSLayoutConstraint!
override func awakeFromNib() { override func awakeFromNib() {
super.awakeFromNib() super.awakeFromNib()
layer.cornerRadius = 8 layer.cornerRadius = 8
layer.masksToBounds = true layer.masksToBounds = true
} }
func reloadData(){
let totall = PhotoManager.shared.getTotalSize(source: [PhotoManager.shared.videoModels])
let sizeKB : Double = Double(totall/2000)
if sizeKB < 1000{
self.sizeL.text = String(format: "%.0fKB" ,sizeKB)
}else if sizeKB < (1000 * 1000) && sizeKB > 1000{
self.sizeL.text = String(format: "%.0fMB" ,sizeKB/1000)
}else{
self.sizeL.text = String(format: "%.0fGB" ,sizeKB/(1000 * 1000))
}
let width = sizeL.text?.textWidthFromTextString(textHeight: 21, font: UIFont.systemFont(ofSize: 14, weight: .semibold))
sizeW.constant = (width ?? 30) + 10
}
} }
...@@ -58,6 +58,10 @@ ...@@ -58,6 +58,10 @@
<constraint firstItem="vvL-sB-aRX" firstAttribute="centerX" secondItem="Qxg-Hm-QKr" secondAttribute="centerX" id="uEJ-q5-lB3"/> <constraint firstItem="vvL-sB-aRX" firstAttribute="centerX" secondItem="Qxg-Hm-QKr" secondAttribute="centerX" id="uEJ-q5-lB3"/>
</constraints> </constraints>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/> <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<connections>
<outlet property="sizeL" destination="rDm-i5-MN1" id="AYR-5C-uKV"/>
<outlet property="sizeW" destination="ijO-3x-MyS" id="zT9-KQ-fTp"/>
</connections>
<point key="canvasLocation" x="187.78625954198472" y="250"/> <point key="canvasLocation" x="187.78625954198472" y="250"/>
</view> </view>
</objects> </objects>
......
...@@ -25,11 +25,11 @@ class ImageSeletedCollectionCell:UICollectionViewCell { ...@@ -25,11 +25,11 @@ class ImageSeletedCollectionCell:UICollectionViewCell {
lazy var allKeepButton : UIButton = { lazy var allKeepButton : UIButton = {
let button = UIButton(type: .custom) let button = UIButton(type: .custom)
button.backgroundColor = UIColor(red: 0.33, green: 0.77, blue: 0.49, alpha: 1) button.backgroundColor = UIColor(red: 0.33, green: 0.77, blue: 0.49, alpha: 1)
button.layer.cornerRadius = 7 button.layer.cornerRadius = 12
button.clipsToBounds = true button.clipsToBounds = true
button.setTitle( "All retained", for: .normal) button.setTitle( "All retained", for: .normal)
button.setTitleColor(.white, for: .normal) button.setTitleColor(.white, for: .normal)
button.titleLabel?.font = UIFont.systemFont(ofSize: 9, weight: .semibold) button.titleLabel?.font = UIFont.systemFont(ofSize: 12, weight: .semibold)
button.addTarget(self, action: #selector(allKeepButtonAction), for: .touchUpInside) button.addTarget(self, action: #selector(allKeepButtonAction), for: .touchUpInside)
button.isHidden = true button.isHidden = true
return button return button
...@@ -37,14 +37,14 @@ class ImageSeletedCollectionCell:UICollectionViewCell { ...@@ -37,14 +37,14 @@ class ImageSeletedCollectionCell:UICollectionViewCell {
lazy var bestResultButton : UIButton = { lazy var bestResultButton : UIButton = {
let button = UIButton(type: .custom) let button = UIButton(type: .custom)
button.layer.cornerRadius = 8 button.layer.cornerRadius = 10
button.clipsToBounds = true button.clipsToBounds = true
button.backgroundColor = UIColor(red: 1, green: 0.65, blue: 0, alpha: 1) button.backgroundColor = UIColor(red: 1, green: 0.65, blue: 0, alpha: 1)
button.setTitle( "Best", for: .normal) button.setTitle( "Best", for: .normal)
button.setImage(UIImage(named: "Frame"), for: .normal) button.setImage(UIImage(named: "Frame"), for: .normal)
button.setTitleColor(.white, for: .normal) button.setTitleColor(.white, for: .normal)
button.isHidden = true button.isHidden = true
button.titleLabel?.font = UIFont.systemFont(ofSize: 10, weight: .semibold) button.titleLabel?.font = UIFont.systemFont(ofSize: 12, weight: .semibold)
return button return button
}() }()
...@@ -174,15 +174,16 @@ class ImageSeletedCollectionCell:UICollectionViewCell { ...@@ -174,15 +174,16 @@ class ImageSeletedCollectionCell:UICollectionViewCell {
self.addSubview(self.bestResultButton) self.addSubview(self.bestResultButton)
self.allKeepButton.snp.makeConstraints { make in self.allKeepButton.snp.makeConstraints { make in
make.top.left.equalToSuperview() make.top.left.equalToSuperview().offset(4)
make.width.equalTo(58) make.width.equalTo(80)
make.height.equalTo(14) make.height.equalTo(24)
} }
self.bestResultButton.snp.makeConstraints { make in self.bestResultButton.snp.makeConstraints { make in
make.left.bottom.equalToSuperview() make.left.equalToSuperview().offset(4)
make.width.equalTo(52) make.bottom.equalToSuperview().offset(-4)
make.height.equalTo(16) make.width.equalTo(60)
make.height.equalTo(20)
} }
} }
...@@ -207,9 +208,9 @@ class ImageSeletedCollectionCell:UICollectionViewCell { ...@@ -207,9 +208,9 @@ class ImageSeletedCollectionCell:UICollectionViewCell {
seletedBtn?.snp.makeConstraints({ make in seletedBtn?.snp.makeConstraints({ make in
make.width.height.equalTo(24) make.width.height.equalTo(12)
make.bottom.equalToSuperview().offset(-12) make.bottom.equalToSuperview().offset(-6)
make.right.equalToSuperview().offset(-20) make.right.equalToSuperview().offset(-6)
}) })
self.extensionView.snp.makeConstraints { make in self.extensionView.snp.makeConstraints { make in
......
...@@ -10,19 +10,7 @@ class HomeViewModel { ...@@ -10,19 +10,7 @@ class HomeViewModel {
func config(){} func config(){}
var trash = TrashDatabase.shared.queryAll().compactMap{$0.localIdentifier}
var keep = GroupDatabase.shared.queryAll().compactMap{$0.localIdentifier}
func reloadTrashAndKeep(){
trash = TrashDatabase.shared.queryAll().compactMap{$0.localIdentifier}
keep = GroupDatabase.shared.queryAll().compactMap{$0.localIdentifier}
filterResource()
}
// 封面图片资源缓存 // 封面图片资源缓存
// actor CoverCacheActor { // actor CoverCacheActor {
// //
...@@ -50,17 +38,10 @@ class HomeViewModel { ...@@ -50,17 +38,10 @@ class HomeViewModel {
// } // }
private var photoManager = PhotoManager.shared private var photoManager = PhotoManager.shared
// let coverCache = CoverCacheActor()
// 相册资源总大小 // 相册资源总大小
var totalSize:Int64{ var totalSize:Int64{
return photoManager.videoTotalSize + photoManager.otherTotalSize + photoManager.screenShotTotalSize //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 totalFilesCount:Int = 0 var totalFilesCount:Int = 0
// 首页UI数据结构 // 首页UI数据结构
...@@ -84,7 +65,9 @@ class HomeViewModel { ...@@ -84,7 +65,9 @@ class HomeViewModel {
HomePhotosModel.init( HomePhotosModel.init(
folderName: HomeUIEnum.Videos.title, folderName: HomeUIEnum.Videos.title,
allFileSize:getTotalSize(source: [photoManager.filterVideoModels]), allFileSize:getTotalSize(source: [photoManager.filterVideoModels]),
assets: [photoManager.filterVideoModels]), assets: [photoManager.filterVideoModels],
originalAssets: [photoManager.videoModels]
),
HomePhotosModel.init( HomePhotosModel.init(
folderName: HomeUIEnum.SimilarScreenshots.title, folderName: HomeUIEnum.SimilarScreenshots.title,
allFileSize: getTotalSize(source: photoManager.filterSimilarScreenShotModels), allFileSize: getTotalSize(source: photoManager.filterSimilarScreenShotModels),
...@@ -92,7 +75,9 @@ class HomeViewModel { ...@@ -92,7 +75,9 @@ class HomeViewModel {
HomePhotosModel.init( HomePhotosModel.init(
folderName: HomeUIEnum.Screensshots.title, folderName: HomeUIEnum.Screensshots.title,
allFileSize:getTotalSize(source: [photoManager.filterScreenShotModels]), allFileSize:getTotalSize(source: [photoManager.filterScreenShotModels]),
assets:[photoManager.filterScreenShotModels]), assets:[photoManager.filterScreenShotModels],
originalAssets: [photoManager.screenShotModels]
),
HomePhotosModel.init( HomePhotosModel.init(
folderName: HomeUIEnum.SimilarVideos.title, folderName: HomeUIEnum.SimilarVideos.title,
allFileSize:getTotalSize(source: photoManager.filterSimilarVideoModels), allFileSize:getTotalSize(source: photoManager.filterSimilarVideoModels),
...@@ -100,7 +85,9 @@ class HomeViewModel { ...@@ -100,7 +85,9 @@ class HomeViewModel {
HomePhotosModel.init( HomePhotosModel.init(
folderName: HomeUIEnum.Other.title, folderName: HomeUIEnum.Other.title,
allFileSize:getTotalSize(source: [photoManager.filterOtherModels]), allFileSize:getTotalSize(source: [photoManager.filterOtherModels]),
assets: [photoManager.filterOtherModels]), assets: [photoManager.filterOtherModels],
originalAssets: [photoManager.otherModels]
)
] ]
} }
...@@ -115,17 +102,6 @@ class HomeViewModel { ...@@ -115,17 +102,6 @@ class HomeViewModel {
var reloadCellHeight:(() ->Void)? var reloadCellHeight:(() ->Void)?
// var dupCoverImage:[AssetModel] = []
//
// var similarCoverImage:[AssetModel] = []
//
// var headCoverImages:[[AssetModel]]{
// return [
// dupCoverImage,
// similarCoverImage
// ]
// }
func setupBindings() { func setupBindings() {
NotificationCenter.default.addObserver(forName: .getBaseAssetsSuccess, object: nil, queue: nil) {[weak self] _ in NotificationCenter.default.addObserver(forName: .getBaseAssetsSuccess, object: nil, queue: nil) {[weak self] _ in
...@@ -151,10 +127,6 @@ class HomeViewModel { ...@@ -151,10 +127,6 @@ 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.getCoverImage(type: type, identifier: screens.first?.localIdentifier)
//weakSelf.screentSize = size
weakSelf.filterResource() weakSelf.filterResource()
weakSelf.homeDataChanged?(1,type.index) weakSelf.homeDataChanged?(1,type.index)
} }
...@@ -163,9 +135,6 @@ class HomeViewModel { ...@@ -163,9 +135,6 @@ 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.getCoverImage(type: type, identifier: others.first?.localIdentifier)
// weakSelf.otherSize = size
weakSelf.filterResource() weakSelf.filterResource()
weakSelf.homeDataChanged?(1,type.index) weakSelf.homeDataChanged?(1,type.index)
} }
...@@ -174,9 +143,6 @@ class HomeViewModel { ...@@ -174,9 +143,6 @@ 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.getCoverImage(type: type, identifier: videos.first?.localIdentifier)
// weakSelf.videoSize = size
weakSelf.filterResource() weakSelf.filterResource()
weakSelf.homeDataChanged?(1,type.index) weakSelf.homeDataChanged?(1,type.index)
} }
...@@ -189,43 +155,20 @@ class HomeViewModel { ...@@ -189,43 +155,20 @@ class HomeViewModel {
getSimilarScreenOptimizer() getSimilarScreenOptimizer()
getSimilarVideoOptimizer() getSimilarVideoOptimizer()
getGroupDuplicateImages() getGroupDuplicateImages()
// DispatchQueue.main.async {[weak self] in
// guard let weakSelf = self else { return }
// weakSelf.getSimilarOptimizer()
// weakSelf.getSimilarScreenOptimizer()
// weakSelf.getSimilarVideoOptimizer()
// //weakSelf.getGroupDuplicateImages()
// }
} }
// 获取相似图片 // 获取相似图片
func getSimilarOptimizer(){ func getSimilarOptimizer(){
let type = HomeUIEnum.Similar let type = HomeUIEnum.Similar
// var currentGorup:[[AssetModel]] = []
// var currentSize:Double = 0
// var firstId:String?
var hadblock = false 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)
// currentSize += group.reduce(0){$0+$1.assetSize}
// weakSelf.totalSize += Int64(currentSize)
// weakSelf.headerGroup[type.index].assets = currentGorup
// weakSelf.headerGroup[type.index].allFileSize = currentSize
weakSelf.photoManager.similarModels.append(group) 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{ if !hadblock{
weakSelf.reloadCellHeight?() weakSelf.reloadCellHeight?()
hadblock = true hadblock = true
...@@ -246,25 +189,10 @@ class HomeViewModel { ...@@ -246,25 +189,10 @@ class HomeViewModel {
func getSimilarScreenOptimizer(){ func getSimilarScreenOptimizer(){
let type = HomeUIEnum.SimilarScreenshots let type = HomeUIEnum.SimilarScreenshots
// var currentGorup:[[AssetModel]] = []
// var currentSize:Double = 0
// 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)
// 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.photoManager.similarScreenShotModels.append(group) weakSelf.photoManager.similarScreenShotModels.append(group)
weakSelf.homeDataChanged?(1,type.index) weakSelf.homeDataChanged?(1,type.index)
...@@ -280,23 +208,9 @@ class HomeViewModel { ...@@ -280,23 +208,9 @@ class HomeViewModel {
func getSimilarVideoOptimizer(){ func getSimilarVideoOptimizer(){
let type = HomeUIEnum.SimilarVideos let type = HomeUIEnum.SimilarVideos
// var currentGorup:[[AssetModel]] = []
// var currentSize:Double = 0
// 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)
// 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.photoManager.similarVideoModels.append(group)
weakSelf.homeDataChanged?(1,type.index) weakSelf.homeDataChanged?(1,type.index)
...@@ -313,25 +227,12 @@ class HomeViewModel { ...@@ -313,25 +227,12 @@ class HomeViewModel {
func getGroupDuplicateImages(){ func getGroupDuplicateImages(){
let type = HomeUIEnum.Dublicates let type = HomeUIEnum.Dublicates
// var currentGorup:[[AssetModel]] = []
// var currentSize:Double = 0
// 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}
// weakSelf.headerGroup[type.index].assets = groups
// weakSelf.headerGroup[type.index].allFileSize = currentSize
weakSelf.photoManager.duplicateModels = groups 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 let currentThread = Thread.current
if currentThread.isMainThread { if currentThread.isMainThread {
print("在主线程执行") print("在主线程执行")
...@@ -342,31 +243,7 @@ class HomeViewModel { ...@@ -342,31 +243,7 @@ class HomeViewModel {
weakSelf.homeDataChanged?(0,type.index) weakSelf.homeDataChanged?(0,type.index)
} progressHandler: {group in } 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)
} completionHandler: {[weak self] totalGroup in } completionHandler: {[weak self] totalGroup in
guard let weakSelf = self else { return } guard let weakSelf = self else { return }
...@@ -383,73 +260,14 @@ class HomeViewModel { ...@@ -383,73 +260,14 @@ class HomeViewModel {
} }
} }
// func getCoverImage(type:HomeUIEnum,identifier:String?){ func reloadTrashAndKeep(){
// guard let identifier = identifier else{ photoManager.reloadTrashAndKeep()
// 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?()
// }
// }
// }
// })
// }
// }
}
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?() 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]] { func filterResource(){
let excludeSet = Set(ids) photoManager.filterResource()
return groups.filter { group in
// 检查子数组中是否所有元素的ID都不在排除列表中
group.allSatisfy { !excludeSet.contains($0.localIdentifier) }
}
} }
} }
...@@ -17,6 +17,10 @@ class MaintaiDetailViewController: BaseViewController { ...@@ -17,6 +17,10 @@ class MaintaiDetailViewController: BaseViewController {
var scrollIndex = 0 var scrollIndex = 0
var isFirstLoad = true var isFirstLoad = true
var removeBtn:UIButton!
var isSelectAll = false
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
configUI() configUI()
...@@ -40,25 +44,56 @@ class MaintaiDetailViewController: BaseViewController { ...@@ -40,25 +44,56 @@ class MaintaiDetailViewController: BaseViewController {
weakSelf.maintaiTipsAlertView.disMiss() weakSelf.maintaiTipsAlertView.disMiss()
} }
maintaiTipsAlertView.cancelBlock = {[weak self] in
guard let weakSelf = self else { return }
weakSelf.isSelectAll = false
}
maintaiBottomView.removeMaintaiBlock = {[weak self] in maintaiBottomView.removeMaintaiBlock = {[weak self] in
guard let weakSelf = self else { return } guard let weakSelf = self else { return }
weakSelf.maintaiTipsAlertView.show() weakSelf.maintaiTipsAlertView.show()
} }
removeBtn = UIButton()
removeBtn.setTitle("Un-keep All", for: .normal)
removeBtn.addTarget(self, action: #selector(removeAll), for: .touchUpInside)
removeBtn.setTitleColor(.black, for: .normal)
removeBtn.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .semibold)
removeBtn.isHidden = true
titleView.addSubview(removeBtn)
removeBtn.snp.makeConstraints { make in
make.right.equalTo(-16)
make.centerY.equalTo(titleView.titleLabel)
}
}
// 移除所有
@objc func removeAll(){
isSelectAll = true
maintaiTipsAlertView.show()
} }
func removeFromKeep(){ func removeFromKeep(){
if isSelectAll{
let ids = selectAsset.flatMap{$0}.compactMap{$0.localIdentifier} let ids = viewModel.souces.flatMap{$0}.compactMap{$0.localIdentifier}
if GroupDatabase.shared.batchDelete(localIdentifiers: ids){
if GroupDatabase.shared.batchDelete(localIdentifiers: ids){ self.navigationController?.popViewController(animated: true)
getData() }
selectAsset.removeAll() isSelectAll = false
}else{
let ids = selectAsset.flatMap{$0}.compactMap{$0.localIdentifier}
if GroupDatabase.shared.batchDelete(localIdentifiers: ids){
getData()
selectAsset.removeAll()
}
} }
} }
func dealBottomView(){ func dealBottomView(){
if selectAsset.count > 0{ if selectAsset.count > 0{
let count = selectAsset.flatMap{$0}.count let count = selectAsset.flatMap{$0}.count
maintaiBottomView.numberL.text = "\(count)" maintaiBottomView.numberL.text = "\(count)"
...@@ -72,10 +107,16 @@ class MaintaiDetailViewController: BaseViewController { ...@@ -72,10 +107,16 @@ class MaintaiDetailViewController: BaseViewController {
func getData(){ func getData(){
viewModel.refreshData {[weak self] in viewModel.refreshData {[weak self] in
guard let self = self else { return } guard let self = self else { return }
self.removeBtn.isHidden = viewModel.souces.count == 0
self.tableView.reloadData() self.tableView.reloadData()
if self.isFirstLoad{ if self.isFirstLoad{
self.tableView.scrollToRow(at: IndexPath.init(row: self.scrollIndex, section: 0), at: .middle, animated: true) self.tableView.layoutIfNeeded()
self.isFirstLoad = false self.isFirstLoad = false
// 异步执行滚动,确保布局已稳定
DispatchQueue.main.async {
self.tableView.scrollToRow(at: IndexPath.init(row: self.scrollIndex, section: 0), at: .middle, animated: true)
}
} }
} }
} }
...@@ -123,7 +164,7 @@ extension MaintaiDetailViewController:UITableViewDelegate,UITableViewDataSource{ ...@@ -123,7 +164,7 @@ extension MaintaiDetailViewController:UITableViewDelegate,UITableViewDataSource{
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if viewModel.souces[indexPath.row].first?.mediaType == 1,viewModel.souces[indexPath.row].count > 1{ if viewModel.souces[indexPath.row].first?.mediaType == 1{
let cell = tableView.dequeueReusableCell(withIdentifier: "MaintaiDetailTableViewCell") as! MaintaiDetailTableViewCell let cell = tableView.dequeueReusableCell(withIdentifier: "MaintaiDetailTableViewCell") as! MaintaiDetailTableViewCell
......
...@@ -15,6 +15,9 @@ class MaintainViewListController: BaseViewController { ...@@ -15,6 +15,9 @@ class MaintainViewListController: BaseViewController {
var viewModel:MaintaiViewModel = MaintaiViewModel() var viewModel:MaintaiViewModel = MaintaiViewModel()
var removeBtn:UIButton!
var isSelectAll = false
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
...@@ -37,22 +40,54 @@ class MaintainViewListController: BaseViewController { ...@@ -37,22 +40,54 @@ class MaintainViewListController: BaseViewController {
weakSelf.maintaiTipsAlertView.disMiss() weakSelf.maintaiTipsAlertView.disMiss()
} }
maintaiTipsAlertView.cancelBlock = {[weak self] in
guard let weakSelf = self else { return }
weakSelf.isSelectAll = false
}
maintaiBottomView.removeMaintaiBlock = {[weak self] in maintaiBottomView.removeMaintaiBlock = {[weak self] in
guard let weakSelf = self else { return } guard let weakSelf = self else { return }
weakSelf.maintaiTipsAlertView.show() weakSelf.maintaiTipsAlertView.show()
} }
removeBtn = UIButton()
removeBtn.setTitle("Un-keep All", for: .normal)
removeBtn.addTarget(self, action: #selector(removeAll), for: .touchUpInside)
removeBtn.setTitleColor(.black, for: .normal)
removeBtn.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .semibold)
removeBtn.isHidden = true
titleView.addSubview(removeBtn)
removeBtn.snp.makeConstraints { make in
make.right.equalTo(-16)
make.centerY.equalTo(titleView.titleLabel)
}
}
// 移除所有
@objc func removeAll(){
isSelectAll = true
maintaiTipsAlertView.show()
} }
func removeFromKeep(){ func removeFromKeep(){
if isSelectAll{
let ids = selectAsset.flatMap{$0}.compactMap{$0.localIdentifier} let ids = viewModel.souces.flatMap{$0}.compactMap{$0.localIdentifier}
if GroupDatabase.shared.batchDelete(localIdentifiers: ids){
getData()
selectAsset.removeAll()
}
isSelectAll = false
}else{
let ids = selectAsset.flatMap{$0}.compactMap{$0.localIdentifier}
if GroupDatabase.shared.batchDelete(localIdentifiers: ids){ if GroupDatabase.shared.batchDelete(localIdentifiers: ids){
getData() getData()
selectAsset.removeAll() selectAsset.removeAll()
}
} }
} }
func getData(){ func getData(){
...@@ -63,7 +98,7 @@ class MaintainViewListController: BaseViewController { ...@@ -63,7 +98,7 @@ class MaintainViewListController: BaseViewController {
} else { } else {
self.maintaiEmptyView.removeFromSuperview() self.maintaiEmptyView.removeFromSuperview()
} }
self.removeBtn.isHidden = viewModel.souces.count == 0
self.collectionView.reloadData() self.collectionView.reloadData()
} }
} }
...@@ -103,6 +138,18 @@ class MaintainViewListController: BaseViewController { ...@@ -103,6 +138,18 @@ class MaintainViewListController: BaseViewController {
maintaiEmptyView.frame = CGRectMake(0, 140, ScreenW, 330) maintaiEmptyView.frame = CGRectMake(0, 140, ScreenW, 330)
return maintaiEmptyView return maintaiEmptyView
}() }()
func dealBottomView(){
if selectAsset.count > 0{
let count = selectAsset.flatMap{$0}.count
maintaiBottomView.numberL.text = "\(count)"
view.addSubview(maintaiBottomView)
maintaiBottomView.show()
}else{
maintaiBottomView.disMiss()
}
}
} }
...@@ -134,6 +181,7 @@ extension MaintainViewListController:UICollectionViewDataSource,UICollectionView ...@@ -134,6 +181,7 @@ extension MaintainViewListController:UICollectionViewDataSource,UICollectionView
guard let weakSelf = self else { return } guard let weakSelf = self else { return }
weakSelf.selectAsset = selects weakSelf.selectAsset = selects
weakSelf.getData() weakSelf.getData()
weakSelf.dealBottomView()
} }
navigationController?.pushViewController(vc, animated: true) navigationController?.pushViewController(vc, animated: true)
} }
...@@ -154,14 +202,7 @@ extension MaintainViewListController:UICollectionViewDataSource,UICollectionView ...@@ -154,14 +202,7 @@ extension MaintainViewListController:UICollectionViewDataSource,UICollectionView
} }
if selectAsset.count > 0{ dealBottomView()
let count = selectAsset.flatMap{$0}.count
maintaiBottomView.numberL.text = "\(count)"
view.addSubview(maintaiBottomView)
maintaiBottomView.show()
}else{
maintaiBottomView.disMiss()
}
} }
} }
//
// KeepListManager.swift
// PhoneManager
//
// Created by edy on 2025/5/16.
//
import UIKit
class KeepListManager {
/// 获取保留列表所有数据
/// - Returns: 所有列表数据
static func getAllKeepListData()->[AssetModel]{
var array : [AssetModel] = []
// 单利中的数据
for (key,value) in Singleton.shared.keepList {
for item in value {
array.append(item)
}
}
// 数据库中的数据
let data = GroupDatabase.shared.queryAll()
for item in data {
array.append(AssetModel(localIdentifier: item.localIdentifier, assetSize: item.assetSize, createDate: item.createDate, mediaType: item.mediaType))
}
return array
}
}
...@@ -39,7 +39,6 @@ class MaintaiDetailTableViewCell: UITableViewCell { ...@@ -39,7 +39,6 @@ class MaintaiDetailTableViewCell: UITableViewCell {
} }
} }
func configMain(){ func configMain(){
let layout = UICollectionViewFlowLayout() let layout = UICollectionViewFlowLayout()
...@@ -47,6 +46,7 @@ class MaintaiDetailTableViewCell: UITableViewCell { ...@@ -47,6 +46,7 @@ class MaintaiDetailTableViewCell: UITableViewCell {
layout.minimumLineSpacing = 0 layout.minimumLineSpacing = 0
layout.minimumInteritemSpacing = 0 layout.minimumInteritemSpacing = 0
layout.scrollDirection = .horizontal layout.scrollDirection = .horizontal
// layout.sectionInset = UIEdgeInsets(top: 0, left: 12, bottom: 0, right: 12)
mainCollectionView.setCollectionViewLayout(layout, animated: false) mainCollectionView.setCollectionViewLayout(layout, animated: false)
mainCollectionView.dataSource = self mainCollectionView.dataSource = self
...@@ -121,11 +121,7 @@ extension MaintaiDetailTableViewCell:UICollectionViewDelegate,UICollectionViewDa ...@@ -121,11 +121,7 @@ extension MaintaiDetailTableViewCell:UICollectionViewDelegate,UICollectionViewDa
selectCallBack?(selectAsset) selectCallBack?(selectAsset)
} }
} }
extension MaintaiDetailTableViewCell:UIScrollViewDelegate{ extension MaintaiDetailTableViewCell:UIScrollViewDelegate{
...@@ -173,6 +169,15 @@ extension MaintaiDetailTableViewCell:UIScrollViewDelegate{ ...@@ -173,6 +169,15 @@ extension MaintaiDetailTableViewCell:UIScrollViewDelegate{
} }
} }
// func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
// if scrollView == mainCollectionView{
// let currentOffset = targetContentOffset.pointee.x
// let page = round(currentOffset / bigW) // 计算目标页(以 Cell 宽度为基准)
// targetContentOffset.pointee.x = page * bigW // 强制对齐到 Cell 边界
// Print("强制对齐",targetContentOffset.pointee.x )
// }
// }
func setPageOffetX(offsetX:CGFloat){ func setPageOffetX(offsetX:CGFloat){
print("----结束滑动----小图") print("----结束滑动----小图")
Print("小图滑动距离",offsetX) Print("小图滑动距离",offsetX)
......
...@@ -10,12 +10,18 @@ import AVKit ...@@ -10,12 +10,18 @@ import AVKit
class MaintaiDetialVideoCell: UITableViewCell { class MaintaiDetialVideoCell: UITableViewCell {
private var player: AVPlayer? // private var player: AVPlayer?
private var playerLayer: AVPlayerLayer? // private var playerLayer: AVPlayerLayer?
var selectBtn:UIButton! var selectBtn:UIButton!
var selectChangeBlock:(() ->Void)? var selectChangeBlock:(() ->Void)?
// var videoPath:String?{
// didSet{
// setPlayerInfo()
// }
// }
override func awakeFromNib() { override func awakeFromNib() {
super.awakeFromNib() super.awakeFromNib()
setupPlayer() setupPlayer()
...@@ -31,22 +37,25 @@ class MaintaiDetialVideoCell: UITableViewCell { ...@@ -31,22 +37,25 @@ class MaintaiDetialVideoCell: UITableViewCell {
contentView.bringSubviewToFront(selectBtn) contentView.bringSubviewToFront(selectBtn)
selectBtn.addTarget(self, action: #selector(selectChange), for: .touchUpInside) selectBtn.addTarget(self, action: #selector(selectChange), for: .touchUpInside)
selectBtn.snp.makeConstraints { make in selectBtn.snp.makeConstraints { make in
make.right.bottom.equalTo(0) make.right.equalTo(-15)
make.bottom.equalTo(-10)
make.size.equalTo(30) make.size.equalTo(30)
} }
} }
private func setupPlayer() { private func setupPlayer() {
// 创建播放器层 // 创建播放器层
playerLayer = AVPlayerLayer() // playerLayer = AVPlayerLayer()
playerLayer?.videoGravity = .resizeAspect // playerLayer?.videoGravity = .resizeAspect
contentView.layer.addSublayer(playerLayer!) contentView.layer.addSublayer(playerLayer)
} }
override func layoutSubviews() { override func layoutSubviews() {
super.layoutSubviews() super.layoutSubviews()
// 设置播放器层的frame // 设置播放器层的frame
playerLayer?.frame = CGRect(x: 0, y: 10, width: contentView.width, height: contentView.height-20) playerLayer.frame = CGRect(x: 15, y: 10, width: contentView.width-30, height: contentView.height-20)
playerLayer.cornerRadius = 15
playerLayer.masksToBounds = true
} }
var model:AssetModel?{ var model:AssetModel?{
...@@ -62,46 +71,72 @@ class MaintaiDetialVideoCell: UITableViewCell { ...@@ -62,46 +71,72 @@ class MaintaiDetialVideoCell: UITableViewCell {
} }
} }
lazy var videoPlayer:AVPlayer = {
let palyer = AVPlayer.init()
palyer.volume = 0
return palyer
}()
lazy var playerLayer:AVPlayerLayer = {
let playerLayer = AVPlayerLayer.init(player: videoPlayer)
playerLayer.backgroundColor = UIColor.black.cgColor
return playerLayer
}()
func configure(with videoURL: URL?) { func configure(with videoURL: URL?) {
guard let videoURL = videoURL else{ guard let videoURL = videoURL else{
player?.pause() videoPlayer.pause()
player = nil
return return
} }
// 创建播放器项
let playerItem = AVPlayerItem(url: videoURL)
// 创建播放器
player = AVPlayer(playerItem: playerItem)
playerLayer?.player = player let item = AVPlayerItem.init(url: videoURL)
// 设置静音 videoPlayer.replaceCurrentItem(with: item)
player?.volume = 0
// 播放视频 videoPlayer.play()
player?.play()
// // 创建播放器项
// let playerItem = AVPlayerItem(url: videoURL)
//
// // 创建播放器
// player = AVPlayer(playerItem: playerItem)
// playerLayer?.player = player
//
// // 设置静音
// player?.volume = 0
//
// // 播放视频
// player?.play()
//
// 添加播放完成的观察者 // 添加播放完成的观察者
NotificationCenter.default.addObserver(self, NotificationCenter.default.addObserver(self,
selector: #selector(playerDidFinishPlaying), selector: #selector(playerDidFinishPlaying),
name: .AVPlayerItemDidPlayToEndTime, name: .AVPlayerItemDidPlayToEndTime,
object: playerItem) object: item)
} }
//
@objc private func playerDidFinishPlaying() { @objc private func playerDidFinishPlaying() {
// 播放结束后不做任何操作,因为只需要播放一次 // // 播放结束后不做任何操作,因为只需要播放一次
player?.pause() // player?.pause()
player?.seek(to: .zero) // player?.seek(to: .zero)
//playerLayer.player?.seek(to: .zero)
videoPlayer.seek(to: .zero)
videoPlayer.play()
} }
//
override func prepareForReuse() { // override func prepareForReuse() {
super.prepareForReuse() // super.prepareForReuse()
// 清理播放器 // // 清理播放器
player?.pause() // player?.pause()
player = nil // player = nil
NotificationCenter.default.removeObserver(self) // NotificationCenter.default.removeObserver(self)
} // }
//
@objc func selectChange(){ @objc func selectChange(){
selectChangeBlock?() selectChangeBlock?()
......
...@@ -10,6 +10,8 @@ import UIKit ...@@ -10,6 +10,8 @@ import UIKit
class MaintaiTipsAlertView: UIView { class MaintaiTipsAlertView: UIView {
var confirmBlock:(() ->Void)? var confirmBlock:(() ->Void)?
var cancelBlock:(() ->Void)?
override func awakeFromNib() { override func awakeFromNib() {
super.awakeFromNib() super.awakeFromNib()
...@@ -25,6 +27,7 @@ class MaintaiTipsAlertView: UIView { ...@@ -25,6 +27,7 @@ class MaintaiTipsAlertView: UIView {
} }
func disMiss(){ func disMiss(){
cancelBlock?()
self.removeFromSuperview() self.removeFromSuperview()
} }
......
...@@ -74,12 +74,6 @@ class TrashDataManager { ...@@ -74,12 +74,6 @@ class TrashDataManager {
for item in dataDB { for item in dataDB {
assetModel.append(AssetModel.init(localIdentifier: item.localIdentifier, assetSize: item.assetSize, createDate: item.createDate, mediaType: item.mediaType)) assetModel.append(AssetModel.init(localIdentifier: item.localIdentifier, assetSize: item.assetSize, createDate: item.createDate, mediaType: item.mediaType))
} }
// 从单利拿数据
if let type = mediaType{
if let dataSg = Singleton.shared.trashData[type]{
assetModel = assetModel + dataSg
}
}
} }
return assetModel return assetModel
} }
......
...@@ -93,7 +93,7 @@ class PhotoAndVideoMananger { ...@@ -93,7 +93,7 @@ class PhotoAndVideoMananger {
class func getPrivacy(suc:@escaping callBack<Any> = {text in}) { class func getPrivacy(suc:@escaping callBack<Any> = {text in}) {
PHPhotoLibrary.requestAuthorization { status in PHPhotoLibrary.requestAuthorization { status in
PhotoAndVideoMananger.mananger.permissionStatus = status PhotoManager.shared.permissionStatus = status
switch status { switch status {
case .authorized: case .authorized:
// 用户授权访问照片库,可以继续操作 // 用户授权访问照片库,可以继续操作
...@@ -659,10 +659,10 @@ class PhotoAndVideoMananger { ...@@ -659,10 +659,10 @@ class PhotoAndVideoMananger {
static func deleteAssets(localIdentifiers: [String],suc:@escaping () -> ()) { static func deleteAssets(localIdentifiers: [String],suc:@escaping () -> ()) {
// 获取要删除的 PHAsset // 获取要删除的 PHAsset
PMLoadingHUD.share.show()
let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: localIdentifiers, options: nil) let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: localIdentifiers, options: nil)
// 开始删除操作 // 开始删除操作
PMLoadingHUD.share.show()
PHPhotoLibrary.shared().performChanges({ PHPhotoLibrary.shared().performChanges({
// 创建删除请求 // 创建删除请求
PHAssetChangeRequest.deleteAssets(fetchResult) PHAssetChangeRequest.deleteAssets(fetchResult)
......
...@@ -138,6 +138,19 @@ extension String { ...@@ -138,6 +138,19 @@ extension String {
.replacingOccurrences(of: "\r", with: "") .replacingOccurrences(of: "\r", with: "")
return cleaned return cleaned
} }
/// 动态计算宽度
/// - Parameters:
/// - textWidth: <#textWidth description#>
/// - font: <#font description#>
/// - isBold: <#isBold description#>
/// - Returns: <#description#>
public func textWidthFromTextString(textHeight: CGFloat, font: UIFont) -> CGFloat {
let dict: NSDictionary = NSDictionary(object: font,forKey: NSAttributedString.Key.font as NSCopying)
let rect: CGRect = (self as NSString).boundingRect(with: CGSize(width: CGFloat(MAXFLOAT), height: textHeight), options: [NSStringDrawingOptions.truncatesLastVisibleLine, NSStringDrawingOptions.usesFontLeading,NSStringDrawingOptions.usesLineFragmentOrigin],attributes: dict as? [NSAttributedString.Key : Any] ,context: nil)
return rect.size.width
}
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment