对齐有线传图页 Android UI,并改用相对路径持久化本地照片。
还原顶栏、浮动卡片、时间侧栏与底部交互;照片路径改为 CameraDownloads 相对路径并兼容旧数据;格式 Chip 固定 JPG 且不可点击。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@ -0,0 +1,58 @@
|
||||
//
|
||||
// DeviceStorageHelper.swift
|
||||
// suixinkan
|
||||
//
|
||||
// 读取本机型号与可用存储,对齐 Android DeviceStorageHelper。
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
/// 设备存储快照,用于有线传图页设备信息面板。
|
||||
struct DeviceStorageSnapshot: Equatable {
|
||||
let modelName: String
|
||||
let availableGbText: String
|
||||
}
|
||||
|
||||
/// 设备存储信息读取工具。
|
||||
enum DeviceStorageHelper {
|
||||
/// 读取当前设备型号与 Documents 目录可用空间。
|
||||
static func readStorageSnapshot() -> DeviceStorageSnapshot {
|
||||
let availableBytes = availableDocumentsBytes()
|
||||
let availableGb = Double(availableBytes) / 1024.0 / 1024.0 / 1024.0
|
||||
return DeviceStorageSnapshot(
|
||||
modelName: buildModelName(),
|
||||
availableGbText: String(format: "还剩 %.1fGB 可用", availableGb)
|
||||
)
|
||||
}
|
||||
|
||||
private static func buildModelName() -> String {
|
||||
var systemInfo = utsname()
|
||||
uname(&systemInfo)
|
||||
let machine = withUnsafePointer(to: &systemInfo.machine) {
|
||||
$0.withMemoryRebound(to: CChar.self, capacity: 1) {
|
||||
String(cString: $0)
|
||||
}
|
||||
}
|
||||
let marketingName = UIDevice.current.name.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
if !marketingName.isEmpty, marketingName != "iPhone", !marketingName.hasPrefix("iPad") {
|
||||
return marketingName
|
||||
}
|
||||
if !machine.isEmpty { return machine }
|
||||
return UIDevice.current.model
|
||||
}
|
||||
|
||||
private static func availableDocumentsBytes() -> Int64 {
|
||||
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
|
||||
guard let documentsURL else { return 0 }
|
||||
let values = try? documentsURL.resourceValues(forKeys: [.volumeAvailableCapacityForImportantUsageKey])
|
||||
if let capacity = values?.volumeAvailableCapacityForImportantUsage {
|
||||
return Int64(capacity)
|
||||
}
|
||||
if let attributes = try? FileManager.default.attributesOfFileSystem(forPath: documentsURL.path),
|
||||
let freeSize = attributes[.systemFreeSize] as? NSNumber {
|
||||
return freeSize.int64Value
|
||||
}
|
||||
return 0
|
||||
}
|
||||
}
|
||||
@ -60,20 +60,44 @@ final class WiredTransferPhotoStore {
|
||||
let records = try? JSONDecoder().decode([WiredTransferPhotoRecord].self, from: data)
|
||||
else { return [] }
|
||||
|
||||
return records
|
||||
.filter { record in
|
||||
!deletedIDs.contains(record.id)
|
||||
&& record.userId == userID
|
||||
&& record.albumId == albumID
|
||||
&& record.isDisplayable
|
||||
}
|
||||
.map { $0.normalizeInterruptedTransfer() }
|
||||
let filteredRecords = records.filter { record in
|
||||
!deletedIDs.contains(record.id)
|
||||
&& record.userId == userID
|
||||
&& record.albumId == albumID
|
||||
}
|
||||
|
||||
let normalizedRecords = filteredRecords.map { $0.normalizeInterruptedTransfer() }
|
||||
let migratedRecords = normalizeStoredPaths(normalizedRecords, albumID: albumID)
|
||||
|
||||
return migratedRecords
|
||||
.filter(\.isDisplayable)
|
||||
.sorted { $0.capturedAt > $1.capturedAt }
|
||||
.also { items in
|
||||
items.forEach { bindPhotoToAlbum(photoID: $0.id, albumID: albumID) }
|
||||
}
|
||||
}
|
||||
|
||||
/// 将旧版绝对路径迁移为相对路径并回写持久化。
|
||||
private func normalizeStoredPaths(
|
||||
_ records: [WiredTransferPhotoRecord],
|
||||
albumID: Int
|
||||
) -> [WiredTransferPhotoRecord] {
|
||||
var migrated = records
|
||||
var needsPersist = false
|
||||
|
||||
for index in migrated.indices {
|
||||
guard let normalized = migrated[index].withNormalizedStoredPaths(),
|
||||
normalized != migrated[index] else { continue }
|
||||
migrated[index] = normalized
|
||||
needsPersist = true
|
||||
}
|
||||
|
||||
if needsPersist {
|
||||
save(albumID: albumID, records: migrated)
|
||||
}
|
||||
return migrated
|
||||
}
|
||||
|
||||
/// 保存相册传图记录。
|
||||
func save(albumID: Int, records: [WiredTransferPhotoRecord]) {
|
||||
guard albumID > 0 else { return }
|
||||
@ -142,7 +166,7 @@ final class WiredTransferPhotoStore {
|
||||
|
||||
private func deleteFileIfExists(_ path: String) {
|
||||
guard !path.isEmpty else { return }
|
||||
let url = URL(fileURLWithPath: path)
|
||||
guard let url = CameraDownloadStorage.resolveLocalURL(from: path) else { return }
|
||||
if FileManager.default.fileExists(atPath: url.path) {
|
||||
try? FileManager.default.removeItem(at: url)
|
||||
}
|
||||
@ -181,7 +205,43 @@ final class WiredTransferPhotoStore {
|
||||
|
||||
private extension WiredTransferPhotoRecord {
|
||||
var isDisplayable: Bool {
|
||||
!localPath.isEmpty || !remoteURL.isEmpty
|
||||
if !remoteURL.isEmpty { return true }
|
||||
if let url = CameraDownloadStorage.resolveLocalURL(from: localPath),
|
||||
FileManager.default.fileExists(atPath: url.path) {
|
||||
return true
|
||||
}
|
||||
if let url = CameraDownloadStorage.resolveLocalURL(from: thumbnailPath),
|
||||
FileManager.default.fileExists(atPath: url.path) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/// 将 localPath/thumbnailPath 中的旧版绝对路径迁移为相对路径。
|
||||
func withNormalizedStoredPaths() -> WiredTransferPhotoRecord? {
|
||||
let migratedLocalPath = localPath.isEmpty ? localPath : (CameraDownloadStorage.migrateStoredPath(localPath) ?? localPath)
|
||||
let migratedThumbnailPath = thumbnailPath.isEmpty
|
||||
? thumbnailPath
|
||||
: (CameraDownloadStorage.migrateStoredPath(thumbnailPath) ?? thumbnailPath)
|
||||
|
||||
guard migratedLocalPath != localPath || migratedThumbnailPath != thumbnailPath else { return nil }
|
||||
|
||||
return WiredTransferPhotoRecord(
|
||||
id: id,
|
||||
sourceId: sourceId,
|
||||
fileName: fileName,
|
||||
localPath: migratedLocalPath,
|
||||
thumbnailPath: migratedThumbnailPath,
|
||||
capturedAt: capturedAt,
|
||||
fileSizeBytes: fileSizeBytes,
|
||||
status: status,
|
||||
progress: progress,
|
||||
errorMessage: errorMessage,
|
||||
albumId: albumId,
|
||||
userId: userId,
|
||||
remoteURL: remoteURL,
|
||||
updatedAt: updatedAt
|
||||
)
|
||||
}
|
||||
|
||||
func normalizeInterruptedTransfer() -> WiredTransferPhotoRecord {
|
||||
|
||||
Reference in New Issue
Block a user