1
This commit is contained in:
@@ -57,6 +57,7 @@
|
|||||||
|
|
||||||
/// pay
|
/// pay
|
||||||
#define API_VALIDATE_RECEIPT @"/api/apple/validate-receipt" // 排行榜标签列表
|
#define API_VALIDATE_RECEIPT @"/api/apple/validate-receipt" // 排行榜标签列表
|
||||||
|
#define API_INAPP_PRODUCT_LIST @"/products/inApp/list" // 查询 type=in-app-purchase 的商品列表
|
||||||
|
|
||||||
/// AI
|
/// AI
|
||||||
#define API_AI_TALK @"/chat/talk" // 排行榜标签列表
|
#define API_AI_TALK @"/chat/talk" // 排行榜标签列表
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
04122F872EC6198C00EF7AB3 /* WMDragView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04122F852EC6198C00EF7AB3 /* WMDragView.m */; };
|
04122F872EC6198C00EF7AB3 /* WMDragView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04122F852EC6198C00EF7AB3 /* WMDragView.m */; };
|
||||||
04122F882EC6F07F00EF7AB3 /* KBFullAccessManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 04A9FE112EB4D0D20020DB6D /* KBFullAccessManager.m */; };
|
04122F882EC6F07F00EF7AB3 /* KBFullAccessManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 04A9FE112EB4D0D20020DB6D /* KBFullAccessManager.m */; };
|
||||||
04122F8B2EC6F7C800EF7AB3 /* IAPVerifyTransactionObj.m in Sources */ = {isa = PBXBuildFile; fileRef = 04122F8A2EC6F7C800EF7AB3 /* IAPVerifyTransactionObj.m */; };
|
04122F8B2EC6F7C800EF7AB3 /* IAPVerifyTransactionObj.m in Sources */ = {isa = PBXBuildFile; fileRef = 04122F8A2EC6F7C800EF7AB3 /* IAPVerifyTransactionObj.m */; };
|
||||||
|
04B5A1A22EEFA12300AAAAAA /* KBPayProductModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 04B5A1A12EEFA12300AAAAAA /* KBPayProductModel.m */; };
|
||||||
04122F8E2EC6F83F00EF7AB3 /* PayVM.m in Sources */ = {isa = PBXBuildFile; fileRef = 04122F8D2EC6F83F00EF7AB3 /* PayVM.m */; };
|
04122F8E2EC6F83F00EF7AB3 /* PayVM.m in Sources */ = {isa = PBXBuildFile; fileRef = 04122F8D2EC6F83F00EF7AB3 /* PayVM.m */; };
|
||||||
04122F912EC73AF700EF7AB3 /* KBVipPay.m in Sources */ = {isa = PBXBuildFile; fileRef = 04122F902EC73AF700EF7AB3 /* KBVipPay.m */; };
|
04122F912EC73AF700EF7AB3 /* KBVipPay.m in Sources */ = {isa = PBXBuildFile; fileRef = 04122F902EC73AF700EF7AB3 /* KBVipPay.m */; };
|
||||||
04122FAA2EC73C0100EF7AB3 /* KBVipPayHeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04122FA92EC73C0100EF7AB3 /* KBVipPayHeaderView.m */; };
|
04122FAA2EC73C0100EF7AB3 /* KBVipPayHeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04122FA92EC73C0100EF7AB3 /* KBVipPayHeaderView.m */; };
|
||||||
@@ -247,6 +248,8 @@
|
|||||||
04122F852EC6198C00EF7AB3 /* WMDragView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WMDragView.m; sourceTree = "<group>"; };
|
04122F852EC6198C00EF7AB3 /* WMDragView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WMDragView.m; sourceTree = "<group>"; };
|
||||||
04122F892EC6F7C800EF7AB3 /* IAPVerifyTransactionObj.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IAPVerifyTransactionObj.h; sourceTree = "<group>"; };
|
04122F892EC6F7C800EF7AB3 /* IAPVerifyTransactionObj.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IAPVerifyTransactionObj.h; sourceTree = "<group>"; };
|
||||||
04122F8A2EC6F7C800EF7AB3 /* IAPVerifyTransactionObj.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IAPVerifyTransactionObj.m; sourceTree = "<group>"; };
|
04122F8A2EC6F7C800EF7AB3 /* IAPVerifyTransactionObj.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IAPVerifyTransactionObj.m; sourceTree = "<group>"; };
|
||||||
|
04B5A1A02EEFA12300AAAAAA /* KBPayProductModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBPayProductModel.h; sourceTree = "<group>"; };
|
||||||
|
04B5A1A12EEFA12300AAAAAA /* KBPayProductModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBPayProductModel.m; sourceTree = "<group>"; };
|
||||||
04122F8C2EC6F83F00EF7AB3 /* PayVM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PayVM.h; sourceTree = "<group>"; };
|
04122F8C2EC6F83F00EF7AB3 /* PayVM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PayVM.h; sourceTree = "<group>"; };
|
||||||
04122F8D2EC6F83F00EF7AB3 /* PayVM.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PayVM.m; sourceTree = "<group>"; };
|
04122F8D2EC6F83F00EF7AB3 /* PayVM.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PayVM.m; sourceTree = "<group>"; };
|
||||||
04122F8F2EC73AF700EF7AB3 /* KBVipPay.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBVipPay.h; sourceTree = "<group>"; };
|
04122F8F2EC73AF700EF7AB3 /* KBVipPay.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBVipPay.h; sourceTree = "<group>"; };
|
||||||
@@ -625,6 +628,8 @@
|
|||||||
children = (
|
children = (
|
||||||
04122F892EC6F7C800EF7AB3 /* IAPVerifyTransactionObj.h */,
|
04122F892EC6F7C800EF7AB3 /* IAPVerifyTransactionObj.h */,
|
||||||
04122F8A2EC6F7C800EF7AB3 /* IAPVerifyTransactionObj.m */,
|
04122F8A2EC6F7C800EF7AB3 /* IAPVerifyTransactionObj.m */,
|
||||||
|
04B5A1A02EEFA12300AAAAAA /* KBPayProductModel.h */,
|
||||||
|
04B5A1A12EEFA12300AAAAAA /* KBPayProductModel.m */,
|
||||||
);
|
);
|
||||||
path = M;
|
path = M;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -1748,6 +1753,7 @@
|
|||||||
04122F882EC6F07F00EF7AB3 /* KBFullAccessManager.m in Sources */,
|
04122F882EC6F07F00EF7AB3 /* KBFullAccessManager.m in Sources */,
|
||||||
04122F622EC5F41D00EF7AB3 /* KBUser.m in Sources */,
|
04122F622EC5F41D00EF7AB3 /* KBUser.m in Sources */,
|
||||||
04122F8B2EC6F7C800EF7AB3 /* IAPVerifyTransactionObj.m in Sources */,
|
04122F8B2EC6F7C800EF7AB3 /* IAPVerifyTransactionObj.m in Sources */,
|
||||||
|
04B5A1A22EEFA12300AAAAAA /* KBPayProductModel.m in Sources */,
|
||||||
04286A062ECC81B200CE730C /* KBSkinService.m in Sources */,
|
04286A062ECC81B200CE730C /* KBSkinService.m in Sources */,
|
||||||
0479204A2EDDCE25004E8522 /* KBUserSessionManager.m in Sources */,
|
0479204A2EDDCE25004E8522 /* KBUserSessionManager.m in Sources */,
|
||||||
04122FAD2EC73C0100EF7AB3 /* KBVipSubscribeCell.m in Sources */,
|
04122FAD2EC73C0100EF7AB3 /* KBVipSubscribeCell.m in Sources */,
|
||||||
|
|||||||
@@ -45,8 +45,10 @@
|
|||||||
[KBHUD showInfo:(sta == !KBBizCodeSuccess ? KBLocalized(@"Payment failed") : KBLocalized(@"Payment successful"))];
|
[KBHUD showInfo:(sta == !KBBizCodeSuccess ? KBLocalized(@"Payment failed") : KBLocalized(@"Payment successful"))];
|
||||||
if (sta == KBBizCodeSuccess) {
|
if (sta == KBBizCodeSuccess) {
|
||||||
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
|
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
|
||||||
|
[KBHUD showSuccess:@"Success"];
|
||||||
if (handler) handler(KBLocalized(@"Success"), nil);
|
if (handler) handler(KBLocalized(@"Success"), nil);
|
||||||
} else {
|
} else {
|
||||||
|
[KBHUD showError:@"Failed"];
|
||||||
if (handler) handler(KBLocalized(@"Failed"), nil);
|
if (handler) handler(KBLocalized(@"Failed"), nil);
|
||||||
}
|
}
|
||||||
(void)weakSelf; // keep self during block life if needed
|
(void)weakSelf; // keep self during block life if needed
|
||||||
|
|||||||
44
keyBoard/Class/Pay/M/KBPayProductModel.h
Normal file
44
keyBoard/Class/Pay/M/KBPayProductModel.h
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
//
|
||||||
|
// KBPayProductModel.h
|
||||||
|
// keyBoard
|
||||||
|
//
|
||||||
|
// Created to map /products/inApp/list responses to strongly typed objects.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
/// 内购商品模型
|
||||||
|
@interface KBPayProductModel : NSObject
|
||||||
|
/// 主键 id
|
||||||
|
@property (nonatomic, assign) NSInteger identifier;
|
||||||
|
/// Apple IAP 商品编号
|
||||||
|
@property (nonatomic, copy, nullable) NSString *productId;
|
||||||
|
/// 商品类型(例如 in-app-purchase)
|
||||||
|
@property (nonatomic, copy, nullable) NSString *type;
|
||||||
|
/// 商品名称(如 100、1000)
|
||||||
|
@property (nonatomic, copy, nullable) NSString *name;
|
||||||
|
/// 单位(如 金币)
|
||||||
|
@property (nonatomic, copy, nullable) NSString *unit;
|
||||||
|
/// 有效期数值(可能为 0)
|
||||||
|
@property (nonatomic, assign) NSInteger durationValue;
|
||||||
|
/// 有效期单位(如 day/week)
|
||||||
|
@property (nonatomic, copy, nullable) NSString *durationUnit;
|
||||||
|
/// 有效期天数
|
||||||
|
@property (nonatomic, assign) NSInteger durationDays;
|
||||||
|
/// 价格
|
||||||
|
@property (nonatomic, assign) double price;
|
||||||
|
/// 货币符号
|
||||||
|
@property (nonatomic, copy, nullable) NSString *currency;
|
||||||
|
/// 文案描述
|
||||||
|
@property (nonatomic, copy, nullable) NSString *productDescription;
|
||||||
|
|
||||||
|
/// 展示金币(自动拼接单位)
|
||||||
|
- (NSString *)coinsDisplayText;
|
||||||
|
/// 展示价格,保留两位小数
|
||||||
|
- (NSString *)priceDisplayText;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
38
keyBoard/Class/Pay/M/KBPayProductModel.m
Normal file
38
keyBoard/Class/Pay/M/KBPayProductModel.m
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
//
|
||||||
|
// KBPayProductModel.m
|
||||||
|
// keyBoard
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "KBPayProductModel.h"
|
||||||
|
#import <MJExtension/MJExtension.h>
|
||||||
|
|
||||||
|
@implementation KBPayProductModel
|
||||||
|
|
||||||
|
+ (NSDictionary *)mj_replacedKeyFromPropertyName {
|
||||||
|
return @{
|
||||||
|
@"identifier": @"id",
|
||||||
|
@"productDescription": @"description",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)coinsDisplayText {
|
||||||
|
NSString *name = self.name ?: @"";
|
||||||
|
NSString *unit = self.unit ?: @"";
|
||||||
|
if (name.length && unit.length) {
|
||||||
|
return [NSString stringWithFormat:@"%@ %@", name, unit];
|
||||||
|
}
|
||||||
|
if (name.length) { return name; }
|
||||||
|
if (unit.length) { return unit; }
|
||||||
|
return @"";
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)priceDisplayText {
|
||||||
|
NSString *currency = self.currency ?: @"";
|
||||||
|
double priceValue = self.price;
|
||||||
|
if (currency.length > 0) {
|
||||||
|
return [NSString stringWithFormat:@"%@%.2f", currency, priceValue];
|
||||||
|
}
|
||||||
|
return [NSString stringWithFormat:@"%.2f", priceValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -6,6 +6,9 @@
|
|||||||
#import "KBJfPayCell.h"
|
#import "KBJfPayCell.h"
|
||||||
#import "FGIAPProductsFilter.h"
|
#import "FGIAPProductsFilter.h"
|
||||||
#import "FGIAPManager.h"
|
#import "FGIAPManager.h"
|
||||||
|
#import "PayVM.h"
|
||||||
|
#import "KBPayProductModel.h"
|
||||||
|
#import "KBBizCode.h"
|
||||||
static NSString * const kKBJfPayCellId = @"kKBJfPayCellId";
|
static NSString * const kKBJfPayCellId = @"kKBJfPayCellId";
|
||||||
|
|
||||||
@interface KBJfPay () <UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
|
@interface KBJfPay () <UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
|
||||||
@@ -32,10 +35,11 @@ static NSString * const kKBJfPayCellId = @"kKBJfPayCellId";
|
|||||||
@property (nonatomic, strong) UIButton *agreementButton;
|
@property (nonatomic, strong) UIButton *agreementButton;
|
||||||
|
|
||||||
// 数据
|
// 数据
|
||||||
@property (nonatomic, strong) NSArray<NSDictionary *> *data; // 简单演示数据:@{coins, price}
|
@property (nonatomic, strong) NSArray<KBPayProductModel *> *data; // In-App 商品展示数据
|
||||||
@property (nonatomic, assign) NSInteger selectedIndex; // 当前选中项
|
@property (nonatomic, assign) NSInteger selectedIndex; // 当前选中项
|
||||||
|
|
||||||
@property (nonatomic, strong) FGIAPProductsFilter *filter;
|
@property (nonatomic, strong) FGIAPProductsFilter *filter;
|
||||||
|
@property (nonatomic, strong) PayVM *payVM;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@@ -44,6 +48,9 @@ static NSString * const kKBJfPayCellId = @"kKBJfPayCellId";
|
|||||||
- (void)viewDidLoad {
|
- (void)viewDidLoad {
|
||||||
[super viewDidLoad];
|
[super viewDidLoad];
|
||||||
self.filter = [[FGIAPProductsFilter alloc] init];
|
self.filter = [[FGIAPProductsFilter alloc] init];
|
||||||
|
self.payVM = [PayVM new];
|
||||||
|
self.data = @[];
|
||||||
|
self.selectedIndex = NSNotFound;
|
||||||
self.bgImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"my_bg_icon"]];
|
self.bgImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"my_bg_icon"]];
|
||||||
self.bgImageView.contentMode = UIViewContentModeScaleAspectFill;
|
self.bgImageView.contentMode = UIViewContentModeScaleAspectFill;
|
||||||
self.kb_navView.backgroundColor = [UIColor clearColor];
|
self.kb_navView.backgroundColor = [UIColor clearColor];
|
||||||
@@ -53,17 +60,6 @@ static NSString * const kKBJfPayCellId = @"kKBJfPayCellId";
|
|||||||
}];
|
}];
|
||||||
self.kb_titleLabel.text = KBLocalized(@"Points Recharge");
|
self.kb_titleLabel.text = KBLocalized(@"Points Recharge");
|
||||||
|
|
||||||
// 默认数据(演示)
|
|
||||||
self.data = @[
|
|
||||||
@{ @"coins": @690, @"price": @"$6.90",@"product_id" : @"100_coin" },
|
|
||||||
@{ @"coins": @1280, @"price": @"$12.90" ,@"product_id" : @"vip_a_week" },
|
|
||||||
@{ @"coins": @3290, @"price": @"$32.90" ,@"product_id" : @"100_coin" },
|
|
||||||
@{ @"coins": @4990, @"price": @"$49.90" ,@"product_id" : @"100_coin" },
|
|
||||||
@{ @"coins": @9990, @"price": @"$99.90" ,@"product_id" : @"100_coin" },
|
|
||||||
@{ @"coins": @19990,@"price": @"$199.90" ,@"product_id" : @"100_coin" },
|
|
||||||
];
|
|
||||||
self.selectedIndex = 0;
|
|
||||||
|
|
||||||
// 视图组装
|
// 视图组装
|
||||||
[self.view addSubview:self.myPointsTitleLabel];
|
[self.view addSubview:self.myPointsTitleLabel];
|
||||||
[self.view addSubview:self.pointsLabel];
|
[self.view addSubview:self.pointsLabel];
|
||||||
@@ -139,34 +135,19 @@ static NSString * const kKBJfPayCellId = @"kKBJfPayCellId";
|
|||||||
// 刷新
|
// 刷新
|
||||||
[self.collectionView reloadData];
|
[self.collectionView reloadData];
|
||||||
|
|
||||||
// 确保首次进入就出现选中态外边框与阴影
|
[self fetchInAppProductList];
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
|
||||||
NSIndexPath *ip = [NSIndexPath indexPathForItem:self.selectedIndex inSection:0];
|
|
||||||
// 让系统层面也处于选中态,便于 setSelected 同步 UI
|
|
||||||
if (ip) {
|
|
||||||
[self.collectionView selectItemAtIndexPath:ip animated:NO scrollPosition:UICollectionViewScrollPositionNone];
|
|
||||||
}
|
|
||||||
KBJfPayCell *cell = (KBJfPayCell *)[self.collectionView cellForItemAtIndexPath:ip];
|
|
||||||
if (cell) { [cell applySelected:YES animated:NO]; }
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewDidAppear:(BOOL)animated {
|
- (void)viewDidAppear:(BOOL)animated {
|
||||||
[super viewDidAppear:animated];
|
[super viewDidAppear:animated];
|
||||||
// 再兜底一次(某些布局时机下,首屏 reload 后 cell 还未可见)
|
[self selectItemAtCurrentIndexAnimated:NO];
|
||||||
NSIndexPath *ip = [NSIndexPath indexPathForItem:self.selectedIndex inSection:0];
|
|
||||||
if (ip) {
|
|
||||||
[self.collectionView selectItemAtIndexPath:ip animated:NO scrollPosition:UICollectionViewScrollPositionNone];
|
|
||||||
}
|
|
||||||
KBJfPayCell *cell = (KBJfPayCell *)[self.collectionView cellForItemAtIndexPath:ip];
|
|
||||||
if (cell) { [cell applySelected:YES animated:NO]; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - UICollectionView Delegate (ensure first show)
|
#pragma mark - UICollectionView Delegate (ensure first show)
|
||||||
- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath {
|
- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
if (![cell isKindOfClass:KBJfPayCell.class]) { return; }
|
if (![cell isKindOfClass:KBJfPayCell.class]) { return; }
|
||||||
KBJfPayCell *c = (KBJfPayCell *)cell;
|
KBJfPayCell *c = (KBJfPayCell *)cell;
|
||||||
BOOL sel = (indexPath.item == self.selectedIndex);
|
BOOL sel = (self.selectedIndex != NSNotFound && indexPath.item == self.selectedIndex);
|
||||||
if (sel) {
|
if (sel) {
|
||||||
[collectionView selectItemAtIndexPath:indexPath animated:NO scrollPosition:UICollectionViewScrollPositionNone];
|
[collectionView selectItemAtIndexPath:indexPath animated:NO scrollPosition:UICollectionViewScrollPositionNone];
|
||||||
}
|
}
|
||||||
@@ -194,9 +175,9 @@ static NSString * const kKBJfPayCellId = @"kKBJfPayCellId";
|
|||||||
|
|
||||||
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
KBJfPayCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kKBJfPayCellId forIndexPath:indexPath];
|
KBJfPayCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kKBJfPayCellId forIndexPath:indexPath];
|
||||||
NSDictionary *item = self.data[indexPath.item];
|
KBPayProductModel *model = self.data[indexPath.item];
|
||||||
NSString *coins = [NSString stringWithFormat:@"%@", item[@"coins"]];
|
NSString *coins = [model coinsDisplayText];
|
||||||
NSString *price = item[@"price"]; // 形如 "$6.90"
|
NSString *price = [model priceDisplayText];
|
||||||
[cell configCoins:coins price:price];
|
[cell configCoins:coins price:price];
|
||||||
[cell applySelected:(indexPath.item == self.selectedIndex) animated:NO];
|
[cell applySelected:(indexPath.item == self.selectedIndex) animated:NO];
|
||||||
return cell;
|
return cell;
|
||||||
@@ -235,30 +216,89 @@ static NSString * const kKBJfPayCellId = @"kKBJfPayCellId";
|
|||||||
return 30;
|
return 30;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - Data
|
||||||
|
- (void)fetchInAppProductList {
|
||||||
|
__weak typeof(self) weakSelf = self;
|
||||||
|
[self.payVM fetchInAppProductsNeedShow:YES completion:^(NSInteger sta, NSString * _Nullable msg, NSArray<KBPayProductModel *> * _Nullable products) {
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
__strong typeof(weakSelf) self = weakSelf;
|
||||||
|
if (!self) { return; }
|
||||||
|
if (sta != KBBizCodeSuccess || ![products isKindOfClass:NSArray.class]) {
|
||||||
|
self.data = @[];
|
||||||
|
self.selectedIndex = NSNotFound;
|
||||||
|
[self.collectionView reloadData];
|
||||||
|
NSString *tip = msg.length ? msg : KBLocalized(@"Failed to load products");
|
||||||
|
[KBHUD showInfo:tip];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.data = products ?: @[];
|
||||||
|
self.selectedIndex = self.data.count > 0 ? 0 : NSNotFound;
|
||||||
|
[self.collectionView reloadData];
|
||||||
|
[self selectItemAtCurrentIndexAnimated:NO];
|
||||||
|
});
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (KBPayProductModel *)currentSelectedProductItem {
|
||||||
|
if (self.selectedIndex == NSNotFound) { return nil; }
|
||||||
|
if (self.selectedIndex < 0 || self.selectedIndex >= self.data.count) { return nil; }
|
||||||
|
id item = self.data[self.selectedIndex];
|
||||||
|
if (![item isKindOfClass:KBPayProductModel.class]) { return nil; }
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)selectItemAtCurrentIndexAnimated:(BOOL)animated {
|
||||||
|
if (self.selectedIndex == NSNotFound) { return; }
|
||||||
|
if (self.selectedIndex < 0 || self.selectedIndex >= self.data.count) { return; }
|
||||||
|
NSIndexPath *ip = [NSIndexPath indexPathForItem:self.selectedIndex inSection:0];
|
||||||
|
if (!ip) { return; }
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
if (self.selectedIndex == NSNotFound) { return; }
|
||||||
|
if ([self.collectionView numberOfItemsInSection:0] <= ip.item) { return; }
|
||||||
|
[self.collectionView selectItemAtIndexPath:ip animated:animated scrollPosition:UICollectionViewScrollPositionNone];
|
||||||
|
KBJfPayCell *cell = (KBJfPayCell *)[self.collectionView cellForItemAtIndexPath:ip];
|
||||||
|
if ([cell isKindOfClass:KBJfPayCell.class]) {
|
||||||
|
[cell applySelected:YES animated:animated];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - Actions
|
#pragma mark - Actions
|
||||||
- (void)onTapPayButton {
|
- (void)onTapPayButton {
|
||||||
// 这里只做 UI,实际支付逻辑由调用方接入
|
KBPayProductModel *selectedItem = [self currentSelectedProductItem];
|
||||||
// if (self.selectedIndex >= 0 && self.selectedIndex < self.data.count) {
|
if (!selectedItem) {
|
||||||
// NSDictionary *item = self.data[self.selectedIndex];
|
[KBHUD showInfo:KBLocalized(@"Please select a product")];
|
||||||
// NSString *msg = [NSString stringWithFormat:@"购买:%@ Coins %@", item[@"coins"], item[@"price"]];
|
return;
|
||||||
// [KBHUD showInfo:msg];
|
}
|
||||||
// }
|
NSString *productId = selectedItem.productId;
|
||||||
NSString *productId = @"com.loveKey.nyx.1day";
|
if (productId.length == 0) {
|
||||||
/// 2.获取商品信息
|
[KBHUD showInfo:KBLocalized(@"Product unavailable")];
|
||||||
|
return;
|
||||||
|
}
|
||||||
[KBHUD show];
|
[KBHUD show];
|
||||||
|
__weak typeof(self) weakSelf = self;
|
||||||
[self.filter requestProductsWith:[NSSet setWithObject:productId] completion:^(NSArray<SKProduct *> * _Nonnull products) {
|
[self.filter requestProductsWith:[NSSet setWithObject:productId] completion:^(NSArray<SKProduct *> * _Nonnull products) {
|
||||||
// NSLog(@"=====");
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
// if (products.count > 0) {
|
__strong typeof(weakSelf) self = weakSelf;
|
||||||
// SKProduct *pro = productsp[0];
|
if (!self) { return; }
|
||||||
// }
|
SKProduct *match = nil;
|
||||||
// [[FGIAPManager shared].iap buyProduct:product onCompletion:^(NSString * _Nonnull message, FGIAPManagerPurchaseRusult result) { }];
|
for (SKProduct *product in products) {
|
||||||
|
if ([product.productIdentifier isEqualToString:productId]) {
|
||||||
/// 3.支付购买
|
match = product;
|
||||||
SKProduct *product = products.firstObject;
|
break;
|
||||||
[[FGIAPManager shared].iap buyProduct:products.firstObject onCompletion:^(NSString * _Nonnull message, FGIAPManagerPurchaseRusult result) {
|
}
|
||||||
// [self.view makeToast:message];
|
}
|
||||||
|
if (!match) {
|
||||||
[KBHUD dismiss];
|
[KBHUD dismiss];
|
||||||
|
[KBHUD showInfo:KBLocalized(@"Unable to load product information")];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[[FGIAPManager shared].iap buyProduct:match onCompletion:^(NSString * _Nonnull message, FGIAPManagerPurchaseRusult result) {
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[KBHUD dismiss];
|
||||||
|
});
|
||||||
}];
|
}];
|
||||||
|
});
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,13 +5,17 @@
|
|||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
@class KBPayProductModel;
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
/// 统一的支付回调:sta 为状态码(0 成功,非 0 失败),msg 为后端返回的消息
|
/// 统一的支付回调:sta 为状态码(0 成功,非 0 失败),msg 为后端返回的消息
|
||||||
typedef void(^KBPayCompletion)(NSInteger sta, NSString * _Nullable msg);
|
typedef void(^KBPayCompletion)(NSInteger sta, NSString * _Nullable msg);
|
||||||
|
|
||||||
/// 统一状态码(与原 Swift 代码的 succCode / errorCode 语义一致)
|
/// In-App 商品列表回调(返回 data 数组)
|
||||||
|
typedef void(^KBPayProductsCompletion)(NSInteger sta,
|
||||||
|
NSString * _Nullable msg,
|
||||||
|
NSArray<KBPayProductModel *> * _Nullable products);
|
||||||
|
|
||||||
@interface PayVM : NSObject
|
@interface PayVM : NSObject
|
||||||
|
|
||||||
@@ -22,7 +26,10 @@ typedef void(^KBPayCompletion)(NSInteger sta, NSString * _Nullable msg);
|
|||||||
needShow:(BOOL)needShow
|
needShow:(BOOL)needShow
|
||||||
completion:(KBPayCompletion)completion;
|
completion:(KBPayCompletion)completion;
|
||||||
|
|
||||||
|
/// 查询 type=in-app-purchase 的商品列表
|
||||||
|
- (void)fetchInAppProductsNeedShow:(BOOL)needShow
|
||||||
|
completion:(KBPayProductsCompletion)completion;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
#import "KBAPI.h"
|
#import "KBAPI.h"
|
||||||
#import "KBHUD.h"
|
#import "KBHUD.h"
|
||||||
#import "KBBizCode.h"
|
#import "KBBizCode.h"
|
||||||
|
#import "KBPayProductModel.h"
|
||||||
|
#import <MJExtension/MJExtension.h>
|
||||||
@implementation PayVM
|
@implementation PayVM
|
||||||
|
|
||||||
- (void)applePayReqWithParams:(NSDictionary *)params
|
- (void)applePayReqWithParams:(NSDictionary *)params
|
||||||
@@ -28,6 +30,40 @@
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)fetchInAppProductsNeedShow:(BOOL)needShow
|
||||||
|
completion:(KBPayProductsCompletion)completion {
|
||||||
|
if (needShow) { [KBHUD show]; }
|
||||||
|
NSDictionary *params = @{ @"type": @"in-app-purchase" };
|
||||||
|
[[KBNetworkManager shared] GET:API_INAPP_PRODUCT_LIST
|
||||||
|
parameters:params
|
||||||
|
headers:nil
|
||||||
|
autoShowBusinessError:NO
|
||||||
|
completion:^(NSDictionary * _Nullable json,
|
||||||
|
NSURLResponse * _Nullable response,
|
||||||
|
NSError * _Nullable error) {
|
||||||
|
if (needShow) { [KBHUD dismiss]; }
|
||||||
|
if (error) {
|
||||||
|
if (completion) {
|
||||||
|
NSInteger code = (error.code == 0 ? KBBizCodeSystemError : error.code);
|
||||||
|
completion(code, error.localizedDescription ?: KBLocalized(@"Network error"), nil);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
id dataObj = json[KBData] ?: json[@"data"];
|
||||||
|
if (![dataObj isKindOfClass:[NSArray class]]) {
|
||||||
|
if (completion) {
|
||||||
|
NSString *msg = [self.class extractMessageFromResponseObject:json] ?: KBLocalized(@"Invalid response");
|
||||||
|
completion(KBBizCodeSystemError, msg, nil);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NSArray<KBPayProductModel *> *models = [KBPayProductModel mj_objectArrayWithKeyValuesArray:(NSArray *)dataObj];
|
||||||
|
if (completion) {
|
||||||
|
completion(KBBizCodeSuccess, nil, models ?: @[]);
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - Helpers
|
#pragma mark - Helpers
|
||||||
|
|
||||||
//+ (NSInteger)extractStatusFromResponseObject:(id)obj response:(NSURLResponse *)resp {
|
//+ (NSInteger)extractStatusFromResponseObject:(id)obj response:(NSURLResponse *)resp {
|
||||||
|
|||||||
Reference in New Issue
Block a user