Compare commits
3 Commits
e4f4557369
...
de8627a230
Author | SHA1 | Date | |
---|---|---|---|
![]() |
de8627a230 | ||
![]() |
9466b65b40 | ||
![]() |
955cc3622f |
@@ -425,7 +425,6 @@
|
||||
4C1E98C62E9A45BC0031AE79 /* EPMomentAPISwiftHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C1E98C52E9A45BC0031AE79 /* EPMomentAPISwiftHelper.swift */; };
|
||||
4C1E98C92E9A4DFD0031AE79 /* EPQCloudConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C1E98C72E9A4DFD0031AE79 /* EPQCloudConfig.swift */; };
|
||||
4C1E98CA2E9A4DFD0031AE79 /* EPSDKManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C1E98C82E9A4DFD0031AE79 /* EPSDKManager.swift */; };
|
||||
4C1E98CD2E9A69B20031AE79 /* EPMomentAPIHelper_Deprecated.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C1E98CC2E9A69B20031AE79 /* EPMomentAPIHelper_Deprecated.m */; };
|
||||
4C3475C42DD1FE590099B984 /* CreateEventSelectRoomViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3475C32DD1FE590099B984 /* CreateEventSelectRoomViewController.m */; };
|
||||
4C3851992DD5F4D50089CFCC /* EventConfigModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3851982DD5F4D50089CFCC /* EventConfigModel.m */; };
|
||||
4C38C2AD2D84064400CFA4A8 /* LoginInputItemView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C38C2AC2D84064300CFA4A8 /* LoginInputItemView.m */; };
|
||||
@@ -2485,8 +2484,6 @@
|
||||
4C1E98C52E9A45BC0031AE79 /* EPMomentAPISwiftHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EPMomentAPISwiftHelper.swift; sourceTree = "<group>"; };
|
||||
4C1E98C72E9A4DFD0031AE79 /* EPQCloudConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EPQCloudConfig.swift; sourceTree = "<group>"; };
|
||||
4C1E98C82E9A4DFD0031AE79 /* EPSDKManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EPSDKManager.swift; sourceTree = "<group>"; };
|
||||
4C1E98CB2E9A69B20031AE79 /* EPMomentAPIHelper_Deprecated.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EPMomentAPIHelper_Deprecated.h; sourceTree = "<group>"; };
|
||||
4C1E98CC2E9A69B20031AE79 /* EPMomentAPIHelper_Deprecated.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EPMomentAPIHelper_Deprecated.m; sourceTree = "<group>"; };
|
||||
4C3475C22DD1FE590099B984 /* CreateEventSelectRoomViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CreateEventSelectRoomViewController.h; sourceTree = "<group>"; };
|
||||
4C3475C32DD1FE590099B984 /* CreateEventSelectRoomViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CreateEventSelectRoomViewController.m; sourceTree = "<group>"; };
|
||||
4C3851972DD5F4D50089CFCC /* EventConfigModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EventConfigModel.h; sourceTree = "<group>"; };
|
||||
@@ -6459,8 +6456,6 @@
|
||||
4C0642952E98F76F00BAF413 /* Services */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4C1E98CB2E9A69B20031AE79 /* EPMomentAPIHelper_Deprecated.h */,
|
||||
4C1E98CC2E9A69B20031AE79 /* EPMomentAPIHelper_Deprecated.m */,
|
||||
4C1E98C52E9A45BC0031AE79 /* EPMomentAPISwiftHelper.swift */,
|
||||
);
|
||||
path = Services;
|
||||
@@ -12766,7 +12761,6 @@
|
||||
E8751E5F28A62A970056EF44 /* XPSailingPresenter.m in Sources */,
|
||||
E84A2E962A5280F900D6AF8A /* XPExchangeDiamondsView.m in Sources */,
|
||||
23F9636A2BB6919D00F440A6 /* PINobleRebateModel.m in Sources */,
|
||||
4C1E98CD2E9A69B20031AE79 /* EPMomentAPIHelper_Deprecated.m in Sources */,
|
||||
E8DAC5AC2858305A00012CFD /* XPRoomMessageBubbleView.m in Sources */,
|
||||
1427218929A75F6F00C7C423 /* HTTPDataResponse.m in Sources */,
|
||||
E8B9843028AB90200022D026 /* XPMoentsTopicListView.m in Sources */,
|
||||
@@ -13789,6 +13783,7 @@
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "YuMi/YuMi-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = 1;
|
||||
};
|
||||
|
@@ -56,6 +56,11 @@
|
||||
value = "disable"
|
||||
isEnabled = "NO">
|
||||
</EnvironmentVariable>
|
||||
<EnvironmentVariable
|
||||
key = "SWIFT_DISABLE_SAFETY_CHECKS"
|
||||
value = "YES"
|
||||
isEnabled = "YES">
|
||||
</EnvironmentVariable>
|
||||
</EnvironmentVariables>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
|
@@ -7,14 +7,13 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
class EPLoginTypesViewController: UIViewController {
|
||||
class EPLoginTypesViewController: BaseViewController {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
var displayType: EPLoginDisplayType = .id
|
||||
|
||||
private let loginService = EPLoginService()
|
||||
private let validator = EPLoginValidator()
|
||||
|
||||
private let backgroundImageView = UIImageView()
|
||||
private let titleLabel = UILabel()
|
||||
@@ -72,6 +71,7 @@ class EPLoginTypesViewController: UIViewController {
|
||||
|
||||
private func setupBackground() {
|
||||
view.addSubview(backgroundImageView)
|
||||
backgroundImageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
backgroundImageView.image = kImage(EPLoginConfig.Images.background)
|
||||
backgroundImageView.contentMode = .scaleAspectFill
|
||||
|
||||
@@ -82,6 +82,7 @@ class EPLoginTypesViewController: UIViewController {
|
||||
|
||||
private func setupNavigationBar() {
|
||||
view.addSubview(backButton)
|
||||
backButton.translatesAutoresizingMaskIntoConstraints = false
|
||||
backButton.setImage(UIImage(systemName: EPLoginConfig.Images.iconBack), for: .normal)
|
||||
backButton.tintColor = EPLoginConfig.Colors.textLight
|
||||
backButton.addTarget(self, action: #selector(handleBack), for: .touchUpInside)
|
||||
@@ -95,16 +96,20 @@ class EPLoginTypesViewController: UIViewController {
|
||||
|
||||
private func setupTitle() {
|
||||
view.addSubview(titleLabel)
|
||||
titleLabel.translatesAutoresizingMaskIntoConstraints = false
|
||||
titleLabel.font = .systemFont(ofSize: EPLoginConfig.Layout.titleFontSize, weight: .bold)
|
||||
titleLabel.textColor = EPLoginConfig.Colors.textLight
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.centerX.equalToSuperview()
|
||||
make.top.equalTo(view.safeAreaLayoutGuide).offset(100)
|
||||
make.centerY.equalTo(backButton) // 与返回按钮垂直居中对齐
|
||||
}
|
||||
}
|
||||
|
||||
private func setupInputViews() {
|
||||
firstInputView.translatesAutoresizingMaskIntoConstraints = false
|
||||
secondInputView.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
view.addSubview(firstInputView)
|
||||
view.addSubview(secondInputView)
|
||||
|
||||
@@ -124,6 +129,7 @@ class EPLoginTypesViewController: UIViewController {
|
||||
|
||||
private func setupActionButton() {
|
||||
view.addSubview(actionButton)
|
||||
actionButton.translatesAutoresizingMaskIntoConstraints = false
|
||||
actionButton.setTitle("Login", for: .normal)
|
||||
actionButton.setTitleColor(EPLoginConfig.Colors.textLight, for: .normal)
|
||||
actionButton.layer.cornerRadius = EPLoginConfig.Layout.uniformCornerRadius
|
||||
@@ -233,7 +239,7 @@ class EPLoginTypesViewController: UIViewController {
|
||||
actionButton.setTitle("Login", for: .normal)
|
||||
|
||||
case .emailReset:
|
||||
titleLabel.text = "Recover Password"
|
||||
titleLabel.text = YMLocalizedString("20.20.51_text_20")
|
||||
firstInputView.configure(with: EPLoginInputConfig(
|
||||
showAreaCode: false,
|
||||
showCodeButton: false,
|
||||
@@ -264,7 +270,7 @@ class EPLoginTypesViewController: UIViewController {
|
||||
actionButton.setTitle("Confirm", for: .normal)
|
||||
|
||||
case .phoneReset:
|
||||
titleLabel.text = "Recover Password"
|
||||
titleLabel.text = YMLocalizedString("20.20.51_text_20")
|
||||
firstInputView.configure(with: EPLoginInputConfig(
|
||||
showAreaCode: false,
|
||||
showCodeButton: false,
|
||||
@@ -298,6 +304,7 @@ class EPLoginTypesViewController: UIViewController {
|
||||
|
||||
private func setupForgotPasswordButton() {
|
||||
let button = UIButton(type: .system)
|
||||
button.translatesAutoresizingMaskIntoConstraints = false
|
||||
button.setTitle("Forgot Password?", for: .normal)
|
||||
button.setTitleColor(EPLoginConfig.Colors.textLight, for: .normal)
|
||||
button.titleLabel?.font = .systemFont(ofSize: EPLoginConfig.Layout.smallFontSize)
|
||||
@@ -315,6 +322,7 @@ class EPLoginTypesViewController: UIViewController {
|
||||
|
||||
private func setupThirdInputView() {
|
||||
let inputView = EPLoginInputView()
|
||||
inputView.translatesAutoresizingMaskIntoConstraints = false
|
||||
inputView.configure(with: EPLoginInputConfig(
|
||||
showAreaCode: false,
|
||||
showCodeButton: false,
|
||||
@@ -380,14 +388,14 @@ class EPLoginTypesViewController: UIViewController {
|
||||
let id = firstInputView.text.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
let password = secondInputView.text
|
||||
|
||||
// 表单验证
|
||||
// 表单验证(简化,仅检查空值)
|
||||
guard !id.isEmpty else {
|
||||
showAlert("请输入用户ID")
|
||||
showErrorToast(YMLocalizedString("LoginPresenter0"))
|
||||
return
|
||||
}
|
||||
|
||||
guard !password.isEmpty else {
|
||||
showAlert("请输入密码")
|
||||
showErrorToast(YMLocalizedString("LoginPresenter1"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -397,13 +405,14 @@ class EPLoginTypesViewController: UIViewController {
|
||||
loginService.loginWithID(id: id, password: password) { [weak self] (accountModel: AccountModel) in
|
||||
DispatchQueue.main.async {
|
||||
self?.showLoading(false)
|
||||
print("[EPLogin] ID登录成功: \(accountModel.uid ?? "")")
|
||||
print("[EPLogin] ID登录成功: \(accountModel.uid)")
|
||||
self?.showSuccessToast(YMLocalizedString("XPLoginPhoneViewController1"))
|
||||
EPLoginManager.jumpToHome(from: self!)
|
||||
}
|
||||
} failure: { [weak self] (code: Int, msg: String) in
|
||||
DispatchQueue.main.async {
|
||||
self?.showLoading(false)
|
||||
self?.showAlert("登录失败: \(msg)")
|
||||
self?.showErrorToast(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -412,14 +421,14 @@ class EPLoginTypesViewController: UIViewController {
|
||||
let email = firstInputView.text.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
let code = secondInputView.text
|
||||
|
||||
// 表单验证
|
||||
guard validator.validateEmail(email) else {
|
||||
showAlert("请输入正确的邮箱地址")
|
||||
// 表单验证(简化,仅检查空值)
|
||||
guard !email.isEmpty else {
|
||||
showErrorToast(YMLocalizedString("LoginPresenter0"))
|
||||
return
|
||||
}
|
||||
|
||||
guard validator.validateCode(code) else {
|
||||
showAlert("请输入6位数字验证码")
|
||||
guard !code.isEmpty else {
|
||||
showErrorToast(YMLocalizedString("LoginPresenter1"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -428,13 +437,14 @@ class EPLoginTypesViewController: UIViewController {
|
||||
loginService.loginWithEmail(email: email, code: code) { [weak self] (accountModel: AccountModel) in
|
||||
DispatchQueue.main.async {
|
||||
self?.showLoading(false)
|
||||
print("[EPLogin] 邮箱登录成功: \(accountModel.uid ?? "")")
|
||||
print("[EPLogin] 邮箱登录成功: \(accountModel.uid)")
|
||||
self?.showSuccessToast(YMLocalizedString("XPLoginPhoneViewController1"))
|
||||
EPLoginManager.jumpToHome(from: self!)
|
||||
}
|
||||
} failure: { [weak self] (code: Int, msg: String) in
|
||||
DispatchQueue.main.async {
|
||||
self?.showLoading(false)
|
||||
self?.showAlert("登录失败: \(msg)")
|
||||
self?.showErrorToast(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -443,14 +453,14 @@ class EPLoginTypesViewController: UIViewController {
|
||||
let phone = firstInputView.text.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
let code = secondInputView.text
|
||||
|
||||
// 表单验证
|
||||
guard validator.validatePhone(phone) else {
|
||||
showAlert("请输入正确的手机号")
|
||||
// 表单验证(简化,仅检查空值)
|
||||
guard !phone.isEmpty else {
|
||||
showErrorToast(YMLocalizedString("XPLoginPhoneViewController0"))
|
||||
return
|
||||
}
|
||||
|
||||
guard validator.validateCode(code) else {
|
||||
showAlert("请输入6位数字验证码")
|
||||
guard !code.isEmpty else {
|
||||
showErrorToast(YMLocalizedString("LoginPresenter1"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -459,13 +469,14 @@ class EPLoginTypesViewController: UIViewController {
|
||||
loginService.loginWithPhone(phone: phone, code: code, areaCode: "+86") { [weak self] (accountModel: AccountModel) in
|
||||
DispatchQueue.main.async {
|
||||
self?.showLoading(false)
|
||||
print("[EPLogin] 手机登录成功: \(accountModel.uid ?? "")")
|
||||
print("[EPLogin] 手机登录成功: \(accountModel.uid)")
|
||||
self?.showSuccessToast(YMLocalizedString("XPLoginPhoneViewController1"))
|
||||
EPLoginManager.jumpToHome(from: self!)
|
||||
}
|
||||
} failure: { [weak self] (code: Int, msg: String) in
|
||||
DispatchQueue.main.async {
|
||||
self?.showLoading(false)
|
||||
self?.showAlert("登录失败: \(msg)")
|
||||
self?.showErrorToast(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -477,19 +488,19 @@ class EPLoginTypesViewController: UIViewController {
|
||||
let code = secondInputView.text
|
||||
let newPassword = thirdInput.text
|
||||
|
||||
// 表单验证
|
||||
guard validator.validateEmail(email) else {
|
||||
showAlert("请输入正确的邮箱地址")
|
||||
// 表单验证(简化,仅检查空值)
|
||||
guard !email.isEmpty else {
|
||||
showErrorToast(YMLocalizedString("LoginPresenter0"))
|
||||
return
|
||||
}
|
||||
|
||||
guard validator.validateCode(code) else {
|
||||
showAlert("请输入6位数字验证码")
|
||||
guard !code.isEmpty else {
|
||||
showErrorToast(YMLocalizedString("LoginPresenter1"))
|
||||
return
|
||||
}
|
||||
|
||||
guard validator.validatePassword(newPassword) else {
|
||||
showAlert("密码需6-16位,包含字母和数字")
|
||||
guard !newPassword.isEmpty else {
|
||||
showErrorToast(YMLocalizedString("LoginPresenter1"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -498,14 +509,13 @@ class EPLoginTypesViewController: UIViewController {
|
||||
loginService.resetEmailPassword(email: email, code: code, newPassword: newPassword) { [weak self] in
|
||||
DispatchQueue.main.async {
|
||||
self?.showLoading(false)
|
||||
self?.showAlert("密码重置成功", completion: {
|
||||
self?.showSuccessToast(YMLocalizedString("XPForgetPwdViewController1"))
|
||||
self?.navigationController?.popViewController(animated: true)
|
||||
})
|
||||
}
|
||||
} failure: { [weak self] (code: Int, msg: String) in
|
||||
DispatchQueue.main.async {
|
||||
self?.showLoading(false)
|
||||
self?.showAlert("重置失败: \(msg)")
|
||||
self?.showErrorToast(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -517,19 +527,19 @@ class EPLoginTypesViewController: UIViewController {
|
||||
let code = secondInputView.text
|
||||
let newPassword = thirdInput.text
|
||||
|
||||
// 表单验证
|
||||
guard validator.validatePhone(phone) else {
|
||||
showAlert("请输入正确的手机号")
|
||||
// 表单验证(简化,仅检查空值)
|
||||
guard !phone.isEmpty else {
|
||||
showErrorToast(YMLocalizedString("XPLoginPhoneViewController0"))
|
||||
return
|
||||
}
|
||||
|
||||
guard validator.validateCode(code) else {
|
||||
showAlert("请输入6位数字验证码")
|
||||
guard !code.isEmpty else {
|
||||
showErrorToast(YMLocalizedString("LoginPresenter1"))
|
||||
return
|
||||
}
|
||||
|
||||
guard validator.validatePassword(newPassword) else {
|
||||
showAlert("密码需6-16位,包含字母和数字")
|
||||
guard !newPassword.isEmpty else {
|
||||
showErrorToast(YMLocalizedString("LoginPresenter1"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -538,14 +548,13 @@ class EPLoginTypesViewController: UIViewController {
|
||||
loginService.resetPhonePassword(phone: phone, code: code, areaCode: "+86", newPassword: newPassword) { [weak self] in
|
||||
DispatchQueue.main.async {
|
||||
self?.showLoading(false)
|
||||
self?.showAlert("密码重置成功", completion: {
|
||||
self?.showSuccessToast(YMLocalizedString("XPForgetPwdViewController1"))
|
||||
self?.navigationController?.popViewController(animated: true)
|
||||
})
|
||||
}
|
||||
} failure: { [weak self] (code: Int, msg: String) in
|
||||
DispatchQueue.main.async {
|
||||
self?.showLoading(false)
|
||||
self?.showAlert("重置失败: \(msg)")
|
||||
self?.showErrorToast(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -555,8 +564,9 @@ class EPLoginTypesViewController: UIViewController {
|
||||
private func sendEmailCode() {
|
||||
let email = firstInputView.text.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
|
||||
guard validator.validateEmail(email) else {
|
||||
showAlert("请输入正确的邮箱地址")
|
||||
// 简化验证,仅检查空值
|
||||
guard !email.isEmpty else {
|
||||
secondInputView.stopCountdown()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -565,11 +575,13 @@ class EPLoginTypesViewController: UIViewController {
|
||||
loginService.sendEmailCode(email: email, type: type) { [weak self] in
|
||||
DispatchQueue.main.async {
|
||||
self?.secondInputView.startCountdown()
|
||||
self?.showAlert("验证码已发送")
|
||||
self?.secondInputView.displayKeyboard()
|
||||
self?.showSuccessToast(YMLocalizedString("XPLoginPhoneViewController2"))
|
||||
}
|
||||
} failure: { [weak self] (code: Int, msg: String) in
|
||||
DispatchQueue.main.async {
|
||||
self?.showAlert("发送失败: \(msg)")
|
||||
self?.secondInputView.stopCountdown()
|
||||
self?.showErrorToast(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -577,8 +589,10 @@ class EPLoginTypesViewController: UIViewController {
|
||||
private func sendPhoneCode() {
|
||||
let phone = firstInputView.text.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
|
||||
guard validator.validatePhone(phone) else {
|
||||
showAlert("请输入正确的手机号")
|
||||
// 简化验证,仅检查空值
|
||||
guard !phone.isEmpty else {
|
||||
showErrorToast(YMLocalizedString("XPLoginPhoneViewController0"))
|
||||
secondInputView.stopCountdown()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -591,11 +605,13 @@ class EPLoginTypesViewController: UIViewController {
|
||||
self.loginService.sendPhoneCode(phone: phone, areaCode: "+86", type: type) { [weak self] in
|
||||
DispatchQueue.main.async {
|
||||
self?.secondInputView.startCountdown()
|
||||
self?.showAlert("验证码已发送")
|
||||
self?.secondInputView.displayKeyboard()
|
||||
self?.showSuccessToast(YMLocalizedString("XPLoginPhoneViewController2"))
|
||||
}
|
||||
} failure: { [weak self] (code: Int, msg: String) in
|
||||
DispatchQueue.main.async {
|
||||
self?.showAlert("发送失败: \(msg)")
|
||||
self?.secondInputView.stopCountdown()
|
||||
self?.showErrorToast(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -653,14 +669,6 @@ class EPLoginTypesViewController: UIViewController {
|
||||
actionButton.alpha = isEnabled ? 1.0 : 0.5
|
||||
}
|
||||
|
||||
private func showAlert(_ message: String, completion: (() -> Void)? = nil) {
|
||||
let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert)
|
||||
alert.addAction(UIAlertAction(title: "确定", style: .default) { _ in
|
||||
completion?()
|
||||
})
|
||||
present(alert, animated: true)
|
||||
}
|
||||
|
||||
/// 加载人机验证 Captcha WebView
|
||||
/// - Parameter completion: 验证成功后的回调
|
||||
private func loadCaptchaWebView(completion: @escaping () -> Void) {
|
||||
|
@@ -15,7 +15,6 @@ import Foundation
|
||||
|
||||
private let clientSecret = EPLoginConfig.API.clientSecret
|
||||
private let clientId = EPLoginConfig.API.clientId
|
||||
private let grantType = EPLoginConfig.API.grantType
|
||||
private let version = EPLoginConfig.API.version
|
||||
|
||||
// MARK: - Private Helper Methods
|
||||
@@ -151,7 +150,7 @@ import Foundation
|
||||
client_secret: clientSecret,
|
||||
version: version,
|
||||
client_id: clientId,
|
||||
grant_type: grantType)
|
||||
grant_type: "password")
|
||||
}
|
||||
|
||||
/// 邮箱 + 验证码登录
|
||||
@@ -182,7 +181,7 @@ import Foundation
|
||||
client_secret: clientSecret,
|
||||
version: version,
|
||||
client_id: clientId,
|
||||
grant_type: grantType)
|
||||
grant_type: "email")
|
||||
}
|
||||
|
||||
/// 手机号 + 验证码登录
|
||||
@@ -215,7 +214,7 @@ import Foundation
|
||||
client_secret: clientSecret,
|
||||
version: version,
|
||||
client_id: clientId,
|
||||
grant_type: grantType,
|
||||
grant_type: "password",
|
||||
phoneAreaCode: areaCode)
|
||||
}
|
||||
|
||||
|
@@ -94,6 +94,7 @@ class EPLoginInputView: UIView {
|
||||
stackView.alignment = .center
|
||||
stackView.distribution = .fill
|
||||
stackView.spacing = 8
|
||||
stackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
addSubview(stackView)
|
||||
|
||||
setupAreaCodeView()
|
||||
@@ -120,19 +121,23 @@ class EPLoginInputView: UIView {
|
||||
areaStackView.alignment = .center
|
||||
areaStackView.distribution = .fill
|
||||
areaStackView.spacing = 8
|
||||
areaStackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
// 区号按钮
|
||||
areaCodeButton.setTitle("+86", for: .normal)
|
||||
areaCodeButton.setTitleColor(EPLoginConfig.Colors.inputText, for: .normal)
|
||||
areaCodeButton.titleLabel?.font = .systemFont(ofSize: 16, weight: .medium)
|
||||
areaCodeButton.isUserInteractionEnabled = false
|
||||
areaCodeButton.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
// 箭头图标
|
||||
areaArrowImageView.image = kImage("login_area_arrow")
|
||||
areaArrowImageView.contentMode = .scaleAspectFit
|
||||
areaArrowImageView.isUserInteractionEnabled = false
|
||||
areaArrowImageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
// 点击区域按钮
|
||||
areaTapButton.translatesAutoresizingMaskIntoConstraints = false
|
||||
areaTapButton.addTarget(self, action: #selector(handleAreaTap), for: .touchUpInside)
|
||||
|
||||
areaStackView.addSubview(areaTapButton)
|
||||
@@ -147,7 +152,6 @@ class EPLoginInputView: UIView {
|
||||
|
||||
areaCodeButton.snp.makeConstraints { make in
|
||||
make.width.lessThanOrEqualTo(60)
|
||||
make.height.equalTo(stackView)
|
||||
}
|
||||
|
||||
areaArrowImageView.snp.makeConstraints { make in
|
||||
@@ -160,6 +164,7 @@ class EPLoginInputView: UIView {
|
||||
// Icon (可选)
|
||||
iconImageView.contentMode = .scaleAspectFit
|
||||
iconImageView.tintColor = EPLoginConfig.Colors.icon
|
||||
iconImageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
stackView.addArrangedSubview(iconImageView)
|
||||
|
||||
iconImageView.snp.makeConstraints { make in
|
||||
@@ -170,12 +175,9 @@ class EPLoginInputView: UIView {
|
||||
inputTextField.textColor = EPLoginConfig.Colors.textLight
|
||||
inputTextField.font = .systemFont(ofSize: 14)
|
||||
inputTextField.tintColor = EPLoginConfig.Colors.textLight
|
||||
inputTextField.translatesAutoresizingMaskIntoConstraints = false
|
||||
inputTextField.addTarget(self, action: #selector(textFieldDidChange), for: .editingChanged)
|
||||
stackView.addArrangedSubview(inputTextField)
|
||||
|
||||
inputTextField.snp.makeConstraints { make in
|
||||
make.height.equalTo(stackView)
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func textFieldDidChange() {
|
||||
@@ -183,6 +185,7 @@ class EPLoginInputView: UIView {
|
||||
}
|
||||
|
||||
private func setupEyeButton() {
|
||||
eyeButton.translatesAutoresizingMaskIntoConstraints = false
|
||||
eyeButton.setImage(kImage(EPLoginConfig.Images.iconPasswordUnsee), for: .normal)
|
||||
eyeButton.setImage(kImage(EPLoginConfig.Images.iconPasswordSee), for: .selected)
|
||||
eyeButton.addTarget(self, action: #selector(handleEyeTap), for: .touchUpInside)
|
||||
@@ -194,6 +197,7 @@ class EPLoginInputView: UIView {
|
||||
}
|
||||
|
||||
private func setupCodeButton() {
|
||||
codeButton.translatesAutoresizingMaskIntoConstraints = false
|
||||
codeButton.setTitle(YMLocalizedString("XPLoginInputView0"), for: .normal)
|
||||
codeButton.setTitleColor(.white, for: .normal)
|
||||
codeButton.titleLabel?.font = .systemFont(ofSize: 12, weight: .medium)
|
||||
@@ -249,6 +253,11 @@ class EPLoginInputView: UIView {
|
||||
inputTextField.text = ""
|
||||
}
|
||||
|
||||
/// 弹出键盘(自动聚焦输入框)
|
||||
func displayKeyboard() {
|
||||
inputTextField.becomeFirstResponder()
|
||||
}
|
||||
|
||||
// MARK: - Actions
|
||||
|
||||
@objc private func handleAreaTap() {
|
||||
|
@@ -11,40 +11,51 @@ import SnapKit
|
||||
|
||||
/// 设置编辑页面
|
||||
/// 支持头像更新、昵称修改和退出登录功能
|
||||
class EPEditSettingViewController: UIViewController {
|
||||
class EPEditSettingViewController: BaseViewController {
|
||||
|
||||
// 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] 未登录,无法获取用户信息")
|
||||
@@ -237,19 +317,33 @@ class EPEditSettingViewController: UIViewController {
|
||||
}
|
||||
|
||||
private func updateNickname(_ newNickname: String) {
|
||||
// 构建UserInfoModel并调用更新方法
|
||||
let userInfo = UserInfoModel()
|
||||
userInfo.nick = newNickname
|
||||
// 显示加载状态
|
||||
showLoading()
|
||||
|
||||
// 调用Presenter方法 (桥接到OC)
|
||||
let presenter = XPMineUserInfoEditPresenter()
|
||||
presenter.getUserInfoEditDataSource(withUserInfo: userInfo)
|
||||
// 调用 API 更新昵称
|
||||
apiHelper.updateNickname(withNick: newNickname,
|
||||
completion: { [weak self] in
|
||||
self?.hideHUD()
|
||||
|
||||
// 更新本地显示
|
||||
self.userInfo?.nick = newNickname
|
||||
tableView.reloadData()
|
||||
// 更新成功后才更新本地显示
|
||||
self?.userInfo?.nick = newNickname
|
||||
self?.tableView.reloadData()
|
||||
|
||||
print("[EPEditSetting] 昵称更新为: \(newNickname)")
|
||||
// 显示成功提示
|
||||
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() {
|
||||
@@ -307,6 +401,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 +418,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 +433,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
|
||||
// 清除之前的自定义视图
|
||||
cell.contentView.subviews.forEach { $0.removeFromSuperview() }
|
||||
|
||||
// 添加头像图片
|
||||
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 {
|
||||
if indexPath.row == 0 {
|
||||
// 昵称行
|
||||
cell.textLabel?.text = YMLocalizedString("EPEditSetting.Nickname")
|
||||
cell.detailTextLabel?.text = userInfo?.nick ?? "未设置"
|
||||
cell.detailTextLabel?.textColor = .lightGray
|
||||
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)
|
||||
}
|
||||
|
||||
// 添加用户昵称标签
|
||||
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 +489,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()
|
||||
}
|
||||
} 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 +546,75 @@ extension EPEditSettingViewController: UIImagePickerControllerDelegate, UINaviga
|
||||
}
|
||||
|
||||
private func uploadAvatar(_ image: UIImage) {
|
||||
// 压缩图片
|
||||
guard let imageData = image.jpegData(compressionQuality: 0.5) else {
|
||||
print("[EPEditSetting] 图片压缩失败")
|
||||
// 显示上传进度
|
||||
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
|
||||
}
|
||||
|
||||
// 生成文件名
|
||||
let format = "jpg"
|
||||
let name = "image/\(UUID().uuidString).\(format)"
|
||||
|
||||
// 上传到腾讯云
|
||||
UploadFile.share().qCloudUploadImage(imageData, named: name, success: { [weak self] (key, resp) in
|
||||
print("[EPEditSetting] 头像上传成功: \(key)")
|
||||
print("[EPEditSetting] 头像上传成功: \(avatarUrl)")
|
||||
|
||||
// 调用API更新头像
|
||||
self?.updateAvatarAPI(avatarUrl: key)
|
||||
self?.updateAvatarAPI(avatarUrl: avatarUrl)
|
||||
},
|
||||
failure: { [weak self] errorMsg in
|
||||
EPProgressHUD.dismiss()
|
||||
print("[EPEditSetting] 头像上传失败: \(errorMsg)")
|
||||
|
||||
}, failure: { (resCode, message) in
|
||||
print("[EPEditSetting] 头像上传失败: \(message)")
|
||||
})
|
||||
// 显示错误提示
|
||||
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
|
||||
DispatchQueue.main.async {
|
||||
if code == 200 {
|
||||
// 使用 API Helper 更新头像
|
||||
apiHelper.updateAvatar(withUrl: avatarUrl, completion: { [weak self] in
|
||||
print("[EPEditSetting] 头像更新成功")
|
||||
|
||||
// 更新本地用户信息
|
||||
self?.userInfo?.avatar = avatarUrl
|
||||
} else {
|
||||
print("[EPEditSetting] 头像更新失败: \(String(describing: msg))")
|
||||
|
||||
// 通知父页面头像已更新
|
||||
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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}, 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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -41,7 +41,6 @@
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
[self setupUI];
|
||||
|
||||
NSLog(@"[EPMineViewController] viewDidLoad 完成");
|
||||
@@ -49,10 +48,7 @@
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// 隐藏导航栏
|
||||
[self.navigationController setNavigationBarHidden:YES animated:animated];
|
||||
|
||||
// 每次显示时加载最新数据
|
||||
[self loadUserDetailInfo];
|
||||
}
|
||||
@@ -60,8 +56,13 @@
|
||||
// MARK: - Setup
|
||||
|
||||
- (void)setupUI {
|
||||
// 背景渐变色
|
||||
self.view.backgroundColor = [UIColor colorWithRed:0.047 green:0.020 blue:0.153 alpha:1.0]; // #0C0527
|
||||
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 setupHeaderView];
|
||||
[self setupMomentListView];
|
||||
@@ -73,19 +74,25 @@
|
||||
self.headerView = [[EPMineHeaderView alloc] initWithFrame:CGRectZero];
|
||||
[self.view addSubview:self.headerView];
|
||||
|
||||
// 使用约束布局
|
||||
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]
|
||||
]];
|
||||
// 使用 Masonry 约束布局
|
||||
[self.headerView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.mas_equalTo(self.view);
|
||||
make.leading.mas_equalTo(self.view);
|
||||
make.trailing.mas_equalTo(self.view);
|
||||
make.height.mas_equalTo(kGetScaleWidth(260));
|
||||
}];
|
||||
|
||||
// 监听设置按钮点击事件
|
||||
// 设置按钮点击回调
|
||||
__weak typeof(self) weakSelf = self;
|
||||
self.headerView.onSettingsButtonTapped = ^{
|
||||
__strong typeof(weakSelf) self = weakSelf;
|
||||
[self openSettings];
|
||||
};
|
||||
|
||||
// 监听头像更新事件
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(openSettings)
|
||||
name:@"EPMineHeaderSettingsButtonTapped"
|
||||
selector:@selector(onAvatarUpdated:)
|
||||
name:@"EPEditSettingAvatarUpdated"
|
||||
object:nil];
|
||||
}
|
||||
|
||||
@@ -93,14 +100,12 @@
|
||||
self.momentListView = [[EPMomentListView alloc] initWithFrame:CGRectZero];
|
||||
[self.view addSubview:self.momentListView];
|
||||
|
||||
// 使用约束布局
|
||||
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]
|
||||
]];
|
||||
[self.momentListView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.mas_equalTo(self.headerView.mas_bottom);
|
||||
make.bottom.mas_equalTo(self.view);
|
||||
make.leading.mas_equalTo(self.view);
|
||||
make.trailing.mas_equalTo(self.view);
|
||||
}];
|
||||
}
|
||||
|
||||
// MARK: - Data Loading
|
||||
@@ -112,10 +117,10 @@
|
||||
return;
|
||||
}
|
||||
|
||||
__weak typeof(self) weakSelf = self;
|
||||
@kWeakify(self);
|
||||
[self.apiHelper getUserDetailInfoWithUid:uid
|
||||
completion:^(UserInfoModel * _Nullable userInfo) {
|
||||
__strong typeof(weakSelf) self = weakSelf;
|
||||
@kStrongify(self);
|
||||
if (!userInfo) {
|
||||
NSLog(@"[EPMineViewController] 加载用户信息失败");
|
||||
return;
|
||||
@@ -172,13 +177,37 @@
|
||||
// MARK: - Actions
|
||||
|
||||
- (void)openSettings {
|
||||
// 隐藏返回按钮文字,只保留白色箭头
|
||||
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@""
|
||||
style:UIBarButtonItemStylePlain
|
||||
target:nil
|
||||
action:nil];
|
||||
|
||||
EPEditSettingViewController *settingsVC = [[EPEditSettingViewController alloc] init];
|
||||
// 传递用户信息到设置页面
|
||||
if (self.userInfo) {
|
||||
[settingsVC updateWithUserInfo:self.userInfo];
|
||||
}
|
||||
[self.navigationController pushViewController:settingsVC animated:YES];
|
||||
NSLog(@"[EPMineViewController] 打开设置页面");
|
||||
NSLog(@"[EPMineViewController] 打开设置页面,已传递用户信息");
|
||||
}
|
||||
|
||||
- (void)onAvatarUpdated:(NSNotification *)notification {
|
||||
NSString *avatarUrl = notification.userInfo[@"avatarUrl"];
|
||||
if (avatarUrl && self.userInfo) {
|
||||
// 更新本地用户信息
|
||||
self.userInfo.avatar = avatarUrl;
|
||||
|
||||
// 更新 UI 显示
|
||||
[self updateHeaderWithUserInfo:self.userInfo];
|
||||
|
||||
NSLog(@"[EPMineViewController] 头像已更新: %@", avatarUrl);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
// 只移除头像更新通知的观察者,设置按钮现在使用 block 回调
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"EPEditSettingAvatarUpdated" object:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
|
@@ -24,6 +24,16 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
completion:(void (^)(UserInfoModel * _Nullable userInfo))completion
|
||||
failure:(void (^)(NSInteger code, NSString * _Nullable msg))failure;
|
||||
|
||||
/// 更新用户头像
|
||||
- (void)updateAvatarWithUrl:(NSString *)avatarUrl
|
||||
completion:(void (^)(void))completion
|
||||
failure:(void (^)(NSInteger code, NSString * _Nullable msg))failure;
|
||||
|
||||
/// 更新用户昵称
|
||||
- (void)updateNicknameWithNick:(NSString *)nickname
|
||||
completion:(void (^)(void))completion
|
||||
failure:(void (^)(NSInteger code, NSString * _Nullable msg))failure;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
@@ -9,6 +9,7 @@
|
||||
#import "Api+Mine.h"
|
||||
#import "UserInfoModel.h"
|
||||
#import "BaseModel.h"
|
||||
#import "AccountInfoStorage.h"
|
||||
|
||||
@implementation EPMineAPIHelper
|
||||
|
||||
@@ -38,5 +39,39 @@
|
||||
} uid:uid page:@"1" pageSize:@"20"];
|
||||
}
|
||||
|
||||
- (void)updateAvatarWithUrl:(NSString *)avatarUrl
|
||||
completion:(void (^)(void))completion
|
||||
failure:(void (^)(NSInteger code, NSString * _Nullable msg))failure {
|
||||
[Api userV2UploadAvatar:^(BaseModel * _Nullable data, NSInteger code, NSString * _Nullable msg) {
|
||||
if (code == 200) {
|
||||
if (completion) completion();
|
||||
} else {
|
||||
if (failure) failure(code, msg);
|
||||
}
|
||||
} avatarUrl:avatarUrl needPay:@NO];
|
||||
}
|
||||
|
||||
- (void)updateNicknameWithNick:(NSString *)nickname
|
||||
completion:(void (^)(void))completion
|
||||
failure:(void (^)(NSInteger code, NSString * _Nullable msg))failure {
|
||||
NSString *uid = [[AccountInfoStorage instance] getUid];
|
||||
NSString *ticket = [[AccountInfoStorage instance] getTicket];
|
||||
|
||||
NSMutableDictionary *params = [NSMutableDictionary dictionary];
|
||||
if (nickname.length > 0) {
|
||||
[params setValue:nickname forKey:@"nick"];
|
||||
}
|
||||
[params setObject:uid forKey:@"uid"];
|
||||
[params setObject:ticket forKey:@"ticket"];
|
||||
|
||||
[Api completeUserInfo:^(BaseModel * _Nullable data, NSInteger code, NSString * _Nullable msg) {
|
||||
if (code == 200) {
|
||||
if (completion) completion();
|
||||
} else {
|
||||
if (failure) failure(code, msg);
|
||||
}
|
||||
} userInfo:params];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
@@ -14,6 +14,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
/// 大圆形头像 + 渐变背景 + 用户信息展示
|
||||
@interface EPMineHeaderView : UIView
|
||||
|
||||
/// 设置按钮点击回调
|
||||
@property (nonatomic, copy, nullable) void(^onSettingsButtonTapped)(void);
|
||||
|
||||
/// 更新用户信息
|
||||
/// @param userInfoDict 用户信息字典
|
||||
- (void)updateWithUserInfo:(NSDictionary *)userInfoDict;
|
||||
|
@@ -24,12 +24,6 @@
|
||||
/// 设置按钮
|
||||
@property (nonatomic, strong) UIButton *settingsButton;
|
||||
|
||||
/// 关注按钮
|
||||
@property (nonatomic, strong) UIButton *followButton;
|
||||
|
||||
/// 粉丝按钮
|
||||
@property (nonatomic, strong) UIButton *fansButton;
|
||||
|
||||
@end
|
||||
|
||||
@implementation EPMineHeaderView
|
||||
@@ -97,36 +91,6 @@
|
||||
make.trailing.equalTo(self).offset(-20);
|
||||
make.size.mas_equalTo(CGSizeMake(40, 40));
|
||||
}];
|
||||
|
||||
// 关注按钮
|
||||
self.followButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[self.followButton setTitle:@"关注" forState:UIControlStateNormal];
|
||||
[self.followButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
|
||||
self.followButton.titleLabel.font = [UIFont systemFontOfSize:16];
|
||||
self.followButton.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.2];
|
||||
self.followButton.layer.cornerRadius = 20;
|
||||
[self addSubview:self.followButton];
|
||||
|
||||
[self.followButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(self.idLabel.mas_bottom).offset(20);
|
||||
make.centerX.equalTo(self).offset(-50);
|
||||
make.size.mas_equalTo(CGSizeMake(80, 40));
|
||||
}];
|
||||
|
||||
// 粉丝按钮
|
||||
self.fansButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[self.fansButton setTitle:@"粉丝" forState:UIControlStateNormal];
|
||||
[self.fansButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
|
||||
self.fansButton.titleLabel.font = [UIFont systemFontOfSize:16];
|
||||
self.fansButton.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.2];
|
||||
self.fansButton.layer.cornerRadius = 20;
|
||||
[self addSubview:self.fansButton];
|
||||
|
||||
[self.fansButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(self.idLabel.mas_bottom).offset(20);
|
||||
make.centerX.equalTo(self).offset(50);
|
||||
make.size.mas_equalTo(CGSizeMake(80, 40));
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)updateWithUserInfo:(NSDictionary *)userInfoDict {
|
||||
@@ -138,14 +102,6 @@
|
||||
NSString *uid = userInfoDict[@"uid"] ?: @"";
|
||||
self.idLabel.text = [NSString stringWithFormat:@"ID:%@", uid];
|
||||
|
||||
// 更新关注数
|
||||
NSNumber *following = userInfoDict[@"following"] ?: @0;
|
||||
[self.followButton setTitle:[NSString stringWithFormat:@"关注 %@", following] forState:UIControlStateNormal];
|
||||
|
||||
// 更新粉丝数
|
||||
NSNumber *followers = userInfoDict[@"followers"] ?: @0;
|
||||
[self.fansButton setTitle:[NSString stringWithFormat:@"粉丝 %@", followers] forState:UIControlStateNormal];
|
||||
|
||||
// 加载头像
|
||||
NSString *avatarURL = userInfoDict[@"avatar"];
|
||||
if (avatarURL && avatarURL.length > 0) {
|
||||
@@ -159,8 +115,10 @@
|
||||
|
||||
- (void)settingsButtonTapped {
|
||||
NSLog(@"[EPMineHeaderView] 设置按钮点击");
|
||||
// 发送通知给父视图
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"EPMineHeaderSettingsButtonTapped" object:nil];
|
||||
// 使用 block 回调
|
||||
if (self.onSettingsButtonTapped) {
|
||||
self.onSettingsButtonTapped();
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
@@ -90,10 +90,16 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
|
||||
make.leading.trailing.equalTo(self.textView);
|
||||
make.height.mas_equalTo(1);
|
||||
}];
|
||||
// 计算显示3行图片所需的高度
|
||||
// itemW = (屏幕宽度 - 左右边距30 - 列间距20) / 3
|
||||
// 总高度 = 3行itemW + 2个行间距(10*2)
|
||||
CGFloat itemW = (KScreenWidth - 15*2 - 10*2)/3.0;
|
||||
CGFloat collectionHeight = itemW * 3 + 10 * 2;
|
||||
|
||||
[self.collectionView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.leading.trailing.equalTo(self.contentView).inset(15);
|
||||
make.top.equalTo(self.lineView.mas_bottom).offset(10);
|
||||
make.height.mas_equalTo(110);
|
||||
make.height.mas_equalTo(collectionHeight);
|
||||
}];
|
||||
|
||||
// 底部发布按钮
|
||||
|
@@ -54,9 +54,6 @@
|
||||
// MARK: - Setup UI
|
||||
|
||||
- (void)setupUI {
|
||||
// 先设置纯色背景作为兜底,避免白色闪烁
|
||||
self.view.backgroundColor = [UIColor colorWithRed:0.95 green:0.95 blue:0.97 alpha:1.0];
|
||||
|
||||
UIImageView *bgImageView = [[UIImageView alloc] initWithImage:kImage(@"vc_bg")];
|
||||
bgImageView.contentMode = UIViewContentModeScaleAspectFill;
|
||||
bgImageView.clipsToBounds = YES;
|
||||
|
@@ -1,42 +0,0 @@
|
||||
//
|
||||
// EPMomentAPIHelper_Deprecated.h
|
||||
// YuMi
|
||||
//
|
||||
// Created by AI on 2025-10-10.
|
||||
//
|
||||
// ⚠️ DEPRECATED: 已被 EPMomentAPISwiftHelper.swift 替代
|
||||
// 原因:
|
||||
// 1. 继承 BaseMvpPresenter 会引起 Bridging Header 依赖链问题
|
||||
// 2. Swift 版本更简洁、类型安全
|
||||
// 3. 功能已完整迁移到 Swift 版本
|
||||
//
|
||||
// 保留此文件仅供参考,后续可删除
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "BaseMvpPresenter.h"
|
||||
#import "MomentsInfoModel.h"
|
||||
#import "MomentsListInfoModel.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// 推荐/我的动态列表数据源类型
|
||||
typedef NS_ENUM(NSInteger, EPMomentListSourceType) {
|
||||
EPMomentListSourceTypeRecommend = 0,
|
||||
EPMomentListSourceTypeMine = 1
|
||||
};
|
||||
|
||||
/// 统一封装 Moments 列表 API
|
||||
@interface EPMomentAPIHelper : BaseMvpPresenter
|
||||
|
||||
/// 拉取最新动态列表(默认 types:"0,2" 图片+文字)
|
||||
- (void)fetchLatestMomentsWithNextID:(NSString *)nextID
|
||||
completion:(void (^)(NSArray <MomentsInfoModel *>* _Nullable list, NSString *nextMomentID))completion
|
||||
failure:(void(^)(NSInteger code, NSString * _Nullable msg))failure;
|
||||
|
||||
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
|
@@ -1,44 +0,0 @@
|
||||
//
|
||||
// EPMomentAPIHelper_Deprecated.m
|
||||
// YuMi
|
||||
//
|
||||
// Created by AI on 2025-10-10.
|
||||
//
|
||||
// ⚠️ DEPRECATED: 已被 EPMomentAPISwiftHelper.swift 替代
|
||||
// 保留此文件仅供参考,后续可删除
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "EPMomentAPIHelper_Deprecated.h"
|
||||
#import "Api+Moments.h"
|
||||
#import "AccountInfoStorage.h"
|
||||
#import "BaseModel.h"
|
||||
|
||||
|
||||
@implementation EPMomentAPIHelper
|
||||
// [Api momentsRecommendList:^(BaseModel * _Nullable data, NSInteger code, NSString * _Nullable msg) {
|
||||
// if (code == 200 && data.data) {
|
||||
// NSArray *array = [MomentsInfoModel modelsWithArray:data.data];
|
||||
// if (completion) completion(array ?: @[], 200, @"success");
|
||||
// } else {
|
||||
// if (completion) completion(@[], code, msg);
|
||||
// }
|
||||
// } page:pageStr pageSize:pageSizeStr types:types];
|
||||
|
||||
- (void)fetchLatestMomentsWithNextID:(NSString *)nextID
|
||||
completion:(void (^)(NSArray <MomentsInfoModel *>* _Nullable list, NSString *nextMomentID))completion
|
||||
failure:(void(^)(NSInteger code, NSString * _Nullable msg))failure {
|
||||
NSString *pageSizeStr = @"20";
|
||||
NSString *types = @"0,2"; // 图片+文字
|
||||
|
||||
[Api momentsLatestList:[self createHttpCompletion:^(BaseModel * _Nonnull data) {
|
||||
MomentsListInfoModel *listInfo = [MomentsListInfoModel modelWithDictionary:data.data];
|
||||
if (completion) completion(listInfo.dynamicList ?: @[],
|
||||
listInfo.nextDynamicId);
|
||||
} fail:^(NSInteger code, NSString * _Nullable msg) {
|
||||
if (failure) failure(code, msg);
|
||||
}] dynamicId:nextID pageSize:pageSizeStr types:types];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
@@ -120,7 +120,8 @@
|
||||
make.leading.trailing.equalTo(self.cardView);
|
||||
make.top.equalTo(self.imagesContainer.mas_bottom).offset(12);
|
||||
make.height.mas_equalTo(50);
|
||||
make.bottom.equalTo(self.cardView).offset(-8);
|
||||
// 降低底部约束优先级,避免与图片容器高度冲突
|
||||
make.bottom.equalTo(self.cardView).offset(-8).priority(UILayoutPriorityDefaultHigh);
|
||||
}];
|
||||
|
||||
// 点赞按钮
|
||||
|
@@ -361,8 +361,51 @@ import SnapKit
|
||||
normalImage: normalImage,
|
||||
selectedImage: selectedImage
|
||||
)
|
||||
|
||||
// 设置 delegate 以监听页面切换
|
||||
nav.delegate = self
|
||||
|
||||
return nav
|
||||
}
|
||||
|
||||
// MARK: - TabBar Visibility Control
|
||||
|
||||
/// 显示悬浮 TabBar
|
||||
private func showCustomTabBar(animated: Bool = true) {
|
||||
guard customTabBarView.isHidden else { return }
|
||||
|
||||
if animated {
|
||||
customTabBarView.isHidden = false
|
||||
customTabBarView.alpha = 0
|
||||
customTabBarView.transform = CGAffineTransform(translationX: 0, y: 20)
|
||||
|
||||
UIView.animate(withDuration: 0.25, delay: 0, options: .curveEaseOut) {
|
||||
self.customTabBarView.alpha = 1
|
||||
self.customTabBarView.transform = .identity
|
||||
}
|
||||
} else {
|
||||
customTabBarView.isHidden = false
|
||||
customTabBarView.alpha = 1
|
||||
}
|
||||
}
|
||||
|
||||
/// 隐藏悬浮 TabBar
|
||||
private func hideCustomTabBar(animated: Bool = true) {
|
||||
guard !customTabBarView.isHidden else { return }
|
||||
|
||||
if animated {
|
||||
UIView.animate(withDuration: 0.25, delay: 0, options: .curveEaseIn, animations: {
|
||||
self.customTabBarView.alpha = 0
|
||||
self.customTabBarView.transform = CGAffineTransform(translationX: 0, y: 20)
|
||||
}) { _ in
|
||||
self.customTabBarView.isHidden = true
|
||||
self.customTabBarView.transform = .identity
|
||||
}
|
||||
} else {
|
||||
customTabBarView.isHidden = true
|
||||
customTabBarView.alpha = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UITabBarControllerDelegate
|
||||
@@ -389,6 +432,29 @@ extension EPTabBarController: UITabBarControllerDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UINavigationControllerDelegate
|
||||
|
||||
extension EPTabBarController: UINavigationControllerDelegate {
|
||||
|
||||
func navigationController(_ navigationController: UINavigationController,
|
||||
willShow viewController: UIViewController,
|
||||
animated: Bool) {
|
||||
|
||||
// 判断是否是根页面(一级页面)
|
||||
let isRootViewController = navigationController.viewControllers.count == 1
|
||||
|
||||
if isRootViewController {
|
||||
// 一级页面:显示 TabBar
|
||||
showCustomTabBar(animated: animated)
|
||||
NSLog("[EPTabBarController] 显示 TabBar - 根页面")
|
||||
} else {
|
||||
// 二级及以上页面:隐藏 TabBar
|
||||
hideCustomTabBar(animated: animated)
|
||||
NSLog("[EPTabBarController] 隐藏 TabBar - 子页面 (层级: \(navigationController.viewControllers.count))")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - OC Compatibility
|
||||
|
||||
extension EPTabBarController {
|
||||
|
@@ -45,6 +45,9 @@
|
||||
#import "YYUtility.h"
|
||||
#import "SDWebImage.h"
|
||||
|
||||
// MARK: - API Helpers
|
||||
#import "EPMineAPIHelper.h"
|
||||
|
||||
// MARK: - Utilities
|
||||
#import "UIImage+Utils.h"
|
||||
#import "NSString+Utils.h"
|
||||
|
Reference in New Issue
Block a user