1
This commit is contained in:
@@ -45,6 +45,10 @@
|
|||||||
#define API_CHARACTER_DEL_USER_CHARACTER @"/character/delUserCharacter" // 删除用户人设
|
#define API_CHARACTER_DEL_USER_CHARACTER @"/character/delUserCharacter" // 删除用户人设
|
||||||
#define API_CHARACTER_ADD_USER_CHARACTER @"/character/addUserCharacter" // 添加用户人设(假定路径,如有不同请按后端实际修改)
|
#define API_CHARACTER_ADD_USER_CHARACTER @"/character/addUserCharacter" // 添加用户人设(假定路径,如有不同请按后端实际修改)
|
||||||
|
|
||||||
|
/// Theme shop
|
||||||
|
#define API_THEME_LIST_ALL_STYLES @"/themes/listAllStyles" // 查询所有主题风格
|
||||||
|
#define API_THEME_LIST_BY_STYLE @"/themes/listByStyle" // 按风格查询主题列表
|
||||||
|
|
||||||
/// pay
|
/// pay
|
||||||
#define API_VALIDATE_RECEIPT @"/api/apple/validate-receipt" // 排行榜标签列表
|
#define API_VALIDATE_RECEIPT @"/api/apple/validate-receipt" // 排行榜标签列表
|
||||||
|
|
||||||
|
|||||||
@@ -116,6 +116,9 @@
|
|||||||
0498BD8F2EE6A3BD006CC1D5 /* KBMyMainModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD8E2EE6A3BD006CC1D5 /* KBMyMainModel.m */; };
|
0498BD8F2EE6A3BD006CC1D5 /* KBMyMainModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD8E2EE6A3BD006CC1D5 /* KBMyMainModel.m */; };
|
||||||
0498BD902EE6A3BD006CC1D5 /* KBMyMainModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD8E2EE6A3BD006CC1D5 /* KBMyMainModel.m */; };
|
0498BD902EE6A3BD006CC1D5 /* KBMyMainModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD8E2EE6A3BD006CC1D5 /* KBMyMainModel.m */; };
|
||||||
0498BDDA2EE7ECEA006CC1D5 /* WJXEventSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BDD82EE7ECEA006CC1D5 /* WJXEventSource.m */; };
|
0498BDDA2EE7ECEA006CC1D5 /* WJXEventSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BDD82EE7ECEA006CC1D5 /* WJXEventSource.m */; };
|
||||||
|
0498BDDE2EE81508006CC1D5 /* KBShopVM.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BDDD2EE81508006CC1D5 /* KBShopVM.m */; };
|
||||||
|
0498BDE12EEA87C9006CC1D5 /* KBShopStyleModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BDE02EEA87C8006CC1D5 /* KBShopStyleModel.m */; };
|
||||||
|
0498BDE42EEA885D006CC1D5 /* KBShopThemeModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BDE32EEA885D006CC1D5 /* KBShopThemeModel.m */; };
|
||||||
049FB20B2EC1C13800FAB05D /* KBSkinBottomActionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB20A2EC1C13800FAB05D /* KBSkinBottomActionView.m */; };
|
049FB20B2EC1C13800FAB05D /* KBSkinBottomActionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB20A2EC1C13800FAB05D /* KBSkinBottomActionView.m */; };
|
||||||
049FB20E2EC1CD2800FAB05D /* KBAlert.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB20D2EC1CD2800FAB05D /* KBAlert.m */; };
|
049FB20E2EC1CD2800FAB05D /* KBAlert.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB20D2EC1CD2800FAB05D /* KBAlert.m */; };
|
||||||
049FB2112EC1F72F00FAB05D /* KBMyListCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB2102EC1F72F00FAB05D /* KBMyListCell.m */; };
|
049FB2112EC1F72F00FAB05D /* KBMyListCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB2102EC1F72F00FAB05D /* KBMyListCell.m */; };
|
||||||
@@ -408,6 +411,12 @@
|
|||||||
0498BD8E2EE6A3BD006CC1D5 /* KBMyMainModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBMyMainModel.m; sourceTree = "<group>"; };
|
0498BD8E2EE6A3BD006CC1D5 /* KBMyMainModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBMyMainModel.m; sourceTree = "<group>"; };
|
||||||
0498BDD72EE7ECEA006CC1D5 /* WJXEventSource.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WJXEventSource.h; sourceTree = "<group>"; };
|
0498BDD72EE7ECEA006CC1D5 /* WJXEventSource.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WJXEventSource.h; sourceTree = "<group>"; };
|
||||||
0498BDD82EE7ECEA006CC1D5 /* WJXEventSource.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WJXEventSource.m; sourceTree = "<group>"; };
|
0498BDD82EE7ECEA006CC1D5 /* WJXEventSource.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WJXEventSource.m; sourceTree = "<group>"; };
|
||||||
|
0498BDDC2EE81508006CC1D5 /* KBShopVM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBShopVM.h; sourceTree = "<group>"; };
|
||||||
|
0498BDDD2EE81508006CC1D5 /* KBShopVM.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBShopVM.m; sourceTree = "<group>"; };
|
||||||
|
0498BDDF2EEA87C8006CC1D5 /* KBShopStyleModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBShopStyleModel.h; sourceTree = "<group>"; };
|
||||||
|
0498BDE02EEA87C8006CC1D5 /* KBShopStyleModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBShopStyleModel.m; sourceTree = "<group>"; };
|
||||||
|
0498BDE22EEA885D006CC1D5 /* KBShopThemeModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBShopThemeModel.h; sourceTree = "<group>"; };
|
||||||
|
0498BDE32EEA885D006CC1D5 /* KBShopThemeModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBShopThemeModel.m; sourceTree = "<group>"; };
|
||||||
049FB2092EC1C13800FAB05D /* KBSkinBottomActionView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBSkinBottomActionView.h; sourceTree = "<group>"; };
|
049FB2092EC1C13800FAB05D /* KBSkinBottomActionView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBSkinBottomActionView.h; sourceTree = "<group>"; };
|
||||||
049FB20A2EC1C13800FAB05D /* KBSkinBottomActionView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBSkinBottomActionView.m; sourceTree = "<group>"; };
|
049FB20A2EC1C13800FAB05D /* KBSkinBottomActionView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBSkinBottomActionView.m; sourceTree = "<group>"; };
|
||||||
049FB20C2EC1CD2800FAB05D /* KBAlert.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBAlert.h; sourceTree = "<group>"; };
|
049FB20C2EC1CD2800FAB05D /* KBAlert.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBAlert.h; sourceTree = "<group>"; };
|
||||||
@@ -765,6 +774,10 @@
|
|||||||
047C654A2EBCBA880035E841 /* M */ = {
|
047C654A2EBCBA880035E841 /* M */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
0498BDDF2EEA87C8006CC1D5 /* KBShopStyleModel.h */,
|
||||||
|
0498BDE02EEA87C8006CC1D5 /* KBShopStyleModel.m */,
|
||||||
|
0498BDE22EEA885D006CC1D5 /* KBShopThemeModel.h */,
|
||||||
|
0498BDE32EEA885D006CC1D5 /* KBShopThemeModel.m */,
|
||||||
);
|
);
|
||||||
path = M;
|
path = M;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -800,6 +813,7 @@
|
|||||||
047C654D2EBCBA880035E841 /* Shop */ = {
|
047C654D2EBCBA880035E841 /* Shop */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
0498BDDB2EE814E3006CC1D5 /* VM */,
|
||||||
047C654A2EBCBA880035E841 /* M */,
|
047C654A2EBCBA880035E841 /* M */,
|
||||||
047C654B2EBCBA880035E841 /* V */,
|
047C654B2EBCBA880035E841 /* V */,
|
||||||
047C654C2EBCBA880035E841 /* VC */,
|
047C654C2EBCBA880035E841 /* VC */,
|
||||||
@@ -921,6 +935,15 @@
|
|||||||
path = WJXEventSource;
|
path = WJXEventSource;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
0498BDDB2EE814E3006CC1D5 /* VM */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
0498BDDC2EE81508006CC1D5 /* KBShopVM.h */,
|
||||||
|
0498BDDD2EE81508006CC1D5 /* KBShopVM.m */,
|
||||||
|
);
|
||||||
|
path = VM;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
049FB2162EC20A6600FAB05D /* BMLongPressDragCellCollectionView */ = {
|
049FB2162EC20A6600FAB05D /* BMLongPressDragCellCollectionView */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -1820,6 +1843,7 @@
|
|||||||
04791F922ED48010004E8522 /* KBNoticeVC.m in Sources */,
|
04791F922ED48010004E8522 /* KBNoticeVC.m in Sources */,
|
||||||
04FC970F2EB334F8007BD342 /* KBWebImageManager.m in Sources */,
|
04FC970F2EB334F8007BD342 /* KBWebImageManager.m in Sources */,
|
||||||
04FC95CF2EB1E7A1007BD342 /* HomeVC.m in Sources */,
|
04FC95CF2EB1E7A1007BD342 /* HomeVC.m in Sources */,
|
||||||
|
0498BDDE2EE81508006CC1D5 /* KBShopVM.m in Sources */,
|
||||||
049FB2112EC1F72F00FAB05D /* KBMyListCell.m in Sources */,
|
049FB2112EC1F72F00FAB05D /* KBMyListCell.m in Sources */,
|
||||||
A1B2D7022EB8C00100000001 /* KBLangTestVC.m in Sources */,
|
A1B2D7022EB8C00100000001 /* KBLangTestVC.m in Sources */,
|
||||||
04122F6D2EC5F40800EF7AB3 /* NSObject+FGIsNullOrEmpty.m in Sources */,
|
04122F6D2EC5F40800EF7AB3 /* NSObject+FGIsNullOrEmpty.m in Sources */,
|
||||||
@@ -1831,6 +1855,7 @@
|
|||||||
048908DA2EBF61AF00FABA60 /* UICollectionViewLeftAlignedLayout.m in Sources */,
|
048908DA2EBF61AF00FABA60 /* UICollectionViewLeftAlignedLayout.m in Sources */,
|
||||||
04C6EABF2EAF86530089C901 /* main.m in Sources */,
|
04C6EABF2EAF86530089C901 /* main.m in Sources */,
|
||||||
0498BD6E2EE0285D006CC1D5 /* KBForgetVerPwdVC.m in Sources */,
|
0498BD6E2EE0285D006CC1D5 /* KBForgetVerPwdVC.m in Sources */,
|
||||||
|
0498BDE12EEA87C9006CC1D5 /* KBShopStyleModel.m in Sources */,
|
||||||
04FC95CC2EB1E780007BD342 /* BaseTabBarController.m in Sources */,
|
04FC95CC2EB1E780007BD342 /* BaseTabBarController.m in Sources */,
|
||||||
0479205A2EDEE1FC004E8522 /* CRBoxTextView.m in Sources */,
|
0479205A2EDEE1FC004E8522 /* CRBoxTextView.m in Sources */,
|
||||||
0479205B2EDEE1FC004E8522 /* CRSecrectImageView.m in Sources */,
|
0479205B2EDEE1FC004E8522 /* CRSecrectImageView.m in Sources */,
|
||||||
@@ -1847,6 +1872,7 @@
|
|||||||
049FB2432EC4BBB700FAB05D /* KBLoginPopView.m in Sources */,
|
049FB2432EC4BBB700FAB05D /* KBLoginPopView.m in Sources */,
|
||||||
048908CC2EBE373500FABA60 /* KBSearchBarView.m in Sources */,
|
048908CC2EBE373500FABA60 /* KBSearchBarView.m in Sources */,
|
||||||
04122F872EC6198C00EF7AB3 /* WMDragView.m in Sources */,
|
04122F872EC6198C00EF7AB3 /* WMDragView.m in Sources */,
|
||||||
|
0498BDE42EEA885D006CC1D5 /* KBShopThemeModel.m in Sources */,
|
||||||
048908CD2EBE373500FABA60 /* KBSearchSectionHeader.m in Sources */,
|
048908CD2EBE373500FABA60 /* KBSearchSectionHeader.m in Sources */,
|
||||||
049FB2202EC30D2700FAB05D /* HomeRankDetailPopView.m in Sources */,
|
049FB2202EC30D2700FAB05D /* HomeRankDetailPopView.m in Sources */,
|
||||||
048908CE2EBE373500FABA60 /* KBSkinCardCell.m in Sources */,
|
048908CE2EBE373500FABA60 /* KBSkinCardCell.m in Sources */,
|
||||||
|
|||||||
@@ -49,7 +49,8 @@
|
|||||||
|
|
||||||
- (void)configWithTitle:(NSString *)title imageURL:(NSString *)url price:(NSString *)price {
|
- (void)configWithTitle:(NSString *)title imageURL:(NSString *)url price:(NSString *)price {
|
||||||
self.titleLabel.text = title.length ? title : @"Dopamine";
|
self.titleLabel.text = title.length ? title : @"Dopamine";
|
||||||
[self.priceBtn setTitle:@"20" forState:UIControlStateNormal];
|
NSString *priceText = price.length ? price : @"20";
|
||||||
|
[self.priceBtn setTitle:priceText forState:UIControlStateNormal];
|
||||||
|
|
||||||
// 简化:本地展示占位色,无网络图
|
// 简化:本地展示占位色,无网络图
|
||||||
self.coverView.backgroundColor = [UIColor colorWithWhite:0.92 alpha:1.0];
|
self.coverView.backgroundColor = [UIColor colorWithWhite:0.92 alpha:1.0];
|
||||||
@@ -84,4 +85,3 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|||||||
20
keyBoard/Class/Shop/M/KBShopStyleModel.h
Normal file
20
keyBoard/Class/Shop/M/KBShopStyleModel.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
//
|
||||||
|
// KBShopStyleModel.h
|
||||||
|
// keyBoard
|
||||||
|
//
|
||||||
|
// Created by Mac on 2025/12/11.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface KBShopStyleModel : NSObject
|
||||||
|
/// 风格 id
|
||||||
|
@property (nonatomic, copy, nullable) NSString *styleId;
|
||||||
|
/// 风格名称
|
||||||
|
@property (nonatomic, copy, nullable) NSString *styleName;
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
18
keyBoard/Class/Shop/M/KBShopStyleModel.m
Normal file
18
keyBoard/Class/Shop/M/KBShopStyleModel.m
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
//
|
||||||
|
// KBShopStyleModel.m
|
||||||
|
// keyBoard
|
||||||
|
//
|
||||||
|
// Created by Mac on 2025/12/11.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "KBShopStyleModel.h"
|
||||||
|
|
||||||
|
@implementation KBShopStyleModel
|
||||||
|
+ (NSDictionary *)mj_replacedKeyFromPropertyName {
|
||||||
|
return @{
|
||||||
|
@"styleId": @"id",
|
||||||
|
@"styleName": @"styleName"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
34
keyBoard/Class/Shop/M/KBShopThemeModel.h
Normal file
34
keyBoard/Class/Shop/M/KBShopThemeModel.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
//
|
||||||
|
// KBShopThemeModel.h
|
||||||
|
// keyBoard
|
||||||
|
//
|
||||||
|
// Created by Mac on 2025/12/11.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface KBShopThemeModel : NSObject
|
||||||
|
/// 主题 id
|
||||||
|
@property (nonatomic, copy, nullable) NSString *themeId;
|
||||||
|
/// 主题名称
|
||||||
|
@property (nonatomic, copy, nullable) NSString *themeName;
|
||||||
|
/// 价格(单位:接口返回的货币)
|
||||||
|
@property (nonatomic, assign) CGFloat themePrice;
|
||||||
|
/// 标签或风格名称
|
||||||
|
@property (nonatomic, copy, nullable) NSString *themeTag;
|
||||||
|
/// 下载量描述
|
||||||
|
@property (nonatomic, copy, nullable) NSString *themeDownload;
|
||||||
|
/// 风格类型(接口返回 themeStyle)
|
||||||
|
@property (nonatomic, assign) NSInteger themeStyle;
|
||||||
|
/// 是否上架
|
||||||
|
@property (nonatomic, assign, getter=isThemeStatus) BOOL themeStatus;
|
||||||
|
/// 购买次数
|
||||||
|
@property (nonatomic, assign) NSInteger themePurchasesNumber;
|
||||||
|
/// 预览图
|
||||||
|
@property (nonatomic, copy, nullable) NSString *themePreviewImageUrl;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
16
keyBoard/Class/Shop/M/KBShopThemeModel.m
Normal file
16
keyBoard/Class/Shop/M/KBShopThemeModel.m
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
//
|
||||||
|
// KBShopThemeModel.m
|
||||||
|
// keyBoard
|
||||||
|
//
|
||||||
|
// Created by Mac on 2025/12/11.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "KBShopThemeModel.h"
|
||||||
|
|
||||||
|
@implementation KBShopThemeModel
|
||||||
|
+ (NSDictionary *)mj_replacedKeyFromPropertyName {
|
||||||
|
return @{
|
||||||
|
@"themeId": @"id",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@end
|
||||||
@@ -10,17 +10,25 @@
|
|||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@class KBShopStyleModel;
|
||||||
|
@class KBShopVM;
|
||||||
|
@class KBShopThemeModel;
|
||||||
|
|
||||||
@interface KBShopItemVC : UIViewController<JXPagerViewListViewDelegate>
|
@interface KBShopItemVC : UIViewController<JXPagerViewListViewDelegate>
|
||||||
/// 列表:使用 UICollectionView 展示两列皮肤卡片
|
/// 列表:使用 UICollectionView 展示两列皮肤卡片
|
||||||
@property (nonatomic, strong) UICollectionView *collectionView;
|
@property (nonatomic, strong) UICollectionView *collectionView;
|
||||||
/// 数据源:简单字符串作为标题(演示用)
|
/// 数据源:主题列表
|
||||||
@property (nonatomic, strong) NSMutableArray<NSString *> *dataSource;
|
@property (nonatomic, strong) NSMutableArray<KBShopThemeModel *> *dataSource;
|
||||||
/// 是否需要上拉加载更多
|
/// 是否需要上拉加载更多
|
||||||
@property (nonatomic, assign) BOOL isNeedFooter;
|
@property (nonatomic, assign) BOOL isNeedFooter;
|
||||||
/// 是否需要下拉刷新
|
/// 是否需要下拉刷新
|
||||||
@property (nonatomic, assign) BOOL isNeedHeader;
|
@property (nonatomic, assign) BOOL isNeedHeader;
|
||||||
/// 首次是否已刷新过(避免重复触发)
|
/// 首次是否已刷新过(避免重复触发)
|
||||||
@property (nonatomic, assign) BOOL isHeaderRefreshed; // 默认为 YES
|
@property (nonatomic, assign) BOOL isHeaderRefreshed; // 默认为 YES
|
||||||
|
/// 当前所属风格
|
||||||
|
@property (nonatomic, strong, nullable) KBShopStyleModel *style;
|
||||||
|
/// 可复用的 ShopVM(由外部传入,便于共用缓存/网络配置)
|
||||||
|
@property (nonatomic, strong, nullable) KBShopVM *shopViewModel;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
||||||
|
|||||||
@@ -11,9 +11,12 @@
|
|||||||
#import "KBSkinCardCell.h"
|
#import "KBSkinCardCell.h"
|
||||||
#import "KBSkinInstallBridge.h"
|
#import "KBSkinInstallBridge.h"
|
||||||
#import "KBHUD.h"
|
#import "KBHUD.h"
|
||||||
|
#import "KBShopVM.h"
|
||||||
|
|
||||||
@interface KBShopItemVC ()<UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
|
@interface KBShopItemVC ()<UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
|
||||||
@property (nonatomic, copy) void(^scrollCallback)(UIScrollView *scrollView);
|
@property (nonatomic, copy) void(^scrollCallback)(UIScrollView *scrollView);
|
||||||
|
@property (nonatomic, strong) KBShopVM *internalViewModel;
|
||||||
|
@property (nonatomic, assign, getter=isLoading) BOOL loading;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation KBShopItemVC
|
@implementation KBShopItemVC
|
||||||
@@ -21,6 +24,7 @@
|
|||||||
- (void)viewDidLoad {
|
- (void)viewDidLoad {
|
||||||
[super viewDidLoad];
|
[super viewDidLoad];
|
||||||
self.view.backgroundColor = [UIColor clearColor];
|
self.view.backgroundColor = [UIColor clearColor];
|
||||||
|
self.dataSource = [NSMutableArray array];
|
||||||
|
|
||||||
// 懒加载 collectionView,并添加到视图
|
// 懒加载 collectionView,并添加到视图
|
||||||
[self.view addSubview:self.collectionView];
|
[self.view addSubview:self.collectionView];
|
||||||
@@ -28,22 +32,15 @@
|
|||||||
make.edges.equalTo(self.view); // mas 布局:铺满
|
make.edges.equalTo(self.view); // mas 布局:铺满
|
||||||
}];
|
}];
|
||||||
|
|
||||||
// 刷新组件(演示:2 秒后结束)
|
|
||||||
KBWeakSelf
|
KBWeakSelf
|
||||||
if (self.isNeedHeader) {
|
if (self.isNeedHeader) {
|
||||||
self.collectionView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
|
self.collectionView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
|
||||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
[weakSelf fetchThemes];
|
||||||
[weakSelf.collectionView.mj_header endRefreshing];
|
|
||||||
});
|
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
if (self.isNeedFooter) {
|
if (self.isNeedFooter) {
|
||||||
self.collectionView.mj_footer = [MJRefreshAutoNormalFooter footerWithRefreshingBlock:^{
|
self.collectionView.mj_footer = [MJRefreshAutoNormalFooter footerWithRefreshingBlock:^{
|
||||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
[weakSelf fetchThemes];
|
||||||
[weakSelf.dataSource addObject:KBLocalized(@"Loaded more successfully")]; // 模拟新增一条
|
|
||||||
[weakSelf.collectionView reloadData];
|
|
||||||
[weakSelf.collectionView.mj_footer endRefreshing];
|
|
||||||
});
|
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,23 +53,58 @@
|
|||||||
|
|
||||||
// 首次进入自动触发一次刷新(如果需要)
|
// 首次进入自动触发一次刷新(如果需要)
|
||||||
- (void)beginFirstRefresh {
|
- (void)beginFirstRefresh {
|
||||||
if (!self.isHeaderRefreshed) {
|
if (self.isHeaderRefreshed || self.isLoading) {
|
||||||
[self beginRefreshImmediately];
|
return;
|
||||||
}
|
}
|
||||||
|
if (!self.style.styleId.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[self beginRefreshImmediately];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)beginRefreshImmediately {
|
- (void)beginRefreshImmediately {
|
||||||
if (self.isNeedHeader) {
|
if (self.isNeedHeader && !self.collectionView.mj_header.isRefreshing) {
|
||||||
[self.collectionView.mj_header beginRefreshing];
|
[self.collectionView.mj_header beginRefreshing];
|
||||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
||||||
self.isHeaderRefreshed = YES;
|
|
||||||
[self.collectionView reloadData];
|
|
||||||
[self.collectionView.mj_header endRefreshing];
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
self.isHeaderRefreshed = YES;
|
|
||||||
[self.collectionView reloadData];
|
|
||||||
}
|
}
|
||||||
|
[self fetchThemes];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)fetchThemes {
|
||||||
|
if (self.isLoading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NSString *styleId = self.style.styleId;
|
||||||
|
if (!styleId.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.loading = YES;
|
||||||
|
KBShopVM *vm = self.shopViewModel;
|
||||||
|
if (!vm) {
|
||||||
|
if (!self.internalViewModel) {
|
||||||
|
self.internalViewModel = [[KBShopVM alloc] init];
|
||||||
|
}
|
||||||
|
vm = self.internalViewModel;
|
||||||
|
}
|
||||||
|
KBWeakSelf
|
||||||
|
[vm fetchThemesForStyleId:styleId completion:^(NSArray<KBShopThemeModel *> * _Nullable themes, NSError * _Nullable error) {
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
weakSelf.loading = NO;
|
||||||
|
weakSelf.isHeaderRefreshed = YES;
|
||||||
|
if (error) {
|
||||||
|
NSString *msg = error.localizedDescription ?: KBLocalized(@"Network error");
|
||||||
|
[KBHUD showInfo:msg];
|
||||||
|
} else {
|
||||||
|
weakSelf.dataSource = themes.count ? themes.mutableCopy : [NSMutableArray array];
|
||||||
|
[weakSelf.collectionView reloadData];
|
||||||
|
}
|
||||||
|
if ([weakSelf.collectionView.mj_header isRefreshing]) {
|
||||||
|
[weakSelf.collectionView.mj_header endRefreshing];
|
||||||
|
}
|
||||||
|
if ([weakSelf.collectionView.mj_footer isRefreshing]) {
|
||||||
|
[weakSelf.collectionView.mj_footer endRefreshing];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - UICollectionView DataSource
|
#pragma mark - UICollectionView DataSource
|
||||||
@@ -84,8 +116,10 @@
|
|||||||
|
|
||||||
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
KBSkinCardCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"KBSkinCardCell" forIndexPath:indexPath];
|
KBSkinCardCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"KBSkinCardCell" forIndexPath:indexPath];
|
||||||
NSString *title = (indexPath.item < self.dataSource.count) ? self.dataSource[indexPath.item] : @"Dopamine";
|
KBShopThemeModel *theme = (indexPath.item < self.dataSource.count) ? self.dataSource[indexPath.item] : nil;
|
||||||
[cell configWithTitle:title imageURL:nil price:@"20"]; // 价格写死 20(演示)
|
NSString *title = theme.themeName.length ? theme.themeName : KBLocalized(@"Themes");
|
||||||
|
NSString *price = [self kb_priceStringForTheme:theme];
|
||||||
|
[cell configWithTitle:title imageURL:nil price:price];
|
||||||
return cell;
|
return cell;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,8 +151,28 @@
|
|||||||
[self kb_handleShopTapAtIndexPath:indexPath];
|
[self kb_handleShopTapAtIndexPath:indexPath];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSString *)kb_priceStringForTheme:(KBShopThemeModel *)theme {
|
||||||
|
if (!theme) {
|
||||||
|
return @"";
|
||||||
|
}
|
||||||
|
if (theme.themePrice <= 0.0f) {
|
||||||
|
return KBLocalized(@"Free");
|
||||||
|
}
|
||||||
|
static NSNumberFormatter *formatter;
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
formatter = [[NSNumberFormatter alloc] init];
|
||||||
|
formatter.minimumFractionDigits = 0;
|
||||||
|
formatter.maximumFractionDigits = 2;
|
||||||
|
formatter.minimumIntegerDigits = 1;
|
||||||
|
});
|
||||||
|
NSString *priceString = [formatter stringFromNumber:@(theme.themePrice)];
|
||||||
|
return priceString ?: [NSString stringWithFormat:@"%.2f", theme.themePrice];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)kb_handleShopTapAtIndexPath:(NSIndexPath *)indexPath {
|
- (void)kb_handleShopTapAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
NSString *title = (indexPath.item < self.dataSource.count) ? self.dataSource[indexPath.item] : KBLocalized(@"专属皮肤002");
|
KBShopThemeModel *theme = (indexPath.item < self.dataSource.count) ? self.dataSource[indexPath.item] : nil;
|
||||||
|
NSString *title = theme.themeName.length ? theme.themeName : KBLocalized(@"专属皮肤002");
|
||||||
// 将需求固定到 002.zip,本地写死皮肤 id,便于键盘扩展识别并解压。
|
// 将需求固定到 002.zip,本地写死皮肤 id,便于键盘扩展识别并解压。
|
||||||
static NSString * const kKBBundleSkinId002 = @"bundle_skin_fense";
|
static NSString * const kKBBundleSkinId002 = @"bundle_skin_fense";
|
||||||
[KBSkinInstallBridge publishBundleSkinRequestWithId:kKBBundleSkinId002
|
[KBSkinInstallBridge publishBundleSkinRequestWithId:kKBBundleSkinId002
|
||||||
@@ -128,6 +182,13 @@
|
|||||||
[KBHUD showInfo:KBLocalized(@"已通知键盘解压,切换到自定义键盘即可生效")];
|
[KBHUD showInfo:KBLocalized(@"已通知键盘解压,切换到自定义键盘即可生效")];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setStyle:(KBShopStyleModel *)style {
|
||||||
|
_style = style;
|
||||||
|
if (self.isViewLoaded && !self.isHeaderRefreshed) {
|
||||||
|
[self beginFirstRefresh];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - UIScrollView Delegate(转发给分页容器)
|
#pragma mark - UIScrollView Delegate(转发给分页容器)
|
||||||
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
|
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
|
||||||
!self.scrollCallback ?: self.scrollCallback(scrollView);
|
!self.scrollCallback ?: self.scrollCallback(scrollView);
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
|
|
||||||
#import "KBWebViewViewController.h"
|
#import "KBWebViewViewController.h"
|
||||||
|
#import "KBShopVM.h"
|
||||||
|
#import "KBHUD.h"
|
||||||
|
|
||||||
static const CGFloat JXTableHeaderViewHeight = (323);
|
static const CGFloat JXTableHeaderViewHeight = (323);
|
||||||
static const CGFloat JXheightForHeaderInSection = 50;
|
static const CGFloat JXheightForHeaderInSection = 50;
|
||||||
@@ -33,11 +35,13 @@ static const CGFloat JXheightForHeaderInSection = 50;
|
|||||||
|
|
||||||
@property (nonatomic, strong) JXCategoryTitleView *categoryView;
|
@property (nonatomic, strong) JXCategoryTitleView *categoryView;
|
||||||
@property (nonatomic, strong) NSArray <NSString *> *titles;
|
@property (nonatomic, strong) NSArray <NSString *> *titles;
|
||||||
|
@property (nonatomic, copy) NSArray<KBShopStyleModel *> *styles;
|
||||||
@property (nonatomic, strong) UIImageView *bgImageView; // 全屏背景图
|
@property (nonatomic, strong) UIImageView *bgImageView; // 全屏背景图
|
||||||
@property (nonatomic, strong) UIButton *searchBtn;
|
@property (nonatomic, strong) UIButton *searchBtn;
|
||||||
@property (nonatomic, strong) UIButton *skinBtn;
|
@property (nonatomic, strong) UIButton *skinBtn;
|
||||||
// 记录当前分类条是否为白底,避免重复设置
|
// 记录当前分类条是否为白底,避免重复设置
|
||||||
@property (nonatomic, assign) BOOL categoryIsWhite;
|
@property (nonatomic, assign) BOOL categoryIsWhite;
|
||||||
|
@property (nonatomic, strong) KBShopVM *shopVM;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@@ -65,6 +69,7 @@ static const CGFloat JXheightForHeaderInSection = 50;
|
|||||||
make.width.height.mas_equalTo(25);
|
make.width.height.mas_equalTo(25);
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
[self fetchShopStylesWithHUD:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 系统导航栏显隐由 Base 统一管理(全局隐藏),该 VC 不再手动切换,避免闪烁。
|
// 系统导航栏显隐由 Base 统一管理(全局隐藏),该 VC 不再手动切换,避免闪烁。
|
||||||
@@ -76,10 +81,8 @@ static const CGFloat JXheightForHeaderInSection = 50;
|
|||||||
self.view.backgroundColor = [UIColor whiteColor];
|
self.view.backgroundColor = [UIColor whiteColor];
|
||||||
self.navigationController.navigationBar.translucent = false;
|
self.navigationController.navigationBar.translucent = false;
|
||||||
self.edgesForExtendedLayout = UIRectEdgeNone;
|
self.edgesForExtendedLayout = UIRectEdgeNone;
|
||||||
_titles = @[KBLocalized(@"能力"), KBLocalized(@"爱好"), KBLocalized(@"队友"),
|
self.styles = @[];
|
||||||
KBLocalized(@"能力2"), KBLocalized(@"爱好2"), KBLocalized(@"队友2"),
|
_titles = @[];
|
||||||
KBLocalized(@"能力"), KBLocalized(@"爱好"), KBLocalized(@"队友"),
|
|
||||||
KBLocalized(@"能力2"), KBLocalized(@"爱好2"), KBLocalized(@"队友2")];
|
|
||||||
|
|
||||||
_userHeaderView = [[KBShopHeadView alloc] init];
|
_userHeaderView = [[KBShopHeadView alloc] init];
|
||||||
_categoryView = (JXCategoryTitleView *)[[KBCategoryTitleView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, JXheightForHeaderInSection)];
|
_categoryView = (JXCategoryTitleView *)[[KBCategoryTitleView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, JXheightForHeaderInSection)];
|
||||||
@@ -133,13 +136,7 @@ static const CGFloat JXheightForHeaderInSection = 50;
|
|||||||
|
|
||||||
__weak typeof(self)weakSelf = self;
|
__weak typeof(self)weakSelf = self;
|
||||||
self.pagerView.mainTableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
|
self.pagerView.mainTableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
|
||||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
[weakSelf fetchShopStylesWithHUD:NO];
|
||||||
self.categoryView.titles = @[KBLocalized(@"高级能力"), KBLocalized(@"高级爱好"), KBLocalized(@"高级队友")];
|
|
||||||
self.categoryView.defaultSelectedIndex = 0;
|
|
||||||
[self.categoryView reloadData];
|
|
||||||
[self.pagerView reloadData];
|
|
||||||
[weakSelf.pagerView.mainTableView.mj_header endRefreshing];
|
|
||||||
});
|
|
||||||
}];
|
}];
|
||||||
|
|
||||||
self.pagerView.pinSectionHeaderVerticalOffset = KB_NAV_TOTAL_HEIGHT;
|
self.pagerView.pinSectionHeaderVerticalOffset = KB_NAV_TOTAL_HEIGHT;
|
||||||
@@ -194,19 +191,9 @@ static const CGFloat JXheightForHeaderInSection = 50;
|
|||||||
list.title = self.titles[index];
|
list.title = self.titles[index];
|
||||||
list.isNeedHeader = self.isNeedHeader;
|
list.isNeedHeader = self.isNeedHeader;
|
||||||
list.isNeedFooter = self.isNeedFooter;
|
list.isNeedFooter = self.isNeedFooter;
|
||||||
if (index == 0) {
|
list.shopViewModel = self.shopVM;
|
||||||
list.dataSource = @[KBLocalized(@"橡胶火箭"), KBLocalized(@"橡胶火箭炮"), KBLocalized(@"橡胶机关枪"), KBLocalized(@"橡胶子弹"),
|
if (index < self.styles.count) {
|
||||||
KBLocalized(@"橡胶攻城炮"), KBLocalized(@"橡胶象枪"), KBLocalized(@"橡胶象枪乱打"), KBLocalized(@"橡胶灰熊铳"),
|
list.style = self.styles[index];
|
||||||
KBLocalized(@"橡胶雷神象枪"), KBLocalized(@"橡胶猿王枪"), KBLocalized(@"橡胶犀·榴弹炮"), KBLocalized(@"橡胶大蛇炮"),
|
|
||||||
KBLocalized(@"橡胶火箭"), KBLocalized(@"橡胶火箭炮"), KBLocalized(@"橡胶机关枪"), KBLocalized(@"橡胶子弹"),
|
|
||||||
KBLocalized(@"橡胶攻城炮"), KBLocalized(@"橡胶象枪"), KBLocalized(@"橡胶象枪乱打"), KBLocalized(@"橡胶灰熊铳"),
|
|
||||||
KBLocalized(@"橡胶雷神象枪"), KBLocalized(@"橡胶猿王枪"), KBLocalized(@"橡胶犀·榴弹炮"), KBLocalized(@"橡胶大蛇炮")].mutableCopy;
|
|
||||||
}else if (index == 1) {
|
|
||||||
list.dataSource = @[KBLocalized(@"吃烤肉"), KBLocalized(@"吃鸡腿肉"), KBLocalized(@"吃牛肉"), KBLocalized(@"各种肉")].mutableCopy;
|
|
||||||
}else {
|
|
||||||
list.dataSource = @[KBLocalized(@"【剑士】罗罗诺亚·索隆"), KBLocalized(@"【航海士】娜美"), KBLocalized(@"【狙击手】乌索普"),
|
|
||||||
KBLocalized(@"【厨师】香吉士"), KBLocalized(@"【船医】托尼托尼·乔巴"), KBLocalized(@"【船匠】 弗兰奇"),
|
|
||||||
KBLocalized(@"【音乐家】布鲁克"), KBLocalized(@"【考古学家】妮可·罗宾")].mutableCopy;
|
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
@@ -277,4 +264,46 @@ static const CGFloat JXheightForHeaderInSection = 50;
|
|||||||
}
|
}
|
||||||
return _skinBtn;
|
return _skinBtn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (KBShopVM *)shopVM {
|
||||||
|
if (!_shopVM) {
|
||||||
|
_shopVM = [[KBShopVM alloc] init];
|
||||||
|
}
|
||||||
|
return _shopVM;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)fetchShopStylesWithHUD:(BOOL)showHUD {
|
||||||
|
if (showHUD) {
|
||||||
|
[KBHUD show];
|
||||||
|
}
|
||||||
|
__weak typeof(self) weakSelf = self;
|
||||||
|
[self.shopVM fetchAllStylesWithCompletion:^(NSArray<KBShopStyleModel *> * _Nullable styles, NSError * _Nullable error) {
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
if (showHUD) {
|
||||||
|
[KBHUD dismiss];
|
||||||
|
}
|
||||||
|
[weakSelf.pagerView.mainTableView.mj_header endRefreshing];
|
||||||
|
if (error) {
|
||||||
|
NSString *msg = error.localizedDescription ?: KBLocalized(@"Network error");
|
||||||
|
[KBHUD showInfo:msg];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[weakSelf applyStyles:styles];
|
||||||
|
});
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applyStyles:(NSArray<KBShopStyleModel *> *)styles {
|
||||||
|
self.styles = styles ?: @[];
|
||||||
|
NSMutableArray *names = [NSMutableArray array];
|
||||||
|
for (KBShopStyleModel *style in self.styles) {
|
||||||
|
NSString *name = style.styleName.length ? style.styleName : KBLocalized(@"Themes");
|
||||||
|
[names addObject:name];
|
||||||
|
}
|
||||||
|
self.titles = names.copy;
|
||||||
|
self.categoryView.titles = self.titles;
|
||||||
|
self.categoryView.defaultSelectedIndex = 0;
|
||||||
|
[self.categoryView reloadData];
|
||||||
|
[self.pagerView reloadData];
|
||||||
|
}
|
||||||
@end
|
@end
|
||||||
|
|||||||
34
keyBoard/Class/Shop/VM/KBShopVM.h
Normal file
34
keyBoard/Class/Shop/VM/KBShopVM.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
//
|
||||||
|
// KBShopVM.h
|
||||||
|
// keyBoard
|
||||||
|
//
|
||||||
|
// Created by Mac on 2025/12/9.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <CoreGraphics/CoreGraphics.h>
|
||||||
|
#import "KBShopStyleModel.h"
|
||||||
|
#import "KBShopThemeModel.h"
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
#pragma mark - Models
|
||||||
|
|
||||||
|
typedef void(^KBShopStylesCompletion)(NSArray<KBShopStyleModel *> *_Nullable styles,
|
||||||
|
NSError *_Nullable error);
|
||||||
|
typedef void(^KBShopThemesCompletion)(NSArray<KBShopThemeModel *> *_Nullable themes,
|
||||||
|
NSError *_Nullable error);
|
||||||
|
|
||||||
|
@interface KBShopVM : NSObject
|
||||||
|
@property (nonatomic, copy, readonly, nullable) NSArray<KBShopStyleModel *> *styles;
|
||||||
|
|
||||||
|
/// 查询全部主题风格
|
||||||
|
- (void)fetchAllStylesWithCompletion:(KBShopStylesCompletion)completion;
|
||||||
|
|
||||||
|
/// 按风格请求主题列表
|
||||||
|
- (void)fetchThemesForStyleId:(nullable NSString *)styleId
|
||||||
|
completion:(KBShopThemesCompletion)completion;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
85
keyBoard/Class/Shop/VM/KBShopVM.m
Normal file
85
keyBoard/Class/Shop/VM/KBShopVM.m
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
//
|
||||||
|
// KBShopVM.m
|
||||||
|
// keyBoard
|
||||||
|
//
|
||||||
|
// Created by Mac on 2025/12/9.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "KBShopVM.h"
|
||||||
|
#import "KBNetworkManager.h"
|
||||||
|
#import "KBAPI.h"
|
||||||
|
#import "KBBizCode.h"
|
||||||
|
#import <MJExtension/MJExtension.h>
|
||||||
|
|
||||||
|
@interface KBShopVM ()
|
||||||
|
@property (nonatomic, copy, readwrite, nullable) NSArray<KBShopStyleModel *> *styles;
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
@implementation KBShopVM
|
||||||
|
|
||||||
|
- (NSError *)kb_invalidResponseError {
|
||||||
|
return [NSError errorWithDomain:KBNetworkErrorDomain
|
||||||
|
code:KBNetworkErrorInvalidResponse
|
||||||
|
userInfo:@{NSLocalizedDescriptionKey: KBLocalized(@"Invalid response")}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSError *)kb_invalidParameterError {
|
||||||
|
return [NSError errorWithDomain:KBNetworkErrorDomain
|
||||||
|
code:KBNetworkErrorInvalidResponse
|
||||||
|
userInfo:@{NSLocalizedDescriptionKey: KBLocalized(@"Invalid parameter")}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)fetchAllStylesWithCompletion:(KBShopStylesCompletion)completion {
|
||||||
|
[[KBNetworkManager shared] GET:API_THEME_LIST_ALL_STYLES
|
||||||
|
parameters:nil
|
||||||
|
headers:nil
|
||||||
|
autoShowBusinessError:NO
|
||||||
|
completion:^(NSDictionary * _Nullable json,
|
||||||
|
NSURLResponse * _Nullable response,
|
||||||
|
NSError * _Nullable error) {
|
||||||
|
if (error) {
|
||||||
|
if (completion) completion(nil, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
id dataObj = json[KBData] ?: json[@"data"];
|
||||||
|
if (![dataObj isKindOfClass:[NSArray class]]) {
|
||||||
|
if (completion) completion(nil, [self kb_invalidResponseError]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NSArray<KBShopStyleModel *> *list = [KBShopStyleModel mj_objectArrayWithKeyValuesArray:(NSArray *)dataObj];
|
||||||
|
self.styles = list;
|
||||||
|
if (completion) completion(list, nil);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)fetchThemesForStyleId:(nullable NSString *)styleId
|
||||||
|
completion:(KBShopThemesCompletion)completion {
|
||||||
|
if (styleId.length == 0) {
|
||||||
|
if (completion) completion(nil, [self kb_invalidParameterError]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NSMutableDictionary *params = [NSMutableDictionary dictionary];
|
||||||
|
params[@"themeStyle"] = @([styleId integerValue]);
|
||||||
|
[[KBNetworkManager shared] GET:API_THEME_LIST_BY_STYLE
|
||||||
|
parameters:params
|
||||||
|
headers:nil
|
||||||
|
autoShowBusinessError:NO
|
||||||
|
completion:^(NSDictionary * _Nullable json,
|
||||||
|
NSURLResponse * _Nullable response,
|
||||||
|
NSError * _Nullable error) {
|
||||||
|
if (error) {
|
||||||
|
if (completion) completion(nil, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
id dataObj = json[KBData] ?: json[@"data"];
|
||||||
|
if (![dataObj isKindOfClass:[NSArray class]]) {
|
||||||
|
if (completion) completion(nil, [self kb_invalidResponseError]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NSArray<KBShopThemeModel *> *list = [KBShopThemeModel mj_objectArrayWithKeyValuesArray:(NSArray *)dataObj];
|
||||||
|
if (completion) completion(list, nil);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
Reference in New Issue
Block a user