1
This commit is contained in:
@@ -53,7 +53,7 @@
|
||||
_useEmptyDataSet = YES; // 默认开启
|
||||
_emptyShouldAllowScroll = YES; // 默认允许滚动
|
||||
_emptyVerticalOffset = 0; // 默认不偏移
|
||||
_emptyTitleText = KBLocalized(@"暂无数据"); // 默认标题
|
||||
_emptyTitleText = KBLocalized(@"No data"); // 默认标题
|
||||
|
||||
#if KB_HAS_DZN
|
||||
self.emptyDataSetSource = self;
|
||||
@@ -148,7 +148,7 @@
|
||||
self.useEmptyDataSet = NO;
|
||||
|
||||
// 默认文案
|
||||
NSString *t = title ?: KBLocalized(@"暂无数据");
|
||||
NSString *t = title ?: KBLocalized(@"No data");
|
||||
|
||||
LYEmptyView *ev = nil;
|
||||
if (buttonTitle.length > 0) {
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
tapHandler:(KBEmptyAction)tapHandler
|
||||
buttonHandler:(KBEmptyAction)buttonHandler {
|
||||
#if KB_HAS_LY
|
||||
NSString *t = title ?: KBLocalized(@"暂无数据");
|
||||
NSString *t = title ?: KBLocalized(@"No data");
|
||||
LYEmptyView *ev = nil;
|
||||
|
||||
if (buttonTitle.length > 0) {
|
||||
|
||||
25
keyBoard/Class/Me/M/KBMyTheme.h
Normal file
25
keyBoard/Class/Me/M/KBMyTheme.h
Normal file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// KBMyTheme.h
|
||||
// keyBoard
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <CoreGraphics/CoreGraphics.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// “我的皮肤”页已购主题模型
|
||||
@interface KBMyTheme : NSObject
|
||||
@property (nonatomic, copy, nullable) NSString *themeId;
|
||||
@property (nonatomic, copy, nullable) NSString *themeName;
|
||||
@property (nonatomic, assign) CGFloat themePrice;
|
||||
@property (nonatomic, copy, nullable) NSArray<NSString *> *themeTag;
|
||||
@property (nonatomic, copy, nullable) NSString *themeDownload;
|
||||
@property (nonatomic, assign) NSInteger themeStyle;
|
||||
@property (nonatomic, assign) BOOL themeStatus;
|
||||
@property (nonatomic, assign) NSInteger themePurchasesNumber;
|
||||
@property (nonatomic, assign) NSInteger sort;
|
||||
@property (nonatomic, assign) BOOL isFree;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
17
keyBoard/Class/Me/M/KBMyTheme.m
Normal file
17
keyBoard/Class/Me/M/KBMyTheme.m
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// KBMyTheme.m
|
||||
// keyBoard
|
||||
//
|
||||
|
||||
#import "KBMyTheme.h"
|
||||
#import <MJExtension/MJExtension.h>
|
||||
|
||||
@implementation KBMyTheme
|
||||
|
||||
+ (NSDictionary *)mj_replacedKeyFromPropertyName {
|
||||
return @{
|
||||
@"themeId": @"id"
|
||||
};
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -11,6 +11,9 @@
|
||||
#import "UIScrollView+KBEmptyView.h" // 统一空态封装(LYEmptyView)
|
||||
|
||||
#import "MySkinCell.h"
|
||||
#import "KBMyVM.h"
|
||||
#import "KBMyTheme.h"
|
||||
#import "KBHUD.h"
|
||||
|
||||
static NSString * const kMySkinCellId = @"kMySkinCellId";
|
||||
|
||||
@@ -20,8 +23,8 @@ static NSString * const kMySkinCellId = @"kMySkinCellId";
|
||||
@property (nonatomic, strong) UILabel *selectedLabel; // 已选择数量
|
||||
@property (nonatomic, strong) UIButton *deleteButton; // 删除
|
||||
|
||||
@property (nonatomic, strong) NSMutableArray<NSDictionary *> *data; // 简单数据源
|
||||
@property (nonatomic, assign) NSInteger loadCount; // 刷新计数(用于演示空/有数据切换)
|
||||
@property (nonatomic, strong) NSMutableArray<KBMyTheme *> *data; // 已购主题
|
||||
@property (nonatomic, strong) KBMyVM *viewModel;
|
||||
@property (nonatomic, assign, getter=isEditingMode) BOOL editingMode; // 是否编辑态
|
||||
@end
|
||||
|
||||
@@ -62,9 +65,9 @@ static NSString * const kMySkinCellId = @"kMySkinCellId";
|
||||
// 空态视图(LYEmptyView)统一样式 + 重试按钮
|
||||
KBWeakSelf
|
||||
[self.collectionView kb_makeDefaultEmptyViewWithImage:nil
|
||||
title:KBLocalized(@"No skins yet")
|
||||
title:KBLocalized(@"No data")
|
||||
detail:KBLocalized(@"Pull down to refresh")
|
||||
buttonTitle:KBLocalized(@"Retry")
|
||||
buttonTitle:KBLocalized(@"")
|
||||
tapHandler:nil
|
||||
buttonHandler:^{ [weakSelf.collectionView.mj_header beginRefreshing]; }];
|
||||
[self.collectionView kb_setLYAutoShowEnabled:NO]; // 采用手动控制显隐
|
||||
@@ -73,7 +76,7 @@ static NSString * const kMySkinCellId = @"kMySkinCellId";
|
||||
[self.collectionView kb_endLoadingForEmpty];
|
||||
|
||||
// 下拉刷新(演示网络加载 + 空态切换)
|
||||
self.collectionView.mj_header = [MJRefreshNormalHeader headerWithRefreshingTarget:self refreshingAction:@selector(fetchData)];
|
||||
self.collectionView.mj_header = [MJRefreshNormalHeader headerWithRefreshingTarget:self refreshingAction:@selector(fetchPurchasedThemes)];
|
||||
|
||||
// 首次进入自动刷新
|
||||
[self.collectionView.mj_header beginRefreshing];
|
||||
@@ -82,25 +85,25 @@ static NSString * const kMySkinCellId = @"kMySkinCellId";
|
||||
self.bottomView.hidden = YES;
|
||||
}
|
||||
|
||||
#pragma mark - Data
|
||||
|
||||
- (void)fetchData {
|
||||
// 模拟网络延迟 1.0s
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
self.loadCount += 1;
|
||||
|
||||
// 交替返回:奇数次空数据,偶数次有数据(演示空态/非空切换)
|
||||
[self.data removeAllObjects];
|
||||
if (self.loadCount % 2 == 0) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
[self.data addObject:@{ @"title": @"Dopamine" }];
|
||||
- (void)fetchPurchasedThemes {
|
||||
KBWeakSelf
|
||||
[self.viewModel fetchPurchasedThemesWithCompletion:^(NSArray<KBMyTheme *> * _Nullable themes, NSError * _Nullable error) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if ([weakSelf.collectionView.mj_header isRefreshing]) {
|
||||
[weakSelf.collectionView.mj_header endRefreshing];
|
||||
}
|
||||
}
|
||||
|
||||
[self.collectionView reloadData];
|
||||
[self.collectionView kb_endLoadingForEmpty]; // 根据数据源显示/隐藏 emptyView
|
||||
[self.collectionView.mj_header endRefreshing];
|
||||
});
|
||||
if (error) {
|
||||
[weakSelf.collectionView kb_endLoadingForEmpty];
|
||||
return;
|
||||
}
|
||||
[weakSelf.data removeAllObjects];
|
||||
if (themes.count > 0) {
|
||||
[weakSelf.data addObjectsFromArray:themes];
|
||||
}
|
||||
[weakSelf.collectionView reloadData];
|
||||
[weakSelf.collectionView kb_endLoadingForEmpty];
|
||||
});
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
@@ -190,8 +193,8 @@ static NSString * const kMySkinCellId = @"kMySkinCellId";
|
||||
|
||||
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
MySkinCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kMySkinCellId forIndexPath:indexPath];
|
||||
NSDictionary *d = self.data[indexPath.item];
|
||||
[cell configWithTitle:d[@"title"] image:nil];
|
||||
KBMyTheme *theme = self.data[indexPath.item];
|
||||
[cell configWithTitle:theme.themeName image:nil];
|
||||
cell.editing = self.isEditingMode; // 控制是否显示选择圆点
|
||||
// 同步选中状态(复用时)
|
||||
BOOL selected = [[collectionView indexPathsForSelectedItems] containsObject:indexPath];
|
||||
@@ -306,4 +309,11 @@ static NSString * const kMySkinCellId = @"kMySkinCellId";
|
||||
return _deleteButton;
|
||||
}
|
||||
|
||||
- (KBMyVM *)viewModel {
|
||||
if (!_viewModel) {
|
||||
_viewModel = [[KBMyVM alloc] init];
|
||||
}
|
||||
return _viewModel;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "KBCharacter.h"
|
||||
#import "KBMyTheme.h"
|
||||
@class KBUser;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
@@ -22,6 +23,7 @@ typedef void(^KBUpLoadAvatarCompletion)(BOOL success, NSError * _Nullable error)
|
||||
typedef void(^KBUpdateUserInfoCompletion)(BOOL success, NSError * _Nullable error);
|
||||
typedef void(^KBUpdateCharacterSortCompletion)(BOOL success, NSError * _Nullable error);
|
||||
typedef void(^KBDeleteUserCharacterCompletion)(BOOL success, NSError * _Nullable error);
|
||||
typedef void(^KBMyPurchasedThemesCompletion)(NSArray<KBMyTheme *> *_Nullable themes, NSError *_Nullable error);
|
||||
|
||||
@interface KBMyVM : NSObject
|
||||
|
||||
@@ -30,6 +32,8 @@ typedef void(^KBDeleteUserCharacterCompletion)(BOOL success, NSError * _Nullable
|
||||
|
||||
/// 用户人设列表(/character/listByUser)
|
||||
- (void)fetchCharacterListByUserWithCompletion:(KBCharacterListCompletion)completion;
|
||||
/// 已购买主题列表(/themes/purchased)
|
||||
- (void)fetchPurchasedThemesWithCompletion:(KBMyPurchasedThemesCompletion)completion;
|
||||
/// 更新用户人设排序
|
||||
- (void)updateUserCharacterSortWithSortArray:(NSArray<NSNumber *> *)sortArray
|
||||
completion:(KBUpdateCharacterSortCompletion)completion;
|
||||
|
||||
@@ -86,6 +86,34 @@ NSString * const KBUserCharacterDeletedNotification = @"KBUserCharacterDeletedNo
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)fetchPurchasedThemesWithCompletion:(KBMyPurchasedThemesCompletion)completion {
|
||||
[[KBNetworkManager shared] GET:API_THEME_PURCHASED
|
||||
parameters:nil
|
||||
headers:nil
|
||||
autoShowBusinessError:NO
|
||||
completion:^(NSDictionary *jsonOrData, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
if (error) {
|
||||
NSString *msg = KBBizMessageFromJSONObject(jsonOrData) ?: error.localizedDescription ?: KBLocalized(@"Network error");
|
||||
[KBHUD showInfo:msg];
|
||||
if (completion) completion(nil, error);
|
||||
return;
|
||||
}
|
||||
|
||||
id dataObj = jsonOrData[KBData] ?: jsonOrData[@"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<KBMyTheme *> *themes = [KBMyTheme mj_objectArrayWithKeyValuesArray:(NSArray *)dataObj];
|
||||
if (completion) completion(themes, nil);
|
||||
}];
|
||||
}
|
||||
|
||||
/// 更新用户人设排序
|
||||
- (void)updateUserCharacterSortWithSortArray:(NSArray<NSNumber *> *)sortArray
|
||||
completion:(KBUpdateCharacterSortCompletion)completion {
|
||||
|
||||
Reference in New Issue
Block a user