3
This commit is contained in:
@@ -19,8 +19,9 @@
|
|||||||
// 兼容旧命名(如有使用 API_APPLE_LOGIN 的位置,映射到统一命名)
|
// 兼容旧命名(如有使用 API_APPLE_LOGIN 的位置,映射到统一命名)
|
||||||
#define API_APPLE_LOGIN @"/user/appleLogin" // Apple 登录
|
#define API_APPLE_LOGIN @"/user/appleLogin" // Apple 登录
|
||||||
#define API_LOGOUT @"/user/logout" // 退出登录
|
#define API_LOGOUT @"/user/logout" // 退出登录
|
||||||
#define KB_API_CHARACTER_LIST @"/character/list" // 排行榜角色列表
|
#define KB_API_CHARACTER_LIST @"/character/list" // 排行榜角色列表(综合)
|
||||||
#define KB_API_TAG_LIST @"/tag/list" // 排行榜标签列表
|
#define KB_API_CHARACTER_LIST_BY_TAG @"/character/listByTag" // 根据 tagId 获取角色列表
|
||||||
|
#define KB_API_TAG_LIST @"/tag/list" // 排行榜标签列表
|
||||||
|
|
||||||
// 应用配置
|
// 应用配置
|
||||||
#ifndef KB_API_APP_CONFIG
|
#ifndef KB_API_APP_CONFIG
|
||||||
|
|||||||
@@ -6,16 +6,20 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
#import "KBCharacter.h"
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
/// 首页排行榜卡片 Cell(两列)
|
/// 首页排行榜卡片 Cell(两列)
|
||||||
@interface HomeRankCardCell : UICollectionViewCell
|
@interface HomeRankCardCell : UICollectionViewCell
|
||||||
|
|
||||||
|
/// 当前展示的角色模型
|
||||||
|
@property (nonatomic, strong, nullable) KBCharacter *character;
|
||||||
|
|
||||||
/// 点击加号/勾选按钮回调
|
/// 点击加号/勾选按钮回调
|
||||||
@property (nonatomic, copy, nullable) void (^onTapAction)(void);
|
@property (nonatomic, copy, nullable) void (^onTapAction)(void);
|
||||||
|
|
||||||
/// 统一配置数据
|
/// 旧的配置方法(兼容用,不推荐继续使用)
|
||||||
- (void)configureWithTitle:(NSString *)title
|
- (void)configureWithTitle:(NSString *)title
|
||||||
desc:(NSString *)desc
|
desc:(NSString *)desc
|
||||||
people:(NSString *)people
|
people:(NSString *)people
|
||||||
@@ -24,4 +28,3 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
@end
|
@end
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
||||||
|
|
||||||
|
|||||||
@@ -10,13 +10,13 @@
|
|||||||
#import "UIView+KBShadow.h"
|
#import "UIView+KBShadow.h"
|
||||||
|
|
||||||
@interface HomeRankCardCell ()
|
@interface HomeRankCardCell ()
|
||||||
@property (nonatomic, strong) UIView *shadowView; // 阴影容器(不裁剪)
|
@property (nonatomic, strong) UIView *shadowView; // 阴影容器(不裁剪)
|
||||||
@property (nonatomic, strong) UIView *cardView; // 白色圆角卡片
|
@property (nonatomic, strong) UIImageView *cardView; // 卡片背景图片
|
||||||
@property (nonatomic, strong) UIView *badgeCircle; // 顶部圆形描边
|
@property (nonatomic, strong) UIView *badgeCircle; // 顶部圆形描边
|
||||||
@property (nonatomic, strong) UILabel *titleLabel;
|
@property (nonatomic, strong) UILabel *titleLabel;
|
||||||
@property (nonatomic, strong) UILabel *descLabel;
|
@property (nonatomic, strong) UILabel *descLabel;
|
||||||
@property (nonatomic, strong) UILabel *peopleLabel;
|
@property (nonatomic, strong) UILabel *peopleLabel;
|
||||||
@property (nonatomic, strong) UIButton *actionBtn; // 加号/勾选按钮
|
@property (nonatomic, strong) UIButton *actionBtn; // 加号/勾选按钮
|
||||||
@property (nonatomic, assign) BOOL added;
|
@property (nonatomic, assign) BOOL added;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@@ -125,6 +125,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setCharacter:(KBCharacter *)character {
|
||||||
|
_character = character;
|
||||||
|
|
||||||
|
NSString *title = character.characterName ?: @"";
|
||||||
|
NSString *people = character.download ?: @"";
|
||||||
|
NSString *desc = @"Be Neither Too Close\nNor Too Distant..."; // 目前暂无描述字段,先用示例文案
|
||||||
|
BOOL added = character.added;
|
||||||
|
|
||||||
|
[self configureWithTitle:title desc:desc people:people added:added];
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - Lazy UI
|
#pragma mark - Lazy UI
|
||||||
|
|
||||||
- (UIView *)shadowView {
|
- (UIView *)shadowView {
|
||||||
@@ -135,12 +146,15 @@
|
|||||||
return _shadowView;
|
return _shadowView;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (UIView *)cardView {
|
- (UIImageView *)cardView {
|
||||||
if (!_cardView) {
|
if (!_cardView) {
|
||||||
_cardView = [UIView new];
|
_cardView = [[UIImageView alloc] init];
|
||||||
_cardView.backgroundColor = UIColor.whiteColor;
|
_cardView.backgroundColor = UIColor.whiteColor;
|
||||||
_cardView.layer.cornerRadius = 18.0;
|
_cardView.layer.cornerRadius = 18.0;
|
||||||
_cardView.layer.masksToBounds = YES;
|
_cardView.layer.masksToBounds = YES;
|
||||||
|
_cardView.contentMode = UIViewContentModeScaleAspectFill;
|
||||||
|
// 默认卡片背景图(可按需要替换)
|
||||||
|
_cardView.image = [UIImage imageNamed:@"home_rank_card_bg"];
|
||||||
}
|
}
|
||||||
return _cardView;
|
return _cardView;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,12 +7,15 @@
|
|||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
#import "JXCategoryListContainerView.h"
|
#import "JXCategoryListContainerView.h"
|
||||||
#import "KBTag.h"
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
@interface HomeRankContentVC : UIViewController<JXCategoryListContentViewDelegate, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
|
@interface HomeRankContentVC : UIViewController<JXCategoryListContentViewDelegate, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
|
||||||
|
|
||||||
@property (nonatomic, strong) UICollectionView *collectionView;
|
@property (nonatomic, strong) UICollectionView *collectionView;
|
||||||
@property (nonatomic, strong) KBTag *tagModel;
|
|
||||||
|
/// 指定标签 id 的构造方法;index 对应的 tagId 由 HomeRankVC 传入
|
||||||
|
- (instancetype)initWithTagId:(nullable NSString *)tagId;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|||||||
@@ -12,35 +12,55 @@
|
|||||||
|
|
||||||
// 自定义卡片 Cell
|
// 自定义卡片 Cell
|
||||||
#import "HomeRankCardCell.h"
|
#import "HomeRankCardCell.h"
|
||||||
|
#import "KBHomeVM.h"
|
||||||
|
#import "KBCharacter.h"
|
||||||
|
|
||||||
@interface HomeRankContentVC ()
|
@interface HomeRankContentVC ()
|
||||||
@property (nonatomic, strong) NSArray<NSDictionary *> *dataSource; // 简单模拟数据
|
@property (nonatomic, copy, nullable) NSString *tagId; // 当前标签 id
|
||||||
|
@property (nonatomic, strong) KBHomeVM *homeVM;
|
||||||
|
@property (nonatomic, strong) NSArray<KBCharacter *> *characters; // 当前标签下的角色列表
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation HomeRankContentVC
|
@implementation HomeRankContentVC
|
||||||
|
|
||||||
|
- (instancetype)initWithTagId:(NSString *)tagId {
|
||||||
|
if (self = [super init]) {
|
||||||
|
_tagId = [tagId copy];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)init {
|
||||||
|
return [self initWithTagId:nil];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)viewDidLoad {
|
- (void)viewDidLoad {
|
||||||
[super viewDidLoad];
|
[super viewDidLoad];
|
||||||
|
|
||||||
self.view.backgroundColor = COLOR_WITH_RGB(246/255.0, 253/255.0, 249/255.0, 1.0); // 淡绿色背景
|
self.view.backgroundColor = COLOR_WITH_RGB(246/255.0, 253/255.0, 249/255.0, 1.0); // 淡绿色背景
|
||||||
|
self.characters = @[];
|
||||||
// 数据
|
self.homeVM = [KBHomeVM new];
|
||||||
self.dataSource = @[
|
|
||||||
@{@"title":@"High EQ", @"desc":@"Be Neither Too Close\nNor Too Distant...", @"people":@"Two Million People\nHave Used It", @"added":@(NO)},
|
|
||||||
@{@"title":@"High EQ", @"desc":@"Be Neither Too Close\nNor Too Distant...", @"people":@"Two Million People\nHave Used It", @"added":@(YES)},
|
|
||||||
@{@"title":@"High EQ", @"desc":@"Be Neither Too Close\nNor Too Distant...", @"people":@"Two Million People\nHave Used It", @"added":@(NO)},
|
|
||||||
@{@"title":@"High EQ", @"desc":@"Be Neither Too Close\nNor Too Distant...", @"people":@"Two Million People\nHave Used It", @"added":@(YES)},
|
|
||||||
@{@"title":@"High EQ", @"desc":@"Be Neither Too Close\nNor Too Distant...", @"people":@"Two Million People\nHave Used It", @"added":@(NO)},
|
|
||||||
@{@"title":@"High EQ", @"desc":@"Be Neither Too Close\nNor Too Distant...", @"people":@"Two Million People\nHave Used It", @"added":@(YES)},
|
|
||||||
@{@"title":@"High EQ", @"desc":@"Be Neither Too Close\nNor Too Distant...", @"people":@"Two Million People\nHave Used It", @"added":@(NO)},
|
|
||||||
@{@"title":@"High EQ", @"desc":@"Be Neither Too Close\nNor Too Distant...", @"people":@"Two Million People\nHave Used It", @"added":@(YES)}
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
[self.view addSubview:self.collectionView];
|
[self.view addSubview:self.collectionView];
|
||||||
[self.collectionView mas_makeConstraints:^(MASConstraintMaker *make) {
|
[self.collectionView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
make.edges.equalTo(self.view);
|
make.edges.equalTo(self.view);
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
// 加载当前 tag 下的角色列表
|
||||||
|
[self loadCharactersForCurrentTag];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)loadCharactersForCurrentTag {
|
||||||
|
KBWeakSelf
|
||||||
|
[self.homeVM fetchRankListByTagId:self.tagId
|
||||||
|
needShow:YES
|
||||||
|
completion:^(NSArray<KBCharacter *> * _Nullable list, NSError * _Nullable error) {
|
||||||
|
if (error) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
weakSelf.characters = list ?: @[];
|
||||||
|
[weakSelf.collectionView reloadData];
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (UICollectionView *)collectionView{
|
- (UICollectionView *)collectionView{
|
||||||
@@ -66,26 +86,21 @@
|
|||||||
#pragma mark - UICollectionViewDataSource
|
#pragma mark - UICollectionViewDataSource
|
||||||
|
|
||||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||||
return self.dataSource.count;
|
return self.characters.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
HomeRankCardCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"HomeRankCardCell" forIndexPath:indexPath];
|
HomeRankCardCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"HomeRankCardCell" forIndexPath:indexPath];
|
||||||
NSDictionary *d = self.dataSource[indexPath.item];
|
KBCharacter *c = self.characters[indexPath.item];
|
||||||
BOOL added = [d[@"added"] boolValue];
|
// 直接把模型交给 cell,由 cell 自己负责展示
|
||||||
[cell configureWithTitle:d[@"title"]
|
cell.character = c;
|
||||||
desc:d[@"desc"]
|
|
||||||
people:d[@"people"]
|
|
||||||
added:added];
|
|
||||||
KBWeakSelf
|
KBWeakSelf
|
||||||
cell.onTapAction = ^{
|
cell.onTapAction = ^{
|
||||||
// 切换添加/已添加状态并刷新该项
|
// 切换添加/已添加状态并刷新该项(只是本地 UI 状态)
|
||||||
NSMutableArray *m = [weakSelf.dataSource mutableCopy];
|
NSMutableArray *m = [weakSelf.characters mutableCopy];
|
||||||
NSMutableDictionary *md = [m[indexPath.item] mutableCopy];
|
KBCharacter *mc = m[indexPath.item];
|
||||||
BOOL cur = [md[@"added"] boolValue];
|
mc.added = !mc.added;
|
||||||
md[@"added"] = @(!cur);
|
weakSelf.characters = [m copy];
|
||||||
m[indexPath.item] = md;
|
|
||||||
weakSelf.dataSource = [m copy];
|
|
||||||
[weakSelf.collectionView reloadItemsAtIndexPaths:@[indexPath]];
|
[weakSelf.collectionView reloadItemsAtIndexPaths:@[indexPath]];
|
||||||
};
|
};
|
||||||
return cell;
|
return cell;
|
||||||
@@ -105,13 +120,13 @@
|
|||||||
|
|
||||||
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
|
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
|
||||||
// 点击卡片 -> 展示弹窗
|
// 点击卡片 -> 展示弹窗
|
||||||
NSDictionary *d = self.dataSource[indexPath.item];
|
KBCharacter *c = self.characters[indexPath.item];
|
||||||
|
|
||||||
// 自定义内容视图(尺寸可按需调节)
|
// 自定义内容视图(尺寸可按需调节)
|
||||||
CGFloat width = MIN(KB_SCREEN_WIDTH - 76, 420);
|
CGFloat width = MIN(KB_SCREEN_WIDTH - 76, 420);
|
||||||
HomeRankDetailPopView *content = [[HomeRankDetailPopView alloc] initWithFrame:CGRectMake(0, 0, width, 460)];
|
HomeRankDetailPopView *content = [[HomeRankDetailPopView alloc] initWithFrame:CGRectMake(0, 0, width, 460)];
|
||||||
NSString *title = d[@"title"] ?: @"High EQ";
|
NSString *title = c.characterName ?: @"High EQ";
|
||||||
NSString *people = d[@"people"] ?: @"Download: 1 Million";
|
NSString *people = c.download ?: @"Download: 1 Million";
|
||||||
NSString *desc = @"Be Neither Too Close\nNor Too Distant"; // 示例文案
|
NSString *desc = @"Be Neither Too Close\nNor Too Distant"; // 示例文案
|
||||||
[content configWithAvatar:nil title:title download:people desc:desc];
|
[content configWithAvatar:nil title:title download:people desc:desc];
|
||||||
|
|
||||||
|
|||||||
@@ -179,11 +179,13 @@
|
|||||||
|
|
||||||
// 返回各个列表菜单下的实例,该实例需要遵守并实现 <JXCategoryListContentViewDelegate> 协议
|
// 返回各个列表菜单下的实例,该实例需要遵守并实现 <JXCategoryListContentViewDelegate> 协议
|
||||||
- (id<JXCategoryListContentViewDelegate>)listContainerView:(JXCategoryListContainerView *)listContainerView initListForIndex:(NSInteger)index {
|
- (id<JXCategoryListContentViewDelegate>)listContainerView:(JXCategoryListContainerView *)listContainerView initListForIndex:(NSInteger)index {
|
||||||
KBTag *tagModel = self.tags[index];
|
NSString *tagId = nil;
|
||||||
HomeRankContentVC *list = [[HomeRankContentVC alloc] init];
|
if (index >= 0 && index < self.tags.count) {
|
||||||
list.tagModel = tagModel;
|
KBTag *tag = self.tags[index];
|
||||||
|
tagId = tag.tagId;
|
||||||
|
}
|
||||||
|
HomeRankContentVC *list = [[HomeRankContentVC alloc] initWithTagId:tagId];
|
||||||
self.collectionView = list.collectionView;
|
self.collectionView = list.collectionView;
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,11 @@ typedef void(^KBHomeTagCompletion)(NSArray<KBTag *> * _Nullable list,
|
|||||||
needShow:(BOOL)needShow
|
needShow:(BOOL)needShow
|
||||||
completion:(KBHomeRankCompletion)completion;
|
completion:(KBHomeRankCompletion)completion;
|
||||||
|
|
||||||
|
/// 根据 tagId 获取角色列表(GET /character/listByTag)
|
||||||
|
- (void)fetchRankListByTagId:(nullable NSString *)tagId
|
||||||
|
needShow:(BOOL)needShow
|
||||||
|
completion:(KBHomeRankCompletion)completion;
|
||||||
|
|
||||||
/// 请求排行榜标签列表(GET /tag/list)
|
/// 请求排行榜标签列表(GET /tag/list)
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - params: 额外查询参数(可为空);
|
/// - params: 额外查询参数(可为空);
|
||||||
|
|||||||
@@ -67,6 +67,63 @@
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)fetchRankListByTagId:(nullable NSString *)tagId
|
||||||
|
needShow:(BOOL)needShow
|
||||||
|
completion:(KBHomeRankCompletion)completion {
|
||||||
|
NSMutableDictionary *params = [NSMutableDictionary dictionary];
|
||||||
|
if (tagId.length) {
|
||||||
|
params[@"tagId"] = tagId;
|
||||||
|
}
|
||||||
|
[self fetchRankListByTagParams:params
|
||||||
|
needShow:needShow
|
||||||
|
completion:completion];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 内部辅助方法:调用 /character/listByTag
|
||||||
|
- (void)fetchRankListByTagParams:(NSDictionary *)params
|
||||||
|
needShow:(BOOL)needShow
|
||||||
|
completion:(KBHomeRankCompletion)completion {
|
||||||
|
if (needShow) {
|
||||||
|
[KBHUD show];
|
||||||
|
}
|
||||||
|
|
||||||
|
[[KBNetworkManager shared] GET:KB_API_CHARACTER_LIST_BY_TAG
|
||||||
|
parameters:params
|
||||||
|
headers:nil
|
||||||
|
autoShowBusinessError:NO
|
||||||
|
completion:^(NSDictionary * _Nullable json, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||||
|
if (needShow) {
|
||||||
|
[KBHUD dismiss];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
NSString *msg = KBBizMessageFromJSONObject(json) ?: error.localizedDescription ?: KBLocalized(@"Network error");
|
||||||
|
[KBHUD showInfo:msg];
|
||||||
|
if (completion) {
|
||||||
|
completion(nil, error);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
id dataObj = json[KBData] ?: json[@"data"];
|
||||||
|
if (![dataObj isKindOfClass:[NSArray class]]) {
|
||||||
|
NSError *e = [NSError errorWithDomain:KBNetworkErrorDomain
|
||||||
|
code:KBNetworkErrorInvalidResponse
|
||||||
|
userInfo:@{NSLocalizedDescriptionKey: KBLocalized(@"Invalid response")}];
|
||||||
|
[KBHUD showInfo:e.localizedDescription];
|
||||||
|
if (completion) {
|
||||||
|
completion(nil, e);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSArray<KBCharacter *> *list = [KBCharacter mj_objectArrayWithKeyValuesArray:(NSArray *)dataObj];
|
||||||
|
if (completion) {
|
||||||
|
completion(list, nil);
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)fetchTagListWithParams:(nullable NSDictionary *)params
|
- (void)fetchTagListWithParams:(nullable NSDictionary *)params
|
||||||
needShow:(BOOL)needShow
|
needShow:(BOOL)needShow
|
||||||
completion:(KBHomeTagCompletion)completion {
|
completion:(KBHomeTagCompletion)completion {
|
||||||
|
|||||||
Reference in New Issue
Block a user