// // HomeHotVC.m // keyBoard // // Created by Mac on 2025/11/6. // #import "HomeHotVC.h" // 视图 #import "KBTopThreeView.h" #import "KBHomeVM.h" #import "KBCharacter.h" #import "HomeHotCell.h" #import "HomeRankVC.h" #import "KBSearchVC.h" #import "HomeRankDetailPopView.h" #import "LSTPopView.h" #import #import "KBMyVM.h" // 用户人设变更通知 #import "KBHUD.h" @interface HomeHotVC () // 顶部前三名视图 @property (nonatomic, strong) KBTopThreeView *topThreeView; /// 首页排行榜 VM @property (nonatomic, strong) KBHomeVM *homeVM; /// 完整的排行榜数据(接口返回) @property (nonatomic, copy) NSArray *allCharacters; /// 列表区域使用的数据:从第 4 名开始 @property (nonatomic, copy) NSArray *listCharacters; @end @interface HomeHotVC () @end @implementation HomeHotVC - (void)viewDidLoad { [super viewDidLoad]; // 搭建 UI [self.view addSubview:self.tableView]; [self.tableView mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self.view); }]; // 顶部前三名作为 tableHeaderView(注意:tableHeaderView 需设定明确高度) CGFloat headerH = 280.0; 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]; // 监听“用户人设删除”通知,用于同步更新加号按钮状态 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(kb_onUserCharacterDeleted:) name:KBUserCharacterDeletedNotification object:nil]; } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; } /// 拉取首页排行榜数据 - (void)kb_reloadRankListWithShowHUD:(BOOL)needShow { KBWeakSelf [self.homeVM fetchRankListWithParams:nil needShow:needShow completion:^(NSArray * _Nullable list, NSError * _Nullable error) { if (error) { // 错误提示已经在 VM 内部通过 HUD 处理,这里不再重复提示 return; } weakSelf.allCharacters = list ?: @[]; // 根据最新数据刷新顶部前三名与列表部分 [weakSelf kb_refreshTopThreeView]; [weakSelf kb_refreshListCharacters]; [weakSelf.tableView reloadData]; // 通知承载 HomeHotVC 的“外层 PanModal 容器”刷新布局。 // 1) 如果 HomeHotVC 是作为子控制器嵌在某个 VC 里(例如 HomeSheetVC), // 则该 VC 实现了 hw_panModalSetNeedsLayoutUpdate。 UIViewController *parent = weakSelf.parentViewController; id target = nil; if ([parent respondsToSelector:@selector(hw_panModalSetNeedsLayoutUpdate)]) { target = parent; } else { // 2) 如果 HomeHotVC 是直接嵌在 HWPanModalContentView(如 KBPanModalView)里, // parentViewController 可能为 nil,需要顺着 view.superview 向上寻找。 UIView *v = weakSelf.view; while (v && ![v respondsToSelector:@selector(hw_panModalSetNeedsLayoutUpdate)]) { v = v.superview; } if (v && [v respondsToSelector:@selector(hw_panModalSetNeedsLayoutUpdate)]) { target = v; } } if (target) { [(id)target hw_panModalSetNeedsLayoutUpdate]; } }]; } /// 收到“用户人设删除”通知:如果当前列表包含该 id,则刷新接口数据 - (void)kb_onUserCharacterDeleted:(NSNotification *)note { NSNumber *cid = note.userInfo[@"characterId"]; if (!cid) { return; } NSInteger targetId = cid.integerValue; if (targetId <= 0) { return; } BOOL contains = NO; for (KBCharacter *c in self.allCharacters) { if (c.ID.integerValue == targetId) { contains = YES; break; } } if (!contains) { return; } // 刷新首页排行榜数据(不需要 HUD) [self kb_reloadRankListWithShowHUD:NO]; } /// 根据当前 allCharacters 刷新顶部前三名区域 - (void)kb_refreshTopThreeView { NSInteger topCount = MIN(3, self.allCharacters.count); if (topCount > 0) { NSRange range = NSMakeRange(0, topCount); NSArray *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 { return self.listCharacters.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { HomeHotCell *cell = [tableView dequeueReusableCellWithIdentifier:HomeHotCell.reuseId forIndexPath:indexPath]; 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; } #pragma mark - UITableViewDelegate - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return 84.0; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:YES]; // KBSearchVC *vc = [[KBSearchVC alloc] init]; // [self.navigationController pushViewController:vc animated:true]; // UINavigationController *nav = KB_CURRENT_NAV; // [nav pushViewController:vc animated:true]; NSLog(@"==="); // 点击卡片 -> 展示弹窗 KBCharacter *c = self.listCharacters[indexPath.row]; // 自定义内容视图(尺寸可按需调节) CGFloat width = MIN(KB_SCREEN_WIDTH - 76, 420); HomeRankDetailPopView *content = [[HomeRankDetailPopView alloc] initWithFrame:CGRectMake(0, 0, width, 460)]; NSString *title = c.characterName ?: @"High EQ"; NSString *people = c.download ?: @"Download: 1 Million"; NSString *desc = @"Be Neither Too Close\nNor Too Distant"; // 示例文案 content.character = c; // 创建并弹出 LSTPopView *pop = [LSTPopView initWithCustomView:content parentView:nil popStyle:LSTPopStyleScale dismissStyle:LSTDismissStyleScale]; pop.hemStyle = LSTHemStyleCenter; // 居中 pop.bgColor = [[UIColor blackColor] colorWithAlphaComponent:0.4]; pop.isClickBgDismiss = YES; // 点击背景关闭 pop.cornerRadius = 0; // 自定义 view 自处理圆角 __weak typeof(pop) weakPop = pop; content.saveHandler = ^{ [weakPop dismiss]; }; content.closeHandler = ^{ [weakPop dismiss]; }; [pop pop]; } #pragma mark - Lazy - (BaseTableView *)tableView { if (!_tableView) { // 使用 BaseTableView,统一默认配置 _tableView = [[BaseTableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain]; _tableView.dataSource = self; _tableView.delegate = self; _tableView.separatorStyle = UITableViewCellSeparatorStyleNone; // 设计为卡片式,去掉系统分割线 _tableView.showsVerticalScrollIndicator = NO; _tableView.contentInset = UIEdgeInsetsMake(8, 0, KB_SafeAreaBottom(), 0); [_tableView registerClass:HomeHotCell.class forCellReuseIdentifier:HomeHotCell.reuseId]; } return _tableView; } @end