feat: 优化视图组件与数据迁移逻辑

- 移除DataMigrationManager类,简化数据迁移逻辑。
- 在FeedListView和MeView中新增图片预览功能,提升用户体验。
- 更新OptimizedDynamicCardView以支持图片点击回调,增强交互性。
- 新增PreviewItem结构体以管理图片预览状态,提升代码可读性与维护性。
- 清理AppDelegate中的冗余代码,优化启动流程。
This commit is contained in:
edwinQQQ
2025-07-25 16:22:38 +08:00
parent 815091a2ff
commit 79fc03b52a
10 changed files with 174 additions and 562 deletions

View File

@@ -1,357 +0,0 @@
import Foundation
///
///
/// UserDefaults Keychain
///
///
///
/// 1.
/// 2. Keychain
/// 3.
/// 4.
@MainActor
final class DataMigrationManager {
// MARK: -
static let shared = DataMigrationManager()
private init() {}
// MARK: -
private let migrationCompleteKey = "keychain_migration_completed_v1"
// MARK: -
private enum LegacyStorageKeys {
static let userId = "user_id"
static let accessToken = "access_token"
static let userInfo = "user_info"
static let accountModel = "account_model"
static let appLanguage = "AppLanguage"
}
// MARK: -
enum MigrationResult {
case completed //
case alreadyMigrated //
case noDataToMigrate //
case failed(Error) //
var description: String {
switch self {
case .completed:
return "数据迁移完成"
case .alreadyMigrated:
return "数据已经迁移过"
case .noDataToMigrate:
return "没有需要迁移的数据"
case .failed(let error):
return "迁移失败: \(error.localizedDescription)"
}
}
}
// MARK: -
///
/// - Returns:
func performMigration() -> MigrationResult {
debugInfoSync("🔄 开始检查数据迁移...")
//
if isMigrationCompleted() {
debugInfoSync("✅ 数据已经迁移过,跳过迁移")
return .alreadyMigrated
}
//
let legacyData = collectLegacyData()
if legacyData.isEmpty {
debugInfoSync(" 没有发现需要迁移的数据")
markMigrationCompleted()
return .noDataToMigrate
}
debugInfoSync("📦 发现需要迁移的数据: \(legacyData.keys.joined(separator: ", "))")
do {
//
try migrateToKeychain(legacyData)
//
try verifyMigration(legacyData)
//
cleanupLegacyData(legacyData.keys)
//
markMigrationCompleted()
debugInfoSync("✅ 数据迁移完成")
return .completed
} catch {
debugErrorSync("❌ 数据迁移失败: \(error)")
return .failed(error)
}
}
///
func forceMigration() -> MigrationResult {
resetMigrationStatus()
return performMigration()
}
// MARK: -
///
private func isMigrationCompleted() -> Bool {
return UserDefaults.standard.bool(forKey: migrationCompleteKey)
}
///
private func markMigrationCompleted() {
UserDefaults.standard.set(true, forKey: migrationCompleteKey)
UserDefaults.standard.synchronize()
}
///
private func resetMigrationStatus() {
UserDefaults.standard.removeObject(forKey: migrationCompleteKey)
UserDefaults.standard.synchronize()
}
///
private func collectLegacyData() -> [String: Any] {
let userDefaults = UserDefaults.standard
var legacyData: [String: Any] = [:]
//
if let userId = userDefaults.string(forKey: LegacyStorageKeys.userId) {
legacyData[LegacyStorageKeys.userId] = userId
}
if let accessToken = userDefaults.string(forKey: LegacyStorageKeys.accessToken) {
legacyData[LegacyStorageKeys.accessToken] = accessToken
}
if let userInfoData = userDefaults.data(forKey: LegacyStorageKeys.userInfo) {
legacyData[LegacyStorageKeys.userInfo] = userInfoData
}
if let accountModelData = userDefaults.data(forKey: LegacyStorageKeys.accountModel) {
legacyData[LegacyStorageKeys.accountModel] = accountModelData
}
if let appLanguage = userDefaults.string(forKey: LegacyStorageKeys.appLanguage) {
legacyData[LegacyStorageKeys.appLanguage] = appLanguage
}
return legacyData
}
/// Keychain
private func migrateToKeychain(_ legacyData: [String: Any]) throws {
let keychain = KeychainManager.shared
// AccountModel
if let accountModelData = legacyData[LegacyStorageKeys.accountModel] as? Data {
do {
let accountModel = try JSONDecoder().decode(AccountModel.self, from: accountModelData)
try keychain.store(accountModel, forKey: "account_model")
debugInfoSync("✅ AccountModel 迁移成功")
} catch {
debugErrorSync("❌ AccountModel 迁移失败: \(error)")
// AccountModel
try migrateAccountModelFromIndependentFields(legacyData)
}
} else {
// AccountModel
try migrateAccountModelFromIndependentFields(legacyData)
}
// UserInfo
if let userInfoData = legacyData[LegacyStorageKeys.userInfo] as? Data {
do {
let userInfo = try JSONDecoder().decode(UserInfo.self, from: userInfoData)
try keychain.store(userInfo, forKey: "user_info")
debugInfoSync("✅ UserInfo 迁移成功")
} catch {
debugErrorSync("❌ UserInfo 迁移失败: \(error)")
throw error
}
}
//
if let appLanguage = legacyData[LegacyStorageKeys.appLanguage] as? String {
try keychain.storeString(appLanguage, forKey: "AppLanguage")
debugInfoSync("✅ 语言设置迁移成功")
}
}
/// AccountModel
private func migrateAccountModelFromIndependentFields(_ legacyData: [String: Any]) throws {
guard let userId = legacyData[LegacyStorageKeys.userId] as? String,
let accessToken = legacyData[LegacyStorageKeys.accessToken] as? String else {
debugInfoSync(" 没有足够的独立字段来重建 AccountModel")
return
}
let accountModel = AccountModel(
uid: userId,
jti: nil,
tokenType: "bearer",
refreshToken: nil,
netEaseToken: nil,
accessToken: accessToken,
expiresIn: nil,
scope: nil,
ticket: nil
)
try KeychainManager.shared.store(accountModel, forKey: "account_model")
debugInfoSync("✅ 从独立字段重建 AccountModel 成功")
}
///
private func verifyMigration(_ legacyData: [String: Any]) throws {
let keychain = KeychainManager.shared
// AccountModel
if legacyData[LegacyStorageKeys.accountModel] != nil ||
(legacyData[LegacyStorageKeys.userId] != nil && legacyData[LegacyStorageKeys.accessToken] != nil) {
let accountModel: AccountModel? = try keychain.retrieve(AccountModel.self, forKey: "account_model")
guard accountModel != nil else {
throw MigrationError.verificationFailed("AccountModel 验证失败")
}
}
// UserInfo
if legacyData[LegacyStorageKeys.userInfo] != nil {
let userInfo: UserInfo? = try keychain.retrieve(UserInfo.self, forKey: "user_info")
guard userInfo != nil else {
throw MigrationError.verificationFailed("UserInfo 验证失败")
}
}
//
if legacyData[LegacyStorageKeys.appLanguage] != nil {
let appLanguage = try keychain.retrieveString(forKey: "AppLanguage")
guard appLanguage != nil else {
throw MigrationError.verificationFailed("语言设置验证失败")
}
}
debugInfoSync("✅ 迁移数据验证成功")
}
///
private func cleanupLegacyData(_ keys: Dictionary<String, Any>.Keys) {
let userDefaults = UserDefaults.standard
for key in keys {
userDefaults.removeObject(forKey: key)
debugInfoSync("🗑️ 清理旧数据: \(key)")
}
userDefaults.synchronize()
debugInfoSync("✅ 旧数据清理完成")
}
}
// MARK: -
enum MigrationError: Error, LocalizedError {
case verificationFailed(String)
case dataCorrupted(String)
case keychainError(Error)
var errorDescription: String? {
switch self {
case .verificationFailed(let message):
return "验证失败: \(message)"
case .dataCorrupted(let message):
return "数据损坏: \(message)"
case .keychainError(let error):
return "Keychain 错误: \(error.localizedDescription)"
}
}
}
// MARK: -
extension DataMigrationManager {
///
/// AppDelegate App
static func performStartupMigration() {
let migrationResult = DataMigrationManager.shared.performMigration()
switch migrationResult {
case .completed:
debugInfoSync("🎉 应用启动时数据迁移完成")
case .alreadyMigrated:
break //
case .noDataToMigrate:
break //
case .failed(let error):
debugErrorSync("⚠️ 应用启动时数据迁移失败: \(error)")
//
}
}
}
// MARK: -
#if DEBUG
extension DataMigrationManager {
///
func debugPrintLegacyData() {
let legacyData = collectLegacyData()
debugInfoSync("🔍 旧版本数据:")
for (key, value) in legacyData {
debugInfoSync(" - \(key): \(type(of: value))")
}
}
///
func debugCreateLegacyData() {
let userDefaults = UserDefaults.standard
userDefaults.set("test_user_123", forKey: LegacyStorageKeys.userId)
userDefaults.set("test_access_token", forKey: LegacyStorageKeys.accessToken)
userDefaults.set("zh-Hans", forKey: LegacyStorageKeys.appLanguage)
userDefaults.synchronize()
debugInfoSync("🧪 已创建测试用的旧版本数据")
}
///
func debugClearAllData() {
// Keychain
do {
try KeychainManager.shared.clearAll()
} catch {
debugErrorSync("❌ 清除 Keychain 数据失败: \(error)")
}
// UserDefaults
let userDefaults = UserDefaults.standard
let allKeys = [
LegacyStorageKeys.userId,
LegacyStorageKeys.accessToken,
LegacyStorageKeys.userInfo,
LegacyStorageKeys.accountModel,
LegacyStorageKeys.appLanguage,
migrationCompleteKey
]
for key in allKeys {
userDefaults.removeObject(forKey: key)
}
userDefaults.synchronize()
debugInfoSync("🧪 已清除所有迁移相关数据")
}
}
#endif