feat: 更新 EPEditSettingViewController 以增强用户信息管理功能
主要变更: 1. 在 EPEditSettingViewController 中添加了用户头像和相机图标的布局,提升用户界面友好性。 2. 引入 EPMineAPIHelper 以支持头像更新功能,简化 API 调用。 3. 优化了导航栏的显示和隐藏逻辑,确保用户体验流畅。 4. 更新了 UITableView 的数据源和布局,确保信息展示清晰。 此更新旨在提升用户体验,简化用户信息的管理和更新流程。
This commit is contained in:
@@ -12,39 +12,50 @@ import SnapKit
|
||||
/// 设置编辑页面
|
||||
/// 支持头像更新、昵称修改和退出登录功能
|
||||
class EPEditSettingViewController: UIViewController {
|
||||
|
||||
|
||||
// MARK: - UI Components
|
||||
|
||||
private lazy var tableView: UITableView = {
|
||||
let tableView = UITableView(frame: .zero, style: .grouped)
|
||||
tableView.backgroundColor = UIColor(hex: "#0C0527")
|
||||
tableView.separatorStyle = .none
|
||||
tableView.delegate = self
|
||||
tableView.dataSource = self
|
||||
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "SettingCell")
|
||||
return tableView
|
||||
}()
|
||||
|
||||
private lazy var profileImageView: UIImageView = {
|
||||
let imageView = UIImageView()
|
||||
imageView.contentMode = .scaleAspectFill
|
||||
imageView.layer.cornerRadius = 50
|
||||
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()
|
||||
navigationController?.setNavigationBarHidden(true, animated: false)
|
||||
setupNavigationBar()
|
||||
setupUI()
|
||||
setupData()
|
||||
loadUserInfo()
|
||||
@@ -52,35 +63,96 @@ class EPEditSettingViewController: UIViewController {
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
// 显示导航栏
|
||||
navigationController?.setNavigationBarHidden(false, animated: animated)
|
||||
navigationController?.navigationBar.titleTextAttributes = [
|
||||
.foregroundColor: UIColor.white,
|
||||
.font: UIFont.systemFont(ofSize: 18, weight: .medium)
|
||||
]
|
||||
navigationController?.navigationBar.barTintColor = UIColor(hex: "#0C0527")
|
||||
navigationController?.navigationBar.tintColor = .white
|
||||
navigationController?.navigationBar.isTranslucent = false
|
||||
}
|
||||
|
||||
override func viewWillDisappear(_ animated: Bool) {
|
||||
super.viewWillDisappear(animated)
|
||||
// 恢复父页面的导航栏配置(透明)
|
||||
restoreParentNavigationBarStyle()
|
||||
}
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
private func setupUI() {
|
||||
view.backgroundColor = UIColor(hex: "#0C0527")
|
||||
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(view.safeAreaLayoutGuide.snp.top)
|
||||
make.leading.trailing.bottom.equalToSuperview()
|
||||
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(
|
||||
@@ -109,9 +181,17 @@ class EPEditSettingViewController: UIViewController {
|
||||
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] 未登录,无法获取用户信息")
|
||||
@@ -159,7 +239,7 @@ class EPEditSettingViewController: UIViewController {
|
||||
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()
|
||||
@@ -307,6 +387,16 @@ class EPEditSettingViewController: UIViewController {
|
||||
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
|
||||
@@ -314,15 +404,13 @@ class EPEditSettingViewController: UIViewController {
|
||||
extension EPEditSettingViewController: UITableViewDataSource, UITableViewDelegate {
|
||||
|
||||
func numberOfSections(in tableView: UITableView) -> Int {
|
||||
return 2 // 头像昵称section + 设置项section
|
||||
return 1 // 只有一个 section
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
if section == 0 {
|
||||
return 2 // 头像 + 昵称
|
||||
} else {
|
||||
return settingItems.count
|
||||
}
|
||||
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 {
|
||||
@@ -331,35 +419,50 @@ extension EPEditSettingViewController: UITableViewDataSource, UITableViewDelegat
|
||||
cell.textLabel?.textColor = .white
|
||||
cell.selectionStyle = .none
|
||||
|
||||
if indexPath.section == 0 {
|
||||
// 头像昵称section
|
||||
if indexPath.row == 0 {
|
||||
// 头像行
|
||||
cell.textLabel?.text = YMLocalizedString("EPEditSetting.Avatar")
|
||||
cell.accessoryType = .disclosureIndicator
|
||||
|
||||
// 添加头像图片
|
||||
if cell.contentView.subviews.contains(profileImageView) {
|
||||
profileImageView.removeFromSuperview()
|
||||
}
|
||||
cell.contentView.addSubview(profileImageView)
|
||||
profileImageView.snp.makeConstraints { make in
|
||||
make.trailing.equalToSuperview().offset(-50)
|
||||
make.centerY.equalToSuperview()
|
||||
make.size.equalTo(100)
|
||||
}
|
||||
} else {
|
||||
// 昵称行
|
||||
cell.textLabel?.text = YMLocalizedString("EPEditSetting.Nickname")
|
||||
cell.detailTextLabel?.text = userInfo?.nick ?? "未设置"
|
||||
cell.detailTextLabel?.textColor = .lightGray
|
||||
cell.accessoryType = .disclosureIndicator
|
||||
// 清除之前的自定义视图
|
||||
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 {
|
||||
// 设置项section
|
||||
let item = settingItems[indexPath.row]
|
||||
// 其他设置项
|
||||
let item = settingItems[indexPath.row - 1]
|
||||
cell.textLabel?.text = item.title
|
||||
cell.accessoryType = .disclosureIndicator
|
||||
|
||||
// 添加右箭头图标
|
||||
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
|
||||
@@ -372,48 +475,36 @@ extension EPEditSettingViewController: UITableViewDataSource, UITableViewDelegat
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
|
||||
if indexPath.section == 0 && indexPath.row == 0 {
|
||||
return 120 // 头像行更高
|
||||
}
|
||||
return 60
|
||||
return 60 // 所有行都是 60pt 高度
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
|
||||
if indexPath.section == 0 {
|
||||
if indexPath.row == 0 {
|
||||
// 头像点击
|
||||
showAvatarSelectionSheet()
|
||||
} else {
|
||||
// 昵称点击
|
||||
showNicknameEditAlert()
|
||||
}
|
||||
if indexPath.row == 0 {
|
||||
// 昵称点击
|
||||
showNicknameEditAlert()
|
||||
} else {
|
||||
// 设置项点击
|
||||
let item = settingItems[indexPath.row]
|
||||
let item = settingItems[indexPath.row - 1]
|
||||
item.action()
|
||||
}
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
|
||||
return section == 0 ? 20 : 10
|
||||
return 0
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
|
||||
let view = UIView()
|
||||
view.backgroundColor = UIColor(hex: "#0C0527")
|
||||
return view
|
||||
return nil
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
|
||||
return 10
|
||||
return 0
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
|
||||
let view = UIView()
|
||||
view.backgroundColor = UIColor(hex: "#0C0527")
|
||||
return view
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -441,41 +532,75 @@ extension EPEditSettingViewController: UIImagePickerControllerDelegate, UINaviga
|
||||
}
|
||||
|
||||
private func uploadAvatar(_ image: UIImage) {
|
||||
// 压缩图片
|
||||
guard let imageData = image.jpegData(compressionQuality: 0.5) else {
|
||||
print("[EPEditSetting] 图片压缩失败")
|
||||
return
|
||||
}
|
||||
// 显示上传进度
|
||||
EPProgressHUD.showProgress(0, total: 1)
|
||||
|
||||
// 生成文件名
|
||||
let format = "jpg"
|
||||
let name = "image/\(UUID().uuidString).\(format)"
|
||||
|
||||
// 上传到腾讯云
|
||||
UploadFile.share().qCloudUploadImage(imageData, named: name, success: { [weak self] (key, resp) in
|
||||
print("[EPEditSetting] 头像上传成功: \(key)")
|
||||
|
||||
// 调用API更新头像
|
||||
self?.updateAvatarAPI(avatarUrl: key)
|
||||
|
||||
}, failure: { (resCode, message) in
|
||||
print("[EPEditSetting] 头像上传失败: \(message)")
|
||||
})
|
||||
// 使用 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更新头像
|
||||
Api.userV2UploadAvatar({ [weak self] (data, code, msg) in
|
||||
// 使用 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 {
|
||||
if code == 200 {
|
||||
print("[EPEditSetting] 头像更新成功")
|
||||
// 更新本地用户信息
|
||||
self?.userInfo?.avatar = avatarUrl
|
||||
} else {
|
||||
print("[EPEditSetting] 头像更新失败: \(String(describing: msg))")
|
||||
}
|
||||
let alert = UIAlertController(
|
||||
title: "更新失败",
|
||||
message: msg ?? "头像更新失败,请稍后重试",
|
||||
preferredStyle: .alert
|
||||
)
|
||||
alert.addAction(UIAlertAction(title: "确定", style: .default))
|
||||
self?.present(alert, animated: true)
|
||||
}
|
||||
}, avatarUrl: avatarUrl, needPay: NSNumber(value: false))
|
||||
})
|
||||
}
|
||||
|
||||
private func notifyParentAvatarUpdated(_ avatarUrl: String) {
|
||||
// 发送通知给 EPMineViewController 更新头像
|
||||
let userInfo = ["avatarUrl": avatarUrl]
|
||||
NotificationCenter.default.post(name: NSNotification.Name("EPEditSettingAvatarUpdated"), object: nil, userInfo: userInfo)
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user