diff --git a/YuMi.xcodeproj/project.pbxproj b/YuMi.xcodeproj/project.pbxproj index b36675c..cd65e15 100644 --- a/YuMi.xcodeproj/project.pbxproj +++ b/YuMi.xcodeproj/project.pbxproj @@ -396,7 +396,6 @@ 4C0642852E97BD9500BAF413 /* APIConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C0642842E97BD9500BAF413 /* APIConfig.swift */; }; 4C0642882E97BDA300BAF413 /* GlobalEventManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C0642872E97BDA300BAF413 /* GlobalEventManager.m */; }; 4C06428B2E98DC5F00BAF413 /* EPTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C06428A2E98DC5F00BAF413 /* EPTabBarController.swift */; }; - 4C06428E2E98DC7E00BAF413 /* EPMineViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C06428D2E98DC7E00BAF413 /* EPMineViewController.m */; }; 4C0642912E98DC8700BAF413 /* EPMomentViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C0642902E98DC8700BAF413 /* EPMomentViewController.m */; }; 4C0642992E98F77900BAF413 /* EPMomentListView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C0642982E98F77900BAF413 /* EPMomentListView.m */; }; 4C06429C2E99120600BAF413 /* EPMomentPublishViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C06429B2E99120600BAF413 /* EPMomentPublishViewController.m */; }; @@ -757,6 +756,8 @@ 4CD19EAB2E9CDF980069DAA0 /* MoliAvatar.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CD19DC02E9CDF980069DAA0 /* MoliAvatar.m */; }; 4CD19EAE2E9CDFC30069DAA0 /* EPLoginButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CD19EAC2E9CDFC30069DAA0 /* EPLoginButton.swift */; }; 4CD19EAF2E9CDFC30069DAA0 /* EPLoginInputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CD19EAD2E9CDFC30069DAA0 /* EPLoginInputView.swift */; }; + 4CD19EB12E9D12600069DAA0 /* EPEditSettingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CD19EB02E9D12600069DAA0 /* EPEditSettingViewController.swift */; }; + 4CD19EB42E9D141A0069DAA0 /* EPMineViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CD19EB32E9D141A0069DAA0 /* EPMineViewController.m */; }; 4CD401472E7183A8003F5009 /* XPPartyRoomItemCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CD401462E7183A8003F5009 /* XPPartyRoomItemCollectionViewCell.m */; }; 4CD4014A2E718E36003F5009 /* XPBlankRoomModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CD401492E718E36003F5009 /* XPBlankRoomModel.m */; }; 4CD47BB52E61514900BCDA46 /* StageViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CD47BB42E61514900BCDA46 /* StageViewManager.m */; }; @@ -2433,8 +2434,6 @@ 4C0642872E97BDA300BAF413 /* GlobalEventManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GlobalEventManager.m; sourceTree = ""; }; 4C0642892E97BDC900BAF413 /* YuMi-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "YuMi-Bridging-Header.h"; sourceTree = ""; }; 4C06428A2E98DC5F00BAF413 /* EPTabBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EPTabBarController.swift; sourceTree = ""; }; - 4C06428C2E98DC7E00BAF413 /* EPMineViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EPMineViewController.h; sourceTree = ""; }; - 4C06428D2E98DC7E00BAF413 /* EPMineViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EPMineViewController.m; sourceTree = ""; }; 4C06428F2E98DC8700BAF413 /* EPMomentViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EPMomentViewController.h; sourceTree = ""; }; 4C0642902E98DC8700BAF413 /* EPMomentViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EPMomentViewController.m; sourceTree = ""; }; 4C0642972E98F77900BAF413 /* EPMomentListView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EPMomentListView.h; sourceTree = ""; }; @@ -2970,6 +2969,9 @@ 4CD19DC82E9CDF980069DAA0 /* XNDJTDDLoadingTool.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = XNDJTDDLoadingTool.m; sourceTree = ""; }; 4CD19EAC2E9CDFC30069DAA0 /* EPLoginButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EPLoginButton.swift; sourceTree = ""; }; 4CD19EAD2E9CDFC30069DAA0 /* EPLoginInputView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EPLoginInputView.swift; sourceTree = ""; }; + 4CD19EB02E9D12600069DAA0 /* EPEditSettingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EPEditSettingViewController.swift; sourceTree = ""; }; + 4CD19EB22E9D141A0069DAA0 /* EPMineViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EPMineViewController.h; sourceTree = ""; }; + 4CD19EB32E9D141A0069DAA0 /* EPMineViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EPMineViewController.m; sourceTree = ""; }; 4CD401452E7183A8003F5009 /* XPPartyRoomItemCollectionViewCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = XPPartyRoomItemCollectionViewCell.h; sourceTree = ""; }; 4CD401462E7183A8003F5009 /* XPPartyRoomItemCollectionViewCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = XPPartyRoomItemCollectionViewCell.m; sourceTree = ""; }; 4CD401482E718E36003F5009 /* XPBlankRoomModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = XPBlankRoomModel.h; sourceTree = ""; }; @@ -6376,8 +6378,9 @@ 4C0642712E97BD6D00BAF413 /* Controllers */ = { isa = PBXGroup; children = ( - 4C06428C2E98DC7E00BAF413 /* EPMineViewController.h */, - 4C06428D2E98DC7E00BAF413 /* EPMineViewController.m */, + 4CD19EB22E9D141A0069DAA0 /* EPMineViewController.h */, + 4CD19EB32E9D141A0069DAA0 /* EPMineViewController.m */, + 4CD19EB02E9D12600069DAA0 /* EPEditSettingViewController.swift */, ); path = Controllers; sourceTree = ""; @@ -12415,7 +12418,6 @@ 23FF426D2AA5E4EE0055733C /* XPNewHomePartyAudioView.m in Sources */, E81060E82987720F00B772F0 /* MessageUnSupportModel.m in Sources */, E8D34D6028082BA5009C4835 /* XPMineUserDataPresenter.m in Sources */, - 4C06428E2E98DC7E00BAF413 /* EPMineViewController.m in Sources */, E84CBCE4284372D800D43221 /* XPRoomHalfMessageView.m in Sources */, E8EEB8F226FC2050007C6EBA /* SDPhotoBrowser.m in Sources */, 23CEFC4F2AFB8FC100576D89 /* BSSDLayoutUtil.m in Sources */, @@ -12640,6 +12642,7 @@ E8412FB02779CB4D006E1101 /* XPRoomSettingPresenter.m in Sources */, E878893C273A54C300BF1D57 /* Api+Gift.m in Sources */, E897ABFC28AF2E71003B3587 /* XPSailingGiftView.m in Sources */, + 4CD19EB42E9D141A0069DAA0 /* EPMineViewController.m in Sources */, E8998D8028597B0300C68558 /* XPRoomLuckyBigPrizeView.m in Sources */, E88E4A80297673DC00019A50 /* SessionNavLiveView.m in Sources */, 544879EA2CD215F400D58DC1 /* CustomRoomBGCell.m in Sources */, @@ -13064,6 +13067,7 @@ 9BAA5FED277A1BBE007453F3 /* XPPrivacyViewController.m in Sources */, E873EB02280922720071030D /* XPMineUserInfoEmptyCollectionViewCell.m in Sources */, E872309326E8D31500B90D4F /* LoginVerifCodeView.m in Sources */, + 4CD19EB12E9D12600069DAA0 /* EPEditSettingViewController.swift in Sources */, E82107872987E49100DE7040 /* MessageRedPacketModel.m in Sources */, 23B8D8E12B87715100CA472F /* PIGeneralPublicScreenModel.m in Sources */, 23194DD52AD292F200649F51 /* PIPageControl.m in Sources */, diff --git a/YuMi/E-P/NewMine/Controllers/EPEditSettingViewController.swift b/YuMi/E-P/NewMine/Controllers/EPEditSettingViewController.swift new file mode 100644 index 0000000..e5cf36b --- /dev/null +++ b/YuMi/E-P/NewMine/Controllers/EPEditSettingViewController.swift @@ -0,0 +1,522 @@ +// +// EPEditSettingViewController.swift +// YuMi +// +// Created by AI on 2025-01-27. +// + +import UIKit +import Photos +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.masksToBounds = true + imageView.backgroundColor = .systemGray5 + imageView.isUserInteractionEnabled = true + return imageView + }() + + // MARK: - Data + + private var settingItems: [SettingItem] = [] + private var userInfo: UserInfoModel? + + // MARK: - Lifecycle + + override func viewDidLoad() { + super.viewDidLoad() + navigationController?.setNavigationBarHidden(true, animated: false) + setupUI() + setupData() + loadUserInfo() + } + + 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 + } + + // MARK: - Setup + + private func setupUI() { + view.backgroundColor = UIColor(hex: "#0C0527") + title = YMLocalizedString("EPEditSetting.Title") + + view.addSubview(tableView) + tableView.snp.makeConstraints { make in + make.top.equalTo(view.safeAreaLayoutGuide.snp.top) + make.leading.trailing.bottom.equalToSuperview() + } + + // 添加头像点击手势 + let tapGesture = UITapGestureRecognizer(target: self, action: #selector(profileImageTapped)) + profileImageView.addGestureRecognizer(tapGesture) + } + + 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") } + ) + ] + } + + private func loadUserInfo() { + // 获取当前用户信息 + 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) { + // 构建UserInfoModel并调用更新方法 + let userInfo = UserInfoModel() + userInfo.nick = newNickname + + // 调用Presenter方法 (桥接到OC) + let presenter = XPMineUserInfoEditPresenter() + presenter.getUserInfoEditDataSource(withUserInfo: userInfo) + + // 更新本地显示 + self.userInfo?.nick = newNickname + tableView.reloadData() + + print("[EPEditSetting] 昵称更新为: \(newNickname)") + } + + 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: - UITableViewDataSource & UITableViewDelegate + +extension EPEditSettingViewController: UITableViewDataSource, UITableViewDelegate { + + func numberOfSections(in tableView: UITableView) -> Int { + return 2 // 头像昵称section + 设置项section + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + if section == 0 { + return 2 // 头像 + 昵称 + } else { + return settingItems.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 + + 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 + } + } else { + // 设置项section + let item = settingItems[indexPath.row] + cell.textLabel?.text = item.title + cell.accessoryType = .disclosureIndicator + + if item.style == .default { + cell.textLabel?.textColor = .systemRed + } else { + cell.textLabel?.textColor = .white + } + } + + return cell + } + + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + if indexPath.section == 0 && indexPath.row == 0 { + return 120 // 头像行更高 + } + return 60 + } + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.deselectRow(at: indexPath, animated: true) + + if indexPath.section == 0 { + if indexPath.row == 0 { + // 头像点击 + showAvatarSelectionSheet() + } else { + // 昵称点击 + showNicknameEditAlert() + } + } else { + // 设置项点击 + let item = settingItems[indexPath.row] + item.action() + } + } + + func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + return section == 0 ? 20 : 10 + } + + func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + let view = UIView() + view.backgroundColor = UIColor(hex: "#0C0527") + return view + } + + func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat { + return 10 + } + + func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { + let view = UIView() + view.backgroundColor = UIColor(hex: "#0C0527") + return view + } +} + +// 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) { + // 压缩图片 + guard let imageData = image.jpegData(compressionQuality: 0.5) else { + print("[EPEditSetting] 图片压缩失败") + return + } + + // 生成文件名 + 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)") + }) + } + + private func updateAvatarAPI(avatarUrl: String) { + // 调用API更新头像 + Api.userV2UploadAvatar({ [weak self] (data, code, msg) in + DispatchQueue.main.async { + if code == 200 { + print("[EPEditSetting] 头像更新成功") + // 更新本地用户信息 + self?.userInfo?.avatar = avatarUrl + } else { + print("[EPEditSetting] 头像更新失败: \(String(describing: msg))") + } + } + }, avatarUrl: avatarUrl, needPay: NSNumber(value: false)) + } +} + +// 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 + ) + } +} diff --git a/YuMi/E-P/NewMine/Controllers/EPMineViewController.m b/YuMi/E-P/NewMine/Controllers/EPMineViewController.m index 5df5277..674d2b8 100644 --- a/YuMi/E-P/NewMine/Controllers/EPMineViewController.m +++ b/YuMi/E-P/NewMine/Controllers/EPMineViewController.m @@ -12,6 +12,8 @@ #import "EPMineAPIHelper.h" #import "AccountInfoStorage.h" #import "UserInfoModel.h" +#import +#import "YuMi-Swift.h" // 导入Swift桥接 @interface EPMineViewController () @@ -42,7 +44,7 @@ [self setupUI]; - NSLog(@"[EPMineViewController] 个人主页加载完成"); + NSLog(@"[EPMineViewController] viewDidLoad 完成"); } - (void)viewWillAppear:(BOOL)animated { @@ -56,17 +58,10 @@ } // MARK: - Setup + - (void)setupUI { - // 先设置纯色背景作为兜底,避免白色闪烁 - self.view.backgroundColor = [UIColor clearColor]; - - UIImageView *bgImageView = [[UIImageView alloc] initWithImage:kImage(@"vc_bg")]; - bgImageView.contentMode = UIViewContentModeScaleAspectFill; - bgImageView.clipsToBounds = YES; - [self.view addSubview:bgImageView]; - [bgImageView mas_makeConstraints:^(MASConstraintMaker *make) { - make.edges.mas_equalTo(self.view); - }]; + // 背景渐变色 + self.view.backgroundColor = [UIColor colorWithRed:0.047 green:0.020 blue:0.153 alpha:1.0]; // #0C0527 [self setupHeaderView]; [self setupMomentListView]; @@ -75,76 +70,88 @@ } - (void)setupHeaderView { - self.headerView = [[EPMineHeaderView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 300)]; - + self.headerView = [[EPMineHeaderView alloc] initWithFrame:CGRectZero]; [self.view addSubview:self.headerView]; - [self.headerView mas_makeConstraints:^(MASConstraintMaker *make) { - make.top.equalTo(self.view).offset(20); - make.leading.trailing.equalTo(self.view); - make.height.equalTo(@300); - }]; + // 使用约束布局 + self.headerView.translatesAutoresizingMaskIntoConstraints = NO; + [NSLayoutConstraint activateConstraints:@[ + [self.headerView.topAnchor constraintEqualToAnchor:self.view.topAnchor], + [self.headerView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], + [self.headerView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor], + [self.headerView.heightAnchor constraintEqualToConstant:320] + ]]; + + // 监听设置按钮点击事件 + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(openSettings) + name:@"EPMineHeaderSettingsButtonTapped" + object:nil]; } - (void)setupMomentListView { + self.momentListView = [[EPMomentListView alloc] initWithFrame:CGRectZero]; [self.view addSubview:self.momentListView]; - [self.momentListView mas_makeConstraints:^(MASConstraintMaker *make) { - make.top.equalTo(self.headerView.mas_bottom).offset(10); - make.leading.trailing.bottom.equalTo(self.view); - }]; + // 使用约束布局 + self.momentListView.translatesAutoresizingMaskIntoConstraints = NO; + [NSLayoutConstraint activateConstraints:@[ + [self.momentListView.topAnchor constraintEqualToAnchor:self.headerView.bottomAnchor], + [self.momentListView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], + [self.momentListView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor], + [self.momentListView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor] + ]]; } // MARK: - Data Loading - (void)loadUserDetailInfo { NSString *uid = [[AccountInfoStorage instance] getUid]; - if (!uid.length) { - NSLog(@"[EPMineViewController] 未登录,无法获取用户信息"); + if (!uid || uid.length == 0) { + NSLog(@"[EPMineViewController] 用户未登录"); return; } __weak typeof(self) weakSelf = self; - [self.apiHelper getUserDetailInfoWithUid:uid completion:^(UserInfoModel * _Nullable userInfo) { + [self.apiHelper getUserDetailInfoWithUid:uid + completion:^(UserInfoModel * _Nullable userInfo) { __strong typeof(weakSelf) self = weakSelf; + if (!userInfo) { + NSLog(@"[EPMineViewController] 加载用户信息失败"); + return; + } + self.userInfo = userInfo; + [self updateHeaderWithUserInfo:userInfo]; - // 更新头部视图 - NSDictionary *userInfoDict = @{ - @"nickname": userInfo.nick ?: @"未设置昵称", - @"avatar": userInfo.avatar ?: @"", - @"uid": userInfo.uid > 0 ? @(userInfo.uid).stringValue : @"", - @"followers": @(userInfo.fansNum), - @"following": @(userInfo.followNum), - }; - [self.headerView updateWithUserInfo:userInfoDict]; - - // 使用本地数组模式显示用户动态 - [self.momentListView loadWithDynamicInfo:userInfo.dynamicInfo refreshCallback:^{ - [self loadUserDetailInfo]; - }]; - - NSLog(@"[EPMineViewController] 用户详情加载成功: %@ (动态数: %lu)", - userInfo.nick, (unsigned long)userInfo.dynamicInfo.count); - + // 如果有动态信息,直接使用 + if (userInfo.dynamicInfo && userInfo.dynamicInfo.count > 0) { + [self.momentListView loadWithDynamicInfo:userInfo.dynamicInfo refreshCallback:^{ + [self loadUserDetailInfo]; // 刷新时重新加载 + }]; + } } failure:^(NSInteger code, NSString * _Nullable msg) { - NSLog(@"[EPMineViewController] 用户详情加载失败: code=%ld, msg=%@", (long)code, msg); + NSLog(@"[EPMineViewController] 加载用户信息失败: %@", msg); }]; } +- (void)updateHeaderWithUserInfo:(UserInfoModel *)userInfo { + NSDictionary *userInfoDict = @{ + @"nickname": userInfo.nick ?: @"未设置昵称", + @"uid": [NSString stringWithFormat:@"%ld", (long)userInfo.uid], + @"avatar": userInfo.avatar ?: @"", + @"following": @(userInfo.followNum), + @"followers": @(userInfo.fansNum) + }; + + [self.headerView updateWithUserInfo:userInfoDict]; +} + // MARK: - Lazy Loading -- (EPMineHeaderView *)headerView { - if (!_headerView) { - _headerView = [[EPMineHeaderView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 300)]; - } - return _headerView; -} - - (EPMomentListView *)momentListView { if (!_momentListView) { - _momentListView = [[EPMomentListView alloc] initWithFrame:CGRectZero]; - + _momentListView = [[EPMomentListView alloc] init]; __weak typeof(self) weakSelf = self; _momentListView.onSelectMoment = ^(NSInteger index) { __strong typeof(weakSelf) self = weakSelf; @@ -162,4 +169,16 @@ return _apiHelper; } +// MARK: - Actions + +- (void)openSettings { + EPEditSettingViewController *settingsVC = [[EPEditSettingViewController alloc] init]; + [self.navigationController pushViewController:settingsVC animated:YES]; + NSLog(@"[EPMineViewController] 打开设置页面"); +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + @end diff --git a/YuMi/E-P/NewMine/Views/EPMineHeaderView.m b/YuMi/E-P/NewMine/Views/EPMineHeaderView.m index 4c6cb3d..e1b9949 100644 --- a/YuMi/E-P/NewMine/Views/EPMineHeaderView.m +++ b/YuMi/E-P/NewMine/Views/EPMineHeaderView.m @@ -159,7 +159,8 @@ - (void)settingsButtonTapped { NSLog(@"[EPMineHeaderView] 设置按钮点击"); - // TODO: 发送通知或回调给父视图 + // 发送通知给父视图 + [[NSNotificationCenter defaultCenter] postNotificationName:@"EPMineHeaderSettingsButtonTapped" object:nil]; } @end \ No newline at end of file diff --git a/YuMi/YuMi-Bridging-Header.h b/YuMi/YuMi-Bridging-Header.h index b84bc5b..50760db 100644 --- a/YuMi/YuMi-Bridging-Header.h +++ b/YuMi/YuMi-Bridging-Header.h @@ -39,6 +39,11 @@ #import "AccountInfoStorage.h" #import "MomentsInfoModel.h" #import "MomentsListInfoModel.h" +#import "UserInfoModel.h" +#import "XPMineUserInfoEditPresenter.h" +#import "UploadFile.h" +#import "YYUtility.h" +#import "SDWebImage.h" // MARK: - Utilities #import "UIImage+Utils.h" diff --git a/YuMi/ar.lproj/Localizable.strings b/YuMi/ar.lproj/Localizable.strings index f221477..7e0c877 100644 --- a/YuMi/ar.lproj/Localizable.strings +++ b/YuMi/ar.lproj/Localizable.strings @@ -4256,3 +4256,23 @@ ineHeadView12" = "الحمل"; "20.20.62_text_22" = "لقد شغّلت شاشة ميكروفون CP."; "20.20.62_text_23" = "لقد أوقفت شاشة ميكروفون CP. شاشة ميكروفون CP غير مرئية في هذه الغرفة. انقر لتفعيلها مرة أخرى."; "20.20.62_text_24" = "لقد أوقفت وضع التربو."; + +// EPEditSetting - 设置页面多语言Key +"EPEditSetting.Title" = "Edit"; +"EPEditSetting.Avatar" = "Avatar"; +"EPEditSetting.Nickname" = "Nickname"; +"EPEditSetting.PersonalInfo" = "Personal Information and Permissions"; +"EPEditSetting.Help" = "Help"; +"EPEditSetting.ClearCache" = "Clear Cache"; +"EPEditSetting.CheckUpdate" = "Check for Updates"; +"EPEditSetting.AboutUs" = "About Us"; +"EPEditSetting.Logout" = "Log out of account"; + +// Alert +"EPEditSetting.Camera" = "Take Photo"; +"EPEditSetting.PhotoLibrary" = "Choose from Album"; +"EPEditSetting.EditNickname" = "Edit Nickname"; +"EPEditSetting.EnterNickname" = "Enter new nickname"; +"EPEditSetting.LogoutConfirm" = "Are you sure you want to log out?"; +"EPEditSetting.Cancel" = "Cancel"; +"EPEditSetting.Confirm" = "Confirm"; diff --git a/YuMi/en.lproj/Localizable.strings b/YuMi/en.lproj/Localizable.strings index de9ec71..b4cdf6f 100644 --- a/YuMi/en.lproj/Localizable.strings +++ b/YuMi/en.lproj/Localizable.strings @@ -4046,3 +4046,23 @@ "20.20.62_text_22" = "You have turn on the CP Mic Display."; "20.20.62_text_23" = "You have turn off the CP Mic Display. The CP Mic Display is not visible in this room. Click to enable it again."; "20.20.62_text_24" = "You have turned off Turbo Mode."; + +// EPEditSetting - 设置页面多语言Key +"EPEditSetting.Title" = "Edit"; +"EPEditSetting.Avatar" = "Avatar"; +"EPEditSetting.Nickname" = "Nickname"; +"EPEditSetting.PersonalInfo" = "Personal Information and Permissions"; +"EPEditSetting.Help" = "Help"; +"EPEditSetting.ClearCache" = "Clear Cache"; +"EPEditSetting.CheckUpdate" = "Check for Updates"; +"EPEditSetting.AboutUs" = "About Us"; +"EPEditSetting.Logout" = "Log out of account"; + +// Alert +"EPEditSetting.Camera" = "Take Photo"; +"EPEditSetting.PhotoLibrary" = "Choose from Album"; +"EPEditSetting.EditNickname" = "Edit Nickname"; +"EPEditSetting.EnterNickname" = "Enter new nickname"; +"EPEditSetting.LogoutConfirm" = "Are you sure you want to log out?"; +"EPEditSetting.Cancel" = "Cancel"; +"EPEditSetting.Confirm" = "Confirm"; diff --git a/YuMi/es.lproj/Localizable.strings b/YuMi/es.lproj/Localizable.strings index 36ba123..c33eea4 100644 --- a/YuMi/es.lproj/Localizable.strings +++ b/YuMi/es.lproj/Localizable.strings @@ -3717,6 +3717,26 @@ "RoomBoom_5" = "Nombre de la sala:";//"Room name:"; "RoomBoom_6" = "Hora de reinicio: 0:00 (GMT+3) diariamente"; "RoomBoom_7" = " Clasificación de Colaboradores"; + +// EPEditSetting - 设置页面多语言Key +"EPEditSetting.Title" = "Edit"; +"EPEditSetting.Avatar" = "Avatar"; +"EPEditSetting.Nickname" = "Nickname"; +"EPEditSetting.PersonalInfo" = "Personal Information and Permissions"; +"EPEditSetting.Help" = "Help"; +"EPEditSetting.ClearCache" = "Clear Cache"; +"EPEditSetting.CheckUpdate" = "Check for Updates"; +"EPEditSetting.AboutUs" = "About Us"; +"EPEditSetting.Logout" = "Log out of account"; + +// Alert +"EPEditSetting.Camera" = "Take Photo"; +"EPEditSetting.PhotoLibrary" = "Choose from Album"; +"EPEditSetting.EditNickname" = "Edit Nickname"; +"EPEditSetting.EnterNickname" = "Enter new nickname"; +"EPEditSetting.LogoutConfirm" = "Are you sure you want to log out?"; +"EPEditSetting.Cancel" = "Cancel"; +"EPEditSetting.Confirm" = "Confirm"; "RoomBoom_8" = "Super Jackpot"; "RoomBoom_9" = "Reset time: 0:00 (GMT+8) daily"; "RoomBoom_10" = "The rewards are for reference only. The specific gifts are determined by your contribution value and luck."; diff --git a/YuMi/pt-BR.lproj/Localizable.strings b/YuMi/pt-BR.lproj/Localizable.strings index e4a9165..e584ffe 100644 --- a/YuMi/pt-BR.lproj/Localizable.strings +++ b/YuMi/pt-BR.lproj/Localizable.strings @@ -3337,3 +3337,23 @@ "20.20.62_text_22" = "Você ativou a Exibição do Microfone CP."; "20.20.62_text_23" = "Você desativou a Exibição do Microfone CP. A Exibição do Microfone CP não está visível nesta sala. Clique para ativá-la novamente."; "20.20.62_text_24" = "Você desativou o Modo Turbo."; + +// EPEditSetting - 设置页面多语言Key +"EPEditSetting.Title" = "Edit"; +"EPEditSetting.Avatar" = "Avatar"; +"EPEditSetting.Nickname" = "Nickname"; +"EPEditSetting.PersonalInfo" = "Personal Information and Permissions"; +"EPEditSetting.Help" = "Help"; +"EPEditSetting.ClearCache" = "Clear Cache"; +"EPEditSetting.CheckUpdate" = "Check for Updates"; +"EPEditSetting.AboutUs" = "About Us"; +"EPEditSetting.Logout" = "Log out of account"; + +// Alert +"EPEditSetting.Camera" = "Take Photo"; +"EPEditSetting.PhotoLibrary" = "Choose from Album"; +"EPEditSetting.EditNickname" = "Edit Nickname"; +"EPEditSetting.EnterNickname" = "Enter new nickname"; +"EPEditSetting.LogoutConfirm" = "Are you sure you want to log out?"; +"EPEditSetting.Cancel" = "Cancel"; +"EPEditSetting.Confirm" = "Confirm"; diff --git a/YuMi/ru.lproj/Localizable.strings b/YuMi/ru.lproj/Localizable.strings index e6ee244..070e31f 100644 --- a/YuMi/ru.lproj/Localizable.strings +++ b/YuMi/ru.lproj/Localizable.strings @@ -3716,6 +3716,26 @@ "RoomBoom_5" = "";//"Название комнаты:"; "RoomBoom_6" = "Время сброса: 0:00 (GMT+3) ежедневно"; "RoomBoom_7" = " Рейтинг спонсоров"; + +// EPEditSetting - 设置页面多语言Key +"EPEditSetting.Title" = "Edit"; +"EPEditSetting.Avatar" = "Avatar"; +"EPEditSetting.Nickname" = "Nickname"; +"EPEditSetting.PersonalInfo" = "Personal Information and Permissions"; +"EPEditSetting.Help" = "Help"; +"EPEditSetting.ClearCache" = "Clear Cache"; +"EPEditSetting.CheckUpdate" = "Check for Updates"; +"EPEditSetting.AboutUs" = "About Us"; +"EPEditSetting.Logout" = "Log out of account"; + +// Alert +"EPEditSetting.Camera" = "Take Photo"; +"EPEditSetting.PhotoLibrary" = "Choose from Album"; +"EPEditSetting.EditNickname" = "Edit Nickname"; +"EPEditSetting.EnterNickname" = "Enter new nickname"; +"EPEditSetting.LogoutConfirm" = "Are you sure you want to log out?"; +"EPEditSetting.Cancel" = "Cancel"; +"EPEditSetting.Confirm" = "Confirm"; "RoomBoom_8" = "Супер джекпот"; "RoomBoom_9" = "Время сброса: 0:00 (GMT+8) ежедневно"; "RoomBoom_10" = "Награды приведены для справки. Конкретные подарки определяются вашим вкладом и удачей."; diff --git a/YuMi/tr.lproj/Localizable.strings b/YuMi/tr.lproj/Localizable.strings index 84a97a1..e761132 100644 --- a/YuMi/tr.lproj/Localizable.strings +++ b/YuMi/tr.lproj/Localizable.strings @@ -3837,3 +3837,23 @@ "20.20.62_text_22" = "CP Mikrofon Ekranını açtınız."; "20.20.62_text_23" = "CP Mikrofon Ekranını kapattınız. CP Mikrofon Ekranı bu odada görünmüyor. Tekrar etkinleştirmek için tıklayın."; "20.20.62_text_24" = "Turbo Modu'nu kapattınız."; + +// EPEditSetting - 设置页面多语言Key +"EPEditSetting.Title" = "Edit"; +"EPEditSetting.Avatar" = "Avatar"; +"EPEditSetting.Nickname" = "Nickname"; +"EPEditSetting.PersonalInfo" = "Personal Information and Permissions"; +"EPEditSetting.Help" = "Help"; +"EPEditSetting.ClearCache" = "Clear Cache"; +"EPEditSetting.CheckUpdate" = "Check for Updates"; +"EPEditSetting.AboutUs" = "About Us"; +"EPEditSetting.Logout" = "Log out of account"; + +// Alert +"EPEditSetting.Camera" = "Take Photo"; +"EPEditSetting.PhotoLibrary" = "Choose from Album"; +"EPEditSetting.EditNickname" = "Edit Nickname"; +"EPEditSetting.EnterNickname" = "Enter new nickname"; +"EPEditSetting.LogoutConfirm" = "Are you sure you want to log out?"; +"EPEditSetting.Cancel" = "Cancel"; +"EPEditSetting.Confirm" = "Confirm"; diff --git a/YuMi/uz-UZ.lproj/Localizable.strings b/YuMi/uz-UZ.lproj/Localizable.strings index a30f724..f1209a5 100644 --- a/YuMi/uz-UZ.lproj/Localizable.strings +++ b/YuMi/uz-UZ.lproj/Localizable.strings @@ -3717,6 +3717,26 @@ Tasdiqlangandan so'ng, sekretar sizga uni chop etishda yordam beradi va sizni xa "1.0.18_1" = "Bepul"; "1.0.18_2" = "Pay"; "1.0.18_3" = "Maxsus"; + +// EPEditSetting - 设置页面多语言Key +"EPEditSetting.Title" = "Edit"; +"EPEditSetting.Avatar" = "Avatar"; +"EPEditSetting.Nickname" = "Nickname"; +"EPEditSetting.PersonalInfo" = "Personal Information and Permissions"; +"EPEditSetting.Help" = "Help"; +"EPEditSetting.ClearCache" = "Clear Cache"; +"EPEditSetting.CheckUpdate" = "Check for Updates"; +"EPEditSetting.AboutUs" = "About Us"; +"EPEditSetting.Logout" = "Log out of account"; + +// Alert +"EPEditSetting.Camera" = "Take Photo"; +"EPEditSetting.PhotoLibrary" = "Choose from Album"; +"EPEditSetting.EditNickname" = "Edit Nickname"; +"EPEditSetting.EnterNickname" = "Enter new nickname"; +"EPEditSetting.LogoutConfirm" = "Are you sure you want to log out?"; +"EPEditSetting.Cancel" = "Cancel"; +"EPEditSetting.Confirm" = "Confirm"; "1.0.18_4" = "Yangi yaratish"; "1.0.18_5" = "Siz maksimal 6 ta fonni moslashtirishingiz mumkin."; "1.0.18_6" = "Maxsus fon sifatida bir vaqtning o'zida maksimal 6 ta rasm yuklashingiz mumkin. \nFon yaratilgandan so'ng, uni bekor qilib bo'lmaydi. \nYuklangan fonni 24 soat ichida tekshiramiz. \nAgar fon rad etilsa, sizga tangalarni qaytarib beramiz."; diff --git a/YuMi/zh-Hant.lproj/Localizable.strings b/YuMi/zh-Hant.lproj/Localizable.strings index 144e72c..28f5ecf 100644 --- a/YuMi/zh-Hant.lproj/Localizable.strings +++ b/YuMi/zh-Hant.lproj/Localizable.strings @@ -3707,3 +3707,23 @@ "20.20.62_text_22" = "您已開啟 CP 麥克風顯示。"; "20.20.62_text_23" = "您已關閉 CP 麥克風顯示。此房間中不顯示 CP 麥克風顯示。點選可重新啟用。"; "20.20.62_text_24" = "您已關閉 Turbo 模式。"; + +// EPEditSetting - 设置页面多语言Key +"EPEditSetting.Title" = "Edit"; +"EPEditSetting.Avatar" = "Avatar"; +"EPEditSetting.Nickname" = "Nickname"; +"EPEditSetting.PersonalInfo" = "Personal Information and Permissions"; +"EPEditSetting.Help" = "Help"; +"EPEditSetting.ClearCache" = "Clear Cache"; +"EPEditSetting.CheckUpdate" = "Check for Updates"; +"EPEditSetting.AboutUs" = "About Us"; +"EPEditSetting.Logout" = "Log out of account"; + +// Alert +"EPEditSetting.Camera" = "Take Photo"; +"EPEditSetting.PhotoLibrary" = "Choose from Album"; +"EPEditSetting.EditNickname" = "Edit Nickname"; +"EPEditSetting.EnterNickname" = "Enter new nickname"; +"EPEditSetting.LogoutConfirm" = "Are you sure you want to log out?"; +"EPEditSetting.Cancel" = "Cancel"; +"EPEditSetting.Confirm" = "Confirm";