移除 Core 层 OTG 相机实现,保留旅拍有线传图 UI 与本地照片上传能力。

将本地存储与上传编排下沉到 Features/TravelAlbum,删除 USB/PTP 相关代码与测试。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-06 10:55:40 +08:00
parent a0549e068a
commit d7fec35715
42 changed files with 187 additions and 5278 deletions

View File

@ -441,7 +441,7 @@ final class WiredCameraTransferViewModel: ObservableObject {
@Published var errorMessage: String?
let context: WiredTransferContext
private let pipeline: CameraTransferPipeline
private let pipeline = WiredCameraTransferPipeline()
private var photoStore: WiredTransferPhotoStore?
private var userIDProvider: (() -> String)?
private var downloadScope: CameraDownloadStorage.Scope?
@ -457,12 +457,8 @@ final class WiredCameraTransferViewModel: ObservableObject {
private var isLeavingPage = false
/// 线 ViewModel
init(
context: WiredTransferContext,
cameraService: any CameraServiceProtocol
) {
init(context: WiredTransferContext) {
self.context = context
self.pipeline = CameraTransferPipeline(cameraService: cameraService)
}
/// Sink
@ -473,16 +469,11 @@ final class WiredCameraTransferViewModel: ObservableObject {
accountContext: AccountContext
) async {
isLeavingPage = false
pipeline.attachToUI(
onConnectionStateChange: { [weak self] state in
self?.handleConnectionStateChange(state)
},
onTasksUpdated: { [weak self] tasks in
Task { @MainActor in
await self?.applyPipelineTasks(tasks)
}
pipeline.attachToUI { [weak self] tasks in
Task { @MainActor in
await self?.applyPipelineTasks(tasks)
}
)
}
let accountCachePrefix = accountContext.accountCachePrefix ?? "guest_"
let currentDownloadScope = CameraDownloadStorage.Scope(
@ -511,19 +502,10 @@ final class WiredCameraTransferViewModel: ObservableObject {
pipeline.configure(uploadSink: uploader, uploadEnabled: autoUpload, downloadScope: currentDownloadScope)
refreshDeviceStorageInfo()
loadPersistedPhotos()
connectionState = .disconnected
do {
await pipeline.connect()
connectionState = pipeline.connectionState
wasConnected = connectionState.isConnected
while !Task.isCancelled {
try await Task.sleep(nanoseconds: 1_000_000_000)
}
} catch is CancellationError {
// task
} catch {
errorMessage = error.localizedDescription
while !Task.isCancelled {
try? await Task.sleep(nanoseconds: 1_000_000_000)
}
detachFromUI()
}
@ -600,25 +582,20 @@ final class WiredCameraTransferViewModel: ObservableObject {
errorMessage = nil
}
/// USB
/// OTG
func refreshCameraFiles() async {
if connectionState.isConnected {
guard !isRefreshingCameraFiles else { return }
isRefreshingCameraFiles = true
defer { isRefreshingCameraFiles = false }
await pipeline.syncExistingPhotos()
return
}
await restartCameraSearch()
guard !isRefreshingCameraFiles else { return }
isRefreshingCameraFiles = true
defer { isRefreshingCameraFiles = false }
loadPersistedPhotos()
}
/// USB
/// OTG
func restartCameraSearch() async {
guard !connectionState.isConnected, !isSearchingCamera else { return }
guard !isSearchingCamera else { return }
isSearchingCamera = true
defer { isSearchingCamera = false }
await pipeline.restartCameraDiscovery()
connectionState = pipeline.connectionState
connectionState = .disconnected
}
/// / /