1
This commit is contained in:
@@ -51,6 +51,8 @@
|
|||||||
#define API_THEME_PURCHASED @"/themes/purchased" // 查询已购买主题
|
#define API_THEME_PURCHASED @"/themes/purchased" // 查询已购买主题
|
||||||
#define API_WALLET_BALANCE @"/wallet/balance" // 查询钱包余额
|
#define API_WALLET_BALANCE @"/wallet/balance" // 查询钱包余额
|
||||||
#define API_THEME_DETAIL @"/themes/detail" // 查询主题详情
|
#define API_THEME_DETAIL @"/themes/detail" // 查询主题详情
|
||||||
|
#define API_THEME_PURCHASE @"/themes/purchase" // 购买主题
|
||||||
|
#define API_THEME_DOWNLOAD @"/themes/download" // 主题下载信息
|
||||||
|
|
||||||
/// pay
|
/// pay
|
||||||
#define API_VALIDATE_RECEIPT @"/api/apple/validate-receipt" // 排行榜标签列表
|
#define API_VALIDATE_RECEIPT @"/api/apple/validate-receipt" // 排行榜标签列表
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
/// 图标(可选),例如金币图
|
/// 图标(可选),例如金币图
|
||||||
@property (nonatomic, strong, nullable) UIImage *iconImage;
|
@property (nonatomic, strong, nullable) UIImage *iconImage;
|
||||||
|
|
||||||
|
/// 是否展示价格区域(隐藏后仅显示标题)
|
||||||
|
@property (nonatomic, assign) BOOL showsPrice;
|
||||||
|
|
||||||
/// 点击回调(也可直接 addTarget 使用)
|
/// 点击回调(也可直接 addTarget 使用)
|
||||||
@property (nonatomic, copy, nullable) void (^tapHandler)(void);
|
@property (nonatomic, copy, nullable) void (^tapHandler)(void);
|
||||||
|
|
||||||
@@ -34,4 +37,3 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
@end
|
@end
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
#import "KBSkinBottomActionView.h"
|
#import "KBSkinBottomActionView.h"
|
||||||
|
|
||||||
@interface KBSkinBottomActionView ()
|
@interface KBSkinBottomActionView ()
|
||||||
@property (nonatomic, strong) UIView *contentView; // 内部容器,使三项整体居中
|
@property (nonatomic, strong) UIView *contentView; // 内部容器,使内容整体居中
|
||||||
|
@property (nonatomic, strong) UIStackView *stackView; // 水平排列 Title/Icon/Price
|
||||||
@property (nonatomic, strong) UILabel *titleLabel; // 左侧标题
|
@property (nonatomic, strong) UILabel *titleLabel; // 左侧标题
|
||||||
@property (nonatomic, strong) UIImageView *coinImageView; // 中间图标(可选)
|
@property (nonatomic, strong) UIImageView *coinImageView; // 中间图标(可选)
|
||||||
@property (nonatomic, strong) UILabel *priceLabel; // 右侧价格
|
@property (nonatomic, strong) UILabel *priceLabel; // 右侧价格
|
||||||
@@ -37,24 +38,20 @@
|
|||||||
}];
|
}];
|
||||||
|
|
||||||
// 三个元素放进容器,左右顺序:Title - Icon - Price
|
// 三个元素放进容器,左右顺序:Title - Icon - Price
|
||||||
[self.contentView addSubview:self.titleLabel];
|
[self.contentView addSubview:self.stackView];
|
||||||
[self.contentView addSubview:self.coinImageView];
|
[self.stackView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
[self.contentView addSubview:self.priceLabel];
|
make.edges.equalTo(self.contentView);
|
||||||
|
|
||||||
[self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
||||||
make.left.equalTo(self.contentView);
|
|
||||||
make.centerY.equalTo(self.contentView);
|
|
||||||
}];
|
}];
|
||||||
|
[self.stackView addArrangedSubview:self.titleLabel];
|
||||||
|
[self.stackView addArrangedSubview:self.coinImageView];
|
||||||
|
[self.stackView addArrangedSubview:self.priceLabel];
|
||||||
|
if (@available(iOS 11.0, *)) {
|
||||||
|
[self.stackView setCustomSpacing:8 afterView:self.titleLabel];
|
||||||
|
[self.stackView setCustomSpacing:6 afterView:self.coinImageView];
|
||||||
|
}
|
||||||
[self.coinImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
[self.coinImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
make.left.equalTo(self.titleLabel.mas_right).offset(8);
|
|
||||||
make.centerY.equalTo(self.contentView);
|
|
||||||
make.width.height.mas_equalTo(18);
|
make.width.height.mas_equalTo(18);
|
||||||
}];
|
}];
|
||||||
[self.priceLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
||||||
make.left.equalTo(self.coinImageView.mas_right).offset(6);
|
|
||||||
make.right.equalTo(self.contentView);
|
|
||||||
make.centerY.equalTo(self.contentView);
|
|
||||||
}];
|
|
||||||
|
|
||||||
// 默认文案
|
// 默认文案
|
||||||
self.titleText = @"Download";
|
self.titleText = @"Download";
|
||||||
@@ -62,6 +59,7 @@
|
|||||||
UIImage *img = [UIImage systemImageNamed:@"circle.fill"];
|
UIImage *img = [UIImage systemImageNamed:@"circle.fill"];
|
||||||
self.iconImage = img; // 若项目没有金币图标,用系统占位(黄色)
|
self.iconImage = img; // 若项目没有金币图标,用系统占位(黄色)
|
||||||
self.coinImageView.tintColor = [UIColor colorWithRed:1.0 green:0.85 blue:0.2 alpha:1.0];
|
self.coinImageView.tintColor = [UIColor colorWithRed:1.0 green:0.85 blue:0.2 alpha:1.0];
|
||||||
|
self.showsPrice = YES;
|
||||||
// 点击回调(可选)
|
// 点击回调(可选)
|
||||||
[self addTarget:self action:@selector(handleTap) forControlEvents:UIControlEventTouchUpInside];
|
[self addTarget:self action:@selector(handleTap) forControlEvents:UIControlEventTouchUpInside];
|
||||||
}
|
}
|
||||||
@@ -100,7 +98,9 @@
|
|||||||
|
|
||||||
- (void)setPriceText:(NSString *)priceText {
|
- (void)setPriceText:(NSString *)priceText {
|
||||||
_priceText = [priceText copy];
|
_priceText = [priceText copy];
|
||||||
|
if (self.showsPrice) {
|
||||||
self.priceLabel.text = _priceText;
|
self.priceLabel.text = _priceText;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setIconImage:(UIImage *)iconImage {
|
- (void)setIconImage:(UIImage *)iconImage {
|
||||||
@@ -108,6 +108,17 @@
|
|||||||
self.coinImageView.image = _iconImage;
|
self.coinImageView.image = _iconImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setShowsPrice:(BOOL)showsPrice {
|
||||||
|
if (_showsPrice == showsPrice) { return; }
|
||||||
|
_showsPrice = showsPrice;
|
||||||
|
self.coinImageView.hidden = !_showsPrice;
|
||||||
|
self.priceLabel.hidden = !_showsPrice;
|
||||||
|
self.priceLabel.text = _showsPrice ? self.priceText : @"";
|
||||||
|
if (@available(iOS 11.0, *)) {
|
||||||
|
[self.stackView setCustomSpacing:_showsPrice ? 8 : 0 afterView:self.titleLabel];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - Lazy
|
#pragma mark - Lazy
|
||||||
|
|
||||||
- (UILabel *)titleLabel {
|
- (UILabel *)titleLabel {
|
||||||
@@ -131,6 +142,16 @@
|
|||||||
return _contentView;
|
return _contentView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (UIStackView *)stackView {
|
||||||
|
if (!_stackView) {
|
||||||
|
_stackView = [[UIStackView alloc] init];
|
||||||
|
_stackView.axis = UILayoutConstraintAxisHorizontal;
|
||||||
|
_stackView.alignment = UIStackViewAlignmentCenter;
|
||||||
|
_stackView.spacing = 6;
|
||||||
|
}
|
||||||
|
return _stackView;
|
||||||
|
}
|
||||||
|
|
||||||
- (UIImageView *)coinImageView {
|
- (UIImageView *)coinImageView {
|
||||||
if (!_coinImageView) {
|
if (!_coinImageView) {
|
||||||
_coinImageView = [[UIImageView alloc] init];
|
_coinImageView = [[UIImageView alloc] init];
|
||||||
|
|||||||
@@ -13,6 +13,8 @@
|
|||||||
#import "KBSkinBottomActionView.h"
|
#import "KBSkinBottomActionView.h"
|
||||||
#import "KBShopVM.h"
|
#import "KBShopVM.h"
|
||||||
#import "KBShopThemeTagModel.h"
|
#import "KBShopThemeTagModel.h"
|
||||||
|
#import "KBHUD.h"
|
||||||
|
#import "KBSkinService.h"
|
||||||
|
|
||||||
static NSString * const kHeaderCellId = @"kHeaderCellId";
|
static NSString * const kHeaderCellId = @"kHeaderCellId";
|
||||||
static NSString * const kTagsContainerCellId = @"kTagsContainerCellId";
|
static NSString * const kTagsContainerCellId = @"kTagsContainerCellId";
|
||||||
@@ -34,6 +36,7 @@ typedef NS_ENUM(NSInteger, KBSkinDetailSection) {
|
|||||||
@property (nonatomic, copy) NSArray<NSDictionary *> *gridData; // 底部网格数据
|
@property (nonatomic, copy) NSArray<NSDictionary *> *gridData; // 底部网格数据
|
||||||
@property (nonatomic, strong) KBShopVM *shopVM;
|
@property (nonatomic, strong) KBShopVM *shopVM;
|
||||||
@property (nonatomic, strong, nullable) KBShopThemeDetailModel *detailModel;
|
@property (nonatomic, strong, nullable) KBShopThemeDetailModel *detailModel;
|
||||||
|
@property (nonatomic, assign) BOOL isProcessingAction;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation KBSkinDetailVC
|
@implementation KBSkinDetailVC
|
||||||
@@ -69,6 +72,7 @@ typedef NS_ENUM(NSInteger, KBSkinDetailSection) {
|
|||||||
make.bottom.equalTo(self.bottomBar.mas_top).offset(-10);
|
make.bottom.equalTo(self.bottomBar.mas_top).offset(-10);
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
[self updateBottomBarAppearance];
|
||||||
[self fetchThemeDetailIfNeeded];
|
[self fetchThemeDetailIfNeeded];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,7 +212,87 @@ typedef NS_ENUM(NSInteger, KBSkinDetailSection) {
|
|||||||
|
|
||||||
#pragma mark - Actions
|
#pragma mark - Actions
|
||||||
- (void)handleDownloadAction {
|
- (void)handleDownloadAction {
|
||||||
// 预留:下载/购买动作
|
if (self.isProcessingAction) { return; }
|
||||||
|
if (self.themeId.length == 0) {
|
||||||
|
[KBHUD showInfo:KBLocalized(@"主题信息缺失")];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!self.detailModel) {
|
||||||
|
[KBHUD showInfo:KBLocalized(@"正在加载主题详情")];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (self.detailModel.isPurchased) {
|
||||||
|
[self requestDownload];
|
||||||
|
} else {
|
||||||
|
[self purchaseCurrentTheme];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)purchaseCurrentTheme {
|
||||||
|
if (self.isProcessingAction) { return; }
|
||||||
|
self.isProcessingAction = YES;
|
||||||
|
[KBHUD show];
|
||||||
|
__weak typeof(self) weakSelf = self;
|
||||||
|
[self.shopVM purchaseThemeWithId:self.themeId completion:^(BOOL success, NSError * _Nullable error) {
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
weakSelf.isProcessingAction = NO;
|
||||||
|
[KBHUD dismiss];
|
||||||
|
if (error || !success) {
|
||||||
|
NSString *msg = error.localizedDescription ?: KBLocalized(@"购买失败");
|
||||||
|
[KBHUD showInfo:msg];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
weakSelf.detailModel.isPurchased = YES;
|
||||||
|
[weakSelf updateBottomBarAppearance];
|
||||||
|
[weakSelf requestDownload];
|
||||||
|
});
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)requestDownload {
|
||||||
|
if (self.isProcessingAction) { return; }
|
||||||
|
self.isProcessingAction = YES;
|
||||||
|
[KBHUD show];
|
||||||
|
NSMutableDictionary *skin = [NSMutableDictionary dictionary];
|
||||||
|
if (!skin[@"id"] && self.detailModel.themeId) {
|
||||||
|
skin[@"id"] = self.detailModel.themeId;
|
||||||
|
}
|
||||||
|
if (!skin[@"name"] && self.detailModel.themeName) {
|
||||||
|
skin[@"name"] = self.detailModel.themeName;
|
||||||
|
}
|
||||||
|
if (!skin[@"themeDownloadUrl"]) {
|
||||||
|
[KBHUD showInfo:KBLocalized(@"缺少下载地址")];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
skin[@"themeDownloadUrl"] = self.detailModel.themeDownloadUrl;
|
||||||
|
|
||||||
|
[[KBSkinService shared] applySkinWithJSON:skin
|
||||||
|
fromViewController:self
|
||||||
|
mode:KBSkinSourceModeRemoteZip
|
||||||
|
completion:^(BOOL success) {
|
||||||
|
if (success) {
|
||||||
|
[KBHUD showSuccess:KBLocalized(@"已开始下载")];
|
||||||
|
} else {
|
||||||
|
[KBHUD showInfo:KBLocalized(@"下载失败")];
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updateBottomBarAppearance {
|
||||||
|
BOOL purchased = self.detailModel.isPurchased;
|
||||||
|
if (purchased) {
|
||||||
|
self.bottomBar.titleText = KBLocalized(@"Download again");
|
||||||
|
self.bottomBar.showsPrice = NO;
|
||||||
|
} else {
|
||||||
|
NSString *price = self.detailModel ? [NSString stringWithFormat:@"%.2f", self.detailModel.themePrice] : @"0";
|
||||||
|
self.bottomBar.titleText = KBLocalized(@"Download");
|
||||||
|
self.bottomBar.priceText = price;
|
||||||
|
self.bottomBar.showsPrice = YES;
|
||||||
|
UIImage *coin = [UIImage imageNamed:@"shop_jb_icon"];
|
||||||
|
if (coin) {
|
||||||
|
self.bottomBar.iconImage = coin;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)fetchThemeDetailIfNeeded {
|
- (void)fetchThemeDetailIfNeeded {
|
||||||
@@ -235,6 +319,7 @@ typedef NS_ENUM(NSInteger, KBSkinDetailSection) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
weakSelf.tags = tagNames.copy;
|
weakSelf.tags = tagNames.copy;
|
||||||
|
[weakSelf updateBottomBarAppearance];
|
||||||
[weakSelf.collectionView reloadData];
|
[weakSelf.collectionView reloadData];
|
||||||
});
|
});
|
||||||
}];
|
}];
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ typedef void(^KBShopBalanceCompletion)(NSNumber *_Nullable balance,
|
|||||||
NSError *_Nullable error);
|
NSError *_Nullable error);
|
||||||
typedef void(^KBShopDetailCompletion)(KBShopThemeDetailModel *_Nullable detail,
|
typedef void(^KBShopDetailCompletion)(KBShopThemeDetailModel *_Nullable detail,
|
||||||
NSError *_Nullable error);
|
NSError *_Nullable error);
|
||||||
|
typedef void(^KBShopPurchaseCompletion)(BOOL success,
|
||||||
|
NSError *_Nullable error);
|
||||||
|
typedef void(^KBShopDownloadInfoCompletion)(NSDictionary *_Nullable info,
|
||||||
|
NSError *_Nullable error);
|
||||||
|
|
||||||
@interface KBShopVM : NSObject
|
@interface KBShopVM : NSObject
|
||||||
@property (nonatomic, copy, readonly, nullable) NSArray<KBShopStyleModel *> *styles;
|
@property (nonatomic, copy, readonly, nullable) NSArray<KBShopStyleModel *> *styles;
|
||||||
@@ -41,6 +45,14 @@ typedef void(^KBShopDetailCompletion)(KBShopThemeDetailModel *_Nullable detail,
|
|||||||
- (void)fetchThemeDetailWithId:(nullable NSString *)themeId
|
- (void)fetchThemeDetailWithId:(nullable NSString *)themeId
|
||||||
completion:(KBShopDetailCompletion)completion;
|
completion:(KBShopDetailCompletion)completion;
|
||||||
|
|
||||||
|
/// 购买主题
|
||||||
|
- (void)purchaseThemeWithId:(nullable NSString *)themeId
|
||||||
|
completion:(KBShopPurchaseCompletion)completion;
|
||||||
|
|
||||||
|
/// 获取主题下载信息
|
||||||
|
- (void)fetchThemeDownloadInfoWithId:(nullable NSString *)themeId
|
||||||
|
completion:(KBShopDownloadInfoCompletion)completion;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
@interface KBShopVM ()
|
@interface KBShopVM ()
|
||||||
@property (nonatomic, copy, readwrite, nullable) NSArray<KBShopStyleModel *> *styles;
|
@property (nonatomic, copy, readwrite, nullable) NSArray<KBShopStyleModel *> *styles;
|
||||||
|
- (id)kb_themeIdParamFromString:(NSString *)themeId;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
@@ -99,17 +100,17 @@
|
|||||||
if (completion) completion(nil, [self kb_invalidResponseError]);
|
if (completion) completion(nil, [self kb_invalidResponseError]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
NSString *balanceValue = dataObj[@"balanceDisplay"];
|
id balanceValue = dataObj[@"balance"];
|
||||||
// NSNumber *balanceNumber = nil;
|
NSNumber *balanceNumber = nil;
|
||||||
// if ([balanceValue isKindOfClass:[NSNumber class]]) {
|
if ([balanceValue isKindOfClass:[NSNumber class]]) {
|
||||||
// balanceNumber = balanceValue;
|
balanceNumber = balanceValue;
|
||||||
// } else if ([balanceValue isKindOfClass:[NSString class]]) {
|
} else if ([balanceValue isKindOfClass:[NSString class]]) {
|
||||||
// balanceNumber = @([(NSString *)balanceValue doubleValue]);
|
balanceNumber = @([(NSString *)balanceValue doubleValue]);
|
||||||
// }
|
}
|
||||||
// if (!balanceNumber) {
|
if (!balanceNumber) {
|
||||||
// balanceNumber = @(0);
|
balanceNumber = @(0);
|
||||||
// }
|
}
|
||||||
if (completion) completion(balanceValue, nil);
|
if (completion) completion(balanceNumber, nil);
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,7 +120,7 @@
|
|||||||
if (completion) completion(nil, [self kb_invalidParameterError]);
|
if (completion) completion(nil, [self kb_invalidParameterError]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
NSDictionary *params = @{@"themeId": themeId};
|
NSDictionary *params = @{@"themeId": [self kb_themeIdParamFromString:themeId]};
|
||||||
[[KBNetworkManager shared] GET:API_THEME_DETAIL
|
[[KBNetworkManager shared] GET:API_THEME_DETAIL
|
||||||
parameters:params
|
parameters:params
|
||||||
headers:nil
|
headers:nil
|
||||||
@@ -141,4 +142,56 @@
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)purchaseThemeWithId:(nullable NSString *)themeId
|
||||||
|
completion:(KBShopPurchaseCompletion)completion {
|
||||||
|
if (themeId.length == 0) {
|
||||||
|
if (completion) completion(NO, [self kb_invalidParameterError]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NSDictionary *body = @{@"themeId": [self kb_themeIdParamFromString:themeId]};
|
||||||
|
[[KBNetworkManager shared] POST:API_THEME_PURCHASE
|
||||||
|
jsonBody:body
|
||||||
|
headers:nil
|
||||||
|
autoShowBusinessError:NO
|
||||||
|
completion:^(NSDictionary * _Nullable json,
|
||||||
|
NSURLResponse * _Nullable response,
|
||||||
|
NSError * _Nullable error) {
|
||||||
|
if (completion) completion(error == nil, error);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)fetchThemeDownloadInfoWithId:(nullable NSString *)themeId
|
||||||
|
completion:(KBShopDownloadInfoCompletion)completion {
|
||||||
|
if (themeId.length == 0) {
|
||||||
|
if (completion) completion(nil, [self kb_invalidParameterError]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NSDictionary *params = @{@"themeId": [self kb_themeIdParamFromString:themeId]};
|
||||||
|
[[KBNetworkManager shared] GET:API_THEME_DOWNLOAD
|
||||||
|
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:[NSDictionary class]]) {
|
||||||
|
if (completion) completion(nil, [self kb_invalidResponseError]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (completion) completion((NSDictionary *)dataObj, nil);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)kb_themeIdParamFromString:(NSString *)themeId {
|
||||||
|
if (themeId.length == 0) { return @""; }
|
||||||
|
NSNumberFormatter *formatter = [NSNumberFormatter new];
|
||||||
|
NSNumber *number = [formatter numberFromString:themeId];
|
||||||
|
return number ?: themeId;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
Reference in New Issue
Block a user