2026-02-04 12:33:01 +08:00
|
|
|
|
//
|
|
|
|
|
|
// KBPaySvipVC.m
|
|
|
|
|
|
// keyBoard
|
|
|
|
|
|
//
|
|
|
|
|
|
// Created by Mac on 2026/2/3.
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
#import "KBPaySvipVC.h"
|
2026-02-04 12:48:18 +08:00
|
|
|
|
#import "KBSvipSubscribeCell.h"
|
|
|
|
|
|
#import "KBSvipBenefitCell.h"
|
|
|
|
|
|
#import "KBSvipFlowLayout.h"
|
|
|
|
|
|
#import "PayVM.h"
|
|
|
|
|
|
#import "KBPayProductModel.h"
|
|
|
|
|
|
#import "KBBizCode.h"
|
|
|
|
|
|
#import "keyBoard-Swift.h"
|
|
|
|
|
|
#import <MJExtension/MJExtension.h>
|
2026-02-04 12:33:01 +08:00
|
|
|
|
|
2026-02-04 12:48:18 +08:00
|
|
|
|
static NSString * const kKBSvipSubscribeCellId = @"kKBSvipSubscribeCellId";
|
|
|
|
|
|
static NSString * const kKBSvipBenefitCellId = @"kKBSvipBenefitCellId";
|
|
|
|
|
|
static NSString * const kKBSvipBenefitHeaderId = @"kKBSvipBenefitHeaderId";
|
|
|
|
|
|
|
|
|
|
|
|
@interface KBPaySvipVC () <UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
|
2026-02-04 12:33:01 +08:00
|
|
|
|
@property (nonatomic, copy) void(^scrollCallback)(UIScrollView *scrollView);
|
2026-02-04 12:48:18 +08:00
|
|
|
|
|
|
|
|
|
|
/// 1:UI 控件
|
2026-02-04 12:33:01 +08:00
|
|
|
|
@property (nonatomic, strong) UICollectionView *collectionView;
|
2026-02-04 12:48:18 +08:00
|
|
|
|
@property (nonatomic, strong) UIButton *payButton;
|
|
|
|
|
|
@property (nonatomic, strong) UILabel *agreementLabel;
|
|
|
|
|
|
@property (nonatomic, strong) UIButton *agreementButton;
|
|
|
|
|
|
|
|
|
|
|
|
/// 2:数据
|
|
|
|
|
|
@property (nonatomic, strong) NSArray<KBPayProductModel *> *plans;
|
|
|
|
|
|
@property (nonatomic, assign) NSInteger selectedIndex;
|
|
|
|
|
|
@property (nonatomic, strong) NSArray<NSDictionary *> *benefits;
|
|
|
|
|
|
@property (nonatomic, strong) PayVM *payVM;
|
2026-02-04 12:33:01 +08:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
@implementation KBPaySvipVC
|
|
|
|
|
|
|
2026-02-04 12:48:18 +08:00
|
|
|
|
#pragma mark - Life Cycle
|
|
|
|
|
|
|
2026-02-04 12:33:01 +08:00
|
|
|
|
- (void)viewDidLoad {
|
|
|
|
|
|
[super viewDidLoad];
|
2026-02-04 12:48:18 +08:00
|
|
|
|
|
|
|
|
|
|
/// 1:控件初始化
|
|
|
|
|
|
[self setupUI];
|
|
|
|
|
|
/// 2:数据初始化
|
|
|
|
|
|
[self setupData];
|
|
|
|
|
|
/// 3:加载数据
|
|
|
|
|
|
[self loadData];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark - 1:控件初始化
|
|
|
|
|
|
|
|
|
|
|
|
- (void)setupUI {
|
|
|
|
|
|
self.view.backgroundColor = [UIColor colorWithHex:0xF6F7FB];
|
|
|
|
|
|
|
|
|
|
|
|
[self.view addSubview:self.payButton];
|
|
|
|
|
|
[self.view addSubview:self.agreementLabel];
|
|
|
|
|
|
[self.view addSubview:self.agreementButton];
|
2026-02-04 12:33:01 +08:00
|
|
|
|
[self.view addSubview:self.collectionView];
|
2026-02-04 12:48:18 +08:00
|
|
|
|
|
|
|
|
|
|
[self.agreementButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
|
make.centerX.equalTo(self.view);
|
|
|
|
|
|
make.bottom.equalTo(self.view).offset(-KB_SAFE_BOTTOM - 15);
|
|
|
|
|
|
}];
|
|
|
|
|
|
|
|
|
|
|
|
[self.agreementLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
|
make.centerX.equalTo(self.view);
|
|
|
|
|
|
make.bottom.equalTo(self.agreementButton.mas_top).offset(0);
|
|
|
|
|
|
}];
|
|
|
|
|
|
|
|
|
|
|
|
[self.payButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
|
make.left.equalTo(self.view).offset(24);
|
|
|
|
|
|
make.right.equalTo(self.view).offset(-24);
|
|
|
|
|
|
make.bottom.equalTo(self.agreementLabel.mas_top).offset(-14);
|
|
|
|
|
|
make.height.mas_equalTo(58);
|
|
|
|
|
|
}];
|
|
|
|
|
|
|
2026-02-04 12:33:01 +08:00
|
|
|
|
[self.collectionView mas_makeConstraints:^(MASConstraintMaker *make) {
|
2026-02-04 15:09:03 +08:00
|
|
|
|
make.left.right.equalTo(self.view);
|
|
|
|
|
|
make.top.equalTo(self.view).offset(16);
|
2026-02-04 12:48:18 +08:00
|
|
|
|
make.bottom.equalTo(self.payButton.mas_top).offset(-16);
|
|
|
|
|
|
}];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark - 2:数据初始化
|
|
|
|
|
|
|
|
|
|
|
|
- (void)setupData {
|
|
|
|
|
|
self.payVM = [PayVM new];
|
|
|
|
|
|
self.plans = @[];
|
|
|
|
|
|
self.selectedIndex = NSNotFound;
|
|
|
|
|
|
|
|
|
|
|
|
// 权益列表数据(使用现有图标资源)
|
|
|
|
|
|
self.benefits = @[
|
2026-02-04 14:59:02 +08:00
|
|
|
|
@{@"icon": @"pay_ais_icon", @"title": KBLocalized(@"Wireless Sub-ai Dialogue")},
|
|
|
|
|
|
@{@"icon": @"pay_keyboards_icon", @"title": KBLocalized(@"Personalized Keyboard")},
|
|
|
|
|
|
@{@"icon": @"pay_person_icon", @"title": KBLocalized(@"Chat Persona")},
|
|
|
|
|
|
@{@"icon": @"pay_phone_icon", @"title": KBLocalized(@"Emotional Counseling")},
|
|
|
|
|
|
@{@"icon": @"pay_history_icon", @"title": KBLocalized(@"Longer Chat History")},
|
|
|
|
|
|
@{@"icon": @"pay_chats_icon", @"title": KBLocalized(@"Unlimited Chatting")},
|
|
|
|
|
|
@{@"icon": @"pay_speed_icon", @"title": KBLocalized(@"Chat Without Speed Limits")},
|
|
|
|
|
|
@{@"icon": @"pay_soon_icon", @"title": KBLocalized(@"Coming Soon")},
|
2026-02-04 12:48:18 +08:00
|
|
|
|
];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark - 3:加载数据
|
|
|
|
|
|
|
|
|
|
|
|
- (void)loadData {
|
|
|
|
|
|
__weak typeof(self) weakSelf = self;
|
|
|
|
|
|
[self.payVM fetchSubscriptionProductsNeedShow: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.plans = @[];
|
|
|
|
|
|
self.selectedIndex = NSNotFound;
|
|
|
|
|
|
[self.collectionView reloadData];
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2026-02-04 15:40:45 +08:00
|
|
|
|
// 过滤 level=2 的 SVIP 数据
|
|
|
|
|
|
NSMutableArray<KBPayProductModel *> *svipProducts = [NSMutableArray array];
|
|
|
|
|
|
for (KBPayProductModel *product in products) {
|
|
|
|
|
|
if (product.level == 1) {
|
|
|
|
|
|
[svipProducts addObject:product];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
self.plans = svipProducts.copy;
|
|
|
|
|
|
self.selectedIndex = self.plans.count > 1 ? 1 : (self.plans.count > 0 ? 0 : NSNotFound); // 默认选中第二个(1 Month)
|
2026-02-04 12:48:18 +08:00
|
|
|
|
[self.collectionView reloadData];
|
|
|
|
|
|
[self selectCurrentPlanAnimated:NO];
|
|
|
|
|
|
[self prepareStoreKitWithPlans:self.plans];
|
|
|
|
|
|
});
|
|
|
|
|
|
}];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark - Private Methods
|
|
|
|
|
|
|
|
|
|
|
|
- (void)prepareStoreKitWithPlans:(NSArray<KBPayProductModel *> *)plans {
|
|
|
|
|
|
if (![plans isKindOfClass:NSArray.class] || plans.count == 0) { return; }
|
|
|
|
|
|
NSMutableArray<NSString *> *ids = [NSMutableArray array];
|
|
|
|
|
|
for (KBPayProductModel *plan in plans) {
|
|
|
|
|
|
if (![plan isKindOfClass:KBPayProductModel.class]) { continue; }
|
|
|
|
|
|
if (plan.productId.length) {
|
|
|
|
|
|
[ids addObject:plan.productId];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (ids.count == 0) { return; }
|
|
|
|
|
|
[[KBStoreKitBridge shared] prepareWithProductIds:ids completion:nil];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (void)selectCurrentPlanAnimated:(BOOL)animated {
|
|
|
|
|
|
if (self.selectedIndex == NSNotFound) { return; }
|
|
|
|
|
|
if (self.selectedIndex < 0 || self.selectedIndex >= self.plans.count) { return; }
|
|
|
|
|
|
NSIndexPath *ip = [NSIndexPath indexPathForItem:self.selectedIndex inSection:0];
|
|
|
|
|
|
[self.collectionView selectItemAtIndexPath:ip animated:animated scrollPosition:UICollectionViewScrollPositionNone];
|
|
|
|
|
|
KBSvipSubscribeCell *cell = (KBSvipSubscribeCell *)[self.collectionView cellForItemAtIndexPath:ip];
|
|
|
|
|
|
if ([cell isKindOfClass:KBSvipSubscribeCell.class]) {
|
|
|
|
|
|
[cell applySelected:YES animated:animated];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (KBPayProductModel *)currentSelectedPlan {
|
|
|
|
|
|
if (self.selectedIndex == NSNotFound) { return nil; }
|
|
|
|
|
|
if (self.selectedIndex < 0 || self.selectedIndex >= self.plans.count) { return nil; }
|
|
|
|
|
|
return self.plans[self.selectedIndex];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (NSString *)displayTitleForPlan:(KBPayProductModel *)plan {
|
|
|
|
|
|
if (!plan) { return @""; }
|
|
|
|
|
|
if (plan.productDescription.length) { return plan.productDescription; }
|
|
|
|
|
|
NSString *name = plan.name ?: @"";
|
|
|
|
|
|
NSString *unit = plan.unit ?: @"";
|
|
|
|
|
|
if (name.length && unit.length) { return [NSString stringWithFormat:@"%@ %@", name, unit]; }
|
|
|
|
|
|
if (name.length) { return name; }
|
|
|
|
|
|
if (unit.length) { return unit; }
|
|
|
|
|
|
return KBLocalized(@"Subscription");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark - Actions
|
|
|
|
|
|
|
|
|
|
|
|
- (void)onTapPayButton {
|
|
|
|
|
|
KBPayProductModel *plan = [self currentSelectedPlan];
|
|
|
|
|
|
if (!plan) {
|
|
|
|
|
|
[KBHUD showInfo:KBLocalized(@"Please select a product")];
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NSMutableDictionary *extra = [NSMutableDictionary dictionary];
|
|
|
|
|
|
if ([plan.productId isKindOfClass:NSString.class] && plan.productId.length > 0) {
|
|
|
|
|
|
extra[@"product_id"] = plan.productId;
|
|
|
|
|
|
}
|
|
|
|
|
|
[[KBMaiPointReporter sharedReporter] reportClickWithEventName:@"click_svip_pay_btn"
|
|
|
|
|
|
pageId:@"svip_pay"
|
|
|
|
|
|
elementId:@"pay_btn"
|
|
|
|
|
|
extra:extra.copy
|
|
|
|
|
|
completion:nil];
|
|
|
|
|
|
|
|
|
|
|
|
NSString *productId = plan.productId;
|
|
|
|
|
|
if (productId.length == 0) {
|
|
|
|
|
|
[KBHUD showInfo:KBLocalized(@"Product unavailable")];
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[KBHUD show];
|
|
|
|
|
|
__weak typeof(self) weakSelf = self;
|
|
|
|
|
|
[[KBStoreKitBridge shared] purchaseWithProductId:productId completion:^(BOOL success, NSString * _Nullable message) {
|
|
|
|
|
|
__strong typeof(weakSelf) self = weakSelf;
|
|
|
|
|
|
[KBHUD dismiss];
|
|
|
|
|
|
[KBHUD showInfo:KBLocalized(message)];
|
|
|
|
|
|
if (!self || !success) { return; }
|
|
|
|
|
|
[self selectCurrentPlanAnimated:NO];
|
2026-02-04 12:33:01 +08:00
|
|
|
|
}];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-04 12:48:18 +08:00
|
|
|
|
- (void)agreementButtonAction {
|
|
|
|
|
|
[KBHUD showInfo:KBLocalized(@"Open agreement")];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark - UICollectionView DataSource
|
|
|
|
|
|
|
|
|
|
|
|
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
|
|
|
|
|
|
// Section 0: 订阅选项(横向)
|
|
|
|
|
|
// Section 1: 权益列表
|
|
|
|
|
|
return 2;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
|
|
|
|
|
if (section == 0) {
|
|
|
|
|
|
return self.plans.count;
|
|
|
|
|
|
}
|
|
|
|
|
|
return self.benefits.count;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
|
|
|
|
|
if (indexPath.section == 0) {
|
|
|
|
|
|
KBSvipSubscribeCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kKBSvipSubscribeCellId forIndexPath:indexPath];
|
|
|
|
|
|
if (indexPath.item < self.plans.count) {
|
|
|
|
|
|
KBPayProductModel *plan = self.plans[indexPath.item];
|
|
|
|
|
|
NSString *title = [self displayTitleForPlan:plan];
|
2026-02-04 15:40:45 +08:00
|
|
|
|
NSString *currency = plan.currency ?: @"$";
|
|
|
|
|
|
NSString *price = [plan priceNumberText];
|
|
|
|
|
|
[cell configTitle:title currency:currency price:price strike:nil];
|
2026-02-04 12:48:18 +08:00
|
|
|
|
[cell applySelected:(indexPath.item == self.selectedIndex) animated:NO];
|
|
|
|
|
|
}
|
|
|
|
|
|
return cell;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
KBSvipBenefitCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kKBSvipBenefitCellId forIndexPath:indexPath];
|
|
|
|
|
|
if (indexPath.item < self.benefits.count) {
|
|
|
|
|
|
NSDictionary *benefit = self.benefits[indexPath.item];
|
|
|
|
|
|
[cell configWithIcon:benefit[@"icon"] title:benefit[@"title"]];
|
|
|
|
|
|
}
|
|
|
|
|
|
return cell;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
|
|
|
|
|
|
if (indexPath.section == 1 && [kind isEqualToString:UICollectionElementKindSectionHeader]) {
|
|
|
|
|
|
UICollectionReusableView *header = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:kKBSvipBenefitHeaderId forIndexPath:indexPath];
|
|
|
|
|
|
// 清除旧的子视图
|
|
|
|
|
|
for (UIView *subview in header.subviews) {
|
|
|
|
|
|
[subview removeFromSuperview];
|
|
|
|
|
|
}
|
|
|
|
|
|
// 添加标题
|
|
|
|
|
|
UILabel *titleLabel = [UILabel new];
|
|
|
|
|
|
titleLabel.text = KBLocalized(@"Membership Benefits");
|
|
|
|
|
|
titleLabel.textColor = [UIColor colorWithHex:0x999999];
|
|
|
|
|
|
titleLabel.font = [KBFont medium:13];
|
|
|
|
|
|
titleLabel.textAlignment = NSTextAlignmentCenter;
|
|
|
|
|
|
[header addSubview:titleLabel];
|
|
|
|
|
|
[titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
|
make.center.equalTo(header);
|
|
|
|
|
|
}];
|
|
|
|
|
|
// 左右横线
|
2026-02-04 15:40:45 +08:00
|
|
|
|
UIImageView *leftLine = [UIImageView new];
|
|
|
|
|
|
leftLine.image = [UIImage imageNamed:@"pay_leftline_icon"];
|
2026-02-04 12:48:18 +08:00
|
|
|
|
[header addSubview:leftLine];
|
|
|
|
|
|
[leftLine mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
|
make.right.equalTo(titleLabel.mas_left).offset(-12);
|
|
|
|
|
|
make.centerY.equalTo(header);
|
2026-02-04 15:40:45 +08:00
|
|
|
|
make.width.mas_equalTo(53);
|
2026-02-04 12:48:18 +08:00
|
|
|
|
make.height.mas_equalTo(1);
|
|
|
|
|
|
}];
|
2026-02-04 15:40:45 +08:00
|
|
|
|
UIImageView *rightLine = [UIImageView new];
|
|
|
|
|
|
rightLine.image = [UIImage imageNamed:@"pay_rightline_icon"];
|
2026-02-04 12:48:18 +08:00
|
|
|
|
[header addSubview:rightLine];
|
|
|
|
|
|
[rightLine mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
|
make.left.equalTo(titleLabel.mas_right).offset(12);
|
|
|
|
|
|
make.centerY.equalTo(header);
|
2026-02-04 15:40:45 +08:00
|
|
|
|
make.width.mas_equalTo(53);
|
2026-02-04 12:48:18 +08:00
|
|
|
|
make.height.mas_equalTo(1);
|
|
|
|
|
|
}];
|
|
|
|
|
|
return header;
|
|
|
|
|
|
}
|
|
|
|
|
|
return [UICollectionReusableView new];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark - UICollectionView Delegate
|
|
|
|
|
|
|
|
|
|
|
|
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
|
|
|
|
|
|
if (indexPath.section != 0 || indexPath.item >= self.plans.count) { return; }
|
|
|
|
|
|
if (self.selectedIndex == indexPath.item) { return; }
|
|
|
|
|
|
|
|
|
|
|
|
NSInteger old = self.selectedIndex;
|
|
|
|
|
|
self.selectedIndex = indexPath.item;
|
|
|
|
|
|
|
|
|
|
|
|
KBPayProductModel *plan = self.plans[indexPath.item];
|
|
|
|
|
|
NSMutableDictionary *extra = [NSMutableDictionary dictionary];
|
|
|
|
|
|
extra[@"index"] = @(indexPath.item);
|
|
|
|
|
|
if ([plan.productId isKindOfClass:NSString.class] && plan.productId.length > 0) {
|
|
|
|
|
|
extra[@"product_id"] = plan.productId;
|
|
|
|
|
|
}
|
|
|
|
|
|
[[KBMaiPointReporter sharedReporter] reportClickWithEventName:@"click_svip_select_plan"
|
|
|
|
|
|
pageId:@"svip_pay"
|
|
|
|
|
|
elementId:@"plan_item"
|
|
|
|
|
|
extra:extra.copy
|
|
|
|
|
|
completion:nil];
|
|
|
|
|
|
|
|
|
|
|
|
KBSvipSubscribeCell *newCell = (KBSvipSubscribeCell *)[collectionView cellForItemAtIndexPath:indexPath];
|
|
|
|
|
|
[newCell applySelected:YES animated:YES];
|
|
|
|
|
|
|
|
|
|
|
|
if (old >= 0 && old < self.plans.count) {
|
|
|
|
|
|
NSIndexPath *oldIP = [NSIndexPath indexPathForItem:old inSection:0];
|
|
|
|
|
|
KBSvipSubscribeCell *oldCell = (KBSvipSubscribeCell *)[collectionView cellForItemAtIndexPath:oldIP];
|
|
|
|
|
|
[oldCell applySelected:NO animated:YES];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath {
|
|
|
|
|
|
if (indexPath.section == 0 && indexPath.item < self.plans.count && [cell isKindOfClass:KBSvipSubscribeCell.class]) {
|
|
|
|
|
|
BOOL sel = (indexPath.item == self.selectedIndex);
|
|
|
|
|
|
KBSvipSubscribeCell *c = (KBSvipSubscribeCell *)cell;
|
|
|
|
|
|
if (sel) {
|
|
|
|
|
|
[collectionView selectItemAtIndexPath:indexPath animated:NO scrollPosition:UICollectionViewScrollPositionNone];
|
|
|
|
|
|
}
|
|
|
|
|
|
[c applySelected:sel animated:NO];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark - FlowLayout
|
|
|
|
|
|
|
|
|
|
|
|
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
|
|
|
|
|
|
CGFloat screenW = KB_SCREEN_WIDTH;
|
|
|
|
|
|
if (indexPath.section == 0) {
|
2026-02-04 15:20:53 +08:00
|
|
|
|
// 订阅选项:尺寸 105 * 124
|
|
|
|
|
|
return CGSizeMake(105, 124);
|
2026-02-04 12:48:18 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
// 权益项
|
|
|
|
|
|
return CGSizeMake(screenW - 32, 56);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section {
|
|
|
|
|
|
if (section == 1) {
|
|
|
|
|
|
return CGSizeMake(KB_SCREEN_WIDTH, 50);
|
|
|
|
|
|
}
|
|
|
|
|
|
return CGSizeZero;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
|
|
|
|
|
|
if (section == 0) { return 10; }
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
|
|
|
|
|
|
if (section == 0) { return 10; }
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
|
|
|
|
|
|
if (section == 0) {
|
2026-02-04 15:40:45 +08:00
|
|
|
|
// 订阅选项:外层背景距屏幕16,Cell距外层背景17,所以 16+17=33
|
|
|
|
|
|
return UIEdgeInsetsMake(16, 22, 10, 22);
|
2026-02-04 12:48:18 +08:00
|
|
|
|
}
|
|
|
|
|
|
return UIEdgeInsetsMake(0, 16, 20, 16);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-04 12:33:01 +08:00
|
|
|
|
#pragma mark - UIScrollView Delegate(转发给分页容器)
|
2026-02-04 12:48:18 +08:00
|
|
|
|
|
2026-02-04 12:33:01 +08:00
|
|
|
|
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
|
|
|
|
|
|
!self.scrollCallback ?: self.scrollCallback(scrollView);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark - JXPagingViewListViewDelegate
|
2026-02-04 12:48:18 +08:00
|
|
|
|
|
2026-02-04 12:33:01 +08:00
|
|
|
|
- (UIView *)listView { return self.view; }
|
|
|
|
|
|
- (UIScrollView *)listScrollView { return self.collectionView; }
|
|
|
|
|
|
- (void)listViewDidScrollCallback:(void (^)(UIScrollView *))callback { self.scrollCallback = callback; }
|
|
|
|
|
|
- (void)listWillAppear { NSLog(@"%@:%@", self.title, NSStringFromSelector(_cmd)); }
|
|
|
|
|
|
- (void)listDidAppear { NSLog(@"%@:%@", self.title, NSStringFromSelector(_cmd)); }
|
|
|
|
|
|
- (void)listWillDisappear { NSLog(@"%@:%@", self.title, NSStringFromSelector(_cmd)); }
|
|
|
|
|
|
- (void)listDidDisappear { NSLog(@"%@:%@", self.title, NSStringFromSelector(_cmd)); }
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark - Lazy
|
2026-02-04 12:48:18 +08:00
|
|
|
|
|
2026-02-04 12:33:01 +08:00
|
|
|
|
- (UICollectionView *)collectionView {
|
|
|
|
|
|
if (!_collectionView) {
|
2026-02-04 12:48:18 +08:00
|
|
|
|
KBSvipFlowLayout *layout = [KBSvipFlowLayout new];
|
2026-02-04 12:33:01 +08:00
|
|
|
|
layout.scrollDirection = UICollectionViewScrollDirectionVertical;
|
2026-02-04 12:48:18 +08:00
|
|
|
|
layout.decorationSection = 1; // Section 1 添加背景
|
2026-02-04 12:33:01 +08:00
|
|
|
|
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
|
|
|
|
|
|
_collectionView.backgroundColor = [UIColor clearColor];
|
2026-02-04 12:48:18 +08:00
|
|
|
|
_collectionView.dataSource = self;
|
|
|
|
|
|
_collectionView.delegate = self;
|
|
|
|
|
|
_collectionView.alwaysBounceVertical = YES;
|
|
|
|
|
|
_collectionView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
|
|
|
|
|
|
[_collectionView registerClass:KBSvipSubscribeCell.class forCellWithReuseIdentifier:kKBSvipSubscribeCellId];
|
|
|
|
|
|
[_collectionView registerClass:KBSvipBenefitCell.class forCellWithReuseIdentifier:kKBSvipBenefitCellId];
|
|
|
|
|
|
[_collectionView registerClass:UICollectionReusableView.class forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:kKBSvipBenefitHeaderId];
|
2026-02-04 12:33:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
return _collectionView;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-04 12:48:18 +08:00
|
|
|
|
- (UIButton *)payButton {
|
|
|
|
|
|
if (!_payButton) {
|
|
|
|
|
|
_payButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
|
|
|
|
|
[_payButton setTitle:KBLocalized(@"Recharge Now") forState:UIControlStateNormal];
|
|
|
|
|
|
[_payButton setTitleColor:[UIColor colorWithHex:KBBlackValue] forState:UIControlStateNormal];
|
|
|
|
|
|
_payButton.titleLabel.font = [KBFont medium:15];
|
|
|
|
|
|
_payButton.layer.cornerRadius = 29;
|
|
|
|
|
|
_payButton.clipsToBounds = YES;
|
|
|
|
|
|
_payButton.backgroundColor = [UIColor colorWithHex:0x222222];
|
|
|
|
|
|
[_payButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
|
|
|
|
|
|
[_payButton addTarget:self action:@selector(onTapPayButton) forControlEvents:UIControlEventTouchUpInside];
|
|
|
|
|
|
}
|
|
|
|
|
|
return _payButton;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (UILabel *)agreementLabel {
|
|
|
|
|
|
if (!_agreementLabel) {
|
|
|
|
|
|
_agreementLabel = [UILabel new];
|
|
|
|
|
|
_agreementLabel.text = KBLocalized(@"By Clicking \"pay\", You Indicate Your Agreement To The");
|
|
|
|
|
|
_agreementLabel.font = [KBFont regular:12];
|
|
|
|
|
|
_agreementLabel.textColor = [UIColor colorWithHex:KBBlackValue];
|
|
|
|
|
|
}
|
|
|
|
|
|
return _agreementLabel;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (UIButton *)agreementButton {
|
|
|
|
|
|
if (!_agreementButton) {
|
|
|
|
|
|
_agreementButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
|
|
|
|
|
[_agreementButton setTitle:KBLocalized(@"《Embership Agreement》") forState:UIControlStateNormal];
|
|
|
|
|
|
[_agreementButton setTitleColor:[UIColor colorWithHex:KBColorValue] forState:UIControlStateNormal];
|
|
|
|
|
|
_agreementButton.titleLabel.font = [KBFont regular:12];
|
|
|
|
|
|
[_agreementButton addTarget:self action:@selector(agreementButtonAction) forControlEvents:UIControlEventTouchUpInside];
|
|
|
|
|
|
}
|
|
|
|
|
|
return _agreementButton;
|
|
|
|
|
|
}
|
2026-02-04 12:33:01 +08:00
|
|
|
|
|
|
|
|
|
|
@end
|