Files
real-e-party-iOS/YuMi/E-P/Mine/Controllers/EPEditSettingViewController.swift.backup
2025-10-17 14:52:29 +08:00

851 lines
32 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// EPEditSettingViewController.swift
// YuMi
//
// Created by AI on 2025-01-27.
//
import UIKit
import Photos
import SnapKit
import WebKit
/// 设置编辑页面
/// 支持头像更新、昵称修改和退出登录功能
class EPEditSettingViewController: BaseViewController {
// MARK: - UI Components
private lazy var profileImageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
imageView.layer.cornerRadius = 60 // 120/2 = 60
imageView.layer.masksToBounds = true
imageView.backgroundColor = .systemGray5
imageView.isUserInteractionEnabled = true
return imageView
}()
private lazy var cameraIconView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFit
imageView.image = UIImage(named: "icon_setting_camear")
imageView.backgroundColor = UIColor(hex: "#0C0527")
imageView.layer.cornerRadius = 15 // 30/2 = 15
imageView.layer.masksToBounds = true
return imageView
}()
private lazy var tableView: UITableView = {
let tableView = UITableView(frame: .zero, style: .plain)
tableView.backgroundColor = UIColor(hex: "#0C0527")
tableView.separatorStyle = .none
tableView.delegate = self
tableView.dataSource = self
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "SettingCell")
tableView.isScrollEnabled = true // 启用内部滚动
return tableView
}()
private lazy var logoutButton: UIButton = {
let button = UIButton(type: .system)
button.setTitle(YMLocalizedString("EPEditSetting.Logout"), for: .normal)
button.setTitleColor(.white, for: .normal)
button.titleLabel?.font = .systemFont(ofSize: 17, weight: .semibold)
button.layer.cornerRadius = 25
button.addTarget(self, action: #selector(logoutButtonTapped), for: .touchUpInside)
return button
}()
// MARK: - Data
private var settingItems: [SettingItem] = []
private var userInfo: UserInfoModel?
private var apiHelper: EPMineAPIHelper = EPMineAPIHelper()
private var hasAddedGradient = false
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
setupNavigationBar()
setupUI()
setupData()
loadUserInfo()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.setNavigationBarHidden(false, animated: animated)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// 恢复父页面的导航栏配置(透明)
restoreParentNavigationBarStyle()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// 添加渐变背景到 Logout 按钮(只添加一次)
if !hasAddedGradient && logoutButton.bounds.width > 0 {
logoutButton.addGradientBackground(
with: [
UIColor(red: 0xF8/255.0, green: 0x54/255.0, blue: 0xFC/255.0, alpha: 1.0), // #F854FC
UIColor(red: 0x50/255.0, green: 0x0F/255.0, blue: 0xFF/255.0, alpha: 1.0) // #500FFF
],
start: CGPoint(x: 0, y: 0.5),
end: CGPoint(x: 1, y: 0.5),
cornerRadius: 25
)
hasAddedGradient = true
}
}
// MARK: - Setup
private func setupNavigationBar() {
title = YMLocalizedString("EPEditSetting.Title")
// 配置导航栏外观iOS 13+
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = UIColor(hex: "#0C0527")
appearance.titleTextAttributes = [
.foregroundColor: UIColor.white,
.font: UIFont.systemFont(ofSize: 18, weight: .medium)
]
appearance.shadowColor = .clear // 移除底部分割线
navigationController?.navigationBar.standardAppearance = appearance
navigationController?.navigationBar.scrollEdgeAppearance = appearance
navigationController?.navigationBar.compactAppearance = appearance
navigationController?.navigationBar.tintColor = .white // 返回按钮颜色
// 隐藏返回按钮文字,只保留箭头
navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
// 如果是从上一页 push 进来的,也要修改上一页的 backButtonTitle
navigationController?.navigationBar.topItem?.backBarButtonItem = UIBarButtonItem(
title: "",
style: .plain,
target: nil,
action: nil
)
}
private func restoreParentNavigationBarStyle() {
// 恢复透明导航栏EPMineViewController 使用的是透明导航栏)
let transparentAppearance = UINavigationBarAppearance()
transparentAppearance.configureWithTransparentBackground()
transparentAppearance.backgroundColor = .clear
transparentAppearance.shadowColor = .clear
navigationController?.navigationBar.standardAppearance = transparentAppearance
navigationController?.navigationBar.scrollEdgeAppearance = transparentAppearance
navigationController?.navigationBar.compactAppearance = transparentAppearance
}
private func setupUI() {
view.backgroundColor = UIColor(hex: "#0C0527")
// 设置头像布局
view.addSubview(profileImageView)
profileImageView.snp.makeConstraints { make in
make.top.equalTo(view.safeAreaLayoutGuide.snp.top).offset(40)
make.centerX.equalTo(view)
make.size.equalTo(120)
}
// 设置相机图标布局
view.addSubview(cameraIconView)
cameraIconView.snp.makeConstraints { make in
make.bottom.equalTo(profileImageView.snp.bottom)
make.trailing.equalTo(profileImageView.snp.trailing)
make.size.equalTo(30)
}
// 设置 Logout 按钮布局
view.addSubview(logoutButton)
logoutButton.snp.makeConstraints { make in
make.leading.trailing.equalTo(view).inset(20)
make.bottom.equalTo(view.safeAreaLayoutGuide).offset(-40)
make.height.equalTo(50)
}
// 设置 TableView 布局
view.addSubview(tableView)
tableView.snp.makeConstraints { make in
make.top.equalTo(profileImageView.snp.bottom).offset(40)
make.leading.trailing.equalTo(view)
make.bottom.equalTo(logoutButton.snp.top).offset(-20)
}
// 添加头像点击手势
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(profileImageTapped))
profileImageView.addGestureRecognizer(tapGesture)
// 添加相机图标点击手势
let cameraTapGesture = UITapGestureRecognizer(target: self, action: #selector(profileImageTapped))
cameraIconView.addGestureRecognizer(cameraTapGesture)
}
private func setupData() {
settingItems = [
SettingItem(
title: YMLocalizedString("EPEditSetting.PersonalInfo"),
action: { [weak self] in self?.handleReservedAction("PersonalInfo") }
),
SettingItem(
title: YMLocalizedString("EPEditSetting.Help"),
action: { [weak self] in self?.handleReservedAction("Help") }
),
SettingItem(
title: YMLocalizedString("EPEditSetting.ClearCache"),
action: { [weak self] in self?.handleReservedAction("ClearCache") }
),
SettingItem(
title: YMLocalizedString("EPEditSetting.AboutUs"),
action: { [weak self] in self?.handleReservedAction("AboutUs") }
)
]
NSLog("[EPEditSetting] setupData 完成,设置项数量: \(settingItems.count)")
}
private func loadUserInfo() {
// 如果已经有用户信息(从 EPMineViewController 传递),则不需要重新加载
if userInfo != nil {
updateProfileImage()
tableView.reloadData()
return
}
// 获取当前用户信息
guard let uid = AccountInfoStorage.instance().getUid(), !uid.isEmpty else {
print("[EPEditSetting] 未登录,无法获取用户信息")
return
}
// TODO: 调用API获取用户详细信息
// 这里暂时创建默认的UserInfoModel用于显示
let tempUserInfo = UserInfoModel()
tempUserInfo.nick = "User"
tempUserInfo.avatar = ""
userInfo = tempUserInfo
updateProfileImage()
tableView.reloadData()
}
private func updateProfileImage() {
guard let avatarUrl = userInfo?.avatar, !avatarUrl.isEmpty else {
profileImageView.image = UIImage(systemName: "person.circle.fill")
return
}
// 使用SDWebImage加载头像
if let url = URL(string: avatarUrl) {
profileImageView.sd_setImage(with: url, placeholderImage: UIImage(systemName: "person.circle.fill"))
}
}
// MARK: - Actions
@objc private func profileImageTapped() {
showAvatarSelectionSheet()
}
@objc private func openSettings() {
// 预留设置按钮功能
handleReservedAction("Settings")
}
@objc private func logoutButtonTapped() {
showLogoutConfirm()
}
private func showAvatarSelectionSheet() {
let alert = UIAlertController(title: YMLocalizedString("EPEditSetting.EditNickname"), message: nil, preferredStyle: .actionSheet)
// 拍照选项
alert.addAction(UIAlertAction(title: YMLocalizedString("EPEditSetting.Camera"), style: .default) { [weak self] _ in
self?.checkCameraPermissionAndPresent()
})
// 相册选项
alert.addAction(UIAlertAction(title: YMLocalizedString("EPEditSetting.PhotoLibrary"), style: .default) { [weak self] _ in
self?.checkPhotoLibraryPermissionAndPresent()
})
alert.addAction(UIAlertAction(title: YMLocalizedString("EPEditSetting.Cancel"), style: .cancel))
// iPad支持
if let popover = alert.popoverPresentationController {
popover.sourceView = profileImageView
popover.sourceRect = profileImageView.bounds
}
present(alert, animated: true)
}
private func checkCameraPermissionAndPresent() {
YYUtility.checkCameraAvailable { [weak self] in
self?.presentImagePicker(sourceType: .camera)
} denied: { [weak self] in
self?.showPermissionAlert(title: "Camera Access", message: "Please allow camera access in Settings")
} restriction: { [weak self] in
self?.showPermissionAlert(title: "Camera Restricted", message: "Camera access is restricted on this device")
}
}
private func checkPhotoLibraryPermissionAndPresent() {
YYUtility.checkAssetsLibrayAvailable { [weak self] in
self?.presentImagePicker(sourceType: .photoLibrary)
} denied: { [weak self] in
self?.showPermissionAlert(title: "Photo Library Access", message: "Please allow photo library access in Settings")
} restriction: { [weak self] in
self?.showPermissionAlert(title: "Photo Library Restricted", message: "Photo library access is restricted on this device")
}
}
private func presentImagePicker(sourceType: UIImagePickerController.SourceType) {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = sourceType
imagePicker.allowsEditing = true
present(imagePicker, animated: true)
}
private func showPermissionAlert(title: String, message: String) {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Settings", style: .default) { _ in
if let settingsURL = URL(string: UIApplication.openSettingsURLString) {
UIApplication.shared.open(settingsURL)
}
})
alert.addAction(UIAlertAction(title: YMLocalizedString("EPEditSetting.Cancel"), style: .cancel))
present(alert, animated: true)
}
private func showNicknameEditAlert() {
let alert = UIAlertController(
title: YMLocalizedString("EPEditSetting.EditNickname"),
message: nil,
preferredStyle: .alert
)
alert.addTextField { [weak self] textField in
textField.text = self?.userInfo?.nick ?? ""
textField.placeholder = YMLocalizedString("EPEditSetting.EnterNickname")
}
alert.addAction(UIAlertAction(title: YMLocalizedString("EPEditSetting.Cancel"), style: .cancel))
alert.addAction(UIAlertAction(title: YMLocalizedString("EPEditSetting.Confirm"), style: .default) { [weak self] _ in
guard let newNickname = alert.textFields?.first?.text, !newNickname.isEmpty else { return }
self?.updateNickname(newNickname)
})
present(alert, animated: true)
}
private func updateNickname(_ newNickname: String) {
// 显示加载状态
showLoading()
// 调用 API 更新昵称
apiHelper.updateNickname(withNick: newNickname,
completion: { [weak self] in
self?.hideHUD()
// 更新成功后才更新本地显示
self?.userInfo?.nick = newNickname
self?.tableView.reloadData()
// 显示成功提示
self?.showSuccessToast(YMLocalizedString("XPMineUserInfoEditViewController13"))
print("[EPEditSetting] 昵称更新成功: \(newNickname)")
},
failure: { [weak self] (code: Int, msg: String?) in
self?.hideHUD()
// 显示错误提示
let errorMsg = msg ?? YMLocalizedString("setting.nickname_update_failed")
self?.showErrorToast(errorMsg)
print("[EPEditSetting] 昵称更新失败: \(code) - \(errorMsg)")
}
)
}
private func showLogoutConfirm() {
let alert = UIAlertController(
title: YMLocalizedString("EPEditSetting.LogoutConfirm"),
message: nil,
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: YMLocalizedString("EPEditSetting.Cancel"), style: .cancel))
alert.addAction(UIAlertAction(title: YMLocalizedString("EPEditSetting.Logout"), style: .destructive) { [weak self] _ in
self?.performLogout()
})
present(alert, animated: true)
}
private func performLogout() {
guard let account = AccountInfoStorage.instance().accountModel else {
print("[EPEditSetting] 账号信息不存在")
return
}
// 调用登出API
Api.logoutCurrentAccount({ [weak self] (data, code, msg) in
DispatchQueue.main.async {
// 清除本地数据
AccountInfoStorage.instance().saveAccountInfo(nil)
AccountInfoStorage.instance().saveTicket(nil)
// 跳转登录页
self?.navigateToLogin()
}
}, access_token: account.access_token)
}
private func navigateToLogin() {
let loginVC = EPLoginViewController()
let nav = UINavigationController(rootViewController: loginVC)
if let window = UIApplication.shared.windows.first {
window.rootViewController = nav
window.makeKeyAndVisible()
}
print("[EPEditSetting] 已跳转到登录页面")
}
private func handleReservedAction(_ title: String) {
print("[\(title)] - 功能触发")
// About Us 已实现
if title == "AboutUs" {
let aboutVC = EPAboutUsViewController()
navigationController?.pushViewController(aboutVC, animated: true)
return
}
// Personal Info - 显示协议和隐私政策选项
if title == "PersonalInfo" {
showPolicyOptionsSheet()
return
}
// Help - 跳转到 FAQ 页面
if title == "Help" {
let faqUrl = getFAQURL()
openPolicyInExternalBrowser(faqUrl)
return
}
// Clear Cache - 清理图片和网页缓存
if title == "ClearCache" {
showClearCacheConfirmation()
return
}
// 其他功能预留
// TODO: Phase 2 implementation
let alert = UIAlertController(title: "Coming Soon", message: "This feature will be available in the next update.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default))
present(alert, animated: true)
}
private func showClearCacheConfirmation() {
let alert = UIAlertController(
title: YMLocalizedString("EPEditSetting.ClearCacheTitle"),
message: YMLocalizedString("EPEditSetting.ClearCacheMessage"),
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: YMLocalizedString("EPEditSetting.Cancel"), style: .cancel))
alert.addAction(UIAlertAction(title: YMLocalizedString("EPEditSetting.Confirm"), style: .destructive) { [weak self] _ in
self?.performClearCache()
})
present(alert, animated: true)
}
private func performClearCache() {
print("[EPEditSetting] 开始清理缓存")
// 显示加载状态
showLoading()
// 1. 清理 SDWebImage 图片缓存
SDWebImageManager.shared.imageCache.clear?(with: .all) {
print("[EPEditSetting] SDWebImage 缓存已清理")
// 2. 清理 WKWebsiteDataStore 网页缓存
let websiteDataTypes = WKWebsiteDataStore.allWebsiteDataTypes()
let dateFrom = Date(timeIntervalSince1970: 0)
WKWebsiteDataStore.default().removeData(ofTypes: websiteDataTypes, modifiedSince: dateFrom) { [weak self] in
print("[EPEditSetting] WKWebsiteDataStore 缓存已清理")
DispatchQueue.main.async {
self?.hideHUD()
self?.showSuccessToast(YMLocalizedString("EPEditSetting.ClearCacheSuccess"))
print("[EPEditSetting] 缓存清理完成")
}
}
}
}
private func showPolicyOptionsSheet() {
let alert = UIAlertController(
title: nil,
message: nil,
preferredStyle: .actionSheet
)
// 用户服务协议
alert.addAction(UIAlertAction(
title: YMLocalizedString("EPEditSetting.UserAgreement"),
style: .default
) { [weak self] _ in
let url = self?.getUserAgreementURL() ?? ""
self?.openPolicyInExternalBrowser(url)
})
// 隐私政策
alert.addAction(UIAlertAction(
title: YMLocalizedString("EPEditSetting.PrivacyPolicy"),
style: .default
) { [weak self] _ in
let url = self?.getPrivacyPolicyURL() ?? ""
self?.openPolicyInExternalBrowser(url)
})
// 取消
alert.addAction(UIAlertAction(
title: YMLocalizedString("EPEditSetting.Cancel"),
style: .cancel
))
// iPad 支持
if let popover = alert.popoverPresentationController {
popover.sourceView = view
popover.sourceRect = CGRect(x: view.bounds.midX, y: view.bounds.midY, width: 0, height: 0)
popover.permittedArrowDirections = []
}
present(alert, animated: true)
}
/// 获取用户协议 URL
private func getUserAgreementURL() -> String {
// kUserProtocalURL 对应枚举值 4
let url = URLWithType(URLType(rawValue: 4)!) as String
print("[EPEditSetting] User agreement URL from URLWithType: \(url)")
return url
}
/// 获取隐私政策 URL
private func getPrivacyPolicyURL() -> String {
// kPrivacyURL 对应枚举值 0
let url = URLWithType(URLType(rawValue: 0)!) as String
print("[EPEditSetting] Privacy policy URL from URLWithType: \(url)")
return url
}
/// 获取 FAQ 帮助页面 URL
private func getFAQURL() -> String {
// kFAQURL 对应枚举值 6
let url = URLWithType(URLType(rawValue: 6)!) as String
print("[EPEditSetting] FAQ URL from URLWithType: \(url)")
return url
}
private func openPolicyInExternalBrowser(_ urlString: String) {
print("[EPEditSetting] Original URL: \(urlString)")
// 如果不是完整 URL拼接域名
var fullUrl = urlString
if !urlString.hasPrefix("http") && !urlString.hasPrefix("https") {
let hostUrl = HttpRequestHelper.getHostUrl()
fullUrl = "\(hostUrl)/\(urlString)"
print("[EPEditSetting] Added host URL, full URL: \(fullUrl)")
}
print("[EPEditSetting] Opening URL in external browser: \(fullUrl)")
guard let url = URL(string: fullUrl) else {
print("[EPEditSetting] ❌ Invalid URL: \(fullUrl)")
return
}
print("[EPEditSetting] URL object created: \(url)")
// 在外部浏览器中打开
if UIApplication.shared.canOpenURL(url) {
print("[EPEditSetting] ✅ Can open URL, attempting to open...")
UIApplication.shared.open(url, options: [:]) { success in
print("[EPEditSetting] Open external browser: \(success ? "✅ Success" : "❌ Failed")")
}
} else {
print("[EPEditSetting] ❌ Cannot open URL: \(fullUrl)")
}
}
// MARK: - Public Methods
/// 更新用户信息(从 EPMineViewController 传递)
@objc func updateWithUserInfo(_ userInfo: UserInfoModel) {
self.userInfo = userInfo
updateProfileImage()
tableView.reloadData()
NSLog("[EPEditSetting] 已更新用户信息: \(userInfo.nick)")
}
}
// MARK: - UITableViewDataSource & UITableViewDelegate
extension EPEditSettingViewController: UITableViewDataSource, UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return 1 // 只有一个 section
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let count = settingItems.count + 1 // +1 for nickname row
NSLog("[EPEditSetting] TableView rows count: \(count), settingItems: \(settingItems.count)")
return count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SettingCell", for: indexPath)
cell.backgroundColor = UIColor(hex: "#0C0527")
cell.textLabel?.textColor = .white
cell.selectionStyle = .none
// 清除之前的自定义视图
cell.contentView.subviews.forEach { $0.removeFromSuperview() }
if indexPath.row == 0 {
// 昵称行
cell.textLabel?.text = YMLocalizedString("EPEditSetting.Nickname")
// 添加右箭头图标
let arrowImageView = UIImageView()
arrowImageView.image = UIImage(named: "icon_setting_right_arrow")
arrowImageView.contentMode = .scaleAspectFit
cell.contentView.addSubview(arrowImageView)
arrowImageView.snp.makeConstraints { make in
make.trailing.equalToSuperview().offset(-20)
make.centerY.equalToSuperview()
make.size.equalTo(22)
}
// 添加用户昵称标签
let nicknameLabel = UILabel()
nicknameLabel.text = userInfo?.nick ?? YMLocalizedString("user.not_set")
nicknameLabel.textColor = .lightGray
nicknameLabel.font = UIFont.systemFont(ofSize: 16)
cell.contentView.addSubview(nicknameLabel)
nicknameLabel.snp.makeConstraints { make in
make.trailing.equalTo(arrowImageView.snp.leading).offset(-12)
make.centerY.equalToSuperview()
}
} else {
// 其他设置项
let item = settingItems[indexPath.row - 1]
cell.textLabel?.text = item.title
cell.textLabel?.textColor = .white
// 添加右箭头图标
let arrowImageView = UIImageView()
arrowImageView.image = UIImage(named: "icon_setting_right_arrow")
arrowImageView.contentMode = .scaleAspectFit
cell.contentView.addSubview(arrowImageView)
arrowImageView.snp.makeConstraints { make in
make.trailing.equalToSuperview().offset(-20)
make.centerY.equalToSuperview()
make.size.equalTo(22)
}
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60 // 所有行都是 60pt 高度
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if indexPath.row == 0 {
// 昵称点击
showNicknameEditAlert()
} else {
// 设置项点击
let item = settingItems[indexPath.row - 1]
item.action()
}
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 0
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
return nil
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 0
}
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
return nil
}
}
// MARK: - UIImagePickerControllerDelegate & UINavigationControllerDelegate
extension EPEditSettingViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
picker.dismiss(animated: true)
guard let image = info[.editedImage] as? UIImage ?? info[.originalImage] as? UIImage else {
print("[EPEditSetting] 未能获取选择的图片")
return
}
// 更新头像显示
profileImageView.image = image
// 上传头像到腾讯云
uploadAvatar(image)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true)
}
private func uploadAvatar(_ image: UIImage) {
// 显示上传进度
EPProgressHUD.showProgress(0, total: 1)
// 使用 EPSDKManager 统一上传接口(避免腾讯云 OCR 配置问题)
EPSDKManager.shared.uploadImages([image],
progress: { uploaded, total in
EPProgressHUD.showProgress(uploaded, total: total)
},
success: { [weak self] resList in
EPProgressHUD.dismiss()
guard !resList.isEmpty,
let firstRes = resList.first,
let avatarUrl = firstRes["resUrl"] as? String else {
print("[EPEditSetting] 头像上传成功但无法获取URL")
return
}
print("[EPEditSetting] 头像上传成功: \(avatarUrl)")
// 调用API更新头像
self?.updateAvatarAPI(avatarUrl: avatarUrl)
},
failure: { [weak self] errorMsg in
EPProgressHUD.dismiss()
print("[EPEditSetting] 头像上传失败: \(errorMsg)")
// 显示错误提示
DispatchQueue.main.async {
let alert = UIAlertController(title: YMLocalizedString("common.upload_failed"), message: errorMsg, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: YMLocalizedString("common.confirm"), style: .default))
self?.present(alert, animated: true)
}
}
)
}
private func updateAvatarAPI(avatarUrl: String) {
// 使用 API Helper 更新头像
apiHelper.updateAvatar(withUrl: avatarUrl, completion: { [weak self] in
print("[EPEditSetting] 头像更新成功")
// 更新本地用户信息
self?.userInfo?.avatar = avatarUrl
// 通知父页面头像已更新
self?.notifyParentAvatarUpdated(avatarUrl)
}, failure: { [weak self] (code: Int, msg: String?) in
print("[EPEditSetting] 头像更新失败: \(code) - \(msg ?? "未知错误")")
// 显示错误提示
DispatchQueue.main.async {
let alert = UIAlertController(
title: YMLocalizedString("common.update_failed"),
message: msg ?? YMLocalizedString("setting.avatar_update_failed"),
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: YMLocalizedString("common.confirm"), style: .default))
self?.present(alert, animated: true)
}
})
}
private func notifyParentAvatarUpdated(_ avatarUrl: String) {
// 发送通知给 EPMineViewController 更新头像
let userInfo = ["avatarUrl": avatarUrl]
NotificationCenter.default.post(name: NSNotification.Name("EPEditSettingAvatarUpdated"), object: nil, userInfo: userInfo)
}
}
// MARK: - Helper Models
private struct SettingItem {
let title: String
let action: () -> Void
init(title: String, action: @escaping () -> Void) {
self.title = title
self.action = action
}
}
// MARK: - UIColor Extension
private extension UIColor {
convenience init(hex: String) {
let hex = hex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
var int: UInt64 = 0
Scanner(string: hex).scanHexInt64(&int)
let a, r, g, b: UInt64
switch hex.count {
case 3: // RGB (12-bit)
(a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17)
case 6: // RGB (24-bit)
(a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF)
case 8: // ARGB (32-bit)
(a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF)
default:
(a, r, g, b) = (1, 1, 1, 0)
}
self.init(
red: CGFloat(r) / 255,
green: CGFloat(g) / 255,
blue: CGFloat(b) / 255,
alpha: CGFloat(a) / 255
)
}
}