1
This commit is contained in:
@@ -34,6 +34,7 @@
|
||||
#define KB_API_CHARACTER_LISTBYUSER @"/character/listByUser" // 用户人设列表
|
||||
#define API_CHARACTER_UPDATE_USER_CHARTSORT @"/character/updateUserCharacterSort" // 更新用户人设排序
|
||||
#define API_CHARACTER_DEL_USER_CHARACTER @"/character/delUserCharacter" // 删除用户人设
|
||||
#define API_CHARACTER_ADD_USER_CHARACTER @"/character/addUserCharacter" // 添加用户人设(假定路径,如有不同请按后端实际修改)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
/// "rank" : 899
|
||||
/// }
|
||||
@interface KBCharacter : NSObject
|
||||
/// 首页用的ID(也是人设ID)
|
||||
@property (nonatomic, copy, nullable) NSString *ID;
|
||||
|
||||
/// 唯一标识,对应后端的 id
|
||||
@property (nonatomic, copy, nullable) NSString *characterId;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
// 后端字段映射到本地属性
|
||||
return @{
|
||||
// id -> characterId
|
||||
@"characterId": @"id",
|
||||
@"ID": @"id",
|
||||
// 名称字段:优先 characterName,兼容部分接口可能返回 title
|
||||
@"characterName": @[@"characterName", @"title"],
|
||||
};
|
||||
|
||||
@@ -15,6 +15,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
/// 当前展示的排行榜角色模型
|
||||
@property (nonatomic, strong, nullable) KBCharacter *character;
|
||||
|
||||
/// 点击右侧加号/勾选按钮的回调,由外部 VC 处理网络逻辑
|
||||
@property (nonatomic, copy, nullable) void (^onTapAction)(void);
|
||||
|
||||
/// 旧的配置方法(不再推荐使用),内部会转成 character 赋值
|
||||
- (void)configWithRank:(NSInteger)rank
|
||||
title:(NSString *)title
|
||||
|
||||
@@ -70,6 +70,12 @@
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)actionButtonTapped {
|
||||
if (self.onTapAction) {
|
||||
self.onTapAction();
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setCharacter:(KBCharacter *)character {
|
||||
_character = character;
|
||||
|
||||
@@ -94,6 +100,8 @@
|
||||
[self.actionButton setTitleColor:[UIColor colorWithRed:0.20 green:0.65 blue:0.50 alpha:1.0] forState:UIControlStateNormal];
|
||||
self.actionButton.backgroundColor = [UIColor colorWithRed:0.88 green:0.97 blue:0.93 alpha:1.0];
|
||||
}
|
||||
// 已加入后禁用按钮,避免重复添加或取消
|
||||
self.actionButton.enabled = !joined;
|
||||
}
|
||||
|
||||
// 兼容旧调用:转成一个临时模型再走统一逻辑
|
||||
@@ -111,6 +119,7 @@
|
||||
[self.avatarView kb_cancelImageLoad];
|
||||
self.avatarView.image = nil;
|
||||
self.character = nil;
|
||||
self.onTapAction = nil;
|
||||
}
|
||||
|
||||
#pragma mark - Lazy
|
||||
@@ -170,6 +179,7 @@
|
||||
_actionButton.layer.cornerRadius = 12;
|
||||
_actionButton.layer.masksToBounds = YES;
|
||||
_actionButton.titleLabel.font = [UIFont systemFontOfSize:20 weight:UIFontWeightBold];
|
||||
[_actionButton addTarget:self action:@selector(actionButtonTapped) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _actionButton;
|
||||
}
|
||||
|
||||
@@ -127,6 +127,8 @@
|
||||
[self.actionBtn setTitle:@"+" forState:UIControlStateNormal];
|
||||
[self.actionBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
|
||||
}
|
||||
// 已添加后禁用按钮(不可再次点击)
|
||||
self.actionBtn.enabled = !added;
|
||||
}
|
||||
|
||||
#pragma mark - Lazy UI
|
||||
|
||||
@@ -16,6 +16,13 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
/// 使用前三名角色模型进行配置(数组元素为 KBCharacter*,最多取前三个)
|
||||
- (void)configWithCharacters:(NSArray<KBCharacter *> *)characters;
|
||||
|
||||
/// 中间卡片底部加号按钮点击回调(传入对应角色模型,可能为 nil)
|
||||
@property (nonatomic, copy, nullable) void (^onCenterPlusTapped)(KBCharacter * _Nullable character);
|
||||
/// 左侧卡片底部加号按钮点击回调
|
||||
@property (nonatomic, copy, nullable) void (^onLeftPlusTapped)(KBCharacter * _Nullable character);
|
||||
/// 右侧卡片底部加号按钮点击回调
|
||||
@property (nonatomic, copy, nullable) void (^onRightPlusTapped)(KBCharacter * _Nullable character);
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -135,6 +135,10 @@
|
||||
/// 左右卡片底部也有 plus 按钮
|
||||
@property (nonatomic, strong) UIButton *leftPlusButton;
|
||||
@property (nonatomic, strong) UIButton *rightPlusButton;
|
||||
/// 对应的前三名角色模型(用于回调和状态控制)
|
||||
@property (nonatomic, strong, nullable) KBCharacter *firstCharacter;
|
||||
@property (nonatomic, strong, nullable) KBCharacter *secondCharacter;
|
||||
@property (nonatomic, strong, nullable) KBCharacter *thirdCharacter;
|
||||
@end
|
||||
|
||||
@implementation KBTopThreeView
|
||||
@@ -203,21 +207,78 @@
|
||||
}
|
||||
|
||||
- (void)configWithCharacters:(NSArray<KBCharacter *> *)characters {
|
||||
if (characters.count == 0) {
|
||||
// 无数据时清空标题与头像
|
||||
self.firstCharacter = characters.count > 0 ? characters[0] : nil;
|
||||
self.secondCharacter = characters.count > 1 ? characters[1] : nil;
|
||||
self.thirdCharacter = characters.count > 2 ? characters[2] : nil;
|
||||
|
||||
if (self.firstCharacter) {
|
||||
[self.centerCard renderWithCharacter:self.firstCharacter rank:1];
|
||||
} else {
|
||||
[self.centerCard renderWithCharacter:[KBCharacter new] rank:1];
|
||||
[self.leftCard renderWithCharacter:[KBCharacter new] rank:2];
|
||||
[self.rightCard renderWithCharacter:[KBCharacter new] rank:3];
|
||||
return;
|
||||
}
|
||||
|
||||
KBCharacter *first = characters.count > 0 ? characters[0] : nil;
|
||||
KBCharacter *second = characters.count > 1 ? characters[1] : nil;
|
||||
KBCharacter *third = characters.count > 2 ? characters[2] : nil;
|
||||
if (self.secondCharacter) {
|
||||
[self.leftCard renderWithCharacter:self.secondCharacter rank:2];
|
||||
} else {
|
||||
[self.leftCard renderWithCharacter:[KBCharacter new] rank:2];
|
||||
}
|
||||
|
||||
if (first) [self.centerCard renderWithCharacter:first rank:1];
|
||||
if (second) [self.leftCard renderWithCharacter:second rank:2];
|
||||
if (third) [self.rightCard renderWithCharacter:third rank:3];
|
||||
if (self.thirdCharacter) {
|
||||
[self.rightCard renderWithCharacter:self.thirdCharacter rank:3];
|
||||
} else {
|
||||
[self.rightCard renderWithCharacter:[KBCharacter new] rank:3];
|
||||
}
|
||||
|
||||
// 根据 added 状态刷新三个加号按钮的 UI 和可点击状态
|
||||
[self updatePlusButtonsState];
|
||||
}
|
||||
|
||||
- (void)onCenterPlusTappedInternal {
|
||||
if (self.onCenterPlusTapped) {
|
||||
self.onCenterPlusTapped(self.firstCharacter);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)onLeftPlusTappedInternal {
|
||||
if (self.onLeftPlusTapped) {
|
||||
self.onLeftPlusTapped(self.secondCharacter);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)onRightPlusTappedInternal {
|
||||
if (self.onRightPlusTapped) {
|
||||
self.onRightPlusTapped(self.thirdCharacter);
|
||||
}
|
||||
}
|
||||
|
||||
/// 根据角色是否已添加,更新三个底部按钮的文案与状态
|
||||
- (void)updatePlusButtonsState {
|
||||
[self updatePlusButton:self.plusButton withCharacter:self.firstCharacter];
|
||||
[self updatePlusButton:self.leftPlusButton withCharacter:self.secondCharacter];
|
||||
[self updatePlusButton:self.rightPlusButton withCharacter:self.thirdCharacter];
|
||||
}
|
||||
|
||||
- (void)updatePlusButton:(UIButton *)button withCharacter:(KBCharacter * _Nullable)character {
|
||||
if (!character) {
|
||||
button.hidden = YES;
|
||||
return;
|
||||
}
|
||||
button.hidden = NO;
|
||||
|
||||
BOOL added = character.added;
|
||||
if (added) {
|
||||
// 已添加:灰色背景 + 勾选,且禁用点击
|
||||
[button setTitle:@"✓" forState:UIControlStateNormal];
|
||||
[button setTitleColor:[UIColor colorWithWhite:0.45 alpha:1.0] forState:UIControlStateNormal];
|
||||
button.backgroundColor = [UIColor colorWithWhite:0.92 alpha:1.0];
|
||||
button.enabled = NO;
|
||||
} else {
|
||||
// 未添加:绿色加号,可点击
|
||||
[button setTitle:@"+" forState:UIControlStateNormal];
|
||||
[button setTitleColor:[UIColor colorWithRed:0.20 green:0.65 blue:0.50 alpha:1.0] forState:UIControlStateNormal];
|
||||
button.backgroundColor = [[UIColor colorWithRed:0.20 green:0.65 blue:0.50 alpha:1.0] colorWithAlphaComponent:0.15];
|
||||
button.enabled = YES;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Lazy
|
||||
@@ -235,6 +296,7 @@
|
||||
_plusButton.layer.masksToBounds = YES;
|
||||
// 默认浅色背景,可按需要在外层配置
|
||||
_plusButton.backgroundColor = [[UIColor colorWithRed:0.20 green:0.65 blue:0.50 alpha:1.0] colorWithAlphaComponent:0.15];
|
||||
[_plusButton addTarget:self action:@selector(onCenterPlusTappedInternal) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _plusButton;
|
||||
}
|
||||
@@ -248,6 +310,7 @@
|
||||
_leftPlusButton.layer.cornerRadius = 14.0;
|
||||
_leftPlusButton.layer.masksToBounds = YES;
|
||||
_leftPlusButton.backgroundColor = [[UIColor colorWithRed:0.20 green:0.65 blue:0.50 alpha:1.0] colorWithAlphaComponent:0.15];
|
||||
[_leftPlusButton addTarget:self action:@selector(onLeftPlusTappedInternal) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _leftPlusButton;
|
||||
}
|
||||
@@ -261,6 +324,7 @@
|
||||
_rightPlusButton.layer.cornerRadius = 14.0;
|
||||
_rightPlusButton.layer.masksToBounds = YES;
|
||||
_rightPlusButton.backgroundColor = [[UIColor colorWithRed:0.20 green:0.65 blue:0.50 alpha:1.0] colorWithAlphaComponent:0.15];
|
||||
[_rightPlusButton addTarget:self action:@selector(onRightPlusTappedInternal) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _rightPlusButton;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#import "LSTPopView.h"
|
||||
#import <HWPanModal/HWPanModal.h>
|
||||
#import "KBMyVM.h" // 用户人设变更通知
|
||||
#import "KBHUD.h"
|
||||
|
||||
@interface HomeHotVC () <UITableViewDataSource, UITableViewDelegate>
|
||||
|
||||
@@ -52,6 +53,18 @@
|
||||
self.topThreeView = [[KBTopThreeView alloc] initWithFrame:CGRectMake(0, 0, KB_SCREEN_WIDTH, headerH)];
|
||||
self.tableView.tableHeaderView = self.topThreeView;
|
||||
|
||||
KBWeakSelf
|
||||
// 顶部三名区域的三个加号按钮:添加人设
|
||||
self.topThreeView.onCenterPlusTapped = ^(KBCharacter * _Nullable character) {
|
||||
[weakSelf kb_addUserCharacterFromTopViewWithCharacter:character];
|
||||
};
|
||||
self.topThreeView.onLeftPlusTapped = ^(KBCharacter * _Nullable character) {
|
||||
[weakSelf kb_addUserCharacterFromTopViewWithCharacter:character];
|
||||
};
|
||||
self.topThreeView.onRightPlusTapped = ^(KBCharacter * _Nullable character) {
|
||||
[weakSelf kb_addUserCharacterFromTopViewWithCharacter:character];
|
||||
};
|
||||
|
||||
// 请求排行榜数据
|
||||
self.homeVM = [KBHomeVM new];
|
||||
[self kb_reloadRankListWithShowHUD:YES];
|
||||
@@ -79,21 +92,9 @@
|
||||
}
|
||||
weakSelf.allCharacters = list ?: @[];
|
||||
|
||||
// 顶部前三名数据:直接取前三个模型交给 KBTopThreeView
|
||||
NSInteger topCount = MIN(3, weakSelf.allCharacters.count);
|
||||
if (topCount > 0) {
|
||||
NSRange range = NSMakeRange(0, topCount);
|
||||
NSArray<KBCharacter *> *topThree = [weakSelf.allCharacters subarrayWithRange:range];
|
||||
[weakSelf.topThreeView configWithCharacters:topThree];
|
||||
}
|
||||
|
||||
// 列表部分:从第 4 名开始
|
||||
if (weakSelf.allCharacters.count > 3) {
|
||||
NSRange range = NSMakeRange(3, weakSelf.allCharacters.count - 3);
|
||||
weakSelf.listCharacters = [weakSelf.allCharacters subarrayWithRange:range];
|
||||
} else {
|
||||
weakSelf.listCharacters = @[];
|
||||
}
|
||||
// 根据最新数据刷新顶部前三名与列表部分
|
||||
[weakSelf kb_refreshTopThreeView];
|
||||
[weakSelf kb_refreshListCharacters];
|
||||
[weakSelf.tableView reloadData];
|
||||
|
||||
// 通知承载 HomeHotVC 的“外层 PanModal 容器”刷新布局。
|
||||
@@ -129,7 +130,7 @@
|
||||
|
||||
BOOL contains = NO;
|
||||
for (KBCharacter *c in self.allCharacters) {
|
||||
if (c.characterId.integerValue == targetId) {
|
||||
if (c.ID.integerValue == targetId) {
|
||||
contains = YES;
|
||||
break;
|
||||
}
|
||||
@@ -140,6 +141,52 @@
|
||||
[self kb_reloadRankListWithShowHUD:NO];
|
||||
}
|
||||
|
||||
/// 根据当前 allCharacters 刷新顶部前三名区域
|
||||
- (void)kb_refreshTopThreeView {
|
||||
NSInteger topCount = MIN(3, self.allCharacters.count);
|
||||
if (topCount > 0) {
|
||||
NSRange range = NSMakeRange(0, topCount);
|
||||
NSArray<KBCharacter *> *topThree = [self.allCharacters subarrayWithRange:range];
|
||||
[self.topThreeView configWithCharacters:topThree];
|
||||
} else {
|
||||
[self.topThreeView configWithCharacters:@[]];
|
||||
}
|
||||
}
|
||||
|
||||
/// 根据当前 allCharacters 刷新列表区域(第 4 名及以后)
|
||||
- (void)kb_refreshListCharacters {
|
||||
if (self.allCharacters.count > 3) {
|
||||
NSRange range = NSMakeRange(3, self.allCharacters.count - 3);
|
||||
self.listCharacters = [self.allCharacters subarrayWithRange:range];
|
||||
} else {
|
||||
self.listCharacters = @[];
|
||||
}
|
||||
}
|
||||
|
||||
/// 顶部三名区域点击“+”添加人设
|
||||
- (void)kb_addUserCharacterFromTopViewWithCharacter:(KBCharacter * _Nullable)character {
|
||||
if (!character || character.added) { return; }
|
||||
|
||||
NSString *cidStr = character.ID ?: @"";
|
||||
if (cidStr.length == 0) { return; }
|
||||
NSNumber *cid = @([cidStr integerValue]);
|
||||
|
||||
[self.homeVM addUserCharacterWithId:cid
|
||||
completion:^(BOOL success, NSError * _Nullable error) {
|
||||
if (!success) {
|
||||
NSString *msg = error.localizedDescription ?: KBLocalized(@"Network error");
|
||||
[KBHUD showInfo:msg];
|
||||
return;
|
||||
}
|
||||
|
||||
// 添加成功:更新模型状态
|
||||
character.added = YES;
|
||||
// 刷新顶部与列表 UI
|
||||
[self kb_refreshTopThreeView];
|
||||
[self.tableView reloadData];
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - UITableViewDataSource
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
@@ -151,6 +198,44 @@
|
||||
KBCharacter *item = self.listCharacters[indexPath.row];
|
||||
// 直接把模型交给 cell,由 cell 自己负责展示
|
||||
cell.character = item;
|
||||
KBWeakSelf
|
||||
__weak typeof(cell) weakCell = cell;
|
||||
cell.onTapAction = ^{
|
||||
__strong typeof(weakSelf) self = weakSelf;
|
||||
HomeHotCell *strongCell = weakCell;
|
||||
if (!self || !strongCell) { return; }
|
||||
|
||||
NSIndexPath *current = [self.tableView indexPathForCell:strongCell];
|
||||
if (!current) { return; }
|
||||
if (current.row >= self.listCharacters.count) { return; }
|
||||
|
||||
KBCharacter *mc = self.listCharacters[current.row];
|
||||
// 已添加状态下不允许再次点击
|
||||
if (mc.added) { return; }
|
||||
|
||||
NSString *cidStr = mc.ID ?: @"";
|
||||
if (cidStr.length == 0) { return; }
|
||||
NSNumber *cid = @([cidStr integerValue]);
|
||||
|
||||
[self.homeVM addUserCharacterWithId:cid
|
||||
completion:^(BOOL success, NSError * _Nullable error) {
|
||||
if (!success) {
|
||||
NSString *msg = error.localizedDescription ?: KBLocalized(@"Network error");
|
||||
[KBHUD showInfo:msg];
|
||||
return;
|
||||
}
|
||||
|
||||
// 添加成功:更新模型状态并刷新当前行(按钮变为已添加且不可再点)
|
||||
mc.added = YES;
|
||||
NSMutableArray *m = [self.listCharacters mutableCopy];
|
||||
[m replaceObjectAtIndex:current.row withObject:mc];
|
||||
self.listCharacters = [m copy];
|
||||
[self.tableView reloadRowsAtIndexPaths:@[current] withRowAnimation:UITableViewRowAnimationNone];
|
||||
|
||||
// 同步更新顶部前三名的展示状态
|
||||
[self kb_refreshTopThreeView];
|
||||
}];
|
||||
};
|
||||
return cell;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#import "HomeRankCardCell.h"
|
||||
#import "KBHomeVM.h"
|
||||
#import "KBCharacter.h"
|
||||
#import "KBHUD.h"
|
||||
#import "KBMyVM.h" // 引入用户人设变更通知
|
||||
|
||||
@interface HomeRankContentVC ()
|
||||
@@ -88,7 +89,7 @@
|
||||
|
||||
BOOL contains = NO;
|
||||
for (KBCharacter *c in self.characters) {
|
||||
if (c.characterId.integerValue == targetId) {
|
||||
if (c.ID.integerValue == targetId) {
|
||||
contains = YES;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,10 @@ typedef void(^KBHomeRankCompletion)(NSArray<KBCharacter *> * _Nullable list,
|
||||
typedef void(^KBHomeTagCompletion)(NSArray<KBTag *> * _Nullable list,
|
||||
NSError * _Nullable error);
|
||||
|
||||
/// 添加用户人设回调
|
||||
typedef void(^KBHomeAddUserCharacterCompletion)(BOOL success,
|
||||
NSError * _Nullable error);
|
||||
|
||||
@interface KBHomeVM : NSObject
|
||||
|
||||
/// 最近一次成功请求到的排行榜数据
|
||||
@@ -51,6 +55,11 @@ typedef void(^KBHomeTagCompletion)(NSArray<KBTag *> * _Nullable list,
|
||||
needShow:(BOOL)needShow
|
||||
completion:(KBHomeTagCompletion)completion;
|
||||
|
||||
/// 添加用户人设(例如在首页排行榜中点 “+”)
|
||||
/// GET /character/addUserCharacter?id={characterId}
|
||||
- (void)addUserCharacterWithId:(NSNumber *)characterId
|
||||
completion:(KBHomeAddUserCharacterCompletion)completion;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#import "KBNetworkManager.h"
|
||||
#import "KBHUD.h"
|
||||
#import "KBBizCode.h"
|
||||
#import "KBAPI.h"
|
||||
|
||||
@interface KBHomeVM ()
|
||||
@property (nonatomic, copy, readwrite, nullable) NSArray<KBCharacter *> *rankList;
|
||||
@@ -170,4 +171,36 @@
|
||||
}];
|
||||
}
|
||||
|
||||
/// 添加用户人设
|
||||
- (void)addUserCharacterWithId:(NSNumber *)characterId
|
||||
completion:(KBHomeAddUserCharacterCompletion)completion {
|
||||
if (!characterId) {
|
||||
if (completion) {
|
||||
NSError *e = [NSError errorWithDomain:KBNetworkErrorDomain
|
||||
code:KBNetworkErrorInvalidResponse
|
||||
userInfo:@{NSLocalizedDescriptionKey: KBLocalized(@"Invalid parameter")}];
|
||||
completion(NO, e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
NSDictionary *params = @{@"characterId": characterId};
|
||||
// [[KBNetworkManager shared] GET:API_CHARACTER_ADD_USER_CHARACTER
|
||||
// parameters:params
|
||||
// headers:nil
|
||||
// autoShowBusinessError:YES
|
||||
// completion:^(NSDictionary *jsonOrData,
|
||||
// NSURLResponse * _Nullable response,
|
||||
// NSError * _Nullable error) {
|
||||
// if (completion) {
|
||||
// completion(error == nil, error);
|
||||
// }
|
||||
// }];
|
||||
[[KBNetworkManager shared] POST:API_CHARACTER_ADD_USER_CHARACTER jsonBody:params headers:nil autoShowBusinessError:false completion:^(NSDictionary * _Nullable json, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
if (completion) {
|
||||
completion(error == nil, error);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
#import "KBEmailLoginVC.h"
|
||||
#import "KBEmailRegistVC.h"
|
||||
#import "KBForgetPwdVC.h"
|
||||
#import "KBLoginVM.h"
|
||||
#import "AppDelegate.h"
|
||||
#import "BaseTabBarController.h"
|
||||
@interface KBEmailLoginVC () <UITextViewDelegate, UITextFieldDelegate>
|
||||
|
||||
// 背景与顶部装饰
|
||||
@@ -41,6 +44,7 @@
|
||||
@property (nonatomic, strong) UITextView *agreementTextView;
|
||||
@property (nonatomic, strong) UILabel *accountTipLabel; // “Don't Have An Account?”
|
||||
@property (nonatomic, strong) UIButton *signUpButton; // “Sign Up”
|
||||
@property (nonatomic, strong) KBLoginVM *loginVM; // Confirm
|
||||
|
||||
@end
|
||||
|
||||
@@ -49,6 +53,7 @@
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
// 与登录/注册页一致:隐藏通用导航栏,使用自定义背景 + 返回按钮
|
||||
self.loginVM = [[KBLoginVM alloc] init];
|
||||
self.kb_enableCustomNavBar = NO;
|
||||
self.view.backgroundColor = [UIColor whiteColor];
|
||||
[self kb_addTapToDismissKeyboard];
|
||||
@@ -217,8 +222,27 @@
|
||||
|
||||
- (void)onTapSubmit {
|
||||
KBLOG(@"KBEmailLoginVC onTapSubmit, email=%@, pwdLen=%zd",
|
||||
self.emailTextField.text,
|
||||
self.emailTextField.text,
|
||||
self.passwordTextField.text.length);
|
||||
NSString *email = self.emailTextField.text ? self.emailTextField.text : @"";
|
||||
NSString *password = self.passwordTextField.text ? self.passwordTextField.text : @"";
|
||||
|
||||
[self.loginVM emailLoginEmail:email password:password WithCompletion:^(BOOL success, NSError * _Nullable error) {
|
||||
if (success) {
|
||||
id<UIApplicationDelegate> appDelegate = UIApplication.sharedApplication.delegate;
|
||||
if ([appDelegate respondsToSelector:@selector(setupRootVC)]) {
|
||||
AppDelegate *delegate = (AppDelegate *)appDelegate;
|
||||
// [delegate toMainTabbarVC];
|
||||
delegate.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
|
||||
delegate.window.backgroundColor = [UIColor whiteColor];
|
||||
[delegate.window makeKeyAndVisible];
|
||||
UIViewController *rootVC = nil;
|
||||
rootVC = [[BaseTabBarController alloc] init];
|
||||
delegate.window.rootViewController = rootVC;
|
||||
}
|
||||
}
|
||||
}];
|
||||
|
||||
}
|
||||
|
||||
- (void)onTapForgotPassword {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#import "KBLoginVM.h"
|
||||
#import "KBUser.h"
|
||||
#import "AppDelegate.h"
|
||||
#import "KBEmailLoginVC.h"
|
||||
|
||||
@interface KBRegistVerEmailVC ()
|
||||
|
||||
@@ -32,6 +33,11 @@
|
||||
[self kb_addTapToDismissKeyboard];
|
||||
|
||||
[self setupUI];
|
||||
// 获取验证码
|
||||
NSString *email = self.params[@"mailAddress"];
|
||||
[self.loginVM sendVerifyMailWithEmail:email withCompletion:^(BOOL success, NSError * _Nullable error) {
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - UI
|
||||
@@ -88,7 +94,7 @@
|
||||
return;
|
||||
}
|
||||
KBLOG(@"KBRegistVerEmailVC confirm with code=%@", code);
|
||||
self.params[@"code"] = code;
|
||||
self.params[@"verifyCode"] = code;
|
||||
NSNumber *genderNumber = [self kb_localGenderParamIfAvailable];
|
||||
if (genderNumber != nil) {
|
||||
self.params[@"gender"] = genderNumber;
|
||||
@@ -98,11 +104,20 @@
|
||||
[KBHUD showInfo:KBLocalized(@"Signed in successfully")];
|
||||
// 登录成功后切换到主 TabBar
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
id<UIApplicationDelegate> appDelegate = UIApplication.sharedApplication.delegate;
|
||||
if ([appDelegate respondsToSelector:@selector(setupRootVC)]) {
|
||||
AppDelegate *delegate = (AppDelegate *)appDelegate;
|
||||
[delegate toMainTabbarVC];
|
||||
}
|
||||
KBEmailLoginVC *vc = [[KBEmailLoginVC alloc] init];
|
||||
[KB_CURRENT_NAV pushViewController:vc animated:true];
|
||||
// id<UIApplicationDelegate> appDelegate = UIApplication.sharedApplication.delegate;
|
||||
// if ([appDelegate respondsToSelector:@selector(setupRootVC)]) {
|
||||
// AppDelegate *delegate = (AppDelegate *)appDelegate;
|
||||
//// [delegate toMainTabbarVC];
|
||||
// delegate.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
|
||||
// delegate.window.backgroundColor = [UIColor whiteColor];
|
||||
// [delegate.window makeKeyAndVisible];
|
||||
// UIViewController *rootVC = nil;
|
||||
// rootVC = [[BaseTabBarController alloc] init];
|
||||
// self.window.rootViewController = rootVC;
|
||||
// }
|
||||
|
||||
});
|
||||
} else {
|
||||
NSString *msg = error.localizedDescription ?: KBLocalized(@"Sign-in failed");
|
||||
|
||||
@@ -13,6 +13,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
/// 登录完成回调
|
||||
typedef void(^KBLoginCompletion)(BOOL success, NSError * _Nullable error);
|
||||
typedef void(^KBRegisterCompletion)(BOOL success, NSError * _Nullable error);
|
||||
typedef void(^KBVerifyMailCompletion)(BOOL success, NSError * _Nullable error);
|
||||
|
||||
@interface KBLoginVM : NSObject
|
||||
|
||||
@@ -30,6 +31,9 @@ typedef void(^KBRegisterCompletion)(BOOL success, NSError * _Nullable error);
|
||||
- (void)emailLoginEmail:(NSString *)email password:(NSString *)password WithCompletion:(KBLoginCompletion)completion;
|
||||
/// 邮箱注册
|
||||
- (void)emailRegisterParams:(NSDictionary *)params withCompletion:(KBRegisterCompletion)completion;
|
||||
/// 发送验证码
|
||||
- (void)sendVerifyMailWithEmail:(NSString *)email withCompletion:(KBVerifyMailCompletion)completion;
|
||||
|
||||
|
||||
/// 是否已登录:由 KBAuthManager 判断(是否存在有效 token)
|
||||
- (BOOL)isLoggedIn;
|
||||
|
||||
@@ -132,6 +132,20 @@
|
||||
}];
|
||||
}
|
||||
|
||||
/// 发送验证码
|
||||
- (void)sendVerifyMailWithEmail:(NSString *)email withCompletion:(KBVerifyMailCompletion)completion{
|
||||
NSMutableDictionary *params = [NSMutableDictionary dictionary];
|
||||
if (email.length) params[@"mailAddress"] = email;
|
||||
// [[KBNetworkManager shared] POST:API_EMAIL_REGISTER jsonBody:params headers:nil completion:^(NSDictionary * _Nullable jsonOrData, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
// if (error) { if (completion) completion(NO, error); return; }
|
||||
// [];
|
||||
// completion(true,nil);
|
||||
// }];
|
||||
[[KBNetworkManager shared] POST:API_EMAIL_REGISTER jsonBody:params headers:nil autoShowBusinessError:true completion:^(NSDictionary * _Nullable json, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Helpers
|
||||
|
||||
// 宽松解析:token / access_token / accessToken,支持顶层或 data/user 层
|
||||
|
||||
@@ -109,7 +109,9 @@ static NSString * const kKBMyKeyboardCellId = @"kKBMyKeyboardCellId";
|
||||
for (KBCharacter *c in characterArray) {
|
||||
NSString *emoji = c.emoji ?: @"";
|
||||
NSString *title = c.characterName ?: @"";
|
||||
NSString *identifier = c.characterId ?: @"";
|
||||
NSString *identifier = c.ID ?: @"";
|
||||
NSString *characterId = c.characterId ?: @"";
|
||||
|
||||
// 如果某条数据既没有 emoji 也没有标题,则忽略
|
||||
if (emoji.length == 0 && title.length == 0) {
|
||||
continue;
|
||||
@@ -117,6 +119,8 @@ static NSString * const kKBMyKeyboardCellId = @"kKBMyKeyboardCellId";
|
||||
NSMutableDictionary *item = [NSMutableDictionary dictionary];
|
||||
item[@"emoji"] = emoji;
|
||||
item[@"title"] = title;
|
||||
item[@"characterId"] = characterId;
|
||||
|
||||
if (identifier.length > 0) {
|
||||
// 用数字类型存储,便于直接作为 sort 数组上送
|
||||
NSInteger cid = identifier.integerValue;
|
||||
@@ -154,18 +158,21 @@ static NSString * const kKBMyKeyboardCellId = @"kKBMyKeyboardCellId";
|
||||
if (!tapIndexPath) { return; }
|
||||
|
||||
// 取出将要删除的人设 id
|
||||
NSNumber *characterId = nil;
|
||||
NSNumber *delId = nil; // 要删除的ID
|
||||
NSString *characterId = @""; // 通知其他页面要刷新的关联ID
|
||||
|
||||
if (tapIndexPath.section < self.dataSourceArray.count) {
|
||||
NSArray *section = self.dataSourceArray[tapIndexPath.section];
|
||||
if (tapIndexPath.item < section.count) {
|
||||
NSDictionary *item = section[tapIndexPath.item];
|
||||
id cid = item[@"id"];
|
||||
characterId = item[@"characterId"];
|
||||
if ([cid isKindOfClass:[NSNumber class]]) {
|
||||
characterId = (NSNumber *)cid;
|
||||
delId = (NSNumber *)cid;
|
||||
} else if ([cid isKindOfClass:[NSString class]]) {
|
||||
NSString *cidStr = (NSString *)cid;
|
||||
if (cidStr.length > 0) {
|
||||
characterId = @([cidStr integerValue]);
|
||||
delId = @([cidStr integerValue]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -181,7 +188,7 @@ static NSString * const kKBMyKeyboardCellId = @"kKBMyKeyboardCellId";
|
||||
if (!ok) { return; }
|
||||
|
||||
// 若无法获取 id,仅做本地删除以保持 UI 一致
|
||||
if (!characterId) {
|
||||
if (!delId) {
|
||||
if (tapIndexPath.section < self.dataSourceArray.count) {
|
||||
NSMutableArray *section = self.dataSourceArray[tapIndexPath.section];
|
||||
if (tapIndexPath.item < section.count) {
|
||||
@@ -196,7 +203,7 @@ static NSString * const kKBMyKeyboardCellId = @"kKBMyKeyboardCellId";
|
||||
|
||||
// 调用删除接口,成功后刷新界面
|
||||
__weak typeof(self) weakSelf2 = self;
|
||||
[self.viewModel deleteUserCharacterWithId:characterId
|
||||
[self.viewModel deleteUserCharacterWithId:delId
|
||||
completion:^(BOOL success, NSError * _Nullable error) {
|
||||
__strong typeof(weakSelf2) strongSelf = weakSelf2;
|
||||
if (!strongSelf) { return; }
|
||||
@@ -206,7 +213,13 @@ static NSString * const kKBMyKeyboardCellId = @"kKBMyKeyboardCellId";
|
||||
[KBHUD showInfo:msg];
|
||||
return;
|
||||
}
|
||||
|
||||
// 通知 App 内其他页面(如 HomeRankContentVC / HomeHotVC)该人设已被删除
|
||||
NSDictionary *info = @{@"characterId": characterId ?: @0};
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:KBUserCharacterDeletedNotification
|
||||
object:nil
|
||||
userInfo:info];
|
||||
});
|
||||
// 重新拉取用户人设列表,刷新 UI
|
||||
[strongSelf kb_reloadUserCharacters];
|
||||
}];
|
||||
|
||||
@@ -123,13 +123,7 @@ NSString * const KBUserCharacterDeletedNotification = @"KBUserCharacterDeletedNo
|
||||
BOOL success = (error == nil);
|
||||
|
||||
if (success) {
|
||||
// 通知 App 内其他页面(如 HomeRankContentVC / HomeHotVC)该人设已被删除
|
||||
NSDictionary *info = @{@"characterId": characterId ?: @0};
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:KBUserCharacterDeletedNotification
|
||||
object:nil
|
||||
userInfo:info];
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
if (completion) {
|
||||
|
||||
Reference in New Issue
Block a user