
主要变更: 1. 在 EPLoginTypesViewController 中添加了对多个 UI 组件的约束设置,确保布局更加灵活。 2. 更新了标题标签的文本内容,使用本地化字符串替代硬编码文本,提升国际化支持。 3. 在 EPLoginInputView 中为多个组件添加了自动布局支持,确保在不同屏幕尺寸下的适配性。 此更新旨在提升用户界面的可用性和美观性,确保更好的用户体验。
662 lines
25 KiB
Swift
662 lines
25 KiB
Swift
//
|
||
// EPEditSettingViewController.swift
|
||
// YuMi
|
||
//
|
||
// Created by AI on 2025-01-27.
|
||
//
|
||
|
||
import UIKit
|
||
import Photos
|
||
import SnapKit
|
||
|
||
/// 设置编辑页面
|
||
/// 支持头像更新、昵称修改和退出登录功能
|
||
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
|
||
}()
|
||
|
||
// MARK: - Data
|
||
|
||
private var settingItems: [SettingItem] = []
|
||
private var userInfo: UserInfoModel?
|
||
private var apiHelper: EPMineAPIHelper = EPMineAPIHelper()
|
||
|
||
// 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()
|
||
}
|
||
|
||
// 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)
|
||
}
|
||
|
||
// 设置 TableView 布局
|
||
view.addSubview(tableView)
|
||
tableView.snp.makeConstraints { make in
|
||
make.top.equalTo(profileImageView.snp.bottom).offset(40)
|
||
make.leading.trailing.bottom.equalTo(view)
|
||
}
|
||
|
||
// 添加头像点击手势
|
||
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.CheckUpdate"),
|
||
action: { [weak self] in self?.handleReservedAction("CheckUpdate") }
|
||
),
|
||
SettingItem(
|
||
title: YMLocalizedString("EPEditSetting.Logout"),
|
||
style: .default,
|
||
action: { [weak self] in self?.showLogoutConfirm() }
|
||
),
|
||
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")
|
||
}
|
||
|
||
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 ?? "昵称更新失败,请稍后重试"
|
||
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)] - 功能预留,待后续实现")
|
||
// 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)
|
||
}
|
||
|
||
// 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 ?? "未设置"
|
||
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
|
||
|
||
// 添加右箭头图标
|
||
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)
|
||
}
|
||
|
||
if item.style == .default {
|
||
cell.textLabel?.textColor = .systemRed
|
||
} else {
|
||
cell.textLabel?.textColor = .white
|
||
}
|
||
}
|
||
|
||
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: "上传失败", message: errorMsg, preferredStyle: .alert)
|
||
alert.addAction(UIAlertAction(title: "确定", 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: "更新失败",
|
||
message: msg ?? "头像更新失败,请稍后重试",
|
||
preferredStyle: .alert
|
||
)
|
||
alert.addAction(UIAlertAction(title: "确定", 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 style: UITableViewCell.SelectionStyle
|
||
let action: () -> Void
|
||
|
||
init(title: String, style: UITableViewCell.SelectionStyle = .default, action: @escaping () -> Void) {
|
||
self.title = title
|
||
self.style = style
|
||
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
|
||
)
|
||
}
|
||
}
|