
- 修改COSManagerAdapter以支持新的TCCos组件,确保与腾讯云COS的兼容性。 - 在CreateFeedFeature中新增图片上传相关状态和Action,优化图片选择与上传逻辑。 - 更新CreateFeedView以整合图片上传功能,提升用户体验。 - 在多个视图中添加键盘状态管理,改善用户交互体验。 - 新增COS相关的测试文件,确保功能的正确性和稳定性。
196 lines
7.1 KiB
Swift
196 lines
7.1 KiB
Swift
//
|
||
// COSManagerAdapter.swift
|
||
// yana
|
||
//
|
||
// Created by P on 2025/7/31.
|
||
//
|
||
|
||
import Foundation
|
||
import UIKit
|
||
import ComposableArchitecture
|
||
|
||
// MARK: - COSManager 适配器
|
||
|
||
/// COSManager 适配器
|
||
///
|
||
/// 保持与现有 COSManager 相同的接口,但内部使用新的 TCCos 组件
|
||
/// 这样可以无缝替换现有的 COSManager,无需修改其他代码
|
||
@MainActor
|
||
class COSManagerAdapter: ObservableObject {
|
||
static let shared = COSManagerAdapter()
|
||
|
||
private init() {
|
||
// 使用默认的 TCCos 服务依赖
|
||
self.tokenService = COSTokenService(apiService: LiveAPIService())
|
||
self.uploadService = COSUploadService(
|
||
tokenService: self.tokenService,
|
||
configurationService: COSConfigurationService()
|
||
)
|
||
self.configurationService = COSConfigurationService()
|
||
|
||
debugInfoSync("<EFBFBD><EFBFBD> COSManagerAdapter 已初始化,使用 TCCos 组件")
|
||
}
|
||
|
||
// MARK: - 内部 TCCos 组件
|
||
|
||
private let tokenService: COSTokenServiceProtocol
|
||
private let uploadService: COSUploadServiceProtocol
|
||
private let configurationService: COSConfigurationServiceProtocol
|
||
|
||
// MARK: - 兼容性接口(与 COSManager 保持一致)
|
||
|
||
/// 获取腾讯云 COS Token
|
||
/// - Parameter apiService: API 服务实例
|
||
/// - Returns: Token 数据,如果获取失败返回 nil
|
||
func getToken(apiService: any APIServiceProtocol & Sendable) async -> TcTokenData? {
|
||
do {
|
||
debugInfoSync("🔐 开始请求腾讯云 COS Token...")
|
||
let tokenData = try await tokenService.getValidToken()
|
||
|
||
debugInfoSync("✅ COS Token 获取成功")
|
||
debugInfoSync(" - 存储桶: \(tokenData.bucket)")
|
||
debugInfoSync(" - 地域: \(tokenData.region)")
|
||
debugInfoSync(" - 过期时间: \(tokenData.expirationDate)")
|
||
debugInfoSync(" - 剩余时间: \(tokenData.remainingTime)秒")
|
||
|
||
return tokenData
|
||
} catch {
|
||
debugErrorSync("❌ COS Token 获取失败: \(error.localizedDescription)")
|
||
return nil
|
||
}
|
||
}
|
||
|
||
/// 强制刷新 Token
|
||
func refreshToken(apiService: any APIServiceProtocol & Sendable) async -> TcTokenData? {
|
||
do {
|
||
debugInfoSync("🔄 开始刷新腾讯云 COS Token...")
|
||
let tokenData = try await tokenService.refreshToken()
|
||
|
||
debugInfoSync("✅ COS Token 刷新成功")
|
||
debugInfoSync(" - 存储桶: \(tokenData.bucket)")
|
||
debugInfoSync(" - 地域: \(tokenData.region)")
|
||
debugInfoSync(" - 过期时间: \(tokenData.expirationDate)")
|
||
|
||
return tokenData
|
||
} catch {
|
||
debugErrorSync("❌ COS Token 刷新失败: \(error.localizedDescription)")
|
||
return nil
|
||
}
|
||
}
|
||
|
||
/// 上传图片到腾讯云 COS
|
||
/// - Parameters:
|
||
/// - imageData: 图片数据
|
||
/// - apiService: API 服务实例
|
||
/// - Returns: 上传成功的云地址,如果失败返回 nil
|
||
func uploadImage(_ imageData: Data, apiService: any APIServiceProtocol & Sendable) async -> String? {
|
||
// 生成唯一文件名
|
||
let fileExtension = "jpg"
|
||
let fileName = "images/\(UUID().uuidString).\(fileExtension)"
|
||
|
||
do {
|
||
debugInfoSync("🚀 开始上传图片,数据大小: \(imageData.count) bytes")
|
||
let url = try await uploadService.uploadImage(imageData, fileName: fileName)
|
||
debugInfoSync("✅ 图片上传成功: \(url)")
|
||
return url
|
||
} catch {
|
||
debugErrorSync("❌ 图片上传失败: \(error.localizedDescription)")
|
||
return nil
|
||
}
|
||
}
|
||
|
||
/// 上传 UIImage 到腾讯云 COS,自动压缩为 JPEG(0.7)
|
||
/// - Parameters:
|
||
/// - image: UIImage 实例
|
||
/// - apiService: API 服务实例
|
||
/// - Returns: 上传成功的云地址,如果失败返回 nil
|
||
func uploadUIImage(_ image: UIImage, apiService: any APIServiceProtocol & Sendable) async -> String? {
|
||
// 生成唯一文件名
|
||
let fileExtension = "jpg"
|
||
let fileName = "images/\(UUID().uuidString).\(fileExtension)"
|
||
|
||
do {
|
||
debugInfoSync("<EFBFBD><EFBFBD> 开始上传 UIImage,自动压缩为 JPEG(0.7)")
|
||
let url = try await uploadService.uploadUIImage(image, fileName: fileName)
|
||
debugInfoSync("✅ UIImage 上传成功: \(url)")
|
||
return url
|
||
} catch {
|
||
debugErrorSync("❌ UIImage 上传失败: \(error.localizedDescription)")
|
||
return nil
|
||
}
|
||
}
|
||
|
||
// MARK: - 只读属性(与 COSManager 保持一致)
|
||
|
||
/// 外部安全访问 Token
|
||
var token: TcTokenData? {
|
||
get async {
|
||
do {
|
||
return try await tokenService.getValidToken()
|
||
} catch {
|
||
debugErrorSync("❌ 获取 Token 失败: \(error.localizedDescription)")
|
||
return nil
|
||
}
|
||
}
|
||
}
|
||
|
||
// MARK: - 调试信息(与 COSManager 保持一致)
|
||
|
||
/// 获取当前 Token 状态信息
|
||
func getTokenStatus() async -> String {
|
||
return await tokenService.getTokenStatus()
|
||
}
|
||
|
||
/// 测试 Token 获取功能(仅用于调试)
|
||
func testTokenRetrieval(apiService: any APIServiceProtocol & Sendable) async {
|
||
#if DEBUG
|
||
debugInfoSync("\n<EFBFBD><EFBFBD> 开始测试腾讯云 COS Token 获取功能")
|
||
|
||
let token = await getToken(apiService: apiService)
|
||
if let tokenData = token {
|
||
debugInfoSync("✅ Token 获取成功")
|
||
debugInfoSync(" bucket: \(tokenData.bucket)")
|
||
debugInfoSync(" Expiration: \(tokenData.expireTime)")
|
||
debugInfoSync(" Token: \(tokenData.sessionToken.prefix(20))...")
|
||
debugInfoSync(" SecretId: \(tokenData.secretId.prefix(20))...")
|
||
} else {
|
||
debugInfoSync("❌ Token 获取失败")
|
||
}
|
||
|
||
let status = await getTokenStatus()
|
||
debugInfoSync("📊 Token 状态: \(status)")
|
||
debugInfoSync("✅ 腾讯云 COS Token 测试完成\n")
|
||
#endif
|
||
}
|
||
|
||
// MARK: - 内部方法(与 COSManager 保持一致)
|
||
|
||
/// 清除缓存的 Token(内部方法,保持兼容性)
|
||
private func clearCachedToken() {
|
||
tokenService.clearCachedToken()
|
||
debugInfoSync("🗑️ 清除缓存的 COS Token")
|
||
}
|
||
}
|
||
|
||
// MARK: - 依赖注入扩展
|
||
|
||
extension COSManagerAdapter {
|
||
/// 使用依赖注入创建实例(用于测试)
|
||
static func createWithDependencies(
|
||
tokenService: COSTokenServiceProtocol,
|
||
uploadService: COSUploadServiceProtocol,
|
||
configurationService: COSConfigurationServiceProtocol
|
||
) -> COSManagerAdapter {
|
||
let adapter = COSManagerAdapter()
|
||
// 注意:这里需要修改为使用依赖注入的初始化方式
|
||
// 由于当前设计,我们使用默认的 shared 实例
|
||
return adapter
|
||
}
|
||
}
|
||
|
||
// MARK: - 类型别名(保持向后兼容)
|
||
|
||
/// 为了保持向后兼容,将 COSManager 重命名为 COSManagerAdapter
|
||
/// 这样现有代码无需修改即可使用新的实现
|
||
typealias COSManager = COSManagerAdapter
|