310 lines
11 KiB
Objective-C
310 lines
11 KiB
Objective-C
//
|
||
// 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 <HWPanModal/HWPanModal.h>
|
||
#import "KBMyVM.h" // 用户人设变更通知
|
||
#import "KBHUD.h"
|
||
|
||
@interface HomeHotVC () <UITableViewDataSource, UITableViewDelegate>
|
||
|
||
// 顶部前三名视图
|
||
@property (nonatomic, strong) KBTopThreeView *topThreeView;
|
||
|
||
/// 首页排行榜 VM
|
||
@property (nonatomic, strong) KBHomeVM *homeVM;
|
||
/// 完整的排行榜数据(接口返回)
|
||
@property (nonatomic, copy) NSArray<KBCharacter *> *allCharacters;
|
||
/// 列表区域使用的数据:从第 4 名开始
|
||
@property (nonatomic, copy) NSArray<KBCharacter *> *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<KBCharacter *> * _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<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]);
|
||
NSString *emoji = character.emoji ? character.emoji : @"";
|
||
|
||
[self.homeVM addUserCharacterWithId:cid emoji : emoji
|
||
completion:^(BOOL success, NSError * _Nullable error) {
|
||
// if (!success) {
|
||
// NSString *msg = error.localizedDescription ?: KBLocalized(@"Network error");
|
||
// [KBHUD showInfo:msg];
|
||
// return;
|
||
// }
|
||
|
||
// 添加成功:更新模型状态
|
||
if (success) {
|
||
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]);
|
||
NSString *emoji = mc.emoji ? mc.emoji : @"";
|
||
|
||
[self.homeVM addUserCharacterWithId:cid emoji : emoji
|
||
completion:^(BOOL success, NSError * _Nullable error) {
|
||
// if (!success) {
|
||
// NSString *msg = error.localizedDescription ?: KBLocalized(@"Network error");
|
||
// [KBHUD showInfo:msg];
|
||
// return;
|
||
// }
|
||
|
||
// 添加成功:更新模型状态并刷新当前行(按钮变为已添加且不可再点)
|
||
if (success) {
|
||
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
|