对齐有线传图页 Android UI,并改用相对路径持久化本地照片。
还原顶栏、浮动卡片、时间侧栏与底部交互;照片路径改为 CameraDownloads 相对路径并兼容旧数据;格式 Chip 固定 JPG 且不可点击。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@ -18,7 +18,7 @@
|
||||
|
||||
1. `SonyCameraService.connect()` 启动 USB 设备搜索。
|
||||
2. 授权通过后打开 ICC 会话并执行 Sony SDIO 握手。
|
||||
3. 拍摄事件触发 PTP 下载,文件写入 `Documents/CameraDownloads/`。
|
||||
3. 拍摄事件触发 PTP 下载,文件写入 `Documents/CameraDownloads/`,持久化路径为相对路径(如 `CameraDownloads/1730_DSC.JPG`)。
|
||||
4. 通过 `onNewAsset` 回调通知上层有新照片。
|
||||
|
||||
## 依赖
|
||||
|
||||
@ -7,16 +7,74 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
/// 相机下载文件本地存储工具,负责目录创建与安全文件名处理。
|
||||
/// 相机下载文件本地存储工具,负责目录创建、相对路径持久化与安全文件名处理。
|
||||
enum CameraDownloadStorage {
|
||||
static let cameraDownloadsFolderName = "CameraDownloads"
|
||||
|
||||
/// Documents 根目录。
|
||||
static var documentsDirectory: URL {
|
||||
FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
|
||||
}
|
||||
|
||||
/// 相机照片下载根目录。
|
||||
static var downloadsDirectory: URL {
|
||||
let documents = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
|
||||
let directory = documents.appendingPathComponent("CameraDownloads", isDirectory: true)
|
||||
let directory = documentsDirectory.appendingPathComponent(cameraDownloadsFolderName, isDirectory: true)
|
||||
try? FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true)
|
||||
return directory
|
||||
}
|
||||
|
||||
/// 将绝对路径转为相对 Documents 的路径,如 `CameraDownloads/1730_DSC.JPG`。
|
||||
static func relativePath(for url: URL) -> String {
|
||||
"\(cameraDownloadsFolderName)/\(url.lastPathComponent)"
|
||||
}
|
||||
|
||||
/// 将持久化的相对或旧版绝对路径解析为当前沙盒内的文件 URL。
|
||||
static func resolveLocalURL(from storedPath: String) -> URL? {
|
||||
guard !storedPath.isEmpty else { return nil }
|
||||
|
||||
if storedPath.hasPrefix("http://") || storedPath.hasPrefix("https://") {
|
||||
return URL(string: storedPath)
|
||||
}
|
||||
|
||||
if storedPath.hasPrefix("/") {
|
||||
let legacyURL = URL(fileURLWithPath: storedPath)
|
||||
if FileManager.default.fileExists(atPath: legacyURL.path) {
|
||||
return legacyURL
|
||||
}
|
||||
let candidate = downloadsDirectory.appendingPathComponent(legacyURL.lastPathComponent)
|
||||
if FileManager.default.fileExists(atPath: candidate.path) {
|
||||
return candidate
|
||||
}
|
||||
return legacyURL
|
||||
}
|
||||
|
||||
return documentsDirectory.appendingPathComponent(storedPath)
|
||||
}
|
||||
|
||||
/// 将旧版绝对路径迁移为相对路径;若文件已在当前 CameraDownloads 中则更新引用。
|
||||
static func migrateStoredPath(_ storedPath: String) -> String? {
|
||||
guard storedPath.hasPrefix("/") else { return storedPath }
|
||||
|
||||
let legacyURL = URL(fileURLWithPath: storedPath)
|
||||
if FileManager.default.fileExists(atPath: legacyURL.path) {
|
||||
return relativePath(for: legacyURL)
|
||||
}
|
||||
|
||||
let candidate = downloadsDirectory.appendingPathComponent(legacyURL.lastPathComponent)
|
||||
if FileManager.default.fileExists(atPath: candidate.path) {
|
||||
return relativePath(for: candidate)
|
||||
}
|
||||
|
||||
return relativePath(for: legacyURL)
|
||||
}
|
||||
|
||||
/// 判断文件是否位于 CameraDownloads 目录内。
|
||||
static func isInDownloadsDirectory(_ url: URL) -> Bool {
|
||||
let downloadsPath = downloadsDirectory.standardizedFileURL.path
|
||||
let filePath = url.standardizedFileURL.path
|
||||
return filePath.hasPrefix(downloadsPath) || filePath.hasPrefix("/private" + downloadsPath)
|
||||
}
|
||||
|
||||
/// 生成带时间戳的唯一本地文件 URL,避免文件名冲突。
|
||||
static func uniqueLocalURL(for filename: String) -> URL {
|
||||
let timestamp = Int(Date().timeIntervalSince1970)
|
||||
@ -44,4 +102,13 @@ enum CameraDownloadStorage {
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
/// 将本地存储路径转为可用于 UI 预览的 file URL 字符串。
|
||||
static func previewURLString(from storedPath: String) -> String {
|
||||
guard let url = resolveLocalURL(from: storedPath),
|
||||
FileManager.default.fileExists(atPath: url.path) else {
|
||||
return ""
|
||||
}
|
||||
return url.absoluteString
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user