Compare commits
3 Commits
e32e5653fd
...
96c44cb032
Author | SHA1 | Date | |
---|---|---|---|
![]() |
96c44cb032 | ||
![]() |
16f9041ba9 | ||
![]() |
99db078b62 |
6
.gitignore
vendored
6
.gitignore
vendored
@@ -82,12 +82,6 @@ iOSInjectionProject/
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
# Package Files #
|
||||
*.war
|
||||
*.ear
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.rar
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
|
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -35,5 +35,6 @@
|
||||
"Superview",
|
||||
"Uids",
|
||||
"XNDJTDD"
|
||||
]
|
||||
],
|
||||
"C_Cpp.errorSquiggles": "disabled"
|
||||
}
|
434
Email-VerificationCode-Login-Flow.md
Normal file
434
Email-VerificationCode-Login-Flow.md
Normal file
@@ -0,0 +1,434 @@
|
||||
# 邮箱验证码登录流程文档
|
||||
|
||||
## 概述
|
||||
|
||||
本文档详细描述了 YuMi iOS 应用中 `LoginTypesViewController` 在 `LoginDisplayType_email` 模式下的邮箱验证码登录流程。该流程实现了基于邮箱和验证码的用户认证机制。
|
||||
|
||||
## 系统架构
|
||||
|
||||
### 核心组件
|
||||
- **LoginTypesViewController**: 登录类型控制器,负责 UI 展示和用户交互
|
||||
- **LoginPresenter**: 登录业务逻辑处理器,负责与 API 交互
|
||||
- **LoginInputItemView**: 输入组件,提供邮箱和验证码输入界面
|
||||
- **Api+Login**: 登录相关 API 接口封装
|
||||
- **AccountInfoStorage**: 账户信息本地存储管理
|
||||
|
||||
### 数据模型
|
||||
|
||||
#### LoginDisplayType 枚举
|
||||
```objc
|
||||
typedef NS_ENUM(NSUInteger, LoginDisplayType) {
|
||||
LoginDisplayType_id, // ID 登录
|
||||
LoginDisplayType_email, // 邮箱登录 ✓
|
||||
LoginDisplayType_phoneNum, // 手机号登录
|
||||
LoginDisplayType_email_forgetPassword, // 邮箱忘记密码
|
||||
LoginDisplayType_phoneNum_forgetPassword, // 手机号忘记密码
|
||||
};
|
||||
```
|
||||
|
||||
#### LoginInputType 枚举
|
||||
```objc
|
||||
typedef NS_ENUM(NSUInteger, LoginInputType) {
|
||||
LoginInputType_email, // 邮箱输入
|
||||
LoginInputType_verificationCode, // 验证码输入
|
||||
LoginInputType_login, // 登录按钮
|
||||
// ... 其他类型
|
||||
};
|
||||
```
|
||||
|
||||
#### GetSmsType 验证码类型
|
||||
```objc
|
||||
typedef NS_ENUM(NSUInteger, GetSmsType) {
|
||||
GetSmsType_Regist = 1, // 注册(邮箱登录使用此类型)
|
||||
GetSmsType_Login = 2, // 登录
|
||||
GetSmsType_Reset_Password = 3, // 重设密码
|
||||
// ... 其他类型
|
||||
};
|
||||
```
|
||||
|
||||
## 登录流程详解
|
||||
|
||||
### 1. 界面初始化流程
|
||||
|
||||
#### 1.1 控制器初始化
|
||||
```objc
|
||||
// 在 LoginViewController 中点击邮箱登录按钮
|
||||
- (void)didTapEntrcyButton:(UIButton *)sender {
|
||||
if (sender.tag == LoginType_Email) {
|
||||
LoginTypesViewController *vc = [[LoginTypesViewController alloc] init];
|
||||
[self.navigationController pushViewController:vc animated:YES];
|
||||
[vc updateLoginType:LoginDisplayType_email]; // 设置为邮箱登录模式
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 1.2 输入区域设置
|
||||
```objc
|
||||
- (void)setupEmailInputArea {
|
||||
[self setupInpuArea:LoginInputType_email // 第一行:邮箱输入
|
||||
second:LoginInputType_verificationCode // 第二行:验证码输入
|
||||
third:LoginInputType_none // 第三行:无
|
||||
action:LoginInputType_login // 操作按钮:登录
|
||||
showForgetPassword:NO]; // 不显示忘记密码
|
||||
}
|
||||
```
|
||||
|
||||
#### 1.3 UI 组件配置
|
||||
- **第一行输入框**: 邮箱地址输入
|
||||
- 占位符: "请输入邮箱地址"
|
||||
- 键盘类型: `UIKeyboardTypeEmailAddress`
|
||||
- 回调: `handleFirstInputContentUpdate`
|
||||
|
||||
- **第二行输入框**: 验证码输入
|
||||
- 占位符: "请输入验证码"
|
||||
- 键盘类型: `UIKeyboardTypeDefault`
|
||||
- 附带"获取验证码"按钮
|
||||
- 回调: `handleSecondInputContentUpdate`
|
||||
|
||||
### 2. 验证码获取流程
|
||||
|
||||
#### 2.1 用户交互触发
|
||||
```objc
|
||||
// 用户点击"获取验证码"按钮
|
||||
[self.secondLineInputView setHandleItemAction:^(LoginInputType inputType) {
|
||||
if (inputType == LoginInputType_verificationCode) {
|
||||
if (self.type == LoginDisplayType_email) {
|
||||
[self handleTapGetMailVerificationCode];
|
||||
}
|
||||
}
|
||||
}];
|
||||
```
|
||||
|
||||
#### 2.2 邮箱验证码获取处理
|
||||
```objc
|
||||
- (void)handleTapGetMailVerificationCode {
|
||||
NSString *email = [self.firstLineInputView inputContent];
|
||||
|
||||
// 邮箱地址验证
|
||||
if (email.length == 0) {
|
||||
[self.secondLineInputView endVerificationCountDown];
|
||||
return;
|
||||
}
|
||||
|
||||
// 调用 Presenter 发送验证码
|
||||
[self.presenter sendMailVerificationCode:email type:GetSmsType_Regist];
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.3 Presenter 层处理
|
||||
```objc
|
||||
- (void)sendMailVerificationCode:(NSString *)emailAddress type:(NSInteger)type {
|
||||
// DES 加密邮箱地址
|
||||
NSString *desEmail = [DESEncrypt encryptUseDES:emailAddress
|
||||
key:KeyWithType(KeyType_PasswordEncode)];
|
||||
|
||||
@kWeakify(self);
|
||||
[Api emailGetCode:[self createHttpCompletion:^(BaseModel *data) {
|
||||
@kStrongify(self);
|
||||
if ([[self getView] respondsToSelector:@selector(emailCodeSucess:type:)]) {
|
||||
[[self getView] emailCodeSucess:@"" type:type];
|
||||
}
|
||||
} fail:^(NSInteger code, NSString *msg) {
|
||||
@kStrongify(self);
|
||||
if ([[self getView] respondsToSelector:@selector(emailCodeFailure)]) {
|
||||
[[self getView] emailCodeFailure];
|
||||
}
|
||||
} showLoading:YES errorToast:YES]
|
||||
emailAddress:desEmail
|
||||
type:@(type)];
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.4 API 接口调用
|
||||
```objc
|
||||
+ (void)emailGetCode:(HttpRequestHelperCompletion)completion
|
||||
emailAddress:(NSString *)emailAddress
|
||||
type:(NSNumber *)type {
|
||||
[self makeRequest:@"email/getCode"
|
||||
method:HttpRequestHelperMethodPOST
|
||||
completion:completion, __FUNCTION__, emailAddress, type, nil];
|
||||
}
|
||||
```
|
||||
|
||||
**API 详情**:
|
||||
- **接口路径**: `POST /email/getCode`
|
||||
- **请求参数**:
|
||||
- `emailAddress`: 邮箱地址(DES 加密)
|
||||
- `type`: 验证码类型(1=注册)
|
||||
|
||||
#### 2.5 获取验证码成功处理
|
||||
```objc
|
||||
- (void)emailCodeSucess:(NSString *)message type:(GetSmsType)type {
|
||||
[self showSuccessToast:YMLocalizedString(@"XPLoginPhoneViewController2")]; // "验证码已发送"
|
||||
[self.secondLineInputView startVerificationCountDown]; // 开始倒计时
|
||||
[self.secondLineInputView displayKeyboard]; // 显示键盘
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.6 获取验证码失败处理
|
||||
```objc
|
||||
- (void)emailCodeFailure {
|
||||
[self.secondLineInputView endVerificationCountDown]; // 结束倒计时
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 邮箱登录流程
|
||||
|
||||
#### 3.1 登录按钮状态检查
|
||||
```objc
|
||||
- (void)checkActionButtonStatus {
|
||||
switch (self.type) {
|
||||
case LoginDisplayType_email: {
|
||||
NSString *accountString = [self.firstLineInputView inputContent]; // 邮箱
|
||||
NSString *codeString = [self.secondLineInputView inputContent]; // 验证码
|
||||
|
||||
// 只有当邮箱和验证码都不为空时才启用登录按钮
|
||||
if (![NSString isEmpty:accountString] && ![NSString isEmpty:codeString]) {
|
||||
self.bottomActionButton.enabled = YES;
|
||||
} else {
|
||||
self.bottomActionButton.enabled = NO;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.2 登录按钮点击处理
|
||||
```objc
|
||||
- (void)didTapActionButton {
|
||||
[self.view endEditing:true];
|
||||
|
||||
switch (self.type) {
|
||||
case LoginDisplayType_email: {
|
||||
// 调用 Presenter 进行邮箱登录
|
||||
[self.presenter loginWithEmail:[self.firstLineInputView inputContent]
|
||||
code:[self.secondLineInputView inputContent]];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.3 Presenter 层登录处理
|
||||
```objc
|
||||
- (void)loginWithEmail:(NSString *)email code:(NSString *)code {
|
||||
// DES 加密邮箱地址
|
||||
NSString *desMail = [DESEncrypt encryptUseDES:email
|
||||
key:KeyWithType(KeyType_PasswordEncode)];
|
||||
|
||||
@kWeakify(self);
|
||||
[Api loginWithCode:[self createHttpCompletion:^(BaseModel *data) {
|
||||
@kStrongify(self);
|
||||
|
||||
// 解析账户模型
|
||||
AccountModel *accountModel = [AccountModel modelWithDictionary:data.data];
|
||||
|
||||
// 保存账户信息
|
||||
if (accountModel && accountModel.access_token.length > 0) {
|
||||
[[AccountInfoStorage instance] saveAccountInfo:accountModel];
|
||||
}
|
||||
|
||||
// 通知登录成功
|
||||
if ([[self getView] respondsToSelector:@selector(loginSuccess)]) {
|
||||
[[self getView] loginSuccess];
|
||||
}
|
||||
} fail:^(NSInteger code, NSString *msg) {
|
||||
@kStrongify(self);
|
||||
[[self getView] loginFailWithMsg:msg];
|
||||
} errorToast:NO]
|
||||
email:desMail
|
||||
code:code
|
||||
client_secret:clinet_s // 客户端密钥
|
||||
version:@"1"
|
||||
client_id:@"erban-client"
|
||||
grant_type:@"email"]; // 邮箱登录类型
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.4 API 接口调用
|
||||
```objc
|
||||
+ (void)loginWithCode:(HttpRequestHelperCompletion)completion
|
||||
email:(NSString *)email
|
||||
code:(NSString *)code
|
||||
client_secret:(NSString *)client_secret
|
||||
version:(NSString *)version
|
||||
client_id:(NSString *)client_id
|
||||
grant_type:(NSString *)grant_type {
|
||||
|
||||
NSString *fang = [NSString stringFromBase64String:@"b2F1dGgvdG9rZW4="]; // oauth/token
|
||||
[self makeRequest:fang
|
||||
method:HttpRequestHelperMethodPOST
|
||||
completion:completion, __FUNCTION__, email, code, client_secret,
|
||||
version, client_id, grant_type, nil];
|
||||
}
|
||||
```
|
||||
|
||||
**API 详情**:
|
||||
- **接口路径**: `POST /oauth/token`
|
||||
- **请求参数**:
|
||||
- `email`: 邮箱地址(DES 加密)
|
||||
- `code`: 验证码
|
||||
- `client_secret`: 客户端密钥
|
||||
- `version`: 版本号 "1"
|
||||
- `client_id`: 客户端ID "erban-client"
|
||||
- `grant_type`: 授权类型 "email"
|
||||
|
||||
#### 3.5 登录成功处理
|
||||
```objc
|
||||
- (void)loginSuccess {
|
||||
[self showSuccessToast:YMLocalizedString(@"XPLoginPhoneViewController1")]; // "登录成功"
|
||||
[PILoginManager loginWithVC:self isLoginPhone:NO]; // 执行登录后续处理
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.6 登录失败处理
|
||||
```objc
|
||||
- (void)loginFailWithMsg:(NSString *)msg {
|
||||
[self showSuccessToast:msg]; // 显示错误信息
|
||||
}
|
||||
```
|
||||
|
||||
## 数据流时序图
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as 用户
|
||||
participant VC as LoginTypesViewController
|
||||
participant IV as LoginInputItemView
|
||||
participant P as LoginPresenter
|
||||
participant API as Api+Login
|
||||
participant Storage as AccountInfoStorage
|
||||
|
||||
Note over User,Storage: 1. 初始化邮箱登录界面
|
||||
User->>VC: 选择邮箱登录
|
||||
VC->>VC: updateLoginType(LoginDisplayType_email)
|
||||
VC->>VC: setupEmailInputArea()
|
||||
VC->>IV: 创建邮箱输入框
|
||||
VC->>IV: 创建验证码输入框
|
||||
|
||||
Note over User,Storage: 2. 获取邮箱验证码
|
||||
User->>IV: 输入邮箱地址
|
||||
User->>IV: 点击"获取验证码"
|
||||
IV->>VC: handleTapGetMailVerificationCode
|
||||
VC->>VC: 验证邮箱地址非空
|
||||
VC->>P: sendMailVerificationCode(email, GetSmsType_Regist)
|
||||
P->>P: DES加密邮箱地址
|
||||
P->>API: emailGetCode(encryptedEmail, type=1)
|
||||
API-->>P: 验证码发送结果
|
||||
P-->>VC: emailCodeSucess / emailCodeFailure
|
||||
VC->>IV: startVerificationCountDown / endVerificationCountDown
|
||||
VC->>User: 显示成功/失败提示
|
||||
|
||||
Note over User,Storage: 3. 邮箱验证码登录
|
||||
User->>IV: 输入验证码
|
||||
IV->>VC: 输入内容变化回调
|
||||
VC->>VC: checkActionButtonStatus()
|
||||
VC->>User: 启用/禁用登录按钮
|
||||
User->>VC: 点击登录按钮
|
||||
VC->>VC: didTapActionButton()
|
||||
VC->>P: loginWithEmail(email, code)
|
||||
P->>P: DES加密邮箱地址
|
||||
P->>API: loginWithCode(email, code, ...)
|
||||
API-->>P: OAuth Token 响应
|
||||
P->>P: 解析 AccountModel
|
||||
P->>Storage: saveAccountInfo(accountModel)
|
||||
P-->>VC: loginSuccess / loginFailWithMsg
|
||||
VC->>User: 显示登录结果
|
||||
VC->>User: 跳转到主界面
|
||||
```
|
||||
|
||||
## 安全机制
|
||||
|
||||
### 1. 数据加密
|
||||
- **邮箱地址加密**: 使用 DES 算法加密邮箱地址后传输
|
||||
```objc
|
||||
NSString *desEmail = [DESEncrypt encryptUseDES:email key:KeyWithType(KeyType_PasswordEncode)];
|
||||
```
|
||||
|
||||
### 2. 输入验证
|
||||
- **邮箱格式验证**: 通过 `UIKeyboardTypeEmailAddress` 键盘类型引导正确输入
|
||||
- **非空验证**: 邮箱和验证码都必须非空才能执行登录
|
||||
|
||||
### 3. 验证码安全
|
||||
- **时效性**: 验证码具有倒计时机制,防止重复获取
|
||||
- **类型标识**: 使用 `GetSmsType_Regist = 1` 标识登录验证码
|
||||
|
||||
### 4. 网络安全
|
||||
- **错误处理**: 完整的成功/失败回调机制
|
||||
- **加载状态**: `showLoading:YES` 防止重复请求
|
||||
- **错误提示**: `errorToast:YES` 显示网络错误
|
||||
|
||||
## 错误处理机制
|
||||
|
||||
### 1. 邮箱验证码获取错误
|
||||
```objc
|
||||
- (void)emailCodeFailure {
|
||||
[self.secondLineInputView endVerificationCountDown]; // 停止倒计时
|
||||
// 用户可以重新获取验证码
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 登录失败处理
|
||||
```objc
|
||||
- (void)loginFailWithMsg:(NSString *)msg {
|
||||
[self showSuccessToast:msg]; // 显示具体错误信息
|
||||
// 用户可以重新尝试登录
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 网络请求错误
|
||||
- **自动重试**: 用户可以手动重新点击获取验证码或登录
|
||||
- **错误提示**: 通过 Toast 显示具体错误信息
|
||||
- **状态恢复**: 失败后恢复按钮可点击状态
|
||||
|
||||
## 本地化支持
|
||||
|
||||
### 关键文本资源
|
||||
- `@"20.20.51_text_1"`: "邮箱登录"
|
||||
- `@"20.20.51_text_4"`: "请输入邮箱地址"
|
||||
- `@"20.20.51_text_7"`: "请输入验证码"
|
||||
- `@"XPLoginPhoneViewController2"`: "验证码已发送"
|
||||
- `@"XPLoginPhoneViewController1"`: "登录成功"
|
||||
|
||||
### 多语言支持
|
||||
- 简体中文 (`zh-Hant.lproj`)
|
||||
- 英文 (`en.lproj`)
|
||||
- 阿拉伯语 (`ar.lproj`)
|
||||
- 土耳其语 (`tr.lproj`)
|
||||
|
||||
## 依赖组件
|
||||
|
||||
### 外部框架
|
||||
- **MASConstraintMaker**: 自动布局
|
||||
- **ReactiveObjC**: 响应式编程(部分组件使用)
|
||||
|
||||
### 内部组件
|
||||
- **YMLocalizedString**: 本地化字符串管理
|
||||
- **DESEncrypt**: DES 加密工具
|
||||
- **AccountInfoStorage**: 账户信息存储
|
||||
- **HttpRequestHelper**: 网络请求管理
|
||||
|
||||
## 扩展和维护
|
||||
|
||||
### 新增功能建议
|
||||
1. **邮箱格式验证**: 添加正则表达式验证邮箱格式
|
||||
2. **验证码长度限制**: 限制验证码输入长度
|
||||
3. **自动填充**: 支持系统邮箱自动填充
|
||||
4. **记住邮箱**: 保存最近使用的邮箱地址
|
||||
|
||||
### 性能优化
|
||||
1. **请求去重**: 防止短时间内重复请求验证码
|
||||
2. **缓存机制**: 缓存验证码倒计时状态
|
||||
3. **网络优化**: 添加请求超时和重试机制
|
||||
|
||||
### 代码维护
|
||||
1. **常量管理**: 将硬编码字符串提取为常量
|
||||
2. **错误码统一**: 统一管理API错误码
|
||||
3. **日志记录**: 添加详细的操作日志
|
||||
|
||||
## 总结
|
||||
|
||||
邮箱验证码登录流程是一个完整的用户认证系统,包含了界面展示、验证码获取、用户登录、数据存储等完整环节。该流程具有良好的安全性、用户体验和错误处理机制,符合现代移动应用的认证标准。
|
||||
|
||||
通过本文档,开发人员可以全面了解邮箱登录的实现细节,便于后续的功能扩展和维护工作。
|
262
OAuth_Ticket_API_Documentation.md
Normal file
262
OAuth_Ticket_API_Documentation.md
Normal file
@@ -0,0 +1,262 @@
|
||||
# OAuth/Ticket 认证系统 API 文档
|
||||
|
||||
## 概述
|
||||
|
||||
本文档描述了 YuMi 应用中 OAuth 认证和 Ticket 会话管理的完整流程。系统采用两阶段认证机制:
|
||||
1. **OAuth 阶段**:用户登录获取 `access_token`
|
||||
2. **Ticket 阶段**:使用 `access_token` 获取业务会话 `ticket`
|
||||
|
||||
## 认证流程架构
|
||||
|
||||
### 核心组件
|
||||
- **AccountInfoStorage**: 负责账户信息和 ticket 的本地存储
|
||||
- **HttpRequestHelper**: 网络请求管理,自动添加认证头
|
||||
- **Api+Login**: 登录相关 API 接口
|
||||
- **Api+Main**: Ticket 获取相关 API 接口
|
||||
|
||||
### 认证数据模型
|
||||
|
||||
#### AccountModel
|
||||
```objc
|
||||
@interface AccountModel : PIBaseModel
|
||||
@property (nonatomic, assign) NSString *uid; // 用户唯一标识
|
||||
@property (nonatomic, copy) NSString *jti; // JWT ID
|
||||
@property (nonatomic, copy) NSString *token_type; // Token 类型
|
||||
@property (nonatomic, copy) NSString *refresh_token; // 刷新令牌
|
||||
@property (nonatomic, copy) NSString *netEaseToken; // 网易云信令牌
|
||||
@property (nonatomic, copy) NSString *access_token; // OAuth 访问令牌
|
||||
@property (nonatomic, assign) NSNumber *expires_in; // 过期时间
|
||||
@end
|
||||
```
|
||||
|
||||
## API 接口详情
|
||||
|
||||
### 1. OAuth 登录接口
|
||||
|
||||
#### 1.1 手机验证码登录
|
||||
```objc
|
||||
+ (void)loginWithCode:(HttpRequestHelperCompletion)completion
|
||||
phone:(NSString *)phone
|
||||
code:(NSString *)code
|
||||
client_secret:(NSString *)client_secret
|
||||
version:(NSString *)version
|
||||
client_id:(NSString *)client_id
|
||||
grant_type:(NSString *)grant_type
|
||||
phoneAreaCode:(NSString *)phoneAreaCode;
|
||||
```
|
||||
|
||||
**接口路径**: `POST /oauth/token`
|
||||
|
||||
**请求参数**:
|
||||
| 参数名 | 类型 | 必填 | 描述 |
|
||||
|--------|------|------|------|
|
||||
| phone | String | 是 | 手机号(DES加密) |
|
||||
| code | String | 是 | 验证码 |
|
||||
| client_secret | String | 是 | 客户端密钥,固定值:"uyzjdhds" |
|
||||
| version | String | 是 | 版本号,固定值:"1" |
|
||||
| client_id | String | 是 | 客户端ID,固定值:"erban-client" |
|
||||
| grant_type | String | 是 | 授权类型,验证码登录为:"sms_code" |
|
||||
| phoneAreaCode | String | 是 | 手机区号 |
|
||||
|
||||
**返回数据**: AccountModel 对象
|
||||
|
||||
#### 1.2 手机密码登录
|
||||
```objc
|
||||
+ (void)loginWithPassword:(HttpRequestHelperCompletion)completion
|
||||
phone:(NSString *)phone
|
||||
password:(NSString *)password
|
||||
client_secret:(NSString *)client_secret
|
||||
version:(NSString *)version
|
||||
client_id:(NSString *)client_id
|
||||
grant_type:(NSString *)grant_type;
|
||||
```
|
||||
|
||||
**接口路径**: `POST /oauth/token`
|
||||
|
||||
**请求参数**:
|
||||
| 参数名 | 类型 | 必填 | 描述 |
|
||||
|--------|------|------|------|
|
||||
| phone | String | 是 | 手机号(DES加密) |
|
||||
| password | String | 是 | 密码(DES加密) |
|
||||
| client_secret | String | 是 | 客户端密钥 |
|
||||
| version | String | 是 | 版本号 |
|
||||
| client_id | String | 是 | 客户端ID |
|
||||
| grant_type | String | 是 | 授权类型,密码登录为:"password" |
|
||||
|
||||
#### 1.3 第三方登录
|
||||
```objc
|
||||
+ (void)loginWithThirdPart:(HttpRequestHelperCompletion)completion
|
||||
openid:(NSString *)openid
|
||||
unionid:(NSString *)unionid
|
||||
access_token:(NSString *)access_token
|
||||
type:(NSString *)type;
|
||||
```
|
||||
|
||||
**接口路径**: `POST /acc/third/login`
|
||||
|
||||
**请求参数**:
|
||||
| 参数名 | 类型 | 必填 | 描述 |
|
||||
|--------|------|------|------|
|
||||
| openid | String | 是 | 第三方平台用户唯一标识 |
|
||||
| unionid | String | 是 | 第三方平台联合ID |
|
||||
| access_token | String | 是 | 第三方平台访问令牌 |
|
||||
| type | String | 是 | 第三方平台类型(1:Apple, 2:Facebook, 3:Google等) |
|
||||
|
||||
### 2. Ticket 获取接口
|
||||
|
||||
#### 2.1 获取 Ticket
|
||||
```objc
|
||||
+ (void)requestTicket:(HttpRequestHelperCompletion)completion
|
||||
access_token:(NSString *)accessToken
|
||||
issue_type:(NSString *)issueType;
|
||||
```
|
||||
|
||||
**接口路径**: `POST /oauth/ticket`
|
||||
|
||||
**请求参数**:
|
||||
| 参数名 | 类型 | 必填 | 描述 |
|
||||
|--------|------|------|------|
|
||||
| access_token | String | 是 | OAuth 登录获取的访问令牌 |
|
||||
| issue_type | String | 是 | 签发类型,固定值:"multi" |
|
||||
|
||||
**返回数据**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"tickets": [
|
||||
{
|
||||
"ticket": "eyJhbGciOiJIUzI1NiJ9..."
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. HTTP 请求头配置
|
||||
|
||||
所有业务 API 请求都会自动添加以下请求头:
|
||||
|
||||
```objc
|
||||
// 在 HttpRequestHelper 中自动配置
|
||||
- (void)setupHeader {
|
||||
AFHTTPSessionManager *client = [HttpRequestHelper requestManager];
|
||||
|
||||
// 用户ID头
|
||||
if ([[AccountInfoStorage instance] getUid].length > 0) {
|
||||
[client.requestSerializer setValue:[[AccountInfoStorage instance] getUid]
|
||||
forHTTPHeaderField:@"pub_uid"];
|
||||
}
|
||||
|
||||
// Ticket 认证头
|
||||
if ([[AccountInfoStorage instance] getTicket].length > 0) {
|
||||
[client.requestSerializer setValue:[[AccountInfoStorage instance] getTicket]
|
||||
forHTTPHeaderField:@"pub_ticket"];
|
||||
}
|
||||
|
||||
// 其他公共头
|
||||
[client.requestSerializer setValue:[NSBundle uploadLanguageText]
|
||||
forHTTPHeaderField:@"Accept-Language"];
|
||||
[client.requestSerializer setValue:PI_App_Version
|
||||
forHTTPHeaderField:@"App-Version"];
|
||||
}
|
||||
```
|
||||
|
||||
## 使用流程
|
||||
|
||||
### 完整登录流程示例
|
||||
|
||||
```objc
|
||||
// 1. 用户登录获取 access_token
|
||||
[Api loginWithCode:^(BaseModel * _Nullable data, NSInteger code, NSString * _Nullable msg) {
|
||||
if (code == 200) {
|
||||
// 保存账户信息
|
||||
AccountModel *accountModel = [AccountModel modelWithDictionary:data.data];
|
||||
[[AccountInfoStorage instance] saveAccountInfo:accountModel];
|
||||
|
||||
// 2. 使用 access_token 获取 ticket
|
||||
[Api requestTicket:^(BaseModel * _Nullable data, NSInteger code, NSString * _Nullable msg) {
|
||||
if (code == 200) {
|
||||
NSArray *tickets = [data.data valueForKey:@"tickets"];
|
||||
NSString *ticket = [tickets[0] valueForKey:@"ticket"];
|
||||
|
||||
// 保存 ticket
|
||||
[[AccountInfoStorage instance] saveTicket:ticket];
|
||||
|
||||
// 3. 登录成功,可以进行业务操作
|
||||
[self navigateToMainPage];
|
||||
}
|
||||
} access_token:accountModel.access_token issue_type:@"multi"];
|
||||
}
|
||||
} phone:encryptedPhone
|
||||
code:verificationCode
|
||||
client_secret:@"uyzjdhds"
|
||||
version:@"1"
|
||||
client_id:@"erban-client"
|
||||
grant_type:@"sms_code"
|
||||
phoneAreaCode:areaCode];
|
||||
```
|
||||
|
||||
### 自动登录流程
|
||||
|
||||
```objc
|
||||
- (void)autoLogin {
|
||||
// 检查本地是否有账户信息
|
||||
AccountModel *accountModel = [[AccountInfoStorage instance] getCurrentAccountInfo];
|
||||
if (accountModel == nil || accountModel.access_token == nil) {
|
||||
[self tokenInvalid]; // 跳转到登录页
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否有有效的 ticket
|
||||
if ([[AccountInfoStorage instance] getTicket].length > 0) {
|
||||
[[self getView] autoLoginSuccess];
|
||||
return;
|
||||
}
|
||||
|
||||
// 使用 access_token 重新获取 ticket
|
||||
[Api requestTicket:^(BaseModel * _Nonnull data) {
|
||||
NSArray *tickets = [data.data valueForKey:@"tickets"];
|
||||
NSString *ticket = [tickets[0] valueForKey:@"ticket"];
|
||||
[[AccountInfoStorage instance] saveTicket:ticket];
|
||||
[[self getView] autoLoginSuccess];
|
||||
} fail:^(NSInteger code, NSString * _Nullable msg) {
|
||||
[self logout]; // ticket 获取失败,重新登录
|
||||
} access_token:accountModel.access_token issue_type:@"multi"];
|
||||
}
|
||||
```
|
||||
|
||||
## 错误处理
|
||||
|
||||
### 401 未授权错误
|
||||
当接收到 401 状态码时,系统会自动处理:
|
||||
|
||||
```objc
|
||||
// 在 HttpRequestHelper 中
|
||||
if (response && response.statusCode == 401) {
|
||||
failure(response.statusCode, YMLocalizedString(@"HttpRequestHelper7"));
|
||||
// 通常需要重新登录
|
||||
}
|
||||
```
|
||||
|
||||
### Ticket 过期处理
|
||||
- Ticket 过期时服务器返回 401 错误
|
||||
- 客户端应该使用保存的 `access_token` 重新获取 ticket
|
||||
- 如果 `access_token` 也过期,则需要用户重新登录
|
||||
|
||||
## 安全注意事项
|
||||
|
||||
1. **数据加密**: 敏感信息(手机号、密码)使用 DES 加密传输
|
||||
2. **本地存储**:
|
||||
- `access_token` 存储在文件系统中
|
||||
- `ticket` 存储在内存中,应用重启需重新获取
|
||||
3. **请求头**: 所有业务请求自动携带 `pub_uid` 和 `pub_ticket` 头
|
||||
4. **错误处理**: 建立完善的 401 错误重试机制
|
||||
|
||||
## 相关文件
|
||||
|
||||
- `YuMi/Structure/MVP/Model/AccountInfoStorage.h/m` - 账户信息存储管理
|
||||
- `YuMi/Modules/YMLogin/Api/Api+Login.h/m` - 登录相关接口
|
||||
- `YuMi/Modules/YMTabbar/Api/Api+Main.h/m` - Ticket 获取接口
|
||||
- `YuMi/Network/HttpRequestHelper.h/m` - 网络请求管理
|
||||
- `YuMi/Structure/MVP/Model/AccountModel.h/m` - 账户数据模型
|
3
Podfile
3
Podfile
@@ -61,7 +61,7 @@ target 'YuMi' do
|
||||
|
||||
pod 'UMCommon'
|
||||
pod 'UMDevice'
|
||||
# pod 'ZLCollectionViewFlowLayout'
|
||||
pod 'ZLCollectionViewFlowLayout'
|
||||
pod 'TABAnimated'
|
||||
pod 'YuMi',:path=>'yum'
|
||||
pod 'QCloudCOSXML'
|
||||
@@ -74,6 +74,7 @@ post_install do |installer|
|
||||
target.build_configurations.each do |config|
|
||||
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '11.0'
|
||||
config.build_settings['DEBUG_INFORMATION_FORMAT'] = 'dwarf-with-dsym'
|
||||
config.build_settings['ENABLE_BITCODE'] = 'NO'
|
||||
xcconfig_path = config.base_configuration_reference.real_path
|
||||
xcconfig = File.read(xcconfig_path)
|
||||
xcconfig_mod = xcconfig.gsub(/DT_TOOLCHAIN_DIR/, "TOOLCHAIN_DIR")
|
||||
|
@@ -2665,6 +2665,8 @@
|
||||
4C44BD5C2D151B5C00F321FA /* RoomSideMenu.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RoomSideMenu.m; sourceTree = "<group>"; };
|
||||
4C4707A32D53430300C8CD24 /* NSData+GZIP.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSData+GZIP.h"; sourceTree = "<group>"; };
|
||||
4C4707A42D53430300C8CD24 /* NSData+GZIP.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSData+GZIP.m"; sourceTree = "<group>"; };
|
||||
4C4DE6442E2513DA00122763 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
|
||||
4C4DE6452E2513DB00122763 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||
4C51B09A2DA3B4C600D8DFB5 /* LudoGameViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LudoGameViewController.h; sourceTree = "<group>"; };
|
||||
4C51B09B2DA3B4C600D8DFB5 /* LudoGameViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LudoGameViewController.m; sourceTree = "<group>"; };
|
||||
4C51B09D2DA50FDA00D8DFB5 /* CPRelationshipChangeView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CPRelationshipChangeView.h; sourceTree = "<group>"; };
|
||||
@@ -5473,7 +5475,6 @@
|
||||
children = (
|
||||
4C7F2A682E0BE7C8002F5058 /* FirstCharge */,
|
||||
4CC312212D79878B00F57A07 /* Share */,
|
||||
234F44E12B3EA4DC00E2B532 /* YMLine */,
|
||||
23CEFC082AFB8FC100576D89 /* sdkContent */,
|
||||
23FF255C2ABA8EEE0064E904 /* PIIAPTool */,
|
||||
23E9EA9B2A84C42B00B792F2 /* SGYProgressView */,
|
||||
@@ -6078,13 +6079,6 @@
|
||||
path = NSTextAttachment;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
234F44E12B3EA4DC00E2B532 /* YMLine */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
);
|
||||
path = YMLine;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
236B2E1B2AA0786E003967A8 /* Library */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -11749,6 +11743,7 @@
|
||||
"zh-Hant",
|
||||
ar,
|
||||
tr,
|
||||
"pt-BR",
|
||||
);
|
||||
mainGroup = 189DD52026DE255300AB55B1;
|
||||
productRefGroup = 189DD52A26DE255300AB55B1 /* Products */;
|
||||
@@ -13499,6 +13494,7 @@
|
||||
2368ECD02BC38FA900EDF4C9 /* en */,
|
||||
2368ECD22BC38FC500EDF4C9 /* zh-Hant */,
|
||||
54435F2C2CC89D4600F4884B /* tr */,
|
||||
4C4DE6442E2513DA00122763 /* pt-BR */,
|
||||
);
|
||||
name = InfoPlist.strings;
|
||||
sourceTree = "<group>";
|
||||
@@ -13519,6 +13515,7 @@
|
||||
2368ECC92BC38F6400EDF4C9 /* ar */,
|
||||
2368ECCA2BC38F6F00EDF4C9 /* en */,
|
||||
54435F2D2CC89D4600F4884B /* tr */,
|
||||
4C4DE6452E2513DB00122763 /* pt-BR */,
|
||||
);
|
||||
name = Localizable.strings;
|
||||
sourceTree = "<group>";
|
||||
@@ -13908,7 +13905,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = 48UCG35Q9W;
|
||||
DEVELOPMENT_TEAM = Z7UCRF23F3;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
@@ -14131,7 +14128,7 @@
|
||||
"-weak_framework",
|
||||
"\"AuthenticationServices\"",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.peko.enterprise.ios;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.hflighting.yumi;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
|
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "room_menu_gift_first_recharge_ar.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 3.6 KiB |
@@ -534,15 +534,14 @@
|
||||
NSString *curImage = image;
|
||||
NSString *language = [NSBundle getLanguageText];
|
||||
|
||||
// 根据语言添加后缀
|
||||
if ([language isEqualToString:@"en"]) {
|
||||
image = [NSString stringWithFormat:@"%@_en", image];
|
||||
} else if ([language isEqualToString:@"ar"]) {
|
||||
image = [NSString stringWithFormat:@"%@_ar", image];
|
||||
} else if ([language isEqualToString:@"tr"]) {
|
||||
if (isMSZH()) {
|
||||
// 不處理
|
||||
} else if (isMSTR()) {
|
||||
image = [NSString stringWithFormat:@"%@_tr", image];
|
||||
} else if (isMSRTL()) {
|
||||
image = [NSString stringWithFormat:@"%@_ar", image];
|
||||
} else {
|
||||
// 华语不处理
|
||||
image = [NSString stringWithFormat:@"%@_en", image];
|
||||
}
|
||||
|
||||
// 尝试获取带语言后缀的图片
|
||||
|
@@ -46,7 +46,7 @@ isPhoneXSeries = [[UIApplication sharedApplication] delegate].window.safeAreaIns
|
||||
#define kFontHeavy(font) [UIFont systemFontOfSize:kGetScaleWidth(font) weight:UIFontWeightHeavy]
|
||||
|
||||
///内置版本号
|
||||
#define PI_App_Version @"1.0.28.1"
|
||||
#define PI_App_Version @"1.0.29"
|
||||
///渠道
|
||||
#define PI_App_Source @"appstore"
|
||||
#define PI_Test_Flight @"TestFlight"
|
||||
@@ -68,6 +68,8 @@ isPhoneXSeries = [[UIApplication sharedApplication] delegate].window.safeAreaIns
|
||||
#define isMSEN() [[NSBundle getLanguageText] hasPrefix:@"en"]
|
||||
///是否土耳其语
|
||||
#define isMSTR() [[NSBundle getLanguageText] hasPrefix:@"tr"]
|
||||
///是否葡萄牙语
|
||||
#define isMSPT() [[NSBundle getLanguageText] hasPrefix:@"pt"]
|
||||
|
||||
|
||||
#endif /* YUMIMacroUitls_h */
|
||||
|
BIN
YuMi/Library/SudMGP.framework/plugin.zip
Normal file
BIN
YuMi/Library/SudMGP.framework/plugin.zip
Normal file
Binary file not shown.
@@ -25,7 +25,9 @@
|
||||
UserInfoModel * infoModel = [UserInfoModel modelWithDictionary:data.data];
|
||||
[[self getView] onGetUserInfoSuccess:infoModel];
|
||||
} fail:^(NSInteger code, NSString * _Nullable msg) {
|
||||
|
||||
if ([self.getView respondsToSelector:@selector(onGetUserFailure:)]) {
|
||||
[self.getView onGetUserFailure:code];
|
||||
}
|
||||
}] uid:uid];
|
||||
}
|
||||
|
||||
|
@@ -17,6 +17,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
///获取用户信息成功
|
||||
- (void)onGetSessionUserInfoSuccess:(UserInfoModel *)userInfo;
|
||||
|
||||
- (void)onGetUserFailure:(NSInteger)code;
|
||||
|
||||
///获取粉丝喜欢成功
|
||||
- (void)getFansLikeSuccess:(BOOL)isLike;
|
||||
///关注成功
|
||||
|
@@ -157,7 +157,7 @@
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
if (![[[ClientConfig shareConfig].configInfo officialAccountUids] containsObject:self.session.sessionId]) {
|
||||
if (![NIMMessageUtils isOfficalAccount:self.session.sessionId]) {
|
||||
[self.presenter getFansLike:self.session.sessionId];
|
||||
if (!self.userInfo) {
|
||||
[self.presenter getUserInfoWithUid:self.session.sessionId];
|
||||
@@ -573,10 +573,27 @@
|
||||
make.top.mas_equalTo(self.sessionNavView.mas_bottom).mas_offset(0);
|
||||
}];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
- (void)onGetUserFailure:(NSInteger)code {
|
||||
if (code == 3009) {
|
||||
if (self.openType == SessionListOpenTypeRoom) {
|
||||
CATransition *transition = [CATransition animation];
|
||||
transition.duration = 0.3f;
|
||||
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
|
||||
transition.type = kCATransitionPush;
|
||||
transition.subtype = kCATransitionFromLeft;
|
||||
[self.view.superview.layer addAnimation:transition forKey:nil];
|
||||
[self willMoveToParentViewController:nil]; //1
|
||||
[self.view removeFromSuperview]; //2
|
||||
[self removeFromParentViewController]; //3
|
||||
return;
|
||||
}
|
||||
[self.navigationController popViewControllerAnimated:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)getFansLikeSuccess:(BOOL)isLike {
|
||||
self.sessionNavView.isLike = isLike;
|
||||
if(self.isAttention == YES && isLike == NO){
|
||||
|
@@ -22,6 +22,7 @@
|
||||
#import "XPSkillCardPlayerManager.h"
|
||||
#import "MessagePresenter.h"
|
||||
#import "MessageProtocol.h"
|
||||
#import "NIMMessageUtils.h"
|
||||
|
||||
NSString * const kMessageShowReadDotKey = @"kMessageShowReadDotKey";
|
||||
|
||||
@@ -147,10 +148,25 @@ NSString * const kMessageShowReadDotKey = @"kMessageShowReadDotKey";
|
||||
|
||||
- (void)onGetUserInfoSuccess:(UserInfoModel *)userInfo {
|
||||
if (userInfo) {
|
||||
SessionViewController *vc = [[SessionViewController alloc] initWithSession:self.recentSession.session];
|
||||
vc.openType = self.openType;
|
||||
vc.userInfo = userInfo;
|
||||
[self.navigationController pushViewController:vc animated:YES];
|
||||
|
||||
if (self.openType == SessionListOpenTypeRoom) {
|
||||
SessionViewController * sessionVC =[[SessionViewController alloc] initWithSession:self.recentSession.session];
|
||||
sessionVC.userInfo = userInfo;
|
||||
sessionVC.openType = self.openType;
|
||||
CATransition *transition = [CATransition animation];
|
||||
transition.duration = 0.3f;
|
||||
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
|
||||
transition.type = kCATransitionPush;
|
||||
transition.subtype = kCATransitionFromRight;
|
||||
[self.mainController.view.layer addAnimation:transition forKey:nil];
|
||||
[self.mainController.view addSubview:sessionVC.view];
|
||||
[self.mainController addChildViewController:sessionVC];
|
||||
} else {
|
||||
SessionViewController *vc = [[SessionViewController alloc] initWithSession:self.recentSession.session];
|
||||
vc.openType = self.openType;
|
||||
vc.userInfo = userInfo;
|
||||
[self.navigationController pushViewController:vc animated:YES];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,28 +176,28 @@ NSString * const kMessageShowReadDotKey = @"kMessageShowReadDotKey";
|
||||
return;
|
||||
}
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||
if (self.openType == SessionListOpenTypeRoom) {
|
||||
NIMRecentSession *recentSession = self.recentSessions[indexPath.row];
|
||||
SessionViewController * sessionVC =[[SessionViewController alloc] initWithSession:recentSession.session];
|
||||
sessionVC.openType = self.openType;
|
||||
CATransition *transition = [CATransition animation];
|
||||
transition.duration = 0.3f;
|
||||
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
|
||||
transition.type = kCATransitionPush;
|
||||
transition.subtype = kCATransitionFromRight;
|
||||
[self.mainController.view.layer addAnimation:transition forKey:nil];
|
||||
[self.mainController.view addSubview:sessionVC.view];
|
||||
[self.mainController addChildViewController:sessionVC];
|
||||
} else {
|
||||
NIMRecentSession *recentSession = self.recentSessions[indexPath.row];
|
||||
self.recentSession = recentSession;
|
||||
if ([[[ClientConfig shareConfig].configInfo officialAccountUids] containsObject:self.recentSession.session.sessionId]) {
|
||||
NIMRecentSession *recentSession = self.recentSessions[indexPath.row];
|
||||
self.recentSession = recentSession;
|
||||
|
||||
if ([NIMMessageUtils isOfficalAccount:self.recentSession.session.sessionId]) {
|
||||
if (self.openType == SessionListOpenTypeRoom) {
|
||||
SessionViewController * sessionVC =[[SessionViewController alloc] initWithSession:self.recentSession.session];
|
||||
sessionVC.openType = self.openType;
|
||||
CATransition *transition = [CATransition animation];
|
||||
transition.duration = 0.3f;
|
||||
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
|
||||
transition.type = kCATransitionPush;
|
||||
transition.subtype = kCATransitionFromRight;
|
||||
[self.mainController.view.layer addAnimation:transition forKey:nil];
|
||||
[self.mainController.view addSubview:sessionVC.view];
|
||||
[self.mainController addChildViewController:sessionVC];
|
||||
} else {
|
||||
SessionViewController *vc = [[SessionViewController alloc] initWithSession:self.recentSession.session];
|
||||
vc.openType = self.openType;
|
||||
[self.navigationController pushViewController:vc animated:YES];
|
||||
} else {
|
||||
[self.presenter getUserInfoWithUid:recentSession.session.sessionId];
|
||||
}
|
||||
} else {
|
||||
[self.presenter getUserInfoWithUid:recentSession.session.sessionId];
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -26,7 +26,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (void)rankListFailure;
|
||||
|
||||
- (void)useMedalSuccess;
|
||||
- (void)userMedalsFailure;
|
||||
- (void)useMedalFailure;
|
||||
|
||||
@end
|
||||
|
||||
|
@@ -14,7 +14,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
+ (void)registerTo:(UICollectionView *)collectionView;
|
||||
+ (instancetype)cellFor:(UICollectionView *)collectionView atIndexPath:(NSIndexPath *)index;
|
||||
|
||||
- (void)updateCell:(MedalSeriesItemVo *)model isForSquare:(BOOL)isSquare;
|
||||
- (void)updateCell:(MedalSeriesItemVo *)model isForSquare:(BOOL)isSquare isForMine:(BOOL)isMine;
|
||||
|
||||
/**
|
||||
* 当 cell 将要显示时调用
|
||||
|
@@ -75,6 +75,8 @@
|
||||
}];
|
||||
|
||||
self.titleLabel = [UILabel labelInitWithText:@"" font:kFontMedium(14) textColor:[UIColor whiteColor]];
|
||||
self.titleLabel.adjustsFontSizeToFitWidth = YES;
|
||||
self.titleLabel.minimumScaleFactor = 0.5;
|
||||
self.subLabel = [UILabel labelInitWithText:@"" font:kFontRegular(11) textColor:[UIColor colorWithWhite:1 alpha:0.6]];
|
||||
self.titleLabel.textAlignment = NSTextAlignmentCenter;
|
||||
self.subLabel.textAlignment = NSTextAlignmentCenter;
|
||||
@@ -82,7 +84,7 @@
|
||||
[self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerX.mas_equalTo(self.contentView);
|
||||
make.top.mas_equalTo(self.imageView.mas_bottom).offset(3);
|
||||
make.leading.trailing.mas_equalTo(self.contentView).inset(13);
|
||||
make.leading.trailing.mas_equalTo(self.contentView).inset(10);
|
||||
}];
|
||||
[self.contentView addSubview:self.subLabel];
|
||||
[self.subLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
@@ -102,18 +104,18 @@
|
||||
}];
|
||||
|
||||
// 设置等级选择回调
|
||||
@kWeakify(self);
|
||||
self.levelIndicatorView.levelSelectedBlock = ^(NSInteger level) {
|
||||
@kStrongify(self);
|
||||
// 处理等级选择事件
|
||||
if (self.currentItemVo && level <= self.currentItemVo.medalVos.count) {
|
||||
MedalVo *selectedMedalVo = [self.currentItemVo.medalVos xpSafeObjectAtIndex:level - 1];
|
||||
if (selectedMedalVo) {
|
||||
self.displayModel = selectedMedalVo;
|
||||
[self updateDisplayWithCurrentModel];
|
||||
}
|
||||
}
|
||||
};
|
||||
// @kWeakify(self);
|
||||
// self.levelIndicatorView.levelSelectedBlock = ^(NSInteger level) {
|
||||
// @kStrongify(self);
|
||||
// // 处理等级选择事件
|
||||
// if (self.currentItemVo && level <= self.currentItemVo.medalVos.count) {
|
||||
// MedalVo *selectedMedalVo = [self.currentItemVo.medalVos xpSafeObjectAtIndex:level - 1];
|
||||
// if (selectedMedalVo) {
|
||||
// self.displayModel = selectedMedalVo;
|
||||
// [self updateDisplayWithCurrentModel];
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
|
||||
// 设置通知监听
|
||||
[self setupNotifications];
|
||||
@@ -160,7 +162,6 @@
|
||||
self.displayModel = nil; // 重置数据模型
|
||||
self.currentItemVo = nil; // 重置当前项
|
||||
|
||||
|
||||
// 清空文本
|
||||
self.titleLabel.text = @"";
|
||||
self.subLabel.text = @"";
|
||||
@@ -173,8 +174,7 @@
|
||||
self.imageView.imageUrl = @"";
|
||||
}
|
||||
|
||||
- (void)updateCell:(MedalSeriesItemVo *)model isForSquare:(BOOL)isSquare {
|
||||
// MedalSeriesItemVo *itemVos = [model.medalSeries xpSafeObjectAtIndex:0];
|
||||
- (void)updateCell:(MedalSeriesItemVo *)model isForSquare:(BOOL)isSquare isForMine:(BOOL)isMine {
|
||||
self.currentItemVo = model;
|
||||
|
||||
// 设置指示器类型为不带图片
|
||||
@@ -184,11 +184,23 @@
|
||||
[self.levelIndicatorView setupWithMaxLevel:model.medalLevel];
|
||||
|
||||
if (isSquare) {
|
||||
self.subLabel.hidden = YES;
|
||||
self.displayModel = [model.medalVos xpSafeObjectAtIndex:model.medalVos.count - 1];
|
||||
[self.levelIndicatorView setSelectedLevel:model.medalLevel animated:NO];
|
||||
} else {
|
||||
self.subLabel.hidden = !isMine;
|
||||
self.levelIndicatorView.userInteractionEnabled = YES;
|
||||
self.displayModel = [model.medalVos xpSafeObjectAtIndex:0];
|
||||
[self.levelIndicatorView setSelectedLevel:1 animated:NO];
|
||||
NSMutableArray *arr = @[].mutableCopy;
|
||||
for (MedalVo *vo in model.medalVos) {
|
||||
if (vo.hasGain) {
|
||||
[arr addObject:@(vo.level)];
|
||||
if (vo.level > self.displayModel.level) {
|
||||
self.displayModel = vo;
|
||||
}
|
||||
}
|
||||
}
|
||||
[self.levelIndicatorView setHighlightLevels:arr animated:NO];
|
||||
}
|
||||
|
||||
self.levelIndicatorView.userInteractionEnabled = !isSquare;
|
||||
@@ -250,7 +262,7 @@
|
||||
|
||||
/// 更新文本标签
|
||||
- (void)updateTextLabels {
|
||||
self.titleLabel.text = self.displayModel.name;
|
||||
self.titleLabel.text = self.currentItemVo.seriesName;
|
||||
self.subLabel.text = [self.displayModel expireDateString];
|
||||
}
|
||||
|
||||
|
@@ -11,7 +11,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface MedalsDetailView : UIView
|
||||
|
||||
@property (nonatomic, strong) MedalSeriesItemVo *detailItemVo;
|
||||
- (void)updateSeriesItem:(MedalSeriesItemVo *)detailItem isMine:(BOOL)isMine;
|
||||
|
||||
@end
|
||||
|
||||
|
@@ -26,6 +26,8 @@
|
||||
@property (nonatomic, strong) MedalSeriesItemVo *currentSeriesItemVO;
|
||||
@property (nonatomic, strong) MedalVo *displayModel;
|
||||
|
||||
@property (nonatomic, strong) MedalSeriesItemVo *detailItemVo;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MedalsDetailView
|
||||
@@ -129,13 +131,35 @@
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)updateSeriesItem:(MedalSeriesItemVo *)detailItem isMine:(BOOL)isMine {
|
||||
self.detailItemVo = detailItem;
|
||||
if (isMine) {
|
||||
MedalVo *tempVo = [detailItem.medalVos xpSafeObjectAtIndex:0];
|
||||
for (MedalVo *vo in detailItem.medalVos) {
|
||||
if (vo.hasGain) {
|
||||
if (vo.level > tempVo.level) {
|
||||
tempVo = vo;
|
||||
}
|
||||
}
|
||||
}
|
||||
self.displayModel = tempVo;
|
||||
[self.levelIndicatorView setSelectedLevel:self.displayModel.level animated:NO];
|
||||
[self updateDisplayWithCurrentModel];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setDetailItemVo:(MedalSeriesItemVo *)detailItemVo {
|
||||
// _detailItemVo = detailItemVo;
|
||||
self.currentSeriesItemVO = detailItemVo;
|
||||
self.displayModel = [detailItemVo.medalVos xpSafeObjectAtIndex:0];
|
||||
|
||||
[self.levelIndicatorView setupWithMaxLevel:self.currentSeriesItemVO.medalLevel];
|
||||
[self.levelIndicatorView setSelectedLevel:1 animated:NO];
|
||||
for (MedalVo *vo in detailItemVo.medalVos) {
|
||||
if (vo.level > self.displayModel.level) {
|
||||
self.displayModel = vo;
|
||||
}
|
||||
}
|
||||
[self.levelIndicatorView setSelectedLevel:self.displayModel.level animated:NO];
|
||||
[self.levelIndicatorView setSeriesItems:detailItemVo.medalVos];
|
||||
|
||||
// 设置指示器类型为带图片
|
||||
|
@@ -23,6 +23,13 @@ typedef NS_ENUM(NSInteger, MedalsLevelIndicatorType) {
|
||||
- (void)setupWithMaxLevel:(NSInteger)maxLevel;
|
||||
- (void)setSelectedLevel:(NSInteger)level animated:(BOOL)animated;
|
||||
|
||||
/**
|
||||
* 设置多个高亮等级
|
||||
* @param levels 需要高亮的等级数组
|
||||
* @param animated 是否使用动画
|
||||
*/
|
||||
- (void)setHighlightLevels:(NSArray<NSNumber *> *)levels animated:(BOOL)animated;
|
||||
|
||||
/**
|
||||
* 重置等级指示器到指定等级
|
||||
* @param level 等级(0表示重置到初始状态)
|
||||
|
@@ -460,6 +460,11 @@
|
||||
CGFloat itemWidth = 25.0; // 每个等级指示器的宽度
|
||||
CGFloat leftMargin = 20.0; // 左边距
|
||||
CGFloat rightMargin = 20.0; // 右边距
|
||||
if (_levelItems.count > 4) {
|
||||
itemWidth = 16;
|
||||
leftMargin = 0;
|
||||
rightMargin = 10;
|
||||
}
|
||||
|
||||
// 计算可用宽度(考虑左右边距)
|
||||
CGFloat availableWidth = self.bounds.size.width - leftMargin - rightMargin;
|
||||
@@ -487,6 +492,9 @@
|
||||
CGFloat totalWidth = totalItemWidth + spacing * (_maxLevel - 1);
|
||||
// 重新计算起始位置,使整体居中
|
||||
startX = (self.bounds.size.width - totalWidth) / 2.0;
|
||||
if (_levelItems.count > 4) {
|
||||
startX -= spacing/2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -645,6 +653,64 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setHighlightLevels:(NSArray<NSNumber *> *)levels animated:(BOOL)animated {
|
||||
if (!levels || levels.count == 0 || _levelItems.count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 先将所有 item 重置为非高亮状态
|
||||
for (LevelItemView *item in _levelItems) {
|
||||
[item setSelected:NO animated:animated];
|
||||
}
|
||||
|
||||
// 将所有连接线重置为非高亮状态
|
||||
for (UIView *line in _connectionLines) {
|
||||
void (^updateBlock)(void) = ^{
|
||||
line.backgroundColor = UIColorFromRGB(0x8B54E8); // 非选中颜色
|
||||
};
|
||||
|
||||
if (animated) {
|
||||
[UIView animateWithDuration:0.2 animations:updateBlock];
|
||||
} else {
|
||||
updateBlock();
|
||||
}
|
||||
}
|
||||
|
||||
// 高亮指定的等级
|
||||
NSMutableSet *highlightedLevels = [NSMutableSet set];
|
||||
for (NSNumber *levelNumber in levels) {
|
||||
NSInteger level = [levelNumber integerValue];
|
||||
if (level >= 1 && level <= _maxLevel) {
|
||||
[highlightedLevels addObject:@(level)];
|
||||
|
||||
// 设置对应的 item 为高亮状态
|
||||
LevelItemView *item = _levelItems[level - 1];
|
||||
[item setSelected:YES animated:animated];
|
||||
}
|
||||
}
|
||||
|
||||
// 更新连接线状态
|
||||
// 只有当连接线两端的等级都被高亮时,连接线才高亮
|
||||
for (NSInteger i = 0; i < _connectionLines.count; i++) {
|
||||
UIView *line = _connectionLines[i];
|
||||
NSInteger startLevel = i + 1;
|
||||
NSInteger endLevel = i + 2;
|
||||
|
||||
BOOL isSelected = [highlightedLevels containsObject:@(startLevel)] &&
|
||||
[highlightedLevels containsObject:@(endLevel)];
|
||||
|
||||
void (^updateBlock)(void) = ^{
|
||||
line.backgroundColor = isSelected ? [UIColor whiteColor] : UIColorFromRGB(0x8B54E8);
|
||||
};
|
||||
|
||||
if (animated) {
|
||||
[UIView animateWithDuration:0.2 animations:updateBlock];
|
||||
} else {
|
||||
updateBlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 计算布局参数
|
||||
- (void)calculateLayoutParams:(CGFloat *)itemWidth spacing:(CGFloat *)spacing startX:(CGFloat *)startX forMaxLevel:(NSInteger)maxLevel {
|
||||
*itemWidth = 25.0; // 每个等级指示器的宽度
|
||||
|
@@ -9,6 +9,8 @@
|
||||
#import "MedalsPresenter.h"
|
||||
#import "MedalsViewController.h"
|
||||
#import "UserInfoModel.h"
|
||||
#import <MJRefresh/MJRefresh.h>
|
||||
#import "DJDKMIMOMColor.h"
|
||||
|
||||
|
||||
@interface MedalsRankListCell : UITableViewCell
|
||||
@@ -17,7 +19,7 @@
|
||||
@property (nonatomic, strong) NetImageView *avatarImageView;
|
||||
@property (nonatomic, strong) UILabel *nameLabel;
|
||||
@property (nonatomic, strong) UILabel *countLabel;
|
||||
@property (nonatomic, strong) UILabel *detailLabel;
|
||||
|
||||
|
||||
+ (void)registerTo:(UITableView *)tableView;
|
||||
+ (instancetype)cellFor:(UITableView *)tableView atIndexPath:(NSIndexPath *)index;
|
||||
@@ -44,9 +46,8 @@
|
||||
- (void)updateCell:(MedalsRankUserModel *)userModel atIndex:(NSInteger)index {
|
||||
self.avatarImageView.imageUrl = userModel.avatar;
|
||||
self.nameLabel.text = userModel.nick;
|
||||
self.indexLabel.text = @(userModel.rank).stringValue;
|
||||
self.indexLabel.text = @(index + 4).stringValue;
|
||||
self.countLabel.text = @(userModel.medalCount).stringValue;
|
||||
// self.detailLabel.hidden = userModel.uid == 0;
|
||||
}
|
||||
|
||||
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
|
||||
@@ -81,12 +82,12 @@
|
||||
make.top.mas_equalTo(self.avatarImageView);
|
||||
}];
|
||||
|
||||
UIImageView *rankIcon = [[UIImageView alloc] initWithImage:[kImage(@"medals_icon_rank") ms_SetImageForRTL]];
|
||||
UIImageView *rankIcon = [[UIImageView alloc] initWithImage:kImage(@"medals_rank")];
|
||||
[self.contentView addSubview:rankIcon];
|
||||
[rankIcon mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.leading.mas_equalTo(self.avatarImageView.mas_trailing).offset(6);
|
||||
make.bottom.mas_equalTo(self.avatarImageView);
|
||||
make.size.mas_equalTo(CGSizeMake(15, 15));
|
||||
make.size.mas_equalTo(CGSizeMake(10, 14));
|
||||
}];
|
||||
|
||||
self.countLabel = [UILabel labelInitWithText:@"" font:kFontMedium(14) textColor:[UIColor whiteColor]];
|
||||
@@ -96,11 +97,11 @@
|
||||
make.centerY.mas_equalTo(rankIcon);
|
||||
}];
|
||||
|
||||
self.detailLabel = [UILabel labelInitWithText:YMLocalizedString(@"20.20.61_text_13")
|
||||
UILabel *detailLabel = [UILabel labelInitWithText:YMLocalizedString(@"20.20.61_text_13")
|
||||
font:kFontRegular(12)
|
||||
textColor:[UIColor colorWithWhite:1 alpha:0.6]];
|
||||
[self.contentView addSubview:self.detailLabel];
|
||||
[self.detailLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
[self.contentView addSubview:detailLabel];
|
||||
[detailLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.trailing.mas_equalTo(self.contentView).offset(-28);
|
||||
make.centerY.mas_equalTo(self.contentView);
|
||||
}];
|
||||
@@ -128,7 +129,7 @@
|
||||
|
||||
@implementation MedalsRankTopView
|
||||
{
|
||||
NetImageView *avataImageView;
|
||||
NetImageView *avatarImageView;
|
||||
UIImageView *decorationImageView;
|
||||
UILabel *nameLabel;
|
||||
UILabel *honorLabel;
|
||||
@@ -144,10 +145,10 @@
|
||||
if (self) {
|
||||
NetImageConfig *config = [[NetImageConfig alloc] init];
|
||||
config.placeHolder = [UIImageConstant defaultAvatarPlaceholder];
|
||||
avataImageView = [[NetImageView alloc] initWithConfig:config];
|
||||
[avataImageView setCornerRadius:50];
|
||||
[self addSubview:avataImageView];
|
||||
[avataImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
avatarImageView = [[NetImageView alloc] initWithConfig:config];
|
||||
[avatarImageView setCornerRadius:50];
|
||||
[self addSubview:avatarImageView];
|
||||
[avatarImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.center.mas_equalTo(self);
|
||||
make.size.mas_equalTo(CGSizeMake(100, 100));
|
||||
}];
|
||||
@@ -158,34 +159,58 @@
|
||||
make.edges.mas_equalTo(self);
|
||||
}];
|
||||
|
||||
honorImageView = [[UIImageView alloc] initWithImage:kImage(@"medals_rank_namebar")];
|
||||
[self addSubview:honorImageView];
|
||||
[honorImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerX.mas_equalTo(self);
|
||||
make.bottom.mas_equalTo(self).offset(6);
|
||||
}];
|
||||
// honorImageView = [[UIImageView alloc] initWithImage:kImage(@"medals_rank_namebar")];
|
||||
// [self addSubview:honorImageView];
|
||||
// [honorImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
// make.centerX.mas_equalTo(self);
|
||||
// make.bottom.mas_equalTo(self).offset(6);
|
||||
// }];
|
||||
//
|
||||
// honorLabel = [UILabel labelInitWithText:YMLocalizedString(@"20.20.61_text_12")
|
||||
// font:kFontSemibold(12)
|
||||
// textColor:UIColorFromRGB(0xfff27b)];
|
||||
// [self addSubview:honorLabel];
|
||||
// [honorLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
// make.center.mas_equalTo(honorImageView);
|
||||
// }];
|
||||
|
||||
// 1. 先加 label,因為我們要讓 imageView 跟著 label 的大小走
|
||||
honorLabel = [UILabel labelInitWithText:YMLocalizedString(@"20.20.61_text_12")
|
||||
font:kFontSemibold(12)
|
||||
textColor:UIColorFromRGB(0xfff27b)];
|
||||
honorLabel.textAlignment = NSTextAlignmentCenter;
|
||||
[self addSubview:honorLabel];
|
||||
|
||||
// 2. 再加 imageView,但先不要給它固定圖片尺寸
|
||||
honorImageView = [[UIImageView alloc] initWithImage:kImage(@"medals_rank_namebar")];
|
||||
honorImageView.contentMode = UIViewContentModeScaleToFill; // 讓圖片自動拉伸
|
||||
[self insertSubview:honorImageView belowSubview:honorLabel]; // 圖片在 label 下面
|
||||
|
||||
// 3. 讓 imageView 的邊緣跟 label 保持固定間距(例如上下左右各 8pt)
|
||||
[honorLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.center.mas_equalTo(honorImageView);
|
||||
make.centerX.mas_equalTo(self);
|
||||
make.bottom.mas_equalTo(self).offset(6); // 與父 view 的相對位置
|
||||
}];
|
||||
|
||||
[honorImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.center.equalTo(honorLabel); // 中心對齊 label
|
||||
make.left.equalTo(honorLabel.mas_left).offset(-8);
|
||||
make.right.equalTo(honorLabel.mas_right).offset(8);
|
||||
make.top.equalTo(honorLabel.mas_top).offset(-4);
|
||||
make.bottom.equalTo(honorLabel.mas_bottom).offset(4);
|
||||
}];
|
||||
|
||||
|
||||
nameLabel = [UILabel labelInitWithText:@"" font:kFontSemibold(15) textColor:UIColorFromRGB(0xffffff)];
|
||||
[self addSubview:nameLabel];
|
||||
|
||||
medalIconImageView = [[UIImageView alloc] initWithImage:kImage(@"medals_icon_rank")];
|
||||
medalIconImageView = [[UIImageView alloc] initWithImage:kImage(@"medals_rank")];
|
||||
medalCountLabel = [UILabel labelInitWithText:@"0" font:kFontMedium(14) textColor:UIColorFromRGB(0xffffff)];
|
||||
medalCountStack = [[UIStackView alloc] initWithArrangedSubviews:@[
|
||||
medalIconImageView,
|
||||
medalCountLabel
|
||||
]];
|
||||
[self addSubview:medalCountStack];
|
||||
[medalIconImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.size.mas_equalTo(CGSizeMake(15, 15));
|
||||
}];
|
||||
|
||||
honorLabel.hidden = YES;
|
||||
honorImageView.hidden = YES;
|
||||
@@ -249,7 +274,7 @@
|
||||
- (void)setUserModel:(MedalsRankUserModel *)userModel {
|
||||
_userModel = userModel;
|
||||
if (userModel) {
|
||||
avataImageView.imageUrl = userModel.avatar;
|
||||
avatarImageView.imageUrl = userModel.avatar;
|
||||
nameLabel.text = userModel.nick;
|
||||
medalCountLabel.text = @(userModel.medalCount).stringValue;
|
||||
}
|
||||
@@ -273,6 +298,9 @@
|
||||
|
||||
@property (nonatomic, strong) UITableView *rankTableView;
|
||||
|
||||
// 分页相关属性
|
||||
@property (nonatomic, assign) NSInteger currentPage;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MedalsRankViewController
|
||||
@@ -288,7 +316,11 @@
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
// 初始化分页
|
||||
self.currentPage = 1;
|
||||
|
||||
[self setupUI];
|
||||
[self setupRefresh];
|
||||
[self loadData];
|
||||
}
|
||||
|
||||
@@ -411,46 +443,86 @@
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)setupRefresh {
|
||||
// 设置下拉刷新
|
||||
MJRefreshNormalHeader *header = [MJRefreshNormalHeader headerWithRefreshingTarget:self refreshingAction:@selector(headerRefresh)];
|
||||
header.stateLabel.font = [UIFont systemFontOfSize:10.0];
|
||||
header.lastUpdatedTimeLabel.font = [UIFont systemFontOfSize:10.0];
|
||||
header.stateLabel.textColor = [DJDKMIMOMColor secondTextColor];
|
||||
header.lastUpdatedTimeLabel.textColor = [DJDKMIMOMColor secondTextColor];
|
||||
self.rankTableView.mj_header = header;
|
||||
|
||||
// // 设置上拉加载更多
|
||||
// MJRefreshBackNormalFooter *footer = [MJRefreshBackNormalFooter footerWithRefreshingTarget:self refreshingAction:@selector(footerRefresh)];
|
||||
// footer.stateLabel.textColor = [DJDKMIMOMColor secondTextColor];
|
||||
// footer.stateLabel.font = [UIFont systemFontOfSize:10.0];
|
||||
// self.rankTableView.mj_footer = footer;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
- (void)loadData {
|
||||
[self.presenter rankList:1];
|
||||
[self.presenter rankList:self.currentPage];
|
||||
}
|
||||
|
||||
- (void)rankListSuccess:(MedalsRankModel *)model {
|
||||
// 结束刷新状态
|
||||
[self.rankTableView.mj_header endRefreshing];
|
||||
[self.rankTableView.mj_footer endRefreshing];
|
||||
|
||||
NSInteger currentRank = 4; // 从第4名开始计算(前三名已经处理)
|
||||
|
||||
if (model) {
|
||||
self.mineRankModel = model.mine;
|
||||
self.avatarImageView.imageUrl = self.mineRankModel.avatar;
|
||||
self.nameLabel.text = self.mineRankModel.nick;
|
||||
self.indexLabel.text = @(self.mineRankModel.rank).stringValue;
|
||||
self.countLabel.text = @(self.mineRankModel.medalCount).stringValue;
|
||||
|
||||
self.rankList = [NSMutableArray array];
|
||||
NSInteger currentRank = 4; // 从第4名开始计算(前三名已经处理)
|
||||
|
||||
for (MedalsRankUserModel *user in model.rankList) {
|
||||
if (user.rank == 1) {
|
||||
self.topOne.userModel = user;
|
||||
} else if (user.rank == 2) {
|
||||
self.topTwo.userModel = user;
|
||||
} else if (user.rank == 3) {
|
||||
self.topThree.userModel = user;
|
||||
} else {
|
||||
[self.rankList addObject:user];
|
||||
currentRank = MAX(currentRank, user.rank + 1);
|
||||
// 第一页时更新个人信息和前三名
|
||||
if (self.currentPage == 1) {
|
||||
self.mineRankModel = model.mine;
|
||||
self.avatarImageView.imageUrl = self.mineRankModel.avatar;
|
||||
self.nameLabel.text = self.mineRankModel.nick;
|
||||
self.indexLabel.text = self.mineRankModel.rank == 0 ? @"10+" : @(self.mineRankModel.rank).stringValue;
|
||||
self.countLabel.text = @(self.mineRankModel.medalCount).stringValue;
|
||||
|
||||
self.rankList = [NSMutableArray array];
|
||||
|
||||
// 处理前三名显示
|
||||
for (MedalsRankUserModel *user in model.rankList) {
|
||||
if (user.rank == 1) {
|
||||
self.topOne.userModel = user;
|
||||
} else if (user.rank == 2) {
|
||||
self.topTwo.userModel = user;
|
||||
} else if (user.rank == 3) {
|
||||
self.topThree.userModel = user;
|
||||
} else {
|
||||
[self.rankList addObject:user];
|
||||
currentRank = MAX(currentRank, user.rank + 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 非第一页,追加数据(排除前三名)
|
||||
for (MedalsRankUserModel *user in model.rankList) {
|
||||
if (user.rank > 3) {
|
||||
[self.rankList addObject:user];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 补充数据至 10 个(rankList 中应有 7 个,因为前三名在 top 视图中)
|
||||
NSInteger targetCount = 7; // 总共10个,减去前3名
|
||||
while (self.rankList.count < targetCount) {
|
||||
MedalsRankUserModel *emptyUser = [[MedalsRankUserModel alloc] init];
|
||||
emptyUser.rank = currentRank;
|
||||
emptyUser.uid = 0;
|
||||
emptyUser.avatar = @"";
|
||||
emptyUser.nick = @"--";
|
||||
emptyUser.medalCount = 0;
|
||||
[self.rankList addObject:emptyUser];
|
||||
currentRank++;
|
||||
// 检查是否还有更多数据
|
||||
if (model.rankList.count < [self.presenter rankListSize]) {
|
||||
if (self.currentPage == 1) {
|
||||
// 补充数据至 10 个(rankList 中应有 7 个,因为前三名在 top 视图中)
|
||||
NSInteger targetCount = 7; // 总共10个,减去前3名
|
||||
while (self.rankList.count < targetCount) {
|
||||
MedalsRankUserModel *emptyUser = [[MedalsRankUserModel alloc] init];
|
||||
emptyUser.rank = currentRank;
|
||||
emptyUser.uid = 0;
|
||||
emptyUser.avatar = @"";
|
||||
emptyUser.nick = @"--";
|
||||
emptyUser.medalCount = 0;
|
||||
[self.rankList addObject:emptyUser];
|
||||
currentRank++;
|
||||
}
|
||||
}
|
||||
[self.rankTableView.mj_footer endRefreshingWithNoMoreData];
|
||||
} else {
|
||||
[self.rankTableView.mj_footer resetNoMoreData];
|
||||
}
|
||||
|
||||
[self.rankTableView reloadData];
|
||||
@@ -458,7 +530,14 @@
|
||||
}
|
||||
|
||||
- (void)rankListFailure {
|
||||
// 结束刷新状态
|
||||
[self.rankTableView.mj_header endRefreshing];
|
||||
[self.rankTableView.mj_footer endRefreshing];
|
||||
|
||||
// 如果是加载更多失败,页码需要回退
|
||||
if (self.currentPage > 1) {
|
||||
self.currentPage--;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - UITableView DataSource & Delegate
|
||||
@@ -482,15 +561,11 @@
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||
|
||||
MedalsRankUserModel *model = [self.rankList xpSafeObjectAtIndex:indexPath.row];
|
||||
|
||||
// 检查是否为有效的用户数据(非空补充数据)
|
||||
if (model && model.uid != 0) {
|
||||
[self handleTopViewTap:model];
|
||||
}
|
||||
[self handleTopViewTap:model];
|
||||
}
|
||||
|
||||
- (void)handleTopViewTap:(MedalsRankUserModel *)model {
|
||||
if (model && model.uid != 0) {
|
||||
if (model) {
|
||||
UserInfoModel *userInfo = [[UserInfoModel alloc] init];
|
||||
userInfo.uid = model.uid;
|
||||
userInfo.avatar = model.avatar;
|
||||
@@ -518,4 +593,15 @@
|
||||
return _rankTableView;
|
||||
}
|
||||
|
||||
#pragma mark - 刷新方法
|
||||
- (void)headerRefresh {
|
||||
self.currentPage = 1;
|
||||
[self loadData];
|
||||
}
|
||||
|
||||
- (void)footerRefresh {
|
||||
self.currentPage++;
|
||||
[self loadData];
|
||||
}
|
||||
|
||||
@end
|
||||
|
@@ -37,7 +37,7 @@ typedef enum : NSInteger {
|
||||
@property (nonatomic, strong) UIButton *emptyUserMedalButton;
|
||||
@property (nonatomic, strong) TYCyclePagerView *medalsCyclePagerView;
|
||||
@property (nonatomic, strong) UIView *emptyView;
|
||||
@property (nonatomic, copy) UICollectionView *medalsCollectionView;
|
||||
@property (nonatomic, strong) UICollectionView *medalsCollectionView;
|
||||
@property (nonatomic, strong) UIStackView *centerTabsStackView;
|
||||
|
||||
@property (nonatomic, strong) NSMutableArray <MedalSeriesItemVo *>*datasourceTaskMedals;
|
||||
@@ -53,9 +53,9 @@ typedef enum : NSInteger {
|
||||
@property (nonatomic, assign) MedalsCenterDisplayType displayType;
|
||||
|
||||
@property (nonatomic, strong) UserMedalsModel *userMedalsModel;
|
||||
@property (nonatomic, copy) NSMutableArray <MedalSeriesVo *>*taskSquareMedalVo;
|
||||
@property (nonatomic, copy) NSMutableArray <MedalSeriesVo *>*activitySquareMedalVo;
|
||||
@property (nonatomic, copy) NSMutableArray <MedalSeriesVo *>*glorySquareMedalVo;
|
||||
@property (nonatomic, strong) NSMutableArray <MedalSeriesVo *>*taskSquareMedalVo;
|
||||
@property (nonatomic, strong) NSMutableArray <MedalSeriesVo *>*activitySquareMedalVo;
|
||||
@property (nonatomic, strong) NSMutableArray <MedalSeriesVo *>*glorySquareMedalVo;
|
||||
|
||||
@property (nonatomic, strong) UIImageView *otherBG;
|
||||
@property (nonatomic, strong) NetImageView *otherAvatar;
|
||||
@@ -294,7 +294,8 @@ typedef enum : NSInteger {
|
||||
|
||||
[bottomBg mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.bottom.leading.trailing.mas_equalTo(self.view);
|
||||
make.height.mas_equalTo(kGetScaleWidth(445));
|
||||
// make.height.mas_equalTo(kGetScaleWidth(445));
|
||||
make.top.mas_equalTo(topBg.mas_bottom).offset(44);
|
||||
}];
|
||||
}
|
||||
}
|
||||
@@ -413,7 +414,10 @@ typedef enum : NSInteger {
|
||||
}];
|
||||
|
||||
[self.view addSubview:self.medalDescLabel];
|
||||
self.medalDescLabel.text = YMLocalizedString(@"20.20.61_text_6");
|
||||
if (self.displayType != MedalsCenterDisplayType_Square) {
|
||||
self.medalDescLabel.text = YMLocalizedString(@"20.20.61_text_6");
|
||||
}
|
||||
|
||||
[self.medalDescLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.mas_equalTo(kGetScaleWidth(290));
|
||||
make.leading.trailing.mas_equalTo(self.view).inset(20);
|
||||
@@ -803,21 +807,25 @@ typedef enum : NSInteger {
|
||||
|
||||
- (void)_updateDataSource:(NSArray <MedalSeriesVo *>*)models {
|
||||
|
||||
if (models.count < [self.presenter pageSize]) {
|
||||
NSArray *targetArr = models;
|
||||
NSMutableArray *itemDataSources = [NSMutableArray array];
|
||||
|
||||
MedalSeriesVo *series = [models xpSafeObjectAtIndex:0];
|
||||
if (series) {
|
||||
targetArr = series.medalSeries;
|
||||
}
|
||||
itemDataSources = targetArr.mutableCopy;
|
||||
|
||||
if (targetArr.count < [self.presenter pageSize]) {
|
||||
[self.medalsCollectionView.mj_footer endRefreshingWithNoMoreData];
|
||||
} else {
|
||||
[self.medalsCollectionView.mj_footer resetNoMoreData];
|
||||
}
|
||||
|
||||
NSMutableArray *itemDataSources = [NSMutableArray array];
|
||||
for (MedalSeriesVo *vo in models) {
|
||||
[itemDataSources addObjectsFromArray:vo.medalSeries];
|
||||
}
|
||||
|
||||
switch (self.currentTabType) {
|
||||
case MedalsCenterTab_TaskMedals:
|
||||
if (self.currentPageTaskMedals == 1) {
|
||||
self.emptyView.hidden = (models.count != 0);
|
||||
self.emptyView.hidden = (targetArr.count != 0);
|
||||
self.datasourceTaskMedals = itemDataSources;
|
||||
} else {
|
||||
[self.datasourceTaskMedals addObjectsFromArray:itemDataSources];
|
||||
@@ -825,7 +833,7 @@ typedef enum : NSInteger {
|
||||
break;
|
||||
case MedalsCenterTab_ActivityMedals:
|
||||
if (self.currentPageActivityMedals == 1) {
|
||||
self.emptyView.hidden = (models.count != 0);
|
||||
self.emptyView.hidden = (targetArr.count != 0);
|
||||
self.datasourceActivityMedals = itemDataSources;
|
||||
} else {
|
||||
[self.datasourceActivityMedals addObjectsFromArray:itemDataSources];
|
||||
@@ -833,7 +841,7 @@ typedef enum : NSInteger {
|
||||
break;
|
||||
case MedalsCenterTab_GloryMedals:
|
||||
if (self.currentPageGloryMedals == 1) {
|
||||
self.emptyView.hidden = (models.count != 0);
|
||||
self.emptyView.hidden = (targetArr.count != 0);
|
||||
self.datasourceGloryMedals = itemDataSources;
|
||||
} else {
|
||||
[self.datasourceGloryMedals addObjectsFromArray:itemDataSources];
|
||||
@@ -934,7 +942,9 @@ typedef enum : NSInteger {
|
||||
|
||||
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
MedalsCollectionViewCell *cell = [MedalsCollectionViewCell cellFor:collectionView atIndexPath:indexPath];
|
||||
[cell updateCell:[self loadModel:indexPath.item] isForSquare:self.displayType == MedalsCenterDisplayType_Square];
|
||||
[cell updateCell:[self loadModel:indexPath.item]
|
||||
isForSquare:self.displayType == MedalsCenterDisplayType_Square
|
||||
isForMine:self.displayType == MedalsCenterDisplayType_Mine];
|
||||
return cell;
|
||||
}
|
||||
|
||||
@@ -960,7 +970,8 @@ typedef enum : NSInteger {
|
||||
return;
|
||||
}
|
||||
MedalsDetailView *view = [[MedalsDetailView alloc] initWithFrame:self.view.bounds];
|
||||
view.detailItemVo = [self loadModel:indexPath.item];
|
||||
[view updateSeriesItem:[self loadModel:indexPath.item]
|
||||
isMine:self.displayType == MedalsCenterDisplayType_Mine || self.displayType == MedalsCenterDisplayType_Other];
|
||||
[self.view addSubview:view];
|
||||
}
|
||||
|
||||
@@ -1110,6 +1121,8 @@ typedef enum : NSInteger {
|
||||
[button setTitleColor:UIColorFromRGB(0xd8a2ff) forState:UIControlStateNormal];
|
||||
[button setTitleColor:UIColorFromRGB(0xFFFFFF) forState:UIControlStateSelected];
|
||||
[button.titleLabel setFont:kFontMedium(13)];
|
||||
[button.titleLabel setAdjustsFontSizeToFitWidth:YES];
|
||||
button.contentEdgeInsets = UIEdgeInsetsMake(0, 20, 0, 20);
|
||||
[button setAdjustsImageWhenDisabled:NO];
|
||||
return button;
|
||||
}
|
||||
@@ -1127,6 +1140,7 @@ typedef enum : NSInteger {
|
||||
|
||||
UIStackView *stack = [[UIStackView alloc] initWithArrangedSubviews:self.centerTabButtons];
|
||||
stack.distribution = UIStackViewDistributionFillEqually;
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
|
@@ -100,24 +100,6 @@
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// Debug 环境:如果数据不满足新逻辑条件,使用现有逻辑
|
||||
if ([NSString isEmpty:medalVo.mp4Url] && [NSString isEmpty:medalVo.picUrl]) {
|
||||
// 都为空,使用旧逻辑
|
||||
[self handleLegacyDisplay:medalVo];
|
||||
return;
|
||||
}
|
||||
|
||||
if (![NSString isEmpty:medalVo.picUrl] && [NSString isEmpty:medalVo.mp4Url]) {
|
||||
// 只有 picUrl 有值,mp4Url 为空,检查是否符合新逻辑
|
||||
if (![NSString isImageFormat:medalVo.picUrl] && ![medalVo.picUrl.lowercaseString hasSuffix:@".mp4"]) {
|
||||
// picUrl 既不是图片也不是 mp4,使用旧逻辑
|
||||
[self handleLegacyDisplay:medalVo];
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// 1. 优先判断 mp4Url 是否有内容
|
||||
if (![NSString isEmpty:medalVo.mp4Url]) {
|
||||
// 该 Cell 不支持 mp4,降级使用 picUrl
|
||||
@@ -136,8 +118,7 @@
|
||||
if ([NSString isImageFormat:medalVo.picUrl]) {
|
||||
self.medalImageView.imageUrl = medalVo.picUrl;
|
||||
} else {
|
||||
// 不是图片格式,显示默认占位图
|
||||
self.medalImageView.image = [UIImageConstant defaultEmptyPlaceholder];
|
||||
[self handleLegacyDisplay:medalVo];
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -150,6 +131,8 @@
|
||||
- (void)handleLegacyDisplay:(MedalVo *)medalVo {
|
||||
if (![medalVo.picUrl hasSuffix:@"mp4"]) {
|
||||
self.medalImageView.imageUrl = medalVo.picUrl;
|
||||
} else {
|
||||
self.medalImageView.image = [UIImageConstant defaultEmptyPlaceholder];
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -61,40 +61,20 @@
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// Debug 环境:如果数据不满足新逻辑条件,使用现有逻辑
|
||||
if ([NSString isEmpty:medalModel.mp4Url] && [NSString isEmpty:medalModel.picUrl]) {
|
||||
// 都为空,使用旧逻辑
|
||||
[self handleLegacyDisplay:medalModel];
|
||||
return;
|
||||
}
|
||||
|
||||
if (![NSString isEmpty:medalModel.picUrl] && [NSString isEmpty:medalModel.mp4Url]) {
|
||||
// 只有 picUrl 有值,mp4Url 为空,检查是否符合新逻辑
|
||||
if (![NSString isImageFormat:medalModel.picUrl] && ![medalModel.picUrl.lowercaseString hasSuffix:@".mp4"]) {
|
||||
// picUrl 既不是图片也不是 mp4,使用旧逻辑
|
||||
[self handleLegacyDisplay:medalModel];
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// 1. 优先判断 mp4Url 是否有内容
|
||||
if (![NSString isEmpty:medalModel.mp4Url]) {
|
||||
[self setMp4Path:medalModel.mp4Url];
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. mp4Url 为空,使用 picUrl
|
||||
// 使用 picUrl
|
||||
if (![NSString isEmpty:medalModel.picUrl]) {
|
||||
// 3. 使用 picUrl 时,判断内容是否为图片
|
||||
if ([NSString isImageFormat:medalModel.picUrl]) {
|
||||
[self setImagePath:medalModel.picUrl];
|
||||
} else {
|
||||
// 不是图片格式,显示默认占位图
|
||||
[self setImagePath:@""];
|
||||
// 降级
|
||||
[self handleLegacyDisplay:medalModel];
|
||||
}
|
||||
return;
|
||||
} else if (![NSString isEmpty:medalModel.mp4Url]) {
|
||||
// 判断 mp4Url 是否有内容
|
||||
[self setMp4Path:medalModel.mp4Url];
|
||||
return;
|
||||
}
|
||||
|
||||
// 4. 都为空,显示默认占位图
|
||||
@@ -185,6 +165,10 @@
|
||||
}
|
||||
|
||||
- (void)setMp4Path:(NSString *)mp4Path {
|
||||
if ([NSString isEmpty:mp4Path]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果是相同的 mp4 路径,不需要重新加载
|
||||
// if ([_mp4Path isEqualToString:mp4Path]) {
|
||||
// return;
|
||||
|
@@ -196,12 +196,10 @@
|
||||
|
||||
if (currentMinVipLevel != NSIntegerMax) {
|
||||
// 更新全局最低VIP level
|
||||
if (self.minVipLevelForSeats == 0 || currentMinVipLevel < self.minVipLevelForSeats) {
|
||||
self.minVipLevelForSeats = currentMinVipLevel;
|
||||
}
|
||||
self.minVipLevelForSeats = currentMinVipLevel;
|
||||
[cell updateVIPLevel:currentMinVipLevel];
|
||||
}
|
||||
} else if (self.minVipLevelForSeats > 0) {
|
||||
} else if (self.minVipLevelForSeats >= 0) {
|
||||
// 当前座位没有对应的vip seat vo,但之前已经有最低VIP level,则沿用
|
||||
[cell updateVIPLevel:self.minVipLevelForSeats];
|
||||
}
|
||||
|
@@ -76,6 +76,7 @@
|
||||
_coinLabel.textAlignment = NSTextAlignmentCenter;
|
||||
_coinLabel.font = kFontSemibold(14);
|
||||
_coinLabel.textColor = UIColorFromRGB(0x4F3500);
|
||||
_coinLabel.adjustsFontSizeToFitWidth = YES;
|
||||
}
|
||||
return _coinLabel;
|
||||
}
|
||||
|
@@ -31,7 +31,9 @@
|
||||
@property (nonatomic, copy) void(^contactCustomerService)(NSString *uid);
|
||||
|
||||
// 记录交易重试次数
|
||||
@property (nonatomic, strong) NSMutableDictionary *retryCountMap;
|
||||
@property (nonatomic, strong) NSMutableDictionary *retryCountDict;
|
||||
// 线程安全队列
|
||||
@property (nonatomic, strong) dispatch_queue_t retryCountQueue;
|
||||
|
||||
@end
|
||||
|
||||
@@ -46,7 +48,10 @@
|
||||
|
||||
proxy.recheckIndex = 0;
|
||||
proxy.recheckInterval = 1.0;
|
||||
proxy.retryCountMap = [NSMutableDictionary dictionary];
|
||||
proxy.retryCountDict = [NSMutableDictionary dictionary];
|
||||
proxy.retryCountQueue = dispatch_queue_create("com.iapmanager.retrycount.queue", DISPATCH_QUEUE_CONCURRENT);
|
||||
proxy.isProcessing = NO;
|
||||
proxy.isLogin = NO;
|
||||
});
|
||||
|
||||
return proxy;
|
||||
@@ -96,6 +101,9 @@
|
||||
self.recheckTimer = nil;
|
||||
}
|
||||
|
||||
// 清理过期交易
|
||||
[self cleanupStaleTransactions];
|
||||
|
||||
// 设置最大重试间隔
|
||||
NSTimeInterval interval = MIN(self.recheckInterval, 300.0);
|
||||
|
||||
@@ -105,112 +113,178 @@
|
||||
selector:@selector(handleRetryCheckReceipt)
|
||||
userInfo:nil
|
||||
repeats:NO];
|
||||
|
||||
// 确保定时器在主运行循环中运行
|
||||
[[NSRunLoop mainRunLoop] addTimer:self.recheckTimer forMode:NSRunLoopCommonModes];
|
||||
}
|
||||
|
||||
// 验单逻辑
|
||||
- (void)handleRetryCheckReceipt {
|
||||
// NSLog(@"[YuMi IAP] 用户触发补单检查 - Retry checking receipts");
|
||||
NSLog(@"[YuMi IAP] 用户触发补单检查 - Retry checking receipts");
|
||||
|
||||
// 如果已经在处理中或未登录,则不执行,直接等待下次定时器触发
|
||||
if (self.isProcessing || !self.isLogin) {
|
||||
// 只销毁当前定时器,不递归创建新定时器,避免无限循环
|
||||
if (self.recheckTimer) {
|
||||
[self.recheckTimer invalidate];
|
||||
self.recheckTimer = nil;
|
||||
}
|
||||
// 重新安排下一次检查(延迟更长时间,防止频繁空转)
|
||||
self.recheckInterval = MIN(self.recheckInterval * 1.5, 300.0);
|
||||
[self retryCheckAllReceipt];
|
||||
return;
|
||||
}
|
||||
|
||||
NSArray *array = [RechargeStorage getAllReceiptsWithUid:[AccountInfoStorage instance].getUid];
|
||||
// NSLog(@" ------------.------------ 尝试:%@", array);
|
||||
@synchronized (array) {
|
||||
if (array.count == 0 || self.isProcessing) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!self.isLogin) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.recheckIndex >= array.count) {
|
||||
self.recheckIndex = 0;
|
||||
}
|
||||
#if DEBUG
|
||||
// [self requestAPPOrderData:@"com.hflighting.yumi.gold.1_7000" isFroRecheck:YES];
|
||||
#endif
|
||||
self.isProcessing = YES;
|
||||
NSDictionary *dic = [array xpSafeObjectAtIndex:self.recheckIndex];
|
||||
NSString *transactionId = dic[@"transactionId"];
|
||||
|
||||
[self _logToBugly:transactionId oID:dic[@"orderId"] status:0];
|
||||
|
||||
NSInteger retryCount = [self getRetryCountForTransaction:transactionId];
|
||||
|
||||
if (retryCount > MAX_RETRY_COUNT) {
|
||||
// 超过最大重试次数,记录并清理
|
||||
[self _logToBugly:transactionId oID:dic[@"orderId"] status:4]; // 新状态:重试次数过多
|
||||
[RechargeStorage delegateTransactionId:transactionId uid:[AccountInfoStorage instance].getUid];
|
||||
self.isProcessing = NO;
|
||||
return;
|
||||
}
|
||||
|
||||
// 增加重试计数
|
||||
[self incrementRetryCountForTransaction:transactionId];
|
||||
|
||||
@kWeakify(self);
|
||||
[self backgroundCheckReceiptWithTransactionID:transactionId
|
||||
orderID:dic[@"orderId"]
|
||||
next:^(BOOL isSuccess){
|
||||
@kStrongify(self);
|
||||
if (isSuccess) {
|
||||
[RechargeStorage delegateTransactionId:transactionId
|
||||
uid:[AccountInfoStorage instance].getUid];
|
||||
self.recheckInterval = MIN(self.recheckInterval * 2, 300.0);
|
||||
|
||||
[self _logToBugly:transactionId oID:dic[@"orderId"] status:1];
|
||||
|
||||
// 成功后移除重试记录
|
||||
[self removeRetryCountForTransaction:transactionId];
|
||||
|
||||
} else {
|
||||
self.recheckInterval = self.recheckInterval * 2;
|
||||
[self _logToBugly:transactionId oID:dic[@"orderId"] status:2];
|
||||
}
|
||||
|
||||
self.recheckIndex += 1;
|
||||
|
||||
self.isProcessing = NO;
|
||||
|
||||
NSLog(@" ------------.------------ 尝试:%@", array);
|
||||
|
||||
// 如果没有需要处理的收据,定时器继续以较长间隔轮询
|
||||
if (array.count == 0) {
|
||||
NSLog(@" ------------.------------ 没有需要验单的数据");
|
||||
if (self.recheckTimer) {
|
||||
[self.recheckTimer invalidate];
|
||||
[self retryCheckAllReceipt];
|
||||
}];
|
||||
self.recheckTimer = nil;
|
||||
}
|
||||
// 设为较长间隔(如10分钟)
|
||||
self.recheckInterval = 600.0;
|
||||
[self retryCheckAllReceipt];
|
||||
return;
|
||||
}
|
||||
|
||||
// 确保索引在有效范围内
|
||||
if (self.recheckIndex >= array.count) {
|
||||
self.recheckIndex = 0;
|
||||
}
|
||||
|
||||
// 标记为处理中
|
||||
self.isProcessing = YES;
|
||||
|
||||
// 安全地获取当前需要处理的收据
|
||||
NSDictionary *dic = [array xpSafeObjectAtIndex:self.recheckIndex];
|
||||
NSString *transactionId = dic[@"transactionId"];
|
||||
NSString *orderId = dic[@"orderId"];
|
||||
|
||||
// 记录尝试验单
|
||||
[self _logToBugly:transactionId oID:orderId status:0];
|
||||
|
||||
// 检查重试次数
|
||||
NSInteger retryCount = [self getRetryCountForTransaction:transactionId];
|
||||
|
||||
if (retryCount > MAX_RETRY_COUNT) {
|
||||
// 超过最大重试次数,记录并清理
|
||||
[self _logToBugly:transactionId oID:orderId status:4]; // 新状态:重试次数过多
|
||||
[RechargeStorage delegateTransactionId:transactionId uid:[AccountInfoStorage instance].getUid];
|
||||
[self removeRetryCountForTransaction:transactionId];
|
||||
|
||||
// 重置处理状态
|
||||
self.isProcessing = NO;
|
||||
|
||||
// 增加索引并安排下一次检查
|
||||
self.recheckIndex = (self.recheckIndex + 1) % array.count;
|
||||
if (self.recheckTimer) {
|
||||
[self.recheckTimer invalidate];
|
||||
self.recheckTimer = nil;
|
||||
}
|
||||
[self retryCheckAllReceipt];
|
||||
return;
|
||||
}
|
||||
|
||||
// 增加重试计数
|
||||
[self incrementRetryCountForTransaction:transactionId];
|
||||
|
||||
@kWeakify(self);
|
||||
[self backgroundCheckReceiptWithTransactionID:transactionId
|
||||
orderID:orderId
|
||||
next:^(BOOL isSuccess){
|
||||
@kStrongify(self);
|
||||
if (isSuccess) {
|
||||
// 成功处理
|
||||
[RechargeStorage delegateTransactionId:transactionId
|
||||
uid:[AccountInfoStorage instance].getUid];
|
||||
|
||||
// 成功后减少重试间隔,加快处理速度
|
||||
self.recheckInterval = MAX(self.recheckInterval / 2, 1.0);
|
||||
|
||||
[self _logToBugly:transactionId oID:orderId status:1];
|
||||
|
||||
// 成功后移除重试记录
|
||||
[self removeRetryCountForTransaction:transactionId];
|
||||
|
||||
} else {
|
||||
// 失败后增加重试间隔,避免频繁请求
|
||||
self.recheckInterval = MIN(self.recheckInterval * 1.5, 300.0);
|
||||
[self _logToBugly:transactionId oID:orderId status:2];
|
||||
}
|
||||
|
||||
// 增加索引,准备处理下一个收据
|
||||
self.recheckIndex = (self.recheckIndex + 1) % array.count;
|
||||
|
||||
// 重置处理状态
|
||||
self.isProcessing = NO;
|
||||
|
||||
// 安排下一次检查
|
||||
if (self.recheckTimer) {
|
||||
[self.recheckTimer invalidate];
|
||||
self.recheckTimer = nil;
|
||||
}
|
||||
[self retryCheckAllReceipt];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)_logToBugly:(NSString *)tid oID:(NSString *)oid status:(NSInteger)status {
|
||||
|
||||
NSMutableDictionary *logDic = [NSMutableDictionary dictionary];
|
||||
[logDic setObject:tid forKey:@"内购 transactionId"];
|
||||
[logDic setObject:oid forKey:@"内购 orderId"];
|
||||
[logDic setObject:[AccountInfoStorage instance].getUid forKey:@"内购 用户id"];
|
||||
// 安全处理交易ID
|
||||
if ([NSString isEmpty:tid]) {
|
||||
[logDic setObject:@"" forKey:@"内购 transactionId"];
|
||||
tid = @"";
|
||||
} else {
|
||||
[logDic setObject:tid forKey:@"内购 transactionId"];
|
||||
}
|
||||
// 安全处理订单ID
|
||||
if ([NSString isEmpty:oid]) {
|
||||
[logDic setObject:@"" forKey:@"内购 orderId"];
|
||||
} else {
|
||||
[logDic setObject:oid forKey:@"内购 orderId"];
|
||||
}
|
||||
|
||||
// 安全获取用户ID
|
||||
NSString *uid = [AccountInfoStorage instance].getUid ?: @"未知用户";
|
||||
[logDic setObject:uid forKey:@"内购 用户id"];
|
||||
|
||||
// 添加重试次数信息
|
||||
[logDic setObject:@([self getRetryCountForTransaction:tid]) forKey:@"重试次数"];
|
||||
[logDic setObject:@(self.recheckInterval) forKey:@"重试间隔"];
|
||||
[logDic setObject:@(self.recheckIndex) forKey:@"当前索引"];
|
||||
[logDic setObject:@(self.isProcessing) forKey:@"处理中状态"];
|
||||
[logDic setObject:@(self.isLogin) forKey:@"登录状态"];
|
||||
|
||||
NSString *statusMsg = @"";
|
||||
NSInteger code = -20000;
|
||||
switch (status) {
|
||||
case 0:
|
||||
statusMsg = [NSString stringWithFormat:@"UID: %@, 尝试验单",
|
||||
[AccountInfoStorage instance].getUid];
|
||||
statusMsg = [NSString stringWithFormat:@"UID: %@, 尝试验单", uid];
|
||||
break;
|
||||
case 1:
|
||||
statusMsg = [NSString stringWithFormat:@"UID: %@, 验单-补单成功",
|
||||
[AccountInfoStorage instance].getUid];
|
||||
statusMsg = [NSString stringWithFormat:@"UID: %@, 验单-补单成功", uid];
|
||||
code = -20001;
|
||||
break;
|
||||
case 2:
|
||||
statusMsg = [NSString stringWithFormat:@"UID: %@, 验单-补单失败",
|
||||
[AccountInfoStorage instance].getUid];
|
||||
statusMsg = [NSString stringWithFormat:@"UID: %@, 验单-补单失败", uid];
|
||||
code = -20002;
|
||||
break;
|
||||
case 3:
|
||||
statusMsg = [NSString stringWithFormat:@"UID: %@, 验单-补单 id 异常",
|
||||
[AccountInfoStorage instance].getUid];
|
||||
statusMsg = [NSString stringWithFormat:@"UID: %@, 验单-补单 id 异常", uid];
|
||||
code = -20002;
|
||||
break;
|
||||
case 4:
|
||||
statusMsg = [NSString stringWithFormat:@"UID: %@, 重试次数过多",
|
||||
[AccountInfoStorage instance].getUid];
|
||||
statusMsg = [NSString stringWithFormat:@"UID: %@, 重试次数过多", uid];
|
||||
code = -20003;
|
||||
break;
|
||||
case 5:
|
||||
statusMsg = [NSString stringWithFormat:@"UID: %@, 过期交易清理", uid];
|
||||
code = -20004;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -299,29 +373,29 @@
|
||||
@kStrongify(self);
|
||||
switch (state) {
|
||||
case StoreConditionResultStart:
|
||||
// NSLog(@"~~~```~~~ Purchase started");
|
||||
NSLog(@"~~~```~~~ Purchase started");
|
||||
break;
|
||||
case StoreConditionResultPay:
|
||||
// NSLog(@"~~~```~~~ Processing payment");
|
||||
NSLog(@"~~~```~~~ Processing payment");
|
||||
break;
|
||||
case StoreConditionResultVerifiedServer:
|
||||
// NSLog(@"~~~```~~~ Verified by server");
|
||||
NSLog(@"~~~```~~~ Verified by server");
|
||||
[self handleIAPSuccess:param];
|
||||
break;
|
||||
case StoreConditionResultUserCancelled:
|
||||
// NSLog(@"~~~```~~~ User cancelled purchase");
|
||||
NSLog(@"~~~```~~~ User cancelled purchase");
|
||||
[self handleFailurePurchase:@""];
|
||||
break;
|
||||
case StoreConditionResultNoProduct:
|
||||
// NSLog(@"~~~```~~~ No product found");
|
||||
NSLog(@"~~~```~~~ No product found");
|
||||
[self handleFailurePurchase:[NSString stringWithFormat:@"%@ No product found", YMLocalizedString(@"XPIAPRechargeViewController1")]];
|
||||
break;
|
||||
case StoreConditionResultFailedVerification:
|
||||
// NSLog(@"~~~```~~~ Verification failed");
|
||||
NSLog(@"~~~```~~~ Verification failed");
|
||||
[self handleFailurePurchase:YMLocalizedString(@"XPIAPRechargeViewController1")];
|
||||
break;
|
||||
case StoreConditionResultUnowned:
|
||||
// NSLog(@"~~~```~~~ Result Unowned");
|
||||
NSLog(@"~~~```~~~ Result Unowned");
|
||||
[self handleFailurePurchase:YMLocalizedString(@"XPIAPRechargeViewController1")];
|
||||
break;
|
||||
default:
|
||||
@@ -421,7 +495,7 @@
|
||||
- (void)checkReceiptWithTransactionID:(NSString *)tID
|
||||
orderID:(NSString *)orderID {
|
||||
|
||||
// NSLog(@" ------------.------------ 后端验单:%@ | %@", tID, orderID);
|
||||
NSLog(@" ------------.------------ 后端验单:%@ | %@", tID, orderID);
|
||||
|
||||
@kWeakify(self);
|
||||
[Api checkReceipt:^(BaseModel * _Nullable data, NSInteger code, NSString * _Nullable msg) {
|
||||
@@ -435,7 +509,7 @@
|
||||
// 参数异常,暂不处理
|
||||
}
|
||||
}
|
||||
// NSLog(@" ------------.------------ 后端验单结果:%@ ",msg);
|
||||
NSLog(@" ------------.------------ 后端验单结果:%@ ",msg);
|
||||
}
|
||||
chooseEnv:@"true"
|
||||
chargeRecordId:orderID
|
||||
@@ -449,6 +523,14 @@
|
||||
orderID:(NSString *)orderID
|
||||
next:(void(^)(BOOL isSuccess))next {
|
||||
|
||||
// 验证参数有效性
|
||||
if (![self isValidTransactionID:tID orderID:orderID]) {
|
||||
if (next) {
|
||||
next(NO);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建后台任务标识
|
||||
UIBackgroundTaskIdentifier backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithName:@"VerifyReceipt"
|
||||
expirationHandler:^{
|
||||
@@ -459,13 +541,24 @@
|
||||
[[UIApplication sharedApplication] endBackgroundTask:backgroundTask];
|
||||
}];
|
||||
|
||||
// 原验证代码...
|
||||
|
||||
// 完成后务必结束后台任务
|
||||
@kWeakify(self);
|
||||
[Api checkReceipt:^(BaseModel * _Nullable data, NSInteger code, NSString * _Nullable msg) {
|
||||
@kStrongify(self);
|
||||
// 原有验证代码...
|
||||
|
||||
BOOL isSuccess = (code == 200);
|
||||
|
||||
if (isSuccess) {
|
||||
[self handleCheckReceiptSuccess:tID isFromRecheck:YES];
|
||||
NSLog(@" ------------.------------ 后台验单成功:%@ | %@", tID, orderID);
|
||||
} else {
|
||||
NSLog(@" ------------.------------ 后台验单失败:%@ | %@ | %@", tID, orderID, msg);
|
||||
}
|
||||
|
||||
// 确保回调被调用
|
||||
if (next) {
|
||||
next(isSuccess);
|
||||
}
|
||||
|
||||
// 结束后台任务
|
||||
[[UIApplication sharedApplication] endBackgroundTask:backgroundTask];
|
||||
@@ -480,13 +573,19 @@
|
||||
// 查找在缓存中的 transactionID 并告知 apple 订单已完成
|
||||
- (void)handleCheckReceiptSuccess:(NSString *)tID
|
||||
isFromRecheck:(BOOL)isFromRecheck {
|
||||
// 验证参数
|
||||
if (tID.length == 0) {
|
||||
NSLog(@" ------------.------------ apple 验单失败:交易ID为空");
|
||||
return;
|
||||
}
|
||||
|
||||
if (@available(iOS 15.0, *)) {
|
||||
@kWeakify(self);
|
||||
[[PIIAPRegulate shared] verifyBusinessAccomplishWithTransactionID:tID
|
||||
completionHandler:^(BOOL success, NSError * _Nullable error) {
|
||||
@kStrongify(self);
|
||||
if (success) {
|
||||
// NSLog(@" ------------.------------ apple 验单成功");
|
||||
NSLog(@" ------------.------------ apple 验单成功");
|
||||
// 流程完成,移除本地缓存账单
|
||||
[RechargeStorage delegateTransactionId:tID
|
||||
uid:[AccountInfoStorage instance].getUid];
|
||||
@@ -494,7 +593,7 @@
|
||||
[self removeRetryCountForTransaction:tID];
|
||||
} else {
|
||||
// 出现异常
|
||||
// NSLog(@" ------------.------------ apple 验单成功:%@ ",error);
|
||||
NSLog(@" ------------.------------ apple 验单失败:%@ ",error);
|
||||
if (error == nil) {
|
||||
// 该订单在 appstore 已无法找到,不必再重试
|
||||
[RechargeStorage delegateTransactionId:tID
|
||||
@@ -502,7 +601,10 @@
|
||||
// 清理不存在的交易记录
|
||||
[self removeRetryCountForTransaction:tID];
|
||||
} else {
|
||||
[self retryCheckAllReceipt];
|
||||
// 只有在重试检查时才安排下一次重试
|
||||
if (isFromRecheck) {
|
||||
// 不立即重试,让定时器自然触发下一次
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -549,48 +651,92 @@
|
||||
// 清理长时间未处理的交易记录
|
||||
- (void)cleanupStaleTransactions {
|
||||
NSArray *receipts = [RechargeStorage getAllReceiptsWithUid:[AccountInfoStorage instance].getUid];
|
||||
if (!receipts || receipts.count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSDate *now = [NSDate date];
|
||||
NSInteger cleanupDays = 70; // 70天后清理
|
||||
|
||||
for (NSDictionary *receipt in receipts) {
|
||||
// 检查交易时间,如果超过7天还未成功,则清理
|
||||
// 检查交易时间,如果超过指定天数还未成功,则清理
|
||||
NSString *timestamp = receipt[@"timestamp"];
|
||||
if (timestamp) {
|
||||
if (!timestamp || timestamp.length == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
NSDate *transactionDate = nil;
|
||||
|
||||
// 尝试多种日期格式解析
|
||||
NSArray *dateFormats = @[
|
||||
@"yyyy-MM-dd HH:mm:ss Z",
|
||||
@"yyyy-MM-dd'T'HH:mm:ssZ",
|
||||
@"EEE MMM dd HH:mm:ss Z yyyy"
|
||||
];
|
||||
|
||||
for (NSString *format in dateFormats) {
|
||||
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
|
||||
[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss Z"]; // 根据实际时间格式调整
|
||||
NSDate *transactionDate = [dateFormatter dateFromString:timestamp];
|
||||
[dateFormatter setDateFormat:format];
|
||||
[dateFormatter setLocale:[NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]];
|
||||
|
||||
if (transactionDate && [now timeIntervalSinceDate:transactionDate] > 70 * 24 * 60 * 60) {
|
||||
NSString *tID = receipt[@"transactionId"];
|
||||
[RechargeStorage delegateTransactionId:tID uid:[AccountInfoStorage instance].getUid];
|
||||
[self _logToBugly:tID oID:receipt[@"orderId"] status:5]; // 新状态:过期清理
|
||||
|
||||
// 清理过期交易的重试记录
|
||||
[self removeRetryCountForTransaction:tID];
|
||||
transactionDate = [dateFormatter dateFromString:timestamp];
|
||||
if (transactionDate) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果无法解析日期,使用当前时间减去60天作为估计值
|
||||
if (!transactionDate) {
|
||||
transactionDate = [now dateByAddingTimeInterval:-60 * 24 * 60 * 60];
|
||||
}
|
||||
|
||||
// 检查是否超过清理期限
|
||||
if ([now timeIntervalSinceDate:transactionDate] > cleanupDays * 24 * 60 * 60) {
|
||||
NSString *tID = receipt[@"transactionId"];
|
||||
NSString *oID = receipt[@"orderId"];
|
||||
|
||||
// 记录清理日志
|
||||
[self _logToBugly:tID oID:oID status:5]; // 状态5:过期清理
|
||||
|
||||
// 从存储中删除
|
||||
[RechargeStorage delegateTransactionId:tID uid:[AccountInfoStorage instance].getUid];
|
||||
|
||||
// 清理过期交易的重试记录
|
||||
[self removeRetryCountForTransaction:tID];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取交易的重试次数
|
||||
- (NSInteger)getRetryCountForTransaction:(NSString *)transactionId {
|
||||
NSNumber *countNumber = self.retryCountMap[transactionId];
|
||||
return countNumber ? [countNumber integerValue] : 0;
|
||||
__block NSInteger count = 0;
|
||||
dispatch_sync(self.retryCountQueue, ^{
|
||||
NSNumber *countNumber = self.retryCountDict[transactionId];
|
||||
count = countNumber ? [countNumber integerValue] : 0;
|
||||
});
|
||||
return count;
|
||||
}
|
||||
|
||||
// 增加交易的重试次数
|
||||
- (void)incrementRetryCountForTransaction:(NSString *)transactionId {
|
||||
NSInteger currentCount = [self getRetryCountForTransaction:transactionId];
|
||||
self.retryCountMap[transactionId] = @(currentCount + 1);
|
||||
dispatch_barrier_async(self.retryCountQueue, ^{
|
||||
NSInteger currentCount = [self.retryCountDict[transactionId] integerValue];
|
||||
self.retryCountDict[transactionId] = @(currentCount + 1);
|
||||
});
|
||||
}
|
||||
|
||||
// 移除交易的重试记录
|
||||
- (void)removeRetryCountForTransaction:(NSString *)transactionId {
|
||||
[self.retryCountMap removeObjectForKey:transactionId];
|
||||
dispatch_barrier_async(self.retryCountQueue, ^{
|
||||
[self.retryCountDict removeObjectForKey:transactionId];
|
||||
});
|
||||
}
|
||||
|
||||
// 清理所有重试记录
|
||||
- (void)cleanAllRetryCount {
|
||||
[self.retryCountMap removeAllObjects];
|
||||
dispatch_barrier_async(self.retryCountQueue, ^{
|
||||
[self.retryCountDict removeAllObjects];
|
||||
});
|
||||
}
|
||||
|
||||
@end
|
||||
|
@@ -89,12 +89,15 @@
|
||||
self.priceLabel.attributedText = priceStr;
|
||||
self.numLabel.text = [NSString stringWithFormat:@"%ld",
|
||||
(long)rechargeModel.chargeGoldNum];
|
||||
|
||||
self.extBG.hidden = YES;
|
||||
self.moneyLabel.hidden = YES;
|
||||
FirstRechargeModel *model = [FirstRechargeManager.sharedManager loadCurrentModel];
|
||||
if (model && model.chargeStatus == NO) {
|
||||
for (FirstRechargeLevelModel *levelModel in model.levelCharge) {
|
||||
if (levelModel.exp == rechargeModel.chargeGoldNum) {
|
||||
[self.moneyLabel updateContent: [NSString stringWithFormat:@"+ %@", @(levelModel.awardNum)]];
|
||||
self.extBG.hidden = NO;
|
||||
self.moneyLabel.hidden = NO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@@ -195,10 +195,23 @@ XPIAPRechargeHeadCellDelegate>
|
||||
@kStrongify(self);
|
||||
[self hideHUD];
|
||||
[self getUserWalletBalanceInfo];
|
||||
|
||||
// 更新首充状态
|
||||
FirstRechargeManager *manager = [FirstRechargeManager sharedManager];
|
||||
// 使用新添加的方法更新首充状态
|
||||
[manager updateChargeStatusToCompleted];
|
||||
[self.collectionView reloadData];
|
||||
|
||||
// 由于服务器可能会返回不同的状态,我们在延迟后再次确认状态已更新
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[[FirstRechargeManager sharedManager] updateChargeStatusToCompleted];
|
||||
});
|
||||
|
||||
if(self.delegate && [self.delegate respondsToSelector:@selector(paySuccess)]){
|
||||
[self.delegate paySuccess];
|
||||
}
|
||||
self.rechargeBtn.userInteractionEnabled = YES;
|
||||
|
||||
} failure:^(NSError * _Nonnull error) {
|
||||
@kStrongify(self);
|
||||
[self hideHUD];
|
||||
@@ -280,9 +293,6 @@ XPIAPRechargeHeadCellDelegate>
|
||||
return CGSizeMake(kGetScaleWidth(108), kGetScaleWidth(121));
|
||||
}
|
||||
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
|
||||
|
||||
XPIAPRechargeCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass(XPIAPRechargeCollectionViewCell.self) forIndexPath:indexPath];
|
||||
NSInteger count = indexPath.item;
|
||||
cell.rechargeModel = [self.dataSource xpSafeObjectAtIndex:count];
|
||||
@@ -300,7 +310,6 @@ XPIAPRechargeHeadCellDelegate>
|
||||
|
||||
}
|
||||
#pragma mark - 懒加载
|
||||
|
||||
- (UICollectionView *)collectionView {
|
||||
if (!_collectionView) {
|
||||
MSBaseRTLFlowLayout *layout = [[MSBaseRTLFlowLayout alloc] init];
|
||||
@@ -317,10 +326,7 @@ XPIAPRechargeHeadCellDelegate>
|
||||
|
||||
_collectionView.delegate = self;
|
||||
_collectionView.dataSource = self;
|
||||
_collectionView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
|
||||
|
||||
// _collectionView.contentInset = UIEdgeInsetsMake(kHeaderViewHeight, 0, 0, 0);
|
||||
|
||||
_collectionView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
|
||||
}
|
||||
return _collectionView;
|
||||
}
|
||||
|
@@ -34,13 +34,15 @@
|
||||
[self.tableView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.mas_equalTo(kGetScaleWidth(20));
|
||||
make.leading.trailing.equalTo(self.view).inset(kGetScaleWidth(16));
|
||||
make.height.mas_equalTo(kGetScaleWidth(51 * 4));
|
||||
make.height.mas_equalTo(kGetScaleWidth(51 * 5));
|
||||
}];
|
||||
}
|
||||
-(void)saveBtnAction{
|
||||
NSString *language ;
|
||||
if ([self.chooseModel.title isEqualToString:@"English"]){
|
||||
language = @"en";
|
||||
} else if ([self.chooseModel.title isEqualToString:@"Português (Brasil)"]){
|
||||
language = @"pt-BR";
|
||||
} else if ([self.chooseModel.title isEqualToString:@"繁體中文"]){
|
||||
language = @"zh-Hant";
|
||||
} else if ([self.chooseModel.title isEqualToString:@"Türkçe"]) {
|
||||
@@ -99,6 +101,8 @@
|
||||
if(!_datasource){
|
||||
XPMineSettingItemModel *enItem = [XPMineSettingItemModel new];
|
||||
enItem.title = @"English";
|
||||
XPMineSettingItemModel *ptBRItem = [XPMineSettingItemModel new];
|
||||
ptBRItem.title = @"Português (Brasil)";
|
||||
XPMineSettingItemModel *zhItem = [XPMineSettingItemModel new];
|
||||
zhItem.title = @"繁體中文";
|
||||
XPMineSettingItemModel *arItem = [XPMineSettingItemModel new];
|
||||
@@ -110,6 +114,9 @@
|
||||
if ([language isEqualToString:@"en"]){
|
||||
enItem.isChoose = YES;
|
||||
self.chooseModel = enItem;
|
||||
}else if ([language isEqualToString:@"pt-BR"]){
|
||||
ptBRItem.isChoose = YES;
|
||||
self.chooseModel = ptBRItem;
|
||||
}else if ([language isEqualToString:@"ar"]){
|
||||
arItem.isChoose = YES;
|
||||
self.chooseModel = arItem;
|
||||
@@ -120,7 +127,7 @@
|
||||
zhItem.isChoose = YES;
|
||||
self.chooseModel = zhItem;
|
||||
}
|
||||
_datasource = @[enItem, zhItem, arItem, trItem];
|
||||
_datasource = @[enItem, ptBRItem, zhItem, arItem, trItem];
|
||||
}
|
||||
return _datasource;
|
||||
}
|
||||
|
@@ -284,16 +284,16 @@
|
||||
@kStrongify(self);
|
||||
[UIView animateWithDuration:0.5 animations:^{
|
||||
self.firstChargeBackgroundView.alpha = 1;
|
||||
} completion:^(BOOL finished) {
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[self removeFirstChargePopup];
|
||||
});
|
||||
}];
|
||||
}];
|
||||
[self.firstChargeWebVC setDidTapCharge:^{
|
||||
@kStrongify(self);
|
||||
[self removeFirstChargePopup];
|
||||
}];
|
||||
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[self removeFirstChargePopup];
|
||||
});
|
||||
}
|
||||
|
||||
// 处理背景点击事件
|
||||
|
@@ -353,4 +353,16 @@
|
||||
return _goButton;
|
||||
}
|
||||
|
||||
// 在主实现体内添加事件穿透逻辑
|
||||
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
|
||||
if (!self.userInteractionEnabled || self.hidden || self.alpha <= 0.01) {
|
||||
return nil;
|
||||
}
|
||||
CGPoint goButtonPoint = [self.goButton convertPoint:point fromView:self];
|
||||
if ([self.goButton pointInside:goButtonPoint withEvent:event]) {
|
||||
return self.goButton;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
@@ -401,4 +401,16 @@
|
||||
return _goButton;
|
||||
}
|
||||
|
||||
// ========== 事件穿透实现 ==========
|
||||
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
|
||||
if (!self.userInteractionEnabled || self.hidden || self.alpha <= 0.01) {
|
||||
return nil;
|
||||
}
|
||||
CGPoint goButtonPoint = [self.goButton convertPoint:point fromView:self];
|
||||
if ([self.goButton pointInside:goButtonPoint withEvent:event]) {
|
||||
return self.goButton;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
@@ -118,18 +118,13 @@
|
||||
NSString * userId = [AccountInfoStorage instance].getUid;
|
||||
NSString * roomId = [NSString stringWithFormat:@"%ld", self.hostDelegate.getRoomInfo.uid];
|
||||
// NSLog(@"用户ID:%@,房间ID:%@, 游戏ID:%lld, code:%@", userId, roomId, self.currentmgId, self.code);
|
||||
//
|
||||
|
||||
NSString *language = [NSBundle getLanguageText];
|
||||
if ([language hasPrefix:@"zh"]) {
|
||||
if ([language rangeOfString:@"Hans"].location != NSNotFound) {
|
||||
language = @"zh-CN"; // 简体中文
|
||||
} else {
|
||||
language = @"zh-TW"; // 繁體中文
|
||||
}
|
||||
}else{
|
||||
language = @"en-US"; // 英文
|
||||
}
|
||||
NSString *language = @"en-US";
|
||||
if (isMSZH()) {
|
||||
language = @"zh-TW";
|
||||
} else if (isMSPT()) {
|
||||
language = @"pt-BR";
|
||||
}
|
||||
self.fsmAPP2MG = [SudMGP loadMG:userId roomId:roomId code:self.code mgId:self.currentmgId language:language fsmMG:self rootView:self];
|
||||
} else {
|
||||
/// 初始化失败, 可根据业务重试
|
||||
|
@@ -25,13 +25,12 @@
|
||||
}
|
||||
-(void)installConstraints{
|
||||
[self.gameView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.mas_equalTo(kGetScaleWidth(20));
|
||||
make.width.height.mas_equalTo(kGetScaleWidth(56));
|
||||
make.centerX.equalTo(self.contentView);
|
||||
make.top.leading.trailing.mas_equalTo(self.contentView).inset(4);
|
||||
make.height.mas_equalTo(self.gameView.mas_width);
|
||||
// make.centerX.equalTo(self.contentView);
|
||||
}];
|
||||
[self.textView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(self.gameView.mas_bottom).mas_offset(kGetScaleWidth(10));
|
||||
|
||||
make.top.equalTo(self.gameView.mas_bottom).mas_offset(7);
|
||||
make.leading.trailing.equalTo(self.contentView).inset(kGetScaleWidth(5));
|
||||
}];
|
||||
}
|
||||
@@ -80,7 +79,7 @@
|
||||
_textView = [UILabel labelInitWithText:@"" font:kFontRegular(12) textColor:[UIColor whiteColor]];
|
||||
_textView.textAlignment = NSTextAlignmentCenter;
|
||||
_textView.numberOfLines = 2;
|
||||
_textView.hidden = YES;
|
||||
_textView.hidden = NO;
|
||||
}
|
||||
return _textView;
|
||||
}
|
||||
|
@@ -27,7 +27,7 @@ static const NSInteger kItemsPerRow = 5;
|
||||
-(instancetype)initWithFrame:(CGRect)frame{
|
||||
self = [super initWithFrame:frame];
|
||||
if(self){
|
||||
self.itemHeight = kGetScaleWidth(80);
|
||||
self.itemHeight = kGetScaleWidth(120);
|
||||
self.emptyHeight = kGetScaleWidth(100);
|
||||
self.dataSource = @[].mutableCopy;
|
||||
|
||||
@@ -52,11 +52,13 @@ static const NSInteger kItemsPerRow = 5;
|
||||
[self.blurEffectView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.leading.trailing.equalTo(self).inset(0);
|
||||
make.bottom.equalTo(self).offset(12);
|
||||
make.height.mas_equalTo(self.collectionView.mas_height).multipliedBy(1.1);
|
||||
make.height.mas_equalTo(KScreenHeight*2/3);
|
||||
}];
|
||||
[self.collectionView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.bottom.leading.trailing.equalTo(self).inset(kGetScaleWidth(0));
|
||||
make.height.mas_equalTo(kGetScaleWidth(246));
|
||||
make.bottom.equalTo(self);
|
||||
make.leading.trailing.equalTo(self).inset(16);
|
||||
// make.height.mas_equalTo(kGetScaleWidth(246));
|
||||
make.height.mas_equalTo(KScreenHeight*2/3 - 30);
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -69,7 +71,6 @@ static const NSInteger kItemsPerRow = 5;
|
||||
-(void)setPlayList:(NSMutableArray *)playList {
|
||||
_playList = playList;
|
||||
[self.dataSource addObjectsFromArray:playList];
|
||||
[self updateViewHeightWithItemCount:self.dataSource.count];
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[self.collectionView reloadData];
|
||||
});
|
||||
@@ -78,7 +79,6 @@ static const NSInteger kItemsPerRow = 5;
|
||||
- (void)setLittleGameList:(NSMutableArray<LittleGameInfoModel *> *)littleGameList {
|
||||
_littleGameList = littleGameList;
|
||||
[self.dataSource addObjectsFromArray:littleGameList];
|
||||
[self updateViewHeightWithItemCount:self.dataSource.count];
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[self.collectionView reloadData];
|
||||
});
|
||||
@@ -90,36 +90,18 @@ static const NSInteger kItemsPerRow = 5;
|
||||
self.dataSource = [NSMutableArray array];
|
||||
[self.dataSource addObjectsFromArray:playList];
|
||||
[self.dataSource addObjectsFromArray:littleGameList];
|
||||
[self updateViewHeightWithItemCount:self.dataSource.count];
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[self.collectionView reloadData];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)updateViewHeightWithItemCount:(NSInteger)count {
|
||||
if (count == 0) {
|
||||
return;
|
||||
}
|
||||
NSInteger lineNum = (count + kItemsPerRow - 1)/kItemsPerRow;// MIN(3, (count + kItemsPerRow - 1)/kItemsPerRow);
|
||||
|
||||
CGFloat calHeight = self.itemHeight;
|
||||
CGFloat height = 20 + 56 * lineNum + 44 * (lineNum - 1) + 70;
|
||||
height = calHeight * lineNum;
|
||||
// [self.ms_bgView mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
// make.height.mas_equalTo(kGetScaleWidth(height + 12));
|
||||
// }];
|
||||
[self.collectionView mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.height.mas_equalTo(kGetScaleWidth(height));
|
||||
}];
|
||||
}
|
||||
|
||||
- (NSInteger)countOfCurrentType {
|
||||
return self.dataSource.count;// self.littleGameList.count > 0 ? self.littleGameList.count : self.playList.count;
|
||||
}
|
||||
|
||||
#pragma mark- UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout
|
||||
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{
|
||||
CGFloat width = (KScreenWidth-kGetScaleWidth(6))/5;
|
||||
CGFloat width = (KScreenWidth - 64)/4;
|
||||
return [self countOfCurrentType] > 0 ? CGSizeMake(width, self.itemHeight) : CGSizeMake(KScreenWidth, self.emptyHeight);
|
||||
}
|
||||
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section{
|
||||
@@ -179,17 +161,17 @@ static const NSInteger kItemsPerRow = 5;
|
||||
- (UICollectionView *)collectionView{
|
||||
if (!_collectionView) {
|
||||
MSBaseRTLFlowLayout *layout = [[MSBaseRTLFlowLayout alloc] init];
|
||||
|
||||
|
||||
layout.minimumLineSpacing = 0;
|
||||
layout.minimumInteritemSpacing = 0;
|
||||
layout.minimumInteritemSpacing = 8;
|
||||
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
|
||||
_collectionView.showsHorizontalScrollIndicator = NO;
|
||||
_collectionView.showsVerticalScrollIndicator = NO;
|
||||
_collectionView.dataSource = self;
|
||||
_collectionView.delegate = self;
|
||||
_collectionView.backgroundColor = [UIColor clearColor];
|
||||
[_collectionView registerClass:[MSRoomMenuGameCell class] forCellWithReuseIdentifier:NSStringFromClass([MSRoomMenuGameCell class])];
|
||||
[_collectionView registerClass:[MSRoomMenuGameEmptyCell class] forCellWithReuseIdentifier:NSStringFromClass([MSRoomMenuGameEmptyCell class])];
|
||||
|
||||
}
|
||||
return _collectionView;
|
||||
}
|
||||
@@ -206,7 +188,7 @@ static const NSInteger kItemsPerRow = 5;
|
||||
_blurEffectView.frame = CGRectMake(0, 0, KScreenWidth, kGetScaleWidth(246));
|
||||
_blurEffectView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
|
||||
[_blurEffectView setCornerRadius:12];
|
||||
[_blurEffectView setCornerRadius:24];
|
||||
}
|
||||
return _blurEffectView;
|
||||
}
|
||||
|
@@ -70,7 +70,7 @@
|
||||
}
|
||||
|
||||
- (void)gameSetUp {
|
||||
// nslog(@"小游戏的版本号是:%@", [SudMGP getVersion]);
|
||||
NSLog(@"ISudFSMMG:小游戏的版本号是:%@", [SudMGP getVersion]);
|
||||
BOOL isTestEnv = NO;
|
||||
#ifdef DEBUG
|
||||
isTestEnv = YES;
|
||||
@@ -80,7 +80,7 @@
|
||||
if(isEnterprise == NO){
|
||||
[[SudMGP getCfg]setBackgroundMode:NO];
|
||||
}
|
||||
[SudMGP initSDK:KeyWithType(KeyType_SudGameAppID)
|
||||
[SudMGP initSDK:KeyWithType(KeyType_SudGameAppID)
|
||||
appKey:KeyWithType(KeyType_SudGameAppKey)
|
||||
isTestEnv:isTestEnv
|
||||
listener:^(int retCode, const NSString *retMsg) {
|
||||
@@ -90,22 +90,17 @@
|
||||
}
|
||||
NSString * userId = [AccountInfoStorage instance].getUid;
|
||||
NSString * roomId = self.gameModel.roomId;
|
||||
// nslog(@"用户ID:%@,房间ID:%@, 游戏ID:%lld, code:%@", userId, roomId, self.currentmgId, self.code);
|
||||
|
||||
NSString *language = [NSBundle getLanguageText];
|
||||
if ([language hasPrefix:@"zh"]) {
|
||||
if ([language rangeOfString:@"Hans"].location != NSNotFound) {
|
||||
language = @"zh-CN"; // 简体中文
|
||||
} else {
|
||||
language = @"zh-TW"; // 繁體中文
|
||||
}
|
||||
}else{
|
||||
language = @"en-US"; // 英文
|
||||
}
|
||||
NSLog(@"ISudFSMMG:用户ID:%@,房间ID:%@, 游戏ID:%lld, code:%@", userId, roomId, self.currentmgId, self.code);
|
||||
NSString *language = @"en-US";
|
||||
if (isMSZH()) {
|
||||
language = @"zh-TW";
|
||||
} else if (isMSPT()) {
|
||||
language = @"pt-BR";
|
||||
}
|
||||
self.fsmAPP2MG = [SudMGP loadMG:userId roomId:roomId code:self.code mgId:self.currentmgId language:language fsmMG:self rootView:self];
|
||||
} else {
|
||||
/// 初始化失败, 可根据业务重试
|
||||
// nslog(@"ISudFSMMG:initGameSDKWithAppID:初始化sdk失败 :%@",retMsg);
|
||||
NSLog(@"ISudFSMMG:initGameSDKWithAppID:初始化sdk失败 :%@",retMsg);
|
||||
}
|
||||
}];
|
||||
}
|
||||
@@ -157,7 +152,7 @@
|
||||
* 游戏日志
|
||||
*/
|
||||
-(void)onGameLog:(NSString*)dataJson {
|
||||
// nslog(@"ISudFSMMG:onGameLog:%@", dataJson);
|
||||
NSLog(@"ISudFSMMG:onGameLog:%@", dataJson);
|
||||
NSDictionary * dic = [SudCommon turnStringToDictionary:dataJson];
|
||||
NSString * msg_string = [dic objectForKey:@"msg"];
|
||||
if (!msg_string) {
|
||||
@@ -169,7 +164,7 @@
|
||||
* 游戏开始
|
||||
*/
|
||||
-(void)onGameStarted {
|
||||
// nslog(@"ISudFSMMG:onGameStarted:游戏开始");
|
||||
NSLog(@"ISudFSMMG:onGameStarted:游戏开始");
|
||||
[self notifySelfInState:YES seatIndex:-1];///加入房间
|
||||
[self handleSelfReadyEvent];///准备游戏
|
||||
}
|
||||
@@ -178,7 +173,7 @@
|
||||
* 游戏销毁
|
||||
*/
|
||||
-(void)onGameDestroyed {
|
||||
// nslog(@"ISudFSMMG:onGameDestroyed:游戏销毁");
|
||||
NSLog(@"ISudFSMMG:onGameDestroyed:游戏销毁");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -186,14 +181,14 @@
|
||||
* @param dataJson {"code":"value"}
|
||||
*/
|
||||
-(void)onExpireCode:(id<ISudFSMStateHandle>)handle dataJson:(NSString*)dataJson {
|
||||
// nslog(@"ISudFSMMG:onExpireCode:Code过期");
|
||||
NSLog(@"ISudFSMMG:onExpireCode:Code过期");
|
||||
// 请求业务服务器刷新令牌
|
||||
[Api getSudGameCode:^(BaseModel * _Nullable data, NSInteger code, NSString * _Nullable msg) {
|
||||
if (code == 200) {
|
||||
NSString * gameCode = data.data[@"code"];
|
||||
self.code = gameCode;
|
||||
[self.fsmAPP2MG updateCode:gameCode listener:^(int retCode, const NSString *retMsg, const NSString *dataJson) {
|
||||
// nslog(@"ISudFSMMG:updateGameCode retCode=%@ retMsg=%@ dataJson=%@", @(retCode), retMsg, dataJson);
|
||||
NSLog(@"ISudFSMMG:updateGameCode retCode=%@ retMsg=%@ dataJson=%@", @(retCode), retMsg, dataJson);
|
||||
}];
|
||||
// 回调结果
|
||||
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:@(0), @"ret_code", @"return form APP onExpireCode", @"ret_msg", nil];
|
||||
@@ -251,15 +246,15 @@
|
||||
|
||||
// 检查是否解析成功
|
||||
if (error) {
|
||||
// nslog(@"JSON 解析失败: %@", error.localizedDescription);
|
||||
NSLog(@"ISudFSMMG:JSON 解析失败: %@", error.localizedDescription);
|
||||
} else {
|
||||
// nslog(@"解析后的字典: %@", dictionary);
|
||||
NSLog(@"ISudFSMMG:解析后的字典: %@", dictionary);
|
||||
// 禁止模式选择
|
||||
NSMutableDictionary *ui = [[NSMutableDictionary alloc] initWithDictionary:dictionary[@"ui"]];
|
||||
[ui setObject: @{@"hide" : @(YES)}
|
||||
forKey:@"lobby_game_setting"];
|
||||
[dictionary setObject:ui forKey:@"ui"];
|
||||
// nslog(@"更新后的字典: %@", dictionary);
|
||||
NSLog(@"ISudFSMMG:更新后的字典: %@", dictionary);
|
||||
}
|
||||
|
||||
// dict[@"ui"] = @{
|
||||
@@ -290,11 +285,11 @@
|
||||
* @param dataJson 回调json
|
||||
*/
|
||||
-(void)onGameStateChange:(id<ISudFSMStateHandle>) handle state:(NSString*) state dataJson:(NSString*) dataJson {
|
||||
// nslog(@"onGameStateChange 回调: %@ \n%@", state, dataJson);
|
||||
NSLog(@"ISudFSMMG:onGameStateChange 回调: %@ \n%@", state, dataJson);
|
||||
if ([state isEqualToString:MG_COMMON_SELF_CLICK_READY_BTN]) {
|
||||
// [self addAI];
|
||||
} else if ([state isEqualToString:@"mg_common_game_add_ai_players"]) {
|
||||
// nslog(@" ????????????????????????????????????????????? ");
|
||||
NSLog(@"ISudFSMMG: ????????????????????????????????????????????? ");
|
||||
} else if([state isEqualToString:MG_COMMON_GAME_SETTLE]){
|
||||
NSDictionary *data = @{@"value0":self.gameModel.data.matchRoundId ?: @""};
|
||||
NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:[data mj_JSONString] , @"reportGameInfoExtras",@"value0" , @"reportGameInfoKey" ,nil];
|
||||
@@ -308,7 +303,7 @@
|
||||
[self.delegate getGameRsultsWithList:list];
|
||||
}
|
||||
}else if ([state isEqualToString:MG_COMMON_PUBLIC_MESSAGE]) {
|
||||
// nslog(@"ISudFSMMG:onGameStateChange:游戏->APP:公屏消息");
|
||||
NSLog(@"ISudFSMMG:ISudFSMMG:onGameStateChange:游戏->APP:公屏消息");
|
||||
} else if ([state isEqualToString:MG_COMMON_KEY_WORD_TO_HIT]) {
|
||||
|
||||
}else if ([state isEqualToString:MG_COMMON_SELF_CLICK_JOIN_BTN]) {//加入游戏按钮点击
|
||||
@@ -318,9 +313,9 @@
|
||||
seatIndex = [[dic objectForKey:@"seatIndex"] intValue];
|
||||
}
|
||||
if (seatIndex == -1) {
|
||||
// nslog(@"来自加入按钮%d",seatIndex);
|
||||
NSLog(@"ISudFSMMG:来自加入按钮%d",seatIndex);
|
||||
}else {
|
||||
// nslog(@"来自麦位+入%d",seatIndex);
|
||||
NSLog(@"ISudFSMMG:来自麦位+入%d",seatIndex);
|
||||
}
|
||||
[self notifySelfInState:YES seatIndex:-1];
|
||||
} else if([state isEqualToString:MG_COMMON_SELF_CLICK_START_BTN]) {//开始游戏按钮点击
|
||||
@@ -330,7 +325,7 @@
|
||||
[self handleSelfInExitEvent];
|
||||
} else {
|
||||
/// 其他状态
|
||||
// nslog(@"ISudFSMMG:onGameStateChange:游戏->APP:state:%@",MG_COMMON_PUBLIC_MESSAGE);
|
||||
NSLog(@"ISudFSMMG:onGameStateChange:游戏->APP:state:%@",MG_COMMON_PUBLIC_MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,7 +337,7 @@
|
||||
* @param dataJson 回调JSON
|
||||
*/
|
||||
-(void)onPlayerStateChange:(nullable id<ISudFSMStateHandle>) handle userId:(NSString*) userId state:(NSString*) state dataJson:(NSString*) dataJson {
|
||||
// nslog(@"ISudFSMMG:onPlayerStateChange:游戏->APP:游戏玩家状态变化:userId: %@ --state: %@ --dataJson: %@", userId, state, dataJson);
|
||||
NSLog(@"ISudFSMMG:onPlayerStateChange:游戏->APP:游戏玩家状态变化:userId: %@ --state: %@ --dataJson: %@", userId, state, dataJson);
|
||||
/// 状态解析
|
||||
NSString *dataStr = @"";
|
||||
if ([state isEqualToString:MG_COMMON_PLAYER_IN]) {
|
||||
@@ -382,9 +377,9 @@
|
||||
dataStr = YMLocalizedString(@"XPRoomLittleGameContainerView8");
|
||||
[self handleState_MG_DG_SCORE_WithUserId:userId dataJson:dataJson];
|
||||
}else {
|
||||
// nslog(@"ISudFSMMG:onPlayerStateChange:未做解析状态:%@", MG_DG_SCORE);
|
||||
NSLog(@"ISudFSMMG:onPlayerStateChange:未做解析状态:%@", MG_DG_SCORE);
|
||||
}
|
||||
// nslog(@"ISudFSMMG:onPlayerStateChange:dataStr:%@", dataStr);
|
||||
NSLog(@"ISudFSMMG:onPlayerStateChange:dataStr:%@", dataStr);
|
||||
/// 回调
|
||||
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:@(0), @"ret_code", @"return form APP onPlayerStateChange", @"ret_msg", nil];
|
||||
[handle success:[SudCommon dictionaryToJson:dict]];
|
||||
@@ -443,9 +438,9 @@
|
||||
/// @param state 状态名称
|
||||
/// @param dataJson 需传递的json
|
||||
- (void)notifyStateChange:(NSString *) state dataJson:(NSString*) dataJson {
|
||||
// nslog(@"ISudFSMMG: START notifyStateChange:state=%@ \ndataJson=%@", state, dataJson);
|
||||
NSLog(@"ISudFSMMG: START notifyStateChange:state=%@ \ndataJson=%@", state, dataJson);
|
||||
[self.fsmAPP2MG notifyStateChange:state dataJson:dataJson listener:^(int retCode, const NSString *retMsg, const NSString *dataJson) {
|
||||
// nslog(@"ISudFSMMG:notifyStateChange:retCode=%@ retMsg=%@ dataJson=%@", @(retCode), retMsg, dataJson);
|
||||
NSLog(@"ISudFSMMG:notifyStateChange:retCode=%@ retMsg=%@ dataJson=%@", @(retCode), retMsg, dataJson);
|
||||
|
||||
if (retCode == 0 && [state isEqualToString:APP_COMMON_SELF_PLAYING]) {//开始游戏
|
||||
//上报游戏开始
|
||||
@@ -606,11 +601,11 @@
|
||||
}
|
||||
|
||||
- (void)handleState_MG_DG_SELECTING_WithUserId:(NSString *)userId dataJson:(NSString *)dataJson {
|
||||
// nslog(@"handleState_MG_DG_SELECTING_WithUserId%@",dataJson);
|
||||
NSLog(@"handleState_MG_DG_SELECTING_WithUserId%@",dataJson);
|
||||
}
|
||||
|
||||
- (void)handleState_MG_DG_PAINTING_WithUserId:(NSString *)userId dataJson:(NSString *)dataJson {
|
||||
// nslog(@"handleState_MG_DG_PAINTING_WithUserId%@",dataJson);
|
||||
NSLog(@"handleState_MG_DG_PAINTING_WithUserId%@",dataJson);
|
||||
/// 设置麦位状态为作画中
|
||||
NSDictionary * dic = [SudCommon turnStringToDictionary:dataJson];
|
||||
bool isPainting = NO;
|
||||
@@ -621,18 +616,18 @@
|
||||
|
||||
- (void)handleState_MG_DG_ERRORANSWER_WithUserId:(NSString *)userId dataJson:(NSString *)dataJson {
|
||||
/// 错误答案
|
||||
// nslog(@"handleState_MG_DG_ERRORANSWER_WithUserId%@",dataJson);
|
||||
NSLog(@"handleState_MG_DG_ERRORANSWER_WithUserId%@",dataJson);
|
||||
|
||||
}
|
||||
|
||||
- (void)handleState_MG_DG_TOTALSCORE_WithUserId:(NSString *)userId dataJson:(NSString *)dataJson {
|
||||
/// 总积分
|
||||
// nslog(@"handleState_MG_DG_TOTALSCORE_WithUserId%@",dataJson);
|
||||
NSLog(@"handleState_MG_DG_TOTALSCORE_WithUserId%@",dataJson);
|
||||
}
|
||||
|
||||
- (void)handleState_MG_DG_SCORE_WithUserId:(NSString *)userId dataJson:(NSString *)dataJson {
|
||||
/// 本次积分
|
||||
// nslog(@"handleState_MG_DG_SCORE_WithUserId%@",dataJson);
|
||||
NSLog(@"handleState_MG_DG_SCORE_WithUserId%@",dataJson);
|
||||
}
|
||||
|
||||
/// 销毁MG
|
||||
|
@@ -1497,9 +1497,7 @@
|
||||
|
||||
#pragma mark -
|
||||
- (void)onGetUserInfoSuccess:(UserInfoModel *)userInfo {
|
||||
#if DEBUG
|
||||
// userInfo.medalsPic = @[];
|
||||
#endif
|
||||
|
||||
self.userInfoModel = userInfo;
|
||||
self.avatar.userInfo = userInfo;
|
||||
@kWeakify(self);
|
||||
@@ -2163,7 +2161,7 @@
|
||||
|
||||
- (void)updateCollectionViewFrame {
|
||||
CGFloat newHeight = [self calculateCollectionViewHeight];
|
||||
if (ABS(self.collectionHeight - newHeight) > 0.1) { // 只有高度确实变化时才更新
|
||||
// if (ABS(self.collectionHeight - newHeight) > 0.1) { // 只有高度确实变化时才更新
|
||||
self.collectionHeight = newHeight;
|
||||
CGFloat space_top = KScreenHeight - self.collectionHeight;
|
||||
|
||||
@@ -2175,7 +2173,7 @@
|
||||
[XNDJTDDLoadingTool hideHUD];
|
||||
}
|
||||
}];
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
@end
|
||||
|
@@ -1447,13 +1447,13 @@ XPCandyTreeInsufficientBalanceViewDelegate>
|
||||
self.userInfo = userInfo;
|
||||
|
||||
[self requestBoomData];
|
||||
[self getOnlineCount];
|
||||
|
||||
@kWeakify(self);
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
|
||||
@kStrongify(self);
|
||||
//获取一下红包信息
|
||||
[self.presenter getRedPacket:[NSString stringWithFormat:@"%ld", self.roomInfo.uid]];
|
||||
[self getOnlineCount];
|
||||
});
|
||||
|
||||
switch (roomInfo.type) {
|
||||
@@ -1842,7 +1842,7 @@ XPCandyTreeInsufficientBalanceViewDelegate>
|
||||
continue;
|
||||
}
|
||||
|
||||
NSLog(@" --- Message Raw Attach Content: %@, %@, %ld", @(message.senderClientType), message.rawAttachContent, (long)message.messageType);
|
||||
// NSLog(@" --- Message Raw Attach Content: %@, %@, %ld", @(message.senderClientType), message.rawAttachContent, (long)message.messageType);
|
||||
|
||||
if (message.messageType == NIMMessageTypeNotification) {
|
||||
NIMNotificationObject *notiMsg = (NIMNotificationObject *)message.messageObject;
|
||||
|
@@ -290,9 +290,10 @@ NSString * const kJPClose = @"newTppClose";
|
||||
if (![self isValidGameURL:url]) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
switch (self.gameType) {
|
||||
case MSGameTypeBaiShun:
|
||||
url = [self addSupportLanguage:url];
|
||||
return [NSURL URLWithString:url];
|
||||
case MSGameTypeJoyPlay:
|
||||
url = [url stringByAppendingFormat:@"?gameId=%@", @(self.gameModel.gameModel.gameId)];
|
||||
@@ -313,25 +314,37 @@ NSString * const kJPClose = @"newTppClose";
|
||||
break;
|
||||
}
|
||||
|
||||
url = [self addSupportLanguage:url];
|
||||
|
||||
if (![NSString isEmpty:self.gameModel.gameModel.urlParam]) {
|
||||
url = [url stringByAppendingString:[NSString stringWithFormat:@"&%@", self.gameModel.gameModel.urlParam]];
|
||||
}
|
||||
|
||||
if (isMSEN()) {
|
||||
url = [url stringByAppendingFormat:@"&lang=%@", @"en-US"];
|
||||
} else if (isMSTR()) {
|
||||
url = [url stringByAppendingFormat:@"&lang=%@", @"tr-TR"];
|
||||
} else if (isMSZH()) {
|
||||
url = [url stringByAppendingFormat:@"&lang=%@", @"zh-TW"];
|
||||
} else if (isMSRTL()) {
|
||||
url = [url stringByAppendingFormat:@"&lang=%@", @"ar-EG"];
|
||||
}
|
||||
url = [url stringByAppendingFormat:@"&token=%@", self.gameModel.gameModel.code];
|
||||
url = [url stringByAppendingFormat:@"&uid=%@", [AccountInfoStorage instance].getUid];
|
||||
|
||||
return [NSURL URLWithString:url];
|
||||
}
|
||||
|
||||
- (NSString *)addSupportLanguage:(NSString *)url {
|
||||
NSString *mark = @"&";
|
||||
NSString *lang = @"en-US";
|
||||
if (![url containsString:@"?"]) {
|
||||
mark = @"?";
|
||||
}
|
||||
if (isMSTR()) {
|
||||
lang = @"tr-TR";
|
||||
} else if (isMSZH()) {
|
||||
lang = @"zh-TW";
|
||||
} else if (isMSRTL()) {
|
||||
lang = @"ar-EG";
|
||||
} else if (isMSPT()) {
|
||||
lang = @"pt-BR";
|
||||
}
|
||||
url = [url stringByAppendingFormat:@"%@lang=%@", mark, lang];
|
||||
return url;
|
||||
}
|
||||
|
||||
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
|
||||
[self hideHUD];
|
||||
self.retryCount = 0;
|
||||
|
@@ -52,7 +52,9 @@
|
||||
return manager;
|
||||
}
|
||||
+(NSString *)getHostUrl{
|
||||
#ifdef DEBUG
|
||||
#if DEBUG
|
||||
// return @"https://api.epartylive.com";
|
||||
|
||||
NSString *isProduction = [[NSUserDefaults standardUserDefaults]valueForKey:@"kIsProductionEnvironment"];
|
||||
if([isProduction isEqualToString:@"YES"]){
|
||||
return API_HOST_URL;
|
||||
@@ -93,13 +95,31 @@
|
||||
editParam = [MSParamsDecode msDecodeParams:editParam];
|
||||
params = [self configBaseParmars:editParam];
|
||||
|
||||
#ifdef DEBUG
|
||||
NSLog(@"\nmethod:\n%@\nparameter:\n%@\n", method, params);
|
||||
#if 0
|
||||
// 构建完整的 URL
|
||||
NSString *baseUrl = [HttpRequestHelper getHostUrl];
|
||||
NSString *fullUrl = [NSString stringWithFormat:@"%@/%@", baseUrl, method];
|
||||
|
||||
// 构建查询字符串
|
||||
NSMutableArray *queryItems = [NSMutableArray array];
|
||||
[params enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
|
||||
[queryItems addObject:[NSString stringWithFormat:@"%@=%@", key, obj]];
|
||||
}];
|
||||
NSString *queryString = [queryItems componentsJoinedByString:@"&"];
|
||||
if (queryString.length > 0) {
|
||||
fullUrl = [NSString stringWithFormat:@"%@?%@", fullUrl, queryString];
|
||||
}
|
||||
|
||||
NSLog(@"\n🌐 API Request Info:");
|
||||
NSLog(@"📍 Full URL: %@", fullUrl);
|
||||
NSLog(@"🔧 Method: %@", method);
|
||||
NSLog(@"📦 Parameter Type: queryParameters");
|
||||
NSLog(@"📋 Parameters: %@\n", params);
|
||||
#endif
|
||||
@kWeakify(self);
|
||||
[manager GET:method parameters:params headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
|
||||
BaseModel *baseModel = [BaseModel modelWithDictionary:responseObject];
|
||||
#ifdef DEBUG
|
||||
#if 0
|
||||
NSLog(@"%@ - \n%@\n", method, [baseModel toJSONString]);
|
||||
#else
|
||||
#endif
|
||||
@@ -226,14 +246,22 @@
|
||||
|
||||
params = [self configBaseParmars:params];
|
||||
|
||||
#ifdef DEBUG
|
||||
NSLog(@"\nmethod:\n%@\nparameter:\n%@", method, params);
|
||||
#if 0
|
||||
// 构建完整的 URL
|
||||
NSString *baseUrl = [HttpRequestHelper getHostUrl];
|
||||
NSString *fullUrl = [NSString stringWithFormat:@"%@/%@", baseUrl, method];
|
||||
|
||||
NSLog(@"\n🌐 API Request Info:");
|
||||
NSLog(@"📍 Full URL: %@", fullUrl);
|
||||
NSLog(@"🔧 Method: %@", method);
|
||||
NSLog(@"📦 Parameter Type: bodyParameters");
|
||||
NSLog(@"📋 Parameters: %@\n", params);
|
||||
#else
|
||||
#endif
|
||||
|
||||
[manager POST:method parameters:params headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
|
||||
BaseModel *baseModel = [BaseModel modelWithDictionary:responseObject];
|
||||
#ifdef DEBUG
|
||||
#if 0
|
||||
NSLog(@"\n%@", [baseModel toJSONString]);
|
||||
#else
|
||||
#endif
|
||||
@@ -259,7 +287,7 @@
|
||||
params = [MSParamsDecode msDecodeParams:[params mutableCopy] ];
|
||||
params = [self configBaseParmars:params];
|
||||
|
||||
#ifdef DEBUG
|
||||
#if 0
|
||||
NSLog(@"\nmethod:\n%@\nparameter:\n%@\n 超時:%@",
|
||||
method,
|
||||
params,
|
||||
@@ -282,13 +310,13 @@ constructingBodyWithBlock:^(id<AFMultipartFormData> _Nonnull formData) {
|
||||
progress:nil
|
||||
success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
|
||||
BaseModel *baseModel = [BaseModel modelWithDictionary:responseObject];
|
||||
#ifdef DEBUG
|
||||
#if 0
|
||||
NSLog(@"%@ - \n%@\n", method, [baseModel toJSONString]);
|
||||
#else
|
||||
#endif
|
||||
success(baseModel);
|
||||
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
|
||||
#ifdef DEBUG
|
||||
#if 0
|
||||
NSLog(@"%@ - \n%@\n", method, error);
|
||||
#else
|
||||
#endif
|
||||
@@ -311,14 +339,32 @@ constructingBodyWithBlock:^(id<AFMultipartFormData> _Nonnull formData) {
|
||||
params = [MSParamsDecode msDecodeParams:[params mutableCopy] ];
|
||||
params = [self configBaseParmars:params];
|
||||
AFHTTPSessionManager *manager = [HttpRequestHelper requestManager];
|
||||
#ifdef DEBUG
|
||||
NSLog(@"\nmethod:\n%@\nparameter:\n%@\n", method, params);
|
||||
#if 0
|
||||
// 构建完整的 URL
|
||||
NSString *baseUrl = [HttpRequestHelper getHostUrl];
|
||||
NSString *fullUrl = [NSString stringWithFormat:@"%@/%@", baseUrl, method];
|
||||
|
||||
// 构建查询字符串
|
||||
NSMutableArray *queryItems = [NSMutableArray array];
|
||||
[params enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
|
||||
[queryItems addObject:[NSString stringWithFormat:@"%@=%@", key, obj]];
|
||||
}];
|
||||
NSString *queryString = [queryItems componentsJoinedByString:@"&"];
|
||||
if (queryString.length > 0) {
|
||||
fullUrl = [NSString stringWithFormat:@"%@?%@", fullUrl, queryString];
|
||||
}
|
||||
|
||||
NSLog(@"\n🌐 API Request Info:");
|
||||
NSLog(@"📍 Full URL: %@", fullUrl);
|
||||
NSLog(@"🔧 Method: %@", method);
|
||||
NSLog(@"📦 Parameter Type: queryParameters");
|
||||
NSLog(@"📋 Parameters: %@\n", params);
|
||||
#else
|
||||
#endif
|
||||
@kWeakify(self);
|
||||
[manager DELETE:method parameters:params headers:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
|
||||
BaseModel *baseModel = [BaseModel modelWithDictionary:responseObject];
|
||||
#ifdef DEBUG
|
||||
#if 0
|
||||
NSLog(@"\n%@\n", [baseModel toJSONString]);
|
||||
#else
|
||||
#endif
|
||||
@@ -456,7 +502,7 @@ constructingBodyWithBlock:^(id<AFMultipartFormData> _Nonnull formData) {
|
||||
failure(error.code, error.localizedDescription.length > 0 ? error.localizedDescription : YMLocalizedString(@"HttpRequestHelper4"));
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
#if 0
|
||||
NSLog(@"\n%@", error);
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
NSDictionary *allHeaders = response.allHeaderFields;
|
||||
@@ -491,7 +537,7 @@ constructingBodyWithBlock:^(id<AFMultipartFormData> _Nonnull formData) {
|
||||
AFHTTPSessionManager *manager = [HttpRequestHelper requestManager];
|
||||
NSString *url = [self getHostUrl];
|
||||
NSString *urlPath = [NSString stringWithFormat:@"%@/%@", url ,path];
|
||||
#ifdef DEBUG
|
||||
#if 0
|
||||
NSLog(@"\nmethod:\n%@\nparameter:\n%@", path, params);
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
[BSNetListenModel addHttpReq:urlPath header:manager.requestSerializer.HTTPRequestHeaders param:[params copy] time:[NSDate getCurrentTimeWithFormat:@"yyyy-MM-dd HH:mm:ss"]];
|
||||
@@ -536,12 +582,12 @@ constructingBodyWithBlock:^(id<AFMultipartFormData> _Nonnull formData) {
|
||||
if (responseObject) {
|
||||
BaseModel *baseModel = [BaseModel modelWithDictionary:responseObject];
|
||||
|
||||
#ifdef DEBUG
|
||||
#if 0
|
||||
NSLog(@"\n%@", [baseModel toJSONString]);
|
||||
#else
|
||||
#endif
|
||||
if (baseModel.code == 200) {
|
||||
#ifdef DEBUG
|
||||
#if 0
|
||||
NSHTTPURLResponse *urlresponse = (NSHTTPURLResponse *)response;
|
||||
NSDictionary *allHeaders = urlresponse.allHeaderFields;
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
|
@@ -11,13 +11,13 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface AccountModel : PIBaseModel
|
||||
|
||||
@property (nonatomic , assign) NSString *uid;
|
||||
@property (nonatomic , copy) NSString *uid;
|
||||
@property (nonatomic , copy) NSString *jti;
|
||||
@property (nonatomic , copy) NSString *token_type;
|
||||
@property (nonatomic , copy) NSString *refresh_token;
|
||||
@property (nonatomic , copy) NSString *netEaseToken;
|
||||
@property (nonatomic , copy) NSString *access_token;
|
||||
@property (nonatomic , assign) NSNumber *expires_in;
|
||||
@property (nonatomic , copy) NSNumber *expires_in;
|
||||
|
||||
@end
|
||||
@interface HomeUserModel : PIBaseModel
|
||||
|
@@ -98,8 +98,8 @@
|
||||
[[self getView] completeUserInfo];
|
||||
return;
|
||||
case 3009: // 账号已注销
|
||||
[[self getView] accountCanceled:data.model2dictionary];
|
||||
return;
|
||||
// [[self getView] accountCanceled:data.model2dictionary];
|
||||
// return;
|
||||
case 31005: {//余额不足
|
||||
}
|
||||
break;
|
||||
|
@@ -71,6 +71,8 @@ static NSString * const kResourceType = @"lproj";
|
||||
return @"ar"; // 阿拉伯语
|
||||
} else if ([language hasPrefix:@"tr"]) {
|
||||
return @"tr"; // 土耳其语
|
||||
} else if ([language hasPrefix:@"pt-BR"] || [language hasPrefix:@"pt"]) {
|
||||
return @"pt-BR"; // 葡萄牙语-巴西
|
||||
} else {
|
||||
return @"en"; // 默认英文
|
||||
}
|
||||
|
@@ -13,6 +13,7 @@
|
||||
- (void)stopMonitoring;
|
||||
- (void)manualCheckFirstRecharge;
|
||||
- (void)markTodayShown;
|
||||
- (void)updateChargeStatusToCompleted;
|
||||
|
||||
- (FirstRechargeModel *)loadCurrentModel;
|
||||
|
||||
@@ -29,4 +30,4 @@
|
||||
- (void)firstRechargeManager:(FirstRechargeManager *)manager
|
||||
didFailWithError:(NSError *)error;
|
||||
|
||||
@end
|
||||
@end
|
||||
|
@@ -106,6 +106,19 @@ static NSString * const kCurrentUserIdKey = @"FirstRechargeCurrentUserId";
|
||||
[self setTodayShownForCurrentUser:today];
|
||||
}
|
||||
|
||||
- (void)updateChargeStatusToCompleted {
|
||||
if (self.currentFirstRechargeData && !self.currentFirstRechargeData.chargeStatus) {
|
||||
// 更新首充状态为已完成
|
||||
self.currentFirstRechargeData.chargeStatus = YES;
|
||||
|
||||
// 保存更新后的模型
|
||||
[self saveCachedModel:self.currentFirstRechargeData];
|
||||
|
||||
// 通知代理(如果需要)
|
||||
[self notifyDelegatesWithModel:self.currentFirstRechargeData shouldShow:NO];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Private Methods
|
||||
|
||||
- (void)setupDailyTimer {
|
||||
|
@@ -127,7 +127,7 @@
|
||||
"LoginBindPhoneViewController2" = "ربط رقم الجوال";
|
||||
|
||||
"MvpViewController0" = "وقت تسجيل الخروج: %@";
|
||||
"MvpViewController1" = "%@\n\nيرجى الاتصال بخدمة العملاء (WeChat: mxyz2050) للاستفسارات.";
|
||||
"MvpViewController1" = "%@\n\nيرجى الاتصال بخدمة العملاء للاستفسارات.";
|
||||
"MvpViewController2" = "تم تسجيل الخروج من هذا الحساب";
|
||||
"MvpViewController3" = "من أجل خلق بيئة عمل
|
||||
|
||||
@@ -2941,8 +2941,8 @@ ineHeadView12" = "الحمل";
|
||||
"LoginBindPhoneViewController2" = "ربط رقم الهاتف المحمول";
|
||||
|
||||
"MvpViewController0" = "وقت الإلغاء: %@";
|
||||
"MvpViewController1.1" = "@%\n\nيرجى الاتصال بخدمة العملاء (WeChat: mxyz2050) للحصول على استفسارات";
|
||||
"MvpViewController1.2" = "يرجى الاتصال بخدمة العملاء (WeChat: mxyz2050) للحصول على استفسارات";
|
||||
"MvpViewController1.1" = "@%\n\nيرجى الاتصال بخدمة العملاء للحصول على استفسارات";
|
||||
"MvpViewController1.2" = "يرجى الاتصال بخدمة العملاء للحصول على استفسارات";
|
||||
"MvpViewController3" = "من أجل خلق بيئة إنترنت آمنة أكثر\nحماية ممتلكاتك وممتلكات الآخرين\nيرجى تقديم التحقق الهوية أولا";
|
||||
|
||||
"MvpViewController5" = "التحقق من الهوية";
|
||||
|
@@ -2548,9 +2548,9 @@
|
||||
"LoginBindPhoneViewController2" = "Bind Mobile Number";
|
||||
|
||||
"MvpViewController0" = "Logoff time: %@";
|
||||
"MvpViewController1" = "%@\n\nPlease contact customer service (WeChat: mxyz2050) for inquiries.";
|
||||
"MvpViewController1.1" = "%@\n\nPlease contact customer service (WeChat: mxyz2050) for inquiries.";
|
||||
"MvpViewController1.2" = "Please contact customer service (WeChat: mxyz2050) for inquiries.";
|
||||
"MvpViewController1" = "%@\n\nPlease contact customer service for inquiries.";
|
||||
"MvpViewController1.1" = "%@\n\nPlease contact customer service for inquiries.";
|
||||
"MvpViewController1.2" = "Please contact customer service for inquiries.";
|
||||
"MvpViewController2" = "This account has been logged off";
|
||||
"MvpViewController3" = "In order to create a safer online environment\nand protect the property safety of you and others,\nplease complete real-name authentication first";
|
||||
|
||||
|
13
YuMi/pt-BR.lproj/InfoPlist.strings
Normal file
13
YuMi/pt-BR.lproj/InfoPlist.strings
Normal file
@@ -0,0 +1,13 @@
|
||||
NSCameraUsageDescription = "O \"MoliStar\" precisa do seu consentimento antes que você possa visitar, tirar fotos e enviar suas imagens, e depois exibi-las em sua página pessoal para que outros possam visualizar";
|
||||
|
||||
NSLocalNetworkUsageDescription = "O aplicativo irá descobrir e conectar-se a dispositivos em sua rede";
|
||||
|
||||
NSLocationWhenInUseUsageDescription = "O seu consentimento é necessário antes que você possa usar os serviços de localização e recomendar amigos próximos";
|
||||
|
||||
NSMicrophoneUsageDescription = "O \"MoliStar\" precisa do seu consentimento antes de poder realizar chat de voz";
|
||||
|
||||
NSPhotoLibraryAddUsageDescription = "O \"MoliStar\" precisa do seu consentimento antes de poder armazenar fotos no álbum";
|
||||
|
||||
NSPhotoLibraryUsageDescription = "O \"MoliStar\" precisa do seu consentimento antes que você possa acessar o álbum e selecionar as imagens que deseja enviar, e depois exibi-las em sua página pessoal para que outros possam visualizar";
|
||||
|
||||
NSUserTrackingUsageDescription = "Por favor, permita-nos obter sua permissão IDFA para fornecer a você atividades e serviços personalizados. Suas informações não serão usadas para outros fins sem a sua permissão";
|
3308
YuMi/pt-BR.lproj/Localizable.strings
Normal file
3308
YuMi/pt-BR.lproj/Localizable.strings
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2223,9 +2223,9 @@
|
||||
"LoginBindPhoneViewController2" = "Telefon numarasını bağla";
|
||||
|
||||
"MvpViewController0" = "Oturumu kapatma zamanı: %@";
|
||||
"MvpViewController1" = "%@\n\nMüşteri hizmetleriyle iletişime geçin (WeChat: mxyz2050) danışın";
|
||||
"MvpViewController1.1" = "%@\n\nMüşteri hizmetleriyle iletişime geçin (WeChat: mxyz2050) danışın";
|
||||
"MvpViewController1.2" = "Müşteri hizmetleriyle iletişime geçin (WeChat: mxyz2050) danışın";
|
||||
"MvpViewController1" = "%@\n\nMüşteri hizmetleriyle iletişime geçin danışın";
|
||||
"MvpViewController1.1" = "%@\n\nMüşteri hizmetleriyle iletişime geçin danışın";
|
||||
"MvpViewController1.2" = "Müşteri hizmetleriyle iletişime geçin danışın";
|
||||
"MvpViewController2" = "Bu hesap kapatıldı";
|
||||
"MvpViewController3" = "Daha güvenli bir ağ ortamı oluşturmak ve sizin ve diğerlerinin mülk güvenliğini korumak için\nlütfen önce kimlik doğrulaması yapın";
|
||||
|
||||
|
@@ -2263,8 +2263,8 @@
|
||||
"LoginBindPhoneViewController2" = "綁定手機號";
|
||||
|
||||
"MvpViewController0" = "註銷時間: %@";
|
||||
"MvpViewController1.1" = "%@\n\n請聯繫客服(微信:mxyz2050)咨詢哦";
|
||||
"MvpViewController1.2" = "請聯繫客服(微信:mxyz2050)咨詢哦";
|
||||
"MvpViewController1.1" = "%@\n\n請聯繫客服咨詢哦";
|
||||
"MvpViewController1.2" = "請聯繫客服咨詢哦";
|
||||
"MvpViewController2" = "該賬號已註銷";
|
||||
"MvpViewController3" = "為了營造更安全的網絡環境\n保護您和他人的財產安全\n請先進行實名認證";
|
||||
|
||||
|
@@ -1,85 +1,16 @@
|
||||
Pods/FBSDKCoreKit/XCFrameworks/FBSDKCoreKit.xcframework/tvos-arm64/FBSDKCoreKit.framework/FBSDKCoreKit
|
||||
Pods/FBSDKCoreKit/XCFrameworks/FBSDKCoreKit.xcframework/tvos-arm64_x86_64-simulator/FBSDKCoreKit.framework/FBSDKCoreKit
|
||||
Pods/FBSDKCoreKit/XCFrameworks/FBSDKCoreKit.xcframework/ios-arm64_x86_64-simulator/FBSDKCoreKit.framework/FBSDKCoreKit
|
||||
Pods/FBSDKCoreKit/XCFrameworks/FBSDKCoreKit.xcframework/ios-arm64_x86_64-maccatalyst/FBSDKCoreKit.framework/FBSDKCoreKit
|
||||
Pods/FBSDKCoreKit/XCFrameworks/FBSDKCoreKit.xcframework/ios-arm64/FBSDKCoreKit.framework/FBSDKCoreKit
|
||||
Pods/UMDevice/UMDevice_3.4.0/UMDevice.xcframework/ios-arm64_x86_64-simulator/UMDevice.framework/UMDevice
|
||||
Pods/UMDevice/UMDevice_3.4.0/UMDevice.xcframework/ios-arm64_armv7/UMDevice.framework/UMDevice
|
||||
Pods/mob_linksdk_pro/MobLinkPro/MobLinkPro.framework/MobLinkPro
|
||||
Pods/FBAEMKit/XCFrameworks/FBAEMKit.xcframework/tvos-arm64/FBAEMKit.framework/FBAEMKit
|
||||
Pods/FBAEMKit/XCFrameworks/FBAEMKit.xcframework/tvos-arm64_x86_64-simulator/FBAEMKit.framework/FBAEMKit
|
||||
Pods/FBAEMKit/XCFrameworks/FBAEMKit.xcframework/ios-arm64_x86_64-simulator/FBAEMKit.framework/FBAEMKit
|
||||
Pods/FBAEMKit/XCFrameworks/FBAEMKit.xcframework/ios-arm64_x86_64-maccatalyst/FBAEMKit.framework/FBAEMKit
|
||||
Pods/FBAEMKit/XCFrameworks/FBAEMKit.xcframework/ios-arm64/FBAEMKit.framework/FBAEMKit
|
||||
Pods/FBSDKLoginKit/XCFrameworks/FBSDKLoginKit.xcframework/tvos-arm64/FBSDKLoginKit.framework/FBSDKLoginKit
|
||||
Pods/FBSDKLoginKit/XCFrameworks/FBSDKLoginKit.xcframework/tvos-arm64_x86_64-simulator/FBSDKLoginKit.framework/FBSDKLoginKit
|
||||
Pods/FBSDKLoginKit/XCFrameworks/FBSDKLoginKit.xcframework/ios-arm64_x86_64-simulator/FBSDKLoginKit.framework/FBSDKLoginKit
|
||||
Pods/FBSDKLoginKit/XCFrameworks/FBSDKLoginKit.xcframework/ios-arm64_x86_64-maccatalyst/FBSDKLoginKit.framework/FBSDKLoginKit
|
||||
Pods/FBSDKLoginKit/XCFrameworks/FBSDKLoginKit.xcframework/ios-arm64/FBSDKLoginKit.framework/FBSDKLoginKit
|
||||
Pods/QCloudTrack/QCloudTrack/Classes/BeaconFramework/COSBeaconAPI_Base.framework/COSBeaconAPI_Base
|
||||
Pods/QCloudTrack/QCloudTrack/Classes/BeaconFramework/QimeiSDK.framework/QimeiSDK
|
||||
Pods/MOBFoundation/MOBFoundation/MOBFoundation.xcframework/ios-arm64/MOBFoundation.framework/MOBFoundation
|
||||
Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/FirebaseAnalytics
|
||||
Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/FirebaseAnalytics
|
||||
Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/FirebaseAnalytics
|
||||
Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/FirebaseAnalytics
|
||||
Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/FirebaseAnalytics
|
||||
Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/FirebaseAnalytics
|
||||
Pods/FBSDKCoreKit_Basics/XCFrameworks/FBSDKCoreKit_Basics.xcframework/tvos-arm64/FBSDKCoreKit_Basics.framework/FBSDKCoreKit_Basics
|
||||
Pods/FBSDKCoreKit_Basics/XCFrameworks/FBSDKCoreKit_Basics.xcframework/tvos-arm64_x86_64-simulator/FBSDKCoreKit_Basics.framework/FBSDKCoreKit_Basics
|
||||
Pods/FBSDKCoreKit_Basics/XCFrameworks/FBSDKCoreKit_Basics.xcframework/ios-arm64_x86_64-simulator/FBSDKCoreKit_Basics.framework/FBSDKCoreKit_Basics
|
||||
Pods/FBSDKCoreKit_Basics/XCFrameworks/FBSDKCoreKit_Basics.xcframework/ios-arm64_x86_64-maccatalyst/FBSDKCoreKit_Basics.framework/FBSDKCoreKit_Basics
|
||||
Pods/FBSDKCoreKit_Basics/XCFrameworks/FBSDKCoreKit_Basics.xcframework/ios-arm64/FBSDKCoreKit_Basics.framework/FBSDKCoreKit_Basics
|
||||
Pods/mob_sharesdk/ShareSDK/Support/Required/ShareSDKConnector.framework/ShareSDKConnector
|
||||
Pods/mob_sharesdk/ShareSDK/Support/Optional/ShareSDKExtension.framework/ShareSDKExtension
|
||||
Pods/mob_sharesdk/ShareSDK/Support/PlatformConnector/AppleAccountConnector.framework/AppleAccountConnector
|
||||
Pods/mob_sharesdk/ShareSDK/ShareSDK.framework/ShareSDK
|
||||
Pods/QCloudTrack/QCloudTrack/Classes/BeaconFramework/COSBeaconAPI_Base.xcframework/ios-arm64_i386_x86_64-simulator/COSBeaconAPI_Base.framework/COSBeaconAPI_Base
|
||||
Pods/QCloudTrack/QCloudTrack/Classes/BeaconFramework/COSBeaconAPI_Base.xcframework/ios-arm64_x86_64-maccatalyst/COSBeaconAPI_Base.framework/COSBeaconAPI_Base
|
||||
Pods/QCloudTrack/QCloudTrack/Classes/BeaconFramework/COSBeaconAPI_Base.xcframework/ios-arm64_armv7/COSBeaconAPI_Base.framework/COSBeaconAPI_Base
|
||||
Pods/mob_sharesdk/ShareSDK/Support/Required/ShareSDKConnector.xcframework/ios-arm64_x86_64-simulator/ShareSDKConnector.framework/ShareSDKConnector
|
||||
Pods/mob_sharesdk/ShareSDK/Support/Required/ShareSDKConnector.xcframework/ios-arm64/ShareSDKConnector.framework/ShareSDKConnector
|
||||
Pods/Bugly/Bugly.framework/Bugly
|
||||
Pods/FBSDKShareKit/XCFrameworks/FBSDKShareKit.xcframework/tvos-arm64/FBSDKShareKit.framework/FBSDKShareKit
|
||||
Pods/FBSDKShareKit/XCFrameworks/FBSDKShareKit.xcframework/tvos-arm64_x86_64-simulator/FBSDKShareKit.framework/FBSDKShareKit
|
||||
Pods/FBSDKShareKit/XCFrameworks/FBSDKShareKit.xcframework/ios-arm64_x86_64-simulator/FBSDKShareKit.framework/FBSDKShareKit
|
||||
Pods/FBSDKShareKit/XCFrameworks/FBSDKShareKit.xcframework/ios-arm64_x86_64-maccatalyst/FBSDKShareKit.framework/FBSDKShareKit
|
||||
Pods/FBSDKShareKit/XCFrameworks/FBSDKShareKit.xcframework/ios-arm64/FBSDKShareKit.framework/FBSDKShareKit
|
||||
./Pods/FBSDKCoreKit/XCFrameworks/FBSDKCoreKit.xcframework/tvos-arm64/FBSDKCoreKit.framework/FBSDKCoreKit
|
||||
./Pods/FBSDKCoreKit/XCFrameworks/FBSDKCoreKit.xcframework/tvos-arm64_x86_64-simulator/FBSDKCoreKit.framework/FBSDKCoreKit
|
||||
./Pods/FBSDKCoreKit/XCFrameworks/FBSDKCoreKit.xcframework/ios-arm64_x86_64-simulator/FBSDKCoreKit.framework/FBSDKCoreKit
|
||||
./Pods/FBSDKCoreKit/XCFrameworks/FBSDKCoreKit.xcframework/ios-arm64_x86_64-maccatalyst/FBSDKCoreKit.framework/FBSDKCoreKit
|
||||
./Pods/FBSDKCoreKit/XCFrameworks/FBSDKCoreKit.xcframework/ios-arm64/FBSDKCoreKit.framework/FBSDKCoreKit
|
||||
./Pods/UMDevice/UMDevice_3.4.0/UMDevice.xcframework/ios-arm64_x86_64-simulator/UMDevice.framework/UMDevice
|
||||
./Pods/UMDevice/UMDevice_3.4.0/UMDevice.xcframework/ios-arm64_armv7/UMDevice.framework/UMDevice
|
||||
./Pods/mob_linksdk_pro/MobLinkPro/MobLinkPro.framework/MobLinkPro
|
||||
./Pods/FBAEMKit/XCFrameworks/FBAEMKit.xcframework/tvos-arm64/FBAEMKit.framework/FBAEMKit
|
||||
./Pods/FBAEMKit/XCFrameworks/FBAEMKit.xcframework/tvos-arm64_x86_64-simulator/FBAEMKit.framework/FBAEMKit
|
||||
./Pods/FBAEMKit/XCFrameworks/FBAEMKit.xcframework/ios-arm64_x86_64-simulator/FBAEMKit.framework/FBAEMKit
|
||||
./Pods/FBAEMKit/XCFrameworks/FBAEMKit.xcframework/ios-arm64_x86_64-maccatalyst/FBAEMKit.framework/FBAEMKit
|
||||
./Pods/FBAEMKit/XCFrameworks/FBAEMKit.xcframework/ios-arm64/FBAEMKit.framework/FBAEMKit
|
||||
./Pods/FBSDKLoginKit/XCFrameworks/FBSDKLoginKit.xcframework/tvos-arm64/FBSDKLoginKit.framework/FBSDKLoginKit
|
||||
./Pods/FBSDKLoginKit/XCFrameworks/FBSDKLoginKit.xcframework/tvos-arm64_x86_64-simulator/FBSDKLoginKit.framework/FBSDKLoginKit
|
||||
./Pods/FBSDKLoginKit/XCFrameworks/FBSDKLoginKit.xcframework/ios-arm64_x86_64-simulator/FBSDKLoginKit.framework/FBSDKLoginKit
|
||||
./Pods/FBSDKLoginKit/XCFrameworks/FBSDKLoginKit.xcframework/ios-arm64_x86_64-maccatalyst/FBSDKLoginKit.framework/FBSDKLoginKit
|
||||
./Pods/FBSDKLoginKit/XCFrameworks/FBSDKLoginKit.xcframework/ios-arm64/FBSDKLoginKit.framework/FBSDKLoginKit
|
||||
./Pods/QCloudTrack/QCloudTrack/Classes/BeaconFramework/COSBeaconAPI_Base.framework/COSBeaconAPI_Base
|
||||
./Pods/QCloudTrack/QCloudTrack/Classes/BeaconFramework/QimeiSDK.framework/QimeiSDK
|
||||
./Pods/MOBFoundation/MOBFoundation/MOBFoundation.xcframework/ios-arm64/MOBFoundation.framework/MOBFoundation
|
||||
./Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/FirebaseAnalytics
|
||||
./Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/FirebaseAnalytics
|
||||
./Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/FirebaseAnalytics
|
||||
./Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/FirebaseAnalytics
|
||||
./Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/FirebaseAnalytics
|
||||
./Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/FirebaseAnalytics
|
||||
./Pods/FBSDKCoreKit_Basics/XCFrameworks/FBSDKCoreKit_Basics.xcframework/tvos-arm64/FBSDKCoreKit_Basics.framework/FBSDKCoreKit_Basics
|
||||
./Pods/FBSDKCoreKit_Basics/XCFrameworks/FBSDKCoreKit_Basics.xcframework/tvos-arm64_x86_64-simulator/FBSDKCoreKit_Basics.framework/FBSDKCoreKit_Basics
|
||||
./Pods/FBSDKCoreKit_Basics/XCFrameworks/FBSDKCoreKit_Basics.xcframework/ios-arm64_x86_64-simulator/FBSDKCoreKit_Basics.framework/FBSDKCoreKit_Basics
|
||||
./Pods/FBSDKCoreKit_Basics/XCFrameworks/FBSDKCoreKit_Basics.xcframework/ios-arm64_x86_64-maccatalyst/FBSDKCoreKit_Basics.framework/FBSDKCoreKit_Basics
|
||||
./Pods/FBSDKCoreKit_Basics/XCFrameworks/FBSDKCoreKit_Basics.xcframework/ios-arm64/FBSDKCoreKit_Basics.framework/FBSDKCoreKit_Basics
|
||||
./Pods/mob_sharesdk/ShareSDK/Support/Required/ShareSDKConnector.framework/ShareSDKConnector
|
||||
./Pods/mob_sharesdk/ShareSDK/Support/Optional/ShareSDKExtension.framework/ShareSDKExtension
|
||||
./Pods/mob_sharesdk/ShareSDK/Support/PlatformConnector/AppleAccountConnector.framework/AppleAccountConnector
|
||||
./Pods/mob_sharesdk/ShareSDK/ShareSDK.framework/ShareSDK
|
||||
./Pods/QCloudTrack/QCloudTrack/Classes/BeaconFramework/COSBeaconAPI_Base.xcframework/ios-arm64_i386_x86_64-simulator/COSBeaconAPI_Base.framework/COSBeaconAPI_Base
|
||||
./Pods/QCloudTrack/QCloudTrack/Classes/BeaconFramework/COSBeaconAPI_Base.xcframework/ios-arm64_x86_64-maccatalyst/COSBeaconAPI_Base.framework/COSBeaconAPI_Base
|
||||
./Pods/QCloudTrack/QCloudTrack/Classes/BeaconFramework/COSBeaconAPI_Base.xcframework/ios-arm64_armv7/COSBeaconAPI_Base.framework/COSBeaconAPI_Base
|
||||
./Pods/mob_sharesdk/ShareSDK/Support/Required/ShareSDKConnector.xcframework/ios-arm64_x86_64-simulator/ShareSDKConnector.framework/ShareSDKConnector
|
||||
./Pods/mob_sharesdk/ShareSDK/Support/Required/ShareSDKConnector.xcframework/ios-arm64/ShareSDKConnector.framework/ShareSDKConnector
|
||||
./Pods/Bugly/Bugly.framework/Bugly
|
||||
./Pods/FBSDKShareKit/XCFrameworks/FBSDKShareKit.xcframework/tvos-arm64/FBSDKShareKit.framework/FBSDKShareKit
|
||||
./Pods/FBSDKShareKit/XCFrameworks/FBSDKShareKit.xcframework/tvos-arm64_x86_64-simulator/FBSDKShareKit.framework/FBSDKShareKit
|
||||
./Pods/FBSDKShareKit/XCFrameworks/FBSDKShareKit.xcframework/ios-arm64_x86_64-simulator/FBSDKShareKit.framework/FBSDKShareKit
|
||||
./Pods/FBSDKShareKit/XCFrameworks/FBSDKShareKit.xcframework/ios-arm64_x86_64-maccatalyst/FBSDKShareKit.framework/FBSDKShareKit
|
||||
./Pods/FBSDKShareKit/XCFrameworks/FBSDKShareKit.xcframework/ios-arm64/FBSDKShareKit.framework/FBSDKShareKit
|
||||
./YuMi/Modules/YMRTC/Library/ZegoAudioRoom.framework/ZegoAudioRoom
|
||||
|
Reference in New Issue
Block a user